def initialize(self): """ This is called when a backend is enabled """ super(Backend, self).initialize() if "state" not in self._parameters: self._parameters["state"] = "start" # Prepare parameters jid = self._parameters["username"] password = self._parameters["password"] server = "pubsub." + jid.split('@', 1)[-1] self._xmpp = PubsubClient(jid, password, server) self._xmpp.register_callback("failed_auth", self.on_failed_auth) self._xmpp.register_callback("connected", self.on_connected) self._xmpp.register_callback("disconnected", self.on_disconnected) if self._xmpp.connect(reattempt=False): self._xmpp.process() else: Log.error("Can't connect to XMPP") if self._parameters["state"] == "start": self.on_failed_auth() BackendSignals().connect('sharing-changed', self.on_sharing_changed) self._xmpp.register_callback("project_tag", self.on_new_remote_project) self._xmpp.register_callback("set_task", self.on_remote_set_task) self._xmpp.register_callback("rm_task", self.on_remote_rm_task)
def _get_avatar(self, jid): """ Return avatar for jid if it is possible. The avatar is cached for the future runs. """ if not os.path.exists(self.AVATARS_DIR): os.makedirs(self.AVATARS_DIR) # If avatar was cached, return it avatars = glob.glob(os.path.join(self.AVATARS_DIR, jid + ".*")) if len(avatars) > 0: return avatars[0] # Download vCard and avatar in it vcard = self['xep_0054'].get_vcard(jid) img_type = vcard['vcard_temp']['PHOTO']['TYPE'] photo = vcard['vcard_temp']['PHOTO']['BINVAL'] # Determine a name for the file if not img_type.startswith("image/") or " " in img_type: return None suffix = img_type[len("image/"):] name = os.path.join(self.AVATARS_DIR, "%s.%s" % (jid, suffix)) Log.info("Saving avatar for '%s'" % jid) with open(name, 'wb') as avatar_file: avatar_file.write(photo) return name
def __init__(self): """ Creates a dictionary of the currently available backend modules """ super(BackendFactory, self).__init__() if hasattr(self, "backend_modules"): # This object has already been constructed return self.backend_modules = {} # Look for backends in the GTG/backends dir this_dir = os.path.dirname(__file__) backend_files = filter( lambda f: f.endswith(".py") and f.startswith(self.BACKEND_PREFIX), os.listdir(this_dir)) # Create module names module_names = map(lambda f: f.replace(".py", ""), backend_files) #Log.debug("Backends found: " + str(module_names)) #print "Backends = " + str(module_names) # Load backend modules for module_name in module_names: extended_module_name = "GTG.backends." + module_name try: __import__(extended_module_name) except ImportError, exception: # Something is wrong with this backend, skipping Log.warning("Backend %s could not be loaded: %s" % (module_name, str(exception))) continue except Exception, exception: # Other exception log as errors Log.error("Malformated backend %s: %s" % (module_name, str(exception))) continue
def restore_backend_from_xml(self, dic): ''' Function restoring a backend from its xml description. dic should be a dictionary containing at least the key - "module", with the module name - "xmlobject", with its xml description. Every other key is passed as-is to the backend, as parameter. Returns the backend instance, or None is something goes wrong ''' if not "module" in dic or not "xmlobject" in dic: Log.debug("Malformed backend configuration found! %s" % dic) module = self.get_backend(dic["module"]) if module is None: Log.debug("could not load module for backend %s" % dic["module"]) return None # we pop the xml object, as it will be redundant when the parameters # are set directly in the dict xp = dic.pop("xmlobject") # Building the dictionary parameters_specs = module.Backend.get_static_parameters() dic["pid"] = str(xp.getAttribute("pid")) for param_name, param_dic in parameters_specs.iteritems(): if xp.hasAttribute(param_name): # we need to convert the parameter to the right format. # we fetch the format from the static_parameters param_type = param_dic[GenericBackend.PARAM_TYPE] param_value = GenericBackend.cast_param_type_from_string( xp.getAttribute(param_name), param_type) dic[param_name] = param_value # We put the backend itself in the dict dic["backend"] = module.Backend(dic) return dic["backend"]
def on_remote_set_task(self, task_id, raw_xml): """ Task was set on server """ if self._parameters["state"] != "online": return if task_id in self._changed_locally: self._changed_locally.remove(task_id) return Log.info("PubSub --set--> GTG: [%s]" % task_id) # Parse XML string into <task> node xmldoc = xml.dom.minidom.parseString(raw_xml) task_xml = xmldoc.getElementsByTagName("task")[0] self._changed_remotely.add(task_id) task = self.datastore.get_task(task_id) if task: # Already exists task = task_from_xml(task, task_xml) else: # New task task = self.datastore.task_factory(task_id) task = task_from_xml(task, task_xml) self.datastore.push_task(task)
def _show_panel(self, panel_name): ''' Helper function to switch between panels. @param panel_name: the name of the wanted panel. Choose between "configuration" or "add" ''' if panel_name == "configuration": panel_to_remove = self.add_panel panel_to_add = self.config_panel side_is_enabled = True elif panel_name == "add": panel_to_remove = self.config_panel panel_to_add = self.add_panel side_is_enabled = False else: Log.error("panel name unknown") return # Central pane # NOTE: self.central_pane is the Gtk.Container in which we load panels if panel_to_remove in self.central_pane: self.central_pane.remove(panel_to_remove) if not panel_to_add in self.central_pane: self.central_pane.add(panel_to_add) self.central_pane.show_all() # Side treeview # disabled if we're adding a new backend try: # when this is called upon initialization of this class, the # backends_tv object has not been created yet. self.add_button.set_sensitive(side_is_enabled) self.remove_button.set_sensitive(side_is_enabled) self.backends_tv.set_sensitive(side_is_enabled) except AttributeError: pass
def set_task(self, task): """ Propagate a change in local tasks into server """ if self._parameters["state"] != "online": return sync_tags = self._xmpp.get_synchronized_tags() tags = task.get_tags_name() tag_overlap = set(sync_tags) & set(tags) if not tag_overlap: return if task.get_id() in self._changed_remotely: self._changed_remotely.remove(task.get_id()) return Log.info("GTG --set--> PubSub: [%s] '%s'" % (task.get_id(), task.get_title())) doc = xml.dom.minidom.parseString("<task></task>") task_id = task.get_id() task_xml = task_to_xml(doc, task).toxml() tags = task.get_tags_name() self._xmpp.set_task(task_id, tags, task_xml) self._sync_tasks.add(task_id) self._changed_locally.add(task_id)
def save_state(self): """ The last function before shutting this backend down. Disconnect XMPP and store picked_file """ Log.info("Quitting backend") self._xmpp.disconnect() Log.info("Backend is shut down")
def openxmlfile(zefile,root ): tmpfile = zefile+'__' # print "opening %s file" %zefile try: if os.path.exists(zefile): f = open(zefile, "r") elif os.path.exists(tmpfile): Log.debug("Something happened to the tags file. Using backup") os.rename(tmpfile, zefile) f = open(zefile, "r") else: # Creating empty file doc,xmlproject = emptydoc(root) newfile = savexml(zefile, doc) # use our function to save file if not newfile: sys.exit(1) return openxmlfile(zefile, root) # recursive call stringed = f.read() stringed = cleanString(stringed,tab,enter) doc = xml.dom.minidom.parseString(stringed) # doc = xml.dom.minidom.parse(f) # print "cleaning %s" %zefile cleanDoc(doc,tab,enter) xmlproject = doc.getElementsByTagName(root)[0] f.close() return doc,xmlproject except IOError, msg: print msg sys.exit(1)
def on_connected(self): """ Get the initial set of the tasks from the XMPP """ if self._parameters["state"] != "onine": self._parameters["state"] = "online" # Ensure all teams tag_tree = self.datastore.get_tagstore().get_main_view() for tag_id in tag_tree.get_all_nodes(): tag = self.datastore.get_tag(tag_id) team = tag.get_people_shared_with() if len(team) > 0: self._xmpp.ensure_team(tag_id, team) # Fetch initial tasks for task_id, tag, raw_xml in self._xmpp.get_tasks(): # Parse the raw_xml by DOM doc = xml.dom.minidom.parseString(raw_xml) task_xml = doc.getElementsByTagName("task")[0] # Create a new task or return the existing one with the same id task = self.datastore.task_factory(task_id) task = task_from_xml(task, task_xml) task.add_tag(tag) self.datastore.push_task(task) self._sync_tasks.add(task_id) Log.info("(init) PubSub --set--> GTG: [%s] '%s'" % (task_id, task.get_title()))
def new_search_tag(self, name, query, attributes={}): """ Create a new search tag @returns GTG.core.tag.Tag: the new search tag/None for a invalid query """ try: parameters = parse_search_query(query) except InvalidQuery as e: Log.warning("Problem with parsing query '%s' (skipping): %s" % (query, e.message)) return None # Create own copy of attributes and add special attributes label, query init_attr = dict(attributes) init_attr["label"] = name init_attr["query"] = query tag = Tag(name, req=self.requester, attributes=init_attr) self._add_new_tag(name, tag, search_filter, parameters, parent_id=SEARCH_TAG) self.save_tagtree() return tag
def get(self, option): """ Get option from configuration. If the option is not specified in the configuration or is of invalid type, return default value. If there is no default value, None is returned """ default_value = self._defaults.get(option) if default_value is None: Log.warning( 'No default value for %s in %s', option, self._section_name) get_function = self._type_function(default_value) try: value = get_function(option) except ValueError as e: value = None Log.warning( 'Invalid configuration value "%s" for %s in %s: %s', self._section.get(option), option, self._section_name, e) if value is None and default_value is None: raise ValueError( 'No valid configuration value or default value was ' 'found for %s in %s'.format(option, self._section_name)) elif value is None: return default_value else: return value
def __init__(self): """ Creates a dictionary of the currently available backend modules """ super(BackendFactory, self).__init__() if hasattr(self, "backend_modules"): #This object has already been constructed return self.backend_modules = {} #Look for backends in the GTG/backends dir this_dir = os.path.dirname(__file__) backend_files = filter(lambda f: f.endswith(".py") and \ f[ : len(self.BACKEND_PREFIX)] == self.BACKEND_PREFIX , \ os.listdir(this_dir)) #Create module names module_names = map(lambda f: f.replace(".py",""), backend_files) Log.debug("Backends found: " + str(module_names)) #Load backend modules for module_name in module_names: extended_module_name = "GTG.backends." + module_name try: __import__(extended_module_name) except ImportError, exception: #Something is wrong with this backend, skipping Log.debug("Backend %s could not be loaded: %s" % \ (module_name, str(exception))) continue self.backend_modules[module_name] = \ sys.modules[extended_module_name]
def openxmlfile(zefile, root): """ Open an XML file in a robust way If file could not be opened, try: - file__ - file.bak.0 - file.bak.1 - .... until BACKUP_NBR If file doesn't exist, create a new file """ tmpfile = zefile + '__' try: if os.path.exists(zefile): return _try_openxmlfile(zefile, root) elif os.path.exists(tmpfile): Log.warning("Something happened to %s. Using backup" % zefile) os.rename(tmpfile, zefile) return _try_openxmlfile(zefile, root) else: # Creating empty file doc, xmlproject = emptydoc(root) newfile = savexml(zefile, doc) if not newfile: Log.error("Could not create a new file %s" % zefile) sys.exit(1) return _try_openxmlfile(zefile, root) except IOError, msg: print msg sys.exit(1)
def _show_panel(self, panel_name): ''' Helper function to switch between panels. @param panel_name: the name of the wanted panel. Choose between "configuration" or "add" ''' if panel_name == "configuration": panel_to_remove = self.add_panel panel_to_add = self.config_panel side_is_enabled = True elif panel_name == "add": panel_to_remove = self.config_panel panel_to_add = self.add_panel side_is_enabled = False else: Log.error("panel name unknown") return # Central pane # NOTE: self.central_pane is the Gtk.Container in which we load panels if panel_to_remove in self.central_pane: self.central_pane.remove(panel_to_remove) if panel_to_add not in self.central_pane: self.central_pane.add(panel_to_add) self.central_pane.show_all() # Side treeview # disabled if we're adding a new backend try: # when this is called upon initialization of this class, the # backends_tv object has not been created yet. self.add_button.set_sensitive(side_is_enabled) self.remove_button.set_sensitive(side_is_enabled) self.backends_tv.set_sensitive(side_is_enabled) except AttributeError: pass
def set_task(self, task): """ See GenericBackend for an explanation of this function. """ self.cancellation_point() is_syncable = self._gtg_task_is_syncable_per_attached_tags(task) tid = task.get_id() with self.datastore.get_backend_mutex(): with self.TomboyConnection(self, *self.BUS_ADDRESS) as tomboy: has_task = self.datastore.has_task has_note = tomboy.NoteExists can_sync = is_syncable with self.DbusWatchdog(self): action, note = self.sync_engine.analyze_local_id(tid, has_task, has_note, can_sync) Log.debug("processing gtg (%s, %d)" % (action, is_syncable)) if action == SyncEngine.ADD: # GTG allows multiple tasks with the same name, # Tomboy doesn't. we need to handle the renaming # manually title = task.get_title() duplicate_counter = 1 with self.DbusWatchdog(self): note = tomboy.CreateNamedNote(title) while note == "": duplicate_counter += 1 note = tomboy.CreateNamedNote(title + "(%d)" % duplicate_counter) if duplicate_counter != 1: # if we needed to rename, we have to rename also # the gtg task task.set_title(title + " (%d)" % duplicate_counter) self._populate_note(note, task) self.record_relationship( local_id=tid, remote_id=note, meme=SyncMeme(task.get_modified(), self.get_modified_for_note(note), "GTG"), ) elif action == SyncEngine.UPDATE: meme = self.sync_engine.get_meme_from_local_id(task.get_id()) modified_for = self.get_modified_for_note(note) newest = meme.which_is_newest(task.get_modified(), modified_for) if newest == "local": self._populate_note(note, task) meme.set_local_last_modified(task.get_modified()) meme.set_remote_last_modified(self.get_modified_for_note(note)) self.save_state() elif action == SyncEngine.REMOVE: self.datastore.request_task_deletion(tid) try: self.sync_engine.break_relationship(local_id=tid) self.save_state() except KeyError: pass elif action == SyncEngine.LOST_SYNCABILITY: self._exec_lost_syncability(tid, note)
def _process_rtm_task(self, rtm_task_id): ''' Takes a rtm task id and carries out the necessary operations to refresh the sync state ''' self.cancellation_point() if not self.rtm_proxy.is_authenticated(): return rtm_task = self.rtm_proxy.get_rtm_tasks_dict()[rtm_task_id] is_syncable = self._rtm_task_is_syncable_per_attached_tags(rtm_task) action, tid = self.sync_engine.analyze_remote_id( rtm_task_id, self.datastore.has_task, self.rtm_proxy.has_rtm_task, is_syncable) Log.debug("GTG<-RTM set task (%s, %s)" % (action, is_syncable)) if action is None: return if action == SyncEngine.ADD: if rtm_task.get_status() != Task.STA_ACTIVE: # OPTIMIZATION: # we don't sync tasks that have already been closed before we # even saw them return tid = str(uuid.uuid4()) task = self.datastore.task_factory(tid) self._populate_task(task, rtm_task) meme = SyncMeme(task.get_modified(), rtm_task.get_modified(), "RTM") self.sync_engine.record_relationship(local_id=tid, remote_id=rtm_task_id, meme=meme) self.datastore.push_task(task) elif action == SyncEngine.UPDATE: task = self.datastore.get_task(tid) with self.datastore.get_backend_mutex(): meme = self.sync_engine.get_meme_from_remote_id(rtm_task_id) newest = meme.which_is_newest(task.get_modified(), rtm_task.get_modified()) if newest == "remote": self._populate_task(task, rtm_task) meme.set_remote_last_modified(rtm_task.get_modified()) meme.set_local_last_modified(task.get_modified()) else: # we skip saving the state return elif action == SyncEngine.REMOVE: try: rtm_task.delete() self.sync_engine.break_relationship(remote_id=rtm_task_id) except KeyError: pass elif action == SyncEngine.LOST_SYNCABILITY: self._exec_lost_syncability(tid, rtm_task) self.save_state()
def on_failed_auth(self): """ Provided credencials are not valid. Disable this instance and show error to user """ Log.error('Failed to authenticate') BackendSignals().backend_failed(self.get_id(), BackendSignals.ERRNO_AUTHENTICATION) self.quit(disable=True)
def get_configuration(self): try: return datetime.time(int(self.config.get('hour')), int(self.config.get('min'))) except(ValueError): Log.error("Invalid time values: %s:%s", self.config.get('hour'), self.config.get('min')) return datetime.time(0, 0)
def _when_taking_too_long(self): """ Function that is executed when the Dbus connection seems to be hanging. It disables the backend and signals the error to the user. """ Log.error("Dbus connection is taking too long for the Tomboy/Gnote" "backend!") BackendSignals().backend_failed(self.backend.get_id(), BackendSignals.ERRNO_DBUS) self.backend.quit(disable=True)
def on_task_modified(self, task_id, path): """ Stop task if it is tracked and it is Done/Dismissed """ Log.debug('Hamster: task modified %s', task_id) task = self.plugin_api.get_requester().get_task(task_id) if not task: return if task.get_status() in (Task.STA_DISMISSED, Task.STA_DONE): self.stop_task(task_id)
def get_configuration(self): try: return datetime.time(int(self.config.get('hour')), int(self.config.get('min'))) except (ValueError): Log.error("Invalid time values: %s:%s", self.config.get('hour'), self.config.get('min')) return datetime.time(0, 0)
def get_tasks(self): """ Return list of all available tasks """ Log.info("Looking for available tasks") for node in self._nodes: project_tag = self._nodes[node] result_items = self['xep_0060'].get_items(self._pubsub, node, max_items=self.MAX_ITEMS, block=True) items = result_items['pubsub']['items']['substanzas'] for item in items: yield item['id'], project_tag, tostring(item['payload'])
def adding_tag(tname,tag): if not self.__tagstore.has_node(tname): p = {'tag':tname,'transparent':True} self.__tasks.add_filter(tname,self.treefactory.tag_filter,parameters=p) self.__tagstore.add_node(tag) tag.set_save_callback(self.save) self.added_tag.pop(tname) Log.debug("********* tag added %s *******" % tname) else: print "Warning: Trying to add tag %s multiple times" %tname
def get_backend(self, backend_name): ''' Returns the backend module for the backend matching backend_name. Else, returns none ''' if backend_name in self.backend_modules: return self.backend_modules[backend_name] else: Log.debug("Trying to load backend %s, but failed!" % backend_name) return None
def open_browser(self): if not self.browser: self.browser = TaskBrowser(self.req, self) # notify user if backup was used backend_dic = self.req.get_all_backends() for backend in backend_dic: if backend.get_name() == "backend_localfile" and \ backend.used_backup(): backend.notify_user_about_backup() Log.debug("Browser is open")
def _when_taking_too_long(self): ''' Function that is executed when the Dbus connection seems to be hanging. It disables the backend and signals the error to the user. ''' Log.error("Dbus connection is taking too long for the Tomboy/Gnote" "backend!") BackendSignals().backend_failed(self.backend.get_id(), BackendSignals.ERRNO_DBUS) self.backend.quit(disable=True)
def set_task(self, task): ''' See GenericBackend for an explanation of this function. ''' tid = task.get_id() is_syncable = self._gtg_task_is_syncable_per_attached_tags(task) action, evo_task_id = self.sync_engine.analyze_local_id( tid, self.datastore.has_task, self._evo_has_task, is_syncable) Log.debug('GTG->Evo set task (%s, %s)' % (action, is_syncable)) if action is None: return if action == SyncEngine.ADD: evo_task = evolution.ecal.ECalComponent( ical=evolution.ecal.CAL_COMPONENT_TODO) with self.datastore.get_backend_mutex(): self._evolution_tasks.add_object(evo_task) self._populate_evo_task(task, evo_task) meme = SyncMeme(task.get_modified(), self._evo_get_modified(evo_task), "GTG") self.sync_engine.record_relationship( local_id=tid, remote_id=evo_task.get_uid(), meme=meme) elif action == SyncEngine.UPDATE: with self.datastore.get_backend_mutex(): evo_task = self._evo_get_task(evo_task_id) meme = self.sync_engine.get_meme_from_local_id(task.get_id()) newest = meme.which_is_newest(task.get_modified(), self._evo_get_modified(evo_task)) if newest == "local": self._populate_evo_task(task, evo_task) meme.set_remote_last_modified( self._evo_get_modified(evo_task)) meme.set_local_last_modified(task.get_modified()) else: # we skip saving the state return elif action == SyncEngine.REMOVE: self.datastore.request_task_deletion(tid) try: self.sync_engine.break_relationship(local_id=tid) except KeyError: pass elif action == SyncEngine.LOST_SYNCABILITY: evo_task = self._evo_get_task(evo_task_id) self._exec_lost_syncability(tid, evo_task) self.save_state()
def _process_tomboy_note(self, note): ''' Given a tomboy note, finds out if it must be synced to a GTG note and, if so, it carries out the synchronization (by creating or updating a GTG task, or deleting itself if the related task has been deleted) @param note: a Tomboy note id ''' with self.datastore.get_backend_mutex(): self.cancellation_point() is_syncable = self._tomboy_note_is_syncable(note) has_task = self.datastore.has_task note_exists = self._tomboy_note_exists with self.DbusWatchdog(self): action, tid = self.sync_engine.analyze_remote_id(note, has_task, note_exists, is_syncable) Log.debug("processing tomboy (%s, %s)" % (action, is_syncable)) if action == SyncEngine.ADD: tid = str(uuid.uuid4()) task = self.datastore.task_factory(tid) self._populate_task(task, note) modified_for = self.get_modified_for_note(note) self.record_relationship(local_id=tid, remote_id=note, meme=SyncMeme(task.get_modified(), modified_for, self.get_id())) self.datastore.push_task(task) elif action == SyncEngine.UPDATE: task = self.datastore.get_task(tid) meme = self.sync_engine.get_meme_from_remote_id(note) newest = meme.which_is_newest(task.get_modified(), self.get_modified_for_note(note)) if newest == "remote": self._populate_task(task, note) meme.set_local_last_modified(task.get_modified()) meme.set_remote_last_modified( self.get_modified_for_note(note)) self.save_state() elif action == SyncEngine.REMOVE: with self.TomboyConnection(self, *self.BUS_ADDRESS) as tomboy: with self.DbusWatchdog(self): tomboy.DeleteNote(note) try: self.sync_engine.break_relationship(remote_id=note) except KeyError: pass elif action == SyncEngine.LOST_SYNCABILITY: self._exec_lost_syncability(tid, note)
def delete_task(self, tid, recursive=True): """Delete the task 'tid' and, by default, delete recursively all the childrens. Note: this modifies the datastore. @param tid: The id of the task to be deleted. """ # send the signal before actually deleting the task ! Log.debug("deleting task %s" % tid) return self.__basetree.del_node(tid, recursive=recursive)
def _login(self): ''' Tries to establish a connection to rtm with a token got from the authentication process ''' try: self.rtm = createRTM(self.PUBLIC_KEY, self.PRIVATE_KEY, self.token) self.timeline = self.rtm.timelines.create().timeline return True except (RTMError, RTMAPIError), e: Log.error("RTM ERROR" + str(e))
def new_search_tag(self, name, query, attributes={}): """ Create a new search tag @returns GTG.core.tag.Tag: the new search tag/None for a invalid query """ try: parameters = parse_search_query(query) except InvalidQuery, e: Log.warning("Problem with parsing query '%s' (skipping): %s" % (query, e.message)) return None
def remove_widget_from_taskeditor(self, widg_id): """Remove a widget from the bottom of the task editor dialog @param widget: The Gtk.Widget that is going to be removed """ if self.is_editor() and widg_id: try: wi = self.__builder.get_object("vbox4") if wi and widg_id in self.taskwidget_widg: wi.remove(self.taskwidget_widg.pop(widg_id)) except Exception as e: Log.debug("Error removing the toolbar item in the TaskEditor:" "%s" % e)
def on_new_remote_project(self, tag_id, team_jids): """ New project was added on server """ if self._parameters["state"] != "online": return team = [unicode(member) for member in team_jids] Log.info("Pubsub --new project--> GTG: %s, teammates: %s" % (tag_id, team)) tag = self.datastore.get_tag(tag_id) if tag is None: tag = self.datastore.new_tag(tag_id) tag.set_people_shared_with(team)
def remove_task(self, task_id): """ After removing local task remove tasks from the server """ if self._parameters["state"] != "online": return if task_id in self._sync_tasks: Log.info("GTG --del--> PubSub: [%s]" % task_id) self._xmpp.delete_task(task_id) self._sync_tasks.remove(task_id) if task_id in self._changed_locally: self._changed_locally.remove(task_id) if task_id in self._changed_remotely: self._changed_remotely.remove(task_id)
def new_relationship(self,par,chi): if self.thread_protection: t = threading.current_thread() if t != self.thread: raise Exception('! could not new_relationship from thread %s' %t) if self.tree: return self.tree.new_relationship(par,chi) else: self.pending_relationship.append([par,chi]) #it's pending, we return False Log.debug("** There's still no tree, relationship is pending") return False
def _process_evo_task(self, evo_task_id): ''' Takes an evolution task id and carries out the necessary operations to refresh the sync state ''' self.cancellation_point() evo_task = self._evo_get_task(evo_task_id) is_syncable = self._evo_task_is_syncable(evo_task) action, tid = self.sync_engine.analyze_remote_id( evo_task_id, self.datastore.has_task, self._evo_has_task, is_syncable) Log.debug('GTG<-Evo set task (%s, %s)' % (action, is_syncable)) if action == SyncEngine.ADD: with self.datastore.get_backend_mutex(): tid = str(uuid.uuid4()) task = self.datastore.task_factory(tid) self._populate_task(task, evo_task) meme = SyncMeme(task.get_modified(), self._evo_get_modified(evo_task), "GTG") self.sync_engine.record_relationship(local_id=tid, remote_id=evo_task_id, meme=meme) self.datastore.push_task(task) elif action == SyncEngine.UPDATE: with self.datastore.get_backend_mutex(): task = self.datastore.get_task(tid) meme = self.sync_engine.get_meme_from_remote_id(evo_task_id) newest = meme.which_is_newest(task.get_modified(), self._evo_get_modified(evo_task)) if newest == "remote": self._populate_task(task, evo_task) meme.set_remote_last_modified( self._evo_get_modified(evo_task)) meme.set_local_last_modified(task.get_modified()) elif action == SyncEngine.REMOVE: return try: evo_task = self._evo_get_task(evo_task_id) self._delete_evolution_task(evo_task) self.sync_engine.break_relationship(remote_id=evo_task) except KeyError: pass elif action == SyncEngine.LOST_SYNCABILITY: self._exec_lost_syncability(tid, evo_task) self.save_state()
def remove_widget_from_taskeditor(self, widg_id): """Remove a widget from the bottom of the task editor dialog @param widget: The gtk.Widget that is going to be removed """ if self.is_editor() and widg_id: try: wi = self.__builder.get_object('vbox4') if wi and widg_id in self.taskwidget_widg: wi.remove(self.taskwidget_widg.pop(widg_id)) except Exception, e: Log.debug("Error removing the toolbar item in the TaskEditor:" "%s" % e)
def __init__(self, req): GObject.GObject.__init__(self) self.req = req self.config_obj = self.req.get_global_config() self.browser_config = self.config_obj.get_subconfig("browser") self.plugins_config = self.config_obj.get_subconfig("plugins") self.task_config = self.config_obj.get_taskconfig() # Editors self.opened_task = {} # This is the list of tasks that are already # opened in an editor of course it's empty # right now self.browser = None self.__start_browser_hidden = False self.gtk_terminate = False # if true, the gtk main is not started # if true, closing the last window doesn't quit GTG # (GTG lives somewhere else without GUI, e.g. notification area) self.daemon_mode = False # Shared clipboard self.clipboard = clipboard.TaskClipboard(self.req) # Initialize Timer self.config = self.req.get_config('browser') self.timer = Timer(self.config) # Browser (still hidden) self.browser = TaskBrowser(self.req, self) self.__init_plugin_engine() if not self.__start_browser_hidden: self.show_browser() # Deletion UI self.delete_dialog = None # Preferences and Backends windows # Initialize dialogs self.preferences = PreferencesDialog(self.req, self) self.plugins = PluginsDialog(self.config_obj) self.edit_backends_dialog = None # Tag Editor self.tag_editor_dialog = None # DBus DBusTaskWrapper(self.req, self) Log.debug("Manager initialization finished")