Merge lp:~gtg-user/gtg/uri-support into lp:~gtg/gtg/old-trunk
- uri-support
- Merge into old-trunk
Status: | Merged |
---|---|
Merged at revision: | 880 |
Proposed branch: | lp:~gtg-user/gtg/uri-support |
Merge into: | lp:~gtg/gtg/old-trunk |
Diff against target: |
276 lines (+98/-32) 5 files modified
CHANGELOG (+1/-0) GTG/__init__.py (+10/-0) GTG/gtg.py (+21/-11) GTG/gtk/browser/browser.py (+2/-1) GTG/gtk/manager.py (+64/-20) |
To merge this branch: | bzr merge lp:~gtg-user/gtg/uri-support |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Gtg developers | Pending | ||
Review via email: mp+32643@code.launchpad.net |
This proposal supersedes a proposal from 2010-08-09.
Commit message
Description of the change
GTG support for URIs of the format gtg://<gtg-task-id>
These URIs are useful for putting tasks links in other programs (e.g, in a tomboy note).
I'm currently using it in the Zeitgeist backend, to let the tasks registered in Zeitgeist and shown through the Activity Journal to be clickable.
On every start, GTG checks if GNOME knows about this kind of URI and, if not, puts itself as an application capable of handling those. Therefore, you can use
xdg-open gtg://<
Tomboy has the same kind of feature through a note:// URI.
Luca Invernizzi (invernizzi) wrote : Posted in a previous version of this proposal | # |
- 874. By Luca Invernizzi
-
GTG can be opened just with some TaskEditor windows
Luca Invernizzi (invernizzi) wrote : | # |
I've just added the support for opening GTG without the task browser (if some uris are given).
If the browser was already open, it stays open, and if ./gtg is executed while in browserless mode, it opens the browser.
We're getting tomboysh :)
- 875. By Luca Invernizzi
-
merge w/ trunk
Preview Diff
1 | === modified file 'CHANGELOG' | |||
2 | --- CHANGELOG 2010-08-04 00:30:22 +0000 | |||
3 | +++ CHANGELOG 2010-08-25 16:29:47 +0000 | |||
4 | @@ -4,6 +4,7 @@ | |||
5 | 4 | * Fixed bug with data consistency #579189, by Marko Kevac | 4 | * Fixed bug with data consistency #579189, by Marko Kevac |
6 | 5 | * Added samba bugzilla to the bugzilla plugin, by Jelmer Vernoij | 5 | * Added samba bugzilla to the bugzilla plugin, by Jelmer Vernoij |
7 | 6 | * Fixed bug #532392, a start date is later than a due date, by Volodymyr Floreskul | 6 | * Fixed bug #532392, a start date is later than a due date, by Volodymyr Floreskul |
8 | 7 | * support for gtg:// URIs by Luca Invernizzi | ||
9 | 7 | 8 | ||
10 | 8 | 2010-03-01 Getting Things GNOME! 0.2.2 | 9 | 2010-03-01 Getting Things GNOME! 0.2.2 |
11 | 9 | * Autostart on login, by Luca Invernizzi | 10 | * Autostart on login, by Luca Invernizzi |
12 | 10 | 11 | ||
13 | === modified file 'GTG/__init__.py' | |||
14 | --- GTG/__init__.py 2010-03-12 11:16:15 +0000 | |||
15 | +++ GTG/__init__.py 2010-08-25 16:29:47 +0000 | |||
16 | @@ -92,3 +92,13 @@ | |||
17 | 92 | 92 | ||
18 | 93 | if os.path.isdir(os.path.join(config_home, 'gtg/plugins')): | 93 | if os.path.isdir(os.path.join(config_home, 'gtg/plugins')): |
19 | 94 | PLUGIN_DIR.append(os.path.join(config_home, 'gtg/plugins')) | 94 | PLUGIN_DIR.append(os.path.join(config_home, 'gtg/plugins')) |
20 | 95 | |||
21 | 96 | #Register GTG URI (temporary, it should be created by a schema upon installing) | ||
22 | 97 | import gconf | ||
23 | 98 | domain = "/desktop/gnome/url-handlers/gtg/" | ||
24 | 99 | client = gconf.client_get_default() | ||
25 | 100 | #this should work both in debugging mode and in deployed mode | ||
26 | 101 | client.set_string(os.path.join(domain, "command"), "gtg %s") | ||
27 | 102 | client.set_bool(os.path.join(domain, "enabled"), True) | ||
28 | 103 | client.set_bool(os.path.join(domain, "needs_terminal"), False) | ||
29 | 104 | |||
30 | 95 | 105 | ||
31 | === modified file 'GTG/gtg.py' | |||
32 | --- GTG/gtg.py 2010-08-03 17:07:31 +0000 | |||
33 | +++ GTG/gtg.py 2010-08-25 16:29:47 +0000 | |||
34 | @@ -46,8 +46,8 @@ | |||
35 | 46 | 46 | ||
36 | 47 | #=== IMPORT =================================================================== | 47 | #=== IMPORT =================================================================== |
37 | 48 | import os | 48 | import os |
38 | 49 | import sys | ||
39 | 49 | import logging | 50 | import logging |
40 | 50 | |||
41 | 51 | import dbus | 51 | import dbus |
42 | 52 | 52 | ||
43 | 53 | #our own imports | 53 | #our own imports |
44 | @@ -55,7 +55,7 @@ | |||
45 | 55 | from GTG import _ | 55 | from GTG import _ |
46 | 56 | from GTG.core import CoreConfig | 56 | from GTG.core import CoreConfig |
47 | 57 | from GTG.core.datastore import DataStore | 57 | from GTG.core.datastore import DataStore |
49 | 58 | #from GTG.gtk.crashhandler import signal_catcher | 58 | from GTG.gtk.crashhandler import signal_catcher |
50 | 59 | from GTG.gtk.manager import Manager | 59 | from GTG.gtk.manager import Manager |
51 | 60 | from GTG.tools.logger import Log | 60 | from GTG.tools.logger import Log |
52 | 61 | 61 | ||
53 | @@ -66,8 +66,11 @@ | |||
54 | 66 | #that's why we put the pid file in the data directory : | 66 | #that's why we put the pid file in the data directory : |
55 | 67 | #we allow one instance of gtg by data directory. | 67 | #we allow one instance of gtg by data directory. |
56 | 68 | 68 | ||
59 | 69 | def check_instance(directory): | 69 | def check_instance(directory, uri_list = []): |
60 | 70 | """Check if gtg is already running.""" | 70 | """ |
61 | 71 | Check if gtg is already running. | ||
62 | 72 | If so, open the tasks whose ids are in the uri_list | ||
63 | 73 | """ | ||
64 | 71 | pidfile = os.path.join(directory, "gtg.pid") | 74 | pidfile = os.path.join(directory, "gtg.pid") |
65 | 72 | if not os.path.exists(pidfile): | 75 | if not os.path.exists(pidfile): |
66 | 73 | open(pidfile, "w").close() | 76 | open(pidfile, "w").close() |
67 | @@ -83,6 +86,10 @@ | |||
68 | 83 | d=dbus.SessionBus().get_object(CoreConfig.BUSNAME,\ | 86 | d=dbus.SessionBus().get_object(CoreConfig.BUSNAME,\ |
69 | 84 | CoreConfig.BUSINTERFACE) | 87 | CoreConfig.BUSINTERFACE) |
70 | 85 | d.show_task_browser() | 88 | d.show_task_browser() |
71 | 89 | #if the user has specified a task to open, do that | ||
72 | 90 | for uri in uri_list: | ||
73 | 91 | if uri.startswith("gtg://"): | ||
74 | 92 | d.open_task_editor(uri[6:]) | ||
75 | 86 | raise SystemExit | 93 | raise SystemExit |
76 | 87 | 94 | ||
77 | 88 | #write the pid file | 95 | #write the pid file |
78 | @@ -102,10 +109,10 @@ | |||
79 | 102 | #To be more user friendly and get the logs of crashes, we show an apport | 109 | #To be more user friendly and get the logs of crashes, we show an apport |
80 | 103 | # hooked window upon crashes | 110 | # hooked window upon crashes |
81 | 104 | if options.no_crash_handler == False: | 111 | if options.no_crash_handler == False: |
86 | 105 | #FIXME: Why is this disabled? Please comment when disabling functionality so we know. :-) | 112 | with signal_catcher(manager.close_browser): |
87 | 106 | #with signal_catcher(manager.close_browser): | 113 | manager.main(once_thru=options.boot_test, uri_list = args) |
88 | 107 | pass | 114 | else: |
89 | 108 | manager.main(once_thru=options.boot_test) | 115 | manager.main(once_thru=options.boot_test, uri_list = args) |
90 | 109 | core_main_quit(config, ds) | 116 | core_main_quit(config, ds) |
91 | 110 | 117 | ||
92 | 111 | def core_main_init(options = None, args = None): | 118 | def core_main_init(options = None, args = None): |
93 | @@ -116,10 +123,11 @@ | |||
94 | 116 | if options.debug: | 123 | if options.debug: |
95 | 117 | Log.setLevel(logging.DEBUG) | 124 | Log.setLevel(logging.DEBUG) |
96 | 118 | Log.debug("Debug output enabled.") | 125 | Log.debug("Debug output enabled.") |
99 | 119 | Log.set_debugging_mode(True) | 126 | else: |
100 | 120 | 127 | Log.setLevel(logging.INFO) | |
101 | 128 | Log.set_debugging_mode(options.debug) | ||
102 | 121 | config = CoreConfig() | 129 | config = CoreConfig() |
104 | 122 | check_instance(config.get_data_dir()) | 130 | check_instance(config.get_data_dir(), args) |
105 | 123 | backends_list = BackendFactory().get_saved_backends_list() | 131 | backends_list = BackendFactory().get_saved_backends_list() |
106 | 124 | # Load data store | 132 | # Load data store |
107 | 125 | ds = DataStore() | 133 | ds = DataStore() |
108 | @@ -145,6 +153,8 @@ | |||
109 | 145 | # Ending the application: we save configuration | 153 | # Ending the application: we save configuration |
110 | 146 | config.save() | 154 | config.save() |
111 | 147 | ds.save(quit = True) | 155 | ds.save(quit = True) |
112 | 156 | sys.exit(0) | ||
113 | 157 | |||
114 | 148 | 158 | ||
115 | 149 | #=== EXECUTION ================================================================ | 159 | #=== EXECUTION ================================================================ |
116 | 150 | 160 | ||
117 | 151 | 161 | ||
118 | === modified file 'GTG/gtk/browser/browser.py' | |||
119 | --- GTG/gtk/browser/browser.py 2010-08-23 01:33:43 +0000 | |||
120 | +++ GTG/gtk/browser/browser.py 2010-08-25 16:29:47 +0000 | |||
121 | @@ -139,7 +139,8 @@ | |||
122 | 139 | #Expand all the tasks in the taskview | 139 | #Expand all the tasks in the taskview |
123 | 140 | self.task_tv.expand_all() | 140 | self.task_tv.expand_all() |
124 | 141 | self.on_select_tag() | 141 | self.on_select_tag() |
126 | 142 | self.window.show() | 142 | |
127 | 143 | self.window.hide() | ||
128 | 143 | 144 | ||
129 | 144 | ### INIT HELPER FUNCTIONS ##################################################### | 145 | ### INIT HELPER FUNCTIONS ##################################################### |
130 | 145 | # | 146 | # |
131 | 146 | 147 | ||
132 | === modified file 'GTG/gtk/manager.py' | |||
133 | --- GTG/gtk/manager.py 2010-08-03 17:07:31 +0000 | |||
134 | +++ GTG/gtk/manager.py 2010-08-25 16:29:47 +0000 | |||
135 | @@ -39,10 +39,12 @@ | |||
136 | 39 | from GTG.core.plugins.engine import PluginEngine | 39 | from GTG.core.plugins.engine import PluginEngine |
137 | 40 | from GTG.core.plugins.api import PluginAPI | 40 | from GTG.core.plugins.api import PluginAPI |
138 | 41 | from GTG.tools.logger import Log | 41 | from GTG.tools.logger import Log |
143 | 42 | 42 | from GTG.gtk.backends_dialog import BackendsDialog | |
144 | 43 | 43 | from GTG.backends.backendsignals import BackendSignals | |
145 | 44 | 44 | ||
146 | 45 | class Manager: | 45 | |
147 | 46 | |||
148 | 47 | class Manager(object): | ||
149 | 46 | 48 | ||
150 | 47 | 49 | ||
151 | 48 | ############## init ##################################################### | 50 | ############## init ##################################################### |
152 | @@ -58,6 +60,7 @@ | |||
153 | 58 | # right now | 60 | # right now |
154 | 59 | 61 | ||
155 | 60 | self.browser = None | 62 | self.browser = None |
156 | 63 | self.gtk_terminate = False #if true, the gtk main is not started | ||
157 | 61 | self.pengine = None | 64 | self.pengine = None |
158 | 62 | self.plugins = None | 65 | self.plugins = None |
159 | 63 | self.plugin_api = None | 66 | self.plugin_api = None |
160 | @@ -65,11 +68,9 @@ | |||
161 | 65 | 68 | ||
162 | 66 | #Shared clipboard | 69 | #Shared clipboard |
163 | 67 | self.clipboard = clipboard.TaskClipboard(self.req) | 70 | self.clipboard = clipboard.TaskClipboard(self.req) |
169 | 68 | 71 | ||
170 | 69 | #Browser | 72 | #Browser (still hidden) |
171 | 70 | #FIXME : the browser should not be built by default and should be a | 73 | self.browser = TaskBrowser(self.req, self, self.config) |
167 | 71 | # window like another and not necessary (like the editor) | ||
168 | 72 | self.open_browser() | ||
172 | 73 | 74 | ||
173 | 74 | #Plugins (that needs to be after the browser, this is ugly) | 75 | #Plugins (that needs to be after the browser, this is ugly) |
174 | 75 | self.__init_plugin_engine() | 76 | self.__init_plugin_engine() |
175 | @@ -80,6 +81,7 @@ | |||
176 | 80 | #Preferences and Backends windows | 81 | #Preferences and Backends windows |
177 | 81 | # Initialize dialogs | 82 | # Initialize dialogs |
178 | 82 | self.preferences_dialog = None | 83 | self.preferences_dialog = None |
179 | 84 | self.edit_backends_dialog = None | ||
180 | 83 | 85 | ||
181 | 84 | #DBus | 86 | #DBus |
182 | 85 | DBusTaskWrapper(self.req, self) | 87 | DBusTaskWrapper(self.req, self) |
183 | @@ -125,9 +127,8 @@ | |||
184 | 125 | ############## Browser ################################################# | 127 | ############## Browser ################################################# |
185 | 126 | 128 | ||
186 | 127 | def open_browser(self): | 129 | def open_browser(self): |
187 | 128 | if not self.browser: | ||
188 | 129 | self.browser = TaskBrowser(self.req, self, self.config) | ||
189 | 130 | Log.debug("Browser is open") | 130 | Log.debug("Browser is open") |
190 | 131 | self.browser.show() | ||
191 | 131 | 132 | ||
192 | 132 | #FIXME : the browser should not be the center of the universe. | 133 | #FIXME : the browser should not be the center of the universe. |
193 | 133 | # In fact, we should build a system where view can register themselves | 134 | # In fact, we should build a system where view can register themselves |
194 | @@ -190,12 +191,30 @@ | |||
195 | 190 | #else, it close_task would be called once again | 191 | #else, it close_task would be called once again |
196 | 191 | #by editor.close | 192 | #by editor.close |
197 | 192 | editor.close() | 193 | editor.close() |
201 | 193 | # else: | 194 | self.check_quit_condition() |
202 | 194 | #FIXME: this one should be a debug statement | 195 | |
203 | 195 | # print "the %s editor was already unregistered" %tid | 196 | def check_quit_condition(self): |
204 | 197 | ''' | ||
205 | 198 | checking if we need to shut down the whole GTG (if no window is open) | ||
206 | 199 | ''' | ||
207 | 200 | if not self.is_browser_visible() and not self.opened_task: | ||
208 | 201 | #no need to live | ||
209 | 202 | print "AAAAAAAAAAA" | ||
210 | 203 | self.quit() | ||
211 | 204 | print self.opened_task | ||
212 | 196 | 205 | ||
213 | 197 | ################ Others dialog ############################################ | 206 | ################ Others dialog ############################################ |
214 | 198 | 207 | ||
215 | 208 | def open_edit_backends(self, sender = None, backend_id = None): | ||
216 | 209 | if not self.edit_backends_dialog: | ||
217 | 210 | self.edit_backends_dialog = BackendsDialog(self.req) | ||
218 | 211 | self.edit_backends_dialog.activate() | ||
219 | 212 | if backend_id != None: | ||
220 | 213 | self.edit_backends_dialog.show_config_for_backend(backend_id) | ||
221 | 214 | |||
222 | 215 | def configure_backend(self, backend_id): | ||
223 | 216 | self.open_edit_backends(None, backend_id) | ||
224 | 217 | |||
225 | 199 | def open_preferences(self, config_priv, sender=None): | 218 | def open_preferences(self, config_priv, sender=None): |
226 | 200 | if not hasattr(self, "preferences"): | 219 | if not hasattr(self, "preferences"): |
227 | 201 | self.preferences = PreferencesDialog(self.pengine, self.p_apis, \ | 220 | self.preferences = PreferencesDialog(self.pengine, self.p_apis, \ |
228 | @@ -209,17 +228,42 @@ | |||
229 | 209 | for t in tids: | 228 | for t in tids: |
230 | 210 | if t in self.opened_task: | 229 | if t in self.opened_task: |
231 | 211 | self.close_task(t) | 230 | self.close_task(t) |
232 | 231 | |||
233 | 232 | ### URIS ################################################################### | ||
234 | 233 | |||
235 | 234 | def open_uri_list(self, unused, uri_list): | ||
236 | 235 | ''' | ||
237 | 236 | Open the Editor windows of the tasks associated with the uris given. | ||
238 | 237 | Uris are of the form gtg://<taskid> | ||
239 | 238 | ''' | ||
240 | 239 | print self.req.get_all_tasks_list() | ||
241 | 240 | for uri in uri_list: | ||
242 | 241 | if uri.startswith("gtg://"): | ||
243 | 242 | self.open_task(uri[6:]) | ||
244 | 243 | #if no window was opened, we just quit | ||
245 | 244 | self.check_quit_condition() | ||
246 | 245 | |||
247 | 212 | 246 | ||
248 | 213 | ### MAIN ################################################################### | 247 | ### MAIN ################################################################### |
250 | 214 | def main(self, once_thru=False): | 248 | |
251 | 249 | def main(self, once_thru = False, uri_list = []): | ||
252 | 250 | if uri_list: | ||
253 | 251 | #before opening the requested tasks, we make sure that all of them | ||
254 | 252 | #are loaded. | ||
255 | 253 | BackendSignals().connect('default-backend-loaded', | ||
256 | 254 | self.open_uri_list, | ||
257 | 255 | uri_list) | ||
258 | 256 | else: | ||
259 | 257 | self.open_browser() | ||
260 | 258 | |||
261 | 215 | gobject.threads_init() | 259 | gobject.threads_init() |
266 | 216 | if once_thru: | 260 | if not self.gtk_terminate: |
267 | 217 | gtk.main_iteration() | 261 | if once_thru: |
268 | 218 | else: | 262 | gtk.main_iteration() |
269 | 219 | gtk.main() | 263 | else: |
270 | 264 | gtk.main() | ||
271 | 220 | return 0 | 265 | return 0 |
272 | 221 | 266 | ||
273 | 222 | |||
274 | 223 | def quit(self,sender=None): | 267 | def quit(self,sender=None): |
275 | 224 | gtk.main_quit() | 268 | gtk.main_quit() |
276 | 225 | #save opened tasks and their positions. | 269 | #save opened tasks and their positions. |
Ps: the last commits messages have the very meaningful name of "a" because I had to do a series of cherrypicking. Only the file that's picked matters.