Пример #1
0
class TopErrorWindow(Toplevel):
    def __init__(self, title, message, detail):
        Toplevel.__init__(self)
        self.details_expanded = False
        self.title(title)
        self.geometry('380x95')
        self.minsize(380, 95)
        self.maxsize(425, 250)
        self.rowconfigure(0, weight=0)
        self.rowconfigure(1, weight=1)
        self.columnconfigure(0, weight=1)

        button_frame = Frame(self)
        button_frame.grid(row=0, column=0, sticky='nsew')
        button_frame.columnconfigure(0, weight=1)
        button_frame.columnconfigure(1, weight=1)

        text_frame = Frame(self)
        text_frame.grid(row=1,
                        column=0,
                        padx=(7, 7),
                        pady=(7, 7),
                        sticky='nsew')
        text_frame.rowconfigure(0, weight=1)
        text_frame.columnconfigure(0, weight=1)

        ttk.Label(button_frame, text=message).grid(row=0,
                                                   column=0,
                                                   columnspan=2,
                                                   pady=(7, 7))
        ttk.Button(button_frame, text='OK',
                   command=self.destroy).grid(row=1, column=0, sticky='e')
        ttk.Button(button_frame, text='Details',
                   command=self.toggle_details).grid(row=1,
                                                     column=1,
                                                     sticky='w')

        self.textbox = Text(text_frame, height=6)
        self.textbox.insert('1.0', detail)
        self.textbox.config(state='disabled')
        self.scrollb = Scrollbar(text_frame, command=self.textbox.yview)
        self.textbox.config(yscrollcommand=self.scrollb.set)

    def toggle_details(self):
        if self.details_expanded:
            self.textbox.grid_forget()
            self.scrollb.grid_forget()
            self.geometry('380x95')
            self.details_expanded = False
        else:
            self.textbox.grid(row=0, column=0, sticky='nsew')
            self.scrollb.grid(row=0, column=1, sticky='nsew')
            self.geometry('380x160')
            self.details_expanded = True
Пример #2
0
class adminPage(Frame):
    def __init__(self, parent, main, **kw):
        Frame.__init__(self, parent, **kw)
        self.main = main
        self.label_head = Label(text='Admin Page', font=MED_FONT)
        self.adm_stock_l = Label(text='Stock Name: ')
        self.adm_stock = StringVar()
        self.adm_stock_c = Combobox(textvariable=self.adm_stock)
        self.adm_ncost_l = Label(text='New Cost of Stock: ')
        self.adm_namount_l = Label(text='New number of stocks added: ')
        self.adm_namount = Entry()
        self.adm_ncost = Entry()
        self.adm_update_b = Button(text='UPDATE', command=self.update)
        self.back_b = Button(text='Log Out', command=self.back)
        self.view_f_text = Text(height=20, width=30)
        self.view_scroll = Scrollbar(orient=VERTICAL,
                                     command=self.view_f_text.yview)
        self.view_f_text.config(yscrollcommand=self.view_scroll.set)
        self.new_stock = False

    def back(self):
        self.main.show_frame(LOGIN_PAGE, ADMIN_PAGE)
        self.main.login = False
        self.main.admin = False

    def showItems(self, main):
        self.label_head.grid(column=0, row=0, columnspan=3)
        self.adm_stock_l.grid(column=0, row=1)
        self.adm_stock_c.grid(column=1, row=1)
        self.adm_stock_c.config(values=main.shares_dict.keys())
        self.adm_ncost_l.grid(column=0, row=2)
        self.adm_ncost.grid(column=1, row=2)
        self.adm_namount_l.grid(column=0, row=3)
        self.adm_namount.grid(column=1, row=3)
        self.adm_update_b.grid(column=0, row=4)
        self.back_b.grid(column=1, row=4)
        self.view_stock()
        self.view_f_text.grid(column=0, row=5, sticky='nsew', columnspan=2)
        self.view_scroll.grid(column=2, row=5, sticky='ns')

    def hideItems(self, main):
        self.label_head.grid_forget()
        self.adm_stock_l.grid_forget()
        self.adm_stock_c.grid_forget()
        self.adm_ncost_l.grid_forget()
        self.adm_ncost.grid_forget()
        self.adm_namount_l.grid_forget()
        self.adm_namount.grid_forget()
        self.adm_update_b.grid_forget()
        self.back_b.grid_forget()
        self.view_f_text.grid_forget()
        self.view_scroll.grid_forget()

    def update(self):
        stock_name = self.adm_stock.get()
        ncost = int(self.adm_ncost.get())
        namount = self.adm_namount.get()
        if ncost < 0:
            showinfo(message='Enter valid cost, Please check data')
            self.adm_ncost.delete(0, END)
        elif namount == '':
            namount = '0'
        elif int(namount) < 0:
            showinfo(message='Enter valid amount, Please check data')
            self.adm_namount.delete(0, END)

        elif stock_name not in self.main.shares_dict:
            if not self.new_stock:
                showinfo(
                    message=
                    'Are you sure you want to add this new stock \n Check the details once again'
                )
                self.new_stock = True
            else:
                self.main.shares_dict[stock_name] = {}
                self.main.shares_dict[stock_name]['cost'] = str(ncost)
                self.main.shares_dict[stock_name]['tot_amount'] = namount
                self.main.shares_dict[stock_name]['name'] = stock_name
                self.main.shares_dict[stock_name]['tot_sold'] = '0'
                self.new_stock = False
                buff = {
                    'tot_owned': '0',
                    'name': stock_name,
                    'money_spent': '0'
                }
                for name in self.main.users_dict:
                    self.main.users_dict[name].append(buff)
                self.adm_namount.delete(0, END)
                self.adm_ncost.delete(0, END)
                self.view_stock()
                self.adm_stock.set('')

        else:
            self.main.shares_dict[stock_name]['cost'] = str(ncost)
            tot_amount = int(self.main.shares_dict[stock_name]['tot_amount'])
            self.main.shares_dict[stock_name]['tot_amount'] = str(tot_amount +
                                                                  int(namount))
            self.adm_namount.delete(0, END)
            self.adm_ncost.delete(0, END)
            self.view_stock()

    def view_stock(self):
        self.view_f_text.config(state='normal')
        self.view_f_text.delete('1.0', 'end')
        key = self.main.shares_dict.keys()
        for name in key:
            li = self.main.shares_dict[name]
            txt_b1 = ' ' * 10 + 'Name: '
            self.view_f_text.insert('end', txt_b1)
            self.view_f_text.insert('end', name + '\n')
            txt_b2 = ' ' * 10 + 'Cost Price: '
            self.view_f_text.insert('end', txt_b2)
            self.view_f_text.insert('end', li['cost'] + '\n')
            available_num = int(li['tot_amount']) - int(li['tot_sold'])
            txt_b3 = ' ' * 10 + 'Available amount: '
            self.view_f_text.insert('end', txt_b3)
            self.view_f_text.insert('end', str(available_num) + '\n')
            txt_b4 = ' ' * 10 + '*' * 20
            self.view_f_text.insert('end', '\n' + txt_b4 + '\n\n')
        self.view_f_text.config(state='disabled')
Пример #3
0
class viewStock(Frame):
    '''The Frame that is kind of a logged in view and contains buttons
        to move to sell, buy or log out. At the same time it
        it also shows what stocks one has along with their profit and more'''
    def __init__(self, parent, main, **kw):
        Frame.__init__(self, parent, **kw)
        self.view_f_text = Text(width=30)
        self.main = main
        self.view_scroll = Scrollbar(orient = VERTICAL, command=self.view_f_text.yview)
        self.view_f_text.config(yscrollcommand = self.view_scroll.set)
        self.label_head = Label(text='Stocks available', font = MED_FONT)
        self.back_b = Button(text='Login and Buy', command = self.back )
        self.buy_b = Button(text='BUY', command = self.buy)
        self.sell_b = Button(text='SELL', command = self.sell)
    def buy(self):
        '''the call back if we click on buy and takes us to the buy window'''
        self.main.frames[RETAIL_PAGE].page = 'b'
        self.main.show_frame(RETAIL_PAGE, VIEW_STOCK)
    def sell(self):
        '''the call back if we click on sell and it takes us to the sell window'''
        self.main.frames[RETAIL_PAGE].page = 's'
        self.main.show_frame(RETAIL_PAGE, VIEW_STOCK)
    def back(self):
        '''this is kind of the '''
        self.main.show_frame(LOGIN_PAGE, VIEW_STOCK)
        self.main.login = False
        self.main.admin = False
    def showItems(self, main):
        if main.login:
            self.back_b.config(text='Log Out')
            self.label_head.config(text='Logged in as %s'%self.main.present_user)
            self.buy_b.grid(column=0, row=2, columnspan=2)
            self.sell_b.grid(column=0, row=3, columnspan=2)
        else:
            self.back_b.config(text='Login and Buy')
            self.label_head.configure(text='View Stock')

        self.label_head.grid(column=0, row=0, columnspan=2)
        self.view_f_text.grid(column=0, row=1, sticky='nsew')
        self.view_scroll.grid(column=2, row=1)
        self.back_b.grid(column=0, row=4, columnspan=2)
        self.view_stock()
    def hideItems(self, main):
        self.label_head.grid_forget()
        self.view_f_text.grid_forget()
        self.view_scroll.grid_forget()
        self.back_b.grid_forget()

        if main.login:
            self.buy_b.grid_forget()
            self.sell_b.grid_forget()
    def view_stock(self):
        self.view_f_text.config(state='normal')
        self.view_f_text.delete('1.0', 'end')

        if self.main.login and not self.main.admin:
            l2 = self.main.accounts[self.main.present_user]
            txt_1 = 'Balance: ' + l2['balance'] + '\n' + 'Profit: ' + l2['profit'] + '\n'*2 + '*'*20 + '\n'
            self.view_f_text.insert('end',txt_1)
        key = self.main.shares_dict.keys()

        if not self.main.login:
            for name in key:
                li = self.main.shares_dict[name]
                txt_b1 = 'Name: '
                self.view_f_text.insert('end',txt_b1)
                self.view_f_text.insert('end',name+'\n')
                txt_b2 = 'Cost Price: '
                self.view_f_text.insert('end',txt_b2)
                self.view_f_text.insert('end',li['cost']+'\n')
                available_num = int(li['tot_amount']) - int(li['tot_sold'])
                txt_b3 = 'Available amount: '
                self.view_f_text.insert('end',txt_b3)
                self.view_f_text.insert('end',str(available_num)+'\n')
                txt_b4 = '*'*20
                self.view_f_text.insert('end','\n'+txt_b4+'\n\n')
        self.view_scroll.grid(column=1, row=0, rowspan=2, sticky='nswe')

        if self.main.login:
            for name in key:
                li = self.main.shares_dict[name]
                txt_b1 = 'Name: '
                self.view_f_text.insert('end',txt_b1)
                self.view_f_text.insert('end',name+'\n')
                txt_b2 = 'Cost Price: '
                self.view_f_text.insert('end',txt_b2)
                self.view_f_text.insert('end',li['cost']+'\n')
                available_num = int(li['tot_amount']) - int(li['tot_sold'])
                txt_b3 = 'Available amount: '
                self.view_f_text.insert('end',txt_b3)
                self.view_f_text.insert('end',str(available_num)+'\n')
                lis =  self.main.p_user_dict
                for i in lis:
                    if i['name'] == name:
                        lis = i
                        break
                txt1 = 'Stocks owned: '+lis['tot_owned']+'\n' if not lis['tot_owned'] == '0' else ''
                self.view_f_text.insert('end', txt1)
                txt2 = 'Money spent: '+ lis['money_spent']+'\n' if not lis['tot_owned'] == '0' else ''
                self.view_f_text.insert('end', txt2)
                txt_b4 = '*'*20
                self.view_f_text.insert('end','\n'+txt_b4+'\n\n')
            self.view_f_text.config(state='disabled')
        else:
            self.view_f_text.config(state='disabled')
Пример #4
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