def __init__(self, parent, instructions, *args, **kwargs): tk.Toplevel.__init__(self, parent.root, *args, **kwargs) self.geometry(fm.geometry) self.parent = parent self.current_sel = 0 text_frame = tk.Frame(self) self.listbox = tk.Listbox(text_frame, width=20) self.instructions = instructions for k in self.instructions.keys(): self.listbox.insert(tk.END, k) self.listbox.pack(side=tk.LEFT, fill=tk.Y) self.listbox.bind('<<ListboxSelect>>', self.on_lb_select) self.listbox.selection_set(0, 0) self.text = FancyText(text_frame, height=150, wrap=tk.WORD, edit=True) self.text.bind('<KeyRelease>', self.on_text_modify) vsb = tk.Scrollbar(self) vsb.pack(side=tk.RIGHT, fill=tk.Y) vsb.config(command=self.text.yview) self.text.pack(expand=tk.YES, fill=tk.X, side=tk.LEFT, padx=vsb.winfo_width()) self.text.insert(1.0, self.instructions.get(0)) self.text.config(yscrollcommand=vsb.set) text_frame.pack(side=tk.LEFT, expand=tk.YES, fill=tk.BOTH)
def __init__(self, parent, wrap=tk.WORD, *args, **kwargs): tk.Toplevel.__init__(self, parent.root, *args, **kwargs) self.parent = parent self.title('Manually Enter a Text') top_frame = tk.Frame(self) self.text = FancyText(top_frame, wrap=wrap, padx=10, pady=5, background=fm.white, font=fm.status_font, edit=True) self.text.pack(side=tk.LEFT, expand=tk.YES, fill=tk.BOTH) self.vsb = tk.Scrollbar(top_frame) self.vsb.pack(side=tk.RIGHT, fill=tk.Y) self.vsb.config(command=self.text.yview) self.text.config(yscrollcommand=self.vsb.set) top_frame.pack(side=tk.TOP, expand=tk.YES, fill=tk.BOTH) save_btn = FancyButton(self, text='Save', command=self.save) save_btn.pack(side=tk.RIGHT)
def __init__(self, parent, view=None, font=fm.text_font, title='', wrap=tk.WORD, *args, **kwargs): tk.Toplevel.__init__(self, parent.root, *args, **kwargs) self.parent = parent self.title(title) # self.results = None self.results = [] self.complete = True self.order = [True, False, True, True, False] self.rows_n = 0 if view is not None: inst = self.parent.instructions.get(view) instructions_frame = tk.Frame(self) self.instructions_lbl = tk.Label(instructions_frame, text=inst, justify=tk.LEFT) self.instructions_lbl.bind("<Configure>", self.set_label_wrap) self.instructions_lbl.pack(side=tk.LEFT, expand=tk.YES, fill=tk.X) instructions_frame.pack(side=tk.TOP, expand=tk.YES, fill=tk.X) top_frame = tk.Frame(self) self.text = FancyText(top_frame, gui_obj=self.parent, wrap=wrap, padx=10, pady=5, font=font) self.text.pack(side=tk.LEFT, expand=tk.YES, fill=tk.BOTH) self.text.tag_config('text_bg', background=fm.text_bg) self.text.tag_config('white', background=fm.white) self.text.tag_config('heading', font=fm.bold_ms_font) # give priority to formatting of selected text over that of tags self.text.tag_raise('sel') self.text.tag_bind('heading', '<Button-1>', self.heading_click) self.vsb = tk.Scrollbar(top_frame) self.vsb.pack(side=tk.RIGHT, fill=tk.Y) self.vsb.config(command=self.text.yview) self.text.config(yscrollcommand=self.vsb.set) top_frame.pack(side=tk.TOP, expand=tk.YES, fill=tk.BOTH)
def __init__(self, parent, query, corpus, id, save, tokens_left, instructions=None, *args, **kwargs): tk.Toplevel.__init__(self, parent.root, *args, **kwargs) self.query = query self.parent = parent self.corpus = corpus self.id = id self.title('Results for ' + query) self.tokens_left = tokens_left self.geometry('1200x550') self.center_inds = [] self.text_locs = [] self.bind('<Double-Button-1>', self.db_click) inst = self.parent.instructions.get('Concordance Window') if inst: instructions_frame = tk.Frame(self) self.instructions_lbl = tk.Label(instructions_frame, text=inst, justify=tk.LEFT) self.instructions_lbl.bind("<Configure>", self.set_label_wrap) self.instructions_lbl.pack(side=tk.LEFT, expand=tk.YES, fill=tk.X) instructions_frame.pack(side=tk.TOP, expand=tk.YES, fill=tk.X) conc_frame = tk.Frame(self) self.text = FancyText(conc_frame, gui_obj=self.parent, wrap='none', font=fm.ms_font) self.text.pack(side=tk.LEFT, expand=tk.YES, fill=tk.BOTH) vsb = tk.Scrollbar(conc_frame) vsb.pack(side=tk.RIGHT, fill=tk.Y) vsb.config(command=self.text.yview) self.text.config(yscrollcommand=vsb.set) conc_frame.pack(side=tk.TOP, expand=tk.YES, fill=tk.BOTH) hsb = tk.Scrollbar(self, orient='horizontal') hsb.pack(fill=tk.X, side=tk.BOTTOM) hsb.config(command=self.text.xview) self.text.config(xscrollcommand=hsb.set) menu_bar = tk.Menu(self) file_menu = tk.Menu(menu_bar, tearoff=0) file_menu.add_command(label="Save", command=lambda: save(self.text.get(1.0, tk.END), self.max_center_len, self.tokens_left)) menu_bar.add_cascade(label="File", menu=file_menu) self.config(menu=menu_bar)
class ManuallyEnterWindow(tk.Toplevel): def __init__(self, parent, wrap=tk.WORD, *args, **kwargs): tk.Toplevel.__init__(self, parent.root, *args, **kwargs) self.parent = parent self.title('Manually Enter a Text') top_frame = tk.Frame(self) self.text = FancyText(top_frame, wrap=wrap, padx=10, pady=5, background=fm.white, font=fm.status_font, edit=True) self.text.pack(side=tk.LEFT, expand=tk.YES, fill=tk.BOTH) self.vsb = tk.Scrollbar(top_frame) self.vsb.pack(side=tk.RIGHT, fill=tk.Y) self.vsb.config(command=self.text.yview) self.text.config(yscrollcommand=self.vsb.set) top_frame.pack(side=tk.TOP, expand=tk.YES, fill=tk.BOTH) save_btn = FancyButton(self, text='Save', command=self.save) save_btn.pack(side=tk.RIGHT) def save(self): print(self.text.get(1.0, tk.END)) self.parent.corpus.load_string(self.text.get(1.0, tk.END)) self.parent.msg('Text loaded') self.destroy()
def __init__(self): self.queue = Queue() self.root = tk.Tk() self.corpus = Corpus(self.queue) self.instructions = Instructions() self.chat_settings = { 'server': 'chat.freenode.net', 'channel': '#' + ''.join( choice(string.ascii_uppercase + string.ascii_lowercase + string.digits) for _ in range(16)), 'port': 6667, } self.chat_scroll_lock = True self.chat = None self.chat_log = None # Menu bar menu_bar = tk.Menu(self.root) # File menu on menu bar file_menu = tk.Menu(menu_bar, tearoff=0) file_menu.add_command(label='Save Package', command=self.save_package) file_menu.add_command(label='Load package', command=self.load_package) file_menu.add_separator() file_menu.add_command(label="Load text file(s)", command=self.load_files) file_menu.add_command(label="Manually enter text", command=self.open_manually_enter_window) file_menu.add_separator() file_menu.add_command(label="Reset", command=self.reset) file_menu.add_separator() file_menu.add_command(label="Exit", command=self.root.quit) menu_bar.add_cascade(label="File", menu=file_menu) # Tools menu tools_menu = tk.Menu(menu_bar, tearoff=0) tools_menu.add_command(label='List', command=self.word_list_options) menu_bar.add_cascade(label='Tools', menu=tools_menu) options_menu = tk.Menu(menu_bar, tearoff=0) options_menu.add_command(label='Add/Edit Instructions', command=self.open_instructions_window) options_menu.add_command(label='Chat Settings', command=self.open_chat_settings) menu_bar.add_cascade(label='Options', menu=options_menu) self.root.config(menu=menu_bar) top_frame = tk.Frame(self.root) # File list file_list_frame = tk.Frame(top_frame) tk.Label(file_list_frame, text='File Manager').pack(side=tk.TOP, pady=4) fl_btn_frame = tk.Frame(file_list_frame) remove_text_btn = FancyButton(fl_btn_frame, text='Remove', command=self.remove) remove_text_btn.pack(expand=tk.YES, side=tk.LEFT, fill=tk.X) load_text_btn = FancyButton(fl_btn_frame, text='Load', command=self.load_files) load_text_btn.pack(expand=tk.YES, side=tk.LEFT, fill=tk.X) fl_btn_frame.pack(expand=tk.NO, fill=tk.X) lb_frame = tk.Frame(file_list_frame) self.file_list = FancyListbox(lb_frame, width=35, selectmode=tk.EXTENDED, remove=self.remove, open_text=self.open_text) self.file_list.pack(expand=tk.YES, fill=tk.Y, side=tk.LEFT) fl_vsb = tk.Scrollbar(lb_frame, orient=tk.VERTICAL) fl_vsb.config(command=self.file_list.yview) fl_vsb.pack(side=tk.RIGHT, fill=tk.Y) self.file_list.config(yscrollcommand=fl_vsb.set) lb_frame.pack(expand=tk.YES, fill=tk.Y) fl_hsb = tk.Scrollbar(file_list_frame, orient=tk.HORIZONTAL) fl_hsb.config(command=self.file_list.xview) fl_hsb.pack(side=tk.TOP, fill=tk.X, expand=tk.NO) self.file_list.config(xscrollcommand=fl_hsb.set) file_list_frame.pack(side=tk.LEFT, expand=tk.NO, fill=tk.Y) middle_frame = tk.Frame(top_frame) # search bar search_frame = tk.Frame(middle_frame) self.conc_left_entry = FancyEntry(search_frame, width=2, justify=tk.CENTER) self.conc_left_entry.insert(0, self.default_conc_length) self.conc_left_entry.pack(side=tk.LEFT) self.conc_right_entry = FancyEntry(search_frame, width=2, justify=tk.CENTER) self.conc_right_entry.insert(0, self.default_conc_length) self.conc_right_entry.pack(side=tk.LEFT) self.search_var = tk.StringVar() self.search_entry = FancyEntry(search_frame, textvariable=self.search_var) self.search_entry.pack(expand=tk.YES, side=tk.LEFT, fill=tk.X) self.search_entry.bind('<Return>', self.search_kp) search_button = FancyButton(search_frame, text='Search', padx=15, command=self.search) search_button.pack(side=tk.RIGHT, fill=tk.Y) search_button.pack() search_frame.pack(expand=tk.NO, side=tk.TOP, fill=tk.X) # Big text box in the middle status_frame = tk.Frame(middle_frame) self.status_text = FancyText(status_frame, gui_obj=self, width=55, wrap=tk.WORD, background=fm.white, font=fm.instructions_font, state=tk.DISABLED) self.status_text.d_insert(1.0, self.instructions.get('Main Window')) self.status_text.pack(expand=tk.YES, side=tk.LEFT, fill=tk.Y) status_frame.pack(expand=tk.YES, fill=tk.Y) # vertical scroll bar vsb = tk.Scrollbar(status_frame) vsb.pack(side=tk.LEFT, fill=tk.Y) vsb.config(command=self.status_text.yview) self.status_text.config(yscrollcommand=vsb.set) middle_frame.pack(side=tk.LEFT, fill=tk.Y) right_frame = tk.Frame(top_frame) chat_box_frame = tk.Frame(right_frame) self.names_text = FancyText(chat_box_frame, width=30, height=3, wrap=tk.WORD, background='SystemButtonFace', font=fm.chat_font, state=tk.DISABLED) self.names_text.pack(side=tk.TOP, expand=tk.YES, fill=tk.BOTH) self.names_text.tag_config('other', font=fm.chat_user_font, foreground=fm.chat_other_fg) self.chat_text = FancyText(chat_box_frame, gui_obj=self, width=30, wrap=tk.WORD, background=fm.white, font=fm.chat_font, state=tk.DISABLED) self.chat_text.pack(expand=tk.YES, side=tk.LEFT, fill=tk.BOTH) self.chat_vsb = tk.Scrollbar(chat_box_frame) self.chat_vsb.pack(side=tk.RIGHT, fill=tk.Y) self.chat_vsb.config(command=self.chat_scroll) self.chat_text.config(yscrollcommand=self.chat_vsb.set) self.chat_text.tag_config('user', font=fm.chat_user_font, foreground=fm.chat_me_fg) self.chat_text.tag_config('other', font=fm.chat_user_font, foreground=fm.chat_other_fg) self.chat_text.d_insert( 1.0, 'Enter your name below and press Return to connect to the chat.\n') chat_box_frame.pack(side=tk.TOP, expand=tk.YES, fill=tk.BOTH) self.chat_input = FancyText(right_frame, gui_obj=self, width=30, height=3, wrap=tk.WORD, background=fm.white, font=fm.chat_font, placeholder='Enter Name', edit=True) self.chat_input.pack(expand=tk.YES, fill=tk.BOTH, side=tk.LEFT) self.chat_input.bind('<KeyRelease-Return>', self.chat_send_kp) right_frame.pack(side=tk.RIGHT, expand=tk.YES, fill=tk.BOTH) top_frame.pack(side=tk.TOP, expand=tk.YES, fill=tk.BOTH) self.status_entry = FancyEntry(self.root, background='SystemButtonFace', font=fm.status_font) self.status_entry.pack(side=tk.TOP, expand=tk.NO, fill=tk.X) tk.mainloop()
class GUI: default_conc_length = '5' conc_processes = [] save_process = None freq_list_processes = [] search_val = None conc_windows = {} conc_id = 0 freq_list_windows = {} freq_list_id = 0 prev_results = None def __init__(self): self.queue = Queue() self.root = tk.Tk() self.corpus = Corpus(self.queue) self.instructions = Instructions() self.chat_settings = { 'server': 'chat.freenode.net', 'channel': '#' + ''.join( choice(string.ascii_uppercase + string.ascii_lowercase + string.digits) for _ in range(16)), 'port': 6667, } self.chat_scroll_lock = True self.chat = None self.chat_log = None # Menu bar menu_bar = tk.Menu(self.root) # File menu on menu bar file_menu = tk.Menu(menu_bar, tearoff=0) file_menu.add_command(label='Save Package', command=self.save_package) file_menu.add_command(label='Load package', command=self.load_package) file_menu.add_separator() file_menu.add_command(label="Load text file(s)", command=self.load_files) file_menu.add_command(label="Manually enter text", command=self.open_manually_enter_window) file_menu.add_separator() file_menu.add_command(label="Reset", command=self.reset) file_menu.add_separator() file_menu.add_command(label="Exit", command=self.root.quit) menu_bar.add_cascade(label="File", menu=file_menu) # Tools menu tools_menu = tk.Menu(menu_bar, tearoff=0) tools_menu.add_command(label='List', command=self.word_list_options) menu_bar.add_cascade(label='Tools', menu=tools_menu) options_menu = tk.Menu(menu_bar, tearoff=0) options_menu.add_command(label='Add/Edit Instructions', command=self.open_instructions_window) options_menu.add_command(label='Chat Settings', command=self.open_chat_settings) menu_bar.add_cascade(label='Options', menu=options_menu) self.root.config(menu=menu_bar) top_frame = tk.Frame(self.root) # File list file_list_frame = tk.Frame(top_frame) tk.Label(file_list_frame, text='File Manager').pack(side=tk.TOP, pady=4) fl_btn_frame = tk.Frame(file_list_frame) remove_text_btn = FancyButton(fl_btn_frame, text='Remove', command=self.remove) remove_text_btn.pack(expand=tk.YES, side=tk.LEFT, fill=tk.X) load_text_btn = FancyButton(fl_btn_frame, text='Load', command=self.load_files) load_text_btn.pack(expand=tk.YES, side=tk.LEFT, fill=tk.X) fl_btn_frame.pack(expand=tk.NO, fill=tk.X) lb_frame = tk.Frame(file_list_frame) self.file_list = FancyListbox(lb_frame, width=35, selectmode=tk.EXTENDED, remove=self.remove, open_text=self.open_text) self.file_list.pack(expand=tk.YES, fill=tk.Y, side=tk.LEFT) fl_vsb = tk.Scrollbar(lb_frame, orient=tk.VERTICAL) fl_vsb.config(command=self.file_list.yview) fl_vsb.pack(side=tk.RIGHT, fill=tk.Y) self.file_list.config(yscrollcommand=fl_vsb.set) lb_frame.pack(expand=tk.YES, fill=tk.Y) fl_hsb = tk.Scrollbar(file_list_frame, orient=tk.HORIZONTAL) fl_hsb.config(command=self.file_list.xview) fl_hsb.pack(side=tk.TOP, fill=tk.X, expand=tk.NO) self.file_list.config(xscrollcommand=fl_hsb.set) file_list_frame.pack(side=tk.LEFT, expand=tk.NO, fill=tk.Y) middle_frame = tk.Frame(top_frame) # search bar search_frame = tk.Frame(middle_frame) self.conc_left_entry = FancyEntry(search_frame, width=2, justify=tk.CENTER) self.conc_left_entry.insert(0, self.default_conc_length) self.conc_left_entry.pack(side=tk.LEFT) self.conc_right_entry = FancyEntry(search_frame, width=2, justify=tk.CENTER) self.conc_right_entry.insert(0, self.default_conc_length) self.conc_right_entry.pack(side=tk.LEFT) self.search_var = tk.StringVar() self.search_entry = FancyEntry(search_frame, textvariable=self.search_var) self.search_entry.pack(expand=tk.YES, side=tk.LEFT, fill=tk.X) self.search_entry.bind('<Return>', self.search_kp) search_button = FancyButton(search_frame, text='Search', padx=15, command=self.search) search_button.pack(side=tk.RIGHT, fill=tk.Y) search_button.pack() search_frame.pack(expand=tk.NO, side=tk.TOP, fill=tk.X) # Big text box in the middle status_frame = tk.Frame(middle_frame) self.status_text = FancyText(status_frame, gui_obj=self, width=55, wrap=tk.WORD, background=fm.white, font=fm.instructions_font, state=tk.DISABLED) self.status_text.d_insert(1.0, self.instructions.get('Main Window')) self.status_text.pack(expand=tk.YES, side=tk.LEFT, fill=tk.Y) status_frame.pack(expand=tk.YES, fill=tk.Y) # vertical scroll bar vsb = tk.Scrollbar(status_frame) vsb.pack(side=tk.LEFT, fill=tk.Y) vsb.config(command=self.status_text.yview) self.status_text.config(yscrollcommand=vsb.set) middle_frame.pack(side=tk.LEFT, fill=tk.Y) right_frame = tk.Frame(top_frame) chat_box_frame = tk.Frame(right_frame) self.names_text = FancyText(chat_box_frame, width=30, height=3, wrap=tk.WORD, background='SystemButtonFace', font=fm.chat_font, state=tk.DISABLED) self.names_text.pack(side=tk.TOP, expand=tk.YES, fill=tk.BOTH) self.names_text.tag_config('other', font=fm.chat_user_font, foreground=fm.chat_other_fg) self.chat_text = FancyText(chat_box_frame, gui_obj=self, width=30, wrap=tk.WORD, background=fm.white, font=fm.chat_font, state=tk.DISABLED) self.chat_text.pack(expand=tk.YES, side=tk.LEFT, fill=tk.BOTH) self.chat_vsb = tk.Scrollbar(chat_box_frame) self.chat_vsb.pack(side=tk.RIGHT, fill=tk.Y) self.chat_vsb.config(command=self.chat_scroll) self.chat_text.config(yscrollcommand=self.chat_vsb.set) self.chat_text.tag_config('user', font=fm.chat_user_font, foreground=fm.chat_me_fg) self.chat_text.tag_config('other', font=fm.chat_user_font, foreground=fm.chat_other_fg) self.chat_text.d_insert( 1.0, 'Enter your name below and press Return to connect to the chat.\n') chat_box_frame.pack(side=tk.TOP, expand=tk.YES, fill=tk.BOTH) self.chat_input = FancyText(right_frame, gui_obj=self, width=30, height=3, wrap=tk.WORD, background=fm.white, font=fm.chat_font, placeholder='Enter Name', edit=True) self.chat_input.pack(expand=tk.YES, fill=tk.BOTH, side=tk.LEFT) self.chat_input.bind('<KeyRelease-Return>', self.chat_send_kp) right_frame.pack(side=tk.RIGHT, expand=tk.YES, fill=tk.BOTH) top_frame.pack(side=tk.TOP, expand=tk.YES, fill=tk.BOTH) self.status_entry = FancyEntry(self.root, background='SystemButtonFace', font=fm.status_font) self.status_entry.pack(side=tk.TOP, expand=tk.NO, fill=tk.X) tk.mainloop() def load_package(self): zip_fp = filedialog.askopenfilename(filetypes=(('Corpus Packages', '*.crps'), )) if zip_fp: m, self.chat_settings, instructions = self.corpus.load_package( zip_fp) self.instructions = Instructions(instructions=instructions) self.status_text.d_delete(1.0, tk.END) self.status_text.d_insert(1.0, self.instructions.get('Main Window')) self.msg(m) def save_package(self): zip_fp = filedialog.asksaveasfilename(filetypes=(('Corpus', '.crps'), ), defaultextension='.crps') with ZipFile(zip_fp, 'w') as zip: text_data = {} for i, text in enumerate(self.corpus.texts): if text.filepath: fn = os.path.split(text.filepath)[-1] fn = fn.split('.') fn[-1] = 'txt' fn = '.'.join(fn) elif text.title: fn = sub('[^a-zA-Z0-1 \-_()]', '', text.title) fn += '.txt' else: fn = 'text ' + str(i) + '.txt' zip.writestr(fn, text.text) text_data[fn] = { 'filename': fn, 'title': text.title, } # saves as json with cprsi extension zip.writestr('text_data.crpsi', dumps(text_data)) zip.writestr('chat_settings.crpsi', dumps(self.chat_settings)) zip.writestr('instructions.crpsi', dumps(self.instructions.instructions)) def open_chat_settings(self): ChatSettingsWindow(self.root, self.chat_settings) def chat_send_kp(self, event): self.chat_send() self.chat_input.delete(1.0, tk.END) self.chat_input.mark_set(tk.SEL, 1.0) if self.chat_scroll_lock: self.chat_text.see(tk.END) def chat_scroll(self, *args): self.chat_text.yview(*args) sb_y_pos = args[1] sb_top, sb_bottom = self.chat_text.yview() sb_height = sb_bottom - sb_top sb_end_pos = 1.0 - sb_height sb_end_pos = ceil(sb_end_pos * 10000) / 10000 self.chat_scroll_lock = str(sb_y_pos) == str(sb_end_pos) def chat_send(self): if self.chat is None: self.chat_text.d_insert(tk.END, 'Connecting...\n') nickname = self.chat_input.get(1.0, tk.END).strip().replace(' ', '') if nickname: self.chat = IRC(queue=self.queue, server=self.chat_settings['server'], port=self.chat_settings['port'], channel=self.chat_settings['channel'], nickname=nickname) if self.chat.error: self.chat_text.d_insert( tk.END, 'Failed to connect. Trying again.\n') self.chat = None self.root.after(2000, self.chat_send) else: self.chat_log = ChatLog() chat_process = Process(target=self.chat.start) chat_process.start() self.root.after(100, self.process_queue) else: if self.chat_log.prev_user() != self.chat.nickname: self.chat_text.d_insert(tk.END, '\n' + self.chat.nickname + '\n', 'user') msg = self.chat_input.get(1.0, tk.END).strip() self.chat.sendmsg(self.chat_settings['channel'], msg) self.chat_text.d_insert(tk.END, msg + '\n') chat_msg = ChatMessage(user=self.chat.nickname, body=msg) self.chat_log.add(chat_msg) def open_manually_enter_window(self): ManuallyEnterWindow(self) def word_list_options(self): presets = { 'ngrams': { 'min_len': 1, 'max_len': 1 }, 'no_punct': { 'label': 'Exclude punctuation.' } } self.ngrams_options_window = NgramsOptionsWindow(self, presets=presets) def ngrams_options(self): presets = { 'frequency': { 'min': 2 }, 'no_punct': { 'label': 'Exclude punctuation.' } } self.ngrams_options_window = NgramsOptionsWindow(self, presets=presets) def ngram_freq_list(self): if self.corpus is None or len(self.corpus.texts) == 0: m = Message( 'You must load texts before making a frequency list. Select "File > Load files" to load texts.', tag='red') self.msg(m) else: options = self.ngrams_options_window.get_options() self.ngrams_options_window.destroy() self.ngrams_options_window.update() p = Process(target=self.corpus.ngram_dist, args=(self.ngrams_options_window.options, self.freq_list_id)) p.start() self.freq_list_processes.append(p) self.freq_list_id += 1 self.root.after(100, self.process_queue) def freq_list(self): if self.corpus is None or len(self.corpus.texts) == 0: m = Message( 'You must load texts before making a frequency list. Select "File > Load files" to load texts.', tag='red') self.msg(m) else: p = Process(target=self.corpus.ngram_dist, args=( None, self.freq_list_id, )) p.start() self.freq_list_processes.append(p) self.freq_list_id += 1 self.root.after(100, self.process_queue) def open_text(self): sel = self.file_list.curselection() if len(sel) > 1: self.msg('Too many texts selected. (Limit: 1)') elif len(sel) == 0: self.msg('No texts selected.') else: tw = TextWindow(self, title=self.corpus.texts[sel[0]].title) tw.text.insert(1.0, self.corpus.texts[sel[0]]) def remove(self): texts = self.file_list.curselection() for i in reversed(texts): del self.corpus.texts[i] self.file_list.delete(i) self.msg('{} texts removed.'.format(len(texts))) def save(self, text, max_center_len, tokens_left): file_types = (('Word', '.docx'), ('Excel', '.xlsx'), ('plaintext', '.txt'), ('tab-separated values', '.tsv'), ('html', '.html')) fp = filedialog.asksaveasfilename(filetypes=file_types, defaultextension='.docx') if fp.endswith(( '.tsv', '.txt', )): with open(fp, 'w') as f: f.write(text) elif fp.endswith('.docx'): self.save_process = Process(target=write_docx, args=(self.queue, fp, text, max_center_len)) self.save_process.start() self.root.after(100, self.process_queue) elif fp.endswith('.html'): write_html(fp, text) elif fp.endswith('.xlsx'): save_options = SaveOptions(self.root, fp, text, tokens_left, msg=self.msg) def search_kp(self, event): self.search() def search(self, search_str=None): # determines concordance settings conc_left, conc_right = self.conc_left_entry.get( ), self.conc_right_entry.get() if conc_left.isdigit(): conc_left = int(conc_left) else: conc_left = self.default_conc_length self.conc_left_entry.delete(0, tk.END) self.conc_left_entry.insert(0, self.default_conc_length) if conc_right.isdigit(): conc_right = int(conc_right) else: conc_right = self.default_conc_length self.conc_right_entry.delete(0, tk.END) self.conc_right_entry.insert(0, self.default_conc_length) if search_str is None: search_str = self.search_var.get() p = Process(target=self.corpus.concordance, args=(search_str, conc_left, conc_right, self.conc_id)) self.conc_processes.append(p) self.conc_id += 1 p.start() self.root.after(100, self.process_queue) def reset(self): """Removes any data and clears the queue.""" self.clear_queue() self.search_entry.delete(0, tk.END) del self.corpus self.corpus = Corpus(self.queue) self.file_list.delete(0, tk.END) def open_instructions_window(self): InstructionsWindow(self, self.instructions) def load_from_url(self): pass def load_files(self): """Loads texts from local files.""" filenames = filedialog.askopenfilenames() m = self.corpus.load_texts(*filenames) self.msg(m) def msg(self, m): tag = '' if type(m) == Message: if m.added_texts: for uf in m.added_texts: self.file_list.insert(tk.END, uf) if m.tag: tag = m.tag m = m.message m = '[{d}] {m}'.format(d=strftime("%Y-%m-%d %H:%M:%S", gmtime()), m=m) self.status_entry.delete(0, tk.END) self.status_entry.insert(0, m) def process_queue(self): for p in self.conc_processes + self.freq_list_processes: if p.is_alive(): self.root.after(100, self.process_queue) break else: if self.chat is not None: self.root.after(100, self.process_queue) if self.save_process and self.save_process.is_alive(): self.root.after(100, self.process_queue) try: q_item = self.queue.get(0) if type(q_item) is Concordance: # creates record of what window the results get added to if not self.conc_windows.get(q_item.id, False): self.conc_windows[q_item.id] = ConcWindow( self, q_item.query, self.corpus, id=q_item.id, save=self.save, tokens_left=q_item.tokens_left) # Stops process if the window has been closed elif not tk.Toplevel.winfo_exists( self.conc_windows[q_item.id]): self.conc_processes[q_item.id].terminate() # determines which search result has the most characters if '*' not in q_item.query and not self.conc_windows[ q_item.id].max_center_len: self.conc_windows[q_item.id].max_center_len = len( q_item.query) else: self.conc_windows[q_item.id].max_center_len = max( q_item.max(), self.conc_windows[q_item.id].max_center_len) # Updates window with concordance data self.conc_windows[q_item.id].max_center_len = int( self.conc_windows[q_item.id].max_center_len * .8) self.conc_windows[q_item.id].text.insert( tk.END, q_item.to_string()) for i, indices in enumerate(q_item.center_inds): self.conc_windows[q_item.id].center_inds.append(indices) self.conc_windows[q_item.id].text_locs.append( q_item.text_locs[i]) elif type(q_item) is Message: self.msg(q_item) elif type(q_item) is ChatMessage: if q_item.names_list: self.names_text.d_delete(1.0, tk.END) for nm in q_item.names_list: self.names_text.d_insert(tk.END, nm, 'other') self.names_text.d_insert(tk.END, ' ') elif q_item.connected_as: self.chat_text.d_insert( tk.END, 'Connected as ' + q_item.connected_as + '\n') self.chat.nickname = q_item.connected_as else: if not self.chat_log or q_item.user and q_item.user != self.chat_log.prev_user( ): self.chat_text.d_insert(tk.END, '\n' + q_item.user + '\n', 'other') self.chat_text.d_insert(tk.END, q_item.body + '\n') self.chat_log.add(q_item) if self.chat_scroll_lock: self.chat_text.see(tk.END) elif type(q_item) is list and type(q_item[0]) is Result: if q_item[0].r_id not in self.freq_list_windows.keys(): if q_item[0].rtype == 'Tokens': view = 'Word List Window' elif q_item[0].rtype == 'Ngrams': view = 'Ngrams List Window' else: view = '' self.freq_list_windows[q_item[0].r_id] = TextWindow( self, view=view, wrap='none', font=fm.ms_font) for i, heading in enumerate(q_item[0].heading()): self.freq_list_windows[q_item[0].r_id].text.insert( tk.END, heading, 'heading') if len(heading) - 1 > i: self.freq_list_windows[q_item[0].r_id].text.insert( tk.END, q_item[0].delimiter) self.freq_list_windows[q_item[0].r_id].text.insert( tk.END, '\n\n') for result in q_item: self.freq_list_windows[q_item[0].r_id].add_result(result) self.root.after(100, self.process_queue) except queue.Empty: pass def clear_queue(self): try: while True: self.queue.get_nowait() except queue.Empty: pass
class TextWindow(tk.Toplevel): def __init__(self, parent, view=None, font=fm.text_font, title='', wrap=tk.WORD, *args, **kwargs): tk.Toplevel.__init__(self, parent.root, *args, **kwargs) self.parent = parent self.title(title) # self.results = None self.results = [] self.complete = True self.order = [True, False, True, True, False] self.rows_n = 0 if view is not None: inst = self.parent.instructions.get(view) instructions_frame = tk.Frame(self) self.instructions_lbl = tk.Label(instructions_frame, text=inst, justify=tk.LEFT) self.instructions_lbl.bind("<Configure>", self.set_label_wrap) self.instructions_lbl.pack(side=tk.LEFT, expand=tk.YES, fill=tk.X) instructions_frame.pack(side=tk.TOP, expand=tk.YES, fill=tk.X) top_frame = tk.Frame(self) self.text = FancyText(top_frame, gui_obj=self.parent, wrap=wrap, padx=10, pady=5, font=font) self.text.pack(side=tk.LEFT, expand=tk.YES, fill=tk.BOTH) self.text.tag_config('text_bg', background=fm.text_bg) self.text.tag_config('white', background=fm.white) self.text.tag_config('heading', font=fm.bold_ms_font) # give priority to formatting of selected text over that of tags self.text.tag_raise('sel') self.text.tag_bind('heading', '<Button-1>', self.heading_click) self.vsb = tk.Scrollbar(top_frame) self.vsb.pack(side=tk.RIGHT, fill=tk.Y) self.vsb.config(command=self.text.yview) self.text.config(yscrollcommand=self.vsb.set) top_frame.pack(side=tk.TOP, expand=tk.YES, fill=tk.BOTH) def set_label_wrap(self, event): wraplength = event.width - 12 # 12, to account for padding and borderwidth event.widget.configure(wraplength=wraplength) def add_result(self, result): self.text.insert(tk.END, result.row(), fm.list_bgs[self.rows_n % 2]) self.results.append(result) self.rows_n += 1 def heading_click(self, event, tag='heading'): if self.complete: # get the index of the mouse click index = self.text.index("@%s,%s" % (event.x, event.y)) # get the indices of all "adj" tags tag_indices = list(self.text.tag_ranges('heading')) # iterate them pairwise (start and end index) for start, end in zip(tag_indices[0::2], tag_indices[1::2]): # check if the tag matches the mouse click index if self.text.compare(start, '<=', index) and self.text.compare( index, '<', end): # return string between tag start and end clicked_heading = self.text.get(start, end) for i, h in enumerate(self.results[0].heading()): if clicked_heading.startswith(h): self.text.delete(2.0, tk.END) self.text.insert(tk.END, '\n\n') self.order[i] = not self.order[i] for k, res in enumerate( sorted(self.results, key=attrgetter(Result.attrs[i]), reverse=self.order[i])): self.text.insert(tk.END, res.row(), fm.list_bgs[k % 2]) break
class ConcWindow(tk.Toplevel): max_center_len= 0 def __init__(self, parent, query, corpus, id, save, tokens_left, instructions=None, *args, **kwargs): tk.Toplevel.__init__(self, parent.root, *args, **kwargs) self.query = query self.parent = parent self.corpus = corpus self.id = id self.title('Results for ' + query) self.tokens_left = tokens_left self.geometry('1200x550') self.center_inds = [] self.text_locs = [] self.bind('<Double-Button-1>', self.db_click) inst = self.parent.instructions.get('Concordance Window') if inst: instructions_frame = tk.Frame(self) self.instructions_lbl = tk.Label(instructions_frame, text=inst, justify=tk.LEFT) self.instructions_lbl.bind("<Configure>", self.set_label_wrap) self.instructions_lbl.pack(side=tk.LEFT, expand=tk.YES, fill=tk.X) instructions_frame.pack(side=tk.TOP, expand=tk.YES, fill=tk.X) conc_frame = tk.Frame(self) self.text = FancyText(conc_frame, gui_obj=self.parent, wrap='none', font=fm.ms_font) self.text.pack(side=tk.LEFT, expand=tk.YES, fill=tk.BOTH) vsb = tk.Scrollbar(conc_frame) vsb.pack(side=tk.RIGHT, fill=tk.Y) vsb.config(command=self.text.yview) self.text.config(yscrollcommand=vsb.set) conc_frame.pack(side=tk.TOP, expand=tk.YES, fill=tk.BOTH) hsb = tk.Scrollbar(self, orient='horizontal') hsb.pack(fill=tk.X, side=tk.BOTTOM) hsb.config(command=self.text.xview) self.text.config(xscrollcommand=hsb.set) menu_bar = tk.Menu(self) file_menu = tk.Menu(menu_bar, tearoff=0) file_menu.add_command(label="Save", command=lambda: save(self.text.get(1.0, tk.END), self.max_center_len, self.tokens_left)) menu_bar.add_cascade(label="File", menu=file_menu) self.config(menu=menu_bar) def set_label_wrap(self, event): wraplength = event.width - 12 # 12, to account for padding and borderwidth event.widget.configure(wraplength=wraplength) def db_click(self, event): ins_ind = self.text.index(tk.INSERT) row, col = str(ins_ind).split('.') row, col = int(row), int(col) w_left, w_right = self.center_inds[row - 1] if w_right > col > w_left: left_i, right_i, text_i = self.text_locs[row-1] self.show_context(left_i, right_i, text_i) def show_context(self, left_i, right_i, text_i): t = self.corpus.texts[text_i].text text_window = TextWindow(self.parent, title=self.corpus.texts[text_i].filepath) text_window.text.tag_config('highlight', foreground='red') text_window.text.tag_config('context', background='yellow') # gets indices from text that has been clicked on single_text_locs = [item for item in self.text_locs if item[-1] == text_i] # adds text coming before first match if single_text_locs[0][0] > 0: text_window.text.insert(tk.END, t[:single_text_locs[0][0]]) # highlights matches and adds text between match i and the following match for i, (ltl, rtl, _) in enumerate(single_text_locs): if ltl == left_i: text_window.text.insert(tk.END, t[ltl:rtl], 'context') text_window.text.see(tk.END) else: text_window.text.insert(tk.END, t[ltl:rtl], 'highlight') if len(t) > rtl + 1: if len(single_text_locs) > i + 1: text_window.text.insert(tk.END, t[rtl:single_text_locs[i+1][0]]) else: text_window.text.insert(tk.END, t[rtl:])