GTG

Merge lp:~gtg-user/gtg/tomboy into lp:~gtg/gtg/old-trunk

Proposed by Luca Invernizzi
Status: Superseded
Proposed branch: lp:~gtg-user/gtg/tomboy
Merge into: lp:~gtg/gtg/old-trunk
Diff against target: 822 lines
16 files modified
.bzrignore (+2/-0)
GTG/core/plugins/api.py (+5/-1)
GTG/core/plugins/engine.py (+15/-4)
GTG/core/plugins/manager.py (+1/-7)
GTG/info.py (+2/-1)
GTG/plugins/rtm-sync.gtg-plugin (+2/-2)
GTG/plugins/rtm_sync/pyrtm/rtm.py (+5/-24)
GTG/plugins/rtm_sync/syncengine.py (+9/-11)
GTG/plugins/tomboy.gtg-plugin (+7/-0)
GTG/plugins/tomboy/__init__.py (+20/-0)
GTG/plugins/tomboy/combobox_enhanced.py (+76/-0)
GTG/plugins/tomboy/tomboy.glade (+110/-0)
GTG/plugins/tomboy/tomboy.py (+229/-0)
GTG/taskeditor/editor.py (+1/-0)
GTG/taskeditor/taskview.py (+3/-9)
locales/gtg.pot (+19/-3)
To merge this branch: bzr merge lp:~gtg-user/gtg/tomboy
Reviewer Review Type Date Requested Status
Gtg developers Pending
Review via email: mp+12056@code.launchpad.net

This proposal has been superseded by a proposal from 2009-09-24.

To post a comment you must log in.
Revision history for this message
Luca Invernizzi (invernizzi) wrote :

Tomboy notes support (via dbus).
A toolbar button displaying the Tomboy icon will appear in each task editor.
Clicking that, one can add a tomboy note just writing the note title in the combo box shown (which supports autocompletion). A new tomboy icon will appear in the task text, where the cursor was.

lp:~gtg-user/gtg/tomboy updated
319. By Lionel Dricot

instant apply plugins in the manager

320. By Bertrand Rousseau

Upgrade RTM plugin

321. By Lionel Dricot

left arrow for RTL locale bug #412578

322. By Lionel Dricot

non started tasks and tags now respect workview bug #409900

323. By Lionel Dricot

refresh task editors bug #339176

324. By Lionel Dricot

personal spelling (bug #427384) and better explanations in the first page (bug #400831)

325. By Lionel Dricot

allow capitalized days in quickadd bug #414116

326. By Lionel Dricot

loop when starting a new task

327. By Lionel Dricot

Solving crazy behaviour of the editor : bug #398651

It was really easier than I thought. I see two possible explanations :

1) I'm a semi-god

2) Our architecture is not bad at all once you know it, you can do a lot of
stuffs, even with the taskview madness.

328. By Lionel Dricot

fix subtask oddities in editor, bug #343251

329. By Lionel Dricot

plays well with text besides icons bug #406420

330. By Lionel Dricot

Don't save unmodified new tasks bug #398658

331. By Lionel Dricot

Fixed tags appearing twice (bug #439368 )

This was one of the most difficult and non-intuitive bug I had to fix in a
long time.

Root of the problem : the end of the title tag was not at the end of the title
line but on the beginning of the next line. Nothing wrong but the fact that a
"\n" was included in the title.

For a reason I don't understand, this led to consider the tag to be sometimes
part of the title, thus adding a new "first line".

Fixed by simply putting the end of title tag at the end of the title line.

332. By Lionel Dricot

all your tasks were deleted by the previous commit ! Also fix bugs #437509 and #341054

333. By Bertrand Rousseau <rousseau@lunchbox>

Merge tomboy plug-in update from Luca

334. By Lionel Dricot

this fixes a shitload of unreported bug in the editor, specially when playing with subtasks and tags. Please test it extensively and report bugs

335. By Lionel Dricot

Fixes bug #358785 and bug #440032

Nevertheless, the refresh is still not perfect. There should be a refresh for
both the tags and tasks when everything is loaded

336. By Lionel Dricot

 * Close calendar on single click (bug #343063 )
 * Patch from mrk to improve compatibility with non-GNU unix systems (bug
#430816
)

337. By Luca Falavigna

Update .pot file

338. By Luca Falavigna

Python 2.5 backward compatibility fixes

339. By Luca Falavigna

Use /usr/bin/python as shebang

340. By Lionel Dricot

Fixes bug #355293 bug #353814 and save open/close status of tasks (but does
    not restore the position, see bug #339852 )

341. By Lionel Dricot

tomboy merge

342. By Bertrand Rousseau

Change editor default size and fixes expanding properties of the bottom bar

343. By Lionel Dricot

fixes a lot of traceback but still very funky with threads

344. By Lionel Dricot

This is a very high experimental commit I want you to try out.

I've heavily refactored datastore so it uses one thread by backend, not
anymore one thread by tasks. It might be more efficient.

There are a lot of profiling to do as time increase with the number of stored
tasks. One low hanging fruit is to do a lot less with closed tasks instead of
considering as first class citizen.

345. By Lionel Dricot

new tasks were deleted if not modified, even children

346. By Lionel Dricot

This revision introduce a symetric relation between tasks and tags.

This allows a lot of optimizations (some are already done). If you find a
function where every task is parsed to check for a given tag, change it to
directly ask the tag for associated tasks

347. By Lionel Dricot

some fixes

348. By Bertrand Rousseau <rousseau@lunchbox>

Fixes bug #445640: Traceback when launching GTG. Also fixes Threadless mode.

349. By Luca Falavigna

Revert r339 to avoid breaking compatibility with non-Linux systems
where python interpreter is not in /usr/bin (LP: #448175)

350. By Lionel Dricot <ploum@spoutnik>

kill the tasks appearing twice

351. By Luca Invernizzi <luca@phoenix>

Bug #448114 fix

Unmerged revisions

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file '.bzrignore'
--- .bzrignore 2009-08-24 10:01:19 +0000
+++ .bzrignore 2009-09-24 17:28:10 +0000
@@ -37,3 +37,5 @@
37_trial_temp37_trial_temp
38doc/api38doc/api
39**/**.glade.h39**/**.glade.h
40**/**.gladep
41**/**.gladep.bak
4042
=== modified file 'GTG/core/plugins/api.py'
--- GTG/core/plugins/api.py 2009-09-24 13:15:17 +0000
+++ GTG/core/plugins/api.py 2009-09-24 17:28:10 +0000
@@ -236,6 +236,10 @@
236 def show_window(self):236 def show_window(self):
237 """Shows the main GTG window (task browser)"""237 """Shows the main GTG window (task browser)"""
238 self.__window.show()238 self.__window.show()
239
240 def get_window(self):
241 """Returns the window for which the plug-in has been created"""
242 return self.__window
239#=== General Methods ==========================================================243#=== General Methods ==========================================================
240244
241245
@@ -426,4 +430,4 @@
426 """430 """
427 if func in self.__filter_cbs:431 if func in self.__filter_cbs:
428 self.__filter_cbs.remove(func) 432 self.__filter_cbs.remove(func)
429#=== Filtering methods ========================================================
430\ No newline at end of file433\ No newline at end of file
434#=== Filtering methods ========================================================
431435
=== modified file 'GTG/core/plugins/engine.py'
--- GTG/core/plugins/engine.py 2009-09-24 13:15:17 +0000
+++ GTG/core/plugins/engine.py 2009-09-24 17:28:10 +0000
@@ -176,9 +176,8 @@
176 # deactivate the enabled plugins176 # deactivate the enabled plugins
177 def deactivatePlugins(self, plugins, plugin_api):177 def deactivatePlugins(self, plugins, plugin_api):
178 for plugin in plugins:178 for plugin in plugins:
179 if not plugin['state'] and not plugin['error'] and plugin['active']:179 if plugin['state'] and not plugin['error'] and plugin['active']:
180 plugin['instance'].deactivate(plugin_api)180 plugin['instance'].deactivate(plugin_api)
181 plugin['instance'] = None
182 plugin['active'] = False181 plugin['active'] = False
183 182
184 # loads the plug-in features for a task183 # loads the plug-in features for a task
@@ -187,19 +186,31 @@
187 if plugin['state'] and plugin['active']:186 if plugin['state'] and plugin['active']:
188 plugin['instance'].onTaskOpened(plugin_api)187 plugin['instance'].onTaskOpened(plugin_api)
189 188
189 # signals to the plug-ins that the task window is being closed
190 def onTaskClose(self, plugins, plugin_api):
191 for plugin in plugins:
192 if plugin['state'] and plugin['active']:
193 if hasattr(plugin['instance'],'onTaskClosed'):
194 plugin['instance'].onTaskClosed(plugin_api)
195
190 # rechecks the plug-ins to see if any changes where done to the state196 # rechecks the plug-ins to see if any changes where done to the state
191 def recheckPlugins(self, plugins, plugin_api):197 def recheckPlugins(self, plugins, plugin_api):
192 for plugin in plugins:198 for plugin in plugins:
193 if plugin['instance'] != None and plugin['state'] == False and plugin['active']:199 if plugin['instance'] != None and plugin['state'] == False and plugin['active']:
194 try:200 try:
195 self.deactivatePlugins([plugin],plugin_api)201 #print "deactivating plugin: " + plgin['name']
202 plugin['instance'].deactivate(plugin_api)
203 plugin['instance'] = None
204 plugin['active'] = False
196 except Exception, e:205 except Exception, e:
197 print "Error: %s" % e206 print "Error: %s" % e
198 elif plugin['instance'] == None and plugin['state'] == True and not plugin['active']: 207 elif plugin['instance'] == None and plugin['state'] == True and not plugin['active']:
199 try: 208 try:
200 #print "activating plugin: " + plgin['name']209 #print "activating plugin: " + plgin['name']
201 if not plugin['error']:210 if not plugin['error']:
202 self.activatePlugins([plugin],plugin_api)211 plugin['instance'] = plugin['class']()
212 plugin['instance'].activate(plugin_api)
213 plugin['active'] = True
203 else:214 else:
204 plugin['state'] = False215 plugin['state'] = False
205 except Exception, e:216 except Exception, e:
206217
=== modified file 'GTG/core/plugins/manager.py'
--- GTG/core/plugins/manager.py 2009-09-24 13:15:17 +0000
+++ GTG/core/plugins/manager.py 2009-09-24 17:28:10 +0000
@@ -134,12 +134,6 @@
134 for plgin in self.plugins:134 for plgin in self.plugins:
135 if model[path][1] == plgin['name'] and model[path][2] == plgin['version']:135 if model[path][1] == plgin['name'] and model[path][2] == plgin['version']:
136 plgin['state'] = not plgin['state']136 plgin['state'] = not plgin['state']
137 #we instantly apply the plugin activation/deactivation
138 #to respect HIG
139 if plgin['state'] :
140 self.pengine.activatePlugins([plgin], self.plugin_api)
141 else :
142 self.pengine.deactivatePlugins([plgin], self.plugin_api)
143 137
144138
145 def pluginExtraInfo(self, treeview, plugins):139 def pluginExtraInfo(self, treeview, plugins):
@@ -215,4 +209,4 @@
215 self.config_btn.set_sensitive(False)209 self.config_btn.set_sensitive(False)
216 210
217 def plugin_configure_dialog(self, widget, data=None):211 def plugin_configure_dialog(self, widget, data=None):
218 self.current_plugin['instance'].configure_dialog(self.plugin_api)212 self.current_plugin['instance'].configure_dialog(self.plugin_api)
219\ No newline at end of file213\ No newline at end of file
220214
=== modified file 'GTG/info.py'
--- GTG/info.py 2009-08-29 14:17:46 +0000
+++ GTG/info.py 2009-09-24 17:28:10 +0000
@@ -26,6 +26,7 @@
26 "\tJean-François Fortin Tam <nekohayo@gmail.com>", \26 "\tJean-François Fortin Tam <nekohayo@gmail.com>", \
27 "\tJonathan Lange <jml@mumak.net>", \27 "\tJonathan Lange <jml@mumak.net>", \
28 "\tPaulo Cabido <paulo.cabido@gmail.com>", \28 "\tPaulo Cabido <paulo.cabido@gmail.com>", \
29 "\tLuca Invernizzi <invernizzi.l@gmail.com>", \
29]30]
30ARTISTS = ["Kalle Persson <kalle@kallepersson.se>", \31ARTISTS = ["Kalle Persson <kalle@kallepersson.se>", \
31 "Bertrand Rousseau <bertrand.rousseau@gmail.com>"]32 "Bertrand Rousseau <bertrand.rousseau@gmail.com>"]
@@ -40,7 +41,7 @@
40Finnish: Mika Tapojärvi41Finnish: Mika Tapojärvi
41French: Lionel Dricot, Rafik Ouerchefani, Bertrand Rousseau, Pititjo42French: Lionel Dricot, Rafik Ouerchefani, Bertrand Rousseau, Pititjo
42German: Philip Stewart, Thomas Pitlik43German: Philip Stewart, Thomas Pitlik
43Italian: Luca Falavigna44Italian: Luca Falavigna, Luca Invernizzi
44Malay: melayubuntu45Malay: melayubuntu
45Polish: Tomasz Maciejewski46Polish: Tomasz Maciejewski
46Portuguese: Paulo Cabido 47Portuguese: Paulo Cabido
4748
=== modified file 'GTG/plugins/rtm-sync.gtg-plugin'
--- GTG/plugins/rtm-sync.gtg-plugin 2009-09-20 14:10:30 +0000
+++ GTG/plugins/rtm-sync.gtg-plugin 2009-09-24 17:28:10 +0000
@@ -3,6 +3,6 @@
3Name=Remember the milk3Name=Remember the milk
4Description=Plugin for synchronising Getting Things Gnome! with the web service Remember the milk ( http://www.rememberthemilk.com ).\n\nLegal note: This product uses the Remember The Milk API but is not endorsed or certified by Remember The Milk.4Description=Plugin for synchronising Getting Things Gnome! with the web service Remember the milk ( http://www.rememberthemilk.com ).\n\nLegal note: This product uses the Remember The Milk API but is not endorsed or certified by Remember The Milk.
5Authors=Luca Invernizzi <invernizzi.l@gmail.com>5Authors=Luca Invernizzi <invernizzi.l@gmail.com>
6Version=0.1.26Version=0.1.1
7Dependencies=python-xml,python-simplejson7Dependencies=minidom,subprocess,BaseDirectory,threading,gobject,gtk,time,pickle,datetime,logging,md5,urllib,warnings,simplejson
8Enabled=False8Enabled=False
99
=== modified file 'GTG/plugins/rtm_sync/pyrtm/rtm.py'
--- GTG/plugins/rtm_sync/pyrtm/rtm.py 2009-09-20 14:10:30 +0000
+++ GTG/plugins/rtm_sync/pyrtm/rtm.py 2009-09-24 17:28:10 +0000
@@ -12,10 +12,8 @@
12import warnings12import warnings
13import urllib13import urllib
14import logging14import logging
15import time
16from hashlib import md515from hashlib import md5
17from GTG import _16from GTG import _
18import httplib
1917
20warnings.simplefilter('default', ImportWarning)18warnings.simplefilter('default', ImportWarning)
2119
@@ -93,7 +91,7 @@
93 params['format'] = 'json'91 params['format'] = 'json'
94 params['api_sig'] = self._sign(params)92 params['api_sig'] = self._sign(params)
9593
96 json = openURL(SERVICE_URL, params)94 json = openURL(SERVICE_URL, params).read()
9795
98 LOG.debug("JSON response: \n%s" % json)96 LOG.debug("JSON response: \n%s" % json)
9997
@@ -180,28 +178,11 @@
180 for key in keys:178 for key in keys:
181 yield key, dictionary[key]179 yield key, dictionary[key]
182180
183def openURL(url, queryArgs = None):181def openURL(url, queryArgs=None):
184 if queryArgs:182 if queryArgs:
185 url = url + '?' + urllib.urlencode(queryArgs)183 url = url + '?' + urllib.urlencode(queryArgs)
186 LOG.debug("URL> %s", url)184 LOG.debug("URL> %s", url)
187 time_to_wait = 0185 return urllib.urlopen(url)
188 while True:
189 try:
190 if time_to_wait !=0:
191 time.sleep(time_to_wait)
192 http_connection = httplib.HTTPConnection("api.rememberthemilk.com",80)
193 http_connection.request("GET", url)
194 http_response = http_connection.getresponse()
195 http_response_data = http_response.read()
196 break
197 except httplib.IncompleteRead as exception:
198 #rtm server issues incomplete responses if we hammer it too much
199 # this way we can be fast *and* safe
200 if time_to_wait == 0:
201 time_to_wait = 2
202 else:
203 raise exception
204 return http_response_data
205186
206class dottedDict(object):187class dottedDict(object):
207 "Make dictionary items accessible via the object-dot notation."188 "Make dictionary items accessible via the object-dot notation."
@@ -267,7 +248,7 @@
267 'getList':248 'getList':
268 [(), ()],249 [(), ()],
269 'removeContact':250 'removeContact':
270 [('timeline', 'group_id', 'contact_id'), ()]251 [('timeline', 'group_id', 'contact_id'), ()],
271 },252 },
272 'lists': {253 'lists': {
273 'add':254 'add':
274255
=== modified file 'GTG/plugins/rtm_sync/syncengine.py'
--- GTG/plugins/rtm_sync/syncengine.py 2009-09-21 17:30:00 +0000
+++ GTG/plugins/rtm_sync/syncengine.py 2009-09-24 17:28:10 +0000
@@ -90,11 +90,11 @@
90 try:90 try:
91 self.synchronizeWorker()91 self.synchronizeWorker()
92 except rtm.RTMAPIError as exception:92 except rtm.RTMAPIError as exception:
93 self.close_gui(exception)93 self.close_gui(exception.message)
94 except rtm.RTMError as exception:94 except rtm.RTMError as exception:
95 self.close_gui(exception)95 self.close_gui(exception.message)
96 except Exception as exception:96 except:
97 self.close_gui(_("Synchronization failed." + str(exception)))97 self.close_gui(_("Synchronization failed."))
9898
99 def synchronizeWorker(self):99 def synchronizeWorker(self):
100 self.update_status(_("Downloading task list..."))100 self.update_status(_("Downloading task list..."))
@@ -157,9 +157,8 @@
157 for gtg_id in gtg_removed:157 for gtg_id in gtg_removed:
158 rtm_id = gtg_to_rtm_id_dict[gtg_id]158 rtm_id = gtg_to_rtm_id_dict[gtg_id]
159 rtm_task = filterAttr(self.rtm_list, 'id', rtm_id)159 rtm_task = filterAttr(self.rtm_list, 'id', rtm_id)
160 if len(rtm_task) > 0:160 self.update_substatus(_("Deleting ") + rtm_task.title)
161 self.update_substatus(_("Deleting ") + rtm_task[0].title)161 map(lambda task: task.delete(), rtm_task)
162 map(lambda task: task.delete(), rtm_task)
163162
164 #Delete from gtg the tasks that have been removed in rtm163 #Delete from gtg the tasks that have been removed in rtm
165 if len(rtm_removed) > 0:164 if len(rtm_removed) > 0:
@@ -168,10 +167,9 @@
168 for rtm_id in rtm_removed:167 for rtm_id in rtm_removed:
169 gtg_id = rtm_to_gtg_id_dict[rtm_id]168 gtg_id = rtm_to_gtg_id_dict[rtm_id]
170 gtg_task = filterAttr(self.gtg_list, 'id', gtg_id)169 gtg_task = filterAttr(self.gtg_list, 'id', gtg_id)
171 if len (gtg_task) > 0:170 self.update_substatus(_("Deleting ") + gtg_task.title)
172 self.update_substatus(_("Deleting ") + gtg_task[0].title)171 map(lambda task: task.delete(), gtg_task)
173 map(lambda task: task.delete(), gtg_task)172 gtg_common.discard(gtg_id)
174 gtg_common.discard(gtg_id)
175173
176 #tasks that must be added to RTM174 #tasks that must be added to RTM
177 #NOTE: should we check if the title is already present in the175 #NOTE: should we check if the title is already present in the
178176
=== added directory 'GTG/plugins/tomboy'
=== added file 'GTG/plugins/tomboy.gtg-plugin'
--- GTG/plugins/tomboy.gtg-plugin 1970-01-01 00:00:00 +0000
+++ GTG/plugins/tomboy.gtg-plugin 2009-09-24 17:28:10 +0000
@@ -0,0 +1,7 @@
1[GTG Plugin]
2Module=tomboy
3Name=Tomboy plugin
4Description=This plugin lets you add as many links as you like to tomboy notes in your tasks.
5Authors=Luca Invernizzi <invernizzi.l@gmail.com>
6Version=0.1.1
7Enabled=True
08
=== added file 'GTG/plugins/tomboy/__init__.py'
--- GTG/plugins/tomboy/__init__.py 1970-01-01 00:00:00 +0000
+++ GTG/plugins/tomboy/__init__.py 2009-09-24 17:28:10 +0000
@@ -0,0 +1,20 @@
1# -*- coding: utf-8 -*-
2# Copyright (c) 2009 - Luca Invernizzi <invernizzi.l@gmail.com>
3#
4# This program is free software: you can redistribute it and/or modify it under
5# the terms of the GNU General Public License as published by the Free Software
6# Foundation, either version 3 of the License, or (at your option) any later
7# version.
8#
9# This program is distributed in the hope that it will be useful, but WITHOUT
10# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
12# details.
13#
14# You should have received a copy of the GNU General Public License along with
15# this program. If not, see <http://www.gnu.org/licenses/>.
16
17import sys
18import os
19sys.path.insert(0, os.getcwd())
20from tomboy import pluginTomboy
021
=== added file 'GTG/plugins/tomboy/combobox_enhanced.py'
--- GTG/plugins/tomboy/combobox_enhanced.py 1970-01-01 00:00:00 +0000
+++ GTG/plugins/tomboy/combobox_enhanced.py 2009-09-24 17:28:10 +0000
@@ -0,0 +1,76 @@
1# -*- coding: utf-8 -*-
2# Copyright (c) 2009 - Luca Invernizzi <invernizzi.l@gmail.com>
3#
4# This program is free software: you can redistribute it and/or modify it under
5# the terms of the GNU General Public License as published by the Free Software
6# Foundation, either version 3 of the License, or (at your option) any later
7# version.
8#
9# This program is distributed in the hope that it will be useful, but WITHOUT
10# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
12# details.
13#
14# You should have received a copy of the GNU General Public License along with
15# this program. If not, see <http://www.gnu.org/licenses/>.
16import gtk
17import gobject
18
19def ifKeyPressedCallback( widget, key, callback):
20 def keyPress(combobox, event):
21 keyname = gtk.gdk.keyval_name(event.keyval)
22 if keyname == key:
23 callback()
24 widget.connect("key-press-event", keyPress)
25
26def ifClipboardTextIsInListCallback (clipboard_obj, list_obj, callback):
27 def clipboardCallback(clipboard_obj, text, list_obj):
28 if len(filter(lambda x: x == text, list_obj)) != 0:
29 callback(text)
30 clipboard_obj.request_text(clipboardCallback, list_obj)
31
32def listStoreFromList(list_obj):
33 list_store = gtk.ListStore(gobject.TYPE_STRING)
34 for elem in list_obj:
35 iter = list_store.append()
36 list_store.set(iter, 0, elem)
37 return list_store
38
39def completionFromListStore (list_store):
40 completion = gtk.EntryCompletion()
41 completion.set_minimum_key_length(0)
42 completion.set_text_column(0)
43 completion.set_inline_completion(True)
44 completion.set_model(list_store)
45 return completion
46
47def smartifyComboboxEntry(combobox, list_obj, callback):
48 entry = gtk.Entry()
49 #check if Clipboard contains an element of the list
50 clipboard = gtk.Clipboard()
51 ifClipboardTextIsInListCallback(clipboard, list_obj, entry.set_text)
52 #pressing Enter will cause the callback
53 ifKeyPressedCallback(entry, "Return", callback)
54 #wrap the combo-box if it's too long
55 if len(list_obj) > 15:
56 combobox.set_wrap_width(5)
57 #populate the combo-box
58 if len(list_obj) > 0:
59 list_store = listStoreFromList(list_obj)
60 entry.set_completion(completionFromListStore(list_store))
61 combobox.set_model(list_store)
62 combobox.set_active(0)
63 combobox.add(entry)
64 combobox.connect('changed', setText, entry )
65 #render the combo-box drop down menu
66 cell = gtk.CellRendererText()
67 combobox.pack_start(cell, True)
68 combobox.add_attribute(cell, 'text', 0)
69 return entry
70
71def setText(combobox, entry):
72 model = combobox.get_model()
73 index = combobox.get_active()
74 if index > -1:
75 entry.set_text(model[index][0])
76
077
=== added file 'GTG/plugins/tomboy/tomboy.glade'
--- GTG/plugins/tomboy/tomboy.glade 1970-01-01 00:00:00 +0000
+++ GTG/plugins/tomboy/tomboy.glade 2009-09-24 17:28:10 +0000
@@ -0,0 +1,110 @@
1<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
2<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd">
3
4<glade-interface>
5
6<widget class="GtkDialog" id="InsertNoteDialog">
7 <property name="width_request">300</property>
8 <property name="title" translatable="yes">Insert Note</property>
9 <property name="type">GTK_WINDOW_TOPLEVEL</property>
10 <property name="window_position">GTK_WIN_POS_NONE</property>
11 <property name="modal">False</property>
12 <property name="resizable">True</property>
13 <property name="destroy_with_parent">False</property>
14 <property name="decorated">True</property>
15 <property name="skip_taskbar_hint">False</property>
16 <property name="skip_pager_hint">False</property>
17 <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
18 <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
19 <property name="focus_on_map">True</property>
20 <property name="urgency_hint">False</property>
21 <property name="has_separator">True</property>
22
23 <child internal-child="vbox">
24 <widget class="GtkVBox" id="dialog-vbox1">
25 <property name="visible">True</property>
26 <property name="homogeneous">False</property>
27 <property name="spacing">0</property>
28
29 <child internal-child="action_area">
30 <widget class="GtkHButtonBox" id="dialog-action_area1">
31 <property name="visible">True</property>
32 <property name="layout_style">GTK_BUTTONBOX_END</property>
33
34 <child>
35 <widget class="GtkButton" id="btn_cancel">
36 <property name="visible">True</property>
37 <property name="can_default">True</property>
38 <property name="can_focus">True</property>
39 <property name="label">gtk-cancel</property>
40 <property name="use_stock">True</property>
41 <property name="relief">GTK_RELIEF_NORMAL</property>
42 <property name="focus_on_click">True</property>
43 <property name="response_id">-6</property>
44 </widget>
45 </child>
46
47 <child>
48 <widget class="GtkButton" id="btn_add">
49 <property name="visible">True</property>
50 <property name="can_default">True</property>
51 <property name="can_focus">True</property>
52 <property name="label">gtk-add</property>
53 <property name="use_stock">True</property>
54 <property name="relief">GTK_RELIEF_NORMAL</property>
55 <property name="focus_on_click">True</property>
56 <property name="response_id">0</property>
57 </widget>
58 </child>
59 </widget>
60 <packing>
61 <property name="padding">0</property>
62 <property name="expand">False</property>
63 <property name="fill">True</property>
64 <property name="pack_type">GTK_PACK_END</property>
65 </packing>
66 </child>
67
68 <child>
69 <widget class="GtkLabel" id="label_caption">
70 <property name="visible">True</property>
71 <property name="label" translatable="yes">Insert the title of the tomboy note </property>
72 <property name="use_underline">False</property>
73 <property name="use_markup">False</property>
74 <property name="justify">GTK_JUSTIFY_LEFT</property>
75 <property name="wrap">False</property>
76 <property name="selectable">False</property>
77 <property name="xalign">0.5</property>
78 <property name="yalign">0.5</property>
79 <property name="xpad">0</property>
80 <property name="ypad">0</property>
81 <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
82 <property name="width_chars">-1</property>
83 <property name="single_line_mode">False</property>
84 <property name="angle">0</property>
85 </widget>
86 <packing>
87 <property name="padding">0</property>
88 <property name="expand">False</property>
89 <property name="fill">False</property>
90 </packing>
91 </child>
92
93 <child>
94 <widget class="GtkComboBox" id="titles_combobox">
95 <property name="visible">True</property>
96 <property name="add_tearoffs">False</property>
97 <property name="has_frame">True</property>
98 <property name="focus_on_click">True</property>
99 </widget>
100 <packing>
101 <property name="padding">0</property>
102 <property name="expand">True</property>
103 <property name="fill">True</property>
104 </packing>
105 </child>
106 </widget>
107 </child>
108</widget>
109
110</glade-interface>
0111
=== added file 'GTG/plugins/tomboy/tomboy.py'
--- GTG/plugins/tomboy/tomboy.py 1970-01-01 00:00:00 +0000
+++ GTG/plugins/tomboy/tomboy.py 2009-09-24 17:28:10 +0000
@@ -0,0 +1,229 @@
1# -*- coding: utf-8 -*-
2# Copyright (c) 2009 - Luca Invernizzi <invernizzi.l@gmail.com>
3#
4# This program is free software: you can redistribute it and/or modify it under
5# the terms of the GNU General Public License as published by the Free Software
6# Foundation, either version 3 of the License, or (at your option) any later
7# version.
8#
9# This program is distributed in the hope that it will be useful, but WITHOUT
10# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
12# details.
13#
14# You should have received a copy of the GNU General Public License along with
15# this program. If not, see <http://www.gnu.org/licenses/>.
16
17import gtk
18import gobject
19import os
20import sys
21import dbus
22from GTG import _
23sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
24import combobox_enhanced
25
26
27class pluginTomboy:
28
29 def __init__(self):
30 #These tokens are used to identify the beginning and the end of the
31 #tomboy note point of insertion
32 self.token_start = 'TOMBOY__'
33 self.token_end = '|'
34 self.path = os.path.dirname(os.path.abspath(__file__))
35
36 #Function called upon plug-in activation
37 def activate(self, plugin_api):
38 self.plugin_api = plugin_api
39
40 #Return a textual token to represent the Tomboy widget. It's useful
41 # since the task is saved as pure text
42 def widgetTotext(self, widget):
43 return self.token_start+ widget.tomboy_note_title+self.token_end
44
45 # Converts all tomboy note widgets in the equivalent text
46 def onTaskClosed(self, plugin_api):
47 for anchor in self.anchors:
48 widgets = anchor.get_widgets()
49 if anchor.get_deleted():
50 #The note has been deleted, skip
51 continue
52 iter_start = self.textview.buff.get_iter_at_child_anchor(anchor)
53 iter_end = iter_start.copy()
54 iter_end.forward_char()
55 if type(widgets) == list and len(widgets) !=0:
56 #the anchor still contains a widget.
57 widget = widgets[0]
58 self.textview.buff.delete(iter_start, iter_end)
59 self.textview.buff.insert(iter_start,
60 self.widgetTotext(widget))
61
62 # adds a item(button) to the ToolBar, with a nice icon
63 def addButtonToToolbar(self, plugin_api):
64 tb_Taskbutton_image = gtk.Image()
65 tb_Taskbutton_image_path =\
66 "/usr/share/icons/hicolor/16x16/apps/tomboy.png"
67 tb_Taskbutton_pixbuf=gtk.gdk.\
68 pixbuf_new_from_file_at_size(tb_Taskbutton_image_path, 16, 16)
69 tb_Taskbutton_image.set_from_pixbuf(tb_Taskbutton_pixbuf)
70 tb_Taskbutton_image.show()
71 self.tb_Taskbutton = gtk.ToolButton(tb_Taskbutton_image)
72 self.tb_Taskbutton.set_label(_("Add Tomboy note"))
73 self.tb_Taskbutton.connect('clicked', self.onTbTaskButton, plugin_api)
74 plugin_api.add_task_toolbar_item(gtk.SeparatorToolItem())
75 plugin_api.add_task_toolbar_item(self.tb_Taskbutton)
76
77
78 # Converts all the textual tokens in tomboy note widgets
79 def convertTokensToWidgets(self):
80 self.anchors=[]
81 start_iter = self.textview.buff.get_start_iter()
82 end_iter = self.textview.buff.get_end_iter()
83 text = self.textview.buff.get_slice(start_iter, end_iter)
84 text_offset = 0
85 token_position = text.find(self.token_start)
86 token_ending = text.find(self.token_end, token_position)
87 while not token_position < 0 and not token_ending < 0:
88 #delete the text of the token
89 tomboy_note_title = text[token_position + len(self.token_start):
90 token_ending]
91 start_iter = self.textview.buff.get_iter_at_offset(text_offset +
92 token_position)
93 end_iter = self.textview.buff.get_iter_at_offset(text_offset+
94 token_ending+1)
95 self.textview.buff.delete(start_iter, end_iter)
96 #add the widget
97 widget =self.widgetCreate(tomboy_note_title)
98 anchor = self.textviewInsertWidget(widget, start_iter)
99 self.anchors.append(anchor)
100 #find the next
101 start_iter = self.textview.buff.get_iter_at_child_anchor(anchor)
102 start_iter.forward_char()
103 end_iter = self.textview.buff.get_end_iter()
104 text = self.textview.buff.get_slice(start_iter, end_iter)
105 text_offset = start_iter.get_offset()
106 token_position = text.find(self.token_start)
107 token_ending = text.find(self.token_end)
108
109 def onTaskOpened(self, plugin_api):
110 #NOTE: get_textview() only works in this function
111 # (see GTG/core/plugins/api.py docs)
112 self.textview = plugin_api.get_textview()
113 self.addButtonToToolbar(plugin_api)
114 self.convertTokensToWidgets()
115
116 def deactivate(self, plugin_api):
117 #nothing to do at all
118 pass
119
120 def close_dialog(self, widget, data=None):
121 self.dialog.destroy()
122 return True
123
124 #opens a dbus connection to tomboy
125 def getTomboyObject(self):
126 bus = dbus.SessionBus()
127 obj = bus.get_object("org.gnome.Tomboy",
128 "/org/gnome/Tomboy/RemoteControl")
129 return dbus.Interface(obj, "org.gnome.Tomboy.RemoteControl")
130
131 #gets the list of the titles of the notes
132 def getTomboyNoteTitleList(self):
133 tomboy = self.getTomboyObject()
134 return map(lambda note: str(tomboy.GetNoteTitle(note)),
135 tomboy.ListAllNotes())
136
137 def onTbTaskButton(self, widget, plugin_api):
138 title_list = self.getTomboyNoteTitleList()
139 #Create the dialog
140 glade_file = os.path.join(self.path, "tomboy.glade")
141 wTree = gtk.glade.XML(glade_file, "InsertNoteDialog")
142 #objects
143 self.dialog = wTree.get_widget("InsertNoteDialog")
144 btn_add = wTree.get_widget("btn_add")
145 btn_cancel = wTree.get_widget("btn_cancel")
146 self.combobox = wTree.get_widget("titles_combobox")
147 self.label_caption = wTree.get_widget("label_caption")
148 #connections
149 self.dialog.connect("delete_event", self.close_dialog)
150 btn_cancel.connect("clicked", self.close_dialog)
151 btn_add.connect("clicked", self.noteChosen)
152 self.combobox_entry = combobox_enhanced.\
153 smartifyComboboxEntry(self.combobox,title_list,self.noteChosen)
154 self.dialog.show_all()
155
156 #A title has been chosen by the user. If the note exists, it will be
157 # linked, otherwise the user will have the option to create the note.
158 def noteChosen(self, widget=None, data=None):
159 tomboy = self.getTomboyObject()
160 supposed_title = self.combobox_entry.get_text()
161 if filter(lambda x: tomboy.GetNoteTitle(x)==supposed_title,
162 tomboy.ListAllNotes()) == []:
163 self.label_caption.set_text(_("That note does not exist!"))
164 dialog = gtk.MessageDialog(parent = self.dialog,
165 flags = gtk.DIALOG_DESTROY_WITH_PARENT,
166 type = gtk.MESSAGE_QUESTION,
167 buttons=gtk.BUTTONS_YES_NO,
168 message_format=_("That note does not \
169exist. Do you want to create a new one?"))
170 response = dialog.run()
171 dialog.destroy()
172 if response == gtk.RESPONSE_YES:
173 tomboy.CreateNamedNote(supposed_title)
174 else:
175 return
176 #note insertion
177 mark_start = self.textview.buff.get_insert()
178 iter_start = self.textview.buff.get_iter_at_mark(mark_start)
179 tomboy_widget =self.widgetCreate(supposed_title)
180 anchor = self.textviewInsertWidget(tomboy_widget, iter_start)
181 self.anchors.append(anchor)
182 self.dialog.destroy()
183
184 #Opens a note in tomboy application via dbus
185 def tomboyDisplayNote(self, widget, data = None):
186 tomboy = self.getTomboyObject()
187 note = tomboy.FindNote(widget.tomboy_note_title)
188 tomboy.DisplayNote(note)
189
190 #inserts a widget in the textview
191 def textviewInsertWidget(self, widget, iter):
192 anchor = self.textview.buff.create_child_anchor(iter)
193 widget.show()
194 self.textview.add_child_at_anchor(widget, anchor)
195 return anchor
196
197 #creates the tomboy widget
198 def widgetCreate(self, tomboy_note_title):
199 image = gtk.Image()
200 image_path = "/usr/share/icons/hicolor/16x16/apps/tomboy.png"
201 pixbuf=gtk.gdk.\
202 pixbuf_new_from_file_at_size(image_path, 16, 16)
203 image.show()
204 image.set_from_pixbuf(pixbuf)
205 image.set_alignment(0.5,1.0)
206 label = gtk.Label()
207 label.show()
208 label.set_alignment(0.5, 1.0)
209 eventbox = gtk.EventBox()
210 eventbox.set_events(gtk.gdk.BUTTON_PRESS_MASK)
211 eventbox.connect('button_press_event', self.tomboyDisplayNote)
212 eventbox.show()
213 window = self.plugin_api.get_window()
214 hbox = gtk.HBox()
215 hbox.show()
216 hbox.add(image)
217 hbox.add(label)
218 eventbox.add(hbox)
219 window.realize()
220 style=window.get_style()
221 color = str(style.text[gtk.STATE_PRELIGHT])
222 label.set_markup("<span underline='low' color='" + color +"'>" + tomboy_note_title + "</span>")
223 eventbox.tomboy_note_title = tomboy_note_title
224 #cursor changes to a hand
225 def realize_callback(widget):
226 eventbox.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.HAND2))
227 eventbox.connect("realize", realize_callback)
228 return eventbox
229
0230
=== modified file 'GTG/taskeditor/editor.py'
--- GTG/taskeditor/editor.py 2009-09-24 14:51:45 +0000
+++ GTG/taskeditor/editor.py 2009-09-24 17:28:10 +0000
@@ -479,6 +479,7 @@
479 #Will be linked to this destruction method that will save the task479 #Will be linked to this destruction method that will save the task
480 def destruction(self,a=None) :#pylint: disable-msg=W0613480 def destruction(self,a=None) :#pylint: disable-msg=W0613
481 #Save should be also called when buffer is modified481 #Save should be also called when buffer is modified
482 self.pengine.onTaskClose(self.plugins, self.te_plugin_api)
482 self.save()483 self.save()
483 self.closing(self.task.get_id())484 self.closing(self.task.get_id())
484 485
485486
=== modified file 'GTG/taskeditor/taskview.py'
--- GTG/taskeditor/taskview.py 2009-09-24 15:45:17 +0000
+++ GTG/taskeditor/taskview.py 2009-09-24 17:28:10 +0000
@@ -39,8 +39,7 @@
39separators = [' ', '.', ',', '/', '\n', '\t', '!', '?', ';', '\0']39separators = [' ', '.', ',', '/', '\n', '\t', '!', '?', ';', '\0']
40url_separators = [' ', ',', '\n', '\t', '\0']40url_separators = [' ', ',', '\n', '\t', '\0']
4141
42bullet1_ltr = '→'42bullet1 = '→'
43bullet1_rtl = '←'
44bullet2 = '↳'43bullet2 = '↳'
4544
4645
@@ -151,11 +150,6 @@
151 self.modified_sigid = self.buff.connect("changed" , self.modified)150 self.modified_sigid = self.buff.connect("changed" , self.modified)
152 self.connect("backspace",self.backspace)151 self.connect("backspace",self.backspace)
153 self.tobe_refreshed = False152 self.tobe_refreshed = False
154
155 if self.get_direction() == gtk.TEXT_DIR_RTL :
156 self.bullet1 = bullet1_rtl
157 else :
158 self.bullet1 = bullet1_ltr
159153
160 154
161 #This function is called to refresh the editor 155 #This function is called to refresh the editor
@@ -883,7 +877,7 @@
883 indentation = indentation + (level-1)*spaces877 indentation = indentation + (level-1)*spaces
884 #adding the symbol 878 #adding the symbol
885 if level == 1 :879 if level == 1 :
886 indentation = "%s%s "%(indentation,self.bullet1)880 indentation = "%s%s "%(indentation,bullet1)
887 buff.insert(itera,indentation)881 buff.insert(itera,indentation)
888 indenttag = self.create_indent_tag(buff,level)882 indenttag = self.create_indent_tag(buff,level)
889 self.__apply_tag_to_mark(start,end,tag=indenttag)883 self.__apply_tag_to_mark(start,end,tag=indenttag)
@@ -985,7 +979,7 @@
985 #Then, if indent > 0, we increment it979 #Then, if indent > 0, we increment it
986 #First step : we preserve it.980 #First step : we preserve it.
987 else :981 else :
988 if not line.lstrip("%s "%self.bullet1) :982 if not line.lstrip("%s "%bullet1) :
989 self.deindent(itera,newlevel=0)983 self.deindent(itera,newlevel=0)
990 tv.emit_stop_by_name('insert-text')984 tv.emit_stop_by_name('insert-text')
991 985
992986
=== modified file 'locales/gtg.pot'
--- locales/gtg.pot 2009-09-12 23:03:15 +0000
+++ locales/gtg.pot 2009-09-24 17:28:10 +0000
@@ -8,7 +8,7 @@
8msgstr ""8msgstr ""
9"Project-Id-Version: PACKAGE VERSION\n"9"Project-Id-Version: PACKAGE VERSION\n"
10"Report-Msgid-Bugs-To: \n"10"Report-Msgid-Bugs-To: \n"
11"POT-Creation-Date: 2009-09-13 01:03+0200\n"11"POT-Creation-Date: 2009-09-18 15:51+0200\n"
12"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"12"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
13"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"13"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
14"Language-Team: LANGUAGE <LL@li.org>\n"14"Language-Team: LANGUAGE <LL@li.org>\n"
@@ -632,6 +632,22 @@
632msgid "due"632msgid "due"
633msgstr ""633msgstr ""
634634
635#: GTG/plugins/tomboy/tomboy.py:67
636msgid "Add Tomboy note"
637msgstr ""
638
639#: GTG/plugins/tomboy/tomboy.py:170
640msgid "That note does not exist!"
641msgstr ""
642
643#: GTG/plugins/tomboy/tomboy.glade.h:1
644msgid "Insert Note"
645msgstr ""
646
647#: GTG/plugins/tomboy/tomboy.glade.h:2
648msgid "Insert the title of the tomboy note "
649msgstr ""
650
635#: GTG/plugins/rtm_sync/utility.py:54651#: GTG/plugins/rtm_sync/utility.py:54
636msgid "saving critical object failed"652msgid "saving critical object failed"
637msgstr ""653msgstr ""
@@ -666,11 +682,11 @@
666"now. When done, press OK"682"now. When done, press OK"
667msgstr ""683msgstr ""
668684
669#: GTG/plugins/rtm_sync/pyrtm/rtm.py:56685#: GTG/plugins/rtm_sync/pyrtm/rtm.py:57
670msgid "Invalid state"686msgid "Invalid state"
671msgstr ""687msgstr ""
672688
673#: GTG/plugins/rtm_sync/pyrtm/rtm.py:105689#: GTG/plugins/rtm_sync/pyrtm/rtm.py:106
674msgid "API call failed"690msgid "API call failed"
675msgstr ""691msgstr ""
676692

Subscribers

People subscribed via source and target branches

to status/vote changes: