def handle_button_click(self, event):

        val = self.button_selected.get() - 1
        val = self.radio_buttons.index(event.widget)
        if event.state & 0x001:  # Shift key down
            self.x_flipped[val] = not self.x_flipped[val]
            try:
                raise IOError
                image_file = imget(self.img_lists[val][self.images_selected[val]])
                import_image = Image.open(image_file)
            except IOError:
                image_file = imget_bdgp(self.img_lists[val][self.images_selected[val]])
                import_image = Image.open(image_file)
                import_image = import_image.resize((180,80), Image.ANTIALIAS)
            import_image = import_image.rotate(180*self.x_flipped[val])
            embryo_image = ImageTk.PhotoImage(import_image)
            label = Label(image=embryo_image)
            label.image = embryo_image
            self.radio_buttons[val].configure(
                #text=image_file,
                image=label.image,
            )
        elif event.state & 0x004: # Control key down
            popup = Menu(root, tearoff=0)
            popup.add_command(label=self.radio_buttons[val].cget('text'))
            popup.add_separator()
            popup.add_command(label="Invert X")
            popup.add_command(label="Invert Y")
            try:
                popup.tk_popup(event.x_root, event.y_root, 0)
            finally:
                # make sure to release the grab (Tk 8.0a1 only)
                popup.grab_release()

        elif val >= 0:
            self.images_selected[val] = ((self.images_selected[val] + 2*event.num
                                         - 3) %
                                         len(self.img_lists[val]))
            self.x_flipped[val] = False
            if self.images_selected[val] == 0:
                stdout.write('\a')
                stdout.flush()

            try:
                raise IOError
                image_file = imget(self.img_lists[val][self.images_selected[val]])
                import_image = Image.open(image_file)
            except IOError:
                image_file = imget_bdgp(self.img_lists[val][self.images_selected[val]])
                import_image = Image.open(image_file)
                import_image = import_image.resize((180,80), Image.ANTIALIAS)
            embryo_image = ImageTk.PhotoImage(import_image)
            label = Label(image=embryo_image)
            label.image = embryo_image
            self.radio_buttons[val].configure(
                #text=image_file,
                image=label.image,
            )
            self.image_files[val] = image_file
        self.button_selected.set(-1)
    def _popUp(self, event):

        row = self.table.identify_row(event.y)
        #print(row)
        col = self.table.identify_column(event.x)
        #print(col)
        ''' I subtract 1 here because the root column has index zero.
        In order that the indices of the columnsfrom the tree_view to map 
        with the indices of the column_names, and popup_choices, 1 needs to be
        subracted.
        '''
        col = int(col.lstrip('#')) - 1

        def setChoice(choice):
            self._sendChoice(self, row, col, choice)

        popup = Menu(self.root, tearoff=0)

        if col in self.popup_choices.keys():
            choices = self.popup_choices[col]
            for i, j in enumerate(choices):
                '''This line below is a bit tricky. Needs to be done this way 
                because the i in the loop is only scoped for the loop, and 
                does not persist.'''
                popup.add_command(
                    command=lambda choice=choices[i]: setChoice(choice),
                    label=j)
        try:
            popup.tk_popup(event.x_root, event.y_root, 0)
        finally:
            popup.grab_release()
Exemple #3
0
class FancyListbox(Listbox):
    def __init__(self, parent, popup_menu=True, *args, **kwargs):
        Listbox.__init__(self, parent, *args, **kwargs)
        self.popup_menu = popup_menu
        if self.popup_menu:
            self.popup_menu = Menu(self, tearoff=0)
            self.popup_menu.add_command(label="Add to user words",
                                        command=self.add_user_word)
            self.bind("<Button-3>", self.popup)
        # self.entry_box = Entry(self, bg='PaleGreen1')
        # self.entry_box.pack()
        self.pack(side='top')
        self.bind('<ButtonRelease-1>', self.get_list_element)

    # @classmethod
    def get_list_element(self):
        vw = self.yview()
        # get selected line index
        if self.curselection():
            index = self.curselection()[0]
            # get the line's text

            # delete previous text in enter1
            # entry.delete(0, 100)
            # # # now display the selected text
            # entry.insert(0, text)
            self.yview_moveto(vw[0])
            print(self.get(index))
            self.last_entry = self.get(index)

    def set_list(self, entry, event):
        """
        insert an edited line from the entry widget
        back into the listbox
        """
        vw = self.yview()
        index = self.curselection()[0]

        # delete old listbox line
        self.delete(index)

        # insert edited item back into listbox1 at index
        self.insert(index, entry)
        self.yview_moveto(vw[0])

    def popup(self, event):
        try:
            self.popup_menu.tk_popup(event.x_root, event.y_root, 0)
        finally:
            self.popup_menu.grab_release()

    def add_user_word(self):
        with open(global_vars.path_root_UI + '/user_words.txt',
                  'a',
                  encoding='UTF-8') as f:
            f.write(self.get(self.curselection()) + '\n')
Exemple #4
0
    def show(self, event: Event, parent: Tk = None, **kwargs) -> bool:
        menu = Menu(parent, tearoff=0)
        added_any = False
        for option in self._options:
            added_any |= option.maybe_add(menu, kwargs)

        if added_any:
            try:
                menu.tk_popup(event.x_root, event.y_root)  # noqa
            finally:
                menu.grab_release()
        return added_any
    def pop(self, event):

        popup = Menu(self.root, tearoff=0)

        def setChoice(choice):
            self.callback(choice)

        for c in self.choices:
            '''This line below is a bit tricky. Needs to be done this way 
            because the i in the loop is only scoped for the loop, and 
            does not persist.'''
            popup.add_command(command=lambda choice=c: setChoice(choice),
                              label=c)
        try:
            popup.tk_popup(event.x_root, event.y_root, 0)
        finally:
            popup.grab_release()
            return self.choice
Exemple #6
0
 def _on_rightClick(self, event):
     """
         create popup; delete message or copy text
     """
     popup = Menu(self.msg_box, tearoff=False,
                  font=("New Times Roman", 9, "bold"),
                  activebackground="DeepSkyBlue3")
     popup.add_separator()
     popup.add_command(label="Copy text",
                       command=lambda: self.copy_text(e=event))
     popup.add_separator()
     popup.add_command(label="Delete for me", command=self.delete)
     popup.add_separator()
     try:
         popup.tk_popup(event.x_root - 10, event.y_root + 30, 0)
     except Exception:
         pass
     finally:
         popup.grab_release()
Exemple #7
0
class Interface(Frame):
    def __init__(self, master=None, *_):
        Frame.__init__(self, master)
        self.master = master

        # settings variables
        self.word_wrap = BooleanVar()
        self.word_wrap.set(True)
        self.__show_status_bar = BooleanVar()
        self.__show_status_bar.set(True)
        self.fnt = font.Font(family="Courier New", size=10)
        self.find_open = False
        self.replace_open = False
        self.goto_open = False
        self.prior_search = ''
        self.prior_goto = ''

        # init methods
        self.__init_main_window()
        self.__build_status_bar()
        self.__build_menu_bar()
        self.__bind_shortcuts()
        self.toggle_word_wrap()
        self.context_menu = Menu(self.master, tearoff=0)

        self.last_hash = get_signature(self.text_area.get(1.0, END))

    def __init_main_window(self):
        self.text_area = Text(self.master, undo=True)
        self.text_area.config(font=self.fnt, wrap=WORD)

        # To add scrollbar
        self.scroll_bar_x = Scrollbar(self.master, orient=HORIZONTAL)
        self.scroll_bar_y = Scrollbar(self.master, orient=VERTICAL)
        __file = None

        try:
            self.master.wm_iconbitmap('notepad.ico')
        except TclError:
            log.error("unable to set icon to notepad.ico")
            pass

        # Set the window text
        self.master.title('Untitled - Notepad')

        # To make the text area auto resizable
        self.master.grid_rowconfigure(0, weight=1)
        self.master.grid_columnconfigure(0, weight=1)

        self.text_area.grid(column=0, row=0, sticky='nsew')

        self.scroll_bar_y.grid(column=1, row=0, sticky='nsew')
        self.scroll_bar_x.grid(column=0, row=1, stic='nsew')

        # Scrollbar will adjust automatically according to the content
        self.scroll_bar_x.config(command=self.text_area.xview)
        self.scroll_bar_y.config(command=self.text_area.yview)
        self.text_area.config(xscrollcommand=self.scroll_bar_x.set,
                              yscrollcommand=self.scroll_bar_y.set)

        self.text_area.focus()

    def __build_menu_bar(self):
        # main and submenus
        self.menu_bar = Menu(self.master)
        self.file_menu = Menu(self.menu_bar, tearoff=0)
        self.edit_menu = Menu(self.menu_bar, tearoff=0)
        self.format_menu = Menu(self.menu_bar, tearoff=0)
        self.thisViewMenu = Menu(self.menu_bar, tearoff=0)
        self.help_menu = Menu(self.menu_bar, tearoff=0)

        # File Menu
        self.menu_bar.add_cascade(label='File',
                                  underline=0,
                                  menu=self.file_menu)
        self.file_menu.add_command(label='New',
                                   underline=0,
                                   accelerator='Ctrl+N',
                                   command=new_file)
        self.file_menu.add_command(label='Open...',
                                   underline=0,
                                   accelerator='Ctrl+O',
                                   command=open_file)
        self.file_menu.add_command(label='Save',
                                   underline=0,
                                   accelerator='Ctrl+S',
                                   command=save_file)
        self.file_menu.add_command(label='Save As...',
                                   underline=5,
                                   command=save_file_as)
        self.file_menu.add_separator()
        self.file_menu.add_command(label='Page Setup...',
                                   underline=5,
                                   accelerator='Ctrl+S',
                                   command=save_file)
        self.file_menu.add_command(label='Print',
                                   underline=0,
                                   accelerator='Ctrl+P',
                                   command=save_file)
        self.file_menu.add_separator()
        self.file_menu.add_command(label='Exit',
                                   underline=1,
                                   command=self.quit_application)

        # Edit Menu
        self.menu_bar.add_cascade(label='Edit',
                                  underline=0,
                                  menu=self.edit_menu)
        self.edit_menu.add_command(label='Undo',
                                   underline=0,
                                   accelerator='Ctrl+Z',
                                   command=self.undo)
        self.edit_menu.add_separator()
        self.edit_menu.add_command(label='Cut',
                                   underline=2,
                                   accelerator='Ctrl+X',
                                   command=self.cut)
        self.edit_menu.add_command(label='Copy',
                                   underline=0,
                                   accelerator='Ctrl+C',
                                   command=self.copy)
        self.edit_menu.add_command(label='Paste',
                                   underline=0,
                                   accelerator='Ctrl+V',
                                   command=self.paste)
        self.edit_menu.add_command(label='Delete',
                                   underline=2,
                                   accelerator='Del',
                                   command=self.delete)
        self.edit_menu.add_command(label='Search with Bing... ',
                                   underline=0,
                                   accelerator='Ctrl+B',
                                   command=self.search_selected_text)
        self.edit_menu.add_separator()
        self.edit_menu.add_command(label='Find...',
                                   underline=0,
                                   accelerator='Ctrl+F',
                                   command=self.show_find)
        self.edit_menu.add_command(label='Find Next',
                                   underline=5,
                                   accelerator='F3',
                                   command=self.find_next)
        self.edit_menu.add_command(label='Replace...',
                                   underline=0,
                                   accelerator='Ctrl+H',
                                   command=self.show_find_replace)
        self.edit_menu.add_command(label='Go To...',
                                   underline=0,
                                   accelerator='Ctrl+G',
                                   command=self.show_goto)
        self.edit_menu.add_separator()
        self.edit_menu.add_command(label='Select All',
                                   underline=7,
                                   accelerator='Ctrl+A',
                                   command=lambda: self.select_all())
        self.edit_menu.add_command(label='Time/Date',
                                   underline=5,
                                   accelerator='F5',
                                   command=self.time_date)

        # Format Menu
        self.menu_bar.add_cascade(label='Format',
                                  underline=0,
                                  menu=self.format_menu)
        self.format_menu.add_checkbutton(label='Word Wrap',
                                         underline=0,
                                         variable=self.word_wrap,
                                         command=self.toggle_word_wrap)
        self.format_menu.add_command(label='Font...',
                                     underline=0,
                                     command=self.set_font)

        # View Menu
        self.menu_bar.add_cascade(label='View',
                                  underline=1,
                                  menu=self.thisViewMenu)
        self.thisViewMenu.add_checkbutton(label='Status Bar',
                                          underline=0,
                                          variable=self.__show_status_bar,
                                          command=self.toggle_status_bar)

        # Help Menu
        self.menu_bar.add_cascade(label='Help',
                                  underline=0,
                                  menu=self.help_menu)
        self.help_menu.add_command(label='View Help',
                                   underline=5,
                                   command=self.get_help)
        self.help_menu.add_separator()
        self.help_menu.add_command(label='About Notepad',
                                   underline=0,
                                   command=show_about)

        self.master.config(menu=self.menu_bar)

    def show_context_menu(self, event):
        try:
            self.context_menu = Menu(self.master, tearoff=0)
            self.context_menu.add_command(label='Undo',
                                          underline=2,
                                          accelerator='Ctrl+Z',
                                          command=self.undo)
            self.context_menu.add_separator()
            self.context_menu.add_command(label='Cut',
                                          underline=2,
                                          accelerator='Ctrl+X',
                                          command=self.cut)
            self.context_menu.add_command(label='Copy',
                                          underline=0,
                                          accelerator='Ctrl+C',
                                          command=self.copy)
            self.context_menu.add_command(label='Paste',
                                          underline=0,
                                          accelerator='Ctrl+V',
                                          command=self.paste)
            self.context_menu.add_command(label='Delete',
                                          underline=2,
                                          accelerator='Del',
                                          command=self.delete)
            self.context_menu.add_separator()
            self.context_menu.add_command(label='Select All',
                                          underline=2,
                                          accelerator='Ctrl+A',
                                          command=self.select_all)
            self.context_menu.add_separator()
            self.context_menu.add_command(label='Search with Bing... ',
                                          underline=0,
                                          accelerator='Ctrl+B',
                                          command=self.search_selected_text)
            self.context_menu.tk_popup(event.x_root, event.y_root)

        finally:
            self.context_menu.grab_release()

    def set_font(self):
        fnt = fontpicker.ask_font(family=self.fnt.actual(option='family'),
                                  size=self.fnt.actual(option='size'),
                                  weight=self.fnt.actual(option='weight'),
                                  slant=self.fnt.actual(option='slant'))

        if fnt:
            self.fnt = font.Font(family=fnt['family'],
                                 size=int(fnt['size']),
                                 weight=fnt['weight'],
                                 slant=fnt['slant'])

            self.text_area.config(font=self.fnt)

    def __build_status_bar(self):
        self.status_bar = Label(self.master,
                                text="Ln 1, Col 1\t",
                                bd=1,
                                relief=SUNKEN,
                                anchor='e')
        self.toggle_status_bar()

    def toggle_status_bar(self):
        if self.__show_status_bar.get():
            self.status_bar.grid(sticky='sew')
        else:
            self.status_bar.grid_forget()

    def toggle_word_wrap(self):
        if self.word_wrap.get():
            self.text_area.config(wrap=WORD)
            self.scroll_bar_x.grid_forget()
            log.info("word wrap on, scroll bar off")
        else:
            self.text_area.config(wrap=NONE)
            self.scroll_bar_x.grid(column=0, row=1, sticky='nsew')
            log.info("word wrap off, scroll bar on")

    def __bind_shortcuts(self):
        self.master.bind_class('Text', '<Control-a>', self.select_all)
        self.master.bind_class('Text', '<Control-A>', self.select_all)
        self.master.bind_class('Text', '<Control-s>', save_file)
        self.master.bind_class('Text', '<Control-S>', save_file)
        self.master.bind_class('Text', '<Control-n>', new_file)
        self.master.bind_class('Text', '<Control-N>', new_file)
        self.master.bind_class('Text', '<Control-b>',
                               self.search_selected_text)
        self.master.bind_class('Text', '<Control-B>',
                               self.search_selected_text)
        self.master.bind_class('Text', '<Control-f>', self.show_find)
        self.master.bind_class('Text', '<Control-F>', self.show_find)
        self.master.bind_class('Text', '<Control-h>', self.show_find_replace)
        self.master.bind_class('Text', '<Control-H>', self.show_find_replace)
        self.master.bind_class('Text', '<Control-g>', self.show_goto)
        self.master.bind_class('Text', '<Control-G>', self.show_goto)
        self.master.bind_class('Text', '<F5>', self.time_date)
        self.master.bind_class('Text', '<F3>', self.find_next)
        self.text_area.bind_class(self.text_area, '<Any-KeyPress>',
                                  self.on_key)
        self.text_area.bind_class(self.text_area, '<Button-1>', self.on_click)
        self.text_area.bind_class(self.text_area, '<Button-3>',
                                  self.show_context_menu)

    def quit_application(self):
        if notepad.has_changed():
            save_box = messagebox.askquestion(
                'Confirm save',
                'Do you want to save before closing this file?',
                icon='warning')
            if save_box == 'yes':
                save_file()
        self.master.destroy()
        exit()

    def undo(self, *_):
        self.text_area.event_generate('<<Undo>>')

    def on_key(self, *_):
        self.update_status_bar(INSERT)

    def on_click(self, *_):
        self.update_status_bar(CURRENT)

        try:
            self.context_menu.destroy()
        except AttributeError:
            log.warning(
                'error occurred while trying to exit context menu, probably not instansiated'
            )

    def update_status_bar(self, obj):
        row, col = self.text_area.index(obj).split('.')
        self.status_bar.config(text=str('Ln ' + row + ', Col ' + col + ' \t'))

    def cut(self, *_):
        self.text_area.event_generate('<<Cut>>')

    def copy(self, *_):
        self.text_area.event_generate('<<Copy>>')

    def paste(self, *_):
        self.text_area.event_generate('<<Paste>>')

    def select_all(self, *_):
        self.text_area.tag_add('sel', '1.0', 'end')

    def delete(self, *_):
        self.text_area.event_generate('<Delete>')

    def search_selected_text(self, *_):
        try:
            s = self.text_area.selection_get()
            if s is not None:
                search_with_bing(s)
            else:
                log.debug('selection was empty, not searching with bing')
        except TclError:
            print('TclError - Probably because nothing was selected ')

    def time_date(self, *_):
        now = datetime.now()
        s = now.strftime("%I:%M %p %m/%d/%Y")
        self.text_area.insert(INSERT, s)

    def show_find(self, *_):
        if not self.find_open:
            self.find_open = True
            FindWindow(master=self)

    def show_find_replace(self, *_):
        if not self.replace_open:
            self.replace_open = True
            FindReplaceWindow(master=self)

    def show_goto(self, *_):
        if not self.goto_open:
            self.goto_open = True
            GotoWindow(master=self)

    @staticmethod
    def get_help():
        search_with_bing("get+help+with+notepad+in+windows+10")

    def run(self):
        # Run main application
        self.master.mainloop()

    def set_title(self, string):
        self.master.title(string + ' - Notepad')

    def clear_text(self):
        self.text_area.delete(1.0, END)

    def get_text(self):
        return self.text_area.get(1.0, END)

    def write_text(self, text, start_index=1.0):
        self.text_area.insert(start_index, text)

    def find_next(self, _):
        search_string = self.prior_search

        location = self.text_area.search(search_string,
                                         self.text_area.index(INSERT),
                                         nocase=True)
        log.info('searching next -- forwards')

        if location != '':
            log.info('found ' + search_string + ' at position ' + location)

            row, col = get_index(location)
            end_col = str(col + len(search_string))
            end_location = str(str(row) + '.' + end_col)

            self.text_area.mark_set("insert", end_location)
            self.text_area.see("insert")
            self.text_area.tag_remove('sel', "1.0", END)
            self.text_area.tag_raise("sel")
            self.text_area.tag_add('sel', location, end_location)
            self.text_area.focus()
        else:
            log.warning(search_string + 'string not found')

    def has_changed(self):
        if get_signature(self.text_area.get(1.0, END)) == self.last_hash:
            log.info('file has changed')
            return False
        else:
            log.info('file has not changed')
            return True
Exemple #8
0
class Main(Frame):
    def __init__(self, window, *args, **kwargs):
        Frame.__init__(self, window, *args, **kwargs)
        self.window = window
        self.window.title("YouTube Downloader")
        self.window.rowconfigure(0, weigh=1)
        self.window.columnconfigure(0, weight=1)
        self.format_tuple = ()
        self.step = 0
        self.bytes = 0
        self.max_bytes = 0

        # Create a Queue
        self.guiQueue = queue.Queue()

        self.create_widgets()

        self.path = os.path.abspath(os.getcwd())

    def create_widgets(self):
        # Variables
        self.url_var = tk.StringVar()
        # self.url_var.trace_add('write', self.populate_format)
        self.save_to_var = tk.StringVar()
        self.format_var = tk.StringVar()
        self.format_var.trace_add('write', self.check_audio)
        self.includes_var = tk.StringVar()
        self.percent_var = tk.StringVar()
        self.bar_var = tk.IntVar()
        self.convert_var = tk.StringVar()

        # Create popup menu for Copy/Paste
        self.m = Menu(self.window, tearoff=0)
        self.m.add_command(label="Cut")
        self.m.add_command(label="Copy")
        self.m.add_command(label="Paste")

        # Main frame
        self.main_frame = tk.Frame(self.window)
        self.main_frame.grid(column=0, row=0, sticky='wne', padx=10, pady=10)
        self.main_frame.rowconfigure(2, weight=1)
        self.main_frame.columnconfigure(0, weight=1)
        self.main_frame.columnconfigure(1, weight=1)

        self.url_frame = ttk.Frame(self.main_frame)
        self.url_frame.grid(column=0, row=0, columnspan=2, sticky='enw')
        self.url_frame.columnconfigure(1, weight=1)
        self.url_label = ttk.Label(self.url_frame, text="URL")
        self.url_label.grid(column=0, row=0, sticky='w')
        self.url_entry = ttk.Entry(self.url_frame, textvariable=self.url_var)
        self.url_entry.grid(column=1, row=0, sticky='ew')
        self.save_to_button = ttk.Button(self.url_frame,
                                         text="Save To",
                                         command=self.save_to)
        self.save_to_button.grid(column=0, row=1, sticky='w')
        self.save_to_entry = ttk.Entry(self.url_frame,
                                       textvariable=self.save_to_var)
        self.save_to_entry.grid(column=1, row=1, sticky='ew')

        self.download_frame = tk.Frame(self.main_frame)
        self.download_frame.columnconfigure(2, weight=1)
        self.download_frame.columnconfigure(3, weight=1)
        # self.download_frame.columnconfigure(1, weight=1)
        self.download_frame.grid(column=0,
                                 row=1,
                                 columnspan=2,
                                 pady=5,
                                 sticky='ew')
        self.load_url = ttk.Button(self.download_frame,
                                   text="Load URL",
                                   command=self.populate_format)
        self.load_url.grid(column=0, row=0, ipady=10)
        self.format_combo = ttk.Combobox(self.download_frame,
                                         textvariable=self.format_var)
        self.format_combo.grid(column=1, row=0, padx=10)
        self.includes_audio = ttk.Label(self.download_frame,
                                        textvariable=self.includes_var,
                                        width=20)
        self.includes_audio.grid(column=2, row=0, padx=10)
        self.download_button = ttk.Button(self.download_frame,
                                          text="Download Video",
                                          command=self.download_video)
        self.download_button.grid(column=3,
                                  row=0,
                                  ipadx=30,
                                  ipady=10,
                                  sticky='e')
        self.download_label = ttk.Label(self.download_frame,
                                        textvariable=self.percent_var)
        self.download_label.grid(column=0, row=1, sticky='ew', columnspan=4)
        self.download_bar = ttk.Progressbar(self.download_frame,
                                            orient=tk.HORIZONTAL,
                                            mode='determinate',
                                            variable=self.bar_var)
        self.download_bar.grid(column=0,
                               row=2,
                               columnspan=4,
                               sticky='ew',
                               pady=10)

        # create a Treeview
        self.tree = ttk.Treeview(self.main_frame,
                                 show='headings',
                                 columns=('Name', 'Format', 'Size',
                                          'Resolution'))
        self.tree.grid(column=0, row=2, columnspan=2, sticky='wne')
        self.tree.bind('<<TreeviewSelect>>', self.file_to_convert)

        self.tree.column('Name', width=250, anchor='center')
        self.tree.heading('Name', text='Name')
        self.tree.column('Format', width=30, anchor='center')
        self.tree.heading('Format', text='Format')
        self.tree.column('Size', width=70, anchor='center')
        self.tree.heading('Size', text='Size')
        self.tree.column('Resolution', width=70, anchor='center')
        self.tree.heading('Resolution', text='Resolution')

        self.check_platform()

        self.convert_frame = ttk.Frame(self.main_frame)
        self.convert_frame.grid(column=0, row=3, columnspan=2, sticky='ew')
        # self.convert_frame.columnconfigure(0, weight=1)
        self.convert_frame.columnconfigure(2, weight=1)
        # self.convert_frame.columnconfigure(2, weight=1)
        # self.convert_frame.columnconfigure(2, weight=1)
        self.file_label = ttk.Label(self.convert_frame, text="File name")
        self.file_label.grid(column=0, row=0)
        self.convert_entry = ttk.Entry(self.convert_frame,
                                       textvariable=self.convert_var)
        self.convert_entry.grid(column=1, row=0, sticky='ew')
        self.convert_progress = ttk.Progressbar(self.convert_frame,
                                                orient=tk.HORIZONTAL,
                                                mode='indeterminate')
        self.convert_progress.grid(column=2, row=0, ipadx=10, sticky='ew')
        self.convert_button = ttk.Button(self.convert_frame,
                                         text="Convert Audio",
                                         command=self.convert_video)
        self.convert_button.grid(column=3,
                                 row=0,
                                 ipadx=30,
                                 ipady=10,
                                 sticky='e')

    def save_to(self):
        file_path = filedialog.askdirectory()
        self.save_to_var.set(file_path)
        self.path = self.save_to_var.get()

    def popup(self, event):
        try:
            self.m.entryconfig(
                "Cut", command=lambda: event.widget.event_generate("<<Cut>>"))
            self.m.entryconfig(
                "Copy",
                command=lambda: event.widget.event_generate("<<Copy>>"))
            self.m.entryconfig(
                "Paste",
                command=lambda: event.widget.event_generate("<<Paste>>"))
            self.m.tk.call("tk_popup", self.m, event.x_root, event.y_root)
        finally:
            self.m.grab_release()

    def check_platform(self):
        plt = platform.system()
        if plt == "Windows":
            print("Your system is Windows")
            self.url_entry.bind("<Button-3>", self.popup)
            self.save_to_entry.bind("<Button-3>", self.popup)
        elif plt == "Linux":
            print("Your system is Linux")
            self.url_entry.bind("<Button-3>", self.popup)
            self.save_to_entry.bind("<Button-3>", self.popup)
        elif plt == "Darwin":
            print("Your system is MacOS")
            self.url_entry.bind("<Button-2>", self.popup)
            self.save_to_entry.bind("<Button-2>", self.popup)
        else:
            print("Unidentified system")
            mBox.showinfo("Copy/Paste functionality not working.")

    def file_to_convert(self, *args):
        # Reset the convert progressbar if used before
        self.convert_progress.stop()

        item = self.tree.focus()
        item = self.tree.item(item)
        self.video_file = item['text']
        title_file = item['values'][0]
        self.convert_var.set(title_file)

    def convert_video(self, *args):
        if len(self.convert_var.get()) > 0:
            try:
                from pydub import AudioSegment
                print("Alabama", self.video_file)
                if os.path.isfile(self.video_file):
                    self.convert_progress.start()
                    self.convert_progress.step(10)
                    self.convert_progress.update_idletasks()
                    audio = AudioSegment.from_file(self.video_file)
                    new_file = self.video_file.replace("mp4", "mp3")
                    audio.export(new_file, format="mp3", codec="libmp3lame")
                    # self.convert_progress.stop()
                    # mBox.showinfo("Convert to MP3", "The video has been converted from MP4 to MP3.")
                else:
                    mBox.showerror(
                        "Convert to MP3",
                        "The file to convert doesn't exists!\nPlease check the folder for the actual file!"
                    )
            except:
                mBox.showerror("Convert to MP3",
                               "The conversion to MP3 failed!")
        else:
            mBox.showwarning(
                "Convert to MP3",
                "No file selected from the list to be converted!")

    def check_audio(self, *args):
        """ Check is current stream has audio"""
        if self.yt.streams[self.format_combo.current()].includes_audio_track:
            self.includes_var.set("Video includes audio? Yes")
        else:
            self.includes_var.set("Video includes audio? No")

    def download_video(self):
        if len(self.url_entry.get()) > 0:
            self.stream = self.yt.streams[self.format_combo.current()]

            # Set progress bar's maximum to video size
            self.max_bytes = self.stream.filesize
            self.download_bar['maximum'] = 100
            self.download_bar['value'] = self.step

            self.t1 = threading.Thread(target=self.fill_bar, args=[])
            self.t1.start()

        else:
            mBox.showwarning(
                "URL Error",
                "You have not entered an Url.\nPlease enter a valid YouTuber Url to download a video."
            )

    def populate_format(self, *args):
        """ Get the streams from URL, filter only the mp4 streams, extract the resolution and fps.
            Populate the combo box with the extracted values. """
        # TODO extract everything in a different thread
        # Reset the convert progressbar if used before
        self.convert_progress.stop()

        self.format_combo['values'] = ()
        try:
            self.yt = YouTube(self.url_entry.get(),
                              on_progress_callback=self.progress_bar,
                              on_complete_callback=self.insert_tree)

            for stream in self.yt.streams.filter(subtype="mp4"):
                if stream.includes_video_track:
                    self.format_tuple += (str(stream.mime_type) + " " +
                                          str(stream.resolution) + " " +
                                          str(stream.fps) + "fps", )

        except exceptions.VideoUnavailable as videoUnavailable:
            mBox.showerror(
                "Error", "Something wrong happened!\nError on line {}".format(
                    sys.exc_info()[-1].tb_lineno) + ". " +
                str(videoUnavailable.__doc__))
        except exceptions.RegexMatchError as regexError:
            mBox.showerror(
                "Error", "Something wrong happened!\nError on line {}".format(
                    sys.exc_info()[-1].tb_lineno) + ". " +
                str(regexError.__doc__))
        except exceptions.HTMLParseError as htmlParseError:
            mBox.showerror(
                "Error", "Something wrong happened!\nError on line {}".format(
                    sys.exc_info()[-1].tb_lineno) + ". " +
                str(htmlParseError.__doc__))
        except exceptions.ExtractError as extractError:
            mBox.showerror(
                "Error", "Something wrong happened!\nError on line {}".format(
                    sys.exc_info()[-1].tb_lineno) + ". " +
                str(extractError.__doc__))
        except exceptions.PytubeError as pytubeError:
            mBox.showerror(
                "Error", "Something wrong happened!\nError on line {}".format(
                    sys.exc_info()[-1].tb_lineno) + ". " +
                str(pytubeError.__doc__))
        except KeyError as io:
            mBox.showerror(
                "Error", "Something wrong happened!\nError on line {}".format(
                    sys.exc_info()[-1].tb_lineno) + ". " + str(io.__doc__) +
                " " + str(io))
        except:
            mBox.showerror("Error", "Something wrong happened!")

        if len(self.format_tuple) > 0:
            self.format_combo['values'] = self.format_tuple
            self.format_combo.current(0)
            self.check_audio()

    def progress_bar(self, chunk, file_handle, bytes_remaining):
        remaining = (100 * bytes_remaining) / self.max_bytes
        self.step = 100 - int(remaining)
        self.guiQueue.put(self.step)
        self.window.after(1000, self.listen_result)

    def fill_bar(self):
        if len(self.save_to_var.get()) > 0:
            self.path = self.save_to_var.get()
        if os.path.isfile(self.path + "/" + str(self.format_combo.current()) +
                          "_" + self.stream.default_filename):
            mBox.showerror("Download error",
                           "This file already exists!\nPlease check again!")
        elif not os.path.isdir(self.path):
            mBox.showerror(
                "Download error",
                "The selected path does not exists!\nPlease check again!")
        else:
            self.stream.download(
                output_path=self.path,
                filename_prefix=str(self.format_combo.current()) + "_")

    def listen_result(self):
        try:
            self.step = self.guiQueue.get_nowait()
            self.bar_var.set(self.step)
            self.percent_var.set("Downloading...  " + str(self.step) + "%")
            self.window.after(1000, self.listen_result)
        except queue.Empty:
            # self.window.after(100, self.listen_result)
            pass

    def insert_tree(self, *args):
        """ Insert details of downloaded video into the tree. """
        self.percent_var.set("Downloading...  " + str(self.step) +
                             "% Completed!")
        iid = self.path + "/" + str(
            self.format_combo.current()) + "_" + self.stream.default_filename
        name = str(
            self.format_combo.current()) + "_" + self.stream.default_filename
        video_format = "mp4"
        size = str(round(self.stream.filesize * 0.000001, 1)) + "MB"
        resolution = self.set_resolution()
        try:
            self.tree.insert('',
                             'end',
                             iid=iid,
                             text=iid,
                             values=(name, video_format, size, resolution))
        except TclError as err:
            mBox.showerror(
                "Download error",
                "Error after download!\nError on line {}".format(
                    sys.exc_info()[-1].tb_lineno) + ". " + str(err))

    def set_resolution(self):
        """ Label the resolution of the video """
        if self.stream.resolution == "2160p":
            return "3840x2160"
        elif self.stream.resolution == "1440p":
            return "2560x1440"
        elif self.stream.resolution == "1080p":
            return "1920x1080"
        elif self.stream.resolution == "720p":
            return "1280x720"
        elif self.stream.resolution == "480p":
            return "854x480"
        elif self.stream.resolution == "360p":
            return "640x360"
        elif self.stream.resolution == "240p":
            return "426x240"
        elif self.stream.resolution == "144p":
            return "256x144"
        else:
            return "No resolution detected"
Exemple #9
0
class CrawlTab(ttk.Frame):
    def __init__(self,
                 root,
                 crawler=None,
                 freeze_tabs=None,
                 unfreeze_tabs=None):
        ttk.Frame.__init__(self)
        self.root = root
        self.crawler = crawler
        self.lock = crawler.lock
        self.freeze_tabs = freeze_tabs
        self.unfreeze_tabs = unfreeze_tabs

        self.topframe = ttk.Frame(self)
        self.topframe.pack(anchor='center', padx=20, pady=20, fill="x")

        self.entry_url_input = EnhancedEntry(self.topframe,
                                             'Enter URL to crawl')
        self.entry_url_input.entry.bind('<Return>', self.enter_hit)

        self.button_crawl = ttk.Button(self.topframe,
                                       text="Start",
                                       command=self.btn_crawl_pushed)
        self.button_crawl.pack(side=LEFT, padx=(0, 20))

        self.button_clear = ttk.Button(self.topframe,
                                       text="Clear",
                                       command=self.btn_clear_pushed)
        self.button_clear.pack(side=LEFT, padx=(0, 20))
        self.button_clear['state'] = 'disabled'

        # macOS and linux have issues with the below style so only use it on
        # windows for now
        if sys.platform != "win32":
            self.progressbar = ttk.Progressbar(self.topframe,
                                               orient="horizontal",
                                               length=150,
                                               mode="determinate",
                                               maximum=100,
                                               value=0)
        elif sys.platform == "win32":
            self.style = ttk.Style(self)
            self.style.layout(
                'text.Horizontal.TProgressbar',
                [('Horizontal.Progressbar.trough', {
                    'children': [('Horizontal.Progressbar.pbar', {
                        'side': 'left',
                        'sticky': 'ns'
                    })],
                    'sticky':
                    'nswe'
                }), ('Horizontal.Progressbar.label', {
                    'sticky': ''
                })])
            self.style.configure('text.Horizontal.TProgressbar', text='0 %')
            self.progressbar = ttk.Progressbar(
                self.topframe,
                orient="horizontal",
                length=150,
                mode="determinate",
                maximum=100,
                value=0,
                style='text.Horizontal.TProgressbar')

        self.progressbar.pack(side=LEFT, fill="x")

        self.middle_frame = ttk.Frame(self)
        self.middle_frame.pack(anchor='center', fill='both', expand=True)

        self.treeview_table = ttk.Treeview(self.middle_frame,
                                           selectmode="browse")

        # Capture right clicks on table
        right_click = '<Button-3>'

        if sys.platform == 'darwin':
            right_click = '<Button-2>'

        self.treeview_table.bind(right_click, self.assign_treeview_click)

        self.scrollbar_vertical = ttk.Scrollbar(
            self.middle_frame,
            orient="vertical",
            command=self.vertical_scrollbar_clicked)
        self.scrollbar_vertical.pack(side="right", fill="y")
        self.scrollbar_horizontal = ttk.Scrollbar(
            self.middle_frame,
            orient="horizontal",
            command=self.treeview_table.xview)
        self.scrollbar_horizontal.pack(side="bottom", fill="x")
        self.treeview_table.configure(
            yscrollcommand=self.scrollbar_vertical.set,
            xscrollcommand=self.scrollbar_horizontal.set)
        self.treeview_table.pack(fill="both", expand=1)

        self.bottom_frame = ttk.Frame(self)
        self.bottom_frame.pack(anchor='center', padx=5, pady=5, fill='x')

        self.urls_string_var = StringVar()
        self.urls_string_var.set("Speed: - URL/s")
        self.label_urls_per_second = ttk.Label(
            self.bottom_frame, textvariable=self.urls_string_var)
        self.label_urls_per_second.pack(side=LEFT)

        self.urls_crawled_string_var = StringVar()
        self.urls_crawled_string_var.set("URLs crawled/discovered: 0/0 (0%)")
        self.label_urls_crawled = ttk.Label(
            self.bottom_frame, textvariable=self.urls_crawled_string_var)
        self.label_urls_crawled.pack(side=RIGHT)

        self.percentage = 0

        self.populate_columns()
        self.row_counter = 1

        # pop up menu for treeview header items
        self.popup_menu = Menu(self, tearoff=0)
        self.popup_menu.add_command(label='Reset Filters',
                                    command=self.reset_filters)
        self.popup_menu.add_separator()
        labels = Defaults.popup_menu_labels
        generate_menu(self.popup_menu, labels, self.show_filter_window)
        self.selected_column = ''

        self.filter_window = None

        # action menu for treeview row items
        self.action_menu = Menu(self, tearoff=0)
        labels = ['Copy URL', 'Open URL in Browser', '_', 'View Inlinks']
        generate_menu(self.action_menu, labels, self.show_action_window)
        self.row_values = []
        self.suspend_auto_scroll = False

        self.viewed_table = 'crawl'
        self.filters = []

    def clear_output_table(self):
        # Clear table
        self.treeview_table.delete(*self.treeview_table.get_children())
        self.row_counter = 1

    def get_display_columns(self, table=None):
        if not table:
            if self.crawler.columns:
                return self.crawler.columns.copy()
            return Defaults.display_columns.copy()
        return self.crawler.get_columns(table)

    def populate_columns(self, columns=None):
        column_default_width = 80
        column_url_width = 700
        column_titles_width = 250

        display_column_mapping = {
            'url': ('URL', column_url_width),
            'redirect_url': ('Redirect URL', column_url_width),
            'canonical_tag': ('Canonical Tag', column_url_width),
            'content_type': ('Content Type', 100),
            'h1': ('H1', column_titles_width),
            'page_title': ('Page Title', column_titles_width),
            'url_from': ('URL From', column_url_width),
            'url_to': ('URL To', column_url_width)
        }

        if not columns:
            columns = self.get_display_columns()

        self.treeview_table["columns"] = tuple(columns)

        self.treeview_table.heading("#0", text="id", anchor=W)
        self.treeview_table.column("#0", width=55, stretch=False)

        for e in self.treeview_table["columns"]:
            name, width = display_column_mapping.get(e, (None, None))
            if not name:
                name = e.replace('_', ' ').title()
                width = column_default_width

            self.treeview_table.heading(e, text=name, anchor=W)
            self.treeview_table.column(e, width=width, stretch=False)

    def enter_hit(self, event=None):
        self.btn_crawl_pushed()

    def start_new_crawl(self, url):
        files = [('Greenflare DB', f'*{Defaults.file_extension}'),
                 ('All files', '.*')]
        db_file = fd.asksaveasfilename(filetypes=files)
        if db_file:
            if not db_file.endswith(Defaults.file_extension):
                db_file += Defaults.file_extension
            if path.isfile(db_file):
                remove(db_file)
            self.crawler.reset_crawl()
            self.run_first_time = False
            self.crawler.db_file = db_file
            self.crawler.settings["STARTING_URL"] = url
            self.entry_url_input.entry["state"] = "disabled"
            self.crawler.start_crawl()
            self.clear_output_table()
            self.populate_columns()
            self.master.title(
                f"{self.crawler.gf.get_domain(self.crawler.settings['STARTING_URL'])} - {Defaults.window_title}"
            )

            self.after(10, self.add_to_outputtable)
            self.after(10, self.update_buttons)

    @run_in_background_with_window([],
                                   title='Stopping crawl ...',
                                   msg='Waiting for crawl to finish ...')
    def stop_crawl(self):
        self.crawler.end_crawl_gracefully()
        self.after(10, self.update_buttons)

    def btn_crawl_pushed(self):
        url = self.entry_url_input.get().strip()

        if self.button_crawl["text"] == "Start":
            # Validate input url
            url_components = self.crawler.gf.parse_url(url)

            if self.crawler.settings.get('MODE', '') == 'Spider':

                if url_components['scheme'] == '':
                    url = 'http://' + url
                    url_components = self.crawler.gf.parse_url(url)

                if url_components['netloc'] == '' or ' ' in url_components[
                        'netloc']:
                    messagebox.showerror(title='Invalid URL',
                                         message='Please enter a valid URL!')
                    return

            url = self.crawler.gf.url_components_to_str(url_components)

            self.entry_url_input.entry.delete(0, 'end')
            self.entry_url_input.entry.insert(0, url)

            self.start_new_crawl(url)

        elif self.button_crawl["text"] == "Pause":
            self.stop_crawl()

        elif self.button_crawl["text"] == "Resume":
            self.populate_columns()
            self.crawler.resume_crawl()
            self.row_counter = self.crawler.urls_crawled + 1
            self.after(10, self.add_to_outputtable)
            self.after(10, self.update_buttons)

        elif self.button_crawl["text"] == "Restart":
            self.start_new_crawl(url)

        print(self.crawler.settings)

    def update_buttons(self):
        btn_txt = self.button_crawl["text"]
        if btn_txt == "Start":
            self.button_crawl["text"] = "Pause"
            self.button_clear['state'] = 'disabled'
            self.freeze_tabs()
        elif btn_txt == "Pause":
            self.button_crawl["text"] = "Resume"
            self.button_clear['state'] = 'enabled'
            self.unfreeze_tabs()
        elif btn_txt == "Resume":
            self.button_crawl["text"] = "Pause"
            self.button_clear['state'] = 'enabled'
            self.freeze_tabs()
        elif btn_txt == "Restart":
            self.button_crawl["text"] = "Pause"
            self.button_clear['state'] = 'enabled'

    def btn_clear_pushed(self):
        msg = messagebox.askquestion(
            'Clear View',
            'Are you sure you want clear the view? All data has been saved.',
            icon='warning')

        if msg == 'yes':
            self.reset(reset_url_input=False)
        else:
            return

    def add_item_to_outputtable(self, item):
        self.treeview_table.insert('',
                                   'end',
                                   text=self.row_counter,
                                   values=item)
        with self.lock:
            self.row_counter += 1

        # Allow user to scroll up and only continue autoscroll if the
        # scroll bar is near the bottom edge
        if not self.suspend_auto_scroll:
            self.treeview_table.yview_moveto(1)

    def add_to_outputtable(self):
        items = []

        with self.lock:
            if self.crawler.gui_url_queue:
                items = self.crawler.gui_url_queue.copy()
                self.crawler.gui_url_queue = []

        if len(items) > 0:
            for item in items:
                self.add_item_to_outputtable(item)

            self.update_progressbar()
            self.update_bottom_stats()

        if self.crawler.crawl_completed.is_set():
            self.button_crawl["text"] = "Restart"
            self.unfreeze_tabs()
            self.button_clear['state'] = 'enabled'
            if self.crawler.settings.get("MODE", "") == "Spider":
                messagebox.showinfo(
                    title='Crawl completed',
                    message=
                    f'{self.crawler.settings.get("ROOT_DOMAIN", "")} has been crawled successfully!'
                )
            else:
                messagebox.showinfo(
                    title='Crawl completed',
                    message='List Mode Crawl has been completed successfully!')
            self.update_bottom_stats()
            return
        if self.crawler.crawl_timed_out.is_set():
            messagebox.showerror(title='Error - Timed Out',
                                 message='Crawl timed out!')
            self.button_crawl["text"] = "Resume"
            self.button_clear['state'] = 'enabled'
            self.update_bottom_stats()
            return
        if self.crawler.crawl_running.is_set():
            self.update_bottom_stats()
            return

        self.after(250, self.add_to_outputtable)

    @tk_after
    def add_items(self, items):
        for i, item in enumerate(items, 1):
            self.treeview_table.insert('', 'end', text=i, values=item)

    @run_in_background_with_window(
        [],
        title='Loading crawl ...',
        msg='Please wait while the data is being loaded ...')
    def load_crawl_to_outputtable(self, filters, table, columns=None):
        self.suspend_auto_scroll = True

        if not filters:
            self.master.title(self.master.title().replace(
                ' (Filtered View)', ''))

        if not table:
            table = self.viewed_table

        self.clear_output_table()
        columns, items = self.crawler.get_crawl_data(filters, table, columns)
        self.populate_columns(columns=columns)

        self.add_items(items)

        self.suspend_auto_scroll = False
        self.treeview_table.yview_moveto(1)

    def update_progressbar(self):
        with self.lock:
            if self.crawler.urls_total > 0:
                self.percentage = int(
                    (self.crawler.urls_crawled / self.crawler.urls_total) *
                    100)
                self.progressbar["value"] = self.percentage
                if sys.platform == "win32":
                    self.style.configure('text.Horizontal.TProgressbar',
                                         text=f'{self.percentage} %')

    def update_bottom_stats(self):
        with self.lock:
            self.urls_string_var.set(
                f"Speed: {self.crawler.current_urls_per_second} URL/s")
            self.urls_crawled_string_var.set(
                f"URLs crawled/discovered: {'{:,}'.format(self.crawler.urls_crawled)}/{'{:,}'.format(self.crawler.urls_total)} ({self.percentage}%)"
            )

    def update(self):
        self.button_crawl["text"] = "Resume"
        self.entry_url_input.entry['state'] = 'enabled'
        self.entry_url_input.entry.delete(0, 'end')
        self.entry_url_input.entry.insert(
            0, self.crawler.settings["STARTING_URL"])
        self.row_counter = self.crawler.urls_crawled
        self.populate_columns()
        self.update_progressbar()

    def reset(self, reset_url_input=True):
        self.entry_url_input.entry["state"] = "enabled"

        if reset_url_input:
            self.entry_url_input.entry.delete(0, 'end')
            self.entry_url_input.entry.insert(0, "Enter URL to crawl")

        self.progressbar["value"] = 0
        self.clear_output_table()
        self.populate_columns()
        self.button_crawl["text"] = "Start"
        self.suspend_auto_scroll = False
        self.filters = None
        self.reset_filter_window()
        self.crawler.reset_crawl()
        self.master.title(Defaults.window_title)

    def show_list_mode(self):
        self.reset()
        self.master.title(f'List Mode - {Defaults.window_title}')
        self.entry_url_input.entry.delete(0, 'end')
        self.entry_url_input.entry.insert(0, "List Mode ...")
        self.freeze_input()

    def freeze_input(self):
        self.entry_url_input.entry["state"] = "disabled"

    def assign_treeview_click(self, event):

        region = self.treeview_table.identify("region", event.x, event.y)

        if region == 'cell':

            iid = self.treeview_table.identify_row(event.y)

            if iid:
                self.treeview_table.selection_set(iid)
                item = self.treeview_table.selection()
                self.row_values = self.treeview_table.item(item)['values']

                try:
                    self.action_menu.tk_popup(event.x_root, event.y_root + 20,
                                              0)
                finally:
                    self.action_menu.grab_release()

        elif region == 'heading':
            col = self.treeview_table.identify_column(event.x)
            self.selected_column = self.treeview_table.heading(col)['text']

            try:
                self.popup_menu.tk_popup(event.x_root, event.y_root + 20, 0)
            finally:
                self.popup_menu.grab_release()

    def show_filter_window(self, label):
        columns = self.get_display_columns()

        if self.viewed_table != 'crawl':
            columns = self.get_display_columns(self.viewed_table)
        if 'Sort' in label:
            column = self.selected_column.lower().replace(' ', '_')
            print('Sorting column', column)

            # Remove previous sorting filters
            self.filters = [t for t in self.filters if 'Sort' not in t[1]]
            self.filters.append((column, label, ''))
            self.load_crawl_to_outputtable(self.filters,
                                           self.viewed_table,
                                           columns=columns)
            return

        # Window has never been initialised
        if not self.filter_window:
            self.filter_window = FilterWindow(
                self,
                label,
                self.selected_column,
                columns,
                table=self.viewed_table,
                title=f'Filter By {self.selected_column}')
        # window has been initialised but has been closed
        elif self.filter_window.winfo_exists() == 0:
            self.filter_window = FilterWindow(
                self,
                label,
                self.selected_column,
                columns,
                table=self.viewed_table,
                title=f'Filter By {self.selected_column}')
        else:
            self.filter_window.update()
            self.filter_window.deiconify()

    def show_action_window(self, label):
        url = ''

        if self.row_values:
            url = self.row_values[0]

        if label == 'Copy URL' and url:
            self.master.clipboard_clear()
            self.master.clipboard_append(url)
        elif label == 'Open URL in Browser' and url:
            open_in_browser(url, new=2)
        elif label == 'View Inlinks' and url:
            ViewInlinks(url, self.crawler.get_inlinks)

    def vertical_scrollbar_clicked(self, *args, **kwargs):
        self.treeview_table.yview(*args, **kwargs)
        if float(args[1]) < 0.95:
            self.suspend_auto_scroll = True
        else:
            self.suspend_auto_scroll = False

    def reset_filters(self):
        self.load_crawl_to_outputtable(None, self.viewed_table)

    def reset_filter_window(self):
        if not self.filter_window:
            return

        self.filter_window = None
Exemple #10
0
class TShapesWindow(Frame):
    """
    Class represents auxiliary window containg shapes information.

    :param master: master window object.
    :type master: tkinter.Tk
    :param app: main app object.
    :type app: TApp
    """
    def __init__(self, master, TApp):
        """
        Call the parent class constructor and initialise object variables.
        """
        super().__init__()
        self.TApp = TApp
        self.round_digits = TTicksSettings.ROUND_DIGITS
        self.init_widgets()

    def init_widgets(self):
        """
        Init frame widgets.
        """
        # Listbox
        self.shapes_list = Listbox(self,
                                   exportselection=False,
                                   selectmode=EXTENDED)
        self.grid_columnconfigure(0, weight=1, minsize=300)
        self.grid_rowconfigure(0, weight=1)
        self.shapes_list.grid(row=0,
                              column=0,
                              sticky=NSEW,
                              padx=(5, 25),
                              pady=5)
        self.shapes_list.bind("<<ListboxSelect>>",
                              self.shapes_list_selected_item)

        # Listbox's yscrollbar
        self.shapes_list_scrollbar = Scrollbar(self, orient = VERTICAL, \
                                               command = self.shapes_list.yview)
        self.shapes_list_scrollbar.grid(row=0,
                                        column=0,
                                        sticky=NS + E,
                                        padx=(0, 5),
                                        pady=5)
        self.shapes_list.config(yscrollcommand=self.shapes_list_scrollbar.set)

        # Drop down menu with materials
        self.material_box = Combobox(self, values=["pec", "free_space"])
        self.material_box.grid(row=1, column=0, sticky=EW, padx=5, pady=5)
        self.material_box.bind("<<ComboboxSelected>>",
                               self.assign_material_to_shape)

        # Right click popup menu
        self.init_popup_menu()
        self.shapes_list.bind("<Button-3>", self.show_popoup_menu)

        # Delete key removes selected shape(s)
        self.shapes_list.bind("<Delete>", self.remove_shape)

    def update_list(self, shapes, *, swap=False):
        """
        Update shapes list.

        :param swap: shapes list selection swap toggle.
        :type swap: boolean
        """
        selection = self.shapes_list.curselection()
        try:
            shape_num = selection[0]
        except:
            shape_num = 0
        self.shapes_list.delete(0, END)
        coord_string = ""
        for i, single_shape in enumerate(shapes):
            if (single_shape.type == "Rectangle"):
                coord_string = "(" + str(round(single_shape.point1_mod.x, self.round_digits)) + \
                               ", " + str(round(single_shape.point1_mod.y, self.round_digits)) + \
                               "), (" + str(round (single_shape.point2_mod.x, self.round_digits)) + \
                               ", " + str(round(single_shape.point2_mod.y, self.round_digits)) + ")"
            elif (single_shape.type == "Cylinder"):
                coord_string = "(" + str(round(single_shape.centre_mod.x, self.round_digits)) + \
                                ", " + str(round(single_shape.centre_mod.y, self.round_digits)) + \
                                "), " + str(round(single_shape.radius_mod, self.round_digits))
            elif (single_shape.type == "CylinSector"):
                coord_string = "(" + str(round(single_shape.centre_mod.x, self.round_digits)) + \
                               ", " + str(round(single_shape.centre_mod.y, self.round_digits)) + \
                               "), " + str(round(single_shape.radius_mod, self.round_digits)) + \
                               ", " + str(round(single_shape.start, self.round_digits)) + \
                               ", " + str(round(single_shape.extent, self.round_digits))
            elif (single_shape.type == "Polygon"):
                coord_string = str(len(single_shape.points))
            self.shapes_list.insert(
                i,
                str(i + 1) + ". " + single_shape.type + ": " + coord_string)
            coord_string = ""
        if (not swap):
            self.shapes_list.select_clear(0, END)
            if (shape_num >= self.shapes_list.size()):
                self.shapes_list.selection_set(shape_num - 1)
                self.shapes_list.activate(shape_num)
            else:
                for item in selection:
                    self.shapes_list.selection_set(item)
                self.shapes_list.activate(shape_num)

    def assign_material_to_shape(self, event):
        """
        Assign material to a shape.

        :param event: event evoking this method (listbox select).
        :type event: tkinter.Event
        """
        material = self.material_box.get()
        try:
            shape_num = (self.shapes_list.curselection())[0]
        except:
            return
        else:
            if (shape_num < 0 or material == ""):
                return
            else:
                try:
                    self.TApp.shapes[shape_num].material = material
                except Exception as message:
                    messagebox.showerror("Material assignment error!", message)
                    return

    def shapes_list_selected_item(self, event):
        """
        Handle listbox selection event.

        :param event: event evoking this method (listbox select).
        :type event: tkinter.Event
        """
        # Add multiple selection
        self.shapes_list.focus_force()
        try:
            shape_num = (self.shapes_list.curselection())[0]
            selection = self.shapes_list.curselection()
        except IndexError:
            return
        except Exception as message:
            messagebox.showerror("Error while picking shape!", message)
        if (shape_num < 0):
            return
        else:
            try:
                shape = self.TApp.shapes[shape_num]
            except Exception as message:
                messagebox.showerror("Materials list error", message)
                return

        self.material_box.set(str(shape.material))

        for single_shape in self.TApp.shapes:
            single_shape.width = 1

        for item in selection:
            self.TApp.shapes[item].width = 2
        self.TApp.main_canvas.delete("all")
        for item in selection:
            self.shapes_list.selection_set(item)
        self.TApp.canvas_refresh()

    def init_popup_menu(self):
        """
        Init shapes pane pup-up menu.
        """
        self.popup_menu = Menu(self, tearoff=0)
        self.popup_menu.add_command(label="Edit shape",
                                    command=self.edit_shape)
        self.popup_menu.add_command(label="Change shape colour",
                                    command=self.change_shape_colour)
        self.popup_menu.add_command(label="Remove shape(s)",
                                    command=self.remove_shape)
        self.popup_menu.add_separator()
        self.popup_menu.add_command(label="Add vertex to polygon",
                                    command=self.add_vertex_to_polygon)
        self.popup_menu.add_separator()
        self.popup_menu.add_command(label="Copy shape",
                                    command=self.copy_shape)
        self.popup_menu.add_command(label="Paste shape",
                                    command=self.paste_shape)
        self.popup_menu.add_separator()
        self.popup_menu.add_command(label="Move up",
                                    command=self.move_shape_up)
        self.popup_menu.add_command(label="Move down",
                                    command=self.move_shape_down)
        self.popup_menu.add_command(label="Move to top",
                                    command=self.move_shape_top)
        self.popup_menu.add_command(label="Move to bottom",
                                    command=self.move_shape_bottom)

    def show_popoup_menu(self, event):
        """
        Show shapes list pop-up menu.

        :param event: event evoking this method (RMB click).
        :type event: tkinter.Event
        """
        try:
            self.popup_menu.post(event.x_root, event.y_root)
        finally:
            self.popup_menu.grab_release()

    def move_shape_up(self):
        """
        Move a shape one place up the shapes list.
        """
        try:
            shape_num = (self.shapes_list.curselection())[0]
        except IndexError:
            return
        if (shape_num < 0):
            return
        else:
            try:
                self.TApp.shapes.insert(shape_num - 1,
                                        self.TApp.shapes.pop(shape_num))
                self.update_list(self.TApp.shapes)
                self.TApp.main_canvas.delete("all")
                self.TApp.canvas_refresh(swap=True)
                self.shapes_list.selection_set(shape_num - 1)
                self.shapes_list.activate(shape_num - 1)
            except Exception as message:
                messagebox.showerror("Error while manipulating shapes list!",
                                     message)
                return

    def move_shape_down(self):
        """
        Move a shape one place down the shapes list.
        """
        try:
            shape_num = (self.shapes_list.curselection())[0]
        except IndexError:
            return
        if (shape_num < 0):
            return
        else:
            try:
                self.TApp.shapes.insert(shape_num + 1,
                                        self.TApp.shapes.pop(shape_num))
                self.update_list(self.TApp.shapes)
                self.TApp.main_canvas.delete("all")
                self.TApp.canvas_refresh(swap=True)
                self.shapes_list.selection_set(shape_num + 1)
                self.shapes_list.activate(shape_num + 1)
            except Exception as message:
                messagebox.showerror("Error while manipulating shapes list!",
                                     message)
                return

    def move_shape_top(self):
        """
        Move a shape to the top of the shapes list.
        """
        try:
            shape_num = (self.shapes_list.curselection())[0]
        except IndexError:
            return
        if (shape_num < 0):
            return
        else:
            try:
                self.TApp.shapes.insert(0, self.TApp.shapes.pop(shape_num))
                self.update_list(self.TApp.shapes)
                self.TApp.main_canvas.delete("all")
                self.TApp.canvas_refresh(swap=True)
                self.shapes_list.selection_set(0)
                self.shapes_list.activate(0)
                # self.shapes_list.focus_set ()
            except Exception as message:
                messagebox.showerror("Error while manipulating shapes list!",
                                     message)
                return

    def move_shape_bottom(self):
        """
        Move a shape to the bottom of the shapes list.
        """
        try:
            shape_num = (self.shapes_list.curselection())[0]
        except IndexError:
            return
        if (shape_num < 0):
            return
        else:
            try:
                self.TApp.shapes.append(self.TApp.shapes.pop(shape_num))
                self.update_list(self.TApp.shapes)
                self.TApp.main_canvas.delete("all")
                self.TApp.canvas_refresh(swap=True)
                self.shapes_list.selection_set(END)
                self.shapes_list.activate(END)
            except Exception as message:
                messagebox.showerror("Error while manipulating shapes list!",
                                     message)
                return

    def edit_shape(self):
        """
        Edit selected shape on the shapes list.
        """
        try:
            shape_num = (self.shapes_list.curselection())[0]
        except IndexError:
            return
        if (shape_num < 0):
            return
        else:
            self.TApp.operations.append(TOperation("edit", shape = \
                                                   deepcopy(self.TApp.shapes[shape_num]), \
                                                   num = shape_num))
            if (self.TApp.shapes[shape_num].type == "Rectangle"):
                self.TApp.edit_rectangle(shape_num)
            elif (self.TApp.shapes[shape_num].type == "Cylinder"):
                self.TApp.edit_cylin(shape_num)
            elif (self.TApp.shapes[shape_num].type == "CylinSector"):
                self.TApp.edit_cylin_sector(shape_num)
            elif (self.TApp.shapes[shape_num].type == "Polygon"):
                self.TApp.edit_polygon(shape_num)

    def change_shape_colour(self):
        """
        Change selected shape on the shapes list colour.
        """
        try:
            shape_num = (self.shapes_list.curselection())[0]
        except IndexError:
            return
        if (shape_num < 0):
            return
        else:
            self.TApp.change_shape_colour(shape_num=shape_num)

    def remove_shape(self, event=None):
        """
        Remove selected shape on the shapes list.
        """
        try:
            selection = self.shapes_list.curselection()
        except IndexError:
            return
        if (len(selection) == 0):
            return
        else:
            try:
                for item in reversed(selection):
                    del self.TApp.shapes[item]
                self.update_list(self.TApp.shapes)
                self.TApp.main_canvas.delete("all")
                self.TApp.canvas_refresh()
            except Exception as message:
                messagebox.showerror("Error while manipulating shapes list!",
                                     message)
                return

    def add_vertex_to_polygon(self):
        """
        Add a vertex to selected polygon on the shapes list.
        """
        try:
            shape_num = (self.shapes_list.curselection())[0]
        except IndexError:
            return
        input_str = simpledialog.askstring("Input coordinates",
                                           "Give mew vertex's coordinates")
        point_mod_x, point_mod_y = [float(val) for val in input_str.split()]
        if (self.TApp.shapes[shape_num].type == "Polygon" and shape_num > -1):
            self.TApp.shapes[shape_num].add_vertex(x_mod=point_mod_x,
                                                   y_mod=point_mod_y)
        self.TApp.main_canvas.delete("all")
        self.TApp.canvas_refresh()

    def copy_shape(self):
        """
        Copy selected shape on the shapes list.
        """
        try:
            shape_num = self.shapes_list.curselection()[0]
        except:
            shape_num = -1
        if (shape_num > -1):
            try:
                self.TApp.copy_shape(shape_num=shape_num)
            except Exception as message:
                messagebox.showerror("Error while manipulating shapes list!",
                                     message)

    def paste_shape(self, *, deltax=15, deltay=15):
        """
        Paste selected shape from buffer.
        
        :param deltax: pasted shape offset in x direction in pixels.
        :type deltax: integer
        :param deltay: pasted shape offset in y direction in pixels.
        :type deltay: integer
        """
        self.TApp.paste_ctrl_v(Event())
Exemple #11
0
class FastMenu():
    def __init__(self, root, text):
        self.root = root
        self.text = text
        self.fastMenu = Menu(self.root, tearoff=0)

        def popup(event):
            try:
                self.fastMenu.tk_popup(event.x_root, event.y_root)
            finally:
                self.fastMenu.grab_release()

        self.fastMenu.add_command(label="Title",
                                  command=lambda: Format(self.root, self.text).
                                  addTags(tag="title", size=4, sizeMod=True),
                                  accelerator="Alt+T")

        self.fastMenu.add_command(
            label="Subtitle",
            command=lambda: Format(self.root, self.text).addTags(
                tag="subtitle", size=2, sizeMod=True),
            accelerator="Alt+S")

        self.fastMenu.add_command(
            label="Bold",
            command=lambda: Format(self.root, self.text).addTags(tag="bold"),
            accelerator="Alt+B")

        self.fastMenu.add_command(
            label="Italic",
            command=lambda: Format(self.root, self.text).addTags(tag="italic"),
            accelerator="Alt+I")

        self.fastMenu.add_command(label="Underline",
                                  command=lambda: Format(self.root, self.text).
                                  addTags(tag="underline"),
                                  accelerator="Alt+Shift+-")

        self.fastMenu.add_command(label="Overstrike",
                                  command=lambda: Format(self.root, self.text).
                                  addTags(tag="overstrike"))

        self.fastMenu.add_command(
            label="Remove tags",
            command=lambda: Format(self.root, self.text).addTags(tag="remove"),
            accelerator="Alt+R")

        self.fastMenu.add_separator()

        self.fastMenu.add_command(
            label="Choose Color",
            command=lambda: Format(self.root, self.text).changeColor())

        self.fastMenu.add_command(
            label="Last Color",
            command=lambda: Format(self.root, self.text).changeColor(),
            accelerator="Alt+C")

        #SubMenu
        self.predefinedColors = Menu(self.fastMenu, tearoff=0)
        for name, color in globals.colorConfig.items():
            self.predefinedColors.add_command(
                label=name.capitalize(),
                command=lambda color=color: Format(self.root, self.text
                                                   ).changeColor(cor=color))
        self.fastMenu.add_cascade(label="Predefined Colors",
                                  menu=self.predefinedColors)

        self.fastMenu.add_separator()
        self.simbolsMenu = Menu(self.fastMenu, tearoff=0)
        for category, simbols in globals.simbols.items():
            self.categoryMenu = Menu(self.simbolsMenu, tearoff=0)
            for simbol in simbols:
                self.categoryMenu.add_command(
                    label=simbol,
                    command=lambda simbol=simbol: Format(
                        self.root, self.text).insertSimbols(simbol))
            self.simbolsMenu.add_cascade(label=category,
                                         menu=self.categoryMenu)
        self.fastMenu.add_cascade(label="Simbols", menu=self.simbolsMenu)

        self.fastMenu.add_separator()
        self.fastMenu.add_command(label="Calculate Selection",
                                  command=lambda: self.calculate())

        self.text.bind("<Button-3>", popup)

        self.fastMenu.add_separator()
        self.fastMenu.add_command(
            label="Cut",
            command=lambda: Edit(self.root, self.text).cut(),
            accelerator="Ctrl+X")
        self.fastMenu.add_command(
            label="Copy",
            command=lambda: Edit(self.root, self.text).copy(),
            accelerator="Ctrl+C")
        self.fastMenu.add_command(
            label="Paste",
            command=lambda: Edit(self.root, self.text).paste(),
            accelerator="Ctrl+V")

    def calculate(self):
        try:
            calculus = eval(self.text.get("sel.first", "sel.last"))
            self.text.insert("sel.last", " ==> (" + str(calculus) + ")")
        except:
            self.text.insert("sel.last", " ==> (Invalid Operation)")
Exemple #12
0
class Window(Listbox):

    # Initializes the variables and settings for the project. Finally
    # executes the create_menu for the menu bar, and the create_notepad
    # for the text window
    def __init__(self, master, **kw):
        # Sets master, or root
        super().__init__(master, **kw)
        self.master = master
        # Set some variables
        self.current_file_path = ''
        self.current_file_text = ''
        self.is_saved = True
        # Set up the context menu and the text box
        self.context_popup_menu = Menu(self.master, tearoff=0)
        self.text_window = ScrolledText(self.master, undo=True)
        self.text_window.focus()
        self.user_data = self.text_window.get('1.0', END + '-1c')
        # Name the window, icon, and start the create functions
        self.master.title(NAME)
        # self.master.iconbitmap('./tk/images/icon.ico')
        self.initiate_shortcuts()
        self.create_menu()
        self.create_notepad()
        self.create_context_menu()

    # Creates the context menu
    def create_context_menu(self):
        # Adds a command for button, separator for separator
        self.context_popup_menu.add_command(label="Undo",
                                            command=lambda: self.undo())
        self.context_popup_menu.add_command(label="Redo",
                                            command=lambda: self.redo())
        self.context_popup_menu.add_separator()
        self.context_popup_menu.add_command(
            label="Cut",
            command=lambda: self.text_window.event_generate("<<Cut>>"))
        self.context_popup_menu.add_command(
            label="Copy",
            command=lambda: self.text_window.event_generate("<<Copy>>"))
        self.context_popup_menu.add_command(
            label="Paste",
            command=lambda: self.text_window.event_generate("<<Paste>>"))
        self.context_popup_menu.add_separator()
        self.context_popup_menu.add_command(label="Delete",
                                            command=lambda: self.clear())
        self.context_popup_menu.add_separator()
        self.context_popup_menu.add_command(label="Select All",
                                            command=lambda: self.select_all())

    # Creates the top bar menu
    def create_menu(self):
        # Creating menu bar and adding it to master
        menu_bar = Menu(self.master)
        text = self.text_window
        # Telling root that menu_bar is the Window's menu
        self.master.config(menu=menu_bar)
        # Creating the File menu dropdown
        file_menu = Menu(menu_bar, tearoff=False)
        file_menu.add_command(label="New Document...",
                              command=self.new_file,
                              accelerator="Ctrl+N")
        file_menu.add_command(label="Open Document...",
                              command=self.open_file,
                              accelerator="Ctrl+O")
        file_menu.add_command(label="Save...",
                              command=self.save_file,
                              accelerator="Ctrl+S")
        file_menu.add_command(label="Save as...",
                              command=self.save_as_file,
                              accelerator="Ctrl+Shift+S")
        file_menu.add_separator()
        file_menu.add_command(label="Quit",
                              command=self.exit,
                              accelerator="Ctrl+Q")
        # Adding it to the menu_bar
        menu_bar.add_cascade(label="File", menu=file_menu, underline=0)
        # Creating the Edit menu dropdown
        edit_menu = Menu(menu_bar, tearoff=False)
        edit_menu.add_command(label="Undo",
                              command=self.undo,
                              accelerator="Ctrl+Z")
        edit_menu.add_command(label="Redo",
                              command=self.redo,
                              accelerator="Ctrl+Y")
        edit_menu.add_separator()
        edit_menu.add_command(label="Cut",
                              command=lambda: text.event_generate("<<Cut>>"),
                              accelerator="Ctrl+X")
        edit_menu.add_command(label="Copy",
                              command=lambda: text.event_generate("<<Copy>>"),
                              accelerator="Ctrl+C")
        edit_menu.add_command(label="Paste",
                              command=lambda: text.event_generate("<<Paste>>"),
                              accelerator="Ctrl+V")
        edit_menu.add_separator()
        edit_menu.add_command(label="Select All",
                              command=lambda: self.select_all(),
                              accelerator="Ctrl+A")
        edit_menu.add_command(label="Delete",
                              command=self.clear,
                              accelerator="Del")
        # edit_menu.add_separator()
        # edit_menu.add_command(label="Settings...", command=settings, accelerator="Ctrl+S")
        # Adding it to the menu_bar
        menu_bar.add_cascade(label="Edit", menu=edit_menu)
        # Creating the Help menu
        help_menu = Menu(menu_bar, tearoff=False)
        help_menu.add_command(label="About...", command=about)
        # Adding it to the menu_bar
        menu_bar.add_cascade(label="Help", menu=help_menu)

    # Bind the shortcuts to their specified functions
    def initiate_shortcuts(self):
        self.master.bind("<KeyRelease>", lambda event: self.on_text_change())
        self.master.bind("<Control-n>", lambda event: self.new_file())
        self.master.bind("<Control-o>", lambda event: self.open_file())
        self.master.bind("<Control-s>", lambda event: self.save_file())
        self.master.bind("<Control-Shift-s>",
                         lambda event: self.save_as_file())
        self.master.bind("<Control-q>", lambda event: self.exit())
        self.master.bind("<Control-z>", lambda event: self.undo())
        self.master.bind("<Control-y>", lambda event: self.redo())
        self.text_window.bind("<Control-a>", lambda event: self.select_all())
        # self.master.bind("<Control-s>", lambda event: settings())
        self.master.bind("<Button-3>",
                         lambda event: self.right_click_popup(event))

    # Display context menu popup
    def right_click_popup(self, event):
        try:
            # Used +45 and + 12 to corner it
            self.context_popup_menu.tk_popup(event.x_root + 45,
                                             event.y_root + 12, 0)
        finally:
            self.context_popup_menu.grab_release()

    # Scaling the text_window to fit the screen
    def create_notepad(self):
        self.text_window.pack(fill="both", expand=True)

    # Returns the value of the text field
    def get_text_data(self):
        return self.text_window.get('1.0', END + '-1c')

    # Clears the text off the screen, resets the variables
    def clear_text(self):
        self.text_window.delete('1.0', END)
        self.current_file_path = ''
        self.current_file_text = ''

    # Called when typing, sets the is_saved variable
    def on_text_change(self):
        # If the text in the textbox is equal to the saved text in the variable
        # This is used when opening a file, changing something, then undoing that change
        if self.get_text_data() == self.current_file_text:
            self.is_saved = True
        else:
            # If the saved file exists or is valid
            if os.path.isfile(self.current_file_path):
                # Open the file, save it's data to this_file
                with open(self.current_file_path, "r") as f:
                    this_file = f.read()
                    # If this_file is equal to the same text in the textbox
                    # Used if no changes were made, and if they were, set to False
                self.is_saved = True if this_file == self.get_text_data(
                ) else False
            else:
                # If the data is not equal to variable, and no file, then changes
                # must have been made
                self.is_saved = False

    # MENU CONTROL FUNCTIONS

    # Clear current selection, erase the current file if saved
    def new_file(self):
        # If it's saved, clear it and set the file to saved
        if self.is_saved is True:
            self.clear_text()
            self.is_saved = True
        else:
            # Popup the saved popup
            popup_value = is_saved_popup()
            if popup_value == "yes":
                # Save the file, clear it and set the is_saved to True
                if self.save_file() is True:
                    self.clear_text()
                    self.is_saved = True
            elif popup_value == "no":
                # Don't save the file, but clear it and set the is_saved to True
                self.clear_text()
                self.is_saved = True
            else:
                # Something went wrong
                print("Error: new_file error")

    # Open a file if the current file is saved, then insert new file data
    def open_file(self):
        # If file is saved, open the open_file window
        if self.is_saved is True:
            self.open_file_popup()
        else:
            # Save the file, if it's saved, open the open_file window
            popup_value = is_saved_popup()
            if popup_value == "yes":
                if self.save_file() is True:
                    self.is_saved = True
                    self.open_file_popup()
            # Open the open_file window
            elif popup_value == "no":
                self.open_file_popup()
            else:
                # An error occurred
                print("Error: open_file error")

    # The function that displays the open_file popup
    def open_file_popup(self):
        # Gets old data from current file
        old_file = self.current_file_path
        # Opens the file location, stores it in file_name
        file_name = filedialog.askopenfilename(
            title="Open",
            filetypes=(("Text files", "*.txt"), ("All files", "*.*")))
        # If a file was actually selected, open it
        if file_name is not '':
            with open(file_name) as f:
                data = f.read()
            # Clear current text
            self.clear_text()
            # Set the path variable of the new file
            self.current_file_path = file_name if os.path.isfile(
                file_name) else old_file
            # Add the file data to the text_box
            self.text_window.insert(INSERT, data)
            # Add the file data to the variable
            self.current_file_text = data
            # is_saved is True
            self.is_saved = True

    # Save file, if file exists, overwrite it, otherwise, call save_as_file function
    def save_file(self):
        # If the file path exists
        if os.path.isfile(self.current_file_path):
            # Stores the current text data into the variable
            self.current_file_text = self.get_text_data()
            # Saves the data to the existing file (overwriting)
            with open(self.current_file_path, "w") as f:
                return True if f.writelines(
                    self.get_text_data()) is True else False
        else:
            # File doesn't exist, call save_as_file
            if self.save_as_file() is True:
                return True

    # Saves file with asksaveasfile to open a save as window.
    def save_as_file(self):
        # Gets old file path
        old_file = self.current_file_path
        # Opens save_as window
        file_name = filedialog.asksaveasfilename(
            title="Save As",
            defaultextension=".txt",
            filetypes=(("Text files", "*.txt"), ("All files", "*.*")))
        # Set current file path
        self.current_file_path = old_file if file_name is None else file_name

        # If the file_path already exists
        if os.path.isfile(self.current_file_path):
            # Copy the current text to the variable
            self.current_file_text = self.get_text_data()
            # Writes to the named file
            with open(self.current_file_path, "w") as f:
                f.writelines(self.get_text_data())
                return True
        else:
            # A file wasn't selected
            if file_name is '':
                print("Error: File is none")
                return False
            # Create a new file to store the data
            self.current_file_text = self.get_text_data()
            with open(file_name, 'w'):
                pass
            self.is_saved = True
            return True

    # Exit override command
    def exit(self):
        # If the file is saved, exit
        if self.is_saved is True:
            self.master.quit()
        else:
            # If the file is not saved, call the saved_popup
            popup_value = is_saved_popup()
            if popup_value == "yes":
                # Save and then quit
                if self.save_file() is True:
                    self.is_saved = True
                    self.quit()
            elif popup_value == "no":
                # Don't save, just quit
                self.master.quit()
            else:
                # An error occurred
                print("Error: open_file error")

    # Undo last action
    def undo(self):
        self.text_window.edit_undo()

    # Redo last action
    def redo(self):
        self.text_window.edit_redo()

    # Clear (delete) the selected text
    def clear(self):
        self.text_window.delete(SEL_FIRST, SEL_LAST)
        self.text_window.update()

    # Select the selected text (without new line)
    def select_all(self):
        self.text_window.tag_add(SEL, "1.0", END + '-1c')
        self.text_window.mark_set(INSERT, "1.0")
        self.text_window.see(INSERT)
        return 'break'
Exemple #13
0
class Brainfsck(Frame):
    ''' Main window of the application    
    '''
    WINDOW_TITLE = "Brainfsck - iivlxsoft"
    WINDOW_WIDTH = 700
    WINDOW_HEIGHT = 700
    WINDOW_WIDTH_MIN = 500
    WINDOW_HEIGHT_MIN = 250
    WINDOW_WIDTH_OFFSET = 100
    WINDOW_HEIGHT_OFFSET = 100
    WINDOW_Y_MIN = 50
    WINDOW_RESIZABLE = (True, True)

    engine = None
    execution_delay = 1
    allow_illegal_characters = True
    input_buffer = []
    output_buffer = []
    _reset_modifed = False  #sponge
    execution_time_start = 0
    execution_time_end = 0
    execution_time_total = 0
    breakpoints = []

    def __init__(self, master, **kw):
        Frame.__init__(self, master, **kw)
        self.style = Style()
        self.configure()

        loadIcon(self.master, self.master, IIVLXICO)
        self.master.title(self.WINDOW_TITLE)
        self.master.resizable(*self.WINDOW_RESIZABLE)
        x = self.master.winfo_pointerx() - self.WINDOW_WIDTH_OFFSET
        y = self.master.winfo_pointery() - self.WINDOW_HEIGHT_OFFSET
        y = y if y > self.WINDOW_Y_MIN else self.WINDOW_Y_MIN
        self.master.geometry(
            f'{self.WINDOW_WIDTH}x{self.WINDOW_HEIGHT}+{x}+{y}')
        self.master.minsize(self.WINDOW_WIDTH_MIN, self.WINDOW_HEIGHT_MIN)
        # configure master grid
        self.master.grid_rowconfigure(0, weight=1)
        self.master.grid_columnconfigure(0, weight=1)
        # place the window
        self.grid(row=0, column=0, sticky='news')
        #configure grid
        self.grid_rowconfigure(0, weight=1)
        self.grid_rowconfigure(1, weight=1)
        self.grid_rowconfigure(2, weight=1)
        self.grid_rowconfigure(2, weight=0)
        self.grid_columnconfigure(0, weight=1)
        self.grid_columnconfigure(1, weight=1)
        self.grid_columnconfigure(2, weight=1)
        self.grid_columnconfigure(2, weight=2)
        # subwindows
        self.memoryview = None
        # draw the window
        self.createMenubar()
        self.createContextMenu()
        self.draw()
        self.setBinds()

    def setBinds(self):
        self.codeInput.bind("<Button-3>", self.showContextMenu)
        #self.textInput.bind("<<Modified>>", self.handleInput)
        self.textInput.bind("<Key>", self.handleKey)

    def draw(self):
        self.drawCode()
        self.drawIO()
        self.drawControls()
        self.drawStatusBar()

    def drawCode(self):
        ''' code'''
        self.codeInput = Text(self)
        self.codeInput.grid(row=0,
                            column=0,
                            rowspan=2,
                            columnspan=2,
                            sticky='news')

    def drawIO(self):
        self.textOutput = Text(self)
        self.textOutput.configure(state=DISABLED)
        self.textOutput.grid(row=0, column=2, columnspan=2, sticky='news')
        self.textInput = Text(self)
        self.textInput.grid(row=1, column=2, columnspan=2, sticky='news')
        self.textInputModified = False
        self.textInputIndex = 0
        self.textInput.config(state=DISABLED)

    def drawControls(self):
        ''' main controls'''
        startStopButton = Button(self, text="Run")
        startStopButton.config(command=lambda: self.startStop())
        startStopButton.grid(row=2, column=0)
        stepButton = Button(self, text="Step", command=lambda: self.step())
        stepButton.grid(row=2, column=1)
        resetButton = Button(self,
                             text="Reset/Load",
                             command=lambda: self.reset())
        resetButton.grid(row=2, column=2)
        quitButton = Button(self, text="Quit")
        quitButton.config(command=lambda: self.close())
        quitButton.grid(row=2, column=3)

    def drawStatusBar(self):
        self.statusBar = Label(
            self,
            text='Instruction Pointer: 0, Memory Pointer: 0, Memory Value: 0')
        self.statusBar.grid(row=3, column=0, columnspan=4, sticky='ews')
        self.statusBar.config(relief=SUNKEN)

    def updateStatusBar(self):
        ip = self.engine.instruction_pointer
        mp = self.engine.memory_pointer
        #print(mp) #sponge
        value = self.engine.memory[mp]
        er = self.engine.running
        p = '' if self.running else ' (paused)'
        status_string = 'Running: %s%s, Instruction Pointer: %d, Memory Pointer: %d, Memory Value: %d' % (
            er, p, ip, mp, value)
        if self.execution_time_total:
            status_string += ', Execution Time: %f' % self.execution_time_total
        self.statusBar.config(text=status_string)

    def createMenubar(self):
        ''' Create and add the menubar
        The menubar consists of the following submenus:
        File
        Edit
        View
        About
        '''
        self.menubar = Menu(self.master)
        self.master.config(menu=self.menubar)
        # add submenus
        self.menubar.add_cascade(label='File', menu=self.createMenubarFile())
        self.menubar.add_cascade(label='Edit', menu=self.createMenubarEdit())
        self.menubar.add_cascade(label='View', menu=self.createMenubarView())
        self.menubar.add_cascade(label='Help', menu=self.createMenubarHelp())

    def createMenubarFile(self):
        ''' Create the File submenu '''
        self.menubar_file = Menu(self.menubar, tearoff=0)
        self.menubar_file.add_command(label='Load')
        self.menubar_file.add_command(label='Save')
        self.menubar_file.add_separator()
        self.menubar_file.add_command(label='Exit', command=self.quit)
        return self.menubar_file

    def createMenubarEdit(self):
        ''' Create the Edit submenu '''
        self.menubar_edit = Menu(self.menubar, tearoff=0)
        self.menubar_edit.add_command(label='Set exectuion delay',
                                      command=self.showSetExecutionDelay)
        self.menubar_edit.add_separator()
        self.menubar_edit.add_command(label='Remove non bf characters',
                                      command=self.stripIllegalCharacters)
        self.menubar_edit.add_command(label='Remove spaces',
                                      command=self.stripSpaces)
        self.menubar_edit.add_command(label='Remove newlines',
                                      command=self.stripNewlines)
        self.menubar_edit.add_separator()
        self.menubar_edit.add_command(label='Delete all breakpoints',
                                      command=self.clearAllBreakpoints)
        self.menubar_edit.add_separator()
        self.menubar_edit.add_command(label='Edit memory cell size')
        self.menubar_edit.add_command(label='Edit memory size')
        self.menubar_edit.add_command(label='Edit maximum memory cell value',
                                      command=self.showSetMaximumCellValue)
        return self.menubar_edit

    def createMenubarView(self):
        ''' Create the View submen '''
        self.menubar_view = Menu(self.menubar, tearoff=0)
        self.menubar_view.add_command(label='Memory Block',
                                      command=self.showMemoryBlock)
        self.menubar_view.add_command(label='Memory Linear',
                                      command=self.showMemoryLinear)
        return self.menubar_view

    def createMenubarHelp(self):
        ''' Create the Help submenu '''
        self.menubar_about = Menu(self.menubar, tearoff=0)
        self.menubar_about.add_command(label='About', command=self.showAbout)
        return self.menubar_about

    def createContextMenu(self):
        ''' Right click context menu '''
        self.contextMenu = Menu(self, tearoff=0)
        self.contextMenu.add_command(label='Set Breakpoint',
                                     command=self.setBreakpoint)
        self.contextMenu.add_command(label='Clear Breakpoint',
                                     command=self.clearBreakpoint)
        return self.contextMenu

    def showContextMenu(self, event):
        try:
            self.contextMenu.tk_popup(event.x_root + 50, event.y_root + 10, 0)
        finally:
            self.contextMenu.grab_release()

    def showAbout(self):
        ''' Show the about dialog '''
        About(self)

    def showMemoryBlock(self):
        ''' Show memory viewer '''
        self.memoryview = MemoryView(self)

    def showMemoryLinear(self):
        ''' Show memory viewer '''
        self.memoryview = MemoryView(self)

    def stripCharacters(self, characters):
        ''' remove characters from code input '''
        # remember current cursor position
        cursor = self.codeInput.index(CURRENT)
        # strip the code of non legal brainfsck characters
        code = self.codeInput.get('1.0', END)
        code = code.translate({ord(c): None for c in characters})
        # remove old code and insert stripped code and reset cursor
        self.codeInput.delete('1.0', END)
        self.codeInput.insert('1.0', code)
        self.codeInput.mark_set('insert', cursor)

    def stripIllegalCharacters(self):
        ''' Remove all non brainfsck characters from the code input'''
        # remember current cursor position
        cursor = self.codeInput.index(CURRENT)
        # strip the code of non legal brainfsck characters
        code = self.codeInput.get('1.0', END)
        code = ''.join(
            filter(
                lambda x: x in
                ['\n', ' ', '.', ',', '+', '-', '>', '<', '[', ']'], code))
        # remove old code and insert stripped code and reset cursor
        self.codeInput.delete('1.0', END)
        self.codeInput.insert('1.0', code)
        self.codeInput.mark_set('insert', cursor)

    def stripSpaces(self):
        self.stripCharacters(' ')

    def stripNewlines(self):
        self.stripCharacters('\n')

    def checkBreakpoint(self):
        ''' Check to see if we hit a breakpoint'''
        if self.engine.instruction_pointer in self.breakpoints:
            self.pause()

    def setBreakpoint(self):
        ''' set a breakpoint at the current selection'''
        # check to see if something is selected
        if self.codeInput.tag_ranges('sel'):
            # add the selection to the breakpoint list

            for i in range(self.codeInput.count('sel.first', 'sel.last')[0]):
                count = self.codeInput.count('1.0', 'sel.first')
                if count is None: count = [0]
                bp = count[0] + i
                if bp not in self.breakpoints:
                    self.breakpoints.append(bp)
            # highlight breakpoints
            self.codeInput.tag_add('breakpoint', 'sel.first', 'sel.last')
            self.codeInput.tag_config('breakpoint',
                                      background='yellow',
                                      foreground='black')
            self.codeInput.tag_raise('sel')

    def clearBreakpoint(self):
        ''' clear the breakpoint at the cursor'''
        # check to see if anything is selected
        if self.codeInput.tag_ranges('sel'):
            # remove selection from breakpoint list
            for i in range(self.codeInput.count('sel.first', 'sel.last')[0]):
                count = self.codeInput.count('1.0', 'sel.first')
                if count is None: count = [0]
                bp = count[0] + i
                if bp in self.breakpoints:
                    self.breakpoints.remove(bp)

            # remove highlight
            self.codeInput.tag_remove('breakpoint', 'sel.first', 'sel.last')

    def clearAllBreakpoints(self):
        for tag in self.codeInput.tag_names():
            if tag == 'breakpoint':
                self.codeInput.tag_delete(tag)
        self.breakpoints = []

    def showSetExecutionDelay(self):
        ''' Open the SetExecutionDelay dialog and use the value returned to set
        the execution delay'''
        SetExecutionDelay(self)

    def showSetMaximumCellValue(self):
        ''' open the SetMaximumCellValue dialog and use the value returend to set the execution delay '''
        SetMaximumCellValue(self)

    def setMaximumCellValue(self, value):
        self.engine.memorymaxvalue = value

    def getCode(self):
        if self.codeInput:
            return self.codeInput.get('1.0', END)
        else:
            return ""

    def startStop(self):
        ''' Start or start the engine,
        If we stopped in the middle of the program we should just begin where we left off
        Otherwise if run_complete is true we want to restart from the beginning.'''
        if not self.engine.running:
            self.reset()
            self.engine.running = True
            self.updateStatusBar()

        if not self.execution_time_start:
            self.execution_time_start = time.time()

        if self.running:
            self.pause()
        else:
            self.running = True
            self.run()

    def pause(self):
        ''' Pause the execution '''
        self.running = False
        self.updateStatusBar()

    def run(self):
        ''' Step through the code one instruction at a time after a timeout until the program finishes.'''
        self.getOutput()
        self.updateStatusBar()
        if self.engine.running == True:
            self.tagCurrentInstruction()
            self.checkBreakpoint()
            self.engine.step()
            if self.memoryview:
                self.memoryview.refreshMemory()
            if self.running:
                self.master.after(self.execution_delay, self.run)
                #self.master.after_idle(self.run)
        else:
            self.execution_time_total = time.time() - self.execution_time_start
            self.updateStatusBar()
            return

    def step(self):
        self.getOutput()
        if self.engine.running == True:
            self.tagCurrentInstruction()
            self.engine.step()
            if self.memoryview:
                self.memoryview.refreshMemory()
            self.updateStatusBar()
        else:
            self.reset()
            self.engine.running = True
            self.updateStatusBar()

    def clearText(self):
        self.textOutput.config(state=NORMAL)
        self.textOutput.delete('1.0', END)
        self.textOutput.config(state=DISABLED)
        self.textInput.config(state=NORMAL)
        self.textInput.delete('1.0', END)
        self.textInput.config(state=DISABLED)
        #self.textInputIndex = 0

    def tagCurrentInstruction(self):
        for tag in self.codeInput.tag_names():
            if tag == 'current':
                self.codeInput.tag_delete(tag)

        current = self.engine.instruction_pointer
        s = self.codeInput.get('1.0', END)[0]
        if s.isspace():
            return  # the code contains only whitespace
        self.codeInput.tag_add('current', '1.0+%dc' % current)
        self.codeInput.tag_config('current', background='red')

    def handleKey(self, event):
        ''' Handle a keypress on the text input window, we want to copy this character
        to the input buffer, and also display it on the text input.'''
        #print(event)
        if not event.char:
            return  # special character we can ignore this
        if event.char == '\r':
            event.char = '\n'

        self.textInput.config(state=NORMAL)
        self.textInput.insert(END, event.char)
        self.textInput.config(state=DISABLED)

        self.input_buffer.append(event.char)

    def getOutput(self):
        if self.output_buffer:
            self.textOutput.config(state=NORMAL)
            self.textOutput.insert(END, self.output_buffer.pop(0))
            self.textOutput.config(state=DISABLED)

    def loadEngine(self, engine):
        self.engine = engine
        self.code = " "
        self.reset()

    def reset(self):
        self.clearText()
        self.engine.reset()
        self.engine.code = self.getCode()
        self.engine.getBrackets()
        self.engine.running = False
        self.running = False
        self.clearText()
        self.input_buffer = []
        self.output_buffer = []
        self.engine.output_buffer = self.output_buffer
        self.engine.input_buffer = self.input_buffer
        self.tagCurrentInstruction()
        self.execution_time_start = 0
        self.execution_time_end = 0
        self.execution_time_total = 0
        #self.engine.run(input = self.input_buffer, output = self.output_buffer)
        self.updateStatusBar()

    def close(self):
        ''' Close this window '''
        self.quit()
Exemple #14
0
class PmaConvert:
    def __init__(self, config):
        root = Tk()

        # Root Definition
        root.geometry('1100x700')
        root.title('PMA Convert')

        # Configuration and Variables
        self.file_selection = ''
        self.is_converting = False
        self.options = config['option_definitions']
        gui_config = config['gui_config']

        # UI
        ## Frames
        self.main_frame = Frame(root)
        self.position_main_frame(gui_config['screen_orientation'])

        ## Components
        self.log = Text(self.main_frame,
                        bd=1,
                        relief=SUNKEN,
                        width=140,
                        height=23,
                        state=DISABLED,
                        spacing3=1,
                        wrap=WORD)

        choose_text = ('1. Choose XLSForm (.xls or .xlsx) file(s) for '
                       'conversion.')
        self.choose_files_label = Label(self.main_frame, text=choose_text)
        # TODO: Get spacing to work.
        # self.choose_files_label.grid(row=3, column=3, padx=(50, 50))
        # self.choose_files_label.grid(row=3, column=3, pady=(50, 50))
        self.choose_files_label.pack()
        self.choose_files_button = Button(self.main_frame,
                                          text='Choose file...',
                                          fg='black',
                                          command=self.on_open)
        self.choose_files_button.pack()

        out_text = 'Choose location for output file(s).'
        self.output_location_label = Label(self.main_frame, text=out_text)
        self.output_location_button = Button(self.main_frame,
                                             text='Choose location...',
                                             fg='black')
        if gui_config['output_location_on'] is True:
            self.output_location_label.pack()
            self.output_location_button.pack()

        self.choose_options_label = Label(self.main_frame,
                                          text='2. Choose conversion options.')
        self.choose_options_label.pack()

        ### Create Options Checkboxes
        # Task: Dynamically generate: http://stackoverflow.com/questions/...
        # ...553784/can-you-use-a-string-to-instantiate-a-class-in-python
        self.preexisting = BooleanVar()
        pre_text = self.options['preexisting']['label']
        self.preexisting_opt = Checkbutton(self.main_frame,
                                           text=pre_text,
                                           variable=self.preexisting)
        self.preexisting_opt.pack()
        self.regular = BooleanVar()
        reg_text = self.options['regular']['label']
        self.regular_opt = Checkbutton(self.main_frame,
                                       text=reg_text,
                                       variable=self.regular)
        self.regular_opt.pack()
        self.novalidate = BooleanVar()
        noval_text = self.options['novalidate']['label']
        self.novalidate_opt = Checkbutton(self.main_frame,
                                          text=noval_text,
                                          variable=self.novalidate)
        self.novalidate_opt.pack()
        self.ignore_version = BooleanVar()
        ig_text = self.options['ignore_version']['label']
        self.ignore_version_opt = Checkbutton(self.main_frame,
                                              text=ig_text,
                                              variable=self.ignore_version)
        self.ignore_version_opt.pack()
        self.linking_warn = BooleanVar()
        link_text = self.options['linking_warn']['label']
        self.linking_warn_option = Checkbutton(self.main_frame,
                                               text=link_text,
                                               variable=self.linking_warn)
        self.linking_warn_option.pack()
        self.debug = BooleanVar()
        debug_text = self.options['debug']['label']
        self.debug_option = Checkbutton(self.main_frame,
                                        text=debug_text,
                                        variable=self.debug)
        self.debug_option.pack()
        self.extras = BooleanVar()
        extras_text = self.options['extras']['label']
        self.extras_option = Checkbutton(self.main_frame,
                                         text=extras_text,
                                         variable=self.extras)
        self.extras_option.pack()

        self.convert_label = Label(self.main_frame, text='3. Run conversion.')
        self.convert_label.pack()

        # Task: Add xscrollcommand and yscrollcommand.
        self.convert_button = Button(self.main_frame,
                                     text='Convert',
                                     fg='black',
                                     command=self.convert)
        self.convert_button.pack()
        self.log.pack(fill=X, expand=1)
        self.log_text(
            'PMA Convert allows you to convert .xls or .xlsx form '
            'definition files to files which are compatible with ODK '
            'Collect.\n\nIf you need to copy and paste from this '
            'log, highlight the text and press CTRL+C to copy. Then '
            'press CTRL+V to paste.\n\n'
            '====================================================\n\n'
            'Awaiting file selection.')

        # Task: Fix menus. They're not working.
        self.context_menu = Menu(self.main_frame, tearoff=0)
        self.context_menu.add_command(label="Convert", command=self.convert)
        self.main_frame.bind("<Button-3>", self.popup)

        # - Note: Strangely this stopped anchoring to bottom suddenly, for some
        # reason. So it is temporarily disabled.
        self.status_bar = Label(self.main_frame,
                                text='Awaiting file selection.',
                                bd=1,
                                relief=SUNKEN,
                                anchor=W)
        if gui_config['status_bar_on'] is True:
            self.status_bar.pack(side=BOTTOM, fill=X)

        # Run
        root.mainloop()

    # Functions
    def popup(self, event):
        # Note: Currently doesn't work.
        self.context_menu.post(event.x_root, event.y_root)
        # display the popup menu
        try:
            self.context_menu.tk_popup(event.x_root, event.y_root, 0)
        finally:
            # make sure to release the grab (Tk 8.0a1 only)
            self.context_menu.grab_release()

    def position_main_frame(self, orientation):
        if orientation == 'center':
            x, y, a = .5, .5, 'c'
            return self.main_frame.place(relx=x, rely=y, anchor=a)
        elif orientation == 'top':
            return self.main_frame.pack()
        else:
            return self.main_frame.pack()

    def on_open(self):
        file_types = [('XLS Files', '*.xls'), ('XLSX Files', '*.xlsx'),
                      ('All files', '*')]
        try:
            self.file_selection = tkinter.filedialog.askopenfilename(
                filetypes=file_types,
                title='Open one or more files.',
                message='Open one or more files',
                multiple=1)
        except:
            self.file_selection = tkinter.filedialog.askopenfilename(
                filetypes=file_types,
                title='Open one or more files.',
                multiple=1)
        if self.file_selection != '':
            self.set_status('Click on Convert to convert files.')
            log_output = 'Ready for conversion: \n'
            for file in self.file_selection:
                log_output += '* ' + str(file) + '\n'
            log_output = log_output[:-1]  # Removes the last '\n'.
            self.log.configure(self.log_text(log_output))

    def set_status(self, new_status):
        self.status_bar.configure(text=new_status)

    def log_text(self, new_text):
        self.log.configure(state=NORMAL)
        self.log.insert(END, str(new_text) + '\n\n')
        self.log.configure(state=DISABLED)
        self.log.bind("<1>", lambda event: self.log.focus_set())

    def convert(self):
        if self.file_selection != '':
            f = self.file_selection

            kwargs = {
                SUFFIX: '',
                PREEXISTING: self.preexisting.get(),
                PMA: not self.regular.get(),
                CHECK_VERSIONING: not self.ignore_version.get(),
                STRICT_LINKING: not self.linking_warn.get(),
                VALIDATE: not self.novalidate.get(),
                EXTRAS: self.extras.get(),
                DEBUG: self.debug.get()
            }

            buffer = io.StringIO()
            if not kwargs[DEBUG]:
                sys.stdout = buffer
                sys.stderr = buffer
            else:
                self.log_text('--> DEBUG MODE: check console output')

            try:
                xlsform_convert(f, **kwargs)
            except ConvertError as e:
                print(str(e))
            except OSError as e:
                # Should catch WindowsError, impossible to test on Mac
                traceback.print_exc()
                print(e)

            if not kwargs[DEBUG]:
                sys.stdout = sys.__stdout__
                sys.stderr = sys.__stderr__

            self.log_text(buffer.getvalue())
Exemple #15
0
class MainFrame(Tk):
    """
        Frame for screenlet
    """

    def __init__(self):
        super().__init__()
        # Window without frame
        self.overrideredirect(1)
        # Set window transparency
        if system() == 'Linux':
            self.attributes('-type', 'normal')
        self.attributes('-alpha', 0.5)

        self.city = StringVar()
        try:
            # Read data from file
            with open('settings.ini', 'r') as file:
                data = file.readlines()
            # Window geometry and position
            geometry = data[0].strip()
            self.city.set(data[1].strip())
            self.t_unit = data[2].strip()
        except:
            geometry = ''
            self.city.set('Kiev, UA')
            self.t_unit = 'metric'

        self.condition = StringVar()
        self.temperature = StringVar()
        self.currency = StringVar()

        self.start_x = 0
        self.start_y = 0

        # Set data for weather and currency exchange
        thread = Thread(target=self.get_data())
        thread.start()

        if geometry == '':
            # Get screen size and calculate window position
            screen_width = self.winfo_screenwidth()
            screen_height = self.winfo_screenheight()
            x = screen_width - 320 - 20
            y = screen_height - (screen_height - 100 - 100)
            # Set new position
            self.geometry(f'320x100+{x}+{y}')
        else:
            self.geometry(geometry)

        self.resizable(width=False, height=False)

        # Pressed over the window
        self.bind('<Button-1>', self.on_mouse_press)
        # Mouse is moved while being held down
        self.bind('<B1-Motion>', self.on_drag)

        # Context menu
        self.popup_menu = Menu(self, tearoff=0)
        self.popup_menu.add_command(label="Settings", command=self.settings)
        self.popup_menu.add_command(label="Exit", command=self.close)
        self.bind("<Button-3>", self.popup)

        self.init_widgets()

    def init_widgets(self):
        """
            Set widgets position
        """
        # Set widget for weather image
        self.image_label = Label(self, image=self.image)
        self.image_label.image = self.image
        self.image_label.pack(side='left')
        self.image_label.configure(image=self.image)

        # Show current weather and currency rate
        Label(self, textvariable=self.condition, fg='Teal',
              font=("Helvetica", 9, 'italic', 'bold')).pack(side='left')

        Label(self, textvariable=self.temperature,
              font=('Helvetica', 20, 'bold'),
              fg='orange').pack(expand=True)

        Label(self, textvariable=self.city,
              font=("Helvetica", 15, 'bold'), padx=10, fg='green').pack()

        Label(self, textvariable=self.currency, fg='Navy',
              font=("Helvetica", 10, 'bold')).pack()

        # Start timer for updating information about
        # weather and currency rate
        self.update_thread = Timer(20 * 60, self.get_data())
        self.update_thread.start()

    def get_data(self):
        """
            Set data for weather and currency exchange
        """
        # Get information about current weather
        # and currency rate
        loop = get_event_loop()
        done, _ = loop.run_until_complete(wait([
            get_weather(self.city.get(), self.t_unit),
            get_currency()
        ]))

        for item in done:
            if isinstance(item.result(), dict):
                weather = item.result()
            else:
                currency = item.result()

        # Update weather image
        img = Image.open(weather['icon']).resize(
            (110, 110), Image.ANTIALIAS)

        self.image = ImageTk.PhotoImage(img)

        # Set current weather
        self.condition.set(weather['humidity'] + '\n\n' + weather['wind'] +
                           '  \n\n' + weather['description'].capitalize())

        self.temperature.set('{:.1f}'.format(
            weather['temperature']) + ('° C' if weather['temperature_unit'] == 'metric' else '° F'))

        self.city.set(value=weather['city'])

        # Set currency rate (USD)
        self.currency.set('\n' + currency[0])

    def popup(self, event):
        # Show context menu
        try:
            self.popup_menu.tk_popup(event.x_root, event.y_root, 0)
        finally:
            self.popup_menu.grab_release()

    def on_mouse_press(self, event):
        # Get mouse coordinates
        self.start_x = event.x
        self.start_y = event.y

    def on_drag(self, event):
        # Get current window position
        _, x, y = self.geometry().split('+')
        # Calculate new position
        x = int(x) + (event.x - self.start_x)
        y = int(y) + (event.y - self.start_y)
        # Move window
        self.geometry(f'+{x}+{y}')

    def settings(self):
        # Open program settings and disable current window
        settings_window = SettingsFrame(self)
        if system() == 'Windows':
            self.wm_attributes("-disabled", True)
        settings_window.mainloop()

    def close(self):
        # Save window geometry, position,
        # city and temperature unit
        with open('settings.ini', 'w') as file:
            print(self.geometry(), file=file)
            print(self.city.get(), file=file)
            print(self.t_unit, file=file)
        # Stop timer for updating information and exit
        self.update_thread.cancel()
        exit()
Exemple #16
0
    def on_button_release(event):
        if event.button != 3:  # Right-click.
            return

        images = [*_iter_overlapping_normed_images(artist, event)]
        if not images:
            return

        def edit_norm(_arg=None):  # Only some backends pass in an argument.
            axs = plt.figure().subplots(len(images), 1, squeeze=False)[:, 0]
            for ax, image in zip(axs, images):
                array = image.get_array()
                ax.hist(array.ravel(),
                        _hist_bins(image),
                        histtype="stepfilled")
                if isinstance(image.norm, mpl.colors.LogNorm):
                    ax.set(xscale="log")
                elif array.dtype.kind in "iu":  # not log.
                    ax.xaxis.get_major_locator().set_params(integer=True)

                def on_select(vmin, vmax, *, _image=image):
                    array = _image.get_array()
                    if vmin == vmax:
                        _image.set_clim((array.min(), array.max()))
                    else:
                        _image.set_clim((vmin, vmax))
                    _image.figure.canvas.draw()

                if hasattr(SpanSelector, "extents"):
                    ss = SpanSelector(ax,
                                      on_select,
                                      "horizontal",
                                      useblit=True,
                                      interactive=True)
                    ss.extents = (image.norm.vmin, image.norm.vmax)
                else:
                    ss = SpanSelector(ax,
                                      on_select,
                                      "horizontal",
                                      useblit=True,
                                      span_stays=True)
                    ss.stay_rect.set(x=image.norm.vmin,
                                     width=image.norm.vmax - image.norm.vmin,
                                     visible=True)
                _selectors.setdefault(ax, []).append(ss)
            plt.show(block=False)

        gui_event = event.guiEvent
        pkg = type(gui_event).__module__.split(".")[0]

        if pkg == "gi":
            from gi.repository import Gtk
            menu = Gtk.Menu()
            item = Gtk.MenuItem.new_with_label("Norm")
            menu.append(item)
            item.connect("activate", edit_norm)
            item.show()
            menu.popup_at_pointer(gui_event)
        elif pkg.startswith(("PyQt", "PySide")):
            from matplotlib.backends.qt_compat import QtWidgets
            menu = QtWidgets.QMenu()
            menu.addAction("Norm", edit_norm)
            menu.exec(gui_event.globalPos())
        elif pkg == "tkinter":
            from tkinter import Menu
            menu = Menu(gui_event.widget, tearoff=0)
            menu.add_command(label="Norm", command=edit_norm)
            try:
                menu.tk_popup(gui_event.x_root, gui_event.y_root)
            finally:
                menu.grab_release()
        elif pkg == "wx":
            import wx
            menu = wx.Menu()
            item = menu.Append(wx.ID_ANY, "Norm")
            gui_event.EventObject.Bind(wx.EVT_MENU, edit_norm, id=item.Id)
            gui_event.EventObject.PopupMenu(menu)
        else:
            raise NotImplementedError("The current backend is not supported")
Exemple #17
0
    def on_button_release(event):
        if event.button != 3:  # Right-click.
            return

        images = [*_iter_overlapping_normed_images(artist, event)]
        if not images:
            return

        def edit_norm(_arg=None):  # Only some backends pass in an argument.
            try:
                im, = images
            except ValueError:
                raise NotImplementedError from None
            array = im.get_array().ravel()
            sub_ax = plt.figure().subplots()
            sub_ax.hist(array, _hist_bins(im), histtype="stepfilled")
            if isinstance(im.norm, mpl.colors.LogNorm):
                sub_ax.set(xscale="log")

            def on_select(vmin, vmax):
                if vmin == vmax:
                    im.set_clim((array.min(), array.max()))
                else:
                    im.set_clim((vmin, vmax))
                im.figure.canvas.draw()

            ss = sub_ax.__ss = SpanSelector(sub_ax,
                                            on_select,
                                            "horizontal",
                                            useblit=True,
                                            span_stays=True)
            ss.stay_rect.set(x=im.norm.vmin,
                             width=im.norm.vmax - im.norm.vmin,
                             visible=True)

            plt.show(block=False)

        gui_event = event.guiEvent
        pkg = type(gui_event).__module__.split(".")[0]

        if pkg == "gi":
            from gi.repository import Gtk
            menu = Gtk.Menu()
            item = Gtk.MenuItem.new_with_label("Norm")
            menu.append(item)
            item.connect("activate", edit_norm)
            item.show()
            menu.popup_at_pointer(gui_event)
        elif pkg.startswith(("PyQt", "PySide")):
            from matplotlib.backends.qt_compat import QtWidgets
            menu = QtWidgets.QMenu()
            menu.addAction("Norm", edit_norm)
            menu.exec(gui_event.globalPos())
        elif pkg == "tkinter":
            from tkinter import Menu
            menu = Menu(gui_event.widget, tearoff=0)
            menu.add_command(label="Norm", command=edit_norm)
            try:
                menu.tk_popup(gui_event.x_root, gui_event.y_root)
            finally:
                menu.grab_release()
        elif pkg == "wx":
            import wx
            menu = wx.Menu()
            item = menu.Append(wx.ID_ANY, "Norm")
            gui_event.EventObject.Bind(wx.EVT_MENU, edit_norm, id=item.Id)
            gui_event.EventObject.PopupMenu(menu)
        else:
            raise NotImplementedError("The current backend is not supported")