# Copyright (C) 2008 Jimmy Do # Copyright (C) 2010 Kenny Meyer # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA import datetime import time import gobject class Timer(gobject.GObject): (STATE_IDLE, STATE_RUNNING, STATE_PAUSED, STATE_FINISHED) = xrange(4) __gsignals__ = {'time-changed': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, ()), 'state-changed': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, ())} def __init__(self): gobject.GObject.__init__(self) self._state = Timer.STATE_IDLE self._duration_seconds = 0 self._remaining_seconds = 0 self._end_time = 0 self._name = '' self._command = '' self._next_timer = '' self._auto_start = False def set_duration(self, seconds): """Set the duration of the timer in seconds.""" assert self._state == Timer.STATE_IDLE self._duration_seconds = seconds def get_duration(self): """Return the duration of the timer in seconds.""" return self._duration_seconds def set_name(self, name): """Set the name of the timer.""" assert self._state == Timer.STATE_IDLE self._name = name def get_name(self): """Return the name of the timer.""" return self._name def set_command(self, command): """Set the command to run of the timer.""" assert self._state == Timer.STATE_IDLE self._command = command def get_command(self): """Return the name of the command of the timer.""" return self._command def set_next_timer(self, timer): """Set the next timeer of the timer.""" assert self._state == Timer.STATE_IDLE self._next_timer = timer def get_next_timer(self): """Get the next timer of the timer.""" return self._next_timer def set_auto_start(self, auto_start): """Set the auto-start value of the timer.""" assert self._state == Timer.STATE_IDLE self._auto_start = auto_start def get_auto_start(self): """Get the auto-start value.""" return self._auto_start def start(self): """Start or resume the timer. This method should only be called when the timer is IDLE or PAUSED. """ assert self._state == Timer.STATE_IDLE or self._state == Timer.STATE_PAUSED self._timer_transition_to_state(Timer.STATE_RUNNING) def stop(self): """Pause the timer. This method should only be called when the timer is RUNNING. """ assert self._state == Timer.STATE_RUNNING self._timer_transition_to_state(Timer.STATE_PAUSED) def reset(self): """Reset the timer. This method should only be called when the timer is not IDLE. """ assert self._state != Timer.STATE_IDLE self._timer_transition_to_state(Timer.STATE_IDLE) def get_state(self): """Return the current state.""" return self._state def get_remaining_time(self): """Return the remaining time in seconds.""" return min(self._duration_seconds, max(0, self._remaining_seconds)) def get_end_time(self): """Return a datetime object representing the end time. This method should only be called when the timer is RUNNING or FINISHED. """ assert self._state == Timer.STATE_RUNNING or self._state == Timer.STATE_FINISHED return datetime.datetime.fromtimestamp(self._end_time) def _timer_set_state(self, state): self._state = state self.emit('state-changed') def _timer_transition_to_state(self, dest_state): cur_time = int(time.time()) if dest_state == Timer.STATE_IDLE: self._end_time = 0 self._set_remaining_time(self._duration_seconds) elif dest_state == Timer.STATE_RUNNING: assert self._duration_seconds >= 0 if self._state == Timer.STATE_IDLE: self._end_time = cur_time + self._duration_seconds self._set_remaining_time(self._duration_seconds) elif self._state == Timer.STATE_PAUSED: self._end_time = cur_time + self._remaining_seconds gobject.timeout_add(500, self._on_timeout) elif dest_state == Timer.STATE_PAUSED: self._set_remaining_time(self._end_time - cur_time) self._end_time = 0 elif dest_state == Timer.STATE_FINISHED: pass else: assert False self._timer_set_state(dest_state) def _on_timeout(self): if self._state != Timer.STATE_RUNNING: return False # remove timeout source new_remaining = self._end_time - int(time.time()) if self._remaining_seconds != new_remaining: self._set_remaining_time(new_remaining) if self._remaining_seconds < 0: self._timer_transition_to_state(Timer.STATE_FINISHED) return False # remove timeout source return True # keep timeout source def _set_remaining_time(self, new_remaining): self._remaining_seconds = new_remaining self.emit('time-changed')