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