summaryrefslogtreecommitdiff
path: root/timer-applet/src/timerapplet/core
diff options
context:
space:
mode:
Diffstat (limited to 'timer-applet/src/timerapplet/core')
-rw-r--r--timer-applet/src/timerapplet/core/AppletMateConfWrapper.py89
-rw-r--r--timer-applet/src/timerapplet/core/Makefile.am6
-rw-r--r--timer-applet/src/timerapplet/core/PresetsStore.py160
-rw-r--r--timer-applet/src/timerapplet/core/Timer.py175
-rw-r--r--timer-applet/src/timerapplet/core/__init__.py19
5 files changed, 449 insertions, 0 deletions
diff --git a/timer-applet/src/timerapplet/core/AppletMateConfWrapper.py b/timer-applet/src/timerapplet/core/AppletMateConfWrapper.py
new file mode 100644
index 00000000..c5d09619
--- /dev/null
+++ b/timer-applet/src/timerapplet/core/AppletMateConfWrapper.py
@@ -0,0 +1,89 @@
+# Copyright (C) 2008 Jimmy Do <[email protected]>
+#
+# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+from os import path
+import mateconf
+
+class AppletMateConfWrapper(object):
+ def __init__(self, applet, schema_path, standalone_key):
+ object.__init__(self)
+ self._connection_ids = []
+
+ self._client = mateconf.client_get_default()
+
+ # Get preferences key path for the given applet instance.
+ self._base_path = applet.get_preferences_key()
+ if self._base_path is not None:
+ # Apply the schema to the applet instance preferences key.
+ applet.add_preferences(schema_path)
+ else:
+ # NOTE: Don't need to apply schema here because the Timer Applet schema file
+ # already specifies that the schema be automatically applied to the standalone key.
+
+ self._base_path = standalone_key
+
+ # Applet would usually do this for us, but since we're running in standalone mode,
+ # we have to do this ourselves in order to receive MateConf change notifications.
+ self._client.add_dir(self._base_path, mateconf.CLIENT_PRELOAD_RECURSIVE)
+
+ print 'Base prefs path = %s' % self._base_path
+
+ def get_base_path(self):
+ return self._base_path
+
+ def add_notification(self, relative_key, callback, data=None):
+ """Register for notifications of changes to the given preference key.
+
+ relative_key should be relative to the applet's base preferences key path.
+ callback should look like: callback(MateConfValue, data=None)
+ """
+ connection_id = self._client.notify_add(self._get_full_path(relative_key),
+ self._notification_callback, (callback, data))
+ self._connection_ids.append(connection_id)
+
+ def get_string(self, relative_key):
+ return self._client.get_string(self._get_full_path(relative_key))
+
+ def get_bool(self, relative_key):
+ return self._client.get_bool(self._get_full_path(relative_key))
+
+ def set_string(self, relative_key, val):
+ self._client.set_string(self._get_full_path(relative_key), val)
+
+ def set_bool(self, relative_key, val):
+ self._client.set_bool(self._get_full_path(relative_key), val)
+
+ def delete(self):
+ for connection_id in self._connection_ids:
+ self._client.notify_remove(connection_id)
+ self._connection_ids = []
+
+ def _notification_callback(self, client, cnxn_id, entry, data=None):
+ (callback, real_data) = data
+
+ # mateconf_value is of type MateConfValue (mateconf.Value)
+ mateconf_value = entry.get_value()
+
+ # Ignore when mateconf_value is None because that
+ # means that the settings are being removed
+ # because the applet has been removed from
+ # the panel.
+ if mateconf_value != None:
+ callback(mateconf_value, real_data)
+
+ def _get_full_path(self, relative_key):
+ return path.join(self._base_path, relative_key)
+
diff --git a/timer-applet/src/timerapplet/core/Makefile.am b/timer-applet/src/timerapplet/core/Makefile.am
new file mode 100644
index 00000000..6c974866
--- /dev/null
+++ b/timer-applet/src/timerapplet/core/Makefile.am
@@ -0,0 +1,6 @@
+moduledir = $(pythondir)/timerapplet/core
+module_PYTHON = \
+ __init__.py \
+ AppletMateConfWrapper.py \
+ PresetsStore.py \
+ Timer.py
diff --git a/timer-applet/src/timerapplet/core/PresetsStore.py b/timer-applet/src/timerapplet/core/PresetsStore.py
new file mode 100644
index 00000000..edd5655a
--- /dev/null
+++ b/timer-applet/src/timerapplet/core/PresetsStore.py
@@ -0,0 +1,160 @@
+# Copyright (C) 2008 Jimmy Do <[email protected]>
+# Copyright (C) 2010 Kenny Meyer <[email protected]>
+#
+# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+try:
+ from xml.etree import ElementTree as et
+except:
+ from elementtree import ElementTree as et
+
+import os
+from os import path
+import gobject
+import gtk
+import timerapplet.utils as utils
+
+from timerapplet.utils import (serialize_bool,
+ deserialize_bool,
+ seconds_to_hms,
+ hms_to_seconds)
+from timerapplet.defs import VERSION
+
+class PersistentStore(gtk.ListStore):
+ def __init__(self, load_func, save_func, *args):
+ gtk.ListStore.__init__(self, *args)
+ load_func(self)
+
+ self.connect('row-deleted', lambda model, row_path: save_func(self))
+ self.connect('row-changed', lambda model, row_path, row_iter: save_func(self))
+
+class PresetsStore(gobject.GObject):
+ (_NAME_COL,
+ _HOURS_COL,
+ _MINUTES_COL,
+ _SECONDS_COL,
+ _COM_COL,
+ _NEXT_COL,
+ _AUTO_START_COL) = xrange(7)
+
+ def __init__(self, filename):
+ object.__init__(self)
+ self._model = PersistentStore(lambda model: PresetsStore._load_presets(model, filename),
+ lambda model: PresetsStore._save_presets(model, filename),
+ gobject.TYPE_STRING,
+ gobject.TYPE_INT,
+ gobject.TYPE_INT,
+ gobject.TYPE_INT,
+ gobject.TYPE_STRING,
+ gobject.TYPE_STRING,
+ gobject.TYPE_BOOLEAN,
+ )
+
+ def get_model(self):
+ """Return GtkTreeModel.
+
+ Should not rely on it being any particular subtype of GtkTreeModel.
+
+ """
+ return self._model
+
+ def get_preset(self, row_iter):
+ return self._model.get(row_iter,
+ PresetsStore._NAME_COL,
+ PresetsStore._HOURS_COL,
+ PresetsStore._MINUTES_COL,
+ PresetsStore._SECONDS_COL,
+ PresetsStore._COM_COL,
+ PresetsStore._NEXT_COL,
+ PresetsStore._AUTO_START_COL,
+ )
+
+ def add_preset(self, name, hours, minutes, seconds, command, next_timer,
+ auto_start):
+ self._model.append((name, hours, minutes, seconds, command, next_timer,
+ auto_start))
+
+ def modify_preset(self, row_iter, name, hours, minutes, seconds, command,
+ next_timer, auto_start):
+ self._model.set(row_iter,
+ PresetsStore._NAME_COL, name,
+ PresetsStore._HOURS_COL, hours,
+ PresetsStore._MINUTES_COL, minutes,
+ PresetsStore._SECONDS_COL, seconds,
+ PresetsStore._COM_COL, command,
+ PresetsStore._NEXT_COL, next_timer,
+ PresetsStore._AUTO_START_COL, auto_start
+ )
+
+ def remove_preset(self, row_iter):
+ self._model.remove(row_iter)
+
+ def preset_name_exists_case_insensitive(self, preset_name):
+ preset_name = preset_name.lower()
+ for preset in self._model:
+ if preset_name == preset[PresetsStore._NAME_COL].lower():
+ return True
+ return False
+
+ def _load_presets(model, file_path):
+ try:
+ tree = et.parse(file_path)
+ except:
+ return
+
+ root = tree.getroot()
+
+ for node in root:
+ name = node.get('name')
+ (hours, minutes, seconds) = seconds_to_hms(int(node.get('duration')))
+ command = node.get('command')
+ next_timer = node.get('next_timer')
+ auto_start = node.get('auto_start')
+ model.append((name, hours, minutes, seconds, command, next_timer,
+ deserialize_bool(auto_start)))
+ _load_presets = staticmethod(_load_presets)
+
+ def _save_presets(model, file_path):
+ root = et.Element('timerapplet')
+ root.set('version', VERSION)
+
+ def add_xml_node(model, path, row_iter):
+ (name, hours, minutes, seconds, command, next_timer, auto_start) = \
+ model.get(row_iter,
+ PresetsStore._NAME_COL,
+ PresetsStore._HOURS_COL,
+ PresetsStore._MINUTES_COL,
+ PresetsStore._SECONDS_COL,
+ PresetsStore._COM_COL,
+ PresetsStore._NEXT_COL,
+ PresetsStore._AUTO_START_COL
+ )
+ node = et.SubElement(root, 'preset')
+ node.set('name', name)
+ node.set('duration', str(hms_to_seconds(hours, minutes, seconds)))
+ node.set('command', command or '')
+ node.set('next_timer', next_timer or '')
+ node.set('auto_start', serialize_bool(auto_start))
+
+ model.foreach(add_xml_node)
+ tree = et.ElementTree(root)
+
+ file_dir = path.dirname(file_path)
+ if not path.exists(file_dir):
+ print 'Creating config directory: %s' % file_dir
+ os.makedirs(file_dir, 0744)
+ tree.write(file_path)
+ _save_presets = staticmethod(_save_presets)
+
diff --git a/timer-applet/src/timerapplet/core/Timer.py b/timer-applet/src/timerapplet/core/Timer.py
new file mode 100644
index 00000000..f4ba57a2
--- /dev/null
+++ b/timer-applet/src/timerapplet/core/Timer.py
@@ -0,0 +1,175 @@
+# Copyright (C) 2008 Jimmy Do <[email protected]>
+# Copyright (C) 2010 Kenny Meyer <[email protected]>
+#
+# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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')
diff --git a/timer-applet/src/timerapplet/core/__init__.py b/timer-applet/src/timerapplet/core/__init__.py
new file mode 100644
index 00000000..861b496d
--- /dev/null
+++ b/timer-applet/src/timerapplet/core/__init__.py
@@ -0,0 +1,19 @@
+# Copyright (C) 2008 Jimmy Do <[email protected]>
+#
+# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+from Timer import Timer
+from PresetsStore import PresetsStore
+from AppletMateConfWrapper import AppletMateConfWrapper