GTG

Merge lp:~huxuan/gtg/port-to-configparser into lp:~gtg/gtg/old-trunk

Proposed by Xuan (Sean) Hu
Status: Merged
Merged at revision: 1307
Proposed branch: lp:~huxuan/gtg/port-to-configparser
Merge into: lp:~gtg/gtg/old-trunk
Diff against target: 935 lines (+314/-257)
21 files modified
GTG/backends/genericbackend.py (+1/-1)
GTG/core/__init__.py (+127/-77)
GTG/core/plugins/engine.py (+20/-13)
GTG/gtk/browser/browser.py (+4/-0)
GTG/gtk/browser/tag_editor.py (+2/-3)
GTG/gtk/editor/editor.py (+12/-12)
GTG/gtk/manager.py (+20/-16)
GTG/gtk/plugins.py (+17/-20)
GTG/plugins/bugzilla.gtg-plugin (+11/-11)
GTG/plugins/export.gtg-plugin (+10/-10)
GTG/plugins/geolocalized-tasks.gtg-plugin (+9/-9)
GTG/plugins/hamster.gtg-plugin (+9/-9)
GTG/plugins/not-today.gtg-plugin (+8/-8)
GTG/plugins/notification-area.gtg-plugin (+10/-10)
GTG/plugins/send-email.gtg-plugin (+9/-9)
GTG/plugins/task-reaper.gtg-plugin (+11/-11)
GTG/plugins/tomboy.gtg-plugin (+10/-11)
GTG/plugins/untouched-tasks.gtg-plugin (+8/-8)
GTG/plugins/urgency-color.gtg-plugin (+14/-15)
GTG/tests/test_backends.py (+1/-1)
README (+1/-3)
To merge this branch: bzr merge lp:~huxuan/gtg/port-to-configparser
Reviewer Review Type Date Requested Status
Izidor Matušov Approve
Review via email: mp+180681@code.launchpad.net

Description of the change

Port from configobj to ConfigParser
Cause configobj do not have an python3 port
It should be better to use official module instead third party one.

To post a comment you must log in.
lp:~huxuan/gtg/port-to-configparser updated
1321. By Xuan (Sean) Hu

Remove configobj related description in README

Revision history for this message
Izidor Matušov (izidor) wrote :

The code looks good (no obvious issues there). I found couple of regressions. With the following data in tmp/ folder, GTG burns 100% of CPU. It might be caused by trying to open an nonexisting tasks (however, it shouldn't):

https://www.dropbox.com/s/589ojjkz7qsk8bf/test-config.zip

It might be because of bad serialization of lists. You don't do it the same way as we were discussing it before. You generate

opened_tasks = ["'8@1'", " '1@1'", " '6@1'", " '4@1'", '7@1']

instead of previous

opened_tasks = 8@1,1@1,6@1,4@1,7@1

Please, fix it.

review: Needs Fixing
lp:~huxuan/gtg/port-to-configparser updated
1322. By Xuan (Sean) Hu

fix opened_tasks bug

1323. By Xuan (Sean) Hu

Make SubConfig.set_list more elegent

1324. By Xuan (Sean) Hu

Make collapsed_tasks, expanded_tags actually work

1325. By Xuan (Sean) Hu

Bug fix for SubConfig.get list value

1326. By Xuan (Sean) Hu

custom_colors config should works fine now

1327. By Xuan (Sean) Hu

plugin enabled/disabled config should works fine now

Revision history for this message
Xuan (Sean) Hu (huxuan) wrote :

Hi, izidor, Thx for your code review.

The problem is caused by the native support for list as value for configuration in configobj, but ConfigParser make them all string. I tried to make all the list configuration to be save as '.'.join(list) pattern string and I am not sure whether it will cause more problems which I have ignored except for the collapsed_tasks, expanded_tags, custom_colors etc.

If you find any more problems, feel free to tell me. :-)

lp:~huxuan/gtg/port-to-configparser updated
1328. By Xuan (Sean) Hu

Combine SubConfig.set/set_list

Revision history for this message
Izidor Matušov (izidor) wrote :

It works now for me. Another really important thing to consider is the backwards compatibility. Please, make sure that you can read the same config files as the old config parser.

Steps to reproduce bug:

1, Open GTG with old config parser
2, Open windows, change width of tag sidebar and other configuration
3, Quit GTG (CTRL + Q)
4, Copy tmp/ to GTG with the new parser
5, Launch it without any problem

I get the following tracebacks:

Traceback (most recent call last):
  File "/home/izidor/projects/gtg/trunk/GTG/gtk/browser/browser.py", line 671, in on_sidebar_toggled
    self.init_tags_sidebar()
  File "/home/izidor/projects/gtg/trunk/GTG/gtk/browser/browser.py", line 221, in init_tags_sidebar
    self.tagtreeview.expand_node(path)
  File "/usr/lib/python2.7/dist-packages/liblarch_gtk/__init__.py", line 227, in expand_node
    self.collapse_node(llpath,collapsing_method=self.expand_one_row)
  File "/usr/lib/python2.7/dist-packages/liblarch_gtk/__init__.py", line 246, in collapse_node
    node_id = llpath[-1].strip("'")
IndexError: tuple index out of range
Traceback (most recent call last):
  File "./gtg", line 89, in <module>
    main()
  File "./gtg", line 85, in main
    sys.exit(gtg.main(options, args))
  File "/home/izidor/projects/gtg/trunk/GTG/gtg.py", line 123, in main
    manager = Manager(req)
  File "/home/izidor/projects/gtg/trunk/GTG/gtk/manager.py", line 75, in __init__
    self.browser = TaskBrowser(self.req, self)
  File "/home/izidor/projects/gtg/trunk/GTG/gtk/browser/browser.py", line 125, in __init__
    self.restore_state_from_conf()
  File "/home/izidor/projects/gtg/trunk/GTG/gtk/browser/browser.py", line 521, in restore_state_from_conf
    self.vtree_panes['active'].collapse_node(path)
  File "/usr/lib/python2.7/dist-packages/liblarch_gtk/__init__.py", line 246, in collapse_node
    node_id = llpath[-1].strip("'")
IndexError: tuple index out of range

Old gtg.conf file:
[browser]
contents_preview_enable = False
bg_color_enable = True
width = 425
height = 400
max = False
x_pos = 458
y_pos = 188
tag_pane = True
sidebar_width = 151
closed_task_pane = False
bottom_pane_position = 300
toolbar = True
quick_add = True
tasklist_sort_column = 5
tasklist_sort_order = 1
collapsed_tasks = ,
view = default
opened_tasks = 0@1, 5@1
font_name =
expanded_tags = ,

[plugins]
disabled = not_today, tomboy, notification_area, task_reaper, send_email, bugzilla, export, hamster, geolocalized_tasks, urgency_color, untouched_tasks
enabled = ,

review: Needs Fixing
lp:~huxuan/gtg/port-to-configparser updated
1329. By Xuan (Sean) Hu

Bug fix for backwards compatibility

Revision history for this message
Xuan (Sean) Hu (huxuan) wrote :

Sorry for the silly error, I do have noticed it but forget to fix it. It should work now. If there is any more problems, feel free to tell me. :-)

lp:~huxuan/gtg/port-to-configparser updated
1330. By Xuan (Sean) Hu

bug fix, mostly related to TaskConfig

Revision history for this message
Xuan (Sean) Hu (huxuan) wrote :

Hi, Izidor

Is there still any bugs about this ConfigParser port? I think I should continue python3 versin of GTG port based on this merge.

Revision history for this message
Izidor Matušov (izidor) wrote :

It looks good now :)

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'GTG/backends/genericbackend.py'
2--- GTG/backends/genericbackend.py 2013-02-25 08:12:02 +0000
3+++ GTG/backends/genericbackend.py 2013-08-25 20:11:23 +0000
4@@ -205,7 +205,7 @@
5 # NOTE: for now I'm disabling changing the default backend. Once it's all
6 # set up, we will see about that (invernizzi)
7 KEY_DEFAULT_BACKEND = "Default"
8- KEY_ENABLED = "Enabled"
9+ KEY_ENABLED = "enabled"
10 KEY_HUMAN_NAME = BACKEND_HUMAN_NAME
11 KEY_ATTACHED_TAGS = "attached-tags"
12 KEY_USER = "user"
13
14=== modified file 'GTG/core/__init__.py'
15--- GTG/core/__init__.py 2013-02-25 07:35:07 +0000
16+++ GTG/core/__init__.py 2013-08-25 20:11:23 +0000
17@@ -36,7 +36,7 @@
18 """
19
20 #=== IMPORT ===================================================================
21-from configobj import ConfigObj, ConfigObjError
22+import ConfigParser
23 from xdg.BaseDirectory import xdg_data_home, xdg_config_home, xdg_data_dirs
24 import os
25
26@@ -46,36 +46,40 @@
27
28 DEFAULTS = {
29 'browser': {
30- "bg_color_enable": True,
31- "contents_preview_enable": False,
32- 'tag_pane': False,
33- "sidebar_width": 120,
34- "closed_task_pane": False,
35- 'bottom_pane_position': 300,
36- 'toolbar': True,
37- 'quick_add': True,
38- 'collapsed_tasks': [],
39- 'expanded_tags': [],
40- 'view': 'default',
41- "opened_tasks": [],
42- 'width': 400,
43- 'height': 400,
44- 'max': False,
45- 'x_pos': 10,
46- 'y_pos': 10,
47- 'tasklist_sort_column': 5,
48- 'tasklist_sort_order': 1,
49- "font_name": "",
50- },
51-'tag_editor': {
52- "custom_colors": [],
53-}
54-}
55-
56-
57-# Instead of accessing directly the ConfigObj dic, each module will have
58+ "bg_color_enable": True,
59+ "contents_preview_enable": False,
60+ 'tag_pane': False,
61+ "sidebar_width": 120,
62+ "closed_task_pane": False,
63+ 'bottom_pane_position': 300,
64+ 'toolbar': True,
65+ 'quick_add': True,
66+ 'collapsed_tasks': [],
67+ 'expanded_tags': [],
68+ 'view': 'default',
69+ "opened_tasks": [],
70+ 'width': 400,
71+ 'height': 400,
72+ 'max': False,
73+ 'x_pos': 10,
74+ 'y_pos': 10,
75+ 'tasklist_sort_column': 5,
76+ 'tasklist_sort_order': 1,
77+ "font_name": "",
78+ },
79+ 'tag_editor': {
80+ "custom_colors": [],
81+ },
82+ 'plugins': {
83+ "enabled": [],
84+ "disabled": [],
85+ }
86+}
87+
88+
89+# Instead of accessing directly the ConfigParser, each module will have
90 # one SubConfig object. (one SubConfig object always match one first level
91-# element of the ConfigObj directory)
92+# element of the ConfigParser directory)
93 #
94 # The goal of the SubConfig object is to handle default value and converting
95 # String to Bool and Int when needed.
96@@ -88,47 +92,88 @@
97
98 class SubConfig():
99
100- def __init__(self, name, conf_dic):
101- self.__name = name
102- self.__conf = conf_dic
103- if name in DEFAULTS:
104- self.__defaults = DEFAULTS[name]
105- else:
106- self.__defaults = {}
107+ def __init__(self, section, conf, conf_path):
108+ self._section = section
109+ self._conf = conf
110+ self._conf_path = conf_path
111
112 # This return the value of the setting (or the default one)
113 #
114 # If a default value exists and is a Int or a Bool, the returned
115 # value is converted to that type.
116- def get(self, name):
117- if name in self.__conf:
118- toreturn = self.__conf[name]
119+ def get(self, option):
120+ if self._conf.has_option(self._section, option):
121+ toreturn = self._conf.get(self._section, option)
122 # Converting to the good type
123- if name in self.__defaults:
124- ntype = type(self.__defaults[name])
125+ if option in DEFAULTS[self._section]:
126+ ntype = type(DEFAULTS[self._section][option])
127 if ntype == int:
128 toreturn = int(toreturn)
129+ elif ntype == list:
130+ # All list config should be saved in ','.join(list) pattern
131+ # This is just for backward compatibility
132+ if toreturn and toreturn[0] == '[' and toreturn[-1] == ']':
133+ toreturn = toreturn[1:-1]
134+ toreturn = toreturn.split(',')
135+ while toreturn and toreturn[-1] == '':
136+ toreturn = toreturn[:-1]
137 elif ntype == bool and type(toreturn) == str:
138 toreturn = toreturn.lower() == "true"
139- elif name in self.__defaults:
140- toreturn = self.__defaults[name]
141- self.__conf[name] = toreturn
142+ elif option in DEFAULTS[self._section]:
143+ toreturn = DEFAULTS[self._section][option]
144+ self.set(option, toreturn)
145 else:
146 print "Warning : no default conf value for %s in %s" % (
147- name, self.__name)
148+ option, self._section)
149 toreturn = None
150 return toreturn
151
152- def set(self, name, value):
153- self.__conf[name] = str(value)
154- # Save immediately
155- self.__conf.parent.write()
156-
157- def set_lst(self, name, value_lst):
158- self.__conf[name] = [str(s) for s in value_lst]
159- # Save immediately
160- self.__conf.parent.write()
161-
162+ def clear(self):
163+ for option in self._conf.options(self._section):
164+ self._conf.remove_option(self._section, option)
165+
166+ def save(self):
167+ self._conf.write(open(self._conf_path, 'w'))
168+
169+ def set(self, option, value):
170+ if type(value) == list:
171+ value = ','.join(value)
172+ self._conf.set(self._section, option, str(value))
173+ # Save immediately
174+ self.save()
175+
176+class TaskConfig():
177+ """ TaskConfig is used to save the position and size of each task, both of
178+ value are one tuple with two numbers, so set and get will use join and split
179+ """
180+
181+ def __init__(self, conf, conf_path):
182+ self._conf = conf
183+ self._conf_path = conf_path
184+
185+ def has_section(self, section):
186+ return self._conf.has_section(section)
187+
188+ def has_option(self, section, option):
189+ return self._conf.has_option(section, option)
190+
191+ def add_section(self, section):
192+ self._conf.add_section(section)
193+
194+ def get(self, tid, option):
195+ value = self._conf.get(tid, option)
196+ # Check single quote for backward compatibility
197+ if value[0] == '(' and value[-1] == ')':
198+ value = value[1:-1]
199+ return value.split(', ')
200+
201+ def set(self, tid, option, value):
202+ value = ','.join(str(x) for x in value)
203+ self._conf.set(tid, option, value)
204+ self.save()
205+
206+ def save(self):
207+ self._conf.write(open(self._conf_path, 'w'))
208
209 class CoreConfig(Borg):
210 # The projects and tasks are of course DATA !
211@@ -147,15 +192,14 @@
212 SEP_TAG = "gtg-tags-sep"
213 SEARCH_TAG = "search"
214
215- def check_config_file(self, file_path):
216+ def check_config_file(self, path):
217 """ This function bypasses the errors of config file and allows GTG
218 to open smoothly"""
219- total_path = self.conf_dir + file_path
220+ config = ConfigParser.ConfigParser()
221 try:
222- config = ConfigObj(total_path)
223- except ConfigObjError:
224- open(total_path, "w").close()
225- config = ConfigObj(total_path)
226+ config.read(path)
227+ except ConfigParser.Error:
228+ open(path, "w").close()
229 return config
230
231 def __init__(self):
232@@ -173,28 +217,32 @@
233 os.makedirs(self.conf_dir)
234 if not os.path.exists(self.data_dir):
235 os.makedirs(self.data_dir)
236- if not os.path.exists(self.conf_dir + self.CONF_FILE):
237- open(self.conf_dir + self.CONF_FILE, "w").close()
238- if not os.path.exists(self.conf_dir + self.TASK_CONF_FILE):
239- open(self.conf_dir + self.TASK_CONF_FILE, "w").close()
240- for conf_file in [self.conf_dir + self.CONF_FILE,
241- self.conf_dir + self.TASK_CONF_FILE]:
242+ self.conf_path = os.path.join(self.conf_dir, self.CONF_FILE)
243+ self.task_conf_path = os.path.join(self.conf_dir, self.TASK_CONF_FILE)
244+ if not os.path.exists(self.conf_path):
245+ open(self.conf_path, "w").close()
246+ if not os.path.exists(self.task_conf_path):
247+ open(self.task_conf_path, "w").close()
248+ for conf_file in [self.conf_path, self.task_conf_path]:
249 if not os.access(conf_file, os.R_OK | os.W_OK):
250 raise Exception("File " + file +
251 " is a configuration file for gtg, but it "
252 "cannot be read or written. Please check it")
253- self.conf_dict = self.check_config_file(self.CONF_FILE)
254- self.task_conf_dict = self.check_config_file(self.TASK_CONF_FILE)
255+ self._conf = self.check_config_file(self.conf_path)
256+ self._task_conf = self.check_config_file(self.task_conf_path)
257
258 def save(self):
259 ''' Saves the configuration of CoreConfig '''
260- self.conf_dict.write()
261- self.task_conf_dict.write()
262-
263- def get_subconfig(self, name):
264- if not name in self.conf_dict:
265- self.conf_dict[name] = {}
266- return SubConfig(name, self.conf_dict[name])
267+ self._conf.write(open(self.conf_path, 'w'))
268+ self._task_conf.write(open(self.task_conf_path, 'w'))
269+
270+ def get_subconfig(self, section):
271+ if not self._conf.has_section(section):
272+ self._conf.add_section(section)
273+ return SubConfig(section, self._conf, self.conf_path)
274+
275+ def get_taskconfig(self):
276+ return TaskConfig(self._task_conf, self.task_conf_path)
277
278 def get_icons_directories(self):
279 """ Returns the directories containing the icons """
280@@ -214,3 +262,5 @@
281
282 def set_conf_dir(self, path):
283 self.conf_dir = path
284+ self.conf_path = os.path.join(self.conf_dir, self.CONF_FILE)
285+ self.task_conf_path = os.path.join(self.conf_dir, self.TASK_CONF_FILE)
286
287=== modified file 'GTG/core/plugins/engine.py'
288--- GTG/core/plugins/engine.py 2013-02-25 07:35:07 +0000
289+++ GTG/core/plugins/engine.py 2013-08-25 20:11:23 +0000
290@@ -19,8 +19,8 @@
291 import imp
292 import os
293 import types
294+import ConfigParser
295
296-from configobj import ConfigObj
297 import dbus
298
299 from GTG.tools.borg import Borg
300@@ -42,16 +42,16 @@
301 missing_dbus = []
302
303 def __init__(self, info, module_path):
304- """Initialize the Plugin using a ConfigObj."""
305+ """Initialize the Plugin using a ConfigParser."""
306 info_fields = {
307- 'module_name': 'Module',
308- 'full_name': 'Name',
309- 'version': 'Version',
310- 'authors': 'Authors',
311- 'short_description': 'Short-description',
312- 'description': 'Description',
313- 'module_depends': 'Dependencies',
314- 'dbus_depends': 'Dbus-dependencies',
315+ 'module_name': 'module',
316+ 'full_name': 'name',
317+ 'version': 'version',
318+ 'authors': 'authors',
319+ 'short_description': 'short-description',
320+ 'description': 'description',
321+ 'module_depends': 'dependencies',
322+ 'dbus_depends': 'dbus-dependencies',
323 }
324 for attr, field in info_fields.iteritems():
325 try:
326@@ -59,7 +59,12 @@
327 except KeyError:
328 setattr(self, attr, [])
329 # turn the enabled attribute into a bool
330- self.enabled = info['Enabled'].lower() == "true"
331+ self.enabled = info['enabled'].lower() == "true"
332+ # ensure the module dependencies are a list
333+ if isinstance(self.module_depends, str):
334+ self.module_depends = self.module_depends.split(',')
335+ if not self.module_depends[-1]:
336+ self.module_depends = self.module_depends[:-1]
337 # ensure the dbus dependencies are a list
338 if isinstance(self.dbus_depends, str):
339 self.dbus_depends = [self.dbus_depends]
340@@ -164,8 +169,10 @@
341 for f in os.listdir(path):
342 info_file = os.path.join(path, f)
343 if os.path.isfile(info_file) and f.endswith('.gtg-plugin'):
344- info = ConfigObj(info_file)
345- p = Plugin(info["GTG Plugin"], self.plugin_path)
346+ info = ConfigParser.ConfigParser()
347+ info.read(info_file)
348+ info = dict(info.items("GTG Plugin"))
349+ p = Plugin(info, self.plugin_path)
350 self.plugins[p.module_name] = p
351
352 def get_plugin(self, module_name):
353
354=== modified file 'GTG/gtk/browser/browser.py'
355--- GTG/gtk/browser/browser.py 2013-02-25 08:29:31 +0000
356+++ GTG/gtk/browser/browser.py 2013-08-25 20:11:23 +0000
357@@ -773,21 +773,25 @@
358 # restore expanded state of subnodes
359 self.vtree_panes['active'].get_model().foreach(
360 self._expand_not_collapsed, colt)
361+ self.config.set("collapsed_tasks", colt)
362
363 def on_task_collapsed(self, sender, tid):
364 colt = self.config.get("collapsed_tasks")
365 if tid not in colt:
366 colt.append(str(tid))
367+ self.config.set("collapsed_tasks", colt)
368
369 def on_tag_expanded(self, sender, tag):
370 colt = self.config.get("expanded_tags")
371 if tag not in colt:
372 colt.append(tag)
373+ self.config.set("expanded_tags", colt)
374
375 def on_tag_collapsed(self, sender, tag):
376 colt = self.config.get("expanded_tags")
377 if tag in colt:
378 colt.remove(str(tag))
379+ self.config.set("expanded_tags", colt)
380
381 def on_quickadd_activate(self, widget):
382 """ Add a new task from quickadd toolbar """
383
384=== modified file 'GTG/gtk/browser/tag_editor.py'
385--- GTG/gtk/browser/tag_editor.py 2013-02-25 08:29:31 +0000
386+++ GTG/gtk/browser/tag_editor.py 2013-08-25 20:11:23 +0000
387@@ -305,7 +305,7 @@
388 # Color selection
389 self.tc_cc_colsel.unselect_color()
390 # Custom colors
391- self.custom_colors = list(self.config.get('custom_colors'))
392+ self.custom_colors = self.config.get('custom_colors')
393 if len(self.custom_colors) > 0:
394 self.tc_cc_colsel.set_custom_colors(self.custom_colors)
395 # Focus
396@@ -452,8 +452,7 @@
397 """Callback: if a new color is added, we register it in the
398 configuration"""
399 self.custom_colors = self.tc_cc_colsel.get_custom_colors()
400- self.config.set_lst("custom_colors", [s for s in self.custom_colors])
401- self.req.save_config()
402+ self.config.set("custom_colors", self.custom_colors)
403
404 def on_close(self, widget, event, arg1=None, arg2=None, arg3=None):
405 """ Callback: hide the tag editor when the close the window.
406
407=== modified file 'GTG/gtk/editor/editor.py'
408--- GTG/gtk/editor/editor.py 2013-02-25 08:29:31 +0000
409+++ GTG/gtk/editor/editor.py 2013-08-25 20:11:23 +0000
410@@ -50,7 +50,7 @@
411 '''
412 req is the requester
413 vmanager is the view manager
414- taskconfig is a ConfigObj dic to save infos about tasks
415+ taskconfig is a ConfigParser to save infos about tasks
416 thisisnew is True when a new task is created and opened
417 '''
418 self.req = requester
419@@ -173,14 +173,14 @@
420 self.textview.grab_focus()
421
422 # restoring size and position, spatial tasks
423- if self.config:
424+ if self.config is not None:
425 tid = self.task.get_id()
426- if tid in self.config:
427- if "position" in self.config[tid]:
428- pos_x, pos_y = self.config[tid]["position"]
429+ if self.config.has_section(tid):
430+ if self.config.has_option(tid, "position"):
431+ pos_x, pos_y = self.config.get(tid, "position")
432 self.move(int(pos_x), int(pos_y))
433- if "size" in self.config[tid]:
434- width, height = self.config[tid]["size"]
435+ if self.config.has_option(tid, "size"):
436+ width, height = self.config.get(tid, "size")
437 self.window.resize(int(width), int(height))
438
439 self.textview.set_editable(True)
440@@ -503,7 +503,7 @@
441 self.task.set_text(self.textview.get_text())
442 self.task.sync()
443 if self.config is not None:
444- self.config.write()
445+ self.config.save()
446 self.time = time.time()
447 # light_save save the task without refreshing every 30seconds
448 # We will reduce the time when the get_text will be in another thread
449@@ -539,10 +539,10 @@
450 # saving the position
451 if self.config is not None:
452 tid = self.task.get_id()
453- if not tid in self.config:
454- self.config[tid] = dict()
455- self.config[tid]["position"] = self.get_position()
456- self.config[tid]["size"] = self.window.get_size()
457+ if not self.config.has_section(tid):
458+ self.config.add_section(tid)
459+ self.config.set(tid, "position", self.get_position())
460+ self.config.set(tid, "size", self.window.get_size())
461
462 # We define dummy variable for when close is called from a callback
463 def close(self, window=None, a=None, b=None, c=None):
464
465=== modified file 'GTG/gtk/manager.py'
466--- GTG/gtk/manager.py 2013-02-25 08:29:31 +0000
467+++ GTG/gtk/manager.py 2013-08-25 20:11:23 +0000
468@@ -27,6 +27,7 @@
469
470 import gtk
471 import gobject
472+import ConfigParser
473
474 import GTG
475 from GTG.gtk.delete_dialog import DeletionUI
476@@ -50,8 +51,9 @@
477 def __init__(self, req):
478 self.req = req
479 self.config_obj = self.req.get_global_config()
480- self.config = self.config_obj.conf_dict
481- self.task_config = self.config_obj.task_conf_dict
482+ self.browser_config = self.config_obj.get_subconfig("browser")
483+ self.plugins_config = self.config_obj.get_subconfig("plugins")
484+ self.task_config = self.config_obj.get_taskconfig()
485
486 # Editors
487 self.opened_task = {} # This is the list of tasks that are already
488@@ -100,8 +102,8 @@
489 self.pengine.register_api(self.plugin_api)
490 # checks the conf for user settings
491 try:
492- plugins_enabled = self.config["plugins"]["enabled"]
493- except KeyError:
494+ plugins_enabled = self.plugins_config.get("enabled")
495+ except ConfigParser.Error:
496 plugins_enabled = []
497 for plugin in self.pengine.get_plugins():
498 plugin.enabled = plugin.module_name in plugins_enabled
499@@ -180,9 +182,10 @@
500 # registering as opened
501 self.opened_task[uid] = tv
502 # save that we opened this task
503- if uid not in self.config["browser"]["opened_tasks"]:
504- self.config["browser"]["opened_tasks"].append(uid)
505- self.config.write()
506+ opened_tasks = self.browser_config.get("opened_tasks")
507+ if uid not in opened_tasks:
508+ opened_tasks.append(uid)
509+ self.browser_config.set("opened_tasks", opened_tasks)
510 return tv
511
512 def close_task(self, tid):
513@@ -197,9 +200,10 @@
514 # else, it close_task would be called once again
515 # by editor.close
516 editor.close()
517- if tid in self.config["browser"]["opened_tasks"]:
518- self.config["browser"]["opened_tasks"].remove(tid)
519- self.config.write()
520+ opened_tasks = self.browser_config.get("opened_tasks")
521+ if tid in opened_tasks:
522+ opened_tasks.remove(tid)
523+ self.browser_config.set("opened_tasks", opened_tasks)
524 self.check_quit_condition()
525
526 def check_quit_condition(self):
527@@ -284,15 +288,15 @@
528 for otid in self.opened_task.keys():
529 open_task.append(otid)
530 self.opened_task[otid].close()
531- self.config["browser"]["opened_tasks"] = open_task
532+ self.browser_config.set("opened_tasks", open_task)
533
534 # adds the plugin settings to the conf
535 # FIXME: this code is replicated in the preference window.
536 if len(self.pengine.plugins) > 0:
537- self.config["plugins"] = {}
538- self.config["plugins"]["disabled"] = \
539- [p.module_name for p in self.pengine.get_plugins("disabled")]
540- self.config["plugins"]["enabled"] = \
541- [p.module_name for p in self.pengine.get_plugins("enabled")]
542+ self.plugins_config.clear()
543+ self.plugins_config.set("disabled",
544+ [p.module_name for p in self.pengine.get_plugins("disabled")])
545+ self.plugins_config.set("enabled",
546+ [p.module_name for p in self.pengine.get_plugins("enabled")])
547 # plugins are deactivated
548 self.pengine.deactivate_plugins()
549
550=== modified file 'GTG/gtk/plugins.py'
551--- GTG/gtk/plugins.py 2013-02-25 08:29:31 +0000
552+++ GTG/gtk/plugins.py 2013-08-25 20:11:23 +0000
553@@ -134,7 +134,7 @@
554
555 def __init__(self, config_obj):
556 self.config_obj = config_obj
557- self.config = self.config_obj.conf_dict
558+ self.config = self.config_obj.get_subconfig("plugins")
559 builder = gtk.Builder()
560 builder.add_from_file(ViewConfig.PLUGINS_GLADE_FILE)
561
562@@ -146,19 +146,12 @@
563 self.plugin_depends = builder.get_object('PluginDepends')
564
565 self.pengine = PluginEngine()
566- # plugin config initiation, if never used
567- if "plugins" in self.config:
568- if "enabled" not in self.config["plugins"]:
569- self.config["plugins"]["enabled"] = []
570-
571- if "disabled" not in self.config["plugins"]:
572- self.config["plugins"]["disabled"] = []
573- elif self.pengine.get_plugins():
574- self.config["plugins"] = {}
575- self.config["plugins"]["disabled"] = \
576- [p.module_name for p in self.pengine.get_plugins("disabled")]
577- self.config["plugins"]["enabled"] = \
578- [p.module_name for p in self.pengine.get_plugins("enabled")]
579+ # plugin config initiation
580+ if self.pengine.get_plugins():
581+ self.config.set("disabled",
582+ [p.module_name for p in self.pengine.get_plugins("disabled")])
583+ self.config.set("enabled",
584+ [p.module_name for p in self.pengine.get_plugins("enabled")])
585
586 # see constants PLUGINS_COL_* for column meanings
587 self.plugin_store = gtk.ListStore(str, bool, str, str, bool)
588@@ -255,16 +248,20 @@
589 plugin = self.pengine.get_plugin(plugin_id)
590 plugin.enabled = not self.plugin_store.get_value(iterator,
591 PLUGINS_COL_ENABLED)
592+ plugins_enabled = self.config.get("enabled")
593+ plugins_disabled = self.config.get("disabled")
594 if plugin.enabled:
595 self.pengine.activate_plugins([plugin])
596- self.config["plugins"]["enabled"].append(plugin.module_name)
597- if plugin.module_name in self.config["plugins"]["disabled"]:
598- self.config["plugins"]["disabled"].remove(plugin.module_name)
599+ plugins_enabled.append(plugin.module_name)
600+ if plugin.module_name in plugins_disabled:
601+ plugins_disabled.remove(plugin.module_name)
602 else:
603 self.pengine.deactivate_plugins([plugin])
604- self.config["plugins"]["disabled"].append(plugin.module_name)
605- if plugin.module_name in self.config["plugins"]["enabled"]:
606- self.config["plugins"]["enabled"].remove(plugin.module_name)
607+ plugins_disabled.append(plugin.module_name)
608+ if plugin.module_name in plugins_enabled:
609+ plugins_enabled.remove(plugin.module_name)
610+ self.config.set("enabled", plugins_enabled)
611+ self.config.set("disabled", plugins_disabled)
612 self.plugin_store.set_value(iterator, PLUGINS_COL_ENABLED,
613 plugin.enabled)
614 self._update_plugin_configure(plugin)
615
616=== modified file 'GTG/plugins/bugzilla.gtg-plugin'
617--- GTG/plugins/bugzilla.gtg-plugin 2013-07-01 14:50:10 +0000
618+++ GTG/plugins/bugzilla.gtg-plugin 2013-08-25 20:11:23 +0000
619@@ -1,12 +1,12 @@
620 [GTG Plugin]
621-Module=bugzilla
622-Name=Bugzilla
623-Short-description="Allow to link a task with a bugzilla ticket."
624-Description="""Allow to link a task with a bugzilla ticket
625-Just paste the URL of the ticket in the quick add entry
626-and a new task will be created for this bug.
627-At the moment the GNOME, Mozilla and Freedesktop.org
628-bugzillas are supported."""
629-Authors=Guillaume Desmottes <gdesmott@gnome.org>
630-Version=0.0.1
631-Enabled=False
632+module=bugzilla
633+name=Bugzilla
634+short-description=Allow to link a task with a bugzilla ticket.
635+description=Allow to link a task with a bugzilla ticket
636+ Just paste the URL of the ticket in the quick add entry
637+ and a new task will be created for this bug.
638+ At the moment the GNOME, Mozilla and Freedesktop.org
639+ bugzillas are supported.
640+authors=Guillaume Desmottes <gdesmott@gnome.org>
641+version=0.0.1
642+enabled=False
643
644=== modified file 'GTG/plugins/export.gtg-plugin'
645--- GTG/plugins/export.gtg-plugin 2012-07-13 17:24:28 +0000
646+++ GTG/plugins/export.gtg-plugin 2013-08-25 20:11:23 +0000
647@@ -1,11 +1,11 @@
648 [GTG Plugin]
649-Module=export
650-Name=Export and print
651-Short-description="Exports the tasks in the current view into a variety of formats."
652-Description="""Exports the tasks in the current view into
653-a variety of formats. You can also personalize the format
654-of your tasks by writing your own template"""
655-Authors=Luca Invernizzi <invernizzi.l@gmail.com>, Izidor Matušov <izidor.matusov@gmail.com>
656-Version=0.2
657-Enabled=False
658-Dependencies=Cheetah,pdflatex,pdftk,pdfjam
659+module=export
660+name=Export and print
661+short-description=Exports the tasks in the current view into a variety of formats.
662+description=Exports the tasks in the current view into
663+ a variety of formats. You can also personalize the format
664+ of your tasks by writing your own template
665+authors=Luca Invernizzi <invernizzi.l@gmail.com>, Izidor Matušov <izidor.matusov@gmail.com>
666+version=0.2
667+enabled=False
668+dependencies=Cheetah,pdflatex,pdftk,pdfjam
669
670=== modified file 'GTG/plugins/geolocalized-tasks.gtg-plugin'
671--- GTG/plugins/geolocalized-tasks.gtg-plugin 2012-05-23 08:55:31 +0000
672+++ GTG/plugins/geolocalized-tasks.gtg-plugin 2013-08-25 20:11:23 +0000
673@@ -1,10 +1,10 @@
674 [GTG Plugin]
675-Module=geolocalized_tasks
676-Name=Geolocalized Tasks
677-Short-description="This plugin adds geolocalized tasks to GTG!."
678-Description="""This plugin adds geolocalized tasks to GTG!.
679-WARNING: This plugin is still under heavy development."""
680-Authors=Paulo Cabido <paulo.cabido@gmail.com>
681-Version=0.1.1
682-Dependencies=configobj,Geoclue,clutter,cluttergtk,champlain,champlaingtk
683-Enabled=False
684+module=geolocalized_tasks
685+name=Geolocalized Tasks
686+short-description=This plugin adds geolocalized tasks to GTG!.
687+description=This plugin adds geolocalized tasks to GTG!.
688+ WARNING: This plugin is still under heavy development.
689+authors=Paulo Cabido <paulo.cabido@gmail.com>
690+version=0.1.1
691+dependencies=Geoclue,clutter,cluttergtk,champlain,champlaingtk
692+enabled=False
693
694=== modified file 'GTG/plugins/hamster.gtg-plugin'
695--- GTG/plugins/hamster.gtg-plugin 2012-05-23 08:55:31 +0000
696+++ GTG/plugins/hamster.gtg-plugin 2013-08-25 20:11:23 +0000
697@@ -1,10 +1,10 @@
698 [GTG Plugin]
699-Module=hamster
700-Name=Hamster Time Tracker Integration
701-Short-description="Track time of GTG task with Hamster applet."
702-Description="""Adds the ability to send a task to
703-the Hamster time tracking applet"""
704-Authors=Kevin Mehall <km@kevinmehall.net>
705-Version=0.3
706-Dbus-dependencies=org.gnome.Hamster:/org/gnome/Hamster
707-Enabled=False
708+module=hamster
709+name=Hamster Time Tracker Integration
710+short-description=Track time of GTG task with Hamster applet.
711+description=Adds the ability to send a task to
712+ the Hamster time tracking applet
713+authors=Kevin Mehall <km@kevinmehall.net>
714+version=0.3
715+dbus-dependencies=org.gnome.Hamster:/org/gnome/Hamster
716+enabled=False
717
718=== modified file 'GTG/plugins/not-today.gtg-plugin'
719--- GTG/plugins/not-today.gtg-plugin 2012-12-18 11:55:24 +0000
720+++ GTG/plugins/not-today.gtg-plugin 2013-08-25 20:11:23 +0000
721@@ -1,9 +1,9 @@
722 [GTG Plugin]
723-Module=not_today
724-Name=Not Today
725-Short-description="Mark task as not to do today"
726-Description="""Move the start date of tasks you don't want to do today to tomorrow."""
727-Authors=Lionel Dricot <lionel@ploum.net>
728-Version=0.1
729-Enabled=False
730-Dependencies=
731+module=not_today
732+name=Not Today
733+short-description=Mark task as not to do today
734+description=Move the start date of tasks you don't want to do today to tomorrow.
735+authors=Lionel Dricot <lionel@ploum.net>
736+version=0.1
737+enabled=False
738+dependencies=
739
740=== modified file 'GTG/plugins/notification-area.gtg-plugin'
741--- GTG/plugins/notification-area.gtg-plugin 2012-07-18 12:09:41 +0000
742+++ GTG/plugins/notification-area.gtg-plugin 2013-08-25 20:11:23 +0000
743@@ -1,11 +1,11 @@
744 [GTG Plugin]
745-Module=notification_area
746-Name=Notification area
747-Short-description="Adds a GTG icon to the notification area."
748-Description="""Adds a GTG icon to the notification area,
749-that keeps the list of the currently workable tasks.
750-To start GTG minimized, click on the 'Configure Plugin' button
751-at the bottom of this window."""
752-Authors="Paulo Cabido <paulo.cabido@gmail.com>, Luca Invernizzi <invernizzi.l@gmail.com>, Jono Bacon <jono@ubuntu.com>, Izidor Matušov <izidor.matusov@gmail.com>, Antonio Roquentin <antonio.roquentin@sfr.fr>"
753-Version=0.95
754-Enabled=False
755+module=notification_area
756+name=Notification area
757+short-description=Adds a GTG icon to the notification area.
758+description=Adds a GTG icon to the notification area,
759+ that keeps the list of the currently workable tasks.
760+ To start GTG minimized, click on the 'Configure Plugin' button
761+ at the bottom of this window.
762+authors="Paulo Cabido <paulo.cabido@gmail.com>, Luca Invernizzi <invernizzi.l@gmail.com>, Jono Bacon <jono@ubuntu.com>, Izidor Matušov <izidor.matusov@gmail.com>, Antonio Roquentin <antonio.roquentin@sfr.fr>"
763+version=0.95
764+enabled=False
765
766=== modified file 'GTG/plugins/send-email.gtg-plugin'
767--- GTG/plugins/send-email.gtg-plugin 2012-05-23 08:55:31 +0000
768+++ GTG/plugins/send-email.gtg-plugin 2013-08-25 20:11:23 +0000
769@@ -1,10 +1,10 @@
770 [GTG Plugin]
771-Module=send_email
772-Name=Send task via email
773-Short-description="Easily send a task via email."
774-Description="""Adds a button on the toolbar to send
775-easily a task via email, also sends status, due_dates, tags and subtasks."""
776-Authors=Luca Invernizzi <invernizzi.l@gmail.com>, Thibault Févry <ThibaultFevry@gmail.com>
777-Version=0.2.0
778-Enabled=False
779-Dependencies=gio, urllib
780+module=send_email
781+name=Send task via email
782+short-description=Easily send a task via email.
783+description=Adds a button on the toolbar to send
784+ easily a task via email, also sends status, due_dates, tags and subtasks.
785+authors=Luca Invernizzi <invernizzi.l@gmail.com>, Thibault Févry <ThibaultFevry@gmail.com>
786+version=0.2.0
787+enabled=False
788+dependencies=gio, urllib
789
790=== modified file 'GTG/plugins/task-reaper.gtg-plugin'
791--- GTG/plugins/task-reaper.gtg-plugin 2012-05-23 08:55:31 +0000
792+++ GTG/plugins/task-reaper.gtg-plugin 2013-08-25 20:11:23 +0000
793@@ -1,12 +1,12 @@
794 [GTG Plugin]
795-Module=task_reaper
796-Name=Closed tasks remover
797-Short-description="Delete old tasks automatically."
798-Description="""This plugin deletes the task that have been
799-closed more than a few days ago. The number of days can be
800-configured in the preference menu. There is also an option
801-to run the deletion automatically."""
802-Authors=Luca Invernizzi <invernizzi.l@gmail.com>
803-Version=0.1.1
804-Enabled=False
805-Dependencies=,
806+module=task_reaper
807+name=Closed tasks remover
808+short-description=Delete old tasks automatically.
809+description=This plugin deletes the task that have been
810+ closed more than a few days ago. The number of days can be
811+ configured in the preference menu. There is also an option
812+ to run the deletion automatically.
813+authors=Luca Invernizzi <invernizzi.l@gmail.com>
814+version=0.1.1
815+enabled=False
816+dependencies=
817
818=== modified file 'GTG/plugins/tomboy.gtg-plugin'
819--- GTG/plugins/tomboy.gtg-plugin 2012-05-23 08:55:31 +0000
820+++ GTG/plugins/tomboy.gtg-plugin 2013-08-25 20:11:23 +0000
821@@ -1,12 +1,11 @@
822 [GTG Plugin]
823-Module=tomboy
824-Name=Tomboy/Gnote plugin
825-Short-description="Enable linking to Tomboy/GNote notes."
826-Description="""This plugin lets you add a link to a Tomboy (or Gnote)
827-note in your tasks, or create a new one"""
828-Authors=Luca Invernizzi <invernizzi.l@gmail.com>
829-Version=0.1.9
830-Enabled=False
831-#Dbus-dependencies=org.gnome.Tomboy:/org/gnome/Tomboy
832-Dependencies=dbus,
833-
834+module=tomboy
835+name=Tomboy/Gnote plugin
836+short-description=Enable linking to Tomboy/GNote notes.
837+description=This plugin lets you add a link to a Tomboy (or Gnote)
838+ note in your tasks, or create a new one
839+authors=Luca Invernizzi <invernizzi.l@gmail.com>
840+version=0.1.9
841+enabled=False
842+#dbus-dependencies=org.gnome.Tomboy:/org/gnome/Tomboy
843+dependencies=dbus,
844
845=== modified file 'GTG/plugins/untouched-tasks.gtg-plugin'
846--- GTG/plugins/untouched-tasks.gtg-plugin 2012-11-05 22:15:18 +0000
847+++ GTG/plugins/untouched-tasks.gtg-plugin 2013-08-25 20:11:23 +0000
848@@ -1,9 +1,9 @@
849 [GTG Plugin]
850-Module=untouched_tasks
851-Name=Untouched tasks
852-Short-description="Keep track of tasks you haven't touched for a while."
853-Description="""Assigns tasks that you haven't touched for a while with the @untouched tag."""
854-Authors=Tom Kadwill <tomkadwill@gmail.com>
855-Version=0.0.1
856-Enabled=False
857-Dependencies=gio, urllib
858+module=untouched_tasks
859+name=Untouched tasks
860+short-description=Keep track of tasks you haven't touched for a while.
861+description=Assigns tasks that you haven't touched for a while with the @untouched tag.
862+authors=Tom Kadwill <tomkadwill@gmail.com>
863+version=0.0.1
864+enabled=False
865+dependencies=gio, urllib
866
867=== modified file 'GTG/plugins/urgency-color.gtg-plugin'
868--- GTG/plugins/urgency-color.gtg-plugin 2012-05-23 08:55:31 +0000
869+++ GTG/plugins/urgency-color.gtg-plugin 2013-08-25 20:11:23 +0000
870@@ -1,16 +1,15 @@
871 [GTG Plugin]
872-Module=urgency_color
873-Name=Urgency Color
874-Short-description="Task urgency color-coding"
875-Description='''This plugin will calculate the urgency status of every of your currently active tasks and color-code it accordingly.
876-
877-Color code
878-
879-Assuming your settings are default:
880-Red means you are within the last 30% of days between the start-date and due-date, or your task is overdue.
881-Yellow means your task's start-date has passed.
882-Green means your task's start-date is oncoming.
883-'''
884-Authors=Wolter Hellmund <wolterh6@gmail.com>
885-Version=0.1
886-Enabled=False
887+module=urgency_color
888+name=Urgency Color
889+short-description=Task urgency color-coding
890+description=This plugin will calculate the urgency status of every of your currently active tasks and color-code it accordingly.
891+
892+ Color code
893+
894+ Assuming your settings are default:
895+ Red means you are within the last 30% of days between the start-date and due-date, or your task is overdue.
896+ Yellow means your task's start-date has passed.
897+ Green means your task's start-date is oncoming.
898+authors=Wolter Hellmund <wolterh6@gmail.com>
899+version=0.1
900+enabled=False
901
902=== modified file 'GTG/tests/test_backends.py'
903--- GTG/tests/test_backends.py 2013-02-25 07:35:07 +0000
904+++ GTG/tests/test_backends.py 2013-08-25 20:11:23 +0000
905@@ -92,7 +92,7 @@
906 dic["module"] = str(domobj.getAttribute("module"))
907 dic["pid"] = str(domobj.getAttribute("pid"))
908 dic["xmlobject"] = domobj
909- dic["Enabled"] = True
910+ dic["enabled"] = True
911 dic["path"] = self.taskpath
912 beobj = localfile.Backend(dic)
913 expectedres = True
914
915=== modified file 'README'
916--- README 2012-11-02 09:04:08 +0000
917+++ README 2013-08-25 20:11:23 +0000
918@@ -15,7 +15,6 @@
919 * Python, version 2.6 or above
920 * PyGTK
921 * python-support
922- * python-configobj
923 * python-xdg
924 * python-dbus
925 * python-liblarch
926@@ -29,8 +28,7 @@
927 To install the all the required packages providing the basic features on
928 Debian-based systems, execute the following command:
929 $ sudo apt-get install python-support python-gtk2 python-gnome2 \
930- python-glade2 python-xdg python-configobj python-dbus \
931- python-liblarch yelp
932+ python-glade2 python-xdg python-dbus python-liblarch yelp
933
934 To enable API documentation generation, execute this command:
935 $ sudo apt-get install python-pydoctor

Subscribers

People subscribed via source and target branches

to status/vote changes: