def __call__(self): fileName = as_human_readable(self.get_chosen_files()[0]) gpg = GPG() myPass, ok = show_prompt('Passphrase') # https://stackoverflow.com/questions/4444923/get-filename-without-extension-in-python fileNameOut, ok = show_prompt('Target', default=os.path.splitext(fileName)[0]) with open(fileName, 'rb') as f: status = gpg.decrypt_file(f, passphrase=myPass, output=fileNameOut) show_alert('Status: ' + status.status)
def setSymbolHiddenF(self, value_default): value_cfg = " ".join(self.cfgCurrent['SymbolHiddenF']) prompt_msg = "Please enter two symbols, separated by space, to indicate whether hidden files are Shown/Hidden" +'\n'\ + "or leave the field empty to restore the default ("+str(value_default)+"):" selection_start = 0 selection_end = 0 value_new = '' value_new_list = [] _len = len(value_new_list) len_def = len(value_default) while _len != len_def: value_new, ok = show_prompt(prompt_msg, value_cfg, selection_start, selection_end) value_cfg = value_new # preserve user input on multiple edits if not ok: show_status_message("StatusBarExtended: setup canceled") return if value_new.strip(' ') == '': self.cfgCurrent['SymbolHiddenF'] = value_default return value_new_nosp = ' '.join( value_new.split()) # replace multiple spaces with 1 value_new_list = value_new_nosp.split(' ') # split by space _len = len(value_new_list) if _len != 2: show_alert("You entered\n" + value_new +'\n'\ + "I parsed it as " + str(value_new_list) + " with " + str(_len) + " element" + ("" if _len==1 else "s") +'\n'\ + "but was expecting " + str(len_def) + " elements") self.cfgCurrent['SymbolHiddenF'] = value_new_list
def setMaxGlob(self, value_default): value_cfg = str(self.cfgCurrent['MaxGlob']) prompt_msg = "Please enter a natural number to set the threshold of the number of folders+files in a pane," +'\n'\ + "above which the status bar for such a pane will not be updated to improve performance" +'\n'\ + "or enter '0' to disable" +'\n'\ + "or leave the field empty to restore the default ("+str(value_default)+"):" selection_start = 0 value_new = '' while not isNat0(value_new): value_new, ok = show_prompt(prompt_msg, value_cfg, selection_start) value_cfg = value_new # preserve user input on multiple edits if not ok: show_status_message("StatusBarExtended: setup canceled") return if value_new.strip(' ') == '': self.cfgCurrent['MaxGlob'] = value_default return if value_new.strip(' ') == '0': self.cfgCurrent['MaxGlob'] = 0 return if not isInt(value_new): show_alert("You entered\n" + value_new +'\n'\ + "but I couldn't parse it as an integer") elif not isNat0(value_new): show_alert("You entered\n" + value_new +'\n'\ + "but I was expecting a non-negative integer 0,1,2,3–∞") self.cfgCurrent['MaxGlob'] = int(value_new)
def __call__(self): show_status_message('Creating a Script...') scriptVars = _GetScriptVars() script, flags = show_prompt("New Script Name?") newScript = scriptVars['directory'] + os.sep + script if os.path.isdir(newScript): show_alert("This is a directory.") else: if os.path.isfile(newScript): show_alert("Script already exists.") else: # # Create the script file. # fp = open(newScript,"w+") fp.write("#!/bin/sh\n\n") fp.write("#\n# The following variable are usable:\n#\n") fp.write("# $FILES_SELECTED - The currently selected file\n") fp.write("# $LEFT_PANE - The directory of the left pane\n") fp.write("# $RIGHT_PANE - The directory of the right pane\n") fp.write("# $CURRENT_DIRECTORY - The currently selected directory\n") fp.write("# $LEFT_PANE_SELECTED_FILE - The currently selected file in the left pane\n") fp.write("# $RIGHT_PANE_SELECTED_FILE - The currently selected file in the right pane\n") fp.close() os.chmod(newScript,0o755) # # Edit the script file. # if self.pane.is_command_visible('open_with_editor'): self.pane.run_command('open_with_editor',{'url': as_url(newScript)}) clear_status_message()
def setEnabled(self, value_default): _t = ('1', 't', 'true') _f = ('0', 'f', 'false') _tsep = "'" + "' or '".join(_t) + "'" _fsep = "'" + "' or '".join(_f) + "'" _accept = (_t + _f) value_cfg = str(self.cfgCurrent['Enabled']) prompt_msg = "Please enter " +_tsep+ " to enable this plugin" +'\n'\ + "or " +_fsep+ " to disable it" +'\n'\ + "or leave the field empty to restore the default ("+str(value_default) +'):' selection_start = 0 value_new = '' value_new_fmt = value_new.casefold() while value_new_fmt not in _accept: value_new, ok = show_prompt(prompt_msg, value_cfg, selection_start) value_cfg = value_new # preserve user input on multiple edits if not ok: show_status_message("StatusBarExtended: setup canceled") return if value_new.strip(' ') == '': self.cfgCurrent['Enabled'] = value_default return value_new_fmt = value_new.casefold() if value_new_fmt not in _accept: show_alert("You entered\n" + value_new +'\n'\ + "I parsed it as " + value_new_fmt +'\n'\ + "but the only acceptable values are:\n" +_tsep+ "\n" +_fsep) self.cfgCurrent['Enabled'] = True if value_new_fmt in _t else False
def __call__(self): text, ok = show_prompt( 'Please enter the URL', default='ftp[s]://[user[:password]@]ftp.host[:port][/path/to/dir]') if text and ok: self.pane.set_path(text) return
def setHideDotfile(self, value_default): _t = ('1', 't', 'true') _f = ('0', 'f', 'false') _tsep = "'" + "' or '".join(_t) + "'" _fsep = "'" + "' or '".join(_f) + "'" _accept = (_t + _f) value_cfg = str(self.cfgCurrent['HideDotfile']) prompt_msg = "Please enter " +_tsep+ " to treat all .dotfiles on Windows as hidden files\n even if they don't have a 'hidden' attribute" +'\n'\ + "or " +_fsep+ " to treat them as regular files" +'\n'\ + "or leave the field empty to restore the default ("+str(value_default) +'):' selection_start = 0 value_new = '' value_new_fmt = value_new.casefold() while value_new_fmt not in _accept: value_new, ok = show_prompt(prompt_msg, value_cfg, selection_start) value_cfg = value_new # preserve user input on multiple edits if not ok: show_status_message("StatusBarExtended: setup canceled") return if value_new.strip(' ') == '': self.cfgCurrent['HideDotfile'] = value_default return value_new_fmt = value_new.casefold() if value_new_fmt not in _accept: show_alert("You entered\n" + value_new +'\n'\ + "I parsed it as " + value_new_fmt +'\n'\ + "but the only acceptable values are:\n" +_tsep+ "\n" +_fsep) self.cfgCurrent['HideDotfile'] = True if value_new_fmt in _t else False
def __call__(self): # # Get the directory path. # selected_files = self.pane.get_selected_files() if len(selected_files) >= 1 or (len(selected_files) == 0 and self.get_chosen_files()): if len(selected_files) == 0 and self.get_chosen_files(): selected_files.append(self.get_chosen_files()[0]) dirName = as_human_readable(selected_files[0]) if os.path.isfile(dirName): # # It's a file, not a directory. Get the directory # name for this file's parent directory. # dirName = os.path.dirname(dirName) # # Add to the list of projects. Get a name # from the user. # shortener, checked = show_prompt("Name this Directory Shortener:") shortEntry = shortener + "|" + dirName writeappend = 'w' if os.path.isfile(SHORTENERLIST): writeappend = 'a' with open(SHORTENERLIST, writeappend) as f: f.write(shortEntry+"\n")
def __call__(self): scriptVars = _GetScriptVars() shellFile, status = show_prompt("What is your shell script?") shellFile = os.path.expanduser(shellFile) if not os.path.isfile(shellFile): show_alert("Not a real file.") else: scriptVars['local_shell'] = shellFile _SaveScriptVars(scriptVars)
def __call__(self): valid_methods = "\n".join(f" - {hm}" for hm in hash_map.keys()) chosen_files = self.get_chosen_files() results = [] # perform some checks on the selected files # as of now, only individual files are allowed, not directories dirs_in_selection = any([is_dir(fl) for fl in chosen_files]) if dirs_in_selection: show_alert("Please specify individual files, not directories.") return else: hmeth, okay = show_prompt( f"Enter one of the following hashing methods:\n{valid_methods}" ) hmeth = hmeth.strip() if hmeth not in hash_map.keys(): response = show_alert( "Invalid hashing method. No action taken.") return s = None if hmeth in ["shake_128", "shake_256"]: s, okay = show_prompt("Enter the size of the hash:") if not s.isnumeric(): response = show_alert("Invalid integer. Goodbye!") return s = int(s) # perform the actual hash calculations num_selected_files = len(chosen_files) for fl in chosen_files: fl = as_human_readable(fl) fhash = file_hash(fl, hmeth, s) hstr = f"{fl}: {fhash}" results.append(hstr) all_results = "\n".join(results) clipboard.set_text(all_results) if num_selected_files == 1: msg = ( f"The path and {hmeth} hash of the specified file has been copied to your clipboard as well as being attached here:\n\n{all_results}" ) else: msg = f"The paths and {hmeth} hashes of the {num_selected_files} selected files have been copied to your clipboard as well as being attached here:\n\n{all_results}" response = show_alert(msg)
def __call__(self): url = self.pane.get_path() if not is_ftp(url): url = 'ftp[s]://user[:password]@other.host[:port]/some_dir' url, ok = show_prompt('New FTP bookmark, please enter the URL', default=url) if not (url and ok): return if not is_ftp(url): show_alert('URL must include any of the following schemes: ' 'ftp://, ftps://') return bookmarks = \ load_json('FTP Bookmarks.json', default={}, save_on_quit=True) # XXX URL is split in `(base, path)` to allow setting a default path u = urlparse(url) base = alias = u._replace(path='').geturl() path = u.path if base in bookmarks: # XXX if base URL points to an alias, resolve to an existing URL base = bookmarks[base][0] if path and path.strip('/'): alias += '-'.join(path.split('/')) alias, ok = show_prompt( 'Please enter an alias (will override aliases with the same name)', default=alias) if not (alias and ok): return if not is_ftp(alias): # XXX alias must include the FTP scheme scheme, _ = splitscheme(base) alias = scheme + alias if urlparse(alias).path: show_alert('Aliases should not include path information') return bookmarks[alias] = (base, path)
def __call__(self): fileName = as_human_readable(self.get_chosen_files()[0]) gpg = GPG() default_recipient = self._get_default_recipient() recipient, ok = show_prompt('Recipient', default=default_recipient) with open(fileName, 'rb') as f: status = gpg.encrypt_file(f, recipients=[recipient], output=fileName + '.gpg') show_alert('Status: ' + status.status)
def __call__(self): # # Get the directory path. # selected_files = self.pane.get_selected_files() if len(selected_files) >= 1 or (len(selected_files) == 0 and self.get_chosen_files()): if len(selected_files) == 0 and self.get_chosen_files(): selected_files.append(self.get_chosen_files()[0]) dirName = as_human_readable(selected_files[0]) if os.path.isfile(dirName): # # It's a file, not a directory. Get the directory # name for this file's parent directory. # dirName = os.path.dirname(dirName) # # Set the directory obtained as a project directory. # with open(PROJECTDIR, "w") as f: f.write(dirName) # # Add to the list of projects. Get a name # from the user. # projName, checked = show_prompt("Name this Project:") projEntry = projName + "|" + dirName writeappend = 'w' if os.path.isfile(PROJECTSLIST): writeappend = 'a' with open(PROJECTSLIST, writeappend) as f: f.write(projEntry + "\n") # # Create the launch script file and open in the # editor. # scriptFile = dirName + "/.startproject" with open(scriptFile, 'w') as f: f.write("#!/bin/sh\n\n") os.chmod(scriptFile, stat.S_IEXEC | stat.S_IRUSR | stat.S_IWUSR) if (_THIRDPARTY_PLUGINS_DIR + "/OpenWithEditor") in _get_thirdparty_plugins(): self.pane.run_command("my_open_with_editor", args={'url': as_url(scriptFile)}) else: self.pane.run_command("open_with_editor", args={'url': as_url(scriptFile)}) else: # # Technically, this will never be reached. Just here # for completeness. # show_alert("No directory selected")
def __call__(self, url=None): text, ok = show_prompt('Enter Filter e.g. *.txt', default="*.txt", selection_start=2) if url is None: url = self.pane.get_file_under_cursor() or self.pane.get_path() if not is_dir(url): url = dirname(url) Flat.filtertext = text new_url = Flat.scheme + splitscheme(url)[1] # Not working yet if ok and text: self.pane.set_path(new_url + '?' + text)
def _get_default_recipient(self): config = load_json(CONFIG_FILE_NAME, default={}) if config and "default_recipient" in config: return config["default_recipient"] else: default_recipient, ok = show_prompt( 'First run - please enter default recipient') config['default_recipient'] = default_recipient save_json(CONFIG_FILE_NAME, config) return default_recipient
def set_tortoisesvnproc_install_path(): new_tortoisesvnproc_filepath, ok = show_prompt( 'Enter full path to TortoiseSVNProc.exe program here', default=get_current_tortoisesvnproc_install_path(), selection_start=0, selection_end=None) if not ok: return False if not exists(as_url(new_tortoisesvnproc_filepath)): show_alert('Path to TortoiseSVNProc given is invalid') return False _TORTOISEPROCPATH = new_tortoisesvnproc_filepath save_json(_TORTOISEPROCCONFIGFILE, {'path': new_tortoisesvnproc_filepath}) return True
def set_sublime_install_path(): new_sublime_filepath, ok = show_prompt( 'Enter full path to Sublime Text program here', default=get_current_sublime_install_path(), selection_start=0, selection_end=None) if not ok: return False if not exists(as_url(new_sublime_filepath)): show_alert('Path to Sublime Text given is invalid') return False _SUBLIMETEXTPATH = new_sublime_filepath save_json(_SUBLIMETEXTCONFIGFILE, {'path': new_sublime_filepath}) return True
def __call__(self): global DBDATA show_status_message('NotePad (A)ppend or Over(w)rite') npdata = load_json('CopyToNotePad.json') if npdata is None: npdata = dict() npdata['number'] = 3 npdata['save'] = 'a' npappend, result = show_prompt( "The 'a'ppend or 'w'rite:") if not npappend: npappend = 'a' npappend = npappend.lower() if (npappend != 'a') and (npappend != 'w'): npappend = 'a' npdata['save'] = npappend save_json('CopyToNotePad.json', npdata) clear_status_message()
def __call__(self): # get_chosen_files() returns the files selected by the user # (="red" files). If no files are selected, the file under the cursor # is returned: chosen_files = self.get_chosen_files() if chosen_files: # equivalent to `len(chosen_files) > 0` ndnam, okay = show_prompt("Directory Name?") # Check ndnam as well because it could be empty if ndnam and okay: numf = 0 newdirp = join(self.pane.get_path(), ndnam) if not self.isADir(newdirp): # Create directory and its parent directories: makedirs(newdirp) for filep in chosen_files: move(filep, join(newdirp, basename(filep))) numf += 1 show_alert('%d items were moved!' % numf) else: show_alert("No files or directories selected")
def setSizeDivisor(self, value_default): _accept = ('1000', '1024') value_cfg = str(int(self.cfgCurrent['SizeDivisor'])) prompt_msg = "Please enter the file size divisor ('1000' or '1024') to display file size\nin a decimal (1k=1000=10³) or binary (1k=1024=2¹⁰) format" + '\n'\ + "or leave the field empty to restore the default ("+str(value_default) +'):' selection_start = 2 value_new = '' while value_new not in _accept: value_new, ok = show_prompt(prompt_msg, value_cfg, selection_start) value_cfg = value_new # preserve user input on multiple edits if not ok: show_status_message("StatusBarExtended: setup canceled") return if value_new.strip(' ') == '': self.cfgCurrent['SizeDivisor'] = value_default return elif value_new not in _accept: show_alert("You entered\n" + value_new +'\n'\ + "but the only acceptable values are:\n1000\n1024") self.cfgCurrent['SizeDivisor'] = float(value_new)
def __call__(self): global DBDATA show_status_message('NotePad Number') npdata = load_json('CopyToNotePad.json') if npdata is None: npdata = dict() npdata['number'] = 3 npdata['save'] = 'a' npnum, result = show_prompt( "The NotePad Number to use:") if not npnum: npnum = 3 else: npnum = int(npnum) if npnum < 1: npnum = 1 elif npnum > 9: npnum = 9 npdata['number'] = npnum save_json('CopyToNotePad.json', npdata) clear_status_message()
def __call__(self): cfg = SingletonConfig() self.cfgCurrent, exit_status = cfg.loadConfig() if self.cfgCurrent is None: return prompt_msg = "Please enter any combination of the the &u&n&d&e&r&l&i&n&e&d numbers/letters" +'\n'\ + "to configure the corresponding option(s)" +'\n'\ + "# \tOption \t\tDescription" +'\n'\ + "&0. \t&a&l&l\t\t" + "Configure all the options" +'\n'\ + "&1. \t&Enabled\t\t" + "Enable/Disable this plugin" +'\n'\ + "&2. \tSize&Divisor\t" + "File size format: decimal or binary" +'\n'\ + "&3. \tMax&Glob\t\t" + "Skip folders with as many items" +'\n'\ + "&4. \tSymbol&Pane\t" + "Left/Right pane symbol" +'\n'\ + "&5. \tSymbol&HiddenF\t" + "Hidden files Shown/Hidden symbol" +'\n'\ + "&6. \tHideD&otfile\t" + "Treat .dotfiles as hidden files on Windows" +'\n'\ + "&7. \t&Justify\t\t" + "Minimum width of the Folder/File/Size values" +'\n'\ + '\n' value_new, ok = show_prompt(prompt_msg) if not ok: show_status_message("StatusBarExtended: setup canceled") return if any(x in value_new.casefold() for x in ('1', 'e', '0', 'all')): self.setEnabled(cfg.Default['Enabled']) if any(x in value_new.casefold() for x in ('2', 'd', '0', 'all')): self.setSizeDivisor(cfg.Default['SizeDivisor']) if any(x in value_new.casefold() for x in ('3', 'g', '0', 'all')): self.setMaxGlob(cfg.Default['MaxGlob']) if any(x in value_new.casefold() for x in ('4', 'p', '0', 'all')): self.setSymbolPane(cfg.Default['SymbolPane']) if any(x in value_new.casefold() for x in ('5', 'h', '0', 'all')): self.setSymbolHiddenF(cfg.Default['SymbolHiddenF']) if any(x in value_new.casefold() for x in ('6', 'o', '0', 'all')): self.setHideDotfile(cfg.Default['HideDotfile']) if any(x in value_new.casefold() for x in ('7', 'j', '0', 'all')): self.setJustify(cfg.Default['Justify']) cfg.saveConfig(self.cfgCurrent) run_application_command('view_configuration_status_bar_extended')
def __call__(self, url=None): # This will get set if the automagically determined destination # directory exists, and will always be the default name when prompted # to manually choose a destination directory name. originalName = None if url is None: workingFile = self.pane.get_file_under_cursor() if workingFile: url = workingFile fileName = basename(url) if _CHECK_EXTENSION: try: extension = fileName[fileName.rindex('.'):] except ValueError: show_alert("Failed to determine extension, aborting!") return if not extension in _SUPPORTED_EXTENSIONS: show_alert("Unsupported extension, aborting!") return newDirName = fileName[0:fileName.rindex('.')] else: try: newDirName = fileName[0:fileName.rindex('.')] except ValueError: message = "Archive has no extension.\n" message += "Click 'YES' to enter a name " message += "for the destination directory.\n" message += "Click 'NO' to use the archive name.\n" message += "Click 'ABORT' to abort extraction." choice = show_alert(message, buttons=YES | NO | ABORT, default_button=ABORT) if choice == YES: newDirName, ok = show_prompt("Destination directory:", default=fileName) if not (newDirName and ok): return elif choice == NO: newDirName = fileName else: return oppositePane = _get_opposite_pane(self.pane) oppositePaneUrl = oppositePane.get_path() oppositePaneScheme, _ = splitscheme(resolve(oppositePaneUrl)) if oppositePaneScheme != 'file://': show_alert("Can't extract to %s, aborting!" % oppositeScheme) return newDirUrl = join(oppositePaneUrl, newDirName) while exists(newDirUrl): if not originalName: originalName = newDirName message = newDirName + " already exists!\nEnter a different name?" choice = show_alert(message, buttons=YES | ABORT, default_button=ABORT) if choice == YES: newDirName, ok = show_prompt("Destination directory:", default=newDirName) if not (newDirName and ok): continue else: newDirUrl = join(oppositePaneUrl, newDirName) try: mkdir(newDirUrl) except (FileNotFoundError, NotImplementedError): message = "Failed to create directory '" message += newDirName + "', aborting!" show_alert(message) return archive = as_human_readable(url) destDir = as_human_readable(newDirUrl) submit_task(ExtractArchive(archive, destDir)) return
def loadConfig(cls): """Check StatusBarExtended.json for consistency/completeness, restore defaults on fail""" msg_t = cls.msgTimeout if hasattr(cls, 'locked_update'): show_status_message( "StatusBarExtended: waiting for the config files to be updated, try again later..." ) return None, 'UpdateInProgress' cls.locked_update = True # ensure globally unique 'loadConfig' run so that e.g. we don't ask a user multiple times to delete corrupted configs cfgCurrent = load_json( 'StatusBarExtended.json' ) # within one fman session, it is guaranteed that multiple calls to load_json(...) with the same JSON name always return the same object, so save {} when deleting the files to force reload if type(cfgCurrent) not in (type(dict()), type(None)): # delete config files, fman's save_json can't replace types config_files = ['StatusBarExtended.json'] config_files.append('StatusBarExtended (' + PLATFORM + ').json') user_settings_url = join(as_url(DATA_DIRECTORY), 'Plugins', 'User', 'Settings') user_input_allow = '' prompt_msg_full = '' corrupt_config = [] for f in config_files: f_url = join(user_settings_url, f) f_path = as_path(f_url) if not exists(f_url): continue excerpt = str(load_json(f_path))[:100] prompt_msg = f_path \ + "\n that begins with:"\ + "\n " + excerpt corrupt_config.append({}) corrupt_config[-1]['url'] = f_url corrupt_config[-1]['path'] = f_path corrupt_config[-1]['prompt_msg'] = prompt_msg corrupt_count = len(corrupt_config) if corrupt_count: # delete corrupt config files with the user's permission prompt_msg_full += "Please enter 'y' or 'yes' or '1' (without the quotes) to delete " + str(corrupt_count) + " corrupt plugin config file" \ + ("\n" if corrupt_count==1 else "s\n") \ + "with incompatible data type " + str(type(cfgCurrent)) + '\n'\ + "(all settings will be reset to their defaults)\n" for corrupt_file_dict in corrupt_config: prompt_msg_full += '\n' + corrupt_file_dict[ 'prompt_msg'] + '\n' user_input_allow, ok = show_prompt(prompt_msg_full, default=user_input_allow) if ok and user_input_allow in ('y', 'yes', '1'): _reset = False for corrupt_file_dict in corrupt_config: f_url = corrupt_file_dict['url'] f_path = corrupt_file_dict['path'] try: move_to_trash(f_url) except Exception as e: show_status_message( "StatusBarExtended: failed to move to trash — " + f_path + " — with exception " + repr(e), msg_t) pass if not exists(f_url): show_status_message( "StatusBarExtended: moved to trash — " + f_path, msg_t) _reset = True else: show_status_message( "StatusBarExtended: failed to move to trash, deleting — " + f_path, msg_t) try: delete(f_url) except Exception as e: show_status_message( "StatusBarExtended: failed to delete — " + f_path + " — with exception " + repr(e), msg_t) pass if not exists(f_url): show_status_message( "StatusBarExtended: deleted — " + f_path, msg_t) _reset = True else: show_alert( "StatusBarExtended: failed to move to trash or delete — " + f_path + "\nPlease, delete it manually") del cls.locked_update return None, 'ConfigDeleteFail' if _reset == True: # can save_json only when both files are deleted, otherwise there is a format mismatch ValueError cls.saveConfig({}) cfgCurrent = load_json('StatusBarExtended.json') else: # user canceled or didn't enter y/1 show_status_message( "StatusBarExtended: you canceled the deletion of the corrupted config files", msg_t) del cls.locked_update return None, 'Canceled' else: # can't find the config files show_alert("StatusBarExtended: can't find the corrupt config files:\n" \ + str(config_files) + "\n @ " + as_path(user_settings_url) \ + "\nMaybe their default location changed, please, delete them manually") del cls.locked_update return None, 'CorruptConfigNotFound' reload = False if (cfgCurrent is None) or ( cfgCurrent == {} ): # empty file or empty dictionary (corrupt configs deleted and replaced with {}), save defaults to the config file cfgCurrent = dict() for key in cls.Default: cfgCurrent[key] = cls.Default[key] reload = True if type(cfgCurrent) is dict: for key in cls.Default: # Fill in missing default values (e.g. in older installs) if key not in cfgCurrent: cfgCurrent[key] = cls.Default[key] reload = True if reload: cls.saveConfig(cfgCurrent) cfgCurrent = load_json('StatusBarExtended.json') if type(cfgCurrent) is dict: # check for still missing keys missing_keys = [] for key in cls.Default: if key in cfgCurrent: continue missing_keys.append(key) if len(missing_keys): show_status_message( "StatusBarExtended: config files are missing some required keys:" + str(missing_keys) + " Maybe try to reload?", msg_t) del cls.locked_update return None, 'MissingKeys' else: del cls.locked_update return cfgCurrent, 'Success' else: show_status_message( "StatusBarExtended: couldn't fix config files, maybe try to reload?", msg_t) del cls.locked_update return None, 'UnknownError'
def setJustify(self, value_default): value_cfg_in = self.cfgCurrent['Justify'] value_cfg = " ".join(str(val) for val in value_cfg_in.values()) val_def_fmt = " ".join(str(val) for val in value_default.values()) max_val = 11 prompt_msg = "Please enter three natural numbers, each <= "+str(max_val)+", separated by space, to set the minimum width of" +'\n'\ + "the folder, file, and size indicators respectively." +'\n'\ + "e.g. with a min width=2, 1 in 1 and 21 will align, but not in 321:" +'\n'\ + " 1" +'\n'\ + "21" +'\n'\ + "321" +'\n'\ + "or enter '0' to restore an individual default" +'\n'\ + "or leave the field empty to restore all the defaults ("+val_def_fmt+"):" selection_start = 0 selection_end = 1 value_new = '' value_new_list = [] _len = len(value_new_list) len_def = len(value_default) above_max = False while (not all([isNat0(v) for v in value_new_list])) \ or above_max \ or _len != len_def: value_new, ok = show_prompt(prompt_msg, value_cfg, selection_start, selection_end) value_cfg = value_new # preserve user input on multiple edits if not ok: show_status_message("StatusBarExtended: setup canceled") return if value_new.strip(' ') == '': self.cfgCurrent['Justify'] = value_default return value_new_nosp = ' '.join( value_new.split()) # replace multiple spaces with 1 value_new_list = value_new_nosp.split(' ') # split by space _len = len(value_new_list) if not all([isInt(v) for v in value_new_list]): show_alert("You entered\n" + value_new +'\n'\ + "I parsed it as " + str(value_new_list) + " with " + str(_len) + " element" + ("" if _len==1 else "s") +'\n'\ + "but I couldn't parse all elements as integers") elif not all([isNat0(v) for v in value_new_list]): show_alert("You entered\n" + value_new +'\n'\ + "I parsed it as " + str(value_new_list) + " with " + str(_len) + " element" + ("" if _len==1 else "s") +'\n'\ + "but couldn't parse all elements as non-negative integers 0,1,2,3–∞") elif True in [int(v) > max_val for v in value_new_list]: above_max = True show_alert("You entered\n" + value_new +'\n'\ + "I parsed it as " + str(value_new_list) + " with " + str(_len) + " element" + ("" if _len==1 else "s") +'\n'\ + "but the maximum value of each number is " + str(max_val)) continue elif all([int(v) <= max_val for v in value_new_list]): above_max = False if _len != len_def: show_alert("You entered\n" + value_new +'\n'\ + "I parsed it as " + str(value_new_list) + " with " + str(_len) + " element" + ("" if _len==1 else "s") +'\n'\ + "but was expecting " + str(len_def) + " elements") for i, key in enumerate(value_default): if value_new_list[i] == '0': self.cfgCurrent['Justify'][key] = value_default[key] else: self.cfgCurrent['Justify'][key] = int(value_new_list[i])