def base_ui_run( inputFilename: str = "", outputFilename: str = "", inputFormat: str = "", outputFormat: str = "", reverse: bool = False, configOptions: "Optional[Dict]" = None, readOptions: "Optional[Dict]" = None, writeOptions: "Optional[Dict]" = None, convertOptions: "Optional[Dict]" = None, ): from pyglossary.glossary import Glossary if reverse: log.error("--reverse does not work with --ui=none") return False ui = UIBase() ui.loadConfig(**configOptions) glos = Glossary(ui=ui) glos.config = ui.config glos.convert(inputFilename=inputFilename, outputFilename=outputFilename, inputFormat=inputFormat, outputFormat=outputFormat, readOptions=readOptions, writeOptions=writeOptions, **convertOptions) return True
def main(): parser = argparse.ArgumentParser(add_help=False) parser.add_argument( "-v", "--verbosity", action="store", dest="verbosity", type=int, choices=(0, 1, 2, 3, 4, 5), required=False, default=3, ) parser.add_argument( "--log-time", dest="log_time", action="store_true", default=None, ) parser.add_argument( "--no-log-time", dest="log_time", action="store_false", default=None, ) parser.add_argument( "--version", action="version", version=f"PyGlossary {VERSION}", ) parser.add_argument( "-h", "--help", dest="help", action="store_true", ) parser.add_argument( "-u", "--ui", dest="ui_type", default="auto", choices=( "cmd", "gtk", "tk", # "qt", "auto", "none", ), ) parser.add_argument( "-r", "--read-options", dest="readOptions", default="", ) parser.add_argument( "-w", "--write-options", dest="writeOptions", default="", ) parser.add_argument( "--read-format", dest="inputFormat", ) parser.add_argument( "--write-format", dest="outputFormat", action="store", ) parser.add_argument( "--direct", dest="direct", action="store_true", default=None, help="if possible, convert directly without loading into memory", ) parser.add_argument( "--indirect", dest="direct", action="store_false", default=None, help=( "disable `direct` mode, load full data into memory before writing" ", this is default"), ) parser.add_argument( "--no-alts", dest="enable_alts", action="store_false", default=None, help="disable alternates", ) parser.add_argument( "--no-progress-bar", dest="progressbar", action="store_false", default=None, ) parser.add_argument( "--no-color", dest="noColor", action="store_true", ) parser.add_argument( "--sort", dest="sort", action="store_true", default=None, ) parser.add_argument( "--no-sort", dest="sort", action="store_false", default=None, ) parser.add_argument( "--sort-cache-size", dest="sortCacheSize", type=int, default=None, ) parser.add_argument( "--skip-resources", dest="skipResources", action="store_true", default=None, help="skip resources (images, audio, etc)", ) parser.add_argument( "--utf8-check", dest="utf8Check", action="store_true", default=None, ) parser.add_argument( "--no-utf8-check", dest="utf8Check", action="store_false", default=None, ) parser.add_argument( "--lower", dest="lower", action="store_true", default=None, help="lowercase words before writing", ) parser.add_argument( "--no-lower", dest="lower", action="store_false", default=None, help="do not lowercase words before writing", ) parser.add_argument( "--remove-html", dest="remove_html", help="remove given html tags (comma-separated) from definitions", ) parser.add_argument( "--remove-html-all", dest="remove_html_all", action="store_true", help="remove all html tags from definitions", ) parser.add_argument( "--normalize-html", dest="normalize_html", action="store_true", help="lowercase and normalize html tags in definitions", ) parser.add_argument( "--cleanup", dest="cleanup", action="store_true", default=None, help="cleanup cache or temporary files after convertion", ) parser.add_argument( "--no-cleanup", dest="cleanup", action="store_false", default=None, help="do not cleanup cache or temporary files after convertion", ) # _______________________________ parser.add_argument( "--info", dest="save_info_json", action="store_true", help="save glossary info as json file with .info extension", ) # _______________________________ parser.add_argument( "--reverse", dest="reverse", action="store_true", ) parser.add_argument( "inputFilename", action="store", default="", nargs="?", ) parser.add_argument( "outputFilename", action="store", default="", nargs="?", ) # _______________________________ args = parser.parse_args() log = logging.getLogger("pyglossary") defaultVerbosity = log.getVerbosity() log.setVerbosity(args.verbosity) log.addHandler(core.StdLogHandler(noColor=args.noColor), ) # with the logger setted up, we can import other pyglossary modules, so they # can do some loggging in right way. core.checkCreateConfDir() if sys.getdefaultencoding() != "utf-8": log.warn( f"System encoding is not utf-8, it's {sys.getdefaultencoding()!r}") ############################## from pyglossary.glossary import Glossary, langDict from pyglossary.ui.ui_cmd import help, parseFormatOptionsStr Glossary.init() if log.isDebug(): log.debug(f"en -> {langDict['en']!r}") ############################## ui_list = ( "gtk", "tk", "qt", ) # log.info("PyGlossary %s"%VERSION) if args.help: help() sys.exit(0) if os.sep != "/": args.noColor = True # only used in ui_cmd for now readOptions = parseFormatOptionsStr(args.readOptions) if readOptions is None: return writeOptions = parseFormatOptionsStr(args.writeOptions) if writeOptions is None: return """ examples for read and write options: --read-options testOption=stringValue --read-options enableFoo=True --read-options fooList=[1,2,3] --read-options 'fooList=[1, 2, 3]' --read-options 'testOption=stringValue; enableFoo=True; fooList=[1, 2, 3]' --read-options 'testOption=stringValue;enableFoo=True;fooList=[1,2,3]' """ prefOptionsKeys = ( # "verbosity", "utf8Check", "lower", "skipResources", "enable_alts", "remove_html", "remove_html_all", "normalize_html", "save_info_json", "log_time", "cleanup", ) convertOptionsKeys = ( "direct", "progressbar", "sort", "sortCacheSize", # "sortKey", # TODO ) prefOptions = {} for param in prefOptionsKeys: value = getattr(args, param, None) if value is not None: prefOptions[param] = value convertOptions = {} for param in convertOptionsKeys: value = getattr(args, param, None) if value is not None: convertOptions[param] = value if convertOptions.get("sort", False): convertOptions["defaultSortKey"] = Entry.defaultSortKey if args.inputFilename and readOptions: inputFormat = Glossary.detectInputFormat( args.inputFilename, format=args.inputFormat, ) if not inputFormat: log.error( f"Could not detect format for input file {args.inputFilename}") sys.exit(1) readOptionsProp = Glossary.plugins[inputFormat].optionsProp for optName, optValue in readOptions.items(): if optName not in Glossary.formatsReadOptions[inputFormat]: log.error( f"Invalid option name {optName} for format {inputFormat}") sys.exit(1) prop = readOptionsProp[optName] optValueNew, ok = prop.evaluate(optValue) if not ok or not prop.validate(optValueNew): log.error(f"Invalid option value {optName}={optValue!r}" f" for format {inputFormat}") sys.exit(1) readOptions[optName] = optValueNew if args.outputFilename and writeOptions: _, outputFormat, _ = Glossary.detectOutputFormat( filename=args.outputFilename, format=args.outputFormat, inputFilename=args.inputFilename, ) if not outputFormat: log.error( f"Could not detect format for output file {args.outputFilename}" ) sys.exit(1) writeOptionsProp = Glossary.plugins[outputFormat].optionsProp for optName, optValue in writeOptions.items(): if optName not in Glossary.formatsWriteOptions[outputFormat]: log.error( f"Invalid option name {optName} for format {outputFormat}") sys.exit(1) prop = writeOptionsProp[optName] optValueNew, ok = prop.evaluate(optValue) if not ok or not prop.validate(optValueNew): log.error(f"Invalid option value {optName}={optValue!r}" f" for format {outputFormat}") sys.exit(1) writeOptions[optName] = optValueNew if prefOptions: log.debug("prefOptions = %s", prefOptions) if convertOptions: log.debug("convertOptions = %s", convertOptions) """ ui_type: User interface type Possible values: cmd - Command line interface, this ui will automatically selected if you give both input and output file gtk - GTK interface tk - Tkinter interface qt - Qt interface auto - Use the first available UI """ ui_type = args.ui_type if args.inputFilename: if args.outputFilename and ui_type != "none": ui_type = "cmd" else: if ui_type == "cmd": log.error("no input file given, try --help") exit(1) if ui_type == "none": if args.reverse: log.error("--reverse does not work with --ui=none") sys.exit(1) glos = Glossary() glos.convert(args.inputFilename, inputFormat=args.inputFormat, outputFilename=args.outputFilename, outputFormat=args.outputFormat, readOptions=readOptions, writeOptions=writeOptions, **convertOptions) sys.exit(0) elif ui_type == "cmd": from ui import ui_cmd sys.exit(0 if ui_cmd.UI().run( args.inputFilename, outputFilename=args.outputFilename, inputFormat=args.inputFormat, outputFormat=args.outputFormat, reverse=args.reverse, prefOptions=prefOptions, readOptions=readOptions, writeOptions=writeOptions, convertOptions=convertOptions, ) else 1) if ui_type == "auto": ui_module = None for ui_type2 in ui_list: try: ui_module = getattr( __import__(f"ui.ui_{ui_type2}"), f"ui_{ui_type2}", ) except ImportError: log.exception("error while importing UI module:") else: break if ui_module is None: log.error("no user interface module found! " f"try \"{sys.argv[0]} -h\" to see command line usage") sys.exit(1) else: ui_module = getattr( __import__(f"ui.ui_{ui_type}"), f"ui_{ui_type}", ) sys.exit(0 if ui_module.UI(**prefOptions).run( editPath=args.inputFilename, readOptions=readOptions, ) else 1)
class UI(gtk.Dialog, MyDialog, UIBase): def status(self, msg): # try: # _id = self.statusMsgDict[msg] # except KeyError: # _id = self.statusMsgDict[msg] = self.statusNewId # self.statusNewId += 1 _id = self.statusBar.get_context_id(msg) self.statusBar.push(_id, msg) def __init__(self): gtk.Dialog.__init__(self) UIBase.__init__(self) self.set_title("PyGlossary (Gtk3)") self.resize(800, 800) self.connect("delete-event", self.onDeleteEvent) self.pages = [] # self.statusNewId = 0 # self.statusMsgDict = {}## message -> id ##### self._convertOptions = {} ##### self.assert_quit = False self.path = "" self.glos = Glossary(ui=self) self.glos.config = self.config # ____________________ Tab 1 - Convert ____________________ # labelSizeGroup = gtk.SizeGroup(mode=gtk.SizeGroupMode.HORIZONTAL) buttonSizeGroup = gtk.SizeGroup(mode=gtk.SizeGroupMode.HORIZONTAL) #### vbox = VBox() vbox.label = _("Convert") vbox.icon = "" # "*.png" self.pages.append(vbox) ###### hbox = HBox(spacing=3) hbox.label = gtk.Label(label=_("Input File:")) pack(hbox, hbox.label) labelSizeGroup.add_widget(hbox.label) hbox.label.set_property("xalign", 0) self.convertInputEntry = gtk.Entry() pack(hbox, self.convertInputEntry, 1, 1) button = BrowseButton( self.convertInputEntry.set_text, label="Browse", actionSave=False, title="Select Input File", ) pack(hbox, button) buttonSizeGroup.add_widget(button) pack(vbox, hbox) ## self.convertInputEntry.connect( "changed", self.convertInputEntryChanged, ) ### hbox = HBox(spacing=3) hbox.label = gtk.Label(label=_("Input Format:")) pack(hbox, hbox.label) labelSizeGroup.add_widget(hbox.label) hbox.label.set_property("xalign", 0) self.convertInputFormatCombo = InputFormatBox(parent=self) buttonSizeGroup.add_widget(self.convertInputFormatCombo.optionsButton) pack(hbox, self.convertInputFormatCombo) pack(hbox, gtk.Label(), 1, 1) pack(hbox, self.convertInputFormatCombo.dependsButton) pack(hbox, self.convertInputFormatCombo.optionsButton) pack(vbox, hbox) ##### vbox.sep1 = gtk.Label(label="") vbox.sep1.show() pack(vbox, vbox.sep1) ##### hbox = HBox(spacing=3) hbox.label = gtk.Label(label=_("Output File:")) pack(hbox, hbox.label) labelSizeGroup.add_widget(hbox.label) hbox.label.set_property("xalign", 0) self.convertOutputEntry = gtk.Entry() pack(hbox, self.convertOutputEntry, 1, 1) button = BrowseButton( self.convertOutputEntry.set_text, label="Browse", actionSave=True, title="Select Output File", ) pack(hbox, button) buttonSizeGroup.add_widget(button) pack(vbox, hbox) ## self.convertOutputEntry.connect( "changed", self.convertOutputEntryChanged, ) ### hbox = HBox(spacing=3) hbox.label = gtk.Label(label=_("Output Format:")) pack(hbox, hbox.label) labelSizeGroup.add_widget(hbox.label) hbox.label.set_property("xalign", 0) self.convertOutputFormatCombo = OutputFormatBox(parent=self) buttonSizeGroup.add_widget(self.convertOutputFormatCombo.optionsButton) pack(hbox, self.convertOutputFormatCombo) pack(hbox, gtk.Label(), 1, 1) pack(hbox, self.convertOutputFormatCombo.dependsButton) pack(hbox, self.convertOutputFormatCombo.optionsButton) pack(vbox, hbox) ##### hbox = HBox(spacing=10) label = gtk.Label(label="") pack(hbox, label, 1, 1, 10) self.convertButton = gtk.Button() self.convertButton.set_label("Convert") self.convertButton.connect("clicked", self.convertClicked) self.convertButton.set_size_request(300, 40) pack(hbox, self.convertButton, 0, 0, 10) pack(vbox, hbox, 0, 0, 15) #### self.convertConsoleTextview = textview = gtk.TextView() swin = gtk.ScrolledWindow() swin.set_policy(gtk.PolicyType.AUTOMATIC, gtk.PolicyType.AUTOMATIC) swin.set_border_width(0) swin.add(textview) pack(vbox, swin, 1, 1) # ____________________ Tab 2 - Reverse ____________________ # self.reverseStatus = "" #### labelSizeGroup = gtk.SizeGroup(mode=gtk.SizeGroupMode.HORIZONTAL) #### vbox = VBox() vbox.label = _("Reverse") vbox.icon = "" # "*.png" # self.pages.append(vbox) ###### hbox = HBox(spacing=3) hbox.label = gtk.Label(label=_("Input Format:")) pack(hbox, hbox.label) labelSizeGroup.add_widget(hbox.label) hbox.label.set_property("xalign", 0) self.reverseInputFormatCombo = InputFormatBox() pack(hbox, self.reverseInputFormatCombo) pack(vbox, hbox) ### hbox = HBox(spacing=3) hbox.label = gtk.Label(label=_("Input File:")) pack(hbox, hbox.label) labelSizeGroup.add_widget(hbox.label) hbox.label.set_property("xalign", 0) self.reverseInputEntry = gtk.Entry() pack(hbox, self.reverseInputEntry, 1, 1) button = BrowseButton( self.reverseInputEntry.set_text, label="Browse", actionSave=False, title="Select Input File", ) pack(hbox, button) pack(vbox, hbox) ## self.reverseInputEntry.connect( "changed", self.reverseInputEntryChanged, ) ##### vbox.sep1 = gtk.Label(label="") vbox.sep1.show() pack(vbox, vbox.sep1) ##### hbox = HBox(spacing=3) hbox.label = gtk.Label(label=_("Output Tabfile:")) pack(hbox, hbox.label) labelSizeGroup.add_widget(hbox.label) hbox.label.set_property("xalign", 0) self.reverseOutputEntry = gtk.Entry() pack(hbox, self.reverseOutputEntry, 1, 1) button = BrowseButton( self.reverseOutputEntry.set_text, label="Browse", actionSave=True, title="Select Output File", ) pack(hbox, button) pack(vbox, hbox) ## self.reverseOutputEntry.connect( "changed", self.reverseOutputEntryChanged, ) ##### hbox = HBox(spacing=3) label = gtk.Label(label="") pack(hbox, label, 1, 1, 5) ### self.reverseStartButton = gtk.Button() self.reverseStartButton.set_label(_("Start")) self.reverseStartButton.connect("clicked", self.reverseStartClicked) pack(hbox, self.reverseStartButton, 1, 1, 2) ### self.reversePauseButton = gtk.Button() self.reversePauseButton.set_label(_("Pause")) self.reversePauseButton.set_sensitive(False) self.reversePauseButton.connect("clicked", self.reversePauseClicked) pack(hbox, self.reversePauseButton, 1, 1, 2) ### self.reverseResumeButton = gtk.Button() self.reverseResumeButton.set_label(_("Resume")) self.reverseResumeButton.set_sensitive(False) self.reverseResumeButton.connect("clicked", self.reverseResumeClicked) pack(hbox, self.reverseResumeButton, 1, 1, 2) ### self.reverseStopButton = gtk.Button() self.reverseStopButton.set_label(_("Stop")) self.reverseStopButton.set_sensitive(False) self.reverseStopButton.connect("clicked", self.reverseStopClicked) pack(hbox, self.reverseStopButton, 1, 1, 2) ### pack(vbox, hbox, 0, 0, 5) ###### about = AboutWidget( logo=logo, header=f"PyGlossary\nVersion {core.VERSION}", # about=summary, about=f'{aboutText}\n<a href="{core.homePage}">{core.homePage}</a>', authors="\n".join(authors), license=licenseText, ) about.label = _("About") about.icon = "" # "*.png" self.pages.append(about) ##### # ____________________________________________________________ # notebook = gtk.Notebook() self.notebook = notebook ######### for vbox in self.pages: label = gtk.Label(label=vbox.label) label.set_use_underline(True) vb = VBox(spacing=3) if vbox.icon: vbox.image = imageFromFile(vbox.icon) pack(vb, vbox.image) pack(vb, label) vb.show_all() notebook.append_page(vbox, vb) try: notebook.set_tab_reorderable(vbox, True) except AttributeError: pass ####################### pack(self.vbox, notebook, 1, 1) # for i in ui.pagesOrder: # try: # j = pagesOrder[i] # except IndexError: # continue # notebook.reorder_child(self.pages[i], j) # ____________________________________________________________ # handler = GtkSingleTextviewLogHandler(textview) log.addHandler(handler) ### textview.override_background_color( gtk.StateFlags.NORMAL, gdk.RGBA(0, 0, 0, 1), ) ### handler.setColor("CRITICAL", rgba_parse("red")) handler.setColor("ERROR", rgba_parse("red")) handler.setColor("WARNING", rgba_parse("yellow")) handler.setColor("INFO", rgba_parse("white")) handler.setColor("DEBUG", rgba_parse("white")) ### textview.get_buffer().set_text("Output & Error Console:\n") textview.set_editable(False) # ____________________________________________________________ # self.progressTitle = "" self.progressBar = pbar = gtk.ProgressBar() pbar.set_fraction(0) # pbar.set_text(_("Progress Bar")) # pbar.get_style_context() # pbar.set_property("height-request", 20) pack(self.vbox, pbar, 0, 0) ############ hbox = HBox(spacing=5) clearButton = gtk.Button( use_stock=gtk.STOCK_CLEAR, always_show_image=True, label=_("Clear"), ) clearButton.show_all() # image = gtk.Image() # image.set_from_stock(gtk.STOCK_CLEAR, gtk.IconSize.MENU) # clearButton.add(image) clearButton.set_border_width(0) clearButton.connect("clicked", self.consoleClearButtonClicked) set_tooltip(clearButton, "Clear Console") pack(hbox, clearButton, 0, 0) #### # hbox.sepLabel1 = gtk.Label(label="") # pack(hbox, hbox.sepLabel1, 1, 1) ###### hbox.verbosityLabel = gtk.Label(label=_("Verbosity:")) pack(hbox, hbox.verbosityLabel, 0, 0) ## self.verbosityCombo = combo = gtk.ComboBoxText() for level, levelName in enumerate(log.levelNamesCap): combo.append_text(f"{level} - {_(levelName)}") combo.set_active(log.getVerbosity()) combo.set_border_width(0) combo.connect("changed", self.verbosityComboChanged) pack(hbox, combo, 0, 0) #### # hbox.sepLabel2 = gtk.Label(label="") # pack(hbox, hbox.sepLabel2, 1, 1) #### self.statusBar = sbar = gtk.Statusbar() pack(hbox, self.statusBar, 1, 1) #### hbox.resizeButton = ResizeButton(self) pack(hbox, hbox.resizeButton, 0, 0) ###### pack(self.vbox, hbox, 0, 0) # ____________________________________________________________ # self.vbox.show_all() notebook.set_current_page(0) # Convert tab self.convertInputFormatCombo.dependsButton.hide() self.convertOutputFormatCombo.dependsButton.hide() self.convertInputFormatCombo.optionsButton.hide() self.convertOutputFormatCombo.optionsButton.hide() ######## self.status("Select input file") def run( self, inputFilename: str = "", outputFilename: str = "", inputFormat: str = "", outputFormat: str = "", reverse: bool = False, configOptions: "Optional[Dict]" = None, readOptions: "Optional[Dict]" = None, writeOptions: "Optional[Dict]" = None, convertOptions: "Optional[Dict]" = None, ): self.loadConfig(**configOptions) if inputFilename: self.convertInputEntry.set_text(abspath(inputFilename)) if outputFilename: self.convertOutputEntry.set_text(abspath(outputFilename)) if inputFormat: self.convertInputFormatCombo.setActive(inputFormat) if outputFormat: self.convertOutputFormatCombo.setActive(outputFormat) if reverse: log.error(f"Gtk interface does not support Reverse feature") if readOptions: self.convertInputFormatCombo.setOptionsValues(readOptions) if writeOptions: self.convertOutputFormatCombo.setOptionsValues(writeOptions) self._convertOptions = convertOptions if convertOptions: log.info(f"Using convertOptions={convertOptions}") gtk.Dialog.present(self) gtk.main() def onDeleteEvent(self, widget, event): self.destroy() # gtk.main_quit() # if callled while converting, main_quit does not exit program, # it keeps printing warnings, # and makes you close the terminal or force kill the proccess sys.exit(0) def consoleClearButtonClicked(self, widget=None): self.convertConsoleTextview.get_buffer().set_text("") def verbosityComboChanged(self, widget=None): verbosity = self.verbosityCombo.get_active() # or int(self.verbosityCombo.get_active_text()) log.setVerbosity(verbosity) def convertClicked(self, widget=None): inPath = self.convertInputEntry.get_text() if not inPath: self.status("Input file path is empty!") log.critical("Input file path is empty!") return inFormat = self.convertInputFormatCombo.getActive() if inFormat: inFormatDesc = Glossary.plugins[inFormat].description else: inFormatDesc = "" # log.critical("Input format is empty!");return outPath = self.convertOutputEntry.get_text() if not outPath: self.status("Output file path is empty!") log.critical("Output file path is empty!") return outFormat = self.convertOutputFormatCombo.getActive() if outFormat: outFormatDesc = Glossary.plugins[outFormat].description else: outFormatDesc = "" # log.critical("Output format is empty!");return while gtk.events_pending(): gtk.main_iteration_do(False) self.convertButton.set_sensitive(False) self.progressTitle = "Converting" readOptions = self.convertInputFormatCombo.optionsValues writeOptions = self.convertOutputFormatCombo.optionsValues try: # if inFormat=="Omnidic": # dicIndex = self.xml.get_widget("spinbutton_omnidic_i")\ # .get_value_as_int() # ex = self.glos.readOmnidic(inPath, dicIndex=dicIndex) # else: log.debug(f"readOptions: {readOptions}") log.debug(f"writeOptions: {writeOptions}") finalOutputFile = self.glos.convert( inPath, inputFormat=inFormat, outputFilename=outPath, outputFormat=outFormat, readOptions=readOptions, writeOptions=writeOptions, **self._convertOptions, ) if finalOutputFile: self.status("Convert finished") else: self.status("Convert failed") return bool(finalOutputFile) finally: self.convertButton.set_sensitive(True) self.assert_quit = False self.progressTitle = "" return True def convertInputEntryChanged(self, widget=None): inPath = self.convertInputEntry.get_text() inFormat = self.convertInputFormatCombo.getActive() if inPath.startswith("file://"): inPath = urlToPath(inPath) self.convertInputEntry.set_text(inPath) if self.config["ui_autoSetFormat"] and not inFormat: inputArgs = Glossary.detectInputFormat(inPath, quiet=True) if inputArgs: inFormatNew = inputArgs[1] self.convertInputFormatCombo.setActive(inFormatNew) if not isfile(inPath): return self.status("Select output file") def convertOutputEntryChanged(self, widget=None): outPath = self.convertOutputEntry.get_text() outFormat = self.convertOutputFormatCombo.getActive() if not outPath: return if outPath.startswith("file://"): outPath = urlToPath(outPath) self.convertOutputEntry.set_text(outPath) if self.config["ui_autoSetFormat"] and not outFormat: outputArgs = Glossary.detectOutputFormat( filename=outPath, inputFilename=self.convertInputEntry.get_text(), quiet=True, ) if outputArgs: outFormat = outputArgs[1] self.convertOutputFormatCombo.setActive(outFormat) if outFormat: self.status("Press \"Convert\"") else: self.status("Select output format") def reverseLoad(self): pass def reverseStartLoop(self): pass def reverseStart(self): if not self.reverseLoad(): return ### self.reverseStatus = "doing" self.reverseStartLoop() ### self.reverseStartButton.set_sensitive(False) self.reversePauseButton.set_sensitive(True) self.reverseResumeButton.set_sensitive(False) self.reverseStopButton.set_sensitive(True) def reverseStartClicked(self, widget=None): self.waitingDo(self.reverseStart) def reversePause(self): self.reverseStatus = "pause" ### self.reverseStartButton.set_sensitive(False) self.reversePauseButton.set_sensitive(False) self.reverseResumeButton.set_sensitive(True) self.reverseStopButton.set_sensitive(True) def reversePauseClicked(self, widget=None): self.waitingDo(self.reversePause) def reverseResume(self): self.reverseStatus = "doing" ### self.reverseStartButton.set_sensitive(False) self.reversePauseButton.set_sensitive(True) self.reverseResumeButton.set_sensitive(False) self.reverseStopButton.set_sensitive(True) def reverseResumeClicked(self, widget=None): self.waitingDo(self.reverseResume) def reverseStop(self): self.reverseStatus = "stop" ### self.reverseStartButton.set_sensitive(True) self.reversePauseButton.set_sensitive(False) self.reverseResumeButton.set_sensitive(False) self.reverseStopButton.set_sensitive(False) def reverseStopClicked(self, widget=None): self.waitingDo(self.reverseStop) def reverseInputEntryChanged(self, widget=None): inPath = self.reverseInputEntry.get_text() inFormat = self.reverseInputFormatCombo.getActive() if inPath.startswith("file://"): inPath = urlToPath(inPath) self.reverseInputEntry.set_text(inPath) if not inFormat and self.config["ui_autoSetFormat"]: inputArgs = Glossary.detectInputFormat(inPath, quiet=True) if inputArgs: inFormat = inputArgs[1] self.reverseInputFormatCombo.setActive(inFormat) def reverseOutputEntryChanged(self, widget=None): pass def progressInit(self, title): self.progressTitle = title def progress(self, rat, text=None): if not text: text = "%" + str(int(rat * 100)) text += " - " + self.progressTitle self.progressBar.set_fraction(rat) # self.progressBar.set_text(text) # not working self.status(text) while gtk.events_pending(): gtk.main_iteration_do(False)
else: if ui_type == "cmd": log.error("no input file given, try --help") exit(1) if ui_type == "none": if args.reverse: log.error("--reverse does not work with --ui=none") sys.exit(1) glos = Glossary() glos.convert( args.inputFilename, inputFormat=args.inputFormat, outputFilename=args.outputFilename, outputFormat=args.outputFormat, readOptions=readOptions, writeOptions=writeOptions, **convertOptions ) sys.exit(0) elif ui_type == "cmd": from ui import ui_cmd sys.exit(0 if ui_cmd.UI().run( args.inputFilename, outputFilename=args.outputFilename, inputFormat=args.inputFormat, outputFormat=args.outputFormat, reverse=args.reverse, prefOptions=prefOptions, readOptions=readOptions,
class UI(tix.Frame, UIBase): fcd_dir_save_path = join(confDir, "ui-tk-fcd-dir") def __init__(self): rootWin = self.rootWin = tix.Tk() # a hack that hides the window until we move it to the center of screen if os.sep == "\\": # Windows rootWin.attributes('-alpha', 0.0) else: # Linux rootWin.withdraw() tix.Frame.__init__(self, rootWin) UIBase.__init__(self) rootWin.title("PyGlossary (Tkinter)") rootWin.resizable(True, False) ######## set_window_icon(rootWin) rootWin.bind('<Escape>', lambda e: rootWin.quit()) ######### # Linux: ('clam', 'alt', 'default', 'classic') # Windows: ('winnative', 'clam', 'alt', 'default', 'classic', 'vista', 'xpnative') # style = ttk.Style() # style.theme_use("default") ######## self.pack(fill="x") # rootWin.bind("<Configure>", self.resized) ####################### defaultFont = tkFont.nametofont('TkDefaultFont') if core.sysName in ("linux", "freebsd"): defaultFont.configure(size=int(defaultFont.cget("size") * 1.4)) #### self.biggerFont = defaultFont.copy() self.biggerFont.configure(size=int(defaultFont.cget("size") * 1.8)) ###################### self.glos = Glossary(ui=self) self.glos.config = self.config self._convertOptions = {} self.pathI = "" self.pathO = "" fcd_dir = join(homeDir, "Desktop") if isfile(self.fcd_dir_save_path): try: with open(self.fcd_dir_save_path, encoding="utf-8") as fp: fcd_dir = fp.read().strip("\n") except Exception: log.exception("") self.fcd_dir = fcd_dir ###################### notebook = tix.NoteBook(self) notebook.add("tabConvert", label="Convert", underline=0) # notebook.add("tabReverse", label="Reverse", underline=0) notebook.add("tabAbout", label="About", underline=0) convertFrame = tix.Frame(notebook.tabConvert) aboutFrame = tix.Frame(notebook.tabAbout) ################### row = 0 label = ttk.Label(convertFrame, text="Input File: ") label.grid( row=row, column=0, sticky=tk.W, padx=5, ) ## entry = tix.Entry(convertFrame) entry.grid( row=row, column=1, columnspan=2, sticky=tk.W + tk.E, padx=0, ) entry.bind_all("<KeyPress>", self.anyEntryChanged) self.entryInputConvert = entry ## button = newButton( convertFrame, text="Browse", command=self.browseInputConvert, # bg="#f0f000", # activebackground="#f6f622", borderwidth=3, ) button.grid( row=row, column=3, sticky=tk.W + tk.E, padx=5, ) ###################### row += 1 label = ttk.Label(convertFrame, text="Input Format: ") label.grid( row=row, column=0, sticky=tk.W, padx=5, ) ## self.formatButtonInputConvert = FormatButton( master=convertFrame, descList=readDesc, dialogTitle="Select Input Format", onChange=self.inputFormatChanged, ) self.formatButtonInputConvert.grid( row=row, column=1, columnspan=2, sticky=tk.W, padx=0, ) ## self.readOptions = {} # type: Dict[str, Any] self.writeOptions = {} # type: Dict[str, Any] ## self.readOptionsButton = FormatOptionsButton( "Read", self.readOptions, self.formatButtonInputConvert, master=convertFrame, ) self.inputFormatRow = row ###################### row += 1 label = ttk.Label(convertFrame) label.grid( row=row, column=0, sticky=tk.W, ) ################### row += 1 label = ttk.Label(convertFrame, text="Output File: ") label.grid( row=row, column=0, sticky=tk.W, padx=5, ) ## entry = tix.Entry(convertFrame) entry.grid( row=row, column=1, columnspan=2, sticky=tk.W + tk.E, padx=0, ) entry.bind_all("<KeyPress>", self.anyEntryChanged) self.entryOutputConvert = entry ## button = newButton( convertFrame, text="Browse", command=self.browseOutputConvert, # bg="#f0f000", # activebackground="#f6f622", borderwidth=3, ) button.grid( row=row, column=3, sticky=tk.W + tk.E, padx=5, ) ###################### row += 1 label = ttk.Label(convertFrame, text="Output Format: ") label.grid( row=row, column=0, sticky=tk.W, padx=5, ) ## self.formatButtonOutputConvert = FormatButton( master=convertFrame, descList=writeDesc, dialogTitle="Select Output Format", onChange=self.outputFormatChanged, ) self.formatButtonOutputConvert.grid( row=row, column=1, columnspan=2, sticky=tk.W, padx=0, ) ## self.writeOptionsButton = FormatOptionsButton( "Write", self.writeOptions, self.formatButtonOutputConvert, master=convertFrame, ) self.outputFormatRow = row ################### row += 1 button = newButton( convertFrame, text="Convert", command=self.convert, # background="#00e000", # activebackground="#22f022", borderwidth=7, font=self.biggerFont, padx=5, pady=5, ) button.grid( row=row, column=2, columnspan=3, sticky=tk.W + tk.E + tk.S, padx=5, pady=5, ) # print(f"row number for Convert button: {row}") ###### convertFrame.pack(fill="x") # convertFrame.grid(sticky=tk.W + tk.E + tk.N + tk.S) ################# row += 1 console = tix.Text( convertFrame, height=15, background="#000", foreground="#fff", ) console.bind("<Key>", self.consoleKeyPress) # self.consoleH = 15 # sbar = Tix.Scrollbar( # convertFrame, # orien=Tix.VERTICAL, # command=console.yview # ) # sbar.grid (row=row, column=1) # console["yscrollcommand"] = sbar.set console.grid( row=row, column=0, columnspan=4, sticky=tk.W + tk.E, padx=5, pady=0, ) log.addHandler(TkTextLogHandler(console), ) console.insert("end", "Console:\n") #### self.console = console ################## aboutFrame2 = tix.Frame(aboutFrame) ## label = newLabelWithImage(aboutFrame2, file=logo) label.pack(side="left") ## ## label = ttk.Label(aboutFrame2, text=f"PyGlossary\nVersion {core.VERSION}") label.pack(side="left") ## aboutFrame2.pack(side="top", fill="x") ## style = ttk.Style(self) style.configure("TNotebook", tabposition="wn") # ws => to the left (west) and to the bottom (south) # wn => to the left (west) and at top aboutNotebook = ttk.Notebook(aboutFrame, style="TNotebook") aboutFrame3 = tk.Frame(aboutNotebook) authorsFrame = tk.Frame(aboutNotebook) licenseFrame = tk.Frame(aboutNotebook) # tabImg = tk.PhotoImage(file=join(resDir, "dialog-information-22.png")) # tabImg = tk.PhotoImage(file=join(resDir, "author-22.png")) aboutNotebook.add( aboutFrame3, text="\n About \n", # image=tabImg, # not working # compound=tk.TOP, # padding=50, # not working ) aboutNotebook.add( authorsFrame, text="\nAuthors\n", ) aboutNotebook.add( licenseFrame, text="\nLicense\n", ) label = newReadOnlyText( aboutFrame3, text=f"{aboutText}\nHome page: {core.homePage}", font=("DejaVu Sans", 11, ""), ) label.pack(fill="x") authorsText = "\n".join(authors) authorsText = authorsText.replace("\t", " ") label = newReadOnlyText( authorsFrame, text=authorsText, font=("DejaVu Sans", 11, ""), ) label.pack(fill="x") label = newReadOnlyText( licenseFrame, text=licenseText, font=("DejaVu Sans", 11, ""), ) label.pack(fill="x") aboutNotebook.pack(fill="x") aboutFrame.pack(fill="x") ###################### tk.Grid.columnconfigure(convertFrame, 0, weight=1) tk.Grid.columnconfigure(convertFrame, 1, weight=30) tk.Grid.columnconfigure(convertFrame, 2, weight=20) tk.Grid.columnconfigure(convertFrame, 3, weight=1) tk.Grid.rowconfigure(convertFrame, 0, weight=50) tk.Grid.rowconfigure(convertFrame, 1, weight=50) tk.Grid.rowconfigure(convertFrame, 2, weight=1) tk.Grid.rowconfigure(convertFrame, 3, weight=50) tk.Grid.rowconfigure(convertFrame, 4, weight=50) tk.Grid.rowconfigure(convertFrame, 5, weight=1) tk.Grid.rowconfigure(convertFrame, 6, weight=50) # _________________________________________________________________ # notebook.pack(fill="both", expand=True) # _________________________________________________________________ # statusBarframe = tk.Frame(self, borderwidth=3) clearB = newButton( statusBarframe, text="Clear", command=self.console_clear, # bg="black", # fg="#ffff00", # activebackground="#333333", # activeforeground="#ffff00", borderwidth=3, height=2, ) clearB.pack(side="left") #### label = ttk.Label(statusBarframe, text="Verbosity") label.pack(side="left") ## comboVar = tk.StringVar() combo = ttk.OptionMenu( statusBarframe, comboVar, log.getVerbosity(), # default 0, 1, 2, 3, 4, 5, ) comboVar.trace("w", self.verbosityChanged) combo.pack(side="left") self.verbosityCombo = comboVar ##### pbar = ProgressBar(statusBarframe, width=700, height=28) pbar.pack(side="left", fill="x", expand=True) self.pbar = pbar statusBarframe.pack(fill="x") self.progressTitle = "" # _________________________________________________________________ # centerWindow(rootWin) # show the window if os.sep == "\\": # Windows rootWin.attributes('-alpha', 1.0) else: # Linux rootWin.deiconify() def textSelectAll(self, tktext): tktext.tag_add(tk.SEL, "1.0", tk.END) tktext.mark_set(tk.INSERT, "1.0") tktext.see(tk.INSERT) def consoleKeyPress(self, e): # print(e.state, e.keysym) if e.state > 0: if e.keysym == "c": return if e.keysym == "a": self.textSelectAll(self.console) return "break" if e.keysym == "Escape": return return "break" def verbosityChanged(self, index, value, op): log.setVerbosity(int(self.verbosityCombo.get())) def resized(self, event): dh = self.rootWin.winfo_height() - self.winfo_height() # log.debug(dh, self.consoleH) # if dh > 20: # self.consoleH += 1 # self.console["height"] = self.consoleH # self.console["width"] = int(self.console["width"]) + 1 # self.console.grid() # for x in dir(self): # if "info" in x: # log.debug(x) def inputFormatChanged(self, *args): formatDesc = self.formatButtonInputConvert.get() if not formatDesc: return self.readOptions.clear() # reset the options, DO NOT re-assign format = pluginByDesc[formatDesc].name if Glossary.formatsReadOptions[format]: self.readOptionsButton.grid( row=self.inputFormatRow, column=3, sticky=tk.W + tk.E, padx=5, pady=0, ) else: self.readOptionsButton.grid_forget() def outputFormatChanged(self, *args): formatDesc = self.formatButtonOutputConvert.get() if not formatDesc: return self.writeOptions.clear() # reset the options, DO NOT re-assign format = pluginByDesc[formatDesc].name if Glossary.formatsWriteOptions[format]: self.writeOptionsButton.grid( row=self.outputFormatRow, column=3, sticky=tk.W + tk.E, padx=5, pady=0, ) else: self.writeOptionsButton.grid_forget() def anyEntryChanged(self, event=None): self.inputEntryChanged() self.outputEntryChanged() def inputEntryChanged(self, event=None): # char = event.keysym pathI = self.entryInputConvert.get() if self.pathI != pathI: if pathI.startswith("file://"): pathI = urlToPath(pathI) self.entryInputConvert.delete(0, "end") self.entryInputConvert.insert(0, pathI) if self.config["ui_autoSetFormat"]: formatDesc = self.formatButtonInputConvert.get() if not formatDesc: inputArgs = Glossary.detectInputFormat(pathI, quiet=True) if inputArgs: format = inputArgs[1] plugin = Glossary.plugins.get(format) if plugin: self.formatButtonInputConvert.set( plugin.description) self.inputFormatChanged() self.pathI = pathI def outputEntryChanged(self, event=None): pathO = self.entryOutputConvert.get() if self.pathO != pathO: if pathO.startswith("file://"): pathO = urlToPath(pathO) self.entryOutputConvert.delete(0, "end") self.entryOutputConvert.insert(0, pathO) if self.config["ui_autoSetFormat"]: formatDesc = self.formatButtonOutputConvert.get() if not formatDesc: outputArgs = Glossary.detectOutputFormat( filename=pathO, inputFilename=self.entryInputConvert.get(), quiet=True, ) if outputArgs: outputFormat = outputArgs[1] self.formatButtonOutputConvert.set( Glossary.plugins[outputFormat].description) self.outputFormatChanged() self.pathO = pathO def save_fcd_dir(self): if not self.fcd_dir: return with open(self.fcd_dir_save_path, mode="w", encoding="utf-8") as fp: fp.write(self.fcd_dir) def browseInputConvert(self): path = filedialog.askopenfilename(initialdir=self.fcd_dir) if path: self.entryInputConvert.delete(0, "end") self.entryInputConvert.insert(0, path) self.inputEntryChanged() self.fcd_dir = os.path.dirname(path) self.save_fcd_dir() def browseOutputConvert(self): path = filedialog.asksaveasfilename() if path: self.entryOutputConvert.delete(0, "end") self.entryOutputConvert.insert(0, path) self.outputEntryChanged() self.fcd_dir = os.path.dirname(path) self.save_fcd_dir() def convert(self): inPath = self.entryInputConvert.get() if not inPath: log.critical("Input file path is empty!") return inFormatDesc = self.formatButtonInputConvert.get() if not inFormatDesc: # log.critical("Input format is empty!");return inFormat = "" else: inFormat = pluginByDesc[inFormatDesc].name outPath = self.entryOutputConvert.get() if not outPath: log.critical("Output file path is empty!") return outFormatDesc = self.formatButtonOutputConvert.get() if not outFormatDesc: log.critical("Output format is empty!") return outFormat = pluginByDesc[outFormatDesc].name finalOutputFile = self.glos.convert(inPath, inputFormat=inFormat, outputFilename=outPath, outputFormat=outFormat, readOptions=self.readOptions, writeOptions=self.writeOptions, **self._convertOptions) # if finalOutputFile: # self.status("Convert finished") # else: # self.status("Convert failed") return bool(finalOutputFile) def run( self, inputFilename: str = "", outputFilename: str = "", inputFormat: str = "", outputFormat: str = "", reverse: bool = False, configOptions: "Optional[Dict]" = None, readOptions: "Optional[Dict]" = None, writeOptions: "Optional[Dict]" = None, convertOptions: "Optional[Dict]" = None, ): self.loadConfig(**configOptions) if inputFilename: self.entryInputConvert.insert(0, abspath(inputFilename)) self.inputEntryChanged() if outputFilename: self.entryOutputConvert.insert(0, abspath(outputFilename)) self.outputEntryChanged() if inputFormat: self.formatButtonInputConvert.set( Glossary.plugins[inputFormat].description) self.inputFormatChanged() if outputFormat: self.formatButtonOutputConvert.set( Glossary.plugins[outputFormat].description) self.outputFormatChanged() if reverse: log.error(f"Tkinter interface does not support Reverse feature") # must be before setting self.readOptions and self.writeOptions self.anyEntryChanged() if readOptions: self.readOptionsButton.setOptionsValues(readOptions) self.readOptions = readOptions if writeOptions: self.writeOptionsButton.setOptionsValues(writeOptions) self.writeOptions = writeOptions self._convertOptions = convertOptions if convertOptions: log.info(f"Using convertOptions={convertOptions}") # inputFilename and readOptions are for DB Editor # which is not implemented self.mainloop() def progressInit(self, title): self.progressTitle = title def progress(self, rat, text=""): if not text: text = "%" + str(int(rat * 100)) text += " - " + self.progressTitle self.pbar.updateProgress(rat * 100, None, text) # self.pbar.value = rat * 100 # self.pbar.update() self.rootWin.update() def console_clear(self, event=None): self.console.delete("1.0", "end") self.console.insert("end", "Console:\n")
def main(): parser = argparse.ArgumentParser(add_help=False) parser.add_argument( "-v", "--verbosity", action="store", dest="verbosity", type=int, choices=(0, 1, 2, 3, 4, 5), required=False, default=3, ) parser.add_argument( "--version", action="version", version=f"PyGlossary {core.VERSION}", ) parser.add_argument( "-h", "--help", dest="help", action="store_true", ) parser.add_argument( "-u", "--ui", dest="ui_type", default="auto", choices=( "cmd", "gtk", "tk", # "qt", "auto", "none", ), ) parser.add_argument( "--cmd", dest="ui_type", action="store_const", const="cmd", default=None, help="use command-line user interface", ) parser.add_argument( "--gtk", dest="ui_type", action="store_const", const="gtk", default=None, help="use Gtk-based user interface", ) parser.add_argument( "--tk", dest="ui_type", action="store_const", const="tk", default=None, help="use Tkinter-based user interface", ) parser.add_argument( "--no-interactive", dest="no_interactive", action="store_true", default=None, help= "do not automatically switch to interactive command line interface, for scripts", ) parser.add_argument( "-r", "--read-options", dest="readOptions", default="", ) parser.add_argument( "-w", "--write-options", dest="writeOptions", default="", ) parser.add_argument( "--json-read-options", dest="jsonReadOptions", default=None, ) parser.add_argument( "--json-write-options", dest="jsonWriteOptions", default=None, ) parser.add_argument( "--read-format", dest="inputFormat", ) parser.add_argument( "--write-format", dest="outputFormat", action="store", ) parser.add_argument( "--direct", dest="direct", action="store_true", default=None, help="if possible, convert directly without loading into memory", ) parser.add_argument( "--indirect", dest="direct", action="store_false", default=None, help=( "disable `direct` mode, load full data into memory before writing" ", this is default"), ) parser.add_argument( "--no-progress-bar", dest="progressbar", action="store_false", default=None, ) parser.add_argument( "--no-color", dest="noColor", action="store_true", default=(os.sep != "/"), ) parser.add_argument( "--sort", dest="sort", action="store_true", default=None, ) parser.add_argument( "--no-sort", dest="sort", action="store_false", default=None, ) parser.add_argument( "--sort-cache-size", dest="sortCacheSize", type=int, default=None, ) # _______________________________ parser.add_argument( "--reverse", dest="reverse", action="store_true", ) parser.add_argument( "inputFilename", action="store", default="", nargs="?", ) parser.add_argument( "outputFilename", action="store", default="", nargs="?", ) # _______________________________ for key, option in UIBase.configDefDict.items(): registerOption(parser, key, option) # _______________________________ args = parser.parse_args() log = logging.getLogger("pyglossary") defaultVerbosity = log.getVerbosity() log.setVerbosity(args.verbosity) log.addHandler(core.StdLogHandler(noColor=args.noColor), ) # with the logger setted up, we can import other pyglossary modules, so they # can do some loggging in right way. core.checkCreateConfDir() if sys.getdefaultencoding() != "utf-8": log.warn( f"System encoding is not utf-8, it's {sys.getdefaultencoding()!r}") ############################## from pyglossary.glossary import Glossary, langDict from pyglossary.ui.ui_cmd import help, parseFormatOptionsStr Glossary.init() if log.isDebug(): log.debug(f"en -> {langDict['en']!r}") ############################## ui_list = [ "gtk", "tk", ] # log.info(f"PyGlossary {core.VERSION}") if args.help: help() sys.exit(0) # only used in ui_cmd for now readOptions = parseFormatOptionsStr(args.readOptions) if readOptions is None: return if args.jsonReadOptions: newReadOptions = json.loads(args.jsonReadOptions) if isinstance(newReadOptions, dict): readOptions.update(newReadOptions) else: log.error(f"invalid value for --json-read-options, " f"must be an object/dict, not {type(newReadOptions)}") writeOptions = parseFormatOptionsStr(args.writeOptions) if writeOptions is None: return if args.jsonWriteOptions: newWriteOptions = json.loads(args.jsonWriteOptions) if isinstance(newWriteOptions, dict): writeOptions.update(newWriteOptions) else: log.error(f"invalid value for --json-write-options, " f"must be an object/dict, not {type(newWriteOptions)}") """ examples for read and write options: --read-options testOption=stringValue --read-options enableFoo=True --read-options fooList=[1,2,3] --read-options 'fooList=[1, 2, 3]' --read-options 'testOption=stringValue; enableFoo=True; fooList=[1, 2, 3]' --read-options 'testOption=stringValue;enableFoo=True;fooList=[1,2,3]' if a desired value contains ";", you can use --json-read-options or --json-write-options flags instead, with json object as value, quoted for command line for example: '--json-write-options={"delimiter": ";"}' """ convertOptionsKeys = ( "direct", "progressbar", "sort", "sortCacheSize", # "sortKey", # TODO ) config = {} for key, option in UIBase.configDefDict.items(): if not option.cmd: continue value = getattr(args, key, None) if value is None: continue option = UIBase.configDefDict[key] if not option.validate(value): log.error("invalid config value: {key} = {value!r}") continue config[key] = value convertOptions = {} for key in convertOptionsKeys: value = getattr(args, key, None) if value is not None: convertOptions[key] = value if convertOptions.get("sort", False): convertOptions["defaultSortKey"] = Entry.defaultSortKey if args.inputFilename and readOptions: inputArgs = Glossary.detectInputFormat( args.inputFilename, format=args.inputFormat, ) if not inputArgs: log.error( f"Could not detect format for input file {args.inputFilename}") sys.exit(1) inputFormat = inputArgs[1] readOptionsProp = Glossary.plugins[inputFormat].optionsProp for optName, optValue in readOptions.items(): if optName not in Glossary.formatsReadOptions[inputFormat]: log.error( f"Invalid option name {optName} for format {inputFormat}") sys.exit(1) prop = readOptionsProp[optName] optValueNew, ok = prop.evaluate(optValue) if not ok or not prop.validate(optValueNew): log.error(f"Invalid option value {optName}={optValue!r}" f" for format {inputFormat}") sys.exit(1) readOptions[optName] = optValueNew if args.outputFilename and writeOptions: _, outputFormat, _ = Glossary.detectOutputFormat( filename=args.outputFilename, format=args.outputFormat, inputFilename=args.inputFilename, ) if not outputFormat: log.error( f"Could not detect format for output file {args.outputFilename}" ) sys.exit(1) writeOptionsProp = Glossary.plugins[outputFormat].optionsProp for optName, optValue in writeOptions.items(): if optName not in Glossary.formatsWriteOptions[outputFormat]: log.error( f"Invalid option name {optName} for format {outputFormat}") sys.exit(1) prop = writeOptionsProp[optName] optValueNew, ok = prop.evaluate(optValue) if not ok or not prop.validate(optValueNew): log.error(f"Invalid option value {optName}={optValue!r}" f" for format {outputFormat}") sys.exit(1) writeOptions[optName] = optValueNew if config: log.debug(f"config = {config}") if convertOptions: log.debug(f"convertOptions = {convertOptions}") ui_type = args.ui_type if ui_type == "auto": if not canRunGUI() or (args.inputFilename and args.outputFilename): ui_type = "cmd" if ui_type == "none": if args.reverse: log.error("--reverse does not work with --ui=none") sys.exit(1) glos = Glossary() glos.convert(args.inputFilename, inputFormat=args.inputFormat, outputFilename=args.outputFilename, outputFormat=args.outputFormat, readOptions=readOptions, writeOptions=writeOptions, **convertOptions) sys.exit(0) runKeywordArgs = dict( inputFilename=args.inputFilename, outputFilename=args.outputFilename, inputFormat=args.inputFormat, outputFormat=args.outputFormat, reverse=args.reverse, configOptions=config, readOptions=readOptions, writeOptions=writeOptions, convertOptions=convertOptions, ) if ui_type == "cmd": if args.inputFilename and args.outputFilename: from ui.ui_cmd import UI elif not args.no_interactive: from ui.ui_cmd_interactive import UI else: log.error("no input file given, try --help") sys.exit(1) sys.exit(0 if UI().run(**runKeywordArgs) else 1) if ui_type == "auto": ui_module = None for ui_type2 in ui_list: try: ui_module = getattr( __import__(f"ui.ui_{ui_type2}"), f"ui_{ui_type2}", ) except ImportError: log.exception("error while importing UI module:") else: break if ui_module is None: log.error("no user interface module found! " f"try \"{sys.argv[0]} -h\" to see command line usage") sys.exit(1) else: ui_module = getattr( __import__(f"ui.ui_{ui_type}"), f"ui_{ui_type}", ) sys.exit(0 if ui_module.UI().run(**runKeywordArgs) else 1)
class UI(tix.Frame, UIBase): fcd_dir_save_path = join(confDir, "ui-tk-fcd-dir") def __init__(self, path="", **options): self.glos = Glossary(ui=self) self.pref = {} self.pref_load(**options) ############################################# rootWin = self.rootWin = tix.Tk() # a hack that hides the window until we move it to the center of screen if os.sep == "\\": # Windows rootWin.attributes('-alpha', 0.0) else: # Linux rootWin.withdraw() tix.Frame.__init__(self, rootWin) rootWin.title("PyGlossary (Tkinter)") rootWin.resizable(True, False) ######## set_window_icon(rootWin) rootWin.bind('<Escape>', lambda e: rootWin.quit()) ######## self.pack(fill="x") # rootWin.bind("<Configure>", self.resized) ###################### self.glos = Glossary(ui=self) self.pref = {} self.pref_load() self.pathI = "" self.pathO = "" fcd_dir = join(homeDir, "Desktop") if isfile(self.fcd_dir_save_path): try: with open(self.fcd_dir_save_path, encoding="utf-8") as fp: fcd_dir = fp.read().strip("\n") except Exception: log.exception("") self.fcd_dir = fcd_dir ###################### notebook = tix.NoteBook(self) notebook.add("tabConvert", label="Convert", underline=0) # notebook.add("tabReverse", label="Reverse", underline=0) notebook.add("tabAbout", label="About", underline=0) convertFrame = tix.Frame(notebook.tabConvert) aboutFrame = tix.Frame(notebook.tabAbout) convertVpaned = ttk.PanedWindow(convertFrame, orient=tk.VERTICAL) ###################### frame = tix.Frame(convertFrame) ## label = ttk.Label(frame, text="Read from format") label.pack(side="left") ## comboVar = tk.StringVar() combo = ttk.OptionMenu( frame, comboVar, None, # default *Glossary.readDesc, ) combo.pack(side="left") comboVar.trace("w", self.inputComboChanged) self.formatVarInputConvert = comboVar ## self.readOptions = {} # type: Dict[str, Any] self.writeOptions = {} # type: Dict[str, Any] ## self.readOptionsButton = FormatOptionsButton( "Read", self.readOptions, self.formatVarInputConvert, master=frame, ) ## frame.pack(fill="x") ################### frame = tix.Frame(convertFrame) ## label = ttk.Label(frame, text=" Path:") label.pack(side="left") ## entry = tix.Entry(frame) entry.pack(side="left", fill="x", expand=True) entry.bind_all("<KeyPress>", self.inputEntryChanged) self.entryInputConvert = entry ## button = ttk.Button( frame, text="Browse", command=self.browseInputConvert, # bg="#f0f000", # activebackground="#f6f622", ) button.pack(side="left") ## frame.pack(fill="x") ###################### frame = tix.Frame(convertFrame) ## label = ttk.Label(frame, text="Write to format ") label.pack(side="left") ## comboVar = tk.StringVar() combo = ttk.OptionMenu( frame, comboVar, None, # default *Glossary.writeDesc, ) combo.pack(side="left") comboVar.trace("w", self.outputComboChanged) self.formatVarOutputConvert = comboVar ## self.writeOptionsButton = FormatOptionsButton( "Write", self.writeOptions, self.formatVarOutputConvert, master=frame, ) ## frame.pack(fill="x") ################### frame = tix.Frame(convertFrame) ## label = ttk.Label(frame, text=" Path:") label.pack(side="left") ## entry = tix.Entry(frame) entry.pack(side="left", fill="x", expand=True) entry.bind_all("<KeyPress>", self.outputEntryChanged) self.entryOutputConvert = entry ## button = ttk.Button( frame, text="Browse", command=self.browseOutputConvert, # bg="#f0f000", # activebackground="#f6f622", ) button.pack(side="left") ## frame.pack(fill="x") ####### frame = tix.Frame(convertFrame) label = ttk.Label(frame, text=" " * 15) label.pack( side="left", fill="x", expand=True, ) button = ttk.Button( frame, text="Convert", command=self.convert, # bg="#00e000", # activebackground="#22f022", ) button.pack( side="left", fill="x", expand=True, ) ### frame.pack(fill="x") convertVpaned.add(frame) ###### convertFrame.pack(fill="x") ################# console = tix.Text(convertVpaned, height=15, background="#000000") # self.consoleH = 15 # sbar = Tix.Scrollbar( # convertVpaned, # orien=Tix.VERTICAL, # command=console.yview # ) # sbar.grid ( row=0, column=1) # console["yscrollcommand"] = sbar.set # console.grid() console.pack(fill="both", expand=True) log.addHandler(TkTextLogHandler(console), ) console.insert("end", "Console:\n") #### convertVpaned.add(console) convertVpaned.pack(fill="both", expand=True) self.console = console ################## # convertVpaned.grid() # bottomFrame.grid() # self.grid() ##################### # lbox = Tix.Listbox(convertFrame) # lbox.insert(0, "aaaaaaaa", "bbbbbbbbbbbbbbbbbbbb") # lbox.pack(fill="x") ############## # __________________________ Reverse Tab __________________________ # # revFrame = tix.Frame(notebook.tabReverse) # revFrame.pack(fill="x") # ###################### # frame = tix.Frame(revFrame) # ## # label = ttk.Label(frame, text="Read from format") # label.pack(side="left") # ## # comboVar = tk.StringVar() # combo = ttk.OptionMenu( # frame, # comboVar, # None, # default # *Glossary.readDesc, # ) # combo.pack(side="left") # self.combobox_r_i = comboVar # ## # frame.pack(fill="x") # ################### # frame = tix.Frame(revFrame) # ## # label = ttk.Label(frame, text=" Path:") # label.pack(side="left") # ## # entry = tix.Entry(frame) # entry.pack(side="left", fill="x", expand=True) # # entry.bind_all("<KeyPress>", self.entry_r_i_changed) # self.entry_r_i = entry # ## # button = ttk.Button( # frame, # text="Browse", # command=self.reverseBrowseInput, # # bg="#f0f000", # # activebackground="#f6f622", # ) # button.pack(side="left") # ## # button = ttk.Button( # frame, # text="Load", # command=self.reverseLoad, # # bg="#7777ff", # ) # button.pack(side="left") # ### # frame.pack(fill="x") # ################### # frame = tix.Frame(revFrame) # ## # label = ttk.Label(frame, text="Output Tabfile") # label.pack(side="left") # ### # entry = tix.Entry(frame) # entry.pack(side="left", fill="x", expand=True) # # entry.bind_all("<KeyPress>", self.entry_r_i_changed) # self.entry_r_o = entry # ## # button = ttk.Button( # frame, # text="Browse", # command=self.reverseBrowseOutput, # # bg="#f0f000", # # activebackground="#f6f622", # ) # button.pack(side="left") # ## # frame.pack(fill="x") # _________________________________________________________________ # aboutFrame2 = tix.Frame(aboutFrame) ## label = newLabelWithImage(aboutFrame2, file=logo) label.pack(side="left") ## ## label = ttk.Label(aboutFrame2, text=f"PyGlossary\nVersion {core.VERSION}") label.pack(side="left") ## aboutFrame2.pack(side="top", fill="x") ## style = ttk.Style(self) style.configure("TNotebook", tabposition="wn") # ws => to the left (west) and to the bottom (south) # wn => to the left (west) and at top aboutNotebook = ttk.Notebook(aboutFrame, style="TNotebook") aboutFrame3 = tk.Frame(aboutNotebook) authorsFrame = tk.Frame(aboutNotebook) licenseFrame = tk.Frame(aboutNotebook) # tabImg = tk.PhotoImage(file=join(resDir, "dialog-information-22.png")) # tabImg = tk.PhotoImage(file=join(resDir, "author-22.png")) aboutNotebook.add( aboutFrame3, text="\n About \n", # image=tabImg, # not working # compound=tk.TOP, # padding=50, # not working ) aboutNotebook.add( authorsFrame, text="\nAuthors\n", ) aboutNotebook.add( licenseFrame, text="\nLicense\n", ) label = newReadOnlyText( aboutFrame3, text=f"{aboutText}\nHome page: {homePage}", font=("DejaVu Sans", 11, ""), ) label.pack(fill="x") authorsText = "\n".join(authors) authorsText = authorsText.replace("\t", " ") label = newReadOnlyText( authorsFrame, text=authorsText, font=("DejaVu Sans", 11, ""), ) label.pack(fill="x") label = newReadOnlyText( licenseFrame, text=licenseText, font=("DejaVu Sans", 11, ""), ) label.pack(fill="x") aboutNotebook.pack(fill="x") aboutFrame.pack(fill="x") # _________________________________________________________________ # notebook.pack(fill="both", expand=True) # _________________________________________________________________ # statusBarframe = tix.Frame(self) clearB = ttk.Button( statusBarframe, text="Clear", command=self.console_clear, # bg="black", # fg="#ffff00", # activebackground="#333333", # activeforeground="#ffff00", ) clearB.pack(side="left") #### label = ttk.Label(statusBarframe, text="Verbosity") label.pack(side="left") ## comboVar = tk.StringVar() combo = ttk.OptionMenu( statusBarframe, comboVar, log.getVerbosity(), # default 0, 1, 2, 3, 4, ) comboVar.trace("w", self.verbosityChanged) combo.pack(side="left") self.verbosityCombo = comboVar ##### pbar = ProgressBar(statusBarframe, width=400) pbar.pack(side="left", fill="x", expand=True) self.pbar = pbar statusBarframe.pack(fill="x") self.progressTitle = "" # _________________________________________________________________ # frame3 = tix.Frame(self) closeB = ttk.Button( frame3, text="Close", command=rootWin.quit, # bg="#ff0000", # activebackground="#ff5050", ) closeB.pack(side="right") frame3.pack(fill="x") # _________________________________________________________________ # centerWindow(rootWin) # show the window if os.sep == "\\": # Windows rootWin.attributes('-alpha', 1.0) else: # Linux rootWin.deiconify() if path: self.entryInputConvert.insert(0, path) self.inputEntryChanged() self.outputEntryChanged() self.load() def verbosityChanged(self, index, value, op): log.setVerbosity(int(self.verbosityCombo.get())) def resized(self, event): dh = self.rootWin.winfo_height() - self.winfo_height() # log.debug(dh, self.consoleH) # if dh > 20: # self.consoleH += 1 # self.console["height"] = self.consoleH # self.console["width"] = int(self.console["width"]) + 1 # self.console.grid() # for x in dir(self): # if "info" in x: # log.debug(x) def inputComboChanged(self, *args): formatDesc = self.formatVarInputConvert.get() if not formatDesc: return self.readOptions.clear() # reset the options, DO NOT re-assign format = Glossary.pluginByDesc[formatDesc].name options = Glossary.formatsReadOptions[format] if options: self.readOptionsButton.pack(side="right") else: self.readOptionsButton.pack_forget() def outputComboChanged(self, *args): # log.debug(self.formatVarOutputConvert.get()) formatDesc = self.formatVarOutputConvert.get() if not formatDesc: return self.writeOptions.clear() # reset the options, DO NOT re-assign format = Glossary.pluginByDesc[formatDesc].name options = Glossary.formatsWriteOptions[format] if options: self.writeOptionsButton.pack(side="right") else: self.writeOptionsButton.pack_forget() if not self.pref["ui_autoSetOutputFileName"]: # and format is None: return pathI = self.entryInputConvert.get() pathO = self.entryOutputConvert.get() formatOD = self.formatVarOutputConvert.get() if formatOD is None: return if pathO: return if "." not in pathI: return extO = Glossary.pluginByDesc[formatOD].extensions[0] pathO = "".join(os.path.splitext(pathI)[:-1]) + extO # self.entryOutputConvert.delete(0, "end") self.entryOutputConvert.insert(0, pathO) def inputEntryChanged(self, event=None): # char = event.keysym pathI = self.entryInputConvert.get() if self.pathI != pathI: if pathI.startswith("file://"): pathI = urlToPath(pathI) self.entryInputConvert.delete(0, "end") self.entryInputConvert.insert(0, pathI) if self.pref["ui_autoSetFormat"]: formatDesc = self.formatVarInputConvert.get() if not formatDesc: format = Glossary.detectInputFormat(pathI, quiet=True) if format: plugin = Glossary.plugins.get(format) if plugin: self.formatVarInputConvert.set(plugin.description) self.pathI = pathI def outputEntryChanged(self, event=None): pathO = self.entryOutputConvert.get() if self.pathO != pathO: if pathO.startswith("file://"): pathO = urlToPath(pathO) self.entryOutputConvert.delete(0, "end") self.entryOutputConvert.insert(0, pathO) if self.pref["ui_autoSetFormat"]: formatDesc = self.formatVarOutputConvert.get() if not formatDesc: outputArgs = Glossary.detectOutputFormat( filename=pathO, inputFilename=self.entryInputConvert.get(), quiet=True, ) if outputArgs: outputFormat = outputArgs[1] self.formatVarOutputConvert.set( Glossary.plugins[outputFormat].description) self.pathO = pathO def save_fcd_dir(self): if not self.fcd_dir: return with open(self.fcd_dir_save_path, mode="w", encoding="utf-8") as fp: fp.write(self.fcd_dir) def browseInputConvert(self): path = filedialog.askopenfilename(initialdir=self.fcd_dir) if path: self.entryInputConvert.delete(0, "end") self.entryInputConvert.insert(0, path) self.inputEntryChanged() self.fcd_dir = os.path.dirname(path) self.save_fcd_dir() def browseOutputConvert(self): path = filedialog.asksaveasfilename() if path: self.entryOutputConvert.delete(0, "end") self.entryOutputConvert.insert(0, path) self.outputEntryChanged() self.fcd_dir = os.path.dirname(path) self.save_fcd_dir() def convert(self): inPath = self.entryInputConvert.get() if not inPath: log.critical("Input file path is empty!") return inFormatDesc = self.formatVarInputConvert.get() if not inFormatDesc: # log.critical("Input format is empty!");return inFormat = "" else: inFormat = Glossary.pluginByDesc[inFormatDesc].name outPath = self.entryOutputConvert.get() if not outPath: log.critical("Output file path is empty!") return outFormatDesc = self.formatVarOutputConvert.get() if not outFormatDesc: log.critical("Output format is empty!") return outFormat = Glossary.pluginByDesc[outFormatDesc].name finalOutputFile = self.glos.convert( inPath, inputFormat=inFormat, outputFilename=outPath, outputFormat=outFormat, readOptions=self.readOptions, writeOptions=self.writeOptions, ) # if finalOutputFile: # self.status("Convert finished") # else: # self.status("Convert failed") return bool(finalOutputFile) def run(self, editPath=None, readOptions=None): if readOptions is None: readOptions = {} # editPath and readOptions are for DB Editor # which is not implemented self.mainloop() def progressInit(self, title): self.progressTitle = title def progress(self, rat, text=""): if not text: text = "%" + str(int(rat * 100)) text += " - " + self.progressTitle self.pbar.updateProgress(rat * 100, None, text) # self.pbar.value = rat * 100 # self.pbar.update() self.rootWin.update() def console_clear(self, event=None): self.console.delete("1.0", "end") self.console.insert("end", "Console:\n")