Example #1
0
    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)
Example #2
0
    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)
Example #3
0
    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)
Example #4
0
    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)
Example #5
0
    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')
Example #6
0
    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()
Example #7
0
    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')
Example #8
0
    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()
Example #9
0
    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)
Example #10
0
    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)
Example #11
0
    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)
Example #12
0
    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)
Example #13
0
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)
Example #14
0
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)