Merge lp:~gtg-user/gtg/tomboy into lp:~gtg/gtg/old-trunk
- tomboy
- Merge into old-trunk
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 | ||||
Related bugs: |
|
||||
Related blueprints: |
Associate a document with a task
(Undefined)
|
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.
Commit message
Description of the change
Luca Invernizzi (invernizzi) wrote : | # |
- 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
1 | === modified file '.bzrignore' |
2 | --- .bzrignore 2009-08-24 10:01:19 +0000 |
3 | +++ .bzrignore 2009-09-24 17:28:10 +0000 |
4 | @@ -37,3 +37,5 @@ |
5 | _trial_temp |
6 | doc/api |
7 | **/**.glade.h |
8 | +**/**.gladep |
9 | +**/**.gladep.bak |
10 | |
11 | === modified file 'GTG/core/plugins/api.py' |
12 | --- GTG/core/plugins/api.py 2009-09-24 13:15:17 +0000 |
13 | +++ GTG/core/plugins/api.py 2009-09-24 17:28:10 +0000 |
14 | @@ -236,6 +236,10 @@ |
15 | def show_window(self): |
16 | """Shows the main GTG window (task browser)""" |
17 | self.__window.show() |
18 | + |
19 | + def get_window(self): |
20 | + """Returns the window for which the plug-in has been created""" |
21 | + return self.__window |
22 | #=== General Methods ========================================================== |
23 | |
24 | |
25 | @@ -426,4 +430,4 @@ |
26 | """ |
27 | if func in self.__filter_cbs: |
28 | self.__filter_cbs.remove(func) |
29 | -#=== Filtering methods ======================================================== |
30 | \ No newline at end of file |
31 | +#=== Filtering methods ======================================================== |
32 | |
33 | === modified file 'GTG/core/plugins/engine.py' |
34 | --- GTG/core/plugins/engine.py 2009-09-24 13:15:17 +0000 |
35 | +++ GTG/core/plugins/engine.py 2009-09-24 17:28:10 +0000 |
36 | @@ -176,9 +176,8 @@ |
37 | # deactivate the enabled plugins |
38 | def deactivatePlugins(self, plugins, plugin_api): |
39 | for plugin in plugins: |
40 | - if not plugin['state'] and not plugin['error'] and plugin['active']: |
41 | + if plugin['state'] and not plugin['error'] and plugin['active']: |
42 | plugin['instance'].deactivate(plugin_api) |
43 | - plugin['instance'] = None |
44 | plugin['active'] = False |
45 | |
46 | # loads the plug-in features for a task |
47 | @@ -187,19 +186,31 @@ |
48 | if plugin['state'] and plugin['active']: |
49 | plugin['instance'].onTaskOpened(plugin_api) |
50 | |
51 | + # signals to the plug-ins that the task window is being closed |
52 | + def onTaskClose(self, plugins, plugin_api): |
53 | + for plugin in plugins: |
54 | + if plugin['state'] and plugin['active']: |
55 | + if hasattr(plugin['instance'],'onTaskClosed'): |
56 | + plugin['instance'].onTaskClosed(plugin_api) |
57 | + |
58 | # rechecks the plug-ins to see if any changes where done to the state |
59 | def recheckPlugins(self, plugins, plugin_api): |
60 | for plugin in plugins: |
61 | if plugin['instance'] != None and plugin['state'] == False and plugin['active']: |
62 | try: |
63 | - self.deactivatePlugins([plugin],plugin_api) |
64 | + #print "deactivating plugin: " + plgin['name'] |
65 | + plugin['instance'].deactivate(plugin_api) |
66 | + plugin['instance'] = None |
67 | + plugin['active'] = False |
68 | except Exception, e: |
69 | print "Error: %s" % e |
70 | elif plugin['instance'] == None and plugin['state'] == True and not plugin['active']: |
71 | try: |
72 | #print "activating plugin: " + plgin['name'] |
73 | if not plugin['error']: |
74 | - self.activatePlugins([plugin],plugin_api) |
75 | + plugin['instance'] = plugin['class']() |
76 | + plugin['instance'].activate(plugin_api) |
77 | + plugin['active'] = True |
78 | else: |
79 | plugin['state'] = False |
80 | except Exception, e: |
81 | |
82 | === modified file 'GTG/core/plugins/manager.py' |
83 | --- GTG/core/plugins/manager.py 2009-09-24 13:15:17 +0000 |
84 | +++ GTG/core/plugins/manager.py 2009-09-24 17:28:10 +0000 |
85 | @@ -134,12 +134,6 @@ |
86 | for plgin in self.plugins: |
87 | if model[path][1] == plgin['name'] and model[path][2] == plgin['version']: |
88 | plgin['state'] = not plgin['state'] |
89 | - #we instantly apply the plugin activation/deactivation |
90 | - #to respect HIG |
91 | - if plgin['state'] : |
92 | - self.pengine.activatePlugins([plgin], self.plugin_api) |
93 | - else : |
94 | - self.pengine.deactivatePlugins([plgin], self.plugin_api) |
95 | |
96 | |
97 | def pluginExtraInfo(self, treeview, plugins): |
98 | @@ -215,4 +209,4 @@ |
99 | self.config_btn.set_sensitive(False) |
100 | |
101 | def plugin_configure_dialog(self, widget, data=None): |
102 | - self.current_plugin['instance'].configure_dialog(self.plugin_api) |
103 | + self.current_plugin['instance'].configure_dialog(self.plugin_api) |
104 | \ No newline at end of file |
105 | |
106 | === modified file 'GTG/info.py' |
107 | --- GTG/info.py 2009-08-29 14:17:46 +0000 |
108 | +++ GTG/info.py 2009-09-24 17:28:10 +0000 |
109 | @@ -26,6 +26,7 @@ |
110 | "\tJean-François Fortin Tam <nekohayo@gmail.com>", \ |
111 | "\tJonathan Lange <jml@mumak.net>", \ |
112 | "\tPaulo Cabido <paulo.cabido@gmail.com>", \ |
113 | + "\tLuca Invernizzi <invernizzi.l@gmail.com>", \ |
114 | ] |
115 | ARTISTS = ["Kalle Persson <kalle@kallepersson.se>", \ |
116 | "Bertrand Rousseau <bertrand.rousseau@gmail.com>"] |
117 | @@ -40,7 +41,7 @@ |
118 | Finnish: Mika Tapojärvi |
119 | French: Lionel Dricot, Rafik Ouerchefani, Bertrand Rousseau, Pititjo |
120 | German: Philip Stewart, Thomas Pitlik |
121 | -Italian: Luca Falavigna |
122 | +Italian: Luca Falavigna, Luca Invernizzi |
123 | Malay: melayubuntu |
124 | Polish: Tomasz Maciejewski |
125 | Portuguese: Paulo Cabido |
126 | |
127 | === modified file 'GTG/plugins/rtm-sync.gtg-plugin' |
128 | --- GTG/plugins/rtm-sync.gtg-plugin 2009-09-20 14:10:30 +0000 |
129 | +++ GTG/plugins/rtm-sync.gtg-plugin 2009-09-24 17:28:10 +0000 |
130 | @@ -3,6 +3,6 @@ |
131 | Name=Remember the milk |
132 | Description=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. |
133 | Authors=Luca Invernizzi <invernizzi.l@gmail.com> |
134 | -Version=0.1.2 |
135 | -Dependencies=python-xml,python-simplejson |
136 | +Version=0.1.1 |
137 | +Dependencies=minidom,subprocess,BaseDirectory,threading,gobject,gtk,time,pickle,datetime,logging,md5,urllib,warnings,simplejson |
138 | Enabled=False |
139 | |
140 | === modified file 'GTG/plugins/rtm_sync/pyrtm/rtm.py' |
141 | --- GTG/plugins/rtm_sync/pyrtm/rtm.py 2009-09-20 14:10:30 +0000 |
142 | +++ GTG/plugins/rtm_sync/pyrtm/rtm.py 2009-09-24 17:28:10 +0000 |
143 | @@ -12,10 +12,8 @@ |
144 | import warnings |
145 | import urllib |
146 | import logging |
147 | -import time |
148 | from hashlib import md5 |
149 | from GTG import _ |
150 | -import httplib |
151 | |
152 | warnings.simplefilter('default', ImportWarning) |
153 | |
154 | @@ -93,7 +91,7 @@ |
155 | params['format'] = 'json' |
156 | params['api_sig'] = self._sign(params) |
157 | |
158 | - json = openURL(SERVICE_URL, params) |
159 | + json = openURL(SERVICE_URL, params).read() |
160 | |
161 | LOG.debug("JSON response: \n%s" % json) |
162 | |
163 | @@ -180,28 +178,11 @@ |
164 | for key in keys: |
165 | yield key, dictionary[key] |
166 | |
167 | -def openURL(url, queryArgs = None): |
168 | +def openURL(url, queryArgs=None): |
169 | if queryArgs: |
170 | url = url + '?' + urllib.urlencode(queryArgs) |
171 | - LOG.debug("URL> %s", url) |
172 | - time_to_wait = 0 |
173 | - while True: |
174 | - try: |
175 | - if time_to_wait !=0: |
176 | - time.sleep(time_to_wait) |
177 | - http_connection = httplib.HTTPConnection("api.rememberthemilk.com",80) |
178 | - http_connection.request("GET", url) |
179 | - http_response = http_connection.getresponse() |
180 | - http_response_data = http_response.read() |
181 | - break |
182 | - except httplib.IncompleteRead as exception: |
183 | - #rtm server issues incomplete responses if we hammer it too much |
184 | - # this way we can be fast *and* safe |
185 | - if time_to_wait == 0: |
186 | - time_to_wait = 2 |
187 | - else: |
188 | - raise exception |
189 | - return http_response_data |
190 | + LOG.debug("URL> %s", url) |
191 | + return urllib.urlopen(url) |
192 | |
193 | class dottedDict(object): |
194 | "Make dictionary items accessible via the object-dot notation." |
195 | @@ -267,7 +248,7 @@ |
196 | 'getList': |
197 | [(), ()], |
198 | 'removeContact': |
199 | - [('timeline', 'group_id', 'contact_id'), ()] |
200 | + [('timeline', 'group_id', 'contact_id'), ()], |
201 | }, |
202 | 'lists': { |
203 | 'add': |
204 | |
205 | === modified file 'GTG/plugins/rtm_sync/syncengine.py' |
206 | --- GTG/plugins/rtm_sync/syncengine.py 2009-09-21 17:30:00 +0000 |
207 | +++ GTG/plugins/rtm_sync/syncengine.py 2009-09-24 17:28:10 +0000 |
208 | @@ -90,11 +90,11 @@ |
209 | try: |
210 | self.synchronizeWorker() |
211 | except rtm.RTMAPIError as exception: |
212 | - self.close_gui(exception) |
213 | + self.close_gui(exception.message) |
214 | except rtm.RTMError as exception: |
215 | - self.close_gui(exception) |
216 | - except Exception as exception: |
217 | - self.close_gui(_("Synchronization failed." + str(exception))) |
218 | + self.close_gui(exception.message) |
219 | + except: |
220 | + self.close_gui(_("Synchronization failed.")) |
221 | |
222 | def synchronizeWorker(self): |
223 | self.update_status(_("Downloading task list...")) |
224 | @@ -157,9 +157,8 @@ |
225 | for gtg_id in gtg_removed: |
226 | rtm_id = gtg_to_rtm_id_dict[gtg_id] |
227 | rtm_task = filterAttr(self.rtm_list, 'id', rtm_id) |
228 | - if len(rtm_task) > 0: |
229 | - self.update_substatus(_("Deleting ") + rtm_task[0].title) |
230 | - map(lambda task: task.delete(), rtm_task) |
231 | + self.update_substatus(_("Deleting ") + rtm_task.title) |
232 | + map(lambda task: task.delete(), rtm_task) |
233 | |
234 | #Delete from gtg the tasks that have been removed in rtm |
235 | if len(rtm_removed) > 0: |
236 | @@ -168,10 +167,9 @@ |
237 | for rtm_id in rtm_removed: |
238 | gtg_id = rtm_to_gtg_id_dict[rtm_id] |
239 | gtg_task = filterAttr(self.gtg_list, 'id', gtg_id) |
240 | - if len (gtg_task) > 0: |
241 | - self.update_substatus(_("Deleting ") + gtg_task[0].title) |
242 | - map(lambda task: task.delete(), gtg_task) |
243 | - gtg_common.discard(gtg_id) |
244 | + self.update_substatus(_("Deleting ") + gtg_task.title) |
245 | + map(lambda task: task.delete(), gtg_task) |
246 | + gtg_common.discard(gtg_id) |
247 | |
248 | #tasks that must be added to RTM |
249 | #NOTE: should we check if the title is already present in the |
250 | |
251 | === added directory 'GTG/plugins/tomboy' |
252 | === added file 'GTG/plugins/tomboy.gtg-plugin' |
253 | --- GTG/plugins/tomboy.gtg-plugin 1970-01-01 00:00:00 +0000 |
254 | +++ GTG/plugins/tomboy.gtg-plugin 2009-09-24 17:28:10 +0000 |
255 | @@ -0,0 +1,7 @@ |
256 | +[GTG Plugin] |
257 | +Module=tomboy |
258 | +Name=Tomboy plugin |
259 | +Description=This plugin lets you add as many links as you like to tomboy notes in your tasks. |
260 | +Authors=Luca Invernizzi <invernizzi.l@gmail.com> |
261 | +Version=0.1.1 |
262 | +Enabled=True |
263 | |
264 | === added file 'GTG/plugins/tomboy/__init__.py' |
265 | --- GTG/plugins/tomboy/__init__.py 1970-01-01 00:00:00 +0000 |
266 | +++ GTG/plugins/tomboy/__init__.py 2009-09-24 17:28:10 +0000 |
267 | @@ -0,0 +1,20 @@ |
268 | +# -*- coding: utf-8 -*- |
269 | +# Copyright (c) 2009 - Luca Invernizzi <invernizzi.l@gmail.com> |
270 | +# |
271 | +# This program is free software: you can redistribute it and/or modify it under |
272 | +# the terms of the GNU General Public License as published by the Free Software |
273 | +# Foundation, either version 3 of the License, or (at your option) any later |
274 | +# version. |
275 | +# |
276 | +# This program is distributed in the hope that it will be useful, but WITHOUT |
277 | +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
278 | +# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more |
279 | +# details. |
280 | +# |
281 | +# You should have received a copy of the GNU General Public License along with |
282 | +# this program. If not, see <http://www.gnu.org/licenses/>. |
283 | + |
284 | +import sys |
285 | +import os |
286 | +sys.path.insert(0, os.getcwd()) |
287 | +from tomboy import pluginTomboy |
288 | |
289 | === added file 'GTG/plugins/tomboy/combobox_enhanced.py' |
290 | --- GTG/plugins/tomboy/combobox_enhanced.py 1970-01-01 00:00:00 +0000 |
291 | +++ GTG/plugins/tomboy/combobox_enhanced.py 2009-09-24 17:28:10 +0000 |
292 | @@ -0,0 +1,76 @@ |
293 | +# -*- coding: utf-8 -*- |
294 | +# Copyright (c) 2009 - Luca Invernizzi <invernizzi.l@gmail.com> |
295 | +# |
296 | +# This program is free software: you can redistribute it and/or modify it under |
297 | +# the terms of the GNU General Public License as published by the Free Software |
298 | +# Foundation, either version 3 of the License, or (at your option) any later |
299 | +# version. |
300 | +# |
301 | +# This program is distributed in the hope that it will be useful, but WITHOUT |
302 | +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
303 | +# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more |
304 | +# details. |
305 | +# |
306 | +# You should have received a copy of the GNU General Public License along with |
307 | +# this program. If not, see <http://www.gnu.org/licenses/>. |
308 | +import gtk |
309 | +import gobject |
310 | + |
311 | +def ifKeyPressedCallback( widget, key, callback): |
312 | + def keyPress(combobox, event): |
313 | + keyname = gtk.gdk.keyval_name(event.keyval) |
314 | + if keyname == key: |
315 | + callback() |
316 | + widget.connect("key-press-event", keyPress) |
317 | + |
318 | +def ifClipboardTextIsInListCallback (clipboard_obj, list_obj, callback): |
319 | + def clipboardCallback(clipboard_obj, text, list_obj): |
320 | + if len(filter(lambda x: x == text, list_obj)) != 0: |
321 | + callback(text) |
322 | + clipboard_obj.request_text(clipboardCallback, list_obj) |
323 | + |
324 | +def listStoreFromList(list_obj): |
325 | + list_store = gtk.ListStore(gobject.TYPE_STRING) |
326 | + for elem in list_obj: |
327 | + iter = list_store.append() |
328 | + list_store.set(iter, 0, elem) |
329 | + return list_store |
330 | + |
331 | +def completionFromListStore (list_store): |
332 | + completion = gtk.EntryCompletion() |
333 | + completion.set_minimum_key_length(0) |
334 | + completion.set_text_column(0) |
335 | + completion.set_inline_completion(True) |
336 | + completion.set_model(list_store) |
337 | + return completion |
338 | + |
339 | +def smartifyComboboxEntry(combobox, list_obj, callback): |
340 | + entry = gtk.Entry() |
341 | + #check if Clipboard contains an element of the list |
342 | + clipboard = gtk.Clipboard() |
343 | + ifClipboardTextIsInListCallback(clipboard, list_obj, entry.set_text) |
344 | + #pressing Enter will cause the callback |
345 | + ifKeyPressedCallback(entry, "Return", callback) |
346 | + #wrap the combo-box if it's too long |
347 | + if len(list_obj) > 15: |
348 | + combobox.set_wrap_width(5) |
349 | + #populate the combo-box |
350 | + if len(list_obj) > 0: |
351 | + list_store = listStoreFromList(list_obj) |
352 | + entry.set_completion(completionFromListStore(list_store)) |
353 | + combobox.set_model(list_store) |
354 | + combobox.set_active(0) |
355 | + combobox.add(entry) |
356 | + combobox.connect('changed', setText, entry ) |
357 | + #render the combo-box drop down menu |
358 | + cell = gtk.CellRendererText() |
359 | + combobox.pack_start(cell, True) |
360 | + combobox.add_attribute(cell, 'text', 0) |
361 | + return entry |
362 | + |
363 | +def setText(combobox, entry): |
364 | + model = combobox.get_model() |
365 | + index = combobox.get_active() |
366 | + if index > -1: |
367 | + entry.set_text(model[index][0]) |
368 | + |
369 | |
370 | === added file 'GTG/plugins/tomboy/tomboy.glade' |
371 | --- GTG/plugins/tomboy/tomboy.glade 1970-01-01 00:00:00 +0000 |
372 | +++ GTG/plugins/tomboy/tomboy.glade 2009-09-24 17:28:10 +0000 |
373 | @@ -0,0 +1,110 @@ |
374 | +<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*--> |
375 | +<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd"> |
376 | + |
377 | +<glade-interface> |
378 | + |
379 | +<widget class="GtkDialog" id="InsertNoteDialog"> |
380 | + <property name="width_request">300</property> |
381 | + <property name="title" translatable="yes">Insert Note</property> |
382 | + <property name="type">GTK_WINDOW_TOPLEVEL</property> |
383 | + <property name="window_position">GTK_WIN_POS_NONE</property> |
384 | + <property name="modal">False</property> |
385 | + <property name="resizable">True</property> |
386 | + <property name="destroy_with_parent">False</property> |
387 | + <property name="decorated">True</property> |
388 | + <property name="skip_taskbar_hint">False</property> |
389 | + <property name="skip_pager_hint">False</property> |
390 | + <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property> |
391 | + <property name="gravity">GDK_GRAVITY_NORTH_WEST</property> |
392 | + <property name="focus_on_map">True</property> |
393 | + <property name="urgency_hint">False</property> |
394 | + <property name="has_separator">True</property> |
395 | + |
396 | + <child internal-child="vbox"> |
397 | + <widget class="GtkVBox" id="dialog-vbox1"> |
398 | + <property name="visible">True</property> |
399 | + <property name="homogeneous">False</property> |
400 | + <property name="spacing">0</property> |
401 | + |
402 | + <child internal-child="action_area"> |
403 | + <widget class="GtkHButtonBox" id="dialog-action_area1"> |
404 | + <property name="visible">True</property> |
405 | + <property name="layout_style">GTK_BUTTONBOX_END</property> |
406 | + |
407 | + <child> |
408 | + <widget class="GtkButton" id="btn_cancel"> |
409 | + <property name="visible">True</property> |
410 | + <property name="can_default">True</property> |
411 | + <property name="can_focus">True</property> |
412 | + <property name="label">gtk-cancel</property> |
413 | + <property name="use_stock">True</property> |
414 | + <property name="relief">GTK_RELIEF_NORMAL</property> |
415 | + <property name="focus_on_click">True</property> |
416 | + <property name="response_id">-6</property> |
417 | + </widget> |
418 | + </child> |
419 | + |
420 | + <child> |
421 | + <widget class="GtkButton" id="btn_add"> |
422 | + <property name="visible">True</property> |
423 | + <property name="can_default">True</property> |
424 | + <property name="can_focus">True</property> |
425 | + <property name="label">gtk-add</property> |
426 | + <property name="use_stock">True</property> |
427 | + <property name="relief">GTK_RELIEF_NORMAL</property> |
428 | + <property name="focus_on_click">True</property> |
429 | + <property name="response_id">0</property> |
430 | + </widget> |
431 | + </child> |
432 | + </widget> |
433 | + <packing> |
434 | + <property name="padding">0</property> |
435 | + <property name="expand">False</property> |
436 | + <property name="fill">True</property> |
437 | + <property name="pack_type">GTK_PACK_END</property> |
438 | + </packing> |
439 | + </child> |
440 | + |
441 | + <child> |
442 | + <widget class="GtkLabel" id="label_caption"> |
443 | + <property name="visible">True</property> |
444 | + <property name="label" translatable="yes">Insert the title of the tomboy note </property> |
445 | + <property name="use_underline">False</property> |
446 | + <property name="use_markup">False</property> |
447 | + <property name="justify">GTK_JUSTIFY_LEFT</property> |
448 | + <property name="wrap">False</property> |
449 | + <property name="selectable">False</property> |
450 | + <property name="xalign">0.5</property> |
451 | + <property name="yalign">0.5</property> |
452 | + <property name="xpad">0</property> |
453 | + <property name="ypad">0</property> |
454 | + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> |
455 | + <property name="width_chars">-1</property> |
456 | + <property name="single_line_mode">False</property> |
457 | + <property name="angle">0</property> |
458 | + </widget> |
459 | + <packing> |
460 | + <property name="padding">0</property> |
461 | + <property name="expand">False</property> |
462 | + <property name="fill">False</property> |
463 | + </packing> |
464 | + </child> |
465 | + |
466 | + <child> |
467 | + <widget class="GtkComboBox" id="titles_combobox"> |
468 | + <property name="visible">True</property> |
469 | + <property name="add_tearoffs">False</property> |
470 | + <property name="has_frame">True</property> |
471 | + <property name="focus_on_click">True</property> |
472 | + </widget> |
473 | + <packing> |
474 | + <property name="padding">0</property> |
475 | + <property name="expand">True</property> |
476 | + <property name="fill">True</property> |
477 | + </packing> |
478 | + </child> |
479 | + </widget> |
480 | + </child> |
481 | +</widget> |
482 | + |
483 | +</glade-interface> |
484 | |
485 | === added file 'GTG/plugins/tomboy/tomboy.py' |
486 | --- GTG/plugins/tomboy/tomboy.py 1970-01-01 00:00:00 +0000 |
487 | +++ GTG/plugins/tomboy/tomboy.py 2009-09-24 17:28:10 +0000 |
488 | @@ -0,0 +1,229 @@ |
489 | +# -*- coding: utf-8 -*- |
490 | +# Copyright (c) 2009 - Luca Invernizzi <invernizzi.l@gmail.com> |
491 | +# |
492 | +# This program is free software: you can redistribute it and/or modify it under |
493 | +# the terms of the GNU General Public License as published by the Free Software |
494 | +# Foundation, either version 3 of the License, or (at your option) any later |
495 | +# version. |
496 | +# |
497 | +# This program is distributed in the hope that it will be useful, but WITHOUT |
498 | +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
499 | +# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more |
500 | +# details. |
501 | +# |
502 | +# You should have received a copy of the GNU General Public License along with |
503 | +# this program. If not, see <http://www.gnu.org/licenses/>. |
504 | + |
505 | +import gtk |
506 | +import gobject |
507 | +import os |
508 | +import sys |
509 | +import dbus |
510 | +from GTG import _ |
511 | +sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) |
512 | +import combobox_enhanced |
513 | + |
514 | + |
515 | +class pluginTomboy: |
516 | + |
517 | + def __init__(self): |
518 | + #These tokens are used to identify the beginning and the end of the |
519 | + #tomboy note point of insertion |
520 | + self.token_start = 'TOMBOY__' |
521 | + self.token_end = '|' |
522 | + self.path = os.path.dirname(os.path.abspath(__file__)) |
523 | + |
524 | + #Function called upon plug-in activation |
525 | + def activate(self, plugin_api): |
526 | + self.plugin_api = plugin_api |
527 | + |
528 | + #Return a textual token to represent the Tomboy widget. It's useful |
529 | + # since the task is saved as pure text |
530 | + def widgetTotext(self, widget): |
531 | + return self.token_start+ widget.tomboy_note_title+self.token_end |
532 | + |
533 | + # Converts all tomboy note widgets in the equivalent text |
534 | + def onTaskClosed(self, plugin_api): |
535 | + for anchor in self.anchors: |
536 | + widgets = anchor.get_widgets() |
537 | + if anchor.get_deleted(): |
538 | + #The note has been deleted, skip |
539 | + continue |
540 | + iter_start = self.textview.buff.get_iter_at_child_anchor(anchor) |
541 | + iter_end = iter_start.copy() |
542 | + iter_end.forward_char() |
543 | + if type(widgets) == list and len(widgets) !=0: |
544 | + #the anchor still contains a widget. |
545 | + widget = widgets[0] |
546 | + self.textview.buff.delete(iter_start, iter_end) |
547 | + self.textview.buff.insert(iter_start, |
548 | + self.widgetTotext(widget)) |
549 | + |
550 | + # adds a item(button) to the ToolBar, with a nice icon |
551 | + def addButtonToToolbar(self, plugin_api): |
552 | + tb_Taskbutton_image = gtk.Image() |
553 | + tb_Taskbutton_image_path =\ |
554 | + "/usr/share/icons/hicolor/16x16/apps/tomboy.png" |
555 | + tb_Taskbutton_pixbuf=gtk.gdk.\ |
556 | + pixbuf_new_from_file_at_size(tb_Taskbutton_image_path, 16, 16) |
557 | + tb_Taskbutton_image.set_from_pixbuf(tb_Taskbutton_pixbuf) |
558 | + tb_Taskbutton_image.show() |
559 | + self.tb_Taskbutton = gtk.ToolButton(tb_Taskbutton_image) |
560 | + self.tb_Taskbutton.set_label(_("Add Tomboy note")) |
561 | + self.tb_Taskbutton.connect('clicked', self.onTbTaskButton, plugin_api) |
562 | + plugin_api.add_task_toolbar_item(gtk.SeparatorToolItem()) |
563 | + plugin_api.add_task_toolbar_item(self.tb_Taskbutton) |
564 | + |
565 | + |
566 | + # Converts all the textual tokens in tomboy note widgets |
567 | + def convertTokensToWidgets(self): |
568 | + self.anchors=[] |
569 | + start_iter = self.textview.buff.get_start_iter() |
570 | + end_iter = self.textview.buff.get_end_iter() |
571 | + text = self.textview.buff.get_slice(start_iter, end_iter) |
572 | + text_offset = 0 |
573 | + token_position = text.find(self.token_start) |
574 | + token_ending = text.find(self.token_end, token_position) |
575 | + while not token_position < 0 and not token_ending < 0: |
576 | + #delete the text of the token |
577 | + tomboy_note_title = text[token_position + len(self.token_start): |
578 | + token_ending] |
579 | + start_iter = self.textview.buff.get_iter_at_offset(text_offset + |
580 | + token_position) |
581 | + end_iter = self.textview.buff.get_iter_at_offset(text_offset+ |
582 | + token_ending+1) |
583 | + self.textview.buff.delete(start_iter, end_iter) |
584 | + #add the widget |
585 | + widget =self.widgetCreate(tomboy_note_title) |
586 | + anchor = self.textviewInsertWidget(widget, start_iter) |
587 | + self.anchors.append(anchor) |
588 | + #find the next |
589 | + start_iter = self.textview.buff.get_iter_at_child_anchor(anchor) |
590 | + start_iter.forward_char() |
591 | + end_iter = self.textview.buff.get_end_iter() |
592 | + text = self.textview.buff.get_slice(start_iter, end_iter) |
593 | + text_offset = start_iter.get_offset() |
594 | + token_position = text.find(self.token_start) |
595 | + token_ending = text.find(self.token_end) |
596 | + |
597 | + def onTaskOpened(self, plugin_api): |
598 | + #NOTE: get_textview() only works in this function |
599 | + # (see GTG/core/plugins/api.py docs) |
600 | + self.textview = plugin_api.get_textview() |
601 | + self.addButtonToToolbar(plugin_api) |
602 | + self.convertTokensToWidgets() |
603 | + |
604 | + def deactivate(self, plugin_api): |
605 | + #nothing to do at all |
606 | + pass |
607 | + |
608 | + def close_dialog(self, widget, data=None): |
609 | + self.dialog.destroy() |
610 | + return True |
611 | + |
612 | + #opens a dbus connection to tomboy |
613 | + def getTomboyObject(self): |
614 | + bus = dbus.SessionBus() |
615 | + obj = bus.get_object("org.gnome.Tomboy", |
616 | + "/org/gnome/Tomboy/RemoteControl") |
617 | + return dbus.Interface(obj, "org.gnome.Tomboy.RemoteControl") |
618 | + |
619 | + #gets the list of the titles of the notes |
620 | + def getTomboyNoteTitleList(self): |
621 | + tomboy = self.getTomboyObject() |
622 | + return map(lambda note: str(tomboy.GetNoteTitle(note)), |
623 | + tomboy.ListAllNotes()) |
624 | + |
625 | + def onTbTaskButton(self, widget, plugin_api): |
626 | + title_list = self.getTomboyNoteTitleList() |
627 | + #Create the dialog |
628 | + glade_file = os.path.join(self.path, "tomboy.glade") |
629 | + wTree = gtk.glade.XML(glade_file, "InsertNoteDialog") |
630 | + #objects |
631 | + self.dialog = wTree.get_widget("InsertNoteDialog") |
632 | + btn_add = wTree.get_widget("btn_add") |
633 | + btn_cancel = wTree.get_widget("btn_cancel") |
634 | + self.combobox = wTree.get_widget("titles_combobox") |
635 | + self.label_caption = wTree.get_widget("label_caption") |
636 | + #connections |
637 | + self.dialog.connect("delete_event", self.close_dialog) |
638 | + btn_cancel.connect("clicked", self.close_dialog) |
639 | + btn_add.connect("clicked", self.noteChosen) |
640 | + self.combobox_entry = combobox_enhanced.\ |
641 | + smartifyComboboxEntry(self.combobox,title_list,self.noteChosen) |
642 | + self.dialog.show_all() |
643 | + |
644 | + #A title has been chosen by the user. If the note exists, it will be |
645 | + # linked, otherwise the user will have the option to create the note. |
646 | + def noteChosen(self, widget=None, data=None): |
647 | + tomboy = self.getTomboyObject() |
648 | + supposed_title = self.combobox_entry.get_text() |
649 | + if filter(lambda x: tomboy.GetNoteTitle(x)==supposed_title, |
650 | + tomboy.ListAllNotes()) == []: |
651 | + self.label_caption.set_text(_("That note does not exist!")) |
652 | + dialog = gtk.MessageDialog(parent = self.dialog, |
653 | + flags = gtk.DIALOG_DESTROY_WITH_PARENT, |
654 | + type = gtk.MESSAGE_QUESTION, |
655 | + buttons=gtk.BUTTONS_YES_NO, |
656 | + message_format=_("That note does not \ |
657 | +exist. Do you want to create a new one?")) |
658 | + response = dialog.run() |
659 | + dialog.destroy() |
660 | + if response == gtk.RESPONSE_YES: |
661 | + tomboy.CreateNamedNote(supposed_title) |
662 | + else: |
663 | + return |
664 | + #note insertion |
665 | + mark_start = self.textview.buff.get_insert() |
666 | + iter_start = self.textview.buff.get_iter_at_mark(mark_start) |
667 | + tomboy_widget =self.widgetCreate(supposed_title) |
668 | + anchor = self.textviewInsertWidget(tomboy_widget, iter_start) |
669 | + self.anchors.append(anchor) |
670 | + self.dialog.destroy() |
671 | + |
672 | + #Opens a note in tomboy application via dbus |
673 | + def tomboyDisplayNote(self, widget, data = None): |
674 | + tomboy = self.getTomboyObject() |
675 | + note = tomboy.FindNote(widget.tomboy_note_title) |
676 | + tomboy.DisplayNote(note) |
677 | + |
678 | + #inserts a widget in the textview |
679 | + def textviewInsertWidget(self, widget, iter): |
680 | + anchor = self.textview.buff.create_child_anchor(iter) |
681 | + widget.show() |
682 | + self.textview.add_child_at_anchor(widget, anchor) |
683 | + return anchor |
684 | + |
685 | + #creates the tomboy widget |
686 | + def widgetCreate(self, tomboy_note_title): |
687 | + image = gtk.Image() |
688 | + image_path = "/usr/share/icons/hicolor/16x16/apps/tomboy.png" |
689 | + pixbuf=gtk.gdk.\ |
690 | + pixbuf_new_from_file_at_size(image_path, 16, 16) |
691 | + image.show() |
692 | + image.set_from_pixbuf(pixbuf) |
693 | + image.set_alignment(0.5,1.0) |
694 | + label = gtk.Label() |
695 | + label.show() |
696 | + label.set_alignment(0.5, 1.0) |
697 | + eventbox = gtk.EventBox() |
698 | + eventbox.set_events(gtk.gdk.BUTTON_PRESS_MASK) |
699 | + eventbox.connect('button_press_event', self.tomboyDisplayNote) |
700 | + eventbox.show() |
701 | + window = self.plugin_api.get_window() |
702 | + hbox = gtk.HBox() |
703 | + hbox.show() |
704 | + hbox.add(image) |
705 | + hbox.add(label) |
706 | + eventbox.add(hbox) |
707 | + window.realize() |
708 | + style=window.get_style() |
709 | + color = str(style.text[gtk.STATE_PRELIGHT]) |
710 | + label.set_markup("<span underline='low' color='" + color +"'>" + tomboy_note_title + "</span>") |
711 | + eventbox.tomboy_note_title = tomboy_note_title |
712 | + #cursor changes to a hand |
713 | + def realize_callback(widget): |
714 | + eventbox.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.HAND2)) |
715 | + eventbox.connect("realize", realize_callback) |
716 | + return eventbox |
717 | + |
718 | |
719 | === modified file 'GTG/taskeditor/editor.py' |
720 | --- GTG/taskeditor/editor.py 2009-09-24 14:51:45 +0000 |
721 | +++ GTG/taskeditor/editor.py 2009-09-24 17:28:10 +0000 |
722 | @@ -479,6 +479,7 @@ |
723 | #Will be linked to this destruction method that will save the task |
724 | def destruction(self,a=None) :#pylint: disable-msg=W0613 |
725 | #Save should be also called when buffer is modified |
726 | + self.pengine.onTaskClose(self.plugins, self.te_plugin_api) |
727 | self.save() |
728 | self.closing(self.task.get_id()) |
729 | |
730 | |
731 | === modified file 'GTG/taskeditor/taskview.py' |
732 | --- GTG/taskeditor/taskview.py 2009-09-24 15:45:17 +0000 |
733 | +++ GTG/taskeditor/taskview.py 2009-09-24 17:28:10 +0000 |
734 | @@ -39,8 +39,7 @@ |
735 | separators = [' ', '.', ',', '/', '\n', '\t', '!', '?', ';', '\0'] |
736 | url_separators = [' ', ',', '\n', '\t', '\0'] |
737 | |
738 | -bullet1_ltr = '→' |
739 | -bullet1_rtl = '←' |
740 | +bullet1 = '→' |
741 | bullet2 = '↳' |
742 | |
743 | |
744 | @@ -151,11 +150,6 @@ |
745 | self.modified_sigid = self.buff.connect("changed" , self.modified) |
746 | self.connect("backspace",self.backspace) |
747 | self.tobe_refreshed = False |
748 | - |
749 | - if self.get_direction() == gtk.TEXT_DIR_RTL : |
750 | - self.bullet1 = bullet1_rtl |
751 | - else : |
752 | - self.bullet1 = bullet1_ltr |
753 | |
754 | |
755 | #This function is called to refresh the editor |
756 | @@ -883,7 +877,7 @@ |
757 | indentation = indentation + (level-1)*spaces |
758 | #adding the symbol |
759 | if level == 1 : |
760 | - indentation = "%s%s "%(indentation,self.bullet1) |
761 | + indentation = "%s%s "%(indentation,bullet1) |
762 | buff.insert(itera,indentation) |
763 | indenttag = self.create_indent_tag(buff,level) |
764 | self.__apply_tag_to_mark(start,end,tag=indenttag) |
765 | @@ -985,7 +979,7 @@ |
766 | #Then, if indent > 0, we increment it |
767 | #First step : we preserve it. |
768 | else : |
769 | - if not line.lstrip("%s "%self.bullet1) : |
770 | + if not line.lstrip("%s "%bullet1) : |
771 | self.deindent(itera,newlevel=0) |
772 | tv.emit_stop_by_name('insert-text') |
773 | |
774 | |
775 | === modified file 'locales/gtg.pot' |
776 | --- locales/gtg.pot 2009-09-12 23:03:15 +0000 |
777 | +++ locales/gtg.pot 2009-09-24 17:28:10 +0000 |
778 | @@ -8,7 +8,7 @@ |
779 | msgstr "" |
780 | "Project-Id-Version: PACKAGE VERSION\n" |
781 | "Report-Msgid-Bugs-To: \n" |
782 | -"POT-Creation-Date: 2009-09-13 01:03+0200\n" |
783 | +"POT-Creation-Date: 2009-09-18 15:51+0200\n" |
784 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" |
785 | "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" |
786 | "Language-Team: LANGUAGE <LL@li.org>\n" |
787 | @@ -632,6 +632,22 @@ |
788 | msgid "due" |
789 | msgstr "" |
790 | |
791 | +#: GTG/plugins/tomboy/tomboy.py:67 |
792 | +msgid "Add Tomboy note" |
793 | +msgstr "" |
794 | + |
795 | +#: GTG/plugins/tomboy/tomboy.py:170 |
796 | +msgid "That note does not exist!" |
797 | +msgstr "" |
798 | + |
799 | +#: GTG/plugins/tomboy/tomboy.glade.h:1 |
800 | +msgid "Insert Note" |
801 | +msgstr "" |
802 | + |
803 | +#: GTG/plugins/tomboy/tomboy.glade.h:2 |
804 | +msgid "Insert the title of the tomboy note " |
805 | +msgstr "" |
806 | + |
807 | #: GTG/plugins/rtm_sync/utility.py:54 |
808 | msgid "saving critical object failed" |
809 | msgstr "" |
810 | @@ -666,11 +682,11 @@ |
811 | "now. When done, press OK" |
812 | msgstr "" |
813 | |
814 | -#: GTG/plugins/rtm_sync/pyrtm/rtm.py:56 |
815 | +#: GTG/plugins/rtm_sync/pyrtm/rtm.py:57 |
816 | msgid "Invalid state" |
817 | msgstr "" |
818 | |
819 | -#: GTG/plugins/rtm_sync/pyrtm/rtm.py:105 |
820 | +#: GTG/plugins/rtm_sync/pyrtm/rtm.py:106 |
821 | msgid "API call failed" |
822 | msgstr "" |
823 |
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.