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 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 delete_tags(self, tags=None): if tags: self.tags_todelete = tags # We must at least have something to delete ! if len(self.tags_todelete) > 0: # We fill the text and the buttons' labels according to the number # of tags to delete label = self.builder.get_object("label1") label_text = label.get_text() cdlabel2 = self.builder.get_object("cd-label2") cdlabel3 = self.builder.get_object("cd-label3") cdlabel4 = self.builder.get_object("cd-label4") singular = len(self.tags_todelete) 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) cdlabel2.set_label( ngettext("Are you sure you want to delete this" " tag?", "Are you sure you want to delete " "these tags?", singular)) cdlabel3.set_label( ngettext("Keep selected tag", "Keep selected tags", singular)) cdlabel4.set_label( ngettext("Permanently remove tag", "Permanently remove tags", 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) label.set_text(label_text + titles + titles_suffix) delete_dialog = self.builder.get_object("confirm_delete_tag") delete_dialog.resize(1, 1) cancel_button = self.builder.get_object("cancel") cancel_button.grab_focus() if delete_dialog.run() != 1: self.tags_todelete = [] delete_dialog.hide() return tagslist else: return []
def refresh_day_left(self): # If the task is marked as done, we display the delay between the # due date and the actual closing date. If the task isn't marked # as done, we display the number of days left. status = self.task.get_status() if status in [Task.STA_DISMISSED, Task.STA_DONE]: delay = self.task.get_days_late() if delay is None: txt = "" elif delay == 0: txt = "Completed on time" elif delay >= 1: txt = ngettext("Completed %(days)d day late", "Completed %(days)d days late", delay) % \ {'days': delay} elif delay <= -1: abs_delay = abs(delay) txt = ngettext("Completed %(days)d day early", "Completed %(days)d days early", abs_delay) % \ {'days': abs_delay} else: due_date = self.task.get_due_date() result = due_date.days_left() if due_date.is_fuzzy(): txt = "" elif result > 0: txt = ngettext("Due tomorrow!", "%(days)d days left", result)\ % {'days': result} elif result == 0: txt = _("Due today!") elif result < 0: abs_result = abs(result) txt = ngettext("Due yesterday!", "Was %(days)d days ago", abs_result) % { 'days': abs_result } style_context = self.window.get_style_context() color = style_context.get_color(Gtk.StateFlags.INSENSITIVE).to_color() self.dayleft_label.set_markup( f"<span color='{color.to_string()}'>{txt}</span>")
def on_combo_changed(self, widget=None): """ Updates the backend description and icon. @param widget: just to make this function usable as a signal callback. Not used. """ backend_name = self.combo_types.get_selected() if backend_name is None: return backend = BackendFactory().get_backend(backend_name) self.label_description.set_markup(backend.Backend.get_description()) markup = '<big><big><big><b>%s</b></big></big></big>' % \ backend.Backend.get_human_default_name() self.label_name.set_markup(markup) authors = backend.Backend.get_authors() author_txt = '<b>%s</b>:\n - %s' % \ (ngettext("Author", "Authors", len(authors)), reduce(lambda a, b: a + "\n" + " - " + b, authors)) self.label_author.set_markup(author_txt) pixbuf = self.dialog.get_pixbuf_from_icon_name(backend_name, 128) self.image_icon.set_from_pixbuf(pixbuf) self.show_all()
def on_combo_changed(self, widget=None): ''' Updates the backend description and icon. @param widget: just to make this function usable as a signal callback. Not used. ''' backend_name = self.combo_types.get_selected() if backend_name is None: return backend = BackendFactory().get_backend(backend_name) self.label_description.set_markup(backend.Backend.get_description()) markup = '<big><big><big><b>%s</b></big></big></big>' % \ backend.Backend.get_human_default_name() self.label_name.set_markup(markup) authors = backend.Backend.get_authors() author_txt = '<b>%s</b>:\n - %s' % \ (ngettext("Author", "Authors", len(authors)), reduce(lambda a, b: a + "\n" + " - " + b, authors)) self.label_author.set_markup(author_txt) pixbuf = self.dialog.get_pixbuf_from_icon_name(backend_name, 128) self.image_icon.set_from_pixbuf(pixbuf) self.show_all()
def update_minutes_label(self): adjustment = int(self.adjustment.get_value()) self.minutes_label.set_markup( ngettext(" minute", " minutes", adjustment))
def show(self, tids=None): self.tids_todelete = tids or self.tids_todelete if not self.tids_todelete: # We must at least have something to delete! return [] # Get full task list to delete tasklist = [] self.update_tags = [] for tid in self.tids_todelete: task = self.req.get_task(tid) self.recursive_list_tasks(tasklist, task) # Prepare Labels singular = len(tasklist) cancel_text = ngettext("Keep selected task", "Keep selected tasks", singular) delete_text = ngettext("Permanently remove task", "Permanently remove tasks", singular) label_text = ngettext( "Deleting a task cannot be undone, " "and will delete the following task: ", "Deleting a task cannot be undone, " "and will delete the following tasks: ", singular) label_text = label_text[0:label_text.find(":") + 1] missing_titles_count = len(tasklist) - self.MAXIMUM_TIDS_TO_SHOW if missing_titles_count >= 2: tasks = tasklist[:self.MAXIMUM_TIDS_TO_SHOW] titles_suffix = _("\nAnd %d more tasks" % missing_titles_count) else: tasks = tasklist titles_suffix = "" titles = "".join("\n• " + task.get_title() for task in tasks) # Build and run dialog dialog = Gtk.MessageDialog(transient_for=self.window, 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: tasklist = [] return tasklist
def refresh_editor(self, title=None, refreshtext=False): if self.window is None: return to_save = False # title of the window if title: self.window.set_title(title) to_save = True else: self.window.set_title(self.task.get_title()) status = self.task.get_status() dismiss_tooltip = GnomeConfig.MARK_DISMISS_TOOLTIP undismiss_tooltip = GnomeConfig.MARK_UNDISMISS_TOOLTIP if status == Task.STA_DISMISSED: self.donebutton.set_label(GnomeConfig.MARK_DONE) self.donebutton.set_tooltip_text(GnomeConfig.MARK_DONE_TOOLTIP) self.donebutton.set_stock_id(Gtk.STOCK_APPLY) self.dismissbutton.set_label(GnomeConfig.MARK_UNDISMISS) self.dismissbutton.set_tooltip_text(undismiss_tooltip) self.dismissbutton.set_stock_id(Gtk.STOCK_REFRESH) elif status == Task.STA_DONE: self.donebutton.set_label(GnomeConfig.MARK_UNDONE) self.donebutton.set_tooltip_text(GnomeConfig.MARK_UNDONE_TOOLTIP) self.donebutton.set_stock_id(Gtk.STOCK_REFRESH) self.dismissbutton.set_label(GnomeConfig.MARK_DISMISS) self.dismissbutton.set_tooltip_text(dismiss_tooltip) self.dismissbutton.set_stock_id(Gtk.STOCK_CLOSE) else: self.donebutton.set_label(GnomeConfig.MARK_DONE) self.donebutton.set_tooltip_text(GnomeConfig.MARK_DONE_TOOLTIP) self.donebutton.set_stock_id(Gtk.STOCK_APPLY) self.dismissbutton.set_label(GnomeConfig.MARK_DISMISS) self.dismissbutton.set_tooltip_text(dismiss_tooltip) self.dismissbutton.set_stock_id(Gtk.STOCK_CLOSE) self.donebutton.show() self.tasksidebar.show() # Refreshing the status bar labels and date boxes if status in [Task.STA_DISMISSED, Task.STA_DONE]: self.builder.get_object("label2").hide() self.builder.get_object("box1").hide() self.builder.get_object("label4").show() self.builder.get_object("box4").show() else: self.builder.get_object("label4").hide() self.builder.get_object("box4").hide() self.builder.get_object("label2").show() self.builder.get_object("box1").show() # refreshing the start date field startdate = self.task.get_start_date() try: prevdate = Date.parse(self.startdate_widget.get_text()) update_date = startdate != prevdate except ValueError: update_date = True if update_date: self.startdate_widget.set_text(str(startdate)) # refreshing the due date field duedate = self.task.get_due_date() try: prevdate = Date.parse(self.duedate_widget.get_text()) update_date = duedate != prevdate except ValueError: update_date = True if update_date: self.duedate_widget.set_text(str(duedate)) # refreshing the closed date field closeddate = self.task.get_closed_date() prevcldate = Date.parse(self.closeddate_widget.get_text()) if closeddate != prevcldate: self.closeddate_widget.set_text(str(closeddate)) # refreshing the day left label # If the task is marked as done, we display the delay between the # due date and the actual closing date. If the task isn't marked # as done, we display the number of days left. if status in [Task.STA_DISMISSED, Task.STA_DONE]: delay = self.task.get_days_late() if delay is None: txt = "" elif delay == 0: txt = "Completed on time" elif delay >= 1: txt = ngettext("Completed %(days)d day late", "Completed %(days)d days late", delay) % \ {'days': delay} elif delay <= -1: abs_delay = abs(delay) txt = ngettext("Completed %(days)d day early", "Completed %(days)d days early", abs_delay) % \ {'days': abs_delay} else: due_date = self.task.get_due_date() result = due_date.days_left() if due_date.is_fuzzy(): txt = "" elif result > 0: txt = ngettext("Due tomorrow!", "%(days)d days left", result) \ % {'days': result} elif result == 0: txt = _("Due today!") elif result < 0: abs_result = abs(result) txt = ngettext("Due yesterday!", "Was %(days)d days ago", abs_result) % {'days': abs_result} style_context = self.window.get_style_context() color = style_context.get_color(Gtk.StateFlags.INSENSITIVE).to_color() self.dayleft_label.set_markup( "<span color='%s'>%s</span>" % (color.to_string(), txt)) # Refreshing the tag list in the insert tag button taglist = self.req.get_used_tags() menu = Gtk.Menu() tag_count = 0 for tagname in taglist: tag_object = self.req.get_tag(tagname) if not tag_object.is_special() and \ not self.task.has_tags(tag_list=[tagname]): tag_count += 1 mi = Gtk.MenuItem(label=tagname, use_underline=False) mi.connect("activate", self.inserttag, tagname) mi.show() menu.append(mi) if tag_count > 0: self.inserttag_button.set_menu(menu) # Refreshing the parent list in open_parent_button menu = Gtk.Menu() parents = self.task.get_parents() if len(parents) > 0: for parent in self.task.get_parents(): task = self.req.get_task(parent) mi = Gtk.MenuItem(label=task.get_title(), use_underline=False) mi.connect("activate", self.open_parent, parent) mi.show() menu.append(mi) self.open_parents_button.set_menu(menu) else: self.open_parents_button.set_sensitive(False) if refreshtext: self.textview.modified(refresheditor=False) if to_save: self.light_save()
def delete_tasks(self, tids=None): if tids: self.tids_todelete = tids # We must at least have something to delete ! if len(self.tids_todelete) > 0: tasklist = [] self.update_tags = [] for tid in self.tids_todelete: def recursive_list_tasks(task_list, root): """Populate a list of all the subtasks and their children, recursively. Also collect the list of affected tags which should be refreshed""" if root not in task_list: task_list.append(root) for tagname in root.get_tags_name(): if tagname not in self.update_tags: self.update_tags.append(tagname) for i in root.get_subtasks(): if i not in task_list: recursive_list_tasks(task_list, i) task = self.req.get_task(tid) recursive_list_tasks(tasklist, task) # We fill the text and the buttons' labels according to the number # of tasks to delete label = self.builder.get_object("label1") label_text = label.get_text() cdlabel2 = self.builder.get_object("cd_question_label") cdlabel3 = self.builder.get_object("cd_cancel_label") cdlabel4 = self.builder.get_object("cd_delete_label") singular = len(tasklist) label_text = ngettext( "Deleting a task cannot be undone, " "and will delete the following task: ", "Deleting a task cannot be undone, " "and will delete the following tasks: ", singular) cdlabel2.set_label( ngettext("Are you sure you want to delete this" " task?", "Are you sure you want to delete " "these tasks?", singular)) cdlabel3.set_label( ngettext("Keep selected task", "Keep selected tasks", singular)) cdlabel4.set_label( ngettext("Permanently remove task", "Permanently remove tasks", 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 missing_titles_count = len(tasklist) - self.MAXIMUM_TIDS_TO_SHOW if missing_titles_count >= 2: tasks = tasklist[:self.MAXIMUM_TIDS_TO_SHOW] titles_suffix = _("\nAnd %d more tasks" % missing_titles_count) else: tasks = tasklist titles_suffix = "" titles = "".join("\n - " + task.get_title() for task in tasks) label.set_text(label_text + titles + titles_suffix) delete_dialog = self.builder.get_object("confirm_delete") delete_dialog.resize(1, 1) cancel_button = self.builder.get_object("cancel") cancel_button.grab_focus() if delete_dialog.run() != 1: tasklist = [] delete_dialog.hide() return tasklist else: return []
def delete_tasks(self, tids=None): if tids: self.tids_todelete = tids # We must at least have something to delete ! if len(self.tids_todelete) > 0: tasklist = [] self.update_tags = [] for tid in self.tids_todelete: def recursive_list_tasks(task_list, root): """Populate a list of all the subtasks and their children, recursively. Also collect the list of affected tags which should be refreshed""" if root not in task_list: task_list.append(root) for tagname in root.get_tags_name(): if tagname not in self.update_tags: self.update_tags.append(tagname) for i in root.get_subtasks(): if i not in task_list: recursive_list_tasks(task_list, i) task = self.req.get_task(tid) recursive_list_tasks(tasklist, task) # We fill the text and the buttons' labels according to the number # of tasks to delete label = self.builder.get_object("label1") label_text = label.get_text() cdlabel2 = self.builder.get_object("cd_question_label") cdlabel3 = self.builder.get_object("cd_cancel_label") cdlabel4 = self.builder.get_object("cd_delete_label") singular = len(tasklist) label_text = ngettext("Deleting a task cannot be undone, " "and will delete the following task: ", "Deleting a task cannot be undone, " "and will delete the following tasks: ", singular) cdlabel2.set_label(ngettext("Are you sure you want to delete this" " task?", "Are you sure you want to delete " "these tasks?", singular)) cdlabel3.set_label(ngettext("Keep selected task", "Keep selected tasks", singular)) cdlabel4.set_label(ngettext("Permanently remove task", "Permanently remove tasks", 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 missing_titles_count = len(tasklist) - self.MAXIMUM_TIDS_TO_SHOW if missing_titles_count >= 2: tasks = tasklist[: self.MAXIMUM_TIDS_TO_SHOW] titles_suffix = _("\nAnd %d more tasks" % missing_titles_count) else: tasks = tasklist titles_suffix = "" titles = "".join("\n - " + task.get_title() for task in tasks) label.set_text(label_text + titles + titles_suffix) delete_dialog = self.builder.get_object("confirm_delete") delete_dialog.resize(1, 1) cancel_button = self.builder.get_object("cancel") cancel_button.grab_focus() if delete_dialog.run() != 1: tasklist = [] delete_dialog.hide() return tasklist else: return []
def update_minutes_label(self): adjustment = int(self.adjustment.get_value()) self.minutes_label.set_markup(ngettext(" minute", " minutes", adjustment))