[kupfer: 1/7] +plugin.gtg: plugin for Getting Things GNOME! (GTG)
- From: Ulrik Sverdrup <usverdrup src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [kupfer: 1/7] +plugin.gtg: plugin for Getting Things GNOME! (GTG)
- Date: Thu, 27 May 2010 19:18:05 +0000 (UTC)
commit c78fc73e3e1fcb4a0e95db26821643488ec8c09b
Author: Karol BÄ?dkowski <karol bedkowski gmail com>
Date: Fri May 7 22:27:20 2010 +0200
+plugin.gtg: plugin for Getting Things GNOME! (GTG)
Plugin provide:
- access to tasks in GTG (list in Kupfer, open in GTG)
- create new task from TextLeaf
- change status of Task to complited, dismiss and delete
When GTG is not running tasks are loading from xml files
stored in ~/.local/share/gtg/. Also new tasks are created by
call gtg_new_task application.
When GTG is available (and dbus connection can be established) all
data are loaded by dbus. Unfortunately GTG don't provide any
"on-data-changes" signal, so all updates are detected by detect changes in
xml files.
kupfer/plugin/gtg.py | 248 ++++++++++++++++++++++++++++++++++++++++++++++++++
po/POTFILES.in | 1 +
2 files changed, 249 insertions(+), 0 deletions(-)
---
diff --git a/kupfer/plugin/gtg.py b/kupfer/plugin/gtg.py
new file mode 100644
index 0000000..b0c4c6b
--- /dev/null
+++ b/kupfer/plugin/gtg.py
@@ -0,0 +1,248 @@
+# -*- coding: UTF-8 -*-
+__kupfer_name__ = _("Getting Things GNOME")
+__kupfer_sources__ = ("TasksSource", )
+__kupfer_actions__ = ("CreateNewTask",)
+__description__ = _("Browse and create new task in GTG")
+__version__ = "2010-05-07"
+__author__ = "Karol BÄ?dkowski <karol bedkowski gmail com>"
+
+
+import os
+import subprocess
+from xml.etree import cElementTree as ElementTree
+
+import dbus
+import gio
+
+from kupfer import plugin_support
+from kupfer import pretty
+from kupfer.obj.base import Leaf, Action, Source
+from kupfer.obj.objects import TextLeaf
+from kupfer.obj.apps import AppLeafContentMixin
+from kupfer.obj.helplib import PicklingHelperMixin
+
+plugin_support.check_dbus_connection()
+
+_SERVICE_NAME = 'org.GTG'
+_OBJECT_NAME = '/org/GTG'
+_IFACE_NAME = 'org.GTG'
+
+
+def _create_dbus_connection(activate=False):
+ ''' Create dbus connection to Gajim
+ @activate: true=starts gajim if not running
+ '''
+ interface = None
+ sbus = dbus.SessionBus()
+ try:
+ proxy_obj = sbus.get_object('org.freedesktop.DBus',
+ '/org/freedesktop/DBus')
+ dbus_iface = dbus.Interface(proxy_obj, 'org.freedesktop.DBus')
+ if activate or dbus_iface.NameHasOwner(_IFACE_NAME):
+ obj = sbus.get_object(_SERVICE_NAME, _OBJECT_NAME)
+ if obj:
+ interface = dbus.Interface(obj, _IFACE_NAME)
+ except dbus.exceptions.DBusException, err:
+ pretty.print_debug(err)
+ return interface
+
+
+def _load_tasks(interface):
+ ''' Load task by dbus interface '''
+ for task in interface.get_tasks():
+ title = task['title'] or task['text'][:80]
+ otask = Task(task['id'], title, task['status'])
+ otask.duedate = task['duedate']
+ otask.startdate = task['startdate']
+ otask.tags = task['tags']
+ yield otask
+
+
+def _load_task_from_xml():
+ ''' Load tasks by xml file (when no gtg running) '''
+ gtg_local_dir = os.path.expanduser("~/.local/share/gtg/")
+ for fname in os.listdir(gtg_local_dir):
+ if not fname.endswith('.xml') or fname == 'projects.xml' or \
+ fname == 'tags.xml':
+ continue
+ ffullpath = os.path.join(gtg_local_dir, fname)
+ if not os.path.isfile(ffullpath):
+ continue
+ tree = ElementTree.parse(ffullpath)
+ for task in tree.findall('task'):
+ status = task.attrib['status']
+ if status != 'Active':
+ continue
+ task_id = task.attrib['id']
+ title = task.find('title').text.strip()
+ otask = Task(task_id, title, status)
+ tags = task.attrib['tags']
+ if tags:
+ otask.tags = tags.split(",")
+ duedate_n = task.find('duedate')
+ if duedate_n is not None:
+ otask.duedate = duedate_n.text.strip()
+ startdate_n = task.find('startdate')
+ if startdate_n is not None:
+ otask.startdate = startdate_n.text.strip()
+ yield otask
+
+
+class Task(Leaf):
+ def __init__(self, task_id, title, status):
+ Leaf.__init__(self, task_id, title)
+ self.status = status
+ self.tags = None
+ self.duedate = None
+ self.startdate = None
+
+ def get_description(self):
+ descr = [self.status]
+ if self.duedate:
+ descr.append(_("due: %s") % self.duedate)
+ if self.startdate:
+ descr.append(_("start: %s") % self.startdate)
+ if self.tags:
+ descr.append(_("tags: %s") % " ".join(self.tags))
+ return " ".join(descr)
+
+ def get_icon_name(self):
+ return 'gtg'
+
+ def get_actions(self):
+ yield OpenTaskEditor()
+ yield DeleteTask()
+ yield MarkTaskDone()
+ yield DismissTask()
+
+
+class OpenTaskEditor(Action):
+ def __init__(self):
+ Action.__init__(self, _("Open Task Editor"))
+
+ def activate(self, leaf):
+ interface = _create_dbus_connection()
+ if interface is not None:
+ interface.open_task_editor(leaf.object)
+
+ def get_icon_name(self):
+ return 'gtk-open'
+
+
+class DeleteTask(Action):
+ rank_adjust = -5
+
+ def __init__(self):
+ Action.__init__(self, _("Delete Task"))
+
+ def activate(self, leaf):
+ interface = _create_dbus_connection()
+ if interface is not None:
+ interface.delete_task(leaf.object)
+
+ def get_icon_name(self):
+ return 'delete'
+
+ def get_description(self):
+ return _("Permanently remove this task")
+
+
+class MarkTaskDone(Action):
+ def __init__(self):
+ Action.__init__(self, _("Mark Task Done"))
+
+ def activate(self, leaf):
+ interface = _create_dbus_connection()
+ if interface is not None:
+ task = interface.get_task(leaf.object)
+ task['status'] = 'Done'
+ interface.modify_task(leaf.object, task)
+
+ def get_icon_name(self):
+ return 'gtg-task-done'
+
+ def get_description(self):
+ return _("Mark this task as done")
+
+
+class DismissTask (Action):
+ def __init__(self):
+ Action.__init__(self, _("Dismiss Task"))
+
+ def activate(self, leaf):
+ interface = _create_dbus_connection()
+ if interface is not None:
+ task = interface.get_task(leaf.object)
+ task['status'] = 'Dismiss'
+ interface.modify_task(leaf.object, task)
+
+ def get_icon_name(self):
+ return 'gtg-task-dismiss'
+
+ def get_description(self):
+ return _("Mark this task as not to be done anymore")
+
+
+class CreateNewTask(Action):
+ def __init__(self):
+ Action.__init__(self, _("Create New Task"))
+
+ def activate(self, leaf):
+ interface = _create_dbus_connection()
+ if interface is not None:
+ if '\n' in leaf.object:
+ title, text = leaf.object.split('\n', 1)
+ interface.open_new_task(title, text)
+ else:
+ interface.open_new_task(leaf.object, '')
+ else:
+ p = subprocess.Popen(["gtg_new_task", "-i"], stdin=subprocess.PIPE,
+ close_fds=True)
+ p.stdin.write(leaf.object)
+ p.stdin.close()
+
+ def item_types(self):
+ yield TextLeaf
+
+ def get_icon_name(self):
+ return 'gtg-task-new'
+
+ def get_description(self):
+ return _("Create new task in Getting Things GNOME")
+
+
+class TasksSource(AppLeafContentMixin, Source, PicklingHelperMixin):
+ appleaf_content_id = 'gtg'
+
+ def __init__(self, name=_('GTG Tasks')):
+ Source.__init__(self, name)
+ self._tasks = []
+ self._version = 2
+
+ def initialize(self):
+ gtg_local_dir = os.path.expanduser("~/.local/share/gtg/")
+ gfile = gio.File(gtg_local_dir)
+ self.monitor = gfile.monitor_directory(gio.FILE_MONITOR_NONE, None)
+ if self.monitor:
+ self.monitor.connect("changed", self._changed)
+
+ def pickle_prepare(self):
+ self.monitor = None
+
+ def get_items(self):
+ interface = _create_dbus_connection()
+ self._tasks = []
+ if interface is None:
+ self._tasks = list(_load_task_from_xml())
+ else:
+ self._tasks = list(_load_tasks(interface))
+ return self._tasks
+
+ def get_icon_name(self):
+ return 'gtg'
+
+ def provides(self):
+ return Task
+
+ def _changed(self, _monitor, _file1, _file2, _evt_type):
+ self.mark_for_update()
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 04cc1ed..b067649 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -77,6 +77,7 @@ kupfer/plugin/gmail/__init__.py
kupfer/plugin/google_picasa/__init__.py
kupfer/plugin/google_search.py
kupfer/plugin/google_translate.py
+kupfer/plugin/gtg.py
kupfer/plugin/higherorder.py
kupfer/plugin/image.py
kupfer/plugin/kupfer_plugins.py
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]