def on_export_start(self, saving): """ Start generating a document. If saving == True, ask user where to store the document. Otherwise, open it afterwards. """ model = self.combo.get_model() active = self.combo.get_active() self.template = Template(model[active][0]) tasks = self.get_selected_tasks() if len(tasks) == 0: self.show_error_dialog( _("No task matches your criteria. " "Empty report can't be generated.")) return self.filename = None if saving: self.filename = self.choose_file() if self.filename is None: return self.save_button.set_sensitive(False) self.open_button.set_sensitive(False) try: self.template.generate(tasks, self.plugin_api, self.on_export_finished) except Exception as err: self.show_error_dialog( _("GTG could not generate the document: %s") % err) raise
class Backend(GenericTomboy): """ A simple class that adds some description to the GenericTomboy class. It's done this way since Tomboy and Gnote backends have different descriptions and Dbus addresses but the same backend behind them. """ _general_description = { GenericBackend.BACKEND_NAME: "backend_gnote", GenericBackend.BACKEND_HUMAN_NAME: _("Gnote"), GenericBackend.BACKEND_AUTHORS: ["Luca Invernizzi"], GenericBackend.BACKEND_TYPE: GenericBackend.TYPE_READWRITE, GenericBackend.BACKEND_DESCRIPTION: _("This service can synchronize all or part of your Gnote" " notes in GTG. If you decide it would be handy to" " have one of your notes in your TODO list, just tag it " "with the tag you have chosen (you'll configure it later" "), and it will appear in GTG."), } _static_parameters = { GenericBackend.KEY_ATTACHED_TAGS: { GenericBackend.PARAM_TYPE: GenericBackend.TYPE_LIST_OF_STRINGS, GenericBackend.PARAM_DEFAULT_VALUE: ["@GTG-Gnote"] }, } BUS_ADDRESS = ("org.gnome.Gnote", "/org/gnome/Gnote/RemoteControl", "org.gnome.Gnote.RemoteControl")
def __build_menu(self): """Build up the widget""" # Reset the widget for i in self: self.remove(i) i.destroy() if self.tag is not None: # Color chooser FIXME: SHOULD BECOME A COLOR PICKER self.mi_cc = Gtk.MenuItem() self.mi_cc.set_label(_("Edit Tag...")) self.mi_ctag = Gtk.MenuItem() self.mi_ctag.set_label(_("Generate Color")) self.mi_del_tag = Gtk.MenuItem() self.mi_del_tag.set_label(_("Delete Tag")) self.append(self.mi_cc) self.append(self.mi_ctag) self.append(self.mi_del_tag) self.mi_del_tag.connect( 'activate', self.vmanager.browser.on_delete_tag_activate) self.mi_cc.connect('activate', self.on_mi_cc_activate) self.mi_ctag.connect('activate', self.on_mi_ctag_activate) if self.tag.is_search_tag(): self.mi_del = Gtk.MenuItem() self.mi_del.set_label(_("Delete")) self.append(self.mi_del) self.mi_del.connect('activate', self.on_mi_del_activate) # Make it visible self.show_all()
def set_error_code(self, error_code): ''' Sets this infobar to show an error to the user @param error_code: the code of the error to show. Error codes are listed in BackendSignals ''' self._populate() self.connect("response", self._on_error_response) backend_name = self.backend.get_human_name() if error_code == BackendSignals.ERRNO_AUTHENTICATION: self.set_message_type(Gtk.MessageType.ERROR) self.label.set_markup(self.AUTHENTICATION_MESSAGE % backend_name) self.add_button(_('Configure synchronization service'), Gtk.ResponseType.ACCEPT) self.add_button(_('Ignore'), Gtk.ResponseType.CLOSE) elif error_code == BackendSignals.ERRNO_NETWORK: if not is_connection_up(): return self.set_message_type(Gtk.MessageType.WARNING) self.label.set_markup(self.NETWORK_MESSAGE % backend_name) # FIXME: use gtk stock button instead self.add_button(_('Ok'), Gtk.ResponseType.CLOSE) elif error_code == BackendSignals.ERRNO_DBUS: self.set_message_type(Gtk.MessageType.WARNING) self.label.set_markup(self.DBUS_MESSAGE % backend_name) self.add_button(_('Ok'), Gtk.ResponseType.CLOSE) self.show_all()
def active_tasks_treeview(self, tree): # Build the title/label/tags columns desc = self.common_desc_for_tasks(tree, "Tasks") # "startdate" column col_name = 'startdate' col = {} col['title'] = _("Start date") col['expandable'] = False col['resizable'] = False col['value'] = [str, self.task_sdate_column] col['order'] = 3 col['sorting_func'] = self.start_date_sorting desc[col_name] = col # 'duedate' column col_name = 'duedate' col = {} col['title'] = _("Due") col['expandable'] = False col['resizable'] = False col['value'] = [str, self.task_duedate_column] col['order'] = 4 col['sorting_func'] = self.due_date_sorting desc[col_name] = col # Returning the treeview treeview = self.build_task_treeview(tree, desc) treeview.set_sort_column('duedate') return treeview
def test_parse_local_fuzzy_dates(self): """ Parse fuzzy dates in their localized version """ self.assertEqual(Date.parse(_("now")), Date.now()) self.assertEqual(Date.parse(_("soon")), Date.soon()) self.assertEqual(Date.parse(_("later")), Date.someday()) self.assertEqual(Date.parse(_("someday")), Date.someday()) self.assertEqual(Date.parse(""), Date.no_date())
def test_parse_fuzzy_dates_str(self): """ Print fuzzy dates in localized version """ self.assertEqual(str(Date.parse("now")), _("now")) self.assertEqual(str(Date.parse("soon")), _("soon")) self.assertEqual(str(Date.parse("later")), _("someday")) self.assertEqual(str(Date.parse("someday")), _("someday")) self.assertEqual(str(Date.parse("")), "")
def __init_gtk(self): menu = Gtk.Menu() # add "new task" # FIXME test this label... is it needed? play with it a little menuItem = Gtk.MenuItem(label=_('Add New Task')) menuItem.connect('activate', self.__open_task) menu.append(menuItem) # Show Main Window show_browser = Gtk.MenuItem(label=_('Show Main Window')) show_browser.connect('activate', self.__show_browser) menu.append(show_browser) # separator (it's intended to be after show_all) # separator should be shown only when having tasks self.__task_separator = Gtk.SeparatorMenuItem() menu.append(self.__task_separator) menu_top_length = len(menu) menu.append(Gtk.SeparatorMenuItem()) # quit item menuItem = Gtk.MenuItem(label=_('Quit')) menuItem.connect('activate', self.__view_manager.close_browser) menu.append(menuItem) menu.show_all() self.__task_separator.hide() self.__tasks_menu = SortedLimitedMenu(self.MAX_ITEMS, menu, menu_top_length) self._indicator.activate(self.__show_browser, menu)
def on_export_start(self, saving): """ Start generating a document. If saving == True, ask user where to store the document. Otherwise, open it afterwards. """ model = self.combo.get_model() active = self.combo.get_active() self.template = Template(model[active][0]) tasks = self.get_selected_tasks() if len(tasks) == 0: self.show_error_dialog(_("No task matches your criteria. " "Empty report can't be generated.")) return self.filename = None if saving: self.filename = self.choose_file() if self.filename is None: return self.save_button.set_sensitive(False) self.open_button.set_sensitive(False) try: self.template.generate(tasks, self.plugin_api, self.on_export_finished) except Exception as err: self.show_error_dialog( _("GTG could not generate the document: %s") % err) raise
def get_tags_tree(self, req): """This create a liblarch tree suitable for tags, including the all_tags_tag and notag_tag. """ tagtree = Tree() # Build the "all tasks tag" alltag = tag.Tag(tag.ALLTASKS_TAG, req=req) alltag.set_attribute("special", "all") alltag.set_attribute("label", "%s" % _("All tasks")) alltag.set_attribute("icon", "emblem-documents-symbolic") alltag.set_attribute("order", 0) tagtree.add_node(alltag) p = {} self.tasktree.add_filter(tag.ALLTASKS_TAG, self.alltag, parameters=p) # Build the "without tag tag" notag_tag = tag.Tag(tag.NOTAG_TAG, req=req) notag_tag.set_attribute("special", "notag") notag_tag.set_attribute("label", "%s" % _("Tasks with no tags")) notag_tag.set_attribute("icon", "task-past-due-symbolic") notag_tag.set_attribute("order", 2) tagtree.add_node(notag_tag) p = {} self.tasktree.add_filter(tag.NOTAG_TAG, self.notag, parameters=p) # Build the search tag search_tag = tag.Tag(tag.SEARCH_TAG, req=req) search_tag.set_attribute("special", "search") search_tag.set_attribute("label", _("Saved searches")) search_tag.set_attribute("icon", "system-search-symbolic") search_tag.set_attribute("order", 1) tagtree.add_node(search_tag) p = {} self.tasktree.add_filter(tag.SEARCH_TAG, search_filter, parameters=p) # Build the separator sep_tag = tag.Tag(tag.SEP_TAG, req=req) sep_tag.set_attribute("special", "sep") sep_tag.set_attribute("order", 3) tagtree.add_node(sep_tag) # Filters tagtree.add_filter('activetag', self.actively_used_tag) tagtree.add_filter('usedtag', self.used_tag) activeview = tagtree.get_viewtree(name='activetags', refresh=False) activeview.apply_filter('activetag') # This view doesn't seem to be used. So it's not useful to build it now # usedview = tagtree.get_viewtree(name='usedtags',refresh=False) # usedview.apply_filter('usedtag') self.tagtree = tagtree self.tagtree_loaded = True return tagtree
def noteChosen(self, widget=None, data=None): tomboy = self.getTomboyObject() if tomboy is None: return supposed_title = self.combobox_entry.get_text() if not self._node_exist(tomboy, supposed_title): self.label_caption.set_text(_("That note does not exist!")) DIALOG_DESTROY_WITH_PARENT = Gtk.DialogFlags.DESTROY_WITH_PARENT message = _( "That note does not exist. Do you want to create a new one?") dialog = Gtk.MessageDialog( parent=self.dialog, flags=DIALOG_DESTROY_WITH_PARENT, type=Gtk.MessageType.QUESTION, buttons=Gtk.ButtonsType.YES_NO, message_format=message, ) response = dialog.run() dialog.destroy() if response == Gtk.ResponseType.YES: tomboy.CreateNamedNote(supposed_title) else: return # note insertion 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 set_error_code(self, error_code): ''' Sets this infobar to show an error to the user @param error_code: the code of the error to show. Error codes are listed in BackendSignals ''' self._populate() self.connect("response", self._on_error_response) backend_name = self.backend.get_human_name() if error_code == BackendSignals.ERRNO_AUTHENTICATION: self.set_message_type(Gtk.MessageType.ERROR) self.label.set_markup(self.AUTHENTICATION_MESSAGE % backend_name) self.add_button(_('Configure synchronization service'), Gtk.ResponseType.ACCEPT) self.add_button(_('Ignore'), Gtk.ResponseType.CLOSE) elif error_code == BackendSignals.ERRNO_NETWORK: if not is_connection_up(): return self.set_message_type(Gtk.MessageType.WARNING) self.label.set_markup(self.NETWORK_MESSAGE % backend_name) # FIXME: use icon-name button instead self.add_button(_('Ok'), Gtk.ResponseType.CLOSE) elif error_code == BackendSignals.ERRNO_DBUS: self.set_message_type(Gtk.MessageType.WARNING) self.label.set_markup(self.DBUS_MESSAGE % backend_name) self.add_button(_('Ok'), Gtk.ResponseType.CLOSE) self.show_all()
def __build_window(self): """Build up the widget""" # toplevel widget self.top_vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) self.add(self.top_vbox) # header line: icon, grid with name and "hide in wv" # FIXME self.hdr_align = Gtk.Alignment() self.top_vbox.pack_start(self.hdr_align, True, True, 0) self.hdr_align.set_padding(0, 25, 0, 0) self.hdr_box = Gtk.Box() self.hdr_align.add(self.hdr_box) self.hdr_box.set_spacing(10) # Button to tag icon selector self.ti_bt = Gtk.Button() self.ti_bt_label = Gtk.Label() self.ti_bt.add(self.ti_bt_label) self.hdr_box.pack_start(self.ti_bt, True, True, 0) self.ti_bt.set_size_request(64, 64) self.ti_bt.set_relief(Gtk.ReliefStyle.HALF) # vbox for tag name and hid in WV self.tp_grid = Gtk.Grid() self.hdr_box.pack_start(self.tp_grid, True, True, 0) self.tp_grid.set_column_spacing(5) self.tn_entry_lbl_align = Gtk.Alignment.new(0, 0.5, 0, 0) self.tp_grid.add(self.tn_entry_lbl_align) self.tn_entry_lbl = Gtk.Label() self.tn_entry_lbl.set_markup("<span weight='bold'>%s</span>" % _("Name : ")) self.tn_entry_lbl_align.add(self.tn_entry_lbl) self.tn_entry = Gtk.Entry() self.tn_entry.set_width_chars(20) self.tp_grid.attach(self.tn_entry, 1, 0, 1, 1) self.tn_cb_lbl_align = Gtk.Alignment.new(0, 0.5, 0, 0) self.tp_grid.attach(self.tn_cb_lbl_align, 0, 1, 1, 1) self.tn_cb_lbl = Gtk.Label(label=_("Show Tag in Work View :")) self.tn_cb_lbl_align.add(self.tn_cb_lbl) self.tn_cb = Gtk.CheckButton() self.tp_grid.attach(self.tn_cb, 1, 1, 1, 1) # Tag color self.tc_vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) self.top_vbox.pack_start(self.tc_vbox, True, True, 0) self.tc_label_align = Gtk.Alignment() self.tc_vbox.pack_start(self.tc_label_align, True, True, 0) self.tc_label_align.set_padding(0, 0, 0, 0) self.tc_label = Gtk.Label() self.tc_label_align.add(self.tc_label) self.tc_label.set_markup("<span weight='bold'>%s</span>" % _("Select Tag Color:")) self.tc_label.set_alignment(0, 0.5) # Tag color chooser self.tc_cc_align = Gtk.Alignment.new(0.5, 0.5, 0, 0) self.tc_vbox.pack_start(self.tc_cc_align, True, True, 0) self.tc_cc_align.set_padding(15, 15, 10, 10) self.tc_cc_colsel = SimpleColorSelector() # self.tc_cc_colsel = Gtk.ColorChooserWidget() self.tc_cc_align.add(self.tc_cc_colsel) # Icon selector self.tag_icon_selector = TagIconSelector()
def __build_window(self): """Build up the widget""" # toplevel widget self.top_vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) self.add(self.top_vbox) # header line: icon, grid with name and "hide in wv" # FIXME self.hdr_align = Gtk.Alignment() self.top_vbox.pack_start(self.hdr_align, True, True, 0) self.hdr_align.set_padding(0, 25, 0, 0) self.hdr_box = Gtk.Box() self.hdr_align.add(self.hdr_box) self.hdr_box.set_spacing(10) # Button to tag icon selector self.ti_bt = Gtk.Button() self.ti_bt_label = Gtk.Label() self.ti_bt.add(self.ti_bt_label) self.hdr_box.pack_start(self.ti_bt, True, True, 0) self.ti_bt.set_size_request(64, 64) self.ti_bt.set_relief(Gtk.ReliefStyle.HALF) # vbox for tag name and hid in WV self.tp_grid = Gtk.Grid() self.hdr_box.pack_start(self.tp_grid, True, True, 0) self.tp_grid.set_column_spacing(5) self.tn_entry_lbl_align = Gtk.Alignment.new(0, 0.5, 0, 0) self.tp_grid.add(self.tn_entry_lbl_align) self.tn_entry_lbl = Gtk.Label() self.tn_entry_lbl.set_markup("<span weight='bold'>%s</span>" % _("Name : ")) self.tn_entry_lbl_align.add(self.tn_entry_lbl) self.tn_entry = Gtk.Entry() self.tn_entry.set_width_chars(20) self.tp_grid.attach(self.tn_entry, 1, 0, 1, 1) self.tn_cb_lbl_align = Gtk.Alignment.new(0, 0.5, 0, 0) self.tp_grid.attach(self.tn_cb_lbl_align, 0, 1, 1, 1) self.tn_cb_lbl = Gtk.Label(label=_("Show Tag in Work View :")) self.tn_cb_lbl_align.add(self.tn_cb_lbl) self.tn_cb = Gtk.CheckButton() self.tp_grid.attach(self.tn_cb, 1, 1, 1, 1) # Tag color self.tc_vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) self.top_vbox.pack_start(self.tc_vbox, True, True, 0) self.tc_label_align = Gtk.Alignment() self.tc_vbox.pack_start(self.tc_label_align, True, True, 0) self.tc_label_align.set_padding(0, 0, 0, 0) self.tc_label = Gtk.Label() self.tc_label_align.add(self.tc_label) self.tc_label.set_markup( "<span weight='bold'>%s</span>" % _("Select Tag Color:")) self.tc_label.set_alignment(0, 0.5) # Tag color chooser self.tc_cc_align = Gtk.Alignment.new(0.5, 0.5, 0, 0) self.tc_vbox.pack_start(self.tc_cc_align, True, True, 0) self.tc_cc_align.set_padding(15, 15, 10, 10) self.tc_cc_colsel = SimpleColorSelector() # self.tc_cc_colsel = Gtk.ColorChooserWidget() self.tc_cc_align.add(self.tc_cc_colsel) # Icon selector self.tag_icon_selector = TagIconSelector()
def refresh_sync_button(self): """ Refreshes the state of the button that enables the backend """ self.sync_button.set_sensitive(not self.backend.is_default()) if self.backend.is_enabled(): label = _("Disable syncing") else: label = _("Enable syncing") self.sync_button.set_label(label)
def _build_issue_text(self, issue_dic): """ Creates the text that describes a issue """ text = _("Reported by: ") + issue_dic["reporter"] + "\n" text += ( _("Link to issue: ") + self._parameters["service-url"] + "/view.php?id=%s" % (issue_dic["number"]) + "\n" ) text += "\n" + issue_dic["text"] return text
def refresh_sync_button(self): ''' Refreshes the state of the button that enables the backend ''' self.sync_button.set_sensitive(not self.backend.is_default()) if self.backend.is_enabled(): label = _("Disable syncing") else: label = _("Enable syncing") self.sync_button.set_label(label)
def _build_issue_text(self, issue_dic): ''' Creates the text that describes a issue ''' text = _("Reported by: ") + issue_dic["reporter"] + '\n' text += _("Link to issue: ") + \ self._parameters['service-url'] + '/view.php?id=%s' % \ (issue_dic["number"]) + '\n' text += '\n' + issue_dic["text"] return text
def _build_issue_text(self, issue_dic): """ Creates the text that describes a issue """ text = _("Reported by: ") + issue_dic["reporter"] + '\n' text += _("Link to issue: ") + \ self._parameters['service-url'] + '/view.php?id=%s' % \ (issue_dic["number"]) + '\n' text += '\n' + issue_dic["text"] return text
def get_tags_tree(self, req): """This create a liblarch tree suitable for tags, including the all_tags_tag and notag_tag. """ tagtree = Tree() # Build the "all tasks tag" alltag = tag.Tag(tag.ALLTASKS_TAG, req=req) alltag.set_attribute("special", "all") alltag.set_attribute("label", "<span weight='bold'>%s</span>" % _("All tasks")) alltag.set_attribute("icon", "gtg-tags-all") alltag.set_attribute("order", 0) tagtree.add_node(alltag) p = {} self.tasktree.add_filter(tag.ALLTASKS_TAG, self.alltag, parameters=p) # Build the "without tag tag" notag_tag = tag.Tag(tag.NOTAG_TAG, req=req) notag_tag.set_attribute("special", "notag") notag_tag.set_attribute("label", "<span weight='bold'>%s</span>" % _("Tasks with no tags")) notag_tag.set_attribute("icon", "gtg-tags-none") notag_tag.set_attribute("order", 2) tagtree.add_node(notag_tag) p = {} self.tasktree.add_filter(tag.NOTAG_TAG, self.notag, parameters=p) # Build the search tag search_tag = tag.Tag(tag.SEARCH_TAG, req=req) search_tag.set_attribute("special", "search") search_tag.set_attribute("label", "<span weight='bold'>%s</span>" % _("Search")) search_tag.set_attribute("icon", "search") search_tag.set_attribute("order", 1) tagtree.add_node(search_tag) p = {} self.tasktree.add_filter(tag.SEARCH_TAG, search_filter, parameters=p) # Build the separator sep_tag = tag.Tag(tag.SEP_TAG, req=req) sep_tag.set_attribute("special", "sep") sep_tag.set_attribute("order", 3) tagtree.add_node(sep_tag) # Filters tagtree.add_filter("activetag", self.actively_used_tag) tagtree.add_filter("usedtag", self.used_tag) activeview = tagtree.get_viewtree(name="activetags", refresh=False) activeview.apply_filter("activetag") # This view doesn't seem to be used. So it's not useful to build it now # usedview = tagtree.get_viewtree(name='usedtags',refresh=False) # usedview.apply_filter('usedtag') self.tagtree = tagtree self.tagtree_loaded = True return tagtree
def refresh_sync_status_label(self): ''' Refreshes the Gtk.Label that shows the current state of this backend ''' if self.backend.is_default(): label = _("This is the default synchronization service") else: if self.backend.is_enabled(): label = _("Syncing is enabled.") else: label = _('Syncing is <span color="red">disabled</span>.') self.sync_status_label.set_markup(label)
def refresh_sync_status_label(self): """ Refreshes the Gtk.Label that shows the current state of this backend """ if self.backend.is_default(): label = _("This is the default synchronization service") else: if self.backend.is_enabled(): label = _("Syncing is enabled.") else: label = _('Syncing is <span color="red">disabled</span>.') self.sync_status_label.set_markup(label)
def set_complex_title(self, text, tags=[]): if tags: assert (isinstance(tags[0], str)) due_date = Date.no_date() defer_date = Date.no_date() if text: # Get tags in the title for match in extract_tags_from_text(text): tags.append(match) # Get attributes regexp = r'([\s]*)([\w-]+):\s*([^\s]+)' matches = re.findall(regexp, text, re.UNICODE) for spaces, attribute, args in matches: valid_attribute = True if attribute.lower() in ["tags", _("tags"), "tag", _("tag")]: for tag in args.split(","): if not tag.strip() == "@" and not tag.strip() == "": if not tag.startswith("@"): tag = "@" + tag tags.append(tag) elif attribute.lower() in [ "defer", _("defer"), "start", _("start") ]: try: defer_date = Date.parse(args) except ValueError: valid_attribute = False elif attribute.lower() == "due" or \ attribute.lower() == _("due"): try: due_date = Date.parse(args) except: valid_attribute = False else: # attribute is unknown valid_attribute = False if valid_attribute: # remove valid attribute from the task title text = \ text.replace(f"{spaces}{attribute}:{args}", "") for t in tags: self.add_tag(t) if text != "": self.set_title(text.strip()) self.set_to_keep() self.set_due_date(due_date) self.set_start_date(defer_date)
def _build_bug_text(self, bug_dic): """ Creates the text that describes a bug """ text = _("Reported by: ") + '%s(karma: %s)' % \ (bug_dic["owner"], bug_dic["owner_karma"]) + '\n' # one link is enough, since they're all alias bug_project = bug_dic['projects'][0]['project_short'] text += _("Link to bug: ") + \ "https://bugs.edge.launchpad.net/%s/+bug/%s" % \ (bug_project, bug_dic["number"]) + '\n' text += '\n' + bug_dic["text"] return text
def _build_bug_text(self, bug_dic): ''' Creates the text that describes a bug ''' text = _("Reported by: ") + '%s(karma: %s)' % \ (bug_dic["owner"], bug_dic["owner_karma"]) + '\n' # one link is enough, since they're all alias bug_project = bug_dic['projects'][0]['project_short'] text += _("Link to bug: ") + \ "https://bugs.edge.launchpad.net/%s/+bug/%s" % \ (bug_project, bug_dic["number"]) + '\n' text += '\n' + bug_dic["text"] return text
def set_complex_title(self, text, tags=[]): if tags: assert(isinstance(tags[0], str)) due_date = Date.no_date() defer_date = Date.no_date() if text: # Get tags in the title for match in extract_tags_from_text(text): tags.append(match) # Get attributes regexp = r'([\s]*)([\w-]+):\s*([^\s]+)' matches = re.findall(regexp, text, re.UNICODE) for spaces, attribute, args in matches: valid_attribute = True if attribute.lower() in ["tags", _("tags"), "tag", _("tag")]: for tag in args.split(","): if not tag.strip() == "@" and not tag.strip() == "": if not tag.startswith("@"): tag = "@" + tag tags.append(tag) elif attribute.lower() in ["defer", _("defer"), "start", _("start")]: try: defer_date = Date.parse(args) except ValueError: valid_attribute = False elif attribute.lower() == "due" or \ attribute.lower() == _("due"): try: due_date = Date.parse(args) except: valid_attribute = False else: # attribute is unknown valid_attribute = False if valid_attribute: # remove valid attribute from the task title text = \ text.replace("%s%s:%s" % (spaces, attribute, args), "") for t in tags: self.add_tag(t) if text != "": self.set_title(text.strip()) self.set_to_keep() self.set_due_date(due_date) self.set_start_date(defer_date)
def __build_custom_palette(self): """Draws the palette of custom colors""" self.__reset_custom_palette() # (re-)create the palette widget self.custom_palette = Gtk.Alignment.new(0, 0, 1, 0) self.custom_palette.set_padding(10, 0, 0, 0) self.pack_start(self.custom_palette, True, True, 0) # Draw the previous color palette: only one line cc_vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) self.custom_palette.add(cc_vbox) cc_vbox.set_spacing(4) cc_box = Gtk.Box() cc_vbox.pack_start(cc_box, True, True, 0) for i in range(len(self.custom_colors)): # add the color box img = SimpleColorSelectorPaletteItem() img.set_size_request( BUTTON_WIDTH, BUTTON_HEIGHT) img.connect("button-press-event", self.on_color_clicked) if i < len(self.custom_colors): img.set_color(self.custom_colors[i]) self.buttons_lookup[self.custom_colors[i]] = img cc_box.pack_start(img, False, False, 0) cc_box.set_spacing(4) self.cc_buttons.append(img) # Draw the add button buttons_hbox = Gtk.Box() cc_vbox.pack_start(buttons_hbox, True, True, 0) img = Gtk.Image() img.set_from_stock(Gtk.STOCK_ADD, Gtk.IconSize.BUTTON) self.add_button = Gtk.Button() self.add_button.set_image(img) self.add_button.set_label(_("Add custom color")) buttons_hbox.pack_start(self.add_button, True, False, 0) self.add_button.connect("clicked", self.on_color_add) # Draw the clear selected color button img = Gtk.Image() img.set_from_stock(Gtk.STOCK_REMOVE, Gtk.IconSize.BUTTON) self.clear_button = Gtk.Button() self.clear_button.set_image(img) self.clear_button.set_label(_("Clear selected color")) buttons_hbox.pack_start(self.clear_button, True, False, 0) self.clear_button.connect("clicked", self.on_color_clear) self.clear_button.set_sensitive(False) # hide the custom palette if no custom color is defined if len(self.custom_colors) == 0: self.custom_palette.hide() else: self.custom_palette.show_all()
class GnomeConfig(): CANLOAD = _("Everything necessary to run this plugin is available.") CANNOTLOAD = _("The plugin can not be loaded") miss1 = _("Some python modules are missing") miss2 = _("Please install the following python modules:") MODULEMISSING = f"{miss1} \n{miss2}" dmiss1 = _("Some remote dbus objects are missing.") dmiss2 = _("Please start the following applications:") DBUSMISSING = f"{dmiss1} \n{dmiss2}" bmiss1 = _("Some modules and remote dbus objects are missing.") bmiss2 = _("Please install or start the following components:") MODULANDDBUS = f"{bmiss1} \n{bmiss2}" umiss1 = _("Unknown error while loading the plugin.") umiss2 = _("Very helpful message, isn't it? Please report a bug.") UNKNOWN = f"{umiss1} \n{umiss2}"
def __build_window(self): """Build up the widget""" self.set_type_hint(Gdk.WindowTypeHint.POPUP_MENU) vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) self.add(vbox) # icon list scld_win = Gtk.ScrolledWindow() scld_win.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.ALWAYS) scld_win.set_shadow_type(Gtk.ShadowType.ETCHED_IN) vbox.pack_start(scld_win, True, True, 0) self.symbol_iv = Gtk.IconView() self.symbol_iv.set_pixbuf_column(0) self.symbol_iv.set_columns(7) self.symbol_iv.set_item_width(32) # IconView size: # -------------- # it seems that with the above parameters, a row width is about: # item_count * (32px (item) + 6px (dflt padding) + 2px (spacing?)) \ # + 2*6px (dflt widget margin) # The same goes for row height, but being right for this value is less # important due to the vertical scrollbar. # The IcVw size should fit the width of 7 cols and height of ~4 lines. SIZE_REQUEST = (40 * 7 + 12, 38 * 4) self.symbol_iv.set_size_request(*SIZE_REQUEST) scld_win.set_size_request(*SIZE_REQUEST) scld_win.add(self.symbol_iv) # icon remove button self.remove_bt = Gtk.Button() self.remove_bt.set_label(_("Remove selected icon")) vbox.pack_start(self.remove_bt, False, False, 0) # set the callbacks self.symbol_iv.connect("selection-changed", self.on_selection_changed) self.remove_bt.connect("clicked", self.on_remove_bt_clicked)
def _populate_task(self, task, bug_dic): ''' Fills a GTG task with the data from a launchpad bug. @param task: a Task @param bug: a launchpad bug dictionary, generated with _prefetch_bug_data ''' # set task status if bug_dic["completed"]: task.set_status(Task.STA_DONE) else: task.set_status(Task.STA_ACTIVE) if task.get_title() != bug_dic['title']: task.set_title("{} {}: {}".format(_("Bug"), bug_dic["number"], bug_dic['title'])) text = self._build_bug_text(bug_dic) if task.get_excerpt() != text: task.set_text(text) new_tags_sources = [] if self._parameters["import-bug-tags"]: new_tags_sources += bug_dic['tags'] if self._parameters["tag-with-project-name"]: new_tags_sources += [ dic['project_short'] for dic in bug_dic['projects'] ] new_tags = set(['@' + str(tag) for tag in new_tags_sources]) current_tags = set(task.get_tags_name()) # remove the lost tags for tag in current_tags.difference(new_tags): task.remove_tag(tag) # add the new ones for tag in new_tags.difference(current_tags): task.add_tag(tag) task.add_remote_id(self.get_id(), bug_dic['self_link'])
def __init__(self, requester): self.req = requester self.config = self.req.get_config("plugins") builder = Gtk.Builder() builder.add_from_file(ViewConfig.PLUGINS_UI_FILE) self.dialog = builder.get_object("PluginsDialog") self.dialog.set_title(_(f"Plugins - {info.NAME}")) self.plugin_tree = builder.get_object("PluginTree") self.plugin_configure = builder.get_object("plugin_configure") self.plugin_about = builder.get_object("PluginAboutDialog") self.plugin_depends = builder.get_object('PluginDepends') self.pengine = PluginEngine() # see constants PLUGINS_COL_* for column meanings self.plugin_store = Gtk.ListStore(str, bool, str, str, bool) builder.connect_signals({ 'on_PluginsDialog_delete_event': self.on_close, 'on_PluginTree_cursor_changed': self.on_plugin_select, 'on_plugin_about': self.on_plugin_about, 'on_plugin_configure': self.on_plugin_configure, 'on_PluginAboutDialog_close': self.on_plugin_about_close, })
def _populate_task(self, task, issue_dic): """ Fills a GTG task with the data from a mantis issue. @param task: a Task @param issue_dic: a mantis issue """ # set task status if issue_dic["completed"]: task.set_status(Task.STA_DONE) else: task.set_status(Task.STA_ACTIVE) if task.get_title() != issue_dic["title"]: task.set_title("{} {}: {}".format(_("Iss."), issue_dic["number"], issue_dic["title"])) text = self._build_issue_text(issue_dic) if task.get_excerpt() != text: task.set_text(text) new_tags = set([]) if self._parameters["tag-with-project-name"]: new_tags = set(["@" + issue_dic["project"]]) current_tags = set(task.get_tags_name()) # add the new ones for tag in new_tags.difference(current_tags): task.add_tag(tag) task.add_remote_id(self.get_id(), issue_dic["number"])
def to_readable_string(self): """ Return nice representation of date. Fuzzy dates => localized version Close dates => Today, Tomorrow, In X days Other => with locale dateformat, stripping year for this year """ if self._fuzzy is not None: return STRINGS[self._fuzzy] days_left = self.days_left() if days_left == 0: return _('Today') elif days_left < 0: abs_days = abs(days_left) return ngettext('Yesterday', '%(days)d days ago', abs_days) % \ {'days': abs_days} elif days_left > 0 and days_left <= 15: return ngettext('Tomorrow', 'In %(days)d days', days_left) % \ {'days': days_left} else: locale_format = locale.nl_langinfo(locale.D_FMT) if calendar.isleap(datetime.date.today().year): year_len = 366 else: year_len = 365 if float(days_left) / year_len < 1.0: # if it's in less than a year, don't show the year field locale_format = locale_format.replace('/%Y', '') locale_format = locale_format.replace('.%Y', '.') return self._real_date.strftime(locale_format)
def _populate_task(self, task, issue_dic): """ Fills a GTG task with the data from a mantis issue. @param task: a Task @param issue_dic: a mantis issue """ # set task status if issue_dic["completed"]: task.set_status(Task.STA_DONE) else: task.set_status(Task.STA_ACTIVE) if task.get_title() != issue_dic['title']: task.set_title("{} {}: {}".format(_("Iss."), issue_dic["number"], issue_dic['title'])) text = self._build_issue_text(issue_dic) if task.get_excerpt() != text: task.set_text(text) new_tags = set([]) if self._parameters["tag-with-project-name"]: new_tags = set(['@' + issue_dic['project']]) current_tags = set(task.get_tags_name()) # add the new ones for tag in new_tags.difference(current_tags): task.add_tag(tag) task.add_remote_id(self.get_id(), issue_dic['number'])
def _show_gsettings_install_label(self): vbox = self.builder.get_object("prefs-vbox7") label = Gtk.Label() label.set_markup( _("<small>Please install <i><b>gsettings</b></i> " "to enable New task shortcut</small>")) vbox.add(label)
def __init__(self, task_id, requester, newtask=False): super().__init__(task_id) # the id of this task in the project should be set # tid is a string ! (we have to choose a type and stick to it) assert (isinstance(task_id, str) or isinstance(task_id, str)) self.tid = str(task_id) self.set_uuid(uuid.uuid4()) self.remote_ids = {} self.content = "" self.title = _("My new task") # available status are: Active - Done - Dismiss - Note self.status = self.STA_ACTIVE self.added_date = Date.no_date() if newtask: self.added_date = datetime.now() self.closed_date = Date.no_date() self.due_date = Date.no_date() self.start_date = Date.no_date() self.can_be_deleted = newtask # tags self.tags = [] self.req = requester self.__main_treeview = requester.get_main_view() # If we don't have a newtask, we will have to load it. self.loaded = newtask # Should not be necessary with the new backends # if self.loaded: # self.req._task_loaded(self.tid) self.attributes = {} self._modified_update()
def __init__(self, ze_id, requester, newtask=False): TreeNode.__init__(self, ze_id) # the id of this task in the project should be set # tid is a string ! (we have to choose a type and stick to it) assert(isinstance(ze_id, str) or isinstance(ze_id, str)) self.tid = str(ze_id) self.set_uuid(uuid.uuid4()) self.remote_ids = {} self.content = "" self.title = _("My new task") # available status are: Active - Done - Dismiss - Note self.status = self.STA_ACTIVE self.closed_date = Date.no_date() self.due_date = Date.no_date() self.start_date = Date.no_date() self.can_be_deleted = newtask # tags self.tags = [] self.req = requester self.__main_treeview = requester.get_main_view() # If we don't have a newtask, we will have to load it. self.loaded = newtask # Should not be necessary with the new backends # if self.loaded: # self.req._task_loaded(self.tid) self.attributes = {} self._modified_update()
def _populate_gtk(self, width): '''Creates the gtk widgets @param width: the width of the Gtk.Label object ''' period_label = Gtk.Label(label=_("Check for new tasks every")) period_label.set_alignment(xalign=0, yalign=0.5) period_label.set_line_wrap(True) period_label.set_size_request(width=width, height=-1) self.pack_start(period_label, False, True, 0) align = Gtk.Alignment.new(0, 0.5, 1, 0) align.set_padding(0, 0, 10, 0) self.pack_start(align, False, True, 0) period = self.backend.get_parameters()['period'] self.adjustment = Gtk.Adjustment(value=period, lower=1, upper=120, step_incr=1, page_incr=0, page_size=0) self.period_spin = Gtk.SpinButton(adjustment=self.adjustment, climb_rate=0.3, digits=0) self.minutes_label = Gtk.Label() self.update_minutes_label() self.minutes_label.set_alignment(xalign=0, yalign=0.5) self.pack_start(self.minutes_label, False, True, 0) align.add(self.period_spin) self.show_all()
def _init_gtk(self): """ Initialize all the GTK widgets """ self.menu_entry = False self.toolbar_entry = False self.menu_item = Gtk.MenuItem(_("Export the tasks currently listed")) self.menu_item.connect('activate', self.show_dialog) self.menu_item.show() self.tb_button = Gtk.ToolButton(Gtk.STOCK_PRINT) self.tb_button.connect('clicked', self.show_dialog) self.tb_button.show() builder = Gtk.Builder() cur_dir = os.path.dirname(os.path.abspath(__file__)) builder_file = os.path.join(cur_dir, "export.ui") builder.add_from_file(builder_file) self.combo = builder.get_object("export_combo_templ") templates_list = Gtk.ListStore( GObject.TYPE_STRING, GObject.TYPE_STRING, GObject.TYPE_STRING, GObject.TYPE_STRING) self.combo.set_model(templates_list) cell = Gtk.CellRendererText() self.combo.pack_start(cell, True) self.combo.add_attribute(cell, 'text', 1) self.export_dialog = builder.get_object("export_dialog") self.export_image = builder.get_object("export_image") self.preferences_dialog = builder.get_object("preferences_dialog") self.pref_menu = builder.get_object("pref_chbox_menu") self.pref_toolbar = builder.get_object("pref_chbox_toolbar") self.description_label = builder.get_object("label_description") self.save_button = builder.get_object("export_btn_save") self.open_button = builder.get_object("export_btn_open") self.export_all_active = builder.get_object( "export_all_active_rb") self.export_all_active.set_active(True) self.export_finished_last_week = builder.get_object( "export_finished_last_week_rb") self.export_all_finished = builder.get_object( "export_all_finished_rb") builder.connect_signals({ "on_export_btn_open_clicked": lambda widget: self.on_export_start(False), "on_export_btn_save_clicked": lambda widget: self.on_export_start(True), "on_export_dialog_delete_event": self._hide_dialog, "on_export_combo_templ_changed": self.on_combo_changed, "on_preferences_dialog_delete_event": self.on_preferences_cancel, "on_btn_preferences_cancel_clicked": self.on_preferences_cancel, "on_btn_preferences_ok_clicked": self.on_preferences_ok, })
def __init__(self, requester): self.req = requester self.config = self.req.get_config("plugins") builder = Gtk.Builder() builder.add_from_file(ViewConfig.PLUGINS_UI_FILE) self.dialog = builder.get_object("PluginsDialog") self.dialog.set_title(_("Plugins - %s" % info.NAME)) self.plugin_tree = builder.get_object("PluginTree") self.plugin_configure = builder.get_object("plugin_configure") self.plugin_about = builder.get_object("PluginAboutDialog") self.plugin_depends = builder.get_object("PluginDepends") help.add_help_shortcut(self.dialog, "plugins") self.pengine = PluginEngine() # plugin config initiation if self.pengine.get_plugins(): self.config.set("disabled", [p.module_name for p in self.pengine.get_plugins("disabled")]) self.config.set("enabled", [p.module_name for p in self.pengine.get_plugins("enabled")]) # see constants PLUGINS_COL_* for column meanings self.plugin_store = Gtk.ListStore(str, bool, str, str, bool) builder.connect_signals( { "on_plugins_help": self.on_help, "on_plugins_close": self.on_close, "on_PluginsDialog_delete_event": self.on_close, "on_PluginTree_cursor_changed": self.on_plugin_select, "on_plugin_about": self.on_plugin_about, "on_plugin_configure": self.on_plugin_configure, "on_PluginAboutDialog_close": self.on_plugin_about_close, } )
def _populate_task(self, task, bug_dic): ''' Fills a GTG task with the data from a launchpad bug. @param task: a Task @param bug: a launchpad bug dictionary, generated with _prefetch_bug_data ''' # set task status if bug_dic["completed"]: task.set_status(Task.STA_DONE) else: task.set_status(Task.STA_ACTIVE) if task.get_title() != bug_dic['title']: task.set_title("{} {}: {}".format( _("Bug"), bug_dic["number"], bug_dic['title'])) text = self._build_bug_text(bug_dic) if task.get_excerpt() != text: task.set_text(text) new_tags_sources = [] if self._parameters["import-bug-tags"]: new_tags_sources += bug_dic['tags'] if self._parameters["tag-with-project-name"]: new_tags_sources += [dic['project_short'] for dic in bug_dic['projects']] new_tags = set(['@' + str(tag) for tag in new_tags_sources]) current_tags = set(task.get_tags_name()) # remove the lost tags for tag in current_tags.difference(new_tags): task.remove_tag(tag) # add the new ones for tag in new_tags.difference(current_tags): task.add_tag(tag) task.add_remote_id(self.get_id(), bug_dic['self_link'])
def delete_tags(self, tags=None): self.tags_todelete = tags or self.tags_todelete if not self.tags_todelete: # We must at least have something to delete ! return [] # Prepare labels singular = len(self.tags_todelete) cancel_text = ngettext("Keep selected tag", "Keep selected tags", singular) delete_text = ngettext("Permanently remove tag", "Permanently remove tags", singular) label_text = ngettext( "Deleting a tag cannot be undone, " "and will delete the following tag: ", "Deleting a tag cannot be undone, " "and will delete the following tag: ", singular) label_text = label_text[0:label_text.find(":") + 1] # we don't want to end with just one task that doesn't fit the # screen and a line saying "And one more task", so we go a # little over our limit tags_count = len(self.tags_todelete) missing_tags_count = tags_count - self.MAXIMUM_TAGS_TO_SHOW if missing_tags_count >= 2: tagslist = self.tags_todelete[:self.MAXIMUM_TAGS_TO_SHOW] titles_suffix = _("\nAnd %d more tags") % missing_tags_count else: tagslist = self.tags_todelete titles_suffix = "" titles = "".join("\n• " + tag for tag in tagslist) # Build and run dialog dialog = Gtk.MessageDialog(transient_for=self.browser, modal=True) dialog.add_button(cancel_text, Gtk.ResponseType.CANCEL) delete_btn = dialog.add_button(delete_text, Gtk.ResponseType.YES) delete_btn.get_style_context().add_class("destructive-action") dialog.props.use_markup = True dialog.props.text = "<span weight=\"bold\">" + label_text + "</span>" dialog.props.secondary_text = titles + titles_suffix response = dialog.run() dialog.destroy() if response == Gtk.ResponseType.YES: self.on_delete_confirm() elif response == Gtk.ResponseType.REJECT: tagslist = [] return tagslist
def common_desc_for_tasks(self, tree, title_label): desc = {} # invisible 'task_id' column col_name = 'task_id' col = {} col['renderer'] = ['markup', Gtk.CellRendererText()] col['value'] = [str, lambda node: node.get_id()] col['visible'] = False col['order'] = 0 desc[col_name] = col # invisible 'bg_color' column col_name = 'bg_color' col = {} col['value'] = [str, lambda node: None] col['visible'] = False desc[col_name] = col # invisible 'title' column col_name = 'title' col = {} render_text = Gtk.CellRendererText() render_text.set_property("ellipsize", Pango.EllipsizeMode.END) col['renderer'] = ['markup', render_text] col['value'] = [str, self.task_title_column] col['visible'] = False col['order'] = 0 col['sorting_func'] = self.title_sorting desc[col_name] = col # "tags" column (no title) col_name = 'tags' col = {} render_tags = CellRendererTags() render_tags.set_property('xalign', 0.0) col['renderer'] = ['tag_list', render_tags] col['value'] = [GObject.TYPE_PYOBJECT, self.task_tags_column] col['expandable'] = False col['resizable'] = False col['order'] = 1 desc[col_name] = col # "label" column col_name = 'label' col = {} col['title'] = _(title_label) render_text = Gtk.CellRendererText() render_text.set_property("ellipsize", Pango.EllipsizeMode.END) col['renderer'] = ['markup', render_text] col['value'] = [str, self.task_label_column] col['expandable'] = True col['resizable'] = True col['sorting'] = 'title' col['order'] = 2 desc[col_name] = col return desc
def __init__(self, tag_completion, req): self.req = req self.tasks = [] self._init_dialog() self.tag_entry.set_completion(tag_completion) # Rember values from last time self.last_tag_entry = _("NewTag") self.last_apply_to_subtasks = False
def notify_user_about_backup(self): """ This function causes the inforbar to show up with the message about file recovery. """ message = _("Oops, something unexpected happened! " "GTG tried to recover your tasks from backups. \n" ) + self.backup_file_info() BackendSignals().interaction_requested( self.get_id(), message, BackendSignals().INTERACTION_INFORM, "on_continue_clicked")
def _init_gtk(self): """ Initialize all the GTK widgets """ self.tb_button = Gtk.ToolButton() self.tb_button.set_sensitive(False) self.tb_button.set_icon_name("document-revert") self.tb_button.set_is_important(True) self.tb_button.set_label(_("Do it tomorrow")) self.tb_button.connect('clicked', self.mark_not_today) self.tb_button.show() self.plugin_api.add_toolbar_item(self.tb_button)
def notify_user_about_backup(self): """ This function causes the inforbar to show up with the message about file recovery. """ message = _( "Oops, something unexpected happened! " "GTG tried to recover your tasks from backups. \n" ) + self.backup_file_info() BackendSignals().interaction_requested( self.get_id(), message, BackendSignals().INTERACTION_INFORM, "on_continue_clicked")
def onTbTaskButton(self, widget, plugin_api): """ When the user presses the button. """ task = plugin_api.get_ui().get_task() # Body contains Status Tags, Subtasks and Content. body = _("Status: %s") % (task.get_status()) + \ _("\nTags: %s") % (", ".join(task.get_tags_name())) + \ _("\nSubtasks:\n%s") % ( "\n - ".join([i.get_title() for i in task.get_subtasks()])) + \ _("\nTask content:\n%s") % (task.get_excerpt()) # Title contains the title and the start and due dates. title = _("Task: %(task_title)s") % {'task_title': task.get_title()} parameters = urllib.parse.urlencode({'subject': title, 'body': body}) parameters = parameters.replace('+', '%20') Gio.app_info_get_default_for_uri_scheme('mailto').launch_uris( ['mailto:' + '[email protected]?' + parameters], None)
def tags_treeview(self, tree): desc = {} # Tag id col_name = 'tag_id' col = {} col['renderer'] = ['markup', Gtk.CellRendererText()] col['value'] = [str, lambda node: node.get_id()] col['visible'] = False col['order'] = 0 col['sorting_func'] = self.tag_sorting desc[col_name] = col # Tags color col_name = 'color' col = {} render_tags = CellRendererTags() render_tags.set_property('ypad', 3) col['title'] = _("Tags") col['renderer'] = ['tag', render_tags] col['value'] = [GObject.TYPE_PYOBJECT, lambda node: node] col['expandable'] = False col['resizable'] = False col['order'] = 1 desc[col_name] = col # Tag names col_name = 'tagname' col = {} render_text = Gtk.CellRendererText() render_text.set_property('ypad', 3) col['renderer'] = ['markup', render_text] col['value'] = [str, self.tag_name] col['expandable'] = True col['new_column'] = False col['order'] = 2 desc[col_name] = col # Tag count col_name = 'tagcount' col = {} render_text = Gtk.CellRendererText() render_text.set_property('xpad', 3) render_text.set_property('ypad', 3) render_text.set_property('xalign', 1.0) col['renderer'] = ['markup', render_text] col['value'] = [str, self.get_tag_count] col['expandable'] = False col['new_column'] = False col['order'] = 3 desc[col_name] = col return self.build_tag_treeview(tree, desc)