def onRightClick(self, event): if self.slot.status == 'Full ': popup = Menu(self,tearoff=0) popup.add_command(label= u'load', command=partial(self.menu_action, self.slot.slot)) try: popup.tk_popup(event.x_root, event.y_root, 0) finally: popup.grab_release() self.updated()
def onRightClick(self, event): if self.slot.status != 'Empty': popup = Menu(self,tearoff=0) unloadmenu = Menu(self, tearoff = 0) for slot in self.slot.device.storage_slots: if slot.status == 'Empty': unloadmenu.add_command(label= u'storage slot %s' % slot.slot, command=partial(self.menu_action, slot.slot)) popup.add_cascade(label='unload',menu =unloadmenu) try: popup.tk_popup(event.x_root, event.y_root, 0) finally: popup.grab_release() self.updated()
class Text(mx.AllMixins, tk.Text): def __init__(self, parent, scrollbar=True, **kw): parent = mx.get_master(parent) self.parent = parent frame = Frame(parent) frame.pack(fill='both', expand=True) # text widget if "wrap" not in kw: kw["wrap"] = "word" tk.Text.__init__(self, frame, **kw) #self.pack(side='left', fill='both', expand=True) mx.AllMixins.__init__(self, parent) # scrollbar if scrollbar: scrb = Scrollbar(frame, orient='vertical', command=self.yview) self.config(yscrollcommand=scrb.set) scrb.pack(side='right', fill='y') # pop-up menu self.popup = Menu(self, tearoff=0) self.popup.add_command(label='Cut', command=self._cut) self.popup.add_command(label='Copy', command=self._copy) self.popup.add_command(label='Paste', command=self._paste) self.popup.add_separator() self.popup.add_command(label='Select All', command=self._select_all) self.popup.add_command(label='Clear All', command=self._clear_all) self.bind('<Button-3>', self._show_popup) # only allow mouse scroll when mouse inside text self.bind("<Leave>", lambda event: self.winfo_toplevel().focus_set(), "+") self.bind("<Enter>", lambda event: self.focus_set(), "+") def apply_theme(self, theme='standard'): '''theme=['standard', 'typewriter', 'terminal']''' if theme == 'typewriter': '''takes all inserted text and inserts it one char every 100ms''' options = {"font": ('Times', 10, 'bold')} self.config(options) text = self.get('1.0', 'end') self.delete('1.0', 'end') self.char_index = 0 self._typewriter([char for char in text]) elif theme == 'terminal': '''blocky insert cursor''' options = {'bg': 'black', 'fg': 'white', 'font': ('Courier', 10)} self.config(options) self.cursor = '1.0' self.fg = self.cget('fg') self.bg = self.cget('bg') self.switch = self.fg self.config(insertwidth=0) self._blink_cursor() self._place_cursor() elif theme == 'matrix': '''blocky insert cursor''' options = {'bg': 'black', 'fg': 'green', 'font': ('Courier', 10)} self.config(options) self.cursor = '1.0' self.fg = self.cget('fg') self.bg = self.cget('bg') self.switch = self.fg self.config(insertwidth=0) self._blink_cursor() self._place_cursor() def highlight_pattern(self, pattern, tag, start="1.0", end="end", regexp=False, nocase=True, exact=True, **kwargs): '''Apply the given tag to all text that matches the given pattern If 'regexp' is set to True, pattern will be treated as a regular expression. From: http://stackoverflow.com/questions/3781670/how-to-highlight-text-in-a-tkinter-text-widget ''' if not pattern: return 0 start = self.index(start) end = self.index(end) self.mark_set("matchStart", start) self.mark_set("matchEnd", start) self.mark_set("searchLimit", end) count = tk.IntVar() while True: index = self.search(pattern, "matchEnd", "searchLimit", count=count, regexp=regexp, nocase=nocase, exact=exact, **kwargs) if index: self.mark_set("matchStart", index) self.mark_set("matchEnd", "%s+%sc" % (index, count.get())) self.tag_add(tag, "matchStart", "matchEnd") else: break return count.get() def clear_highlights(self, *tagnames): names = tagnames or self.tag_names() self.tag_delete(*names) def next_pattern(self, pattern, current, regexp=False, nocase=True, exact=True, **kwargs): if not pattern: return None start = self.index(current) end = self.index("end") count = tk.IntVar() index = self.search(pattern, start, end, count=count, regexp=regexp, nocase=nocase, exact=exact, **kwargs) if index: return index, index+"+%sc"%count.get() else: return None def prev_pattern(self, pattern, current, regexp=False, nocase=True, exact=True, **kwargs): if not pattern: return None start = self.index(current) end = self.index("1.0") count = tk.IntVar() index = self.search(pattern, start, end, count=count, regexp=regexp, nocase=nocase, exact=exact, backwards=True, **kwargs) if index: return index, index+"-%sc"%count.get() else: return None # MISC INTERNALS def _show_popup(self, event): '''right-click popup menu''' if self.parent.focus_get() != self: self.focus_set() try: self.popup.post(event.x_root, event.y_root) finally: self.popup.grab_release() def _cut(self): try: selection = self.get(*self.tag_ranges('sel')) self.clipboard_clear() self.clipboard_append(selection) self.delete(*self.tag_ranges('sel')) except TypeError: pass def _copy(self): try: selection = self.get(*self.tag_ranges('sel')) self.clipboard_clear() self.clipboard_append(selection) except TypeError: pass def _paste(self): self.insert('insert', self.selection_get(selection='CLIPBOARD')) def _select_all(self): '''selects all text''' self.tag_add('sel', '1.0', 'end-1c') def _clear_all(self): '''erases all text''' isok = askokcancel('Clear All', 'Erase all text?', parent=self, default='ok') if isok: self.delete('1.0', 'end') def _typewriter(self, text): # theme: typewriter '''after the theme is applied, this method takes all the inserted text and types it out one character every 100ms''' self.insert('insert', text[self.char_index]) self.char_index += 1 if hasattr(self, "typer") and self.char_index == len(text): self.after_cancel(self.typer) else: self.typer = self.after(100, self._typewriter, text) def _place_cursor(self): # theme: terminal '''check the position of the cursor against the last known position every 15ms and update the cursorblock tag as needed''' current_index = self.index('insert') if self.cursor != current_index: self.cursor = current_index self.tag_delete('cursorblock') start = self.index('insert') end = self.index('insert+1c') if start[0] != end[0]: self.insert(start, ' ') end = self.index('insert') self.tag_add('cursorblock', start, end) self.mark_set('insert', self.cursor) self.after(15, self._place_cursor) def _blink_cursor(self): # theme: terminal '''alternate the background color of the cursorblock tagged text every 600 milliseconds''' if self.switch == self.fg: self.switch = self.bg else: self.switch = self.fg self.tag_config('cursorblock', background=self.switch) self.after(600, self._blink_cursor)
class SuperText(Text): def __init__(self, parent, scrollbar=True, **kw): self.parent = parent frame = Frame(parent) frame.pack(fill='both', expand=True) # text widget Text.__init__(self, frame, **kw) self.pack(side='left', fill='both', expand=True) # scrollbar if scrollbar: scrb = Scrollbar(frame, orient='vertical', command=self.yview) self.config(yscrollcommand=scrb.set) scrb.pack(side='right', fill='y') # pop-up menu self.popup = Menu(self, tearoff=0) self.popup.add_command(label='Cut', command=self._cut) self.popup.add_command(label='Copy', command=self._copy) self.popup.add_command(label='Paste', command=self._paste) self.popup.add_separator() self.popup.add_command(label='Select All', command=self._select_all) self.popup.add_command(label='Clear All', command=self._clear_all) self.bind('<Button-3>', self._show_popup) def apply_theme(self, theme='standard'): '''theme=['standard', 'typewriter', 'terminal']''' if theme == 'typewriter': '''takes all inserted text and inserts it one char every 100ms''' text = self.get('1.0', 'end') self.delete('1.0', 'end') self.char_index = 0 self._typewriter([char for char in text]) elif theme == 'terminal': '''blocky insert cursor''' self.cursor = '1.0' self.fg = self.cget('fg') self.bg = self.cget('bg') self.switch = self.fg self.config(insertwidth=0) self._blink_cursor() self._place_cursor() def _show_popup(self, event): '''right-click popup menu''' if self.parent.focus_get() != self: self.focus_set() try: self.popup.tk_popup(event.x_root, event.y_root, 0) finally: self.popup.grab_release() def _cut(self): try: selection = self.get(*self.tag_ranges('sel')) self.clipboard_clear() self.clipboard_append(selection) self.delete(*self.tag_ranges('sel')) except TypeError: pass def _copy(self): try: selection = self.get(*self.tag_ranges('sel')) self.clipboard_clear() self.clipboard_append(selection) except TypeError: pass def _paste(self): self.insert('insert', self.selection_get(selection='CLIPBOARD')) def _select_all(self): '''selects all text''' self.tag_add('sel', '1.0', 'end-1c') def _clear_all(self): '''erases all text''' isok = askokcancel('Clear All', 'Erase all text?', parent=self, default='ok') if isok: self.delete('1.0', 'end') def _typewriter(self, text): # theme: typewriter '''after the theme is applied, this method takes all the inserted text and types it out one character every 100ms''' self.insert('insert', text[self.char_index]) self.char_index += 1 if self.char_index == len(text): self.after_cancel(self.typer) else: self.typer = self.after(100, self._typewriter, text) def _place_cursor(self): # theme: terminal '''check the position of the cursor against the last known position every 15ms and update the cursorblock tag as needed''' current_index = self.index('insert') if self.cursor != current_index: self.cursor = current_index self.tag_delete('cursorblock') start = self.index('insert') end = self.index('insert+1c') if start[0] != end[0]: self.insert(start, ' ') end = self.index('insert') self.tag_add('cursorblock', start, end) self.mark_set('insert', self.cursor) self.after(15, self._place_cursor) def _blink_cursor(self): # theme: terminal '''alternate the background color of the cursorblock tagged text every 600 milliseconds''' if self.switch == self.fg: self.switch = self.bg else: self.switch = self.fg self.tag_config('cursorblock', background=self.switch) self.after(600, self._blink_cursor)
class Text(mx.AllMixins, tk.Text): def __init__(self, parent, scrollbar=True, **kw): parent = mx.get_master(parent) self.parent = parent frame = Frame(parent) frame.pack(fill='both', expand=True) # text widget if "wrap" not in kw: kw["wrap"] = "word" tk.Text.__init__(self, frame, **kw) #self.pack(side='left', fill='both', expand=True) mx.AllMixins.__init__(self, parent) # scrollbar if scrollbar: scrb = Scrollbar(frame, orient='vertical', command=self.yview) self.config(yscrollcommand=scrb.set) scrb.pack(side='right', fill='y') # pop-up menu self.popup = Menu(self, tearoff=0) self.popup.add_command(label='Cut', command=self._cut) self.popup.add_command(label='Copy', command=self._copy) self.popup.add_command(label='Paste', command=self._paste) self.popup.add_separator() self.popup.add_command(label='Select All', command=self._select_all) self.popup.add_command(label='Clear All', command=self._clear_all) self.bind('<Button-3>', self._show_popup) # only allow mouse scroll when mouse inside text self.bind("<Leave>", lambda event: self.winfo_toplevel().focus_set(), "+") self.bind("<Enter>", lambda event: self.focus_set(), "+") def apply_theme(self, theme='standard'): '''theme=['standard', 'typewriter', 'terminal']''' if theme == 'typewriter': '''takes all inserted text and inserts it one char every 100ms''' options = {"font": ('Times', 10, 'bold')} self.config(options) text = self.get('1.0', 'end') self.delete('1.0', 'end') self.char_index = 0 self._typewriter([char for char in text]) elif theme == 'terminal': '''blocky insert cursor''' options = {'bg': 'black', 'fg': 'white', 'font': ('Courier', 10)} self.config(options) self.cursor = '1.0' self.fg = self.cget('fg') self.bg = self.cget('bg') self.switch = self.fg self.config(insertwidth=0) self._blink_cursor() self._place_cursor() elif theme == 'matrix': '''blocky insert cursor''' options = {'bg': 'black', 'fg': 'green', 'font': ('Courier', 10)} self.config(options) self.cursor = '1.0' self.fg = self.cget('fg') self.bg = self.cget('bg') self.switch = self.fg self.config(insertwidth=0) self._blink_cursor() self._place_cursor() def highlight_pattern(self, pattern, tag, start="1.0", end="end", regexp=False, nocase=True, exact=True, **kwargs): '''Apply the given tag to all text that matches the given pattern If 'regexp' is set to True, pattern will be treated as a regular expression. From: http://stackoverflow.com/questions/3781670/how-to-highlight-text-in-a-tkinter-text-widget ''' if not pattern: return 0 start = self.index(start) end = self.index(end) self.mark_set("matchStart", start) self.mark_set("matchEnd", start) self.mark_set("searchLimit", end) count = tk.IntVar() while True: index = self.search(pattern, "matchEnd", "searchLimit", count=count, regexp=regexp, nocase=nocase, exact=exact, **kwargs) if index: self.mark_set("matchStart", index) self.mark_set("matchEnd", "%s+%sc" % (index, count.get())) self.tag_add(tag, "matchStart", "matchEnd") else: break return count.get() def clear_highlights(self, *tagnames): names = tagnames or self.tag_names() self.tag_delete(*names) def next_pattern(self, pattern, current, regexp=False, nocase=True, exact=True, **kwargs): if not pattern: return None start = self.index(current) end = self.index("end") count = tk.IntVar() index = self.search(pattern, start, end, count=count, regexp=regexp, nocase=nocase, exact=exact, **kwargs) if index: return index, index + "+%sc" % count.get() else: return None def prev_pattern(self, pattern, current, regexp=False, nocase=True, exact=True, **kwargs): if not pattern: return None start = self.index(current) end = self.index("1.0") count = tk.IntVar() index = self.search(pattern, start, end, count=count, regexp=regexp, nocase=nocase, exact=exact, backwards=True, **kwargs) if index: return index, index + "-%sc" % count.get() else: return None # MISC INTERNALS def _show_popup(self, event): '''right-click popup menu''' if self.parent.focus_get() != self: self.focus_set() try: self.popup.post(event.x_root, event.y_root) finally: self.popup.grab_release() def _cut(self): try: selection = self.get(*self.tag_ranges('sel')) self.clipboard_clear() self.clipboard_append(selection) self.delete(*self.tag_ranges('sel')) except TypeError: pass def _copy(self): try: selection = self.get(*self.tag_ranges('sel')) self.clipboard_clear() self.clipboard_append(selection) except TypeError: pass def _paste(self): self.insert('insert', self.selection_get(selection='CLIPBOARD')) def _select_all(self): '''selects all text''' self.tag_add('sel', '1.0', 'end-1c') def _clear_all(self): '''erases all text''' isok = askokcancel('Clear All', 'Erase all text?', parent=self, default='ok') if isok: self.delete('1.0', 'end') def _typewriter(self, text): # theme: typewriter '''after the theme is applied, this method takes all the inserted text and types it out one character every 100ms''' self.insert('insert', text[self.char_index]) self.char_index += 1 if hasattr(self, "typer") and self.char_index == len(text): self.after_cancel(self.typer) else: self.typer = self.after(100, self._typewriter, text) def _place_cursor(self): # theme: terminal '''check the position of the cursor against the last known position every 15ms and update the cursorblock tag as needed''' current_index = self.index('insert') if self.cursor != current_index: self.cursor = current_index self.tag_delete('cursorblock') start = self.index('insert') end = self.index('insert+1c') if start[0] != end[0]: self.insert(start, ' ') end = self.index('insert') self.tag_add('cursorblock', start, end) self.mark_set('insert', self.cursor) self.after(15, self._place_cursor) def _blink_cursor(self): # theme: terminal '''alternate the background color of the cursorblock tagged text every 600 milliseconds''' if self.switch == self.fg: self.switch = self.bg else: self.switch = self.fg self.tag_config('cursorblock', background=self.switch) self.after(600, self._blink_cursor)
class Gamelist(): def __init__(self, drive, platform): GameListData.game_list_data_json = GameListData().get_game_list() self.json_game_list_data = GameListData.game_list_data_json if drive == 'USB(*)': self.drive_to_show = '/dev_' + drive.lower().replace('(*)', '') else: self.drive_to_show = '/dev_' + drive.lower() + '/' self.platform_to_show = platform + '_games' self.WCM_BASE_PATH = AppPaths.wcm_gui self.last_selection = (None, 0) self.list_of_items = [] self.selected_title_id = None self.selected_title = None self.selected_path = None self.selected_filename = None self.drive_system_path_array = None self.is_cleared = False def create_main_frame(self, entry_field_title_id, entry_field_title, entry_field_filename, entry_field_iso_path, entry_field_platform, drive_system_array): self.entry_field_title_id = entry_field_title_id self.entry_field_title = entry_field_title self.entry_field_filename = entry_field_filename self.entry_field_iso_path = entry_field_iso_path self.entry_field_platform = entry_field_platform self.drive_system_path_array = drive_system_array self.corrected_index = [] self.main_frame = Frame() self.popup_menu = Menu(self.main_frame, tearoff=0) self.popup_menu.add_command(label="Delete", command=self.delete_selected) self.popup_menu.add_command(label="Rename", command=self.rename_selected) # self.popup_menu.add_command(label="Refetch", # command=self.refetch) # self.popup_menu.add_command(label="Select All", # command=self.select_all) s = Scrollbar(self.main_frame) self._listbox = Listbox(self.main_frame, width=465) self._listbox.bind('<Enter>', self._bound_to_mousewheel) self._listbox.bind('<Leave>', self._unbound_to_mousewheel) self._listbox.bind("<Button-3>", self.popup) # Button-2 on Aqua s.pack(side=RIGHT, fill=Y) self._listbox.pack(side=LEFT, fill=Y) s['command'] = self._listbox.yview self._listbox['yscrollcommand'] = s.set # default filters if 'ALL_games' == self.platform_to_show: # iterate all platforms for platform in self.json_game_list_data: for list_game in self.json_game_list_data[platform]: # titles in the list has been designed to be unique if '/dev_all/' == self.drive_to_show or self.drive_to_show in list_game['path']: self.add_item(list_game['title']) else: for list_game in self.json_game_list_data[self.platform_to_show]: if '/dev_all/' == self.drive_to_show or self.drive_to_show in list_game['path']: self.add_item(list_game['title']) for x in range(19 - self._listbox.size()): self.add_item('') # adding shade to every other row of the list for x in range(0, self._listbox.size()): if x % 2 == 0: self._listbox.itemconfig(x, {'fg': 'white'}, background='#001738') else: self._listbox.itemconfig(x, {'fg': 'white'}, background='#001F4C') self.label = Label(self.main_frame) self.selection_poller() return self.main_frame def selection_poller(self): self.label.after(200, self.selection_poller) self.new_selection = self._listbox.curselection() # cursor har been initiated if self._listbox.curselection() is not (): if self.new_selection[0] is not self.last_selection[0] or self.is_cleared: self.entry_fields_update(self.new_selection) self.is_cleared = False self.last_selection = self.new_selection def entry_fields_update(self, new_selection): for platform in self.json_game_list_data: for list_game in self.json_game_list_data[platform]: self.selected_title = self._listbox.get(new_selection[0]) tmp_title = list_game['title'] match = self.selected_title == str(tmp_title) if match: self.selected_title_id = str(list_game['title_id']).replace('-', '') self.selected_title = str(list_game['title']) self.selected_path = str(list_game['path']) self.selected_filename = str(list_game['filename']) self.selected_platform = str(list_game['platform']) # parse drive and system from json data path_array = filter(None, self.selected_path.split('/')) self.drive_system_path_array[0] = path_array[0] self.drive_system_path_array[1] = path_array[1] self.drive_system_path_array[2] = '/'.join(path_array[2:len(path_array)]).replace('//', '') self.entry_field_title_id.delete(0, len(self.entry_field_title_id.get())-1) self.entry_field_title_id.delete(0, END) self.entry_field_title_id.insert(0, self.selected_title_id) self.entry_field_title.delete(0, END) self.entry_field_title.insert(0, self.selected_title) self.entry_field_filename.delete(0, END) self.entry_field_filename.insert(0, self.selected_filename) self.entry_field_platform.delete(0, END) self.entry_field_platform.insert(0, self.selected_platform) return True def get_selected_path(self): return self.current_iso_path def get_listbox(self): return self._listbox def get_ascending_index(self, list_of_items, item, ignore_case=True): lo = 0 hi = len(list_of_items) if ignore_case: item = item.lower() while lo < hi: mid = (lo + hi) // 2 if item < list_of_items[mid].lower(): hi = mid else: lo = mid + 1 else: while lo < hi: mid = (lo + hi) // 2 if item < list_of_items[mid]: hi = mid else: lo = mid + 1 return lo def add_item(self, item): if item != '': self.list_of_items = self._listbox.get(0, END) # getting ascending index in order to sort alphabetically index = self.get_ascending_index(self.list_of_items, item) self._listbox.insert(index, item) else: self._listbox.insert(END, item) def get_items(self): return self.list_of_items def _bound_to_mousewheel(self, event): self._listbox.bind_all("<MouseWheel>", self._on_mousewheel) def _unbound_to_mousewheel(self, event): self._listbox.unbind_all("<MouseWheel>") def _on_mousewheel(self, event): self._listbox.yview_scroll(int(-1*(event.delta/30)), "units") def popup(self, event): try: self._listbox.selection_clear(0, END) self._listbox.selection_set(self._listbox.nearest(event.y)) self._listbox.activate(self._listbox.nearest(event.y)) finally: if self._listbox.get(self._listbox.curselection()[0]) is not '': self.popup_menu.tk_popup(event.x_root + 43, event.y_root + 12, 0) self.popup_menu.grab_release() self.popup_menu.focus_set() def delete_selected(self): import tkMessageBox game_folder_path = os.path.join(AppPaths.game_work_dir, '..') response = tkMessageBox.askyesno('Delete game folder', 'Delete \'' + self.entry_field_title.get() + '\'?\n\nFolder path: ' + os.path.realpath(game_folder_path)) # yes if response: # remove game from visual game list for i in self._listbox.curselection()[::-1]: self._listbox.delete(i) removed_index = i # remove game from json game list platform_key = self.entry_field_platform.get() + '_games' self.json_game_list_data[platform_key] = [x for x in self.json_game_list_data[platform_key] if x['title'] != self.selected_title] # update the json game list file with open(GameListData.GAME_LIST_DATA_PATH, 'w') as newFile: json_text = json.dumps(self.json_game_list_data, indent=4, separators=(",", ":")) newFile.write(json_text) # remove the game build folder too if AppPaths.game_work_dir != os.path.join(AppPaths.wcm_gui, 'work_dir'): if os.path.isdir(game_folder_path): if 'webman-classics-maker' in game_folder_path: shutil.rmtree(game_folder_path) # clear entry_fields self.clear_entries_and_path() # set cursor self._listbox.select_set(removed_index) #This only sets focus on the first item. def rename_selected(self): self.entry_field_title.selection_range(0, END) self.entry_field_title.focus_set() def select_all(self): self._listbox.selection_set(0, 'end') def clear_entries_and_path(self): self.entry_field_title_id.delete(0, len(self.entry_field_title_id.get())-1) self.entry_field_title_id.delete(0, END) self.entry_field_title.delete(0, END) self.entry_field_platform.delete(0, END) self.entry_field_filename.delete(0, END) self.is_cleared = True def get_selected_build_dir_path(self): self.build_dir_path = '' if self.selected_filename not in {'', None}: filename = self.selected_filename title_id = self.selected_title_id.replace('-', '') build_base_path = AppPaths.builds tmp_filename = filename # removes the file extension from tmp_filename for file_ext in GlobalVar.file_extensions: if filename.upper().endswith(file_ext): tmp_filename = filename[0:len(filename)-len(file_ext)] break game_folder_name = tmp_filename.replace(' ', '_') + '_(' + title_id.replace('-', '') + ')' self.build_dir_path = os.path.join(build_base_path, game_folder_name) return self.build_dir_path
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 = tkFileDialog.askopenfilename( filetypes=file_types, title='Open one or more files.', message='Open one or more files', multiple=1 ) except: self.file_selection = tkFileDialog.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: u'', 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 = StringIO.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 unicode(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())