class AboutDialog(QDialog): # pylint: disable=too-many-instance-attributes """Logic for managing about box""" def __init__(self, parent, app_settings): super().__init__(parent) self._log = logging.getLogger(__name__) self._settings = QSettings() self._app_settings = app_settings self._load_ui() # Flag indicating whether the user has requested the GUI settings to be reset. # If so, the caller should disable any further settings recording logic self.cleared = False def _load_ui(self): """Internal helper method that configures the UI for the dialog""" load_ui("about_dlg.ui", self) self.title_label = self.findChild(QLabel, "title_label") self.title_label.setText(f"Friendly Pics 2 v{__version__}") self.runtime_env_label = self.findChild(QLabel, "runtime_env_label") if is_mac_app_bundle(): self.runtime_env_label.setText("Running as MacOS app bundle") elif is_pyinstaller_bundle(): self.runtime_env_label.setText("Running as a pyinstaller binary") else: self.runtime_env_label.setText( "Running under conventional Python environment") self.gui_settings_label = self.findChild(QLabel, "gui_settings_label") self.gui_settings_label.setText( f"<b>GUI Settings:</b> {self._settings.fileName()}") self.gui_settings_clear_button = self.findChild( QPushButton, "gui_settings_clear_button") self.gui_settings_clear_button.clicked.connect( self._clear_gui_settings) self.app_settings_label = self.findChild(QLabel, "app_settings_label") self.app_settings_label.setText( f"<b>App Settings:</b> {self._app_settings.path}") # Center the about box on the parent window parent_geom = self.parent().geometry() self.move(parent_geom.center() - self.rect().center()) @Slot() def _clear_gui_settings(self): """Callback for when user selects the clear gui settings button""" self._settings.clear() self._settings.sync() self.gui_settings_clear_button.setEnabled(False) self.cleared = True
class Config(QObject): "Configuration provider for the whole program, wrapper for QSettings" row_height_changed = Signal(int) def __init__(self, log=None): super().__init__() if log: self.log = log.getChild('Conf') self.log.setLevel(30) else: self.log = logging.getLogger() self.log.setLevel(99) self.log.debug('Initializing') self.qsettings = QSettings() self.qsettings.setIniCodec('UTF-8') self.options = None self.option_spec = self.load_option_spec() self.options = self.load_options() self.full_name = "{} {}".format(QCoreApplication.applicationName(), QCoreApplication.applicationVersion()) # options that need fast access are also defined as attributes, which # are updated by calling update_attributes() # (on paper it's 4 times faster, but I don't think it matters in my case) self.logger_table_font = None self.logger_table_font_size = None self.logger_row_height = None self.benchmark_interval = None self.update_attributes() def post_init(self): running_version = StrictVersion(QCoreApplication.applicationVersion()) config_version = self.options['cutelog_version'] if config_version == "" or config_version != running_version: self.save_running_version() def __getitem__(self, name): # self.log.debug('Getting "{}"'.format(name)) value = self.options.get(name) if value is None: raise Exception('No option with name "{}"'.format(name)) # self.log.debug('Returning "{}"'.format(value)) return value def __setitem__(self, name, value): # self.log.debug('Setting "{}"'.format(name)) if name not in self.options: raise Exception('No option with name "{}"'.format(name)) self.options[name] = value def set_option(self, name, value): self[name] = value self.qsettings.beginGroup('Configuration') self.qsettings.setValue(name, value) self.qsettings.endGroup() @staticmethod def get_resource_path(name, directory='ui'): data_dir = resource_filename('cutelog', directory) path = os.path.join(data_dir, name) if not os.path.exists(path): raise FileNotFoundError('Resource file not found in this path: "{}"'.format(path)) return path def get_ui_qfile(self, name): file = QFile(':/ui/{}'.format(name)) if not file.exists(): raise FileNotFoundError('ui file not found: ":/ui/{}"'.format(name)) file.open(QFile.ReadOnly) return file @property def listen_address(self): host = self.options.get('listen_host') port = self.options.get('listen_port') if host is None or port is None: raise Exception('Listen host or port not in options: "{}:{}"'.format(host, port)) return (host, port) def load_option_spec(self): option_spec = [] for spec in OPTION_SPEC: option = Option(*spec) option_spec.append(option) return option_spec def load_options(self): self.log.debug('Loading options') options = {} self.qsettings.beginGroup('Configuration') for option in self.option_spec: value = self.qsettings.value(option.name, option.default) if option.type == bool: value = str(value).lower() # needed because QSettings stores bools as strings value = True if value == "true" or value is True else False elif option.type == int and value is None: value = 0 # workaround for bug PYSIDE-820 else: try: value = option.type(value) except Exception: self.log.warn('Could not parse value "{}" for option "{}", falling back to the ' 'default value "{}"'.format(value, option.name, option.default)) value = option.default options[option.name] = value self.qsettings.endGroup() return options def update_options(self, new_options, save=True): self.emit_needed_changes(new_options) self.options.update(new_options) if save: self.save_options() self.update_attributes(new_options) def update_attributes(self, options=None): "Updates fast attributes and everything else outside of self.options" if options is None: options = self.options self.benchmark_interval = options.get('benchmark_interval', self.benchmark_interval) self.logger_table_font = options.get('logger_table_font', self.logger_table_font) self.logger_table_font_size = options.get('logger_table_font_size', self.logger_table_font_size) self.logger_row_height = options.get('logger_row_height', self.logger_row_height) self.set_logging_level(options.get('console_logging_level', ROOT_LOG.level)) def emit_needed_changes(self, new_options): new_row_height = new_options.get('logger_row_height') old_row_height = self.options.get('logger_row_height') if new_row_height != old_row_height: self.logger_row_height = new_row_height self.row_height_changed.emit(new_row_height) def save_options(self, sync=False): self.log.debug('Saving options') self.qsettings.beginGroup('Configuration') for option in self.option_spec: self.qsettings.setValue(option.name, self.options[option.name]) self.qsettings.endGroup() if sync: # syncing is probably not necessary here, so the default is False self.sync() def sync(self): self.log.debug('Syncing QSettings') self.qsettings.sync() def set_settings_value(self, name, value): self.qsettings.beginGroup('Configuration') self.qsettings.setValue(name, value) self.qsettings.endGroup() def set_logging_level(self, level): global ROOT_LOG ROOT_LOG.setLevel(level) self.log.setLevel(level) def get_levels_presets(self): self.qsettings.beginGroup('Levels_Presets') result = self.qsettings.childGroups() self.qsettings.endGroup() return result def save_levels_preset(self, name, levels): self.log.debug('Saving levels preset "{}"'.format(name)) s = self.qsettings s.beginGroup('Levels_Presets') s.beginWriteArray(name, len(levels)) for i, levelname in enumerate(levels): level = levels[levelname] s.setArrayIndex(i) dump = level.dumps() s.setValue('level', dump) s.endArray() s.endGroup() def load_levels_preset(self, name): from .log_levels import LogLevel self.log.debug('Loading levels preset "{}"'.format(name)) s = self.qsettings if name not in self.get_levels_presets(): return None s.beginGroup('Levels_Presets') size = s.beginReadArray(name) result = {} for i in range(size): s.setArrayIndex(i) new_level = LogLevel(None).loads(s.value('level')) result[new_level.levelname] = new_level s.endArray() s.endGroup() return result def delete_levels_preset(self, name): s = self.qsettings s.beginGroup('Levels_Presets') s.remove(name) s.endGroup() def get_header_presets(self): self.qsettings.beginGroup('Header_Presets') result = self.qsettings.childGroups() self.qsettings.endGroup() return result def save_header_preset(self, name, columns): self.log.debug('Saving header preset "{}"'.format(name)) s = self.qsettings s.beginGroup('Header_Presets') s.beginWriteArray(name, len(columns)) for i, col in enumerate(columns): s.setArrayIndex(i) # read the comment in Column.dumps() for reasoning if i == len(columns) - 1: col.width = 10 # dump = col.dumps(width=10) dump = col.dumps() s.setValue('column', dump) s.endArray() s.endGroup() def load_header_preset(self, name): from .logger_table_header import Column self.log.debug('Loading header preset "{}"'.format(name)) s = self.qsettings if name not in self.get_header_presets(): return None s.beginGroup('Header_Presets') size = s.beginReadArray(name) result = [] for i in range(size): s.setArrayIndex(i) new_column = Column().loads(s.value('column')) result.append(new_column) s.endArray() s.endGroup() return result def delete_header_preset(self, name): s = self.qsettings s.beginGroup('Header_Presets') s.remove(name) s.endGroup() def save_geometry(self, geometry): s = self.qsettings s.beginGroup('Geometry') s.setValue('Main_Window_Geometry', geometry) s.endGroup() self.sync() def load_geometry(self): s = self.qsettings s.beginGroup('Geometry') geometry = s.value('Main_Window_Geometry') s.endGroup() return geometry def save_running_version(self): version = QCoreApplication.applicationVersion() self.log.debug("Updating the config version to {}".format(version)) s = self.qsettings s.beginGroup('Configuration') s.setValue('cutelog_version', version) self.options['cutelog_version'] = version s.endGroup() self.sync() def restore_defaults(self): self.qsettings.clear() self.sync()
def setUp(self): settings = QSettings() settings.clear()
def tearDown(self): settings = QSettings() settings.clear() rmtree(dirname(settings.fileName()))
def clear_settings(self): settings = QSettings("QtGuiApplication", "%s_%s" % (self.app_name, self.__class__.__name__)) settings.clear()