class KRCCModule: __metaclass__ = ABCMeta def __init__(self): self._terminate = BooleanVar(False) self._id = StringVar(False) @property def terminate(self): return self._terminate.get() @terminate.setter def terminate(self, value): self._terminate.set(value) @property def id(self): return self._id.get() @id.setter def id(self, value): self._id.set(value) @abstractproperty def name(self): pass @abstractmethod def run(self): pass
def test_invalid_value_domain(self): false = 0 if self.root.wantobjects() else "0" v = BooleanVar(self.root, name="name") with self.assertRaises(TclError): v.set("value") self.assertEqual(self.root.globalgetvar("name"), false) self.root.globalsetvar("name", "value") with self.assertRaises(ValueError): v.get() self.root.globalsetvar("name", "1.0") with self.assertRaises(ValueError): v.get()
def test_set(self): true = 1 if self.root.wantobjects() else "1" false = 0 if self.root.wantobjects() else "0" v = BooleanVar(self.root, name="name") v.set(True) self.assertEqual(self.root.globalgetvar("name"), true) v.set("0") self.assertEqual(self.root.globalgetvar("name"), false) v.set(42) self.assertEqual(self.root.globalgetvar("name"), true) v.set(0) self.assertEqual(self.root.globalgetvar("name"), false) v.set("on") self.assertEqual(self.root.globalgetvar("name"), true)
class Preferences(Frame): def __init__(self, client): # Basic setup super(Preferences, self).__init__() self.client = client # Setup the variables used self.echo_input = BooleanVar() self.echo_input.set(self.client.config['UI'].getboolean('echo_input')) self.echo_input.trace("w", self.echo_handler) self.logging = BooleanVar() self.logging.set(self.client.config['logging'].getboolean('log_session')) self.logging.trace('w', self.logging_handler) self.log_dir = self.client.config['logging']['log_directory'] # Build the actual window and widgets prefs = Toplevel(self) prefs.wm_title("Preferences") echo_input_label = Label(prefs, text="Echo Input:") logging_label = Label(prefs, text='Log to file:') echo_checkbox = Checkbutton(prefs, variable=self.echo_input) logging_checkbox = Checkbutton(prefs, variable=self.logging) logging_button_text = 'Choose file...' if self.log_dir == "" else self.log_dir logging_button = Button(prefs, text=logging_button_text, command=self.logging_pick_location) # Pack 'em in. echo_input_label.grid(row=0, column=0) echo_checkbox.grid(row=0, column=1) logging_label.grid(row=1, column=0) logging_checkbox.grid(row=1, column=1) logging_button.grid(row=1, column=2) def logging_pick_location(self): location = askdirectory(initialdir="%UserProfile%\Documents\\") self.client.config['logging']['log_directory'] = location self.write_config() def echo_handler(self, arg1, arg2, mode): pprint(self.echo_input.get()) self.client.config['UI']['echo_input'] = 'yes' if self.echo_input.get() else 'no' self.write_config() def logging_handler(self, arg1, arg2, mode): self.client.config['logging']['log_session'] = 'yes' if self.logging.get else 'no' self.write_config() def write_config(self, file='config.ini'): self.client.config.write(open(file, 'w'))
class Plastey(Tk): #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # def __init__(self, *args, **kwargs): Tk.__init__(self, *args, **kwargs) # Set window title self.wm_title('Plastey Configurator') # Create GUI driven variables self._mode = BooleanVar() self._base = BooleanVar() self._comm = BooleanVar() self._pass = StringVar() self._addressed = StringVar() self._connected = StringVar() self._this_host = StringVar() self._this_port = StringVar() self._other_host = StringVar() self._other_port = StringVar() # Create GUI self._build_gui() # Set default values for GUI driven variables self._mode.set(MODE_SINGLE_PLAYER) self._base.set(BASE_OPENED_GEOMETRY) self._comm.set(COMM_SOCKET_SERVER) self._pass.set('') self._addressed.set( ADDR_HAVE_ADDRESS if check(COMM_THIS_HOST) else ADDR_NO_ADDRESS) self._connected.set(CONN_NOT_CONNECTED) self._this_host.set(COMM_THIS_HOST) self._this_port.set(COMM_THIS_PORT) self._other_host.set(COMM_THIS_HOST) self._other_port.set(COMM_OTHER_PORT) # Follow changes on password self._pass.trace('w', self._on_bind_address) # Create folder structures if they don't exists yet makedirs(FILE_TEMPORARY_FOLDER, exist_ok=True) makedirs(FILE_PERMANENT_FOLDER, exist_ok=True) makedirs(FILE_TEMP_SAVE_FOLDER, exist_ok=True) makedirs(FILE_AUTO_SAVE_FOLDER, exist_ok=True) #makedirs(FILE_TEMP_STATE_FOLDER, exist_ok=True) #makedirs(FILE_TEMP_FEEDS_FOLDER, exist_ok=True) #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # def _build_gui(self): # Create GUI sections row = 0 col = 0 # Warning text Label(master=self, text=WARN_TEXT, anchor=WEST, justify=CENTER).grid(row=row, column=col, sticky=NORTH_WEST, rowspan=16) # Set column spacing self.columnconfigure(index=col, pad=GUI_SECTION_PAD_X) row = 0 col += 1 # Game mode options Label(master=self, text='Game Mode:').grid(row=row, column=col, sticky=WEST) row += 1 Radiobutton(master=self, text='Single Player', value=MODE_SINGLE_PLAYER, variable=self._mode).grid(row=row, column=col, sticky=WEST) row += 1 Radiobutton(master=self, text='Multi Player', value=MODE_MULTI_PLAYER, variable=self._mode).grid(row=row, column=col, sticky=WEST) row += 1 # Base object modes Label(master=self, text='Base Object:').grid(row=row, column=col, sticky=WEST) row += 1 Radiobutton(master=self, text='Plane mesh', value=BASE_OPENED_GEOMETRY, variable=self._base).grid(row=row, column=col, sticky=WEST) row += 1 Radiobutton(master=self, text='Sphere mesh', value=BASE_CLOSED_GEOMETRY, variable=self._base).grid(row=row, column=col, sticky=WEST) row += 1 # Start oculus-daemon Label(master=self, text='Daemons:').grid(row=row, column=col, sticky=WEST) row += 1 Button(master=self, text='Start OVRD', command=self._on_start_oculus_daemon).grid(row=row, column=col, sticky=WEST) # Set column spacing self.columnconfigure(index=col, pad=GUI_SECTION_PAD_X) row = 0 col += 1 # Multiplayer mode options Label(master=self, text='Multi Player Options:').grid(row=row, column=col, sticky=WEST, columnspan=2) row += 1 Label(master=self, text='This role:').grid(row=row, column=col, sticky=WEST) Radiobutton(master=self, text='Server', value=COMM_SOCKET_SERVER, variable=self._comm).grid(row=row, column=col + 1, sticky=WEST) row += 1 Radiobutton(master=self, text='Client', value=COMM_SOCKET_CLIENT, variable=self._comm).grid(row=row, column=col + 1, sticky=WEST) row += 1 Label(master=self, text='This host:').grid(row=row, column=col, sticky=WEST) Entry(master=self, textvariable=self._this_host).grid(row=row, column=col + 1, sticky=WEST) row += 1 Label(master=self, text='This port:').grid(row=row, column=col, sticky=WEST) Entry(master=self, textvariable=self._this_port).grid(row=row, column=col + 1, sticky=WEST) row += 1 Label(master=self, text='Other host:').grid(row=row, column=col, sticky=WEST) Entry(master=self, textvariable=self._other_host).grid(row=row, column=col + 1, sticky=WEST) row += 1 Label(master=self, text='Other port:').grid(row=row, column=col, sticky=WEST) Entry(master=self, textvariable=self._other_port).grid(row=row, column=col + 1, sticky=WEST) row += 1 Button(master=self, text='Bind address', command=self._on_ask_password).grid(row=row, column=col, sticky=WEST + EAST) Label(master=self, textvariable=self._addressed).grid(row=row, column=col + 1, sticky=WEST) row += 1 Button(master=self, text='Connect machines', command=self._on_bind_address).grid(row=row, column=col, sticky=WEST + EAST) Label(master=self, textvariable=self._connected).grid(row=row, column=col + 1, sticky=WEST) # Set column spacing self.columnconfigure(index=col + 1, pad=GUI_SECTION_PAD_X) row = 0 col += 2 # Controller buttons Label(master=self, text='Controllers:').grid(row=row, column=col, sticky=WEST) row += 1 Button(master=self, text='Start game', command=self._on_start_game).grid(row=row, column=col, sticky=WEST + EAST) row += 1 Button(master=self, text='Restart game', command=self._on_restart_game).grid(row=row, column=col, sticky=WEST + EAST) row += 1 Button(master=self, text='Stop game', command=self._on_stop_game).grid(row=row, column=col, sticky=WEST + EAST) row += 1 Button(master=self, text='Save last mesh', command=self._on_save_mesh).grid(row=row, column=col, sticky=WEST + EAST) row += 1 Button(master=self, text='Load last mesh', command=self._on_load_mesh).grid(row=row, column=col, sticky=WEST + EAST) row += 1 Button(master=self, text='Save log file', command=self._on_save_log).grid(row=row, column=col, sticky=WEST + EAST) row += 1 #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # def _on_ask_password(self, *args, **kwargs): # Create a password-dialog self._dialog = Password(self._pass) #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # def _on_start_oculus_daemon(self, *args, **kwargs): print('starting daemon...') #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # def _on_bind_address(self, *args, **kwargs): # Check for status and if address is not bound if not check(COMM_THIS_HOST): # Bind address try: setup(self._this_host, user_pass=self._pass.get()) except CommunicationSetupError as exception: Report(exception.error) # Check status and report to user self._addressed.set(ADDR_HAVE_ADDRESS if check(COMM_THIS_HOST) else ADDR_NO_ADDRESS) #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # def _on_connect(self, *args, **kwargs): pass #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # def _on_start_game(self, *args, **kwargs): # HACK: Is this really the best option we have, to get into fullscreen, # other than using the blender's fullscreen option, which will # unfortunately resize the display's resolution??? :( window_command = ['sleep 1'] window_command.append('wmctrl -r :ACTIVE: ' '-e 0,{},{},{},{}'.format( DRAW_DISPLAY_X, DRAW_DISPLAY_Y, DRAW_RESOLUTION_X, DRAW_RESOLUTION_Y)) if DRAW_FULL_SCREEN: window_command.append('wmctrl -r :ACTIVE: -b add,fullscreen') Popen(args=' && '.join(window_command), shell=True, stdin=PIPE, stderr=PIPE, universal_newlines=True) # Store subprocess, for further communication self._pipe = Popen(args='./plastey', stdin=PIPE, stdout=PIPE, stderr=PIPE, universal_newlines=True) #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # def _on_restart_game(self, *args, **kwargs): self._pipe.stdin.write('hello-world\n') #if not self._locked: # self._locked = True # with open(FILE_STATE_RESTART, mode='w') as file: # file.write('') # Thread(name = 'feedbackd-restart', # target = self._get_feedback_to_clean_up).start() #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # def _on_stop_game(self, *args, **kwargs): #if not self._locked: # self._locked = True # with open(FILE_STATE_SHUT_DOWN, mode='w') as file: # file.write('') # Thread(name = 'feedbackd-shutdown', # target = self._get_feedback_to_clean_up).start() self._pipe.communicate('hello-world\n') #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # def _on_save_mesh(self, *args, **kwargs): pass #if self._pipe.poll(): # print('saving inside game') #else: # print('save last auto-saved') #print('parent says: hey there, daemon!\n') #self._pipe.stdin.write('hey there, daemon!\n') #self._pipe.stdin.close() #try: # self._pipe.communicate('hey there, daemon!\n', timeout=0.1) ## Hack: since communicate waits for the subprocess to terminate, the ## timeout value is necessary, however, after the timeout, the app ## won't terminate either. One solution should be ## self._pipe.stdin.write instead of the communicate method, but ## unfortunately the process's stdin.read/input are not getting ## anything.. is it because the value set to shell=True? #except TimeoutExpired: # return #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # def _on_load_mesh(self, *args, **kwargs): pass #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # def _on_save_log(self, *args, **kwargs): pass #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # def run(self): self.mainloop()
def overwriteWindow(root): '''Creates the window for deciding to overwrite or not.''' def toggle(*args): setState(choice.get(), 'disabled', [gen2Label, gen3Label, gen2Button, gen3Button, gen2Entry, gen3Entry]) setState(not choice.get(), 'disabled', [warningLabel]) if not choice.get() and (gen2Text.get() == '' or gen3Text.get() == ''): navFrame.disable('next', True) else: navFrame.disable('next', False) def gen2Dialog(): askSave = filedialog.asksaveasfilename file = askSave(title='Gen II Save File', initialdir=root.dir, filetypes=[('GB Save', '.sav'), ('All Files', '.*')], defaultextension='.sav') if file != '': gen2Text.set(file) gen2Entry.after_idle(gen2Entry.xview_moveto, 1) root.dir = getDir(file) def gen3Dialog(): askSave = filedialog.asksaveasfilename file = askSave(title='Gen III Save File', initialdir=root.dir, filetypes=[('GBA Save', '.sav'), ('All Files', '.*')], defaultextension='.sav') if file != '': gen3Text.set(file) gen3Entry.after_idle(gen3Entry.xview_moveto, 1) root.dir = getDir(file) def nextPage(): global newGen2, newGen3, oldGen2, oldGen3 if choice.get(): newGen2 = oldGen2 newGen3 = oldGen3 else: newGen2 = gen2Entry.get() newGen3 = gen3Entry.get() root.nextPage() baseFrame = ttk.Frame(root) baseFrame.rowconfigure(0, weight=1) baseFrame.columnconfigure(0, weight=1) mainFrame = ttk.Frame(baseFrame, padding=MAIN_PAD) mainFrame.grid(row=0, column=0, sticky='ns') mainFrame.rowconfigure(0, weight=2) mainFrame.rowconfigure(3, weight=1) instrText = 'Select whether to overwrite the original save files, or to create new save files.' instrLabel = ttk.Label(mainFrame, text=instrText) instrLabel.grid(row=0, column=0) choiceFrame = ttk.Frame(mainFrame) choiceFrame.grid(row=1, column=0) choice = BooleanVar(value=True) choice1Radio = ttk.Radiobutton(choiceFrame, text='Overwrite', variable=choice, command=toggle, value=True) choice1Radio.grid(row=0, column=0, pady=5, sticky='w') warningText = 'WARNING! Once new data is created, this program can not recover old save data.' warningLabel = ttk.Label(choiceFrame, text=warningText, wraplength=300) warningLabel.grid(row=1, column=0, pady=5) choice2Radio = ttk.Radiobutton(choiceFrame, text='Do not overwrite', variable=choice, command=toggle, value=False) choice2Radio.grid(row=2, column=0, pady=5, sticky='w') pickerFrame = ttk.Frame(mainFrame) pickerFrame.grid(row=2, column=0) gen2Label = ttk.Label(pickerFrame, text='New Gen II file:') gen2Label.grid(row=0, column=0, columnspan=2) gen2Button = ttk.Button(pickerFrame, text='To...', command=gen2Dialog) gen2Button.grid(row=1, column=0, sticky='e', padx=5, pady=5) gen2Text = StringVar(pickerFrame) gen2Text.trace('w', toggle) gen2Entry = ttk.Entry(pickerFrame, textvariable=gen2Text, state='readonly') gen2Entry.grid(row=1, column=1, sticky='w', padx=5, pady=5) gen3Label = ttk.Label(pickerFrame, text='New Gen III file:') gen3Label.grid(row=2, column=0, columnspan=2) gen3Button = ttk.Button(pickerFrame, text='To...', command=gen3Dialog) gen3Button.grid(row=3, column=0, sticky='e', padx=5, pady=5) gen3Text = StringVar(pickerFrame) gen3Text.trace('w', toggle) gen3Entry = ttk.Entry(pickerFrame, textvariable=gen3Text, state='readonly') gen3Entry.grid(row=3, column=1, sticky='w', padx=5, pady=5) #todo: make sure user doesn't put the same file for both entries fillerFrame = ttk.Frame(mainFrame) fillerFrame.grid(row=3, column=0, sticky='ns') navFrame = Nav(baseFrame, root.prevPage, nextPage) navFrame.grid(row=1, column=0, sticky='we') if debug: gen2Text.set('C:/Users/Sidnoea/Documents/GitHub/pokeBridge/New Gen 2.sav') gen3Text.set('C:/Users/Sidnoea/Documents/GitHub/pokeBridge/New Gen 3.sav') choice.set(False) toggle() return (baseFrame, 'Overwrite?', {'sticky':'nsew'})
class PortSelector(Frame): def __init__(self, root, parent): settings = parent.settings('port_selector') Frame.__init__(self, root, borderwidth=2, relief="groove", height=10) self.parent = parent self.autoconnect = BooleanVar() self.autoconnect.set(settings['autoconnect']) self.debug = BooleanVar() self.debug.set(settings['debug']) self.selected_port = StringVar(name='selected_port') port_select_label = Label(self, text="Port:", anchor="e", width=10) port_select_label.grid(row=0, column=0) self.port_select = ttk.Combobox(self, state="readonly", textvariable=self.selected_port, postcommand=self.update_portlist) self.update_portlist(settings['port']) self.port_select.bind('<<ComboboxSelected>>', self.port_changed) self.port_select.grid(row=0, column=1) self.port_connect = Button(self, text="Connect", command=self.connect, width=12) self.port_connect.grid(row=0, column=2) self.port_autoconnect = Checkbutton(self, variable=self.autoconnect, command=self.port_changed, text="Autoconnect") self.port_autoconnect.grid(row=1, column=1, columnspan=3, sticky="W") # self.port_debug = Checkbutton(self, variable=self.debug, command=self.port_changed,text="Debug") # self.port_debug.grid(row=1,column=2,columnspan=3,sticky="W") # self.port_descriptor_label = Label(self,text=" Desc:",anchor="e",width=10) # self.port_descriptor_label.grid(row=2,column=0) # self.port_descriptor = Label(self, text="-",justify="left") # self.port_descriptor.grid(row=2,column=1,columnspan=3,sticky="W") # linfo = Label(self,text='Info:',anchor="e",width=10) # linfo.grid(row=3,column=0,sticky="N") # self.info = Label(self,text='-',anchor="w",justify='left') # self.info.grid(row=3,column=1,columnspan=3,sticky="W") self.grid_columnconfigure(0, minsize=10) self.grid_columnconfigure(1, weight=1) self.grid_columnconfigure(2, pad=10) self.grid_rowconfigure(0, pad=10) def __call__(self): return { 'port': self.port_select.get(), 'autoconnect': self.autoconnect.get(), 'debug': self.debug.get() } def update_portlist(self, port=None): self.ports = [] ports = [] if sys.platform.startswith('win'): for p in list_ports.comports(): self.ports.append(p) ports.append(p.device) self.port_select['values'] = ports if port is None: return if port in ports: self.port_select.set(port) def port_changed(self, e=None): self.parent.settings('port_selector', self()) def connect(self): if self.parent.console.connect(self.port_select.get()): self.connected() else: self.parent.console.disconnect() self.disconnected() def connected(self): self.port_connect['text'] = 'Disconnect' self.port_select['state'] = 'disabled' def disconnected(self): self.port_connect['text'] = 'Connect' self.port_select['state'] = 'readonly'
class RulesInput(): """ Class to manage gui and logic for entry fields of rules in Parameters frame """ def __init__(self, parent_class): """ Initialize parent_frame to the provided class to hold self.frame self.frame contains all the elements self.entries is a list of dynamically generated entries """ self.parent_class = parent_class # frame in parent Parameters class self.frame = Frame(parent_class.frame) self.preview_canvas = None # canvas to preview curve self.entries = [] # list of dictionaries, each dictionary # contains the keys for frame, and its children self.add_button = None self.sub_button = None self.radio_angle_var = BooleanVar( self.frame) # initially set to radians self.radio_angle_var.set(True) self.init_preview_canvas() self.init_info_labels() self.init_add_entry_button() self.init_sub_entry_button() # self.init_extract_rules_button() self.frame.grid(row=7, column=0, columnspan=3, sticky='nw', pady=10) def create_entry_dictionary(self): """ Creates and returns a dictionary which contains references to a frame and entries in it keys: ["frame", "ent_len", "ent_angle", "chk_is_flip", "chk_is_rev", "flip_state","reverse_state"] """ vcmd = (self.frame.register(self.validate_float), '%P') entry_frame = Frame(self.frame) ent_length = Entry(entry_frame, validate='key', width=8, validatecommand=vcmd) ent_angle = Entry(entry_frame, validate='key', width=8, validatecommand=vcmd) is_reversed_state = BooleanVar(entry_frame) is_flipped_state = BooleanVar(entry_frame) chkbtn_is_reversed = Checkbutton(entry_frame, text='reverse', var=is_reversed_state) chkbtn_is_flipped = Checkbutton(entry_frame, text='flip', var=is_flipped_state) ent_angle.pack(side=LEFT) ent_length.pack(side=LEFT) chkbtn_is_flipped.pack(side=LEFT) chkbtn_is_reversed.pack(side=LEFT) entry_frame.grid(row=len(self.entries) + 3, columnspan=4) entry_dict = { "frame": entry_frame, "ent_len": ent_length, "ent_angle": ent_angle, "chk_is_flip": chkbtn_is_flipped, "chk_is_rev": chkbtn_is_reversed, "flip_state": is_flipped_state, "reverse_state": is_reversed_state } return entry_dict def init_add_entry_button(self): """ Initialize the button which adds frames for entry of each rule """ def add_entry(): """ create a new entry and add to self.entries """ new_entry = self.create_entry_dictionary() self.entries.append(new_entry) self.render_preview() self.add_button = Button(self.frame, text='+', command=add_entry) self.add_button.grid(row=1, column=2) def init_sub_entry_button(self): """ Initialize the button to remove entry fields """ def sub_entry(): """ Pop and destroy the last entry from self.entries """ if self.entries != []: self.entries.pop()["frame"].destroy() self.render_preview() self.sub_button = Button(self.frame, text='-', command=sub_entry) self.sub_button.grid(row=1, column=3) def validate_float(self, p_str): """ Validate if input is a valid floating point number """ # may validate only '[+-].' which needs to be handled later float_pattern = r"^[\+\-]?([0-9]*[.])?[0-9]*$" if re.search(float_pattern, p_str) or p_str == "": return True return False def extract_rules(self): """ Extract rules from the input fields to a list """ def get_float_value(entry_string): """ Get the float value out of entry strings (function to handle corner cases) """ if entry_string in ['', '.', '+.', '-.', '+', '-']: return 0.0 return float(entry_string) extracted_rules = [] for entry in self.entries: if self.radio_angle_var.get( ): # if true, means radians, extract as is ent_angle = get_float_value(entry["ent_angle"].get()) else: ent_angle = get_float_value(entry["ent_angle"].get( )) * RAD_FAC # convert degree to radians ent_angle = ent_angle % (2 * PI) ent_len = get_float_value(entry["ent_len"].get()) is_reversed = entry["reverse_state"].get() is_flipped = entry["flip_state"].get() if ent_angle or ent_len: # user entered something, otherwise nothing changed extracted_rules.append( (ent_angle, ent_len, is_flipped, is_reversed)) return extracted_rules def fill_entries_from_rules(self, rules): """ Fill in the entries in GUI for user feedback """ for rule in rules: angle, length, is_flipped, is_reversed = rule new_entry = self.create_entry_dictionary() # clear and insert angle new_entry['ent_angle'].delete(0, END) if self.radio_angle_var.get(): # if angle in radians new_entry['ent_angle'].insert(0, str(angle)) else: new_entry['ent_angle'].insert(0, str(angle * DEG_FAC)) # clear and insert length new_entry['ent_len'].delete(0, END) new_entry['ent_len'].insert(0, str(length)) # set booleans new_entry['reverse_state'].set(is_reversed) new_entry['flip_state'].set(is_flipped) self.entries.append(new_entry) # def init_extract_rules_button(self): # """ # Test button to check extracted rules # """ # def print_extracted(): # """ # Print the extracted rules to stdout # """ # print("Extracted:") # print(self.extract_rules()) # # self.test_button = Button( # self.frame, text="extract", command=print_extracted) # self.test_button.pack() def init_preview_canvas(self): """ Canvas to draw the base curve from rules and give preview to the user """ self.preview_canvas = Canvas(self.frame, width=200, height=200) self.preview_canvas.grid(row=0, columnspan=4, sticky=W) def form_base_curve(self, rules): """ Form the base curve from extracted rules for previewing Resized to fit into the preview canvas """ curve = [(0, 0)] for theta, scale_fac, _, _ in rules: last_x, last_y = curve[-1] curve.append((last_x + scale_fac * cos(theta), last_y + scale_fac * sin(theta))) min_x = min(point[0] for point in curve) min_y = min(point[1] for point in curve) scale_y = max(point[1] - min_y for point in curve) scale_x = max(point[0] - min_x for point in curve) if scale_x == 0 or scale_y == 0: return curve canvas_width = self.preview_canvas.winfo_width() canvas_height = self.preview_canvas.winfo_height() to_scale = min(canvas_width / scale_x, canvas_height / scale_y) * 0.8 curve = [((point[0] - min_x) * to_scale + canvas_width / 10, (point[1] - min_y) * to_scale + canvas_height / 10) for point in curve] return curve def render_preview(self): """ Render the preview on canvas on calling the function Desired to be called by some update function """ # Not the best way to do it but the curve size is of constant # order, <20 segments, so it wouldnt create much difference extracted_rules = self.extract_rules() self.set_rules_in_curve(extracted_rules) # set the rules in the parent curve dynamically curve = self.form_base_curve(extracted_rules) self.preview_canvas.delete("all") if len(curve) > 1: # draw only if there are more than one points self.preview_canvas.create_line(curve, arrow=LAST) def init_info_labels(self): """ Initialize the labels providing info about input fields """ Radiobutton(self.frame, variable=self.radio_angle_var, value=False, text="Degrees").grid(row=1, column=0) Radiobutton(self.frame, variable=self.radio_angle_var, value=True, text="Radians").grid(row=1, column=1) Label(self.frame, text="Angle").grid(row=2, column=0, sticky=W) Label(self.frame, text="Length").grid(row=2, column=1, sticky=W) def set_rules_in_curve(self, rules): """ Set the rules entries received into the rules of Curve class """ self.parent_class.parent_class.classes["fractal"].set_rules(rules)
class Checkbox(object): """ A utility class to represent a custom checkbox with helper methods. Parameters ---------- text : `str` The text label for the checkbox. cfg : `dict` A dictionary representing of widgets with `key` being the key in the cfg for this widget. key : `str` The key for this widget in `cfg`. Attributes ---------- checkbox : `Checkbox` A tk checkbox widget. enabled : `bool` Boolean indicating if this widget is enabled. value : `BooleanVar` The tk variable linked to the checkbox. text : `str` The text label for the checkbox cfg : `dict` A dictionary representing of widgets with `key` being the key in the cfg for this widget. key : `str` The key for this widget in `cfg`. Methods ------- body Place the required elements using the grid layout method. Returns the number of rows taken by this element. validate Validate the checkbox selection. Returns True, always. apply If enabled, sets the configuration for `key` as the current checkbox selection. enable Enables the checkbox widget from interaction. disable Disables the checkbox widget from interaction. """ def __init__(self, text, cfg, key): self.checkbox = None self.enabled = True self.value = BooleanVar() self.text = text self.cfg = cfg self.key = key try: if self.cfg[self.key] not in (True, False): self.value.set(False) else: self.value.set(self.cfg[self.key]) except KeyError: self.value.set(False) # default to False def body(self, master, row, columns=DEFAULT_COLUMNS, **kwargs): """ Place the required elements using the grid layout method. Returns the number of rows taken by this element. Parameters ---------- master : A tk widget or window. row : `int` The row variable to use during packing/grid columns : `int` The columnspan to use during packing/grid kwargs : `dict` Keyword arguements to pass to packing/grid. Currently ignored. Returns ------- `int` Returns the number of rows taken by this element. """ self.checkbox = Checkbutton(master, text=self.text, variable=self.value) self.checkbox.grid(row=row, column=0, columnspan=columns, sticky="w") return 1 def validate(self): """ Validate the checkbox selection. """ return True def apply(self): """ If enabled, sets the configuration for `key` as the current checkbox selection. """ if self.enabled: self.cfg[self.key] = self.value.get() else: self.cfg[self.key] = None def enable(self): """ Set the state of the checkbox widget to not disabled. """ self.enabled = True self.checkbox.state(["!disabled"]) def disable(self): """ Set the state of the checkbox widget to disabled. """ self.enabled = False self.checkbox.state(["disabled"])
class FrameSpreadsheetDataset(FrameCustomFileDataset): """ Holds an instance of, and visually represents, a spreadsheet dataset. See qal.dataset.spreadsheet.SpreadsheetDataset """ def __init__(self, _master, _dataset=None, _relief=None, _is_destination=None): super(FrameSpreadsheetDataset, self).__init__(_master, _dataset, _relief, _is_destination=_is_destination) if _dataset is None: self.dataset = SpreadsheetDataset() def on_select(self): """Brings up a selector dialog, prompting the user to select a file, the relative path if the file is then saved to the filename property. Also, the base path is set. """ self.select_file(_default_extension=".xlsx", _file_types=[('.xlsx files', '.xlsx'), ('all files', '.*')]) def init_widgets(self): # file selector self.btn_file_select = Button(self, text="Select file", command=self.on_select) self.btn_file_select.grid(column=0, row=0, columnspan=2) # filename self.filename, self.e_filename, self.l_filename = make_entry(self, "File name: ", 1) # delimiter self.delimiter, self.e_delimiter, self.l_delimiter = make_entry(self, "Delimiter: ", 2) # has_header self.l_has_header = ttk.Label(self, text="Has header: ") self.l_has_header.grid(column=0, row=3, sticky=W) self.has_header = BooleanVar() self.e_has_header = ttk.Checkbutton(self, variable=self.has_header) self.e_has_header.grid(column=1, row=3, sticky=W) # sheet_name self.sheet_name, self.e_sheet_name, self.l_sheet_name = make_entry(self, "Sheet name: ", 4) # x_offset self.x_offset, self.e_x_offset, self.l_x_offset = make_entry(self, "X offset: ", 5) # y_offset self.y_offset, self.e_y_offset, self.l_y_offset = make_entry(self, "Y offset: ", 6) def read_from_dataset(self): super(FrameSpreadsheetDataset, self).read_from_dataset() self.filename.set(empty_when_none(self.dataset.filename)) self.has_header.set(bool_to_binary_int(self.dataset.has_header)) self.sheet_name.set(empty_when_none(self.dataset.sheet_name)) self.x_offset.set(empty_when_none(self.dataset.x_offset)) self.y_offset.set(empty_when_none(self.dataset.y_offset)) def write_to_dataset(self): super(FrameSpreadsheetDataset, self).write_to_dataset() if self.dataset is None: self.dataset = SpreadsheetDataset() self.dataset.filename = self.filename.get() self.dataset.delimiter = self.delimiter.get() self.dataset.has_header = binary_int_to_bool(self.has_header.get()) self.dataset.sheet_name = self.sheet_name.get() if self.x_offset.get() == "": self.dataset.x_offset = None else: self.dataset.x_offset = int(self.x_offset.get()) if self.y_offset.get() == "": self.dataset.y_offset = None else: self.dataset.y_offset = int(self.y_offset.get()) def reload(self): self.notify_task("Load spreadsheet " + self.dataset.filename, 10) self.dataset.load() self.notify_task("Loaded spreadsheet " + self.dataset.filename + ".", 100) def get_possible_references(self, _force=None): if not self.dataset.field_names or _force == True: self.reload() self.references = self.dataset.field_names return self.dataset.field_names
class CopyToMoveTo: """ Minimalist file manager intended to be used independently or alongside Windows Explorer """ def __init__(self, root): """ Setup window geometry, init settings, define widgets + layout """ self.master = root self.master.title("CopyTo-MoveTo") self.master.iconbitmap(f"{dirname(__file__)}/icon.ico") if system() != "Windows": self.master.withdraw() messagebox.showwarning( "Incompatible platform", "CopyTo-MoveTo currently supports Windows platforms only.") raise SystemExit #Settings: self.settings_show_hidden = BooleanVar() self.settings_include_files = BooleanVar(value=True) self.settings_ask_overwrite = BooleanVar() self.settings_ask_overwrite.trace("w", self.settings_exclusives) self.settings_rename_dupes = BooleanVar(value=True) self.settings_rename_dupes.trace("w", self.settings_exclusives) self.settings_multiselect = BooleanVar(value=True) self.settings_select_dirs = BooleanVar(value=True) self.settings_select_dirs.trace("w", self.settings_mutuals) self.settings_select_files = BooleanVar(value=True) self.settings_select_files.trace("w", self.settings_mutuals) self.settings_geometry = None self.appdata_dir = getenv("APPDATA") + "/CopyTo-MoveTo" self.appdata_path = self.appdata_dir + "/settings.json" self.settings = self.init_settings() if self.settings: self.settings_geometry = self.settings["geometry"] self.settings_show_hidden.set(self.settings["show_hidden"]) self.settings_include_files.set(self.settings["include_files"]) self.settings_ask_overwrite.set(self.settings["ask_overwrite"]) self.settings_rename_dupes.set(self.settings["rename_dupes"]) self.settings_multiselect.set(self.settings["multiselect"]) self.settings_select_dirs.set(self.settings["select_dirs"]) self.settings_select_files.set(self.settings["select_files"]) self.dialog_showing = BooleanVar() self.help_showing = BooleanVar() self.about_showing = BooleanVar() self.master.protocol("WM_DELETE_WINDOW", self.master_close) self.master.bind("<Control-w>", self.master_close) #Geometry: self.master.minsize(width=450, height=200) if self.settings_geometry: self.master.geometry(self.settings_geometry) self.master.update() else: self.master.geometry("600x400") self.master.update_idletasks() (width_offset, height_offset) = Ufd.get_offset(self.master) self.master.geometry(f"+{width_offset}+{height_offset}") self.master.update_idletasks() # Menu: self.main_menu = Menu(self.master) self.master.config(menu=self.main_menu) self.file_menu = Menu(self.main_menu, tearoff=0) self.settings_menu = Menu(self.main_menu, tearoff=0) self.main_menu.add_cascade(label="File", menu=self.file_menu) self.main_menu.add_cascade(label="Settings", menu=self.settings_menu) self.file_menu.add_command(label="Open Source(s)", accelerator="Ctrl+O", command=lambda: self.show_ufd(source=True)) self.master.bind("<Control-o>", lambda event: self.show_ufd(source=True)) self.file_menu.add_command(label="Open Destination(s)", accelerator="Ctrl+K+O", command=lambda: self.show_ufd(source=False)) self.master.bind("<Control-k>o", lambda event: self.show_ufd(source=False)) self.file_menu.add_separator() self.file_menu.add_command(label="Help / Commands", command=self.show_help) self.file_menu.add_command(label="About", command=self.show_about) #Settings menu: self.settings_menu.add_checkbutton(label="Show Hidden Files & Folders", variable=self.settings_show_hidden, onvalue=True, offvalue=False) self.settings_menu.add_checkbutton( label="Include Files in Tree", variable=self.settings_include_files, onvalue=True, offvalue=False) self.settings_menu.add_separator() self.settings_menu.add_checkbutton( label="Ask Overwrite", variable=self.settings_ask_overwrite, onvalue=True, offvalue=False) self.settings_menu.add_checkbutton(label="Rename Duplicates", variable=self.settings_rename_dupes, onvalue=True, offvalue=False) self.settings_menu.add_separator() self.settings_menu.add_checkbutton(label="Multiselect", variable=self.settings_multiselect, onvalue=True, offvalue=False) self.settings_menu.add_checkbutton(label="Select Folders", variable=self.settings_select_dirs, onvalue=True, offvalue=False) self.settings_menu.add_checkbutton(label="Select Files", variable=self.settings_select_files, onvalue=True, offvalue=False) self.main_menu.add_separator() #Menu commands: self.main_menu.add_command(label="Swap Selected", command=self.swap_selected) self.master.bind("<Control-s>", lambda event: self.swap_selected()) self.main_menu.add_command(label="Clear Selected", command=self.clear_selected) self.master.bind("<Control-x>", lambda event: self.clear_selected()) self.main_menu.add_command(label="Clear All", command=self.clear_all) self.master.bind("<Control-Shift-X>", lambda event: self.clear_all()) self.main_menu.add_separator() self.main_menu.add_command(label="COPY", command=lambda: self._submit(copy=True)) self.master.bind("<Control-Shift-Return>", lambda event: self._submit(copy=True)) self.main_menu.add_command(label="MOVE", command=lambda: self._submit(copy=False)) self.master.bind("<Control-Return>", lambda event: self._submit(copy=False)) # Body: self.paneview = PanedWindow(self.master, sashwidth=7, bg="#cccccc", bd=0, orient="vertical") self.top_pane = PanedWindow(self.paneview) self.bottom_pane = PanedWindow(self.paneview) self.paneview.add(self.top_pane) self.paneview.add(self.bottom_pane) self.label_source = Label(self.top_pane, text="Source(s):") self.label_dest = Label(self.bottom_pane, text="Destination(s):") self.y_scrollbar_source = Scrollbar(self.top_pane, orient="vertical") self.x_scrollbar_source = Scrollbar(self.top_pane, orient="horizontal") self.y_scrollbar_dest = Scrollbar(self.bottom_pane, orient="vertical") self.x_scrollbar_dest = Scrollbar(self.bottom_pane, orient="horizontal") self.list_box_source = Listbox( self.top_pane, selectmode="extended", yscrollcommand=self.y_scrollbar_source.set, xscrollcommand=self.x_scrollbar_source.set) self.list_box_dest = Listbox(self.bottom_pane, selectmode="extended", yscrollcommand=self.y_scrollbar_dest.set, xscrollcommand=self.x_scrollbar_dest.set) self.x_scrollbar_source.config(command=self.list_box_source.xview) self.y_scrollbar_source.config(command=self.list_box_source.yview) self.x_scrollbar_dest.config(command=self.list_box_dest.xview) self.y_scrollbar_dest.config(command=self.list_box_dest.yview) # Layout: self.master.rowconfigure(0, weight=1) self.master.columnconfigure(0, weight=1) self.top_pane.rowconfigure(1, weight=1) self.top_pane.columnconfigure(0, weight=1) self.bottom_pane.rowconfigure(1, weight=1) self.bottom_pane.columnconfigure(0, weight=1) self.paneview.paneconfigure(self.top_pane, minsize=100) self.paneview.paneconfigure(self.bottom_pane, minsize=100) self.paneview.grid(row=0, column=0, sticky="nsew") self.label_source.grid(row=0, column=0, sticky="w") self.list_box_source.grid(row=1, column=0, sticky="nsew") self.y_scrollbar_source.grid(row=1, column=1, sticky="ns") self.x_scrollbar_source.grid(row=2, column=0, sticky="ew") self.label_dest.grid(row=0, column=0, sticky="w", columnspan=2) self.list_box_dest.grid(row=1, column=0, sticky="nsew") self.y_scrollbar_dest.grid(row=1, column=1, sticky="ns") self.x_scrollbar_dest.grid(row=2, column=0, sticky="ew") def __str__(self): """Return own address""" return f"CopyTo-MoveTo @ {hex(id(self))}" def init_settings(self): """Called on startup, loads, parses, and returns json settings.""" if exists(self.appdata_path): with open(self.appdata_path, "r") as settings_file: settings_json = settings_file.read() settings = loads(settings_json) return settings else: return None def settings_exclusives(self, *args): """ Callback assigned to settings that are mutually exclusive, to prevent logical/runtime errors or unexpected behavior. """ if args[0] == "PY_VAR2": if self.settings_ask_overwrite.get() == 1: self.settings_rename_dupes.set(0) return elif args[0] == "PY_VAR3": if self.settings_rename_dupes.get() == 1: self.settings_ask_overwrite.set(0) return def settings_mutuals(self, *args): """ Prevent select folders & select files from being disabled concurrently If both are unselected, reselect the one we didn't just deselect on. """ if self.settings_select_dirs.get() == 0 \ and self.settings_select_files.get() == 0: if args[0] == "PY_VAR5": self.settings_select_files.set(1) elif args[0] == "PY_VAR6": self.settings_select_dirs.set(1) def master_close(self, event=None): """ Similar to utils.toplevel_close(). writes settings to the disk as json. """ settings = { "geometry": self.master.geometry(), "show_hidden": self.settings_show_hidden.get(), "include_files": self.settings_include_files.get(), "ask_overwrite": self.settings_ask_overwrite.get(), "rename_dupes": self.settings_rename_dupes.get(), "multiselect": self.settings_multiselect.get(), "select_dirs": self.settings_select_dirs.get(), "select_files": self.settings_select_files.get(), } settings_json = dumps(settings) if not exists(self.appdata_dir): mkdir(self.appdata_dir) with open(self.appdata_path, "w+") as settings_file: settings_file.write(settings_json) if self.dialog_showing.get() == 1: self.ufd.cancel() self.master.destroy() def toplevel_close(self, dialog, boolean): """ This callback flips the value for a given toplevel_showing boolean to false, before disposing of the toplevel. """ boolean.set(0) dialog.destroy() def swap_selected(self): """Swap list entries between source & destination""" source_selection = list(self.list_box_source.curselection()) dest_selection = list(self.list_box_dest.curselection()) for i in reversed(source_selection): item = self.list_box_source.get(i) self.list_box_source.delete(i) self.list_box_dest.insert("0", item) for i in reversed(dest_selection): item = self.list_box_dest.get(i) self.list_box_dest.delete(i) self.list_box_source.insert("0", item) def clear_selected(self): """Removes selected (highlighted) item(s) from a given listbox""" source_selection = list(self.list_box_source.curselection()) dest_selection = list(self.list_box_dest.curselection()) if source_selection: for i in reversed(source_selection): self.list_box_source.delete(i) self.list_box_source.selection_set(source_selection[0]) if dest_selection: for i in reversed(dest_selection): self.list_box_dest.delete(i) self.list_box_dest.selection_set(dest_selection[0]) def clear_all(self): """Clears both listboxes in the main UI, resetting the form.""" self.list_box_source.delete(0, "end") self.list_box_dest.delete(0, "end") def handled(fn): """Filesystem operations are wrapped here for error handling""" @wraps(fn) def inner(self, *args, **kwargs): try: fn(self, *args, **kwargs) return True except (PermissionError, FileNotFoundError) as err: self.skipped_err.append(f"{err.args[1]}:\n" + (" => ".join(args))) return False return inner @handled def _copy(self, path, destination): """Wrapper for shutil.copy2() || shutil.copytree()""" if isfile(path): copy2(path, destination) else: copytree(path, destination) @handled def _move(self, path, destination): """Wrapper for shutil.move()""" move(path, destination) @handled def _delete(self, path): """Wrapper for os.remove() || shutil.rmtree()""" if isfile(path): remove(path) elif isdir(path): rmtree(path) def disabled_ui(fn): """Menubar is disabled during operations""" @wraps(fn) def inner(self, *args, **kwargs): self.main_menu.entryconfig("File", state="disabled") self.main_menu.entryconfig("Settings", state="disabled") self.main_menu.entryconfig("Clear Selected", state="disabled") self.main_menu.entryconfig("Clear All", state="disabled") self.main_menu.entryconfig("COPY", state="disabled") self.main_menu.entryconfig("MOVE", state="disabled") fn(self, *args, **kwargs) self.main_menu.entryconfig("File", state="normal") self.main_menu.entryconfig("Settings", state="normal") self.main_menu.entryconfig("Clear Selected", state="normal") self.main_menu.entryconfig("Clear All", state="normal") self.main_menu.entryconfig("COPY", state="normal") self.main_menu.entryconfig("MOVE", state="normal") return inner def _submit(self, copy): """Thread/wrapper for submit() so we don't block the UI during operations""" self.thread = Thread(target=self.submit, args=(copy, ), daemon=True) self.thread.start() @disabled_ui def submit(self, copy): """ Move or copy each item in the origin list to the path in the destination list. Supports no more than one destination directory where copy == False. Ask Overwrite and Rename Dupes will alter the way we handle existing data standing in the way. By default, duplicates are renamed with an index. A messagebox can complain to the user if shutil raises a PermissionError, and the operation is skipped. """ if (self.list_box_dest.size() > 1) and not copy: messagebox.showwarning( "Invalid Operation", "Move operation only supports a single destination directory.") return sources = self.list_box_source.get(0, "end") destinations = self.list_box_dest.get(0, "end") self.skipped_err = [] for j, destination in enumerate(destinations): if isfile(destination): self.skipped_err.append(f"Invalid destination: {destination}") continue for i, source in enumerate(sources): self.progress(i, j) (_, filename) = split(source) future_destination = join(destination + sep, filename) if exists(future_destination): if not self.settings_ask_overwrite.get() \ and not self.settings_rename_dupes.get(): if not self._delete(future_destination): continue if self.settings_ask_overwrite.get(): if self.ask_overwrite(future_destination): if not self._delete(future_destination): continue else: continue if self.settings_rename_dupes.get(): future_destination = self.name_dupe(future_destination) if copy: if not self._copy(source, future_destination): continue else: if not self._move(source, future_destination): continue self.list_box_source.delete(0, "end") self.list_box_dest.delete(0, "end") if self.skipped_err: messagebox.showerror(title="Error(s)", message="\n\n".join(self.skipped_err)) @staticmethod def name_dupe(path): """ Renames the file or directory until it doesn't exist in the destination with that name anymore, by appending the filename with an index wrapped in parenthesis. (Windows platforms) file.txt => file (1).txt => file (2).txt """ if system() != "Windows": raise OSError("For use with Windows filesystems.") path_ = path (root, filename) = split(path_) if isdir(path_): title = filename ext = None else: (title, ext) = splitext(filename) filecount = 0 while exists(path_): filecount += 1 new_title = title + " (" + str(filecount) + ")" if ext: new_title = new_title + ext path_ = join(root, new_title) return path_ def ask_overwrite(self, future_destination): """Messagebox result returned as truth value""" return messagebox.askyesno( title="Path Conflict", message=f"Overwrite:\n\n{future_destination}?\n\n" \ f"YES - Overwrite\nNO - Skip" ) def progress(self, i, j): """ Visualize operands in GUI during operations i = current source operand index j = current destination operand index """ for y, _ in enumerate(self.list_box_source.get(0, "end")): if y != i: self.list_box_source.itemconfigure(y, bg="#FFFFFF", fg="#000000") else: self.list_box_source.itemconfigure(y, bg="#cccccc", fg="#000000") for x, _ in enumerate(self.list_box_dest.get(0, "end")): if x != j: self.list_box_dest.itemconfigure(x, bg="#FFFFFF", fg="#000000") else: self.list_box_dest.itemconfigure(x, bg="#cccccc", fg="#000000") self.master.update() #Toplevels: def show_about(self): """ Displays a static dialog that doesn't allow additional instances of itself to be created while showing. """ if self.about_showing.get() == 0: self.about_showing.set(1) try: with open(f"{dirname(__file__)}/about.txt", "r") as aboutfile: about_info = aboutfile.read() except FileNotFoundError: messagebox.showerror("Error", "File not found") self.about_showing.set(0) return else: self.about = Toplevel() self.about.title("About") self.about.iconbitmap(f"{dirname(__file__)}/icon.ico") self.about.geometry("600x400") self.about.resizable(0, 0) self.about.update_idletasks() (width_offset, height_offset) = Ufd.get_offset(self.about) self.about.geometry(f"+{width_offset-75}+{height_offset-75}") self.about.update_idletasks() self.about_message = Label( self.about, text=about_info, justify="left", wraplength=(self.about.winfo_width() - 25)) self.about_message.grid(sticky="nsew") self.about.protocol( "WM_DELETE_WINDOW", lambda: self.toplevel_close( self.about, self.about_showing)) def show_help(self): """ Displays a scrollable dialog that doesn't allow additional instances of itself to be created while showing. """ if self.help_showing.get() == 0: self.help_showing.set(1) try: with open(f"{dirname(__file__)}/help.txt", "r") as helpfile: help_info = helpfile.read() except FileNotFoundError: messagebox.showerror("Error", "File not found") self.help_showing.set(0) return else: self.help_window = Toplevel() self.help_window.title("Help") self.help_window.iconbitmap(f"{dirname(__file__)}/icon.ico") self.help_window.geometry("500x300") self.help_window.update_idletasks() (width_offset, height_offset) = Ufd.get_offset(self.help_window) self.help_window.geometry( f"+{width_offset+75}+{height_offset-75}") self.help_window.update_idletasks() self.message_y_scrollbar = Scrollbar(self.help_window, orient="vertical") self.help_text = Text( self.help_window, wrap="word", yscrollcommand=self.message_y_scrollbar.set) self.help_window.rowconfigure(0, weight=1) self.help_window.columnconfigure(0, weight=1) self.help_text.grid(row=0, column=0, sticky="nsew") self.message_y_scrollbar.grid(row=0, column=1, sticky="nse") self.message_y_scrollbar.config(command=self.help_text.yview) self.help_text.insert("end", help_info) self.help_text.config(state="disabled") self.help_window.protocol( "WM_DELETE_WINDOW", lambda: self.toplevel_close( self.help_window, self.help_showing)) def show_ufd(self, source=True): """ Display Ufd w/ appropriate kwargs => Populate GUI w/ result""" if self.dialog_showing.get() == 0: self.dialog_showing.set(1) self.ufd = Ufd(title="Add Items", show_hidden=self.settings_show_hidden.get(), include_files=self.settings_include_files.get(), multiselect=self.settings_multiselect.get(), select_dirs=self.settings_select_dirs.get(), select_files=self.settings_select_files.get(), unix_delimiter=False, stdout=False) for result in self.ufd(): if source: self.list_box_source.insert("end", result) else: self.list_box_dest.insert("end", result) self.dialog_showing.set(0)
class Application: def __init__(self): self.root = Tk() self.root.title("docx-merge %s" % __version__) # Template document (.docx) frame = Frame(self.root) frame.pack(side="top", fill="x", padx=5, pady=5) label = Label(frame, text="Template document (.docx):", justify="left") label.pack(side="top", fill="x") self.template = Text(frame, height=1) self.template.pack(side="left", fill="x") Button(frame, text="Browse", command=self.on_browse_template).pack(side="right") # CSV data (.csv) frame = Frame(self.root) frame.pack(side="top", fill="x", padx=5, pady=5) label = Label(frame, text="CSV data (.csv):", justify="left") label.pack(side="top", fill="x") self.data = Text(frame, height=1) self.data.pack(side="left", fill="x") Button(frame, text="Browse", command=self.on_browse_data).pack(side="right") # Filename pattern frame = Frame(self.root) frame.pack(side="top", fill="x", padx=5, pady=5) label = Label(frame, text="Filename pattern:", justify="left") label.pack(side="top") self.pattern = Text(frame, height=1) self.pattern.pack(side="top", fill="x") # -- self.notification = StringVar() self.notification.set("") self.convert = BooleanVar() self.convert.set(False) frame = Frame(self.root) frame.pack(side="top", fill="x", padx=5, pady=5) Label(frame, textvariable=self.notification, justify="left").pack(side="left", fill="x") Button(frame, text="Process", command=self.on_process).pack(side="right", padx=5) Checkbutton( frame, text="Convert to PDF", variable=self.convert, onvalue=True, offvalue=False, ).pack(side="right") # Autofill self.pattern.insert("insert", "{{ARCHITECTE}}-{{FACTURE}}.docx") def run(self): self.root.mainloop() def notify(self, text=""): self.notification.set(text) def on_browse_template(self): filename = filedialog.LoadFileDialog(self.root, title="Browse").go( pattern="*.docx", dir_or_file=os.path.expanduser("~")) if not filename: return self.template.delete("0.1", "end") self.template.insert("insert", filename) self.notify() def on_browse_data(self): filename = filedialog.LoadFileDialog(self.root, title="Browse").go( pattern="*.csv", dir_or_file=os.path.expanduser("~")) if not filename: return self.data.delete("0.1", "end") self.data.insert("insert", filename) self.notify() def on_process(self): template = self.template.get("1.0", "end").strip() data = self.data.get("1.0", "end").strip() pattern = self.pattern.get("1.0", "end").strip() convert = self.convert.get() if not template or not data or not pattern: return try: path = merge(template, data, pattern, convert=convert) except Exception as e: self.notify("Error: %s" % str(e)) raise e self.notify("Done in %s" % path)
def run(self): root = Tk() icon_path = path.join(path.dirname(path.abspath(__file__)), "./logo.png") root.iconphoto(True, PhotoImage(file=icon_path)) root.title("Lukkkim/Bounty-RLBot") root.geometry("255x250") title = ttk.Label(root, text=f"{self.agent.name} framework by VirxERLU") title.pack() author = ttk.Label(root, text=f"Bounty by Lukim (Lukkkim/Bounty-RLBot") author.pack() # Disable driving drive_bool = BooleanVar() drive_bool.set(self.agent.disable_driving) def set_drive(): self.agent.disable_driving = drive_bool.get() drive_btn = ttk.Checkbutton(root, text='Disable driving', variable=drive_bool, command=set_drive) drive_btn.pack() # Debugging debug_bool = BooleanVar() debug_bool.set(self.agent.debugging) def set_debug(): self.agent.debugging = debug_bool.get() debug_btn = ttk.Checkbutton(root, text='Debugging', variable=debug_bool, command=set_debug) debug_btn.pack() # Debug 2D debug_2d_bool = BooleanVar() debug_2d_bool.set(self.agent.debug_2d_bool) def set_debug_2d(): self.agent.debug_2d_bool = debug_2d_bool.get() debug_2d = ttk.Checkbutton(root, text='Debug 2D', variable=debug_2d_bool, command=set_debug_2d) debug_2d.pack() # Location show_coords_bool = BooleanVar() show_coords_bool.set(self.agent.show_coords) def set_show_coords(): self.agent.show_coords = show_coords_bool.get() show_coords_btn = ttk.Checkbutton(root, text='Show Car Info (2D/Lines)', variable=show_coords_bool, command=set_show_coords) show_coords_btn.pack() # Debug 3D debug_3d_bool = BooleanVar() debug_3d_bool.set(self.agent.debug_3d_bool) def set_debug_3d(): self.agent.debug_3d = debug_3d_bool.get() debug_3d = ttk.Checkbutton(root, text='Debug 3D', variable=debug_3d_bool, command=set_debug_3d) debug_3d.pack() # Debug Stack debug_stack_bool = BooleanVar() debug_stack_bool.set(self.agent.debug_stack_bool) def set_debug_stack(): self.agent.debug_stack_bool = debug_stack_bool.get() debug_stack = ttk.Checkbutton(root, text='Debug Stack (3D)', variable=debug_stack_bool, command=set_debug_stack) debug_stack.pack() # Debug Lines debug_lines_bool = BooleanVar() debug_lines_bool.set(self.agent.debug_lines) def set_debug_lines(): self.agent.debug_lines = debug_lines_bool.get() debug_lines = ttk.Checkbutton(root, text='Debug Lines', variable=debug_lines_bool, command=set_debug_lines) debug_lines.pack() # Debug ball prediction debug_ball_path_bool = BooleanVar() debug_ball_path_bool.set(self.agent.debug_ball_path) def set_debug_ball_path(): self.agent.debug_ball_path = debug_ball_path_bool.get() debug_ball_path = ttk.Checkbutton(root, text='Debug Ball Path (Lines)', variable=debug_ball_path_bool, command=set_debug_ball_path) debug_ball_path.pack() # Debug ball prediction precision debug_ball_path_precision_str = StringVar() debug_ball_path_precision_str.set( "Precision: " + str(self.agent.debug_ball_path_precision)) debug_ball_path_precision_label = ttk.Label( root, textvariable=debug_ball_path_precision_str) debug_ball_path_precision_label.pack() def set_debug_ball_path_precision(value): value = round(float(value)) self.agent.debug_ball_path_precision = value debug_ball_path_precision_str.set("Precision: " + str(value)) debug_ball_path_precision = ttk.Scale( root, orient=HORIZONTAL, from_=2, to=20, command=set_debug_ball_path_precision) debug_ball_path_precision.set(self.agent.debug_ball_path_precision) debug_ball_path_precision.pack() self.stop = root.destroy try: root.mainloop() except Exception: print_exc()
class App: def __init__(self, master): frame = Frame(master) frame.pack() self.process = None self.pitch = BooleanVar() self.checkPitch = Checkbutton(frame, text="Use Pitch Shift", variable=self.pitch, command=self.pitchTabManagement) self.checkPitch.grid(row=0, column=0, columnspan=3) self.pitchValue = DoubleVar() self.pitchslider = Scale(frame, from_=-2000, to=2000, length=500, orient=HORIZONTAL, variable=self.pitchValue, showvalue=0) self.pitchslider.grid(row=1, column=1) self.entryLabel = Label(frame, text="Pitch:") self.entryLabel.grid(row=1, column=0) self.pitchTxt = Entry(frame, textvariable=self.pitchValue) self.pitchTxt.grid(row=1, column=2) self.flanger = BooleanVar() self.checkFlanger = Checkbutton(frame, text="Use Flanger Effect", variable=self.flanger, command=self.flangerTabManagement) self.checkFlanger.grid(row=2, column=0, columnspan=3) self.delayValue = DoubleVar() self.delaylbl = Label(frame, text="Delay:") self.delaylbl.grid(row=3, column=0) self.delayslider = Scale(frame, from_=0, to=30, length=500, orient=HORIZONTAL, variable=self.delayValue, showvalue=0) self.delayslider.grid(row=3, column=1) self.delayTxt = Entry(frame, textvariable=self.delayValue) self.delayTxt.grid(row=3, column=2) self.depthValue = DoubleVar() self.depthlbl = Label(frame, text="Depth:") self.depthlbl.grid(row=4, column=0) self.depthslider = Scale(frame, from_=0, to=10, length=500, orient=HORIZONTAL, variable=self.depthValue, showvalue=0) self.depthslider.grid(row=4, column=1) self.depthTxt = Entry(frame, textvariable=self.depthValue) self.depthTxt.grid(row=4, column=2) self.regenValue = DoubleVar() self.regenlbl = Label(frame, text="Regen:") self.regenlbl.grid(row=5, column=0) self.regenslider = Scale(frame, from_=-95, to=95, length=500, orient=HORIZONTAL, variable=self.regenValue, showvalue=0) self.regenslider.grid(row=5, column=1) self.regenTxt = Entry(frame, textvariable=self.regenValue) self.regenTxt.grid(row=5, column=2) self.widthValue = DoubleVar() self.widthlbl = Label(frame, text="Width:") self.widthlbl.grid(row=6, column=0) self.widthslider = Scale(frame, from_=0, to=100, length=500, orient=HORIZONTAL, variable=self.widthValue, showvalue=0) self.widthslider.grid(row=6, column=1) self.widthTxt = Entry(frame, textvariable=self.widthValue) self.widthTxt.grid(row=6, column=2) self.speedValue = DoubleVar() self.speedlbl = Label(frame, text="Speed:") self.speedlbl.grid(row=7, column=0) self.speedslider = Scale(frame, from_=0.1, to=10., length=500, orient=HORIZONTAL, resolution=0.1, showvalue=0, variable=self.speedValue) self.speedslider.grid(row=7, column=1) self.speedTxt = Entry(frame, textvariable=self.speedValue) self.speedTxt.grid(row=7, column=2) self.flangerShape = StringVar() self.flangerShape.set("sine") self.shapelbl = Label(frame, text="Shape:") self.shapelbl.grid(row=8, column=0) self.shapesine = Radiobutton(frame, text="Sine", variable=self.flangerShape, value="sine") self.shapesine.grid(row=8, column=1) self.shapetri = Radiobutton(frame, text="Triangle", variable=self.flangerShape, value="triangle") self.shapetri.grid(row=8, column=2) self.phaseValue = DoubleVar() self.phaselbl = Label(frame, text="Phase:") self.phaselbl.grid(row=9, column=0) self.phaseslider = Scale(frame, from_=0, to=100, length=500, orient=HORIZONTAL, variable=self.phaseValue, showvalue=0) self.phaseslider.grid(row=9, column=1) self.phaseTxt = Entry(frame, textvariable=self.phaseValue) self.phaseTxt.grid(row=9, column=2) self.interpolation = StringVar() self.interpolation.set("linear") self.interplbl = Label(frame, text="Interpolation:") self.interplbl.grid(row=10, column=0) self.intlin = Radiobutton(frame, text="Linear", variable=self.interpolation, value="linear") self.intlin.grid(row=10, column=1) self.intquad = Radiobutton(frame, text="Quadratic", variable=self.interpolation, value="quadratic") self.intquad.grid(row=10, column=2) self.gain = BooleanVar() self.checkGain = Checkbutton(frame, text="Enable Gain", variable=self.gain, command=self.gainTabManagement) self.checkGain.grid(row=11, column=0, columnspan=3) self.gainValue = DoubleVar() self.gainLabel = Label(frame, text="Volume Gain:") self.gainLabel.grid(row=12, column=0) self.gainSlider = Scale(frame, from_=-3.0, to=3.0, length=500, orient=HORIZONTAL, variable=self.gainValue, showvalue=0, resolution=0.1) self.gainSlider.grid(row=12, column=1) self.txtGain = Entry(frame, textvariable=self.gainValue) self.txtGain.grid(row=12, column=2) self.startBtn = Button(frame, text="Start SoX", command=self.start_sox) self.startBtn.grid(row=13, column=0) self.stopBtn = Button(frame, text="Stop SoX", command=self.stop_sox) self.stopBtn.config(state=DISABLED) self.stopBtn.grid(row=14, column=0) self.loadBtn = Button(frame, text="Load Preset", command=self.load) self.loadBtn.grid(row=13, column=1) self.saveBtn = Button(frame, text="Save Preset", command=self.save) self.saveBtn.grid(row=14, column=1) self.status = Label(frame, text="SoX not started, waiting for user operation") self.status.grid(row=15, column=0, columnspan=3) self.pitchcontrols = [self.pitchslider, self.pitchTxt] self.flangercontrols = [ self.delayslider, self.delayTxt, self.depthslider, self.depthTxt, self.regenslider, self.regenTxt, self.widthslider, self.widthTxt, self.speedslider, self.speedTxt, self.shapetri, self.shapesine, self.phaseslider, self.phaseTxt, self.intlin, self.intquad ] self.gaincontrols = [self.txtGain, self.gainSlider] self.toDisableList = self.pitchcontrols + self.flangercontrols\ + self.gaincontrols self.pitchTabManagement() self.flangerTabManagement() self.gainTabManagement() def load(self): messagebox.showwarning( "Attention", "This feature uses Python's pickle module, which is weak to arbitrary code execution.\nNever load settings from an untrusted source, it might break your system!" ) f = filedialog.askopenfile(filetypes=[("Python3 Pickle", "*.pickle")], mode="rb") if f is None: return self.pitch.set(pickle.load(f)) self.pitchValue.set(pickle.load(f)) self.flanger.set(pickle.load(f)) self.delayValue.set(pickle.load(f)) self.depthValue.set(pickle.load(f)) self.regenValue.set(pickle.load(f)) self.widthValue.set(pickle.load(f)) self.speedValue.set(pickle.load(f)) self.flangerShape.set(pickle.load(f)) self.phaseValue.set(pickle.load(f)) self.interpolation.set(pickle.load(f)) self.gain.set(pickle.load(f)) self.gainValue.set(pickle.load(f)) f.close() self.pitchTabManagement() self.flangerTabManagement() self.gainTabManagement() def save(self): f = filedialog.asksaveasfile(mode="wb", defaultextension="*.pickle", filetypes=[("Python3 Pickle", "*.pickle") ]) if f is None: return pickle.dump(self.pitch.get(), f) pickle.dump(self.pitchValue.get(), f) pickle.dump(self.flanger.get(), f) pickle.dump(self.delayValue.get(), f) pickle.dump(self.depthValue.get(), f) pickle.dump(self.regenValue.get(), f) pickle.dump(self.widthValue.get(), f) pickle.dump(self.speedValue.get(), f) pickle.dump(self.flangerShape.get(), f) pickle.dump(self.phaseValue.get(), f) pickle.dump(self.interpolation.get(), f) pickle.dump(self.gain.get(), f) pickle.dump(self.gainValue.get(), f) f.close() def pitchTabManagement(self): if self.pitch.get(): for item in self.pitchcontrols: item.config(state=NORMAL) else: for item in self.pitchcontrols: item.config(state=DISABLED) def flangerTabManagement(self): if self.flanger.get(): for item in self.flangercontrols: item.config(state=NORMAL) else: for item in self.flangercontrols: item.config(state=DISABLED) def gainTabManagement(self): if self.gain.get(): for item in self.gaincontrols: item.config(state=NORMAL) else: for item in self.gaincontrols: item.config(state=DISABLED) def createSink(self): try: Popen([ "pactl", "load-module", "module-null-sink", "sink_name=Voice_Changer", "sink_properties=device.description=Voice_Changer" ]) self.createSinkBtn.config(state=DISABLED) self.startBtn.config(state=NORMAL) self.status.config( text= "Sink seems to have been created successfully, now you can try using the software" ) except: self.status.config( text= "There has been an error creating the Sink, call a Computer Expert" ) def start_sox(self): sinkList = Popen(["pacmd", "list-sinks"], stdout=PIPE).communicate() sinkPresent = b"Voice_Changer" in sinkList[0] if not sinkPresent: self.createSink() try: modules = [] if self.pitch.get(): print("Pitch Shift Enabled") modules += ["pitch", str(self.pitchValue.get())] if self.flanger.get(): print("Flanger Enabled") modules += [ "flanger", str(self.delayValue.get()), str(self.depthValue.get()), str(self.regenValue.get()), str(self.widthValue.get()), str(self.speedValue.get()), str(self.flangerShape.get()), str(self.phaseValue.get()), str(self.interpolation.get()) ] if self.gain.get(): print("Gain Enabled") modules += ["gain", str(self.gainValue.get())] self.process = Popen([ "sox", "-t", "pulseaudio", "default", "-t", "pulseaudio", "Voice_Changer" ] + modules) self.status.config( text= "SoX Started, make sure to configure pavucontrol accordingly") self.startBtn.config(state=DISABLED) self.stopBtn.config(state=NORMAL) for item in self.toDisableList: item.config(state=DISABLED) except: self.status.config( text= "There has been an error starting SoX, check your system configuration" ) def stop_sox(self): self.process.kill() self.startBtn.config(state=NORMAL) self.stopBtn.config(state=DISABLED) for item in self.toDisableList: item.config(state=NORMAL) self.status.config( text="SoX Stopped, now you can change your settings and restart")
string_browning.set('Browning Index = ' + str(browning)) string_hue.set('Hue Angle = ' + str(hue)) entry_l.configure(validate='key') entry_a.configure(validate='key') entry_b.configure(validate='key') entry_browning.configure(validate='key') entry_hue.configure(validate='key') window.update() set_lab_values([0.0, 0.0, 0.0]) # Creating buttons print('Creating buttons...') remove_img_bg = BooleanVar() remove_img_bg.set(False) check_remove_bg = Checkbutton(frame_settings, text='Remove background?', var=remove_img_bg, background='#ffffff', foreground='#000000', font=('Arial', 12)) check_remove_bg.pack(side='top', anchor='center') check_remove_bg.toggle() def choose_file(): # Asking for filename update_status('Asking for filename...') window.update() filename = filedialog.askopenfilename(initialdir='~/Pictures')
#------------------------------------------------------------------------------ if __name__ == "__main__": Z = 18 path1 = os.path.dirname(sys.argv[0]) + '/' sim = Tk() sim.title('Plasma diagnostics') #sim.iconbitmap(r'atom.ico') #Optional .ico (does not work in my Ubuntu) kexc_var = BooleanVar() kion_var = BooleanVar() klion_var = BooleanVar() kllion_var = BooleanVar() total_var = BooleanVar() total_var.set(True) #Consider all #Database loader db = dbloader(path1, Z, kexc_var.get(), kion_var.get(), klion_var.get(), kllion_var.get(), total_var.get()) if db == None: sys.exit() #Does not open without a transition database #Database assignment kexc_var.set(db[0]) kion_var.set(db[1]) klion_var.set(db[2]) kllion_var.set(db[3]) total_var.set(db[4]) (hw_trans, cs_K_exc, cs_K_ion, cs_KL_ion, cs_KLL_ion, cs_K_exc_exists, cs_K_ion_exists, cs_KL_ion_exists, cs_KLL_ion_exists) = db[5:] tf_var = StringVar()
class TrimWindow: def __init__(self, root): self.window = tk.Toplevel(root) audio.TRIMMED_AUDIO = audio.get_audio()[0] self.start_marker_position = 0.0 self.end_marker_position = (len(audio.TRIMMED_AUDIO) + 1.) / audio.SAMPLE_RATE self.start_marker_edit = BooleanVar() self.start_marker_edit.set('false') self.end_marker_edit = BooleanVar() self.end_marker_edit.set('false') self.frame = tk.Frame(self.window) self.frame.grid() self.start_marker_button = \ tk.Button(self.frame, text="Move start marker", relief="raised", command=self.toggle_start_marker_button) self.start_marker_button.grid(row=0, column=0, padx=5, pady=5) self.end_marker_button = \ tk.Button(self.frame, text="Move end marker", relief="raised", command=self.toggle_end_marker_button) self.end_marker_button.grid(row=0, column=1, padx=5, pady=5) self.plot_canvas, self.plot_figure, self.plot_axes = self.get_matplotlib_canvas() self.plot_canvas.get_tk_widget().grid(row=1, columnspan=2, column=0, padx=5, pady=5) self.trim_button = \ tk.Button(self.frame, text="Trim to markers", command=self.trim_audio) self.trim_button.grid(row=2, column=0, padx=5, pady=5) self.accept_button = tk.Button(self.frame, text="OK", command=self.replace_audio) self.accept_button.grid(row=2, column=1, padx=5, pady=5) self.update_plot() self.window.update() self.window.grab_set() self.window.protocol("WM_DELETE_WINDOW", self.kill_trim_window) def get_matplotlib_canvas(self): f = Figure(figsize=(7, 2), dpi=100) ax = f.add_subplot(111) ax.get_yaxis().set_visible(False) f.patch.set_facecolor(self.frame["background"]) canvas = FigureCanvasTkAgg(f, self.frame) canvas.draw() canvas.mpl_connect('button_press_event', self.on_plot_click) return canvas, f, ax def update_plot(self): self.plot_axes.clear() self.draw_audio_plot(audio.TRIMMED_AUDIO, audio.SAMPLE_RATE) self.draw_start_marker() self.draw_end_marker() self.plot_canvas.draw() def on_plot_click(self, event): print('start:' + str(self.start_marker_edit.get())) print('end:' + str(self.end_marker_edit.get())) if self.start_marker_edit.get(): if event.xdata > self.end_marker_position - 0.01: self.start_marker_position = self.end_marker_position - 1 else: self.start_marker_position = event.xdata if self.end_marker_edit.get(): if event.xdata < self.start_marker_position + 0.01: self.end_marker_position = self.start_marker_position + 1 else: self.end_marker_position = event.xdata self.update_plot() def draw_start_marker(self): self.plot_axes.axvline(x=self.start_marker_position, color='green') def draw_end_marker(self): self.plot_axes.axvline(x=self.end_marker_position, color='red') def draw_audio_plot(self, signal, sr): libdisplay.waveplot(signal, sr, x_axis='time', ax=self.plot_axes) def toggle_start_marker_button(self): if self.start_marker_button.config('relief')[-1] == 'sunken': self.start_marker_button.config(relief="raised") self.start_marker_edit.set('false') else: if self.end_marker_button.config('relief')[-1] == 'sunken': self.end_marker_button.config(relief="raised") self.end_marker_edit.set('false') self.start_marker_button.config(relief="sunken") self.start_marker_edit.set('true') def toggle_end_marker_button(self): if self.end_marker_button.config('relief')[-1] == 'sunken': self.end_marker_button.config(relief="raised") self.end_marker_edit.set('false') else: if self.start_marker_button.config('relief')[-1] == 'sunken': self.start_marker_button.config(relief="raised") self.start_marker_edit.set('false') self.end_marker_button.config(relief="sunken") self.end_marker_edit.set('true') def trim_audio(self): audio.trim_audio(self.start_marker_position, self.end_marker_position) self.start_marker_position = 0.0 self.end_marker_position = (len(audio.TRIMMED_AUDIO) + 1.) / audio.SAMPLE_RATE self.update_plot() def replace_audio(self): audio.replace_audio() def kill_trim_window(self): global trim_window trim_window = None self.window.destroy()
class FrameMapping(FrameCustomItem): """Holds and visualizes a Map between two columns of different datasets""" row_index = None is_key = None src_reference = None src_datatype = None src_cast_to = None dest_table = None curr_data = None curr_raw_data = None mapping = None preview = None dest_reference = None def __init__(self, _master, _mapping = None, _on_get_source_references = None, _on_get_destination_references = None, _on_select = None): super(FrameMapping, self).__init__(_master) # Add monitored variables. self.is_key = BooleanVar() self.src_reference = StringVar() self.src_datatype = StringVar() self.curr_data = StringVar() self.result_cast_to = StringVar() self.preview = StringVar() self.dest_reference = StringVar() self.on_get_source_references = _on_get_source_references self.on_get_destination_references = _on_get_destination_references self.on_select = _on_select self.init_widgets() self.mapping = _mapping if _mapping is not None: self.mapping_to_gui() def mapping_to_gui(self): self.src_reference.set(str(empty_when_none(self.mapping.src_reference))) self.dest_reference.set(str(empty_when_none(self.mapping.dest_reference))) self.src_datatype.set(self.mapping.src_datatype) self.is_key.set(bool_to_binary_int(self.mapping.is_key)) def gui_to_mapping(self): self.mapping.src_reference = self.src_reference.get() self.mapping.dest_reference = self.dest_reference.get() self.mapping.is_key = binary_int_to_bool(self.is_key.get()) def reload_references(self): self.cb_source_ref['values'] = self.get_source_references() self.cb_dest_ref['values'] = self.get_destination_references() def get_source_references(self, _force = None): if self.on_get_source_references: return self.on_get_source_references(_force) def get_destination_references(self, _force = None): if self.on_get_destination_references: return self.on_get_destination_references( _force) def on_change_source_ref(self, *args): # reload dataset. pass def init_widgets(self): """Init all widgets""" # Source reference self.cb_source_ref = ttk.Combobox(self, textvariable=self.src_reference, state='normal') self.cb_source_ref['values'] = self.get_source_references() self.cb_source_ref.pack(side=LEFT, fill=X, expand=1) # Data type label self.l_data_type = ttk.Label(self, textvariable=self.src_datatype, width=8) self.src_datatype.set("Not set") self.l_data_type.pack(side=LEFT) # Dest reference self.cb_dest_ref = ttk.Combobox(self, textvariable=self.dest_reference, state='normal') self.cb_dest_ref['values'] = self.get_destination_references() self.cb_dest_ref.pack(side=RIGHT, fill=X, expand=1) # Is key field self.cb_is_key = ttk.Checkbutton(self, variable=self.is_key) self.cb_is_key.pack(side=RIGHT) # Current data self.l_data = ttk.Label(self, textvariable=self.curr_data) self.curr_data.set("No data") self.l_data.pack(side=RIGHT, fill=X, padx=5)
def __init__(self, master, par=False): """ GUI for selecting default parameters - will write parameters to file \ of users choosing. :type master: Tk :param master: Tkinter window :type par: EQcorrscanParameters :param par: Default parameters to start-up with. """ from tkinter import Label, Button, Entry, DoubleVar, StringVar, IntVar from tkinter import BooleanVar, OptionMenu, Checkbutton import tkMessageBox from eqcorrscan.utils import parameters from obspy import UTCDateTime import warnings # Set the default par, only if they don't already exist. if not par: par = parameters.EQcorrscanParameters([''], 2, 10, 4, 100, 2, '1900-01-01', '2300-01-01', '', 'seishub', 4, False, '', 'jpg', False, 8, 'MAD', 6) # Callback functions for all variables (ugly) def update_template_names(*args): par.template_names = [name.strip() for name in template_names.get().split(',')] template_names.set(', '.join(par.template_names)) def update_lowcut(*args): par.lowcut = lowcut.get() lowcut.set(par.lowcut) def update_highcut(*args): par.highcut = highcut.get() if par.highcut >= 0.5 * par.samp_rate: msg = ('Highcut must be less than the Nyquist, setting to ' + str((par.samp_rate / 2.0) - 1)) tkMessageBox.showwarning(title="Nyquist error", message=msg) par.highcut = (par.samp_rate / 2.0) - 1 highcut.set(par.highcut) def update_filt_order(*args): par.filt_order = filt_order.get() filt_order.set(par.filt_order) def update_samp_rate(*args): par.samp_rate = samp_rate.get() if par.highcut >= 0.5 * par.samp_rate: msg = ('Highcut must be less than the Nyquist, setting to ' + str((par.samp_rate / 2.0) - 1)) tkMessageBox.showwarning(title="Nyquist error", message=msg) par.highcut = (par.samp_rate / 2.0) - 1 highcut.set(par.highcut) samp_rate.set(par.samp_rate) def update_debug(*args): par.debug = debug.get() debug.set(par.debug) def update_startdate(*args): par.startdate = UTCDateTime(startdate.get()) startdate.set(str(par.startdate)) def update_enddate(*args): par.enddate = UTCDateTime(enddate.get()) enddate.set(str(par.enddate)) def update_archive(*args): par.archive = archive.get() archive.set(par.archive) def update_arc_type(*args): par.arc_type = arc_type.get() arc_type.set(par.arc_type) def update_cores(*args): par.cores = cores.get() cores.set(par.cores) def update_plotvar(*args): par.plotvar = plotvar.get() plotvar.set(par.plotvar) def update_plot_format(*args): par.plot_format = plot_format.get() plot_format.set(par.plot_format) def update_tempdir(*args): par.tempdir = tempdir.get() tempdir.set(par.tempdir) def update_threshold(*args): par.threshold = threshold.get() threshold.set(par.threshold) def update_threshold_type(*args): par.threshold_type = threshold_type.get() threshold_type.set(par.threshold_type) def update_plotdir(*args): par.plotdir = plotdir.get() plotdir.set(par.plotdir) def update_trigger_interval(*args): par.trigger_interval = trigger_interval.get() trigger_interval.set(par.trigger_interval) # Set some grid parameters nrows = 25 ncolumns = 3 self.master = master master.title("EQcorrscan parameter setup") self.label = Label(master, text="Alpha GUI for default setup") self.label.grid(column=0, columnspan=ncolumns, row=0) # Set up parameter input self.t_names_label = Label(master, text="Template names", anchor='e') self.t_names_label.grid(column=0, row=1, sticky='e') template_names = StringVar() template_names.set(', '.join(par.template_names)) self.t_names_box = Entry(master, bd=2, textvariable=template_names) self.t_names_box.grid(column=1, row=1) template_names.trace("w", update_template_names) self.t_names_lookup = Button(master, text="Lookup", command=lambda: self.get_template_names(par)) self.t_names_lookup.grid(column=2, row=1) self.lowcut_label = Label(master, text="Lowcut (Hz)", anchor='e') self.lowcut_label.grid(column=0, row=2, sticky='e') lowcut = DoubleVar() lowcut.set(par.lowcut) self.lowcut_box = Entry(master, bd=2, textvariable=lowcut) self.lowcut_box.grid(column=1, row=2) lowcut.trace("w", update_lowcut) self.highcut_label = Label(master, text="Highcut (Hz)", anchor='e') self.highcut_label.grid(column=0, row=3, sticky='e') highcut = DoubleVar() highcut.set(par.highcut) self.highcut_box = Entry(master, bd=2, textvariable=highcut) self.highcut_box.grid(column=1, row=3) highcut.trace("w", update_highcut) self.filt_order_label = Label(master, text="Filter order") self.filt_order_label.grid(column=0, row=4, sticky='e') filt_order = DoubleVar() filt_order.set(par.filt_order) self.filt_order_box = Entry(master, bd=2, textvariable=filt_order) self.filt_order_box.grid(column=1, row=4) filt_order.trace("w", update_filt_order) self.samp_rate_label = Label(master, text="Sample rate (Hz)") self.samp_rate_label.grid(column=0, row=5, sticky='e') samp_rate = DoubleVar() samp_rate.set(par.samp_rate) self.samp_rate_box = Entry(master, bd=2, textvariable=samp_rate) self.samp_rate_box.grid(column=1, row=5) samp_rate.trace("w", update_samp_rate) self.debug_label = Label(master, text="Debug") self.debug_label.grid(column=0, row=6, sticky='e') debug = IntVar() debug.set(par.debug) self.debug_box = Entry(master, bd=2, textvariable=debug) self.debug_box.grid(column=1, row=6) debug.trace("w", update_debug) self.startdate_label = Label(master, text="Start date (yyyy-mm-dd)") self.startdate_label.grid(column=0, row=6, sticky='e') startdate = StringVar() startdate.set(par.startdate) self.startdate_box = Entry(master, bd=2, textvariable=startdate) self.startdate_box.grid(column=1, row=6) startdate.trace("w", update_startdate) self.enddate_label = Label(master, text="End date (yyyy-mm-dd)") self.enddate_label.grid(column=0, row=8, sticky='e') enddate = StringVar() enddate.set(par.enddate) self.enddate_box = Entry(master, bd=2, textvariable=enddate) self.enddate_box.grid(column=1, row=8) enddate.trace("w", update_enddate) self.archive_label = Label(master, text="Archive") self.archive_label.grid(column=0, row=9, sticky='e') archive = StringVar() archive.set(par.archive) self.archive_box = Entry(master, bd=2, textvariable=archive) self.archive_box.grid(column=1, row=9) archive.trace("w", update_archive) self.archive_lookup = Button(master, text="Lookup", command=lambda: self.get_archive(par)) self.archive_lookup.grid(column=2, row=9) self.arc_type_label = Label(master, text="Archive type") self.arc_type_label.grid(column=0, row=10, sticky='e') arc_type = StringVar() arc_type.set(par.arc_type) self.arc_type_box = OptionMenu(master, arc_type, "seishub", "fdsn", "day_vols") self.arc_type_box.grid(column=1, row=10, sticky='w,e') arc_type.trace("w", update_arc_type) self.cores_label = Label(master, text="Number of cores") self.cores_label.grid(column=0, row=11, sticky='e') cores = IntVar() cores.set(par.cores) self.cores_box = Entry(master, bd=2, textvariable=cores) self.cores_box.grid(column=1, row=11) cores.trace("w", update_cores) self.plotvar_label = Label(master, text="Plotting on/off") self.plotvar_label.grid(column=0, row=12, sticky='e') plotvar = BooleanVar() plotvar.set(par.plotvar) self.plotvar_box = Checkbutton(master, text='Plot on', var=plotvar, onvalue=True, offvalue=False) self.plotvar_box.grid(column=1, row=12) plotvar.trace("w", update_plotvar) self.plotdir_label = Label(master, text="Plot directory") self.plotdir_label.grid(column=0, row=13, sticky='e') plotdir = StringVar() plotdir.set(par.plotdir) self.plotdir_box = Entry(master, bd=2, textvariable=plotdir) self.plotdir_box.grid(column=1, row=13) plotdir.trace("w", update_plotdir) self.plotdir_lookup = Button(master, text="Lookup", command=lambda: self.get_plotdir(par)) self.plotdir_lookup.grid(column=2, row=13) self.plot_format_label = Label(master, text="Plot format") self.plot_format_label.grid(column=0, row=14, sticky='e') plot_format = StringVar() plot_format.set(par.plot_format) self.plot_format_box = OptionMenu(master, plot_format, "jpg", "eps", "pdf", "png") self.plot_format_box.grid(column=1, row=14, sticky='w,e') plot_format.trace("w", update_plot_format) self.tempdir_label = Label(master, text="Temporary directory") self.tempdir_label.grid(column=0, row=15, sticky='e') tempdir = StringVar() tempdir.set(par.tempdir) self.tempdir_box = Entry(master, bd=2, textvariable=tempdir) self.tempdir_box.grid(column=1, row=15) tempdir.trace("w", update_tempdir) self.tempdir_lookup = Button(master, text="Lookup", command=lambda: self.get_tempdir(par)) self.tempdir_lookup.grid(column=2, row=15) self.threshold_label = Label(master, text="Threshold") self.threshold_label.grid(column=0, row=16, sticky='e') threshold = DoubleVar() threshold.set(par.threshold) self.threshold_box = Entry(master, bd=2, textvariable=threshold) self.threshold_box.grid(column=1, row=16) threshold.trace("w", update_threshold) self.threshold_type_label = Label(master, text="Threshold type") self.threshold_type_label.grid(column=0, row=17, sticky='e') threshold_type = StringVar() threshold_type.set(par.threshold_type) self.threshold_type_box = OptionMenu(master, threshold_type, "MAD", "absolute", "av_chan_corr") self.threshold_type_box.grid(column=1, row=17, sticky='w,e') threshold_type.trace("w", update_threshold_type) self.trigger_interval_label = Label(master, text="Minimum trigger " + "interval (s)") self.trigger_interval_label.grid(column=0, row=18, sticky='e') trigger_interval = DoubleVar() trigger_interval.set(par.trigger_interval) self.trigger_interval_box = Entry(master, bd=2, textvariable=trigger_interval) self.trigger_interval_box.grid(column=1, row=18) trigger_interval.trace("w", update_trigger_interval) # End of user editable section, now we have read/write buttons self.read_button = Button(master, text="Read parameters", command=lambda: self.read_par(master)) self.read_button.grid(column=0, row=nrows-2, sticky='w,e') self.write_button = Button(master, text="Write parameters", command=lambda: self.write_par(par)) self.write_button.grid(column=1, row=nrows-2, sticky='w,e')
class ReplicatorMain(VerticalScrolledFrame): """The main class for the GUI of the application""" merge = None """This is the merge object of the application, it holds all settings for the merge operation""" filename = None """The name of the file containing the merge definition""" fr_src_dataset = None """The fram of the source dataset, contains a FrameCustomDataset descendant""" fr_dest_dataset = None """The fram of the source dataset, contains a FrameCustomDataset descendant""" suppress_errors = None """Do not show any errors""" _row_index = None """The current row in the dataset""" curr_mapping_frame = None """The currently selected mapping frame""" def __init__(self, _merge=None, _filename=None, *args, **kw): self.parent = Tk() # Init oneself super(ReplicatorMain, self).__init__(self.parent, bd=1, relief=SUNKEN, *args, **kw) self.grid(stick=(E, W, N, S)) self.suppress_errors = None self.merge = _merge self.filename = _filename self.fr_src_dataset = None self.fr_dest_dataset = None self.grid() self.ip_address = StringVar() self._row_index = 0 self.init_GUI() if _filename is not None and _merge is not None: # _merge._load_datasets() self._merge_to_gui() self.parent.columnconfigure(0, weight=1) self.parent.rowconfigure(0, weight=1) self.resize() self.parent.mainloop() def resize(self): """ Resize the window, set the width what the internal windows need. """ self._canvas.update_idletasks() self.fr_top_right.update_idletasks() self._canvas.config(width=self.interior.winfo_reqwidth() + 1, height=self.interior.winfo_reqheight()) def on_dataset_columns_change(self, *args): # Columns have changed; force reload columns from structure self.fr_src_dataset.get_possible_references(True) self.fr_dest_dataset.get_possible_references(True) for curr_mapping in self.g_mappings.items: curr_mapping.fr_item.reload_references() def notify_task(self, _task, _progress): """Override as this is the top widget""" self.fr_Status_Bar.update_task(_task, _progress) def notify_messagebox(self, _title, _message, _kind=None): """Override as this is the top class, default is error.""" if self.suppress_errors is None: if _kind == "message": messagebox.showinfo(_title, _message) elif _kind == "warning": messagebox.showwarning(_title, _message) else: messagebox.showerror(_title, _message) def on_post_merge_sql(self, *args): # Show post-merge-SQL dialog _wdw = Toplevel() _wdw.geometry('+400+400') _wdw.e = TextExtension(_wdw, textvariable=self.post_execute_sql) _wdw.e.pack() _wdw.e.focus_set() _wdw.transient(self.parent) _wdw.grab_set() self.parent.wait_window(_wdw) _wdw.e.unhook() del (_wdw) def on_src_connect(self, *args): """Event handler for when the source connection is set""" self.fr_mapping.src_dal = self.fr_dataset_src.dal def on_dest_connect(self, *args): """Event handler for when the destination connection is set""" self.fr_mapping.dest_dal = self.fr_dataset_dest.dal def init_GUI(self): """Init main application GUI""" print("Initializing GUI...", end="") self.parent.title("Optimal Sync - Move that data - a part of Optimal BPM") self.interior.notify_task = self.notify_task self.interior.notify_messagebox = self.notify_messagebox self.fr_top = BPMFrame(self.interior) self.fr_top.pack(side=TOP, fill=BOTH, expand=1) self.fr_top_left = BPMFrame(self.fr_top) self.fr_top_left.pack(side=LEFT, fill=BOTH, expand=1) self.fr_rw = BPMFrame(self.fr_top_left) self.fr_rw.pack(side=TOP, fill=X) self.btn_Load_json_json = ttk.Button(self.fr_rw, text="Load", command=self.on_load_json) self.btn_Load_json_json.pack(side=LEFT) self.btn_Save_json = ttk.Button(self.fr_rw, text="Save", command=self.on_save_json) self.btn_Save_json.pack(side=LEFT) self.fr_subnet_sql = BPMFrame(self.fr_rw) self.l_ip = ttk.Label(self.fr_subnet_sql, text="IP(for subnet scan):") self.l_ip.pack(side=LEFT) self.ip_address.set("192.168.0.1") self.e_ip_address = ttk.Entry(self.fr_subnet_sql, textvariable=self.ip_address) self.e_ip_address.pack(side=RIGHT) self.fr_subnet_sql.pack(side=RIGHT) # datasets self.fr_datasets = BPMFrame(self.fr_top_left) self.fr_datasets.pack(side=TOP) self.sel_src_dataset_type = Selector(_master=self.fr_datasets, _values=('RDBMS', 'XPath', 'Flatfile', 'Spreadsheet'), _caption="Sources dataset type:", _onchange=self.on_src_dataset_type_change) self.sel_src_dataset_type.grid(column=0, row=0, sticky=W) self.sel_dest_dataset_type = Selector(_master=self.fr_datasets, _values=('RDBMS', 'XPath', 'Flatfile', 'Spreadsheet'), _caption="Destination dataset type:", _onchange=self.on_dest_dataset_type_change) self.sel_dest_dataset_type.grid(column=1, row=0, sticky=W) # Mappings self.fr_mapping_header = BPMFrame(self.fr_top_left) self.fr_mapping_header.pack(side=TOP) self.l_mapping = ttk.Label(self.fr_mapping_header, text="Mappings:") self.l_mapping.pack(side=TOP) self.fr_mapping_header_nav = BPMFrame(self.fr_mapping_header) self.fr_mapping_header_nav.pack(side=BOTTOM) self.btn_first = Button(self.fr_mapping_header_nav, text="<<", command=self.on_first) self.btn_first.pack(side=LEFT) self.btn_prev = Button(self.fr_mapping_header_nav, text="<", command=self.on_prev) self.btn_prev.pack(side=LEFT) self.btn_reload = Button(self.fr_mapping_header_nav, text="Reload data", command=self.on_reload_data) self.btn_reload.pack(side=LEFT) self.btn_next = Button(self.fr_mapping_header_nav, text=">", command=self.on_next) self.btn_next.pack(side=LEFT) self.btn_last = Button(self.fr_mapping_header_nav, text=">>", command=self.on_last) self.btn_last.pack(side=LEFT) self.g_mappings = FrameList(self.fr_top_left, _detail_key_text="Transformations >>", bd=1, relief=SUNKEN) self.g_mappings.pack(side=TOP, fill=X) self.g_mappings.on_delete = self.mappings_do_on_delete self.g_mappings.on_move_up = self.mappings_do_on_move_up self.g_mappings.on_move_down = self.mappings_do_on_move_down self.g_mappings.on_detail = self.mappings_do_on_detail self.btn_append_mapping = Button(self.fr_top_left, text="Append mapping", command=self.on_append_mapping) self.btn_append_mapping.pack(side=TOP) # Transformation self.fr_top_right = BPMFrame(self.fr_top) self.fr_top_right.pack(side=RIGHT, fill=Y) self.l_transformations = ttk.Label(self.fr_top_right, text="Transformations") self.l_transformations.pack(side=TOP) self.g_transformations = FrameList(self.fr_top_right, bd=1, relief=SUNKEN) self.g_transformations.pack(fill=BOTH, expand=1) self.g_transformations.on_delete = self.transformations_do_on_delete self.g_transformations.on_move_up = self.transformations_do_on_move_up self.g_transformations.on_move_down = self.transformations_do_on_move_down self.fr_append_transformation = ttk.Frame(self.fr_top_right) self.fr_append_transformation.pack(side=BOTTOM) self.btn_append_transformation = Button(self.fr_append_transformation, text="Append Transformation", command=self.on_append_transformation) self.btn_append_transformation.pack(side=LEFT) self.transformation_append_type = StringVar() self.sel_transformation_append_type = ttk.Combobox(self.fr_append_transformation, textvariable=self.transformation_append_type, state='readonly') self.sel_transformation_append_type['values'] = ["Replace", "Replace regex", "Cast", "If empty", "Trim"] self.sel_transformation_append_type.current(0) self.sel_transformation_append_type.pack(side=LEFT, fill=X) # Merge preview self.fr_Preview = ttk.Frame(self.fr_top_left) self.fr_Preview.pack(side=TOP, fill=BOTH, expand=1) self.fr_merge_actions = ttk.Frame(self.fr_Preview) self.fr_merge_actions.pack(side=TOP, fill=X) self.btn_execute_preview = Button(self.fr_merge_actions, text="Preview merge", command=self.on_preview_merge) self.btn_execute_preview.pack(side=LEFT) self.btn_execute_preview = Button(self.fr_merge_actions, text="Commit merge", command=self.on_commit_merge) self.btn_execute_preview.pack(side=LEFT) # Update self.merge_update = BooleanVar() self.e_merge_update = ttk.Checkbutton(self.fr_merge_actions, variable=self.merge_update) self.e_merge_update.pack(side=RIGHT) self.l_merge_update = ttk.Label(self.fr_merge_actions, text="Update: ") self.l_merge_update.pack(side=RIGHT) # Insert self.merge_insert = BooleanVar() self.e_merge_insert = ttk.Checkbutton(self.fr_merge_actions, variable=self.merge_insert) self.e_merge_insert.pack(side=RIGHT) self.l_merge_insert = ttk.Label(self.fr_merge_actions, text="Insert: ") self.l_merge_insert.pack(side=RIGHT) # Delete self.merge_delete = BooleanVar() self.e_merge_delete = ttk.Checkbutton(self.fr_merge_actions, variable=self.merge_delete) self.e_merge_delete.pack(side=RIGHT) self.l_merge_delete = ttk.Label(self.fr_merge_actions, text="Delete: ") self.l_merge_delete.pack(side=RIGHT) # Set post-merge SQL self.post_execute_sql = StringVar() self.btn_Post_Merge_SQL = ttk.Button(self.fr_merge_actions, text="Set post-merge SQL", command=self.on_post_merge_sql) self.btn_Post_Merge_SQL.pack(side=RIGHT, padx=30) # Preview self.gr_preview = ttk.Treeview(self.fr_Preview, columns=('size', 'modified')) self.gr_preview.pack(side=TOP, fill=BOTH, expand=1) self.gr_preview.bind("<<TreeviewSelect>>", self.on_preview_selected) self.preview_detail = StringVar() self.e_previev_detail = ttk.Entry(self.fr_Preview, textvariable=self.preview_detail) self.e_previev_detail.pack(side=BOTTOM, fill=X, expand=0) self.fr_bottom = BPMFrame(self.interior) self.fr_bottom.pack(side=BOTTOM, fill=X) self.fr_Status_Bar = Status_Bar(self.fr_bottom) self.fr_Status_Bar.pack(fill=X) print("done.") # ######################################################################### # This section contains functions handling the entire merge(load/save/GUI) # ######################################################################### def _merge_to_gui(self): """ Populate the GUI from the merge class. """ if self.fr_src_dataset is not None: self.fr_src_dataset.destroy() _src_type = self.dataset_instance_to_dataset_type(self.merge.source) self.sel_src_dataset_type.set_but_do_not_propagate(_src_type) self.fr_src_dataset = self.dataset_frame_factory(_dataset=self.merge.source, _is_destination=False) self.fr_src_dataset.grid(column=0, row=1) if self.fr_dest_dataset is not None: self.fr_dest_dataset.destroy() _dest_type = self.dataset_instance_to_dataset_type(self.merge.destination) self.sel_dest_dataset_type.set_but_do_not_propagate(_dest_type) self.fr_dest_dataset = self.dataset_frame_factory(_dataset=self.merge.destination, _is_destination=False) self.fr_dest_dataset.grid(column=1, row=1) self.mappings_to_gui() self.merge_insert.set(bool_to_binary_int(self.merge.insert)) self.merge_delete.set(bool_to_binary_int(self.merge.delete)) self.merge_update.set(bool_to_binary_int(self.merge.update)) if self.merge.post_execute_sql is None: self.post_execute_sql.set("") else: self.post_execute_sql.set(self.merge.post_execute_sql) # Hereafter, update column list when they change self.fr_src_dataset.on_columns_change = self.on_dataset_columns_change self.fr_dest_dataset.on_columns_change = self.on_dataset_columns_change def _gui_to_merge(self): """Copy the data from the GUI to the merge object""" self.fr_src_dataset.write_to_dataset() self.merge.source = self.fr_src_dataset.dataset self.fr_dest_dataset.write_to_dataset() self.merge.destination = self.fr_dest_dataset.dataset self.gui_to_mappings() self.merge.insert = binary_int_to_bool(self.merge_insert.get()) self.merge.delete = binary_int_to_bool(self.merge_delete.get()) self.merge.update = binary_int_to_bool(self.merge_update.get()) self.merge.post_execute_sql = self.post_execute_sql.get() def load_json(self, _filename): """Load an JSON into the merge object, and populate the GUI""" with open(_filename, "r") as _f: _json = json.load(_f) self.filename = _filename self.notify_task('Loading transformation..', 0) self.merge = Merge(_json=_json, _base_path=os.path.dirname(_filename)) try: self.merge._load_datasets() except Exception as e: self.notify_messagebox("Error loading data", str(e)) # Supress the following errors. There is no real errors that matters. self.suppress_errors = True self._merge_to_gui() self.suppress_errors = None self.notify_task('Loading transformation..done', 100) self.resize() def on_save_json(self, *args): """Triggered when save-button is clicked. Displays a save dialog, fetches GUI data into merge, and saves as JSON into the selected file.""" self.notify_task('Saving..', 0) _filename = filedialog.asksaveasfilename(initialfile= self.filename, defaultextension=".json", filetypes=[('JSON files', '.json'), ('all files', '.*')], title="Choose location") if _filename: self._gui_to_merge() self.notify_task('Saving(Generating JS)..', 0) _json = self.merge.as_json() self.notify_task('Saving(Writing file)..', 50) with open (_filename, "w") as _f: json.dump(_json, fp=_f, sort_keys=True, indent=4) self.notify_task('Saving..done.', 100) else: self.notify_task('Saving cancelled.', 0) def on_load_json(self, *args): """Triggered when load-button is clicked. Displays a load dialog, clears the GUI, populates the merge and uppdates the GUI""" _filename = filedialog.askopenfilename(defaultextension=".json", filetypes=[('JSON files', '.json'), ('all files', '.*')], title="Choose file") if _filename: self.g_transformations.clear() self.g_mappings.clear() self.clear_preview() self.curr_mapping_frame = None self._row_index = 0 self.load_json(_filename) def check_prerequisites_for_reload(self): """Can a reload be made using the current settings? If not, display cause in status field""" if self.fr_src_dataset is None: self.notify_task("Cannot reload: Source dataset must be specified.", 0) return False elif self.fr_dest_dataset is None: self.notify_task("Cannot reload: Destination dataset must be specified.", 0) return False _tmp = self.fr_src_dataset.check_reload() if _tmp: self.notify_task("Cannot reload source: " + _tmp, 0) return False _tmp = self.fr_dest_dataset.check_reload() if _tmp: self.notify_task("Cannot reload destination: " + _tmp, 0) return False else: return True def update_data(self, _refresh=None): """ Reload all data into the GUI :param _refresh: Force reload of datasets :return: """ if self.check_prerequisites_for_reload() is False: return self.notify_task("", 0) if len(self.merge.source.data_table) == 0 or _refresh: # Update settings self._gui_to_merge() # Update XPath references especially, since it addresses an XML structure, not a dataset. if isinstance(self.merge.source, XpathDataset): self.merge.source.field_xpaths = [] self.merge.source.field_names = [] for _curr_mapping_idx in range(0, len(self.g_mappings.items)): self.merge.source.field_xpaths.append( self.g_mappings.items[_curr_mapping_idx].fr_item.src_reference.get()) self.merge.source.field_names.append( self.g_mappings.items[_curr_mapping_idx].fr_item.src_reference.get()) self.merge.source.load() # Reset identity values self.reset_substitions_identity() # Is there any data? if len(self.merge.source.data_table) > 0: # Try to retain the approximate position in the table. if self._row_index < 0: self._row_index = 0 elif self._row_index > len(self.merge.source.data_table) - 1: self._row_index = len(self.merge.source.data_table) - 1 # Loop through mappings, update data and perform transformations # TODO: This certainly doesn't seem to belong here, should be extracted for _curr_mapping_idx in range(0, len(self.g_mappings.items)): _curr_frame = self.g_mappings.items[_curr_mapping_idx].fr_item _curr_frame.hide_error() _src_ref = _curr_frame.src_reference.get() try: if isinstance(self.merge.source, XpathDataset): _col_idx = self.merge.source.field_xpaths.index(_src_ref) else: _col_idx = self.merge.source.field_names.index(_src_ref) except ValueError: _col_idx = -1 if _col_idx > -1: _curr_frame.curr_raw_data = self.merge.source.data_table[self._row_index][_col_idx] try: perform_transformations(_input=_curr_frame.curr_raw_data, _transformations=_curr_frame.mapping.transformations) except Exception as e: self.notify_task( 'Error in one of the transformations, mapping: ' + _src_ref + " error: " + str(e), 0) _curr_frame.curr_data.set(str(_curr_frame.curr_raw_data)) else: _curr_frame.show_error(_msg="No mapping") _curr_frame.curr_data.set("") try: _curr_frame.curr_raw_data = perform_transformations(_input=None, _transformations= _curr_frame.mapping.transformations) except Exception as e: self.notify_task( 'Error in one of the transformations, mapping: ' + _curr_frame.dest_reference.get() + " error: " + str(e), 0) _curr_frame.curr_data.set(str(_curr_frame.curr_raw_data)) self.g_mappings.items[_curr_mapping_idx].fr_item.reload_references() # ######################################################### # The following events deals with navigating the active dataset ########################################################## def on_prev(self): """Triggered when the "<"-button is pressed.""" self._row_index -= 1 self.update_data() def on_next(self): """Triggered when the ">"-button is pressed.""" self._row_index += 1 self.update_data() def on_reload_data(self): """Triggered when the "Reload data"-button is pressed.""" self.update_data(_refresh=True) def on_first(self): """Triggered when the "<<"-button is pressed.""" self._row_index = 0 self.update_data() def on_last(self): """Triggered when the ">>!-button is pressed.""" if len(self.merge.source.data_table) == 0: self.merge.source.load() self._row_index = len(self.merge.source.data_table) - 1 self.update_data() def dataset_instance_to_dataset_type(self, _dataset): """ Identify an instance of a dataset and return a string description. Used in the dataset type selector. :param _dataset: The dataset to identify """ if isinstance(_dataset, RDBMSDataset): return "RDBMS" elif isinstance(_dataset, XpathDataset): return "XPATH" elif isinstance(_dataset, FlatfileDataset): return "FLATFILE" elif isinstance(_dataset, SpreadsheetDataset): return "SPREADSHEET" else: raise Exception("Internal error, unsupported dataset instance type: " + str(_dataset)) def dataset_frame_factory(self, _dataset=None, _dataset_type=None, _is_destination=False): """ This is a factory function for creating matching frames(visual property editors) for the dataset classes. :param _dataset: The dataset, if existing. :param _dataset_type: The dataset type string representation ("RDBMS", and so on) """ if _dataset: _dataset_type = self.dataset_instance_to_dataset_type(_dataset) if _dataset_type == "RDBMS": _tmp = FrameRDBMSDataset(self.fr_datasets, _dataset=_dataset, _relief=SUNKEN, _is_destination=_is_destination) _tmp.subnet_ip = self.ip_address elif _dataset_type == "FLATFILE": _tmp = FrameFlatfileDataset(self.fr_datasets, _dataset=_dataset, _relief=SUNKEN, _is_destination=_is_destination) elif _dataset_type == "XPATH": _tmp = FrameXPathDataset(self.fr_datasets, _dataset=_dataset, _relief=SUNKEN, _is_destination=_is_destination) elif _dataset_type == "SPREADSHEET": _tmp = FrameSpreadsheetDataset(self.fr_datasets, _dataset=_dataset, _relief=SUNKEN, _is_destination=_is_destination) else: raise Exception("Internal error, unsupported dataset type: " + str(_dataset_type)) if self.filename is not None: _tmp.base_path = os.path.dirname(self.filename) return _tmp def on_src_dataset_type_change(self, _current_value): """ Triggered when a user selects a different dataset type for the source dataset :param _current_value: A string describing what dataset type has been selected. """ if self.fr_src_dataset is not None: self.fr_src_dataset.destroy() self.fr_src_dataset = self.dataset_frame_factory(_dataset_type=_current_value.upper(), _is_destination=False) self.merge.source = self.fr_src_dataset.dataset self.fr_src_dataset.grid(column=0, row=1) def on_dest_dataset_type_change(self, _current_value): """ Triggered when a user selects a different dataset type for the destination dataset :param _current_value: A string describing what dataset type has been selected. """ if self.fr_dest_dataset is not None: self.fr_dest_dataset.destroy() self.fr_dest_dataset = self.dataset_frame_factory(_dataset_type=_current_value.upper(), _is_destination=True) self.merge.destination = self.fr_dest_dataset.dataset self.fr_dest_dataset.grid(column=1, row=1) def get_source_references(self, _force=None): """ Returns the possible field references from the source dataset :param _force: If True, forces a reload of the underlying dataset. """ if self.fr_src_dataset is not None: try: return self.fr_src_dataset.get_possible_references(_force) except Exception as e: self.notify_messagebox(_title="Failed refreshing source references", _message="Error: " + str(e), _kind="warning") return [] def get_destination_references(self, _force=None): """ Returns the possible field references from the destination dataset :param _force: If True, forces a reload of the underlying dataset. """ if self.fr_dest_dataset is not None: try: return self.fr_dest_dataset.get_possible_references(_force) except Exception as e: self.notify_messagebox(_title="Failed refreshing destination references", _message="Error: " + str(e), _kind="warning") return [] ########################################################## # This section contains functions handling field mappings ########################################################## def mappings_to_gui(self): """Populates the GUI from the mappings list of the merge object""" self.g_mappings.clear() for _curr_mapping in self.merge.mappings: _new_item = self.g_mappings.append_item() _new_item.make_item(_class=FrameMapping, _mapping=_curr_mapping, _on_get_source_references=self.get_source_references, _on_get_destination_references=self.get_destination_references) def gui_to_mappings(self): """Gathers data from GUI into the mappings list of the merge object""" self.gui_to_transformations() for _curr_mapping in self.g_mappings.items: _curr_mapping.fr_item.gui_to_mapping() self.merge._mappings_to_fields(self.merge.source, _use_dest=False) self.merge._mappings_to_fields(self.merge.destination, _use_dest=True) def mappings_do_on_delete(self, _g_mappings, _item_frame): """Triggered if the "del"-button has been clicked""" self.merge.mappings.remove(_item_frame.fr_item.mapping) def mappings_do_on_move_up(self, _g_mappings, _item_frame): """Triggered if the up arrow-button has been clicked""" _curr_idx = self.merge.mappings.index(_item_frame.fr_item.mapping) self.merge.mappings.insert(_curr_idx - 1, self.merge.mappings.pop(_curr_idx)) def mappings_do_on_move_down(self, _g_mappings, _item_frame): """Triggered if the down arrow-button has been clicked""" _curr_idx = self.merge.mappings.index(_item_frame.fr_item.mapping) self.merge.mappings.insert(_curr_idx + 1, self.merge.mappings.pop(_curr_idx)) def on_append_mapping(self, *args): """Triggered if the "Append mapping"-button has been clicked.""" _new_mapping = Mapping() self.merge.mappings.append(_new_mapping) _new_item = self.g_mappings.append_item() _new_item.make_item(_class=FrameMapping, _mapping=_new_mapping, _on_get_source_references=self.get_source_references, _on_get_destination_references=self.get_destination_references) def mappings_do_on_detail(self, _g_mappings, _item_frame): self.notify_task("", 0) if self.curr_mapping_frame: self.gui_to_transformations() self.g_transformations.clear() for _curr_transformation in _item_frame.fr_item.mapping.transformations: _frame_class = self._transformation_frame_class_lookup(_curr_transformation) if _frame_class: _new_item = self.g_transformations.append_item() _new_item.make_item(_class=_frame_class, _transformation=_curr_transformation) _item_frame['background'] = "dark grey" try: if _item_frame.fr_item.curr_raw_data is not None: perform_transformations(_input=_item_frame.fr_item.curr_raw_data, _transformations=_item_frame.fr_item.mapping.transformations) except Exception as e: self.notify_task( 'Error in one of the transformations, mapping: ' + _item_frame.fr_item.mapping.src_reference + " error: " + str( e), 0) if self.curr_mapping_frame: try: self.curr_mapping_frame['background'] = self['background'] except Exception as e: raise Exception("Error setting background to: " + self['background'] + ":" + str(e)) self.curr_mapping_frame = _item_frame ########################################################## # This section contains functions handling transformations ########################################################## def gui_to_transformations(self): """Gathers data from GUI into the transformation objects""" for _curr_transformation in self.g_transformations.items: _curr_transformation.fr_item.gui_to_transformation() def _transformation_frame_class_lookup(self, _transformation=None, _type=None): if _type is None: _type, _desc = transformation_to_type(_transformation) if _type == "Cast": return FrameTransformationCast if _type == "Trim": return FrameTransformationTrim if _type == "If empty": return FrameTransformationIfEmpty if _type == "Replace": return FrameTransformationReplace if _type == "Replace regex": return FrameTransformationReplaceRegex else: return None #raise Exception("Internal error, unsupported transformation type: " + str(_transformation_type)) def transformations_do_on_delete(self, _g_transformations, _item_frame): self.curr_mapping_frame.fr_item.mapping.transformations.remove(_item_frame.fr_item.transformation) def transformations_do_on_move_up(self, _g_transformations, _item_frame): _curr_transformations = self.curr_mapping_frame.fr_item.mapping.transformations _curr_idx = _curr_transformations.index(_item_frame.fr_item.transformation) _curr_transformations.insert(_curr_idx - 1, _curr_transformations.pop( _curr_idx)) def transformations_do_on_move_down(self, _g_transformations, _item_frame): _curr_transformations = self.curr_mapping_frame.fr_item.mapping.transformations _curr_idx = _curr_transformations.index(_item_frame.fr_item.transformation) _curr_transformations.insert(_curr_idx + 1, _curr_transformations.pop( _curr_idx)) def on_append_transformation(self, *args): if self.curr_mapping_frame is not None: _new_transformation = type_to_transformation(self.sel_transformation_append_type.get())( _substitution=self.curr_mapping_frame.fr_item.mapping.substitution) self.curr_mapping_frame.fr_item.mapping.transformations.append(_new_transformation) _frame_class = self._transformation_frame_class_lookup(_new_transformation) if _frame_class: _new_item = self.g_transformations.append_item() _new_item.make_item(_class=_frame_class, _transformation=_new_transformation) def clear_transformation_events(self): for _curr_mapping in self.merge.mappings: for _curr_transformation in _curr_mapping.transformations: _curr_transformation.on_done = None ############################################################ # This section contains functions handling the merge preview ############################################################ def clear_preview(self): for _curr_item in self.gr_preview.get_children(): self.gr_preview.delete(_curr_item) def reset_substitions_identity(self): """Reset substitions""" for _curr_mapping in self.merge.mappings: _curr_mapping.substitution.set_identity(0) def on_preview_merge(self, *args): self.do_merge(_commit=False) def on_commit_merge(self, *args): if askokcancel(title="Warning: committing merge", message="This will commit actual changes to the destination, " "do you want to proceed?") is True: self.do_merge(_commit=True) def do_merge(self, _commit=False): self._gui_to_merge() self.update_data(_refresh=True) self.merge.destination_log_level = DATASET_LOGLEVEL_DETAIL # Clear GUI events self.clear_transformation_events() self.merge.clear_log() try: _data_table, _log, _deletes, _inserts, _updates = self.merge.execute(_commit=_commit) except Exception as e: self.notify_messagebox("Error while merging", str(e)) return # Call columns src/dest field names if they differ if len(self.merge.key_fields) > 0: _key_field = self.merge.key_fields[0] else: _key_field = 0 self.clear_preview() self.gr_preview["columns"] = ["Change_Data"] self.gr_preview.column("Change_Data", width=500) self.gr_preview.heading("Change_Data", text="Change/Data") # Add a main for each action # Add deletes self.gr_preview.insert(parent="", index="end", iid="obpm_deletes", text="Deletes") if self.merge.delete: for _curr_row in _deletes: _curr_item_idx = self.gr_preview.insert(parent="obpm_deletes", index="end", iid="", text=_curr_row[2][_key_field]) _curr_value = ",".join([str(_item) for _item in _curr_row[2]]) self.gr_preview.item(_curr_item_idx, values=[_curr_value]) for _curr_column_idx in range(len(_curr_row[2])): _curr_change_item_idx = self.gr_preview.insert(parent=_curr_item_idx, index="end", iid="", text=str( self.merge.destination.field_names[_curr_column_idx])) self.gr_preview.item(_curr_change_item_idx, values=[str(_curr_row[2][_curr_column_idx])]) # Add inserts self.gr_preview.insert(parent="", index="end", iid="obpm_inserts", text="Inserts") if self.merge.insert: for _curr_row in _inserts: _curr_item_idx = self.gr_preview.insert(parent="obpm_inserts", index="end", iid="", text=_curr_row[2][_key_field]) _curr_value = ",".join([str(_item) for _item in _curr_row[2]]) self.gr_preview.item(_curr_item_idx, values=[_curr_value]) for _curr_column_idx in range(len(_curr_row[2])): _curr_change_item_idx = self.gr_preview.insert(parent=_curr_item_idx, index="end", iid="", text=str( self.merge.destination.field_names[_curr_column_idx])) self.gr_preview.item(_curr_change_item_idx, values=[str(_curr_row[2][_curr_column_idx])]) # Add updates self.gr_preview.insert(parent="", index="end", iid="obpm_updates", text="Updates") if self.merge.update: for _curr_row in _updates: _curr_item_idx = self.gr_preview.insert(parent="obpm_updates", index="end", iid="", text=_curr_row[2][_key_field]) _changes = [] for _curr_column_idx in range(len(_curr_row[2])): if _curr_row[2][_curr_column_idx] != _curr_row[3][_curr_column_idx]: _curr_change_item_idx = self.gr_preview.insert(parent=_curr_item_idx, index="end", iid="", text=str(self.merge.destination.field_names[ _curr_column_idx])) self.gr_preview.item(_curr_change_item_idx, values=[ str(_curr_row[3][_curr_column_idx]) + "=>" + str(_curr_row[2][_curr_column_idx])]) _changes.append(str(self.merge.destination.field_names[_curr_column_idx])) _curr_value = ",".join([str(_item) for _item in _changes]) self.gr_preview.item(_curr_item_idx, values=[_curr_value]) # Add log self.gr_preview.insert(parent="", index="end", iid="obpm_log", text="Log") if _log is not None: for _curr_row in _log: _log_fields = _curr_row.split(";") _curr_item_idx = self.gr_preview.insert(parent="obpm_log", index="end", iid="", text=_log_fields[0]) _curr_value = ",".join([unquote(str(_item)) for _item in _log_fields[1:]]) self.gr_preview.item(_curr_item_idx, values=[_curr_value]) # Add data table self.gr_preview.insert(parent="", index="end", iid="obpm_data_table", text="Result") if _data_table is not None: for _curr_row in _data_table: _curr_item_idx = self.gr_preview.insert(parent="obpm_data_table", index="end", iid="", text=_curr_row[_key_field]) _curr_value = ",".join([str(_item) for _item in _curr_row]) self.gr_preview.item(_curr_item_idx, values=[_curr_value]) for _curr_column_idx in range(len(_curr_row)): _curr_change_item_idx = self.gr_preview.insert(parent=_curr_item_idx, index="end", iid="", text=str( self.merge.destination.field_names[_curr_column_idx])) self.gr_preview.item(_curr_change_item_idx, values=[str(_curr_row[_curr_column_idx])]) if _commit == True: _simulation_expression = "Merge" else: _simulation_expression = "Simulated merge" if not (self.merge.insert or self.merge.delete or self.merge.update): self.notify_task( _simulation_expression + " done. (Expecting merge results? Neither insert, delete or update is selected)", 100) else: self.notify_task(_simulation_expression + " done.", 100) def on_preview_selected(self, *args): _selection = self.gr_preview.selection() if len(_selection) > 0: _item = self.gr_preview.item(_selection[0]) self.preview_detail.set(str(",".join([str(_item) for _item in _item["values"]])))
class Plastey(Tk): #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # def __init__(self, *args, **kwargs): Tk.__init__(self, *args, **kwargs) # Set window title self.wm_title('Plastey Configurator') # Create GUI driven variables self._mode = BooleanVar() self._base = BooleanVar() self._comm = BooleanVar() self._pass = StringVar() self._addressed = StringVar() self._connected = StringVar() self._this_host = StringVar() self._this_port = StringVar() self._other_host = StringVar() self._other_port = StringVar() # Create GUI self._build_gui() # Set default values for GUI driven variables self._mode.set(MODE_SINGLE_PLAYER) self._base.set(BASE_OPENED_GEOMETRY) self._comm.set(COMM_SOCKET_SERVER) self._pass.set('') self._addressed.set(ADDR_HAVE_ADDRESS if check(COMM_THIS_HOST) else ADDR_NO_ADDRESS) self._connected.set(CONN_NOT_CONNECTED) self._this_host.set(COMM_THIS_HOST) self._this_port.set(COMM_THIS_PORT) self._other_host.set(COMM_THIS_HOST) self._other_port.set(COMM_OTHER_PORT) # Follow changes on password self._pass.trace('w', self._on_bind_address) # Create folder structures if they don't exists yet makedirs(FILE_TEMPORARY_FOLDER, exist_ok=True) makedirs(FILE_PERMANENT_FOLDER, exist_ok=True) makedirs(FILE_TEMP_SAVE_FOLDER, exist_ok=True) makedirs(FILE_AUTO_SAVE_FOLDER, exist_ok=True) #makedirs(FILE_TEMP_STATE_FOLDER, exist_ok=True) #makedirs(FILE_TEMP_FEEDS_FOLDER, exist_ok=True) #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # def _build_gui(self): # Create GUI sections row = 0 col = 0 # Warning text Label(master = self, text = WARN_TEXT, anchor = WEST, justify = CENTER).grid(row = row, column = col, sticky = NORTH_WEST, rowspan = 16) # Set column spacing self.columnconfigure(index = col, pad = GUI_SECTION_PAD_X) row = 0 col += 1 # Game mode options Label(master = self, text = 'Game Mode:').grid(row = row, column = col, sticky = WEST) row += 1 Radiobutton(master = self, text = 'Single Player', value = MODE_SINGLE_PLAYER, variable = self._mode).grid(row = row, column = col, sticky = WEST) row += 1 Radiobutton(master = self, text = 'Multi Player', value = MODE_MULTI_PLAYER, variable = self._mode).grid(row = row, column = col, sticky = WEST) row += 1 # Base object modes Label(master = self, text = 'Base Object:').grid(row = row, column = col, sticky = WEST) row += 1 Radiobutton(master = self, text = 'Plane mesh', value = BASE_OPENED_GEOMETRY, variable = self._base).grid(row = row, column = col, sticky = WEST) row += 1 Radiobutton(master = self, text = 'Sphere mesh', value = BASE_CLOSED_GEOMETRY, variable = self._base).grid(row = row, column = col, sticky = WEST) row += 1 # Start oculus-daemon Label(master = self, text = 'Daemons:').grid(row = row, column = col, sticky = WEST) row += 1 Button(master = self, text = 'Start OVRD', command = self._on_start_oculus_daemon).grid(row = row, column = col, sticky = WEST) # Set column spacing self.columnconfigure(index = col, pad = GUI_SECTION_PAD_X) row = 0 col += 1 # Multiplayer mode options Label(master = self, text = 'Multi Player Options:').grid(row = row, column = col, sticky = WEST, columnspan = 2) row += 1 Label(master = self, text = 'This role:').grid(row = row, column = col, sticky = WEST) Radiobutton(master = self, text = 'Server', value = COMM_SOCKET_SERVER, variable = self._comm).grid(row = row, column = col + 1, sticky = WEST) row += 1 Radiobutton(master = self, text = 'Client', value = COMM_SOCKET_CLIENT, variable = self._comm).grid(row = row, column = col + 1, sticky = WEST) row += 1 Label(master = self, text = 'This host:').grid(row = row, column = col, sticky = WEST) Entry(master = self, textvariable = self._this_host).grid(row = row, column = col + 1, sticky = WEST) row += 1 Label(master = self, text = 'This port:').grid(row = row, column = col, sticky = WEST) Entry(master = self, textvariable = self._this_port).grid(row = row, column = col + 1, sticky = WEST) row += 1 Label(master = self, text = 'Other host:').grid(row = row, column = col, sticky = WEST) Entry(master = self, textvariable = self._other_host).grid(row = row, column = col + 1, sticky = WEST) row += 1 Label(master = self, text = 'Other port:').grid(row = row, column = col, sticky = WEST) Entry(master = self, textvariable = self._other_port).grid(row = row, column = col + 1, sticky = WEST) row += 1 Button(master = self, text = 'Bind address', command = self._on_ask_password).grid(row = row, column = col, sticky = WEST + EAST) Label(master = self, textvariable = self._addressed).grid(row = row, column = col + 1, sticky = WEST) row += 1 Button(master = self, text = 'Connect machines', command = self._on_bind_address).grid(row = row, column = col, sticky = WEST + EAST) Label(master = self, textvariable = self._connected).grid(row = row, column = col + 1, sticky = WEST) # Set column spacing self.columnconfigure(index = col + 1, pad = GUI_SECTION_PAD_X) row = 0 col += 2 # Controller buttons Label(master = self, text = 'Controllers:').grid(row = row, column = col, sticky = WEST) row += 1 Button(master = self, text = 'Start game', command = self._on_start_game).grid(row = row, column = col, sticky = WEST + EAST) row += 1 Button(master = self, text = 'Restart game', command = self._on_restart_game).grid(row = row, column = col, sticky = WEST + EAST) row += 1 Button(master = self, text = 'Stop game', command = self._on_stop_game).grid(row = row, column = col, sticky = WEST + EAST) row += 1 Button(master = self, text = 'Save last mesh', command = self._on_save_mesh).grid(row = row, column = col, sticky = WEST + EAST) row += 1 Button(master = self, text = 'Load last mesh', command = self._on_load_mesh).grid(row = row, column = col, sticky = WEST + EAST) row += 1 Button(master = self, text = 'Save log file', command = self._on_save_log).grid(row = row, column = col, sticky = WEST + EAST) row += 1 #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # def _on_ask_password(self, *args, **kwargs): # Create a password-dialog self._dialog = Password(self._pass) #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # def _on_start_oculus_daemon(self, *args, **kwargs): print('starting daemon...') #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # def _on_bind_address(self, *args, **kwargs): # Check for status and if address is not bound if not check(COMM_THIS_HOST): # Bind address try: setup(self._this_host, user_pass=self._pass.get()) except CommunicationSetupError as exception: Report(exception.error) # Check status and report to user self._addressed.set(ADDR_HAVE_ADDRESS if check(COMM_THIS_HOST) else ADDR_NO_ADDRESS) #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # def _on_connect(self, *args, **kwargs): pass #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # def _on_start_game(self, *args, **kwargs): # HACK: Is this really the best option we have, to get into fullscreen, # other than using the blender's fullscreen option, which will # unfortunately resize the display's resolution??? :( window_command = ['sleep 1'] window_command.append('wmctrl -r :ACTIVE: ' '-e 0,{},{},{},{}'.format(DRAW_DISPLAY_X, DRAW_DISPLAY_Y, DRAW_RESOLUTION_X, DRAW_RESOLUTION_Y)) if DRAW_FULL_SCREEN: window_command.append('wmctrl -r :ACTIVE: -b add,fullscreen') Popen(args = ' && '.join(window_command), shell = True, stdin = PIPE, stderr = PIPE, universal_newlines=True) # Store subprocess, for further communication self._pipe = Popen(args = './plastey', stdin = PIPE, stdout = PIPE, stderr = PIPE, universal_newlines=True) #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # def _on_restart_game(self, *args, **kwargs): self._pipe.stdin.write('hello-world\n') #if not self._locked: # self._locked = True # with open(FILE_STATE_RESTART, mode='w') as file: # file.write('') # Thread(name = 'feedbackd-restart', # target = self._get_feedback_to_clean_up).start() #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # def _on_stop_game(self, *args, **kwargs): #if not self._locked: # self._locked = True # with open(FILE_STATE_SHUT_DOWN, mode='w') as file: # file.write('') # Thread(name = 'feedbackd-shutdown', # target = self._get_feedback_to_clean_up).start() self._pipe.communicate('hello-world\n') #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # def _on_save_mesh(self, *args, **kwargs): pass #if self._pipe.poll(): # print('saving inside game') #else: # print('save last auto-saved') #print('parent says: hey there, daemon!\n') #self._pipe.stdin.write('hey there, daemon!\n') #self._pipe.stdin.close() #try: # self._pipe.communicate('hey there, daemon!\n', timeout=0.1) ## Hack: since communicate waits for the subprocess to terminate, the ## timeout value is necessary, however, after the timeout, the app ## won't terminate either. One solution should be ## self._pipe.stdin.write instead of the communicate method, but ## unfortunately the process's stdin.read/input are not getting ## anything.. is it because the value set to shell=True? #except TimeoutExpired: # return #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # def _on_load_mesh(self, *args, **kwargs): pass #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # def _on_save_log(self, *args, **kwargs): pass #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # def run(self): self.mainloop()
class PolicyFrame(Frame): ''' ClassPolicy screen record blocker. A custom image can be used. ''' def __init__(self, master, title): Frame.__init__(self, master) self.grid() self.block = BooleanVar() self.block.set(True) self.use_custom = BooleanVar() self.use_custom.set(False) self.title = title self.l1 = Label(self, text='The last time your teacher used ClassPolicy') self.l1.grid(row=0) self.last_used = Text(self, height=1, width=30) self.last_used.grid(row=1) self.last_used.insert(END, 'Has not used yet') self.l2 = Label(self, text='Current time') self.l2.grid(row=0, column=1) self.current = Text(self, height=1, width=20) self.current.grid(row=1, column=1) self.options = Frame(self) self.options.grid(row=2, column=0, columnspan=2, sticky=W) self.b_change = Button(self.options, text='Change Custom Image', command=self.change_custom) self.b_change.grid() self.b_get_location = Button(self.options, text='Custom Image View', command=self.view_custom) self.b_get_location.grid(row=0, column=1) self.blocking = Checkbutton(self.options, text='Block CP', var=self.block, onvalue=True, offvalue=False) self.blocking.grid(row=0, column=2) self.using_custom = Checkbutton(self.options, text='Use Custom Image', var=self.use_custom, onvalue=True, offvalue=False) self.using_custom.grid(row=0, column=3) def format_time(self, now=time.localtime()): ''' For ''' now = list(now) if now[5] < 10: now[5] = '0' + str(now[5]) if int(now[3]) == 0: now[3] = 12 if len(str(now[3])) == 1: now[3] = '0' + str(now[3]) if len(str(now[4])) == 1: now[4] = '0' + str(now[4]) return str( str(now[3]) + ':' + str(now[4]) + ':' + str(now[5]) + ' ' + str(now[1]) + '/' + str(now[2]) + '/' + str(now[0])) def check(self): if self.use_custom.get() == 1 and self.get_custom() != '': #Using custom image try: shutil.copy(self.get_custom(), f'c:\\classpolicy\\{os.getlogin()}.jpeg') except: pass #Copies personal file to ClassPolicy folder try: same = filecmp.cmp(self.get_custom(), f'c:\\classpolicy\\{os.getlogin()}.jpeg') except: same = False if same == False: self.insert_last_used() try: os.remove(f'c:\\classpolicy\\{os.getlogin()}.jpeg') except: pass elif self.use_custom.get() == 1 and self.get_custom() == '': #Need to set a custom image self.change_custom() else: #Not using custom image if os.path.exists(f'c:\\classpolicy\\{os.getlogin()}.jpeg'): #If the ClassPolicy file gets created self.insert_last_used() try: os.remove(f'c:\\classpolicy\\{os.getlogin()}.jpeg') except: pass def update(self): self.insert_time() def get_custom(self): try: with open(PREFERENCES, 'r') as file: content = file.read() file.close() return content except PermissionError: showerror(title=' denied', message=''' Could not get the custom image. Check your permissions.''') self.use_custom.set(0) def change_custom(self): content = askopenfilename(title='Open image') if content != '': try: with open(PREFERENCES, 'w+') as file: file.write(content) file.close() except PermissionError as err: print(err) self.use_custom.set(0) else: self.use_custom.set(0) def view_custom(self): pass def insert_time(self): self.current.delete(1.0, END) self.current.insert(END, self.format_time(time.localtime())) def insert_last_used(self): self.last_used.delete(1.0, END) self.last_used.insert(END, self.format_time(time.localtime()))
class TkApp(Tk): """ The main Tk class for the gui of simplebackup """ def __init__(self, **kwargs): super().__init__() title = "Simple Backup | V" + __version__ self.wm_title(title) self.protocol("WM_DELETE_WINDOW", self.on_closing) self.__thread = None self.__files_found = 0 self.__files_copied = 0 config_fn = kwargs.get("config_fn", user_config_filepath()) self.__app_config = Config_Handler(config_fn) self.__curr_config = self.__app_config.default_config_i self.__menu = Menu(self) self.__menu_file = Menu(self.__menu, tearoff=0) self.__menu_file.add_command(label="Quit", command=self.quit) self.__menu_config = Menu(self.__menu, tearoff=0) self.__menu_config.add_command(label="New", command=self.new_config) self.__menu_config.add_command(label="Load", command=self.switch_config) self.__menu_config.add_command(label="Change Default", command=self.change_default_config) self.__menu_config.add_command(label="Rename Current", command=self.rename_curr_conf) self.__menu_config.add_separator() self.__menu_config.add_command(label="Delete Current", command=self.delete_current_config) self.__menu_config.add_command(label="Delete All", command=self.reset_config) self.__menu_help = Menu(self.__menu, tearoff=0) self.__menu_help.add_command(label="Check for Updates", command=self.show_update_popup) self.__menu_help.add_command(label="About", command=self.show_about_popup) self.__menu.add_cascade(label="File", menu=self.__menu_file) self.__menu.add_cascade(label="Config", menu=self.__menu_config) self.__menu.add_cascade(label="Help", menu=self.__menu_help) self.__title_l = Label(self, text=title, font=(16)) self.__curr_config_name_l = Label(self) self.__last_backup_l = Label(self) self.__set_versions_to_keep = Button( self, text="Set Versions To Keep", command=self.update_versions_to_keep) self.__versions_to_keep_l = Label(self) self.__inc_folder_bnt = Button(self, text="Include Another Folder", command=self.add_included_folder) self.__included_folders_lb = Listbox(self, height=4) self.__included_folders_lb.bind("<<ListboxSelect>>", self.remove_selected_included_folder) self.__included_folders_lb.bind('<FocusOut>', self.deselect_included_folder) self.__excl_folder_bnt = Button(self, text="Exclude Another Folder", command=self.add_excluded_folder) self.__excluded_folders_lb = Listbox(self, height=4) self.__excluded_folders_lb.bind("<<ListboxSelect>>", self.remove_selected_excluded_folder) self.__excluded_folders_lb.bind('<FocusOut>', self.deselect_excluded_folder) self.__backup_to_bnt = Button(self, text="Backup Folder", command=self.set_backup_folder) self.__backup_folder_l = Label(self) self.__use_tar_l = Label(self, text="Use Tar") self.__use_tar_var = BooleanVar(self) self.__use_tar_var.trace_add("write", self.use_tar_changed) self.__use_tar = Checkbutton(self, variable=self.__use_tar_var) self.__backup_start_bnt = Button(self, text="Start Backup", command=self.start_backup) self.__progress = Progressbar(self) self.__statusbar = Label(self, text="ok", relief=SUNKEN, anchor=W) self._load_display() self._layout() if self.__app_config.show_help: self.show_help_popup() def on_closing(self): """ called on window close """ if self.__files_found != self.__files_copied: if messagebox.askyesno("Backup Running", "Do you want to stop the backup?"): self.destroy() else: self.destroy() def _load_display(self): """ load the widgets with data from the current backup config, should be run after loading a config from file and at app launch """ self.__versions_to_keep = self.__app_config.get_versions_to_keep( self.__curr_config) self.__included_folders = self.__app_config.get_included_folders( self.__curr_config) self.__excluded_folders = self.__app_config.get_excluded_folders( self.__curr_config) self.__backup_location = self.__app_config.get_backup_path( self.__curr_config) curr_conf_name = self.__app_config.get_config_name(self.__curr_config) self.__curr_config_name_l.config(text=f"Config Name: {curr_conf_name}") self.__last_backup_l.config( text= f"Last Known Backup: {self.__app_config.get_human_last_backup(self.__curr_config)}" ) self.__versions_to_keep_l.config(text=self.__versions_to_keep) self.__included_folders_lb.delete(0, END) self.__included_folders_lb.insert(0, *self.__included_folders) self.__excluded_folders_lb.delete(0, END) self.__excluded_folders_lb.insert(0, *self.__excluded_folders) self.__backup_folder_l.config(text=str(self.__backup_location)) self.__use_tar_var.set( self.__app_config.get_use_tar(self.__curr_config)) def switch_config(self): """ switches what config to use for backup, asks the user for a config to load, then loads the display """ next_combo = ask_combobox("Load Config", "Config Name", self.__app_config.get_config_names()) if next_combo != None: self.__curr_config = next_combo self._load_display() def change_default_config(self): """ switches what config to use for the default backup, asks the user for a config to load """ next_combo = ask_combobox("Default Config", "Config Name", self.__app_config.get_config_names()) if next_combo != None: self.__app_config.default_config_i = next_combo def rename_curr_conf(self): """ rename a existing config, will ask the user in a popup string input """ new_name = simpledialog.askstring("Rename Config", "New Name") if new_name: self.__app_config.rename_config(self.__curr_config, new_name) self._load_display() def new_config(self): """ creates a new empty backup config, asks the user for config name """ name = simpledialog.askstring("New Config", "Config Name") if name: self.__app_config.create_config(name) def delete_current_config(self): """ deletes the current selected config, asks the user to confirm """ if messagebox.askyesno( "Confirm Delete", "Are you sure you want to delete the current config?"): self.__app_config.remove_config(self.__curr_config) self.__curr_config = self.__app_config.default_config_i self._load_display() def reset_config(self): """ resets all the user configs, asks the user to confirm """ if messagebox.askyesno( "Confirm Reset", "Are you sure you want to reset the all configurations?"): self.__app_config.reset_config() self.__curr_config = self.__app_config.default_config_i self._load_display() def use_tar_changed(self, *args): """ called each time the __use_tar_var is called """ self.__app_config.set_use_tar(self.__curr_config, self.__use_tar_var.get()) def update_versions_to_keep(self): """ update the number of versions to keep, asks the user for a integer """ new_val = simpledialog.askinteger( "Versions To Keep", "How many backups do you want to keep", minvalue=0) if new_val != self.__versions_to_keep and new_val != None: self.__versions_to_keep = new_val self.__app_config.set_versions_to_keep(self.__curr_config, self.__versions_to_keep) self.__versions_to_keep_l.config(text=self.__versions_to_keep) def deselect_included_folder(self, *args): """ deselects the selected element in included folder """ self.__included_folders_lb.selection_clear(0, END) def deselect_excluded_folder(self, *args): """ deselects the selected element in excluded folder """ self.__excluded_folders_lb.selection_clear(0, END) def add_included_folder(self): """ add a folder to include in the backup, will ask user for a directory """ folder = filedialog.askdirectory(initialdir="/", title="Select Folder To Backup") if folder: folder_path = Path(folder) if folder_path != self.__backup_location: self.__included_folders.append(folder_path) self.__included_folders_lb.insert(END, folder_path) self.__app_config.set_included_folders(self.__curr_config, self.__included_folders) else: messagebox.showwarning( title="Folder Same As Backup Path", message= "You selected a folder that was the same as the backup path!" ) def remove_selected_included_folder(self, *args): """ remove the currently selected item in the included folders ListBox, will ask the user to confirm """ curr_selection = self.__included_folders_lb.curselection() # check if there is a selection if curr_selection: if messagebox.askyesno("Confirm Delete", "Are you want to delete this folder?"): index_to_del = curr_selection[0] self.__included_folders.pop(index_to_del) self.__app_config.set_included_folders(self.__curr_config, self.__included_folders) self.__included_folders_lb.delete(index_to_del) self.deselect_included_folder() def add_excluded_folder(self): """ add a folder to exclude in the backup, will ask user for a directory """ folder = filedialog.askdirectory(initialdir="/", title="Select Folder To Exclude") if folder: folder_path = Path(folder) self.__excluded_folders.append(folder_path) self.__excluded_folders_lb.insert(END, folder_path) self.__app_config.set_excluded_folders(self.__curr_config, self.__excluded_folders) def remove_selected_excluded_folder(self, *args): """ remove the currently selected item in the excluded folders ListBox, will ask the user to confirm """ curr_selection = self.__excluded_folders_lb.curselection() # check if there is a selection if curr_selection: if messagebox.askyesno("Confirm Delete", "Are you want to delete this folder?"): index_to_del = curr_selection[0] self.__excluded_folders.pop(index_to_del) self.__app_config.set_excluded_folders(self.__curr_config, self.__excluded_folders) self.__excluded_folders_lb.delete(index_to_del) self.deselect_excluded_folder() def set_backup_folder(self): """ sets the backup folder by asking the user for a base directory """ folder = filedialog.askdirectory(initialdir="/", title="Select Where To Backup To") if folder: self.__backup_location = Path(folder) self.__backup_folder_l.config(text=folder) self.__app_config.set_backup_path(self.__curr_config, self.__backup_location) def enable_gui(self): """ enable the gui buttons, run when a backup has completed """ self.__set_versions_to_keep.config(state=NORMAL) self.__inc_folder_bnt.config(state=NORMAL) self.__included_folders_lb.config(state=NORMAL) self.__excl_folder_bnt.config(state=NORMAL) self.__excluded_folders_lb.config(state=NORMAL) self.__backup_to_bnt.config(state=NORMAL) self.__use_tar.config(state=NORMAL) self.__backup_start_bnt.config(state=NORMAL) def disable_gui(self): """ disable the gui buttons, run when a backup is started """ self.__set_versions_to_keep.config(state=DISABLED) self.__inc_folder_bnt.config(state=DISABLED) self.__included_folders_lb.config(state=DISABLED) self.__excl_folder_bnt.config(state=DISABLED) self.__excluded_folders_lb.config(state=DISABLED) self.__backup_to_bnt.config(state=DISABLED) self.__use_tar.config(state=DISABLED) self.__backup_start_bnt.config(state=DISABLED) def progress_find_incr(self, finished=False): """ increment the progress bar for finding files by 1 or mark as finished :param finished: mark the progressbar as finished """ if finished: self.__progress.config(mode="determinate") self.__progress.config(value=0, maximum=self.__files_found) self.__statusbar.config(text=f"Found {self.__files_found} Files") else: self.__files_found += 1 self.__progress.config(value=self.__files_found) self.__statusbar.config( text=f"Searching For Files, Found {self.__files_found} Files") def progress_copy_incr(self): """ increment the progress bar for copying files by 1 or mark as finished """ self.__files_copied += 1 self.__progress.config(value=self.__files_copied) self.__statusbar.config( text=f"Copying Files {self.__files_copied} of {self.__files_found}" ) if self.__files_copied == self.__files_found: self.__app_config.set_last_backup(self.__curr_config, datetime.utcnow()) self.__last_backup_l.config( text= f"Last Known Backup: {self.__app_config.get_human_last_backup(self.__curr_config)}" ) self.__statusbar.config(text=f"Finished Copying Files") messagebox.showinfo(title="Finished Copying Files", message="Finished copying all found files") # reset counters self.__files_found = 0 self.__files_copied = 0 self.__progress.config(value=0, maximum=100) self.enable_gui() def start_backup(self): """ starts the backup """ if not self.__backup_location: # no backup location was selected messagebox.showwarning( title="Backup Location Not Selected", message="You did not select a backup location!") elif not self.__included_folders: # no folders where found to backup messagebox.showwarning( title="No Folders To Backup", message="You did not add any folders to backup!") else: # basic checks passed self.disable_gui() # prep for search of files self.__progress.config(mode="indeterminate") self.__statusbar.config(text=f"Searching For Files") self.__thread = BackupThread( self.__included_folders, self.__excluded_folders, self.__backup_location, self.__versions_to_keep, self.progress_find_incr, self.progress_copy_incr, self.handle_error_message, self.__use_tar_var.get()) # start the background backup thread so GUI wont appear frozen self.__thread.start() def show_about_popup(self): """ show the about popup """ messagebox.showinfo( "About", "simplebackup V" + __version__ + """ is cross-platform backup program written in python. This app was made by enchant97/Leo Spratt. It is licenced under GPL-3.0""") def show_update_popup(self): """ open the default webbrowser to the update url """ webbrowser.open(UPDATE_URL) def show_help_popup(self): messagebox.showinfo( "Welcome", """Welcome to simplebackup, here is some help to get you started: \nIncluding a folder to backup - Press the 'Include Folder' button to add a folder to backup - Remove a entry by clicking on the list below \nExcluding a folder from the backup - Press the 'Exclude Folder' button to skip a folder to backup - Remove a entry by clicking on the list below \nSetting where backups are stored - Click the 'Backup Folder' button to set where backups should be placed \nMultiple backup configs Use the 'Config' button in the titlebar to change varius settings like creating a new config \nVersions to keep This will be the number of backup to keep in the backup folder """) self.__app_config.show_help = False def handle_error_message(self, error_type: ERROR_TYPES): self.__statusbar.config(text="Failed") if error_type is ERROR_TYPES.NO_BACKUP_WRITE_PERMISION: messagebox.showerror("No Write Permission", ERROR_TYPES.NO_BACKUP_WRITE_PERMISION.value) elif error_type is ERROR_TYPES.NO_BACKUP_READ_PERMISION: messagebox.showerror("No Read Permission", ERROR_TYPES.NO_BACKUP_READ_PERMISION.value) elif error_type is ERROR_TYPES.NO_FILES_FOUND_TO_BACKUP: messagebox.showerror("No Files Found", ERROR_TYPES.NO_FILES_FOUND_TO_BACKUP.value) elif error_type is ERROR_TYPES.NO_BACKUP_PATH_FOUND: messagebox.showerror("No Backup Path Found", ERROR_TYPES.NO_BACKUP_PATH_FOUND.value) self.__progress.config(mode="determinate") self.enable_gui() def _layout(self): self.config(menu=self.__menu) self.__title_l.pack(fill=X, pady=10, padx=5) self.__curr_config_name_l.pack(fill=X, padx=5) self.__last_backup_l.pack(fill=X, padx=5) self.__set_versions_to_keep.pack(fill=X, padx=5) self.__versions_to_keep_l.pack(fill=X, padx=5) self.__inc_folder_bnt.pack(fill=X, padx=5) self.__included_folders_lb.pack(fill=X, padx=5) self.__excl_folder_bnt.pack(fill=X, padx=5) self.__excluded_folders_lb.pack(fill=X, padx=5) self.__backup_to_bnt.pack(fill=X, padx=5) self.__backup_folder_l.pack(fill=X, padx=5) self.__use_tar_l.pack(fill=X, padx=5) self.__use_tar.pack(fill=X, padx=5) self.__backup_start_bnt.pack(fill=X, padx=5) self.__progress.pack(fill=X) self.__statusbar.pack(side=BOTTOM, fill=X) self.wm_minsize(300, self.winfo_height()) self.wm_resizable(True, False)
class GUIDatasetClasificacion(): def __init__(self, root): self.root = root #TODO Esta información se lee desde .cfg con ConfigParser self.ruta_datasets = '' self.ruta_resultados = '' self.rutas_relativas = BooleanVar(root, True) self.usa_sha1 = BooleanVar(root, True) self._tamanyo_muestra = 5 self.clase_al_final = BooleanVar(root, True) self.mostrar_proceso = BooleanVar(root, False) self.lee_configuracion() estilo_bien = Style() estilo_bien.configure('G.TLabel', foreground='green') estilo_mal = Style() estilo_mal.configure('R.TLabel', foreground='red') self.crea_GUI() self.root.title(APP_NAME) # self.root.update() # self.root.minsize(self.root.winfo_width(), self.root.winfo_height()) self.root.minsize(800, 500) # self.lee_configuracion() self.root.protocol('WM_DELETE_WINDOW', self.cerrar_aplicacion) def crea_GUI(self): root = self.root #Menús self.menubar = Menu(root, tearoff=0) m_archivo = Menu(self.menubar, tearoff=0) m_archivo.add_command(label='Abrir', command=self.abrir_dataset, accelerator='Ctrl+O') m_archivo.add_separator() m_archivo.add_command(label='Salir', command=self.cerrar_aplicacion) self.menubar.add_cascade(label='Archivo', menu=m_archivo) m_proyecto = Menu(self.menubar, tearoff=0) m_proyecto.add_command(label='Abrir', command=self.abrir_proyecto, state="disabled") m_proyecto.add_separator() m_proyecto.add_checkbutton(label='Clase al final', onvalue=True, offvalue=False, variable=self.clase_al_final) self.menubar.add_cascade(label='Proyecto', menu=m_proyecto) self.m_configuracion = Menu(self.menubar, tearoff=0) self.m_configuracion.add_command( label='Ruta datasets', command=lambda: self.rutas('datasets')) self.m_configuracion.add_command( label='Ruta resultados', command=lambda: self.rutas('resultados')) self.m_configuracion.add_checkbutton(label='Rutas relativas', onvalue=True, offvalue=False, variable=self.rutas_relativas, command=self.cambia_rutas) self.m_configuracion.add_separator() #TODO Revisar self.v_tamanyo_muestra, no la uso # self.v_tamanyo_muestra = StringVar(root, 'Tamaño muestra ({:,})'.\ # format(self._tamanyo_muestra)) self.m_cfg_tamanyo_muestra = \ self.m_configuracion.add_command(label='Tamaño muestra ({:,})'.\ format(self._tamanyo_muestra), command=lambda: self.tamanyo_muestra(\ self._tamanyo_muestra)) self.m_configuracion.add_separator() self.m_configuracion.add_checkbutton(label='Utiliza sha1', onvalue=True, offvalue=False, variable=self.usa_sha1) self.menubar.add_cascade(label='Configuración', menu=self.m_configuracion) m_ver = Menu(self.menubar, tearoff=0) self.v_tipo_dataset = StringVar(self.root, 'Dataset original') m_ver.add_radiobutton(label='Dataset original', value='Dataset original', variable=self.v_tipo_dataset, command=self.muestra_atributos_y_clase) m_ver.add_radiobutton(label='Dataset sin evidencias incompletas', value='Dataset sin evidencias incompletas', variable=self.v_tipo_dataset, command=self.muestra_atributos_y_clase) m_ver.add_radiobutton(label='Dataset sin atributos constantes', value='Dataset sin atributos constantes', variable=self.v_tipo_dataset, command=self.muestra_atributos_y_clase) m_ver.add_radiobutton(label='Catálogo', value='Catálogo', variable=self.v_tipo_dataset, command=self.muestra_atributos_y_clase) m_ver.add_radiobutton(label='Catálogo Robusto', value='Catálogo Robusto', variable=self.v_tipo_dataset, command=self.muestra_atributos_y_clase) m_ver.add_separator() m_ver.add_checkbutton(label='Log del proceso', onvalue=True, offvalue=False, variable=self.mostrar_proceso, state='disabled') self.menubar.add_cascade(label='Ver', menu=m_ver) root.config(menu=self.menubar) #Dataset de clasificación lf_dataset = LabelFrame(root, text='Dataset de Clasificación') lf_dataset.pack(fill='both', expand=True, padx=5, pady=5) Label(lf_dataset, text='Nombre:').grid(row=0, column=0, sticky='e') self.v_nombre_dataset = StringVar(root, '-------') self.l_nombre_dataset = Label(lf_dataset, textvariable=self.v_nombre_dataset) self.l_nombre_dataset.grid(row=0, column=1, sticky='w') Label(lf_dataset, text='Tamaño:').grid(row=0, column=2, sticky='e') self.v_tamanyo_dataset = StringVar(root, '-------') Label(lf_dataset, textvariable=self.v_tamanyo_dataset).grid(row=0, column=3, sticky='w') Label(lf_dataset, text='Ubicación:').grid(row=1, column=0, sticky='e') self.v_ruta_dataset = StringVar(root, '-------------------------') #TODO Expandir en columnas 1-3, puede ser muy larga Label(lf_dataset, textvariable=self.v_ruta_dataset).grid(row=1, column=1, sticky='w', columnspan=3) #Dataset de clasificación / Muestra lf_dataset_muestra = LabelFrame(lf_dataset, text='Muestra') lf_dataset_muestra.grid(row=2, column=0, sticky='nsew', columnspan=4, padx=5, pady=5) self.sb_v_t_muestra = Scrollbar(lf_dataset_muestra) self.sb_v_t_muestra.grid(row=0, column=1, sticky='sn') self.sb_h_t_muestra = Scrollbar(lf_dataset_muestra, orient='horizontal') self.sb_h_t_muestra.grid(row=1, column=0, sticky='ew') self.t_muestra = Text(lf_dataset_muestra, yscrollcommand=self.sb_v_t_muestra.set, xscrollcommand=self.sb_h_t_muestra.set, bd=0, wrap='none', state='disabled', height=8) self.t_muestra.grid(row=0, column=0, sticky='nswe') self.sb_v_t_muestra.config(command=self.t_muestra.yview) self.sb_h_t_muestra.config(command=self.t_muestra.xview) lf_dataset_muestra.rowconfigure(0, weight=1) lf_dataset_muestra.columnconfigure(0, weight=1) lf_dataset.rowconfigure(2, weight=3) lf_dataset.columnconfigure(1, weight=1) lf_dataset.columnconfigure(3, weight=1) #Dataset de clasificación / Evidencias lf_dataset_evidencias = LabelFrame(lf_dataset, text='Evidencias') lf_dataset_evidencias.grid(row=3, column=0, sticky='nsew', padx=5, pady=5) Label(lf_dataset_evidencias, text='Total:').grid(row=0, column=0, sticky='e') self.v_evidencias_total = StringVar(root, '-------') Label(lf_dataset_evidencias, textvariable=self.v_evidencias_total).\ grid(row=0, column=1, sticky='w') Label(lf_dataset_evidencias, text='Completas:').grid(row=1, column=0, sticky='e') self.v_evidencias_completas = StringVar(root, '-------') Label(lf_dataset_evidencias, textvariable=self.v_evidencias_completas).\ grid(row=1, column=1, sticky='w') Label(lf_dataset_evidencias, text='Únicas:').grid(row=2, column=0, sticky='e') self.v_evidencias_catalogo = StringVar(root, '-------') Label(lf_dataset_evidencias, textvariable=self.v_evidencias_catalogo).\ grid(row=2, column=1, sticky='w') Label(lf_dataset_evidencias, text='Robustas:').grid(row=3, column=0, sticky='e') self.v_evidencias_robustas = StringVar(root, '-------') Label(lf_dataset_evidencias, textvariable=self.v_evidencias_robustas).\ grid(row=3, column=1, sticky='w') #Dataset de clasificación / Atributos lf_dataset_clase_y_atributos = LabelFrame(lf_dataset, text='Clase y atributos') lf_dataset_clase_y_atributos.grid(row=3, column=1, sticky='nsew', columnspan=3, padx=5, pady=5) PROPIEDADES_ATRIBUTOS = ('Nombre', 'count', 'unique', 'top', 'freq', 'mean', 'std', 'min', '25%', '50%', '75%', 'max') self.sb_h_tv_clase = Scrollbar(lf_dataset_clase_y_atributos, orient='horizontal') self.sb_h_tv_clase.grid(row=1, column=0, sticky='ew') self.tv_clase = Treeview(lf_dataset_clase_y_atributos, columns=PROPIEDADES_ATRIBUTOS, height=1, xscrollcommand=self.sb_h_tv_clase.set) self.tv_clase.grid(row=0, column=0, sticky='ew') self.sb_h_tv_clase.config(command=self.tv_clase.xview) self.tv_clase.heading("#0", text="#") self.tv_clase.column("#0", minwidth=30, width=40, stretch=False) self.sb_v_tv_atributos = Scrollbar(lf_dataset_clase_y_atributos) self.sb_v_tv_atributos.grid(row=2, column=1, sticky='sn') self.sb_h_tv_atributos = Scrollbar(lf_dataset_clase_y_atributos, orient='horizontal') self.sb_h_tv_atributos.grid(row=3, column=0, sticky='ew') self.tv_atributos = Treeview(lf_dataset_clase_y_atributos, columns=PROPIEDADES_ATRIBUTOS, yscrollcommand=self.sb_v_tv_atributos.set, xscrollcommand=self.sb_h_tv_atributos.set) self.tv_atributos.grid(row=2, column=0, sticky='nsew') self.tv_atributos.bind('<ButtonRelease-1>', self.selectItem) self.sb_v_tv_atributos.config(command=self.tv_atributos.yview) self.sb_h_tv_atributos.config(command=self.tv_atributos.xview) self.tv_atributos.heading("#0", text="#") self.tv_atributos.column("#0", minwidth=30, width=40, stretch=False) for i in PROPIEDADES_ATRIBUTOS: self.tv_clase.heading(i, text=i) self.tv_clase.column(i, minwidth=50, width=50, stretch=False) self.tv_atributos.heading(i, text=i) self.tv_atributos.column(i, minwidth=50, width=50, stretch=False) lf_dataset_clase_y_atributos.rowconfigure(2, weight=1) lf_dataset_clase_y_atributos.columnconfigure(0, weight=1) lf_dataset.rowconfigure(3, weight=1) def abrir_dataset(self): inicio = time.time() #TODO Las constantes se podrán modificar a través de .cfg nombre = askopenfilename( initialdir=self.ruta_datasets, filetypes=(('Archivos de valores separado por comas', '*.csv'), ('Todos los archivos', '*.*')), title='Selecciona un Dataset de Clasificación') self.root.focus_force() if not nombre: return self.v_nombre_dataset.set( os.path.splitext(os.path.basename(nombre))[0]) #TODO Esto debería hacerlo en otro sitio, no cuando lo elijo con # filedialog, y tener en cuenta self.usa_sha1 if os.path.exists(os.path.dirname(nombre)): self.l_nombre_dataset.configure(style='G.TLabel') else: self.l_nombre_dataset.configure(style='R.TLabel') self.v_tamanyo_dataset.set(tamanyo_legible(os.path.getsize(nombre))) self.v_ruta_dataset.set(os.path.relpath(os.path.dirname(nombre)) \ if self.rutas_relativas.get() else \ os.path.dirname(nombre)) self.limpia_muestra() self.limpia_atributos_y_clase() self.root.update() #TODO Usar hilos o procesos para leer grandes datasets sin problemas # self.progreso = Toplevel(self.root) # self.progreso.title("Leyendo Dataset de Clasificación") # barra = Progressbar(self.progreso, length=200, mode="indeterminate") # barra.pack() # self.q = Queue() # hilo_lectura = Process(target=self.get_dc) # hilo_lectura.start() ## self.dc = self.q.get() ## hilo_lectura.join() # self.root.after(50, self.check_if_running, hilo_lectura, self.progreso) self.dc = DC(self.v_ruta_dataset.get(), self.v_nombre_dataset.get(), self.ruta_resultados, guardar_resultados=False, clase_al_final=self.clase_al_final.get(), mostrar_proceso=self.mostrar_proceso, num_filas_a_leer=None, obtener_catalogo_robusto=False, guardar_datos_proyecto=False, mostrar_uso_ram=False) self.escribe_datos() def escribe_datos(self): self.escribe_muestra() self.v_evidencias_total.set('{:,}'.\ format(self.dc.info_dataset_original.num_evidencias())) self.v_evidencias_completas.set('{:,}'.\ format(self.dc.info_dataset_sin_datos_desconocidos.num_evidencias())) self.v_evidencias_catalogo.set('{:,}'.\ format(self.dc.info_catalogo.num_evidencias())) self.v_evidencias_robustas.set('{:,}'.\ format(self.dc.info_catalogo_robusto.num_evidencias())) self.muestra_atributos_y_clase() self.root.title('{} - {}'.format(APP_NAME, self.v_nombre_dataset.get())) def get_dc(self): #TODO No puedo crear self.dc en un try mientras depure DC # try: self.dc = DC(self.v_ruta_dataset.get(), self.v_nombre_dataset.get(), self.ruta_resultados, guardar_resultados=False, clase_al_final=self.clase_al_final, mostrar_proceso=self.mostrar_proceso, num_filas_a_leer=None, obtener_catalogo_robusto=False, guardar_datos_proyecto=False, mostrar_uso_ram=False) self.q.put(self.dc) # except Exception as e: # self.t_muestra.delete(1.0, 'end') # self.t_muestra.insert('end', e) def check_if_running(self, hilo, ventana): """Check every second if the function is finished.""" if hilo.is_alive(): self.root.after(50, self.check_if_running, hilo, ventana) else: ventana.destroy() self.escribe_datos() def abrir_proyecto(self): inicio = time.time() #TODO Diseñar estrategia para que el usuario sepa si ha de cambiarlo. # Podría bastar con mostrarle los atributos y sus características. # clase_al_final = self._clase_al_final #TODO Las constantes se podrán modificar a través de .cfg nombre = askopenfilename(initialdir=self.ruta_resultados, filetypes=(('Proyectos ACDC', '*.prjACDC'), ('Todos los archivos', '*.*')), title='Selecciona un proyecto ACDC') if nombre is None: return #TODO ¿Mostrar sólo el nombre del dataset original? self.root.title('{} - {}'.format( APP_NAME, os.path.splitext(os.path.basename(nombre))[0])) def rutas(self, r=None): ruta = askdirectory(title='Directorio de {}'.format(r), initialdir=eval('self.ruta_{}'.format(r)), mustexist=True) if ruta != '': if self.rutas_relativas.get(): if r == 'datasets': self.ruta_datasets = os.path.relpath(ruta) else: self.ruta_resultados = os.path.relpath(ruta) else: if r == 'datasets': self.ruta_datasets = ruta else: self.ruta_resultados = ruta def cambia_rutas(self): if self.rutas_relativas.get(): self.ruta_datasets = os.path.relpath(self.ruta_datasets) self.ruta_resultados = os.path.relpath(self.ruta_resultados) else: self.ruta_datasets = os.path.abspath(self.ruta_datasets) self.ruta_resultados = os.path.abspath(self.ruta_resultados) def limpia_atributos_y_clase(self): for i in self.tv_clase.get_children(): self.tv_clase.delete(i) for i in self.tv_atributos.get_children(): self.tv_atributos.delete(i) def limpia_muestra(self): self.t_muestra['state'] = 'normal' self.t_muestra.delete(1.0, 'end') self.t_muestra['state'] = 'disabled' def tamanyo_muestra(self, tamanyo): nuevo_tamanyo = askinteger('Muestra', '¿Cuántas evidencias quieres ver?', parent=self.root, minvalue=1, initialvalue=self._tamanyo_muestra) # minvalue=0, maxvalue=1000) if nuevo_tamanyo: self._tamanyo_muestra = nuevo_tamanyo #TODO Debería averiguar el índice del menú que quiero modificar self.m_configuracion.entryconfigure(4, label='Tamaño muestra ({:,})'.\ format(self._tamanyo_muestra)) self.escribe_muestra() #TODO Tratar excepciones para que no se quede habilitada la escritura def escribe_muestra(self): self.t_muestra['state'] = 'normal' self.t_muestra.delete(1.0, 'end') self.t_muestra.insert('end', '#######################################'\ '########################\n') self.t_muestra.insert('end', ' PRIMERAS {:,} LÍNEAS DEL DATASET DE '\ 'CLASIFICACIÓN ORIGINAL\n'.\ format(self._tamanyo_muestra)) self.t_muestra.insert('end', '#######################################'\ '########################\n') self.t_muestra.insert('end', self.dc.muestra(self._tamanyo_muestra)) self.t_muestra.insert('end', '\n\n') self.t_muestra['state'] = 'disabled' def muestra_atributos_y_clase(self): self.limpia_atributos_y_clase() if self.v_tipo_dataset.get() == 'Dataset original': df = self.dc.info_dataset_original.columnas elif self.v_tipo_dataset.get() == 'Dataset sin evidencias incompletas': df = self.dc.info_dataset_sin_datos_desconocidos.columnas elif self.v_tipo_dataset.get() == 'Dataset sin atributos constantes': df = self.dc.info_dataset_sin_atributos_constantes.columnas elif self.v_tipo_dataset.get() == 'Catálogo': df = self.dc.info_catalogo.columnas elif self.v_tipo_dataset.get() == 'Catálogo Robusto': df = self.dc.info_catalogo_robusto.columnas self.tv_clase["columns"] = list(df.index).insert(0, 'Nombre') self.tv_atributos["columns"] = list(df.index).insert(0, 'Nombre') self.tv_clase.heading('Nombre', text='Nombre') self.tv_atributos.heading('Nombre', text='Nombre') for i in df.index: self.tv_clase.heading(i, text=i) self.tv_clase.column(i, minwidth=50, width=50, stretch=False) self.tv_atributos.heading(i, text=i) self.tv_atributos.column(i, minwidth=50, width=50, stretch=False) for i, atributo in enumerate(df.columns): valores = [valor if not pd.isnull(valor) else '-' for valor \ in df[atributo]] valores.insert(0, atributo) if atributo == self.dc.info_dataset_original.clase: self.tv_clase.insert('', 'end', text=(0), values=valores) else: self.tv_atributos.insert('', 'end', text=(i + 1), values=valores) #TODO Modificar para que muestre información relevante de la celda. def selectItem(self, event): curItem = self.tv_atributos.item(self.tv_atributos.focus()) col = self.tv_atributos.identify_column(event.x) print('curItem = ', curItem) print('col = ', col) if col == '#0': cell_value = curItem['text'] else: cell_value = curItem['values'][int(col[1:]) - 1] print('cell_value = ', cell_value) def lee_configuracion(self): archivo_cfg = ConfigParser() archivo_cfg.optionxform = lambda option: option archivo_cfg.read('app.cfg') self.root.geometry( archivo_cfg.get('Ventana principal', 'Dimensiones y posición')) self.clase_al_final.set( archivo_cfg.get('Proyecto', 'Clase al final', fallback=True)) self.rutas_relativas.set( archivo_cfg.get('Proyecto', 'Rutas relativas', fallback=True)) self.ruta_datasets = archivo_cfg.get('Proyecto', 'Ruta datasets', fallback='../datos/ACDC/') self.ruta_resultados = archivo_cfg.get('Proyecto', 'Ruta resultados', fallback='../datos/catalogos/') def guarda_configuracion(self): archivo_cfg = ConfigParser() archivo_cfg.optionxform = lambda option: option #Dimensiones y posición de la ventana self.root.update() ancho, alto = self.root.winfo_width(), self.root.winfo_height() x, y = self.root.winfo_x(), self.root.winfo_y() archivo_cfg['Ventana principal'] = {\ 'Dimensiones y posición': '{}x{}+{}+{}'.format(ancho, alto, x, y)} archivo_cfg['Proyecto'] = {\ 'Clase al final': self.clase_al_final.get(), 'Ruta datasets': self.ruta_datasets, 'Ruta resultados': self.ruta_resultados, 'Rutas relativas': self.rutas_relativas.get()} with open('app.cfg', 'w') as archivo: archivo_cfg.write(archivo) def cerrar_aplicacion(self): self.guarda_configuracion() self.root.destroy()
class MainWindow: def __init__(self) -> None: self.Root = Tk() self.App = Frame(self.Root, padding=(5, 2)) self.UpdatesFrame = LabelFrame(self.App, text=L.UpdatesFrame, borderwidth=2, relief='sunken', padding=(5, 2)) self.upd_enabled = BooleanVar() # Флаг обновлений self.upd_unit = StringVar() # Единица измерения времени self.time_units = { Minutes: L.Minutes, Hours: L.Hours, Days: L.Days, Weeks: L.Weeks, Months: L.Months } self.size_units = { Bytes: L.Bytes, KBytes: L.KBytes, MBytes: L.MBytes, GBytes: L.GBytes, TBytes: L.TBytes } # Список единиц измерения времени self.maxfsize = StringVar() # Максимальный размер файла self.size_unit = StringVar() # Единица измерения информации self.units_amount1 = StringVar() # Количество единиц self.quar = BooleanVar() # False - удалять, True - карантин self.quar_path = StringVar() # Расположение карантина self.rpt_enabled = BooleanVar() # Флаг отправки отчета self.email = StringVar() # Адрес отправки self.passwd = StringVar() # Пароль исходящего ящика self.rpt_unit = StringVar() # Единица измерения времени self.units_amount2 = StringVar() # Количество единиц self.Upd_Label1 = Label(self.UpdatesFrame, text=L.Upd_Label1) self.Upd_Checkbutton1 = Checkbutton(self.UpdatesFrame, variable=self.upd_enabled) self.Upd_Label2 = Label(self.UpdatesFrame, text=L.Upd_Label2) self.Upd_Spinbox1 = Spinbox(self.UpdatesFrame, textvariable=self.units_amount1, from_=1, to=999999999, width=4) self.Upd_OptionMenu1 = OptionMenu(self.UpdatesFrame, self.upd_unit, *self.time_units.values()) self.Upd_Button1 = Button( self.UpdatesFrame, text=L.Upd_Button1, command=lambda: EntryOptionsWindow('AV_SOURCES', self.Root)) self.ScanFrame = LabelFrame(self.App, text=L.ScanFrame, borderwidth=2, relief='sunken', padding=(5, 2)) self.Scn_Label1 = Label(self.ScanFrame, text=L.Scn_Label1) self.Scn_Spinbox1 = Spinbox(self.ScanFrame, textvariable=self.maxfsize, from_=0, to=999999999, width=8) self.Quar_Label = Label(self.ScanFrame, text=L.Quar_Label) self.Quar_RadButton1 = Radiobutton(self.ScanFrame, text=L.Quar_RadButton1, variable=self.quar, value=False) self.Quar_RadButton2 = Radiobutton(self.ScanFrame, text=L.Quar_RadButton2, variable=self.quar, value=True) self.Scn_OptionMenu1 = OptionMenu(self.ScanFrame, self.size_unit, *self.size_units.values()) self.Scn_Edit_Targets = Button( self.ScanFrame, text=L.Scn_Edit_Targets, command=lambda: EntryOptionsWindow( 'SCAN_TARGETS', self.Root, select_path=True)) self.Scn_Edit_Exceptions = Button( self.ScanFrame, text=L.Scn_Edit_Exceptions, command=lambda: EntryOptionsWindow('SCAN_EXCLUDE', self.Root)) self.Quar_Button1 = Button( self.ScanFrame, text=L.Quar_Button1, command=lambda: self.quar_path.set(filedialog.askdirectory())) self.ReportFrame = LabelFrame(self.App, text=L.ReportFrame, borderwidth=2, relief='sunken', padding=(5, 2)) self.Rpt_Label1 = Label(self.ReportFrame, text=L.Rpt_Label1) self.Rpt_Checkbutton1 = Checkbutton(self.ReportFrame, variable=self.rpt_enabled) self.Rpt_Label2 = Label(self.ReportFrame, text=L.Rpt_Label2) self.Rpt_Entry1 = Entry(self.ReportFrame, textvariable=self.email, width=32) self.Rpt_Label3 = Label(self.ReportFrame, text=L.Rpt_Label3) self.Rpt_Entry2 = Entry(self.ReportFrame, textvariable=self.passwd, width=32, show='*') self.Rpt_Label4 = Label(self.ReportFrame, text=L.Rpt_Label4) self.Rpt_Spinbox1 = Spinbox(self.ReportFrame, textvariable=self.units_amount2, from_=1, to=999999999, width=4) self.Rpt_OptionMenu1 = OptionMenu(self.ReportFrame, self.rpt_unit, *self.time_units.values()) self.Rpt_Button1 = Button( self.ReportFrame, text=L.Rpt_Button1, command=lambda: EntryOptionsWindow('SEND_TO', self.Root)) self.Buttons = Frame(self.App, padding=(5, 2)) self.Button1 = Button(self.Buttons, text=L.Done, command=self.save_conf) self.Button2 = Button(self.Buttons, text=L.Cancel, command=self.Root.destroy) def main(self) -> None: self.upd_unit.set(self.time_units[type(UPDATE_FREQ)]) self.units_amount1.set(UPDATE_FREQ.value) self.upd_enabled.set(CHECK_FOR_UPDATES) self.Upd_Checkbutton1.configure(command=(lambda: self.__change_state( self.upd_enabled, self.Upd_Label2, self.Upd_Spinbox1, self. Upd_OptionMenu1, self.Upd_Button1) and self.upd_enabled.set( not self.upd_enabled.get()))) self.Rpt_Checkbutton1.configure(command=(lambda: self.__change_state( self.rpt_enabled, self.Rpt_Label2, self.Rpt_Entry1, self. Rpt_Label3, self.Rpt_Entry2, self.Rpt_Label4, self.Rpt_Spinbox1, self.Rpt_OptionMenu1, self.Rpt_Button1) and self.rpt_enabled.set( not self.rpt_enabled.get()))) self.maxfsize.set(MAX_FILE_SIZE.value) self.size_unit.set(self.size_units[type(MAX_FILE_SIZE)]) self.quar.set(REMOVE_THREATS) self.quar_path.set(QUARANTINE_PATH) self.rpt_enabled.set(SEND_SCAN_REPORTS) self.email.set(SEND_FROM) try: with open('/root/.cobpwd', 'r') as f: self.passwd.set(f.read()) except FileNotFoundError: pass self.rpt_unit.set(self.time_units[type(SEND_FREQ)]) self.units_amount2.set(SEND_FREQ.value) self.App.pack(fill='both', expand=True) center_win(self.Root, '500x500') self.Root.resizable(False, False) self.Root.title('CobraAV Configuration') self.UpdatesFrame.place(y=0, height=150, width=490) self.__change_state(self.upd_enabled, self.Upd_Label2, self.Upd_Spinbox1, self.Upd_OptionMenu1) self.__change_state(self.rpt_enabled, self.Rpt_Label2, self.Rpt_Entry1, self.Rpt_Label3, self.Rpt_Entry2, self.Rpt_Label4, self.Rpt_Spinbox1, self.Rpt_OptionMenu1, self.Rpt_Button1) self.Upd_Label1.place(relx=.01, rely=.05) # Проверять обновления ? self.Upd_Checkbutton1.place(relx=.8, rely=.05) # Да/Нет self.Upd_Label2.place(relx=.01, rely=.3) # Частота проверки self.Upd_Spinbox1.place(relx=.55, rely=.3, width=60) # Количество self.Upd_OptionMenu1.place(relx=.72, rely=.28) # Единицы измерения self.Upd_Button1.place(relx=.01, rely=.65) # Источники сигнатур self.ScanFrame.place(y=150, height=150, width=490) self.Scn_Label1.place(relx=.01, rely=.05) # Максимальный размер файла self.Scn_Spinbox1.place(relx=.55, rely=.05, width=60) # Количество self.Quar_Label.place(relx=.01, rely=.35) self.Quar_RadButton1.place( relx=.52, rely=.35) # Переключатель на удаление угрозы self.Quar_RadButton2.place( relx=.72, rely=.35) # Переключатель на добавление вкарантина угрозы self.Quar_Button1.place(relx=.56, rely=.65) # Расположение карантина self.Scn_OptionMenu1.place(relx=.72, rely=.014) # Единицы измерения self.Scn_Edit_Targets.place(relx=.01, rely=.65) # Цели сканирования self.Scn_Edit_Exceptions.place(relx=.33, rely=.65) # Исключения self.Rpt_Label1.place(relx=.01, rely=.05) # Отправлять отчеты ? self.Rpt_Checkbutton1.place(relx=.8, rely=.05) # Да/Нет self.ReportFrame.place(y=300, height=150, width=490) self.Rpt_Label2.place(relx=.01, rely=.35) # Адрес отправки отчетов: self.Rpt_Entry1.place(relx=.35, rely=.35) # Ввод адреса отправки отчетов self.Rpt_Label3.place(relx=.01, rely=.50) # Пароль: self.Rpt_Entry2.place(relx=.35, rely=.50) # Ввод пароля: self.Rpt_Label4.place(relx=.01, rely=.75) # Частота отправки self.Rpt_Spinbox1.place(relx=.35, rely=.75, width=60) # Количество self.Rpt_OptionMenu1.place(relx=.52, rely=.72) # Единицы измерения self.Rpt_Button1.place(relx=.72, rely=.74) # Получатели self.Buttons.place(y=450, height=50, width=490) self.Button1.place(relx=.62, rely=.2) # Кнопка "Готово" self.Button2.place(relx=.82, rely=.2) # Кнопка "Отмена" self.Root.mainloop() @staticmethod def __change_state(state: BooleanVar, *args: Widget) -> None: for i in args: i.configure(state=('disabled', 'normal')[state.get()]) def save_conf(self) -> None: size_units = {v: k for k, v in self.size_units.items()} time_units = {v: k for k, v in self.time_units.items()} def wrap_list(a: 'list[str]') -> str: return '[' + ', \n'.join(f"r'{i}'" for i in a) + ']' def wrap_cls(_unit: Variable, amount: Variable) -> str: unit = _unit.get() if unit in size_units: return size_units[unit].__name__ + f'({amount.get()})' elif unit in time_units: return time_units[unit].__name__ + f'({amount.get()})' else: raise NotImplementedError if self.upd_enabled.get() and not CHECK_FOR_UPDATES: system('systemctl enable cobra-update.service') system('systemctl restart cobra-update.service') else: system('systemctl stop cobra-update.service') system('systemctl disable cobra-update.service') if self.rpt_enabled.get() and not SEND_SCAN_REPORTS: system('systemctl enable cobra-notify.service') system('systemctl restart cobra-notify.service') else: system('systemctl stop cobra-notify.service') system('systemctl disable cobra-notify.service') with open('/root/.cobpwd', 'w') as f: f.write(self.passwd.get()) with open(CONF_PATH, 'w') as f: f.write(f"""from libunits import * CHECK_FOR_UPDATES = {int(self.upd_enabled.get())} # Check for updates UPDATE_FREQ = {wrap_cls(self.upd_unit, self.units_amount1)} # Check interval MAX_FILE_SIZE = {wrap_cls(self.size_unit, self.maxfsize)} # Max file size # Antivirus database sources AV_SOURCES = {wrap_list(AV_SOURCES)} # Antivirus database path DB_PATH = r'{DB_PATH}' # On threat: # 0 - quarantine # 1 - remove REMOVE_THREATS = {int(self.quar.get())} # Directories to scan SCAN_TARGETS = {wrap_list(SCAN_TARGETS)} # Exclude from scanning SCAN_EXCLUDE = {wrap_list(SCAN_EXCLUDE)} # quarantine location QUARANTINE_PATH = r'{self.quar_path.get() or QUARANTINE_PATH}' # Send scan reports SEND_SCAN_REPORTS = {int(self.rpt_enabled.get())} # Scan reports frequency SEND_FREQ = {wrap_cls(self.rpt_unit, self.units_amount2)} # Send from this email SEND_FROM = r'{self.email.get()}' # Send to these emails SEND_TO = {wrap_list(SEND_TO)} # SMTP settings (preset for gmail) SMTP_HOST = 'smtp.gmail.com' SMTP_PORT = 587 # GUI Language LANG = '{LANG}' """) self.Root.destroy()
class SetUp(): def __init__(self, parent): self.parent = parent print('We are in the SetUp class') self.myFont = font.Font(family='Helvetica', size=15) self.setup() def setup(self): """ Sets program variables that can be cleared upon "Clear" button function "destroy_f1_frame" Setup styles for window, buttons, labels, and grids """ # variables self.urls = [] self.url_data = False self.checkboxes = [] self.checkboxes_val = False self.filename = None self.upload_val = False # text widget self.text = Text(self.parent) # styles widget self.f1_style = ttk.Style() # styles config self.f1_style.configure('My.TFrame') self.f1 = ttk.Frame(self.parent, style='My.TFrame') # styles/config buttons self.f1_style.configure('TButton', foreground='#013A70', font=('Helvetica', 15)) self.quit_Button = ttk.Button(self.parent, width=5, text="Quit ", command=self.parent.quit) self.start_Button = ttk.Button(self.f1, width=5, text="Start", command=ValidationStuff(self).get_entries) self.clear_Button = ttk.Button(self.parent, width=5, text="Clear", command=ValidationStuff(self).destroy_f1_frame) self.help_Button = ttk.Button(self.parent, width=5, text="Help", command=Factory("HelpScreen")(self.parent).help_screen) # logo image self.image = Image.open('assets/ezgif-2-18770de0fea5.gif') self.photo = ImageTk.PhotoImage(self.image) self.img_label = Label(self.parent, image=self.photo, width=70) # label stuff self.url_Label_0 = ttk.Label(self.f1, text=" ") self.url_Label_1 = ttk.Label(self.f1, text="Enter URL To Parse ") self.url_Label_1['font'] = self.myFont self.url_Entry = ttk.Entry(self.f1) self.parse_data_Label = ttk.Label(self.f1, text="Data To Parse") self.parse_data_Label['font'] = self.myFont self.upload_File = ttk.Label(self.f1, text="Upload Data File") self.upload_File['font'] = self.myFont self.upload_Button = ttk.Button(self.f1, text="Upload", command=ValidationStuff(self).uploadAction) self.error_message = ttk.Label(self.f1, foreground="red", text="Please complete all fields... ") self.go_message = ttk.Label(self.f1, foreground="blue", text="Working on parsing... ") self.done_message = ttk.Label(self.f1, foreground="#006400", text="Finished parsing this page... ") self.finished_message = ttk.Label(background="white", foreground="blue", text="Finished... ") self.clear_values_message = ttk.Label(self.f1, foreground="blue", text="Cleared the URL and any attached file... ") # checkbox variables self.body_Var = BooleanVar() # set checkbox values self.body_Var.set(True) # add functionality to checkbox self.body_tag = ttk.Checkbutton(self.f1, text="Full HTML", variable=self.body_Var, onvalue=True) # main style grid self.f1.grid(column=0, row=0, sticky=(E, W, S, N)) # blank line grid self.url_Label_0.grid(column=0, row=0, sticky=(N, E, S, W), padx=(10,10), pady=1) # url input and parse grid self.url_Label_1.grid(column=0, row=1, sticky=(N, E, S, W), padx=(10,1), pady=1) self.url_Entry.grid(column=0, row=2, sticky=(N, E, S, W), padx=(10,1), pady=1) # check boxes grid self.parse_data_Label.grid(column=0, row=4, sticky=(N, E, S, W), padx=(10,1), pady=(10,1)) self.body_tag.grid(column=0, row=4, padx=(10,1), pady=(55,1), sticky=(W)) # upload button grid self.upload_File.grid(column=0, row=7, sticky=(N, E, S, W), padx=(10,1), pady=(40,1)) self.upload_Button.grid(column=0, row=8, sticky=(E, W, N, S), padx=(10,110), pady=(1,1)) # error message and go message self.done_message.grid(column=0, row=9, sticky=(E, W), pady=(2,1),padx=(10,1)) self.done_message.grid_remove() self.error_message.grid(column=0, row=9, sticky=(E, W), pady=(2,1),padx=(10,1)) self.error_message.grid_remove() self.go_message.grid(column=0, row=9, sticky=(N, S, E, W), pady=(2,1),padx=(10,1)) self.go_message.grid_remove() self.clear_values_message.grid(column=0, row=9, sticky=(N, S, E, W), pady=(2,1),padx=(10,1)) self.clear_values_message.grid_remove() # image grid self.img_label.grid(column=2, row=0, sticky=(N, W), pady=(0,0), padx=(0,0)) self.start_Button.grid(column=1, row=10, sticky=(E, W), pady=(40,10), padx=(20,10)) # quit button grid self.quit_Button.grid(column=2, row=0, sticky=(S), pady=(1,10), padx=(1,1)) self.clear_Button.grid(column=2, row=0, sticky=(S), pady=(1,40), padx=(1,1)) self.help_Button.grid(column=2, row=0, sticky=(S), pady=(1,70), padx=(1,1)) # need to check what these do self.parent.columnconfigure(0, weight=1)# weight determines how much of the available space a row or column should occupy relative to the other rows or columns self.parent.rowconfigure(0, weight=1) self.f1.columnconfigure(0, weight=2)# weight determines how much of the available space a row or column should occupy relative to the other rows or columns self.f1.rowconfigure(0, weight=2) ValidationStuff(self)
def load_data(self): # reads in various other pieces of information required with open(self.file, 'rb') as file: # let's get the gain: file.seek(0x70) offset = unpack('i', file.read(4))[0] file.seek(offset) amp_data = unpack('i', file.read(4))[0] gain1 = (amp_data & 0x00007000) >> 12 gain2 = (amp_data & 0x70000000) >> 28 gain3 = (amp_data & 0x07000000) >> 24 self.info['gains'] = '{0}, {1}, {2}'.format( GAINS[gain1], GAINS[gain2], GAINS[gain3]) # get the InsitutionName and ManufacturersModelName: # code taken pretty much directly from the kit.py script in mne file.seek(0x20C) system_name = unpack('128s', file.read(0x80))[0].decode() model_name = unpack('128s', file.read(0x80))[0].decode() nchans = unpack('i', file.read(4))[0] file.seek(0x100, 1) # ignore any comments create_time, = unpack('i', file.read(0x4)) system_name = system_name.replace('\x00', '') # system_name = system_name.strip().replace('\n', '/') model_name = model_name.replace('\x00', '') # model_name = model_name.strip().replace('\n', '/') self.info['Institution name'] = system_name self.info['Serial Number'] = model_name self.info['Channels'] = nchans self.info['Measurement date'] = datetime.fromtimestamp( create_time).strftime('%d/%m/%Y') # determine whether the data has continuous head movement data file.seek(0x1D0) reTHM_offset, = unpack('i', file.read(0x4)) self.extra_data['ContinuousHeadLocalization'] = (reTHM_offset != 0) # Get all the channel information here separately from mne. # This way the data is intrinsically linked to the con file # and we can generate the channels tab from the start file.seek(0x40) chan_offset, chan_size = unpack('2i', file.read(8)) # check to see if any of the channels are designated as triggers # by default def_trigger_info = None if isinstance(self.container, KITData): if self.container.contains_required_files: if isinstance(self.container.settings, dict): def_trigger_info = self.container.settings.get( 'DefaultTriggers', None) default_triggers = [] default_descriptions = [] if def_trigger_info is not None: default_triggers = [int(row[0]) for row in def_trigger_info] default_descriptions = [row[1] for row in def_trigger_info] channels_from_load = list(self.interesting_channels) """ optimise to only load interesting channels """ for i in range(nchans): file.seek(chan_offset + i * chan_size) channel_type, = unpack('i', file.read(4)) if channel_type in KIT.CHANNELS_MEG: name = "MEG {0:03d}".format(i) elif (channel_type in KIT.CHANNELS_MISC or channel_type == KIT.CHANNEL_NULL): ch_type_label = KIT.CH_LABEL[channel_type] name = "{0} {1:03d}".format(ch_type_label, i) self.channel_names.append(name) # only add the default channels if the list of channels loaded # is empty. Otherwise default channels removed before save will # be re-added if channels_from_load == []: if i in default_triggers: is_trigger = True self.interesting_channels.add(i) else: is_trigger = False if (i in self.interesting_channels and i not in self.tab_info.keys()): name_var = StringVar() name_var.set(name) bad_var = BooleanVar() bad_var.set(False) trigger_var = BooleanVar() trigger_var.set(is_trigger) if is_trigger: idx = default_triggers.index(i) description = default_descriptions[idx] else: description = '' desc_var = StringVar() desc_var.set(description) self.tab_info[i] = [ name_var, bad_var, trigger_var, desc_var ] self.loaded = True
class BaseFeature(Pane): _instance = None name = "Feature" pane = None bar = None icon = "blank" _view_mode = None _transparency_flag = None _side = None rec = (20, 20, 300, 300) # Default window mode position _defaults = { "mode": "docked", "inactive_transparency": False, "position": "left", "visible": True, "side": "left", "pane": { "height": 300, "index": 1000, # setting 1000 allows the feature pane to pick an index }, "pos": { "initialized": False, "x": 20, "y": 20, "width": 200, "height": 200, } } @classmethod def update_defaults(cls): pref = Preferences.acquire() path = "features::{}".format(cls.name) if not pref.exists(path): pref.set(path, copy.deepcopy(cls._defaults)) else: pref.update_defaults(path, copy.deepcopy(cls._defaults)) def __init__(self, master, studio=None, **cnf): super().__init__(master, **cnf) self.update_defaults() self.__class__._instance = self if not self.__class__._view_mode: self.__class__._view_mode = StringVar(None, self.get_pref('mode')) self.__class__._transparency_flag = t = BooleanVar( None, self.get_pref('inactive_transparency')) self.__class__._side = StringVar(None, self.get_pref('side')) self.is_visible = BooleanVar(None, self.get_pref('visible')) t.trace_add( "write", lambda *_: self.set_pref('inactive_transparency', t.get())) self.studio = studio Label(self._header, **self.style.text_accent, text=self.name).pack(side="left") self._min = Button(self._header, image=get_icon_image("close", 15, 15), **self.style.button, width=25, height=25) self._min.pack(side="right") self._min.on_click(self.minimize) self._pref = MenuButton(self._header, **self.style.button) self._pref.configure(image=get_icon_image("settings", 15, 15)) self._pref.pack(side="right") self._pref.tooltip("Options") menu = self.make_menu( (("cascade", "View Mode", None, None, { "menu": ( ("radiobutton", "Docked", None, self.open_as_docked, { "variable": self._view_mode, "value": "docked" }), ("radiobutton", "Window", None, self.open_as_window, { "variable": self._view_mode, "value": "window" }), ) }), ("cascade", "Position", None, None, { "menu": ( ("radiobutton", "Left", None, lambda: self.reposition("left"), { "variable": self._side, "value": "left" }), ("radiobutton", "Right", None, lambda: self.reposition("right"), { "variable": self._side, "value": "right" }), ) }), EnableIf(lambda: self._view_mode.get() == 'window', ("cascade", "Window options", None, None, { "menu": (("checkbutton", "Transparent when inactive", None, None, { "variable": self._transparency_flag }), ) })), ("command", "Close", get_icon_image( "close", 14, 14), self.minimize, {}), ("separator", ), *self.create_menu()), self._pref) self._pref.config(menu=menu) # self._pref.on_click(self.minimize) self.config(**self.style.surface) self.indicator = None self.window_handle = None self.on_focus(self._on_focus_get) self.on_focus_lost(self._on_focus_release) self.on_close(self.close_window) self._mode_map = { 'window': self.open_as_window, 'docked': self.open_as_docked } @classmethod def get_pref_path(cls, short_path): return "features::{}::{}".format(cls.name, short_path) @classmethod def get_pref(cls, short_path): return Preferences.acquire().get(cls.get_pref_path(short_path)) @classmethod def set_pref(cls, short_path, value): Preferences.acquire().set(cls.get_pref_path(short_path), value) @classmethod def get_instance(cls): return cls._instance def on_select(self, widget): """ Called when a widget is selected in the designer :param widget: selected widget :return:None """ pass def on_widget_change(self, old_widget, new_widget=None): """ Called when a widget is fundamentally altered :param old_widget: Altered widget :param new_widget: The new widget taking the older widgets place :return: None """ pass def on_widget_layout_change(self, widget): """ Called when layout options of a widget are changed :param widget: Widget with altered layout options :return: None """ pass def on_widget_add(self, widget, parent): """ Called when a new widget is added to the designer :param widget: widget :param parent: the container widget to which thw widget is added :return: None """ pass def on_widget_delete(self, widget, silently=False): """ Called when a widget is deleted from the designer :param widget: deleted widget :param silently: flag indicating whether the deletion should be treated implicitly which is useful for instance when you don't want the deletion to be logged in the undo stack :return: None """ pass def on_widget_restore(self, widget): """ Called when a deleted widget is restored :param widget: restored widget :return: None """ pass def on_session_clear(self): """ Override to perform operations before a session is cleared and the studio resets to a new design :return: None """ pass def on_context_switch(self): """ Override to perform operations when the active tab changes """ pass def on_context_close(self, context): """ Override to perform operations when a tab context is closed """ pass def on_app_close(self) -> bool: """ Override to perform operations before the studio app closes. :return: True to allow shutdown to proceed or False to abort shutdown """ return True def minimize(self, *_): if self.window_handle: self.close_window() return self.studio.minimize(self) self.set_pref("visible", False) self.is_visible.set(False) def maximize(self): if self.get_pref("mode") == "window": self.open_as_window() self.bar.select(self) else: self.studio.maximize(self) self.set_pref("visible", True) self.is_visible.set(True) def toggle(self): if self.get_pref("visible"): self.minimize() else: self.maximize() def create_menu(self): """ Override this method to provide additional menu options :return: tuple of menu templates i.e. (type, label, image, callback, **additional_config) """ # return an empty tuple as default return () def _on_focus_release(self): if self._transparency_flag.get() and self.window_handle: if self.window_handle: self.window_handle.wm_attributes('-alpha', 0.3) if self.window_handle: self.save_window_pos() def _on_focus_get(self): if self.window_handle: self.window_handle.wm_attributes('-alpha', 1.0) def open_as_docked(self): self._view_mode.set("docked") self.set_pref('mode', 'docked') if self.window_handle: self.master.window.wm_forget(self) self.window_handle = None self.maximize() def reposition(self, side): self._side.set(side) self.studio.reposition(self, side) def open_as_window(self): if TkVersion < 8.5: logging.error("Window mode is not supported in current tk version") return self.master.window.wm_forget(self) rec = absolute_position( self) if not self.get_pref("pos::initialized") else ( self.get_pref("pos::x"), self.get_pref("pos::y"), self.get_pref("pos::width"), self.get_pref("pos::height"), ) self.window.wm_manage(self) # Allow us to create a hook in the close method of the window manager self.bind_close() self.title(self.name) self.geometry('{}x{}+{}+{}'.format(rec[2], rec[3], rec[0], rec[1])) self.update_idletasks() self.window_handle = self self._view_mode.set("window") self.set_pref("mode", "window") self.studio._adjust_pane(self.pane) self.transient(self.master.window) self.save_window_pos() if self.focus_get() != self and self.get_pref("inactive_transparency"): self.window_handle.wm_attributes('-alpha', 0.3) def save_window_pos(self): if not self.window_handle: if self.winfo_ismapped(): self.set_pref("pane::height", self.height) return self.update_idletasks() geometry = parse_geometry(self.geometry(), default=0) if geometry: # more accurate # cast geometry values returned to int self.set_pref( "pos", dict({k: int(v) for k, v in geometry.items()}, initialized=True)) else: raise Exception("Could not parse window geometry") def close_window(self): if self.window_handle: # Store the current position of our window handle to used when it is reopened self.save_window_pos() self.master.window.wm_forget(self) self.window_handle = None self.studio.minimize(self) self.set_pref("visible", False)
class ViewManager: def __init__(self): self.network_manager = NetworkManager(self.state_changer) self.running = True self.labels, self.entries, self.buttons = dict(), dict(), dict() self.root = Tk() self.override_data = BooleanVar() self.override_data.set(True) self.tk_root_setup() def tk_root_setup(self): self.root.title("Deshe AutoReporter") self.labels.update( {'username': Label(master=self.root, text="Username: "******"Password: "******"Username", command=None) }) self.entries.update({ 'password': Entry(master=self.root, text="Password", show="*", command=None) }) self.buttons.update({ 'authentication': Button(master=self.root, text="Login", command=lambda: self.network_manager.login(entries=self. entries)) }) self.buttons.update({ 'override_data': Checkbutton(master=self.root, text="Override existing data", variable=self.override_data, onvalue=True, offvalue=False) }) self.buttons.update({ 'submit_excel_hours': Button(master=self.root, text="Submit Hours from Excel", command=self.set_hours_from_excel, state='disabled') }) self.buttons.update({ 'get_salary': Button(master=self.root, text="Last Salary", command=self.network_manager.get_last_salary, state='disabled') }) row = 0 for key in self.labels: self.labels[key].grid(row=row, column=0) row += 1 row = 0 for key in self.entries: self.entries[key].bind( '<Return>', lambda event: self.network_manager.login(entries=self.entries)) self.entries[key].grid(row=row, column=1) row += 1 column = 0 for key in self.buttons: self.buttons[key].grid(row=2, column=column) column += 1 menu_bar = Menu(master=self.root) self.root.config(menu=menu_bar) menu_bar.add_command(label="Close Window", command=self.close_app) menu_bar.add_command(label="Help!", command=self.help_user) self.root.after(200, lambda: self.geometry_setter(self.root)) self.root.mainloop() def help_user(self): """ Input: Clicked by user! Output: Explains about the program. Meaning: Contains information about the program. """ top = Toplevel(master=self.root) top.title("Instructions") top.resizable(width=False, height=False) menu_bar = Menu(master=top) menu_bar.add_command(label="Quit", command=top.destroy) top.config(menu=menu_bar) labels = list() labels.append( Label( master=top, text="1) Insert your username and password in the given fields." )) labels.append(Label(master=top, text="2) Click login.")) labels.append( Label( master=top, text= "3) Once you get the message you're authenticated you're good to go, else, retry." )) labels.append( Label( master=top, text= "4) If you want to run on existing dates tick v on override existing data." )) labels.append( Label( master=top, text= "5) Click Submit Hours from Excel, choose your excel hours file." )) labels.append( Label(master=top, text="6)You're free to go, your hours have been submitted.")) labels.append( Label( master=top, text= "\nNote) It doesn't take breaks in count, only the earliest hour and the latest one." )) for label in labels: label.pack() self.geometry_setter(top, minimum_x=500, minimum_y=160) def close_app(self): self.running = False self.root.quit() def state_changer(self, is_logged_in): if is_logged_in: self.update_when_need(self.buttons['submit_excel_hours'], 'state', 'normal') self.update_when_need(self.buttons['get_salary'], 'state', 'normal') self.update_when_need(self.buttons['authentication'], 'text', 'Logout') for key in self.entries: self.update_when_need(self.entries[key], 'state', 'disabled') else: self.update_when_need(self.buttons['submit_excel_hours'], 'state', 'normal') self.update_when_need(self.buttons['get_salary'], 'state', 'disabled') self.update_when_need(self.buttons['authentication'], 'text', 'Login') for key in self.entries: self.update_when_need(self.entries[key], 'state', 'normal') @staticmethod def update_when_need(element, field_to_change, variable): if element[field_to_change] != variable: element[field_to_change] = variable def set_hours_from_excel(self): path_to_excel = askopenfilename( title="Select your Excel file for import", filetypes=(("Excel Files", ".xlsx"), )) threads = [] if path_to_excel: try: dates = DateManager(path_to_excel).get_all_days() for date in dates: if date.get('dead'): showinfo('Invalid Credential', date) elif date.get('reason'): thr = Thread( target=self.network_manager.enter_special_occasion, args=(date['reason'], date['start_date'], date['hours'], date['minutes'], date['elaboration_text'], self.override_data)) thr.start() threads.append(thr) else: thr = Thread(target=self.network_manager.report_shift, args=(date['start_date'], date['end_date'], date['elaboration_text'], self.override_data)) thr.start() threads.append(thr) for thr in threads: thr.join() showinfo('Submitted', 'Hours successfully passed!') except TimeoutException as ex: showinfo('Timeout', 'Error ' + str(ex)) else: showinfo('Cancelled', 'Process cancelled.') @staticmethod def geometry_setter(root, minimum_x=0, minimum_y=0): root.minsize(width=root.winfo_width() + minimum_x, height=root.winfo_height() + minimum_y) x_width_pos = int( (root.winfo_screenwidth() - (root.winfo_width() + minimum_x)) / 2) y_height_pos = int((root.winfo_screenheight() - (root.winfo_height() + minimum_y)) / 2) geometry_text = str(root.winfo_width() + minimum_x) + "x" + str( root.winfo_height() + minimum_y) + "+" + str(x_width_pos - 75) + "+" + str(y_height_pos) + "" root.geometry(geometry_text) root.update()
class Gui(Tk): ''' ------------------------------------------------------------------------------------------------ ''' def __init__(self): Tk.__init__(self) self.title("Steam Career - " + constants.APP_VERSION) self.iconbitmap(os.getcwd() + '\\resources\\favicon.ico') self.buildGui() self.__centre(self) ''' ------------------------------------------------------------------------------------------------ ''' def __centre(self, toplevel): toplevel.update_idletasks() w = toplevel.winfo_screenwidth() h = toplevel.winfo_screenheight() size = tuple( int(_) for _ in toplevel.geometry().split('+')[0].split('x')) x = w / 2 - size[0] / 2 y = h / 2 - size[1] / 2 toplevel.geometry("%dx%d+%d+%d" % (size + (x, y))) ''' ------------------------------------------------------------------------------------------------ ''' def __setResultLocation(self): filename = filedialog.askdirectory() self.resultLocation.set(filename) ''' ------------------------------------------------------------------------------------------------ ''' def __generateResult(self): try: os.makedirs(os.path.dirname(constants.CONF_FILE_STEAM_USER), exist_ok=True) with open(constants.CONF_FILE_STEAM_USER, "wb") as f: f.write(self.entry.get().encode("UTF-8")) os.makedirs(os.path.dirname(constants.CONF_FILE_STEAM_API_KEY), exist_ok=True) with open(constants.CONF_FILE_STEAM_API_KEY, "wb") as f: f.write(self.apiKeyEntry.get().encode("UTF-8")) os.makedirs(os.path.dirname(constants.CONF_RESULT_LOCATION), exist_ok=True) with open(constants.CONF_RESULT_LOCATION, "wb") as f: f.write(self.resultLocationEntry.get().encode("UTF-8")) os.makedirs(os.path.dirname(constants.OVERWRITE_CSS_LOCATION), exist_ok=True) with open(constants.OVERWRITE_CSS_LOCATION, "wb") as f: if (self.overwriteCssState.get() == True): f.write("true".encode("UTF-8")) else: f.write("false".encode("UTF-8")) logic.generateResultPage(self.apiKeyEntry.get(), self.entry.get(), self.resultLocationEntry.get(), self.overwriteCssState.get()) except Exception as exception: messagebox.showerror("Error", str(exception)) ''' ------------------------------------------------------------------------------------------------ ''' def buildGui(self): padx = 5 pady = 5 self.frame = Frame(self) self.frame.pack(padx=padx, pady=pady) self.bottomframe = Frame(self) self.bottomframe.pack(side=BOTTOM, padx=padx, pady=pady) self.__buildUsername(padx, pady) self.__buildApiKey(padx, pady) self.__buildResultLocation(padx, pady) self.__buildOverwriteCss(padx, pady) self.button = Button(self.bottomframe, text="Go", command=self.__generateResult, height=2, width=30, padx=padx, pady=pady) self.button.pack(side=BOTTOM) ''' ------------------------------------------------------------------------------------------------ ''' def __buildUsername(self, padx, pady): self.label = Label(self.frame, text="User Name") self.label.grid(row=0, column=0, sticky=E, padx=padx, pady=pady) self.entry = Entry(self.frame, width=40) if os.path.isfile(constants.CONF_FILE_STEAM_USER): with open(constants.CONF_FILE_STEAM_USER, 'r') as myfile: steamApiUser = myfile.read().replace('\n', '') self.entry.insert(END, steamApiUser) self.entry.grid(row=0, column=1, padx=padx, pady=pady) ''' ------------------------------------------------------------------------------------------------ ''' def __buildApiKey(self, padx, pady): self.apiKeyLabel = Label(self.frame, text="API Key") self.apiKeyLabel.grid(row=1, column=0, sticky=E, padx=padx, pady=pady) self.apiKeyEntry = Entry(self.frame, width=40) if os.path.isfile(constants.CONF_FILE_STEAM_API_KEY): with open(constants.CONF_FILE_STEAM_API_KEY, 'r') as myfile: steamApiKey = myfile.read().replace('\n', '') self.apiKeyEntry.insert(END, steamApiKey) self.apiKeyEntry.grid(row=1, column=1, padx=padx, pady=pady) ''' ------------------------------------------------------------------------------------------------ ''' def __buildResultLocation(self, padx, pady): self.resultLocationLabel = Label(self.frame, text="Result Location") self.resultLocationLabel.grid(row=2, column=0, sticky=E, padx=padx, pady=pady) self.resultLocation = StringVar() self.resultLocationEntry = Entry(self.frame, textvariable=self.resultLocation, width=40) if os.path.isfile(constants.CONF_RESULT_LOCATION): with open(constants.CONF_RESULT_LOCATION, 'r') as myfile: resultLocation = myfile.read().replace('\n', '') self.resultLocationEntry.insert(END, resultLocation) self.resultLocationEntry.grid(row=2, column=1, padx=padx, pady=pady) self.resultLocationButton = Button(self.frame, text="...", command=self.__setResultLocation, height=1, width=1, padx=padx, pady=pady) self.resultLocationButton.grid(row=2, column=2, padx=padx, pady=pady) ''' ------------------------------------------------------------------------------------------------ ''' def __buildOverwriteCss(self, padx, pady): self.overwriteCssLabel = Label(self.frame, text="Overwrite CSS?") self.overwriteCssLabel.grid(row=3, column=0, sticky=E, padx=padx, pady=pady) self.overwriteCssState = BooleanVar() self.overwriteCss = Checkbutton(self.frame, justify=tkinter.LEFT, variable=self.overwriteCssState) if os.path.isfile(constants.OVERWRITE_CSS_LOCATION): with open(constants.OVERWRITE_CSS_LOCATION, 'r') as myfile: if myfile.read().replace('\n', '') == 'true': self.overwriteCssState.set(True) else: self.overwriteCssState.set(False) self.overwriteCss.grid(row=3, column=1, sticky=W, padx=padx, pady=pady)
class ImporterGUI: """ This class is the main gui and shows the import window, it also contains the main methods which uses other helper classes Attributes: root = the root tk previewFrame = the frame that shows the preview of the dataframe XMLList = the 2D list which holds the xml filepath on the index 0 and the xsl filepath on index 1 """ def __init__(self, root: Tk): self.root = root self.previewFrame = Frame(root) self.pt = Table(self.previewFrame) self.dialect = detector.Dialect() self.XMLList = [] self.DialectList = [] self.hasHeaderVar = BooleanVar() self.currentPath = "" h1 = Label(self.root, text="Imported Files", bg="#eee") h1.pack(padx=5, pady=5, fill="x") # Dialog Frame dialogFrame = Frame(self.root) dialogFrame.grid_columnconfigure(1, weight=1) Button(dialogFrame, text="Import Files", command=self.openFileDialog, width=20).grid(row=0, column=0) Button(dialogFrame, text="Delete selected File", command=self.deleteSelectedFile, width=20).grid(row=1, column=0) Button(dialogFrame, text="Delete all", command=self.deleteAllFiles, width=20).grid(row=2, column=0) # the outside frame for the files listbox (it holds the listbox and the scrollbar) listbox_border = Frame(dialogFrame, bd=2, relief="sunken", background="white") listbox_border.grid(row=0, column=1, rowspan=3, padx=3, sticky="nsew") # the actual listbox self.importedFiles = Listbox(listbox_border, selectmode=SINGLE, height=4, borderwidth=0, highlightthickness=0, relief=SUNKEN, background="white") self.importedFiles.bind("<<ListboxSelect>>", self.selectionChanged) # the scrollbar inside the listbox_border frame vsb = Scrollbar(listbox_border, orient="vertical", command=self.importedFiles.yview) self.importedFiles.configure(yscrollcommand=vsb) vsb.pack(side="right", fill="y") self.importedFiles.pack(padx=2, pady=2, fill="both", expand=True) dialogFrame.pack(fill="x", padx=10) # XSL File Frame (its disabled when a csv file is selected in the listbox, # and set to "normal" when a xml is selected h1 = Label(root, text="XSL File", bg="#eee") h1.pack(padx=5, pady=5, fill="x") xslFrame = Frame(root) self.importXSL_btn = Button(xslFrame, state=DISABLED, text="Import XSL File", command=self.openXSLFileDialog, width=20) self.importXSL_btn.grid(row=0, column=0) self.XSLPath_text = Text(xslFrame, height=1, borderwidth=2, relief=SUNKEN) self.XSLPath_text.grid(row=0, column=1) xslFrame.pack(fill="x", padx=10, pady=5) # Detector Frame h1 = Label(root, text="Detector", bg="#eee") h1.pack(padx=5, pady=5, fill="x") detectorFrame = Frame(root) Label(detectorFrame, text="Encoding:", width=20, anchor="w", justify="left").grid(row=0) self.encodingText = Text(detectorFrame, height=1, borderwidth=2, relief=SUNKEN, width=10) self.encodingText.grid(row=0, column=1) Label(detectorFrame, text="Has Header:", width=20, anchor="w", justify="left").grid(row=1) self.hasHeaderCheckbutton = Checkbutton(detectorFrame, var=self.hasHeaderVar, onvalue=1, offvalue=0) self.hasHeaderCheckbutton.grid(sticky="W", row=1, column=1) Label(detectorFrame, text="Seperator:", width=20, anchor="w", justify="left").grid(row=2) self.seperatorText = Text(detectorFrame, height=1, borderwidth=2, relief=SUNKEN, width=10) self.seperatorText.grid(row=2, column=1) Label(detectorFrame, text="Quote Char:", width=20, anchor="w", justify="left").grid(row=3) self.quoteCharText = Text(detectorFrame, height=1, borderwidth=2, relief=SUNKEN, width=10) self.quoteCharText.grid(row=3, column=1) Button(detectorFrame, text="Save Dialect Changes", command=self.saveDialectChanges, width=20).grid(row=4, column=0) detectorFrame.pack(fill="x", padx=10, pady=5) # dataframe preview frame preview = Label(root, text="Preview", bg="#eee") preview.pack(expand=TRUE, fill="x", padx=5, side=TOP) self.pt.show() self.previewFrame.pack(pady=10, padx=10, fill="both", side=TOP) # the bottom most centered export button which leads to the export window exportBtn = Button(root, text="Export", command=self.export, width=20, padx=0) exportBtn.pack(fill="x", padx=10, pady=10) def saveDialectChanges(self): """ saves the Dialect changes made by the user """ dialect = detector.Dialect() dialect.encoding = self.encodingText.get(1.0, 'end-1c') dialect.hasHeader = self.hasHeaderVar.get() dialect.delimiter = self.seperatorText.get(1.0, 'end-1c') dialect.quoteChar = self.quoteCharText.get(1.0, 'end-1c') if not self.currentPath: files = self.getImportedFiles() self.currentPath = files[0] path = self.currentPath print(path) if not any(path in x for x in self.DialectList): self.DialectList.append([path, dialect]) elif any(path in x for x in self.DialectList): x = [x for x in self.DialectList if path in x][0] self.DialectList[self.DialectList.index(x)][1] = dialect self.updateDf(self.getImportedFiles()) def selectionChanged(self, event): """ this is an event which is triggered by selection changed inside the listbox widget it checks if the selected file is a xml, if so it sets the textbox intractable for the user :param event: the event which called it """ selection = event.widget.curselection() if selection: data = event.widget.get(selection[0]) self.currentPath = data if data.endswith(".xml"): # disable encoding changes self.encodingText.delete(1.0, END) self.hasHeaderVar.set(False) self.seperatorText.delete(1.0, END) self.quoteCharText.delete(1.0, END) self.encodingText["state"] = "disabled" self.hasHeaderCheckbutton["state"] = "disabled" self.seperatorText["state"] = "disabled" self.quoteCharText["state"] = "disabled" self.importXSL_btn["state"] = "normal" if any(data in x for x in self.XMLList): x = [x for x in self.XMLList if data in x][0] self.XSLPath_text.delete(1.0, END) self.XSLPath_text.insert( 1.0, self.XMLList[self.XMLList.index(x)][1]) else: self.XSLPath_text.delete(1.0, END) self.XSLPath_text.insert(1.0, "please import a XSL File!") else: self.encodingText.delete(1.0, END) self.hasHeaderVar.set(False) self.seperatorText.delete(1.0, END) self.quoteCharText.delete(1.0, END) self.encodingText["state"] = "normal" self.hasHeaderCheckbutton["state"] = "normal" self.seperatorText["state"] = "normal" self.quoteCharText["state"] = "normal" self.importXSL_btn["state"] = "disabled" self.XSLPath_text.delete(1.0, END) if any(data in x for x in self.DialectList): x = [x for x in self.DialectList if data in x][0] dialect = self.DialectList[self.DialectList.index(x)][1] self.updateDialect(dialect) def openXSLFileDialog(self): """ this function is called if the user wants to import a xsl file in the xsl file frame it opens the filedialog and appends the xsl to the according xml into the XMLList attribute after that, it try's to update the dataframe and its preview by calling the update function """ file = askopenfilename(parent=self.root, title='Choose a file', filetypes=[("Extensible Stylesheet Language", "*.xsl"), ("All files", "*.*")]) self.XMLList.append( [self.importedFiles.get(self.importedFiles.curselection()), file]) self.XSLPath_text.delete(1.0, END) self.XSLPath_text.insert(1.0, file) self.updateDf(self.getImportedFiles()) def openFileDialog(self): """ this function opens the file dialog and imports the selected filepaths into the listbox and also calls the update function to redraw the new dataframe """ files = list( askopenfilenames(parent=self.root, title='Choose a file', filetypes=[("Excel files", ".xml .csv")])) self.updateSelectedFiles(files) self.updateDf(self.getImportedFiles()) def deleteSelectedFile(self): """ deletes the selected file from the listbox and redraws the dataframe since one of its source is deleted also if a xml file is deleted, it also deletes the corresponding xsl file from the XMLList """ path = self.importedFiles.get(self.importedFiles.curselection()) if path is self.currentPath: self.currentPath = "" # delete from dialect list if any(path in x for x in self.DialectList): x = [x for x in self.DialectList if path in x][0] self.DialectList.pop(self.DialectList.index(x)) index = self.importedFiles.get(0, END).index(path) self.importedFiles.delete(index) # delete from xml list if path.endswith(".xml"): x = [x for x in self.XMLList if path in x][0] self.XMLList.pop(self.XMLList.index(x)) self.updateDf(self.getImportedFiles()) def deleteAllFiles(self): """ deletes all imported filepaths from the listbox and also from the dataframe """ self.importedFiles.delete(0, END) self.currentPath = "" self.XMLList = [] self.DialectList = [] def getImportedFiles(self): """ :return: returns the selected filepath from the listbox """ return self.importedFiles.get(0, END) def updateSelectedFiles(self, files): """ after opening a file dialog, this method is called to pass the new imported filepaths into the listbox :param files: filespaths from the filedialog """ startIndex = self.importedFiles.size() for index, file in enumerate(files): self.importedFiles.insert(index + startIndex, file) def export(self): """ opens the export window and passes the dataframe from the preview frame """ importer.setDataFrame(self.pt.model.df) ExporterGUI(self.root, importer, self.dialect) def updateDf(self, files: list): """ checks if the dataframe can be updated by the newly imported filepaths calls the merge function if there is more than 1 file inside the filelist also udpates the detector frame (displaying dialect data) :param files: the whole filepath list """ if len(files) > 1 or len(self.XMLList) > 0: canMerge = merger.prepareMerge(files, self.XMLList, self.DialectList) self.DialectList = merger.dialectList if canMerge: newDataFrame = merger.mergeFiles() importer.setDataFrame(newDataFrame) self.pt.updateModel(TableModel(newDataFrame)) self.pt.redraw() elif len(files) > 0 and files[0].endswith(".csv"): if not any(files[0] in x for x in self.DialectList): self.dialect.guessDialectCSV(files[0]) self.DialectList.append([files[0], self.dialect]) else: x = [x for x in self.DialectList if files[0] in x][0] self.dialect = self.DialectList[self.DialectList.index(x)][1] importer.importCSV(files[0], self.dialect) updatedDataframe = importer.getDataFrame() self.pt.updateModel(TableModel(updatedDataframe)) self.pt.redraw() self.updateDialect(self.dialect) def updateDialect(self, dialect: detector.Dialect): """ updates the dialect text fields from the gui :param dialect: the new changed dialect """ # updates the dialect data self.encodingText.delete(1.0, END) self.encodingText.insert(1.0, dialect.encoding) self.hasHeaderVar.set(dialect.hasHeader) self.seperatorText.delete(1.0, END) self.seperatorText.insert(1.0, dialect.delimiter) self.quoteCharText.delete(1.0, END) self.quoteCharText.insert(1.0, dialect.quoteChar)
ttk.Checkbutton(mainframe, variable=grass_e).grid(column=4, row=1, sticky=(W)) ttk.Entry(mainframe, textvariable=no_branch_grace_e).grid(column=4, row=2, sticky=(W)) ttk.Entry(mainframe, textvariable=seed_e).grid(column=1, row=18, sticky=(W), columnspan=2) ttk.OptionMenu(mainframe, save_size_e, save_sizes[1], *save_sizes).grid(column=1, row=19, sticky=(W), columnspan=2) ttk.Button( mainframe, text="Regenerate", command=lambda: [x() for x in [lambda: animate_e.set(False), gen]]).grid( column=1, row=20, sticky=W) ttk.Button(mainframe, text="Random Seed", command=lambda: [x() for x in [lambda: animate_e.set(False), set_seed, gen]]).grid( column=2, row=20, sticky=W) ttk.Button(mainframe, text="Animate", command=lambda: [x() for x in [lambda: animate_e.set(True), gen]] if not animate_e.get() else None).grid(column=3, row=20, sticky=W) ttk.Button(mainframe, text="Save", command=save).grid(column=0, row=20, sticky=W) ttk.Button(mainframe, text="Save Animation", command=save_animation).grid(column=4, row=20, sticky=W)
class MediumQuestions(Frame): def __init__(self, master=None, cnf={}, **kw): self.root = Tk() self.root.title("Medium questions") self.root.option_add("*Font", "arial 18") self.root.geometry("800x400") self.questions = QuestionService.open_json_by_tag("medium") self.var1 = BooleanVar() self.var2 = BooleanVar() self.var3 = BooleanVar() self.var4 = BooleanVar() self.pos = -1 self.root.grid() self.render() self.root.protocol("WM_DELETE_WINDOW", self.on_closing) self.root.mainloop() def create_widgets(self): lb = Label(self.root, text=self.questions[self.pos]['text']) lb.pack(side=TOP) variants = self.questions[self.pos]['answers'] self.var1.set(0) self.var2.set(0) self.var3.set(0) self.var4.set(0) self.checkbuttons = list() c1 = Checkbutton(self.root, text=variants["1"], variable=self.var1, onvalue=1, offvalue=0) c1.pack() self.checkbuttons.append(c1) c2 = Checkbutton(self.root, text=variants["2"], variable=self.var2, onvalue=1, offvalue=0) c2.pack() self.checkbuttons.append(c2) c3 = Checkbutton(self.root, text=variants["3"], variable=self.var3, onvalue=1, offvalue=0) c3.pack() self.checkbuttons.append(c3) c4 = Checkbutton(self.root, text=variants["4"], variable=self.var4, onvalue=1, offvalue=0) c4.pack() self.checkbuttons.append(c4) Button(self.root, text="Next question", command=self.next_question).pack(side=LEFT) def next_question(self): if self.var1.get() == 0 and self.var2.get() == 0 and self.var3.get( ) == 0 and self.var4.get() == 0: warning = Tk() warning.geometry("100x50") Label(warning, text='Pick a variant!').pack(side=TOP) else: vars = [self.var1, self.var2, self.var3, self.var4] res = zip(self.checkbuttons, vars) tmp = list() for el in res: if el[1].get() == True: tmp.append(el[0].cget('text')) print(tmp) set_answers = set(tmp) set_correct = set(self.questions[self.pos]['correctAns']) if set_answers == set_correct: QuestionService.answers.append(len(set_correct)) elif len(set_answers) > len(set_correct): QuestionService.answers.append(0) elif set_correct - set_answers == {}: QuestionService.answers.append(0) else: QuestionService.answers.append( len(set_correct - (set_correct - set_answers))) # QuestionService.answers.append(tmp == self.questions[self.pos]['correctAns']) # tmp.clear() self.render() def render(self): self.pos += 1 for w in self.root.winfo_children(): w.destroy() if self.pos == len(self.questions): self.root.destroy() else: self.create_widgets() def on_closing(self): if messagebox.askokcancel("Quit", "Are you sure?"): self.root.destroy() exit(0)
class take_data: ''' ''' def __init__(self, pype, toplevel=False, filename=False, num_sequences=10, run_tag=''): ''' ''' self.pype = pype self.toplevel = toplevel self.keep_runningVar = BooleanVar(value=True) self.extend_runVar = BooleanVar(value=False) self.run_typeVar = StringVar(value="/tmp/") self.run_tagVar = StringVar(value=run_tag) self.num_sequencesVar = IntVar(value=num_sequences) self.sequence_spacingVar = DoubleVar(value=0) self.len_sequenceVar = DoubleVar() self.stateVar = StringVar(value='done') self.conf_filename = StringVar(value='') self.params = {} self.runthread = multiprocessing.Process() self._GetParamFuncs() if toplevel: self._BuildGui() def _BuildGui(self): ''' Setup all of the buttons and user entries ''' # Data Location row = 0 Label(self.toplevel, text='-'*20+'Data Location'+'-'*20).grid(row=row, columnspan=3, column=0) row += 1 Label(self.toplevel, text='/data').grid(row=row, column=0, sticky='E') run_type_options = ["/tmp/", "/commissioning/", "/runs/"] OptionMenu(self.toplevel, self.run_typeVar, *run_type_options).grid( row=row, column=1, sticky='EW') Entry(self.toplevel, textvariable=self.run_tagVar).grid(row=row, column=2) Checkbutton(self.toplevel, text="Extend if Exists", variable=self.extend_runVar).grid(row=row, column=3) row += 1 Label(self.toplevel, text="(raid location)").grid(row=row, column=0, sticky='E') Label(self.toplevel, text="(run type)").grid(row=row, column=1) Label(self.toplevel, text="(run tag)").grid(row=row, column=2) row += 1 # Acquisition Cycle Details Label(self.toplevel, text='-'*20+'Acquisition Cycles'+'-'*20).grid(row=row, columnspan=3, column=0) row += 1 Label(self.toplevel, text='Number of Sequences').grid(row=row, column=0) Entry(self.toplevel, textvariable=self.num_sequencesVar).grid(row=row, column=1) row += 1 Label(self.toplevel, text='Delay Between').grid(row=row, column=0) Entry(self.toplevel, textvariable=self.sequence_spacingVar).grid(row=row, column=1) Label(self.toplevel, text='[s]').grid(row=row, column=2, sticky='W') row += 1 builtins_list = ['default_run', 'noise_analysis_run'] self.conf_filename.set(builtins_list[0]) Button(self.toplevel, text='Load Builtin Run Def', command=self._GetParamFuncs).grid(row=row, column=0) OptionMenu(self.toplevel, self.conf_filename, *builtins_list).grid( row=row, column=1) self.conf_filename.set(builtins_list[0]) row += 1 Label(self.toplevel, text='Load Custom Run Def').grid(row=row, column=0) Button(self.toplevel, text="find file", command=self._ParamFuncFile ).grid(row=row, column=1) row += 1 # Mantis Settings Label(self.toplevel, text='-'*20+'Mantis Settings'+'-'*20).grid(row=row, columnspan=3, column=0) row += 1 Label(self.toplevel, text='(Empty fields use default values)').grid(row=row, columnspan=3, column=0) row += 1 Label(self.toplevel, text='Digitization Time').grid(row=row, column=0) Entry(self.toplevel, textvariable=self.len_sequenceVar).grid(row=row, column=1) Label(self.toplevel, text='[ms]').grid(row=row, column=2, sticky='W') row += 1 Button(self.toplevel, text="Start Run", command=self.DoRun ).grid(row=row, column=0) Button(self.toplevel, text="ABORT", command=self._Abort, bg='red' ).grid(row=row, column=1) Label(self.toplevel, textvariable=self.stateVar).grid(row=row, column=2) def _ParamFuncFile(self): ''' ''' self.conf_filename.set(askopenfilename()) if self.conf_filename.get(): self._GetParamFuncs() def _Abort(self): ''' ''' self.keep_runningVar.set(False) if self.runthread.is_alive(): print('terminating child process') self.runthread.terminate() else: print('no current thread') self.stateVar.set('aborted') def _IsRunning(self): ''' ''' print(self.runthread.is_alive()) def _GetParamFuncs(self): ''' ''' fname = self.conf_filename.get() if not fname or fname == 'default_run': if not 'run_params' in sys.modules: from . import default_run as run_params else: reload(run_params) elif fname == 'noise_analysis_run': from . import noise_analysis_run as run_params else: imp.load_source('run_params', fname) import run_params self.DefaultParams = run_params.DefaultParams self.SequenceParams = run_params.SequenceParams self.FilenamePrefix = run_params.FilenamePrefix self.Mantis_kwargs = run_params.Mantis_kwargs() if 'duration' in self.Mantis_kwargs: self.len_sequenceVar.set(self.Mantis_kwargs['duration']) def DoRun(self): ''' Execute the run ''' self.keep_runningVar.set(True) self.stateVar.set('normal') if self.runthread.is_alive(): print('there is already live process, abort first or let it finish') else: self.runthread = multiprocessing.Process(target=self.__DoRun) self.runthread.start() def __DoRun(self): ''' the run called by DoRun in a subprocess ''' self.params['run_tag'] = self.run_tagVar.get() self.params['num_sequences'] = self.num_sequencesVar.get() print('setting defaults') self._SetParams(self.DefaultParams()) for sequence_num in range(self.params['num_sequences']): print('--> starting sequence {0}/{1}'.format(sequence_num, self.params['num_sequences'] - 1)) if not self.keep_runningVar.get(): print('Aborting!') break self._DoSequence(sequence_num) print('--> sequence {0}/{1} complete.'.format(sequence_num, self.params['num_sequences'] - 1)) sleep(self.sequence_spacingVar.get()) print('-> run (tag: {0}) complete.'.format(self.params['run_tag'])) self.stateVar.set('run complete') def _SetParams(self, params_list): ''' ''' for channel_name, value in params_list: setattempt = self.pype.Set(channel_name, value) setattempt.Wait() if setattempt.Waiting(): raise NoResponseError('setting ' + str(channel_name)) print(channel_name, '->', value) def _DoSequence(self, sequence_number): ''' Do one sequence within the run ''' mantis_kwargs = self.Mantis_kwargs.copy() run_doc = self.pype.NewDump(uuid4().hex, self.params['run_tag'], new_run=((not sequence_number) and not self.extend_runVar.get())) self._SetParams(self.SequenceParams(sequence_number)) for channel in self.pype.ListWithProperty('dump'): run_doc[channel] = self.pype.Get(channel) run_doc[channel].Update() run_doc[channel].Wait() run_doc._UpdateTo() outfilename = '/data/{:s}_{:05d}_{:05d}.egg'.format( self.FilenamePrefix(sequence_number), run_doc['run_number'], run_doc['sequence_number']) print('outputting '+outfilename) run_descrip = ast.literal_eval(mantis_kwargs['description']) for (chan, val) in self.SequenceParams(sequence_number): run_descrip[chan] = val run_descrip['run_tag'] = self.params['run_tag'] run_doc['sequence_tag'] = dumps(run_descrip) mantis_kwargs.update({'output': outfilename, 'description': dumps(run_descrip), 'duration': self.len_sequenceVar.get()}) run = self.pype.RunMantis(**mantis_kwargs) print('mantis run starting') run.Wait() run_doc['mantis'] = run run_doc._UpdateTo()
class ChkBoxes(tk.Frame): def __init__(self, parent): tk.Frame.__init__(self, master=parent) self.lbl_printfilt = tk.Label(self, text="Print Filters: ", font=("Times", 20)) self.lbl_printfilt.grid(row=0, column=0) self.title = BooleanVar(self) self.title.set(True) self.genre = BooleanVar(self) self.genre.set(True) self.director = BooleanVar(self) self.director.set(True) self.vrate = BooleanVar(self) self.vrate.set(True) self.srate = BooleanVar(self) self.srate.set(True) self.relyear = BooleanVar(self) self.relyear.set(True) self.tb = BooleanVar(self) self.tb.set(True) self.chk_1 = tk.Checkbutton(self, text="Title", variable=self.title, selectcolor="black", font=("Times", 15)) self.chk_1.grid(row=1, column=0, sticky="w") self.chk_2 = tk.Checkbutton(self, text="Genre", variable=self.genre, selectcolor="black", font=("Times", 15)) self.chk_2.grid(row=2, column=0, sticky="w") self.chk_3 = tk.Checkbutton(self, text="Director", variable=self.director, selectcolor="black", font=("Times", 15)) self.chk_3.grid(row=3, column=0, sticky="w") self.chk_4 = tk.Checkbutton(self, text="Viewer Rating", selectcolor="black", variable=self.vrate, font=("Times", 15)) self.chk_4.grid(row=1, column=1, sticky="w") self.chk_5 = tk.Checkbutton(self, text="Star Rating", selectcolor="black", variable=self.srate, font=("Times", 15)) self.chk_5.grid(row=2, column=1, sticky="w") self.chk_6 = tk.Checkbutton(self, text="Release Year", selectcolor="black", variable=self.relyear, font=("Times", 15)) self.chk_6.grid(row=3, column=1, sticky="w") self.chk_7 = tk.Checkbutton(self, text="Top-Billed", selectcolor="black", variable=self.tb, font=("Times", 15)) self.chk_7.grid(row=4, column=0, sticky="w") self.grid_columnconfigure(0, weight=1) self.grid_columnconfigure(1, weight=1)
class GrepDialog(SearchDialogBase): title = "Find in Files Dialog" icon = "Grep" needwrapbutton = 0 def __init__(self, root, engine, flist): SearchDialogBase.__init__(self, root, engine) self.flist = flist self.globvar = StringVar(root) self.recvar = BooleanVar(root) def open(self, text, searchphrase, io=None): SearchDialogBase.open(self, text, searchphrase) if io: path = io.filename or "" else: path = "" dir, base = os.path.split(path) head, tail = os.path.splitext(base) if not tail: tail = ".py" self.globvar.set(os.path.join(dir, "*" + tail)) def create_entries(self): SearchDialogBase.create_entries(self) self.globent = self.make_entry("In files:", self.globvar)[0] def create_other_buttons(self): f = self.make_frame()[0] btn = ui.Checkbutton(f, variable=self.recvar, text="Recurse down subdirectories") btn.pack(side="top", fill="both") self.recvar.set(True) if not ui.using_ttk: btn.select() def create_command_buttons(self): SearchDialogBase.create_command_buttons(self) self.make_button("Search Files", self.default_command, 1) def default_command(self, event=None): prog = self.engine.getprog() if not prog: return path = self.globvar.get() if not path: self.top.bell() return from idlelib.OutputWindow import OutputWindow # leave here! save = sys.stdout try: sys.stdout = OutputWindow(self.flist) self.grep_it(prog, path) finally: sys.stdout = save def grep_it(self, prog, path): dir, base = os.path.split(path) list = self.findfiles(dir, base, self.recvar.get()) list.sort() self.close() pat = self.engine.getpat() print("Searching %r in %s ..." % (pat, path)) hits = 0 try: for fn in list: try: with open(fn, errors='replace') as f: for lineno, line in enumerate(f, 1): if line[-1:] == '\n': line = line[:-1] if prog.search(line): sys.stdout.write("%s: %s: %s\n" % (fn, lineno, line)) hits += 1 except OSError as msg: print(msg) print(("Hits found: %s\n" "(Hint: right-click to open locations.)" % hits) if hits else "No hits.") except AttributeError: # Tk window has been closed, OutputWindow.text = None, # so in OW.write, OW.text.insert fails. pass def findfiles(self, dir, base, rec): try: names = os.listdir(dir or os.curdir) except OSError as msg: print(msg) return [] list = [] subdirs = [] for name in names: fn = os.path.join(dir, name) if os.path.isdir(fn): subdirs.append(fn) else: if fnmatch.fnmatch(name, base): list.append(fn) if rec: for subdir in subdirs: list.extend(self.findfiles(subdir, base, rec)) return list def close(self, event=None): if self.top: self.top.grab_release() self.top.withdraw()
class MainFrame(Frame): def set_saved_title(self, fpath): fname = split(fpath)[-1].replace('.json', '') self.master.title('{} - {}'.format(fname, _title)) def set_unsaved_title(self, *args): if len(roller_groups) < 1: return if self.autosave.get(): self.save_config(self.fpath) return title = self.master.title() if title == _title: title = '{} - {}'.format('Unsaved', title) if '*' not in title: title = '*' + title self.master.title(title) def __init__(self, master): Frame.__init__(self, master) self.master = master self.use_random_org = BooleanVar() self.allow_odd = IntVar() self.always_on_top = BooleanVar() self.autosave = BooleanVar() self.use_random_org.trace('w', self.set_unsaved_title) self.allow_odd.trace('w', self.set_unsaved_title) self.always_on_top.trace('w', self.set_unsaved_title) self.set_defaults() self.menubar = Menu(master) self.filemenu = Menu(self.menubar, tearoff=0, postcommand=maintain_group_indices) self.filemenu.add_command(label='New', underline=0, command=self.reset_default_group, accelerator='Ctrl+N') self.filemenu.add_command(label='Load', underline=3, command=self.load_config, accelerator='Ctrl+D') self.filemenu.add_command( label='Save', underline=1, command=lambda: self.save_config(fpath=self.fpath), accelerator='Ctrl+S') self.filemenu.add_command(label='Save as...', underline=4, command=self.save_config, accelerator='Ctrl+Shift+S') self.editmenu = Menu(self.menubar, tearoff=0) self.editmenu.add_checkbutton(label='Use random.org', underline=0, variable=self.use_random_org) self.editmenu.add_checkbutton(label='Allow odd dice', underline=6, variable=self.allow_odd, command=self.toggle_odd, onvalue=1, offvalue=2) self.editmenu.add_separator() # ------------------ self.editmenu.add_checkbutton(label='Always on top', underline=10, variable=self.always_on_top, command=self.pin) self.editmenu.add_checkbutton(label='Autosave', underline=4, variable=self.autosave, command=self.toggle_autosave) self.editmenu.add_separator() # ------------------ self.editmenu.add_command(label='Repeat last action', underline=0, accelerator='Ctrl+R') self.menubar.add_cascade(label='File', underline=0, menu=self.filemenu) self.menubar.add_cascade(label='Edit', underline=0, menu=self.editmenu) self.menubar.config(relief='flat') master.config(menu=self.menubar) self.reset_default_group() self.bind_all('<Control-n>', lambda e: self.reset_default_group()) self.bind_all('<Control-d>', lambda e: self.load_config()) self.bind_all('<Control-s>', lambda e: self.save_config(fpath=self.fpath)) self.bind_all('<Control-Shift-S>', lambda e: self.save_config()) def ask_proceed(self): if '*' in self.master.title(): if not askyesno( 'Unsaved changes!', 'There are unsaved changes!\r\nWould you like to proceed anyway?' ): return False return True def pin(self): self.master.wm_attributes('-topmost', self.always_on_top.get()) def toggle_odd(self): for group in roller_groups: for roller in group.rollers: roller.die_faces_spin.interval = self.allow_odd.get() num = roller.die_faces.get() if num % 2 != 0: roller.die_faces.set(num - 1) def toggle_autosave(self): if self.autosave.get(): self.save_config(self.fpath) else: self.set_unsaved_title() def set_defaults(self): self.master.title(_title) self.fpath = '' self.use_random_org.set(False) self.allow_odd.set(2) self.always_on_top.set(False) self.autosave.set(False) def reset_default_group(self): if self.ask_proceed(): self.autosave.set(False) self.clear_groups() self.set_defaults() self.create_group(0, 1) @staticmethod def clear_groups(): temp_groups = list(roller_groups) for group in temp_groups: group.remove_group(override=True) def create_group(self, index, rollers): default_group = RollerGroup(self, index) for i in range(rollers): default_group.rollers.append(Roller(default_group, i)) roller_groups.append(default_group) def load_config(self): autosave = False self.autosave.set(autosave) if not self.ask_proceed(): return fpath = askopenfilename(filetypes=[('JSON', '*.json'), ('All', '*.*')], defaultextension='.json') if not fpath or not isfile(fpath): return self.fpath = fpath self.clear_groups() with open(fpath, 'r') as f: group_dict = load(f) try: settings_dict = group_dict.pop('settings') autosave = (settings_dict['autosave']) self.use_random_org.set(settings_dict['use_random_org']) self.allow_odd.set(settings_dict['allow_odd']) self.always_on_top.set(settings_dict['always_on_top']) except KeyError: pass g = 0 for group_name, group_settings in group_dict.items(): self.create_group(g, len(group_settings['rollers'])) group = roller_groups[g] group.name.set(group_name) group.index = group_settings['index'] r = 0 h = 0 for roller_name, roller_settings in group_settings[ 'rollers'].items(): roller = group.rollers[r] roller.name.set(roller_name) for attr, value in roller_settings.items(): try: getattr(roller, attr).set(value) except AttributeError: setattr(roller, attr, value) roller.reset(loading=True) h = len(roller.history) - 1 r += 1 group.navigate_history(desired_index=h) g += 1 roller_groups.sort(key=lambda x: x.index) maintain_group_indices() for group in roller_groups: group.rollers.sort(key=lambda x: x.index) group.maintain_roller_indices() for roller in group.rollers: roller.apply_modifiers() maintain_tabstops() self.pin() self.autosave.set(autosave) self.set_saved_title(fpath) def save_config(self, fpath=''): if not fpath: fpath = asksaveasfilename(filetypes=[('JSON', '*.json'), ('All', '*.*')], defaultextension='.json') if not fpath: if '*' in self.master.title(): self.autosave.set(False) return self.fpath = fpath d1 = {} d1['settings'] = { 'use_random_org': self.use_random_org.get(), 'allow_odd': self.allow_odd.get(), 'always_on_top': self.always_on_top.get(), 'autosave': self.autosave.get() } for group in roller_groups: group.maintain_roller_indices() d2 = {} d2['index'] = group.index d2['rollers'] = {} for roller in group.rollers: name = roller.name.get() while name in d2['rollers']: name += '!' d2['rollers'][name] = { 'index': roller.index, 'history': roller.history, 'dice_qty': roller.dice_qty.get(), 'die_faces': roller.die_faces.get(), 'modifier': roller.modifier.get(), 'finalmod': roller.finalmod.get() } name = group.name.get() if name in d1: name += '!' d1[name] = d2 with open(fpath, 'w') as f: f.write(dumps(d1, indent=2, separators=(',', ': '))) self.set_saved_title(fpath)
class OmxGui(Frame): def __init__(self, parent, argv): Frame.__init__(self, parent, padding=(3,6,3,12), style="TFrame") self.parent = parent self.initData() self.initUI() if len(argv) > 1: try: self.updateAndPlayVideo(argv[1]) except FileNotFoundError: self.logDebug('File Not Found') def initData(self): self.browseInitialDir = def_initialDir self.recentFile = def_recentFile self.menuOutputAudio = StringVar() self.menuOutputAudio.set(def_menuOutputAudio) self.menuVideoRefresh = BooleanVar() self.menuVideoRefresh.set(def_menuVideoRefresh) self.menuBgBlack = BooleanVar() self.menuBgBlack.set(def_menuBgBlack) self.maxRecentVideos = def_maxRecentVideos self.moreOptions = def_moreOptions self.playProcess = None def initUI(self): self.parent.title('OMX GUI') self.parent.bind("<Key>", self.keyEvt) # ---- STYLE ---- Style().theme_use('default') Style().configure("TFrame", background="white") Style().configure("TButton", font="12", padding=(5,1,5,1), background="#4285F4", foreground="white") Style().configure("TEntry", font="12", padding=(5,3,5,2)) Style().configure("TLabel", background="white") Style().map('TButton', foreground=[('pressed', 'white'), ('active', 'white')], background=[('pressed', '!disabled', '#3367d6'), ('active', '#3b78e7')], highlightcolor=[('focus','#4285F4')], relief=[('pressed', '!disabled', 'flat')]) Style().configure('Treeview', foreground='#333', background="white", highlightthickness='0') Style().map('Treeview', foreground=[('focus', '#000')], background=[('focus', '#F5F5F5')]) # ---- MENU ---- self.menubar = menubar = MenuBar(self, self.parent) # ---- TREE ---- self.filesTree = filesTree = FilesTree(self) self.filesTree.loadRecentFile() # ---- BUTTONS ---- bBrowse = Button(self, text=_("browse"), width="6", command=self.openVideo) bPlay = Button(self, text=_("play"), width="6", command=self.playVideo) # ---- GRID ---- self.grid(column=0, row=0, sticky=(N, E, W, S)) filesTree.grid(column=0, row=0, columnspan=2, rowspan=2, sticky=(N,W,E)) bBrowse.grid(column=0, row=2, sticky=(N,W)) bPlay.grid(column=0, row=2, sticky=(N,W), padx=70) self.parent.columnconfigure(0, weight=1) self.parent.rowconfigure(0, weight=1) self.columnconfigure(0, weight=1) self.columnconfigure(1, weight=1) self.rowconfigure(0, weight=1) self.rowconfigure(1, weight=1) self.centerWindow() def centerWindow(self): self.parent.update_idletasks() w = self.parent.winfo_reqwidth() + 20 h = self.parent.winfo_reqheight() + 20 sw = self.parent.winfo_screenwidth() sh = self.parent.winfo_screenheight() x = (sw - w)/4 y = (sh - h)/4 self.parent.geometry("%dx%d+%d+%d" % (w, h, x, y)) self.parent.resizable(False,False) self.parent.focus_force() self.parent.lift() def quitProgram(self): self.parent.quit() def clearRecentVideos(self): self.filesTree.clearRecentVideos() def updateRecentVideos(self, fullpath): return self.filesTree.updateRecentVideos(fullpath) def updateAndPlayVideo(self, fullpath): if self.updateRecentVideos(fullpath): self.playVideo() def openVideo(self): fullpath = fileDialog.askopenfilename( title=_('open.file') ,initialdir=self.browseInitialDir) self.updateAndPlayVideo(fullpath) def playVideo(self): lastFile = self.filesTree.getLastFile() if lastFile is not None and lastFile['fullpath'] is not '': outputAudio = '-o ' + self.menuOutputAudio.get() + ' ' adjustVideo = '-r ' if self.menuVideoRefresh.get() else '' bgBlack = '-b ' if self.menuBgBlack.get() else '' moreOptions = self.moreOptions fPath = lastFile['fullpath'].replace(' ', '\ ') cmdStr = 'omxplayer ' + outputAudio + adjustVideo + bgBlack + moreOptions + fPath self.logDebug(cmdStr) self.playProcess = Popen(['bash', '-c', cmdStr], stdin=PIPE, bufsize = 1) self.parent.focus_force() def keyEvt(self, event): self.logDebug('char: ' + event.char + ' --- key simbol: ' + event.keysym + ' --- key code: ' + str(event.keycode)) if self.playProcess is not None: # right if event.keysym == 'Right': self.playProcess.stdin.write(bytes('^[[C', 'UTF-8')) # left elif event.keysym == 'Left': self.playProcess.stdin.write(bytes('^[[D', 'UTF-8')) # up elif event.keysym == 'Up': self.playProcess.stdin.write(bytes('^[[A', 'UTF-8')) # down elif event.keysym == 'Down': self.playProcess.stdin.write(bytes('^[[B', 'UTF-8')) elif event.char == 'x': self.playProcess.kill() self.playProcess = None else: self.playProcess.stdin.write(bytes(event.char, 'UTF-8')) try: self.playProcess.stdin.flush() except IOError: try: self.playProcess.stdin.close() self.playProcess = None except IOError: self.playProcess = None self.parent.focus_force() def logDebug(self, msg): if isDebug and msg is not None: print(str(msg))
class MainWindow: def __init__(self, credentials): self.window = Tk() self.window.withdraw() self.credentials = credentials self.settings = readSettings() self.followedStreams = getAllStreamsUserFollows(self.credentials) self.topTwitchStreams = getTopTwitchStreams(self.credentials) self.teams = readTeams(self.followedStreams) self.tags = readTags(self.credentials.oauth) self.windowFrame = Frame(self.window) self.searchFrame = SearchFrame(self) self.singleSelectMode = BooleanVar() self.multipleSelectMode = BooleanVar() self.hideThumbnail = BooleanVar() self.hideBoxArt = BooleanVar() self.enableFilters = BooleanVar() self.enableDesktopNotifications = BooleanVar() self.autoRefreshLength = IntVar() self.scrollableFrame = ScrollableFrame(1010, 680, self) self.liveStreams = getLiveFollowedStreams(credentials.oauth, [ self.followedStreams[i:i + 100] for i in range(0, len(self.followedStreams), 100) ]) self.initializeWindow() self.gridFrames() self.addMenu() self.applySettings() self.window.update() self.scrollableFrame.loadImagesIntoFrames() self.window.deiconify() def gridFrames(self): self.searchFrame.topFrame.grid(row=0, column=0, sticky=NSEW, padx=4, pady=6) self.searchFrame.middleFrame.grid(row=1, column=0, sticky=NSEW, padx=4, pady=6) self.searchFrame.bottomFrame.grid(row=2, column=0, sticky=NSEW, padx=4, pady=6) self.searchFrame.bottomestFrame.grid(row=3, column=0, sticky=NSEW, padx=4, pady=8) self.scrollableFrame.grid(row=0, column=1, rowspan=4, sticky=NSEW, padx=4) self.windowFrame.grid() def addMenu(self): menu = Menu(self.window) fileMenu = Menu(menu, tearoff=0) fileMenu.add_command(label=LabelConstants.QUIT, command=lambda: self.closeWindow()) menu.add_cascade(label=LabelConstants.FILE, menu=fileMenu) manageMenu = Menu(menu, tearoff=0) manageMenu.add_command(label=LabelConstants.SETTINGS_TEAM_WINDOW, command=lambda: TeamWindow(self, self.teams)) manageMenu.add_command( label=LabelConstants.SETTINGS_FILTER_WINDOW, command=lambda: FilterWindow(self, self.scrollableFrame.filters)) manageMenu.add_command(label=LabelConstants.SETTINGS_TAG_WINDOW, command=lambda: TagWindow(self)) menu.add_cascade(label=LabelConstants.EDIT, menu=manageMenu) settingsMenu = Menu(menu, tearoff=0) settingsMenu.add_checkbutton(label=LabelConstants.HIDE_THUMBNAIL, variable=self.hideThumbnail, command=lambda: self.toggleThumbnail()) settingsMenu.add_checkbutton(label=LabelConstants.HIDE_BOXART, variable=self.hideBoxArt, command=lambda: self.toggleBoxArt()) settingsMenu.add_checkbutton( label=LabelConstants.ENABLE_FILTERS, variable=self.scrollableFrame.enableFilters, command=lambda: self.scrollableFrame.toggleFilters()) autoRefreshMenu = Menu(settingsMenu, tearoff=0) autoRefreshMenu.add_radiobutton( label=LabelConstants.AUTO_REFRESH_ZERO, var=self.autoRefreshLength, value=0, command=lambda: self.scrollableFrame.setAutoRefreshLength(0)) autoRefreshMenu.add_radiobutton( label=LabelConstants.AUTO_REFRESH_ONE, var=self.autoRefreshLength, value=1, command=lambda: self.scrollableFrame.setAutoRefreshLength(1)) autoRefreshMenu.add_radiobutton( label=LabelConstants.AUTO_REFRESH_FIVE, var=self.autoRefreshLength, value=5, command=lambda: self.scrollableFrame.setAutoRefreshLength(5)) autoRefreshMenu.add_radiobutton( label=LabelConstants.AUTO_REFRESH_TEN, var=self.autoRefreshLength, value=10, command=lambda: self.scrollableFrame.setAutoRefreshLength(10)) settingsMenu.add_cascade(label=LabelConstants.AUTO_REFRESH, menu=autoRefreshMenu) settingsMenu.add_checkbutton( label=LabelConstants.DESKTOP_NOTIFICATIONS, variable=self.enableDesktopNotifications, command=lambda: self.toggleDesktopNotifications()) menu.add_cascade(label=LabelConstants.SETTINGS_MENU, menu=settingsMenu) issueMenu = Menu(menu, tearoff=0) issueMenu.add_command( label=LabelConstants.VIA_DISCORD, command=lambda: webbrowser.open(URLConstants.DISCORD, new=2)) issueMenu.add_command( label=LabelConstants.VIA_GITHUB, command=lambda: webbrowser.open(URLConstants.GITHUB, new=2)) helpMenu = Menu(menu, tearoff=0) helpMenu.add_cascade(label=LabelConstants.REPORT_ISSUE, menu=issueMenu) helpMenu.add_command(label=LabelConstants.ABOUT, command=lambda: AboutWindow(self)) menu.add_cascade(label=LabelConstants.HELP, menu=helpMenu) self.window.config(menu=menu) def initializeWindow(self): self.window.iconbitmap(FileConstants.STREAMOPENER_ICON) self.window.geometry('1280x720') self.window.title(LabelConstants.STREAMOPENER) self.window.resizable(width=False, height=False) def closeWindow(self): sys.exit(0) def toggleThumbnail(self): if self.hideThumbnail.get(): self.scrollableFrame.showThumbnails(False) else: self.scrollableFrame.showThumbnails(True) self.settings[LabelConstants.SETTINGS_JSON][ MiscConstants.KEY_HIDE_THUMBNAIL] = self.hideThumbnail.get() writeSettings(self.settings) def toggleBoxArt(self): if self.hideBoxArt.get(): self.scrollableFrame.showBoxArts(False) else: self.scrollableFrame.showBoxArts(True) self.settings[LabelConstants.SETTINGS_JSON][ MiscConstants.KEY_HIDE_BOXART] = self.hideBoxArt.get() writeSettings(self.settings) def toggleDesktopNotifications(self): self.settings[LabelConstants.SETTINGS_JSON][ MiscConstants. KEY_DESKTOP_NOTIFICATIONS] = self.enableDesktopNotifications.get() writeSettings(self.settings) def applySettings(self): if MiscConstants.KEY_HIDE_THUMBNAIL in self.settings[ LabelConstants.SETTINGS_JSON]: self.hideThumbnail.set(self.settings[LabelConstants.SETTINGS_JSON][ MiscConstants.KEY_HIDE_THUMBNAIL]) else: self.hideThumbnail.set(False) if MiscConstants.KEY_HIDE_BOXART in self.settings[ LabelConstants.SETTINGS_JSON]: self.hideBoxArt.set(self.settings[LabelConstants.SETTINGS_JSON][ MiscConstants.KEY_HIDE_BOXART]) else: self.hideBoxArt.set(False) if MiscConstants.KEY_OPEN_STREAMS_ON in self.settings[ LabelConstants.SETTINGS_JSON]: self.searchFrame.site.set( self.settings[LabelConstants.SETTINGS_JSON][ MiscConstants.KEY_OPEN_STREAMS_ON]) else: self.searchFrame.site.set(URLConstants.ORDERED_STREAMING_SITES[ LabelConstants.URL_TWITCH]) if MiscConstants.KEY_TEAM in self.settings[ LabelConstants.SETTINGS_JSON] and self.settings[ LabelConstants.SETTINGS_JSON][ MiscConstants.KEY_TEAM] in self.teams.keys(): self.searchFrame.currentTeam.set(self.settings[ LabelConstants.SETTINGS_JSON][MiscConstants.KEY_TEAM]) if MiscConstants.KEY_AUTOREFRESH in self.settings[ LabelConstants.SETTINGS_JSON]: self.autoRefreshLength.set(self.settings[ LabelConstants.SETTINGS_JSON][MiscConstants.KEY_AUTOREFRESH]) if MiscConstants.KEY_DESKTOP_NOTIFICATIONS in self.settings[ LabelConstants.SETTINGS_JSON]: self.enableDesktopNotifications.set( self.settings[LabelConstants.SETTINGS_JSON][ MiscConstants.KEY_DESKTOP_NOTIFICATIONS]) def setTags(self, tags): self.tags = deepcopy(tags) self.searchFrame.populateTwitchTagsListbox() writeTags(self.tags) def setTeams(self, teams): self.teams = teams writeTeams(self.teams) self.searchFrame.updateComboboxTeam()
class FrameFlatfileDataset(FrameCustomFileDataset): """ Holds an instance of, and visually represents, a flatfile dataset. See qal.dataset.flatfile.FlatfileDataset """ def __init__(self, _master, _dataset = None, _relief = None, _is_destination=None): super(FrameFlatfileDataset, self ).__init__(_master, _dataset, _relief, _is_destination=_is_destination) if _dataset is None: self.dataset = FlatfileDataset() def on_select(self): """Brings up a selector dialog, prompting the user to select a file, the relative path if the file is then saved to the filename property. Also, the base path is set. """ self.select_file(_default_extension = ".csv", _file_types=[('.csv files', '.csv'), ('all files', '.*')]) def init_widgets(self): # file selector self.btn_file_select=Button(self, text="Select file",command=self.on_select) self.btn_file_select.grid(column=0, row=0, columnspan=2) # filename self.filename, self.e_filename, self.l_filename = make_entry(self,"File name: ", 1) # delimiter self.delimiter, self.e_delimiter, self.l_delimiter = make_entry(self,"Delimiter: ", 2) # has_header self.l_has_header = ttk.Label(self, text="Has header: ") self.l_has_header.grid(column=0, row=3, sticky=W) self.has_header = BooleanVar() self.e_has_header = ttk.Checkbutton(self, variable=self.has_header) self.e_has_header.grid(column=1, row=3, sticky=W) # csv_dialect self.csv_dialect, self.e_csv_dialect, self.l_csv_dialect = make_entry(self,"CSV dialect: ", 4) # quoting self.quoting, self.e_quoting, self.l_quoting = make_entry(self, "Quoting: ", 5) # escapechar self.escapechar, self.e_escapechar, self.l_escapechar = make_entry(self, "Escape character: ", 6) # lineterminator self.lineterminator, self.e_lineterminator, self.l_lineterminator = make_entry(self, "Line terminator: ", 7) # quotechar self.quotechar, self.e_quotechar, self.l_quotechar = make_entry(self, "Quote character: ", 8) # skipinitialspace self.skipinitialspace, self.e_skipinitialspace, self.l_skipinitialspace = make_entry(self, "Skip initial space: ", 9) def read_from_dataset(self): super(FrameFlatfileDataset, self ).read_from_dataset() self.filename.set(empty_when_none(self.dataset.filename)) self.delimiter.set(empty_when_none(self.dataset.delimiter)) self.has_header.set(bool_to_binary_int(self.dataset.has_header)) self.csv_dialect.set(empty_when_none(self.dataset.csv_dialect)) self.quoting.set(empty_when_none(self.dataset.quoting)) self.escapechar.set(empty_when_none(self.dataset.escapechar)) self.lineterminator.set(empty_when_none(self.dataset.lineterminator)) self.quotechar.set(empty_when_none(self.dataset.quotechar)) self.skipinitialspace.set(empty_when_none(self.dataset.skipinitialspace)) def write_to_dataset(self): super(FrameFlatfileDataset, self ).write_to_dataset() if self.dataset is None: self.dataset = FlatfileDataset() self.dataset.filename = self.filename.get() self.dataset.delimiter = self.delimiter.get() self.dataset.has_header = self.has_header.get() self.dataset.csv_dialect = self.csv_dialect.get() self.dataset.quoting = self.quoting.get() self.dataset.escapechar = self.escapechar.get() self.dataset.lineterminator = self.lineterminator.get() self.dataset.quotechar = self.quotechar.get() self.dataset.skipinitialspace = self.skipinitialspace.get() def reload(self): self.notify_task("Load file "+ self.dataset.filename, 10) self.dataset.load() self.notify_task("Loaded filed "+ self.dataset.filename + ".", 100) def get_possible_references(self, _force = None): if not self.dataset.field_names or _force == True: self.reload() self.references = self.dataset.field_names return self.dataset.field_names def check_reload(self): _filename = self.filename.get() if not os.path.isabs(_filename) and self.base_path is None: return "First save the merge. You use a relative path to the flatfile dataset." else: return False
class UI: def __init__(self) -> None: self.ventana = tk.Tk() self.ventana.title("You Make A Moon 1.2.1") self.ventana.iconbitmap('settings/images/moon.ico') self.ventana.resizable(False, False) self.ventana.overrideredirect(True) #! ESTO self.ventana.tk.eval(""" set base_theme_dir settings/theme/awthemes-10.3.0/ package ifneeded awthemes 10.3.0 \ [list source [file join $base_theme_dir awthemes.tcl]] package ifneeded colorutils 4.8 \ [list source [file join $base_theme_dir colorutils.tcl]] package ifneeded awdark 7.11 \ [list source [file join $base_theme_dir awdark.tcl]] package ifneeded awlight 7.6 \ [list source [file join $base_theme_dir awlight.tcl]] """) self.ventana.tk.call("package", "require", 'awdark') self.ventana.tk.call("package", "require", 'awlight') self.style = ttk.Style() self.style.theme_use(settings.get_theme()) self.tamanio = 30 self.style.configure('TButton', font=('arial', 20, 'bold')) self.style.configure('TLabel', font=('arial', 15)) self.style.configure('TEntry', font=('arial', 15)) title_bar = ttk.Frame(self.ventana, relief='raised') close_button = ttk.Button(title_bar, text='X', command=self.ventana.destroy) title_text = ttk.Label(title_bar, text="You Make A Moon 1.2", font=(20)) title_bar.pack(expand=1, fill=tk.X, side=tk.TOP) title_text.pack(side=tk.LEFT, padx=10) close_button.pack(side=tk.RIGHT) title_bar.bind('<B1-Motion>', self.move_window) self.notebook = ttk.Notebook(self.ventana) self.notebook.pack() self.menuframe = ttk.LabelFrame(self.notebook, border=0) self.menuframe.pack() self.infoframe = ttk.LabelFrame(self.notebook, border=0) self.infoframe.pack() self.settingsframe = ttk.LabelFrame(self.notebook, border=0) self.settingsframe.pack() self.notebook.add(self.menuframe, text="You Make A Moon") self.notebook.add(self.settingsframe, text="Configuración") self.notebook.add(self.infoframe, text="Info") def move_window(self, event): self.ventana.geometry('+{0}+{1}'.format(event.x_root - 550, event.y_root)) def principal(self): self.texto = tk.StringVar() self.plantilla = tk.IntVar() lf_mesadetrabajo = ttk.LabelFrame(self.menuframe, border=0) lf_mesadetrabajo.pack(side=tk.LEFT, padx=20) self.canvas2 = tk.Canvas(lf_mesadetrabajo, width="716", height="402", relief=tk.RIDGE, bd=0) self.canvas2.grid(row=0, column=0, columnspan=2) l_name = ttk.Label(lf_mesadetrabajo, text="Ingrese el texto de su Luna: ") l_name.grid(row=1, column=0, padx=20, pady=10) e_text = ttk.Entry(lf_mesadetrabajo, textvariable=self.texto, font=(20), width=30) e_text.grid(row=1, column=1, padx=20) e_text.bind('<Key>', lambda i: MakePhoto.minifoto(i, self.canvas2, self.texto)) b_generar = ttk.Button(lf_mesadetrabajo, text="Guardar Foto", command=lambda: self.foto(self.texto.get())) b_generar.grid(row=2, column=0, columnspan=2, pady=10) plantilla_l = ttk.Label(lf_mesadetrabajo, text="Plantilla: ") plantilla_l.grid(row=2, column=1, padx=55, sticky='E') plantilla = ttk.Spinbox(lf_mesadetrabajo, from_=1, to=len(os.listdir('settings/images/temples')), width=5, textvariable=self.plantilla, command=self.temple) self.plantilla.set(settings.get_temple()) plantilla.grid(row=2, column=1, sticky='E') MakePhoto.default(self.canvas2) def temple(self): settings.update_json(self.var_theme.get(), settings.get_moons(), self.var_history.get(), self.plantilla.get(), settings.get_photo()) MakePhoto.minifoto_historial(self.canvas2, self.texto.get()) def foto(self, texto): MakePhoto.cearfoto(texto) settings.update_json(self.var_theme.get(), settings.get_moons() + 1, self.var_history.get(), settings.get_temple(), settings.get_photo()) self.lb_moon["text"] = f"Lunas creadas: {settings.get_moons()}" if (self.var_history.get()): self.colocar_historial() def historial(self): def borrar(): texto = self.lista.get(self.lista.curselection()[0]) base = DataBase.DataBase() base.delet_moon(texto) base.desconectar() self.colocar_historial() def seleccionado(): try: self.texto.set(self.lista.get(self.lista.curselection()[0])) MakePhoto.minifoto_historial(self.canvas2, self.texto.get()) except IndexError: pass lf_historial = ttk.LabelFrame(self.menuframe, border=0) lf_historial.pack(expand='yes', fill='both') scrollbar = ttk.Scrollbar(lf_historial) scrollbar.pack(side=tk.RIGHT, fill=tk.Y) if settings.get_theme() == 'awdark': self.lista = tk.Listbox(lf_historial, font=self.tamanio, yscrollcommand=scrollbar.set, width=25, bg='#232829', fg="#FFFFFF") else: self.lista = tk.Listbox(lf_historial, font=self.tamanio, yscrollcommand=scrollbar.set, width=25) self.lista.pack(fill='both', expand='yes', side=tk.LEFT) self.lista.bind("<<ListboxSelect>>", lambda x: seleccionado()) self.lista.bind("<BackSpace>", lambda x: borrar()) scrollbar.config(command=self.lista.yview) self.colocar_historial() def colocar_historial(self): base_datos = DataBase.DataBase() textos = base_datos.get_moons() self.lista.delete(0, tk.END) for a in textos: self.lista.insert(tk.END, a[1]) base_datos.desconectar() def info(self): creditos = ttk.LabelFrame(self.infoframe, border=0) creditos.pack() l_creditos = ttk.Label( creditos, text="You Make a Moon es un software libre desarrollado ", font=25) l_creditos.pack() l_creditos1 = ttk.Label(creditos, text="por La Odisea de los Memes", font=25) l_creditos1.pack() lf_enlaces = ttk.LabelFrame(creditos, text="Links de Referencia:", border=0) lf_enlaces.pack(pady=20, expand='yes') self.i_face = tk.PhotoImage( file=("settings/images/logos/facebook.png")) b_facebook = ttk.Button(lf_enlaces, image=self.i_face, command=Links.facebook) b_facebook.pack(side=tk.LEFT) self.i_twit = tk.PhotoImage(file='settings/images/logos/twitter.png') b_twitter = ttk.Button(lf_enlaces, image=self.i_twit, command=Links.twitter) b_twitter.pack(side=tk.LEFT, padx=30, pady=10) self.i_github = tk.PhotoImage(file='settings/images/logos/github.png') b_github = ttk.Button(lf_enlaces, image=self.i_github, command=Links.github) b_github.pack(side=tk.LEFT) self.logo1 = Image.open('settings/images/logos/Make.png') if settings.get_theme() == 'awdark': self.logo2 = Image.open('settings/images/logos/Logo_white.png') else: self.logo2 = Image.open('settings/images/logos/Logo_black.png') self.logo1 = self.logo1.resize((290, 110), Image.ANTIALIAS) self.logo1 = ImageTk.PhotoImage(self.logo1) self.logo2 = self.logo2.resize((290, 129), Image.ANTIALIAS) self.logo2 = ImageTk.PhotoImage(self.logo2) lf_logo = ttk.LabelFrame(creditos, border=0) lf_logo.pack() l_logo1 = ttk.Label(lf_logo, image=self.logo1) l_logo1.pack(side=tk.RIGHT, padx=20) l_logo2 = ttk.Label(lf_logo, image=self.logo2) l_logo2.pack(side=tk.RIGHT, padx=20) l_legal = ttk.Label( creditos, text="Super Mario Odyssey is a trademark of Nintendo Co., Ltd.", font=40) l_legal.pack(side=tk.BOTTOM) def settings(self): def update_theme(): settings.update_json(self.var_theme.get(), settings.get_moons(), self.var_history.get(), settings.get_temple(), settings.get_photo()) lb_warning.grid(row=0, column=3, padx=30) def update_history(): settings.update_json(self.var_theme.get(), settings.get_moons(), self.var_history.get(), settings.get_temple(), self.var_photo.get()) self.var_theme = StringVar() self.var_history = BooleanVar() self.var_photo = BooleanVar() lb_theme = ttk.Label(self.settingsframe, text="Tema: ", font=(25)) lb_theme.grid(row=0, column=0, sticky='W') awdark = ttk.Radiobutton(self.settingsframe, text="Oscuro", variable=self.var_theme, value="awdark", command=update_theme) awdark.grid(row=0, column=1, padx=30) awlight = ttk.Radiobutton(self.settingsframe, text="Claro", variable=self.var_theme, value="awlight", command=update_theme) awlight.grid(row=0, column=2, padx=30) self.var_theme.set(settings.get_theme()) lb_theme = ttk.Label(self.settingsframe, text="Historial de Lunas: ", font=(25)) lb_theme.grid(row=1, column=0, sticky='W') self.var_history.set(bool(settings.get_history())) switchistory = ttk.Checkbutton(self.settingsframe, variable=self.var_history, command=update_history) switchistory.grid(row=1, column=1) lb_photo = ttk.Label(self.settingsframe, text="Ver foto: ", font=(25)) lb_photo.grid(row=2, column=0, sticky='W') self.var_photo.set(bool(settings.get_photo())) switchphoto = ttk.Checkbutton(self.settingsframe, variable=self.var_photo, command=update_history) switchphoto.grid(row=2, column=1) lb_warning = ttk.Label( self.settingsframe, text="Es necesario reiniciar el programa para aplicar el tema") self.lb_moon = ttk.Label(self.settingsframe, text=f"Lunas creadas: {settings.get_moons()}", font=25) self.lb_moon.grid(row=6, column=0, columnspan=2, sticky='W', pady=20) def mantener(self): self.ventana.configure(bg=self.style.lookup('TFrame', 'background')) self.ventana.mainloop()
class LayoutTester(object): """Gränssnitt för testning av layoutfunktioner.""" def __init__(self, layout_func, debug=False): """Skapa GUI och förbereder tkinter.Labels som ska layoutas. layout_func -- Funktionen som ska placera kvadraterna, se modulbeskrivning ovan. """ self.layout_func = layout_func self.debug = debug # storleksalternativ self.size_options = [ size for size in range(MIN_SQUARE_SIZE, MAX_SQUARE_SIZE + 1, SIZE_STEP) ] + ["random"] # lista för kvadraterna self.squares = [] # skapa gränssnittet och kör igång mainloop self.ui_xpadding = 4 self.ui_ypadding = 4 self.init_ui() # slumpa fram fönsterstorlek w_size = "{}x{}".format(705 + randint(0, 300), 250 + randint(0, 500)) self.root.geometry(w_size) self.root.mainloop() def init_ui(self): """Skapa gränssnittet och kör igång mainloop.""" self.root = Tk() self.root.title("Laboration 5") # root.resizable(width=False, height=False) # Tk-variabler till kvadratsstorlek, antal kvadrater, start_left och # start_top. self.size_value = StringVar() self.size_value.set(self.size_options[0]) self.number_of_squares = IntVar() self.start_left = BooleanVar() self.start_left.set(True) self.start_top = BooleanVar() self.start_top.set(True) # Frame att lägga kvadraterna i self.square_frame = Frame( self.root, # height=self.squares_frame_height, # width=self.squares_frame_width, bg="#eef") if self.debug: self.square_frame.bind("<Configure>", self.frame_changed) self.square_frame.pack(side=TOP, expand=1, fill=BOTH, padx=self.ui_xpadding, pady=self.ui_ypadding) # Frame med inställningar self.controll_panel = LabelFrame(self.root, text="Inställningar") self.init_controll_panel() self.controll_panel.pack(fill=BOTH, padx=self.ui_xpadding, pady=self.ui_ypadding) # Informationstext infotext = "Kom ihåg att ändra fönstrets storlek när du testar! " + \ "Se även utskrifterna i terminalen." self.instructions = Label(self.root, text=infotext) self.instructions.pack(anchor=W) def init_controll_panel(self): """Skapa kontrollpanel för inställningar.""" self.create_size_panel() self.create_num_squares_panel() # self.create_start_pos_panel() self.create_run_quit_panel() def create_size_panel(self): """Skapa OptionMenu för storlek på kvadraterna.""" size_panel = Frame(self.controll_panel) Label(size_panel, text="Kvadratsstorlek").pack(side=LEFT) OptionMenu(size_panel, self.size_value, *self.size_options).pack(side=LEFT) size_panel.pack(side=LEFT, padx=self.ui_xpadding, pady=self.ui_ypadding) def create_num_squares_panel(self): """Skapa kontroller för att välja antal kvadrater som skapas.""" num_squares_panel = Frame(self.controll_panel) Label(num_squares_panel, text="Antal kvadrater").pack(side=LEFT, anchor=S) Scale(num_squares_panel, variable=self.number_of_squares, from_=4, to=MAX_NUM_SQUARES, orient=HORIZONTAL).pack(side=LEFT, anchor=N) num_squares_panel.pack(side=LEFT, anchor=N, padx=self.ui_xpadding, pady=self.ui_ypadding) def create_start_pos_panel(self): """Skapa kontroller för att välja var layouten börjar.""" start_panel = Frame(self.controll_panel) Checkbutton(start_panel, text="Börja från vänster", justify=LEFT, variable=self.start_left, onvalue=True, offvalue=False).pack(fill=X, anchor=N) Checkbutton(start_panel, text="Börja uppifrån", variable=self.start_top, justify=LEFT, onvalue=True, offvalue=False).pack(fill=X, anchor=N) start_panel.pack(side=LEFT, anchor=N, padx=self.ui_xpadding, pady=self.ui_ypadding) def create_run_quit_panel(self): """Skapa knappar för att köra layout och avsluta programmet.""" button_panel = Frame(self.controll_panel) Button(button_panel, text="Kör layoutfunktion", command=self.run_layout).pack(fill=X) Button(button_panel, text="Avsluta", command=self.root.quit).pack(fill=X) button_panel.pack(side=RIGHT, anchor=N, padx=self.ui_xpadding, pady=self.ui_ypadding) def create_squares(self): """Skapa tkinter.Label objekt som sparas i LayoutTester-instansen. Antalet kvadrater som ska skapas, samt kvadraternas storlek hämtas från gränssnittet. """ number_of_squares = self.number_of_squares.get() size = self.size_value.get() square_counter = 0 hue_step = 1 / number_of_squares hue_value = 0 # Skapa kvadrater och lägg dem i listan self.squares while square_counter < number_of_squares: # konververa hsv-färg till rgb-trippel (heltal 0-255) rgb = [int(val * 255) for val in hsv_to_rgb(hue_value, 0.75, 0.70)] # konvertera rgb-trippel till sträng bg_color = "#{:x}{:x}{:x}".format(rgb[0], rgb[1], rgb[2]) # textfärg fg_color = "#fff" # sätt storleken på kvadraten if size != "random": square_size = int(size) else: square_size = choice(self.size_options[:-1]) # sätt storleken på texten baserat på kvadratstorleken font_size = int(square_size * 0.6) # skapa kvadraten square = Label(self.square_frame, fg=fg_color, bg=bg_color, font=Font(family="Verdana", weight=NORMAL, size=font_size), text=str(square_counter + 1)) # spara den i listan med kvadrater self.squares.append(square) # göm kvadraten utanför det synliga området och ställ in # dess storlek square.place(x=-square_size, y=-square_size, height=square_size, width=square_size) # gå vidare till nästa kvadrat och färg square_counter += 1 hue_value += hue_step # uppdatera geometri-info för alla widgets (ser till att de vet hur # stora de är) square.update_idletasks() def clear_squares(self): """Ta bort existerande kvadrater.""" for square in self.squares: square.destroy() del self.squares[:] def frame_changed(self, event): if event.widget == self.square_frame or event.widget == self.root: print("Resize. root: {}x{}, square_frame: {}x{}".format( self.root.winfo_width(), self.root.winfo_height(), self.square_frame.winfo_width(), self.square_frame.winfo_height())) def run_layout(self): """Skapa nya kvadrater och kör layoutfunktionen.""" # ta bort gamla kvadrater self.clear_squares() # skapa nya kvadrater self.create_squares() # placera ut kvadraterna print("Running '{0}(<squares>, {1}, {2})'...".format( self.layout_func.__name__, self.square_frame.winfo_height(), self.square_frame.winfo_width())) self.layout_func(self.squares, self.square_frame.winfo_height(), self.square_frame.winfo_width())
class App: def __init__(self, master): self.master = master self.fname = StringVar(value='') # 搜索文件名 self.ftype = StringVar(value='') # 搜索文件类型 self.fpath = StringVar(value=os.environ['HOME']) # 搜索路径 self.advance = BooleanVar(value=False) # 遍历子目录 self.view() def about(self): '''关于''' txt = '作者:%s\n版本:%s' % (__author__, __version__) self.showinfo(title='关于', message=txt) def close(self): '''关闭应用''' self.master.quit() exit() def showinfo(self, title, message): '''显示提示''' messagebox.showinfo(parent=self.master, title=title, message=message) def showerror(self, title, message): '''显示报错''' messagebox.showerror(parent=self.master, title=title, message=message) def view(self): '''加载视图''' # 区域:文件名 row_1 = Frame(self.master) row_1.pack(side='top', fill='x', expand=True) Label(row_1, text='文件名:', width=13, justify='left').pack(side='left') # 文件名输入框 self.entry_fname = Entry(row_1, textvariable=self.fname, borderwidth=1, highlightcolor='#ddd', width=60) self.entry_fname.pack(side='right', fill='x', expand=True) # 区域:文件类型 row_2 = Frame(self.master) row_2.pack(side='top', fill='x', expand=True) Label(row_2, text='文件后缀:', width=13, justify='left').pack(side='left') # 文件类型输入框 self.entry_ftype = Entry(row_2, textvariable=self.ftype, borderwidth=1, highlightcolor='#ddd') self.entry_ftype.pack(side='left', fill='x', expand=True) # 区域:搜索路径 row_3 = Frame(self.master) row_3.pack(side='top', fill='x', expand=True) Label(row_3, text='搜索位置:', width=13, justify='left').pack(side='left') # 路径输入框 self.entry_fpath = Entry(row_3, textvariable=self.fpath, borderwidth=1, highlightcolor='#ddd') self.entry_fpath.pack(side='left', fill='x', expand=True) # 按钮:选择路径按钮 # bbb = Label(row_3, text='...', justify='left') # bbb.bind('<Button-1>', self.select_path) # 绑定双击事件 # bbb.pack(side='left') button_path = Button(row_3, text='选择', command=self.select_path) button_path.pack(side='right') # 区域:选项配置 row_4 = Frame(self.master) row_4.pack(side='top', fill='x', expand=True) Label(row_4, text='选项', width=13, justify='left').pack(side='left') # 是否查找子目录 Checkbutton(row_4, text='高级功能', variable=self.advance).pack(side='left') # 区域:操作按钮 row_5 = Frame(self.master) row_5.pack(side='top', fill='x', expand=True) # 按钮 Label(row_5, text='操作', width=13, justify='left').pack(side='left') button = Button(row_5, text='搜索', command=self.do_search) button.pack(side='left') button = Button(row_5, text='清理结果', command=self.do_clean) button.pack(side='left') button = Button(row_5, text='重置', command=self.do_reset) button.pack(side='left') button = Button(row_5, text='关于', command=self.about) button.pack(side='left') button = Button(row_5, text='关闭', command=self.close) button.pack(side='left') # 区域:搜索结果 row_6 = Frame( self.master, # relief='raised', borderwidth=1,highlightbackground='#ddd' ) row_6.pack(side='bottom', fill='both', expand=True) # 滚动条 # scroll_x = Scrollbar(row_6) # scroll_x.pack(side='bottom', fill='x', expand=True) scroll_y = Scrollbar(row_6) scroll_y.pack(side='right', fill='y') # 列表 self.result = Listbox( row_6, width=40, height=200, relief='ridge', borderwidth=1, highlightcolor='#ddd', # foreground='#ddd', ) self.result.pack(side='left', fill='both', expand=True) # 列表与滚动绑定 # self.result['xscrollcommand'] = scroll_x.set # scroll_x.config(command=self.result.xview) self.result['yscrollcommand'] = scroll_y.set scroll_y.config(command=self.result.yview) # 双击打开 self.result.bind('<Double-Button-1>', self.opendir) def select_path(self): '''选择文件夹''' fpath = askdirectory(parent=self.master, message='选择搜索位置', title='选择搜索位置') if isdir(fpath): self.fpath.set(fpath) def do_search(self): '''搜索''' fname = self.fname.get() ftype = self.ftype.get() fpath = self.fpath.get() advance = self.advance.get() if advance: self.showinfo(title='错误提示', message='高级功能还没想好。。') elif not ftype: self.showinfo(title='错误提示', message='文件后缀不能为空') elif not fpath: self.showinfo(title='错误提示', message='搜索路径不能为空') else: ftype = '.' + ftype self.result.delete(0, 'end') fileList = os.walk(fpath) # 所有文件目录 resList = [] for path, _, file in fileList: # path:路径,_:文件夹,file:文件 for filename in file: # re.I不区分大小写 rr = re.compile(r'.*?(%s).*(%s)$' % (fname, ftype), re.I) res = rr.search(filename) if res != None: resList.append(filename) self.result.insert('end', join(path, filename)) if len(resList) == 0: self.showerror('错误提示', '没有找到相关的文件') return def do_reset(self): '''重置''' self.fname.set('') self.ftype.set('') self.fpath.set(value=os.environ['HOME']) self.advance.set(False) self.result.delete(0, 'end') def do_clean(self): '''清理结果''' self.result.delete(0, 'end') def opendir(self, event): '''打开所在文件夹''' index = self.result.curselection() # 获取文件列表索引 print('index', index) if index == (): self.showerror('错误提示', '没有找到相关的文件') else: p = self.result.get(index) d = os.path.dirname(p) # for Mac os.system('open ' + d)
class BaseWidget(Toplevel): def __init__(self, master, name, config, save_config): """Create base desktop widget.""" Toplevel.__init__(self, master, class_=APP_NAME) self.rowconfigure(2, weight=1) self.columnconfigure(0, weight=1) self.minsize(50, 50) self.protocol('WM_DELETE_WINDOW', self.withdraw) self.ewmh = EWMH() self.name = name self.config = config # configparser self.save_config = save_config # save config method # get splash window type compatibility if CONFIG.getboolean('General', 'splash_supported', fallback=True): self.attributes('-type', 'splash') else: self.attributes('-type', 'toolbar') # control main menu checkbutton self.variable = BooleanVar(self, False) # save widget's position self._position = StringVar( self, self.config.get(name, 'position', fallback='normal')) add_trace(self._position, 'write', self._position_trace) self.title('feedagregator.widget.{}'.format(name.replace(' ', '_'))) self.withdraw() # window dragging self.x = None self.y = None # --- menu self._create_menu() # --- elements # --- --- title bar frame = Frame(self, style='widget.TFrame') Button(frame, style='widget.close.TButton', command=self.withdraw).pack(side='left') self.label = Label(frame, text=name, style='widget.title.TLabel', anchor='center') self.label.pack(side='left', fill='x', expand=True) frame.grid(row=0, columnspan=2, padx=4, pady=4, sticky='ew') sep = Separator(self, style='widget.Horizontal.TSeparator') sep.grid(row=1, columnspan=2, sticky='ew') # --- --- widget body self.canvas = Canvas(self, highlightthickness=0) self.canvas.grid(row=2, column=0, sticky='ewsn', padx=(2, 8), pady=(2, 4)) scroll = AutoScrollbar(self, orient='vertical', style='widget.Vertical.TScrollbar', command=self.canvas.yview) scroll.grid(row=2, column=1, sticky='ns', pady=(2, 14)) self.canvas.configure(yscrollcommand=scroll.set) self.display = Frame(self.canvas, style='widget.TFrame') self.canvas.create_window(0, 0, anchor='nw', window=self.display, tags=('display', )) self.display.columnconfigure(0, weight=1) # --- style self.style = Style(self) self._font_size = 10 self.update_style() # --- resizing and geometry corner = Sizegrip(self, style="widget.TSizegrip") corner.place(relx=1, rely=1, anchor='se', bordermode='outside') geometry = self.config.get(self.name, 'geometry') if geometry: self.geometry(geometry) self.update_idletasks() if self.config.getboolean(self.name, 'visible', fallback=True): self.deiconify() # --- bindings self.bind('<3>', lambda e: self.menu.tk_popup(e.x_root, e.y_root)) for widget in [self.label, self.canvas, sep]: widget.bind('<ButtonPress-1>', self._start_move) widget.bind('<ButtonRelease-1>', self._stop_move) widget.bind('<B1-Motion>', self._move) self.label.bind('<Map>', self._change_position) self.bind('<Configure>', self._on_configure) self.bind('<4>', lambda e: self._scroll(-1)) self.bind('<5>', lambda e: self._scroll(1)) self.update_idletasks() self.canvas.configure(scrollregion=self.canvas.bbox('all')) self.populate_widget() if not CONFIG.getboolean('General', 'splash_supported', fallback=True) and self.config.getboolean( self.name, 'visible', fallback=True): Toplevel.withdraw(self) Toplevel.deiconify(self) def _create_menu(self): self.menu = Menu(self, tearoff=False) self.menu_sort = Menu(self.menu, tearoff=False) menu_pos = Menu(self.menu, tearoff=False) menu_pos.add_radiobutton(label=_('Normal'), value='normal', variable=self._position, command=self._change_position) menu_pos.add_radiobutton(label=_('Above'), value='above', variable=self._position, command=self._change_position) menu_pos.add_radiobutton(label=_('Below'), value='below', variable=self._position, command=self._change_position) self.menu.add_cascade(label=_('Sort'), menu=self.menu_sort) self.menu.add_cascade(label=_('Position'), menu=menu_pos) self.menu.add_command(label=_('Hide'), command=self.withdraw) self.menu.add_command(label=_('Open all'), command=self.open_all) self.menu.add_command(label=_('Close all'), command=self.close_all) def populate_widget(self): pass # to be overriden by subclass def open_all(self): pass # to be overriden by subclass def close_all(self): pass # to be overriden by subclass def entry_add(self, title, date, summary, url): """Display entry and return the toggleframe and htmlframe.""" def unwrap(event): l.update_idletasks() try: h = l.html.bbox()[-1] except TclError: pass else: l.configure(height=h + 2) def resize(event): if l.winfo_viewable(): try: h = l.html.bbox()[-1] except TclError: pass else: l.configure(height=h + 2) # convert date to locale time formatted_date = format_datetime(datetime.strptime( date, '%Y-%m-%d %H:%M').astimezone(tz=None), 'short', locale=getlocale()[0]) tf = ToggledFrame(self.display, text="{} - {}".format(title, formatted_date), style='widget.TFrame') l = HtmlFrame(tf.interior, height=50, style='widget.interior.TFrame') l.set_content(summary) l.set_style(self._stylesheet) l.set_font_size(self._font_size) tf.interior.configure(style='widget.interior.TFrame') tf.interior.rowconfigure(0, weight=1) tf.interior.columnconfigure(0, weight=1) l.grid(padx=4, sticky='eswn') Button(tf.interior, text='Open', style='widget.TButton', command=lambda: webopen(url)).grid(pady=4, padx=6, sticky='e') tf.grid(sticky='we', row=len(self.entries), pady=2, padx=(8, 4)) tf.bind("<<ToggledFrameOpen>>", unwrap) l.bind("<Configure>", resize) return tf, l def update_position(self): if self._position.get() == 'normal': if CONFIG.getboolean('General', 'splash_supported', fallback=True): self.attributes('-type', 'splash') else: self.attributes('-type', 'toolbar') if self.variable.get(): Toplevel.withdraw(self) Toplevel.deiconify(self) def update_style(self): self.attributes('-alpha', CONFIG.getint('Widget', 'alpha') / 100) text_font = Font(self, font=CONFIG.get('Widget', 'font')).actual() bg = CONFIG.get('Widget', 'background') feed_bg = CONFIG.get('Widget', 'feed_background', fallback='gray20') feed_fg = CONFIG.get('Widget', 'feed_foreground', fallback='white') self._stylesheet = """ body { background-color: %(bg)s; color: %(fg)s; font-family: %(family)s; font-weight: %(weight)s; font-style: %(slant)s; } ul { padding-left: 5px; } ol { padding-left: 5px; } #title { font-weight: bold; font-size: large; } a { color: %(link)s; font-style: italic; } code {font-family: monospace;} a:hover { font-style: italic; border-bottom: 1px solid %(link)s; } """ % (dict(bg=feed_bg, fg=feed_fg, link=CONFIG.get('Widget', 'link_color', fallback='#89B9F6'), **text_font)) self.configure(bg=bg) self.canvas.configure(background=bg) self._font_size = text_font['size'] def withdraw(self): Toplevel.withdraw(self) self.variable.set(False) def deiconify(self): Toplevel.deiconify(self) self.variable.set(True) def _scroll(self, delta): top, bottom = self.canvas.yview() top += delta * 0.05 top = min(max(top, 0), 1) self.canvas.yview_moveto(top) def _position_trace(self, *args): self.config.set(self.name, 'position', self._position.get()) self.save_config() def _change_position(self, event=None): '''Make widget sticky and set its position with respects to the other windows.''' pos = self._position.get() splash_supp = CONFIG.getboolean('General', 'splash_supported', fallback=True) try: for w in self.ewmh.getClientList(): if w.get_wm_name() == self.title(): self.ewmh.setWmState(w, 1, '_NET_WM_STATE_STICKY') self.ewmh.setWmState(w, 1, '_NET_WM_STATE_SKIP_TASKBAR') self.ewmh.setWmState(w, 1, '_NET_WM_STATE_SKIP_PAGER') if pos == 'above': self.attributes('-type', 'dock') self.ewmh.setWmState(w, 1, '_NET_WM_STATE_ABOVE') self.ewmh.setWmState(w, 0, '_NET_WM_STATE_BELOW') elif pos == 'below': self.attributes('-type', 'desktop') self.ewmh.setWmState(w, 0, '_NET_WM_STATE_ABOVE') self.ewmh.setWmState(w, 1, '_NET_WM_STATE_BELOW') else: if splash_supp: self.attributes('-type', 'splash') else: self.attributes('-type', 'toolbar') self.ewmh.setWmState(w, 0, '_NET_WM_STATE_BELOW') self.ewmh.setWmState(w, 0, '_NET_WM_STATE_ABOVE') self.ewmh.display.flush() if event is None and not splash_supp: Toplevel.withdraw(self) Toplevel.deiconify(self) except ewmh.display.error.BadWindow: pass def _on_configure(self, event): if event.widget is self: geometry = self.geometry() if geometry != '1x1+0+0': self.config.set(self.name, 'geometry', geometry) self.save_config() elif event.widget in [self.canvas, self.display]: self.canvas.configure(scrollregion=self.canvas.bbox('all')) self.canvas.itemconfigure('display', width=self.canvas.winfo_width() - 4) def _start_move(self, event): self.x = event.x self.y = event.y self.configure(cursor='fleur') self.display.configure(cursor='fleur') def _stop_move(self, event): self.x = None self.y = None self.configure(cursor='arrow') self.display.configure(cursor='arrow') def _move(self, event): if self.x is not None and self.y is not None: deltax = event.x - self.x deltay = event.y - self.y x = self.winfo_x() + deltax y = self.winfo_y() + deltay self.geometry("+%s+%s" % (x, y))
class Xls2kml(object): ''' Interface builted in Tkinter() ''' def __init__(self): ''' None -> None Builds the Tkinter window and all his elements. ''' # variables ---------------------------------------------------- # log file open("erros.log", "w").close() # to open and clean the logfile logging.basicConfig(level=logging.DEBUG, filename='erros.log') sys.stderr = LogFile('stderr') # Redirect stderr self.original_working_dir = os.getcwd() # original working dir self.master = Tk() # Tk() object self.master.title('EXCEL to KMZ Transformer - ver. 1.6') # window name icons = os.getcwd() + os.sep + "icons" + os.sep # path to icons foto_folder = os.getcwd() + os.sep + "fotos" # path to fotos icon = icons + "compass.ico" self.master.iconbitmap(icon) # window icon self.master.resizable(width=FALSE, height=FALSE) self.master.geometry("548x314") self.file_name = "" # the name of the EXEL file self.last_dir = "C:/" # image to decorate the window self.img = ImageTk.PhotoImage(Image.open(icons + "excel-kmz.jpg")) # to use in frame, message, labels and buttons ----------------- self.message = StringVar() self.message.set("\nSelecciona um ficheiro EXCEL") bg = "gray25" bg1 = "dark orange" fc = "white smoke" font = ("Helvetica", "8", "bold") text0 = " ----- " # " ------------------------------------------ " text1 = " Boris & Vladimir Software " text = text0 + text1 + text0 # Menu --------------------------------------------------------- self.menu = Menu(self.master) self.master.config(menu=self.menu) filemenu = Menu(self.menu) self.menu.add_cascade(label="Ficheiro", menu=filemenu) filemenu.add_command(label="Sair", command=self.__callback_3) filemenu.add_command(label='Pasta Fotos', command=lambda: (self.__open_folder(foto_folder))) # --------------------- NOVO ----------------------------------- self.openGE = BooleanVar() # não esquecer de importar BooleanVar self.openGE.set(False) optionsmenu = Menu(self.menu) self.menu.add_cascade(label="Opções", menu=optionsmenu) optionsmenu.add_checkbutton(label="Não abrir o Google Earth", onvalue=True, offvalue=False, variable=self.openGE) docsmenu = Menu(self.menu) docs = ["docs\manual.pdf", "docs\icons.pdf", "docs\colors.pdf", "docs\GPS.xlsx", "docs\GPS.kmz", "docs\Celulas.xlsx", "docs\Celulas.kmz", "docs\Foto.xlsx", "docs\Foto.kmz", "docs\Quadrado.xls", "docs\Quadrado.kmz"] self.menu.add_cascade(label="Documentação", menu=docsmenu) docsmenu.add_command(label="Manual", command=lambda: (self.__open_file(docs[0]))) docsmenu.add_command(label="Ícones", command=lambda: (self.__open_file(docs[1]))) docsmenu.add_command(label="Cores", command=lambda: (self.__open_file(docs[2]))) exemplemenu = Menu(docsmenu) docsmenu.add_cascade(label="Exemplos", menu=exemplemenu) gpsmenu = Menu(exemplemenu) exemplemenu.add_cascade(label="Trajetos", menu=gpsmenu) gpsmenu.add_command(label="Excel", command=lambda: (self.__open_file(docs[3]))) gpsmenu.add_command(label="Google Earth", command=lambda: (self.__open_file(docs[4]))) cellmenu = Menu(exemplemenu) exemplemenu.add_cascade(label="Células Telefónicas", menu=cellmenu) cellmenu.add_command(label="Excel", command=lambda: (self.__open_file(docs[5]))) cellmenu.add_command(label="Google Earth", command=lambda: (self.__open_file(docs[6]))) fotomenu = Menu(exemplemenu) exemplemenu.add_cascade(label="Fotos", menu=fotomenu) fotomenu.add_command(label="Excel", command=lambda: (self.__open_file(docs[7]))) fotomenu.add_command(label="Google Earth", command=lambda: (self.__open_file(docs[8]))) squaremenu = Menu(exemplemenu) exemplemenu.add_cascade(label="Quadrado", menu=squaremenu) squaremenu.add_command(label="Excel", command=lambda: (self.__open_file(docs[9]))) squaremenu.add_command(label="Google Earth", command=lambda: (self.__open_file(docs[10]))) helpmenu = Menu(self.menu) self.menu.add_cascade(label='Ajuda', menu=helpmenu) helpmenu.add_command(label="Sobre", command=self.__about) helpmenu.add_command(label="Ver erros", command=lambda: (self.__open_file("erros.log"))) # Frame to suport butons, labels and separators ---------------- self.f = Frame(self.master, bg=bg) self.f.pack_propagate(0) # don't shrink self.f.pack(side=BOTTOM, padx=0, pady=0) # Message and Labels ------------------------------------------- self.l1 = Message( self.f, bg=bg1, bd=5, fg=bg, textvariable=self.message, font=("Helvetica", "13", "bold italic"), width=500).grid( row=0, columnspan=6, sticky=EW, padx=5, pady=5) self.l2 = Label( self.f, image=self.img, fg=bg ).grid(row=1, columnspan=6, padx=5, pady=2) self.l6 = Label( self.f, text=text, font=("Helvetica", "11", "bold"), bg=bg, fg=bg1 ).grid(row=3, column=2, columnspan=3, sticky=EW, pady=5) # Buttons ------------------------------------------------------ self.b0 = Button( self.f, text="Abrir EXCEL...", command=self.__callback, width=10, bg="forest green", fg=fc, font=font ).grid(row=3, column=0, padx=5, sticky=W) self.b1 = Button( self.f, text="Gravar KMZ", command=self.__callback_2, width=10, bg="DodgerBlue4", fg=fc, font=font ).grid(row=3, column=1, sticky=W) self.b2 = Button( self.f, text="Sair", command=self.__callback_3, width=10, bg="orange red", fg=fc, font=font ).grid(row=3, column=5, sticky=E, padx=5) # Separator ---------------------------------------------------- # self.s = ttk.Separator(self.f, orient=HORIZONTAL).grid( # row=4, columnspan=5, sticky=EW, padx=5, pady=5) # Progressbar -------------------------------------------------- # self.pb = Canvas(self.f, width=260, height=10) self.s = ttk.Style() # themes: winnative, clam, alt, default, classic, vista, xpnative self.s.theme_use('winnative') self.s.configure("red.Horizontal.TProgressbar", foreground='green', background='forest green') self.pb = ttk.Progressbar(self.f, orient='horizontal', mode='determinate', style="red.Horizontal.TProgressbar") self.pb.grid(row=2, column=0, columnspan=6, padx=5, pady=5, sticky=EW) # Mainloop ----------------------------------------------------- self.master.mainloop() def __callback(self): # "Abrir EXEL..." button handler ------------ ''' None -> None Opens a new window (filedialog.askopenfilename) to choose the EXCEL file that is necessary to make the KMZ file. ''' title = 'Selecciona um ficheiro Excel' message = 'Ficheiro EXCEL carregado em memória.\nTransforma-o em KMZ!' self.file_name = filedialog.askopenfilename(title=title, initialdir=self.last_dir) self.last_dir = self.file_name[:self.file_name.rfind('/')] if self.file_name[self.file_name.rfind('.')+1:] != 'xls' and \ self.file_name[self.file_name.rfind('.')+1:] != 'xlsx': message = self.file_name + ' não é um ficheiro Excel válido!' self.message.set(message) def __callback_2(self): # "Gravar KMZ" button handler --------------- ''' None -> None Calls the function self.__threat() ''' sleep(1) message = 'Ficheiro EXCEL carregado em memória.\nTransforma-o em KMZ!' if self.message.get() != message: self.message.set("\nEscolhe um ficheiro EXCEL primeiro") self.master.update_idletasks() else: self.message.set("\nA processar...") self.master.update_idletasks() sleep(1) self.__threads() def __callback_3(self): # "Sair" button handler --------------------- ''' None -> None Kills the window ''' self.master.destroy() def __threads(self): ''' None -> MyTread() objects Creates two threads to run at the same time the functions: self.__create_kmz() self.__progressbar() ''' funcs = [self.__create_kmz, self.__progressbar] threads = [] nthreads = list(range(len(funcs))) for i in nthreads: t = MyThread(funcs[i], (), funcs[i].__name__) threads.append(t) for i in nthreads: threads[i].start() def __create_kmz(self): ''' None -> None Calls the exel_to_kml() atribute of the MotherControl() class And when it returns, calls self.__open_Google_Earth() ''' kmz = MotherControl(self.file_name, self.original_working_dir).exel_to_kml() if type(kmz) == str: self.message.set(kmz) self.pb.stop() self.master.update_idletasks else: sleep(2) self.pb.stop() self.master.update_idletasks() self.__open_Google_Earth() def __open_Google_Earth(self): ''' None -> None Opens the maded KMZ file in Google Earth ''' sleep(1) self.master.update_idletasks() if not self.openGE.get(): self.message.set("KMZ gravado com sucesso.\nA abrir o Google Earth...") else: self.message.set("\nKMZ gravado com sucesso.\n") sleep(2) self.master.update_idletasks() path = self.file_name[:self.file_name.rindex('/')] path_1 = self.file_name[self.file_name.rindex('/')+1:self.file_name.rfind('.')] kmzs = [x for x in os.listdir(path) if x[-4:] == '.kmz' and x[:-12] == path_1] kmzs.sort() try: if not self.openGE.get(): os.startfile(path + os.sep + kmzs[-1]) sleep(2) self.message.set("\nSelecciona um ficheiro EXCEL") except: self.message.set("Instale o Google Earth\nhttp://www.google.com/earth/") self.master.update_idletasks() def __progressbar(self, ratio=0): ''' None -> None Starts the progressbar in the window ''' self.pb.start(50) def __about(self): ''' None -> None Associated with the Help Menu. Creates a new window with the "About" information ''' appversion = "1.6" appname = "EXCEL to KML Transformer" copyright = 14 * ' ' + '(c) 2013' + 12 * ' ' + \ 'SDATO - DP - UAF - GNR\n' + 34 * ' '\ + "All Rights Reserved" licence = 18 * ' ' + 'http://opensource.org/licenses/GPL-3.0\n' contactname = "Nuno Venâncio" contactphone = "(00351) 969 564 906" contactemail = "*****@*****.**" message = "Version: " + appversion + 5 * "\n" message0 = "Copyright: " + copyright + "\n" + "Licença: " + licence message1 = contactname + '\n' + contactphone + '\n' + contactemail icons = os.getcwd() + os.sep + "icons" + os.sep # path to icons icon = icons + "compass.ico" tl = Toplevel(self.master) tl.configure(borderwidth=5) tl.title("Sobre...") tl.iconbitmap(icon) tl.resizable(width=FALSE, height=FALSE) f1 = Frame(tl, borderwidth=2, relief=SUNKEN, bg="gray25") f1.pack(side=TOP, expand=TRUE, fill=BOTH) l0 = Label(f1, text=appname, fg="white", bg="gray25", font=('courier', 16, 'bold')) l0.grid(row=0, column=0, sticky=W, padx=10, pady=5) l1 = Label(f1, text=message, justify=CENTER, fg="white", bg="gray25") l1.grid(row=2, column=0, sticky=E, columnspan=3, padx=10, pady=0) l2 = Label(f1, text=message0, justify=LEFT, fg="white", bg="gray25") l2.grid(row=6, column=0, columnspan=2, sticky=W, padx=10, pady=0) l3 = Label(f1, text=message1, justify=CENTER, fg="white", bg="gray25") l3.grid(row=7, column=0, columnspan=2, padx=10, pady=0) button = Button(tl, text="Ok", command=tl.destroy, width=10) button.pack(pady=5) def __open_file(self, doc): try: os.startfile(doc) except: pass # os.system(doc) # não gosto disto mas os.startfile(doc) # faz com que a janela não se desenhe bem def __open_folder(self, folder): os.system('start explorer "' + folder + '"')