def __init__(self, form_type): Curso.__init__(self) Form.__init__(self) self.id_curso = None self.form_type = form_type fieldsFrame = Frame(self.root, padding=10) fieldsFrame.grid(row=0, column=0, padx=10, pady=(0,10)) lbl_select = Label(fieldsFrame, text="Seleccione los docentes:", width=26) lbl_select.grid(row=0, column=0, columnspan=26) self.listaPersonas = Listbox(fieldsFrame, highlightthickness=0, selectmode="extended", height=25, width=40) self.listaPersonas.grid(row=1, column=0, columnspan=40, pady=(5,10)) btn_aceptar = Button(fieldsFrame, text="Aceptar", width=16) btn_aceptar.grid(row=2, column=0, columnspan=16) btn_cancelar = Button(fieldsFrame, text="Cancelar", width=16, command=self.hide) btn_cancelar.grid(row=2, column=24, columnspan=16) if form_type == "add": self.set_title("Agregar docentes") btn_aceptar.config(command=lambda: self.add_docente()) elif form_type == "remove": self.set_title("Eliminar docentes") btn_aceptar.config(command=lambda: self.remove_docente())
def create_final_figure( original_file_name: str, model, final_layer_name: str, mapping_name_to_index: Dict[str, int], combobox_chosen_class: ttk.Combobox, labelframe_fig_with_heatmap: ttk.Labelframe, button_save_figure: ttk.Button, ): """Creates heatmap overlaid over original figure and saves it to temporary file and window interface. Args: original_file_name (str): File name including dir, e.g. C:\\images\\penquin.jpg. model (keras.engine.training.Model): Used ML model. final_layer_name (str): Name of final convolution layer in ML model. mapping_name_to_index (Dict[str,int]): Mapping of class name to class index. combobox_chosen_class(ttk.Combobox): Choose class combobox. labelframe_fig_with_heatmap(ttk.Labelframe): Container for heatmap adjusted figure. button_save_figure(ttk.Button): Save image button. """ chosen_class = combobox_chosen_class.get() index = mapping_name_to_index[chosen_class] processed_image = load_image(original_file_name) feature_map = create_feature_map(model, final_layer_name, index, processed_image) heatmap = create_heatmap(feature_map) heatmap_overlay = join_heatmap_and_fig(original_file_name, heatmap) cv2.imwrite("temp\\temporary_picture.jpg", heatmap_overlay) load_image_to_labelframe("temp\\temporary_picture.jpg", labelframe_fig_with_heatmap) button_save_figure.config(state=tk.NORMAL)
def make_button(self, text, disabled=False): b = Button(self.commands, text=text, command=lambda n=text: self.button_pressed(n)) b.bind("<Return>", self.return_pressed ) # binds the Return key to the return_pressed method b.pack(side=LEFT) if disabled: b.config(state=DISABLED)
def scale_button( self, button: ttk.Button, image_enum: ImageEnum = None, image_file: str = None ) -> None: image = None if image_enum: image = self.app.get_icon(image_enum, TOOLBAR_SIZE) elif image_file: image = self.app.get_custom_icon(image_file, TOOLBAR_SIZE) if image: button.config(image=image) button.image = image
def initialize_video_selection_ui(self): # Initialize logo picture logo = Label(self, image=self.logo_image) logo.image = self.logo_image logo.place(y=125, x=200, anchor=tk.CENTER) # Initialize settings button settings_button = Button(self, command=self.open_settings, image=self.settings_icon) settings_button.place(y=275, x=25, anchor=tk.CENTER) # Initialize select video button select_video_button = Button(self, text="Select Video") select_video_button.config(command=partial(self.select_video, [logo, select_video_button, settings_button], [select_video_button, settings_button])) select_video_button.place(y=200, x=200, anchor=tk.CENTER)
def initialize_face_toggle_ui(self, face_locations, face_encodings, unique_encodings): # Initialize canvas canvas = tk.Canvas(self, width=400, height=250) canvas.place(y=0, relx=0.5, anchor=tk.N) # Initialize the strip below canvas strip = tk.Canvas(self, width=400, height=50, bg="#222222") strip.place(y=250, relx=0.5, anchor=tk.N) # Initialize blur toggle button blur_toggle_button = Button(self) blur_toggle_button.config(command=partial(self.toggle_blur, canvas, blur_toggle_button)) blur_toggle_button.place(y=275, x=200, anchor=tk.CENTER) # Initialize back arrow button back_button = Button(self, image=self.back_icon) back_button.config(command=partial(self.back, canvas, blur_toggle_button)) back_button.place(y=275, x=150, anchor=tk.CENTER) # Initialize forward arrow button forward_button = Button(self, image=self.forward_icon) forward_button.config(command=partial(self.forward, canvas, blur_toggle_button)) forward_button.place(y=275, x=250, anchor=tk.CENTER) # Initialize close button close_button = Button(self, command=self.cancel, image=self.close_icon) close_button.place(y=275, x=25, anchor=tk.CENTER) # Initialize done button done_button = Button(self, image=self.done_icon) done_button.config(command=partial(self.done, [back_button, forward_button, done_button, close_button, blur_toggle_button], face_locations, face_encodings, unique_encodings)) done_button.place(y=275, x=375, anchor=tk.CENTER) # Display first face image self.display_face(canvas, blur_toggle_button)
def drawControls(self): ''' main controls''' startStopButton = Button(self, text="Run") startStopButton.config(command=lambda: self.startStop()) startStopButton.grid(row=2, column=0) stepButton = Button(self, text="Step", command=lambda: self.step()) stepButton.grid(row=2, column=1) resetButton = Button(self, text="Reset/Load", command=lambda: self.reset()) resetButton.grid(row=2, column=2) quitButton = Button(self, text="Quit") quitButton.config(command=lambda: self.close()) quitButton.grid(row=2, column=3)
def __init__(self, form_type): Curso.__init__(self) Form.__init__(self) self.id_curso = None self.form_type = form_type fieldsFrame = Frame(self.root, padding=10) fieldsFrame.grid(row=0, column=0, padx=10, pady=10) lbl_alumnos = Label(fieldsFrame, width=30) lbl_alumnos.grid(row=2, column=0, columnspan=30) self.listaPersonas = Listbox(fieldsFrame, highlightthickness=0, selectmode="extended", height=25, width=40) self.listaPersonas.grid(row=3, column=0, columnspan=40, pady=(5,10)) btn_aceptar = Button(fieldsFrame, text="Aceptar", width=16) btn_aceptar.grid(row=4, column=0, columnspan=16) btn_cancelar = Button(fieldsFrame, text="Cancelar", width=16, command=self.hide) btn_cancelar.grid(row=4, column=26, columnspan=16) if form_type == "add": self.set_title("Inscribir alumnos") lbl_alumnos.config(text="Seleccione los alumnos:") lbl_date = Label(fieldsFrame, text="Seleccione la fecha:", width=20) lbl_date.grid(row=0, column=0, columnspan=20) self.date = StringVar() e_date = Entry(fieldsFrame, textvariable=self.date, width=30) e_date.grid(row=1, column=0, columnspan=30, pady=(0,10)) e_date.config(state="readonly") btn_date = Button(fieldsFrame, text="...", width=8, command=lambda: self.date.set(DatePicker(fieldsFrame).selection())) btn_date.grid(row=1, column=32, columnspan=8, pady=(0,10)) btn_aceptar.config(command=lambda: self.add_cursante()) elif form_type == "remove": self.set_title("Remover inscriptos") lbl_alumnos.config(text="Seleccione los inscriptos:") btn_aceptar.config(command=lambda: self.remove_cursante())
class PuzzleViewer(Frame): @classmethod def _format(cls, obj, indent=0): prefix = ' ' * indent if isinstance(obj, list): return textwrap.indent( '\n[' + ','.join(cls._format(e, indent + 1) for e in obj) + '\n]', prefix) elif isinstance(obj, dict): return textwrap.indent( '\n{' + (','.join( '{}:{}'.format(cls._format(k, indent + 1), cls._format(v, indent + 1)) for k, v in obj.items())) + '\n}', prefix) return textwrap.indent('\n' + str(obj), prefix) def __init__(self, master): super().__init__(master) self._text = Text(self, font=("Mono", 12)) self.button = Button(self, text='repr', command=self.toggle) self._raw_text = '' self._text.pack(fill='both', expand=1) self.button.pack() def update_text(self, obj): self._raw_text = obj self._text.delete('0.0', 'end') if self.button.cget('text') == 'repr': self._text.insert('end', pprint.pformat(obj)) else: self._text.insert('end', self._format(obj)) def toggle(self): if self.button.cget('text') == 'repr': self.button.config(text='str') self.update_text(self._raw_text) else: self.button.config(text='repr') self.update_text(self._raw_text)
def main(): root = Tk() root.geometry("400x400+300+300") # root.iconbitmap('../resources/png/icon.ico') # main icon root.iconphoto( False, tk.PhotoImage(file=r'../resources/icon/png/stop.png')) # or this frame = Frame(root) btn = Button(frame, width=5) photo = tk.PhotoImage(file=r"../resources/icon/png/delete.png") # # btn_start_timer['image'] = photo.subsample(1, 1) # Resizing image to fit on button icon = photo.subsample(2, 2) # Resizing image to fit on button btn.config(image=icon) btn.pack() frame.pack() root.mainloop()
def initUI(self): self.message = StringVar() self.master.title("Objasni Baki") self.pack(fill=BOTH, expand=True, pady=5) frames = [] frame1 = Frame(self) frame1.pack(fill=X) #message = StringVar() self.message.set("Objasni babi šta je: ") label = Label(frame1, textvariable=self.message, font=(None, 18)).grid(row=0, column=0, pady=20, padx=5) frame2 = Frame(self) frame2.pack(fill=X) start = Button(frame2, text="START", command=self.start_click) start.pack(pady=30) start.config(height=15, width=30)
def load_image_into_window( labelframe_orig_figure: ttk.Labelframe, button_find_class: ttk.Button, button_create_heatmap: ttk.Button, button_save_figure: ttk.Button, ): """Shows figure choosen by user in window interface + sets global variable with figure name Args: labelframe_orig_figure(ttk.Labelframe): Container for original figure. button_find_class(ttk.Button): Find classes button. button_create_heatmap(ttk.Button): Create heatmap button. button_save_figure(ttk.Button): Save button. """ global global_figure_name global_figure_name = fld.askopenfilename( initialdir=".", title="Select picture for classification", filetypes=[("jpeg files", "*.jpg")], ) load_image_to_labelframe(global_figure_name, labelframe_orig_figure) button_find_class.config(state=tk.NORMAL) button_create_heatmap.config(state=tk.DISABLED) button_save_figure.config(state=tk.DISABLED)
def determine_classes( file_name: str, model, textbox_classes_list: tk.Text, combobox_chosen_class: ttk.Combobox, button_save_figure: ttk.Button, button_create_heatmap: ttk.Button, ): """Fills combobox and text widget with figure classes prediction. Args: file_name (str): File name including dir, e.g. C:\\images\\penquin.jpg. model (keras.engine.training.Model): Used ML model. textbox_classes_list(tk.Text): List of predictions textbox. combobox_chosen_class(ttk.Combobox): Choose class combobox. button_save_figure(ttk.Button): Save image button. button_create_heatmap(ttk.Button): Show heatmap button. """ figure = load_image(file_name) prediction_list = get_prediction_list(figure, model) classes_for_combobox = [] global global_mapping_name_to_index textbox_classes_list.config(state=tk.NORMAL) textbox_classes_list.delete(1.0, tk.END) for figure_class in prediction_list: text_message = (f"{figure_class.order_number}. " f"class {figure_class.class_name} " f"with probability {figure_class.probability}%\n") textbox_classes_list.insert(tk.END, text_message) classes_for_combobox.append(figure_class.class_name) global_mapping_name_to_index[ figure_class.class_name] = figure_class.class_index textbox_classes_list.config(state=tk.DISABLED) combobox_chosen_class["values"] = classes_for_combobox button_save_figure.config(state=tk.DISABLED) button_create_heatmap.config(state=tk.NORMAL)
class TimerUi: """View""" def __init__(self, app): self.time_label = Label(app.root, textvariable=app.time, anchor=CENTER, foreground='black', background='lightgray', font=('Helvetica', 60)) self.time_label.pack(fill=BOTH, expand=True) validate_command = (app.root.register(self.check), '%P') self.entry = Spinbox(app.root, from_=1, to=MAX_COUNT, textvariable=app.count_start, validate='all', validatecommand=validate_command) self.entry.pack(fill=X) self.entry.focus() buttons_frame = Frame(app.root) buttons_frame.pack(fill=X) self.start_button = Button(buttons_frame, text='Start', command=app.start_timer) self.stop_button = Button(buttons_frame, text='Stop', state=DISABLED, command=app.stop_timer) self.start_button.pack(side=LEFT, fill=X, expand=True) self.stop_button.pack(side=RIGHT, fill=X, expand=True) def check(self, new_val): return new_val.isdigit() and 1 <= int(new_val) <= MAX_COUNT def state_started(self): self.stop_button.config(state=NORMAL) self.start_button.config(state=DISABLED) self.entry.config(state=DISABLED) self.time_label.config(foreground='white', background='red') def state_stopped(self): self.stop_button.config(state=DISABLED) self.start_button.config(state=NORMAL) self.entry.config(state=NORMAL) self.time_label.config(foreground='black', background='lightgray')
class Application(Frame): """The main Tk application, a simple dialog.""" def __init__(self, master=None): super().__init__(master) self.badge = None self.grid() self.columnconfigure(0, minsize=200) self.columnconfigure(1, minsize=200) self.rowconfigure(0, minsize=300) self.rowconfigure(3, minsize=30) self.create_widgets() self.connect() def create_widgets(self): """Sets up dialog elements.""" self.select = tix.FileSelectBox(self, browsecmd=self.on_file_selected, pattern="*.fs", directory="forth") # self.select["textVariable"] = self.forth_file self.select.grid(row=0, columnspan=2, sticky='n'+'w'+'e') self.connect_btn = Button(self, text="Connect", command=self.toggle_connect) self.connect_btn.grid(row=1, column=0, columnspan=2) self.exec_btn = Button(self, text="Execute", command=self.send_file) self.exec_btn.state(["disabled"]) self.exec_btn.grid(row=2, column=0, sticky='w' + 'e', padx=5, pady=3) self.quit = Button(self, text="QUIT", command=self.master.destroy) self.quit.grid(row=2, column=1, sticky='w' + 'e', padx=5, pady=3) self.status_panel = Frame(self, relief="groove", borderwidth=3) self.status_panel.grid(row=3, columnspan=2, sticky='nwse') self.connect_status = Label(self.status_panel, text="Not Connected") self.connect_status.grid(row=0, padx=5, pady=5, sticky="w") if self.badge is not None: self.connect_btn.state(["disabled"]) self.connect_status.config(text="Connected: " + self.badge.os_device) def send_file(self, _retry=False): """Send the selected file to the badge.""" if self.badge: try: # oddly, very first set LED seems to not set correct color self.badge.led(0, 0, 128) self.badge.led(0, 0, 128) with open(self.select.cget("value"), 'r') as forthin: self.badge.forth_run(forthin.read()) time.sleep(1) # because forth_run() may be too fast self.badge.led(0, 128, 0) except IOError: if not _retry: self.connect() self.send_file(True) else: raise def toggle_connect(self): "If connected, disconnect, otherwise connect." if self.connect_btn.cget("text") == "Connect": self.connect() else: self.disconnect() def disconnect(self): "Disconnect from current badge." isinstance(self.badge, Badge) self.badge.close() self.badge = None self.connect_btn.config(text="Connect") self.connect_status.config(text="Not connected.") self.exec_btn.state(["disabled"]) def connect(self): """Attempt to connect to a badge; toggle Connect button if successful.""" try: self.badge = Badge() self.connect_status.config(text="Connected: " + self.badge.os_device) self.connect_btn.config(text="Disconnect") # enable "Execute" if file is selected self.on_file_selected(self.select.cget("value")) except BadgeSerialException: self.connect_status.config(text="Not connected") def on_file_selected(self, selected_file): """Respond to user selection of file by enabling the Execute button.""" if Path(selected_file).is_file: self.exec_btn.state(["!disabled"]) else: self.exec_btn.state(["disabled"])
class DialogOpenArchive(Toplevel): def __init__(self, parent, openType, filesource, filenames, title, colHeader, showAltViewButton=False): if isinstance(parent, Cntlr): cntlr = parent parent = parent.parent # parent is cntlrWinMain else: # parent is a Toplevel dialog cntlr = parent.cntlr super(DialogOpenArchive, self).__init__(parent) self.parent = parent self.showAltViewButton = showAltViewButton parentGeometry = re.match("(\d+)x(\d+)[+]?([-]?\d+)[+]?([-]?\d+)", parent.geometry()) dialogX = int(parentGeometry.group(3)) dialogY = int(parentGeometry.group(4)) self.accepted = False self.transient(self.parent) frame = Frame(self) treeFrame = Frame(frame, width=500) vScrollbar = Scrollbar(treeFrame, orient=VERTICAL) hScrollbar = Scrollbar(treeFrame, orient=HORIZONTAL) self.treeView = Treeview(treeFrame, xscrollcommand=hScrollbar.set, yscrollcommand=vScrollbar.set) self.treeView.grid(row=0, column=0, sticky=(N, S, E, W)) hScrollbar["command"] = self.treeView.xview hScrollbar.grid(row=1, column=0, sticky=(E, W)) vScrollbar["command"] = self.treeView.yview vScrollbar.grid(row=0, column=1, sticky=(N, S)) treeFrame.columnconfigure(0, weight=1) treeFrame.rowconfigure(0, weight=1) treeFrame.grid(row=0, column=0, columnspan=4, sticky=(N, S, E, W), padx=3, pady=3) self.treeView.focus_set() if openType not in (PLUGIN, PACKAGE): cntlr.showStatus(_("loading archive {0}").format(filesource.url)) self.filesource = filesource self.filenames = filenames self.selection = filesource.selection self.hasToolTip = False selectedNode = None if openType == ENTRY_POINTS: try: metadataFiles = filesource.taxonomyPackageMetadataFiles ''' take first for now if len(metadataFiles) != 1: raise IOError(_("Taxonomy package contained more than one metadata file: {0}.") .format(', '.join(metadataFiles))) ''' metadataFile = metadataFiles[0] metadata = filesource.url + os.sep + metadataFile self.metadataFilePrefix = os.sep.join( os.path.split(metadataFile)[:-1]) if self.metadataFilePrefix: self.metadataFilePrefix += "/" # zip contents have /, never \ file seps self.taxonomyPkgMetaInf = '{}/META-INF/'.format( os.path.splitext(os.path.basename(filesource.url))[0]) self.taxonomyPackage = parsePackage( cntlr, filesource, metadata, os.sep.join(os.path.split(metadata)[:-1]) + os.sep) if self.taxonomyPackage["entryPoints"]: # may have instance documents too self.packageContainedInstances = [] packageContentTypeCounts = {} for suffix in (".xhtml", ".htm", ".html"): for potentialInstance in filesource.dir: if potentialInstance.endswith(".xhtml"): _type = "Inline Instance" self.packageContainedInstances.append( [potentialInstance, _type]) packageContentTypeCounts[ potentialInstance] = packageContentTypeCounts.get( potentialInstance, 0) + 1 if self.packageContainedInstances: break if self.packageContainedInstances: # add sequences to any duplicated entry types for _type, count in packageContentTypeCounts.items(): if count > 1: _dupNo = 0 for i in range( len(self.packageContainedInstances)): if self.packageContainedInstances[i][ 0] == _type: _dupNo += 1 self.packageContainedInstances[i][ 0] = "{} {}".format(_type, _dupNo) else: # may be a catalog file with no entry oint names openType = ARCHIVE # no entry points to show, just archive self.showAltViewButton = False except Exception as e: self.close() err = _( "Failed to parse metadata; the underlying error was: {0}" ).format(e) messagebox.showerror(_("Malformed taxonomy package"), err) cntlr.addToLog(err) return if openType not in (PLUGIN, PACKAGE): cntlr.showStatus(None) if openType in (DISCLOSURE_SYSTEM, PLUGIN, PACKAGE): y = 3 else: y = 1 okButton = Button(frame, text=_("OK"), command=self.ok) cancelButton = Button(frame, text=_("Cancel"), command=self.close) okButton.grid(row=y, column=2, sticky=(S, E, W), pady=3) cancelButton.grid(row=y, column=3, sticky=(S, E, W), pady=3, padx=3) if self.showAltViewButton: self.altViewButton = Button(frame, command=self.showAltView) self.altViewButton.grid(row=y, column=0, sticky=(S, W), pady=3, padx=3) self.loadTreeView(openType, colHeader, title) self.geometry("+{0}+{1}".format(dialogX + 50, dialogY + 100)) frame.grid(row=0, column=0, sticky=(N, S, E, W)) frame.columnconfigure(0, weight=1) frame.rowconfigure(0, weight=1) window = self.winfo_toplevel() window.columnconfigure(0, weight=1) window.rowconfigure(0, weight=1) self.bind("<Return>", self.ok) self.bind("<Escape>", self.close) self.toolTipText = StringVar() if self.hasToolTip: self.treeView.bind("<Motion>", self.motion, '+') self.treeView.bind("<Leave>", self.leave, '+') self.toolTipText = StringVar() self.toolTip = ToolTip(self.treeView, textvariable=self.toolTipText, wraplength=640, follow_mouse=True, state="disabled") self.toolTipRowId = None self.protocol("WM_DELETE_WINDOW", self.close) self.grab_set() self.wait_window(self) def loadTreeView(self, openType, title, colHeader): self.title(title) self.openType = openType selectedNode = None # clear previous treeview entries for previousNode in self.treeView.get_children(""): self.treeView.delete(previousNode) # set up treeView widget and tabbed pane if openType in (ARCHIVE, DISCLOSURE_SYSTEM, PLUGIN, PACKAGE): if openType in (PLUGIN, PACKAGE): width = 770 else: width = 500 self.treeView.column("#0", width=width, anchor="w") self.treeView.heading("#0", text=colHeader) self.isRss = getattr(self.filesource, "isRss", False) if self.isRss: self.treeView.column("#0", width=350, anchor="w") self.treeView["columns"] = ("descr", "date", "instDoc") self.treeView.column("descr", width=50, anchor="center", stretch=False) self.treeView.heading("descr", text="Form") self.treeView.column("date", width=170, anchor="w", stretch=False) self.treeView.heading("date", text="Pub Date") self.treeView.column("instDoc", width=200, anchor="w", stretch=False) self.treeView.heading("instDoc", text="Instance Document") elif openType == PLUGIN: self.treeView.column("#0", width=150, anchor="w") self.treeView["columns"] = ("name", "vers", "descr", "license") self.treeView.column("name", width=150, anchor="w", stretch=False) self.treeView.heading("name", text="Name") self.treeView.column("vers", width=60, anchor="w", stretch=False) self.treeView.heading("vers", text="Version") self.treeView.column("descr", width=300, anchor="w", stretch=False) self.treeView.heading("descr", text="Description") self.treeView.column("license", width=60, anchor="w", stretch=False) self.treeView.heading("license", text="License") elif openType == PACKAGE: self.treeView.column("#0", width=200, anchor="w") self.treeView["columns"] = ("vers", "descr", "license") self.treeView.column("vers", width=100, anchor="w", stretch=False) self.treeView.heading("vers", text="Version") self.treeView.column("descr", width=400, anchor="w", stretch=False) self.treeView.heading("descr", text="Description") self.treeView.column("license", width=70, anchor="w", stretch=False) self.treeView.heading("license", text="License") else: self.treeView["columns"] = tuple() loadedPaths = [] for i, filename in enumerate(self.filenames): if isinstance(filename, tuple): if self.isRss: form, date, instDoc = filename[2:5] elif openType == PLUGIN: name, vers, descr, license = filename[3:7] elif openType == PACKAGE: vers, descr, license = filename[3:6] filename = filename[0] # ignore tooltip self.hasToolTip = True if filename.endswith("/"): filename = filename[:-1] path = filename.split("/") if not self.isRss and len( path) > 1 and path[:-1] in loadedPaths: parent = "file{0}".format(loadedPaths.index(path[:-1])) else: parent = "" node = self.treeView.insert(parent, "end", "file{0}".format(i), text=path[-1]) if self.isRss: self.treeView.set(node, "descr", form) self.treeView.set(node, "date", date) self.treeView.set(node, "instDoc", os.path.basename(instDoc)) elif openType == PLUGIN: self.treeView.set(node, "name", name) self.treeView.set(node, "vers", vers) self.treeView.set(node, "descr", descr) self.treeView.set(node, "license", license) elif openType == PACKAGE: self.treeView.set(node, "vers", vers) self.treeView.set(node, "descr", descr) self.treeView.set(node, "license", license) if self.selection == filename: selectedNode = node loadedPaths.append(path) elif openType == ENTRY_POINTS: self.treeView.column("#0", width=200, anchor="w") self.treeView.heading("#0", text="Name") self.treeView["columns"] = ("url", ) self.treeView.column("url", width=300, anchor="w") self.treeView.heading("url", text="URL") for fileType, fileUrl in getattr(self, "packageContainedInstances", ()): self.treeView.insert("", "end", fileUrl, values=fileType, text=fileUrl or urls[0][2]) for name, urls in sorted( self.taxonomyPackage["entryPoints"].items(), key=lambda i: i[0][2]): self.treeView.insert("", "end", name, values="\n".join(url[1] for url in urls), text=name or urls[0][2]) self.hasToolTip = True else: # unknown openType return None if selectedNode: self.treeView.see(selectedNode) self.treeView.selection_set(selectedNode) if self.showAltViewButton: self.altViewButton.config(text=_("Show Files") if openType == ENTRY_POINTS else _("Show Entries")) def ok(self, event=None): selection = self.treeView.selection() if len(selection) > 0: if hasattr(self, "taxonomyPackage"): # load file source remappings self.filesource.mappedPaths = self.taxonomyPackage[ "remappings"] filename = None if self.openType in (ARCHIVE, DISCLOSURE_SYSTEM): filename = self.filenames[int(selection[0][4:])] if isinstance(filename, tuple): if self.isRss: filename = filename[4] else: filename = filename[0] elif self.openType == ENTRY_POINTS: epName = selection[0] #index 0 is the remapped Url, as opposed to the canonical one used for display # Greg Acsone reports [0] does not work for Corep 1.6 pkgs, need [1], old style packages filenames = [] for _url, _type in self.packageContainedInstances: # check if selection was an inline instance if _type == epName: filenames.append(_url) if not filenames: # else if it's a named taxonomy entry point for url in self.taxonomyPackage["entryPoints"][epName]: filename = url[0] if not filename.endswith("/"): # check if it's an absolute URL rather than a path into the archive if not isHttpUrl( filename ) and self.metadataFilePrefix != self.taxonomyPkgMetaInf: # assume it's a path inside the archive: filename = self.metadataFilePrefix + filename filenames.append(filename) if filenames: self.filesource.select(filenames) self.accepted = True self.close() return elif self.openType in (PLUGIN, PACKAGE): filename = self.filenames[int(selection[0][4:])][2] if filename is not None and not filename.endswith("/"): if hasattr(self, "taxonomyPackage"): # attempt to unmap the filename to original file # will be mapped again in loading, but this allows schemaLocation to be unmapped for prefix, remapping in self.taxonomyPackage[ "remappings"].items(): if isHttpUrl(remapping): remapStart = remapping else: remapStart = self.metadataFilePrefix + remapping if filename.startswith(remapStart): # set unmmapped file filename = prefix + filename[len(remapStart):] break if self.openType in (PLUGIN, PACKAGE): self.filesource.selection = filename else: self.filesource.select(filename) self.accepted = True self.close() def close(self, event=None): self.parent.focus_set() self.destroy() def showAltView(self, event=None): if self.openType == ENTRY_POINTS: self.loadTreeView(ARCHIVE, _("Select Entry Point"), _("File")) else: self.loadTreeView(ENTRY_POINTS, _("Select Archive File"), _("File")) def leave(self, *args): self.toolTipRowId = None def motion(self, *args): tvRowId = self.treeView.identify_row(args[0].y) if tvRowId != self.toolTipRowId: text = None if self.openType in (ARCHIVE, DISCLOSURE_SYSTEM, PLUGIN, PACKAGE): self.toolTipRowId = tvRowId if tvRowId and len(tvRowId) > 4: try: text = self.filenames[int(tvRowId[4:])] if isinstance(text, tuple): text = (text[1] or "").replace("\\n", "\n") except (KeyError, ValueError): pass elif self.openType == ENTRY_POINTS: try: text = "{0}\n{1}".format( tvRowId, "\n".join( url[1] for url in self.taxonomyPackage["entryPoints"][tvRowId])) except KeyError: pass self.setToolTip(text) def setToolTip(self, text): self.toolTip._hide() if text: self.toolTipText.set(text) self.toolTip.configure(state="normal") self.toolTip._schedule() else: self.toolTipText.set("") self.toolTip.configure(state="disabled")
class GUI(): def __init__(self): self.root = ThemedTk(theme="radiance") INIT_WIDTH, INIT_HEIGHT = self.root.winfo_screenwidth( ), self.root.winfo_screenheight() boldStyle = ttk.Style() boldStyle.configure("Bold.TButton", font=('Sans', '12', 'bold')) #icon_loc = os.path.join(os.getcwd(),ICON_NAME) #img = ImageTk.PhotoImage(master = self.root, file=icon_loc) #self.root.wm_iconbitmap(img) #self.root.ttk.call('wm', 'iconphoto', self.root._w, img) self.root.title("Form Labeller") self.root.maxsize(INIT_WIDTH, INIT_HEIGHT) self.supported_formats = SUPPORTED_FORMATS self.left_frame = Frame(self.root, width=BUTTON_WIDTH) self.top_frame1 = Frame(self.left_frame, width=BUTTON_WIDTH, height=int(INIT_HEIGHT / 2)) self.top_frame = Frame(self.left_frame, width=BUTTON_WIDTH, height=INIT_HEIGHT - int(INIT_HEIGHT / 2)) self.bottom_frame = Frame(self.root, width=INIT_WIDTH - BUTTON_WIDTH) self.load_image_directory_button = Button(self.top_frame1, text='Open Folder', command=self.load_directory, width=int(BUTTON_WIDTH), style="Bold.TButton") self.load_image_directory_button.grid(row=OPEN_FOLDER_ROW, columnspan=2, sticky=tk.W + tk.E) self.prev_img_button = Button(self.top_frame1, text='← Prev', command=self.previous_img, state=tk.DISABLED, width=int(BUTTON_WIDTH / 2), style="Bold.TButton") self.prev_img_button.grid(row=PREV_ROW, column=0, sticky=tk.W + tk.E) self.next_img_button = Button(self.top_frame1, text='Next → ', command=self.next_img, width=int(BUTTON_WIDTH / 2), style="Bold.TButton") self.next_img_button.grid(row=NEXT_COL, column=1, sticky=tk.W + tk.E) self.save_image_button = Button(self.top_frame1, text='Save ', command=self.saver, width=int(BUTTON_WIDTH), style="Bold.TButton") self.save_image_button.grid(row=SAVE_ROW, columnspan=2, sticky=tk.W + tk.E) self.delete_poly_button = Button(self.top_frame, text='Delete Selected', command=self.delete_selected, width=int(BUTTON_WIDTH), style="Bold.TButton") self.delete_poly_button.grid(row=DEL_SELECTED_ROW, columnspan=2, sticky=tk.W + tk.E) self.type_choices = TYPE_CHOICES self.variable = StringVar(self.top_frame) self.variable.set(self.type_choices[0]) self.type_options = OptionMenu(self.top_frame, self.variable, *self.type_choices, style="Bold.TButton") self.type_options.config(width=int(BUTTON_WIDTH / 2)) self.type_options.grid(row=DROP_DOWN_ROW, column=0) self.save_type_button = Button(self.top_frame, text='Save Type', command=self.save_type, width=int(BUTTON_WIDTH / 2), style="Bold.TButton") self.save_type_button.grid(row=SAVE_TYPE_ROW, column=1, sticky=tk.W + tk.E) self.deselect_all_button = Button(self.top_frame, text='Deselect All', command=self.deselect_all, width=BUTTON_WIDTH, style="Bold.TButton") self.deselect_all_button.grid(row=DESELECT_ALL_ROW, columnspan=2, sticky=tk.W + tk.E) self.select_all_button = Button(self.top_frame, text='Select All', command=self.select_all, width=BUTTON_WIDTH, style="Bold.TButton") self.select_all_button.grid(row=SELECT_ALL_ROW, columnspan=2, sticky=tk.W + tk.E) self.draw_poly_button = Button(self.top_frame, text='Draw Poly', command=self.draw_poly_func, width=BUTTON_WIDTH, style="Bold.TButton") self.draw_poly_button.grid(row=DRAW_POLY_ROW, columnspan=2, sticky=tk.W + tk.E) self.draw_rect_button = Button(self.top_frame, text='Draw Rectangle', command=self.draw_rect_func, width=BUTTON_WIDTH, style="Bold.TButton") self.draw_rect_button.grid(row=DRAW_RECT_ROW, columnspan=2, sticky=tk.W + tk.E) self.delete_all_button = Button(self.top_frame, text='Delete All', command=self.delete_all, width=BUTTON_WIDTH, style="Bold.TButton") self.save_poly_button = Button(self.top_frame, text='Save Poly', command=self.save_drawing, width=int(BUTTON_WIDTH / 2), style="Bold.TButton") self.discard_poly_button = Button(self.top_frame, text='Discard Poly', command=self.discard_drawing, width=int(BUTTON_WIDTH / 2), style="Bold.TButton") self.save_rect_button = Button(self.top_frame, text='Save Rect', command=self.save_drawing, width=int(BUTTON_WIDTH / 2), style="Bold.TButton") self.discard_rect_button = Button(self.top_frame, text='Discard Rect', command=self.discard_drawing, width=int(BUTTON_WIDTH / 2), style="Bold.TButton") self.show_type_button = Button(self.top_frame, text='Show Type', command=self.show_type, width=int(BUTTON_WIDTH / 2), style="Bold.TButton") self.show_type_button.grid(row=SHOW_TYPE_ROW, column=0, columnspan=1, sticky=tk.W + tk.E) self.hide_type_button = Button(self.top_frame, text='Hide Type', command=self.hide_type, width=int(BUTTON_WIDTH / 2), style="Bold.TButton") self.hide_type_button.grid(row=HIDE_TYPE_ROW, columnspan=1, column=1, sticky=tk.W + tk.E) self.make_tight_button = Button(self.top_frame, text='Make Tight', command=self.make_tight, width=int(BUTTON_WIDTH / 2), style="Bold.TButton") self.make_tight_button.grid(row=MAKE_TIGHT_ROW, columnspan=2, column=0, sticky=tk.W + tk.E) self.threshold_scale = Scale(self.top_frame, from_=0, to=255, orient=HORIZONTAL, width=int(BUTTON_WIDTH / 2), label="Binary Threshold") self.threshold_scale.set(128) self.threshold_scale.grid(row=THRESHOLD_ROW, columnspan=2, column=0, sticky=tk.W + tk.E) self.tight_save_button = Button(self.top_frame, text='Accept Tight', command=self.save_tight) self.tight_discard_button = Button(self.top_frame, text='Discard Tight', command=self.discard_tight) self.canvas = Canvas(self.bottom_frame, width=INIT_WIDTH - BUTTON_WIDTH, height=INIT_HEIGHT, borderwidth=1) self.image_name = None #self.image_path = os.path.join('imgs','img1.jpg') self.image_dir = None self.images_in_dir = None self.curr_idx = None self.img_cnv = None #self.img_cnv = ImageOnCanvas(self.root,self.canvas,self.image_path) self.drawing_obj = None self.tight_box_obj = None self.left_frame.pack(side=tk.LEFT) self.top_frame1.pack(side=tk.TOP) self.top_frame.pack(side=tk.BOTTOM) self.bottom_frame.pack(side=tk.LEFT) self.canvas.pack() self.hide_buttons() self.load_image_directory_button.config(state="normal") def save_tight(self): self.tight_box_obj.save_tight_box() self.tight_save_button.grid_forget() self.tight_discard_button.grid_forget() self.make_tight_button.grid(row=MAKE_TIGHT_ROW, columnspan=2, sticky=tk.W + tk.E) self.show_buttons() self.tight_box_obj = None def discard_tight(self): self.tight_box_obj.discard_tight_box() self.tight_save_button.grid_forget() self.tight_discard_button.grid_forget() self.make_tight_button.grid(row=MAKE_TIGHT_ROW, columnspan=2, sticky=tk.W + tk.E) self.show_buttons() self.tight_box_obj = None def show_type(self): for poly in self.img_cnv.polygons: if poly.select_poly: poly.show_type() def hide_type(self): for poly in self.img_cnv.polygons: poly.unshow_type() def hide_buttons(self): self.load_image_directory_button.config(state=tk.DISABLED) self.save_image_button.config(state=tk.DISABLED) self.delete_poly_button.config(state=tk.DISABLED) self.save_type_button.config(state=tk.DISABLED) self.deselect_all_button.config(state=tk.DISABLED) self.select_all_button.config(state=tk.DISABLED) self.delete_all_button.config(state=tk.DISABLED) self.show_type_button.config(state=tk.DISABLED) self.hide_type_button.config(state=tk.DISABLED) self.make_tight_button.config(state=tk.DISABLED) def show_buttons(self): self.load_image_directory_button.config(state="normal") self.save_image_button.config(state="normal") self.delete_poly_button.config(state="normal") self.save_type_button.config(state="normal") self.deselect_all_button.config(state="normal") self.select_all_button.config(state="normal") self.delete_all_button.config(state="normal") self.show_type_button.config(state="normal") self.hide_type_button.config(state="normal") self.draw_poly_button.config(state="normal") self.draw_rect_button.config(state="normal") self.make_tight_button.config(state="normal") def select_all(self): for poly in self.img_cnv.polygons: poly.select_polygon() def deselect_all(self): self.hide_type() for poly in self.img_cnv.polygons: poly.deselect_poly() def delete_all(self): result = messagebox.askyesno("Confirm Delete All", "Delete All Annotations?") if not result: return self.select_all() self.delete_selected() #self.img_cnv.polygons_mutex.acquire() #for poly in self.img_cnv.polygons: # poly.delete_self() #self.img_cnv.polygons_mutex.release() def save_type(self): selected_option = self.variable.get() self.img_cnv.polygons_mutex.acquire() for poly in self.img_cnv.polygons: if poly.select_poly == True: if selected_option == "None": poly.poly_type = None else: poly.poly_type = selected_option #poly.unshow_type() #poly.show_type() self.img_cnv.polygons_mutex.release() self.variable.set(self.type_choices[0]) #self.deselect_all() def load_new_img(self): self.canvas.delete('all') self.img_cnv = None path = os.path.join(self.image_dir, self.image_name) self.img_cnv = ImageOnCanvas(self.root, self.canvas, path) logger("LOADED: " + self.img_cnv.image_path) def load_directory(self): while True: selection = filedialog.askdirectory() if selection == () or selection == '': return self.root.directory = selection self.image_dir = self.root.directory file_names = os.listdir(self.image_dir) self.images_in_dir = [] self.curr_idx = None self.image_name = None for name in file_names: if name.split('.')[-1] in self.supported_formats: self.images_in_dir.append(name) if len(self.images_in_dir) == 0: self.pop_up("No supported images in the selected directory") else: break self.show_buttons() self.next_img() def pop_up(self, text): top = Toplevel() top.title("ERROR") msg = Message(top, text=text) msg.pack() button = Button(top, text="Dismiss", command=top.destroy) button.pack() def next_img(self): if self.curr_idx == None: self.curr_idx = -1 self.curr_idx = self.curr_idx + 1 if self.curr_idx >= len(self.images_in_dir): self.pop_up("Done with Images in this directory") self.curr_idx = self.curr_idx - 1 return if self.curr_idx > 0: self.prev_img_button.config(state="normal") self.image_name = self.images_in_dir[self.curr_idx] self.load_new_img() self.root.title("Form Labeller - " + self.image_name + "(" + str(self.curr_idx + 1) + "/" + str(len(self.images_in_dir)) + ")") def previous_img(self): if self.curr_idx == 1: self.curr_idx = -1 self.prev_img_button.config(state=tk.DISABLED) else: self.curr_idx = self.curr_idx - 2 self.next_img() def delete_selected(self): to_be_deleted = [] for i, poly in enumerate(self.img_cnv.polygons): if poly.select_poly == True: poly.delete_self() to_be_deleted.append(i) j = 0 for idx in to_be_deleted: self.img_cnv.polygons.pop(idx - j) self.img_cnv.bbs.pop(idx - j) self.img_cnv.poly_type.pop(idx - j) j = j + 1 def start_gui(self): self.root.mainloop() def saver(self): logger("Saving: " + self.img_cnv.image_path) self.save_image_button.config(state=tk.DISABLED) self.img_cnv.save_json(self.root.directory) self.save_image_button.config(state="normal") def draw_poly_func(self): self.deselect_all() self.img_cnv.drawing_polygon = True self.draw_poly_button.grid_forget() self.save_poly_button.grid(row=DRAW_POLY_ROW, column=0, sticky=tk.W + tk.E) self.discard_poly_button.grid(row=DRAW_POLY_ROW, column=1, sticky=tk.W + tk.E) self.hide_buttons() self.draw_rect_button.config(state=tk.DISABLED) self.drawing_obj = DrawPoly(self.bottom_frame, self.canvas, self.img_cnv, RADIUS) def draw_rect_func(self): self.deselect_all() self.img_cnv.drawing_polygon = True self.draw_rect_button.grid_forget() self.save_rect_button.grid(row=DRAW_RECT_ROW, column=0, sticky=tk.W + tk.E) self.discard_rect_button.grid(row=DRAW_RECT_ROW, column=1, sticky=tk.W + tk.E) self.hide_buttons() self.draw_poly_button.config(state=tk.DISABLED) self.drawing_obj = DrawRect(self.bottom_frame, self.canvas, self.img_cnv, RADIUS) def save_drawing(self): self.show_buttons() self.img_cnv.drawing_polygon = False new_poly_pts = self.drawing_obj.pt_coords print("Trying to save polygon with pts:", str(new_poly_pts)) for pt in self.drawing_obj.points: self.canvas.delete(pt) if self.img_cnv.scale_factor != None: for i in range(len(new_poly_pts)): for j in range(2): new_poly_pts[i][ j] = new_poly_pts[i][j] / self.img_cnv.scale_factor self.img_cnv.add_poly(new_poly_pts) #self.img_cnv.bbs.append(new_poly_pts) #self.img_cnv.draw_bbs([self.img_cnv.bbs[-1]]) #debug (1, str(type(self.drawing_obj))) if isinstance(self.drawing_obj, DrawRect): self.save_rect_button.grid_forget() self.discard_rect_button.grid_forget() self.draw_rect_button.grid(row=DRAW_RECT_ROW, columnspan=2, sticky=tk.W + tk.E) elif isinstance(self.drawing_obj, DrawPoly): self.save_poly_button.grid_forget() self.discard_poly_button.grid_forget() self.draw_poly_button.grid(row=DRAW_POLY_ROW, columnspan=2, sticky=tk.W + tk.E) self.drawing_obj.delete_self() self.drawing_obj = None def discard_drawing(self): self.show_buttons() self.img_cnv.drawing_polygon = False #for pt in self.drawing_obj.points: # self.canvas.delete(pt) self.drawing_obj.delete_self() if isinstance(self.drawing_obj, DrawRect): self.save_rect_button.grid_forget() self.discard_rect_button.grid_forget() self.draw_rect_button.grid(row=DRAW_RECT_ROW, columnspan=2, sticky=tk.W + tk.E) elif isinstance(self.drawing_obj, DrawPoly): self.save_poly_button.grid_forget() self.discard_poly_button.grid_forget() self.draw_poly_button.grid(row=DRAW_POLY_ROW, columnspan=2, sticky=tk.W + tk.E) self.drawing_obj = None def make_tight(self): self.hide_buttons() self.tight_box_obj = TightBox(self.root, self.img_cnv, self.threshold_scale.get()) self.tight_box_obj.tight_box() self.make_tight_button.grid_forget() self.tight_save_button.grid(row=MAKE_TIGHT_ROW, column=0, columnspan=1, sticky=tk.W + tk.E) self.tight_discard_button.grid(row=MAKE_TIGHT_ROW, column=1, columnspan=1, sticky=tk.W + tk.E)
lbl_result_folder = Label(master=f3, textvariable=sampling_folder_path) lbl_result_folder.pack() Separator(f3, orient=HORIZONTAL).pack(fill='x', pady=10) btn_start_sample = ttk.Button(f3, text="Start Sampling", command=start_sampling) btn_start_sample.pack() Separator(f3, orient=HORIZONTAL).pack(fill='x', pady=10) lbl_frame_select_sampled_midi = ttk.LabelFrame( f3, text="Which midi do you want to play?") lbl_frame_select_sampled_midi.pack() btn_select_sampled_midi = ttk.Button(lbl_frame_select_sampled_midi, text="Select Midi file", command=select_sampled_midi) btn_select_sampled_midi.pack() lbl_sampled_midi = Label(master=f3, textvariable=sampled_midi) lbl_sampled_midi.pack() midi_play_button = Button(f3, text="play", command=play_midi) img_play = PhotoImage(file=os.path.join(base_path, "play.png")) midi_play_button.config(image=img_play) midi_play_button.pack(padx=5, pady=0) root.mainloop()
class DialogPluginManager(Toplevel): def __init__(self, mainWin, modulesWithNewerFileDates): super(DialogPluginManager, self).__init__(mainWin.parent) self.ENABLE = _("Enable") self.DISABLE = _("Disable") self.parent = mainWin.parent self.cntlr = mainWin # copy plugins for temporary display self.pluginConfig = PluginManager.pluginConfig self.pluginConfigChanged = False self.uiClassMethodsChanged = False self.modelClassesChanged = False self.disclosureSystemTypesChanged = False self.modulesWithNewerFileDates = modulesWithNewerFileDates parentGeometry = re.match("(\d+)x(\d+)[+]?([-]?\d+)[+]?([-]?\d+)", self.parent.geometry()) dialogX = int(parentGeometry.group(3)) dialogY = int(parentGeometry.group(4)) self.title(_("Plug-in Manager")) frame = Frame(self) # left button frame buttonFrame = Frame(frame, width=40) buttonFrame.columnconfigure(0, weight=1) addLabel = Label(buttonFrame, text=_("Find plug-in modules:"), wraplength=60, justify="center") addLocalButton = Button(buttonFrame, text=_("Locally"), command=self.findLocally) ToolTip(addLocalButton, text=_("File chooser allows selecting python module files to add (or reload) plug-ins, from the local file system."), wraplength=240) addWebButton = Button(buttonFrame, text=_("On Web"), command=self.findOnWeb) ToolTip(addWebButton, text=_("Dialog to enter URL full path to load (or reload) plug-ins, from the web or local file system."), wraplength=240) addLabel.grid(row=0, column=0, pady=4) addLocalButton.grid(row=1, column=0, pady=4) addWebButton.grid(row=2, column=0, pady=4) buttonFrame.grid(row=0, column=0, rowspan=2, sticky=(N, S, W), padx=3, pady=3) # right tree frame (plugins already known to arelle) modulesFrame = Frame(frame, width=700) vScrollbar = Scrollbar(modulesFrame, orient=VERTICAL) hScrollbar = Scrollbar(modulesFrame, orient=HORIZONTAL) self.modulesView = Treeview(modulesFrame, xscrollcommand=hScrollbar.set, yscrollcommand=vScrollbar.set, height=7) self.modulesView.grid(row=0, column=0, sticky=(N, S, E, W)) self.modulesView.bind('<<TreeviewSelect>>', self.moduleSelect) hScrollbar["command"] = self.modulesView.xview hScrollbar.grid(row=1, column=0, sticky=(E,W)) vScrollbar["command"] = self.modulesView.yview vScrollbar.grid(row=0, column=1, sticky=(N,S)) modulesFrame.columnconfigure(0, weight=1) modulesFrame.rowconfigure(0, weight=1) modulesFrame.grid(row=0, column=1, columnspan=4, sticky=(N, S, E, W), padx=3, pady=3) self.modulesView.focus_set() self.modulesView.column("#0", width=120, anchor="w") self.modulesView.heading("#0", text=_("Name")) self.modulesView["columns"] = ("author", "ver", "status", "date", "update", "descr", "license") self.modulesView.column("author", width=100, anchor="w", stretch=False) self.modulesView.heading("author", text=_("Author")) self.modulesView.column("ver", width=50, anchor="w", stretch=False) self.modulesView.heading("ver", text=_("Version")) self.modulesView.column("status", width=50, anchor="w", stretch=False) self.modulesView.heading("status", text=_("Status")) self.modulesView.column("date", width=70, anchor="w", stretch=False) self.modulesView.heading("date", text=_("File Date")) self.modulesView.column("update", width=50, anchor="w", stretch=False) self.modulesView.heading("update", text=_("Update")) self.modulesView.column("descr", width=200, anchor="w", stretch=False) self.modulesView.heading("descr", text=_("Description")) self.modulesView.column("license", width=70, anchor="w", stretch=False) self.modulesView.heading("license", text=_("License")) classesFrame = Frame(frame) vScrollbar = Scrollbar(classesFrame, orient=VERTICAL) hScrollbar = Scrollbar(classesFrame, orient=HORIZONTAL) self.classesView = Treeview(classesFrame, xscrollcommand=hScrollbar.set, yscrollcommand=vScrollbar.set, height=5) self.classesView.grid(row=0, column=0, sticky=(N, S, E, W)) hScrollbar["command"] = self.classesView.xview hScrollbar.grid(row=1, column=0, sticky=(E,W)) vScrollbar["command"] = self.classesView.yview vScrollbar.grid(row=0, column=1, sticky=(N,S)) classesFrame.columnconfigure(0, weight=1) classesFrame.rowconfigure(0, weight=1) classesFrame.grid(row=1, column=1, columnspan=4, sticky=(N, S, E, W), padx=3, pady=3) self.classesView.focus_set() self.classesView.column("#0", width=200, anchor="w") self.classesView.heading("#0", text=_("Class")) self.classesView["columns"] = ("modules",) self.classesView.column("modules", width=500, anchor="w", stretch=False) self.classesView.heading("modules", text=_("Modules")) # bottom frame module info details moduleInfoFrame = Frame(frame, width=700) moduleInfoFrame.columnconfigure(1, weight=1) self.moduleNameLabel = Label(moduleInfoFrame, wraplength=600, justify="left", font=font.Font(family='Helvetica', size=12, weight='bold')) self.moduleNameLabel.grid(row=0, column=0, columnspan=4, sticky=W) self.moduleAuthorHdr = Label(moduleInfoFrame, text=_("author:"), state=DISABLED) self.moduleAuthorHdr.grid(row=1, column=0, sticky=W) self.moduleAuthorLabel = Label(moduleInfoFrame, wraplength=600, justify="left") self.moduleAuthorLabel.grid(row=1, column=1, columnspan=3, sticky=W) self.moduleDescrHdr = Label(moduleInfoFrame, text=_("description:"), state=DISABLED) self.moduleDescrHdr.grid(row=2, column=0, sticky=W) self.moduleDescrLabel = Label(moduleInfoFrame, wraplength=600, justify="left") self.moduleDescrLabel.grid(row=2, column=1, columnspan=3, sticky=W) self.moduleClassesHdr = Label(moduleInfoFrame, text=_("classes:"), state=DISABLED) self.moduleClassesHdr.grid(row=3, column=0, sticky=W) self.moduleClassesLabel = Label(moduleInfoFrame, wraplength=600, justify="left") self.moduleClassesLabel.grid(row=3, column=1, columnspan=3, sticky=W) ToolTip(self.moduleClassesLabel, text=_("List of classes that this plug-in handles."), wraplength=240) self.moduleUrlHdr = Label(moduleInfoFrame, text=_("URL:"), state=DISABLED) self.moduleUrlHdr.grid(row=4, column=0, sticky=W) self.moduleUrlLabel = Label(moduleInfoFrame, wraplength=600, justify="left") self.moduleUrlLabel.grid(row=4, column=1, columnspan=3, sticky=W) ToolTip(self.moduleUrlLabel, text=_("URL of plug-in module (local file path or web loaded file)."), wraplength=240) self.moduleDateHdr = Label(moduleInfoFrame, text=_("date:"), state=DISABLED) self.moduleDateHdr.grid(row=5, column=0, sticky=W) self.moduleDateLabel = Label(moduleInfoFrame, wraplength=600, justify="left") self.moduleDateLabel.grid(row=5, column=1, columnspan=3, sticky=W) ToolTip(self.moduleDateLabel, text=_("Date of currently loaded module file (with parenthetical node when an update is available)."), wraplength=240) self.moduleLicenseHdr = Label(moduleInfoFrame, text=_("license:"), state=DISABLED) self.moduleLicenseHdr.grid(row=6, column=0, sticky=W) self.moduleLicenseLabel = Label(moduleInfoFrame, wraplength=600, justify="left") self.moduleLicenseLabel.grid(row=6, column=1, columnspan=3, sticky=W) self.moduleEnableButton = Button(moduleInfoFrame, text=self.ENABLE, state=DISABLED, command=self.moduleEnable) ToolTip(self.moduleEnableButton, text=_("Enable/disable plug in."), wraplength=240) self.moduleEnableButton.grid(row=7, column=1, sticky=E) self.moduleReloadButton = Button(moduleInfoFrame, text=_("Reload"), state=DISABLED, command=self.moduleReload) ToolTip(self.moduleReloadButton, text=_("Reload/update plug in."), wraplength=240) self.moduleReloadButton.grid(row=7, column=2, sticky=E) self.moduleRemoveButton = Button(moduleInfoFrame, text=_("Remove"), state=DISABLED, command=self.moduleRemove) ToolTip(self.moduleRemoveButton, text=_("Remove plug in from plug in table (does not erase the plug in's file)."), wraplength=240) self.moduleRemoveButton.grid(row=7, column=3, sticky=E) moduleInfoFrame.grid(row=2, column=0, columnspan=5, sticky=(N, S, E, W), padx=3, pady=3) moduleInfoFrame.config(borderwidth=4, relief="groove") okButton = Button(frame, text=_("Close"), command=self.ok) ToolTip(okButton, text=_("Accept and changes (if any) and close dialog."), wraplength=240) cancelButton = Button(frame, text=_("Cancel"), command=self.close) ToolTip(cancelButton, text=_("Cancel changes (if any) and close dialog."), wraplength=240) okButton.grid(row=3, column=3, sticky=(S,E), pady=3) cancelButton.grid(row=3, column=4, sticky=(S,E), pady=3, padx=3) enableDisableFrame = Frame(frame) enableDisableFrame.grid(row=3, column=1, sticky=(S,W), pady=3) enableAllButton = Button(enableDisableFrame, text=_("Enable All"), command=self.enableAll) ToolTip(enableAllButton, text=_("Enable all plug ins."), wraplength=240) disableAllButton = Button(enableDisableFrame, text=_("Disable All"), command=self.disableAll) ToolTip(disableAllButton, text=_("Disable all plug ins."), wraplength=240) enableAllButton.grid(row=1, column=1) disableAllButton.grid(row=1, column=2) self.loadTreeViews() self.geometry("+{0}+{1}".format(dialogX+50,dialogY+100)) frame.grid(row=0, column=0, sticky=(N,S,E,W)) frame.columnconfigure(0, weight=0) frame.columnconfigure(1, weight=1) frame.rowconfigure(0, weight=1) window = self.winfo_toplevel() window.columnconfigure(0, weight=1) window.rowconfigure(0, weight=1) self.bind("<Return>", self.ok) self.bind("<Escape>", self.close) self.protocol("WM_DELETE_WINDOW", self.close) self.grab_set() self.wait_window(self) def loadTreeViews(self): self.selectedModule = None # clear previous treeview entries for previousNode in self.modulesView.get_children(""): self.modulesView.delete(previousNode) for i, moduleItem in enumerate(sorted(self.pluginConfig.get("modules", {}).items())): moduleInfo = moduleItem[1] name = moduleInfo.get("name", moduleItem[0]) node = self.modulesView.insert("", "end", name, text=name) self.modulesView.set(node, "author", moduleInfo.get("author")) self.modulesView.set(node, "ver", moduleInfo.get("version")) self.modulesView.set(node, "status", moduleInfo.get("status")) self.modulesView.set(node, "date", moduleInfo.get("fileDate")) if name in self.modulesWithNewerFileDates: self.modulesView.set(node, "update", _("available")) self.modulesView.set(node, "descr", moduleInfo.get("description")) self.modulesView.set(node, "license", moduleInfo.get("license")) # clear previous treeview entries for previousNode in self.classesView.get_children(""): self.classesView.delete(previousNode) for i, classItem in enumerate(sorted(self.pluginConfig.get("classes", {}).items())): className, moduleList = classItem node = self.classesView.insert("", "end", className, text=className) self.classesView.set(node, "modules", ', '.join(moduleList)) self.moduleSelect() # clear out prior selection def ok(self, event=None): if self.pluginConfigChanged: PluginManager.pluginConfig = self.pluginConfig PluginManager.pluginConfigChanged = True PluginManager.reset() # force reloading of modules if self.uiClassMethodsChanged or self.modelClassesChanged or self.disclosureSystemTypesChanged: # may require reloading UI affectedItems = "" if self.uiClassMethodsChanged: affectedItems += _("menus of the user interface") if self.modelClassesChanged: if self.uiClassMethodsChanged: affectedItems += _(" and ") affectedItems += _("model objects of the processor") if (self.uiClassMethodsChanged or self.modelClassesChanged): affectedItems += _(" and ") if self.disclosureSystemTypesChanged: if (self.uiClassMethodsChanged or self.modelClassesChanged): affectedItems += _(" and ") affectedItems += _("disclosure system types") if messagebox.askyesno(_("User interface plug-in change"), _("A change in plug-in class methods may have affected {0}. " "Please restart Arelle to due to these changes. \n\n" "Should Arelle restart itself now " "(if there are any unsaved changes they would be lost!)?" ).format(affectedItems), parent=self): self.cntlr.uiThreadQueue.put((self.cntlr.quit, [None, True])) self.close() def close(self, event=None): self.parent.focus_set() self.destroy() def moduleSelect(self, *args): node = (self.modulesView.selection() or (None,))[0] moduleInfo = self.pluginConfig.get("modules", {}).get(node) if moduleInfo: self.selectedModule = node name = moduleInfo["name"] self.moduleNameLabel.config(text=name) self.moduleAuthorHdr.config(state=ACTIVE) self.moduleAuthorLabel.config(text=moduleInfo["author"]) self.moduleDescrHdr.config(state=ACTIVE) self.moduleDescrLabel.config(text=moduleInfo["description"]) self.moduleClassesHdr.config(state=ACTIVE) self.moduleClassesLabel.config(text=', '.join(moduleInfo["classMethods"])) self.moduleUrlHdr.config(state=ACTIVE) self.moduleUrlLabel.config(text=moduleInfo["moduleURL"]) self.moduleDateHdr.config(state=ACTIVE) self.moduleDateLabel.config(text=moduleInfo["fileDate"] + " " + (_("(an update is available)") if name in self.modulesWithNewerFileDates else "")) self.moduleLicenseHdr.config(state=ACTIVE) self.moduleLicenseLabel.config(text=moduleInfo["license"]) self.moduleEnableButton.config(state=ACTIVE, text={"enabled":self.DISABLE, "disabled":self.ENABLE}[moduleInfo["status"]]) self.moduleReloadButton.config(state=ACTIVE) self.moduleRemoveButton.config(state=ACTIVE) else: self.selectedModule = None self.moduleNameLabel.config(text="") self.moduleAuthorHdr.config(state=DISABLED) self.moduleAuthorLabel.config(text="") self.moduleDescrHdr.config(state=DISABLED) self.moduleDescrLabel.config(text="") self.moduleClassesHdr.config(state=DISABLED) self.moduleClassesLabel.config(text="") self.moduleUrlHdr.config(state=DISABLED) self.moduleUrlLabel.config(text="") self.moduleDateHdr.config(state=DISABLED) self.moduleDateLabel.config(text="") self.moduleLicenseHdr.config(state=DISABLED) self.moduleLicenseLabel.config(text="") self.moduleEnableButton.config(state=DISABLED, text=self.ENABLE) self.moduleReloadButton.config(state=DISABLED) self.moduleRemoveButton.config(state=DISABLED) def findLocally(self): initialdir = self.cntlr.pluginDir # default plugin directory if not self.cntlr.isMac: # can't navigate within app easily, always start in default directory initialdir = self.cntlr.config.setdefault("pluginOpenDir", initialdir) filename = self.cntlr.uiFileDialog("open", parent=self, title=_("Choose plug-in module file"), initialdir=initialdir, filetypes=[(_("Python files"), "*.py")], defaultextension=".py") if filename: # check if a package is selected (any file in a directory containing an __init__.py if (os.path.isdir(os.path.dirname(filename)) and os.path.isfile(os.path.join(os.path.dirname(filename), "__init__.py"))): filename = os.path.dirname(filename) # refer to the package instead self.cntlr.config["pluginOpenDir"] = os.path.dirname(filename) moduleInfo = PluginManager.moduleModuleInfo(filename) self.loadFoundModuleInfo(moduleInfo, filename) def findOnWeb(self): url = DialogURL.askURL(self) if url: # url is the in-cache or local file moduleInfo = PluginManager.moduleModuleInfo(url) self.cntlr.showStatus("") # clear web loading status self.loadFoundModuleInfo(moduleInfo, url) def loadFoundModuleInfo(self, moduleInfo, url): if moduleInfo and moduleInfo.get("name"): self.addPluginConfigModuleInfo(moduleInfo) self.loadTreeViews() else: messagebox.showwarning(_("Module is not itself a plug-in or in a directory with package __init__.py plug-in. "), _("File does not itself contain a python program with an appropriate __pluginInfo__ declaration: \n\n{0}") .format(url), parent=self) def removePluginConfigModuleInfo(self, name): moduleInfo = self.pluginConfig["modules"].get(name) if moduleInfo: for classMethod in moduleInfo["classMethods"]: classMethods = self.pluginConfig["classes"].get(classMethod) if classMethods and name in classMethods: classMethods.remove(name) if not classMethods: # list has become unused del self.pluginConfig["classes"][classMethod] # remove class if classMethod.startswith("CntlrWinMain.Menu"): self.uiClassMethodsChanged = True # may require reloading UI elif classMethod == "ModelObjectFactory.ElementSubstitutionClasses": self.modelClassesChanged = True # model object factor classes changed elif classMethod == "DisclosureSystem.Types": self.disclosureSystemTypesChanged = True # disclosure system types changed del self.pluginConfig["modules"][name] self.pluginConfigChanged = True def addPluginConfigModuleInfo(self, moduleInfo): name = moduleInfo["name"] self.removePluginConfigModuleInfo(name) # remove any prior entry for this module self.modulesWithNewerFileDates.discard(name) # no longer has an update available self.pluginConfig["modules"][name] = moduleInfo # add classes for classMethod in moduleInfo["classMethods"]: classMethods = self.pluginConfig["classes"].setdefault(classMethod, []) if name not in classMethods: classMethods.append(name) if classMethod.startswith("CntlrWinMain.Menu"): self.uiClassMethodsChanged = True # may require reloading UI elif classMethod == "ModelObjectFactory.ElementSubstitutionClasses": self.modelClassesChanged = True # model object factor classes changed elif classMethod == "DisclosureSystem.Types": self.disclosureSystemTypesChanged = True # disclosure system types changed self.pluginConfigChanged = True def moduleEnable(self): if self.selectedModule in self.pluginConfig["modules"]: moduleInfo = self.pluginConfig["modules"][self.selectedModule] if self.moduleEnableButton['text'] == self.ENABLE: moduleInfo["status"] = "enabled" self.moduleEnableButton['text'] = self.DISABLE elif self.moduleEnableButton['text'] == self.DISABLE: moduleInfo["status"] = "disabled" self.moduleEnableButton['text'] = self.ENABLE self.pluginConfigChanged = True self.loadTreeViews() def moduleReload(self): if self.selectedModule in self.pluginConfig["modules"]: url = self.pluginConfig["modules"][self.selectedModule].get("moduleURL") if url: moduleInfo = PluginManager.moduleModuleInfo(url, reload=True) if moduleInfo: self.addPluginConfigModuleInfo(moduleInfo) self.loadTreeViews() self.cntlr.showStatus(_("{0} reloaded").format(moduleInfo.get("name")), clearAfter=5000) else: messagebox.showwarning(_("Module error"), _("File or module cannot be reloaded: \n\n{0}") .format(url), parent=self) def moduleRemove(self): if self.selectedModule in self.pluginConfig["modules"]: self.removePluginConfigModuleInfo(self.selectedModule) self.pluginConfigChanged = True self.loadTreeViews() def enableAll(self): self.enableDisableAll(True) def disableAll(self): self.enableDisableAll(False) def enableDisableAll(self, doEnable): for module in self.pluginConfig["modules"]: moduleInfo = self.pluginConfig["modules"][module] if doEnable: moduleInfo["status"] = "enabled" self.moduleEnableButton['text'] = self.DISABLE else: moduleInfo["status"] = "disabled" self.moduleEnableButton['text'] = self.ENABLE self.pluginConfigChanged = True self.loadTreeViews()
class DialogPluginManager(Toplevel): def __init__(self, mainWin, modulesWithNewerFileDates): super(DialogPluginManager, self).__init__(mainWin.parent) self.ENABLE = _("Enable") self.DISABLE = _("Disable") self.parent = mainWin.parent self.cntlr = mainWin # copy plugins for temporary display self.pluginConfig = PluginManager.pluginConfig self.pluginConfigChanged = False self.uiClassMethodsChanged = False self.modelClassesChanged = False self.customTransformsChanged = False self.disclosureSystemTypesChanged = False self.hostSystemFeaturesChanged = False self.modulesWithNewerFileDates = modulesWithNewerFileDates parentGeometry = re.match("(\d+)x(\d+)[+]?([-]?\d+)[+]?([-]?\d+)", self.parent.geometry()) dialogX = int(parentGeometry.group(3)) dialogY = int(parentGeometry.group(4)) self.title(_("Plug-in Manager")) frame = Frame(self) # left button frame buttonFrame = Frame(frame, width=40) buttonFrame.columnconfigure(0, weight=1) addLabel = Label(buttonFrame, text=_("Find plug-in modules:"), wraplength=60, justify="center") addSelectLocalButton = Button(buttonFrame, text=_("Select"), command=self.selectLocally) ToolTip( addSelectLocalButton, text=_( "Select python module files from the local plugin directory."), wraplength=240) addBrowseLocalButton = Button(buttonFrame, text=_("Browse"), command=self.browseLocally) ToolTip( addBrowseLocalButton, text= _("File chooser allows browsing and selecting python module files to add (or reload) plug-ins, from the local file system." ), wraplength=240) addWebButton = Button(buttonFrame, text=_("On Web"), command=self.findOnWeb) ToolTip( addWebButton, text= _("Dialog to enter URL full path to load (or reload) plug-ins, from the web or local file system." ), wraplength=240) addLabel.grid(row=0, column=0, pady=4) addSelectLocalButton.grid(row=1, column=0, pady=4) addBrowseLocalButton.grid(row=2, column=0, pady=4) addWebButton.grid(row=3, column=0, pady=4) buttonFrame.grid(row=0, column=0, rowspan=3, sticky=(N, S, W), padx=3, pady=3) # right tree frame (plugins already known to arelle) modulesFrame = Frame(frame, width=720) vScrollbar = Scrollbar(modulesFrame, orient=VERTICAL) hScrollbar = Scrollbar(modulesFrame, orient=HORIZONTAL) self.modulesView = Treeview(modulesFrame, xscrollcommand=hScrollbar.set, yscrollcommand=vScrollbar.set, height=7) self.modulesView.grid(row=0, column=0, sticky=(N, S, E, W)) self.modulesView.bind('<<TreeviewSelect>>', self.moduleSelect) hScrollbar["command"] = self.modulesView.xview hScrollbar.grid(row=1, column=0, sticky=(E, W)) vScrollbar["command"] = self.modulesView.yview vScrollbar.grid(row=0, column=1, sticky=(N, S)) modulesFrame.columnconfigure(0, weight=1) modulesFrame.rowconfigure(0, weight=1) modulesFrame.grid(row=0, column=1, columnspan=4, sticky=(N, S, E, W), padx=3, pady=3) self.modulesView.focus_set() self.modulesView.column("#0", width=120, anchor="w") self.modulesView.heading("#0", text=_("Name")) self.modulesView["columns"] = ("author", "ver", "status", "date", "update", "descr", "license") self.modulesView.column("author", width=100, anchor="w", stretch=False) self.modulesView.heading("author", text=_("Author")) self.modulesView.column("ver", width=60, anchor="w", stretch=False) self.modulesView.heading("ver", text=_("Version")) self.modulesView.column("status", width=50, anchor="w", stretch=False) self.modulesView.heading("status", text=_("Status")) self.modulesView.column("date", width=70, anchor="w", stretch=False) self.modulesView.heading("date", text=_("File Date")) self.modulesView.column("update", width=50, anchor="w", stretch=False) self.modulesView.heading("update", text=_("Update")) self.modulesView.column("descr", width=200, anchor="w", stretch=False) self.modulesView.heading("descr", text=_("Description")) self.modulesView.column("license", width=70, anchor="w", stretch=False) self.modulesView.heading("license", text=_("License")) classesFrame = Frame(frame) vScrollbar = Scrollbar(classesFrame, orient=VERTICAL) hScrollbar = Scrollbar(classesFrame, orient=HORIZONTAL) self.classesView = Treeview(classesFrame, xscrollcommand=hScrollbar.set, yscrollcommand=vScrollbar.set, height=5) self.classesView.grid(row=0, column=0, sticky=(N, S, E, W)) hScrollbar["command"] = self.classesView.xview hScrollbar.grid(row=1, column=0, sticky=(E, W)) vScrollbar["command"] = self.classesView.yview vScrollbar.grid(row=0, column=1, sticky=(N, S)) classesFrame.columnconfigure(0, weight=1) classesFrame.rowconfigure(0, weight=1) classesFrame.grid(row=1, column=1, columnspan=4, sticky=(N, S, E, W), padx=3, pady=3) self.classesView.focus_set() self.classesView.column("#0", width=200, anchor="w") self.classesView.heading("#0", text=_("Class")) self.classesView["columns"] = ("modules", ) self.classesView.column("modules", width=500, anchor="w", stretch=False) self.classesView.heading("modules", text=_("Modules")) # bottom frame module info details moduleInfoFrame = Frame(frame, width=700) moduleInfoFrame.columnconfigure(1, weight=1) self.moduleNameLabel = Label(moduleInfoFrame, wraplength=600, justify="left", font=font.Font(family='Helvetica', size=12, weight='bold')) self.moduleNameLabel.grid(row=0, column=0, columnspan=4, sticky=W) self.moduleAuthorHdr = Label(moduleInfoFrame, text=_("author:"), state=DISABLED) self.moduleAuthorHdr.grid(row=1, column=0, sticky=W) self.moduleAuthorLabel = Label(moduleInfoFrame, wraplength=600, justify="left") self.moduleAuthorLabel.grid(row=1, column=1, columnspan=3, sticky=W) self.moduleDescrHdr = Label(moduleInfoFrame, text=_("description:"), state=DISABLED) self.moduleDescrHdr.grid(row=2, column=0, sticky=W) self.moduleDescrLabel = Label(moduleInfoFrame, wraplength=600, justify="left") self.moduleDescrLabel.grid(row=2, column=1, columnspan=3, sticky=W) self.moduleClassesHdr = Label(moduleInfoFrame, text=_("classes:"), state=DISABLED) self.moduleClassesHdr.grid(row=3, column=0, sticky=W) self.moduleClassesLabel = Label(moduleInfoFrame, wraplength=600, justify="left") self.moduleClassesLabel.grid(row=3, column=1, columnspan=3, sticky=W) ToolTip(self.moduleClassesLabel, text=_("List of classes that this plug-in handles."), wraplength=240) self.moduleVersionHdr = Label(moduleInfoFrame, text=_("version:"), state=DISABLED) self.moduleVersionHdr.grid(row=4, column=0, sticky=W) self.moduleVersionLabel = Label(moduleInfoFrame, wraplength=600, justify="left") self.moduleVersionLabel.grid(row=4, column=1, columnspan=3, sticky=W) ToolTip(self.moduleVersionLabel, text=_("Version of plug-in module."), wraplength=240) self.moduleUrlHdr = Label(moduleInfoFrame, text=_("URL:"), state=DISABLED) self.moduleUrlHdr.grid(row=5, column=0, sticky=W) self.moduleUrlLabel = Label(moduleInfoFrame, wraplength=600, justify="left") self.moduleUrlLabel.grid(row=5, column=1, columnspan=3, sticky=W) ToolTip( self.moduleUrlLabel, text=_( "URL of plug-in module (local file path or web loaded file)."), wraplength=240) self.moduleDateHdr = Label(moduleInfoFrame, text=_("date:"), state=DISABLED) self.moduleDateHdr.grid(row=6, column=0, sticky=W) self.moduleDateLabel = Label(moduleInfoFrame, wraplength=600, justify="left") self.moduleDateLabel.grid(row=6, column=1, columnspan=3, sticky=W) ToolTip( self.moduleDateLabel, text= _("Date of currently loaded module file (with parenthetical node when an update is available)." ), wraplength=240) self.moduleLicenseHdr = Label(moduleInfoFrame, text=_("license:"), state=DISABLED) self.moduleLicenseHdr.grid(row=7, column=0, sticky=W) self.moduleLicenseLabel = Label(moduleInfoFrame, wraplength=600, justify="left") self.moduleLicenseLabel.grid(row=7, column=1, columnspan=3, sticky=W) self.moduleImportsHdr = Label(moduleInfoFrame, text=_("imports:"), state=DISABLED) self.moduleImportsHdr.grid(row=8, column=0, sticky=W) self.moduleImportsLabel = Label(moduleInfoFrame, wraplength=600, justify="left") self.moduleImportsLabel.grid(row=8, column=1, columnspan=3, sticky=W) self.moduleEnableButton = Button(moduleInfoFrame, text=self.ENABLE, state=DISABLED, command=self.moduleEnable) ToolTip(self.moduleEnableButton, text=_("Enable/disable plug in."), wraplength=240) self.moduleEnableButton.grid(row=9, column=1, sticky=E) self.moduleReloadButton = Button(moduleInfoFrame, text=_("Reload"), state=DISABLED, command=self.moduleReload) ToolTip(self.moduleReloadButton, text=_("Reload/update plug in."), wraplength=240) self.moduleReloadButton.grid(row=9, column=2, sticky=E) self.moduleRemoveButton = Button(moduleInfoFrame, text=_("Remove"), state=DISABLED, command=self.moduleRemove) ToolTip( self.moduleRemoveButton, text= _("Remove plug in from plug in table (does not erase the plug in's file)." ), wraplength=240) self.moduleRemoveButton.grid(row=9, column=3, sticky=E) moduleInfoFrame.grid(row=2, column=0, columnspan=5, sticky=(N, S, E, W), padx=3, pady=3) moduleInfoFrame.config(borderwidth=4, relief="groove") okButton = Button(frame, text=_("Close"), command=self.ok) ToolTip(okButton, text=_("Accept and changes (if any) and close dialog."), wraplength=240) cancelButton = Button(frame, text=_("Cancel"), command=self.close) ToolTip(cancelButton, text=_("Cancel changes (if any) and close dialog."), wraplength=240) okButton.grid(row=3, column=3, sticky=(S, E), pady=3) cancelButton.grid(row=3, column=4, sticky=(S, E), pady=3, padx=3) enableDisableFrame = Frame(frame) enableDisableFrame.grid(row=3, column=1, sticky=(S, W), pady=3) enableAllButton = Button(enableDisableFrame, text=_("Enable All"), command=self.enableAll) ToolTip(enableAllButton, text=_("Enable all plug ins."), wraplength=240) disableAllButton = Button(enableDisableFrame, text=_("Disable All"), command=self.disableAll) ToolTip(disableAllButton, text=_("Disable all plug ins."), wraplength=240) enableAllButton.grid(row=1, column=1) disableAllButton.grid(row=1, column=2) self.loadTreeViews() self.geometry("+{0}+{1}".format(dialogX + 50, dialogY + 100)) frame.grid(row=0, column=0, sticky=(N, S, E, W)) frame.columnconfigure(0, weight=0) frame.columnconfigure(1, weight=1) frame.rowconfigure(0, weight=1) window = self.winfo_toplevel() window.columnconfigure(0, weight=1) window.rowconfigure(0, weight=1) self.bind("<Return>", self.ok) self.bind("<Escape>", self.close) self.protocol("WM_DELETE_WINDOW", self.close) self.grab_set() self.wait_window(self) def loadTreeViews(self): self.selectedModule = None # clear previous treeview entries for previousNode in self.modulesView.get_children(""): self.modulesView.delete(previousNode) def loadSubtree(parentNode, moduleItems): for moduleItem in sorted(moduleItems, key=lambda item: item[0]): moduleInfo = moduleItem[1] if parentNode or not moduleInfo.get("isImported"): nodeName = moduleItem[0] if parentNode: nodeName = parentNode + GROUPSEP + nodeName name = moduleInfo.get("name", nodeName) node = self.modulesView.insert(parentNode, "end", nodeName, text=name) self.modulesView.set(node, "author", moduleInfo.get("author")) self.modulesView.set(node, "ver", moduleInfo.get("version")) self.modulesView.set(node, "status", moduleInfo.get("status")) self.modulesView.set(node, "date", moduleInfo.get("fileDate")) if name in self.modulesWithNewerFileDates: self.modulesView.set(node, "update", _("available")) self.modulesView.set(node, "descr", moduleInfo.get("description")) self.modulesView.set(node, "license", moduleInfo.get("license")) if moduleInfo.get("imports"): loadSubtree( node, [(importModuleInfo["name"], importModuleInfo) for importModuleInfo in moduleInfo["imports"]]) loadSubtree("", self.pluginConfig.get("modules", {}).items()) # clear previous treeview entries for previousNode in self.classesView.get_children(""): self.classesView.delete(previousNode) for i, classItem in enumerate( sorted(self.pluginConfig.get("classes", {}).items())): className, moduleList = classItem node = self.classesView.insert("", "end", className, text=className) self.classesView.set(node, "modules", ', '.join(moduleList)) self.moduleSelect() # clear out prior selection def ok(self, event=None): # check for orphaned classes (for which there is no longer a corresponding module) _moduleNames = self.pluginConfig.get("modules", {}).keys() _orphanedClassNames = set() for className, moduleList in self.pluginConfig.get("classes", {}).items(): for _moduleName in moduleList.copy(): if _moduleName not in _moduleNames: # it's orphaned moduleList.remove(_moduleName) self.pluginConfigChanged = True if not moduleList: # now orphaned _orphanedClassNames.add(className) self.pluginConfigChanged = True for _orphanedClassName in _orphanedClassNames: del self.pluginConfig["classes"][_orphanedClassName] if self.pluginConfigChanged: PluginManager.pluginConfig = self.pluginConfig PluginManager.pluginConfigChanged = True PluginManager.reset() # force reloading of modules if self.uiClassMethodsChanged or self.modelClassesChanged or self.customTransformsChanged or self.disclosureSystemTypesChanged or self.hostSystemFeaturesChanged: # may require reloading UI affectedItems = "" if self.uiClassMethodsChanged: affectedItems += _("menus of the user interface") if self.modelClassesChanged: if affectedItems: affectedItems += _(" and ") affectedItems += _("model objects of the processor") if self.customTransformsChanged: if affectedItems: affectedItems += _(" and ") affectedItems += _("custom transforms") if self.disclosureSystemTypesChanged: if affectedItems: affectedItems += _(" and ") affectedItems += _("disclosure system types") if self.hostSystemFeaturesChanged: if affectedItems: affectedItems += _(" and ") affectedItems += _("host system features") if messagebox.askyesno( _("User interface plug-in change"), _("A change in plug-in class methods may have affected {0}. " "Please restart Arelle to due to these changes. \n\n" "Should Arelle restart itself now " "(if there are any unsaved changes they would be lost!)?" ).format(affectedItems), parent=self): self.cntlr.uiThreadQueue.put((self.cntlr.quit, [None, True])) self.close() def close(self, event=None): self.parent.focus_set() self.destroy() def moduleSelect(self, *args): node = (self.modulesView.selection() or (None, ))[0] if node: node = node.rpartition(GROUPSEP)[ 2] # drop leading path names for module name moduleInfo = self.pluginConfig.get("modules", {}).get(node) if moduleInfo: self.selectedModule = node name = moduleInfo["name"] self.moduleNameLabel.config(text=name) self.moduleAuthorHdr.config(state=ACTIVE) self.moduleAuthorLabel.config(text=moduleInfo.get("author")) self.moduleDescrHdr.config(state=ACTIVE) self.moduleDescrLabel.config(text=moduleInfo.get("description")) self.moduleClassesHdr.config(state=ACTIVE) self.moduleClassesLabel.config( text=', '.join(moduleInfo["classMethods"])) self.moduleVersionHdr.config(state=ACTIVE) self.moduleVersionLabel.config(text=moduleInfo.get("version")) self.moduleUrlHdr.config(state=ACTIVE) self.moduleUrlLabel.config(text=moduleInfo["moduleURL"]) self.moduleDateHdr.config(state=ACTIVE) self.moduleDateLabel.config( text=moduleInfo["fileDate"] + " " + (_("(an update is available)") if name in self.modulesWithNewerFileDates else "")) self.moduleLicenseHdr.config(state=ACTIVE) self.moduleLicenseLabel.config(text=moduleInfo.get("license")) if moduleInfo.get("imports"): self.moduleImportsHdr.config(state=ACTIVE) _text = ", ".join(mi["name"] for mi in moduleInfo["imports"][:3]) if len(moduleInfo["imports"]) >= 3: _text += ", ..." self.moduleImportsLabel.config(text=_text) _buttonState = DISABLED if moduleInfo.get("isImported") else ACTIVE self.moduleEnableButton.config(state=_buttonState, text={ "enabled": self.DISABLE, "disabled": self.ENABLE }[moduleInfo["status"]]) self.moduleReloadButton.config(state=_buttonState) self.moduleRemoveButton.config(state=_buttonState) else: self.selectedModule = None self.moduleNameLabel.config(text="") self.moduleAuthorHdr.config(state=DISABLED) self.moduleAuthorLabel.config(text="") self.moduleDescrHdr.config(state=DISABLED) self.moduleDescrLabel.config(text="") self.moduleClassesHdr.config(state=DISABLED) self.moduleClassesLabel.config(text="") self.moduleVersionHdr.config(state=DISABLED) self.moduleVersionLabel.config(text="") self.moduleUrlHdr.config(state=DISABLED) self.moduleUrlLabel.config(text="") self.moduleDateHdr.config(state=DISABLED) self.moduleDateLabel.config(text="") self.moduleLicenseHdr.config(state=DISABLED) self.moduleLicenseLabel.config(text="") self.moduleImportsHdr.config(state=DISABLED) self.moduleImportsLabel.config(text="") self.moduleEnableButton.config(state=DISABLED, text=self.ENABLE) self.moduleReloadButton.config(state=DISABLED) self.moduleRemoveButton.config(state=DISABLED) def selectLocally(self): choices = [] # list of tuple of (file name, description) def sortOrder(key): return { "EdgarRenderer": "1", "validate": "2", "xbrlDB": "3" }.get(key, "4") + key.lower() def selectChoices(dir, indent=""): dirHasEntries = False for f in sorted(os.listdir(dir), key=sortOrder): if f not in (".", "..", "__pycache__", "__init__.py"): fPath = os.path.join(dir, f) fPkgInit = os.path.join(fPath, "__init__.py") dirInsertPoint = len(choices) moduleInfo = None if ((os.path.isdir(fPath) and os.path.exists(fPkgInit)) or ((os.path.isfile(fPath) and f.endswith(".py")))): moduleInfo = PluginManager.moduleModuleInfo(fPath) if moduleInfo: choices.append(( indent + f, "name: {}\ndescription: {}\nversion: {}\nlicense: {}" .format(moduleInfo["name"], moduleInfo.get("description"), moduleInfo.get("version"), moduleInfo.get("license")), fPath, moduleInfo["name"], moduleInfo.get("version"), moduleInfo.get("description"), moduleInfo.get("license"))) dirHasEntries = True if os.path.isdir(fPath) and f not in ("DQC_US_Rules", ): if selectChoices(fPath, indent=indent + " ") and not moduleInfo: choices.insert(dirInsertPoint, (indent + f, None, None, None, None, None, None)) return dirHasEntries selectChoices(self.cntlr.pluginDir) selectedPath = DialogOpenArchive.selectPlugin(self, choices) if selectedPath: moduleInfo = PluginManager.moduleModuleInfo( selectedPath[len(self.cntlr.pluginDir) + 1:]) self.loadFoundModuleInfo(moduleInfo, selectedPath) def browseLocally(self): initialdir = self.cntlr.pluginDir # default plugin directory if not self.cntlr.isMac: # can't navigate within app easily, always start in default directory initialdir = self.cntlr.config.setdefault("pluginOpenDir", initialdir) filename = self.cntlr.uiFileDialog( "open", parent=self, title=_("Choose plug-in module file"), initialdir=initialdir, filetypes=[(_("Python files"), "*.py")], defaultextension=".py") if filename: # check if a package is selected (any file in a directory containing an __init__.py #if (os.path.basename(filename) == "__init__.py" and os.path.isdir(os.path.dirname(filename)) and # os.path.isfile(filename)): # filename = os.path.dirname(filename) # refer to the package instead self.cntlr.config["pluginOpenDir"] = os.path.dirname(filename) moduleInfo = PluginManager.moduleModuleInfo(filename) self.loadFoundModuleInfo(moduleInfo, filename) def findOnWeb(self): url = DialogURL.askURL(self) if url: # url is the in-cache or local file moduleInfo = PluginManager.moduleModuleInfo(url) self.cntlr.showStatus("") # clear web loading status self.loadFoundModuleInfo(moduleInfo, url) def loadFoundModuleInfo(self, moduleInfo, url): if moduleInfo and moduleInfo.get("name"): self.addPluginConfigModuleInfo(moduleInfo) self.loadTreeViews() else: messagebox.showwarning( _("Module is not itself a plug-in or in a directory with package __init__.py plug-in. " ), _("File does not itself contain a python program with an appropriate __pluginInfo__ declaration: \n\n{0}" ).format(url), parent=self) def checkIfImported(self, moduleInfo): if moduleInfo.get("isImported"): messagebox.showwarning( _("Plug-in is imported by a parent plug-in. "), _("Plug-in has a parent, please request operation on the parent: \n\n{0}" ).format(moduleInfo.get("name")), parent=self) return True return False def checkClassMethodsChanged(self, moduleInfo): for classMethod in moduleInfo["classMethods"]: if classMethod.startswith("CntlrWinMain.Menu"): self.uiClassMethodsChanged = True # may require reloading UI elif classMethod == "ModelObjectFactory.ElementSubstitutionClasses": self.modelClassesChanged = True # model object factor classes changed elif classMethod == "ModelManager.LoadCustomTransforms": self.customTransformsChanged = True elif classMethod == "DisclosureSystem.Types": self.disclosureSystemTypesChanged = True # disclosure system types changed elif classMethod.startswith("Proxy."): self.hostSystemFeaturesChanged = True # system features (e.g., proxy) changed def removePluginConfigModuleInfo(self, name): moduleInfo = self.pluginConfig["modules"].get(name) if moduleInfo: if self.checkIfImported(moduleInfo): return def _removePluginConfigModuleInfo(moduleInfo): _name = moduleInfo.get("name") if _name: self.checkClassMethodsChanged(moduleInfo) for classMethod in moduleInfo["classMethods"]: classMethods = self.pluginConfig["classes"].get( classMethod) if classMethods and _name in classMethods: classMethods.remove(_name) if not classMethods: # list has become unused del self.pluginConfig["classes"][ classMethod] # remove class for importModuleInfo in moduleInfo.get( "imports", EMPTYLIST): _removePluginConfigModuleInfo(importModuleInfo) self.pluginConfig["modules"].pop(_name, None) _removePluginConfigModuleInfo(moduleInfo) if not self.pluginConfig["modules"] and self.pluginConfig[ "classes"]: self.pluginConfig["classes"].clear() # clean orphan classes self.pluginConfigChanged = True def addPluginConfigModuleInfo(self, moduleInfo): if self.checkIfImported(moduleInfo): return name = moduleInfo.get("name") self.removePluginConfigModuleInfo( name) # remove any prior entry for this module def _addPlugin(moduleInfo): _name = moduleInfo.get("name") if _name: self.modulesWithNewerFileDates.discard( _name) # no longer has an update available self.pluginConfig["modules"][_name] = moduleInfo # add classes for classMethod in moduleInfo["classMethods"]: classMethods = self.pluginConfig["classes"].setdefault( classMethod, []) if name not in classMethods: classMethods.append(_name) self.checkClassMethodsChanged(moduleInfo) for importModuleInfo in moduleInfo.get("imports", EMPTYLIST): _addPlugin(importModuleInfo) _addPlugin(moduleInfo) self.pluginConfigChanged = True def moduleEnable(self): if self.selectedModule in self.pluginConfig["modules"]: moduleInfo = self.pluginConfig["modules"][self.selectedModule] if self.checkIfImported(moduleInfo): return def _moduleEnable(moduleInfo): if self.moduleEnableButton['text'] == self.ENABLE: moduleInfo["status"] = "enabled" elif self.moduleEnableButton['text'] == self.DISABLE: moduleInfo["status"] = "disabled" self.checkClassMethodsChanged(moduleInfo) for importModuleInfo in moduleInfo.get("imports", EMPTYLIST): _moduleEnable( importModuleInfo) # set status on nested moduleInfo if importModuleInfo['name'] in self.pluginConfig[ "modules"]: # set status on top level moduleInfo _moduleEnable(self.pluginConfig["modules"][ importModuleInfo['name']]) _moduleEnable(moduleInfo) if self.moduleEnableButton['text'] == self.ENABLE: self.moduleEnableButton['text'] = self.DISABLE elif self.moduleEnableButton['text'] == self.DISABLE: self.moduleEnableButton['text'] = self.ENABLE self.pluginConfigChanged = True self.loadTreeViews() def moduleReload(self): if self.selectedModule in self.pluginConfig["modules"]: url = self.pluginConfig["modules"][self.selectedModule].get( "moduleURL") if url: moduleInfo = PluginManager.moduleModuleInfo(url, reload=True) if moduleInfo: if self.checkIfImported(moduleInfo): return self.addPluginConfigModuleInfo(moduleInfo) self.loadTreeViews() self.cntlr.showStatus(_("{0} reloaded").format( moduleInfo["name"]), clearAfter=5000) else: messagebox.showwarning( _("Module error"), _("File or module cannot be reloaded: \n\n{0}").format( url), parent=self) def moduleRemove(self): if self.selectedModule in self.pluginConfig["modules"]: self.removePluginConfigModuleInfo(self.selectedModule) self.pluginConfigChanged = True self.loadTreeViews() def enableAll(self): self.enableDisableAll(True) def disableAll(self): self.enableDisableAll(False) def enableDisableAll(self, doEnable): for module in self.pluginConfig["modules"]: moduleInfo = self.pluginConfig["modules"][module] if not moduleInfo.get("isImported"): def _enableDisableAll(moduleInfo): if doEnable: moduleInfo["status"] = "enabled" else: moduleInfo["status"] = "disabled" for importModuleInfo in moduleInfo.get( "imports", EMPTYLIST): _enableDisableAll(importModuleInfo) _enableDisableAll(moduleInfo) if doEnable: self.moduleEnableButton['text'] = self.DISABLE else: self.moduleEnableButton['text'] = self.ENABLE self.pluginConfigChanged = True self.loadTreeViews()
class App(Tk): #the main class for the main window def __init__(self): Tk.__init__(self) # window properties self.title(string="Screen Recorder") self.iconbitmap("icon.ico") self.resizable(width=False, height=False) ffmpegAvailable = False for item in os.listdir(): if item == "ffmpeg.exe": ffmpegAvailable = True break if not ffmpegAvailable: self.withdraw() if messagebox.askyesno( "FFmpeg Not Found", "ffmpeg.exe could not be found in screen recorder's directory. Do you want to be redirected to the ffmpeg download website?" ): webbrowser.open_new_tab("https://ffmpeg.zeranoe.com/builds/") exit() self.cmdGen = cmdGen( ) # create a command generator object to store settings # file name label1 = Label(self, text="File Name:") label1.grid(row=0, column=0, sticky="") self.entry1 = Entry(self) self.entry1.grid(row=0, column=1, sticky="ew") # ensure the existance of the "ScreenCaptures" directory try: os.mkdir("ScreenCaptures") except FileExistsError: pass os.chdir("ScreenCaptures") # find a default file name that is currently available. defaultFile = "ScreenCapture.mp4" available = False fileNum = 0 while available == False: hasMatch = False for item in os.listdir(): if item == defaultFile: hasMatch = True break if not hasMatch: available = True else: fileNum += 1 defaultFile = "ScreenCapture" + str(fileNum) + ".mp4" os.chdir("..") self.entry1.insert(END, defaultFile) # radio buttons determine what to record self.what = StringVar() self.what.set("desktop") self.radio2 = Radiobutton(self, text="record the window with the title of: ", variable=self.what, value="title", command=self.enDis1) self.radio1 = Radiobutton(self, text="record the entire desktop", variable=self.what, value="desktop", command=self.enDis) self.radio1.grid(row=1, column=0, sticky="w") self.radio2.grid(row=2, column=0, sticky="w") self.entry2 = Entry(self, state=DISABLED) self.entry2.grid(row=2, column=1, sticky="ew") # initialize webcam self.webcamdevices = Webcam.listCam() self.webcamrecorder = Webcam.capturer("") # "record from webcam" checkbox self.rcchecked = IntVar() self.recordcam = Checkbutton(self, text="Record from webcam", command=self.checkboxChanged, variable=self.rcchecked) self.recordcam.grid(row=3, column=0) # a drop-down allowing you to select the webcam device from the available directshow capture devices self.devicename = StringVar(self) if self.webcamdevices: self.devicename.set(self.webcamdevices[0]) self.deviceselector = OptionMenu(self, self.devicename, *self.webcamdevices) self.deviceselector.config(state=DISABLED) self.deviceselector.grid(row=3, column=1) else: self.devicename.set("NO DEVICES AVAILABLE") self.recordcam.config(state=DISABLED) self.deviceselector = OptionMenu(self, self.devicename, "NO DEVICES AVAILABLE") self.deviceselector.config(state=DISABLED) self.deviceselector.grid(row=3, column=1) self.opButton = Button(self, text="⚙ Additional Options...", command=self.openSettings) self.opButton.grid(row=4, column=1, sticky='e') # the "start recording" button self.startButton = Button(self, text="⏺ Start Recording", command=self.startRecord) self.startButton.grid(row=5, column=0, columnspan=2) # some variables self.recording = False # are we recording? self.proc = None # the popen object for ffmpeg (during screenrecord) self.recorder = recordFile.recorder( ) # the "recorder" object for audio (see recordFile.py) self.mergeProcess = None # the popen object for ffmpeg (while merging video and audio files) # start the ffmpeg monitoring callback self.pollClosed() def openSettings(self): self.settings = settingsWin(self, self.cmdGen, self.recorder) def pollClosed(self): """callback that repeats itself every 100ms. Automatically determines if ffmpeg is still running.""" if self.recording: if self.proc.poll() != None: self.startRecord() messagebox.showerror( "ffmpeg error", "ffmpeg has stopped working. ERROR: \n" + str(self.proc.stderr.read()).replace('\\r\\n', '\n')) if self.recorder.error: self.startRecord() if self.mergeProcess and self.recording == False: if self.mergeProcess.poll() != None: self.startButton.config(text="⏺ Start Recording", state=NORMAL) self.title(string="Screen Recorder") self.after(100, self.pollClosed) def enDis(self): """Called when the "desktop" radio button is pressed""" self.entry2.config(state=DISABLED) # self.what.set("desktop") def enDis1(self): """Called when the "window title" radio button is pressed""" self.entry2.config(state=NORMAL) # self.what.set("title") def checkboxChanged(self): """Called when the "record webcam" checkbox is checked or unchecked.""" #self.rcchecked = not self.rcchecked if self.rcchecked.get(): self.deviceselector.config(state=NORMAL) else: self.deviceselector.config(state=DISABLED) def startRecord(self): """toggles recording. Will start conversion subprocess on recording completion""" if self.recording == False: # change the window self.title(string="Screen Recorder (Recording...)") self.startButton.config(text="⏹️ Stop Recording") self.filename = self.entry1.get() # disable interface self.entry1.config(state=DISABLED) self.radio1.config(state=DISABLED) self.radio2.config(state=DISABLED) self.deviceselector.config(state=DISABLED) self.opButton.config(state=DISABLED) if self.what.get() == "title": self.entry2.config(state=DISABLED) # ensure the existence of the "tmp" directory try: os.mkdir("tmp") except FileExistsError: pass # start screen recording process self.recording = True startupinfo = subprocess.STARTUPINFO() startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW startupinfo.wShowWindow = subprocess.SW_HIDE # self.cmdGen.setFps(60) # self.cmdGen.setEncode('nvenc_h264') # CPU: mpeg4 // NVIDIA: h264_nvenc // AMD: no. self.cmdGen.setSource(self.what.get() == "title", self.entry2.get()) command = self.cmdGen.getCmd("tmp/tmp.mkv") self.proc = subprocess.Popen(args=command, startupinfo=startupinfo, stderr=subprocess.PIPE) # start audio recording self.recorder.record("tmp/tmp.wav") # start webcam recording, if checked self.recordcam.config(state=DISABLED) if self.rcchecked.get() and self.webcamdevices: self.webcamrecorder.setDevice(str(self.devicename.get())) self.webcamrecorder.startCapture("tmp/webcamtmp.mkv") # minimize the window to get it out of the way of the recording self.iconify() elif self.recording == True: self.deiconify() defaultFile = self.filename # re-enable interface self.entry1.config(state=NORMAL) self.radio1.config(state=NORMAL) self.radio2.config(state=NORMAL) self.opButton.config(state=NORMAL) if self.webcamdevices: self.recordcam.config(state=NORMAL) if self.rcchecked.get(): self.deviceselector.config(state=NORMAL) if self.what.get() == "title": self.entry2.config(state=NORMAL) available = False fileNum = 0 # stop all recording processes self.recording = False self.proc.terminate() self.recorder.stop_recording() if self.rcchecked.get() and self.webcamdevices: self.webcamrecorder.stopCapture() try: os.mkdir("ScreenCaptures") except FileExistsError: pass # change the window title and button text to reflect the current process self.title(string="Screen Recorder (converting...)") self.startButton.config( text="converting your previous recording, please wait...", state=DISABLED) # start the video conversion process startupinfo = subprocess.STARTUPINFO() startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW startupinfo.wShowWindow = subprocess.SW_HIDE self.cmdGen.config(audList=self.recorder.devices) command = self.cmdGen.getCvtCmd("ScreenCaptures/" + self.filename) if not self.recorder.error: self.mergeProcess = subprocess.Popen(args=command, startupinfo=startupinfo) # if self.rcchecked.get(): # self.mergeProcess = subprocess.Popen(args= ["ffmpeg","-i",'tmp/tmp.mkv','-i','tmp/tmp.wav','-i','tmp/webcamtmp.mkv','-filter_complex','[2:v] scale=640:-1 [inner]; [0:0][inner] overlay=0:0 [out]',"-shortest",'-map','[out]','-y',"ScreenCaptures/"+self.filename]) # else: # self.mergeProcess = subprocess.Popen(args= ["ffmpeg","-i",'tmp/tmp.mkv','-i','tmp/tmp.wav',"-shortest",'-y',"ScreenCaptures/"+self.filename], startupinfo=startupinfo) # change the screen capture name to something that is not taken os.chdir("ScreenCaptures") while True: matches = 0 for item in os.listdir(): if item == defaultFile: matches += 1 if matches == 0: self.entry1.delete(0, END) self.entry1.insert(END, defaultFile) break else: fileNum += 1 file = self.filename.split(".") defaultFile = file[0].rstrip("1234567890") + str( fileNum) + "." + file[1] os.chdir("../")
class DialogVidget(ToplevelVidget): """ DialogVidget contains a Toplevel widget, a main Frame widget, a custom view widget, and two button widgets for `Confirm` and `Cancel`. """ def __init__( self, view_widget=None, confirm_handler=None, confirm_buttion_text='Confirm', cancel_handler=None, cancel_buttion_text='Cancel', close_handler=None, master=None, ): """ Initialize object. @param view_widget: Custom view widget. @param confirm_handler: Confirm button event handler. @param confirm_buttion_text: Confirm button text. @param cancel_handler: Cancel button event handler. @param cancel_buttion_text: Cancel button text. @param close_handler: Window close button event handler. @param master: Master widget. @return: None. """ # Initialize ToplevelVidget ToplevelVidget.__init__( self, close_handler=close_handler, master=master, ) # Create main frame self._frame = Frame(master=self._toplevel) # Custom view widget self._view_widget = view_widget # Confirm button event handler self._confirm_handler = confirm_handler \ if confirm_handler is not None else self._confirm_handler_default # Create confirm button self._confirm_button = Button( master=self._toplevel, text=confirm_buttion_text, command=self._confirm_handler, ) # Cancel button event handler self._cancel_handler = cancel_handler \ if cancel_handler is not None else self._cancel_handler_default # Create cancel button self._cancel_button = Button( master=self._toplevel, text=cancel_buttion_text, command=self._cancel_handler, ) # If the view widget is given if self._view_widget is not None: # Set view widget self.view_set(self._view_widget) # Update widget self._widget_update() def _widget_update(self): """ Update widget. @return: None. """ # Configure layout weights for children self._toplevel.rowconfigure(0, weight=1) self._toplevel.columnconfigure(0, weight=1) # Lay out the main frame widget self._frame.grid( in_=self._toplevel, row=0, column=0, sticky='NSEW', ) # Do not use children to compute main frame's geometry info self._frame.grid_propagate(False) # Configure layout weights for children. # Row 0 is for the view widget. self._frame.rowconfigure(0, weight=1) # Row 1 is for the confirm and cancel button widgets. self._frame.rowconfigure(0, weight=0) # Use only one column self._frame.columnconfigure(0, weight=1) # Lay out the confirm button self._confirm_button.grid( in_=self._frame, row=1, column=0, sticky='W', ) # Lay out the cancel button self._cancel_button.grid( in_=self._frame, row=1, column=0, sticky='E', ) def main_frame(self): """ Get the main frame widget. @return: Main frame widget. """ # Return the main frame widget return self._frame def view_set(self, widget): """ Set view widget. @param widget: View widget. @return: None. """ # Hide old view widget if self._view_widget is not None: self._view_widget.grid_forget() # Store new view widget self._view_widget = widget # Lay out new view widget self._view_widget.grid( in_=self._frame, row=0, column=0, sticky='NSEW', ) def confirm_button(self): """ Get the confirm button widget. @return: Confirm button widget. """ # Return the confirm button widget return self._confirm_button def confirm_handler_set(self, handler): """ Set confirm button event handler. @handler: Confirm button event handler. @return: None. """ # Store confirm button event handler self._confirm_handler = handler # Set confirm button event handler self._confirm_button.config(command=self._confirm_handler) def _confirm_handler_default(self): """ Default confirm button event handler. @return: None. """ # Do nothing pass def cancel_button(self): """ Get the cancel button widget. @return: Cancel button widget. """ # Return the cancel button widget return self._cancel_button def cancel_handler_set(self, handler): """ Set cancel button event handler. @handler: Cancel button event handler. @return: None. """ # Store cancel button event handler self._cancel_handler = handler # Set cancel button event handler self._cancel_button.config(command=self._cancel_handler) def _cancel_handler_default(self): """ Default cancel button event handler. @return: None. """ # Hide the toplevel widget self._toplevel.withdraw() # Release grab on the toplevel widget self._toplevel.grab_release()
class Example(Frame): def __init__(self, parent): Frame.__init__(self, parent) self.parent = parent self.initUI() def initUI(self): self.username = '' self.r = praw.Reddit(USERAGENT) self.parent.title("") self.style = Style() self.style.theme_use("clam") self.pack(fill=BOTH, expand = 1) self.labelU = Label(self, text="U:") self.labelP = Label(self, text="P:") self.entryUsername = Entry(self) self.entryUsername.config(relief='flat') self.entryUsername.focus_set() self.entryUsername.bind('<Return>', lambda event: self.login(self.entryUsername.get())) self.entryUsername.bind('<Up>', lambda event: self.entryUsername.insert(0, self.username)) self.quitbutton = Button(self, text="Quit", command= lambda: self.quit()) self.quitbutton.config(width=6) self.labelKarma = Label(self, text = '•') self.labelKarma.grid(row = 3, column = 1) self.labelU.grid(row=0, column=0) self.entryUsername.grid(row=0, column=1) self.quitbutton.grid(row=2, column=1, pady=4) self.usernamelabel = Label(self, text='') self.usernamelabel.grid(row=1, column=1) def login(self, username): print('U: ' + username) self.username = username self.entryUsername.delete(0, 200) if username == '': self.entryUsername.focus_set() else: try: self.user = self.r.get_redditor(self.username) lkarma = str(self.user.link_karma) ckarma = str(self.user.comment_karma) lkarma = self.karmaRound(lkarma) ckarma = self.karmaRound(ckarma) karmastring = lkarma + ' • ' + ckarma self.labelKarma.config(text = karmastring) self.usernamelabel.config(text= self.username) except: self.labelKarma.config(text = '•') self.usernamelabel.config(text= 'User not found') pass def karmaRound(self, karma): if len(karma) > 4 and len(karma) < 7: tstring = karma[:-3] tstring2 = karma[-3:] karma = tstring + '.' + tstring2[:2] + 'K' return karma if len(karma) > 6: tstring = karma[:-6] tstring2 = karma[-6:] karma = tstring + '.' + tstring2[:2] + 'M' return karma else: return karma
class Aplicacion(Frame): pi = pigpio.pi('192.168.15.4') def __init__(self,parent): Frame.__init__(self , parent) self.enc1 = Encoder(21) self.parent = parent self.conexion = True#is_connected() self.est_pinza = 1 self.est_subebaja = 1 self.initUI() def initUI(self): for i in range(4): self.columnconfigure(i, pad=3) for i in range(4): self.rowconfigure(i, pad=3) #self.listBox() sw = self.parent.winfo_screenwidth() sh = self.parent.winfo_screenheight() self.fischerpi() self.parent.geometry('%dx%d' % (sw/4, sh/4)) self.pack() def fischerpi(self): self.botonPrueba = Button(self , text = 'Prueba Motores', command = self.prueba) self.botonPrueba.grid() self.botonGiro = Button(self , text = 'Giro PID', command = self.Giro) self.botonGiro.grid(row = 1 , column = 0) self.cant_posicion = Entry(self) self.cant_posicion.grid(row = 1 , column = 1) self.pinza = Button(self , text = 'Pinza', command = lambda estado = self.est_pinza :self.pinzac(estado)) self.pinza.grid(row = 2 , column = 0) self.subeybaja = Button(self , text = 'sube', command = self.subebaja) self.subeybaja.grid(row = 3 , column = 0) def subebaja(self): estado = self.est_subebaja if estado: self.pi.write(9,0) self.pi.write(11,1) self.id_sb = self.subeybaja.after(5000,self.sbcancel) else: self.pi.write(9,1) self.pi.write(11,0) print('bajando...') print(estado) self.id_sb = self.subeybaja.after(1000,self.sbcancel) self.est_subebaja = not self.est_subebaja def sbcancel(self): self.subeybaja.after_cancel(self.id_sb) self.pi.write(9,0) self.pi.write(11,0) def pinzacancel(self ): self.pinza.after_cancel(self.id) self.pi.write(27,0) self.pi.write(17,0) def pinzac(self , estado): estado = self.est_pinza if estado: self.pi.write(27,0) self.pi.write(17,1) print('abriendo...') print(estado) else: self.pi.write(27,1) self.pi.write(17,0) print('cerrando...') print(estado) self.est_pinza = not self.est_pinza print (self.est_pinza) self.id = self.pinza.after(1000,self.pinzacancel) def Giro(self): grados = self.cant_posicion.get() pulsos = int(grados) * 12.222222222222221 self.enc1.setPoint(int(pulsos)) def prueba(self): self.botonPrueba.config(state = DISABLED) pines = [17,27,18,23,9,11,25,8] for pin in pines: self.pi.write(pin,0) for pin in pines: print('Probando pin %s...'%pin) ppin = PWM(pin) ppin.set_duty(128) time.sleep(1) ppin.set_duty(172) time.sleep(1) ppin.set_duty(0) time.sleep(0.5) self.botonPrueba.config(state = NORMAL) def onExit(self,*args): self.quit()
class Example(Frame): def __init__(self, parent): Frame.__init__(self, parent) self.parent = parent self.initUI() def initUI(self): self.parent.title("") self.style = Style() self.style.theme_use("clam") self.pack(fill=BOTH, expand = 1) self.labelU = Label(self, text="U:") self.labelP = Label(self, text="P:") self.entryUsername = Entry(self) self.entryUsername.config(relief='flat') self.entryUsername.focus_set() self.entryUsername.bind('<Return>', lambda event: self.entryPassword.focus_set()) self.entryPassword = Entry(self) self.entryPassword.config(relief='flat', show='•') self.entryPassword.bind('<Return>', lambda event: self.login(self.entryUsername.get(), self.entryPassword.get())) self.newbutton = Button(self, text="Login", command= lambda: self.login(self.entryUsername.get(), self.entryPassword.get())) self.newbutton.bind('<Return>', lambda event: self.login(self.entryUsername.get(), self.entryPassword.get())) self.newbutton.config(width=6) self.quitbutton = Button(self, text="Quit", command= lambda: self.quit()) self.quitbutton.config(width=6) self.mailIconRed = PhotoImage(file="mail.gif") self.labelRed = Label(self, image=self.mailIconRed) self.mailIconGray = PhotoImage(file="mail2.gif") self.labelGray = Label(self, image=self.mailIconGray) self.labelKarma = Label(self, text = '•') self.labelU.grid(row=0, column=0) self.entryUsername.grid(row=0, column=1) self.labelP.grid(row=1, column=0) self.entryPassword.grid(row=1, column=1, pady=4) self.newbutton.grid(row=2, column=1) self.quitbutton.grid(row=3, column=1, pady=4) ''' sw = self.parent.winfo_screenwidth() sh = self.parent.winfo_screenheight() w=150 h=112 x = (sw - w) / 2 y = (sh - h) / 2 self.parent.geometry('%dx%d+%d+%d' % (w, h, x, y-50)) ''' def login(self, username, password): #print('U: ' + username) self.username = username if username == '': #print('Please enter a username') self.entryUsername.focus_set() elif password == '': #print('Please enter a password') self.entryPassword.set_focus() if username != '' and password != '': #print('Attempting login for ' + username) try: self.USERAGENT = username + ' scans his inbox for new mail.' self.r = praw.Reddit(self.USERAGENT) #self.r.config._ssl_url = None self.r.login(username, password) #print('You have logged in as ' + username) self.labelU.grid_forget() self.labelP.grid_forget() self.entryUsername.grid_forget() self.entryPassword.grid_forget() self.newbutton.grid_forget() self.quitbutton.grid_forget() self.usernamelabel = Label(self, text=username) self.usernamelabel.grid(row=0, column=0, pady = 10, padx = 30) self.quitbutton.grid(row=1, column=0) self.labelKarma.grid(row = 3, column = 0) self.playedSound = 'false' self.loop() except praw.errors.InvalidUserPass: pass #print('Invalid username or password') def loop(self): while True: try: #print('Starting new search') hasmail = 'false' for msg in self.r.get_unread(limit=None): hasmail = 'true' if hasmail == 'true': #print("You've got mail!") if self.playedSound == 'false': winsound.PlaySound('pop.wav', winsound.SND_FILENAME) self.playedSound = 'true' self.labelGray.grid_forget() self.labelRed.grid(row=2, column=0) if hasmail == 'false': self.playedSound = 'false' #print('No mail!') self.labelRed.grid_forget() self.labelGray.grid(row=2, column=0) self.user = self.r.get_redditor(self.username) lkarma = str(self.user.link_karma) ckarma = str(self.user.comment_karma) lkarma = self.karmaRound(lkarma) ckarma = self.karmaRound(ckarma) karmastring = lkarma + ' • ' + ckarma self.labelKarma.config(text = karmastring) time.sleep(10) except Exception: time.sleep(10) def karmaRound(self, karma): if len(karma) > 4 and len(karma) < 7: tstring = karma[:-3] tstring2 = karma[-3:] karma = tstring + '.' + tstring2[:2] + 'K' return karma if len(karma) > 6: tstring = karma[:-6] tstring2 = karma[-6:] karma = tstring + '.' + tstring2[:2] + 'M' return karma else: return karma
class GetKeysDialog(Toplevel): # Dialog title for invalid key sequence keyerror_title = 'Key Sequence Error' def __init__(self, parent, title, action, current_key_sequences, *, _htest=False, _utest=False): """ parent - parent of this dialog title - string which is the title of the popup dialog action - string, the name of the virtual event these keys will be mapped to current_key_sequences - list, a list of all key sequence lists currently mapped to virtual events, for overlap checking _htest - bool, change box location when running htest _utest - bool, do not wait when running unittest """ Toplevel.__init__(self, parent) self.withdraw() # Hide while setting geometry. self.configure(borderwidth=5) self.resizable(height=False, width=False) self.title(title) self.transient(parent) self.grab_set() self.protocol("WM_DELETE_WINDOW", self.cancel) self.parent = parent self.action = action self.current_key_sequences = current_key_sequences self.result = '' self.key_string = StringVar(self) self.key_string.set('') # Set self.modifiers, self.modifier_label. self.set_modifiers_for_platform() self.modifier_vars = [] for modifier in self.modifiers: variable = StringVar(self) variable.set('') self.modifier_vars.append(variable) self.advanced = False self.create_widgets() self.update_idletasks() self.geometry( "+%d+%d" % ( parent.winfo_rootx() + (parent.winfo_width()/2 - self.winfo_reqwidth()/2), parent.winfo_rooty() + ((parent.winfo_height()/2 - self.winfo_reqheight()/2) if not _htest else 150) ) ) # Center dialog over parent (or below htest box). if not _utest: self.deiconify() # Geometry set, unhide. self.wait_window() def showerror(self, *args, **kwargs): # Make testing easier. Replace in #30751. messagebox.showerror(*args, **kwargs) def create_widgets(self): self.frame = frame = Frame(self, borderwidth=2, relief='sunken') frame.pack(side='top', expand=True, fill='both') frame_buttons = Frame(self) frame_buttons.pack(side='bottom', fill='x') self.button_ok = Button(frame_buttons, text='OK', width=8, command=self.ok) self.button_ok.grid(row=0, column=0, padx=5, pady=5) self.button_cancel = Button(frame_buttons, text='Cancel', width=8, command=self.cancel) self.button_cancel.grid(row=0, column=1, padx=5, pady=5) # Basic entry key sequence. self.frame_keyseq_basic = Frame(frame, name='keyseq_basic') self.frame_keyseq_basic.grid(row=0, column=0, sticky='nsew', padx=5, pady=5) basic_title = Label(self.frame_keyseq_basic, text=f"New keys for '{self.action}' :") basic_title.pack(anchor='w') basic_keys = Label(self.frame_keyseq_basic, justify='left', textvariable=self.key_string, relief='groove', borderwidth=2) basic_keys.pack(ipadx=5, ipady=5, fill='x') # Basic entry controls. self.frame_controls_basic = Frame(frame) self.frame_controls_basic.grid(row=1, column=0, sticky='nsew', padx=5) # Basic entry modifiers. self.modifier_checkbuttons = {} column = 0 for modifier, variable in zip(self.modifiers, self.modifier_vars): label = self.modifier_label.get(modifier, modifier) check = Checkbutton(self.frame_controls_basic, command=self.build_key_string, text=label, variable=variable, onvalue=modifier, offvalue='') check.grid(row=0, column=column, padx=2, sticky='w') self.modifier_checkbuttons[modifier] = check column += 1 # Basic entry help text. help_basic = Label(self.frame_controls_basic, justify='left', text="Select the desired modifier keys\n"+ "above, and the final key from the\n"+ "list on the right.\n\n" + "Use upper case Symbols when using\n" + "the Shift modifier. (Letters will be\n" + "converted automatically.)") help_basic.grid(row=1, column=0, columnspan=4, padx=2, sticky='w') # Basic entry key list. self.list_keys_final = Listbox(self.frame_controls_basic, width=15, height=10, selectmode='single') self.list_keys_final.insert('end', *AVAILABLE_KEYS) self.list_keys_final.bind('<ButtonRelease-1>', self.final_key_selected) self.list_keys_final.grid(row=0, column=4, rowspan=4, sticky='ns') scroll_keys_final = Scrollbar(self.frame_controls_basic, orient='vertical', command=self.list_keys_final.yview) self.list_keys_final.config(yscrollcommand=scroll_keys_final.set) scroll_keys_final.grid(row=0, column=5, rowspan=4, sticky='ns') self.button_clear = Button(self.frame_controls_basic, text='Clear Keys', command=self.clear_key_seq) self.button_clear.grid(row=2, column=0, columnspan=4) # Advanced entry key sequence. self.frame_keyseq_advanced = Frame(frame, name='keyseq_advanced') self.frame_keyseq_advanced.grid(row=0, column=0, sticky='nsew', padx=5, pady=5) advanced_title = Label(self.frame_keyseq_advanced, justify='left', text=f"Enter new binding(s) for '{self.action}' :\n" + "(These bindings will not be checked for validity!)") advanced_title.pack(anchor='w') self.advanced_keys = Entry(self.frame_keyseq_advanced, textvariable=self.key_string) self.advanced_keys.pack(fill='x') # Advanced entry help text. self.frame_help_advanced = Frame(frame) self.frame_help_advanced.grid(row=1, column=0, sticky='nsew', padx=5) help_advanced = Label(self.frame_help_advanced, justify='left', text="Key bindings are specified using Tkinter keysyms as\n"+ "in these samples: <Control-f>, <Shift-F2>, <F12>,\n" "<Control-space>, <Meta-less>, <Control-Alt-Shift-X>.\n" "Upper case is used when the Shift modifier is present!\n\n" + "'Emacs style' multi-keystroke bindings are specified as\n" + "follows: <Control-x><Control-y>, where the first key\n" + "is the 'do-nothing' keybinding.\n\n" + "Multiple separate bindings for one action should be\n"+ "separated by a space, eg., <Alt-v> <Meta-v>." ) help_advanced.grid(row=0, column=0, sticky='nsew') # Switch between basic and advanced. self.button_level = Button(frame, command=self.toggle_level, text='<< Basic Key Binding Entry') self.button_level.grid(row=2, column=0, stick='ew', padx=5, pady=5) self.toggle_level() def set_modifiers_for_platform(self): """Determine list of names of key modifiers for this platform. The names are used to build Tk bindings -- it doesn't matter if the keyboard has these keys; it matters if Tk understands them. The order is also important: key binding equality depends on it, so config-keys.def must use the same ordering. """ if sys.platform == "darwin": self.modifiers = ['Shift', 'Control', 'Option', 'Command'] else: self.modifiers = ['Control', 'Alt', 'Shift'] self.modifier_label = {'Control': 'Ctrl'} # Short name. def toggle_level(self): "Toggle between basic and advanced keys." if self.button_level.cget('text').startswith('Advanced'): self.clear_key_seq() self.button_level.config(text='<< Basic Key Binding Entry') self.frame_keyseq_advanced.lift() self.frame_help_advanced.lift() self.advanced_keys.focus_set() self.advanced = True else: self.clear_key_seq() self.button_level.config(text='Advanced Key Binding Entry >>') self.frame_keyseq_basic.lift() self.frame_controls_basic.lift() self.advanced = False def final_key_selected(self, event=None): "Handler for clicking on key in basic settings list." self.build_key_string() def build_key_string(self): "Create formatted string of modifiers plus the key." keylist = modifiers = self.get_modifiers() final_key = self.list_keys_final.get('anchor') if final_key: final_key = translate_key(final_key, modifiers) keylist.append(final_key) self.key_string.set(f"<{'-'.join(keylist)}>") def get_modifiers(self): "Return ordered list of modifiers that have been selected." mod_list = [variable.get() for variable in self.modifier_vars] return [mod for mod in mod_list if mod] def clear_key_seq(self): "Clear modifiers and keys selection." self.list_keys_final.select_clear(0, 'end') self.list_keys_final.yview('moveto', '0.0') for variable in self.modifier_vars: variable.set('') self.key_string.set('') def ok(self, event=None): keys = self.key_string.get().strip() if not keys: self.showerror(title=self.keyerror_title, parent=self, message="No key specified.") return if (self.advanced or self.keys_ok(keys)) and self.bind_ok(keys): self.result = keys self.grab_release() self.destroy() def cancel(self, event=None): self.result = '' self.grab_release() self.destroy() def keys_ok(self, keys): """Validity check on user's 'basic' keybinding selection. Doesn't check the string produced by the advanced dialog because 'modifiers' isn't set. """ final_key = self.list_keys_final.get('anchor') modifiers = self.get_modifiers() title = self.keyerror_title key_sequences = [key for keylist in self.current_key_sequences for key in keylist] if not keys.endswith('>'): self.showerror(title, parent=self, message='Missing the final Key') elif (not modifiers and final_key not in FUNCTION_KEYS + MOVE_KEYS): self.showerror(title=title, parent=self, message='No modifier key(s) specified.') elif (modifiers == ['Shift']) \ and (final_key not in FUNCTION_KEYS + MOVE_KEYS + ('Tab', 'Space')): msg = 'The shift modifier by itself may not be used with'\ ' this key symbol.' self.showerror(title=title, parent=self, message=msg) elif keys in key_sequences: msg = 'This key combination is already in use.' self.showerror(title=title, parent=self, message=msg) else: return True return False def bind_ok(self, keys): "Return True if Tcl accepts the new keys else show message." try: binding = self.bind(keys, lambda: None) except TclError as err: self.showerror( title=self.keyerror_title, parent=self, message=(f'The entered key sequence is not accepted.\n\n' f'Error: {err}')) return False else: self.unbind(keys, binding) return True
class DialogOpenArchive(Toplevel): def __init__(self, parent, openType, filesource, filenames, title, colHeader, showAltViewButton=False): if isinstance(parent, Cntlr): cntlr = parent parent = parent.parent # parent is cntlrWinMain else: # parent is a Toplevel dialog cntlr = parent.cntlr super(DialogOpenArchive, self).__init__(parent) self.parent = parent self.showAltViewButton = showAltViewButton parentGeometry = re.match("(\d+)x(\d+)[+]?([-]?\d+)[+]?([-]?\d+)", parent.geometry()) dialogX = int(parentGeometry.group(3)) dialogY = int(parentGeometry.group(4)) self.accepted = False self.transient(self.parent) frame = Frame(self) treeFrame = Frame(frame, width=500) vScrollbar = Scrollbar(treeFrame, orient=VERTICAL) hScrollbar = Scrollbar(treeFrame, orient=HORIZONTAL) self.treeView = Treeview(treeFrame, xscrollcommand=hScrollbar.set, yscrollcommand=vScrollbar.set) self.treeView.grid(row=0, column=0, sticky=(N, S, E, W)) hScrollbar["command"] = self.treeView.xview hScrollbar.grid(row=1, column=0, sticky=(E,W)) vScrollbar["command"] = self.treeView.yview vScrollbar.grid(row=0, column=1, sticky=(N,S)) treeFrame.columnconfigure(0, weight=1) treeFrame.rowconfigure(0, weight=1) treeFrame.grid(row=0, column=0, columnspan=4, sticky=(N, S, E, W), padx=3, pady=3) self.treeView.focus_set() if openType not in (PLUGIN, PACKAGE): cntlr.showStatus(_("loading archive {0}").format(filesource.url)) self.filesource = filesource self.filenames = filenames self.selection = filesource.selection self.hasToolTip = False selectedNode = None if openType == ENTRY_POINTS: try: metadataFiles = filesource.taxonomyPackageMetadataFiles ''' take first for now if len(metadataFiles) != 1: raise IOError(_("Taxonomy package contained more than one metadata file: {0}.") .format(', '.join(metadataFiles))) ''' metadataFile = metadataFiles[0] metadata = filesource.url + os.sep + metadataFile self.metadataFilePrefix = os.sep.join(os.path.split(metadataFile)[:-1]) if self.metadataFilePrefix: self.metadataFilePrefix += "/" # zip contents have /, never \ file seps self.taxonomyPkgMetaInf = '{}/META-INF/'.format( os.path.splitext(os.path.basename(filesource.url))[0]) self.taxonomyPackage = parsePackage(cntlr, filesource, metadata, os.sep.join(os.path.split(metadata)[:-1]) + os.sep) if self.taxonomyPackage["entryPoints"]: # may have instance documents too self.packageContainedInstances = [] packageContentTypeCounts = {} for suffix in (".xhtml", ".htm", ".html"): for potentialInstance in filesource.dir: if potentialInstance.endswith(".xhtml"): _type = "Inline Instance" self.packageContainedInstances.append([potentialInstance, _type]) packageContentTypeCounts[potentialInstance] = packageContentTypeCounts.get(potentialInstance, 0) + 1 if self.packageContainedInstances: break if self.packageContainedInstances: # add sequences to any duplicated entry types for _type, count in packageContentTypeCounts.items(): if count > 1: _dupNo = 0 for i in range(len(self.packageContainedInstances)): if self.packageContainedInstances[i][0] == _type: _dupNo += 1 self.packageContainedInstances[i][0] = "{} {}".format(_type, _dupNo) else: # may be a catalog file with no entry oint names openType = ARCHIVE # no entry points to show, just archive self.showAltViewButton = False except Exception as e: self.close() err = _("Failed to parse metadata; the underlying error was: {0}").format(e) messagebox.showerror(_("Malformed taxonomy package"), err) cntlr.addToLog(err) return if openType not in (PLUGIN, PACKAGE): cntlr.showStatus(None) if openType in (DISCLOSURE_SYSTEM, PLUGIN, PACKAGE): y = 3 else: y = 1 okButton = Button(frame, text=_("OK"), command=self.ok) cancelButton = Button(frame, text=_("Cancel"), command=self.close) okButton.grid(row=y, column=2, sticky=(S,E,W), pady=3) cancelButton.grid(row=y, column=3, sticky=(S,E,W), pady=3, padx=3) if self.showAltViewButton: self.altViewButton = Button(frame, command=self.showAltView) self.altViewButton.grid(row=y, column=0, sticky=(S,W), pady=3, padx=3) self.loadTreeView(openType, colHeader, title) self.geometry("+{0}+{1}".format(dialogX+50,dialogY+100)) frame.grid(row=0, column=0, sticky=(N,S,E,W)) frame.columnconfigure(0, weight=1) frame.rowconfigure(0, weight=1) window = self.winfo_toplevel() window.columnconfigure(0, weight=1) window.rowconfigure(0, weight=1) self.bind("<Return>", self.ok) self.bind("<Escape>", self.close) self.toolTipText = StringVar() if self.hasToolTip: self.treeView.bind("<Motion>", self.motion, '+') self.treeView.bind("<Leave>", self.leave, '+') self.toolTipText = StringVar() self.toolTip = ToolTip(self.treeView, textvariable=self.toolTipText, wraplength=640, follow_mouse=True, state="disabled") self.toolTipRowId = None self.protocol("WM_DELETE_WINDOW", self.close) self.grab_set() self.wait_window(self) def loadTreeView(self, openType, title, colHeader): self.title(title) self.openType = openType selectedNode = None # clear previous treeview entries for previousNode in self.treeView.get_children(""): self.treeView.delete(previousNode) # set up treeView widget and tabbed pane if openType in (ARCHIVE, DISCLOSURE_SYSTEM, PLUGIN, PACKAGE): if openType in (PLUGIN, PACKAGE): width = 770 else: width = 500 self.treeView.column("#0", width=width, anchor="w") self.treeView.heading("#0", text=colHeader) self.isRss = getattr(self.filesource, "isRss", False) if self.isRss: self.treeView.column("#0", width=350, anchor="w") self.treeView["columns"] = ("descr", "date", "instDoc") self.treeView.column("descr", width=50, anchor="center", stretch=False) self.treeView.heading("descr", text="Form") self.treeView.column("date", width=170, anchor="w", stretch=False) self.treeView.heading("date", text="Pub Date") self.treeView.column("instDoc", width=200, anchor="w", stretch=False) self.treeView.heading("instDoc", text="Instance Document") elif openType == PLUGIN: self.treeView.column("#0", width=150, anchor="w") self.treeView["columns"] = ("name", "vers", "descr", "license") self.treeView.column("name", width=150, anchor="w", stretch=False) self.treeView.heading("name", text="Name") self.treeView.column("vers", width=60, anchor="w", stretch=False) self.treeView.heading("vers", text="Version") self.treeView.column("descr", width=300, anchor="w", stretch=False) self.treeView.heading("descr", text="Description") self.treeView.column("license", width=60, anchor="w", stretch=False) self.treeView.heading("license", text="License") elif openType == PACKAGE: self.treeView.column("#0", width=200, anchor="w") self.treeView["columns"] = ("vers", "descr", "license") self.treeView.column("vers", width=100, anchor="w", stretch=False) self.treeView.heading("vers", text="Version") self.treeView.column("descr", width=400, anchor="w", stretch=False) self.treeView.heading("descr", text="Description") self.treeView.column("license", width=70, anchor="w", stretch=False) self.treeView.heading("license", text="License") else: self.treeView["columns"] = tuple() loadedPaths = [] for i, filename in enumerate(self.filenames): if isinstance(filename,tuple): if self.isRss: form, date, instDoc = filename[2:5] elif openType == PLUGIN: name, vers, descr, license = filename[3:7] elif openType == PACKAGE: vers, descr, license = filename[3:6] filename = filename[0] # ignore tooltip self.hasToolTip = True if filename.endswith("/"): filename = filename[:-1] path = filename.split("/") if not self.isRss and len(path) > 1 and path[:-1] in loadedPaths: parent = "file{0}".format(loadedPaths.index(path[:-1])) else: parent = "" node = self.treeView.insert(parent, "end", "file{0}".format(i), text=path[-1]) if self.isRss: self.treeView.set(node, "descr", form) self.treeView.set(node, "date", date) self.treeView.set(node, "instDoc", os.path.basename(instDoc)) elif openType == PLUGIN: self.treeView.set(node, "name", name) self.treeView.set(node, "vers", vers) self.treeView.set(node, "descr", descr) self.treeView.set(node, "license", license) elif openType == PACKAGE: self.treeView.set(node, "vers", vers) self.treeView.set(node, "descr", descr) self.treeView.set(node, "license", license) if self.selection == filename: selectedNode = node loadedPaths.append(path) elif openType == ENTRY_POINTS: self.treeView.column("#0", width=200, anchor="w") self.treeView.heading("#0", text="Name") self.treeView["columns"] = ("url",) self.treeView.column("url", width=300, anchor="w") self.treeView.heading("url", text="URL") for fileType, fileUrl in getattr(self, "packageContainedInstances", ()): self.treeView.insert("", "end", fileUrl, values=fileType, text=fileUrl or urls[0][2]) for name, urls in sorted(self.taxonomyPackage["entryPoints"].items(), key=lambda i:i[0][2]): self.treeView.insert("", "end", name, values="\n".join(url[1] for url in urls), text=name or urls[0][2]) self.hasToolTip = True else: # unknown openType return None if selectedNode: self.treeView.see(selectedNode) self.treeView.selection_set(selectedNode) if self.showAltViewButton: self.altViewButton.config(text=_("Show Files") if openType == ENTRY_POINTS else _("Show Entries")) def ok(self, event=None): selection = self.treeView.selection() if len(selection) > 0: if hasattr(self, "taxonomyPackage"): # load file source remappings self.filesource.mappedPaths = self.taxonomyPackage["remappings"] filename = None if self.openType in (ARCHIVE, DISCLOSURE_SYSTEM): filename = self.filenames[int(selection[0][4:])] if isinstance(filename,tuple): if self.isRss: filename = filename[4] else: filename = filename[0] elif self.openType == ENTRY_POINTS: epName = selection[0] #index 0 is the remapped Url, as opposed to the canonical one used for display # Greg Acsone reports [0] does not work for Corep 1.6 pkgs, need [1], old style packages filenames = [] for _url, _type in self.packageContainedInstances: # check if selection was an inline instance if _type == epName: filenames.append(_url) if not filenames: # else if it's a named taxonomy entry point for url in self.taxonomyPackage["entryPoints"][epName]: filename = url[0] if not filename.endswith("/"): # check if it's an absolute URL rather than a path into the archive if not isHttpUrl(filename) and self.metadataFilePrefix != self.taxonomyPkgMetaInf: # assume it's a path inside the archive: filename = self.metadataFilePrefix + filename filenames.append(filename) if filenames: self.filesource.select(filenames) self.accepted = True self.close() return elif self.openType in (PLUGIN, PACKAGE): filename = self.filenames[int(selection[0][4:])][2] if filename is not None and not filename.endswith("/"): if hasattr(self, "taxonomyPackage"): # attempt to unmap the filename to original file # will be mapped again in loading, but this allows schemaLocation to be unmapped for prefix, remapping in self.taxonomyPackage["remappings"].items(): if isHttpUrl(remapping): remapStart = remapping else: remapStart = self.metadataFilePrefix + remapping if filename.startswith(remapStart): # set unmmapped file filename = prefix + filename[len(remapStart):] break if self.openType in (PLUGIN, PACKAGE): self.filesource.selection = filename else: self.filesource.select(filename) self.accepted = True self.close() def close(self, event=None): self.parent.focus_set() self.destroy() def showAltView(self, event=None): if self.openType == ENTRY_POINTS: self.loadTreeView(ARCHIVE, _("Select Entry Point"), _("File")) else: self.loadTreeView(ENTRY_POINTS, _("Select Archive File"), _("File")) def leave(self, *args): self.toolTipRowId = None def motion(self, *args): tvRowId = self.treeView.identify_row(args[0].y) if tvRowId != self.toolTipRowId: text = None if self.openType in (ARCHIVE, DISCLOSURE_SYSTEM, PLUGIN, PACKAGE): self.toolTipRowId = tvRowId if tvRowId and len(tvRowId) > 4: try: text = self.filenames[ int(tvRowId[4:]) ] if isinstance(text, tuple): text = (text[1] or "").replace("\\n","\n") except (KeyError, ValueError): pass elif self.openType == ENTRY_POINTS: try: text = "{0}\n{1}".format(tvRowId, "\n".join(url[1] for url in self.taxonomyPackage["entryPoints"][tvRowId])) except KeyError: pass self.setToolTip(text) def setToolTip(self, text): self.toolTip._hide() if text: self.toolTipText.set(text) self.toolTip.configure(state="normal") self.toolTip._schedule() else: self.toolTipText.set("") self.toolTip.configure(state="disabled")
class Example(Frame): def __init__(self, parent, q): Frame.__init__(self, parent) self.queue = q self.parent = parent self.initUI() def initUI(self): self.parent.title("Pi computation") self.pack(fill=BOTH, expand=True) self.grid_columnconfigure(4, weight=1) self.grid_rowconfigure(3, weight=1) lbl1 = Label(self, text="Digits:") lbl1.grid(row=0, column=0, sticky=E, padx=10, pady=10) self.ent1 = Entry(self, width=10) self.ent1.insert(END, "4000") self.ent1.grid(row=0, column=1, sticky=W) lbl2 = Label(self, text="Accuracy:") lbl2.grid(row=0, column=2, sticky=E, padx=10, pady=10) self.ent2 = Entry(self, width=10) self.ent2.insert(END, "100") self.ent2.grid(row=0, column=3, sticky=W) self.startBtn = Button(self, text="Start", command=self.onStart) self.startBtn.grid(row=1, column=0, padx=10, pady=5, sticky=W) self.pbar = Progressbar(self, mode='indeterminate') self.pbar.grid(row=1, column=1, columnspan=3, sticky=W+E) self.txt = scrolledtext.ScrolledText(self) self.txt.grid(row=2, column=0, rowspan=4, padx=10, pady=5, columnspan=5, sticky=E+W+S+N) def onStart(self): self.startBtn.config(state=DISABLED) self.txt.delete("1.0", END) self.digits = int(self.ent1.get()) self.accuracy = int(self.ent2.get()) self.p1 = Process(target=self.generatePi, args=(self.queue,)) self.p1.start() self.pbar.start(DELAY2) self.after(DELAY1, self.onGetValue) def onGetValue(self): if (self.p1.is_alive()): self.after(DELAY1, self.onGetValue) return else: try: self.txt.insert('end', self.queue.get(0)) self.txt.insert('end', "\n") self.pbar.stop() self.startBtn.config(state=NORMAL) except queue.Empty: print("queue is empty") def generatePi(self, queue): getcontext().prec = self.digits time.sleep(10) pi = Decimal(0) k = 0 n = self.accuracy while k < n: pi += (Decimal(1)/(16**k))*((Decimal(4)/(8*k+1)) - (Decimal(2)/(8*k+4)) - (Decimal(1)/(8*k+5)) - (Decimal(1)/(8*k+6))) k += 1 print(self.p1.is_alive()) queue.put(pi) print("end")
class App(object): def __init__(self): self.win=Tk() self.win.geometry('405x380') self.win.title("网易云mp3播放下载器") self.creat_res() self.res_config() self.win.mainloop() def creat_res(self): self.music_temp=StringVar(value="(.)(.)") self.mp3_lis=[] #备用 self.temp=StringVar()#url输入框 self.temp2=IntVar() #单选框 播放或者下载 self.temp3=StringVar()#path 输入框 self.T_message=Listbox(self.win,background="#EEE9E9") self.B_search=Button(self.win,text="搜索") self.B_path=Button(self.win,text="选择目录") self.E_song=Entry(self.win,textvariable=self.temp) self.E_path=Entry(self.win,textvariable=self.temp3) self.Play_button=Button(self.win,text="播放") self.Pause_button=Button(self.win,textvariable=self.music_temp) self.Temp_button=Button(self.win,text="单曲下载") self.Stop_button=Button(self.win,text="停止") self.Info=Button(self.win,text="说明") self.More_down=Button(self.win,text="歌单批量下载") self.B_search_loacl=Button(self.win,text="扫描本地歌曲") self.S_bal=Scrollbar(self.win) self.R_1=Radiobutton(self.win,variable=self.temp2,text="下载",value=True) self.R_2=Radiobutton(self.win,variable=self.temp2,text="播放",value=False) self.L_mp3_message=Label(self.win,background="#EEE9E9",fg="#9370DB") self.B_search.place(x=340,y=5,width=50,height=30) self.E_song.place(x=10,y=10,width=300,height=35) self.T_message.place(x=10,y=165,width=280,height=200) self.Play_button.place(x=340,y=160,width=50,height=40) self.Pause_button.place(x=340,y=209,width=50,height=40) self.Temp_button.place(x=130,y=125,width=100,height=30) self.S_bal.place(x=286,y=165,width=20,height=200) self.E_path.place(x=10,y=70,width=200,height=40) self.B_path.place(x=230,y=75,width=60,height=38) self.L_mp3_message.place(x=241,y=125,width=152,height=30) self.Info.place(x=340,y=315,width=50,height=40) self.More_down.place(x=10,y=125,width=100,height=30) self.B_search_loacl.place(x=300,y=75,width=100,height=38) self.R_1.place(x=265,y=50,width=60,height=25) self.R_2.place(x=340,y=50,width=60,height=25) self.Stop_button.place(x=340,y=260,width=50,height=40) def res_config(self): self.B_search.config(command=self.get_lis) self.S_bal.config(command=self.T_message.yview) self.T_message["yscrollcommand"]=self.S_bal.set self.T_message.config(selectmode=BROWSE) self.B_path.config(command=self.choose_path) self.More_down.config(command=self.download_music) self.Info.config(command=self.show_mesage) self.Temp_button.config(command=self.single_music_down) self.Play_button.config(command=self.play_music) self.Pause_button.config(command=self.pause_button_click) self.Stop_button.config(command=self.stop_button_click) self.temp2.set(1) #默认配置为下载模式 def choose_path(self): self.path_=askdirectory() self.temp3.set(self.path_) def show_mesage(self): msg="输入框可识别歌单list,或者歌曲名称 '\n'" \ "输入歌单,请搜索后选择单独下载或者全部批量下载 '\n'" \ "播放单曲需要先选择路径,选择歌曲" messagebox.showinfo(message=msg,title="使用说明") def get_web_lis(self): if self.temp.get()!="":#输入框非空 flag = music_get.do_something(self.temp.get()) music_dic=music_get.get_music_id(self.temp.get()) if flag==True:#输入的是链接 mp3_url=music_get.get_mps_url(self.temp.get()) for i, j in mp3_url.items():#i是id号 self.T_message.insert(END,"歌曲:"+i+"\n") else:#如果输入的是单曲 self.T_message.insert(END, "正在查找歌曲:" + self.temp.get() + "\n") for id,name in music_dic.items(): self.T_message.insert(END, "找到歌曲:{}-{}".format(id,name)+ "\n") else: self.T_message.insert(END, "清输入歌曲名或者歌单链接:" + "\n") messagebox.showerror(title="警告",message="请输入歌名或者歌曲清单链接") def get_loacl_lis(self): for file in os.listdir(self.temp3.get()): self.T_message.insert(END, file + "\n") def get_lis(self):#搜索按钮,先判断下输入的是url 还是单曲 print("开关",self.temp2.get()) if self.temp2.get():#wen搜索 print("web搜索") self.get_web_lis() else: #本地搜所 print("本地搜索") self.get_loacl_lis() def download_music(self):#歌单批量下载 try: mp3_url = music_get.get_mps_url(self.temp.get())#mp3 清单表 字典 print(mp3_url) music_get.down_mp3(self.temp3.get(),self.temp.get()) flag = music_get.do_something(self.temp.get()) print(self.temp.get(),self.temp3.get()) if os.path.exists(self.temp3.get()) and flag==True and len(mp3_url)>0:#路径存在,输入连接,dic飞空 self.L_mp3_message.config(text="批量下载中,请不要再操作软件") for i in mp3_url.keys(): t=random.randint(100,300)*0.01 self.T_message.insert(END, "正在努力下载歌曲:" + i + "\n") time.sleep(t) else: self.T_message.insert(END, "请输入歌单连接和存储路径" + "\n") except Exception as s: print(s.args) self.T_message.insert(END, "请先输入歌单连接和存储路径" + "\n") messagebox.showerror(title="警告",message="请输入歌名或者歌曲清单链接") def get_id(self):#获取id号 if self.T_message.curselection():#不为空 s=self.T_message.curselection() res=self.T_message.get(s[0]) pa_id='找到歌曲:[\d]+-.+' if re.match(pa_id,res):#选择listbox id=res[res.find(":")+1:res.find("-")] return id else: self.T_message.insert(END, "请选择带id号的歌曲" + "\n") else: self.T_message.insert(END, "请先搜索歌名" + "\n") def single_music_down(self):#单曲下载 print("----------下载单曲----------") id=self.get_id() flag=music_get.do_something(self.temp.get())#判断是url 还是歌曲名字 如果是url true 否则f if os.path.exists(self.temp3.get()) and flag==False: try: music_get.down_music2(self.temp3.get(),id,self.temp.get()) self.T_message.insert(END, "正在下载歌曲:" +self.temp.get()+ str(id) + "\n") self.L_mp3_message.config(text="歌曲{}_{}下载完成".format(self.temp.get(),id)) except Exception: self.T_message.insert(END, "请选择带的ID号的歌曲:" + "\n") messagebox.showwarning(title="友情提示", message="请选择带的ID号的歌曲") else: self.T_message.insert(END, "erro,请选择存储路径:" + "\n") messagebox.showwarning(title="温馨提示",message="请先搜索歌曲再选择存储路径") def play_music(self): print("播放音乐") path=self.temp3.get()#路径 if os.path.exists(path) and self.temp2.get()==False:#如果路径存在,开关在播放模式 if self.T_message.curselection():#lisbox飞空 print("--------开始播放--------") music_file=self.T_message.get(self.T_message.curselection()) current_music_path=self.temp3.get()+"/"+music_file pa_music=".+[\.]mp3" if re.match(pa_music,music_file):#匹配mp3文件 print("文件识别OK") print(current_music_path) self.L_mp3_message.config(text="文件识别OK") self.play_music_mp3(current_music_path.strip()) #此处有坑,需要清除字符串换行符 self.music_temp.set("暂停") else: print("非mp3文件") self.L_mp3_message.config(text="非mp3文件") else: self.T_message.insert(END, "erro,请选择歌名:" + "\n") else: messagebox.showwarning(title="温馨提示",message="请选择歌曲路径,选择播放模式") def play_music_mp3(self,name):#播放音乐 pygame.init() pygame.mixer.music.load(name) pygame.mixer.music.play() time.sleep(12) # pygame.mixer.music.stop() def pause_button_click(self): if self.music_temp.get()=="暂停": pygame.mixer.music.pause() self.music_temp.set("继续") elif self.music_temp.get()=="继续": pygame.mixer.music.unpause() self.music_temp.set("暂停") def pause_music(self): print("暂停播放") pygame.mixer.music.pause() def stop_button_click(self): pygame.mixer.music.stop()
class DialogOpenArchive(Toplevel): def __init__(self, mainWin, openType, filesource, filenames, title, colHeader, showAltViewButton=False): parent = mainWin.parent super(DialogOpenArchive, self).__init__(parent) self.parent = parent self.showAltViewButton = showAltViewButton parentGeometry = re.match("(\d+)x(\d+)[+]?([-]?\d+)[+]?([-]?\d+)", parent.geometry()) dialogX = int(parentGeometry.group(3)) dialogY = int(parentGeometry.group(4)) self.accepted = False self.transient(self.parent) frame = Frame(self) treeFrame = Frame(frame, width=500) vScrollbar = Scrollbar(treeFrame, orient=VERTICAL) hScrollbar = Scrollbar(treeFrame, orient=HORIZONTAL) self.treeView = Treeview(treeFrame, xscrollcommand=hScrollbar.set, yscrollcommand=vScrollbar.set) self.treeView.grid(row=0, column=0, sticky=(N, S, E, W)) hScrollbar["command"] = self.treeView.xview hScrollbar.grid(row=1, column=0, sticky=(E,W)) vScrollbar["command"] = self.treeView.yview vScrollbar.grid(row=0, column=1, sticky=(N,S)) treeFrame.columnconfigure(0, weight=1) treeFrame.rowconfigure(0, weight=1) treeFrame.grid(row=0, column=0, columnspan=4, sticky=(N, S, E, W), padx=3, pady=3) self.treeView.focus_set() mainWin.showStatus(_("loading archive {0}").format(filesource.url)) self.filesource = filesource self.filenames = filenames self.selection = filesource.selection self.hasToolTip = False selectedNode = None if openType == ENTRY_POINTS: try: metadataFiles = filesource.taxonomyPackageMetadataFiles if len(metadataFiles) > 1: raise IOError(_("Taxonomy package contained more than one metadata file: {0}.") .format(', '.join(metadataFiles))) metadataFile = metadataFiles[0] metadata = filesource.file(filesource.url + os.sep + metadataFile)[0] self.metadataFilePrefix = os.sep.join(os.path.split(metadataFile)[:-1]) if self.metadataFilePrefix: self.metadataFilePrefix += os.sep self.nameToUrls, self.remappings = parseTxmyPkg(mainWin, metadata) except Exception as e: self.close() err = _("Failed to parse metadata; the underlying error was: {0}").format(e) messagebox.showerror(_("Malformed taxonomy package"), err) mainWin.addToLog(err) return mainWin.showStatus(None) if openType == DISCLOSURE_SYSTEM: y = 3 else: y = 1 okButton = Button(frame, text=_("OK"), command=self.ok) cancelButton = Button(frame, text=_("Cancel"), command=self.close) okButton.grid(row=y, column=2, sticky=(S,E,W), pady=3) cancelButton.grid(row=y, column=3, sticky=(S,E,W), pady=3, padx=3) if showAltViewButton: self.altViewButton = Button(frame, command=self.showAltView) self.altViewButton.grid(row=y, column=0, sticky=(S,W), pady=3, padx=3) self.loadTreeView(openType, colHeader, title) frame.grid(row=0, column=0, sticky=(N,S,E,W)) frame.columnconfigure(0, weight=1) window = self.winfo_toplevel() window.columnconfigure(0, weight=1) self.geometry("+{0}+{1}".format(dialogX+50,dialogY+100)) self.bind("<Return>", self.ok) self.bind("<Escape>", self.close) self.toolTipText = StringVar() if self.hasToolTip: self.treeView.bind("<Motion>", self.motion, '+') self.treeView.bind("<Leave>", self.leave, '+') self.toolTipText = StringVar() self.toolTip = ToolTip(self.treeView, textvariable=self.toolTipText, wraplength=640, follow_mouse=True, state="disabled") self.toolTipRowId = None self.protocol("WM_DELETE_WINDOW", self.close) self.grab_set() self.wait_window(self) def loadTreeView(self, openType, title, colHeader): self.title(title) self.openType = openType selectedNode = None # clear previous treeview entries for previousNode in self.treeView.get_children(""): self.treeView.delete(previousNode) # set up treeView widget and tabbed pane if openType in (ARCHIVE, DISCLOSURE_SYSTEM): self.treeView.column("#0", width=500, anchor="w") self.treeView.heading("#0", text=colHeader) try: self.isRss = self.filesource.isRss if self.isRss: self.treeView.column("#0", width=350, anchor="w") self.treeView["columns"] = ("descr", "date", "instDoc") self.treeView.column("descr", width=50, anchor="center", stretch=False) self.treeView.heading("descr", text="Form") self.treeView.column("date", width=170, anchor="w", stretch=False) self.treeView.heading("date", text="Pub Date") self.treeView.column("instDoc", width=200, anchor="w", stretch=False) self.treeView.heading("instDoc", text="Instance Document") except AttributeError: self.isRss = False self.treeView["columns"] = tuple() loadedPaths = [] for i, filename in enumerate(self.filenames): if isinstance(filename,tuple): if self.isRss: form, date, instDoc = filename[2:5] filename = filename[0] # ignore tooltip self.hasToolTip = True if filename.endswith("/"): filename = filename[:-1] path = filename.split("/") if not self.isRss and len(path) > 1 and path[:-1] in loadedPaths: parent = "file{0}".format(loadedPaths.index(path[:-1])) else: parent = "" node = self.treeView.insert(parent, "end", "file{0}".format(i), text=path[-1]) if self.isRss: self.treeView.set(node, "descr", form) self.treeView.set(node, "date", date) self.treeView.set(node, "instDoc", os.path.basename(instDoc)) if self.selection == filename: selectedNode = node loadedPaths.append(path) elif openType == ENTRY_POINTS: self.treeView.column("#0", width=150, anchor="w") self.treeView.heading("#0", text="Name") self.treeView["columns"] = ("url",) self.treeView.column("url", width=350, anchor="w") self.treeView.heading("url", text="URL") for name, urls in self.nameToUrls.items(): displayUrl = urls[1] # display the canonical URL self.treeView.insert("", "end", name, values=[displayUrl], text=name) self.hasToolTip = True else: # unknown openType return None if selectedNode: self.treeView.see(selectedNode) self.treeView.selection_set(selectedNode) if self.showAltViewButton: self.altViewButton.config(text=_("Show Files") if openType == ENTRY_POINTS else _("Show Entries")) def ok(self, event=None): selection = self.treeView.selection() if len(selection) > 0: if self.openType in (ARCHIVE, DISCLOSURE_SYSTEM): filename = self.filenames[int(selection[0][4:])] if isinstance(filename,tuple): if self.isRss: filename = filename[4] else: filename = filename[0] if not filename.endswith("/"): self.filesource.select(filename) self.accepted = True self.close() elif self.openType == ENTRY_POINTS: epName = selection[0] #index 0 is the remapped Url, as opposed to the canonical one used for display urlOrFile = self.nameToUrls[epName][0] # load file source remappings self.filesource.mappedPaths = \ dict((prefix, remapping if isHttpUrl(remapping) else (self.filesource.baseurl + os.sep + self.metadataFilePrefix +remapping.replace("/", os.sep))) for prefix, remapping in self.remappings.items()) if not urlOrFile.endswith("/"): # check if it's an absolute URL rather than a path into the archive if isHttpUrl(urlOrFile): self.filesource.select(urlOrFile) # absolute path selection else: # assume it's a path inside the archive: self.filesource.select(self.metadataFilePrefix + urlOrFile) self.accepted = True self.close() def close(self, event=None): self.parent.focus_set() self.destroy() def showAltView(self, event=None): if self.openType == ENTRY_POINTS: self.loadTreeView(ARCHIVE, _("Select Entry Point"), _("File")) else: self.loadTreeView(ENTRY_POINTS, _("Select Archive File"), _("File")) def leave(self, *args): self.toolTipRowId = None def motion(self, *args): tvRowId = self.treeView.identify_row(args[0].y) if tvRowId != self.toolTipRowId: text = None if self.openType in (ARCHIVE, DISCLOSURE_SYSTEM): self.toolTipRowId = tvRowId if tvRowId and len(tvRowId) > 4: try: text = self.filenames[ int(tvRowId[4:]) ] if isinstance(text, tuple): text = text[1].replace("\\n","\n") except (KeyError, ValueError): pass elif self.openType == ENTRY_POINTS: try: epUrl = self.nameToUrls[tvRowId][1] text = "{0}\n{1}".format(tvRowId, epUrl) except KeyError: pass self.setToolTip(text) def setToolTip(self, text): self.toolTip._hide() if text: self.toolTipText.set(text) self.toolTip.configure(state="normal") self.toolTip._schedule() else: self.toolTipText.set("") self.toolTip.configure(state="disabled")
class retailPage(Frame): ''' the main page that actually branches into 2 seperate frames for buying and selling this frame provides the use with the ''' def __init__(self, parent, main, **kw): Frame.__init__(self, parent, **kw) self.main = main self.Head = Label(font=MED_FONT) self.retail_back_b = Button(text='BACK', command=self.back_fb) self.stock_name = StringVar() self.stock_name_ = '' self.stock_name_c = Combobox(textvariable=self.stock_name) self.stock_name_l = Label(text='Stock name: ') self.amount = Entry() self.amount_l = Label(text='Number of stocks :') self.check_avail_b = Button(text='Check') self.cost_l = Label(text='Cost: ') self.cost = Label() self.buy_stock_b = Button(text='BUY Stock') self.sellp_l = Label(text='Current Selling Price: ') self.profit_l = Label(text='PROFIT/LOSS') self.sell_stock_b = Button(text='SELL Stock') self.page = None def showItems(self, main): self.Head.grid(column=0, row=0, columnspan=2) self.Head.configure(text='logged in as %s' % main.present_user) if self.page == 'b': self.buy() elif self.page == 's': self.sell() def hideItems(self, main): self.Head.grid_forget() def buy(self): '''This function creates the buy window ''' self.retail_back_b.grid(column=1, row=5) self.retail_back_b.config(command=self.back_fb) self.stock_name_l.grid(column=0, row=1) self.stock_name_c.grid(column=1, row=1) self.stock_name_c.config(values=self.main.shares_dict.keys()) self.amount_l.grid(column=0, row=2) self.amount.grid(column=1, row=2) self.check_avail_b.config(command=self.check_avail_buy) self.check_avail_b.grid(column=0, row=3) self.cost_l.grid(column=0, row=4, columnspan=2) self.buy_stock_b.config(command=self.buy_stock, text='Buy Stock', state='disabled') self.buy_stock_b.grid(column=0, row=5) def sell(self): '''This function creats the sell window''' self.retail_back_b.grid(column=1, row=6) self.retail_back_b.config(command=self.back_fs) self.check_avail_b.config(command=self.check_avail_sell) self.stock_name_l.grid(column=0, row=1) self.stock_name_c.grid(column=1, row=1) self.stock_name_c.config(values=self.main.shares_dict.keys()) self.amount_l.grid(column=0, row=2) self.amount.grid(column=1, row=2) self.check_avail_b.grid(column=0, row=3) self.sellp_l.grid(column=0, row=4, columnspan=2) self.profit_l.grid(column=0, row=5, columnspan=2) self.sell_stock_b.config(command=self.sell_stock, state='disabled', text='Check') self.sell_stock_b.grid(column=0, row=6) def back_fb(self): '''Back from buy i.e. removes all the items needed to make buy''' self.retail_back_b.grid_forget() self.Head.grid(column=0, row=0, columnspan=2) self.stock_name_l.grid_forget() self.stock_name_c.grid_forget() self.amount_l.grid_forget() self.amount.grid_forget() self.check_avail_b.grid_forget() self.cost_l.grid_forget() self.buy_stock_b.grid_forget() self.buy_stock_b.config(state='disabled') self.main.show_frame(VIEW_STOCK, RETAIL_PAGE) self.stock_name.set('') self.amount.delete(0, END) def back_fs(self): ''' Back from sell i.e. removes all the items needed to make it sell window''' self.Head.grid(column=0, row=0, columnspan=2) self.retail_back_b.grid_forget() self.check_avail_b.grid_forget() self.stock_name_l.grid_forget() self.stock_name_c.grid_forget() self.amount_l.grid_forget() self.amount.grid_forget() self.sellp_l.grid_forget() self.profit_l.grid_forget() self.sell_stock_b.grid_forget() self.main.show_frame(VIEW_STOCK, RETAIL_PAGE) self.stock_name.set('') self.amount.delete(0, END) self.check_avail_b.grid_forget() def check_avail_buy(self): ''' Performs a check whether the number of shares requisted are available or not and then check whether the person has the required amounts of fund or not for the transaction to go through''' name = self.stock_name.get() l2 = self.main.accounts[self.main.present_user] if name in self.main.shares_dict.keys(): li = self.main.shares_dict[name] else: self.stock_name.delete(0, END) showinfo(meassage='Enter a Valid Stock name') available_num = int(li['tot_amount']) - int(li['tot_sold']) req = int(self.amount.get()) cost = req * int(li['cost']) if req < 0: showinfo(message='Enter a Valid amount') elif req > available_num: showinfo(message='Enter an amount less than ' + str(available_num)) elif cost > int(l2['balance']): showinfo(message='You have only %s in you account' % l2['balance']) else: self.cost_l.config(text='Cost: \t' + li['cost'] + '*' + str(req) + '=' + str(cost)) self.buy_stock_b.config(state='normal') def check_avail_sell(self): ''' Performs a check whether the user has enough stocks to sell''' name = self.stock_name.get() if name in self.main.shares_dict.keys(): li = self.main.shares_dict[name] else: self.stock_name.delete(0, END) showinfo(message='Enter a Valid Stock name') req = int(self.amount.get()) if req < 0: showinfo(message='Please Enter a Valid amount') self.amount.delete(0, END) li = self.main.p_user_dict ok = False for i in li: if name == i['name']: ok = True buff = i if req > int(buff['tot_owned']): showinfo(message='You dont have that many stocks try less than ' + buff['tot_owned']) self.amount.delete(0, END) cost = self.main.shares_dict[name]['cost'] tot_cost = req * int(cost) try: spent = req * float(buff['money_spent']) / int(buff['tot_owned']) except: spent = 0 pol = tot_cost - spent if pol >= 0: self.profit_l.config() elif pol < 0: self.profit_l.config() if req <= int(buff['tot_owned']): self.sellp_l.config(text='Current Selling Price: \t' + cost) self.profit_l.config(text="PROFIT-LOSS: \t" + str(pol)) self.sell_stock_b.config(command=self.sell_stock, text='Sell Stock') showinfo(message= 'Everthing is ok, \nClicking Sell will execute the trade') self.sell_stock_b.config(state='normal') def buy_stock(self): '''Finally Executes the transaction and asks the user for conformation one last time''' name = self.stock_name.get() li = self.main.shares_dict[name] for i in range(len(self.main.p_user_dict)): if name == self.main.p_user_dict[i]['name']: index = i req = int(self.amount.get()) tot_cost = req * int(li['cost']) self.main.shares_dict[name]['tot_sold'] = str( int(self.main.shares_dict[name]['tot_sold']) + req) self.main.p_user_dict[index]['tot_owned'] = str( int(self.main.p_user_dict[index]['tot_owned']) + req) self.main.p_user_dict[index]['money_spent'] = str( int(self.main.p_user_dict[index]['money_spent']) + tot_cost) self.main.users_dict[ self.main.present_user][index] = self.main.p_user_dict[index] balance = int(self.main.accounts[self.main.present_user]['balance']) self.main.accounts[self.main.present_user]['balance'] = str(balance - tot_cost) self.cost_l.config(text='Cost: ') showinfo( message='You have just bought %s of the stock %s at the price %s' % (str(req), name, str(tot_cost))) self.stock_name.set('') self.main.show_frame(VIEW_STOCK, RETAIL_PAGE) self.back_fb() def sell_stock(self): '''Asks the user for conformation and then completes the transaction of selling, at this point the profit field is also updated''' name = self.stock_name.get() req = int(self.amount.get()) li = self.main.p_user_dict for i in range(len(li)): if name == li[i]['name']: ok = True buff = i tot_cost = req * int(self.main.shares_dict[name]['cost']) try: spent = req * float( self.main.p_user_dict[buff]['money_spent']) / int( self.main.p_user_dict[buff]['tot_owned']) except ZeroDivisionError: spent = 0 self.main.shares_dict[name]['tot_sold'] = str( int(self.main.shares_dict[name]['tot_sold']) - req) self.main.p_user_dict[buff]['tot_owned'] = str( int(self.main.p_user_dict[buff]['tot_owned']) - req) pol = tot_cost - spent diff = int(self.main.p_user_dict[buff]['money_spent']) - tot_cost self.main.p_user_dict[buff]['money_spent'] = str( diff) if diff > 0 else '0' self.main.users_dict[self.main.present_user] = self.main.p_user_dict profit = int(self.main.accounts[self.main.present_user]['profit']) self.main.accounts[self.main.present_user]['profit'] = str( int(profit + pol)) balance = int(self.main.accounts[self.main.present_user]['balance']) self.main.accounts[self.main.present_user]['balance'] = str(balance + tot_cost) self.retail_back_b.grid_forget() self.profit_l.config(text='PROFIT/LOSS: ') self.sellp_l.config(text='Current selling price: ') self.main.show_frame(VIEW_STOCK, RETAIL_PAGE) self.back_fs()
class ManagerWindow: """ 主管理界面入口类,直接无参数创建对象即可。 """ # 窗口宽高 WIN_WIDTH = 800 WIN_HEIGHT = 600 def __init__(self): # 界面根节点 self.root = Tk() # 主窗口标题 self.root.title(MANAGER_TITLE) # 读取config self.config_dict = ConfigOperation.get_dir_from_file() # 主窗口分辨率 self.root.geometry("%sx%s+%s+%s" % ( self.WIN_WIDTH, self.WIN_HEIGHT, int((self.root.winfo_screenwidth() - self.WIN_WIDTH) / 2), int((self.root.winfo_screenheight() - self.WIN_HEIGHT) / 2) )) self.root.minsize(self.WIN_WIDTH, self.WIN_HEIGHT) # 选项卡 self.tab_main = Notebook(self.root) self.tab_main.pack(expand=True, fill=BOTH) # 登录选项卡 self.frame_login = Frame(self.tab_main, bg=BG_COLOR) self.frame_login.pack(side=TOP) self.tab_main.add(self.frame_login, text=TAB_NAME_LIST["login"]["text"]) # 管理选项卡 self.frame_manage = Frame(self.tab_main, bg=BG_COLOR) self.tab_main.add(self.frame_manage, text=TAB_NAME_LIST["manage"]["text"]) # 好友选项卡 self.frame_friend = Frame(self.tab_main, bg=BG_COLOR) self.frame_friend.pack(side=TOP) self.tab_main.add(self.frame_friend, text=TAB_NAME_LIST["friends"]["text"]) # 群选项卡 self.frame_group = Frame(self.tab_main, bg=BG_COLOR) self.frame_group.pack(side=TOP) self.tab_main.add(self.frame_group, text=TAB_NAME_LIST["groups"]["text"]) # 插件选项卡 self.frame_plugin = Frame(self.tab_main, bg=BG_COLOR) self.frame_plugin.pack(side=TOP) self.tab_main.add(self.frame_plugin, text=TAB_NAME_LIST["plugins"]["text"]) # 初始化登录选项卡 self.__init_login_tab() # 初始化好友选项卡 self.__init_friend_tab() # 初始化群选项卡 self.__init_group_tab() # 初始化管理选项卡 self.__init_manage_tab() # 初始化插件选项卡 self.__init_plugin_tab() # 关闭窗口自动释放Session self.root.protocol("WM_DELETE_WINDOW", lambda: self.__on_close_root()) # 刷新显示 self.__refresh() # 运行相关线程 fetch_message_thread = FetchMessageThread() fetch_message_thread.daemon = True fetch_message_thread.start() # 运行插件初始化方法 PluginHandler.call_init() # 执行自动连接一次 self.__auto_connect() # 显示 self.root.mainloop() def __init_login_tab(self): """ 初始化登录选项卡界面 :return: 无 """ # 左边列表的frame frame_login_list = Frame(self.frame_login, bg=BG_COLOR) frame_login_list.pack( side=LEFT, expand=True, fill=BOTH, padx=5, pady=5 ) # 列表,用于保存连接记录 self.treeview_login_list = Treeview( frame_login_list, columns=[ LOGIN_GUIDE["host"], LOGIN_GUIDE["port"], LOGIN_GUIDE["authkey"], LOGIN_GUIDE["qq"] ], show="headings", selectmode=BROWSE ) self.treeview_login_list.pack( expand=True, fill=BOTH, side=LEFT ) self.treeview_login_list.column( LOGIN_GUIDE["host"], width=0 ) self.treeview_login_list.heading( LOGIN_GUIDE["host"], text=LOGIN_GUIDE["host"] ) self.treeview_login_list.column( LOGIN_GUIDE["port"], width=0 ) self.treeview_login_list.heading( LOGIN_GUIDE["port"], text=LOGIN_GUIDE["port"] ) self.treeview_login_list.column( LOGIN_GUIDE["authkey"], width=40 ) self.treeview_login_list.heading( LOGIN_GUIDE["authkey"], text=LOGIN_GUIDE["authkey"] ) self.treeview_login_list.column( LOGIN_GUIDE["qq"], width=0 ) self.treeview_login_list.heading( LOGIN_GUIDE["qq"], text=LOGIN_GUIDE["qq"] ) # 设定双击事件 self.treeview_login_list.bind( "<Double-Button-1>", lambda event: self.__on_double_click_login_list_content() ) # 设定登录列表的滚动条 scrollbar_login_list = Scrollbar(frame_login_list) scrollbar_login_list.pack(fill="y", expand=True) self.treeview_login_list.config(yscrollcommand=scrollbar_login_list.set) scrollbar_login_list.config(command=self.treeview_login_list.yview) # 设置列表右键菜单 self.treeview_login_list.bind("<Button-3>", self.__show_login_list_pop_up_menu) # 登录界面显示的那一坨 frame_login_menu = Frame(self.frame_login, bg=BG_COLOR) frame_login_menu.pack(side=LEFT, padx=5, pady=5) # mirai端地址 Label(frame_login_menu, text=LOGIN_GUIDE["host"], bg=BG_COLOR).grid(row=0, sticky=E, padx=5, pady=5) self.entry_host = Entry(frame_login_menu) self.entry_host.grid(row=0, column=1, sticky=W, padx=5, pady=5) # mirai端端口号 Label(frame_login_menu, text=LOGIN_GUIDE["port"], bg=BG_COLOR).grid(row=1, sticky=E, padx=5, pady=5) self.entry_port = Entry(frame_login_menu) self.entry_port.grid(row=1, column=1, sticky=W, padx=5, pady=5) # mirai端http授权码 Label(frame_login_menu, text=LOGIN_GUIDE["authkey"], bg=BG_COLOR).grid( row=2, sticky=E, padx=5, pady=5 ) self.entry_authkey = Entry(frame_login_menu, show=PWD_CHAR_CIRCLE) self.entry_authkey.grid(row=2, column=1, sticky=W, padx=5, pady=5) # 用于激活sessioKey的qq号码 Label(frame_login_menu, text=LOGIN_GUIDE["qq"], bg=BG_COLOR).grid( row=3, sticky=E, padx=5, pady=5 ) self.entry_qq = Entry(frame_login_menu) self.entry_qq.grid(row=3, column=1, sticky=W, padx=5, pady=5) # 自动连接复选框 self.auto_connect_var = BooleanVar() self.checkbutton_auto_connect = Checkbutton( frame_login_menu, text=AUTO_CONNECT_GUIDE, onvalue=True, offvalue=False, variable=self.auto_connect_var, bg=BG_COLOR ) self.checkbutton_auto_connect.grid(row=4, column=0, padx=5, pady=5, columnspan=2) # 连接按钮 self.btn_connect = Button( frame_login_menu, text=BTN_TEXT_CONN["connect"], width=15, command=lambda: self.__on_click_connect_event(), ) self.btn_connect.grid(row=5, columnspan=2, padx=5, pady=5) # 添加到登录列表按钮 self.btn_save_login = Button( frame_login_menu, width=15, text=BTN_TEXT_ADD_LOGIN, command=lambda: self.__on_click_add_to_login_list() ) self.btn_save_login.grid(row=6, columnspan=2, padx=5, pady=5) # 状态栏 self.label_login_status_bar = Label( self.root, text=LOGIN_STATUS_BAR_TEXT["notConnect"], fg=STATUS_BAR_COLOR["normal"] ) self.label_login_status_bar.pack(side=LEFT) # 下面开始从config中将内容填充进文本框中 self.entry_host.delete(0, END) self.entry_host.insert(END, self.config_dict["lastConnection"]["host"]) self.entry_port.delete(0, END) self.entry_port.insert(END, self.config_dict["lastConnection"]["port"]) self.entry_authkey.delete(0, END) self.entry_authkey.insert(END, self.config_dict["lastConnection"]["authkey"]) self.entry_qq.delete(0, END) self.entry_qq.insert(END, self.config_dict["lastConnection"]["qq"]) # 自动连接复选框内容 self.auto_connect_var.set(self.config_dict["autoConnect"]) def __init_friend_tab(self): """ 初始化好友选项卡内容 :return: 无 """ # 创建好友列表框架 frame_friend_list = Frame(self.frame_friend, bg=BG_COLOR) frame_friend_list.pack( side=LEFT, expand=True, fill=BOTH, padx=5, pady=5 ) # 创建消息测试发送框架 frame_friend_send = Frame(self.frame_friend, bg=BG_COLOR) frame_friend_send.pack( side=LEFT, padx=5, pady=5 ) # 设置列表 self.treeview_friend_list = Treeview( frame_friend_list, columns=[ FRIEND_GUIDE["qq"], FRIEND_GUIDE["nickname"], FRIEND_GUIDE["remark"] ], show="headings", selectmode=BROWSE ) self.treeview_friend_list.pack( expand=True, fill=BOTH, side=LEFT ) self.treeview_friend_list.column( FRIEND_GUIDE["qq"], width=0 ) self.treeview_friend_list.heading( FRIEND_GUIDE["qq"], text=FRIEND_GUIDE["qq"] ) self.treeview_friend_list.column( FRIEND_GUIDE["nickname"], width=0 ) self.treeview_friend_list.heading( FRIEND_GUIDE["nickname"], text=FRIEND_GUIDE["nickname"] ) self.treeview_friend_list.column( FRIEND_GUIDE["remark"], width=0 ) self.treeview_friend_list.heading( FRIEND_GUIDE["remark"], text=FRIEND_GUIDE["remark"] ) # 设定好友列表的滚动条 scrollbar_friend_list = Scrollbar(frame_friend_list) scrollbar_friend_list.pack(fill="y", expand=True) self.treeview_friend_list.config(yscrollcommand=scrollbar_friend_list.set) scrollbar_friend_list.config(command=self.treeview_friend_list.yview) # 刷新列表按钮 Button( frame_friend_send, text=BTN_FRIEND_REFRESH, command=lambda: self.__on_click_refresh_friend_list_event() ).grid(row=0, padx=5, pady=5) # 发送纯文本窗口标题 Label(frame_friend_send, text=SEND_TITLE, bg=BG_COLOR).grid(row=1, padx=5, pady=5) # 发送纯文本窗口 self.text_friend_send = Text(frame_friend_send, width=30, height=5) self.text_friend_send.grid(row=2, padx=5, pady=5) # 发送按钮 Button( frame_friend_send, text=BTN_SEND, command=lambda: self.__on_click_send_friend_message() ).grid(row=3, padx=5, pady=5) def __init_group_tab(self): """ 初始化群选项卡内容 :return: 无 """ # 创建好友列表框架 frame_group_list = Frame(self.frame_group, bg=BG_COLOR) frame_group_list.pack( side=LEFT, expand=True, fill=BOTH, padx=5, pady=5 ) # 创建消息测试发送框架 frame_group_send = Frame(self.frame_group, bg=BG_COLOR) frame_group_send.pack( side=LEFT, padx=5, pady=5 ) # 设置列表 self.treeview_group_list = Treeview( frame_group_list, columns=[ GROUP_GUIDE["group"], GROUP_GUIDE["name"], GROUP_GUIDE["permission"] ], show="headings", selectmode=BROWSE ) self.treeview_group_list.pack( expand=True, fill=BOTH, side=LEFT ) self.treeview_group_list.column( GROUP_GUIDE["group"], width=0 ) self.treeview_group_list.heading( GROUP_GUIDE["group"], text=GROUP_GUIDE["group"] ) self.treeview_group_list.column( GROUP_GUIDE["name"], width=0 ) self.treeview_group_list.heading( GROUP_GUIDE["name"], text=GROUP_GUIDE["name"] ) self.treeview_group_list.column( GROUP_GUIDE["permission"], width=0 ) self.treeview_group_list.heading( GROUP_GUIDE["permission"], text=GROUP_GUIDE["permission"] ) # 设定群列表的滚动条 scrollbar_group_list = Scrollbar(frame_group_list) scrollbar_group_list.pack(fill="y", expand=True) self.treeview_group_list.config(yscrollcommand=scrollbar_group_list.set) scrollbar_group_list.config(command=self.treeview_group_list.yview) # 刷新列表按钮 Button( frame_group_send, text=BTN_GROUP_REFRESH, command=lambda: self.__on_click_refresh_group_list_event() ).grid(row=0, padx=5, pady=5) # 发送纯文本窗口标题 Label(frame_group_send, text=SEND_TITLE, bg=BG_COLOR).grid(row=1, padx=5, pady=5) # 发送纯文本窗口 self.text_group_send = Text(frame_group_send, width=30, height=5) self.text_group_send.grid(row=2, padx=5, pady=5) # 发送按钮 Button( frame_group_send, text=BTN_SEND, command=lambda: self.__on_click_send_group_message() ).grid(row=3, padx=5, pady=5) def __init_manage_tab(self): """ 初始化管理选项卡 :return: 无 """ f_manage = Frame(self.frame_manage, bg=BG_COLOR) f_manage.pack(padx=5, pady=5, expand=True) # 指定头指示 Label(f_manage, text=MANAGE_GUIDE["commandHead"], bg=BG_COLOR).grid( row=0, column=0, padx=5, pady=5, sticky=E ) # 指令头文本框 self.entry_command_head = Entry(f_manage) self.entry_command_head.grid(row=0, column=1, padx=5, pady=5, sticky=EW) # 调试复选框 self.debug_var = BooleanVar() checkbutton_debug = Checkbutton( f_manage, text=MANAGE_GUIDE["debug"], onvalue=True, offvalue=False, variable=self.debug_var, bg=BG_COLOR ) checkbutton_debug.grid(row=1, column=0, columnspan=3, padx=5, pady=5) # 启用机器人 self.enable_var = BooleanVar() checkbutton_enable = Checkbutton( f_manage, text=MANAGE_GUIDE["enable"], onvalue=True, offvalue=False, variable=self.enable_var, bg=BG_COLOR ) checkbutton_enable.grid(row=2, column=0, columnspan=3, padx=5, pady=5) # 配置保存 Button( f_manage, text=MANAGE_GUIDE["saveConfig"], command=self.__on_click_save_config ).grid( row=3, column=1, padx=5, pady=5, sticky=EW ) # bot管理qq列表 self.treeview_op_list = Treeview( f_manage, columns=[ MANAGE_GUIDE["botOpQQ"] ], show="headings", selectmode=BROWSE ) self.treeview_op_list.column(MANAGE_GUIDE["botOpQQ"], width=200) self.treeview_op_list.heading(MANAGE_GUIDE["botOpQQ"], text=MANAGE_GUIDE["botOpQQ"]) self.treeview_op_list.grid( row=4, column=0, columnspan=3, rowspan=10, sticky=EW ) # 列表右键 self.treeview_op_list.bind("<Button-3>", self.__show_op_list_pop_up_menu) # 添加管理标签 Label(f_manage, text=MANAGE_GUIDE["addOpQQ"], bg=BG_COLOR).grid(row=14, column=0, padx=5, pady=5) # 添加管理文本框 self.entry_add_op = Entry(f_manage) self.entry_add_op.grid(row=14, column=1, padx=5, pady=5) # 添加添加按钮 Button( f_manage, text=MANAGE_GUIDE["btnAddOpQQ"], command=lambda: self.__on_click_add_op() ).grid(row=14, column=2, padx=5, pady=5, sticky=EW) def __init_plugin_tab(self): """ 初始化插件选项卡 :return: 无 """ # 指示标签 Label(self.frame_plugin, text=PLUGIN_LABEL_TEXT, bg=BG_COLOR).pack(side=TOP) # 插件列表frame frame_plugin_list = Frame(self.frame_plugin, bg=BG_COLOR) frame_plugin_list.pack( side=TOP, expand=True, fill=BOTH, padx=5, pady=5 ) # 插件列表 self.treeview_plugin_list = Treeview( frame_plugin_list, columns=[ PLUGIN_GUIDE["pluginName"] ], show="headings", selectmode=BROWSE ) self.treeview_plugin_list.pack(fill=BOTH, expand=True, side=LEFT) self.treeview_plugin_list.column(PLUGIN_GUIDE["pluginName"]) self.treeview_plugin_list.heading(PLUGIN_GUIDE["pluginName"], text=PLUGIN_GUIDE["pluginName"]) # 设定插件列表滚动条 scrollbar_plugin_list = Scrollbar(frame_plugin_list) scrollbar_plugin_list.pack(fill="y", expand=True) self.treeview_plugin_list.config(yscrollcommand=scrollbar_plugin_list.set) scrollbar_plugin_list.config(command=self.treeview_plugin_list.yview) def __on_click_connect_event(self): """ 点击连接按钮事件 :return: 无 """ if not GlobalValues.is_connected: # 如果是要连接 # 存到全局使用变量 GlobalValues.conn_host = self.entry_host.get() GlobalValues.conn_port = self.entry_port.get() GlobalValues.conn_authkey = self.entry_authkey.get() try: # 转换为整型后保存 GlobalValues.conn_qq = int(self.entry_qq.get()) except ValueError: self.label_login_status_bar.config(text=LOGIN_STATUS_BAR_TEXT["wrongQQ"], fg=STATUS_BAR_COLOR["failed"]) return # 修改界面上的一些内容为不可修改 self.__set_login_tools_active(False) # 修改按钮内容 self.btn_connect.config(text=BTN_TEXT_CONN["disconnect"]) # 修改状态栏内容 self.label_login_status_bar.config(text=LOGIN_STATUS_BAR_TEXT["connecting"], fg=STATUS_BAR_COLOR["normal"]) # 调用连接 try: Conn.new_session_key() except ( requests.exceptions.InvalidURL, requests.exceptions.ConnectionError, ): # 连接错误 # 错误信息显示到状态栏 self.label_login_status_bar.config( text=LOGIN_STATUS_BAR_TEXT["connectFailed"], fg=STATUS_BAR_COLOR["failed"] ) # 修改文本框为可修改 self.__set_login_tools_active(True) self.btn_connect.config(text=BTN_TEXT_CONN["connect"]) return except WrongAuthkeyException: # 授权码错误 # 显示到状态栏 self.label_login_status_bar.config( text=LOGIN_STATUS_BAR_TEXT["wrongAuthkey"], fg=STATUS_BAR_COLOR["failed"] ) # 修改文本框为可修改 self.__set_login_tools_active(True) self.btn_connect.config(text=BTN_TEXT_CONN["connect"]) return except BotNotExistException: # bot不存在错误 self.label_login_status_bar.config( text=LOGIN_STATUS_BAR_TEXT["qqNotExist"], fg=STATUS_BAR_COLOR["failed"] ) # 修改文本框为可修改 self.__set_login_tools_active(True) self.btn_connect.config(text=BTN_TEXT_CONN["connect"]) return self.label_login_status_bar.config( text=LOGIN_STATUS_BAR_TEXT["connected"], fg=STATUS_BAR_COLOR["passed"] ) # 修改连接状态值 GlobalValues.is_connected = True # 修改上次连接键值对 ConfigOperation.modify_dict("lastConnection", { "host": GlobalValues.conn_host, "port": GlobalValues.conn_port, "authkey": GlobalValues.conn_authkey, "qq": GlobalValues.conn_qq }) # 修改文件中自动连接开关 ConfigOperation.modify_dict("autoConnect", self.auto_connect_var.get()) else: # 如果要断开连接 # 修改文本框为可修改 self.__set_login_tools_active(True) # 修改按钮名称 self.btn_connect.config(text=BTN_TEXT_CONN["connect"]) # 修改属性值 self.label_login_status_bar.config( text=LOGIN_STATUS_BAR_TEXT["disconnectSuccess"], fg=STATUS_BAR_COLOR["normal"] ) # 释放session Conn.release_session_key() # 修改连接状态值 GlobalValues.is_connected = False def __set_login_tools_active(self, active: bool): """ 修改界面上的一些内容为不可修改 :param active: bool,如果为False则禁用掉文本框,否则启用 :return: 无 """ if active: self.entry_host.config(state=ACTIVE) self.entry_port.config(state=ACTIVE) self.entry_authkey.config(state=ACTIVE) self.entry_qq.config(state=ACTIVE) self.checkbutton_auto_connect.config(state=ACTIVE) else: self.entry_host.config(state=DISABLED) self.entry_port.config(state=DISABLED) self.entry_authkey.config(state=DISABLED) self.entry_qq.config(state=DISABLED) self.checkbutton_auto_connect.config(state=DISABLED) def __on_close_root(self): """ 关闭窗口的事件 :return: 无 """ # 如果正在连接则释放连接 if GlobalValues.is_connected: Conn.release_session_key() # 杀掉root self.root.destroy() def __refresh(self): """ 用于刷新界面,在必要时调用 :return: 无 """ def refresh_login_list(): """ 刷新登录列表 :return: 无 """ # 删除目前表中的所有内容 self.treeview_login_list.delete(*self.treeview_login_list.get_children()) # 把登录列表内容添加到显示中 for one_record in LoginListOperation.get_list_from_file(): self.treeview_login_list.insert("", index=END, values=( one_record["host"], one_record["port"], one_record["authkey"], one_record["qq"] )) def refresh_op_list(): """ 刷新bot管理员qq列表 :return: 无 """ # 删除目前表中的所有内容 self.treeview_op_list.delete(*self.treeview_op_list.get_children()) # 把内容添加到显示中 for one_record in OpListOperation.get_list(): self.treeview_op_list.insert("", index=END, values=( one_record )) def refresh_config(): """ 刷新配置 :return: 无 """ # 重新获取config self.config_dict = ConfigOperation.get_dir_from_file() # 将文件中的内容显示到界面中 self.entry_command_head.delete(0, END) self.entry_command_head.insert(END, self.config_dict["commandHead"]) # 设置复选框默认勾选 self.debug_var.set(self.config_dict["debug"]) self.enable_var.set(self.config_dict["enable"]) # 将内容设置到全局变量 GlobalValues.command_head = self.config_dict["commandHead"] GlobalValues.debug_var = self.debug_var GlobalValues.enable_var = self.enable_var def refresh_plugin_list(): # 获取插件名称 plugin_names = PluginHandler.get_plugin_name_list() # 显示 self.treeview_plugin_list.delete(*self.treeview_plugin_list.get_children()) for name in plugin_names: self.treeview_plugin_list.insert("", index=END, values=( name )) # 调用刷新登录列表 refresh_login_list() # 调用刷新op列表 refresh_op_list() # 刷新config显示 refresh_config() # 刷新插件列表显示 refresh_plugin_list() def __on_click_add_to_login_list(self): """ 将填写内容添加到列表中 :return: 无 """ # 非空检测 if [ self.entry_host.get(), self.entry_port.get(), self.entry_authkey.get(), self.entry_qq.get() ] == [""] * 4: return # 调用添加登录项方法 LoginListOperation.add_to_list( self.entry_host.get(), self.entry_port.get(), self.entry_authkey.get(), self.entry_qq.get() ) # 刷新显示 self.__refresh() def __on_double_click_login_list_content(self): """ 双击登录列表项目时,自动填充到右侧 :return: 无 """ # 获取item的值 item_list = self.treeview_login_list.item(self.treeview_login_list.focus(), "values") # 获取需要的项目并设置 self.entry_host.delete(0, END) self.entry_host.insert(END, item_list[0]) self.entry_port.delete(0, END) self.entry_port.insert(END, item_list[1]) self.entry_authkey.delete(0, END) self.entry_authkey.insert(END, item_list[2]) self.entry_qq.delete(0, END) self.entry_qq.insert(END, item_list[3]) def __show_login_list_pop_up_menu(self, event): """ 显示右键菜单 :param event: 事件 :return: 无 """ def on_delete_event(item_id): """ 删除选项的事件 :return: 无 """ # 删除该项 LoginListOperation.remove_from_list(*self.treeview_login_list.item(item_id, "values")) self.treeview_login_list.delete(item_id) self.__refresh() # 获取选择对象 iid = self.treeview_login_list.identify_row(event.y) # 如果有选择,则弹出右键菜单 if iid: self.treeview_login_list.selection_set(iid) menu_pop_up = Menu(self.treeview_login_list, tearoff=False) menu_pop_up.add_command( label=POP_UP_MENU_DELETE_STR, command=lambda: on_delete_event(iid) ) menu_pop_up.post(event.x_root, event.y_root) def __on_click_refresh_friend_list_event(self): """ 点击刷新好友列表事件 :return: 无 """ try: # 如果未连接,则可能会抛出异常,此处直接弹出错误消息框 friend_list = Conn.get_friend_list() except: messagebox.showerror(message=REFRESH_ERROR_MSG) return # 删除列表内容 self.treeview_friend_list.delete(*self.treeview_friend_list.get_children()) # 解析friend_list for friend_block in friend_list: self.treeview_friend_list.insert("", index=END, values=( friend_block["id"], friend_block["nickname"], friend_block["remark"] )) def __on_click_refresh_group_list_event(self): """ 点击刷新群列表事件 :return: 无 """ try: # 如果未连接,则可能会抛出异常,此处直接弹出错误消息框 group_list = Conn.get_group_list() except: messagebox.showerror(message=REFRESH_ERROR_MSG) return # 删除列表内容 self.treeview_group_list.delete(*self.treeview_group_list.get_children()) # 解析group_list for group_block in group_list: self.treeview_group_list.insert("", index=END, values=( group_block["id"], group_block["name"], group_block["permission"] )) def __on_click_send_friend_message(self): """ 点击发送消息给好友按钮 :return: 无 """ # 获取到选中好友的值列表 value_list = self.treeview_friend_list.item(self.treeview_friend_list.focus(), "values") try: # 获取qq并发送消息 qq = value_list[0] message_chain = MessageChain() text = self.text_friend_send.get(1.0, END) if text == "\n": return message_chain.add_plain_text(text) Conn.send_friend_message(qq, message_chain) self.text_friend_send.delete(1.0, END) except: messagebox.showerror(message=SEND_ERROR_MSG) return def __on_click_send_group_message(self): """ 点击发送消息给群按钮 :return: 无 """ # 获取到选中群的值列表 value_list = self.treeview_group_list.item(self.treeview_group_list.focus(), "values") try: # 获取qq并发送消息 qq = value_list[0] message_chain = MessageChain() text = self.text_group_send.get(1.0, END) if text == "\n": return message_chain.add_plain_text(text) Conn.send_group_message(qq, message_chain) self.text_group_send.delete(1.0, END) except: messagebox.showerror(message=SEND_ERROR_MSG) return def __on_click_add_op(self): """ 点击添加op按钮事件 :return: 无 """ content = self.entry_add_op.get() # 如果添加op的文本框中没有东西,则不添加 if content == "": return # 如果转换数字出错则不添加 try: op_qq = int(content) except ValueError: return # 添加到op列表中 OpListOperation.add_to_list(op_qq) # 刷新显示 self.__refresh() def __show_op_list_pop_up_menu(self, event): """ op列表右键菜单 :return: 无 """ def on_delete_event(): """ 删除选项的事件 :return: 无 """ # 删除该项 # 注意此处的强转,由于能够保证显示出来的内容一定只含有数字,故可以直接转换 OpListOperation.remove_from_list(int(self.treeview_op_list.item(op_qq, "values")[0])) self.treeview_op_list.delete(op_qq) self.__refresh() # 获取选择对象 op_qq = self.treeview_op_list.identify_row(event.y) # 如果有选择,则弹出右键菜单 if op_qq: menu_pop_up = Menu(self.treeview_op_list, tearoff=False) self.treeview_op_list.selection_set(op_qq) menu_pop_up.add_command( label=POP_UP_MENU_DELETE_STR, command=lambda: on_delete_event() ) menu_pop_up.post(event.x_root, event.y_root) def __on_click_save_config(self): """ 点击保存配置事件 :return: 无 """ content = self.entry_command_head.get() # 如果为空,则不存入,但是刷新 # 这样是为了保证点击后会显示原来的设置 if content == "": self.__refresh() return ConfigOperation.modify_dict("commandHead", content) ConfigOperation.modify_dict("debug", self.debug_var.get()) ConfigOperation.modify_dict("enable", self.enable_var.get()) # 刷新 self.__refresh() # 弹出对话框 messagebox.showinfo(message=MANAGE_GUIDE["successSaveCommandHeadMsg"]) def __auto_connect(self): if self.config_dict["autoConnect"]: self.__on_click_connect_event()
class Example(Frame): def __init__(self, parent): Frame.__init__(self, parent) self.parent = parent self.initUI() def initUI(self): self.parent.title("") #self.style = Style() #self.style.theme_use("clam") #self.pack(fill=BOTH, expand = 1) self.labelU = Label(self, text="U:") self.labelP = Label(self, text="P:") self.mailrecipient = 'GoldenSights' self.entryUsername = Entry(self) self.entryUsername.focus_set() self.entryUsername.bind('<Return>', lambda event: self.entryPassword.focus_set()) self.entryPassword = Entry(self) self.entryPassword.config(show='•') self.entryPassword.bind('<Return>', lambda event: self.login(self.entryUsername.get(), self.entryPassword.get())) self.newbutton = Button(self, text="Login", command= lambda: self.login(self.entryUsername.get(), self.entryPassword.get())) self.newbutton.bind('<Return>', lambda event: self.login(self.entryUsername.get(), self.entryPassword.get())) self.newbutton.config(width=6) self.quitbutton = Button(self, text="Quit", command= lambda: self.quit()) self.quitbutton.config(width=6) self.labelU.grid(row=0, column=0,padx=0) self.entryUsername.grid(row=0, column=1) self.labelP.grid(row=1, column=0) self.entryPassword.grid(row=1, column=1, pady=4) self.newbutton.grid(row=2, column=1) self.quitbutton.grid(row=3, column=1, pady=4) self.labelErrorPointer = Label(self, text="◀") self.indicatorGreen = PhotoImage(file="indicatorGreen.gif") self.indicatorRed = PhotoImage(file="indicatorRed.gif") self.indicatorBlue = PhotoImage(file="indicatorBlue.gif") self.indicatorBlack = PhotoImage(file="indicatorBlack.gif") sw = self.parent.winfo_screenwidth() sh = self.parent.winfo_screenheight() w=400 h=480 x = (sw - w) / 2 y = (sh - h) / 2 self.parent.geometry('%dx%d+%d+%d' % (w, h, x, y-50)) def login(self, username, password): print('U: ' + username) self.username = username if username == '' or not all(char in string.ascii_letters+string.digits+'_-' for char in username): print('Please enter a username') self.entryUsername.focus_set() self.labelErrorPointer.grid(row=0, column=2) elif password == '': print('Please enter a password') self.entryPassword.focus_set() self.labelErrorPointer.grid(row=1, column=2) else: self.labelErrorPointer.grid_forget() print('Attempting login for ' + username) try: self.USERAGENT = username + ' practices Tkinter+PRAW mixing with utility by /u/GoldenSights.' self.r = praw.Reddit(self.USERAGENT) #self.r.login(username, password) print('Success') self.labelU.grid_forget() self.labelP.grid_forget() self.entryUsername.grid_forget() self.entryPassword.grid_forget() self.newbutton.grid_forget() self.quitbutton.grid_forget() self.usernamelabel = Label(self, text=username + ', Sending to /u/' + self.mailrecipient) self.usernamelabel.grid(row=0, column=0, columnspan=8) self.quitbutton.grid(row=900, column=0) self.labellist = [] self.entrylist = [] self.verifylist = [] self.misclist = [] self.optionDiscuss = "Discussion Flair + Crossposting" self.optionRegister = "Register a new Candidate" self.prevmode = self.optionDiscuss self.curmode = self.optionDiscuss self.optionvar = tkinter.StringVar(self) self.optionvar.trace("w",self.permaloop) self.optionvar.set(self.optionDiscuss) self.option = OptionMenu(self, self.optionvar, self.optionDiscuss, self.optionRegister, "three", "four") self.newbutton.unbind("<Return>") self.entryUsername.unbind("<Return>") self.entryPassword.unbind("<Return>") self.option.grid(row=1,column=0,columnspan=8,pady=8) self.updategui(True) except praw.errors.InvalidUserPass: pass print('Invalid username or password') self.entryPassword.delete(0,200) self.labelErrorPointer.grid(row=1, column=2) def permaloop(self, *args): self.curmode = self.optionvar.get() print('Was: ' + self.prevmode + ' | Now: ' + self.curmode) if self.curmode != self.prevmode: self.prevmode = self.curmode self.updategui(True) def updategui(self, *args): if args[0] == True: print('Cleaning GUI') for item in self.labellist: item.grid_forget() for item in self.entrylist: item.grid_forget() for item in self.verifylist: item.grid_forget() for item in self.misclist: item.grid_forget() self.labellist = [] self.entrylist = [] self.verifylist = [] self.misclist = [] if self.curmode == self.optionDiscuss: self.newrowindex = 4 self.labelPermalink = Label(self, text="Thread Permalink:") self.entryPermalink = Entry(self) self.rowconfigure(2,weight=2) self.labelPermalink.grid(row=2,column=0) self.entryPermalink.grid(row=2,column=1) self.labelcrossposting = Label(self,text="Crosspost to:") self.labelcrossposting.grid(row=3,column=0,columnspan=2,sticky="w") for m in range(5): self.redditlabel = Label(self,text="/r/") self.redditlabel.grid(row=self.newrowindex,column=0, sticky="e") self.labellist.append(self.redditlabel) self.redditentry = Entry(self) self.redditentry.grid(row=self.newrowindex,column=1) self.entrylist.append(self.redditentry) self.newrowindex +=1 self.morerowbutton = Button(self,text="+row",command=lambda: self.morerows('/r/', 0, 1, 20)) self.morerowbutton.grid(row=898,column=0,columnspan=2) self.verifybutton = Button(self,text="Verify",command= lambda: self.updategui(False)) self.verifybutton.grid(row=899,column=0,columnspan=2) self.newrowindex += 2 self.misclist.append(self.labelPermalink) self.misclist.append(self.labelcrossposting) self.misclist.append(self.entryPermalink) self.misclist.append(self.morerowbutton) self.misclist.append(self.verifybutton) if self.curmode == self.optionRegister: self.newrowindex = 6 self.labelCanUsername = Label(self, text="Candidate's Username: /u/") self.entryCanUsername = Entry(self) self.labelCanRealname = Label(self, text="Candidate's Realname:") self.entryCanRealname = Entry(self) self.labelCanFlair = Label(self, text="Candidate's Flair:") self.entryCanFlair = Entry(self) self.entryMo = Spinbox(self, width=9, values=('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December')) self.entryDa = Spinbox(self, width=2, from_=1, to=31) self.entryYr = Spinbox(self, width=4, from_=2014, to=2500) self.labelHH = Label(self, text="Schedule time UTC:") self.entryHH = Spinbox(self, from_=0, to=23, width=2) self.entryMM = Spinbox(self, from_=0, to=59, width=2) self.entryYr.delete(0,'end') self.entryYr.insert(0,2014) self.morerowbutton = Button(self,text="+question",command=lambda: self.morerows('Q:', 0, 1, 25)) self.morerowbutton.grid(row=898,column=0,columnspan=8) self.verifybutton = Button(self,text="Verify",command= lambda: self.updategui(False)) self.verifybutton.grid(row=899,column=0,columnspan=8) self.misclist.append(self.labelCanUsername) self.misclist.append(self.labelCanRealname) self.misclist.append(self.entryCanUsername) self.misclist.append(self.entryCanRealname) self.misclist.append(self.labelHH) self.misclist.append(self.entryHH) self.misclist.append(self.entryMM) self.misclist.append(self.entryMo) self.misclist.append(self.entryDa) self.misclist.append(self.entryYr) self.labelCanUsername.grid(row=2, column=0, sticky="e") self.labelCanRealname.grid(row=3, column=0, sticky="e") self.entryCanUsername.grid(row=2, column=1, columnspan=3) self.entryCanRealname.grid(row=3, column=1, columnspan=3) self.entryMo.grid(row=4, column=1,sticky="e") self.entryDa.grid(row=4, column=2) self.entryYr.grid(row=4, column=3) self.labelHH.grid(row=4, column=0, sticky="se", pady=5) self.entryHH.grid(row=5, column=1, sticky="e") self.entryMM.grid(row=5, column=2, sticky="w") else: if self.curmode == self.optionDiscuss: verifies = [] i = self.entryPermalink.get() if len(i) == 6: pid = i else: if 'www.reddit.com/r/' in i and '/comments/' in i: pid = i.split('/comments/')[1].split('/')[0] if 'http://redd.it/' in i: pid = i.split('redd.it/')[1] for flag in self.verifylist: flag.grid_forget() self.verifylist.remove(flag) try: print('Fetching Submission ' + pid) self.r.get_info(thing_id="t3_" + pid).title + 'Check' self.redditlabel = Label(self, image=self.indicatorGreen) self.redditlabel.grid(row=2,column=2) self.verifylist.append(self.redditlabel) verifies.append(True) print('\tSuccess') except: print('Failed. Make sure to include the http://. Copy and paste straight from your browser for best result') self.redditlabel = Label(self, image=self.indicatorRed) self.redditlabel.grid(row=2,column=2) self.verifylist.append(self.redditlabel) verifies.append(False) for entry in self.entrylist: i = entry.get() if i != '': print('Fetching /r/' + i) if all(char in string.ascii_letters+string.digits+'_-' for char in i): try: sub = self.r.get_subreddit(i,fetch=True) self.redditlabel = Label(self, image=self.indicatorGreen) self.redditlabel.grid(row=entry.grid_info()['row'],column=2) self.verifylist.append(self.redditlabel) verifies.append(True) print('\tSuccess') except: self.redditlabel = Label(self, image=self.indicatorRed) self.redditlabel.grid(row=entry.grid_info()['row'],column=2) self.verifylist.append(self.redditlabel) verifies.append(False) print('\tFailed') time.sleep(2) else: self.redditlabel = Label(self, image=self.indicatorRed) self.redditlabel.grid(row=entry.grid_info()['row'],column=2) self.verifylist.append(self.redditlabel) verifies.append(False) print('\tFailed') print(verifies) if self.curmode == self.optionRegister: verifies = [] u=self.entryCanUsername.get() print('Fetching /u/' + u) if not all(char in string.ascii_letters+string.digits+'_-' for char in u): self.redditlabel = Label(self, image=self.indicatorRed) self.redditlabel.grid(row=2, column=4) self.verifylist.append(self.redditlabel) verifies.append(False) print('\tBad characterage') else: try: u = self.r.get_redditor(u) print(u) self.redditlabel = Label(self, image=self.indicatorGreen) self.redditlabel.grid(row=2,column=4) self.verifylist.append(self.redditlabel) verifies.append(True) print('\tSuccess') except: self.redditlabel = Label(self, image=self.indicatorRed) self.redditlabel.grid(row=2,column=4) self.verifylist.append(self.redditlabel) verifies.append(False) print('\tFailed') try: print('Checking Time') t = self.entryMo.get() + ' ' + self.entryDa.get() + ' ' + self.entryYr.get() + ' ' + self.entryHH.get() + ':' + self.entryMM.get() plandate = datetime.datetime.strptime(t, "%B %d %Y %H:%M") plandate = datetime.datetime.utcfromtimestamp(plandate.timestamp()) print('\t' + str(plandate.timestamp())) self.redditlabel = Label(self, image=self.indicatorGreen) self.redditlabel.grid(row=5,column=3) self.verifylist.append(self.redditlabel) verifies.append(True) except: print('\tFailed') self.redditlabel = Label(self, image=self.indicatorRed) self.redditlabel.grid(row=5,column=3) self.verifylist.append(self.redditlabel) verifies.append(False) print(verifies) def morerows(self, label, columnm, columnn, limit, *args): self.redditlabel = Label(self,text=label) self.redditlabel.grid(row=self.newrowindex,column=columnm, sticky="e") self.labellist.append(self.redditlabel) self.redditentry = Entry(self) self.redditentry.grid(row=self.newrowindex,column=columnn, columnspan=8) self.entrylist.append(self.redditentry) self.newrowindex += 1 if self.newrowindex >= limit: self.morerowbutton.grid_forget() print(self.newrowindex)
class App_test(object): def __init__(self, master, fuc): self.win = master self.win.title('12306火车票查询系统V2.6') curWidth = self.win.winfo_width() curHeight = self.win.winfo_height() scnWidth, scnHeight = self.win.maxsize() tmpcnf = '1130x600+500+300' # % ((scnWidth - curWidth) / 2, (scnHeight - curHeight) / 2) self.win.geometry(tmpcnf) self.creat_res() self.add_train_info() self.add_check_button() self.res_config(fuc) self.set_combox_defaut() self.train_message = {} # self.get_train_args() # self.win.mainloop() def creat_res(self): self.v = IntVar() # 车票查询 self.v.set(True) self.temp = StringVar() # 开始站 self.temp2 = StringVar() # 目的站 self.start_mon = StringVar() # 出发月 self.start_day = StringVar() # 出发日 self.start_year = StringVar() # 出啊年 self.La_start_end = Label(self.win, text="请输入出发地和目的地", fg="blue") self.E_startstation = Entry(self.win, textvariable=self.temp) self.E_endstation = Entry(self.win, textvariable=self.temp2) self.La_startstation = Label(self.win, text="出发站:") self.La_endstation = Label(self.win, text="目的站:") self.La_time = Label(self.win, text="请选择出发时间-年-月-日", fg="blue") self.B_search = Button(self.win, text="搜索") self.R_site = Radiobutton(self.win, text="车票查询", variable=self.v, value=True) self.R_price = Radiobutton(self.win, text="票价查询", variable=self.v, value=False) self.B_buy_tick = Button(self.win, text="购票") self.C_year = Combobox(self.win, textvariable=self.start_year) self.La_s = Label(self.win, text="--") self.C_mon = Combobox(self.win, textvariable=self.start_mon) self.La_s1 = Label(self.win, text="--") self.C_day = Combobox(self.win, textvariable=self.start_day) # 滚动条 self.S_move = Scrollbar(self.win) self.La_start_end.place(x=10, y=10, width=150, height=30) self.E_startstation.place(x=70, y=50, width=145, height=30) self.E_startstation.insert(10, "杭州东") self.E_endstation.place(x=70, y=100, width=145, height=30) self.E_endstation.insert(10, "南京南") self.La_startstation.place(x=10, y=50, width=50, height=30) self.La_endstation.place(x=10, y=100, width=50, height=30) self.La_time.place(x=0, y=140, width=190, height=30) self.C_year.place(x=10, y=180, width=70, height=30) self.La_s.place(x=80, y=180, width=20, height=30) self.C_mon.place(x=100, y=180, width=50, height=30) self.La_s1.place(x=150, y=180, width=20, height=30) self.C_day.place(x=170, y=180, width=50, height=30) self.B_search.place(x=10, y=220, width=80, height=40) self.S_move.place(x=1100, y=40, width=30, height=550) self.B_buy_tick.place(x=10, y=310, width=80, height=40) self.R_site.place(x=10, y=270, width=90, height=30) self.R_price.place(x=100, y=270, width=90, height=30) def res_config(self, fuc): localTime = time.localtime(int(time.time())) # 获取今年的年份 startTime = int(time.strftime("%Y", localTime)) # 2018 self.C_year.config( values=[x for x in range(startTime, startTime + 10)]) self.C_mon.config(values=["{:02d}".format(x) for x in range(1, 13)]) # 时间格式是2018-01-01 self.C_day.config(values=["{:02d}".format(x) for x in range(1, 32)]) self.B_search.config(command=fuc) self.S_move.config(command=self.tree.yview) self.tree.config(yscrollcommand=self.S_move.set) def add_train_info(self): lis_train = ["C" + str(x) for x in range(0, 15)] tuple_train = tuple(lis_train) self.tree = Treeview(self.win, columns=tuple_train, height=30, show="headings") self.tree.place(x=228, y=40, width=870, height=550) train_info = [ ' 车次 ', ' 出发/到达站', '出发/到达时间', '历时 ', '商/特座', '一等座', '二等座', '高软', '软卧', '动卧', '硬卧', '软座', '硬座', '无座', '其他' ] for i in range(0, len(lis_train)): self.tree.column(lis_train[i], width=len(train_info[i]) * 11, anchor='center') self.tree.heading(lis_train[i], text=train_info[i]) def add_check_button(self): self.v1 = IntVar() self.v2 = IntVar() self.v3 = IntVar() self.v4 = IntVar() self.v5 = IntVar() self.v6 = IntVar() self.v7 = IntVar() self.v1.set("T") self.Check_total = Checkbutton(self.win, text="全部车次", variable=self.v1, onvalue='T') self.Check_total.place(x=228, y=7, width=90, height=30) self.Check_total = Checkbutton(self.win, text="G-高铁", variable=self.v2, onvalue='T') self.Check_total.place(x=318, y=7, width=70, height=30) self.Check_total = Checkbutton(self.win, text="D-动车", variable=self.v3, onvalue='T') self.Check_total.place(x=398, y=7, width=70, height=30) self.Check_total = Checkbutton(self.win, text="Z-直达", variable=self.v4, onvalue='T') self.Check_total.place(x=478, y=7, width=70, height=30) self.Check_total = Checkbutton(self.win, text="T-特快", variable=self.v5, onvalue='T') self.Check_total.place(x=558, y=7, width=70, height=30) self.Check_total = Checkbutton(self.win, text="K-快速", variable=self.v6, onvalue='T') self.Check_total.place(x=638, y=7, width=70, height=30) self.Check_total = Checkbutton(self.win, text="其他", variable=self.v7, onvalue='T') self.Check_total.place(x=718, y=7, width=70, height=30) # 设置下拉框默认值 def set_combox_defaut(self): localTime = time.localtime(int(time.time())) mon = int(time.strftime("%m", localTime)) day = int(time.strftime("%d", localTime)) self.C_year.current(0) self.C_mon.current(mon - 1) self.C_day.current(day - 1)
class DialogPackageManager(Toplevel): def __init__(self, mainWin, packageNamesWithNewerFileDates): super(DialogPackageManager, self).__init__(mainWin.parent) self.ENABLE = _("Enable") self.DISABLE = _("Disable") self.parent = mainWin.parent self.cntlr = mainWin # copy plugins for temporary display self.packagesConfig = PackageManager.packagesConfig self.packagesConfigChanged = False self.packageNamesWithNewerFileDates = packageNamesWithNewerFileDates parentGeometry = re.match("(\d+)x(\d+)[+]?([-]?\d+)[+]?([-]?\d+)", self.parent.geometry()) dialogX = int(parentGeometry.group(3)) dialogY = int(parentGeometry.group(4)) self.title(_("Taxonomy Packages Manager")) frame = Frame(self) # left button frame buttonFrame = Frame(frame, width=40) buttonFrame.columnconfigure(0, weight=1) addLabel = Label(buttonFrame, text=_("Find taxonomy packages:"), wraplength=64, justify="center") addLocalButton = Button(buttonFrame, text=_("Locally"), command=self.findLocally) ToolTip(addLocalButton, text=_("File chooser allows selecting taxonomy packages to add (or reload), from the local file system. " "Select either a taxonomy package zip file, or a taxonomy manifest (.taxonomyPackage.xml) within an unzipped taxonomy package. "), wraplength=240) addWebButton = Button(buttonFrame, text=_("On Web"), command=self.findOnWeb) ToolTip(addWebButton, text=_("Dialog to enter URL full path to load (or reload) package, from the web or local file system. " "URL may be either a taxonomy package zip file, or a taxonomy manifest (.taxonomyPackage.xml) within an unzipped taxonomy package. "), wraplength=240) manifestNameButton = Button(buttonFrame, text=_("Manifest"), command=self.manifestName) ToolTip(manifestNameButton, text=_("Provide non-standard archive manifest file name pattern (e.g., *taxonomyPackage.xml). " "Uses unix file name pattern matching. " "Multiple manifest files are supported in archive (such as oasis catalogs). " "(Replaces search for either .taxonomyPackage.xml or catalog.xml). "), wraplength=240) self.manifestNamePattern = "" addLabel.grid(row=0, column=0, pady=4) addLocalButton.grid(row=1, column=0, pady=4) addWebButton.grid(row=2, column=0, pady=4) manifestNameButton.grid(row=3, column=0, pady=4) buttonFrame.grid(row=0, column=0, rowspan=3, sticky=(N, S, W), padx=3, pady=3) # right tree frame (packages already known to arelle) packagesFrame = Frame(frame, width=700) vScrollbar = Scrollbar(packagesFrame, orient=VERTICAL) hScrollbar = Scrollbar(packagesFrame, orient=HORIZONTAL) self.packagesView = Treeview(packagesFrame, xscrollcommand=hScrollbar.set, yscrollcommand=vScrollbar.set, height=7) self.packagesView.grid(row=0, column=0, sticky=(N, S, E, W)) self.packagesView.bind('<<TreeviewSelect>>', self.packageSelect) hScrollbar["command"] = self.packagesView.xview hScrollbar.grid(row=1, column=0, sticky=(E,W)) vScrollbar["command"] = self.packagesView.yview vScrollbar.grid(row=0, column=1, sticky=(N,S)) packagesFrame.columnconfigure(0, weight=1) packagesFrame.rowconfigure(0, weight=1) packagesFrame.grid(row=0, column=1, columnspan=4, sticky=(N, S, E, W), padx=3, pady=3) self.packagesView.focus_set() self.packagesView.column("#0", width=120, anchor="w") self.packagesView.heading("#0", text=_("Name")) self.packagesView["columns"] = ("ver", "status", "date", "update", "descr") self.packagesView.column("ver", width=150, anchor="w", stretch=False) self.packagesView.heading("ver", text=_("Version")) self.packagesView.column("status", width=50, anchor="w", stretch=False) self.packagesView.heading("status", text=_("Status")) self.packagesView.column("date", width=170, anchor="w", stretch=False) self.packagesView.heading("date", text=_("File Date")) self.packagesView.column("update", width=50, anchor="w", stretch=False) self.packagesView.heading("update", text=_("Update")) self.packagesView.column("descr", width=200, anchor="w", stretch=False) self.packagesView.heading("descr", text=_("Description")) remappingsFrame = Frame(frame) vScrollbar = Scrollbar(remappingsFrame, orient=VERTICAL) hScrollbar = Scrollbar(remappingsFrame, orient=HORIZONTAL) self.remappingsView = Treeview(remappingsFrame, xscrollcommand=hScrollbar.set, yscrollcommand=vScrollbar.set, height=5) self.remappingsView.grid(row=0, column=0, sticky=(N, S, E, W)) hScrollbar["command"] = self.remappingsView.xview hScrollbar.grid(row=1, column=0, sticky=(E,W)) vScrollbar["command"] = self.remappingsView.yview vScrollbar.grid(row=0, column=1, sticky=(N,S)) remappingsFrame.columnconfigure(0, weight=1) remappingsFrame.rowconfigure(0, weight=1) remappingsFrame.grid(row=1, column=1, columnspan=4, sticky=(N, S, E, W), padx=3, pady=3) self.remappingsView.focus_set() self.remappingsView.column("#0", width=200, anchor="w") self.remappingsView.heading("#0", text=_("Prefix")) self.remappingsView["columns"] = ("remapping") self.remappingsView.column("remapping", width=500, anchor="w", stretch=False) self.remappingsView.heading("remapping", text=_("Remapping")) # bottom frame package info details packageInfoFrame = Frame(frame, width=700) packageInfoFrame.columnconfigure(1, weight=1) self.packageNameLabel = Label(packageInfoFrame, wraplength=600, justify="left", font=font.Font(family='Helvetica', size=12, weight='bold')) self.packageNameLabel.grid(row=0, column=0, columnspan=6, sticky=W) self.packageVersionHdr = Label(packageInfoFrame, text=_("version:"), state=DISABLED) self.packageVersionHdr.grid(row=1, column=0, sticky=W) self.packageVersionLabel = Label(packageInfoFrame, wraplength=600, justify="left") self.packageVersionLabel.grid(row=1, column=1, columnspan=5, sticky=W) self.packageDescrHdr = Label(packageInfoFrame, text=_("description:"), state=DISABLED) self.packageDescrHdr.grid(row=2, column=0, sticky=W) self.packageDescrLabel = Label(packageInfoFrame, wraplength=600, justify="left") self.packageDescrLabel.grid(row=2, column=1, columnspan=5, sticky=W) self.packagePrefixesHdr = Label(packageInfoFrame, text=_("prefixes:"), state=DISABLED) self.packagePrefixesHdr.grid(row=3, column=0, sticky=W) self.packagePrefixesLabel = Label(packageInfoFrame, wraplength=600, justify="left") self.packagePrefixesLabel.grid(row=3, column=1, columnspan=5, sticky=W) ToolTip(self.packagePrefixesLabel, text=_("List of prefixes that this package remaps."), wraplength=240) self.packageUrlHdr = Label(packageInfoFrame, text=_("URL:"), state=DISABLED) self.packageUrlHdr.grid(row=4, column=0, sticky=W) self.packageUrlLabel = Label(packageInfoFrame, wraplength=600, justify="left") self.packageUrlLabel.grid(row=4, column=1, columnspan=5, sticky=W) ToolTip(self.packageUrlLabel, text=_("URL of taxonomy package (local file path or web loaded file)."), wraplength=240) self.packageDateHdr = Label(packageInfoFrame, text=_("date:"), state=DISABLED) self.packageDateHdr.grid(row=5, column=0, sticky=W) self.packageDateLabel = Label(packageInfoFrame, wraplength=600, justify="left") self.packageDateLabel.grid(row=5, column=1, columnspan=5, sticky=W) ToolTip(self.packageDateLabel, text=_("Date of currently loaded package file (with parenthetical node when an update is available)."), wraplength=240) self.packageEnableButton = Button(packageInfoFrame, text=self.ENABLE, state=DISABLED, command=self.packageEnable) ToolTip(self.packageEnableButton, text=_("Enable/disable package."), wraplength=240) self.packageEnableButton.grid(row=6, column=1, sticky=E) self.packageMoveUpButton = Button(packageInfoFrame, text=_("Move Up"), state=DISABLED, command=self.packageMoveUp) ToolTip(self.packageMoveUpButton, text=_("Move package up (above other remappings)."), wraplength=240) self.packageMoveUpButton.grid(row=6, column=2, sticky=E) self.packageMoveDownButton = Button(packageInfoFrame, text=_("Move Down"), state=DISABLED, command=self.packageMoveDown) ToolTip(self.packageMoveDownButton, text=_("Move package down (below other remappings)."), wraplength=240) self.packageMoveDownButton.grid(row=6, column=3, sticky=E) self.packageReloadButton = Button(packageInfoFrame, text=_("Reload"), state=DISABLED, command=self.packageReload) ToolTip(self.packageReloadButton, text=_("Reload/update package."), wraplength=240) self.packageReloadButton.grid(row=6, column=4, sticky=E) self.packageRemoveButton = Button(packageInfoFrame, text=_("Remove"), state=DISABLED, command=self.packageRemove) ToolTip(self.packageRemoveButton, text=_("Remove package from packages table (does not erase the package file)."), wraplength=240) self.packageRemoveButton.grid(row=6, column=5, sticky=E) packageInfoFrame.grid(row=2, column=0, columnspan=5, sticky=(N, S, E, W), padx=3, pady=3) packageInfoFrame.config(borderwidth=4, relief="groove") okButton = Button(frame, text=_("Close"), command=self.ok) ToolTip(okButton, text=_("Accept and changes (if any) and close dialog."), wraplength=240) cancelButton = Button(frame, text=_("Cancel"), command=self.close) ToolTip(cancelButton, text=_("Cancel changes (if any) and close dialog."), wraplength=240) okButton.grid(row=3, column=3, sticky=(S,E), pady=3) cancelButton.grid(row=3, column=4, sticky=(S,E), pady=3, padx=3) self.loadTreeViews() self.geometry("+{0}+{1}".format(dialogX+50,dialogY+100)) frame.grid(row=0, column=0, sticky=(N,S,E,W)) frame.columnconfigure(0, weight=0) frame.columnconfigure(1, weight=1) frame.rowconfigure(0, weight=1) window = self.winfo_toplevel() window.columnconfigure(0, weight=1) window.rowconfigure(0, weight=1) self.bind("<Return>", self.ok) self.bind("<Escape>", self.close) self.protocol("WM_DELETE_WINDOW", self.close) self.grab_set() self.wait_window(self) def loadTreeViews(self): self.selectedModule = None # clear previous treeview entries for previousNode in self.packagesView.get_children(""): self.packagesView.delete(previousNode) for i, packageInfo in enumerate(self.packagesConfig.get("packages", [])): name = packageInfo.get("name", "package{}".format(i)) node = self.packagesView.insert("", "end", "_{}".format(i), text=name) self.packagesView.set(node, "ver", packageInfo.get("version")) self.packagesView.set(node, "status", packageInfo.get("status")) self.packagesView.set(node, "date", packageInfo.get("fileDate")) if name in self.packageNamesWithNewerFileDates: self.packagesView.set(node, "update", _("available")) self.packagesView.set(node, "descr", packageInfo.get("description")) # clear previous treeview entries for previousNode in self.remappingsView.get_children(""): self.remappingsView.delete(previousNode) for i, remappingItem in enumerate(sorted(self.packagesConfig.get("remappings", {}).items())): prefix, remapping = remappingItem node = self.remappingsView.insert("", "end", prefix, text=prefix) self.remappingsView.set(node, "remapping", remapping) self.packageSelect() # clear out prior selection def ok(self, event=None): if self.packagesConfigChanged: PackageManager.packagesConfig = self.packagesConfig PackageManager.packagesConfigChanged = True self.cntlr.onPackageEnablementChanged() self.close() def close(self, event=None): self.parent.focus_set() self.destroy() def packageSelect(self, *args): node = (self.packagesView.selection() or (None,))[0] try: nodeIndex = int(node[1:]) except (ValueError, TypeError): nodeIndex = -1 if 0 <= nodeIndex < len(self.packagesConfig["packages"]): packageInfo = self.packagesConfig["packages"][nodeIndex] self.selectedPackageIndex = nodeIndex name = packageInfo["name"] self.packageNameLabel.config(text=name) self.packageVersionHdr.config(state=ACTIVE) self.packageVersionLabel.config(text=packageInfo["version"]) self.packageDescrHdr.config(state=ACTIVE) self.packageDescrLabel.config(text=packageInfo["description"]) self.packagePrefixesHdr.config(state=ACTIVE) self.packagePrefixesLabel.config(text=', '.join(packageInfo["remappings"].keys())) self.packageUrlHdr.config(state=ACTIVE) self.packageUrlLabel.config(text=packageInfo["URL"]) self.packageDateHdr.config(state=ACTIVE) self.packageDateLabel.config(text=packageInfo["fileDate"] + " " + (_("(an update is available)") if name in self.packageNamesWithNewerFileDates else "")) self.packageEnableButton.config(state=ACTIVE, text={"enabled":self.DISABLE, "disabled":self.ENABLE}[packageInfo["status"]]) self.packageMoveUpButton.config(state=ACTIVE if 0 < nodeIndex else DISABLED) self.packageMoveDownButton.config(state=ACTIVE if nodeIndex < (len(self.packagesConfig["packages"]) - 1) else DISABLED) self.packageReloadButton.config(state=ACTIVE) self.packageRemoveButton.config(state=ACTIVE) else: self.selectedPackageIndex = -1 self.packageNameLabel.config(text="") self.packageVersionHdr.config(state=DISABLED) self.packageVersionLabel.config(text="") self.packageDescrHdr.config(state=DISABLED) self.packageDescrLabel.config(text="") self.packagePrefixesHdr.config(state=DISABLED) self.packagePrefixesLabel.config(text="") self.packageUrlHdr.config(state=DISABLED) self.packageUrlLabel.config(text="") self.packageDateHdr.config(state=DISABLED) self.packageDateLabel.config(text="") self.packageEnableButton.config(state=DISABLED, text=self.ENABLE) self.packageMoveUpButton.config(state=DISABLED) self.packageMoveDownButton.config(state=DISABLED) self.packageReloadButton.config(state=DISABLED) self.packageRemoveButton.config(state=DISABLED) def findLocally(self): initialdir = self.cntlr.pluginDir # default plugin directory if not self.cntlr.isMac: # can't navigate within app easily, always start in default directory initialdir = self.cntlr.config.setdefault("packageOpenDir", initialdir) filename = self.cntlr.uiFileDialog("open", parent=self, title=_("Choose taxonomy package file"), initialdir=initialdir, filetypes=[(_("Taxonomy package files (*.zip)"), "*.zip"), (_("Manifest (*.taxonomyPackage.xml)"), "*.taxonomyPackage.xml"), (_("Oasis Catalog (*catalog.xml)"), "*catalog.xml")], defaultextension=".zip") if filename: # check if a package is selected (any file in a directory containing an __init__.py self.cntlr.config["packageOpenDir"] = os.path.dirname(filename) packageInfo = PackageManager.packageInfo(filename, packageManifestName=self.manifestNamePattern) self.loadFoundPackageInfo(packageInfo, filename) def findOnWeb(self): url = DialogURL.askURL(self) if url: # url is the in-cache or local file packageInfo = PackageManager.packageInfo(url, packageManifestName=self.manifestNamePattern) self.cntlr.showStatus("") # clear web loading status self.loadFoundPackageInfo(packageInfo, url) def manifestName(self): self.manifestNamePattern = simpledialog.askstring(_("Archive manifest file name pattern"), _("Provide non-standard archive manifest file name pattern (e.g., *taxonomyPackage.xml). \n" "Uses unix file name pattern matching. \n" "Multiple manifest files are supported in archive (such as oasis catalogs). \n" "(If blank, search for either .taxonomyPackage.xml or catalog.xml). "), initialvalue=self.manifestNamePattern, parent=self) def loadFoundPackageInfo(self, packageInfo, url): if packageInfo and packageInfo.get("name"): self.addPackageInfo(packageInfo) self.loadTreeViews() else: messagebox.showwarning(_("Package is not itself a taxonomy package. "), _("File does not itself contain a manifest file: \n\n{0}\n\n " "If opening an archive file, the manifest file search pattern currently is \"\", please press \"Manifest\" to change manifest file name pattern, e.g.,, \"*.taxonomyPackage.xml\", if needed. ") .format(url), parent=self) def removePackageInfo(self, name, version): # find package entry packagesList = self.packagesConfig["packages"] j = -1 for i, packageInfo in enumerate(packagesList): if packageInfo['name'] == name and packageInfo['version'] == version: j = i break if 0 <= j < len(packagesList): del self.packagesConfig["packages"][i] self.packagesConfigChanged = True def addPackageInfo(self, packageInfo): name = packageInfo["name"] version = packageInfo["version"] self.removePackageInfo(name, version) # remove any prior entry for this package self.packageNamesWithNewerFileDates.discard(name) # no longer has an update available self.packagesConfig["packages"].append(packageInfo) PackageManager.rebuildRemappings() self.packagesConfigChanged = True def packageEnable(self): if 0 <= self.selectedPackageIndex < len(self.packagesConfig["packages"]): packageInfo = self.packagesConfig["packages"][self.selectedPackageIndex] if self.packageEnableButton['text'] == self.ENABLE: packageInfo["status"] = "enabled" self.packageEnableButton['text'] = self.DISABLE elif self.packageEnableButton['text'] == self.DISABLE: packageInfo["status"] = "disabled" self.packageEnableButton['text'] = self.ENABLE self.packagesConfigChanged = True PackageManager.rebuildRemappings() self.loadTreeViews() def packageMoveUp(self): if 1 <= self.selectedPackageIndex < len(self.packagesConfig["packages"]): packages = self.packagesConfig["packages"] packageInfo = packages[self.selectedPackageIndex] del packages[self.selectedPackageIndex] packages.insert(self.selectedPackageIndex -1, packageInfo) self.packagesConfigChanged = True PackageManager.rebuildRemappings() self.loadTreeViews() def packageMoveDown(self): if 0 <= self.selectedPackageIndex < len(self.packagesConfig["packages"]) - 1: packages = self.packagesConfig["packages"] packageInfo = packages[self.selectedPackageIndex] del packages[self.selectedPackageIndex] packages.insert(self.selectedPackageIndex + 1, packageInfo) self.packagesConfigChanged = True PackageManager.rebuildRemappings() self.loadTreeViews() def packageReload(self): if 0 <= self.selectedPackageIndex < len(self.packagesConfig["packages"]): packageInfo = self.packagesConfig["packages"][self.selectedPackageIndex] url = packageInfo.get("URL") if url: packageInfo = PackageManager.packageInfo(url, reload=True, packageManifestName=packageInfo.get("manifestName")) if packageInfo: self.addPackageInfo(packageInfo) PackageManager.rebuildRemappings() self.loadTreeViews() self.cntlr.showStatus(_("{0} reloaded").format(packageInfo.get("name")), clearAfter=5000) else: messagebox.showwarning(_("Package error"), _("File or package cannot be reloaded: \n\n{0}") .format(url), parent=self) def packageRemove(self): if 0 <= self.selectedPackageIndex < len(self.packagesConfig["packages"]): packageInfo = self.packagesConfig["packages"][self.selectedPackageIndex] self.removePackageInfo(packageInfo["name"], packageInfo["version"]) self.packagesConfigChanged = True PackageManager.rebuildRemappings() self.loadTreeViews()
class DialogPluginManager(Toplevel): def __init__(self, mainWin, modulesWithNewerFileDates): super(DialogPluginManager, self).__init__(mainWin.parent) self.ENABLE = _("Enable") self.DISABLE = _("Disable") self.parent = mainWin.parent self.cntlr = mainWin # copy plugins for temporary display self.pluginConfig = PluginManager.pluginConfig self.pluginConfigChanged = False self.uiClassMethodsChanged = False self.modulesWithNewerFileDates = modulesWithNewerFileDates parentGeometry = re.match("(\d+)x(\d+)[+]?([-]?\d+)[+]?([-]?\d+)", self.parent.geometry()) dialogX = int(parentGeometry.group(3)) dialogY = int(parentGeometry.group(4)) self.title(_("Plug-in Manager")) frame = Frame(self) # left button frame buttonFrame = Frame(frame, width=40) buttonFrame.columnconfigure(0, weight=1) addLabel = Label(buttonFrame, text=_("Find plug-in modules:"), wraplength=60, justify="center") addLocalButton = Button(buttonFrame, text=_("Locally"), command=self.findLocally) ToolTip(addLocalButton, text=_("File chooser allows selecting python module files to add (or reload) plug-ins, from the local file system."), wraplength=240) addWebButton = Button(buttonFrame, text=_("On Web"), command=self.findOnWeb) ToolTip(addWebButton, text=_("Dialog to enter URL full path to load (or reload) plug-ins, from the web or local file system."), wraplength=240) addLabel.grid(row=0, column=0, pady=4) addLocalButton.grid(row=1, column=0, pady=4) addWebButton.grid(row=2, column=0, pady=4) buttonFrame.grid(row=0, column=0, rowspan=2, sticky=(N, S, W), padx=3, pady=3) # right tree frame (plugins already known to arelle) modulesFrame = Frame(frame, width=700) vScrollbar = Scrollbar(modulesFrame, orient=VERTICAL) hScrollbar = Scrollbar(modulesFrame, orient=HORIZONTAL) self.modulesView = Treeview(modulesFrame, xscrollcommand=hScrollbar.set, yscrollcommand=vScrollbar.set, height=7) self.modulesView.grid(row=0, column=0, sticky=(N, S, E, W)) self.modulesView.bind('<<TreeviewSelect>>', self.moduleSelect) hScrollbar["command"] = self.modulesView.xview hScrollbar.grid(row=1, column=0, sticky=(E,W)) vScrollbar["command"] = self.modulesView.yview vScrollbar.grid(row=0, column=1, sticky=(N,S)) modulesFrame.columnconfigure(0, weight=1) modulesFrame.rowconfigure(0, weight=1) modulesFrame.grid(row=0, column=1, columnspan=4, sticky=(N, S, E, W), padx=3, pady=3) self.modulesView.focus_set() self.modulesView.column("#0", width=120, anchor="w") self.modulesView.heading("#0", text=_("Name")) self.modulesView["columns"] = ("author", "ver", "status", "date", "update", "descr", "license") self.modulesView.column("author", width=100, anchor="w", stretch=False) self.modulesView.heading("author", text=_("Author")) self.modulesView.column("ver", width=50, anchor="w", stretch=False) self.modulesView.heading("ver", text=_("Version")) self.modulesView.column("status", width=50, anchor="w", stretch=False) self.modulesView.heading("status", text=_("Status")) self.modulesView.column("date", width=70, anchor="w", stretch=False) self.modulesView.heading("date", text=_("File Date")) self.modulesView.column("update", width=50, anchor="w", stretch=False) self.modulesView.heading("update", text=_("Update")) self.modulesView.column("descr", width=200, anchor="w", stretch=False) self.modulesView.heading("descr", text=_("Description")) self.modulesView.column("license", width=70, anchor="w", stretch=False) self.modulesView.heading("license", text=_("License")) classesFrame = Frame(frame) vScrollbar = Scrollbar(classesFrame, orient=VERTICAL) hScrollbar = Scrollbar(classesFrame, orient=HORIZONTAL) self.classesView = Treeview(classesFrame, xscrollcommand=hScrollbar.set, yscrollcommand=vScrollbar.set, height=5) self.classesView.grid(row=0, column=0, sticky=(N, S, E, W)) hScrollbar["command"] = self.classesView.xview hScrollbar.grid(row=1, column=0, sticky=(E,W)) vScrollbar["command"] = self.classesView.yview vScrollbar.grid(row=0, column=1, sticky=(N,S)) classesFrame.columnconfigure(0, weight=1) classesFrame.rowconfigure(0, weight=1) classesFrame.grid(row=1, column=1, columnspan=4, sticky=(N, S, E, W), padx=3, pady=3) self.classesView.focus_set() self.classesView.column("#0", width=200, anchor="w") self.classesView.heading("#0", text=_("Class")) self.classesView["columns"] = ("modules") self.classesView.column("modules", width=500, anchor="w", stretch=False) self.classesView.heading("modules", text=_("Modules")) # bottom frame module info details moduleInfoFrame = Frame(frame, width=700) moduleInfoFrame.columnconfigure(1, weight=1) self.moduleNameLabel = Label(moduleInfoFrame, wraplength=600, justify="left", font=font.Font(family='Helvetica', size=12, weight='bold')) self.moduleNameLabel.grid(row=0, column=0, columnspan=4, sticky=W) self.moduleAuthorHdr = Label(moduleInfoFrame, text=_("author:"), state=DISABLED) self.moduleAuthorHdr.grid(row=1, column=0, sticky=W) self.moduleAuthorLabel = Label(moduleInfoFrame, wraplength=600, justify="left") self.moduleAuthorLabel.grid(row=1, column=1, columnspan=3, sticky=W) self.moduleDescrHdr = Label(moduleInfoFrame, text=_("description:"), state=DISABLED) self.moduleDescrHdr.grid(row=2, column=0, sticky=W) self.moduleDescrLabel = Label(moduleInfoFrame, wraplength=600, justify="left") self.moduleDescrLabel.grid(row=2, column=1, columnspan=3, sticky=W) self.moduleClassesHdr = Label(moduleInfoFrame, text=_("classes:"), state=DISABLED) self.moduleClassesHdr.grid(row=3, column=0, sticky=W) self.moduleClassesLabel = Label(moduleInfoFrame, wraplength=600, justify="left") self.moduleClassesLabel.grid(row=3, column=1, columnspan=3, sticky=W) ToolTip(self.moduleClassesLabel, text=_("List of classes that this plug-in handles."), wraplength=240) self.moduleUrlHdr = Label(moduleInfoFrame, text=_("URL:"), state=DISABLED) self.moduleUrlHdr.grid(row=4, column=0, sticky=W) self.moduleUrlLabel = Label(moduleInfoFrame, wraplength=600, justify="left") self.moduleUrlLabel.grid(row=4, column=1, columnspan=3, sticky=W) ToolTip(self.moduleUrlLabel, text=_("URL of plug-in module (local file path or web loaded file)."), wraplength=240) self.moduleDateHdr = Label(moduleInfoFrame, text=_("date:"), state=DISABLED) self.moduleDateHdr.grid(row=5, column=0, sticky=W) self.moduleDateLabel = Label(moduleInfoFrame, wraplength=600, justify="left") self.moduleDateLabel.grid(row=5, column=1, columnspan=3, sticky=W) ToolTip(self.moduleDateLabel, text=_("Date of currently loaded module file (with parenthetical node when an update is available)."), wraplength=240) self.moduleLicenseHdr = Label(moduleInfoFrame, text=_("license:"), state=DISABLED) self.moduleLicenseHdr.grid(row=6, column=0, sticky=W) self.moduleLicenseLabel = Label(moduleInfoFrame, wraplength=600, justify="left") self.moduleLicenseLabel.grid(row=6, column=1, columnspan=3, sticky=W) self.moduleEnableButton = Button(moduleInfoFrame, text=self.ENABLE, state=DISABLED, command=self.moduleEnable) ToolTip(self.moduleEnableButton, text=_("Enable/disable plug in."), wraplength=240) self.moduleEnableButton.grid(row=7, column=1, sticky=E) self.moduleReloadButton = Button(moduleInfoFrame, text=_("Reload"), state=DISABLED, command=self.moduleReload) ToolTip(self.moduleReloadButton, text=_("Reload/update plug in."), wraplength=240) self.moduleReloadButton.grid(row=7, column=2, sticky=E) self.moduleRemoveButton = Button(moduleInfoFrame, text=_("Remove"), state=DISABLED, command=self.moduleRemove) ToolTip(self.moduleRemoveButton, text=_("Remove plug in from plug in table (does not erase the plug in's file)."), wraplength=240) self.moduleRemoveButton.grid(row=7, column=3, sticky=E) moduleInfoFrame.grid(row=2, column=0, columnspan=5, sticky=(N, S, E, W), padx=3, pady=3) moduleInfoFrame.config(borderwidth=4, relief="groove") okButton = Button(frame, text=_("Close"), command=self.ok) ToolTip(okButton, text=_("Accept and changes (if any) and close dialog."), wraplength=240) cancelButton = Button(frame, text=_("Cancel"), command=self.close) ToolTip(cancelButton, text=_("Cancel changes (if any) and close dialog."), wraplength=240) okButton.grid(row=3, column=3, sticky=(S,E), pady=3) cancelButton.grid(row=3, column=4, sticky=(S,E), pady=3, padx=3) self.loadTreeViews() frame.grid(row=0, column=0, sticky=(N,S,E,W)) frame.columnconfigure(0, weight=1) frame.columnconfigure(1, weight=1) window = self.winfo_toplevel() window.columnconfigure(0, weight=1) self.geometry("+{0}+{1}".format(dialogX+50,dialogY+100)) self.bind("<Return>", self.ok) self.bind("<Escape>", self.close) self.protocol("WM_DELETE_WINDOW", self.close) self.grab_set() self.wait_window(self) def loadTreeViews(self): self.selectedModule = None # clear previous treeview entries for previousNode in self.modulesView.get_children(""): self.modulesView.delete(previousNode) for i, moduleItem in enumerate(sorted(self.pluginConfig.get("modules", {}).items())): moduleInfo = moduleItem[1] name = moduleInfo.get("name", moduleItem[0]) node = self.modulesView.insert("", "end", name, text=name) self.modulesView.set(node, "author", moduleInfo.get("author")) self.modulesView.set(node, "ver", moduleInfo.get("version")) self.modulesView.set(node, "status", moduleInfo.get("status")) self.modulesView.set(node, "date", moduleInfo.get("fileDate")) if name in self.modulesWithNewerFileDates: self.modulesView.set(node, "update", _("available")) self.modulesView.set(node, "descr", moduleInfo.get("description")) self.modulesView.set(node, "license", moduleInfo.get("license")) # clear previous treeview entries for previousNode in self.classesView.get_children(""): self.classesView.delete(previousNode) for i, classItem in enumerate(sorted(self.pluginConfig.get("classes", {}).items())): className, moduleList = classItem node = self.classesView.insert("", "end", className, text=className) self.classesView.set(node, "modules", ', '.join(moduleList)) self.moduleSelect() # clear out prior selection def ok(self, event=None): if self.pluginConfigChanged: PluginManager.pluginConfig = self.pluginConfig PluginManager.pluginConfigChanged = True PluginManager.reset() # force reloading of modules if self.uiClassMethodsChanged: # may require reloading UI if messagebox.askyesno(_("User interface plug-in change"), _("A change in plug-in class methods may have affected the menus " "of the user interface. It may be necessary to restart Arelle to " "access the menu entries or the changes to their plug-in methods. \n\n" "Should Arelle restart with changed user interface language, " "(if there are any unsaved changes they would be lost!)?"), parent=self): self.cntlr.uiThreadQueue.put((self.cntlr.quit, [None, True])) self.close() def close(self, event=None): self.parent.focus_set() self.destroy() def moduleSelect(self, *args): node = (self.modulesView.selection() or (None,))[0] moduleInfo = self.pluginConfig.get("modules", {}).get(node) if moduleInfo: self.selectedModule = node name = moduleInfo["name"] self.moduleNameLabel.config(text=name) self.moduleAuthorHdr.config(state=ACTIVE) self.moduleAuthorLabel.config(text=moduleInfo["author"]) self.moduleDescrHdr.config(state=ACTIVE) self.moduleDescrLabel.config(text=moduleInfo["description"]) self.moduleClassesHdr.config(state=ACTIVE) self.moduleClassesLabel.config(text=', '.join(moduleInfo["classMethods"])) self.moduleUrlHdr.config(state=ACTIVE) self.moduleUrlLabel.config(text=moduleInfo["moduleURL"]) self.moduleDateHdr.config(state=ACTIVE) self.moduleDateLabel.config(text=moduleInfo["fileDate"] + " " + (_("(an update is available)") if name in self.modulesWithNewerFileDates else "")) self.moduleLicenseHdr.config(state=ACTIVE) self.moduleLicenseLabel.config(text=moduleInfo["license"]) self.moduleEnableButton.config(state=ACTIVE, text={"enabled":self.DISABLE, "disabled":self.ENABLE}[moduleInfo["status"]]) self.moduleReloadButton.config(state=ACTIVE) self.moduleRemoveButton.config(state=ACTIVE) else: self.selectedModule = None self.moduleNameLabel.config(text="") self.moduleAuthorHdr.config(state=DISABLED) self.moduleAuthorLabel.config(text="") self.moduleDescrHdr.config(state=DISABLED) self.moduleDescrLabel.config(text="") self.moduleClassesHdr.config(state=DISABLED) self.moduleClassesLabel.config(text="") self.moduleUrlHdr.config(state=DISABLED) self.moduleUrlLabel.config(text="") self.moduleDateHdr.config(state=DISABLED) self.moduleDateLabel.config(text="") self.moduleLicenseHdr.config(state=DISABLED) self.moduleLicenseLabel.config(text="") self.moduleEnableButton.config(state=DISABLED, text=self.ENABLE) self.moduleReloadButton.config(state=DISABLED) self.moduleRemoveButton.config(state=DISABLED) def findLocally(self): filename = self.cntlr.uiFileDialog("open", owner=self, title=_("Choose plug-in module file"), initialdir=self.cntlr.config.setdefault("pluginOpenDir","."), filetypes=[(_("Python files"), "*.py")], defaultextension=".py") if filename: self.cntlr.config["pluginOpenDir"] = os.path.dirname(filename) moduleInfo = PluginManager.moduleModuleInfo(filename) self.loadFoundModuleInfo(moduleInfo, filename) def findOnWeb(self): url = DialogURL.askURL(self) if url: # url is the in-cache or local file moduleInfo = PluginManager.moduleModuleInfo(url) self.cntlr.showStatus("") # clear web loading status self.loadFoundModuleInfo(moduleInfo, url) def loadFoundModuleInfo(self, moduleInfo, url): if moduleInfo and moduleInfo.get("name"): self.addPluginConfigModuleInfo(moduleInfo) self.loadTreeViews() else: messagebox.showwarning(_("Module is not a plug-in"), _("File does not contain a python program with an appropriate __pluginInfo__ declaration: \n\n{0}") .format(url), parent=self) def removePluginConfigModuleInfo(self, name): moduleInfo = self.pluginConfig["modules"].get(name) if moduleInfo: for classMethod in moduleInfo["classMethods"]: classMethods = self.pluginConfig["classes"].get(classMethod) if classMethods and name in classMethods: classMethods.remove(name) if not classMethods: # list has become unused del self.pluginConfig["classes"][classMethod] # remove class if classMethod.startswith("CntlrWinMain.Menu"): self.uiClassMethodsChanged = True # may require reloading UI del self.pluginConfig["modules"][name] self.pluginConfigChanged = True def addPluginConfigModuleInfo(self, moduleInfo): name = moduleInfo["name"] self.removePluginConfigModuleInfo(name) # remove any prior entry for this module self.modulesWithNewerFileDates.discard(name) # no longer has an update available self.pluginConfig["modules"][name] = moduleInfo # add classes for classMethod in moduleInfo["classMethods"]: classMethods = self.pluginConfig["classes"].setdefault(classMethod, []) if name not in classMethods: classMethods.append(name) if classMethod.startswith("CntlrWinMain.Menu"): self.uiClassMethodsChanged = True # may require reloading UI self.pluginConfigChanged = True def moduleEnable(self): if self.selectedModule in self.pluginConfig["modules"]: moduleInfo = self.pluginConfig["modules"][self.selectedModule] if self.moduleEnableButton['text'] == self.ENABLE: moduleInfo["status"] = "enabled" self.moduleEnableButton['text'] = self.DISABLE elif self.moduleEnableButton['text'] == self.DISABLE: moduleInfo["status"] = "disabled" self.moduleEnableButton['text'] = self.ENABLE self.pluginConfigChanged = True self.loadTreeViews() def moduleReload(self): if self.selectedModule in self.pluginConfig["modules"]: url = self.pluginConfig["modules"][self.selectedModule].get("moduleURL") if url: moduleInfo = PluginManager.moduleModuleInfo(url, reload=True) if moduleInfo: self.addPluginConfigModuleInfo(moduleInfo) self.loadTreeViews() self.cntlr.showStatus(_("{0} reloaded").format(moduleInfo.get("name")), clearAfter=5000) else: messagebox.showwarning(_("Module error"), _("File or module cannot be reloaded: \n\n{0}") .format(url), parent=self) def moduleRemove(self): if self.selectedModule in self.pluginConfig["modules"]: self.removePluginConfigModuleInfo(self.selectedModule) self.pluginConfigChanged = True self.loadTreeViews()
class Playback(Module): ''' Module to handle playback of audio and video files. ''' def __init__(self, app): self.app = app self.current = None if AUDIO_LIBS_INSTALLED: info( ' - initializing module: Audio' ) self.sfile = None self.p = pyaudio.PyAudio() self.currentInterval = None self.started = False self.paused = False self.sync = threading.Event() self.stoprequest = threading.Event() # widget management #self.frame = Frame(self.app.BOTTOM) self.frame = Frame(self.app.LEFT)#, pady=7) self.header = Header(self.frame, text="Playback") self.playBtn = Button(self.frame, text="⏯", command=self.playpauseAV, state='disabled', takefocus=0) # NOTE: not currently appearing self.app.bind('<space>', self.playpauseAV ) self.app.bind('<Escape>', self.stopAV ) if VIDEO_LIBS_INSTALLED: info( ' - initializing module: Video' ) self.app.bind('<space>', self.playpauseAV ) self.app.bind('<Escape>', self.stopAV ) self.grid() self.reset() def update(self): ''' don't change the audio file when we change frames ''' pass def reset(self): ''' try to load an audio file ''' if AUDIO_LIBS_INSTALLED: self.current = None audioFallbacks = [ '.wav', '.flac', '.ogg', '.mp3' ] for codec in audioFallbacks: if self.loadAudio( codec ) == True: self.playBtn.config( state='normal' ) return def loadAudio(self, codec): ''' load an audio file with a specific codec ''' audiofile = self.app.Data.getFileLevel( codec ) if audiofile != None: try: audiofile = self.app.Data.unrelativize(audiofile) self.sfile = AudioSegment.from_file( audiofile ) self.current = audiofile self.duration = len(self.sfile)/1000.0 return True except Exception as e: error('Unable to load audio file: `%s`' % audiofile, e) return False def playpauseAV(self, event): ''' ''' # debug(self.started, self.paused, '1858') if self.started == False or self.currentInterval != self.app.TextGrid.selectedItem: #if we haven't started playing or we're in a new interval #reset monitoring variables self.currentInterval = self.app.TextGrid.selectedItem self.started = False self.paused = False if self.app.TextGrid.selectedItem: start, end = self.app.TextGrid.getMinMaxTime() else: start = self.app.TextGrid.start end = self.app.TextGrid.end # if VIDEO_LIBS_INSTALLED and AUDIO_LIBS_INSTALLED: # self.readyVideo() # self.readyAudio(start, end) # self.playAudio() # elif AUDIO_LIBS_INSTALLED: # self.readyAudio(start, end) # self.playAudio() # elif VIDEO_LIBS_INSTALLED: # self.readyVideo() # self.dicomframeQ = queue.Queue() # for i in range(len(self.pngs)): # self.dicomframeQ.put(self.pngs[i]) # self.playVideoNoAudio() if self.app.Dicom.isLoaded(): self.readyVideo() if AUDIO_LIBS_INSTALLED: self.readyAudio(start, end) self.playAudio() elif self.app.Dicom.isLoaded(): self.dicomframeQ = queue.Queue() for i in range(len(self.pngs)): self.dicomframeQ.put(self.pngs[i]) self.playVideoNoAudio() elif self.started == True: if self.paused == False: self.paused = True self.stream.stop_stream() else: self.paused = False self.playAudio() def readyAudio(self, start, end): ''' ''' #audio stuff start_idx = round(float(start)*1000) end_idx = round(float(end)*1000) self.flen = float(self.app.TextGrid.frame_len) fpb = 512 extrafs = (end_idx-start_idx)%fpb extrasecs = extrafs/self.sfile.frame_rate pad = AudioSegment.silent(duration=round(extrasecs*1000)) seg_nopad = self.sfile[start_idx:end_idx] self.seg = seg_nopad + pad # seg.append() self.audioframe = 0 # open stream using callback (3) self.stream = self.p.open(format=self.p.get_format_from_width(self.seg.sample_width), channels=self.seg.channels, rate=self.seg.frame_rate, frames_per_buffer=fpb, output=True, start=False, stream_callback=self.callback) # debug(self.seg.frame_count()/fpb, 'number of chunks') # debug(self.seg.frame_count()%fpb, 'last chunk size') # self.chunkcount = 0 def readyVideo(self): ''' ''' self.app.Trace.reset() tags = self.app.TextGrid.selectedItem[0].gettags(self.app.TextGrid.selectedItem[1]) framenums = [tag[5:] for tag in tags if tag[:5]=='frame'] self.framestart = int(framenums[0]) imgs = self.app.Dicom.getFrames(framenums) canvas = self.app.Dicom.zframe.canvas bbox = canvas.bbox(canvas.find_all()[0]) dim = (bbox[2] - bbox[0], bbox[3] - bbox[1]) self.pngs = [] traces = self.app.Data.getTopLevel('traces') file = self.app.Data.getCurrentFilename() l = util.CROSSHAIR_SELECT_RADIUS for frame, img in zip(framenums, imgs): img = img.resize(dim) draw = ImageDraw.Draw(img) for name in traces: color = traces[name]['color'] if file in traces[name]['files'] and frame in traces[name]['files'][file]: for pt in traces[name]['files'][file][frame]: x = int(pt['x'] * img.width) y = int(pt['y'] * img.height) draw.line((x-l, y, x+l, y), fill=color) draw.line((x, y-l, x, y+l), fill=color) del draw self.pngs.append(ImageTk.PhotoImage(img)) #video w/audio stuff self.dicomframe_timer = 0 self.dicomframe_num = 1 self.dicomframeQ = queue.Queue() self.dicomframeQ.put(self.pngs[0]) #put now, because audio callback puts frames when audio segments end # for i in range(len(self.pngs)): # self.dicomframeQ.put(self.pngs[i]) def callback(self, in_data, frame_count, time_info, status): ''' Called by pyaudio stream. Gets chunks of audio ready for playing With video capabilities, also updates video frame information ''' # self.sync.clear() # self.chunkcount+=1 data = b''.join([self.seg.get_frame(i) for i in range(self.audioframe, self.audioframe+frame_count)]) # debug(len(data), 'line 1960') self.audioframe+=frame_count if self.app.Dicom.isLoaded(): #check & update video frame canvas = self.app.Dicom.zframe.canvas callbacklen = frame_count/self.seg.frame_rate self.dicomframe_timer += callbacklen #go to next frame if self.dicomframe_timer % self.flen != self.dicomframe_timer and self.dicomframe_num < len(self.pngs): floor = math.floor(self.dicomframe_timer/self.flen) # debug(floor, 'line 1961') self.dicomframe_timer = self.dicomframe_timer-self.flen*floor if floor > 1: for i in range(floor-1): # debug(self.dicomframe_num+self.framestart+i, 'putting frame into Q') if self.dicomframe_num+i < len(self.pngs): self.dicomframeQ.put(self.pngs[self.dicomframe_num+i]) else: self.dicomframeQ.put(self.pngs[self.dicomframe_num]) # self.sync.set() self.dicomframe_num+=floor # debug(self.dicomframe_num, len(self.pngs), 'line 1968') # else: #stop video loop if self.dicomframe_num >= len(self.pngs): self.stoprequest.set() return (data, pyaudio.paContinue) def playAudio(self): self.stream.start_stream() self.started = True if self.app.Dicom.isLoaded(): self.playVideoWithAudio() else: pass #write a loop that keeps audio playing # stop stream (6) if self.stoprequest.is_set(): self.stopAV() # self.stream.stop_stream() # if self.stoprequest.is_set(): # self.stream.close() # self.started = False # debug(self.chunkcount) # close PyAudio (7) # self.p.terminate() # NOTE: needs to be removed in order to play multiple audio files in a row def playVideoWithAudio(self): ''' ''' # self.sync.wait() if self.paused == True: return canvas = self.app.Dicom.zframe.canvas # debug(self.dicomframeQ.qsize(),'line 1991') try: pic = self.dicomframeQ.get(timeout=.5) canvas.itemconfig(canvas.find_all()[0] , image=pic ) # canvas.lift(pic) # canvas.img = pic canvas.update() except Exception as e: error(e) # debug(pic, 'displayed') # debug(self.dicomframe_num+self.framestart, 'displayed') if not self.stoprequest.is_set() or not self.dicomframeQ.empty(): #should this if be at the top? self.playVideoWithAudio() # canvas.after(10, self.playVideoWithAudio) def playVideoNoAudio(self): ''' ''' canvas = self.app.Dicom.zframe.canvas # pic = self.dicomframeQ.get() pic = self.dicomframeQ.get(block=False) canvas.itemconfig( canvas.find_all()[0], image=pic ) canvas.update() if not self.dicomframeQ.empty() and self.stoprequest.is_set() == False: #should this if be at the top? self.playVideoNoAudio() def stopAV(self,event=None): self.stoprequest.set() if AUDIO_LIBS_INSTALLED: self.stream.stop_stream() self.stream.close() self.started = False self.paused = False self.app.framesJumpTo() self.stoprequest.clear() def grid(self): ''' grid widgets ''' self.frame.grid( row=8 ) self.header.grid() self.playBtn.grid() def grid_remove(self): ''' remove widgets from grid ''' self.frame.grid_remove() self.header.grid_remove() self.playBtn.grid_remove()
class Example(Frame): def __init__(self, parent): Frame.__init__(self, parent, name="frame") self.parent = parent self.initUI() def initUI(self): self.parent.title("Pi computation") self.pack(fill=BOTH, expand=True) self.grid_columnconfigure(4, weight=1) self.grid_rowconfigure(3, weight=1) lbl1 = Label(self, text="Digits:") lbl1.grid(row=0, column=0, sticky=E, padx=10, pady=10) self.btn1 = Button(self, text='Populate Queue', command=self.on_populate) self.btn1.grid(row=0, column=1, sticky=W) lbl2 = Label(self, text="Accuracy:") lbl2.grid(row=0, column=2, sticky=E, padx=10, pady=10) self.btn2 = Button(self, text='Check Queue', command=self.on_check) self.btn2.grid(row=0, column=3, sticky=W) self.startBtn = Button(self, text="Start", command=self.onStart) self.startBtn.grid(row=1, column=0, padx=10, pady=5, sticky=W) self.pbar = Progressbar(self, mode='indeterminate') self.pbar.grid(row=1, column=1, columnspan=3, sticky=W + E) self.txt = scrolledtext.ScrolledText(self) self.txt.grid(row=2, column=0, rowspan=4, padx=10, pady=5, columnspan=5, sticky=E + W + S + N) def on_populate(self): print('populating queue ...') #populate_queue() #lengthy_function() self.p2 = Process(target=populate_queue) self.p2.start() def on_check(self): print('checking queue ...') # iterate through queue and print messages while True: try: result = q.get(timeout=0) except queue.Empty: print('queue is empty') return print(result) '''while True: if queue.Empty: print('queue is empty') return else: print('queue is not empty') result = q.get() print(result)''' '''while True: item = q.get() if item == 'done': break else: print(item)''' def onStart(self): self.startBtn.config(state=DISABLED) self.txt.delete("1.0", END) self.p1 = Process(target=lengthy_function) self.p1.start() self.pbar.start(DELAY2) self.after(DELAY1, self.onGetValue) def onGetValue(self): if (self.p1.is_alive()): self.after(DELAY1, self.onGetValue) return else: try: result = q.get(timeout=0) except queue.Empty: print('queue is empty') return # Do work print(result) self.pbar.stop() self.startBtn.config(state=NORMAL)
class Download(Frame): def __init__(self, master, **kwargs): super(Download, self).__init__(master, borderwidth=20, **kwargs) self.fs = None self.tree = None self.logfile = None # User informations self.info_tree = False self.start_time = None info = Frame(self, borderwidth=10) self.info_label = Label(info, wraplength=350, borderwidth=20, justify='center', font=('a', 10, 'bold')) self.info_indis = Label(info) self.info_fams = Label(info) self.time = Label(info) self.info_label.grid(row=0, column=0, columnspan=2) self.info_indis.grid(row=1, column=0) self.info_fams.grid(row=1, column=1) self.time.grid(row=3, column=0, columnspan=2) self.form = Frame(self) self.sign_in = SignIn(self.form) self.options = None self.title = Label(self, text=_('Sign In to FamilySearch'), font=('a', 12, 'bold')) buttons = Frame(self) self.btn_quit = Button(buttons, text=_('Quit'), command=Thread(target=self.quit).start) self.btn_valid = Button(buttons, text=_('Sign In'), command=self.command_in_thread(self.login)) self.title.pack() self.sign_in.pack() self.form.pack() self.btn_quit.pack(side='left', padx=(0, 40)) self.btn_valid.pack(side='right', padx=(40, 0)) info.pack() buttons.pack(side='bottom') self.pack() self.update_needed = False def info(self, text): self.info_label.config(text=text) def save(self): filename = filedialog.asksaveasfilename(title=_('Save as'), defaultextension='.csv', filetypes=(('CSV', '.csv'), (_('All files'), '*.*'))) if not filename: return #with open(filename, 'w', encoding='utf-8') as file: #self.tree.print(file) fh = open(filename, "w") fh.write('personnum') fh.write(';') fh.write('given names') fh.write(';') fh.write('surname') fh.write(';') fh.write('gender') fh.write(';') fh.write('birthdate') fh.write(';') fh.write('birthplace') fh.write(';') fh.write('deathdate') fh.write(';') fh.write('deathplace') fh.write(';') fh.write('fathernum') fh.write(';') fh.write('mothernum') fh.write(';') fh.write('spousenum') fh.write(';') fh.write('childnum') fh.write(';') fh.write('Life Summary') fh.write('\n') for fid in sorted(self.tree.indi, key=lambda x: self.tree.indi.__getitem__(x).num): #person number personnum = self.tree.indi[fid].fid #name givennames = self.tree.indi[fid].name.given #surname, all caps surname = self.tree.indi[fid].name.surname #gender gender = self.tree.indi[fid].gender #birth and death birthstring = 'b. ' deathstring = 'd. ' birthdate = '' birthplace = '' deathdate = '' deathplace = '' for o in self.tree.indi[fid].facts: if o.type == 'http://gedcomx.org/Birth': if o.date: birthdate = o.date birthstring = birthstring + o.date if o.place: birthplace = o.place birthstring = birthstring + ' in ' + o.place if o.type == 'http://gedcomx.org/Death': if o.date: deathdate = o.date deathstring = deathstring + o.date if o.place: deathplace = o.place deathstring = deathstring + ' in ' + o.place fathernum = '' mothernum = '' for p in self.tree.indi[fid].parents: #father number fathernum = p[0] #mother number mothernum = p[1] spousenum = '' childnum = '' childset = '' for husb, wife in sorted( self.tree.fam, key=lambda x: self.tree.fam.__getitem__(x).num): if self.tree.fam[(husb, wife)].husb_fid == fid: childnum = self.tree.fam[(husb, wife)].chil_fid.pop() self.tree.fam[(husb, wife)].chil_fid.add(childnum) spousenum = self.tree.fam[(husb, wife)].wife_fid elif self.tree.fam[(husb, wife)].wife_fid == fid: childnum = self.tree.fam[(husb, wife)].chil_fid.pop() self.tree.fam[(husb, wife)].chil_fid.add(childnum) spousenum = self.tree.fam[(husb, wife)].husb_fid else: continue #print('') #print(personnum) #print(givennames + ' ' + surname) #print(surname.upper()) #print(birthstring) #print(deathstring) #print(fathernum) #print(mothernum) #print(spousenum) #print(childnum) #print('Life Summary ...') #Print out in semicolon-csv format if personnum: fh.write(personnum) fh.write(';') if givennames: fh.write(givennames) fh.write(';') if surname: fh.write(surname) fh.write(';') if gender: fh.write(gender) fh.write(';') if birthdate: fh.write(birthdate) fh.write(';') if birthplace: fh.write(birthplace) fh.write(';') if deathdate: fh.write(deathdate) fh.write(';') if deathplace: fh.write(deathplace) fh.write(';') if fathernum: fh.write(fathernum) fh.write(';') if mothernum: fh.write(mothernum) fh.write(';') if spousenum: fh.write(spousenum) fh.write(';') if childnum: fh.write(childnum) fh.write(';') fh.write('') fh.write('\n') fh.close() def login(self): global _ username = self.sign_in.username.get() password = self.sign_in.password.get() if not (username and password): messagebox.showinfo(message=_( 'Please enter your FamilySearch username and password.')) return self.btn_valid.config(state='disabled') self.info(_('Login to FamilySearch...')) self.logfile = open('download.log', 'w', encoding='utf-8') self.fs = Session(self.sign_in.username.get(), self.sign_in.password.get(), verbose=True, logfile=self.logfile, timeout=1) if not self.fs.logged: messagebox.showinfo( _('Error'), message=_('The username or password was incorrect')) self.btn_valid.config(state='normal') self.info('') return self.tree = Tree(self.fs) _ = self.fs._ self.title.config(text=_('Options')) cache.delete('lang') cache.add('lang', self.fs.lang) lds_account = self.fs.get_url( '/platform/tree/persons/%s/ordinances' % self.fs.fid) != 'error' self.options = Options(self.form, lds_account) self.info('') self.sign_in.destroy() self.options.pack() self.master.change_lang() self.btn_valid.config(command=self.command_in_thread(self.download), state='normal', text=_('Download')) self.options.start_indis.add_indi(self.fs.fid) self.update_needed = False def quit(self): self.update_needed = False if self.logfile: self.logfile.close() super(Download, self).quit() # prevent exception during download os._exit(1) def download(self): todo = [ self.options.start_indis.indis[key] for key in sorted(self.options.start_indis.indis) ] for fid in todo: if not re.match(r'[A-Z0-9]{4}-[A-Z0-9]{3}', fid): messagebox.showinfo(_('Error'), message=_('Invalid FamilySearch ID: ') + fid) return self.start_time = time.time() self.options.destroy() self.form.destroy() self.title.config(text='Ancestor Cards') self.btn_valid.config(state='disabled') self.info(_('Download starting individuals...')) self.info_tree = True self.tree.add_indis(todo) # download ancestors #todo = set(todo) todo = set(self.tree.indi.keys()) done = set() for i in range(self.options.ancestors.get()): if not todo: break done |= todo #self.info(_('Download ') + str(i + 1) + _('th generation of ancestors...')) print(_("Downloading %s. of generations of ancestors...") % (i + 1), file=sys.stderr) todo = self.tree.add_parents(todo) - done #todo = set(self.tree.indi.keys()) #done = set() #for i in range(self.options.descendants.get()): # if not todo: # break # done |= todo # self.info(_('Download ') + str(i + 1) + _('th generation of descendants...')) # todo = self.tree.add_children(todo) - done #if self.options.spouses.get(): # self.info(_('Download spouses and marriage information...')) # todo = set(self.tree.indi.keys()) # self.tree.add_spouses(todo) self.tree.reset_num() self.btn_valid.config(command=self.save, state='normal', text=_('Save')) self.info(text=_('Success ! Click below to save your CSV file')) self.update_info_tree() self.update_needed = False def command_in_thread(self, func): def res(): self.update_needed = True Thread(target=self.update_gui).start() Thread(target=func).start() return res def update_info_tree(self): if self.info_tree and self.start_time and self.tree: self.info_indis.config(text=_('Individuals: %s') % len(self.tree.indi)) self.info_fams.config(text=_('Families: %s') % len(self.tree.fam)) t = round(time.time() - self.start_time) minutes = t // 60 seconds = t % 60 self.time.config(text=_('Elapsed time: %s:%s') % (minutes, '00%s'[len(str(seconds)):] % seconds)) def update_gui(self): while self.update_needed: self.update_info_tree() self.master.update() time.sleep(0.1)
class MultipleABFEditor(Toplevel): def __init__(self, parent, paths, dispatch_event): """ Initialises a window for loading datasets. First loads a datafile. After waiting for this process, creates a window to select different channels and specify the unit of the data. """ super().__init__(None) self.parent = parent self.dispatch_event = dispatch_event self.title("ABF data set") self.editor = None self.paths = paths self.paths_new = [] if not test1.alpha: self.path = paths[0] self.abf = ABF(self.path) self.values = None self.values1 = None self.resizable(width=False, height=False) waiting_popup = Toplevel(parent) waiting_popup.attributes("-topmost", True) waiting_label = Label(waiting_popup, text="Preparing data...") waiting_label.pack() waiting_popup.update() waiting_popup.destroy() try: if not test1.alpha: self.attributes("-topmost", True) dividends = self.abf._abf[self.abf._abf.names.index("channelNames")] units = self.abf._abf[self.abf._abf.names.index("channelUnits")] for i in range(len(self.abf._abf[self.abf._abf.names.index("channelNames")])): dividends[i] = dividends[i] + " " + \ self.abf._abf[self.abf._abf.names.index("channelUnits")][i] divisors = dividends + 'None' self.dividend_var = StringVar(self) # usually contains current self.divisor_var = StringVar(self) # usually contains voltage self.dividend_var.set(dividends[0]) self.divisor_var.set(divisors[1]) self.dividends = dividends self.units = units self.divisors = divisors path_lab = Label(self, text="Path: {}".format(self.paths[0])) path_lab.pack(padx=10, pady=10) channel_selector = Frame(self) warning = Label(channel_selector, text="Select a channel, optionally divide it by another channel") dividend_menu = OptionMenu(channel_selector, self.dividend_var, *dividends) divisor_menu = OptionMenu(channel_selector, self.divisor_var, *divisors) warning.pack() dividend_menu.pack() divisor_menu.pack() channel_selector.pack(padx=10, pady=10) unit_selector = Frame(self) unit_lab = Label(unit_selector, text="Unit: ") unit_lab.pack(side="left", fill="x") self.unit = Entry(unit_selector) self.unit.delete(0, "end") self.unit.insert(0, "nS") self.unit.pack(side="left", fill="x") unit_selector.pack(padx=10, pady=10) self.ok = Button(self, text="Load", command=self.load) self.ok.pack(side="left", fill="x", padx=10, pady=10) self.ok_all = Button(self, text="Load All", command=self.load_all) self.ok_all.pack() self.ok_all.place(relx=0.5, rely=0.88, anchor=CENTER) cancel = Button(self, text="Don't load", command=self.destroy) cancel.pack(side="right", fill="x", padx=10, pady=10) self.bind('<Return>', self.load) except: messagebox.showwarning( "Error loading file", self.paths[0] + " could not be loaded.") self.destroy() @property def params(self): """ Parameters which will be given to the controller. """ dividend = self.dividend_var.get() # print(dividend) divisor = self.divisor_var.get() # print(divisor) channels = [self.dividends.index(dividend) + 1] # print("Channels", channels) if divisor != 'None': channels += [self.divisors.index(divisor) + 1] return dict(sweep=1, channels=channels, unit=self.unit.get()) def load(self, test=None): """ Gives the dataset and parameters to the controller, then destroys the editor. """ self.ok.config(state = DISABLED) self.ok_all.config(state=DISABLED) if len(self.paths) > 0: del self.paths[0] self.dispatch_event("add_abf_dataset", self.abf, self.params) if len(self.paths) != 0: test1.alpha = False Editor = MultipleABFEditor self.editor = Editor(self.parent, self.paths, self.dispatch_event) else: test1.alpha = True self.destroy() def load_all(self, test=None): """ Gives the datasets with same channel names , channel units , same number of channels and parameters( same parameters to all data sets with same channel names , channel units , same number of channels )to the controller, then destroys the editor. """ self.ok_all.config(state = DISABLED) self.ok.config(state=DISABLED) self.values = ABF.names1(self.abf) values = set(self.values) self.values1 = ABF.units1(self.abf) values1 = set(self.values1) params1 = self.params for path in self.paths: self.abf = ABF(path) dividends = self.abf._abf[self.abf._abf.names.index("channelNames")] for i in range(len(self.abf._abf[self.abf._abf.names.index("channelNames")])): dividends[i] = dividends[i] + " " + \ self.abf._abf[self.abf._abf.names.index("channelUnits")][i] units = self.abf._abf[self.abf._abf.names.index("channelUnits")] dividends = set(dividends) units = set(units) if len(self.values) == len(dividends) and len(self.values1) == len(units) and (values == dividends) and ( values1 == units): self.dispatch_event("add_abf_dataset", self.abf, params1) else: self.paths_new.append(path) if len(self.paths_new) != 0: test1.alpha = False Editor = MultipleABFEditor self.editor = Editor(self.parent, self.paths_new, self.dispatch_event) else: test1.alpha = True self.destroy()
class Example(Frame): def __init__(self, parent): Frame.__init__(self, parent) self.parent = parent self.initUI() def initUI(self): self.parent.title("") #self.style = Style() #self.style.theme_use("clam") #self.pack(fill=BOTH, expand = 1) self.labelU = Label(self, text="U:") self.labelP = Label(self, text="P:") self.mailrecipient = 'GoldenSights' self.entryUsername = Entry(self) self.entryUsername.focus_set() self.entryUsername.bind('<Return>', lambda event: self.entryPassword.focus_set()) self.entryPassword = Entry(self) self.entryPassword.config(show='•') self.entryPassword.bind( '<Return>', lambda event: self.login(self.entryUsername.get(), self.entryPassword.get())) self.newbutton = Button( self, text="Login", command=lambda: self.login(self.entryUsername.get(), self.entryPassword.get())) self.newbutton.bind( '<Return>', lambda event: self.login(self.entryUsername.get(), self.entryPassword.get())) self.newbutton.config(width=6) self.quitbutton = Button(self, text="Quit", command=lambda: self.quit()) self.quitbutton.config(width=6) self.labelU.grid(row=0, column=0, padx=0) self.entryUsername.grid(row=0, column=1) self.labelP.grid(row=1, column=0) self.entryPassword.grid(row=1, column=1, pady=4) self.newbutton.grid(row=2, column=1) self.quitbutton.grid(row=3, column=1, pady=4) self.labelErrorPointer = Label(self, text="◀") self.indicatorGreen = PhotoImage(file="indicatorGreen.gif") self.indicatorRed = PhotoImage(file="indicatorRed.gif") self.indicatorBlue = PhotoImage(file="indicatorBlue.gif") self.indicatorBlack = PhotoImage(file="indicatorBlack.gif") sw = self.parent.winfo_screenwidth() sh = self.parent.winfo_screenheight() w = 400 h = 480 x = (sw - w) / 2 y = (sh - h) / 2 self.parent.geometry('%dx%d+%d+%d' % (w, h, x, y - 50)) def login(self, username, password): print('U: ' + username) self.username = username if username == '' or not all( char in string.ascii_letters + string.digits + '_-' for char in username): print('Please enter a username') self.entryUsername.focus_set() self.labelErrorPointer.grid(row=0, column=2) elif password == '': print('Please enter a password') self.entryPassword.focus_set() self.labelErrorPointer.grid(row=1, column=2) else: self.labelErrorPointer.grid_forget() print('Attempting login for ' + username) try: self.USERAGENT = username + ' practices Tkinter+PRAW mixing with utility by /u/GoldenSights.' self.r = praw.Reddit(self.USERAGENT) #self.r.login(username, password) print('Success') self.labelU.grid_forget() self.labelP.grid_forget() self.entryUsername.grid_forget() self.entryPassword.grid_forget() self.newbutton.grid_forget() self.quitbutton.grid_forget() self.usernamelabel = Label(self, text=username + ', Sending to /u/' + self.mailrecipient) self.usernamelabel.grid(row=0, column=0, columnspan=8) self.quitbutton.grid(row=900, column=0) self.labellist = [] self.entrylist = [] self.verifylist = [] self.misclist = [] self.optionDiscuss = "Discussion Flair + Crossposting" self.optionRegister = "Register a new Candidate" self.prevmode = self.optionDiscuss self.curmode = self.optionDiscuss self.optionvar = tkinter.StringVar(self) self.optionvar.trace("w", self.permaloop) self.optionvar.set(self.optionDiscuss) self.option = OptionMenu(self, self.optionvar, self.optionDiscuss, self.optionRegister, "three", "four") self.newbutton.unbind("<Return>") self.entryUsername.unbind("<Return>") self.entryPassword.unbind("<Return>") self.option.grid(row=1, column=0, columnspan=8, pady=8) self.updategui(True) except praw.errors.InvalidUserPass: pass print('Invalid username or password') self.entryPassword.delete(0, 200) self.labelErrorPointer.grid(row=1, column=2) def permaloop(self, *args): self.curmode = self.optionvar.get() print('Was: ' + self.prevmode + ' | Now: ' + self.curmode) if self.curmode != self.prevmode: self.prevmode = self.curmode self.updategui(True) def updategui(self, *args): if args[0] == True: print('Cleaning GUI') for item in self.labellist: item.grid_forget() for item in self.entrylist: item.grid_forget() for item in self.verifylist: item.grid_forget() for item in self.misclist: item.grid_forget() self.labellist = [] self.entrylist = [] self.verifylist = [] self.misclist = [] if self.curmode == self.optionDiscuss: self.newrowindex = 4 self.labelPermalink = Label(self, text="Thread Permalink:") self.entryPermalink = Entry(self) self.rowconfigure(2, weight=2) self.labelPermalink.grid(row=2, column=0) self.entryPermalink.grid(row=2, column=1) self.labelcrossposting = Label(self, text="Crosspost to:") self.labelcrossposting.grid(row=3, column=0, columnspan=2, sticky="w") for m in range(5): self.redditlabel = Label(self, text="/r/") self.redditlabel.grid(row=self.newrowindex, column=0, sticky="e") self.labellist.append(self.redditlabel) self.redditentry = Entry(self) self.redditentry.grid(row=self.newrowindex, column=1) self.entrylist.append(self.redditentry) self.newrowindex += 1 self.morerowbutton = Button( self, text="+row", command=lambda: self.morerows('/r/', 0, 1, 20)) self.morerowbutton.grid(row=898, column=0, columnspan=2) self.verifybutton = Button( self, text="Verify", command=lambda: self.updategui(False)) self.verifybutton.grid(row=899, column=0, columnspan=2) self.newrowindex += 2 self.misclist.append(self.labelPermalink) self.misclist.append(self.labelcrossposting) self.misclist.append(self.entryPermalink) self.misclist.append(self.morerowbutton) self.misclist.append(self.verifybutton) if self.curmode == self.optionRegister: self.newrowindex = 6 self.labelCanUsername = Label( self, text="Candidate's Username: /u/") self.entryCanUsername = Entry(self) self.labelCanRealname = Label(self, text="Candidate's Realname:") self.entryCanRealname = Entry(self) self.labelCanFlair = Label(self, text="Candidate's Flair:") self.entryCanFlair = Entry(self) self.entryMo = Spinbox( self, width=9, values=('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December')) self.entryDa = Spinbox(self, width=2, from_=1, to=31) self.entryYr = Spinbox(self, width=4, from_=2014, to=2500) self.labelHH = Label(self, text="Schedule time UTC:") self.entryHH = Spinbox(self, from_=0, to=23, width=2) self.entryMM = Spinbox(self, from_=0, to=59, width=2) self.entryYr.delete(0, 'end') self.entryYr.insert(0, 2014) self.morerowbutton = Button( self, text="+question", command=lambda: self.morerows('Q:', 0, 1, 25)) self.morerowbutton.grid(row=898, column=0, columnspan=8) self.verifybutton = Button( self, text="Verify", command=lambda: self.updategui(False)) self.verifybutton.grid(row=899, column=0, columnspan=8) self.misclist.append(self.labelCanUsername) self.misclist.append(self.labelCanRealname) self.misclist.append(self.entryCanUsername) self.misclist.append(self.entryCanRealname) self.misclist.append(self.labelHH) self.misclist.append(self.entryHH) self.misclist.append(self.entryMM) self.misclist.append(self.entryMo) self.misclist.append(self.entryDa) self.misclist.append(self.entryYr) self.misclist.append(self.morerowbutton) self.misclist.append(self.verifybutton) self.labelCanUsername.grid(row=2, column=0, sticky="e") self.labelCanRealname.grid(row=3, column=0, sticky="e") self.labelCanFlair.grid(row=4, column=0, sticky="e") self.entryCanUsername.grid(row=2, column=1, columnspan=3) self.entryCanRealname.grid(row=3, column=1, columnspan=3) self.entryCanFlair.grid(row=4, column=1, columnspan=3) self.entryMo.grid(row=5, column=1, sticky="e") self.entryDa.grid(row=5, column=2) self.entryYr.grid(row=5, column=3) self.labelHH.grid(row=5, column=0, sticky="se", pady=5) self.entryHH.grid(row=6, column=1, sticky="e") self.entryMM.grid(row=6, column=2, sticky="w") else: if self.curmode == self.optionDiscuss: verifies = [] i = self.entryPermalink.get() if len(i) == 6: pid = i else: if 'www.reddit.com/r/' in i and '/comments/' in i: pid = i.split('/comments/')[1].split('/')[0] if 'http://redd.it/' in i: pid = i.split('redd.it/')[1] for flag in self.verifylist: flag.grid_forget() self.verifylist.remove(flag) try: print('Fetching Submission ' + pid) self.r.get_info(thing_id="t3_" + pid).title + 'Check' self.redditlabel = Label(self, image=self.indicatorGreen) self.redditlabel.grid(row=2, column=2) self.verifylist.append(self.redditlabel) verifies.append(True) print('\tSuccess') except: print( 'Failed. Make sure to include the http://. Copy and paste straight from your browser for best result' ) self.redditlabel = Label(self, image=self.indicatorRed) self.redditlabel.grid(row=2, column=2) self.verifylist.append(self.redditlabel) verifies.append(False) for entry in self.entrylist: i = entry.get() if i != '': print('Fetching /r/' + i) if all(char in string.ascii_letters + string.digits + '_-' for char in i): try: sub = self.r.get_subreddit(i, fetch=True) self.redditlabel = Label( self, image=self.indicatorGreen) self.redditlabel.grid( row=entry.grid_info()['row'], column=2) self.verifylist.append(self.redditlabel) verifies.append(True) print('\tSuccess') except: self.redditlabel = Label( self, image=self.indicatorRed) self.redditlabel.grid( row=entry.grid_info()['row'], column=2) self.verifylist.append(self.redditlabel) verifies.append(False) print('\tFailed') time.sleep(2) else: self.redditlabel = Label(self, image=self.indicatorRed) self.redditlabel.grid(row=entry.grid_info()['row'], column=2) self.verifylist.append(self.redditlabel) verifies.append(False) print('\tFailed') print(verifies) if self.curmode == self.optionRegister: verifies = [] u = self.entryCanUsername.get() print('Fetching /u/' + u) if not all(char in string.ascii_letters + string.digits + '_-' for char in u): self.redditlabel = Label(self, image=self.indicatorRed) self.redditlabel.grid(row=2, column=4) self.verifylist.append(self.redditlabel) verifies.append(False) print('\tBad characterage') else: try: u = self.r.get_redditor(u) print(u) self.redditlabel = Label(self, image=self.indicatorGreen) self.redditlabel.grid(row=2, column=4) self.verifylist.append(self.redditlabel) verifies.append(True) print('\tSuccess') except: self.redditlabel = Label(self, image=self.indicatorRed) self.redditlabel.grid(row=2, column=4) self.verifylist.append(self.redditlabel) verifies.append(False) print('\tFailed') try: print('Checking Time') t = self.entryMo.get() + ' ' + self.entryDa.get( ) + ' ' + self.entryYr.get() + ' ' + self.entryHH.get( ) + ':' + self.entryMM.get() plandate = datetime.datetime.strptime(t, "%B %d %Y %H:%M") plandate = datetime.datetime.utcfromtimestamp( plandate.timestamp()) print('\t' + str(plandate.timestamp())) self.redditlabel = Label(self, image=self.indicatorGreen) self.redditlabel.grid(row=5, column=3) self.verifylist.append(self.redditlabel) verifies.append(True) except: print('\tFailed') self.redditlabel = Label(self, image=self.indicatorRed) self.redditlabel.grid(row=5, column=3) self.verifylist.append(self.redditlabel) verifies.append(False) print(verifies) def morerows(self, label, columnm, columnn, limit, *args): self.redditlabel = Label(self, text=label) self.redditlabel.grid(row=self.newrowindex, column=columnm, sticky="e") self.labellist.append(self.redditlabel) self.redditentry = Entry(self) self.redditentry.grid(row=self.newrowindex, column=columnn, columnspan=9) self.entrylist.append(self.redditentry) self.newrowindex += 1 if self.newrowindex >= limit: self.morerowbutton.grid_forget() print(self.newrowindex)
class MainView(Frame): def __init__(self, root, model: Model): super().__init__(root) root.columnconfigure(0, weight=1) root.rowconfigure(0, weight=1) self.model = model self.__init_components() self.grid(sticky='nsew') self.__bind_action_events() def __init_components(self): # Instanciar widgets self.panel_form = Labelframe(self, text='Tarea') self.panel_tasks = Labelframe(self, text='Tareas por hacer') self.panel_complete_tasks = Labelframe(self, text='Tareas completas') self.label_name = Label(self.panel_form, text='Nombre:') self.label_description = Label(self.panel_form, text='Descripción:') self.entry_name = Entry(self.panel_form) self.entry_description = Entry(self.panel_form) self.btn_modify_task = Button(self.panel_form, text='Editar tarea', state=DISABLED, command=self.__modify_task) self.btn_new_task = Button(self.panel_form, text='Nueva tarea', command=self.__new_task) self.btn_delete_task = Button(self.panel_form, text='Eliminar tarea', state=DISABLED, command=self.__delete_task) self.btn_clear_form = Button(self.panel_form, text='Limpiar campos', command=self.__clear_form) self.btn_complete_task = Button(self.panel_form, text='Completar tarea', state=DISABLED, command=self.__complete_task) self.scroll_tasks = Scrollbar(self.panel_tasks, orient=VERTICAL) self.scroll_complete_tasks = Scrollbar(self.panel_complete_tasks, orient=VERTICAL) self.list_tasks = Listbox(self.panel_tasks, selectmode=SINGLE, height=10, width=25, yscrollcommand=self.scroll_tasks.set) self.list_complete_tasks = Listbox( self.panel_complete_tasks, selectmode=SINGLE, height=10, width=25, yscrollcommand=self.scroll_complete_tasks.set) # Posicionar los widgets # Panel de formulario de tareas self.panel_form.pack(fill='both', expand='yes', padx=10, pady=5, ipadx=5, ipady=5) self.panel_form.columnconfigure(0, weight=1) self.panel_form.rowconfigure(0, weight=1) self.label_name.grid(row=0, column=0, padx=5, sticky='w') self.entry_name.grid(row=0, column=1, padx=5, sticky='w') self.label_description.grid(row=1, column=0, padx=5, pady=5, sticky='w') self.entry_description.grid(row=1, column=1, padx=5, pady=10, sticky='w') # Botones self.btn_modify_task.grid(row=2, column=0, ipady=4, sticky='we') self.btn_new_task.grid(row=2, column=1, ipady=4, sticky='we') self.btn_delete_task.grid(row=3, column=0, ipady=4, sticky='we') self.btn_clear_form.grid(row=3, column=1, ipady=4, sticky='we') self.btn_complete_task.grid(row=4, column=0, columnspan=2, ipady=4, sticky='we') config_list = { 'fill': 'both', 'expand': 'yes', 'padx': 10, 'pady': 5, 'ipadx': 5, 'ipady': 5 } # Panel de lista de tareas pendientes self.panel_tasks.pack(config_list) self.panel_tasks.columnconfigure(0, weight=20) self.panel_tasks.columnconfigure(1, weight=1) self.list_tasks.grid(row=0, column=0, sticky='we') self.scroll_tasks.configure(command=self.list_tasks.yview) self.scroll_tasks.grid(row=0, column=1, sticky='ns') # Panel de lista de tareas completas self.panel_complete_tasks.pack(config_list) self.panel_complete_tasks.columnconfigure(0, weight=20) self.panel_complete_tasks.columnconfigure(1, weight=1) self.list_complete_tasks.grid(row=0, column=0, sticky='we') self.scroll_complete_tasks.configure( command=self.list_complete_tasks.yview) self.scroll_complete_tasks.grid(row=0, column=1, sticky='ns') def __bind_action_events(self): # self.btn_new_task.bind('<Button>', self.__new_task) # self.btn_modify_task.bind('<Button>', self.__modify_task) # self.btn_delete_task.bind('<Button>', self.__delete_task) # self.btn_complete_task.bind('<Button>', self.__complete_task) self.list_tasks.bind('<<ListboxSelect>>', self.__select_task) def __new_task(self): log_info('Botón {} pulsado'.format( self.btn_new_task.config('text')[-1])) name_value = self.entry_name.get() description_value = self.entry_description.get() if name_value: self.model.new_task(name_value, description_value) self.update_tables() else: messagebox.showwarning('AVISO', 'Complete el campo de nombre') def __modify_task(self): index = self.__selected_task() name_value = self.entry_name.get() description_value = self.entry_description.get() if index != -1: task = self.model.get_task(self.model.tasks[index].get_id()) complete = self.model.modify_task(task.get_id(), name_value, description_value) if complete: messagebox.showinfo('Aviso', 'Tarea: {} editada'.format(task.name)) self.update_tables() def __delete_task(self): index = self.__selected_task() if index != -1: task = self.model.get_task(self.model.tasks[index].get_id()) self.model.delete_task(task.get_id()) self.update_tables() def __complete_task(self): index = self.__selected_task() if index != -1: task = self.model.get_task(self.model.tasks[index].get_id()) task.close_todo() complete = self.model.modify_task(task.get_id(), task.name, task.description) if complete: messagebox.showinfo('Aviso', 'Tarea: {} completa'.format(task.name)) self.update_tables() def __clear_form(self): self.clear_form() self.__change_state_btn(DISABLED) def __select_task(self, event): self.clear_form() index = self.__selected_task() if index != -1: task = self.model.get_task(self.model.tasks[index].get_id()) self.set_form(task) self.__change_state_btn(NORMAL) def __change_state_btn(self, state: str): self.btn_new_task.config( state=NORMAL if state == DISABLED else DISABLED) self.btn_delete_task.config(state=state) self.btn_modify_task.config(state=state) self.btn_complete_task.config(state=state) def __selected_task(self): try: return self.list_tasks.curselection()[0] except IndexError: self.__change_state_btn(DISABLED) self.list_complete_tasks.activate(-1) return -1 def update_tables(self): log_info('Actualizando tablas') self.list_tasks.delete(0, END) self.list_complete_tasks.delete(0, END) for index in range(len(self.model.tasks)): self.list_tasks.insert(index, self.model.tasks[index].name) for index in range(len(self.model.complete_tasks)): self.list_complete_tasks.insert( index, self.model.complete_tasks[index].name) def clear_form(self): self.entry_name.delete(0, END) self.entry_description.delete(0, END) def set_form(self, task: Task): if task is not None: self.entry_name.insert(0, task.name) self.entry_description.insert(0, task.description) else: log_error('No se encontró la tarea seleccionada')
class Download(Frame): def __init__(self, master, **kwargs): super(Download, self).__init__(master, borderwidth=20, **kwargs) self.fs = None self.tree = None self.logfile = None # User informations self.info_tree = False self.start_time = None info = Frame(self, borderwidth=10) self.info_label = Label(info, wraplength=350, borderwidth=20, justify='center', font=('a', 10, 'bold')) self.info_indis = Label(info) self.info_fams = Label(info) self.info_sources = Label(info) self.info_notes = Label(info) self.time = Label(info) self.info_label.grid(row=0, column=0, columnspan=2) self.info_indis.grid(row=1, column=0) self.info_fams.grid(row=1, column=1) self.info_sources.grid(row=2, column=0) self.info_notes.grid(row=2, column=1) self.time.grid(row=3, column=0, columnspan=2) self.form = Frame(self) self.sign_in = SignIn(self.form) self.options = None self.title = Label(self, text=_('Sign In to FamilySearch'), font=('a', 12, 'bold')) buttons = Frame(self) self.btn_quit = Button(buttons, text=_('Quit'), command=Thread(target=self.quit).start) self.btn_valid = Button(buttons, text=_('Sign In'), command=self.command_in_thread(self.login)) self.title.pack() self.sign_in.pack() self.form.pack() self.btn_quit.pack(side='left', padx=(0, 40)) self.btn_valid.pack(side='right', padx=(40, 0)) info.pack() buttons.pack(side='bottom') self.pack() self.update_needed = False def info(self, text): self.info_label.config(text=text) def save(self): filename = filedialog.asksaveasfilename(title=_('Save as'), defaultextension='.ged', filetypes=(('GEDCOM', '.ged'), (_('All files'), '*.*'))) if not filename: return with open(filename, 'w', encoding='utf-8') as file: self.tree.print(file) def login(self): global _ username = self.sign_in.username.get() password = self.sign_in.password.get() if not (username and password): messagebox.showinfo(message=_('Please enter your FamilySearch username and password.')) return self.btn_valid.config(state='disabled') self.info(_('Login to FamilySearch...')) self.logfile = open('download.log', 'w', encoding='utf-8') self.fs = Session(self.sign_in.username.get(), self.sign_in.password.get(), verbose=True, logfile=self.logfile, timeout=1) if not self.fs.logged: messagebox.showinfo(_('Error'), message=_('The username or password was incorrect')) self.btn_valid.config(state='normal') self.info('') return self.tree = Tree(self.fs) _ = self.fs._ self.title.config(text=_('Options')) cache.delete('lang') cache.add('lang', self.fs.lang) self.options = Options(self.form, True) self.info('') self.sign_in.destroy() self.options.pack() self.master.change_lang() self.btn_valid.config(command=self.command_in_thread(self.download), state='normal', text=_('Download')) self.options.start_indis.add_indi(self.fs.get_userid()) self.update_needed = False def quit(self): self.update_needed = False if self.logfile: self.logfile.close() super(Download, self).quit() # prevent exception during download os._exit(1) def download(self): todo = [self.options.start_indis.indis[key] for key in sorted(self.options.start_indis.indis)] for fid in todo: if not re.match(r'[A-Z0-9]{4}-[A-Z0-9]{3}', fid): messagebox.showinfo(_('Error'), message=_('Invalid FamilySearch ID: ') + fid) return self.start_time = time.time() self.options.destroy() self.form.destroy() self.title.config(text='FamilySearch to GEDCOM') self.btn_valid.config(state='disabled') self.info(_('Download starting individuals...')) self.info_tree = True self.tree.add_indis(todo) todo = set(todo) done = set() for i in range(self.options.ancestors.get()): if not todo: break done |= todo self.info(_('Download ') + str(i + 1) + _('th generation of ancestors...')) todo = self.tree.add_parents(todo) - done todo = set(self.tree.indi.keys()) done = set() for i in range(self.options.descendants.get()): if not todo: break done |= todo self.info(_('Download ') + str(i + 1) + _('th generation of descendants...')) todo = self.tree.add_children(todo) - done if self.options.spouses.get(): self.info(_('Download spouses and marriage information...')) todo = set(self.tree.indi.keys()) self.tree.add_spouses(todo) ordi = self.options.ordinances.get() cont = self.options.contributors.get() async def download_stuff(loop): futures = set() for fid, indi in self.tree.indi.items(): futures.add(loop.run_in_executor(None, indi.get_notes)) if ordi: futures.add(loop.run_in_executor(None, self.tree.add_ordinances, fid)) if cont: futures.add(loop.run_in_executor(None, indi.get_contributors)) for fam in self.tree.fam.values(): futures.add(loop.run_in_executor(None, fam.get_notes)) if cont: futures.add(loop.run_in_executor(None, fam.get_contributors)) for future in futures: await future loop = asyncio.get_event_loop() self.info(_('Download notes') + (((',' if cont else _(' and')) + _(' ordinances')) if ordi else '') + (_(' and contributors') if cont else '') + '...') loop.run_until_complete(download_stuff(loop)) self.tree.reset_num() self.btn_valid.config(command=self.save, state='normal', text=_('Save')) self.info(text=_('Success ! Click below to save your GEDCOM file')) self.update_info_tree() self.update_needed = False def command_in_thread(self, func): def res(): self.update_needed = True Thread(target=self.update_gui).start() Thread(target=func).start() return res def update_info_tree(self): if self.info_tree and self.start_time and self.tree: self.info_indis.config(text=_('Individuals: %s') % len(self.tree.indi)) self.info_fams.config(text=_('Families: %s') % len(self.tree.fam)) self.info_sources.config(text=_('Sources: %s') % len(self.tree.sources)) self.info_notes.config(text=_('Notes: %s') % len(self.tree.notes)) t = round(time.time() - self.start_time) minutes = t // 60 seconds = t % 60 self.time.config(text=_('Elapsed time: %s:%s') % (minutes, '00%s'[len(str(seconds)):] % seconds)) def update_gui(self): while self.update_needed: self.update_info_tree() self.master.update() time.sleep(0.1)
class DialogPluginManager(Toplevel): def __init__(self, mainWin, modulesWithNewerFileDates): super(DialogPluginManager, self).__init__(mainWin.parent) self.ENABLE = _("Enable") self.DISABLE = _("Disable") self.parent = mainWin.parent self.cntlr = mainWin # copy plugins for temporary display self.pluginConfig = PluginManager.pluginConfig self.pluginConfigChanged = False self.uiClassMethodsChanged = False self.modelClassesChanged = False self.disclosureSystemTypesChanged = False self.hostSystemFeaturesChanged = False self.modulesWithNewerFileDates = modulesWithNewerFileDates parentGeometry = re.match("(\d+)x(\d+)[+]?([-]?\d+)[+]?([-]?\d+)", self.parent.geometry()) dialogX = int(parentGeometry.group(3)) dialogY = int(parentGeometry.group(4)) self.title(_("Plug-in Manager")) frame = Frame(self) # left button frame buttonFrame = Frame(frame, width=40) buttonFrame.columnconfigure(0, weight=1) addLabel = Label(buttonFrame, text=_("Find plug-in modules:"), wraplength=60, justify="center") addLocalButton = Button(buttonFrame, text=_("Locally"), command=self.findLocally) ToolTip(addLocalButton, text=_("File chooser allows selecting python module files to add (or reload) plug-ins, from the local file system."), wraplength=240) addWebButton = Button(buttonFrame, text=_("On Web"), command=self.findOnWeb) ToolTip(addWebButton, text=_("Dialog to enter URL full path to load (or reload) plug-ins, from the web or local file system."), wraplength=240) addLabel.grid(row=0, column=0, pady=4) addLocalButton.grid(row=1, column=0, pady=4) addWebButton.grid(row=2, column=0, pady=4) buttonFrame.grid(row=0, column=0, rowspan=2, sticky=(N, S, W), padx=3, pady=3) # right tree frame (plugins already known to arelle) modulesFrame = Frame(frame, width=700) vScrollbar = Scrollbar(modulesFrame, orient=VERTICAL) hScrollbar = Scrollbar(modulesFrame, orient=HORIZONTAL) self.modulesView = Treeview(modulesFrame, xscrollcommand=hScrollbar.set, yscrollcommand=vScrollbar.set, height=7) self.modulesView.grid(row=0, column=0, sticky=(N, S, E, W)) self.modulesView.bind('<<TreeviewSelect>>', self.moduleSelect) hScrollbar["command"] = self.modulesView.xview hScrollbar.grid(row=1, column=0, sticky=(E,W)) vScrollbar["command"] = self.modulesView.yview vScrollbar.grid(row=0, column=1, sticky=(N,S)) modulesFrame.columnconfigure(0, weight=1) modulesFrame.rowconfigure(0, weight=1) modulesFrame.grid(row=0, column=1, columnspan=4, sticky=(N, S, E, W), padx=3, pady=3) self.modulesView.focus_set() self.modulesView.column("#0", width=120, anchor="w") self.modulesView.heading("#0", text=_("Name")) self.modulesView["columns"] = ("author", "ver", "status", "date", "update", "descr", "license") self.modulesView.column("author", width=100, anchor="w", stretch=False) self.modulesView.heading("author", text=_("Author")) self.modulesView.column("ver", width=50, anchor="w", stretch=False) self.modulesView.heading("ver", text=_("Version")) self.modulesView.column("status", width=50, anchor="w", stretch=False) self.modulesView.heading("status", text=_("Status")) self.modulesView.column("date", width=70, anchor="w", stretch=False) self.modulesView.heading("date", text=_("File Date")) self.modulesView.column("update", width=50, anchor="w", stretch=False) self.modulesView.heading("update", text=_("Update")) self.modulesView.column("descr", width=200, anchor="w", stretch=False) self.modulesView.heading("descr", text=_("Description")) self.modulesView.column("license", width=70, anchor="w", stretch=False) self.modulesView.heading("license", text=_("License")) classesFrame = Frame(frame) vScrollbar = Scrollbar(classesFrame, orient=VERTICAL) hScrollbar = Scrollbar(classesFrame, orient=HORIZONTAL) self.classesView = Treeview(classesFrame, xscrollcommand=hScrollbar.set, yscrollcommand=vScrollbar.set, height=5) self.classesView.grid(row=0, column=0, sticky=(N, S, E, W)) hScrollbar["command"] = self.classesView.xview hScrollbar.grid(row=1, column=0, sticky=(E,W)) vScrollbar["command"] = self.classesView.yview vScrollbar.grid(row=0, column=1, sticky=(N,S)) classesFrame.columnconfigure(0, weight=1) classesFrame.rowconfigure(0, weight=1) classesFrame.grid(row=1, column=1, columnspan=4, sticky=(N, S, E, W), padx=3, pady=3) self.classesView.focus_set() self.classesView.column("#0", width=200, anchor="w") self.classesView.heading("#0", text=_("Class")) self.classesView["columns"] = ("modules",) self.classesView.column("modules", width=500, anchor="w", stretch=False) self.classesView.heading("modules", text=_("Modules")) # bottom frame module info details moduleInfoFrame = Frame(frame, width=700) moduleInfoFrame.columnconfigure(1, weight=1) self.moduleNameLabel = Label(moduleInfoFrame, wraplength=600, justify="left", font=font.Font(family='Helvetica', size=12, weight='bold')) self.moduleNameLabel.grid(row=0, column=0, columnspan=4, sticky=W) self.moduleAuthorHdr = Label(moduleInfoFrame, text=_("author:"), state=DISABLED) self.moduleAuthorHdr.grid(row=1, column=0, sticky=W) self.moduleAuthorLabel = Label(moduleInfoFrame, wraplength=600, justify="left") self.moduleAuthorLabel.grid(row=1, column=1, columnspan=3, sticky=W) self.moduleDescrHdr = Label(moduleInfoFrame, text=_("description:"), state=DISABLED) self.moduleDescrHdr.grid(row=2, column=0, sticky=W) self.moduleDescrLabel = Label(moduleInfoFrame, wraplength=600, justify="left") self.moduleDescrLabel.grid(row=2, column=1, columnspan=3, sticky=W) self.moduleClassesHdr = Label(moduleInfoFrame, text=_("classes:"), state=DISABLED) self.moduleClassesHdr.grid(row=3, column=0, sticky=W) self.moduleClassesLabel = Label(moduleInfoFrame, wraplength=600, justify="left") self.moduleClassesLabel.grid(row=3, column=1, columnspan=3, sticky=W) ToolTip(self.moduleClassesLabel, text=_("List of classes that this plug-in handles."), wraplength=240) self.moduleUrlHdr = Label(moduleInfoFrame, text=_("URL:"), state=DISABLED) self.moduleUrlHdr.grid(row=4, column=0, sticky=W) self.moduleUrlLabel = Label(moduleInfoFrame, wraplength=600, justify="left") self.moduleUrlLabel.grid(row=4, column=1, columnspan=3, sticky=W) ToolTip(self.moduleUrlLabel, text=_("URL of plug-in module (local file path or web loaded file)."), wraplength=240) self.moduleDateHdr = Label(moduleInfoFrame, text=_("date:"), state=DISABLED) self.moduleDateHdr.grid(row=5, column=0, sticky=W) self.moduleDateLabel = Label(moduleInfoFrame, wraplength=600, justify="left") self.moduleDateLabel.grid(row=5, column=1, columnspan=3, sticky=W) ToolTip(self.moduleDateLabel, text=_("Date of currently loaded module file (with parenthetical node when an update is available)."), wraplength=240) self.moduleLicenseHdr = Label(moduleInfoFrame, text=_("license:"), state=DISABLED) self.moduleLicenseHdr.grid(row=6, column=0, sticky=W) self.moduleLicenseLabel = Label(moduleInfoFrame, wraplength=600, justify="left") self.moduleLicenseLabel.grid(row=6, column=1, columnspan=3, sticky=W) self.moduleImportsHdr = Label(moduleInfoFrame, text=_("imports:"), state=DISABLED) self.moduleImportsHdr.grid(row=7, column=0, sticky=W) self.moduleImportsLabel = Label(moduleInfoFrame, wraplength=600, justify="left") self.moduleImportsLabel.grid(row=7, column=1, columnspan=3, sticky=W) self.moduleEnableButton = Button(moduleInfoFrame, text=self.ENABLE, state=DISABLED, command=self.moduleEnable) ToolTip(self.moduleEnableButton, text=_("Enable/disable plug in."), wraplength=240) self.moduleEnableButton.grid(row=8, column=1, sticky=E) self.moduleReloadButton = Button(moduleInfoFrame, text=_("Reload"), state=DISABLED, command=self.moduleReload) ToolTip(self.moduleReloadButton, text=_("Reload/update plug in."), wraplength=240) self.moduleReloadButton.grid(row=8, column=2, sticky=E) self.moduleRemoveButton = Button(moduleInfoFrame, text=_("Remove"), state=DISABLED, command=self.moduleRemove) ToolTip(self.moduleRemoveButton, text=_("Remove plug in from plug in table (does not erase the plug in's file)."), wraplength=240) self.moduleRemoveButton.grid(row=8, column=3, sticky=E) moduleInfoFrame.grid(row=2, column=0, columnspan=5, sticky=(N, S, E, W), padx=3, pady=3) moduleInfoFrame.config(borderwidth=4, relief="groove") okButton = Button(frame, text=_("Close"), command=self.ok) ToolTip(okButton, text=_("Accept and changes (if any) and close dialog."), wraplength=240) cancelButton = Button(frame, text=_("Cancel"), command=self.close) ToolTip(cancelButton, text=_("Cancel changes (if any) and close dialog."), wraplength=240) okButton.grid(row=3, column=3, sticky=(S,E), pady=3) cancelButton.grid(row=3, column=4, sticky=(S,E), pady=3, padx=3) enableDisableFrame = Frame(frame) enableDisableFrame.grid(row=3, column=1, sticky=(S,W), pady=3) enableAllButton = Button(enableDisableFrame, text=_("Enable All"), command=self.enableAll) ToolTip(enableAllButton, text=_("Enable all plug ins."), wraplength=240) disableAllButton = Button(enableDisableFrame, text=_("Disable All"), command=self.disableAll) ToolTip(disableAllButton, text=_("Disable all plug ins."), wraplength=240) enableAllButton.grid(row=1, column=1) disableAllButton.grid(row=1, column=2) self.loadTreeViews() self.geometry("+{0}+{1}".format(dialogX+50,dialogY+100)) frame.grid(row=0, column=0, sticky=(N,S,E,W)) frame.columnconfigure(0, weight=0) frame.columnconfigure(1, weight=1) frame.rowconfigure(0, weight=1) window = self.winfo_toplevel() window.columnconfigure(0, weight=1) window.rowconfigure(0, weight=1) self.bind("<Return>", self.ok) self.bind("<Escape>", self.close) self.protocol("WM_DELETE_WINDOW", self.close) self.grab_set() self.wait_window(self) def loadTreeViews(self): self.selectedModule = None # clear previous treeview entries for previousNode in self.modulesView.get_children(""): self.modulesView.delete(previousNode) def loadSubtree(parentNode, moduleItems): for moduleItem in sorted(moduleItems, key=lambda item: item[0]): moduleInfo = moduleItem[1] if parentNode or not moduleInfo.get("isImported"): nodeName = moduleItem[0] if parentNode: nodeName = parentNode + GROUPSEP + nodeName name = moduleInfo.get("name", nodeName) node = self.modulesView.insert(parentNode, "end", nodeName, text=name) self.modulesView.set(node, "author", moduleInfo.get("author")) self.modulesView.set(node, "ver", moduleInfo.get("version")) self.modulesView.set(node, "status", moduleInfo.get("status")) self.modulesView.set(node, "date", moduleInfo.get("fileDate")) if name in self.modulesWithNewerFileDates: self.modulesView.set(node, "update", _("available")) self.modulesView.set(node, "descr", moduleInfo.get("description")) self.modulesView.set(node, "license", moduleInfo.get("license")) if moduleInfo.get("imports"): loadSubtree(node, [(importModuleInfo["name"],importModuleInfo) for importModuleInfo in moduleInfo["imports"]]) loadSubtree("", self.pluginConfig.get("modules", {}).items()) # clear previous treeview entries for previousNode in self.classesView.get_children(""): self.classesView.delete(previousNode) for i, classItem in enumerate(sorted(self.pluginConfig.get("classes", {}).items())): className, moduleList = classItem node = self.classesView.insert("", "end", className, text=className) self.classesView.set(node, "modules", ', '.join(moduleList)) self.moduleSelect() # clear out prior selection def ok(self, event=None): if self.pluginConfigChanged: PluginManager.pluginConfig = self.pluginConfig PluginManager.pluginConfigChanged = True PluginManager.reset() # force reloading of modules if self.uiClassMethodsChanged or self.modelClassesChanged or self.disclosureSystemTypesChanged or self.hostSystemFeaturesChanged: # may require reloading UI affectedItems = "" if self.uiClassMethodsChanged: affectedItems += _("menus of the user interface") if self.modelClassesChanged: if affectedItems: affectedItems += _(" and ") affectedItems += _("model objects of the processor") if self.disclosureSystemTypesChanged: if affectedItems: affectedItems += _(" and ") affectedItems += _("disclosure system types") if self.hostSystemFeaturesChanged: if affectedItems: affectedItems += _(" and ") affectedItems += _("host system features") if messagebox.askyesno(_("User interface plug-in change"), _("A change in plug-in class methods may have affected {0}. " "Please restart Arelle to due to these changes. \n\n" "Should Arelle restart itself now " "(if there are any unsaved changes they would be lost!)?" ).format(affectedItems), parent=self): self.cntlr.uiThreadQueue.put((self.cntlr.quit, [None, True])) self.close() def close(self, event=None): self.parent.focus_set() self.destroy() def moduleSelect(self, *args): node = (self.modulesView.selection() or (None,))[0] if node: node = node.rpartition(GROUPSEP)[2] # drop leading path names for module name moduleInfo = self.pluginConfig.get("modules", {}).get(node) if moduleInfo: self.selectedModule = node name = moduleInfo["name"] self.moduleNameLabel.config(text=name) self.moduleAuthorHdr.config(state=ACTIVE) self.moduleAuthorLabel.config(text=moduleInfo["author"]) self.moduleDescrHdr.config(state=ACTIVE) self.moduleDescrLabel.config(text=moduleInfo["description"]) self.moduleClassesHdr.config(state=ACTIVE) self.moduleClassesLabel.config(text=', '.join(moduleInfo["classMethods"])) self.moduleUrlHdr.config(state=ACTIVE) self.moduleUrlLabel.config(text=moduleInfo["moduleURL"]) self.moduleDateHdr.config(state=ACTIVE) self.moduleDateLabel.config(text=moduleInfo["fileDate"] + " " + (_("(an update is available)") if name in self.modulesWithNewerFileDates else "")) self.moduleLicenseHdr.config(state=ACTIVE) self.moduleLicenseLabel.config(text=moduleInfo["license"]) if moduleInfo.get("imports"): self.moduleImportsHdr.config(state=ACTIVE) _text = ", ".join(mi["name"] for mi in moduleInfo["imports"][:3]) if len(moduleInfo["imports"]) >= 3: _text += ", ..." self.moduleImportsLabel.config(text=_text) _buttonState = DISABLED if moduleInfo.get("isImported") else ACTIVE self.moduleEnableButton.config(state=_buttonState, text={"enabled":self.DISABLE, "disabled":self.ENABLE}[moduleInfo["status"]]) self.moduleReloadButton.config(state=_buttonState) self.moduleRemoveButton.config(state=_buttonState) else: self.selectedModule = None self.moduleNameLabel.config(text="") self.moduleAuthorHdr.config(state=DISABLED) self.moduleAuthorLabel.config(text="") self.moduleDescrHdr.config(state=DISABLED) self.moduleDescrLabel.config(text="") self.moduleClassesHdr.config(state=DISABLED) self.moduleClassesLabel.config(text="") self.moduleUrlHdr.config(state=DISABLED) self.moduleUrlLabel.config(text="") self.moduleDateHdr.config(state=DISABLED) self.moduleDateLabel.config(text="") self.moduleLicenseHdr.config(state=DISABLED) self.moduleLicenseLabel.config(text="") self.moduleImportsHdr.config(state=DISABLED) self.moduleImportsLabel.config(text="") self.moduleEnableButton.config(state=DISABLED, text=self.ENABLE) self.moduleReloadButton.config(state=DISABLED) self.moduleRemoveButton.config(state=DISABLED) def findLocally(self): initialdir = self.cntlr.pluginDir # default plugin directory if not self.cntlr.isMac: # can't navigate within app easily, always start in default directory initialdir = self.cntlr.config.setdefault("pluginOpenDir", initialdir) filename = self.cntlr.uiFileDialog("open", parent=self, title=_("Choose plug-in module file"), initialdir=initialdir, filetypes=[(_("Python files"), "*.py")], defaultextension=".py") if filename: # check if a package is selected (any file in a directory containing an __init__.py #if (os.path.basename(filename) == "__init__.py" and os.path.isdir(os.path.dirname(filename)) and # os.path.isfile(filename)): # filename = os.path.dirname(filename) # refer to the package instead self.cntlr.config["pluginOpenDir"] = os.path.dirname(filename) moduleInfo = PluginManager.moduleModuleInfo(filename) self.loadFoundModuleInfo(moduleInfo, filename) def findOnWeb(self): url = DialogURL.askURL(self) if url: # url is the in-cache or local file moduleInfo = PluginManager.moduleModuleInfo(url) self.cntlr.showStatus("") # clear web loading status self.loadFoundModuleInfo(moduleInfo, url) def loadFoundModuleInfo(self, moduleInfo, url): if moduleInfo and moduleInfo.get("name"): self.addPluginConfigModuleInfo(moduleInfo) self.loadTreeViews() else: messagebox.showwarning(_("Module is not itself a plug-in or in a directory with package __init__.py plug-in. "), _("File does not itself contain a python program with an appropriate __pluginInfo__ declaration: \n\n{0}") .format(url), parent=self) def checkIfImported(self, moduleInfo): if moduleInfo.get("isImported"): messagebox.showwarning(_("Plug-in is imported by a parent plug-in. "), _("Plug-in has a parent, please request operation on the parent: \n\n{0}") .format(moduleInfo.get("name")), parent=self) return True return False def removePluginConfigModuleInfo(self, name): moduleInfo = self.pluginConfig["modules"].get(name) if moduleInfo: if self.checkIfImported(moduleInfo): return; def _removePluginConfigModuleInfo(moduleInfo): _name = moduleInfo.get("name") if _name: for classMethod in moduleInfo["classMethods"]: classMethods = self.pluginConfig["classes"].get(classMethod) if classMethods and _name in classMethods: classMethods.remove(_name) if not classMethods: # list has become unused del self.pluginConfig["classes"][classMethod] # remove class if classMethod.startswith("CntlrWinMain.Menu"): self.uiClassMethodsChanged = True # may require reloading UI elif classMethod == "ModelObjectFactory.ElementSubstitutionClasses": self.modelClassesChanged = True # model object factor classes changed elif classMethod == "DisclosureSystem.Types": self.disclosureSystemTypesChanged = True # disclosure system types changed elif classMethod.startswith("Proxy."): self.hostSystemFeaturesChanged = True # system features (e.g., proxy) changed for importModuleInfo in moduleInfo.get("imports", EMPTYLIST): _removePluginConfigModuleInfo(importModuleInfo) self.pluginConfig["modules"].pop(_name, None) _removePluginConfigModuleInfo(moduleInfo) self.pluginConfigChanged = True def addPluginConfigModuleInfo(self, moduleInfo): if self.checkIfImported(moduleInfo): return; name = moduleInfo.get("name") self.removePluginConfigModuleInfo(name) # remove any prior entry for this module def _addPlugin(moduleInfo): _name = moduleInfo.get("name") if _name: self.modulesWithNewerFileDates.discard(_name) # no longer has an update available self.pluginConfig["modules"][_name] = moduleInfo # add classes for classMethod in moduleInfo["classMethods"]: classMethods = self.pluginConfig["classes"].setdefault(classMethod, []) if name not in classMethods: classMethods.append(_name) if classMethod.startswith("CntlrWinMain.Menu"): self.uiClassMethodsChanged = True # may require reloading UI elif classMethod == "ModelObjectFactory.ElementSubstitutionClasses": self.modelClassesChanged = True # model object factor classes changed elif classMethod == "DisclosureSystem.Types": self.disclosureSystemTypesChanged = True # disclosure system types changed elif classMethod.startswith("Proxy."): self.hostSystemFeaturesChanged = True # system features (e.g., proxy) changed for importModuleInfo in moduleInfo.get("imports", EMPTYLIST): _addPlugin(importModuleInfo) _addPlugin(moduleInfo) self.pluginConfigChanged = True def moduleEnable(self): if self.selectedModule in self.pluginConfig["modules"]: moduleInfo = self.pluginConfig["modules"][self.selectedModule] if self.checkIfImported(moduleInfo): return; def _moduleEnable(moduleInfo): if self.moduleEnableButton['text'] == self.ENABLE: moduleInfo["status"] = "enabled" elif self.moduleEnableButton['text'] == self.DISABLE: moduleInfo["status"] = "disabled" for importModuleInfo in moduleInfo.get("imports", EMPTYLIST): _moduleEnable(importModuleInfo) _moduleEnable(moduleInfo) if self.moduleEnableButton['text'] == self.ENABLE: self.moduleEnableButton['text'] = self.DISABLE elif self.moduleEnableButton['text'] == self.DISABLE: self.moduleEnableButton['text'] = self.ENABLE self.pluginConfigChanged = True self.loadTreeViews() def moduleReload(self): if self.selectedModule in self.pluginConfig["modules"]: url = self.pluginConfig["modules"][self.selectedModule].get("moduleURL") if url: moduleInfo = PluginManager.moduleModuleInfo(url, reload=True) if moduleInfo: if self.checkIfImported(moduleInfo): return; self.addPluginConfigModuleInfo(moduleInfo) self.loadTreeViews() self.cntlr.showStatus(_("{0} reloaded").format(moduleInfo["name"]), clearAfter=5000) else: messagebox.showwarning(_("Module error"), _("File or module cannot be reloaded: \n\n{0}") .format(url), parent=self) def moduleRemove(self): if self.selectedModule in self.pluginConfig["modules"]: self.removePluginConfigModuleInfo(self.selectedModule) self.pluginConfigChanged = True self.loadTreeViews() def enableAll(self): self.enableDisableAll(True) def disableAll(self): self.enableDisableAll(False) def enableDisableAll(self, doEnable): for module in self.pluginConfig["modules"]: if not module.get("isImported"): moduleInfo = self.pluginConfig["modules"][module] def _enableDisableAll(moduleInfo): if doEnable: moduleInfo["status"] = "enabled" else: moduleInfo["status"] = "disabled" for importModuleInfo in moduleInfo.get("imports", EMPTYLIST): _enableDisableAll(importModuleInfo) _enableDisableAll(moduleInfo) if doEnable: self.moduleEnableButton['text'] = self.DISABLE else: self.moduleEnableButton['text'] = self.ENABLE self.pluginConfigChanged = True self.loadTreeViews()