Merge lp:~gtg-user/gtg/tomboy-backend into lp:~gtg/gtg/old-trunk
- tomboy-backend
- Merge into old-trunk
Status: | Superseded |
---|---|
Proposed branch: | lp:~gtg-user/gtg/tomboy-backend |
Merge into: | lp:~gtg/gtg/old-trunk |
Prerequisite: | lp:~gtg-user/gtg/multibackends-halfgsoc_merge |
Diff against target: |
750 lines (+708/-1) 5 files modified
CHANGELOG (+1/-0) GTG/backends/backend_gnote.py (+61/-0) GTG/backends/backend_tomboy.py (+60/-0) GTG/backends/generictomboy.py (+583/-0) GTG/gtk/browser/browser.py (+3/-1) |
To merge this branch: | bzr merge lp:~gtg-user/gtg/tomboy-backend |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Lionel Dricot (community) | Approve | ||
Gtg developers | Pending | ||
Review via email: mp+28257@code.launchpad.net |
This proposal has been superseded by a proposal from 2010-08-13.
Commit message
Description of the change
The tomboy backend. Any tomboy note matching a particular tag will be inserted (r/w) in GTG.
It handles gracefully the change of the "attached tags", that are the tags to which the backend is looking for. The r/w synchronization engine is included.
It's complemented with a series of testcases and exception handling (when tomboy is put under stress - ~500 notes on my laptop - it begins to drop connections on dbus).
This is just to show the code for a review. I'll need to review the docstrings and use this backend for a couple of weeks before considering it stable - it works pretty well so far-.
Lionel Dricot (ploum-deactivatedaccount) wrote : | # |
- 824. By Bryce Harrington
-
If there aren't any unscheduled items, don't print them
- 825. By Luca Invernizzi
-
Multiple backends core features merge:
- using signals instead of callback function to save tasks
- superclass for all backends added, managing anything that's common to
them
- localfile baceknd updated (with tests)Unit testing now doesn't clutter the ~/.local/share directroy anymore
- 826. By Luca Invernizzi
-
small fix for tests (forgot to remove unused code)
- 827. By Lionel Dricot
-
Working on liblarch. It progress and it looks like it will be really good
- 828. By Luca Invernizzi
-
small fix in delete_dialog
- 829. By Lionel Dricot
-
liblarch progress
- 830. By Lionel Dricot
-
forgot some more liblarch love
- 831. By Lionel Dricot
-
only 21 todos left in liblarch before porting GTG to it
- 832. By Lionel Dricot
-
Very interesting! Starting from a unit test and fighting to find an unrelated
bug that was still afecting the test. - 833. By Lionel Dricot
-
liblarch progress
- 834. By Luca Invernizzi
-
small fix in tagstore (checking if a task object is not None)
- 835. By Lionel Dricot
-
liblarch test suite nearly finished
- 836. By Lionel Dricot
-
liblarch is now fully covered. Lets start liblarch-gtk now
- 837. By Bryce Harrington
-
Fix merge conflict
- 838. By Bryce Harrington
-
Add ability to postpone tasks by tag
- 839. By Bryce Harrington
-
Merge branch by Volodymyr Floreskul to move due date when start date changed
- 840. By Luca Invernizzi
-
small fixes in filteredtree
- 841. By Bryce Harrington
-
ghost position error messages should be debug data.
There are already several error messages about this to stdout before
hitting this code, so user is already notified. These prints display a
number of lines of task ids which won't be useful to the user. - 842. By Bryce Harrington
-
Clean up some more messy debug messages
This leaves a one line message to display to the user, the rest is
displayed only if --debug is specified. The information it provides is
really only interesting for debug purposes (and probably of limited use
even there), so this reduces the spewage to stdout when these errors are
present. - 843. By Bryce Harrington
-
'old paths are' is debugging output, move to Logger
- 844. By Bryce Harrington
-
Allow for sensible default values if none provided.
This change allows anonymize_
task_file. py to be called with no args, and
it does the sensible default - read the user's regular tasks xml file
and anonymize it to a temporary file. - 845. By Bryce Harrington
-
Increase column width for ids now that ids can be uuids
- 846. By Luca Invernizzi
-
Disabling the gtk crash handler
- 847. By Bertrand Rousseau <rousseau@biscuit>
-
Add short description to plugins. Edit the preference window aspects.
- 848. By Luca Invernizzi
-
Better phrasing in "Learn how to use the QuickAdd Entry" by Chris Johnston
- 849. By Luca Invernizzi
-
Typo in notification area plugin description (fixing bug #599832)
- 850. By Bryce Harrington
-
sp.
- 851. By Bryce Harrington
-
Include children of tags recursively. Fixes regression #592445
When a tag is selected, the browser displays tasks that belong to that
tag or its children, but not its grandchildren. We change the
functionality to be recursive so it'll include all descendant tags of
the given tag. - 852. By Bryce Harrington
-
The tests should not be disabled in trunk.
I've verified all the tests still pass fine on my system. I guess they
were disabled simply for focusing on testing liblarch, but this is bad,
since it gives people false impressions that code committed to trunk is
okay, when it might not be.Also, please do not disable tests without leaving some comment as to
*why* they are being disabled. - 853. By Bryce Harrington
-
Fixup grammar
- 854. By Bryce Harrington
-
Add a --no-crash-handler option to disable apport, to be used by debug.sh
(Looks like someone temporarily disabled apport anyway, but not sure
why, so left it disabled for now.) - 855. By Bryce Harrington
-
Also select whatever task cursor is over when right clicking
This better mimics nautilus' behavior, better matching expectations for
GNOME users. - 856. By Bryce Harrington <bryce@salisbury>
-
Fix grammar
- 857. By Luca Invernizzi
-
Anonymizer script uses reasonable defaults (by bryce)
- 858. By Bryce Harrington
-
Add a simple boot performance test.
This adds a -b option to gtg which causes it to exit immediately after
completing the first iteration of the main loop, thus permitting a way
to reliably measure initialization time.scripts/debug.sh is also updated to also support a -b option, which it
passes to gtg. This permits doing boot-up time profiling like this:scripts/debug.sh -b -p
Of course, that's not interesting since there's only 5 tasks in the
default data set. But you can use any data set in gtg/test/data/, for
instance, the infamous 'bryce' dataset:scripts/debug.sh -b -p -s bryce
- 859. By Bryce Harrington
-
Flesh out man page with recently added options
- 860. By Bryce Harrington
-
Include mention of the code documentation available online
- 861. By Bryce Harrington
-
Add coding guidelines for commented out code
- 862. By Bryce Harrington
-
Fixed crash traceback that's shown when pressing 'delete' key
Patch from Jeff Oliver (LP: #583103) Thanks!
- 863. By Bryce Harrington
-
Namespace gtg's D-BUS service name (LP: #582453)
- 864. By Bryce Harrington
-
Add a -v / --version option to show current version
- 865. By Bryce Harrington
-
Add ability to put lengthy text bodies into generated tasks
- 866. By Bryce Harrington
-
Be more consistent with date formatting
If no tasks were scheduled for a day, the date would be formatted
differently than if there was a task scheduled. E.g.:...
Fri 8-20 13 1
2010-08-21 0 0
Sun 8-22 2 0
Mon 8-23 16 0
Tue 8-24 4 0
2010-08-25 0 0 - 867. By Luca Invernizzi
-
Accented tags are accepted in the quick-add field (by Jonathan Barnoud)
Fixing bug LP #615519 - 868. By Luca Invernizzi
-
UnitTests are automatically loaded at run time in GTG/tests/
__init_ _.py. Before, we had to add all the tests that we've written by hand in the
test_suite function, and that lead to a lot of merge conflicts. As tests
are now automatically added, there's no need to edit that file anymore. - 869. By Luca Invernizzi
-
Solved bug in quickadd: when using the "tags:" option, it wasn't actually
inserting the tag text into the task content, but only attaching the Tag object
to the task. Some code elsewhere was adding the text upon task opening in the
Editor.
(This was causing weird behaviour in the backends, otherwise it would be hard
to spot). - 870. By Luca Invernizzi
-
a
- 871. By Luca Invernizzi
-
a
- 872. By Luca Invernizzi
-
a
- 873. By Luca Invernizzi
-
a
- 874. By Luca Invernizzi
-
a
- 875. By Luca Invernizzi
-
a
- 876. By Luca Invernizzi
-
a
- 877. By Luca Invernizzi
-
a
- 878. By Luca Invernizzi
-
a
- 879. By Luca Invernizzi
-
a
- 880. By Luca Invernizzi
-
a
- 881. By Luca Invernizzi
-
Changelog changed
- 882. By Luca Invernizzi
-
cherripicking files
- 883. By Luca Invernizzi
-
cherripicking files
- 884. By Luca Invernizzi
-
cherrypicking from my development branch
- 885. By Luca Invernizzi
-
merge w/ trunk
- 886. By Luca Invernizzi
-
small typo in docs:
- 887. By Luca Invernizzi
-
merge w/ trunk
- 888. By Luca Invernizzi
-
cherrypicking from my development branch
Unmerged revisions
Preview Diff
1 | === modified file 'CHANGELOG' | |||
2 | --- CHANGELOG 2010-08-04 00:30:22 +0000 | |||
3 | +++ CHANGELOG 2010-08-13 23:43:03 +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 | * New Tomboy/Gnote backend, 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 | === added file 'GTG/backends/backend_gnote.py' | |||
14 | --- GTG/backends/backend_gnote.py 1970-01-01 00:00:00 +0000 | |||
15 | +++ GTG/backends/backend_gnote.py 2010-08-13 23:43:03 +0000 | |||
16 | @@ -0,0 +1,61 @@ | |||
17 | 1 | # -*- coding: utf-8 -*- | ||
18 | 2 | # ----------------------------------------------------------------------------- | ||
19 | 3 | # Gettings Things Gnome! - a personal organizer for the GNOME desktop | ||
20 | 4 | # Copyright (c) 2008-2009 - Lionel Dricot & Bertrand Rousseau | ||
21 | 5 | # | ||
22 | 6 | # This program is free software: you can redistribute it and/or modify it under | ||
23 | 7 | # the terms of the GNU General Public License as published by the Free Software | ||
24 | 8 | # Foundation, either version 3 of the License, or (at your option) any later | ||
25 | 9 | # version. | ||
26 | 10 | # | ||
27 | 11 | # This program is distributed in the hope that it will be useful, but WITHOUT | ||
28 | 12 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | ||
29 | 13 | # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more | ||
30 | 14 | # details. | ||
31 | 15 | # | ||
32 | 16 | # You should have received a copy of the GNU General Public License along with | ||
33 | 17 | # this program. If not, see <http://www.gnu.org/licenses/>. | ||
34 | 18 | # ----------------------------------------------------------------------------- | ||
35 | 19 | |||
36 | 20 | ''' | ||
37 | 21 | The gnote backend. The actual backend is all in GenericTomboy, since it's | ||
38 | 22 | shared with the tomboy backend. | ||
39 | 23 | ''' | ||
40 | 24 | #To introspect tomboy: qdbus org.gnome.Tomboy /org/gnome/Tomboy/RemoteControl | ||
41 | 25 | |||
42 | 26 | from GTG.backends.genericbackend import GenericBackend | ||
43 | 27 | from GTG import _ | ||
44 | 28 | from GTG.backends.generictomboy import GenericTomboy | ||
45 | 29 | |||
46 | 30 | |||
47 | 31 | |||
48 | 32 | class Backend(GenericTomboy): | ||
49 | 33 | ''' | ||
50 | 34 | A simple class that adds some description to the GenericTomboy class. | ||
51 | 35 | It's done this way since Tomboy and Gnote backends have different | ||
52 | 36 | descriptions and Dbus addresses but the same backend behind them. | ||
53 | 37 | ''' | ||
54 | 38 | |||
55 | 39 | |||
56 | 40 | _general_description = { \ | ||
57 | 41 | GenericBackend.BACKEND_NAME: "backend_gnote", \ | ||
58 | 42 | GenericBackend.BACKEND_HUMAN_NAME: _("Gnote"), \ | ||
59 | 43 | GenericBackend.BACKEND_AUTHORS: ["Luca Invernizzi"], \ | ||
60 | 44 | GenericBackend.BACKEND_TYPE: GenericBackend.TYPE_READWRITE, \ | ||
61 | 45 | GenericBackend.BACKEND_DESCRIPTION: \ | ||
62 | 46 | _("This backend can synchronize all or part of your Gnote" | ||
63 | 47 | " notes in GTG. If you decide it would be handy to" | ||
64 | 48 | " have one of your notes in your TODO list, just tag it " | ||
65 | 49 | "with the tag you have chosen (you'll configure it later" | ||
66 | 50 | "), and it will appear in GTG."),\ | ||
67 | 51 | } | ||
68 | 52 | |||
69 | 53 | _static_parameters = { \ | ||
70 | 54 | GenericBackend.KEY_ATTACHED_TAGS: {\ | ||
71 | 55 | GenericBackend.PARAM_TYPE: GenericBackend.TYPE_LIST_OF_STRINGS, \ | ||
72 | 56 | GenericBackend.PARAM_DEFAULT_VALUE: ["@GTG-Gnote"]}, \ | ||
73 | 57 | } | ||
74 | 58 | |||
75 | 59 | _BUS_ADDRESS = ("org.gnome.Gnote", | ||
76 | 60 | "/org/gnome/Gnote/RemoteControl", | ||
77 | 61 | "org.gnome.Gnote.RemoteControl") | ||
78 | 0 | 62 | ||
79 | === added file 'GTG/backends/backend_tomboy.py' | |||
80 | --- GTG/backends/backend_tomboy.py 1970-01-01 00:00:00 +0000 | |||
81 | +++ GTG/backends/backend_tomboy.py 2010-08-13 23:43:03 +0000 | |||
82 | @@ -0,0 +1,60 @@ | |||
83 | 1 | # -*- coding: utf-8 -*- | ||
84 | 2 | # ----------------------------------------------------------------------------- | ||
85 | 3 | # Getting Things Gnome! - a personal organizer for the GNOME desktop | ||
86 | 4 | # Copyright (c) 2008-2009 - Lionel Dricot & Bertrand Rousseau | ||
87 | 5 | # | ||
88 | 6 | # This program is free software: you can redistribute it and/or modify it under | ||
89 | 7 | # the terms of the GNU General Public License as published by the Free Software | ||
90 | 8 | # Foundation, either version 3 of the License, or (at your option) any later | ||
91 | 9 | # version. | ||
92 | 10 | # | ||
93 | 11 | # This program is distributed in the hope that it will be useful, but WITHOUT | ||
94 | 12 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | ||
95 | 13 | # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more | ||
96 | 14 | # details. | ||
97 | 15 | # | ||
98 | 16 | # You should have received a copy of the GNU General Public License along with | ||
99 | 17 | # this program. If not, see <http://www.gnu.org/licenses/>. | ||
100 | 18 | # ----------------------------------------------------------------------------- | ||
101 | 19 | |||
102 | 20 | ''' | ||
103 | 21 | The tomboy backend. The actual backend is all in GenericTomboy, since it's | ||
104 | 22 | shared with the Gnote backend. | ||
105 | 23 | ''' | ||
106 | 24 | |||
107 | 25 | from GTG.backends.genericbackend import GenericBackend | ||
108 | 26 | from GTG import _ | ||
109 | 27 | from GTG.backends.generictomboy import GenericTomboy | ||
110 | 28 | |||
111 | 29 | |||
112 | 30 | |||
113 | 31 | class Backend(GenericTomboy): | ||
114 | 32 | ''' | ||
115 | 33 | A simple class that adds some description to the GenericTomboy class. | ||
116 | 34 | It's done this way since Tomboy and Gnote backends have different | ||
117 | 35 | descriptions and Dbus addresses but the same backend behind them. | ||
118 | 36 | ''' | ||
119 | 37 | |||
120 | 38 | |||
121 | 39 | _general_description = { \ | ||
122 | 40 | GenericBackend.BACKEND_NAME: "backend_tomboy", \ | ||
123 | 41 | GenericBackend.BACKEND_HUMAN_NAME: _("Tomboy"), \ | ||
124 | 42 | GenericBackend.BACKEND_AUTHORS: ["Luca Invernizzi"], \ | ||
125 | 43 | GenericBackend.BACKEND_TYPE: GenericBackend.TYPE_READWRITE, \ | ||
126 | 44 | GenericBackend.BACKEND_DESCRIPTION: \ | ||
127 | 45 | _("This backend can synchronize all or part of your Tomboy" | ||
128 | 46 | " notes in GTG. If you decide it would be handy to" | ||
129 | 47 | " have one of your notes in your TODO list, just tag it " | ||
130 | 48 | "with the tag you have chosen (you'll configure it later" | ||
131 | 49 | "), and it will appear in GTG."),\ | ||
132 | 50 | } | ||
133 | 51 | |||
134 | 52 | _static_parameters = { \ | ||
135 | 53 | GenericBackend.KEY_ATTACHED_TAGS: {\ | ||
136 | 54 | GenericBackend.PARAM_TYPE: GenericBackend.TYPE_LIST_OF_STRINGS, \ | ||
137 | 55 | GenericBackend.PARAM_DEFAULT_VALUE: ["@GTG-Tomboy"]}, \ | ||
138 | 56 | } | ||
139 | 57 | |||
140 | 58 | _BUS_ADDRESS = ("org.gnome.Tomboy", | ||
141 | 59 | "/org/gnome/Tomboy/RemoteControl", | ||
142 | 60 | "org.gnome.Tomboy.RemoteControl") | ||
143 | 0 | 61 | ||
144 | === added file 'GTG/backends/generictomboy.py' | |||
145 | --- GTG/backends/generictomboy.py 1970-01-01 00:00:00 +0000 | |||
146 | +++ GTG/backends/generictomboy.py 2010-08-13 23:43:03 +0000 | |||
147 | @@ -0,0 +1,583 @@ | |||
148 | 1 | # -*- coding: utf-8 -*- | ||
149 | 2 | # ----------------------------------------------------------------------------- | ||
150 | 3 | # Getting Things Gnome! - a personal organizer for the GNOME desktop | ||
151 | 4 | # Copyright (c) 2008-2009 - Lionel Dricot & Bertrand Rousseau | ||
152 | 5 | # | ||
153 | 6 | # This program is free software: you can redistribute it and/or modify it under | ||
154 | 7 | # the terms of the GNU General Public License as published by the Free Software | ||
155 | 8 | # Foundation, either version 3 of the License, or (at your option) any later | ||
156 | 9 | # version. | ||
157 | 10 | # | ||
158 | 11 | # This program is distributed in the hope that it will be useful, but WITHOUT | ||
159 | 12 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | ||
160 | 13 | # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more | ||
161 | 14 | # details. | ||
162 | 15 | # | ||
163 | 16 | # You should have received a copy of the GNU General Public License along with | ||
164 | 17 | # this program. If not, see <http://www.gnu.org/licenses/>. | ||
165 | 18 | # ----------------------------------------------------------------------------- | ||
166 | 19 | |||
167 | 20 | ''' | ||
168 | 21 | Contains the Backend class for both Tomboy and Gnote | ||
169 | 22 | ''' | ||
170 | 23 | #Note: To introspect tomboy, execute: | ||
171 | 24 | # qdbus org.gnome.Tomboy /org/gnome/Tomboy/RemoteControl | ||
172 | 25 | |||
173 | 26 | import os | ||
174 | 27 | import re | ||
175 | 28 | import threading | ||
176 | 29 | import uuid | ||
177 | 30 | import dbus | ||
178 | 31 | import datetime | ||
179 | 32 | |||
180 | 33 | from GTG.tools.testingmode import TestingMode | ||
181 | 34 | from GTG.tools.borg import Borg | ||
182 | 35 | from GTG.backends.genericbackend import GenericBackend | ||
183 | 36 | from GTG.backends.backendsignals import BackendSignals | ||
184 | 37 | from GTG.backends.syncengine import SyncEngine, SyncMeme | ||
185 | 38 | from GTG.tools.logger import Log | ||
186 | 39 | from GTG.tools.watchdog import Watchdog | ||
187 | 40 | from GTG.tools.interruptible import interruptible | ||
188 | 41 | |||
189 | 42 | |||
190 | 43 | |||
191 | 44 | class GenericTomboy(GenericBackend): | ||
192 | 45 | '''Backend class for Tomboy/Gnote''' | ||
193 | 46 | |||
194 | 47 | |||
195 | 48 | ############################################################################### | ||
196 | 49 | ### Backend standard methods ################################################## | ||
197 | 50 | ############################################################################### | ||
198 | 51 | |||
199 | 52 | def __init__(self, parameters): | ||
200 | 53 | """ | ||
201 | 54 | See GenericBackend for an explanation of this function. | ||
202 | 55 | """ | ||
203 | 56 | super(GenericTomboy, self).__init__(parameters) | ||
204 | 57 | #loading the saved state of the synchronization, if any | ||
205 | 58 | self.data_path = os.path.join('backends/tomboy/', \ | ||
206 | 59 | "sync_engine-" + self.get_id()) | ||
207 | 60 | self.sync_engine = self._load_pickled_file(self.data_path, \ | ||
208 | 61 | SyncEngine()) | ||
209 | 62 | #if the backend is being tested, we connect to a different DBus | ||
210 | 63 | # interface to avoid clashing with a running instance of Tomboy | ||
211 | 64 | if TestingMode().get_testing_mode(): | ||
212 | 65 | #just used for testing purposes | ||
213 | 66 | self.BUS_ADDRESS = \ | ||
214 | 67 | self._parameters["use this fake connection instead"] | ||
215 | 68 | else: | ||
216 | 69 | self.BUS_ADDRESS = self._BUS_ADDRESS | ||
217 | 70 | #we let some time pass before considering a tomboy task for importing, | ||
218 | 71 | # as the user may still be editing it. Here, we store the Timer objects | ||
219 | 72 | # that will execute after some time after each tomboy signal. | ||
220 | 73 | #NOTE: I'm not sure if this is the case anymore (but it shouldn't hurt | ||
221 | 74 | # anyway). (invernizzi) | ||
222 | 75 | self._tomboy_setting_timers = {} | ||
223 | 76 | |||
224 | 77 | def initialize(self): | ||
225 | 78 | ''' | ||
226 | 79 | See GenericBackend for an explanation of this function. | ||
227 | 80 | Connects to the session bus and sets the callbacks for bus signals | ||
228 | 81 | ''' | ||
229 | 82 | super(GenericTomboy, self).initialize() | ||
230 | 83 | with self.DbusWatchdog(self): | ||
231 | 84 | bus = dbus.SessionBus() | ||
232 | 85 | bus.add_signal_receiver(self.on_note_saved, | ||
233 | 86 | dbus_interface = self.BUS_ADDRESS[2], | ||
234 | 87 | signal_name = "NoteSaved") | ||
235 | 88 | bus.add_signal_receiver(self.on_note_deleted, | ||
236 | 89 | dbus_interface = self.BUS_ADDRESS[2], | ||
237 | 90 | signal_name = "NoteDeleted") | ||
238 | 91 | |||
239 | 92 | @interruptible | ||
240 | 93 | def start_get_tasks(self): | ||
241 | 94 | ''' | ||
242 | 95 | See GenericBackend for an explanation of this function. | ||
243 | 96 | Gets all the notes from Tomboy and sees if they must be added in GTG | ||
244 | 97 | (and, if so, it adds them). | ||
245 | 98 | ''' | ||
246 | 99 | with self.TomboyConnection(self, *self.BUS_ADDRESS) as tomboy: | ||
247 | 100 | with self.DbusWatchdog(self): | ||
248 | 101 | tomboy_notes = [str(note_id) for note_id in \ | ||
249 | 102 | tomboy.ListAllNotes()] | ||
250 | 103 | #adding the new ones | ||
251 | 104 | for note in tomboy_notes: | ||
252 | 105 | self.cancellation_point() | ||
253 | 106 | self._process_tomboy_note(note) | ||
254 | 107 | #checking if some notes have been deleted while GTG was not running | ||
255 | 108 | stored_notes_ids = self.sync_engine.get_all_remote() | ||
256 | 109 | for note in set(stored_notes_ids).difference(set(tomboy_notes)): | ||
257 | 110 | self.on_note_deleted(note, None) | ||
258 | 111 | |||
259 | 112 | def save_state(self): | ||
260 | 113 | '''Saves the state of the synchronization''' | ||
261 | 114 | self._store_pickled_file(self.data_path, self.sync_engine) | ||
262 | 115 | |||
263 | 116 | def quit(self, disable = False): | ||
264 | 117 | ''' | ||
265 | 118 | See GenericBackend for an explanation of this function. | ||
266 | 119 | ''' | ||
267 | 120 | def quit_thread(): | ||
268 | 121 | while True: | ||
269 | 122 | try: | ||
270 | 123 | [key, timer] = \ | ||
271 | 124 | self._tomboy_setting_timers.iteritems().next() | ||
272 | 125 | except StopIteration: | ||
273 | 126 | break | ||
274 | 127 | timer.cancel() | ||
275 | 128 | del self._tomboy_setting_timers[key] | ||
276 | 129 | threading.Thread(target = quit_thread).start() | ||
277 | 130 | super(GenericTomboy, self).quit(disable) | ||
278 | 131 | |||
279 | 132 | ############################################################################### | ||
280 | 133 | ### Something got removed ##################################################### | ||
281 | 134 | ############################################################################### | ||
282 | 135 | |||
283 | 136 | @interruptible | ||
284 | 137 | def on_note_deleted(self, note, something): | ||
285 | 138 | ''' | ||
286 | 139 | Callback, executed when a tomboy note is deleted. | ||
287 | 140 | Deletes the related GTG task. | ||
288 | 141 | |||
289 | 142 | @param note: the id of the Tomboy note | ||
290 | 143 | @param something: not used, here for signal callback compatibility | ||
291 | 144 | ''' | ||
292 | 145 | note = str(note) | ||
293 | 146 | with self.datastore.get_backend_mutex(): | ||
294 | 147 | self.cancellation_point() | ||
295 | 148 | try: | ||
296 | 149 | tid = self.sync_engine.get_local_id(note) | ||
297 | 150 | except KeyError: | ||
298 | 151 | return | ||
299 | 152 | if self.datastore.has_task(tid): | ||
300 | 153 | self.datastore.request_task_deletion(tid) | ||
301 | 154 | self.break_relationship(remote_id = note) | ||
302 | 155 | |||
303 | 156 | @interruptible | ||
304 | 157 | def remove_task(self, tid): | ||
305 | 158 | ''' | ||
306 | 159 | See GenericBackend for an explanation of this function. | ||
307 | 160 | ''' | ||
308 | 161 | with self.datastore.get_backend_mutex(): | ||
309 | 162 | self.cancellation_point() | ||
310 | 163 | try: | ||
311 | 164 | note = self.sync_engine.get_remote_id(tid) | ||
312 | 165 | except KeyError: | ||
313 | 166 | return | ||
314 | 167 | with self.TomboyConnection(self, *self.BUS_ADDRESS) as tomboy: | ||
315 | 168 | with self.DbusWatchdog(self): | ||
316 | 169 | if tomboy.NoteExists(note): | ||
317 | 170 | tomboy.DeleteNote(note) | ||
318 | 171 | self.break_relationship(local_id = tid) | ||
319 | 172 | |||
320 | 173 | def _exec_lost_syncability(self, tid, note): | ||
321 | 174 | ''' | ||
322 | 175 | Executed when a relationship between tasks loses its syncability | ||
323 | 176 | property. See SyncEngine for an explanation of that. | ||
324 | 177 | This function finds out which object (task/note) is the original one | ||
325 | 178 | and which is the copy, and deletes the copy. | ||
326 | 179 | |||
327 | 180 | @param tid: a GTG task tid | ||
328 | 181 | #param note: a tomboy note id | ||
329 | 182 | ''' | ||
330 | 183 | self.cancellation_point() | ||
331 | 184 | meme = self.sync_engine.get_meme_from_remote_id(note) | ||
332 | 185 | #First of all, the relationship is lost | ||
333 | 186 | self.sync_engine.break_relationship(remote_id = note) | ||
334 | 187 | if meme.get_origin() == "GTG": | ||
335 | 188 | with self.TomboyConnection(self, *self.BUS_ADDRESS) as tomboy: | ||
336 | 189 | with self.DbusWatchdog(self): | ||
337 | 190 | tomboy.DeleteNote(note) | ||
338 | 191 | else: | ||
339 | 192 | self.datastore.request_task_deletion(tid) | ||
340 | 193 | |||
341 | 194 | ############################################################################### | ||
342 | 195 | ### Process tasks ############################################################# | ||
343 | 196 | ############################################################################### | ||
344 | 197 | |||
345 | 198 | def _process_tomboy_note(self, note): | ||
346 | 199 | ''' | ||
347 | 200 | Given a tomboy note, finds out if it must be synced to a GTG note and, | ||
348 | 201 | if so, it carries out the synchronization (by creating or updating a GTG | ||
349 | 202 | task, or deleting itself if the related task has been deleted) | ||
350 | 203 | |||
351 | 204 | @param note: a Tomboy note id | ||
352 | 205 | ''' | ||
353 | 206 | with self.datastore.get_backend_mutex(): | ||
354 | 207 | self.cancellation_point() | ||
355 | 208 | is_syncable = self._tomboy_note_is_syncable(note) | ||
356 | 209 | with self.DbusWatchdog(self): | ||
357 | 210 | action, tid = self.sync_engine.analyze_remote_id(note, \ | ||
358 | 211 | self.datastore.has_task, \ | ||
359 | 212 | self._tomboy_note_exists, is_syncable) | ||
360 | 213 | Log.debug("processing tomboy (%s, %s)" % (action, is_syncable)) | ||
361 | 214 | |||
362 | 215 | if action == SyncEngine.ADD: | ||
363 | 216 | tid = str(uuid.uuid4()) | ||
364 | 217 | task = self.datastore.task_factory(tid) | ||
365 | 218 | self._populate_task(task, note) | ||
366 | 219 | self.record_relationship(local_id = tid,\ | ||
367 | 220 | remote_id = note, \ | ||
368 | 221 | meme = SyncMeme(task.get_modified(), | ||
369 | 222 | self.get_modified_for_note(note), | ||
370 | 223 | self.get_id())) | ||
371 | 224 | self.datastore.push_task(task) | ||
372 | 225 | |||
373 | 226 | elif action == SyncEngine.UPDATE: | ||
374 | 227 | task = self.datastore.get_task(tid) | ||
375 | 228 | meme = self.sync_engine.get_meme_from_remote_id(note) | ||
376 | 229 | newest = meme.which_is_newest(task.get_modified(), | ||
377 | 230 | self.get_modified_for_note(note)) | ||
378 | 231 | if newest == "remote": | ||
379 | 232 | self._populate_task(task, note) | ||
380 | 233 | meme.set_local_last_modified(task.get_modified()) | ||
381 | 234 | meme.set_remote_last_modified(\ | ||
382 | 235 | self.get_modified_for_note(note)) | ||
383 | 236 | self.save_state() | ||
384 | 237 | |||
385 | 238 | elif action == SyncEngine.REMOVE: | ||
386 | 239 | with self.TomboyConnection(self, *self.BUS_ADDRESS) as tomboy: | ||
387 | 240 | with self.DbusWatchdog(self): | ||
388 | 241 | tomboy.DeleteNote(note) | ||
389 | 242 | try: | ||
390 | 243 | self.sync_engine.break_relationship(remote_id = note) | ||
391 | 244 | except KeyError: | ||
392 | 245 | pass | ||
393 | 246 | |||
394 | 247 | elif action == SyncEngine.LOST_SYNCABILITY: | ||
395 | 248 | self._exec_lost_syncability(tid, note) | ||
396 | 249 | |||
397 | 250 | @interruptible | ||
398 | 251 | def set_task(self, task): | ||
399 | 252 | ''' | ||
400 | 253 | See GenericBackend for an explanation of this function. | ||
401 | 254 | ''' | ||
402 | 255 | self.cancellation_point() | ||
403 | 256 | is_syncable = self._gtg_task_is_syncable_per_attached_tags(task) | ||
404 | 257 | tid = task.get_id() | ||
405 | 258 | with self.datastore.get_backend_mutex(): | ||
406 | 259 | with self.TomboyConnection(self, *self.BUS_ADDRESS) as tomboy: | ||
407 | 260 | with self.DbusWatchdog(self): | ||
408 | 261 | action, note = self.sync_engine.analyze_local_id(tid, \ | ||
409 | 262 | self.datastore.has_task, tomboy.NoteExists, \ | ||
410 | 263 | is_syncable) | ||
411 | 264 | Log.debug("processing gtg (%s, %d)" % (action, is_syncable)) | ||
412 | 265 | |||
413 | 266 | if action == SyncEngine.ADD: | ||
414 | 267 | #GTG allows multiple tasks with the same name, | ||
415 | 268 | #Tomboy doesn't. we need to handle the renaming | ||
416 | 269 | #manually | ||
417 | 270 | title = task.get_title() | ||
418 | 271 | duplicate_counter = 1 | ||
419 | 272 | with self.DbusWatchdog(self): | ||
420 | 273 | note = str(tomboy.CreateNamedNote(title)) | ||
421 | 274 | while note == "": | ||
422 | 275 | duplicate_counter += 1 | ||
423 | 276 | note = tomboy.CreateNamedNote(title + "(%d)" % | ||
424 | 277 | duplicate_counter) | ||
425 | 278 | if duplicate_counter != 1: | ||
426 | 279 | #if we needed to rename, we have to rename also | ||
427 | 280 | # the gtg task | ||
428 | 281 | task.set_title(title + " (%d)" % duplicate_counter) | ||
429 | 282 | |||
430 | 283 | self._populate_note(note, task) | ||
431 | 284 | self.record_relationship( \ | ||
432 | 285 | local_id = tid, remote_id = note, \ | ||
433 | 286 | meme = SyncMeme(task.get_modified(), | ||
434 | 287 | self.get_modified_for_note(note), | ||
435 | 288 | "GTG")) | ||
436 | 289 | |||
437 | 290 | elif action == SyncEngine.UPDATE: | ||
438 | 291 | meme = self.sync_engine.get_meme_from_local_id(\ | ||
439 | 292 | task.get_id()) | ||
440 | 293 | newest = meme.which_is_newest(task.get_modified(), | ||
441 | 294 | self.get_modified_for_note(note)) | ||
442 | 295 | if newest == "local": | ||
443 | 296 | self._populate_note(note, task) | ||
444 | 297 | meme.set_local_last_modified(task.get_modified()) | ||
445 | 298 | meme.set_remote_last_modified(\ | ||
446 | 299 | self.get_modified_for_note(note)) | ||
447 | 300 | self.save_state() | ||
448 | 301 | |||
449 | 302 | elif action == SyncEngine.REMOVE: | ||
450 | 303 | self.datastore.request_task_deletion(tid) | ||
451 | 304 | try: | ||
452 | 305 | self.sync_engine.break_relationship(local_id = tid) | ||
453 | 306 | self.save_state() | ||
454 | 307 | except KeyError: | ||
455 | 308 | pass | ||
456 | 309 | |||
457 | 310 | elif action == SyncEngine.LOST_SYNCABILITY: | ||
458 | 311 | self._exec_lost_syncability(tid, note) | ||
459 | 312 | |||
460 | 313 | ############################################################################### | ||
461 | 314 | ### Helper methods ############################################################ | ||
462 | 315 | ############################################################################### | ||
463 | 316 | |||
464 | 317 | @interruptible | ||
465 | 318 | def on_note_saved(self, note): | ||
466 | 319 | ''' | ||
467 | 320 | Callback, executed when a tomboy note is saved by Tomboy itself. | ||
468 | 321 | Updates the related GTG task (or creates one, if necessary). | ||
469 | 322 | |||
470 | 323 | @param note: the id of the Tomboy note | ||
471 | 324 | ''' | ||
472 | 325 | note = str(note) | ||
473 | 326 | self.cancellation_point() | ||
474 | 327 | #NOTE: we let some seconds pass before executing the real callback, as | ||
475 | 328 | # the editing of the Tomboy note may still be in progress | ||
476 | 329 | @interruptible | ||
477 | 330 | def _execute_on_note_saved(self, note): | ||
478 | 331 | self.cancellation_point() | ||
479 | 332 | try: | ||
480 | 333 | del self._tomboy_setting_timers[note] | ||
481 | 334 | except: | ||
482 | 335 | pass | ||
483 | 336 | self._process_tomboy_note(note) | ||
484 | 337 | self.save_state() | ||
485 | 338 | |||
486 | 339 | try: | ||
487 | 340 | self._tomboy_setting_timers[note].cancel() | ||
488 | 341 | except KeyError: | ||
489 | 342 | pass | ||
490 | 343 | finally: | ||
491 | 344 | timer =threading.Timer(5, _execute_on_note_saved, | ||
492 | 345 | args = (self, note)) | ||
493 | 346 | self._tomboy_setting_timers[note] = timer | ||
494 | 347 | timer.start() | ||
495 | 348 | |||
496 | 349 | def _tomboy_note_is_syncable(self, note): | ||
497 | 350 | ''' | ||
498 | 351 | Returns True if this tomboy note should be synced into GTG tasks. | ||
499 | 352 | |||
500 | 353 | @param note: the note id | ||
501 | 354 | @returns Boolean | ||
502 | 355 | ''' | ||
503 | 356 | attached_tags = self.get_attached_tags() | ||
504 | 357 | if GenericBackend.ALLTASKS_TAG in attached_tags: | ||
505 | 358 | return True | ||
506 | 359 | with self.TomboyConnection(self, *self.BUS_ADDRESS) as tomboy: | ||
507 | 360 | with self.DbusWatchdog(self): | ||
508 | 361 | content = tomboy.GetNoteContents(note) | ||
509 | 362 | syncable = False | ||
510 | 363 | for tag in attached_tags: | ||
511 | 364 | try: | ||
512 | 365 | content.index(tag) | ||
513 | 366 | syncable = True | ||
514 | 367 | break | ||
515 | 368 | except ValueError: | ||
516 | 369 | pass | ||
517 | 370 | return syncable | ||
518 | 371 | |||
519 | 372 | def _tomboy_note_exists(self, note): | ||
520 | 373 | ''' | ||
521 | 374 | Returns True if a tomboy note exists with the given id. | ||
522 | 375 | |||
523 | 376 | @param note: the note id | ||
524 | 377 | @returns Boolean | ||
525 | 378 | ''' | ||
526 | 379 | with self.TomboyConnection(self, *self.BUS_ADDRESS) as tomboy: | ||
527 | 380 | with self.DbusWatchdog(self): | ||
528 | 381 | return tomboy.NoteExists(note) | ||
529 | 382 | |||
530 | 383 | def get_modified_for_note(self, note): | ||
531 | 384 | ''' | ||
532 | 385 | Returns the modification time for the given note id. | ||
533 | 386 | |||
534 | 387 | @param note: the note id | ||
535 | 388 | @returns datetime.datetime | ||
536 | 389 | ''' | ||
537 | 390 | with self.TomboyConnection(self, *self.BUS_ADDRESS) as tomboy: | ||
538 | 391 | with self.DbusWatchdog(self): | ||
539 | 392 | return datetime.datetime.fromtimestamp( \ | ||
540 | 393 | tomboy.GetNoteChangeDate(note)) | ||
541 | 394 | |||
542 | 395 | def _tomboy_split_title_and_text(self, content): | ||
543 | 396 | ''' | ||
544 | 397 | Tomboy does not have a "getTitle" and "getText" functions to get the | ||
545 | 398 | title and the text of a note separately. Instead, it has a getContent | ||
546 | 399 | function, that returns both of them. | ||
547 | 400 | This function splits up the output of getContent into a title string and | ||
548 | 401 | a text string. | ||
549 | 402 | |||
550 | 403 | @param content: a string, the result of a getContent call | ||
551 | 404 | @returns list: a list composed by [title, text] | ||
552 | 405 | ''' | ||
553 | 406 | try: | ||
554 | 407 | end_of_title = content.index('\n') | ||
555 | 408 | except ValueError: | ||
556 | 409 | return content, "" | ||
557 | 410 | title = content[: end_of_title] | ||
558 | 411 | if len(content) > end_of_title: | ||
559 | 412 | return title, content[end_of_title +1 :] | ||
560 | 413 | else: | ||
561 | 414 | return title, "" | ||
562 | 415 | |||
563 | 416 | def _populate_task(self, task, note): | ||
564 | 417 | ''' | ||
565 | 418 | Copies the content of a Tomboy note into a task. | ||
566 | 419 | |||
567 | 420 | @param task: a GTG Task | ||
568 | 421 | @param note: a Tomboy note | ||
569 | 422 | ''' | ||
570 | 423 | #add tags objects (it's not enough to have @tag in the text to add a | ||
571 | 424 | # tag | ||
572 | 425 | with self.TomboyConnection(self, *self.BUS_ADDRESS) as tomboy: | ||
573 | 426 | with self.DbusWatchdog(self): | ||
574 | 427 | content = tomboy.GetNoteContents(note) | ||
575 | 428 | #update the tags list | ||
576 | 429 | matches = re.finditer("(?<![^|\s])(@\w+)", content) | ||
577 | 430 | new_tags_list = [content[g.start() : g.end()] for g in matches] | ||
578 | 431 | for tag in task.get_tags_name(): | ||
579 | 432 | try: | ||
580 | 433 | new_tags_list.remove(tag) | ||
581 | 434 | task.remove_tag(tag) | ||
582 | 435 | except: | ||
583 | 436 | task.add_tag(tag) | ||
584 | 437 | for tag in new_tags_list: | ||
585 | 438 | task.add_tag(tag) | ||
586 | 439 | #extract title and text | ||
587 | 440 | [title, text] = self._tomboy_split_title_and_text(content) | ||
588 | 441 | task.set_title(title) | ||
589 | 442 | task.set_text(text) | ||
590 | 443 | task.add_remote_id(self.get_id(), note) | ||
591 | 444 | |||
592 | 445 | def _populate_note(self, note, task): | ||
593 | 446 | ''' | ||
594 | 447 | Copies the content of a task into a Tomboy note. | ||
595 | 448 | |||
596 | 449 | @param note: a Tomboy note | ||
597 | 450 | @param task: a GTG Task | ||
598 | 451 | ''' | ||
599 | 452 | title = task.get_title() | ||
600 | 453 | tested_title = title | ||
601 | 454 | duplicate_counter = 1 | ||
602 | 455 | with self.TomboyConnection(self, *self.BUS_ADDRESS) as tomboy: | ||
603 | 456 | with self.DbusWatchdog(self): | ||
604 | 457 | tomboy.SetNoteContents(note, title + '\n' + \ | ||
605 | 458 | task.get_excerpt(strip_tags = False)) | ||
606 | 459 | |||
607 | 460 | def break_relationship(self, *args, **kwargs): | ||
608 | 461 | ''' | ||
609 | 462 | Proxy method for SyncEngine.break_relationship, which also saves the | ||
610 | 463 | state of the synchronization. | ||
611 | 464 | ''' | ||
612 | 465 | try: | ||
613 | 466 | self.sync_engine.break_relationship(*args, **kwargs) | ||
614 | 467 | #we try to save the state at each change in the sync_engine: | ||
615 | 468 | #it's slower, but it should avoid widespread task | ||
616 | 469 | #duplication | ||
617 | 470 | self.save_state() | ||
618 | 471 | except KeyError: | ||
619 | 472 | pass | ||
620 | 473 | |||
621 | 474 | def record_relationship(self, *args, **kwargs): | ||
622 | 475 | ''' | ||
623 | 476 | Proxy method for SyncEngine.break_relationship, which also saves the | ||
624 | 477 | state of the synchronization. | ||
625 | 478 | ''' | ||
626 | 479 | self.sync_engine.record_relationship(*args, **kwargs) | ||
627 | 480 | #we try to save the state at each change in the sync_engine: | ||
628 | 481 | #it's slower, but it should avoid widespread task | ||
629 | 482 | #duplication | ||
630 | 483 | self.save_state() | ||
631 | 484 | |||
632 | 485 | ############################################################################### | ||
633 | 486 | ### Connection handling ####################################################### | ||
634 | 487 | ############################################################################### | ||
635 | 488 | |||
636 | 489 | |||
637 | 490 | |||
638 | 491 | class TomboyConnection(Borg): | ||
639 | 492 | ''' | ||
640 | 493 | TomboyConnection creates a connection to TOMBOY via DBUS and | ||
641 | 494 | handles all the possible exceptions. | ||
642 | 495 | It is a class that can be used with a with statement. | ||
643 | 496 | Example: | ||
644 | 497 | with self.TomboyConnection(self, *self.BUS_ADDRESS) as tomboy: | ||
645 | 498 | #do something | ||
646 | 499 | ''' | ||
647 | 500 | |||
648 | 501 | |||
649 | 502 | def __init__(self, backend, bus_name, bus_path, bus_interface): | ||
650 | 503 | ''' | ||
651 | 504 | Sees if a TomboyConnection object already exists. If so, since we | ||
652 | 505 | are inheriting from a Borg object, the initialization already took | ||
653 | 506 | place. | ||
654 | 507 | If not, it tries to connect to Tomboy via Dbus. If the connection | ||
655 | 508 | is not possible, the user is notified about it. | ||
656 | 509 | |||
657 | 510 | @param backend: a reference to a Backend | ||
658 | 511 | @param bus_name: the DBUS address of Tomboy | ||
659 | 512 | @param bus_path: the DBUS path of Tomboy RemoteControl | ||
660 | 513 | @param bus_interface: the DBUS address of Tomboy RemoteControl | ||
661 | 514 | ''' | ||
662 | 515 | super(GenericTomboy.TomboyConnection, self).__init__() | ||
663 | 516 | if hasattr(self, "tomboy_connection_is_ok") and \ | ||
664 | 517 | self.tomboy_connection_is_ok: | ||
665 | 518 | return | ||
666 | 519 | self.backend = backend | ||
667 | 520 | with GenericTomboy.DbusWatchdog(backend): | ||
668 | 521 | bus = dbus.SessionBus() | ||
669 | 522 | obj = bus.get_object(bus_name, bus_path) | ||
670 | 523 | self.tomboy = dbus.Interface(obj, bus_interface) | ||
671 | 524 | self.tomboy_connection_is_ok = True | ||
672 | 525 | |||
673 | 526 | def __enter__(self): | ||
674 | 527 | ''' | ||
675 | 528 | Returns the Tomboy connection | ||
676 | 529 | |||
677 | 530 | @returns dbus.Interface | ||
678 | 531 | ''' | ||
679 | 532 | return self.tomboy | ||
680 | 533 | |||
681 | 534 | def __exit__(self, exception_type, value, traceback): | ||
682 | 535 | ''' | ||
683 | 536 | Checks the state of the connection. | ||
684 | 537 | If something went wrong for the connection, notifies the user. | ||
685 | 538 | |||
686 | 539 | @param exception_type: the type of exception that occurred, or | ||
687 | 540 | None | ||
688 | 541 | @param value: the instance of the exception occurred, or None | ||
689 | 542 | @param traceback: the traceback of the error | ||
690 | 543 | @returns: False if some exception must be re-raised. | ||
691 | 544 | ''' | ||
692 | 545 | if isinstance(value, dbus.DBusException): | ||
693 | 546 | self.tomboy_connection_is_ok = False | ||
694 | 547 | self.backend.quit(disable = True) | ||
695 | 548 | BackendSignals().backend_failed(self.backend.get_id(), \ | ||
696 | 549 | BackendSignals.ERRNO_DBUS) | ||
697 | 550 | else: | ||
698 | 551 | return False | ||
699 | 552 | return True | ||
700 | 553 | |||
701 | 554 | |||
702 | 555 | |||
703 | 556 | class DbusWatchdog(Watchdog): | ||
704 | 557 | ''' | ||
705 | 558 | A simple watchdog to detect stale dbus connections | ||
706 | 559 | ''' | ||
707 | 560 | |||
708 | 561 | |||
709 | 562 | def __init__(self, backend): | ||
710 | 563 | ''' | ||
711 | 564 | Simple constructor, which sets _when_taking_too_long as the function | ||
712 | 565 | to run when the connection is taking too long. | ||
713 | 566 | |||
714 | 567 | @param backend: a Backend object | ||
715 | 568 | ''' | ||
716 | 569 | self.backend = backend | ||
717 | 570 | super(GenericTomboy.DbusWatchdog, self).__init__(3, \ | ||
718 | 571 | self._when_taking_too_long) | ||
719 | 572 | |||
720 | 573 | def _when_taking_too_long(self): | ||
721 | 574 | ''' | ||
722 | 575 | Function that is executed when the Dbus connection seems to be | ||
723 | 576 | hanging. It disables the backend and signals the error to the user. | ||
724 | 577 | ''' | ||
725 | 578 | Log.error("Dbus connection is taking too long for the Tomboy/Gnote" | ||
726 | 579 | "backend!") | ||
727 | 580 | self.backend.quit(disable = True) | ||
728 | 581 | BackendSignals().backend_failed(self.backend.get_id(), \ | ||
729 | 582 | BackendSignals.ERRNO_DBUS) | ||
730 | 583 | |||
731 | 0 | 584 | ||
732 | === modified file 'GTG/gtk/browser/browser.py' | |||
733 | --- GTG/gtk/browser/browser.py 2010-08-10 17:30:24 +0000 | |||
734 | +++ GTG/gtk/browser/browser.py 2010-08-13 23:43:03 +0000 | |||
735 | @@ -953,7 +953,9 @@ | |||
736 | 953 | text = \ | 953 | text = \ |
737 | 954 | text.replace("%s%s:%s" % (spaces, attribute, args), "") | 954 | text.replace("%s%s:%s" % (spaces, attribute, args), "") |
738 | 955 | # Create the new task | 955 | # Create the new task |
740 | 956 | task = self.req.new_task(tags=[t.get_name() for t in tags], newtask=True) | 956 | task = self.req.new_task( newtask=True) |
741 | 957 | for tag in tags: | ||
742 | 958 | task.add_tag(tag.get_name()) | ||
743 | 957 | if text != "": | 959 | if text != "": |
744 | 958 | task.set_title(text.strip()) | 960 | task.set_title(text.strip()) |
745 | 959 | task.set_to_keep() | 961 | task.set_to_keep() |
746 | 960 | 962 | ||
747 | === added file 'data/icons/hicolor/scalable/apps/backend_gnote.png' | |||
748 | 961 | Binary files data/icons/hicolor/scalable/apps/backend_gnote.png 1970-01-01 00:00:00 +0000 and data/icons/hicolor/scalable/apps/backend_gnote.png 2010-08-13 23:43:03 +0000 differ | 963 | Binary files data/icons/hicolor/scalable/apps/backend_gnote.png 1970-01-01 00:00:00 +0000 and data/icons/hicolor/scalable/apps/backend_gnote.png 2010-08-13 23:43:03 +0000 differ |
749 | === added file 'data/icons/hicolor/scalable/apps/backend_tomboy.png' | |||
750 | 962 | Binary files data/icons/hicolor/scalable/apps/backend_tomboy.png 1970-01-01 00:00:00 +0000 and data/icons/hicolor/scalable/apps/backend_tomboy.png 2010-08-13 23:43:03 +0000 differ | 964 | Binary files data/icons/hicolor/scalable/apps/backend_tomboy.png 1970-01-01 00:00:00 +0000 and data/icons/hicolor/scalable/apps/backend_tomboy.png 2010-08-13 23:43:03 +0000 differ |
Not touching anything in GTG so, obviously, you can merge it. Very good work !