← Back to team overview

gtg team mailing list archive

[Merge] lp:~tomkadwill/gtg/untouched-plugin into lp:gtg

 

Tom Kadwill has proposed merging lp:~tomkadwill/gtg/untouched-plugin into lp:gtg.

Requested reviews:
  Gtg developers (gtg)

For more details, see:
https://code.launchpad.net/~tomkadwill/gtg/untouched-plugin/+merge/132986

Added untouched-tasks plugin in response to bug #320589
-- 
https://code.launchpad.net/~tomkadwill/gtg/untouched-plugin/+merge/132986
Your team Gtg developers is requested to review the proposed merge of lp:~tomkadwill/gtg/untouched-plugin into lp:gtg.
=== modified file 'AUTHORS'
--- AUTHORS	2012-08-12 23:01:10 +0000
+++ AUTHORS	2012-11-05 22:34:19 +0000
@@ -109,3 +109,4 @@
 * Abhiram <abhiram.ampabathina@xxxxxxxxx>
 * Alan Gomes <alangalvino@xxxxxxxxx>
 * Stefan Handschuh <https://launchpad.net/~handschuh> (no email provided)
+* Tom Kadwill <tomkadwill@xxxxxxxxx>

=== modified file 'CHANGELOG'
--- CHANGELOG	2012-11-01 16:34:04 +0000
+++ CHANGELOG	2012-11-05 22:34:19 +0000
@@ -56,6 +56,7 @@
     * Remove use of liblarch's "transparent" concept (since it's been removed from liblarch), fixes bugs #1001962, #1001962, #1069257, #1069963: intermediary tags, counter initialization, and regressions caused by initial versions of the patch
     * Fix for bug #1038662: Undefined due dates in subtasks should always stay undefined and displayed as such in the editor
     * Fix for bug #1036695: Date constraints after drag and drop not applied
+    * Fix for bug #320589: Added untouched_tasks plugin
 
 2012-02-13 Getting Things GNOME! 0.2.9
     * Big refractorization of code, now using liblarch

=== added file 'GTG/plugins/untouched-tasks.gtg-plugin'
--- GTG/plugins/untouched-tasks.gtg-plugin	1970-01-01 00:00:00 +0000
+++ GTG/plugins/untouched-tasks.gtg-plugin	2012-11-05 22:34:19 +0000
@@ -0,0 +1,9 @@
+[GTG Plugin]
+Module=untouched_tasks
+Name=Untouched tasks
+Short-description="Keep track of tasks you haven't touched for a while."
+Description="""Assigns tasks that you haven't touched for a while with the @untouched tag."""
+Authors=Tom Kadwill <tomkadwill@xxxxxxxxx>
+Version=0.0.1
+Enabled=False
+Dependencies=gio, urllib

=== added directory 'GTG/plugins/untouched_tasks'
=== added file 'GTG/plugins/untouched_tasks/__init__.py'
--- GTG/plugins/untouched_tasks/__init__.py	1970-01-01 00:00:00 +0000
+++ GTG/plugins/untouched_tasks/__init__.py	2012-11-05 22:34:19 +0000
@@ -0,0 +1,22 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2012 - Tom Kadwill <tomkadwill@xxxxxxxxx>
+#
+# 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 3 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, see <http://www.gnu.org/licenses/>.
+
+from GTG.plugins.untouched_tasks.untouchedTasks import pluginUntouchedTasks
+
+
+#suppress pyflakes warning (given by make lint)
+if False == True:
+    pluginUntouchedTasks()

=== added file 'GTG/plugins/untouched_tasks/untouchedTasks.py'
--- GTG/plugins/untouched_tasks/untouchedTasks.py	1970-01-01 00:00:00 +0000
+++ GTG/plugins/untouched_tasks/untouchedTasks.py	2012-11-05 22:34:19 +0000
@@ -0,0 +1,203 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2012 - Tom Kadwill <tomkadwill@xxxxxxxxx>
+#
+# 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 3 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, see <http://www.gnu.org/licenses/>.
+
+import sys
+import os
+import gio
+import gtk
+import urllib
+import datetime
+
+from GTG import _
+from GTG.tools.logger import Log
+from GTG.tools.dates import Date
+from threading import Timer
+from datetime import date, timedelta
+
+try:
+    import pygtk
+    pygtk.require("2.0")
+except: # pylint: disable-msg=W0702
+    sys.exit(1)
+
+try:
+    import gtk
+except: # pylint: disable-msg=W0702
+    sys.exit(1)
+
+###################################
+
+class pluginUntouchedTasks:
+
+    DEFAULT_PREFERENCES = {'max_days': 30,
+                           'is_automatic': False,
+                           'show_menu_item': True}
+
+    PLUGIN_NAME = "untouched-tasks"
+
+    # In case of automatic removing tasks, the time
+    # between two runs of the cleaner function
+    TIME_BETWEEN_PURGES = 60 * 60
+
+    def __init__(self):
+        self.path = os.path.dirname(os.path.abspath(__file__))
+        #GUI initialization
+        self.builder = gtk.Builder()
+        self.builder.add_from_file(os.path.join(
+                             os.path.dirname(os.path.abspath(__file__)) + \
+                             "/untouchedTasks.ui"))
+        self.preferences_dialog = self.builder.get_object("preferences_dialog")
+        self.pref_chbox_show_menu_item = \
+                        self.builder.get_object("pref_chbox_show_menu_item")
+        self.pref_chbox_is_automatic = \
+                        self.builder.get_object("pref_chbox_is_automatic")
+        self.pref_spinbtn_max_days = \
+                        self.builder.get_object("pref_spinbtn_max_days")
+        SIGNAL_CONNECTIONS_DIC = {
+            "on_preferences_dialog_delete_event":
+                self.on_preferences_cancel,
+            "on_btn_preferences_cancel_clicked":
+                self.on_preferences_cancel,
+            "on_btn_preferences_ok_clicked":
+                self.on_preferences_ok,
+        }
+        self.builder.connect_signals(SIGNAL_CONNECTIONS_DIC)
+        self.menu_item = gtk.MenuItem("Add @untouched tag")
+        self.menu_item.connect('activate', self.add_untouched_tag)
+
+    def activate(self, plugin_api):
+        self.plugin_api = plugin_api
+        #preferences initialization
+        self.menu_item_is_shown = False
+        self.is_automatic = False
+        self.timer = None
+        self.preferences_load()
+        self.preferences_apply()
+        requester = self.plugin_api.get_requester()
+
+    def deactivate(self, plugin_api):
+        """
+        Deactivates the plugin.
+        """
+        #everything should be removed, in case a task is currently opened
+        try:
+            self.plugin_api.remove_task_toolbar_item(self.tb_Taskbutton)
+        except:
+            pass
+
+## HELPER FUNCTIONS ###########################################################
+    def __log(self, message):
+        Log.debug(message)
+
+## CORE FUNCTIONS #############################################################
+    def schedule_autopurge(self):
+        self.timer = Timer(self.TIME_BETWEEN_PURGES,
+                                self.add_untouched_tag)
+        self.timer.setDaemon(True)
+        self.timer.start()
+        self.__log("Automatic untouched tasks check scheduled")
+
+    def cancel_autopurge(self):
+        if self.timer:
+            self.__log("Automatic untouched tasks check cancelled")
+            self.timer.cancel()
+
+    def add_untouched_tag(self, widget = None):
+        """
+        When the user presses the button.
+        """
+        self.__log("Starting process for adding @untouched tag")
+        today = datetime.datetime.now()
+        max_days = self.preferences["max_days"]
+        requester = self.plugin_api.get_requester()
+        closed_tree = requester.get_tasks_tree(name = 'inactive')
+        closed_tasks = [requester.get_task(tid) for tid in \
+                        closed_tree.get_all_nodes()]
+        for task in closed_tasks:
+            modified_time = task.get_modified()
+            new_time = modified_time + datetime.timedelta(days=max_days)
+            if new_time < today:
+                self.__log('Adding @untouched tag to: "' + task.title +
+                '" as last time it was modified was ' + str(modified_time))
+                task.add_tag('@untouched')
+
+        #If automatic purging is on, schedule another run
+        if self.is_automatic:
+            self.schedule_autopurge()
+
+## Preferences methods ########################################################
+    def is_configurable(self):
+        """A configurable plugin should have this method and return True"""
+        return True
+
+    def configure_dialog(self, manager_dialog):
+        self.preferences_load()
+        self.preferences_dialog.set_transient_for(manager_dialog)
+        self.pref_chbox_is_automatic.set_active(
+                        self.preferences["is_automatic"])
+        self.pref_chbox_show_menu_item.set_active(
+                        self.preferences["show_menu_item"])
+        self.pref_spinbtn_max_days.set_value(
+                        self.preferences["max_days"])
+        self.preferences_dialog.show_all()
+
+    def on_preferences_cancel(self, widget = None, data = None):
+        self.preferences_dialog.hide()
+        return True
+
+    def on_preferences_ok(self, widget = None, data = None):
+        self.preferences["is_automatic"] = \
+                self.pref_chbox_is_automatic.get_active()
+        self.preferences["show_menu_item"] = \
+                self.pref_chbox_show_menu_item.get_active()
+        self.preferences["max_days"] = \
+                self.pref_spinbtn_max_days.get_value()
+        self.preferences_apply()
+        self.preferences_store()
+        self.preferences_dialog.hide()
+
+    def preferences_load(self):
+        data = self.plugin_api.load_configuration_object(self.PLUGIN_NAME,
+                                                         "preferences")
+        if data == None or type(data) != type(dict()):
+            self.preferences = self.DEFAULT_PREFERENCES
+        else:
+            self.preferences = data
+
+    def preferences_store(self):
+        self.plugin_api.save_configuration_object(self.PLUGIN_NAME,
+                                      "preferences", self.preferences)
+
+    def preferences_apply(self):
+        #Showing the GUI
+        if self.preferences['show_menu_item'] == True and \
+                            self.menu_item_is_shown == False:
+            self.plugin_api.add_menu_item(self.menu_item)
+            self.menu_item_is_shown = True
+        elif self.preferences['show_menu_item'] == False and \
+                            self.menu_item_is_shown == True:
+            self.plugin_api.remove_menu_item(self.menu_item)
+            self.menu_item_is_shown = False
+        #Auto-purge
+        if self.preferences['is_automatic'] == True and \
+                            self.is_automatic == False:
+            self.is_automatic = True
+            # Run the first iteration immediately and schedule next iteration
+            self.add_untouched_tag()
+        elif self.preferences['is_automatic'] == False and \
+                            self.is_automatic == True:
+            self.cancel_autopurge()
+            self.is_automatic = False

=== added file 'GTG/plugins/untouched_tasks/untouchedTasks.ui'
--- GTG/plugins/untouched_tasks/untouchedTasks.ui	1970-01-01 00:00:00 +0000
+++ GTG/plugins/untouched_tasks/untouchedTasks.ui	2012-11-05 22:34:19 +0000
@@ -0,0 +1,138 @@
+<?xml version="1.0"?>
+<interface>
+  <requires lib="gtk+" version="2.16"/>
+  <!-- interface-naming-policy toplevel-contextual -->
+  <object class="GtkAccelGroup" id="accelgroup1"/>
+  <object class="GtkWindow" id="preferences_dialog">
+    <property name="border_width">10</property>
+    <property name="window_position">center-on-parent</property>
+    <property name="type_hint">dialog</property>
+    <signal name="delete_event" handler="on_preferences_dialog_delete_event"/>
+    <child>
+      <object class="GtkVBox" id="vbox1">
+        <property name="visible">True</property>
+        <property name="orientation">vertical</property>
+        <child>
+          <object class="GtkVBox" id="vbox2">
+            <property name="visible">True</property>
+            <property name="orientation">vertical</property>
+            <property name="spacing">12</property>
+            <child>
+              <object class="GtkHBox" id="hbox2">
+                <property name="visible">True</property>
+                <child>
+                  <object class="GtkLabel" id="label2">
+                    <property name="visible">True</property>
+                    <property name="label" translatable="yes">Add @untouched tag to task after it has been left untouched for at least </property>
+                  </object>
+                  <packing>
+                    <property name="position">0</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkSpinButton" id="pref_spinbtn_max_days">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="max_length">3</property>
+                    <property name="invisible_char">&#x2022;</property>
+                    <property name="adjustment">adjustment1</property>
+                    <property name="climb_rate">0.5</property>
+                    <property name="snap_to_ticks">True</property>
+                    <property name="numeric">True</property>
+                  </object>
+                  <packing>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkLabel" id="label3">
+                    <property name="visible">True</property>
+                    <property name="label" translatable="yes"> days</property>
+                  </object>
+                  <packing>
+                    <property name="position">2</property>
+                  </packing>
+                </child>
+              </object>
+              <packing>
+                <property name="position">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkCheckButton" id="pref_chbox_is_automatic">
+                <property name="label" translatable="yes">Add @untouched tag to old tasks automatically</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">False</property>
+                <property name="image_position">top</property>
+                <property name="draw_indicator">True</property>
+              </object>
+              <packing>
+                <property name="position">1</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkCheckButton" id="pref_chbox_show_menu_item">
+                <property name="label" translatable="yes">Add the "Plugins &gt; Add @untouched plugin" menu item</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">False</property>
+                <property name="image_position">top</property>
+                <property name="draw_indicator">True</property>
+              </object>
+              <packing>
+                <property name="position">2</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="padding">21</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkHBox" id="hbox1">
+            <property name="height_request">30</property>
+            <property name="visible">True</property>
+            <property name="spacing">50</property>
+            <child>
+              <object class="GtkButton" id="btn_preferences_cancel">
+                <property name="label">gtk-cancel</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="use_stock">True</property>
+                <signal name="clicked" handler="on_btn_preferences_cancel_clicked"/>
+              </object>
+              <packing>
+                <property name="position">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkButton" id="btn_preferences_ok">
+                <property name="label">gtk-ok</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="use_stock">True</property>
+                <signal name="clicked" handler="on_btn_preferences_ok_clicked"/>
+              </object>
+              <packing>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="position">1</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+  </object>
+  <object class="GtkAdjustment" id="adjustment1">
+    <property name="lower">1</property>
+    <property name="upper">100</property>
+    <property name="step_increment">1</property>
+    <property name="page_increment">10</property>
+  </object>
+</interface>


Follow ups