class FileWidget(QWidget): on_open = pyqtSignal(str) # TODO consider removing directory_aliases since it is not used any more def __init__(self, dialog_title='', dialog_format='', start_dir=os.path.expanduser('~/'), icon_size=(12, 20), minimal_width=200, browse_label='Browse', on_open=None, reload_button=True, reload_label='Reload', recent_files=None, directory_aliases=None, allow_empty=True, empty_file_label='(none)'): """ Creates a widget with a button for file loading and an optional combo box for recent files and reload buttons. Args: dialog_title (str): The title of the dialog. dialog_format (str): Formats for the dialog. start_dir (str): A directory to start from. icon_size (int, int): The size of buttons' icons. on_open (callable): A callback function that accepts filepath as the only argument. reload_button (bool): Whether to show reload button. reload_label (str): The text displayed on the reload button. recent_files (List[str]): List of recent files. directory_aliases (dict): An {alias: dir} dictionary for fast directories' access. allow_empty (bool): Whether empty path is allowed. """ super().__init__() self.dialog_title = dialog_title self.dialog_format = dialog_format self.start_dir = start_dir # Recent files should also contain `empty_file_label` so # when (none) is selected this is stored in settings. self.recent_files = recent_files if recent_files is not None else [] self.directory_aliases = directory_aliases or {} self.allow_empty = allow_empty self.empty_file_label = empty_file_label if self.empty_file_label not in self.recent_files \ and (self.allow_empty or not self.recent_files): self.recent_files.append(self.empty_file_label) self.check_existence() self.on_open.connect(on_open) layout = QHBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) if recent_files is not None: self.file_combo = QComboBox() self.file_combo.setMinimumWidth(minimal_width) self.file_combo.activated[int].connect(self.select) self.update_combo() layout.addWidget(self.file_combo) self.browse_button = QPushButton(browse_label) self.browse_button.setFocusPolicy(Qt.NoFocus) self.browse_button.clicked.connect(self.browse) self.browse_button.setIcon(self.style().standardIcon( QStyle.SP_DirOpenIcon)) self.browse_button.setIconSize(QSize(*icon_size)) self.browse_button.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) layout.addWidget(self.browse_button) if reload_button: self.reload_button = QPushButton(reload_label) self.reload_button.setFocusPolicy(Qt.NoFocus) self.reload_button.clicked.connect(self.reload) self.reload_button.setIcon(self.style().standardIcon( QStyle.SP_BrowserReload)) self.reload_button.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) self.reload_button.setIconSize(QSize(*icon_size)) layout.addWidget(self.reload_button) def browse(self, start_dir=None): start_dir = start_dir or self.start_dir path, _ = QFileDialog().getOpenFileName(self, self.dialog_title, start_dir, self.dialog_format) if path and self.recent_files is not None: if path in self.recent_files: self.recent_files.remove(path) self.recent_files.insert(0, path) self.update_combo() if path: self.open_file(path) def select(self, n): name = self.file_combo.currentText() if name == self.empty_file_label: del self.recent_files[n] self.recent_files.insert(0, self.empty_file_label) self.update_combo() self.open_file(self.empty_file_label) elif name in self.directory_aliases: self.browse(self.directory_aliases[name]) elif n < len(self.recent_files): name = self.recent_files[n] del self.recent_files[n] self.recent_files.insert(0, name) self.update_combo() self.open_file(self.recent_files[0]) def update_combo(self): """ Sync combo values to the changes in self.recent_files. """ if self.recent_files is not None: self.file_combo.clear() for i, file in enumerate(self.recent_files): # remove (none) when we have some files and allow_empty=False if file == self.empty_file_label and \ not self.allow_empty and len(self.recent_files) > 1: del self.recent_files[i] else: self.file_combo.addItem(os.path.split(file)[1]) for alias in self.directory_aliases.keys(): self.file_combo.addItem(alias) def reload(self): if self.recent_files: self.select(0) def check_existence(self): if self.recent_files: to_remove = [] for file in self.recent_files: doc_path = os.path.join(get_sample_corpora_dir(), file) exists = any(os.path.exists(f) for f in [file, doc_path]) if file != self.empty_file_label and not exists: to_remove.append(file) for file in to_remove: self.recent_files.remove(file) def open_file(self, path): self.on_open.emit(path if path != self.empty_file_label else '') def get_selected_filename(self): if self.recent_files: return self.recent_files[0] else: return self.empty_file_label
class FileLoader(QWidget): activated = pyqtSignal() file_loaded = pyqtSignal() def __init__(self): super().__init__() self.recent_paths = [] self.file_combo = QComboBox() self.file_combo.setMinimumWidth(80) self.file_combo.activated.connect(self._activate) self.browse_btn = QPushButton("...") icon = self.style().standardIcon(QStyle.SP_DirOpenIcon) self.browse_btn.setIcon(icon) self.browse_btn.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Fixed) self.browse_btn.clicked.connect(self.browse) self.load_btn = QPushButton("") icon = self.style().standardIcon(QStyle.SP_BrowserReload) self.load_btn.setIcon(icon) self.load_btn.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Fixed) self.load_btn.setAutoDefault(True) self.load_btn.clicked.connect(self.file_loaded) def browse(self): start_file = self.last_path() or os.path.expanduser("~/") formats = ["Text files (*.txt)", "All files (*)"] file_name, _ = QFileDialog.getOpenFileName(None, "Open...", start_file, ";;".join(formats), formats[0]) if not file_name: return self.add_path(file_name) self._activate() def _activate(self): self.activated.emit() self.file_loaded.emit() def set_current_file(self, path: str): if path: self.add_path(path) self.file_combo.setCurrentText(path) else: self.file_combo.setCurrentText("(none)") def get_current_file(self) -> Optional[RecentPath]: index = self.file_combo.currentIndex() if index >= len(self.recent_paths) or index < 0: return None path = self.recent_paths[index] return path if isinstance(path, RecentPath) else None def add_path(self, filename: str): recent = RecentPath.create(filename, []) if recent in self.recent_paths: self.recent_paths.remove(recent) self.recent_paths.insert(0, recent) self.set_file_list() def set_file_list(self): self.file_combo.clear() for i, recent in enumerate(self.recent_paths): self.file_combo.addItem(recent.basename) self.file_combo.model().item(i).setToolTip(recent.abspath) if not os.path.exists(recent.abspath): self.file_combo.setItemData(i, QBrush(Qt.red), Qt.TextColorRole) self.file_combo.addItem(_DEFAULT_NONE) def last_path(self) -> Optional[str]: return self.recent_paths[0].abspath if self.recent_paths else None
class ControlButton(ControlBase): def __init__(self, *args, **kwargs): self._checkable = kwargs.get('checkable', False) super(ControlButton, self).__init__(*args, **kwargs) default = kwargs.get('default', None) if default: self.value = default def init_form(self): self._form = QPushButton() self._form.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Fixed) self._form.setCheckable(self._checkable) self.label = self._label self._form.setToolTip(self.help) def click(self): self._form.click() def load_form(self, data, path=None): pass def save_form(self, data, path=None): pass ########################################################################## @property def label(self): return ControlBase.label.fget(self) @label.setter def label(self, value): ControlBase.label.fset(self, value) self._form.setText(self._label) @property def icon(self): return self._form.icon() @icon.setter def icon(self, value): if isinstance(value, (str, bytes)): self._form.setIcon(QIcon(value)) else: self._form.setIcon(value) ########################################################################## @property def value(self): return None @value.setter def value(self, value): try: self._form.clicked.disconnect() # ignore previous signals if any except TypeError as err: # http://stackoverflow.com/questions/21586643/pyqt-widget-connect-and-disconnect pass self._form.clicked[bool].connect(value) @property def checked(self): return self._form.isChecked() @checked.setter def checked(self, value): self._form.setChecked(value)
class MainUI(QWidget): def __init__(self): super().__init__() self.left = Config.geometry[0] self.top = Config.geometry[1] self.width = Config.geometry[2] self.height = Config.geometry[3] self.setLayout(QHBoxLayout(self)) # Init logger self.logger = Logger('mainUI', 'UI : Main') # Read in user prefs self.prefs = {} self.loadPrefs() # Load configured objects self.lights = Lights() self.lights.load() self.obas = OBAs() self.obas.load() self.tracs = Tracs() self.tracs.load() # Init I2C control if 'i2cAddress' in self.prefs.keys(): _address = self.prefs['i2cAddress'] else: _address = Config.defaultI2CAddress if 'i2cBus' in self.prefs.keys(): _bus = self.prefs['i2cBus'] else: _bus = Config.defaultI2CBus if 'i2cDebug' in self.prefs.keys(): _debug = self.prefs['i2cDebug'] else: _debug = False self._i2cBus = I2CBus(int(_bus), str(_address), bool(_debug)) del _bus, _address, _debug # Create menu frame self._sidebarMenu = QFrame(self) self._sidebarMenu.layout = QVBoxLayout(self._sidebarMenu) self._sidebarMenu.setMaximumWidth(Config.menuWidth + 50) self._sidebarMenu.setMaximumHeight(Config.geometry[3]) self._sidebarMenu.setStyleSheet( "QFrame{border-right: 1px solid black}") # Create menu _container = QWidget() _container.layout = QVBoxLayout() _container.setLayout(_container.layout) _scroll = QScrollArea() _scroll.setWidget(_container) _scroll.setWidgetResizable(True) self._sidebarMenu.layout.addWidget(_scroll) for _key in [ 'enableOBA', 'enableLighting', 'enableTracControl', 'enableCamViewer', 'enableGyro' ]: if _key in self.prefs.keys(): if self.prefs[_key]: _title = { 'enableOBA': 'control_oba', 'enableLighting': 'control_light', 'enableTracControl': 'control_trac', 'enableCamViewer': 'control_cam', 'enableGyro': 'control_gyro' }[_key] _icon = { 'enableOBA': Config.faIcon("wind"), 'enableLighting': Config.faIcon("lightbulb"), 'enableTracControl': Config.icon("tracControl", "rearDiff")['path'], 'enableCamViewer': Config.faIcon("camera"), 'enableGyro': Config.faIcon("truck-pickup") }[_key] _button = MenuButton(panel=_title, parent=self) _button.setIcon(QIcon(_icon)) _container.layout.addWidget(_button) _settingsButton = MenuButton(panel="config_prefs", parent=self) _settingsButton.setIcon(QIcon(Config.faIcon("user-cog"))) _container.layout.addWidget(_settingsButton) del _container, _scroll, _key, _settingsButton, _title, _icon, _button # Create version info label self._version = QLabel('v%s' % Config.version, self) self._version.setAlignment(Qt.AlignCenter) self._version.setFixedWidth(Config.menuWidth) self._version.setStyleSheet("QLabel{border: none}") self._sidebarMenu.layout.addWidget(self._version) # Create OSK button self._oskButton = QPushButton('', self) self._oskButton.setIcon(QIcon(Config.faIcon('keyboard'))) self._oskButton.setFixedWidth(Config.menuWidth) self._oskButton.clicked.connect(self.showOSK) self._sidebarMenu.layout.addWidget(self._oskButton) # Add menu frame to main UI self.layout().addWidget(self._sidebarMenu) # Create main UI panel self._mainPanel = QWidget(self) self._mainPanel.setLayout(QVBoxLayout(self._mainPanel)) self.layout().addWidget(self._mainPanel) # Init default UI for _key in [ 'enableOBA', 'enableLighting', 'enableTracControl', 'enableCamViewer', 'enableGyro' ]: _cUI = None _uiName = None if _key in self.prefs.keys(): if self.prefs[_key]: if _key == 'enableOBA': _cUI = OBAControlUI(self.obas.obas, self) _uiName = 'control_oba' elif _key == 'enableLighting': _cUI = LightControlUI(self.lights.lights, self) _uiName = 'control_light' elif _key == 'enableTracControl': _cUI = TracControlUI(self.tracs.tracs, self) _uiName = 'control_trac' elif _key == 'enableCamViewer': _cUI = CamViewer(0) _uiName = 'control_cam' elif _key == 'enableGryo': _cUI = Gyrometer() _uiName = 'control_gyro' if _cUI is not None: break if _cUI is None: _cUI = UserPrefUI(self.prefs, parent=self) _uiName = 'config_prefs' self._currentUI = {'name': _uiName, 'obj': _cUI} _cUI.setParent(self) self._mainPanel.layout().addWidget(_cUI) _cUI.show() # Create button panel self._btnPanel = QWidget(self) self._btnPanel.setLayout(QHBoxLayout(self._btnPanel)) self._mainPanel.layout().addWidget(self._btnPanel) # Create Config button self._configButton = QPushButton('Configure', self) self._configButton.setFixedHeight(50) self._configButton.setIcon(QIcon(Config.faIcon('cog'))) self._configButton.clicked.connect(self.__configButtonAction) self._btnPanel.layout().addWidget(self._configButton) # Create Night Mode button self._nightModeButton = QPushButton('', self) self._nightModeButton.setFixedHeight(50) self._nightModeButton.setIcon( QIcon({ True: Config.faIcon('sun'), False: Config.faIcon('moon') }[self.prefs['nightMode']])) self._nightModeButton.setText({ True: 'Day Mode', False: 'Night Mode' }[self.prefs['nightMode']]) self._nightModeButton.clicked.connect(self.toggleNightMode) self._btnPanel.layout().addWidget(self._nightModeButton) self.setNightMode(self.prefs['nightMode']) def closeEvent(self, event): self.savePrefs() self._i2cBus.deEnergizeAll() super(MainUI, self).closeEvent(event) def availablePins(self, value=None): if not self.prefs['allowDuplicatePins']: _pins = Config.outputPinList for _light in self.lights.lights: if _light.outputPin in _pins: _pins.remove(_light.outputPin) for _oba in self.obas.obas: if _oba.outputPin in _pins: _pins.remove(_oba.outputPin) for _trac in self.tracs.tracs: if _trac.outputPin in _pins: _pins.remove(_trac.outputPin) else: _pins = Config.outputPinList _pins.sort() return _pins def setOutputPin(self, pin, state): fx = { True: self.i2cBus.energizeRelay, False: self.i2cBus.deEnergizeRelay }[state] fx(pin) def disableConfigButtons(self): for _ctrl in [self.configButton]: _ctrl.setEnabled(False) del _ctrl def enableConfigButtons(self): for _ctrl in [self.configButton]: _ctrl.setEnabled(True) del _ctrl def loadUI(self, ui, idx=None): if 'cam' in self.currentUI['name']: self.currentUI['obj'].stop() if 'gyro' in self.currentUI['name']: self.currentUI['obj'].stopSerial() self.currentUI['obj'].stopRotation() self.currentUI['obj'].hide() self.mainPanel.layout().removeWidget(self.currentUI['obj']) self.mainPanel.layout().removeWidget(self.btnPanel) _mode = ui.split('_')[0] _type = ui.split('_')[1] _ui = None if _mode == 'control': if _type == 'gyro': self.configButton.setText("Calibrate") else: self.configButton.setText("Configure") if _type == 'light': _ui = LightControlUI(self.lights.lights, self) elif _type == 'oba': _ui = OBAControlUI(self.obas.obas, self) elif _type == 'trac': _ui = TracControlUI(self.tracs.tracs, self) elif _type == 'cam': _ui = CamViewer(0) _ui.start() elif _type == 'gyro': _ui = Gyrometer(parent=self) _ui.startSerial() _ui.startRotation() elif _mode == 'config': if _type == 'light': _ui = LightConfigUI(self.lights.lights, self) elif _type == 'oba': _ui = OBAConfigUI(self.obas.obas, self) elif _type == 'trac': _ui = TracConfigUI(self.tracs.tracs, self) elif _type == 'prefs': _ui = UserPrefUI(self.prefs, self) elif _mode == 'edit': if _type == 'light': _ui = EditLightUI(self.lights.lights[idx], self) elif _type == 'oba': _ui = EditOBAUI(self.obas.obas[idx], self) elif _type == 'trac': _ui = EditTracUI(self.tracs.tracs[idx], self) elif _mode == 'create': if _type == 'light': _ui = AddLightUI(self) elif _type == 'oba': _ui = AddOBAUI(self) elif _type == 'trac': _ui = AddTracUI(self) if _ui is not None: _ui.setParent(self) self.mainPanel.layout().addWidget(_ui) _ui.show() self.currentUI = {'name': ui, 'obj': _ui} self.mainPanel.layout().addWidget(self.btnPanel) def toggleNightMode(self): _mode = self.prefs['nightMode'] _value = {False: Config.dayBright, True: Config.nightBright}[not _mode] self.nightModeButton.setIcon({ False: QIcon(Config.faIcon('sun')), True: QIcon(Config.faIcon('moon')) }[not _mode]) self.nightModeButton.setText({ False: 'Day Mode', True: 'Night Mode' }[not _mode]) os.system("echo %s > /sys/class/backlight/rpi_backlight/brightness" % _value) self.prefs['nightMode'] = not _mode self.savePrefs() self.logger.log('Night mode %s: backlight set to %s' % (not _mode, _value)) del _mode, _value def setNightMode(self, mode): _value = {False: Config.dayBright, True: Config.nightBright}[mode] self.nightModeButton.setIcon({ False: QIcon(Config.faIcon('sun')), True: QIcon(Config.faIcon('moon')) }[mode]) self.nightModeButton.setText({ False: 'Day Mode', True: 'Night Mode' }[mode]) os.system("echo %s > /sys/class/backlight/rpi_backlight/brightness" % _value) del _value def loadPrefs(self): _pPrefs = open(Config.prefs, 'rb') _prefs = pickle.load(_pPrefs) for key in _prefs: self.prefs[key] = _prefs[key] _pPrefs.close() del _pPrefs, _prefs def savePrefs(self): _pPrefs = open(Config.prefs, 'wb') pickle.dump(self.prefs, _pPrefs) _pPrefs.close() def showOSK(self): if self.window().dock.isHidden(): self.window().dock.show() else: self.window().dock.hide() def __configButtonAction(self): if self.currentUI['name'] not in ['control_camera', 'control_gyro']: self.disableConfigButtons() self.mainPanel.layout().removeWidget(self.currentUI['obj']) self.loadUI(self.currentUI['name'].replace('control', 'config')) elif self.currentUI['name'] == 'control_gyro': self.currentUI['obj'].calibrate() @property def mainPanel(self): return self._mainPanel @property def btnPanel(self): return self._btnPanel @property def nightModeButton(self): return self._nightModeButton @property def configButton(self): return self._configButton @property def currentUI(self): return self._currentUI @currentUI.setter def currentUI(self, value): self._currentUI = value @property def i2cBus(self): return self._i2cBus
class FileWidget(QWidget): on_open = pyqtSignal(str) def __init__(self, dialog_title='', dialog_format='', start_dir=os.path.expanduser('~/'), icon_size=(12, 20), minimal_width=200, browse_label='Browse', on_open=None, reload_button=True, reload_label='Reload', recent_files=None, directory_aliases=None, allow_empty=True, empty_file_label='(none)'): """ Creates a widget with a button for file loading and an optional combo box for recent files and reload buttons. Args: dialog_title (str): The title of the dialog. dialog_format (str): Formats for the dialog. start_dir (str): A directory to start from. icon_size (int, int): The size of buttons' icons. on_open (callable): A callback function that accepts filepath as the only argument. reload_button (bool): Whether to show reload button. reload_label (str): The text displayed on the reload button. recent_files (List[str]): List of recent files. directory_aliases (dict): An {alias: dir} dictionary for fast directories' access. allow_empty (bool): Whether empty path is allowed. """ super().__init__() self.dialog_title = dialog_title self.dialog_format = dialog_format self.start_dir = start_dir self.recent_files = recent_files self.directory_aliases = directory_aliases or {} self.check_existence() self.on_open.connect(on_open) self.allow_empty = allow_empty self.empty_file_label = empty_file_label layout = QHBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) if recent_files is not None: self.file_combo = QComboBox() self.file_combo.setMinimumWidth(minimal_width) self.file_combo.activated[int].connect(self.select) self.update_combo() layout.addWidget(self.file_combo) self.browse_button = QPushButton(browse_label) self.browse_button.setFocusPolicy(Qt.NoFocus) self.browse_button.clicked.connect(self.browse) self.browse_button.setIcon(self.style().standardIcon( QStyle.SP_DirOpenIcon)) self.browse_button.setIconSize(QSize(*icon_size)) self.browse_button.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) layout.addWidget(self.browse_button) if reload_button: self.reload_button = QPushButton(reload_label) self.reload_button.setFocusPolicy(Qt.NoFocus) self.reload_button.clicked.connect(self.reload) self.reload_button.setIcon(self.style().standardIcon( QStyle.SP_BrowserReload)) self.reload_button.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) self.reload_button.setIconSize(QSize(*icon_size)) layout.addWidget(self.reload_button) def browse(self, start_dir=None): start_dir = start_dir or self.start_dir path, _ = QFileDialog().getOpenFileName(self, self.dialog_title, start_dir, self.dialog_format) if path and self.recent_files is not None: if path in self.recent_files: self.recent_files.remove(path) self.recent_files.insert(0, path) self.update_combo() self.open_file(path) def select(self, n): name = self.file_combo.currentText() if n < len(self.recent_files): name = self.recent_files[n] del self.recent_files[n] self.recent_files.insert(0, name) self.open_file(self.recent_files[0]) self.update_combo() elif name == self.empty_file_label: self.open_file(self.empty_file_label) elif name in self.directory_aliases: self.browse(self.directory_aliases[name]) def update_combo(self): if self.recent_files is not None: self.file_combo.clear() for file in self.recent_files: self.file_combo.addItem(os.path.split(file)[1]) if self.allow_empty or not self.recent_files: self.file_combo.addItem(self.empty_file_label) for alias in self.directory_aliases.keys(): self.file_combo.addItem(alias) def reload(self): if self.recent_files: self.select(0) def check_existence(self): if self.recent_files: to_remove = [ file for file in self.recent_files if not os.path.exists(file) ] for file in to_remove: self.recent_files.remove(file) def open_file(self, path): try: self.on_open.emit(path if path != self.empty_file_label else '') except (OSError, IOError): self.loading_error_signal.emit('Could not open "{}".'.format(path))
class FileWidget(QWidget): on_open = pyqtSignal(str) def __init__(self, dialog_title='', dialog_format='', start_dir=os.path.expanduser('~/'), icon_size=(12, 20), minimal_width=200, browse_label='Browse', on_open=None, reload_button=True, reload_label='Reload', recent_files=None, directory_aliases=None, allow_empty=True, empty_file_label='(none)'): """ Creates a widget with a button for file loading and an optional combo box for recent files and reload buttons. Args: dialog_title (str): The title of the dialog. dialog_format (str): Formats for the dialog. start_dir (str): A directory to start from. icon_size (int, int): The size of buttons' icons. on_open (callable): A callback function that accepts filepath as the only argument. reload_button (bool): Whether to show reload button. reload_label (str): The text displayed on the reload button. recent_files (List[str]): List of recent files. directory_aliases (dict): An {alias: dir} dictionary for fast directories' access. allow_empty (bool): Whether empty path is allowed. """ super().__init__() self.dialog_title = dialog_title self.dialog_format = dialog_format self.start_dir = start_dir self.recent_files = recent_files self.directory_aliases = directory_aliases or {} self.check_existence() self.on_open.connect(on_open) self.allow_empty = allow_empty self.empty_file_label = empty_file_label layout = QHBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) if recent_files is not None: self.file_combo = QComboBox() self.file_combo.setMinimumWidth(minimal_width) self.file_combo.activated[int].connect(self.select) self.update_combo() layout.addWidget(self.file_combo) self.browse_button = QPushButton(browse_label) self.browse_button.setFocusPolicy(Qt.NoFocus) self.browse_button.clicked.connect(self.browse) self.browse_button.setIcon(self.style() .standardIcon(QStyle.SP_DirOpenIcon)) self.browse_button.setIconSize(QSize(*icon_size)) self.browse_button.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) layout.addWidget(self.browse_button) if reload_button: self.reload_button = QPushButton(reload_label) self.reload_button.setFocusPolicy(Qt.NoFocus) self.reload_button.clicked.connect(self.reload) self.reload_button.setIcon(self.style() .standardIcon(QStyle.SP_BrowserReload)) self.reload_button.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) self.reload_button.setIconSize(QSize(*icon_size)) layout.addWidget(self.reload_button) def browse(self, start_dir=None): start_dir = start_dir or self.start_dir path, _ = QFileDialog().getOpenFileName(self, self.dialog_title, start_dir, self.dialog_format) if path and self.recent_files is not None: if path in self.recent_files: self.recent_files.remove(path) self.recent_files.insert(0, path) self.update_combo() self.open_file(path) def select(self, n): name = self.file_combo.currentText() if n < len(self.recent_files): name = self.recent_files[n] del self.recent_files[n] self.recent_files.insert(0, name) self.open_file(self.recent_files[0]) self.update_combo() elif name == self.empty_file_label: self.open_file(self.empty_file_label) elif name in self.directory_aliases: self.browse(self.directory_aliases[name]) def update_combo(self): if self.recent_files is not None: self.file_combo.clear() for file in self.recent_files: self.file_combo.addItem(os.path.split(file)[1]) if self.allow_empty or not self.recent_files: self.file_combo.addItem(self.empty_file_label) for alias in self.directory_aliases.keys(): self.file_combo.addItem(alias) def reload(self): if self.recent_files: self.select(0) def check_existence(self): if self.recent_files: to_remove = [ file for file in self.recent_files if not os.path.exists(file) ] for file in to_remove: self.recent_files.remove(file) def open_file(self, path): try: self.on_open.emit(path if path != self.empty_file_label else '') except (OSError, IOError): self.loading_error_signal.emit('Could not open "{}".' .format(path))
def init_form(self): # Get the current path of the file rootPath = os.path.dirname(__file__) vlayout = QVBoxLayout() hlayout = QHBoxLayout() if _api.USED_API == _api.QT_API_PYQT5: hlayout.setContentsMargins(0, 0, 0, 0) vlayout.setContentsMargins(0, 0, 0, 0) elif _api.USED_API == _api.QT_API_PYQT4: hlayout.setMargin(0) vlayout.setMargin(0) self.setLayout(vlayout) # Add scroll area scrollarea = QScrollArea() self._scrollArea = scrollarea scrollarea.setMinimumHeight(140) scrollarea.setWidgetResizable(True) scrollarea.keyPressEvent = self.__scrollAreaKeyPressEvent scrollarea.keyReleaseEvent = self.__scrollAreaKeyReleaseEvent vlayout.addWidget(scrollarea) # The timeline widget self._time = widget = TimelineWidget(self) widget._scroll = scrollarea scrollarea.setWidget(widget) # Timeline zoom slider slider = QSlider(QtCore.Qt.Horizontal) slider.setFocusPolicy(QtCore.Qt.NoFocus) slider.setMinimum(1) slider.setMaximum(100) slider.setValue(10) slider.setPageStep(1) slider.setTickPosition(QSlider.NoTicks) # TicksBothSides slider.valueChanged.connect(self.__scaleSliderChange) slider_label_zoom_in = QLabel() slider_label_zoom_out = QLabel() slider_label_zoom_in.setPixmap( conf.PYFORMS_PIXMAP_EVENTTIMELINE_ZOOM_IN) slider_label_zoom_out.setPixmap( conf.PYFORMS_PIXMAP_EVENTTIMELINE_ZOOM_OUT) self._zoomLabel = QLabel("100%") hlayout.addWidget(self._zoomLabel) hlayout.addWidget(slider_label_zoom_out) hlayout.addWidget(slider) hlayout.addWidget(slider_label_zoom_in) # Import/Export Buttons btn_import = QPushButton("Import") btn_import.setIcon(conf.PYFORMS_ICON_EVENTTIMELINE_IMPORT) btn_import.clicked.connect(self.__open_import_win_evt) btn_export = QPushButton("Export") btn_export.setIcon(conf.PYFORMS_ICON_EVENTTIMELINE_EXPORT) btn_export.clicked.connect(self.__export) hlayout.addWidget(btn_import) hlayout.addWidget(btn_export) vlayout.addLayout(hlayout)
class FileWidget(QWidget): on_open = pyqtSignal(str) # TODO consider removing directory_aliases since it is not used any more def __init__(self, dialog_title='', dialog_format='', start_dir=os.path.expanduser('~/'), icon_size=(12, 20), minimal_width=200, browse_label='Browse', on_open=None, reload_button=True, reload_label='Reload', recent_files=None, directory_aliases=None, allow_empty=True, empty_file_label='(none)'): """ Creates a widget with a button for file loading and an optional combo box for recent files and reload buttons. Args: dialog_title (str): The title of the dialog. dialog_format (str): Formats for the dialog. start_dir (str): A directory to start from. icon_size (int, int): The size of buttons' icons. on_open (callable): A callback function that accepts filepath as the only argument. reload_button (bool): Whether to show reload button. reload_label (str): The text displayed on the reload button. recent_files (List[str]): List of recent files. directory_aliases (dict): An {alias: dir} dictionary for fast directories' access. allow_empty (bool): Whether empty path is allowed. """ super().__init__() self.dialog_title = dialog_title self.dialog_format = dialog_format self.start_dir = start_dir # Recent files should also contain `empty_file_label` so # when (none) is selected this is stored in settings. self.recent_files = recent_files if recent_files is not None else [] self.directory_aliases = directory_aliases or {} self.allow_empty = allow_empty self.empty_file_label = empty_file_label if self.empty_file_label not in self.recent_files \ and (self.allow_empty or not self.recent_files): self.recent_files.append(self.empty_file_label) self.check_existence() self.on_open.connect(on_open) layout = QHBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) if recent_files is not None: self.file_combo = QComboBox() self.file_combo.setMinimumWidth(minimal_width) self.file_combo.activated[int].connect(self.select) self.update_combo() layout.addWidget(self.file_combo) self.browse_button = QPushButton(browse_label) self.browse_button.setFocusPolicy(Qt.NoFocus) self.browse_button.clicked.connect(self.browse) self.browse_button.setIcon(self.style() .standardIcon(QStyle.SP_DirOpenIcon)) self.browse_button.setIconSize(QSize(*icon_size)) self.browse_button.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) layout.addWidget(self.browse_button) if reload_button: self.reload_button = QPushButton(reload_label) self.reload_button.setFocusPolicy(Qt.NoFocus) self.reload_button.clicked.connect(self.reload) self.reload_button.setIcon(self.style() .standardIcon(QStyle.SP_BrowserReload)) self.reload_button.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) self.reload_button.setIconSize(QSize(*icon_size)) layout.addWidget(self.reload_button) def browse(self, start_dir=None): start_dir = start_dir or self.start_dir path, _ = QFileDialog().getOpenFileName(self, self.dialog_title, start_dir, self.dialog_format) if path and self.recent_files is not None: if path in self.recent_files: self.recent_files.remove(path) self.recent_files.insert(0, path) self.update_combo() if path: self.open_file(path) def select(self, n): name = self.file_combo.currentText() if name == self.empty_file_label: del self.recent_files[n] self.recent_files.insert(0, self.empty_file_label) self.update_combo() self.open_file(self.empty_file_label) elif name in self.directory_aliases: self.browse(self.directory_aliases[name]) elif n < len(self.recent_files): name = self.recent_files[n] del self.recent_files[n] self.recent_files.insert(0, name) self.update_combo() self.open_file(self.recent_files[0]) def update_combo(self): """ Sync combo values to the changes in self.recent_files. """ if self.recent_files is not None: self.file_combo.clear() for i, file in enumerate(self.recent_files): # remove (none) when we have some files and allow_empty=False if file == self.empty_file_label and \ not self.allow_empty and len(self.recent_files) > 1: del self.recent_files[i] else: self.file_combo.addItem(os.path.split(file)[1]) for alias in self.directory_aliases.keys(): self.file_combo.addItem(alias) def reload(self): if self.recent_files: self.select(0) def check_existence(self): if self.recent_files: to_remove = [] for file in self.recent_files: doc_path = os.path.join(get_sample_corpora_dir(), file) exists = any(os.path.exists(f) for f in [file, doc_path]) if file != self.empty_file_label and not exists: to_remove.append(file) for file in to_remove: self.recent_files.remove(file) def open_file(self, path): self.on_open.emit(path if path != self.empty_file_label else '') def get_selected_filename(self): if self.recent_files: return self.recent_files[0] else: return self.empty_file_label