Example #1
0
        def save(event=None):
            name = name_entry.get().strip()
            if not mailbox:
                # new mailbox
                i = self.b_add.grid_info()['row']
                self.b_add.grid_configure(row=i + 1)
                c = Checkbutton(self.frame)
                c.state(('selected',))
                c.grid(row=i, column=0, pady=4, padx=(4, 0))
                l = Label(self.frame, text=name)
                l.grid(row=i, column=1, padx=4, pady=4)
                b_edit = Button(self.frame, image=self.im_edit, width=1,
                                command=lambda m=name: self.mailbox_info(m))
                b_edit.grid(row=i, column=2, padx=4, pady=4)
                b_del = Button(self.frame, image=self.im_del, width=1,
                               command=lambda m=name: self.del_mailbox(m))
                b_del.grid(row=i, column=3, padx=4, pady=4)
                self.mailboxes[name] = [c, l, b_edit, b_del]
            elif name != mailbox:
                # change name of mailbox
                os.remove(os.path.join(LOCAL_PATH, mailbox))
                c, l, b_edit, b_del = self.mailboxes[mailbox]
                del(self.mailboxes[mailbox])
                l.configure(text=name)
                b_edit.configure(command=lambda m=name: self.mailbox_info(m))
                b_del.configure(command=lambda m=name: self.del_mailbox(m))
                self.mailboxes[name] = [c, l, b_edit, b_del]

            encrypt(name, self.pwd, server_entry.get().strip(),
                    login_entry.get().strip(), password_entry.get().strip(),
                    folder_entry.get().strip())
            top.destroy()
Example #2
0
    def __init__(self, master, pwd):
        """Create the mailbox manager dialog."""
        Toplevel.__init__(self, master, class_="CheckMails")
        self.title(_("Mailbox Manager"))
        self.minsize(200, 10)
        self.pwd = pwd
        self.resizable(False, False)
        self.protocol("WM_DELETE_WINDOW", self.quit)
        self.im_add = PhotoImage(master=self, file=ADD)
        self.im_del = PhotoImage(master=self, file=DEL)
        self.im_edit = PhotoImage(master=self, file=EDIT)
        self.mailboxes = {}
        active = CONFIG.get("Mailboxes", "active").split(", ")
        inactive = CONFIG.get("Mailboxes", "inactive").split(", ")
        while "" in active:
            active.remove("")
        while "" in inactive:
            inactive.remove("")
        active.sort()
        inactive.sort()
        self.frame = Frame(self)
        self.columnconfigure(0, weight=1)
        self.frame.columnconfigure(1, weight=1)
        self.frame.grid(row=0, column=0, padx=10, pady=10, sticky="eswn")
        i = -1
        for i, box in enumerate(active):
            c = Checkbutton(self.frame)
            c.state(('selected',))
            c.grid(row=i, column=0, pady=4, padx=(4, 0))
            l = Label(self.frame, text=box)
            l.grid(row=i, column=1, padx=4, pady=4)
            b_edit = Button(self.frame, image=self.im_edit, width=1,
                            command=lambda m=box: self.mailbox_info(m))
            b_edit.grid(row=i, column=2, padx=4, pady=4)
            b_del = Button(self.frame, image=self.im_del, width=1,
                           command=lambda m=box: self.del_mailbox(m))
            b_del.grid(row=i, column=3, padx=4, pady=4)
            self.mailboxes[box] = [c, l, b_edit, b_del]
        for box in inactive:
            i += 1
            c = Checkbutton(self.frame)
            c.grid(row=i, column=0, pady=4, padx=(4, 0))
            l = Label(self.frame, text=box)
            l.grid(row=i, column=1, padx=4, pady=4)
            b_edit = Button(self.frame, image=self.im_edit, width=1,
                            command=lambda m=box: self.mailbox_info(m))
            b_edit.grid(row=i, column=2, padx=4, pady=4)
            b_del = Button(self.frame, image=self.im_del, width=1,
                           command=lambda m=box: self.del_mailbox(m))
            b_del.grid(row=i, column=3, padx=4, pady=4)
            self.mailboxes[box] = [c, l, b_edit, b_del]

        self.b_add = Button(self.frame, image=self.im_add, command=self.mailbox_info, width=1)
        self.b_add.grid(row=i + 1, column=0, columnspan=4, pady=4, padx=4, sticky='w')
Example #3
0
class UpdateChecker(Toplevel):

    version_parser = VersionParser()

    def __init__(self, master, notify=False):
        Toplevel.__init__(self, master, class_="CheckMails")
        logging.info('Checking for updates')
        self.title(_("Update"))
        self.withdraw()
        self.rowconfigure(0, weight=1)
        self.columnconfigure(0, weight=1)
        self.columnconfigure(1, weight=1)
        self.protocol("WM_DELETE_WINDOW", self.quit)

        self.notify = notify

        self.img = PhotoImage(file=IM_QUESTION, master=self)

        frame = Frame(self)
        frame.grid(row=0, columnspan=2, sticky="ewsn")
        Label(frame, image=self.img).pack(side="left",
                                          padx=(10, 4),
                                          pady=(10, 4))
        Label(frame,
              text=_("A new version of CheckMails is available.\
\nDo you want to download it?"),
              font="TkDefaultFont 10 bold",
              wraplength=335).pack(side="left", padx=(4, 10), pady=(10, 4))

        self.b1 = Button(self, text=_("Yes"), command=self.download)
        self.b1.grid(row=1, column=0, padx=10, pady=10, sticky="e")
        Button(self, text=_("No"), command=self.quit).grid(row=1,
                                                           column=1,
                                                           padx=10,
                                                           pady=10,
                                                           sticky="w")
        self.ch = Checkbutton(self, text=_("Check for updates on startup."))
        if CONFIG.getboolean("General", "check_update"):
            self.ch.state(("selected", ))
        self.ch.grid(row=2, columnspan=2, sticky='w')
        self.update = None

        self.thread = Thread(target=self.update_available, daemon=True)
        self.thread.start()
        self.after(1000, self.check_update)

    def check_update(self):
        if self.update is None:
            self.after(1000, self.check_update)
        elif self.update:
            self.deiconify()
            self.grab_set()
            self.lift()
            self.b1.focus_set()
        else:
            if self.notify:
                run([
                    "notify-send", "-i", IMAGE2,
                    _("Update"),
                    _("CheckMails is up-to-date.")
                ])
            logging.info("CheckMails is up-to-date")
            self.destroy()

    def quit(self):
        CONFIG.set("General", "check_update",
                   str("selected" in self.ch.state()))
        save_config()
        self.destroy()

    def download(self):
        webOpen("https://sourceforge.net/projects/checkmails/files")
        self.quit()

    def update_available(self):
        """
        Check for updates online, return True if an update is available, False
        otherwise (and if there is no Internet connection).
        """
        try:
            with request.urlopen(
                    'https://sourceforge.net/projects/checkmails') as page:
                latest_version = self.version_parser.feed(page.read().decode())
            self.update = latest_version > __version__
        except error.URLError as e:
            if e.reason.errno == -2:
                # no Internet connection
                self.update = False
            elif e.reason.errno == 104:
                # connection timed out
                self.update_available()
            else:
                raise e
Example #4
0
class StringEntry(LabelFrame):  # changed
    """String class for entry
        rationalised with integer and float classes
        super

    Parameters
    ----------
    parent : str
        parent handle
    lf_text : str
        text on LabelFrame
    def_inp : str
        default text
    colour : str
        frame colour
    mod : boolean
        enable or disable state switch

    Returns
    -------
    string
    """
    def __init__(self, parent, lf_text, def_inp="", colour='brown', mod=False):
        self.lf_text = lf_text

        super().__init__(parent, text=lf_text)  # added

        self.mod = mod

        self.ent0 = None  # for entry
        self.cb_opt = None  # for check option

        self.out_var = StringVar()
        self.out_var.set(def_inp)

        self.construct(colour)

    def construct(self, colour):
        """construct of colour style

        Parameters
        ----------
        colour : str
            frame colour

        Returns
        -------
        None
        """
        self.farbe = farbe = {
            'blue': 'light blue',
            'brown': 'brown1',
            'green': 'light green',
            'pink': '#EAAFBF'
        }

        colour = colour if colour in farbe else 'brown'

        self.colour = colour

        st1 = Style()
        st1.theme_use('default')

        st1.configure(colour + '.TLabelframe', background='#C9B99B')
        st1.configure(colour + '.TLabelframe.Label', background=farbe[colour])
        st1.configure(colour + '.TCheckbutton', background=farbe[colour])
        st1.configure('brown.TLabel', background='#EDEF77')
        st1.configure('lowr.TLabel', background='lightblue')
        st1.configure('upr.TLabel', background='red')

        #       self.lf1 = Labelframe(self.fr, text=self.lf_text,
        #                           style=self.colour+'.TLabelframe')
        #       self.lf1.grid(column=0,row=0,padx=10, pady=10)
        self['style'] = self.colour + '.TLabelframe'
        self.messlbl = Label(self, style='brown.TLabel')  # self.lf1
        self.messlbl.grid(row=2, column=0, pady=10, padx=10)

        self.make_entry()

    def make_entry(self):
        """construct of Entry

        Parameters
        ----------
        None

        Returns
        -------
        None
        """
        vcmd = self.register(self.is_okay)

        self.ent0 = ent0 = Entry(
            self,
            validate='key',
            validatecommand=(vcmd, '%P', '%S', '%i'),  # self.lf1
            textvariable=self.out_var)
        ent0.bind("<Return>", self.end_input)
        ent0.grid(row=1, column=0, padx=10)
        ent0.focus()

        if self.mod in (True, False):
            self.modify()

    def modify(self):
        """construct of state switch

        Parameters
        ----------
        None

        Returns
        -------
        None
        """
        # entry disabled until checkbox is ticked
        self.cb_opt = Checkbutton(
            self,
            command=self.toggle_opt,  # self.lf1
            style=self.colour + '.TCheckbutton')
        self['labelwidget'] = self.cb_opt  # self.lf1[
        if self.mod:
            self.ent0.state(['!disabled'])
            self.cb_opt.state(['!selected'])
            self.cb_opt['text'] = self.lf_text
            self.ent0.focus()
        else:
            self.ent0.state(['disabled'])
            self.cb_opt.state(['selected'])
            self.cb_opt['text'] = self.lf_text

    def toggle_opt(self):
        """state switch logic

        Parameters
        ----------
        None

        Returns
        -------
        None
        """
        # state of entry controlled
        # by the state of the check button in Option frame label widget
        if self.cb_opt.instate(['selected']):
            self.ent0.state(['disabled'])
            self.cb_opt['text'] = self.lf_text
        else:
            self.ent0.state(['!disabled'])
            self.cb_opt['text'] = self.lf_text
            self.ent0.focus()

    def end_input(self, _evt):
        """limit on string

        Parameters
        ----------
        evt : str
            bind handle

        Returns
        -------
        None
        """
        if len(self.out_var.get()) > 5:
            self.messlbl['text'] = "That's OK"
        else:
            self.messlbl['text'] = "Need at least 6 characters"

    def is_okay(self, text, inp, ind):
        """ validation function

        Parameters
        ----------
        text : str
            text if allowed
        inp : str
            current input

        Returns
        -------
        boolean
        """
        ind = int(ind)
        if (inp.isalnum() or inp in (",", ".", "'", " ")) and ind > 0:
            return True
        else:
            return bool((text.isupper() or text == "") and ind == 0)
Example #5
0
class Config(Toplevel):
    def __init__(self, master):
        Toplevel.__init__(self, master, class_=APP_NAME)
        self.title(_("Settings"))
        self.grab_set()
        self.columnconfigure(0, weight=1)
        self.columnconfigure(1, weight=1)
        self.rowconfigure(0, weight=1)
        self.resizable(True, True)
        self.minsize(470, 574)

        style = Style(self)
        self._bg = style.lookup('TFrame', 'background')

        self.notebook = Notebook(self)
        self._validate = self.register(self._validate_entry_nb)

        self.img_color = PhotoImage(master=self, file=IM_COLOR)

        self.lang = StringVar(self,
                              LANGUAGES[CONFIG.get("General", "language")])
        self.gui = StringVar(self,
                             CONFIG.get("General", "trayicon").capitalize())

        self._init_general()
        self._init_widget()

        self.notebook.grid(sticky='ewsn', row=0, column=0, columnspan=2)
        Button(self, text=_('Ok'), command=self.ok).grid(row=1,
                                                         column=0,
                                                         sticky='e',
                                                         padx=4,
                                                         pady=10)
        Button(self, text=_('Cancel'), command=self.destroy).grid(row=1,
                                                                  column=1,
                                                                  sticky='w',
                                                                  padx=4,
                                                                  pady=10)

    def _init_general(self):
        frame_general = Frame(self)
        self.notebook.add(frame_general, text=_("General"))
        # --- Language
        Label(frame_general, text=_("Language")).grid(row=0,
                                                      column=0,
                                                      padx=8,
                                                      pady=4,
                                                      sticky="e")

        menu_lang = Menu(frame_general, tearoff=False, background=self._bg)
        mb = Menubutton(frame_general, menu=menu_lang, textvariable=self.lang)
        mb.grid(row=0, column=1, padx=8, pady=4, sticky="w")
        for lang in LANGUAGES:
            language = LANGUAGES[lang]
            menu_lang.add_radiobutton(label=language,
                                      value=language,
                                      variable=self.lang,
                                      command=self.translate)

        # --- gui toolkit
        Label(frame_general,
              text=_("GUI Toolkit for the system tray icon")).grid(row=2,
                                                                   column=0,
                                                                   padx=8,
                                                                   pady=4,
                                                                   sticky="e")

        menu_gui = Menu(frame_general, tearoff=False, background=self._bg)
        Menubutton(frame_general,
                   menu=menu_gui,
                   width=9,
                   textvariable=self.gui).grid(row=2,
                                               column=1,
                                               padx=8,
                                               pady=4,
                                               sticky="w")
        for toolkit, b in TOOLKITS.items():
            if b:
                menu_gui.add_radiobutton(label=toolkit.capitalize(),
                                         value=toolkit.capitalize(),
                                         variable=self.gui,
                                         command=self.change_gui)
        # --- Update delay
        Label(frame_general,
              text=_("Feed update delay (min)")).grid(row=4,
                                                      column=0,
                                                      padx=8,
                                                      pady=4,
                                                      sticky="e")
        self.entry_delay = Entry(frame_general,
                                 width=10,
                                 justify='center',
                                 validate='key',
                                 validatecommand=(self._validate, '%P'))
        self.entry_delay.grid(row=4, column=1, padx=8, pady=4, sticky='w')
        self.entry_delay.insert(
            0,
            CONFIG.getint('General', 'update_delay') // 60000)
        # --- image loading timeout
        Label(frame_general,
              text=_("Image loading timeout (s)")).grid(row=5,
                                                        column=0,
                                                        padx=8,
                                                        pady=4,
                                                        sticky="e")
        self.entry_timeout = Entry(frame_general,
                                   width=10,
                                   justify='center',
                                   validate='key',
                                   validatecommand=(self._validate, '%P'))
        self.entry_timeout.grid(row=5, column=1, padx=8, pady=4, sticky='w')
        self.entry_timeout.insert(
            0, CONFIG.getint('General', 'img_timeout', fallback=10))
        # --- Notifications
        self.notifications = Checkbutton(frame_general,
                                         text=_("Activate notifications"))
        self.notifications.grid(row=6,
                                column=0,
                                padx=8,
                                pady=4,
                                columnspan=2,
                                sticky='w')
        if CONFIG.getboolean('General', 'notifications', fallback=True):
            self.notifications.state(('selected', '!alternate'))
        else:
            self.notifications.state(('!selected', '!alternate'))

        # --- Confirm remove feed
        self.confirm_feed_rem = Checkbutton(
            frame_general,
            text=_("Show confirmation dialog before removing feed"))
        self.confirm_feed_rem.grid(row=7,
                                   column=0,
                                   padx=8,
                                   pady=4,
                                   columnspan=2,
                                   sticky='w')
        if CONFIG.getboolean('General', 'confirm_feed_remove', fallback=True):
            self.confirm_feed_rem.state(('selected', '!alternate'))
        else:
            self.confirm_feed_rem.state(('!selected', '!alternate'))
        # --- Confirm remove cat
        self.confirm_cat_rem = Checkbutton(
            frame_general,
            text=_("Show confirmation dialog before removing category"))
        self.confirm_cat_rem.grid(row=8,
                                  column=0,
                                  padx=8,
                                  pady=4,
                                  columnspan=2,
                                  sticky='w')
        if CONFIG.getboolean('General', 'confirm_cat_remove', fallback=True):
            self.confirm_cat_rem.state(('selected', '!alternate'))
        else:
            self.confirm_cat_rem.state(('!selected', '!alternate'))
        # --- Confirm update
        self.confirm_update = Checkbutton(
            frame_general, text=_("Check for updates on start-up"))
        self.confirm_update.grid(row=9,
                                 column=0,
                                 padx=8,
                                 pady=4,
                                 columnspan=2,
                                 sticky='w')
        if CONFIG.getboolean('General', 'check_update', fallback=True):
            self.confirm_update.state(('selected', '!alternate'))
        else:
            self.confirm_update.state(('!selected', '!alternate'))

        # --- Splash supported
        self.splash_support = Checkbutton(
            frame_general,
            text=_("Check this box if the widgets disappear when you click"))
        self.splash_support.grid(row=10,
                                 column=0,
                                 padx=8,
                                 pady=4,
                                 columnspan=2,
                                 sticky='w')
        if not CONFIG.getboolean('General', 'splash_supported', fallback=True):
            self.splash_support.state(('selected', '!alternate'))
        else:
            self.splash_support.state(('!selected', '!alternate'))

    def _init_widget(self):
        frame_widget = Frame(self)
        self.notebook.add(frame_widget, text=_('Widget'))

        # --- font
        frame_font = Frame(frame_widget)
        self.title_font = FontFrame(frame_font,
                                    CONFIG.get("Widget", "font_title"), True)
        self.text_font = FontFrame(frame_font, CONFIG.get("Widget", "font"))
        frame_font.columnconfigure(1, weight=1)
        Label(frame_font, text=_('Title')).grid(row=0,
                                                column=0,
                                                sticky='nw',
                                                padx=4,
                                                pady=4)
        self.title_font.grid(row=0, column=1)
        Separator(frame_font, orient='horizontal').grid(row=1,
                                                        columnspan=2,
                                                        sticky='ew',
                                                        padx=4,
                                                        pady=4)
        Label(frame_font, text=_('Text')).grid(row=2,
                                               column=0,
                                               sticky='nw',
                                               padx=4,
                                               pady=4)
        self.text_font.grid(row=2, column=1)

        # --- opacity
        self.opacity_frame = OpacityFrame(frame_widget,
                                          CONFIG.get("Widget", "alpha"))

        # --- colors
        frame_color = Frame(frame_widget)
        frame_color.columnconfigure(1, weight=1)
        frame_color.columnconfigure(3, weight=1)
        self.color_bg = ColorFrame(frame_color,
                                   CONFIG.get("Widget", "background"),
                                   _('Background color'))
        self.color_fg = ColorFrame(frame_color,
                                   CONFIG.get("Widget", "foreground"),
                                   _('Foreground color'))
        self.color_feed_bg = ColorFrame(
            frame_color, CONFIG.get("Widget", "feed_background"),
            _('Background color'))
        self.color_feed_fg = ColorFrame(
            frame_color, CONFIG.get("Widget", "feed_foreground"),
            _('Foreground color'))
        self.color_link = ColorFrame(frame_color,
                                     CONFIG.get("Widget", "link_color"),
                                     _('Link color'))
        Label(frame_color, text=_('General')).grid(row=0,
                                                   column=0,
                                                   sticky='w',
                                                   padx=4,
                                                   pady=2)
        self.color_bg.grid(row=0, column=1, sticky='e', padx=4, pady=2)
        self.color_fg.grid(row=1, column=1, sticky='e', padx=4, pady=2)

        Separator(frame_color, orient='horizontal').grid(row=2,
                                                         columnspan=4,
                                                         sticky='ew',
                                                         padx=4,
                                                         pady=4)
        Label(frame_color, text=_('Feed entry')).grid(row=3,
                                                      column=0,
                                                      sticky='w',
                                                      padx=4,
                                                      pady=2)
        self.color_feed_bg.grid(row=3, column=1, sticky='e', padx=4, pady=2)
        self.color_feed_fg.grid(row=4, column=1, sticky='e', padx=4, pady=2)
        self.color_link.grid(row=5, column=1, sticky='e', padx=4, pady=2)

        # --- pack
        Label(frame_widget,
              text=_('Font'),
              font='TkDefaultFont 9 bold',
              anchor='w').pack(padx=4, fill='x')
        frame_font.pack(fill='x', padx=14)
        Separator(frame_widget, orient='horizontal').pack(fill='x', pady=6)
        self.opacity_frame.pack(padx=(4, 10), fill='x')
        Separator(frame_widget, orient='horizontal').pack(fill='x', pady=6)
        Label(frame_widget,
              text=_('Colors'),
              font='TkDefaultFont 9 bold',
              anchor='w').pack(padx=4, fill='x')
        frame_color.pack(fill='x', padx=14)

    def display_label(self, value):
        self.opacity_label.configure(text=" {val} %".format(
            val=int(float(value))))

    def translate(self):
        showinfo(
            "Information",
            _("The language setting will take effect after restarting the application"
              ),
            parent=self)

    @staticmethod
    def _config_size(variable, font):
        size = variable.get()
        if size:
            font.configure(size=size)

    @staticmethod
    def _validate_entry_nb(P):
        """ Allow only to enter numbers"""
        parts = P.split(".")
        b = len(parts) < 3 and P != "."
        for p in parts:
            b = b and (p == "" or p.isdigit())
        return b

    def change_gui(self):
        showinfo(
            "Information",
            _("The GUI Toolkit setting will take effect after restarting the application"
              ),
            parent=self)

    def ok(self):
        # --- general
        CONFIG.set("General", "language", REV_LANGUAGES[self.lang.get()])
        CONFIG.set("General", "trayicon", self.gui.get().lower())
        CONFIG.set("General", "update_delay",
                   "%i" % (int(self.entry_delay.get()) * 60000))
        CONFIG.set("General", "img_timeout",
                   "%i" % (int(self.entry_timeout.get())))
        CONFIG.set('General', 'confirm_feed_remove',
                   str(self.confirm_feed_rem.instate(('selected', ))))
        CONFIG.set('General', 'confirm_cat_remove',
                   str(self.confirm_cat_rem.instate(('selected', ))))
        CONFIG.set('General', 'check_update',
                   str(self.confirm_update.instate(('selected', ))))
        CONFIG.set('General', 'splash_supported',
                   str(not self.splash_support.instate(('selected', ))))
        CONFIG.set('General', 'notifications',
                   str(self.notifications.instate(('selected', ))))
        # --- widget
        CONFIG.set("Widget", "alpha", "%i" % self.opacity_frame.get_opacity())

        font_title_dic = self.title_font.get_font()
        font_title_dic[
            'underline'] = 'underline' if font_title_dic['underline'] else ''
        font_title_dic['family'] = font_title_dic['family'].replace(' ', '\ ')
        CONFIG.set(
            "Widget", "font_title",
            "{family} {size} {weight} {slant} {underline}".format(
                **font_title_dic))
        font_text_dic = self.text_font.get_font()
        font_text_dic['family'] = font_text_dic['family'].replace(' ', '\ ')
        CONFIG.set("Widget", "font", "{family} {size}".format(**font_text_dic))
        CONFIG.set("Widget", "foreground", self.color_fg.get_color())
        CONFIG.set("Widget", "background", self.color_bg.get_color())
        CONFIG.set("Widget", "feed_foreground", self.color_feed_fg.get_color())
        CONFIG.set("Widget", "feed_background", self.color_feed_bg.get_color())
        CONFIG.set("Widget", "link_color", self.color_link.get_color())
        self.destroy()
Example #6
0
class StringEntry:
    """String class for entry
        added colour, change state

    Parameters
    ----------
    parent : str
        parent handle
    lf_text : str
        text on LabelFrame
    mess_text : str
        message
    def_text : str
        default text
    colour : str
        frame colour
    mod : str
        enable or disable state switch

    Returns
    -------
    string
    """
    def __init__(self,
                 parent,
                 lf_text,
                 mess_text,
                 def_text="",
                 colour='brown',
                 mod=False):
        self.parent = parent
        self.lf_text = lf_text
        self.mess_text = mess_text
        self.mod = mod

        self.out_var = StringVar()
        self.out_var.set(def_text)

        self.farbe = farbe = {
            'blue': 'light blue',
            'brown': '#EDEF77',
            'green': 'light green',
            'pink': '#EAAFBF'
        }

        colour = colour if colour in farbe else 'brown'

        self.colour = colour

        st1 = Style()
        st1.theme_use('default')

        st1.configure(colour + '.TLabelframe', background='#C9B99B')
        st1.configure(colour + '.TLabelframe.Label', background=farbe[colour])
        st1.configure(colour + '.TCheckbutton', background=farbe[colour])
        st1.configure('brown.TLabel', background='#EDEF77')

        self.construct()

    def construct(self):
        """construct of LabelFrame and message

        Parameters
        ----------
        None

        Returns
        -------
        None
        """
        self.lf1 = Labelframe(self.parent,
                              text=self.lf_text,
                              style=self.colour + '.TLabelframe')
        self.lf1.grid(column=0, row=0, padx=10, pady=10)
        self.messlbl = Label(self.lf1,
                             text=self.mess_text,
                             style='brown.TLabel')
        self.messlbl.grid(row=2, column=0, pady=10, padx=10)

        self.make_entry()

    def make_entry(self):
        """construct of Entry

        Parameters
        ----------
        None

        Returns
        -------
        None
        """
        vcmd = self.lf1.register(self.is_okay)

        self.ent1 = ent1 = Entry(self.lf1,
                                 validate='key',
                                 validatecommand=(vcmd, '%P', '%S', '%i'),
                                 textvariable=self.out_var)
        ent1.bind("<Return>", self.end_input)
        ent1.grid(row=1, column=0, padx=10)
        ent1.focus()

        if self.mod in (True, False):
            self.modify()

    def modify(self):
        """construct of state switch

        Parameters
        ----------
        None

        Returns
        -------
        None
        """
        lf_text = self.lf_text
        # entry disabled until checkbox is ticked
        self.cb_opt = Checkbutton(self.lf1,
                                  command=self.toggle_opt,
                                  style=self.colour + '.TCheckbutton')
        self.lf1['labelwidget'] = self.cb_opt
        if self.mod:
            self.ent1.state(['!disabled'])
            self.cb_opt.state(['!selected'])
            self.cb_opt['text'] = lf_text + ' Check to prevent editing '
            self.ent1.focus()
        else:
            self.ent1.state(['disabled'])
            self.cb_opt.state(['selected'])
            self.cb_opt['text'] = lf_text + ' Check to modify '

    def toggle_opt(self):
        """state switch logic

        Parameters
        ----------
        None

        Returns
        -------
        None
        """
        lf_text = self.lf_text
        #       state of entry controlled
        #       by the state of the check button in Option frame label widget
        if self.cb_opt.instate(['selected']):
            print('selected state')
            self.ent1.state(['disabled'])
            self.cb_opt['text'] = lf_text + ' Check to modify '
        else:
            print('unselected state')
            self.ent1.state(['!disabled'])  # enable option
            self.cb_opt['text'] = lf_text + ' Check to prevent editing '
            self.ent1.focus()

    def end_input(self, _evt):
        """limit on string

        Parameters
        ----------
        evt : str
            bind handle

        Returns
        -------
        None
        """
        if len(self.out_var.get()) > 5:
            self.messlbl['text'] = "That's OK"
        else:
            self.messlbl['text'] = "Should be at least 6 characters long"

    def is_okay(self, text, inp, ind):
        """ validation function

        Parameters
        ----------
        text : str
            text if allowed
        inp : str
            current input

        Returns
        -------
        boolean
        """
        ind = int(ind)
        print(ind)
        if (inp.isalnum() or inp in (",", ".", "'", " ")) and ind > 0:
            return True
        else:
            return bool((text.isupper() or text == "") and ind == 0)
Example #7
0
class Root(Frame):
    '''
    The root window
    '''
    def __init__(self,parent,csvpath="",rosterpath=""):
        '''
        Initilization of the window, assigning height
        centering the window, and starting the interface.
        '''
        self.queue       = Queue()
        self.parent      = parent
        self.interface   = GuiInterface()
        self.loadWindow  = None
        self.remember    = False
        self.initialized = False
        self.csvpathh    = csvpath
        self.rosterpathh = rosterpath
        self.outpathh    = ""
        self.teamsizeh   = ""

        self.startMainUI()

    def centerWindow(self,notself=None):
        '''
        This centers the window into place
        if notself is set, then it centers
        the notself window

        @param:
            notself - TKobject
        '''

        if notself != None: #notself is primarly for progressbar
            sw = self.parent.winfo_screenwidth()
            sh = self.parent.winfo_screenheight()
            x = (sw - self.w/2) / 2
            y = (sh - self.h/2) / 2
            notself.geometry('%dx%d+%d+%d' % (self.w/1.8,self.h/1.8, x,y))
        else:
            sw = self.parent.winfo_screenwidth()
            sh = self.parent.winfo_screenheight()
            x = (sw - self.w) / 2
            y = (sh - self.h) / 2
            self.parent.geometry('%dx%d+%d+%d' % (self.w,self.h, x ,y))

    def startWindow(self):
        '''
        This method starts/creates the window for
        the UI
        '''
        Frame.__init__(self, self.parent, background="white")
        self.style = Style()
        self.style.theme_use("default")
        self.pack(fill=BOTH, expand=1)
        if(not self.initialized):
            self.centerWindow()
        else:
            self.parent.geometry('%dx%d' % (self.w,self.h))
        self.initialized = True

    def resetWindow(self):
        '''
        Resets the window
        '''
        if(self.initialized):
            self.destroy()
        if(self.loadWindow != None):
            self.loadWindow.destroy()

        self.startWindow()

    def startMainUI(self):
        '''
        Starting the main UI takes some work, this creates the buttons
        labels and entrys. Also puts them into place, and adds
        function calls to the buttons
        '''
        #RESETING WINDOW
        self.h           = 290
        self.w           = 600
        self.resetWindow()
        self.parent.title("Input")

        #CREATING CSV FRAME
        csvFrame = Frame(self)
        csvFrame.pack(fill=X, side=TOP)

        csvLabel = Label(csvFrame, text="Path to csv:", background="white")
        csvLabel.pack(side=LEFT, padx=15, pady=10)

        self.csvEntry = Entry(csvFrame, width=30)
        self.csvEntry.insert(0,self.csvpathh)
        self.csvEntry.pack(side=LEFT, padx=35, pady=10)

        csvButton = Button(csvFrame, command=self.csvstartfilebrowser, text="Browse...")
        csvButton.pack(side=LEFT, padx=10, pady=10)
        #DONE CSV FRAME

        #CREATING ROSTER FRAME
        rosterFrame = Frame(self)
        rosterFrame.pack(fill=X, side=TOP)

        rosterLabel = Label(rosterFrame, text="Path to roster:", background="white")
        rosterLabel.pack(side=LEFT, padx=17, pady=10)

        self.rosterEntry = Entry(rosterFrame, width=30)
        self.rosterEntry.insert(0,self.rosterpathh)
        self.rosterEntry.pack(side=LEFT, padx=15, pady=10)

        rosterButton = Button(rosterFrame, command=self.rosterstartfilebrowser, text="Browse...")
        rosterButton.pack(side=LEFT, padx=28, pady=10)
        #DONE ROSTER FRAME

        #CREATING OUTPUT FRAME
        outputFrame = Frame(self)
        outputFrame.pack(fill=X, side=TOP)

        outputLabel = Label(outputFrame, text="Path to output:", background="white")
        outputLabel.pack(side=LEFT, padx=15, pady=10)

        self.outputEntry = Entry(outputFrame, width=30)
        self.outputEntry.insert(0,self.outpathh)
        self.outputEntry.pack(side=LEFT, padx=15, pady=10)

        outputButton = Button(outputFrame, command=self.outputstartfilebrowser, text="Browse...")
        outputButton.pack(side=LEFT, padx=28, pady=10)
        #DONE OUTPUT FRAME

        #CREATING TEAMSIZE FRAME
        teamsizeFrame= Frame(self)
        teamsizeFrame.pack(fill=X, side=TOP)

        teamsizeLabel = Label(teamsizeFrame, text="Team size:", background="white")
        teamsizeLabel.pack(side=LEFT, padx=15, pady=10)

        self.teamsizeEntry = Entry(teamsizeFrame, width=5)
        self.teamsizeEntry.insert(0,self.teamsizeh)
        self.teamsizeEntry.pack(side=LEFT, padx=43, pady=10)
        #DONE TEAMSIZE FRAME

        #CREATING BOTTOM BUTTONS
        frame = Frame(self, borderwidth=1)
        frame.pack(fill=BOTH, expand=True)
        self.pack(fill=BOTH, expand=True)

        exitButton = Button(self,text="Exit",command=self.parent.destroy)
        exitButton.pack(side=RIGHT, padx=5, pady=5)
        self.submitButton = Button(self,text="Submit",command=self.submitFiles)
        self.submitButton.pack(side=RIGHT)
        #DONE BOTTOM BUTTONS

    def optionUI(self):
        '''
        This creates the option window which
        presents the user with the generated
        teams and their options
        '''
        #RESETING WINDOW
        self.h = 400
        self.w = 800
        self.resetWindow()
        self.parent.title("Options")

        #CREATING SCROLL AREA
        scrollFrame = Frame(self)
        scrollFrame.pack(fill=X, side=TOP)

        self.teamlisting = Listbox(scrollFrame, width=self.w, height=18, \
                                selectmode=MULTIPLE)

        count = 1
        for team in self.interface.teams:
            teamstring  = "Team: " + str(count)
            teamstring += " score: " + "%.4f " % team.rating
            teamstring += " members: "
            for student in team.members:
                teamstring += student.name + " | "
            count += 1
            self.teamlisting.insert(END, teamstring)

        self.teamlisting.pack(padx=5, pady=5)
        #DONE SCROLL AREA

        #This will enable double-clicking
        self.teamlisting.bind('<Double-1>', lambda x: self.inspectTeamUI(self.teamlisting.curselection()))

        #CREATING BOTTOM BUTTONS
        frame = Frame(self, borderwidth=1)
        frame.pack(fill=BOTH, expand=True)
        self.pack(fill=BOTH, expand=True)

        backButton = Button(self,text="Back",command=self.startMainUI)
        backButton.pack(side=LEFT, padx=5, pady=5)
        exitButton = Button(self,text="Exit",command=lambda: self.parent.destroy() and exit())
        exitButton.pack(side=RIGHT, padx=5, pady=5)
        saveButton = Button(self,text="Save",command=self.interface.writeFile)
        saveButton.pack(side=RIGHT)
        rerunButton = Button(self,text="Rerun",command=self.reRun)
        rerunButton.pack(side=RIGHT, padx=5, pady=5)
        shuffleTeamsButton = Button(self,text="Shuffle Selected",command=self.shuffleSelected)
        shuffleTeamsButton.pack(side=RIGHT)
        swappingMembersButton = Button(self,text="Swap Members",command=self.memberSwap)
        swappingMembersButton.pack(side=RIGHT,padx=5, pady=5)
        emailscreenButton = Button(self,text="Email Team(s)",command=self.emailScreen)
        emailscreenButton.pack(side=RIGHT)
        #DONE BOTTOM BUTTONS

    def inspectTeamUI(self,selection):
        '''
        This page will allow the user to see info on the team that was double clicked.
        '''
        #RESETING WINDOW
        self.h = 400
        self.w = 800
        self.resetWindow()
        self.parent.title("About This Team")

        #CREATING SCROLL AREA
        scrollFrame = Frame(self)
        scrollFrame.pack(fill=X, side=TOP)

        self.inspectedTeamStudentListing = Listbox(scrollFrame, width=self.w, height=9)
        self.inspectedTeamScheduleListing = Listbox(scrollFrame, width=self.w, height=9)

        if selection:
            inspectedTeamIndex = selection[0]
            inspectedTeam = self.interface.teams[inspectedTeamIndex]
            for student in inspectedTeam.members:
                studentstring  = "Name: " + student.name
                studentstring += " |Languages: " + str(student.filters.get("Languages")[0]).strip('[]')
                studentstring += " |Pref. Teammates: " + str(student.filters.get("Teammates")[0]).strip('[]')
                self.inspectedTeamStudentListing.insert(END, studentstring)
                studentstring  = "Schedule for " + student.name + " = "
                for time_and_day in student.filters.get("Schedule")[0]:
                    studentstring += str(time_and_day.name) + " " + str(time_and_day.times) + " | "
                self.inspectedTeamScheduleListing.insert(END, studentstring)

        else:
            self.inspectedTeamStudentListing.insert(END, "Please try again")

        self.inspectedTeamStudentListing.pack(padx=5, pady=5)
        self.inspectedTeamScheduleListing.pack(padx=5, pady=5)
        #DONE SCROLL AREA

        #CREATING BOTTOM BUTTONS
        frame = Frame(self, borderwidth=1)
        frame.pack(fill=BOTH, expand=True)
        self.pack(fill=BOTH, expand=True)

        closeButton = Button(self,text="Close",command=self.optionUI)
        closeButton.pack(side=RIGHT,padx=5, pady=5)
        #DONE BOTTOM BUTTONS


    def memberSwapUI(self,indexes):
        '''
        This creates the window which
        allows the user to swap
        individual members and reweigh
        teams.

        @param:
            indexes = int[]
        '''
        #RESETING WINDOW
        self.h = 400
        self.w = 800
        self.resetWindow()
        self.parent.title("Swapping Members")

        #CREATING SCROLL AREA
        scrollFrame = Frame(self)
        scrollFrame.pack(fill=X, side=TOP)

        self.teamlisting1 = Listbox(scrollFrame, width=self.w, height=9)

        self.teamlisting2 = Listbox(scrollFrame, width=self.w, height=9)

        count = 1
        team = self.interface.teams[indexes[0]]
        for student in team.members:
            teamstring = ""
            teamstring += student.name
            self.teamlisting1.insert(END, teamstring)
        count += 1

        team = self.interface.teams[indexes[1]]
        for student in team.members:
            teamstring = ""
            teamstring += student.name
            self.teamlisting2.insert(END, teamstring)
        count += 1

        self.teamlisting1.pack(padx=5, pady=5)
        self.teamlisting2.pack(padx=5, pady=5)
        #DONE SCROLL AREA

        #CREATING BOTTOM BUTTONS
        frame = Frame(self, borderwidth=1)
        frame.pack(fill=BOTH, expand=True)
        self.pack(fill=BOTH, expand=True)

        backButton = Button(self,text="Back",command=lambda: self.swapSizeCheck(indexes))
        backButton.pack(side=LEFT, padx=5, pady=5)
        exitButton = Button(self,text="Exit",command=self.parent.destroy)
        exitButton.pack(side=RIGHT, padx=5, pady=5)
        swapButton = Button(self,text="Swap Team",command= lambda: self.switchTeams(indexes))
        swapButton.pack(side=RIGHT,padx=5, pady=5)
        #DONE BOTTOM BUTTONS

    def emailScreen(self):
        '''
        This starts the email login screen
        '''
        if(len(self.teamlisting.curselection()) < 1):
            messagebox.showinfo("Error","Please select one or more teams")
            return

        if(self.remember):
            self.emailTeams()
            return

        self.emailWindow = Toplevel(self.parent)
        self.centerWindow(self.emailWindow)

        #CREATING EMAIL FRAME
        emailFrame = Frame(self.emailWindow)
        emailFrame.pack(fill=X, side=TOP)
        emailLabel = Label(emailFrame, text="Email address:", background="white")
        emailLabel.pack(side=LEFT, padx=15, pady=10)

        self.emailEntry = Entry(emailFrame, width=20)
        self.emailEntry.insert(0,"")
        self.emailEntry.pack(side=LEFT, padx=43, pady=10)
        #EMAIL FRAME DONE

        #CREATING PASSWORD FRAME
        passwordFrame = Frame(self.emailWindow)
        passwordFrame.pack(fill=X, side=TOP)
        passwordLabel = Label(passwordFrame, text="Password:"******"white")
        passwordLabel.pack(side=LEFT, padx=17, pady=10)

        self.passwordEntry = Entry(passwordFrame, width=20, show="*")
        self.passwordEntry.insert(0,"")
        self.passwordEntry.pack(side=LEFT, padx=65, pady=10)
        #PASSWORD FRAME DONE

        #CREATING REMEMBER FRAME
        rememberFrame = Frame(self.emailWindow)
        rememberFrame.pack(fill=X, side=TOP)
        rememberLabel = Label(rememberFrame, text="Remember Username/Password", background="white")
        rememberLabel.pack(side=LEFT, padx=15, pady=10)

        self.rememberCheck = Checkbutton(rememberFrame)
        self.rememberCheck.pack(side=LEFT, padx=15, pady=10)
        #REMEMBER FRAME DONE

        #CREATING BOTTOM BUTTONS
        frame = Frame(self.emailWindow, borderwidth=1)
        frame.pack(fill=BOTH, expand=True)

        exitButton = Button(self.emailWindow,text="Cancel",command=self.emailWindow.destroy)
        exitButton.pack(side=RIGHT, padx=5, pady=5)
        submitButton = Button(self.emailWindow,text="Submit",command=self.emailTeams)
        submitButton.pack(side=RIGHT,padx=5, pady=5)
        #DONE BOTTOM BUTTONS

    def emailTeams(self):
        '''
        This invokes emailing the selected teams
        '''
        success = True

        if(not self.remember):
            selection = self.teamlisting.curselection()
            email     = self.emailEntry.get()
            password  = self.passwordEntry.get()

            if(email == "" or password == ""):
                messagebox.showinfo("Error","Cannot leave fields empty")
                return

            if(len(self.rememberCheck.state()) != 0 and self.rememberCheck.state()[0] == "selected"):
                self.remember = True
                success = self.interface.sendEmail(selection,email,password,True)
            else:
                success = self.interface.sendEmail(selection,email,password)

        else:
           success = self.interface.sendEmail(self.teamlisting.curselection())

        if not success:
            self.remember = False
            messagebox.showinfo("Error","Sending the email was unsuccessful, check your email and password")
            return

        if success:
            messagebox.showinfo("Success","Email was sent successfully")
            self.emailWindow.destroy()
            return

    def loadingScreen(self):
        '''
        This starts the loading screen
        and disables all buttons
        '''
        for i in self.winfo_children():
            if Button == type(i):
                i.configure(state=DISABLED)

        self.loadWindow = Toplevel(self.parent)
        loadingstring   = "Please wait while we run the algorithm"
        loadinglabel    = Label(self.loadWindow, text=loadingstring, background="white")
        progressbar     = Progressbar(self.loadWindow, orient= "horizontal", \
                                    length=300, mode="indeterminate")
        progressbar.pack(pady=self.h/10)
        loadinglabel.pack()

        self.centerWindow(self.loadWindow)
        self.loadWindow.title("Wait")
        progressbar.start()

    def memberSwap(self):
        '''
        This will setup the call for memberSwapUI
        and check for improper/missing selections
        '''
        indexes = []
        selection = self.teamlisting.curselection()
        for i in selection:
            indexes.append(i)
        if len(indexes) == 2:
            self.memberSwapUI(indexes);
        else:
            messagebox.showinfo("Error","Please select 2 teams")

    def switchTeams(self, indexes):
        '''
        Puts selected members into the other team in
        the memberSwapUI
        @param:
            indexes = int[]
        '''
        student1 = self.teamlisting1.curselection()
        student2 = self.teamlisting2.curselection()

        if student1:
            if len(self.interface.teams[indexes[1]].members) < self.interface.teams[indexes[1]].maxsize:
                student = self.interface.teams[indexes[0]].members[int(student1[0])]
                newTeam = self.interface.teams[indexes[1]]
                oldTeam = self.interface.teams[indexes[0]]
                newTeam.insertStudent(student)
                oldTeam.remStudent(student)
                self.memberSwapUI(indexes)
            else:
                messagebox.showinfo("Max Capacity", "Group is at maximum capacity")

        if student2:
            if len(self.interface.teams[indexes[0]].members) < self.interface.teams[indexes[0]].maxsize:
                student = self.interface.teams[indexes[1]].members[int(student2[0])]
                newTeam = self.interface.teams[indexes[0]]
                oldTeam = self.interface.teams[indexes[1]]
                newTeam.insertStudent(student)
                oldTeam.remStudent(student)
                self.memberSwapUI(indexes)
            else:
                messagebox.showinfo("Max Capacity", "Group is at maximum capacity")

    def swapSizeCheck(self,indexes):
        '''
        This is a check to make sure before you back up from the
        memberSwapUI that the sizes are still correct

        @param:
            indexes = int[]
        '''
        if len(self.interface.teams[indexes[0]].members) < self.interface.teams[indexes[0]].maxsize \
                or len(self.interface.teams[indexes[1]].members) < self.interface.teams[indexes[1]].maxsize:
            if messagebox.askokcancel("WARNING", "Warning: A group is shorthanded. You sure you want to proceed?"):
                for index in indexes:
                    self.interface.algorithm.weightCalc(self.interface.teams[index])
                self.optionUI();
        else:
            for index in indexes:
                self.interface.algorithm.weightCalc(self.interface.teams[index])
            self.optionUI();

    def shuffleSelected(self):
        '''
        This is a wrapper function that
        shuffles the selected teams
        '''
        #Gets selected values
        indexes   = []
        selection = self.teamlisting.curselection()
        for i in selection:
            indexes.append(i)

        self.interface.reShuffleSelectedTeams(indexes)
        self.optionUI()

    def reRun(self):
        '''
        A wrapper function to rerun the
        algorithm
        '''

        thread = ThreadedTask(self.queue,\
            self.interface.reShuffleAll)
        thread.start()
        ThreadedTask(self.queue,self.loadingScreen).start()
        self.checkThread(thread,self.optionUI)

    def submitFiles(self):
        '''
        Checks the validity of the entry feilds for
        After checks it runs our python script.
        '''
        csvtext     = self.csvEntry.get()
        teamsize    = self.teamsizeEntry.get()
        rostertext  = self.rosterEntry.get()
        outputtext  = self.outputEntry.get()

        #Checking existance of paths and extensions
        if(not os.path.exists(csvtext) and csvtext[-4:] != ".csv"):
            messagebox.showinfo("Error","Not a CSV or the file does not exist")
            return

        #Checking existance of paths and extensions
        if(not os.path.exists(rostertext) and rostertext[-4:] != ".txt"):
           messagebox.showinfo("Error","Not a roster or the file does not exist")
           return

        #Checking existance of path
        if(not os.path.exists(outputtext)):
           messagebox.showinfo("Error","Directory dosen't exists for output")
           return

        #Checking if the string is an int and in range
        if(not self.testNumber(teamsize)):
            messagebox.showinfo("Error","Please enter a positive integer for teamsize(2,5)")
            return

        self.csvpathh    = csvtext
        self.rosterpathh = rostertext
        self.outpathh    = outputtext
        self.teamsizeh   = teamsize

        self.interface.setOutputPath(outputtext)

        self.submitButton.configure(state=DISABLED)
        runalgorithm = lambda: self.interface.runGeneral(\
                        rostertext,csvtext,int(teamsize))
        thread1 = ThreadedTask(self.queue,runalgorithm)
        thread2 = ThreadedTask(self.queue,self.loadingScreen)
        thread2.start()
        thread1.start()

        self.checkThread(thread1,self.optionUI)

    def checkThread(self,thread,function):
        '''
        This function checks to see if
        the given thread is dead, if it
        is not, it recalls a new checkThread.
        After the thread is dead, it calls the
        given function

        @param:
            thread   - ThreadedTask
            functoin - a function
        '''
        if thread.is_alive():
            self.parent.after(1000, lambda: self.checkThread(thread,function))
        else:
            function()

    def testNumber(self,i,minimum=0,maximum=5):
        '''
        Checks if i is an integer and between
        a certain range

        @param:
            i (string)
            minimum (optional int)
            maximum (optional int)
        '''
        try:
            i = int(i)
            return (i >= minimum) and (i <= maximum)
        except:
            return False

    def csvstartfilebrowser(self):
        '''
        Starts the filebrowser for the csv file
        '''
        currdir = os.getcwd()
        fileopt = [('csv files', '*.csv')]
        directo = filedialog.askopenfilename(parent=self, filetypes=fileopt, \
                                         initialdir=currdir, title="Select file")
        #clearning and setting csventry
        self.csvEntry.delete(0,'end')
        self.csvEntry.insert(0,str(directo))

    def rosterstartfilebrowser(self):
        '''
        Starts the filebrowser for the text file
        '''
        currdir = os.getcwd()
        fileopt = [('text files', '*.txt')]
        directo = filedialog.askopenfilename(parent=self, filetypes=fileopt, \
                                         initialdir=currdir, title="Select file")
        #clearning and setting rosterentry
        self.rosterEntry.delete(0,'end')
        self.rosterEntry.insert(0,str(directo))

    def outputstartfilebrowser(self):
        '''
        Starts the filebrowser for the output
        '''
        currdir = os.getcwd()
        directo = filedialog.askdirectory(parent=self,\
                                    initialdir=currdir, title="Select file")

        #clearning and setting outputentry
        self.outputEntry.delete(0,'end')
        self.outputEntry.insert(0,str(directo))
Example #8
0
class Config(Toplevel):
    """Config dialog."""
    def __init__(self, master):
        """Create Config dialog."""
        Toplevel.__init__(self, master, class_='MyNotes')
        self.title(_("Preferences"))
        self.grab_set()
        self.protocol("WM_DELETE_WINDOW", self.quit)
        self.changes = {}, {}, False, False
        self.minsize(width=430, height=450)

        # --- style
        style = Style(self)
        style.theme_use("clam")
        style.configure("TScale", sliderlength=20)
        style.map("TCombobox",
                  fieldbackground=[('readonly', 'white')],
                  selectbackground=[('readonly', 'white')],
                  selectforeground=[('readonly', 'black')])
        style.configure("prev.TLabel", background="white")
        style.map("prev.TLabel", background=[("active", "white")])
        color = CONFIG.get("Categories",
                           CONFIG.get("General", "default_category"))
        style.configure("titlebar.TFrame", background=color)
        style.configure("titlebar.TLabel", background=color)
        style.configure("text.TFrame", background="white")

        # --- body
        self.notebook = Notebook(self)
        okcancel_frame = Frame(self)
        okcancel_frame.columnconfigure(0, weight=1)
        okcancel_frame.columnconfigure(1, weight=1)
        okcancel_frame.pack(fill="x", side='bottom')
        self.notebook.pack(expand=True, fill="both")

        # --- * General settings
        self._init_general()

        # --- * Font settings
        self._init_font()

        # --- * Categories
        self.category_settings = CategoryManager(self.notebook, master)
        self.notebook.add(self.category_settings,
                          text=_("Categories"),
                          sticky="ewsn",
                          padding=4)
        # --- * Symbols
        size = CONFIG.get("Font", "text_size")
        family = CONFIG.get("Font", "text_family")
        symbols_settings = Frame(self.notebook, padding=4)
        self.notebook.add(symbols_settings,
                          text=_("Symbols"),
                          sticky="ewsn",
                          padding=4)
        txt_frame = Frame(symbols_settings,
                          relief="sunken",
                          borderwidth=1,
                          style="text.TFrame")
        txt_frame.rowconfigure(0, weight=1)
        txt_frame.columnconfigure(0, weight=1)
        self.symbols = Text(txt_frame,
                            width=1,
                            height=1,
                            highlightthickness=0,
                            spacing2=5,
                            spacing1=5,
                            relief="flat",
                            padx=4,
                            pady=4,
                            font="%s %s" % (family.replace(" ", "\ "), size))
        scroll_y = AutoScrollbar(txt_frame,
                                 orient='vertical',
                                 command=self.symbols.yview)
        self.symbols.configure(yscrollcommand=scroll_y.set)

        self.symbols.insert("1.0", CONFIG.get("General", "symbols"))
        Label(symbols_settings, text=_("Available symbols")).pack(padx=4,
                                                                  pady=4)
        txt_frame.pack(fill="both", expand=True, padx=4, pady=4)
        self.symbols.grid(sticky='ewns')
        scroll_y.grid(row=0, column=1, sticky='ns')
        Button(symbols_settings, text=_('Reset'),
               command=self.reset_symbols).pack(padx=4, pady=4)

        # --- * AutoCorrect
        self.autocorrect_settings = AutoCorrectConfig(self.notebook, master)
        self.notebook.add(self.autocorrect_settings,
                          text=_("AutoCorrect"),
                          sticky="ewsn",
                          padding=4)

        # --- Ok/Cancel buttons
        Button(okcancel_frame, text="Ok", command=self.ok).grid(row=1,
                                                                column=0,
                                                                padx=4,
                                                                pady=10,
                                                                sticky="e")
        Button(okcancel_frame, text=_("Cancel"),
               command=self.destroy).grid(row=1,
                                          column=1,
                                          padx=4,
                                          pady=10,
                                          sticky="w")

    def _init_general(self):
        general_settings = Frame(self.notebook, padding=4)
        general_settings.columnconfigure(0, weight=1)
        self.notebook.add(general_settings,
                          text=_("General"),
                          sticky="ewsn",
                          padding=4)

        # ---- language

        self.lang = StringVar(self,
                              LANGUAGES[CONFIG.get("General", "language")])
        lang_frame = Frame(general_settings)
        Label(lang_frame, text=_("Language")).grid(row=0,
                                                   sticky="w",
                                                   padx=4,
                                                   pady=4)
        menu_lang = Menu(lang_frame, tearoff=False)
        Menubutton(lang_frame, menu=menu_lang, width=9,
                   textvariable=self.lang).grid(row=0,
                                                column=1,
                                                padx=8,
                                                pady=4)
        for lang in LANGUAGES.values():
            menu_lang.add_radiobutton(variable=self.lang,
                                      label=lang,
                                      value=lang,
                                      command=self.translate)
        # ---- gui toolkit
        self.gui = StringVar(self,
                             CONFIG.get("General", "trayicon").capitalize())
        gui_frame = Frame(general_settings)
        Label(gui_frame,
              text=_("GUI Toolkit for the system tray icon")).grid(row=0,
                                                                   column=0,
                                                                   padx=4,
                                                                   pady=4,
                                                                   sticky="w")
        menu_gui = Menu(gui_frame, tearoff=False)
        Menubutton(gui_frame, menu=menu_gui, width=9,
                   textvariable=self.gui).grid(row=0,
                                               column=1,
                                               padx=4,
                                               pady=4,
                                               sticky="w")
        for toolkit, b in TOOLKITS.items():
            if b:
                menu_gui.add_radiobutton(label=toolkit.capitalize(),
                                         value=toolkit.capitalize(),
                                         variable=self.gui,
                                         command=self.change_gui)
        # ---- opacity
        self.opacity = OpacityFrame(general_settings,
                                    CONFIG.getint("General", "opacity"))
        # ---- position
        frame_position = Frame(general_settings)
        self.position = StringVar(self, CONFIG.get("General", "position"))
        Label(frame_position,
              text=_("Default position of the notes")).grid(row=0,
                                                            columnspan=3,
                                                            sticky="w",
                                                            padx=4,
                                                            pady=4)
        Radiobutton(frame_position,
                    text=_("Always above"),
                    value="above",
                    variable=self.position).grid(row=1, column=0, padx=4)
        Radiobutton(frame_position,
                    text=_("Always below"),
                    value="below",
                    variable=self.position).grid(row=1, column=1, padx=4)
        Radiobutton(frame_position,
                    text=_("Normal"),
                    value="normal",
                    variable=self.position).grid(row=1, column=2, padx=4)
        # ---- titlebar
        self.titlebar_disposition = StringVar(
            self, CONFIG.get("General", "buttons_position"))
        self.title_var = StringVar(
            self)  # to add date if date_in_title is true
        font_title = "%s %s" % (CONFIG.get("Font", "title_family").replace(
            " ", "\ "), CONFIG.get("Font", "title_size"))
        style = CONFIG.get("Font", "title_style").split(",")
        if style:
            font_title += " "
            font_title += " ".join(style)

        frame_titlebar = Frame(general_settings)
        frame_titlebar.columnconfigure(1, weight=1)
        frame_titlebar.columnconfigure(3, weight=1)
        Label(frame_titlebar,
              text=_("Title bar disposition")).grid(row=0,
                                                    columnspan=4,
                                                    sticky="w",
                                                    padx=4,
                                                    pady=4)
        Radiobutton(frame_titlebar,
                    value="right",
                    variable=self.titlebar_disposition).grid(row=1,
                                                             column=0,
                                                             padx=4)
        right = Frame(frame_titlebar, style="titlebar.TFrame")
        right.grid(row=1, column=1, sticky="ew", padx=4)

        def select_right(event):
            self.titlebar_disposition.set("right")

        Label(right,
              textvariable=self.title_var,
              style="titlebar.TLabel",
              anchor="center",
              font=font_title).pack(side="left", fill="x", expand=True)
        Label(right, image="img_close",
              style="titlebar.TLabel").pack(side="right")
        Label(right, image="img_roll",
              style="titlebar.TLabel").pack(side="right")
        for ch in right.children.values():
            ch.bind("<Button-1>", select_right)
        Radiobutton(frame_titlebar,
                    value="left",
                    variable=self.titlebar_disposition).grid(row=1, column=2)
        left = Frame(frame_titlebar, style="titlebar.TFrame")
        left.grid(row=1, column=3, sticky="ew")

        def select_left(event):
            self.titlebar_disposition.set("left")

        Label(left, image="img_close",
              style="titlebar.TLabel").pack(side="left")
        Label(left, image="img_roll",
              style="titlebar.TLabel").pack(side="left")
        Label(left,
              textvariable=self.title_var,
              style="titlebar.TLabel",
              anchor="center",
              font=font_title).pack(side="right", fill="x", expand=True)
        for ch in left.children.values():
            ch.bind("<Button-1>", select_left)

        self.date_in_title = BooleanVar(
            self, CONFIG.getboolean('General', 'date_in_title', fallback=True))
        date_in_title = Checkbutton(frame_titlebar,
                                    variable=self.date_in_title,
                                    text=_('Display creation date in title'),
                                    command=self.toggle_date)
        date_in_title.grid(row=2, columnspan=4, sticky='w', pady=4, padx=4)
        self.toggle_date()
        # ---- placement
        lang_frame.grid(sticky="w")
        Separator(general_settings, orient="horizontal").grid(sticky="ew",
                                                              pady=10)
        gui_frame.grid(sticky="w")
        Separator(general_settings, orient="horizontal").grid(sticky="ew",
                                                              pady=10)
        # opacity_frame.grid(sticky='w')
        self.opacity.grid(sticky='w', padx=4)
        Separator(general_settings, orient="horizontal").grid(sticky="ew",
                                                              pady=10)
        frame_position.grid(sticky="ew")
        Separator(general_settings, orient="horizontal").grid(sticky="ew",
                                                              pady=10)
        frame_titlebar.grid(sticky="ew", pady=4)

        # ---- clean local data
        Separator(general_settings, orient="horizontal").grid(sticky="ew",
                                                              pady=10)
        Button(general_settings,
               text=_('Delete unused local data'),
               command=self.cleanup).grid(padx=4, pady=4, sticky='w')

        # ---- splash supported
        Separator(general_settings, orient="horizontal").grid(sticky="ew",
                                                              pady=10)
        self.splash_support = Checkbutton(
            general_settings,
            text=_("Check this box if the notes disappear when you click"))
        self.splash_support.grid(padx=4, pady=4, sticky='w')
        if not CONFIG.getboolean('General', 'splash_supported', fallback=True):
            self.splash_support.state(('selected', '!alternate'))
        else:
            self.splash_support.state(('!selected', '!alternate'))

    def _init_font(self):
        font_settings = Frame(self.notebook, padding=4)
        font_settings.columnconfigure(1, weight=1)
        self.notebook.add(font_settings,
                          text=_("Font"),
                          sticky="ewsn",
                          padding=4)

        # ---- title
        title_size = CONFIG.get("Font", "title_size")
        title_family = CONFIG.get("Font", "title_family").replace(" ", "\ ")
        font_title = '{} {}'.format(title_family, title_size)
        style = CONFIG.get("Font", "title_style").split(",")
        if style:
            font_title = font_title + " " + " ".join(style)

        self.title_font = FontFrame(font_settings, font_title, style=True)
        # ---- text
        size = CONFIG.get("Font", "text_size")
        family = CONFIG.get("Font", "text_family").replace(" ", "\ ")

        self.text_font = FontFrame(font_settings, '{} {}'.format(family, size))

        # ---- mono
        mono_fonts = [f for f in set(font.families()) if 'Mono' in f]
        mono_family = CONFIG.get("Font", "mono").replace(" ", "\ ")

        self.mono_font = FontFrame(font_settings,
                                   '{} {}'.format(mono_family, size),
                                   size=False,
                                   font_list=mono_fonts)
        add_trace(
            self.text_font.font_size,
            'write', lambda *args: self.mono_font._config_size(
                self.text_font.font_size, self.mono_font.font))

        # ---- placement
        Label(font_settings, text=_("Title")).grid(row=0,
                                                   column=0,
                                                   padx=4,
                                                   pady=4,
                                                   sticky="nw")
        self.title_font.grid(row=0, column=1, sticky="w", padx=20)
        Separator(font_settings, orient="horizontal").grid(row=1,
                                                           columnspan=2,
                                                           sticky="ew",
                                                           pady=10)
        Label(font_settings, text=_("Text")).grid(row=2,
                                                  column=0,
                                                  padx=4,
                                                  pady=4,
                                                  sticky="nw")
        self.text_font.grid(row=2, column=1, sticky="w", padx=20)
        Separator(font_settings, orient="horizontal").grid(row=3,
                                                           columnspan=2,
                                                           sticky="ew",
                                                           pady=10)
        Label(font_settings, text=_("Mono")).grid(row=4,
                                                  column=0,
                                                  padx=4,
                                                  pady=4,
                                                  sticky="nw")
        self.mono_font.grid(row=4, column=1, sticky="w", padx=20)

    def reset_symbols(self):
        self.symbols.delete('1.0', 'end')
        self.symbols.insert('1.0', SYMBOLS)

    def toggle_date(self):
        if self.date_in_title.get():
            self.title_var.set('{} - {}'.format(_('Title'), strftime('%x')))
        else:
            self.title_var.set(_('Title'))

    def cleanup(self):
        """Remove unused local data and latex images."""
        self.master.cleanup()
        showinfo(_('Information'),
                 _('Unused local data have been cleaned up.'))

    def ok(self):
        """Validate configuration."""
        # --- splash supported
        splash_supp = not self.splash_support.instate(('selected', ))
        splash_change = splash_supp != CONFIG.getboolean(
            "General", "splash_supported", fallback=True)
        # --- font
        mono_font = self.mono_font.get_font()['family']
        text_font = self.text_font.get_font()
        title_font = self.title_font.get_font()
        style = "{weight},{slant}".format(**title_font)
        style = style + ',underline' * title_font['underline']

        # --- language
        language = REV_LANGUAGES[self.lang.get()]

        # --- symbols
        symbols = [
            l.strip() for l in self.symbols.get("1.0", "end").splitlines()
        ]

        # --- autocorrect
        self.autocorrect_settings.ok()
        autocorrect = "\t".join(
            ["%s %s" % (key, val) for key, val in AUTOCORRECT.items()])

        # --- update CONFIG
        CONFIG.set("General", "default_category",
                   self.category_settings.default_category.get().lower())
        CONFIG.set("General", "language", language)
        CONFIG.set("General", "opacity", str(self.opacity.get()))
        CONFIG.set("General", "position", self.position.get())
        CONFIG.set("General", "buttons_position",
                   self.titlebar_disposition.get())
        CONFIG.set("General", "date_in_title", str(self.date_in_title.get()))
        CONFIG.set("General", "symbols", "".join(symbols))
        CONFIG.set("General", "trayicon", self.gui.get().lower())
        CONFIG.set("General", "autocorrect", autocorrect)
        CONFIG.set('General', 'splash_supported', str(splash_supp))

        CONFIG.set("Font", "text_size", str(text_font['size']))
        CONFIG.set("Font", "text_family", text_font['family'])
        CONFIG.set("Font", "title_family", title_font['family'])
        CONFIG.set("Font", "title_size", str(title_font['size']))
        CONFIG.set("Font", "title_style", style)
        CONFIG.set("Font", "mono", mono_font)

        # --- notes config
        col_changes = {}
        name_changes = {}
        new_cat = False
        for cat in self.category_settings.categories:
            new_name = self.category_settings.get_name(cat)
            if cat in CONFIG.options("Categories"):
                old_color = CONFIG.get("Categories", cat)
                new_color = COLORS[self.category_settings.get_color(cat)]
                if new_name != cat:
                    name_changes[cat] = new_name
                    CONFIG.remove_option("Categories", cat)
                    CONFIG.set("Categories", new_name, new_color)
                if old_color != new_color:
                    col_changes[new_name] = (old_color, new_color)
                    CONFIG.set("Categories", new_name, new_color)

            else:
                new_cat = True
                CONFIG.set("Categories", new_name,
                           COLORS[self.category_settings.get_color(cat)])
        save_config()
        self.changes = col_changes, name_changes, new_cat, splash_change
        self.destroy()

    def get_changes(self):
        return self.changes

    def translate(self):
        """Show information dialog about language change."""
        showinfo(
            _("Information"),
            _("The language setting will take effect after restarting the application"
              ),
            parent=self)

    def change_gui(self):
        """Show information dialog about gui toolkit change."""
        showinfo(
            "Information",
            _("The GUI Toolkit setting will take effect after restarting the application"
              ),
            parent=self)

    def display_label(self, value):
        self.opacity_label.configure(text=" {val} %".format(
            val=int(float(value))))

    def quit(self):
        self.destroy()
Example #9
0
                    background='black',
                    foreground='white')

ram.grid(column=1, row=1)
disk.grid(column=2, row=1)

p = Progressbar(root, orient="vertical", variable=battery)
# Add the label to the progressbar style
p_label = Label(background='black', foreground='white', text='')
p_label.grid(column=3, row=2)
p.grid(column=3, row=1)
clock_hours.grid(column=4, row=1)

top = Checkbutton(root, text='Keep on top')
top.grid(column=1, row=2)
top.state(['!alternate'])
clock_minutes.grid(column=6, row=1)
clock_colon.grid(column=5, row=1)

root.config(bg='black')
root.resizable(False, False)

while True:
    try:
        if ram_display:
            ram.set_value(round(bytes_to_gb(virtual_memory().used), 1))
        else:
            ram.set_value(int(virtual_memory().percent))
        if hasattr(sensors_battery(), 'percent'):
            battery.set(int(sensors_battery().percent))
            if sensors_battery().power_plugged:
Example #10
0
class Export(Toplevel):
    """Category export dialog."""
    def __init__(self, master, note_data):
        """Create export dialog."""
        Toplevel.__init__(self, master, class_='MyNotes')
        self.title(_("Export"))
        self.minsize(350, 250)
        self.grab_set()
        self.columnconfigure(0, weight=1)
        self.rowconfigure(3, weight=1)

        self.note_data = note_data
        self.categories = CONFIG.options("Categories")
        self.categories.sort()
        self.notes_to_export = []
        self.export_type = None
        self.export_data = False

        # export type
        self.type = StringVar(self, _("Notes (.notes)"))

        type_frame = Frame(self)
        menu_type = Menu(self, tearoff=False)
        for etype in EXT_DICT:
            menu_type.add_radiobutton(label=etype, value=etype, variable=self.type)
        mb = Menubutton(type_frame, menu=menu_type, textvariable=self.type, width=max([int(len(key) * 0.8) for key in EXT_DICT]))
        Label(type_frame, text=_('Export to')).pack(side='left', padx=4)
        mb.pack(side='left', padx=4)
        type_frame.grid(row=0, columnspan=2, sticky='w', pady=4)

        Separator(self).grid(columnspan=2, sticky="ew", padx=4, pady=4)

        # export only visible notes checkbutton
        self.ch_only_visible = Checkbutton(self, text=_("Only visible notes"),
                                           command=self.select_only_visible)
        self.ch_only_visible.grid(columnspan=2, sticky="w", padx=4, pady=4)

        # note selection
        self.tree = CheckboxTreeview(self, show='tree')
        self.tree.grid(row=3, sticky="nsew", padx=4, pady=4)
        scroll = Scrollbar(self, orient='vertical', command=self.tree.yview)
        self.tree.configure(yscrollcommand=scroll.set)
        scroll.grid(row=3, column=1, sticky='ns')

        self.tree.insert('', 'end', 'root', text=_('Categories'))
        for cat in self.categories:
            self.tree.insert('root', 'end', cat, text=cat.capitalize())
        for key, data in self.note_data.items():
            self.tree.insert(data['category'], 'end', key,
                             text='{} - {}'.format(data['title'], data.get('date', '??')),
                             tags=['visible'] if data['visible'] else [])
        for cat in self.categories:
            if not self.tree.get_children(cat):
                self.tree.detach(cat)
        self.tree.bind('<<Checked>>', self.toggle_select_visible)
        self.tree.bind('<<Unchecked>>', self.toggle_select_visible)

        Separator(self).grid(sticky="ew", columnspan=2, padx=4, pady=4)
        self.ch_export_data = Checkbutton(self, text=_('Export data (pictures and linked files)'))
        self.ch_export_data.grid(sticky="w", columnspan=2, padx=4, pady=4)

        frame = Frame(self)
        frame.grid(columnspan=2)

        Button(frame, text="Ok",
               command=self.ok).grid(row=0, column=0, sticky="w", padx=4, pady=4)
        Button(frame, text=_("Cancel"),
               command=self.destroy).grid(row=0, column=1, sticky="e", padx=4, pady=4)
        self.tree.check_item('root')
        self.tree.expand_all()
        self.toggle_select_visible()

    def ok(self):
        """Validate choice."""
        self.notes_to_export = self.tree.get_checked()
        self.export_type = self.type.get()
        self.export_data = "selected" in self.ch_export_data.state()
        self.destroy()

    def select_only_visible(self):
        """Select only visible notes."""
        for cat in self.categories:
            for item in self.tree.get_children(cat):
                if self.tree.tag_has('visible', item):
                    self.tree.check_item(item)
                else:
                    self.tree.uncheck_item(item)

    def toggle_select_visible(self, event=None):
        """Change select all checkbutton state when another checkbutton is clicked."""
        checked = list(self.tree.get_checked())
        checked.sort()
        visible = list(self.tree.tag_has('visible'))
        visible.sort()
        self.ch_only_visible.state(['!' * (visible != checked) + 'selected'])

    def get_export(self):
        return self.export_type, self.notes_to_export, self.export_data
Example #11
0
class Export(Toplevel):
    """ Category export dialog """
    def __init__(self, master):
        Toplevel.__init__(self, master)
        self.title(_("Export"))
        self.resizable(False, False)
        self.grab_set()
        #        self.columnconfigure(0, weight=1)
        self.categories = CONFIG.options("Categories")
        self.categories.sort()
        self.categories_to_export = []
        self.only_visible = False

        self.ch_all = Checkbutton(self,
                                  text=_("Select all"),
                                  command=self.select_all)
        self.ch_only_visible = Checkbutton(self, text=_("Only visible notes"))
        self.ch_all.grid(sticky="w", padx=4, pady=4)
        self.ch_only_visible.grid(sticky="w", padx=4, pady=4)
        Separator(self).grid(sticky="ew", padx=4, pady=4)
        self.checkbuttons = []
        for cat in self.categories:
            self.checkbuttons.append(
                Checkbutton(self,
                            text=cat.capitalize(),
                            command=self.toggle_select_all))
            self.checkbuttons[-1].grid(sticky="w", padx=4, pady=4)

        frame = Frame(self)
        frame.grid()

        Button(frame, text="Ok", command=self.ok).grid(row=0,
                                                       column=0,
                                                       sticky="w",
                                                       padx=4,
                                                       pady=4)
        Button(frame, text=_("Cancel"), command=self.destroy).grid(row=0,
                                                                   column=1,
                                                                   sticky="e",
                                                                   padx=4,
                                                                   pady=4)
        self.ch_all.state(("selected", ))
        self.select_all()

    def ok(self):
        for ch, cat in zip(self.checkbuttons, self.categories):
            if "selected" in ch.state():
                self.categories_to_export.append(cat)
        self.only_visible = "selected" in self.ch_only_visible.state()
        self.destroy()

    def select_all(self):
        if ("selected" in self.ch_all.state()):
            state = "selected"
        else:
            state = "!selected"
        for ch in self.checkbuttons:
            ch.state((state, ))

    def toggle_select_all(self):
        b = 0
        for ch in self.checkbuttons:
            if "selected" in ch.state():
                b += 1
        if b == len(self.checkbuttons):
            self.ch_all.state(("selected", ))
        else:
            self.ch_all.state(("!selected", ))

    def get_export(self):
        return self.categories_to_export, self.only_visible
Example #12
0
class Config(Toplevel):
    def __init__(self, master):
        Toplevel.__init__(self, master)
        self.title(_("Preferences"))
        self.grab_set()
        self.resizable(False, False)
        self.protocol("WM_DELETE_WINDOW", self.quit)
        self.changes = {}, {}

        # --- style
        style = Style(self)
        style.theme_use("clam")
        style.configure("TScale", sliderlength=20)
        style.map("TCombobox",
                  fieldbackground=[('readonly', 'white')],
                  selectbackground=[('readonly', 'white')],
                  selectforeground=[('readonly', 'black')])
        style.configure("prev.TLabel", background="white")
        style.map("prev.TLabel", background=[("active", "white")])
        color = CONFIG.get("Categories",
                           CONFIG.get("General", "default_category"))
        style.configure("titlebar.TFrame", background=color)
        style.configure("titlebar.TLabel", background=color)
        style.configure("text.TFrame", background="white")

        # --- body
        self.notebook = Notebook(self)
        okcancel_frame = Frame(self)
        okcancel_frame.columnconfigure(0, weight=1)
        okcancel_frame.columnconfigure(1, weight=1)
        self.notebook.pack(expand=True, fill="both")
        okcancel_frame.pack(fill="x", expand=True)

        # --- * General settings
        general_settings = Frame(self.notebook)
        general_settings.columnconfigure(0, weight=1)
        self.notebook.add(general_settings,
                          text=_("General"),
                          sticky="ewsn",
                          padding=4)

        # --- *-- language
        lang = {"fr": "Français", "en": "English"}
        self.lang = StringVar(self, lang[CONFIG.get("General", "language")])
        lang_frame = Frame(general_settings)
        Label(lang_frame, text=_("Language")).grid(row=0,
                                                   sticky="w",
                                                   padx=4,
                                                   pady=4)
        menu_lang = Menu(lang_frame, tearoff=False)
        Menubutton(lang_frame, menu=menu_lang, width=9,
                   textvariable=self.lang).grid(row=0,
                                                column=1,
                                                padx=8,
                                                pady=4)
        menu_lang.add_radiobutton(label="English",
                                  value="English",
                                  variable=self.lang,
                                  command=self.translate)
        menu_lang.add_radiobutton(label="Français",
                                  value="Français",
                                  variable=self.lang,
                                  command=self.translate)
        # --- *-- opacity
        self.opacity_scale = Scale(general_settings,
                                   orient="horizontal",
                                   length=200,
                                   from_=0,
                                   to=100,
                                   value=CONFIG.get("General", "opacity"),
                                   command=self.display_label)
        self.opacity_label = Label(
            general_settings,
            text="{val}%".format(val=self.opacity_scale.get()))
        # --- *-- position
        frame_position = Frame(general_settings)
        self.position = StringVar(self, CONFIG.get("General", "position"))
        Label(frame_position,
              text=_("Default position of the notes")).grid(row=0,
                                                            columnspan=3,
                                                            sticky="w",
                                                            padx=4,
                                                            pady=4)
        Radiobutton(frame_position,
                    text=_("Always above"),
                    value="above",
                    variable=self.position).grid(row=1, column=0)
        Radiobutton(frame_position,
                    text=_("Always below"),
                    value="below",
                    variable=self.position).grid(row=1, column=1)
        Radiobutton(frame_position,
                    text=_("Normal"),
                    value="normal",
                    variable=self.position).grid(row=1, column=2)
        # --- *-- titlebar
        self.titlebar_disposition = StringVar(
            self, CONFIG.get("General", "buttons_position"))
        font_title = "%s %s" % (CONFIG.get("Font", "title_family").replace(
            " ", "\ "), CONFIG.get("Font", "title_size"))
        style = CONFIG.get("Font", "title_style").split(",")
        if style:
            font_title += " "
            font_title += " ".join(style)

        frame_titlebar = Frame(general_settings)
        frame_titlebar.columnconfigure(1, weight=1)
        frame_titlebar.columnconfigure(3, weight=1)
        Label(frame_titlebar,
              text=_("Title bar disposition")).grid(row=0,
                                                    columnspan=4,
                                                    sticky="w",
                                                    padx=4,
                                                    pady=4)
        Radiobutton(frame_titlebar,
                    value="right",
                    variable=self.titlebar_disposition).grid(row=1, column=0)
        right = Frame(frame_titlebar, style="titlebar.TFrame")
        right.grid(row=1, column=1, sticky="ew")

        def select_right(event):
            self.titlebar_disposition.set("right")

        Label(right,
              text=_("Title"),
              style="titlebar.TLabel",
              anchor="center",
              font=font_title).pack(side="left", fill="x", expand=True)
        Label(right, image="img_close",
              style="titlebar.TLabel").pack(side="right")
        Label(right, image="img_roll",
              style="titlebar.TLabel").pack(side="right")
        for ch in right.children.values():
            ch.bind("<Button-1>", select_right)
        Radiobutton(frame_titlebar,
                    value="left",
                    variable=self.titlebar_disposition).grid(row=1, column=2)
        left = Frame(frame_titlebar, style="titlebar.TFrame")
        left.grid(row=1, column=3, sticky="ew")

        def select_left(event):
            self.titlebar_disposition.set("left")

        Label(left, image="img_close",
              style="titlebar.TLabel").pack(side="left")
        Label(left, image="img_roll",
              style="titlebar.TLabel").pack(side="left")
        Label(left,
              text=_("Title"),
              style="titlebar.TLabel",
              anchor="center",
              font=font_title).pack(side="right", fill="x", expand=True)
        for ch in left.children.values():
            ch.bind("<Button-1>", select_left)
        # --- *-- placement
        lang_frame.grid(sticky="w")
        Separator(general_settings, orient="horizontal").grid(sticky="ew",
                                                              pady=10)
        Label(general_settings, text=_("Opacity")).grid(sticky="w",
                                                        padx=4,
                                                        pady=4)
        self.opacity_scale.grid(padx=4, pady=(4, 10))
        self.opacity_label.place(in_=self.opacity_scale,
                                 relx=1,
                                 rely=0.5,
                                 anchor="w",
                                 bordermode="outside")
        Separator(general_settings, orient="horizontal").grid(sticky="ew",
                                                              pady=10)
        frame_position.grid(sticky="ew")
        Separator(general_settings, orient="horizontal").grid(sticky="ew",
                                                              pady=10)
        frame_titlebar.grid(sticky="ew", pady=4)
        if LATEX:
            Separator(general_settings, orient="horizontal").grid(sticky="ew",
                                                                  pady=10)
            Button(general_settings,
                   text=_('Delete unused LaTex data'),
                   command=self.cleanup).grid(padx=4, pady=4, sticky='w')

        # --- * Font settings
        font_settings = Frame(self.notebook)
        font_settings.columnconfigure(0, weight=1)
        self.notebook.add(font_settings,
                          text=_("Font"),
                          sticky="ewsn",
                          padding=4)

        # --- *-- title
        fonttitle_frame = Frame(font_settings)

        title_size = CONFIG.get("Font", "title_size")
        title_family = CONFIG.get("Font", "title_family")

        self.sampletitle = Label(fonttitle_frame,
                                 text=_("Sample text"),
                                 anchor="center",
                                 style="prev.TLabel",
                                 relief="groove")

        self.sampletitle.grid(row=2,
                              columnspan=2,
                              padx=4,
                              pady=6,
                              ipadx=4,
                              ipady=4,
                              sticky="eswn")
        self.fonts = list(set(font.families()))
        self.fonts.append("TkDefaultFont")
        self.fonts.sort()
        w = max([len(f) for f in self.fonts])
        self.sizes = [
            "%i" % i for i in (list(range(6, 17)) + list(range(18, 32, 2)))
        ]

        self.fonttitle_family = Combobox(fonttitle_frame,
                                         values=self.fonts,
                                         width=(w * 2) // 3,
                                         exportselection=False,
                                         validate="key")
        self._validate_title_size = self.register(
            lambda *args: self.validate_font_size(self.fonttitle_size, *args))
        self._validate_title_family = self.register(
            lambda *args: self.validate_font_family(self.fonttitle_family, *
                                                    args))
        self.fonttitle_family.configure(
            validatecommand=(self._validate_title_family, "%d", "%S", "%i",
                             "%s", "%V"))
        self.fonttitle_family.current(self.fonts.index(title_family))
        self.fonttitle_family.grid(row=0, column=0, padx=4, pady=4)
        self.fonttitle_size = Combobox(
            fonttitle_frame,
            values=self.sizes,
            width=5,
            exportselection=False,
            validate="key",
            validatecommand=(self._validate_title_size, "%d", "%P", "%V"))
        self.fonttitle_size.current(self.sizes.index(title_size))
        self.fonttitle_size.grid(row=0, column=1, padx=4, pady=4)

        frame_title_style = Frame(fonttitle_frame)
        frame_title_style.grid(row=1, columnspan=2, padx=4, pady=6)
        self.is_bold = Checkbutton(frame_title_style,
                                   text=_("Bold"),
                                   command=self.update_preview_title)
        self.is_italic = Checkbutton(frame_title_style,
                                     text=_("Italic"),
                                     command=self.update_preview_title)
        self.is_underlined = Checkbutton(frame_title_style,
                                         text=_("Underline"),
                                         command=self.update_preview_title)
        style = CONFIG.get("Font", "title_style")
        if "bold" in style:
            self.is_bold.state(("selected", ))
        if "italic" in style:
            self.is_italic.state(("selected", ))
        if "underline" in style:
            self.is_underlined.state(("selected", ))
        self.is_bold.pack(side="left")
        self.is_italic.pack(side="left")
        self.is_underlined.pack(side="left")

        self.update_preview_title()
        # --- *-- text
        size = CONFIG.get("Font", "text_size")
        family = CONFIG.get("Font", "text_family")

        font_frame = Frame(font_settings)
        self.sample = Label(font_frame,
                            text=_("Sample text"),
                            anchor="center",
                            style="prev.TLabel",
                            relief="groove")
        self.sample.grid(row=1,
                         columnspan=2,
                         padx=4,
                         pady=6,
                         ipadx=4,
                         ipady=4,
                         sticky="eswn")

        self.font_family = Combobox(font_frame,
                                    values=self.fonts,
                                    width=(w * 2) // 3,
                                    exportselection=False,
                                    validate="key")
        self._validate_family = self.register(
            lambda *args: self.validate_font_family(self.font_family, *args))
        self._validate_size = self.register(
            lambda *args: self.validate_font_size(self.font_size, *args))
        self.font_family.configure(validatecommand=(self._validate_family,
                                                    "%d", "%S", "%i", "%s",
                                                    "%V"))
        self.font_family.current(self.fonts.index(family))
        self.font_family.grid(row=0, column=0, padx=4, pady=4)
        self.font_size = Combobox(font_frame,
                                  values=self.sizes,
                                  width=5,
                                  exportselection=False,
                                  validate="key",
                                  validatecommand=(self._validate_size, "%d",
                                                   "%P", "%V"))
        self.font_size.current(self.sizes.index(size))
        self.font_size.grid(row=0, column=1, padx=4, pady=4)

        self.update_preview()

        # --- *-- placement
        Label(font_settings, text=_("Title")).grid(row=0,
                                                   padx=4,
                                                   pady=4,
                                                   sticky="w")
        fonttitle_frame.grid(row=1)
        Separator(font_settings, orient="horizontal").grid(row=2,
                                                           sticky="ew",
                                                           pady=10)
        Label(font_settings, text=_("Text")).grid(row=3,
                                                  padx=4,
                                                  pady=4,
                                                  sticky="w")
        font_frame.grid(row=4)

        # --- * Categories
        self.category_settings = CategoryManager(self.notebook, master)
        self.notebook.add(self.category_settings,
                          text=_("Categories"),
                          sticky="ewsn",
                          padding=4)
        # --- * Symbols
        symbols_settings = Frame(self.notebook)
        self.notebook.add(symbols_settings,
                          text=_("Symbols"),
                          sticky="ewsn",
                          padding=4)
        txt_frame = Frame(symbols_settings,
                          relief="sunken",
                          borderwidth=1,
                          style="text.TFrame")
        self.symbols = Text(txt_frame,
                            width=1,
                            height=1,
                            highlightthickness=0,
                            spacing2=5,
                            spacing1=5,
                            relief="flat",
                            padx=4,
                            pady=4,
                            font="%s %s" % (family.replace(" ", "\ "), size))
        self.symbols.insert("1.0", CONFIG.get("General", "symbols"))
        Label(symbols_settings, text=_("Available symbols")).pack(padx=4,
                                                                  pady=4)
        txt_frame.pack(fill="both", expand=True, padx=4, pady=4)
        self.symbols.pack(fill="both", expand=True)
        Button(symbols_settings, text=_('Reset'),
               command=self.reset_symbols).pack(padx=4, pady=4)

        # --- Ok/Cancel buttons
        Button(okcancel_frame, text="Ok", command=self.ok).grid(row=1,
                                                                column=0,
                                                                padx=4,
                                                                pady=10,
                                                                sticky="e")
        Button(okcancel_frame, text=_("Cancel"),
               command=self.destroy).grid(row=1,
                                          column=1,
                                          padx=4,
                                          pady=10,
                                          sticky="w")
        # --- bindings
        self.font_family.bind('<<ComboboxSelected>>', self.update_preview)
        self.font_family.bind('<Return>', self.update_preview)
        self.font_size.bind('<<ComboboxSelected>>',
                            self.update_preview,
                            add=True)
        self.font_size.bind('<Return>', self.update_preview, add=True)
        self.fonttitle_family.bind('<<ComboboxSelected>>',
                                   self.update_preview_title)
        self.fonttitle_size.bind('<<ComboboxSelected>>',
                                 self.update_preview_title,
                                 add=True)
        self.fonttitle_family.bind('<Return>', self.update_preview_title)
        self.fonttitle_size.bind('<Return>',
                                 self.update_preview_title,
                                 add=True)

    def reset_symbols(self):
        self.symbols.delete('1.0', 'end')
        self.symbols.insert('1.0', SYMBOLS)

    def cleanup(self):
        ''' Remove unused latex images '''
        self.master.cleanup()

    def validate_font_size(self, combo, d, ch, V):
        ''' Validation of the size entry content '''
        if d == '1':
            l = [i for i in self.sizes if i[:len(ch)] == ch]
            if l:
                i = self.sizes.index(l[0])
                combo.current(i)
                index = combo.index("insert")
                combo.selection_range(index + 1, "end")
                combo.icursor(index + 1)
            return ch.isdigit()
        else:
            return True

    def validate_font_family(self, combo, action, modif, pos, prev_txt, V):
        """ completion of the text in the path entry with existing
            folder/file names """
        try:
            sel = combo.selection_get()
            txt = prev_txt.replace(sel, '')
        except TclError:
            txt = prev_txt
        if action == "0":
            txt = txt[:int(pos)] + txt[int(pos) + 1:]
            return True
        else:
            txt = txt[:int(pos)] + modif + txt[int(pos):]
            l = [i for i in self.fonts if i[:len(txt)] == txt]
            if l:
                i = self.fonts.index(l[0])
                combo.current(i)
                index = combo.index("insert")
                combo.delete(0, "end")
                combo.insert(0, l[0].replace("\ ", " "))
                combo.selection_range(index + 1, "end")
                combo.icursor(index + 1)
                return True
            else:
                return False

    def ok(self):
        family = self.font_family.get()
        if family not in self.fonts:
            l = [i for i in self.fonts if i[:len(family)] == family]
            if l:
                family = l[0]
            else:
                family = 'TkDefaultFont'
        size = self.font_size.get()
        familytitle = self.fonttitle_family.get()
        if familytitle not in self.fonts:
            l = [i for i in self.fonts if i[:len(familytitle)] == familytitle]
            if l:
                familytitle = l[0]
            else:
                familytitle = 'TkDefaultFont'
        sizetitle = self.fonttitle_size.get()
        opacity = "%i" % float(self.opacity_scale.get())
        language = self.lang.get().lower()[:2]
        style = ""
        if self.is_bold.instate(("selected", )):
            style += "bold,"
        if self.is_italic.instate(("selected", )):
            style += "italic,"
        if self.is_underlined.instate(("selected", )):
            style += "underline,"
        if style:
            style = style[:-1]

        symbols = [
            l.strip() for l in self.symbols.get("1.0", "end").splitlines()
        ]

        CONFIG.set("General", "default_category",
                   self.category_settings.default_category.get().lower())
        CONFIG.set("General", "language", language)
        CONFIG.set("General", "opacity", opacity)
        CONFIG.set("General", "position", self.position.get())
        CONFIG.set("General", "buttons_position",
                   self.titlebar_disposition.get())
        CONFIG.set("General", "symbols", "".join(symbols))
        CONFIG.set("Font", "text_size", size)
        CONFIG.set("Font", "text_family", family)
        CONFIG.set("Font", "title_family", familytitle)
        CONFIG.set("Font", "title_size", sizetitle)
        CONFIG.set("Font", "title_style", style)

        col_changes = {}
        name_changes = {}
        for cat in self.category_settings.categories:
            new_name = self.category_settings.get_name(cat)
            if cat in CONFIG.options("Categories"):
                old_color = CONFIG.get("Categories", cat)
                new_color = COLORS[self.category_settings.get_color(cat)]
                if new_name != cat:
                    name_changes[cat] = new_name
                    CONFIG.remove_option("Categories", cat)
                    CONFIG.set("Categories", new_name, new_color)
                if old_color != new_color:
                    col_changes[new_name] = (old_color, new_color)
                    CONFIG.set("Categories", new_name, new_color)

            else:
                CONFIG.set("Categories", new_name,
                           COLORS[self.category_settings.get_color(cat)])
        save_config()
        self.changes = col_changes, name_changes
        self.destroy()

    def get_changes(self):
        return self.changes

    def translate(self):
        showinfo(
            "Information",
            _("The language setting will take effect after restarting the application"
              ),
            parent=self)

    def update_preview(self, event=None):
        family = self.font_family.get()
        size = self.font_size.get()
        self.sample.configure(font="%s %s" % (family.replace(" ", "\ "), size))

    def update_preview_title(self, event=None):
        family = self.fonttitle_family.get()
        size = self.fonttitle_size.get()
        config = "%s %s" % (family.replace(" ", "\ "), size)
        if self.is_bold.instate(("selected", )):
            config += " bold"
        if self.is_italic.instate(("selected", )):
            config += " italic"
        if self.is_underlined.instate(("selected", )):
            config += " underline"
        self.sampletitle.configure(font=config)

    def display_label(self, value):
        self.opacity_label.configure(text=" {val} %".format(
            val=int(float(value))))

    def quit(self):
        self.destroy()
Example #13
0
class ToggledFrame(Frame):
    """
    A frame that can be toggled to open and close
    """
    def __init__(self, master=None, text="", **kwargs):
        font = kwargs.pop('font', '')
        Frame.__init__(self, master, **kwargs)
        self.style_name = self.cget('style')
        self.toggle_style_name = '%s.Toggle' % ('.'.join(
            self.style_name.split('.')[:-1]))
        self.columnconfigure(1, weight=1)
        self.rowconfigure(1, weight=1)
        self.style = Style(self)
        self.style.configure(self.toggle_style_name,
                             background=self.style.lookup(
                                 self.style_name, 'background'))
        self.style.map(self.toggle_style_name, background=[])
        self._checkbutton = Checkbutton(self,
                                        style=self.toggle_style_name,
                                        command=self.toggle,
                                        cursor='arrow')
        self.label = Label(self,
                           text=text,
                           font=font,
                           style=self.style_name.replace('TFrame', 'TLabel'))
        self.interior = Frame(self, style=self.style_name)
        self.interior.grid(row=1, column=1, sticky="nswe", padx=(4, 0))
        self.interior.grid_remove()
        self.label.bind('<Configure>', self._wrap)
        self.label.bind('<1>', lambda e: self._checkbutton.invoke())
        self._grid_widgets()
        self.bind('<<ThemeChanged>>', self._theme_changed)

    def _theme_changed(self, event):
        self.style.configure(self.toggle_style_name,
                             background=self.style.lookup(
                                 self.style_name, 'background'))

    def _wrap(self, event):
        self.label.configure(wraplength=self.label.winfo_width())

    def _grid_widgets(self):
        self._checkbutton.grid(row=0, column=0)
        self.label.grid(row=0, column=1, sticky="we")

    def toggle(self):
        if 'selected' not in self._checkbutton.state():
            self.interior.grid_remove()
            self.event_generate("<<ToggledFrameClose>>")
        else:
            self.interior.grid()
            self.event_generate("<<ToggledFrameOpen>>")

    def open(self):
        self._checkbutton.state(('selected', ))
        self.interior.grid()
        self.event_generate("<<ToggledFrameOpen>>")

    def close(self):
        self._checkbutton.state(('!selected', ))
        self.interior.grid_remove()
        self.event_generate("<<ToggledFrameClose>>")
Example #14
0
class ManagerItem(Frame):
    def __init__(self, master, note_data, toggle_visibility_cmd):
        Frame.__init__(self,
                       master,
                       class_='ManagerItem',
                       style='manager.TFrame')
        self.columnconfigure(0, weight=0, minsize=18)
        self.columnconfigure(1, weight=1, minsize=198)
        self.columnconfigure(2, weight=1, minsize=198)
        self.columnconfigure(3, weight=0, minsize=85)
        self.columnconfigure(4, weight=0, minsize=22)
        self.toggle_visibility_cmd = toggle_visibility_cmd
        title = note_data['title']
        if title:
            title = title[:17] + (len(title) > 17) * '...'
        title = title.replace('\t', ' ')
        date = note_data.get('date', '??')
        txt = note_data['txt'].splitlines()
        if txt:
            txt = txt[0][:17] + (len(txt[0]) > 17 or len(txt) > 1) * '...'
        else:
            txt = ''
        txt = txt.replace('\t', ' ')
        self._data = {'title': title, 'text': txt, 'date': date}
        self.title = Label(self,
                           text=title,
                           anchor='w',
                           style='manager.TLabel')
        self.text = Label(self, text=txt, anchor='w', style='manager.TLabel')
        self.date = Label(self,
                          text=date,
                          anchor='center',
                          style='manager.TLabel')
        self.checkbutton = Checkbutton(self, style='manager.TCheckbutton')
        self.visibility = BooleanVar(self, note_data['visible'])
        self.toggle_visibility = Checkbutton(self,
                                             style='manager.Toggle',
                                             variable=self.visibility,
                                             command=self.toggle_visibility)
        self.checkbutton.grid(row=0,
                              column=0,
                              padx=(2, 0),
                              pady=4,
                              sticky='nsew')
        self.title.grid(row=0, column=1, padx=4, pady=4, sticky='ew')
        self.text.grid(row=0, column=2, padx=4, pady=4, sticky='ew')
        self.date.grid(row=0, column=3, padx=4, pady=4, sticky='ew')
        self.toggle_visibility.grid(row=0,
                                    column=4,
                                    padx=(0, 2),
                                    pady=4,
                                    sticky='wens')
        self.bind('<Enter>', self._on_enter)
        self.bind('<Leave>', self._on_leave)
        self.checkbutton.bind('<Enter>',
                              self._on_enter)  # override class binding
        self.checkbutton.bind('<Leave>',
                              self._on_leave)  # override class binding
        self.toggle_visibility.bind('<Enter>',
                                    self._on_enter)  # override class binding
        self.toggle_visibility.bind('<Leave>',
                                    self._on_leave)  # override class binding
        self.bind('<ButtonRelease-1>', self._on_click)
        self.text.bind('<ButtonRelease-1>', self._on_click)
        self.title.bind('<ButtonRelease-1>', self._on_click)
        self.date.bind('<ButtonRelease-1>', self._on_click)

    def state(self, statespec=None):
        return self.checkbutton.state(statespec)

    def toggle_visibility(self):
        self.toggle_visibility_cmd(self.visibility.get())

    def get(self, key):
        if key == 'visibility':
            return self.visibility.get()
        else:
            return self._data[key]

    def get_values(self):
        return (self._data['title'], self._data['text'], self._data['date'],
                self.visibility.get())

    def _on_enter(self, event):
        self.title.state(('active', ))
        self.text.state(('active', ))
        self.date.state(('active', ))
        self.checkbutton.state(('active', ))
        self.toggle_visibility.state(('active', ))
        Frame.state(self, ('active', ))
        return "break"

    def _on_leave(self, event):
        self.title.state(('!active', ))
        self.text.state(('!active', ))
        self.date.state(('!active', ))
        self.checkbutton.state(('!active', ))
        self.toggle_visibility.state(('!active', ))
        Frame.state(self, ('!active', ))
        return "break"

    def _on_click(self, event):
        self.checkbutton.invoke()
        return "break"
Example #15
0
    def build(self):
        self.rbs = []
        self.rbs1 = []
        self.lF0 = lF0 = LabelFrame(self.fr, text='Widget and Themes')
        lF0.grid(row=0, column=0, sticky='nw')
        self.fr1 = fr1 = Frame(lF0)
        fr1.grid(row=0, column=0, sticky='nw')
        # create check box to select reverse selection order
        self.lF12 = lF12 = LabelFrame(fr1, text='Select Widget before Theme')
        lF12.grid(row=0, column=0, sticky='nw')
        self.ord = ord = IntVar()
        ord.set(0)
        cbut3 = Checkbutton(lF12, text='Reverse selection order', variable=ord, 
                command=self.selord)
        cbut3.grid(row=0, column=0, padx=5, pady=5)
        cbut3.state(['!selected'])
        
        # create a Combobox to choose widgets
        widget_sel = ['Button', 'Checkbutton', 'Combobox', 'Entry', 'Frame',
                      'Label', 'LabelFrame', 'Menubutton', 'Notebook', 
                      'PanedWindow', 'Progressbar', 'Radiobutton', 'Scale', 
                      'Scrollbar', 'Separator', 'Sizegrip', 'Treeview']
        ord = self.ord

        self.lf6 = LabelFrame(self.fr1, text='Select Widget', style="RoundedFrame",
                               padding=(10,1,10,10))
        self.lf6.grid(row=1, column=0, sticky='nw')
        
        self.lf6.state([("focus" if self.ord.get() == 0 else "!focus")]) 
        self.widget_value = StringVar()
        self.cb = Combobox(self.lf6, values=widget_sel,
                           textvariable=self.widget_value,
                           state= ('disabled' if self.ord.get()==1 else 'active'))
        self.cb.grid(row=0, column=0, padx=5, pady=5, sticky='nw')
        self.cb.bind('<<ComboboxSelected>>', self.enabled)

        # create a Radio Buttons to choose orientation
        fr2 = Frame(self.lF0)
        fr2.grid(row=0, column=1, sticky='nw')        
        self.lF5 = lF5 = LabelFrame(fr2, style="RoundedFrame", padding=(10,1,10,10),
            text='Orientation of \nProgressbar \nScale \nScrollbar')
        lF5.grid(row=0, column=0, padx=5, pady=5, sticky='nw')
        self.orient = StringVar()
        orientT = ['Horizontal', 'Vertical']
        for ix, val in enumerate(orientT):
            rb = Radiobutton(lF5, text=val, value=val, command=self.orient_command,
                             variable=self.orient, state='disabled')
            rb.grid(row=ix, column=0, sticky='w')
            self.rbs.append(rb)
            
        # create Radio Buttons to choose themes
        themes = {"alt":  "alt - standard", 
            "clam":  "clam - standard", "classic":  "classic - standard",
            "default":  "default - standard"}
            
        self.lF1 = LabelFrame(self.fr1, text='Select Theme', style="RoundedFrame",
                              padding=(10,1,10,10))
        self.lF1.grid(row=2, column=0, sticky='n')
        self.theme_value = StringVar()
        for ix, val in enumerate(themes):
            rb1 = Radiobutton(self.lF1, text=themes[val], value=val, 
                state='disabled', variable=self.theme_value, command=self.theme_command)
            rb1.grid(row=ix, column=0, padx=10, sticky='nw')
            self.rbs1.append(rb1)
Example #16
0
    def __init__(self, master, key, **kwargs):
        """ Create a new sticky note.
            master: main app
            key: key identifying this note in master.note_data
            kwargs: dictionnary of the other arguments
            (title, txt, category, color, tags, geometry, locked, checkboxes,
             images, rolled)
        """
        Toplevel.__init__(self, master)
        # --- window properties
        self.id = key
        self.is_locked = not (kwargs.get("locked", False))
        self.images = []
        self.links = {}
        self.latex = {}
        self.nb_links = 0
        self.title('mynotes%s' % key)
        self.attributes("-type", "splash")
        self.attributes("-alpha", CONFIG.getint("General", "opacity") / 100)
        self.focus_force()
        # window geometry
        self.update_idletasks()
        self.geometry(kwargs.get("geometry", '220x235'))
        self.save_geometry = kwargs.get("geometry", '220x235')
        self.update()
        self.rowconfigure(1, weight=1)
        self.minsize(10, 10)
        self.protocol("WM_DELETE_WINDOW", self.hide)

        # --- style
        self.style = Style(self)
        self.style.configure(self.id + ".TCheckbutton", selectbackground="red")
        self.style.map('TEntry', selectbackground=[('!focus', '#c3c3c3')])
        selectbg = self.style.lookup('TEntry', 'selectbackground', ('focus', ))
        self.style.configure("sel.TCheckbutton", background=selectbg)
        self.style.map("sel.TCheckbutton", background=[("active", selectbg)])

        # --- note elements
        # title
        font_title = "%s %s" % (CONFIG.get("Font", "title_family").replace(
            " ", "\ "), CONFIG.get("Font", "title_size"))
        style = CONFIG.get("Font", "title_style").split(",")
        if style:
            font_title += " "
            font_title += " ".join(style)

        self.title_var = StringVar(master=self,
                                   value=kwargs.get("title", _("Title")))
        self.title_label = Label(self,
                                 textvariable=self.title_var,
                                 anchor="center",
                                 style=self.id + ".TLabel",
                                 font=font_title)
        self.title_entry = Entry(self,
                                 textvariable=self.title_var,
                                 exportselection=False,
                                 justify="center",
                                 font=font_title)
        # buttons/icons
        self.roll = Label(self, image="img_roll", style=self.id + ".TLabel")
        self.close = Label(self, image="img_close", style=self.id + ".TLabel")
        self.im_lock = PhotoImage(master=self, file=IM_LOCK)
        self.cadenas = Label(self, style=self.id + ".TLabel")
        # corner grip
        self.corner = Sizegrip(self, style=self.id + ".TSizegrip")
        # texte
        font_text = "%s %s" % (CONFIG.get("Font", "text_family").replace(
            " ", "\ "), CONFIG.get("Font", "text_size"))
        self.txt = Text(self,
                        wrap='word',
                        undo=True,
                        selectforeground='white',
                        inactiveselectbackground=selectbg,
                        selectbackground=selectbg,
                        tabs=(10, 'right', 21, 'left'),
                        relief="flat",
                        borderwidth=0,
                        highlightthickness=0,
                        font=font_text)
        # tags
        self.txt.tag_configure("bold", font="%s bold" % font_text)
        self.txt.tag_configure("italic", font="%s italic" % font_text)
        self.txt.tag_configure("bold-italic",
                               font="%s bold italic" % font_text)
        self.txt.tag_configure("underline",
                               underline=True,
                               selectforeground="white")
        self.txt.tag_configure("overstrike",
                               overstrike=True,
                               selectforeground="white")
        self.txt.tag_configure("center", justify="center")
        self.txt.tag_configure("left", justify="left")
        self.txt.tag_configure("right", justify="right")
        self.txt.tag_configure("link",
                               foreground="blue",
                               underline=True,
                               selectforeground="white")
        self.txt.tag_configure("list",
                               lmargin1=0,
                               lmargin2=21,
                               tabs=(10, 'right', 21, 'left'))
        self.txt.tag_configure("todolist",
                               lmargin1=0,
                               lmargin2=21,
                               tabs=(10, 'right', 21, 'left'))
        margin = 2 * Font(self, font=font_text).measure("m")
        self.txt.tag_configure("enum",
                               lmargin1=0,
                               lmargin2=margin + 5,
                               tabs=(margin, 'right', margin + 5, 'left'))

        for coul in TEXT_COLORS.values():
            self.txt.tag_configure(coul,
                                   foreground=coul,
                                   selectforeground="white")
            self.txt.tag_configure(coul + "-underline",
                                   foreground=coul,
                                   selectforeground="white",
                                   underline=True)
            self.txt.tag_configure(coul + "-overstrike",
                                   foreground=coul,
                                   overstrike=True,
                                   selectforeground="white")
        # --- menus
        # --- * menu on title
        self.menu = Menu(self, tearoff=False)
        # note color
        menu_note_color = Menu(self.menu, tearoff=False)
        colors = list(COLORS.keys())
        colors.sort()
        for coul in colors:
            menu_note_color.add_command(
                label=coul, command=lambda key=coul: self.change_color(key))
        # category
        self.category = StringVar(
            self,
            kwargs.get("category", CONFIG.get("General", "default_category")))
        self.menu_categories = Menu(self.menu, tearoff=False)
        categories = CONFIG.options("Categories")
        categories.sort()
        for cat in categories:
            self.menu_categories.add_radiobutton(label=cat.capitalize(),
                                                 value=cat,
                                                 variable=self.category,
                                                 command=self.change_category)
        # position: normal, always above, always below
        self.position = StringVar(
            self, kwargs.get("position", CONFIG.get("General", "position")))
        menu_position = Menu(self.menu, tearoff=False)
        menu_position.add_radiobutton(label=_("Always above"),
                                      value="above",
                                      variable=self.position,
                                      command=self.set_position_above)
        menu_position.add_radiobutton(label=_("Always below"),
                                      value="below",
                                      variable=self.position,
                                      command=self.set_position_below)
        menu_position.add_radiobutton(label=_("Normal"),
                                      value="normal",
                                      variable=self.position,
                                      command=self.set_position_normal)
        # mode: note, list, todo list
        menu_mode = Menu(self.menu, tearoff=False)
        self.mode = StringVar(self, kwargs.get("mode", "note"))
        menu_mode.add_radiobutton(label=_("Note"),
                                  value="note",
                                  variable=self.mode,
                                  command=self.set_mode_note)
        menu_mode.add_radiobutton(label=_("List"),
                                  value="list",
                                  variable=self.mode,
                                  command=self.set_mode_list)
        menu_mode.add_radiobutton(label=_("ToDo List"),
                                  value="todolist",
                                  variable=self.mode,
                                  command=self.set_mode_todolist)
        menu_mode.add_radiobutton(label=_("Enumeration"),
                                  value="enum",
                                  variable=self.mode,
                                  command=self.set_mode_enum)

        self.menu.add_command(label=_("Delete"), command=self.delete)
        self.menu.add_cascade(label=_("Category"), menu=self.menu_categories)
        self.menu.add_cascade(label=_("Color"), menu=menu_note_color)
        self.menu.add_command(label=_("Lock"), command=self.lock)
        self.menu.add_cascade(label=_("Position"), menu=menu_position)
        self.menu.add_cascade(label=_("Mode"), menu=menu_mode)

        # --- * menu on main text
        self.menu_txt = Menu(self.txt, tearoff=False)
        # style
        menu_style = Menu(self.menu_txt, tearoff=False)
        menu_style.add_command(label=_("Bold"),
                               command=lambda: self.toggle_text_style("bold"))
        menu_style.add_command(
            label=_("Italic"),
            command=lambda: self.toggle_text_style("italic"))
        menu_style.add_command(label=_("Underline"),
                               command=self.toggle_underline)
        menu_style.add_command(label=_("Overstrike"),
                               command=self.toggle_overstrike)
        # text alignment
        menu_align = Menu(self.menu_txt, tearoff=False)
        menu_align.add_command(label=_("Left"),
                               command=lambda: self.set_align("left"))
        menu_align.add_command(label=_("Right"),
                               command=lambda: self.set_align("right"))
        menu_align.add_command(label=_("Center"),
                               command=lambda: self.set_align("center"))
        # text color
        menu_colors = Menu(self.menu_txt, tearoff=False)
        colors = list(TEXT_COLORS.keys())
        colors.sort()
        for coul in colors:
            menu_colors.add_command(label=coul,
                                    command=lambda key=coul: self.
                                    change_sel_color(TEXT_COLORS[key]))

        # insert
        menu_insert = Menu(self.menu_txt, tearoff=False)
        menu_insert.add_command(label=_("Symbols"), command=self.add_symbols)
        menu_insert.add_command(label=_("Checkbox"), command=self.add_checkbox)
        menu_insert.add_command(label=_("Image"), command=self.add_image)
        menu_insert.add_command(label=_("Date"), command=self.add_date)
        menu_insert.add_command(label=_("Link"), command=self.add_link)
        if LATEX:
            menu_insert.add_command(label="LaTex", command=self.add_latex)

        self.menu_txt.add_cascade(label=_("Style"), menu=menu_style)
        self.menu_txt.add_cascade(label=_("Alignment"), menu=menu_align)
        self.menu_txt.add_cascade(label=_("Color"), menu=menu_colors)
        self.menu_txt.add_cascade(label=_("Insert"), menu=menu_insert)

        # --- restore note content/appearence
        self.color = kwargs.get("color",
                                CONFIG.get("Categories", self.category.get()))
        self.txt.insert('1.0', kwargs.get("txt", ""))
        self.txt.edit_reset()  # clear undo stack
        # restore inserted objects (images and checkboxes)
        # we need to restore objects with increasing index to avoid placment errors
        indexes = list(kwargs.get("inserted_objects", {}).keys())
        indexes.sort(key=sorting)
        for index in indexes:
            kind, val = kwargs["inserted_objects"][index]
            if kind == "checkbox":
                ch = Checkbutton(self.txt,
                                 takefocus=False,
                                 style=self.id + ".TCheckbutton")
                if val:
                    ch.state(("selected", ))
                self.txt.window_create(index, window=ch)

            elif kind == "image":
                if os.path.exists(val):
                    self.images.append(PhotoImage(master=self.txt, file=val))
                    self.txt.image_create(index,
                                          image=self.images[-1],
                                          name=val)
        # restore tags
        for tag, indices in kwargs.get("tags", {}).items():
            if indices:
                self.txt.tag_add(tag, *indices)

        for link in kwargs.get("links", {}).values():
            self.nb_links += 1
            self.links[self.nb_links] = link
            self.txt.tag_bind("link#%i" % self.nb_links,
                              "<Button-1>",
                              lambda e, l=link: open_url(l))

        for img, latex in kwargs.get("latex", {}).items():
            self.latex[img] = latex
            if LATEX:
                self.txt.tag_bind(img,
                                  '<Double-Button-1>',
                                  lambda e, im=img: self.add_latex(im))
        mode = self.mode.get()
        if mode != "note":
            self.txt.tag_add(mode, "1.0", "end")
        self.txt.focus_set()
        self.lock()
        if kwargs.get("rolled", False):
            self.rollnote()
        if self.position.get() == "above":
            self.set_position_above()
        elif self.position.get() == "below":
            self.set_position_below()

        # --- placement
        # titlebar
        if CONFIG.get("General", "buttons_position") == "right":
            # right = lock icon - title - roll - close
            self.columnconfigure(1, weight=1)
            self.roll.grid(row=0, column=2, sticky="e")
            self.close.grid(row=0, column=3, sticky="e", padx=(0, 2))
            self.cadenas.grid(row=0, column=0, sticky="w")
            self.title_label.grid(row=0, column=1, sticky="ew", pady=(1, 0))
        else:
            # left = close - roll - title - lock icon
            self.columnconfigure(2, weight=1)
            self.roll.grid(row=0, column=1, sticky="w")
            self.close.grid(row=0, column=0, sticky="w", padx=(2, 0))
            self.cadenas.grid(row=0, column=3, sticky="e")
            self.title_label.grid(row=0, column=2, sticky="ew", pady=(1, 0))
        # body
        self.txt.grid(row=1,
                      columnspan=4,
                      column=0,
                      sticky="ewsn",
                      pady=(1, 4),
                      padx=4)
        self.corner.lift(self.txt)
        self.corner.place(relx=1.0, rely=1.0, anchor="se")

        # --- bindings
        self.bind("<FocusOut>", self.save_note)
        self.bind('<Configure>', self.bouge)
        self.bind('<Button-1>', self.change_focus, True)
        self.close.bind("<Button-1>", self.hide)
        self.close.bind("<Enter>", self.enter_close)
        self.close.bind("<Leave>", self.leave_close)
        self.roll.bind("<Button-1>", self.rollnote)
        self.roll.bind("<Enter>", self.enter_roll)
        self.roll.bind("<Leave >", self.leave_roll)
        self.title_label.bind("<Double-Button-1>", self.edit_title)
        self.title_label.bind("<ButtonPress-1>", self.start_move)
        self.title_label.bind("<ButtonRelease-1>", self.stop_move)
        self.title_label.bind("<B1-Motion>", self.move)
        self.title_label.bind('<Button-3>', self.show_menu)
        self.title_entry.bind("<Return>",
                              lambda e: self.title_entry.place_forget())
        self.title_entry.bind("<FocusOut>",
                              lambda e: self.title_entry.place_forget())
        self.title_entry.bind("<Escape>",
                              lambda e: self.title_entry.place_forget())
        self.txt.tag_bind("link", "<Enter>",
                          lambda event: self.txt.configure(cursor="hand1"))
        self.txt.tag_bind("link", "<Leave>",
                          lambda event: self.txt.configure(cursor=""))
        self.txt.bind("<FocusOut>", self.save_note)
        self.txt.bind('<Button-3>', self.show_menu_txt)
        # add binding to the existing class binding so that the selected text
        # is erased on pasting
        self.txt.bind("<Control-v>", self.paste)
        self.corner.bind('<ButtonRelease-1>', self.resize)

        # --- keyboard shortcuts
        self.txt.bind('<Control-b>', lambda e: self.toggle_text_style('bold'))
        self.txt.bind('<Control-i>',
                      lambda e: self.toggle_text_style('italic'))
        self.txt.bind('<Control-u>', lambda e: self.toggle_underline())
        self.txt.bind('<Control-r>', lambda e: self.set_align('right'))
        self.txt.bind('<Control-l>', lambda e: self.set_align('left'))
Example #17
0
class UpdateChecker(Toplevel):
    def __init__(self, master, notify=False):
        Toplevel.__init__(self, master, class_=APP_NAME)
        logging.info('Checking for updates')
        self.title(_("Update"))
        self.withdraw()
        self.rowconfigure(0, weight=1)
        self.columnconfigure(0, weight=1)
        self.columnconfigure(1, weight=1)
        self.protocol("WM_DELETE_WINDOW", self.quit)

        self.notify = notify
        self._version = __version__

        self.img = PhotoImage(file=ICONS['question'], master=self)

        frame = Frame(self)
        frame.grid(row=0, columnspan=2, sticky="ewsn")
        Label(frame, image=self.img).pack(side="left",
                                          padx=(10, 4),
                                          pady=(10, 4))
        Label(frame,
              text=_("A new version of {app_name} is available.\
\nDo you want to download it?").format(app_name=APP_NAME),
              font="TkDefaultFont 10 bold",
              wraplength=335).pack(side="left", padx=(4, 10), pady=(10, 4))

        self.b1 = Button(self, text=_("Yes"), command=self.download)
        self.b1.grid(row=1, column=0, padx=10, pady=10, sticky="e")
        Button(self, text=_("No"), command=self.quit).grid(row=1,
                                                           column=1,
                                                           padx=10,
                                                           pady=10,
                                                           sticky="w")
        self.ch = Checkbutton(self, text=_("Check for updates on startup."))
        if CONFIG.getboolean("General", "check_update"):
            self.ch.state(("selected", "!alternate"))
        else:
            self.ch.state(("!selected", "!alternate"))
        self.ch.grid(row=2, columnspan=2, sticky='w')
        self.update = None

        self.thread = Process(target=self.update_available, daemon=True)
        self.thread.start()
        self.after(1000, self.check_update)

    def check_update(self):
        if self.update is None:
            self.after(1000, self.check_update)
        elif self.update:
            logging.info("%s %s is available", APP_NAME, self._version)
            self.deiconify()
            self.grab_set()
            self.lift()
            self.b1.focus_set()
        else:
            if self.notify:
                run([
                    "notify-send", "-i", IM_ICON_SVG,
                    _("Update"),
                    _("{app_name} is up-to-date.").format(app_name=APP_NAME)
                ])
            logging.info("%s is up-to-date", APP_NAME)
            self.destroy()

    def quit(self):
        CONFIG.set("General", "check_update",
                   str("selected" in self.ch.state()))
        save_config()
        self.destroy()

    def download(self):
        webOpen("https://github.com/j4321/{app_name}/releases/tag/v{version}".
                format(app_name=APP_NAME, version=self._version))
        self.quit()

    def update_available(self):
        """
        Check for updates online, return True if an update is available, False
        otherwise (and if there is no Internet connection).
        """
        feed = feedparser.parse(
            "https://github.com/j4321/{app_name}/releases.atom".format(
                app_name=APP_NAME))
        try:
            # feed['entries'][0]['id'] is of the form 'tag:github.com,...:Repository/.../vx.y.z'
            self._version = os.path.split(feed['entries'][0]['id'])[1][1:]
            self.update = self._version > __version__
        except IndexError:
            # feed['entries'] == [] because there is no Internet connection
            self.update = False