gtg team mailing list archive
-
gtg team
-
Mailing list archive
-
Message #00204
[Merge] lp:~gtg-user/gtg/tomboy into lp:gtg
Luca Invernizzi has proposed merging lp:~gtg-user/gtg/tomboy into lp:gtg.
Requested reviews:
Gtg developers (gtg)
Tomboy notes support (via dbus).
A toolbar button displaying the Tomboy icon will appear in each task editor.
Clicking that, one can add a tomboy note just writing the note title in the combo box shown (which supports autocompletion). A new tomboy icon will appear in the task text, where the cursor was.
--
https://code.launchpad.net/~gtg-user/gtg/tomboy/+merge/12056
Your team Gtg developers is subscribed to branch lp:gtg.
=== modified file '.bzrignore'
--- .bzrignore 2009-08-24 10:01:19 +0000
+++ .bzrignore 2009-09-18 13:33:33 +0000
@@ -37,3 +37,5 @@
_trial_temp
doc/api
**/**.glade.h
+**/**.gladep
+**/**.gladep.bak
=== modified file 'GTG/core/plugins/engine.py'
--- GTG/core/plugins/engine.py 2009-09-12 23:33:04 +0000
+++ GTG/core/plugins/engine.py 2009-09-15 21:45:40 +0000
@@ -186,6 +186,13 @@
if plugin['state'] and plugin['active']:
plugin['instance'].onTaskOpened(plugin_api)
+ # signals to the plug-ins that the task window is being closed
+ def onTaskClose(self, plugins, plugin_api):
+ for plugin in plugins:
+ if plugin['state'] and plugin['active']:
+ if hasattr(plugin['instance'],'onTaskClosed'):
+ plugin['instance'].onTaskClosed(plugin_api)
+
# rechecks the plug-ins to see if any changes where done to the state
def recheckPlugins(self, plugins, plugin_api):
for plugin in plugins:
@@ -292,4 +299,4 @@
if missing_dbus:
plugin['missing_dbus'] = missing_dbus
-
\ No newline at end of file
+
=== modified file 'GTG/info.py'
--- GTG/info.py 2009-08-29 14:17:46 +0000
+++ GTG/info.py 2009-09-17 17:55:17 +0000
@@ -26,6 +26,7 @@
"\tJean-François Fortin Tam <nekohayo@xxxxxxxxx>", \
"\tJonathan Lange <jml@xxxxxxxxx>", \
"\tPaulo Cabido <paulo.cabido@xxxxxxxxx>", \
+ "\tLuca Invernizzi <invernizzi.l@xxxxxxxxx>", \
]
ARTISTS = ["Kalle Persson <kalle@xxxxxxxxxxxxxxx>", \
"Bertrand Rousseau <bertrand.rousseau@xxxxxxxxx>"]
@@ -40,7 +41,7 @@
Finnish: Mika Tapojärvi
French: Lionel Dricot, Rafik Ouerchefani, Bertrand Rousseau, Pititjo
German: Philip Stewart, Thomas Pitlik
-Italian: Luca Falavigna
+Italian: Luca Falavigna, Luca Invernizzi
Malay: melayubuntu
Polish: Tomasz Maciejewski
Portuguese: Paulo Cabido
=== modified file 'GTG/plugins/rtm-sync.gtg-plugin'
--- GTG/plugins/rtm-sync.gtg-plugin 2009-09-12 09:54:39 +0000
+++ GTG/plugins/rtm-sync.gtg-plugin 2009-09-17 17:55:17 +0000
@@ -4,5 +4,5 @@
Description=Plugin for synchronising Getting Things Gnome! with the web service Remember the milk ( http://www.rememberthemilk.com ).\n\nLegal note: This product uses the Remember The Milk API but is not endorsed or certified by Remember The Milk.
Authors=Luca Invernizzi <invernizzi.l@xxxxxxxxx>
Version=0.1.1
-Dependencies=python-xml,python-simplejson
+Dependencies=minidom,subprocess,BaseDirectory,threading,gobject,gtk,time,pickle,datetime,logging,md5,urllib,warnings,simplejson
Enabled=False
=== modified file 'GTG/plugins/rtm_sync/pyrtm/rtm.py'
--- GTG/plugins/rtm_sync/pyrtm/rtm.py 2009-09-12 14:19:54 +0000
+++ GTG/plugins/rtm_sync/pyrtm/rtm.py 2009-09-17 17:55:17 +0000
@@ -14,6 +14,7 @@
import logging
from hashlib import md5
from GTG import _
+import httplib
warnings.simplefilter('default', ImportWarning)
@@ -91,7 +92,7 @@
params['format'] = 'json'
params['api_sig'] = self._sign(params)
- json = openURL(SERVICE_URL, params).read()
+ json = openURL(SERVICE_URL, params)
LOG.debug("JSON response: \n%s" % json)
@@ -180,9 +181,25 @@
def openURL(url, queryArgs=None):
if queryArgs:
- url = url + '?' + urllib.urlencode(queryArgs)
+# url = url + '?' + urllib.urlencode(queryArgs)
+ url = urllib.urlencode(queryArgs)
LOG.debug("URL> %s", url)
- return urllib.urlopen(url)
+ try:
+ print url
+ SERVICE_URL = 'http://api.rememberthemilk.com/services/rest/'
+ c = httplib.HTTPConnection("api.rememberthemilk.com",80)
+ c.request("POST", "/services/rest/",url)
+ r = c.getresponse()
+ data = r.read()
+
+ #url_retrieved = urllib.urlopen(url)
+# data = url_retrieved.read()
+ print "mannaggia "+ str(len(data))
+ print data
+ except URLError as e:
+ print "Urllib error" + str(e.code)
+ print e.read()
+ return data
class dottedDict(object):
"Make dictionary items accessible via the object-dot notation."
@@ -248,7 +265,7 @@
'getList':
[(), ()],
'removeContact':
- [('timeline', 'group_id', 'contact_id'), ()],
+ [('timeline', 'group_id', 'contact_id'), ()]
},
'lists': {
'add':
=== modified file 'GTG/plugins/rtm_sync/rtm_proxy.py'
--- GTG/plugins/rtm_sync/rtm_proxy.py 2009-09-12 14:27:13 +0000
+++ GTG/plugins/rtm_sync/rtm_proxy.py 2009-09-17 17:55:17 +0000
@@ -47,8 +47,8 @@
os.path.join(xdg_config_home, 'gtg/plugins/rtm-sync')
self.token = utility.smartLoadFromFile(self.config_dir, 'token')
if self.token == None:
- self.rtm=rtm.createRTM("2a440fdfe9d890c343c25a91afd84c7e", \
- "ca078fee48d0bbfa")
+ self.rtm=rtm.createRTM("646052cf5bb8b638a356e052f6493150", \
+ "203a347c94c015b4")
subprocess.Popen(['xdg-open', self.rtm.getAuthURL()])
return False
return True
@@ -77,14 +77,22 @@
#(it's easier to debug the things you see)
lists_id_list = map(lambda x: x.id, \
self.rtm.lists.getList().lists.list)
-
- def get_list_of_taskseries(x):
- currentlist = self.rtm.tasks.getList(filter='status:incomplete', \
- list_id=x).tasks
- if hasattr(currentlist, 'list'):
- return currentlist.list
+ print self.rtm
+ def get_list_of_taskseries(list_id):
+ try:
+ print list_id
+ print self.rtm
+ currentlist = self.rtm.tasks.getList(filter='status:incomplete AND includeArchived:false', \
+ list_id = list_id)
+ except Exception as e:
+ print e
+ print "puppa"
+ if hasattr(currentlist,'task') and hasattr(currentlist, 'list'):
+ currentlist = currentlist.task.list
else:
return []
+
+ print lists_id_list
task_list_global= map(get_list_of_taskseries, lists_id_list)
taskseries_list = filter(lambda x: hasattr(x[0], 'taskseries'), \
zip(task_list_global, lists_id_list))
=== added directory 'GTG/plugins/tomboy'
=== added file 'GTG/plugins/tomboy.gtg-plugin'
--- GTG/plugins/tomboy.gtg-plugin 1970-01-01 00:00:00 +0000
+++ GTG/plugins/tomboy.gtg-plugin 2009-09-15 14:02:26 +0000
@@ -0,0 +1,7 @@
+[GTG Plugin]
+Module=tomboy
+Name=Tomboy plugin
+Description=Plugin Description goes here. Hello World!
+Authors=Luca Invernizzi <invernizzi.l@xxxxxxxxx>
+Version=0.1.1
+Enabled=True
=== added file 'GTG/plugins/tomboy/__init__.py'
--- GTG/plugins/tomboy/__init__.py 1970-01-01 00:00:00 +0000
+++ GTG/plugins/tomboy/__init__.py 2009-09-18 13:51:14 +0000
@@ -0,0 +1,20 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2009 - Luca Invernizzi <invernizzi.l@xxxxxxxxx>
+#
+# This program is free software: you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free Software
+# Foundation, either version 3 of the License, or (at your option) any later
+# version.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+# details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program. If not, see <http://www.gnu.org/licenses/>.
+
+import sys
+import os
+sys.path.insert(0, os.getcwd())
+from tomboy import pluginTomboy
=== added file 'GTG/plugins/tomboy/tomboy.glade'
--- GTG/plugins/tomboy/tomboy.glade 1970-01-01 00:00:00 +0000
+++ GTG/plugins/tomboy/tomboy.glade 2009-09-18 13:31:55 +0000
@@ -0,0 +1,110 @@
+<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
+<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd">
+
+<glade-interface>
+
+<widget class="GtkDialog" id="InsertNoteDialog">
+ <property name="width_request">300</property>
+ <property name="title" translatable="yes">Insert Note</property>
+ <property name="type">GTK_WINDOW_TOPLEVEL</property>
+ <property name="window_position">GTK_WIN_POS_NONE</property>
+ <property name="modal">False</property>
+ <property name="resizable">True</property>
+ <property name="destroy_with_parent">False</property>
+ <property name="decorated">True</property>
+ <property name="skip_taskbar_hint">False</property>
+ <property name="skip_pager_hint">False</property>
+ <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
+ <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
+ <property name="focus_on_map">True</property>
+ <property name="urgency_hint">False</property>
+ <property name="has_separator">True</property>
+
+ <child internal-child="vbox">
+ <widget class="GtkVBox" id="dialog-vbox1">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child internal-child="action_area">
+ <widget class="GtkHButtonBox" id="dialog-action_area1">
+ <property name="visible">True</property>
+ <property name="layout_style">GTK_BUTTONBOX_END</property>
+
+ <child>
+ <widget class="GtkButton" id="btn_cancel">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-cancel</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="response_id">-6</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="btn_add">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-add</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="response_id">0</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">GTK_PACK_END</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label_caption">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Insert the title of the tomboy note </property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkComboBoxEntry" id="titles_combobox">
+ <property name="visible">True</property>
+ <property name="add_tearoffs">False</property>
+ <property name="has_frame">True</property>
+ <property name="focus_on_click">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+</widget>
+
+</glade-interface>
=== added file 'GTG/plugins/tomboy/tomboy.py'
--- GTG/plugins/tomboy/tomboy.py 1970-01-01 00:00:00 +0000
+++ GTG/plugins/tomboy/tomboy.py 2009-09-18 13:51:14 +0000
@@ -0,0 +1,202 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2009 - Luca Invernizzi <invernizzi.l@xxxxxxxxx>
+#
+# This program is free software: you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free Software
+# Foundation, either version 3 of the License, or (at your option) any later
+# version.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+# details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program. If not, see <http://www.gnu.org/licenses/>.
+
+import gtk
+import os
+import dbus
+from GTG import _
+
+
+class pluginTomboy:
+
+ def __init__(self):
+ self.token_start = 'TOMBOY__'
+ self.token_end = '|'
+ self.path = os.path.dirname(os.path.abspath(__file__))
+
+ # Plug-in engine methods
+ def activate(self, plugin_api):
+ self.plugin_api = plugin_api
+
+ def widgetTotext(self, widget):
+ return self.token_start+ widget.tomboy_note_title+self.token_end
+
+ # Converts all tomboy note widgets in the
+ # equivalent text
+ def onTaskClosed(self, plugin_api):
+ for anchor in self.anchors:
+ widgets = anchor.get_widgets()
+ if anchor.get_deleted():
+ #The note has been deleted, go
+ continue
+ iter_start = self.textview.buff.get_iter_at_child_anchor(anchor)
+ iter_end = iter_start.copy()
+ iter_end.forward_char()
+ if type(widgets) == list and len(widgets) !=0:
+ #the anchor point contains a widget.
+ widget = widgets[0]
+ self.textview.buff.delete(iter_start, iter_end)
+ self.textview.buff.insert(iter_start,
+ self.widgetTotext(widget))
+
+ def onTaskOpened(self, plugin_api):
+ #get_textview() only works here(from GTG/core/plugins/api.py docs)
+ self.textview = plugin_api.get_textview()
+ # add a item(button) to the ToolBar, with a nice icon
+ tb_Taskbutton_image = gtk.Image()
+ tb_Taskbutton_image_path =\
+ "/usr/share/icons/hicolor/16x16/apps/tomboy.png"
+ tb_Taskbutton_pixbuf=gtk.gdk.\
+ pixbuf_new_from_file_at_size(tb_Taskbutton_image_path, 16, 16)
+ tb_Taskbutton_image.set_from_pixbuf(tb_Taskbutton_pixbuf)
+ tb_Taskbutton_image.show()
+ self.tb_Taskbutton = gtk.ToolButton(tb_Taskbutton_image)
+ self.tb_Taskbutton.set_label(_("Add Tomboy note"))
+ self.tb_Taskbutton.connect('clicked', self.onTbTaskButton, plugin_api)
+ plugin_api.add_task_toolbar_item(gtk.SeparatorToolItem())
+ plugin_api.add_task_toolbar_item(self.tb_Taskbutton)
+ #convert tokens in text to images
+ self.anchors=[]
+ start_iter = self.textview.buff.get_start_iter()
+ end_iter = self.textview.buff.get_end_iter()
+ text = self.textview.buff.get_slice(start_iter, end_iter)
+ text_offset = 0
+ token_position = text.find(self.token_start)
+ token_ending = text.find(self.token_end, token_position)
+ while not token_position < 0 and not token_ending < 0:
+ #delete the widget
+ tomboy_note_title = text[token_position + len(self.token_start):
+ token_ending]
+ start_iter = self.textview.buff.get_iter_at_offset(text_offset +
+ token_position)
+ end_iter = self.textview.buff.get_iter_at_offset(text_offset+
+ token_ending+1)
+ self.textview.buff.delete(start_iter, end_iter)
+ #add the widget
+ widget =self.widgetCreate(tomboy_note_title)
+ anchor = self.textviewInsertWidget(widget, start_iter)
+ self.anchors.append(anchor)
+ #find the next
+ start_iter = self.textview.buff.get_iter_at_child_anchor(anchor)
+ start_iter.forward_char()
+ end_iter = self.textview.buff.get_end_iter()
+ text = self.textview.buff.get_slice(start_iter, end_iter)
+ text_offset = start_iter.get_offset()
+ token_position = text.find(self.token_start)
+ token_ending = text.find(self.token_end)
+
+ def deactivate(self, plugin_api):
+ #nothing to remove
+ pass
+
+ def close_dialog(self, widget, data=None):
+ self.dialog.destroy()
+ return True
+
+ def getTomboyObject(self):
+ bus = dbus.SessionBus()
+ obj = bus.get_object("org.gnome.Tomboy",
+ "/org/gnome/Tomboy/RemoteControl")
+ return dbus.Interface(obj, "org.gnome.Tomboy.RemoteControl")
+
+ def getTomboyNoteTitleList(self):
+ tomboy = self.getTomboyObject()
+ return map(lambda note: tomboy.GetNoteTitle(note),
+ tomboy.ListAllNotes())
+
+ def onTbTaskButton(self, widget, plugin_api):
+ title_list = self.getTomboyNoteTitleList()
+ #Create the dialog
+ glade_file = os.path.join(self.path, "tomboy.glade")
+ wTree = gtk.glade.XML(glade_file, "InsertNoteDialog")
+ #objects
+ self.dialog = wTree.get_widget("InsertNoteDialog")
+ btn_add = wTree.get_widget("btn_add")
+ btn_cancel = wTree.get_widget("btn_cancel")
+ self.combobox = wTree.get_widget("titles_combobox")
+ self.label_caption = wTree.get_widget("label_caption")
+ title_entry = gtk.Entry()
+ clipboard = gtk.Clipboard()
+ #connects
+ self.dialog.connect("delete_event", self.close_dialog)
+ btn_cancel.connect("clicked", self.close_dialog)
+ btn_add.connect("clicked", self.noteChosen)
+
+ def comboKeyPress(combobox, event):
+ keyname = gtk.gdk.keyval_name(event.keyval)
+ if keyname == "Return":
+ self.noteChosen()
+ title_entry.connect("key-press-event", comboKeyPress)
+ #clipboard management(if a note title is in the clipboard,
+ # put that into the combobox
+ def clipboardCallback(clipboard, text, title_el):
+ title_entry= title_el[0]
+ title_list= title_el[1]
+ if len(filter(lambda x: x == text, title_list)) != 0:
+ title_entry.set_text(text)
+ clipboard.request_text(clipboardCallback, [title_entry, title_list])
+ self.combobox.add(title_entry)
+ #populate the combo-box
+ if title_list:
+ completion = gtk.EntryCompletion()
+ note_list_store = gtk.ListStore(str)
+ for title in title_list:
+ iter = note_list_store.append()
+ note_list_store.set(iter, 0, title)
+ title_entry.set_completion(completion)
+ completion.set_model(note_list_store)
+ completion.set_inline_completion(True)
+ completion.set_text_column(0)
+ self.dialog.show_all()
+
+ def noteChosen(self, widget=None, data=None):
+ tomboy = self.getTomboyObject()
+ supposed_title = self.combobox.get_active_text()
+ if filter(lambda x: tomboy.GetNoteTitle(x)==supposed_title,
+ tomboy.ListAllNotes()) == []:
+ self.label_caption.set_text(_("That note does not exist!"))
+ return
+ mark_start = self.textview.buff.get_insert()
+ iter_start = self.textview.buff.get_iter_at_mark(mark_start)
+ tomboy_widget =self.widgetCreate(supposed_title)
+ anchor = self.textviewInsertWidget(tomboy_widget, iter_start)
+ self.anchors.append(anchor)
+ self.dialog.destroy()
+
+ def tomboyDisplayNote(self, widget):
+ tomboy = self.getTomboyObject()
+ note = tomboy.FindNote(widget.tomboy_note_title)
+ tomboy.DisplayNote(note)
+
+ def textviewInsertWidget(self, widget, iter):
+ anchor = self.textview.buff.create_child_anchor(iter)
+ widget.show()
+ self.textview.add_child_at_anchor(widget, anchor)
+ return anchor
+
+ def widgetCreate(self, tomboy_note_title):
+ image = gtk.Image()
+ image_path = "/usr/share/icons/hicolor/16x16/apps/tomboy.png"
+ pixbuf=gtk.gdk.\
+ pixbuf_new_from_file_at_size(image_path, 16, 16)
+ image.show()
+ image.set_from_pixbuf(pixbuf)
+ widget= gtk.Button()
+ widget.set_image(image)
+ widget.tomboy_note_title = tomboy_note_title
+ widget.set_label(tomboy_note_title)
+ widget.connect('clicked', self.tomboyDisplayNote)
+ return widget
=== modified file 'GTG/taskeditor/editor.py'
--- GTG/taskeditor/editor.py 2009-08-29 14:17:46 +0000
+++ GTG/taskeditor/editor.py 2009-09-15 21:45:40 +0000
@@ -470,6 +470,7 @@
#Will be linked to this destruction method that will save the task
def destruction(self,a=None) :#pylint: disable-msg=W0613
#Save should be also called when buffer is modified
+ self.pengine.onTaskClose(self.plugins, self.te_plugin_api)
self.save()
self.closing(self.task.get_id())
=== modified file 'locales/gtg.pot'
--- locales/gtg.pot 2009-09-12 23:03:15 +0000
+++ locales/gtg.pot 2009-09-18 13:51:14 +0000
@@ -8,7 +8,7 @@
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2009-09-13 01:03+0200\n"
+"POT-Creation-Date: 2009-09-18 15:51+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@xxxxxx>\n"
@@ -632,6 +632,22 @@
msgid "due"
msgstr ""
+#: GTG/plugins/tomboy/tomboy.py:67
+msgid "Add Tomboy note"
+msgstr ""
+
+#: GTG/plugins/tomboy/tomboy.py:170
+msgid "That note does not exist!"
+msgstr ""
+
+#: GTG/plugins/tomboy/tomboy.glade.h:1
+msgid "Insert Note"
+msgstr ""
+
+#: GTG/plugins/tomboy/tomboy.glade.h:2
+msgid "Insert the title of the tomboy note "
+msgstr ""
+
#: GTG/plugins/rtm_sync/utility.py:54
msgid "saving critical object failed"
msgstr ""
@@ -666,11 +682,11 @@
"now. When done, press OK"
msgstr ""
-#: GTG/plugins/rtm_sync/pyrtm/rtm.py:56
+#: GTG/plugins/rtm_sync/pyrtm/rtm.py:57
msgid "Invalid state"
msgstr ""
-#: GTG/plugins/rtm_sync/pyrtm/rtm.py:105
+#: GTG/plugins/rtm_sync/pyrtm/rtm.py:106
msgid "API call failed"
msgstr ""
Follow ups