def _post_init(self): text = core_api.get_item_text(self.filename, self.id_) title = self.make_title(text) self.area = textarea.TextArea(self.filename, self.id_, self.item, text) self.pbox.Add(self.area.area, proportion=1, flag=wx.EXPAND) self.accelerators = {} open_editor_event.signal(filename=self.filename, id_=self.id_, item=self.item, text=text) aconfig = config("ContextualShortcuts")("RightNotebook")("Editor") self.accelerators.update({ aconfig["apply"]: lambda event: self.apply(), aconfig["find"]: lambda event: self.find_in_tree(), aconfig["focus_text"]: lambda event: self.focus_text(), }) self.accelerators.update( wx.GetApp().nb_right.get_generic_accelerators()) acctable = wx.GetApp().root.accmanager.generate_table( wx.GetApp().nb_right, self.accelerators) self.panel.store_accelerators_table(acctable) nb = wx.GetApp().nb_right nb.add_page(self.panel, title, select=True, imageId=nb.editors.icon_index)
def snooze_alarms(self, alarmsd, stime, newalarm): for id_ in alarmsd: for alarmid in alarmsd[id_]: text = core_api.get_item_text(self.filename, id_) qconn = core_api.get_connection(self.filename) cursor = qconn.cursor() cursor.execute(queries.alarms_update_id, (newalarm, alarmid)) core_api.give_connection(self.filename, qconn) self._insert_alarm_log(id_, 0, text.partition('\n')[0]) # Signal the event after updating the database, so, for # example, the tasklist can be correctly updated alarm_off_event.signal(filename=self.filename, id_=id_, alarmid=alarmid)
def _handle_alarm(self, kwargs): now = int(time.time()) // 60 * 60 # Don't notify for old alarms to avoid filling the screen with # notifications # Of course this check will prevent a valid notification if Outspline # takes more than 1 minute from the activation of the alarm to get # here, but in case of such serious slowness, a missed notification is # probably just a minor problem if kwargs['alarm'] == now: filename = kwargs['filename'] id_ = kwargs['id_'] start = kwargs['start'] end = kwargs['end'] text = core_api.get_item_text(filename, id_).partition('\n')[0] rstart = start - now if rstart > 0: body = "In {}".format( TimeSpanFormatters.format_compact(rstart)) elif rstart == 0: body = "Now" else: body = "{} ago".format( TimeSpanFormatters.format_compact(rstart * -1)) if end: body += ", for {}".format( TimeSpanFormatters.format_compact(end - start)) self.alarm = Notify.Notification.new(summary=text, body=body, icon=self.ICON) if wxgui_api: self.alarm.add_action("open_item", "Open", self._open_item, [filename, id_]) try: self.alarm.show() except GLib.Error: log.warning('Alarm notification could not be displayed: check ' 'that you have a notification server installed, ' 'properly configured and running')
def _update_pane_ancestors(self, event): # Reset ancestors with EVT_COLLAPSIBLEPANE_CHANGED, otherwise they # should be reset everytime one of them is updated # This way if an ancestor is updated while the collapsible pane is # expanded, it will have to be collapsed and expanded again to be # reset, but that is a reasonable compromise if not event.GetCollapsed(): # Get the size of the panel *before* adding or destroying any # children psize = self.pane.GetSize() self.cpane.DestroyChildren() for anc in core_api.get_item_ancestors(self.filename, self.id_): ancestor = wx.StaticText(self.cpane) # Setting the label directly when instantiating StaticText # through the 'label' parameter would make it parse '&' # characters to form mnemonic shortcuts, like in menus # Note that in this case the '&' characters have to be escaped # explicitly ancestor.SetLabel(core_api.get_item_text(self.filename, anc ).partition('\n')[0].replace('&', '&&')) self.cbox.Add(ancestor, flag=wx.LEFT | wx.TOP, border=4) dbname = wx.StaticText(self.cpane) # Setting the label directly when instantiating StaticText through # the 'label' parameter would make it parse '&' characters to form # mnemonic shortcuts, like in menus dbname.SetLabel(_os.path.basename(self.filename).replace('&', '&&')) self.cbox.Add(dbname, flag=wx.LEFT | wx.TOP, border=4) # Without these operations, the panel's expanded height would # always be the one of its previous state (0 at the first expansion # attempt) self.cpane.Fit() csize = self.cpane.GetSize() psize.SetHeight(psize.GetHeight() + csize.GetHeight()) self.pane.SetMinSize(psize) # This in conjunction with the wx.CP_NO_TLW_RESIZE style are necessary # for the correct functioning of the collapsible pane self.panel.GetParent().SendSizeEvent()
def _handle_alarm(self, kwargs): now = int(time.time()) // 60 * 60 # Don't notify for old alarms to avoid filling the screen with # notifications # Of course this check will prevent a valid notification if Outspline # takes more than 1 minute from the activation of the alarm to get # here, but in case of such serious slowness, a missed notification is # probably just a minor problem if kwargs['alarm'] == now: filename = kwargs['filename'] id_ = kwargs['id_'] start = kwargs['start'] end = kwargs['end'] text = core_api.get_item_text(filename, id_).partition('\n')[0] rstart = start - now if rstart > 0: body = "In {}".format(TimeSpanFormatters.format_compact( rstart)) elif rstart == 0: body = "Now" else: body = "{} ago".format(TimeSpanFormatters.format_compact( rstart * -1)) if end: body += ", for {}".format(TimeSpanFormatters.format_compact( end - start)) self.alarm = Notify.Notification.new(summary=text, body=body, icon=self.ICON) if wxgui_api: self.alarm.add_action("open_item", "Open", self._open_item, [filename, id_]) try: self.alarm.show() except GLib.Error: log.warning('Alarm notification could not be displayed: check ' 'that you have a notification server installed, ' 'properly configured and running')
def _init_widgets(self, parent): hbox = wx.BoxSizer(wx.HORIZONTAL) self.pbox.Add(hbox, flag=wx.EXPAND | wx.ALL, border=4) startdate = wx.StaticText(parent, label=_time.strftime( '%Y.%m.%d %H:%M', _time.localtime(self.start))) hbox.Add(startdate, 1, flag=wx.ALIGN_CENTER_VERTICAL) button_s = wx.Button(parent, label='Snooze', style=wx.BU_EXACTFIT) hbox.Add(button_s) button_d = wx.Button(parent, label='Dismiss', style=wx.BU_EXACTFIT) hbox.Add(button_d, flag=wx.LEFT, border=4) button_e = wx.Button(parent, label='Open', style=wx.BU_EXACTFIT) hbox.Add(button_e, flag=wx.LEFT, border=4) # wx.CP_NO_TLW_RESIZE in conjunction with # self.panel.GetParent().SendSizeEvent() on EVT_COLLAPSIBLEPANE_CHANGED # are necessary for the correct functioning self.pane = wx.CollapsiblePane(parent, style=wx.CP_NO_TLW_RESIZE) # Setting the label directly when instantiating CollapsiblePane through # the 'label' parameter would make it parse '&' characters to form # mnemonic shortcuts, like in menus self._set_pane_label(core_api.get_item_text(self.filename, self.id_)) self.pbox.Add(self.pane, flag=wx.EXPAND | wx.BOTTOM, border=4) self.cpane = self.pane.GetPane() self.cbox = wx.BoxSizer(wx.VERTICAL) self.cpane.SetSizer(self.cbox) line = wx.StaticLine(parent, style=wx.LI_HORIZONTAL) self.pbox.Add(line, flag=wx.EXPAND) core_api.bind_to_update_item_text(self._update_info) self.panel.Bind(wx.EVT_COLLAPSIBLEPANE_CHANGED, self._update_pane_ancestors) self.panel.Bind(wx.EVT_BUTTON, self.snooze, button_s) self.panel.Bind(wx.EVT_BUTTON, self.dismiss, button_d) self.panel.Bind(wx.EVT_BUTTON, self._open, button_e)
def dismiss_alarms(self, alarmsd): for id_ in alarmsd: for alarmid in alarmsd[id_]: text = core_api.get_item_text(self.filename, id_) qconn = core_api.get_connection(self.filename) cursor = qconn.cursor() cursor.execute(queries.alarms_delete_id, (alarmid, )) core_api.give_connection(self.filename, qconn) self._insert_alarm_log(id_, 1, text.partition('\n')[0]) # It's necessary to change the dismiss status, otherwise it's # possible that a database is loaded and some of its alarms are # activated: if at that point those alarms are dismissed and # then the user tries to close the database, the database will # seem unmodified, and won't ask to be saved self.modified_state = True # Signal the event after updating the database, so, for # example, the tasklist can be correctly updated alarm_off_event.signal(filename=self.filename, id_=id_, alarmid=alarmid)
def upsert_link(filename, id_, target, group, description='Insert link'): # target could be None (creating a broken link) or could be a no-longer # existing item if core_api.is_item(filename, target): # Forbid circular links (including links to self), as it could generate # unexpected infinite recursions (e.g. with synchronize_links_text) if id_ in find_links_chain(filename, target): raise exceptions.CircularLinksError() else: # Sync text tgttext = core_api.get_item_text(filename, target) core_api.update_item_text(filename, id_, tgttext, group=group, description=description) # Drop any rules if organism_api and filename in \ organism_api.get_supported_open_databases(): organism_api.update_item_rules(filename, id_, [], group=group, description=description) else: # Force target = None if the given target no longer exists target = None # Drop any rules if organism_api and filename in \ organism_api.get_supported_open_databases(): organism_api.update_item_rules(filename, id_, [], group=group, description=description) # Note that exceptions.CircularLinksError could be raised before getting # here qconn = core_api.get_connection(filename) cursor = qconn.cursor() cursor.execute(queries.links_select_id, (id_, )) res = cursor.fetchone() # Do not allow creating more than one link per item if res: oldtarget = res['L_target'] do_update_link(filename, cursor, target, id_) core_api.give_connection(filename, qconn) core_api.insert_history(filename, group, id_, 'link_update', description, str(target) if target is not None else None, oldtarget if str(oldtarget) is not None else None) else: oldtarget = False # 'target' can be None, thus allowing the creation of a broken link do_insert_link(filename, cursor, id_, target) core_api.give_connection(filename, qconn) core_api.insert_history(filename, group, id_, 'link_insert', description, str(target) if target is not None else None, None) upsert_link_event.signal(filename=filename, id_=id_, target=target, oldtarget=oldtarget)
def upsert_link(filename, id_, target, group, description='Insert link'): # target could be None (creating a broken link) or could be a no-longer # existing item if core_api.is_item(filename, target): # Forbid circular links (including links to self), as it could generate # unexpected infinite recursions (e.g. with synchronize_links_text) if id_ in find_links_chain(filename, target): raise exceptions.CircularLinksError() else: # Sync text tgttext = core_api.get_item_text(filename, target) core_api.update_item_text(filename, id_, tgttext, group=group, description=description) # Drop any rules if organism_api and filename in \ organism_api.get_supported_open_databases(): organism_api.update_item_rules(filename, id_, [], group=group, description=description) else: # Force target = None if the given target no longer exists target = None # Drop any rules if organism_api and filename in \ organism_api.get_supported_open_databases(): organism_api.update_item_rules(filename, id_, [], group=group, description=description) # Note that exceptions.CircularLinksError could be raised before getting # here qconn = core_api.get_connection(filename) cursor = qconn.cursor() cursor.execute(queries.links_select_id, (id_, )) res = cursor.fetchone() # Do not allow creating more than one link per item if res: oldtarget = res['L_target'] do_update_link(filename, cursor, target, id_) core_api.give_connection(filename, qconn) core_api.insert_history( filename, group, id_, 'link_update', description, str(target) if target is not None else None, oldtarget if str(oldtarget) is not None else None) else: oldtarget = False # 'target' can be None, thus allowing the creation of a broken link do_insert_link(filename, cursor, id_, target) core_api.give_connection(filename, qconn) core_api.insert_history(filename, group, id_, 'link_insert', description, str(target) if target is not None else None, None) upsert_link_event.signal(filename=filename, id_=id_, target=target, oldtarget=oldtarget)