class PreferencesDialogBase(QDialog): def __init__(self, parent, app, **kwargs): flags = Qt.CustomizeWindowHint | Qt.WindowTitleHint | Qt.WindowSystemMenuHint super().__init__(parent, flags, **kwargs) self.app = app all_languages = get_langnames() self.supportedLanguages = sorted(SUPPORTED_LANGUAGES, key=lambda lang: all_languages[lang]) self._setupUi() self.filterHardnessSlider.valueChanged["int"].connect( self.filterHardnessLabel.setNum) self.buttonBox.clicked.connect(self.buttonClicked) self.buttonBox.accepted.connect(self.accept) self.buttonBox.rejected.connect(self.reject) def _setupFilterHardnessBox(self): self.filterHardnessHLayout = QHBoxLayout() self.filterHardnessLabel = QLabel(self) self.filterHardnessLabel.setText(tr("Filter Hardness:")) self.filterHardnessLabel.setMinimumSize(QSize(0, 0)) self.filterHardnessHLayout.addWidget(self.filterHardnessLabel) self.filterHardnessVLayout = QVBoxLayout() self.filterHardnessVLayout.setSpacing(0) self.filterHardnessHLayoutSub1 = QHBoxLayout() self.filterHardnessHLayoutSub1.setSpacing(12) self.filterHardnessSlider = QSlider(self) sizePolicy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth( self.filterHardnessSlider.sizePolicy().hasHeightForWidth()) self.filterHardnessSlider.setSizePolicy(sizePolicy) self.filterHardnessSlider.setMinimum(1) self.filterHardnessSlider.setMaximum(100) self.filterHardnessSlider.setTracking(True) self.filterHardnessSlider.setOrientation(Qt.Horizontal) self.filterHardnessHLayoutSub1.addWidget(self.filterHardnessSlider) self.filterHardnessLabel = QLabel(self) self.filterHardnessLabel.setText("100") self.filterHardnessLabel.setMinimumSize(QSize(21, 0)) self.filterHardnessHLayoutSub1.addWidget(self.filterHardnessLabel) self.filterHardnessVLayout.addLayout(self.filterHardnessHLayoutSub1) self.filterHardnessHLayoutSub2 = QHBoxLayout() self.filterHardnessHLayoutSub2.setContentsMargins(-1, 0, -1, -1) self.moreResultsLabel = QLabel(self) self.moreResultsLabel.setText(tr("More Results")) self.filterHardnessHLayoutSub2.addWidget(self.moreResultsLabel) spacerItem = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) self.filterHardnessHLayoutSub2.addItem(spacerItem) self.fewerResultsLabel = QLabel(self) self.fewerResultsLabel.setText(tr("Fewer Results")) self.filterHardnessHLayoutSub2.addWidget(self.fewerResultsLabel) self.filterHardnessVLayout.addLayout(self.filterHardnessHLayoutSub2) self.filterHardnessHLayout.addLayout(self.filterHardnessVLayout) def _setupBottomPart(self): # The bottom part of the pref panel is always the same in all editions. self.copyMoveLabel = QLabel(self) self.copyMoveLabel.setText(tr("Copy and Move:")) self.widgetsVLayout.addWidget(self.copyMoveLabel) self.copyMoveDestinationComboBox = QComboBox(self) self.copyMoveDestinationComboBox.addItem(tr("Right in destination")) self.copyMoveDestinationComboBox.addItem(tr("Recreate relative path")) self.copyMoveDestinationComboBox.addItem(tr("Recreate absolute path")) self.widgetsVLayout.addWidget(self.copyMoveDestinationComboBox) self.customCommandLabel = QLabel(self) self.customCommandLabel.setText( tr("Custom Command (arguments: %d for dupe, %r for ref):")) self.widgetsVLayout.addWidget(self.customCommandLabel) self.customCommandEdit = QLineEdit(self) self.widgetsVLayout.addWidget(self.customCommandEdit) def _setupDisplayPage(self): self.ui_groupbox = QGroupBox("&General Interface") layout = QVBoxLayout() self.languageLabel = QLabel(tr("Language:"), self) self.languageComboBox = QComboBox(self) for lang in self.supportedLanguages: self.languageComboBox.addItem(get_langnames()[lang]) layout.addLayout( horizontalWrap([self.languageLabel, self.languageComboBox, None])) self._setupAddCheckbox( "tabs_default_pos", tr("Use default position for tab bar (requires restart)")) self.tabs_default_pos.setToolTip( tr("Place the tab bar below the main menu instead of next to it\n\ On MacOS, the tab bar will fill up the window's width instead.")) layout.addWidget(self.tabs_default_pos) self.ui_groupbox.setLayout(layout) self.displayVLayout.addWidget(self.ui_groupbox) gridlayout = QFormLayout() result_groupbox = QGroupBox("&Result Table") self.fontSizeSpinBox = QSpinBox() self.fontSizeSpinBox.setMinimum(5) gridlayout.addRow(tr("Font size:"), self.fontSizeSpinBox) self._setupAddCheckbox("reference_bold_font", tr("Use bold font for references")) gridlayout.addRow(self.reference_bold_font) self.result_table_ref_foreground_color = ColorPickerButton(self) gridlayout.addRow(tr("Reference foreground color:"), self.result_table_ref_foreground_color) self.result_table_ref_background_color = ColorPickerButton(self) gridlayout.addRow(tr("Reference background color:"), self.result_table_ref_background_color) self.result_table_delta_foreground_color = ColorPickerButton(self) gridlayout.addRow(tr("Delta foreground color:"), self.result_table_delta_foreground_color) gridlayout.setLabelAlignment(Qt.AlignLeft) # Keep same vertical spacing as parent layout for consistency gridlayout.setVerticalSpacing(self.displayVLayout.spacing()) result_groupbox.setLayout(gridlayout) self.displayVLayout.addWidget(result_groupbox) details_groupbox = QGroupBox("&Details Window") self.details_groupbox_layout = QVBoxLayout() self._setupAddCheckbox("details_dialog_titlebar_enabled", tr("Show the title bar and can be docked")) self.details_dialog_titlebar_enabled.setToolTip( tr("While the title bar is hidden, \ use the modifier key to drag the floating window around") if ISLINUX else tr("The title bar can only be disabled while the window is docked" )) self.details_groupbox_layout.addWidget( self.details_dialog_titlebar_enabled) self._setupAddCheckbox("details_dialog_vertical_titlebar", tr("Vertical title bar")) self.details_dialog_vertical_titlebar.setToolTip( tr("Change the title bar from horizontal on top, to vertical on the left side" )) self.details_groupbox_layout.addWidget( self.details_dialog_vertical_titlebar) self.details_dialog_vertical_titlebar.setEnabled( self.details_dialog_titlebar_enabled.isChecked()) self.details_dialog_titlebar_enabled.stateChanged.connect( self.details_dialog_vertical_titlebar.setEnabled) gridlayout = QGridLayout() self.details_table_delta_foreground_color_label = QLabel( tr("Delta foreground color:")) gridlayout.addWidget(self.details_table_delta_foreground_color_label, 4, 0) self.details_table_delta_foreground_color = ColorPickerButton(self) gridlayout.addWidget(self.details_table_delta_foreground_color, 4, 2, 1, 1, Qt.AlignLeft) gridlayout.setColumnStretch(1, 1) gridlayout.setColumnStretch(3, 4) self.details_groupbox_layout.addLayout(gridlayout) details_groupbox.setLayout(self.details_groupbox_layout) self.displayVLayout.addWidget(details_groupbox) def _setupAddCheckbox(self, name, label, parent=None): if parent is None: parent = self cb = QCheckBox(parent) cb.setText(label) setattr(self, name, cb) def _setupPreferenceWidgets(self): # Edition-specific pass def _setupUi(self): self.setWindowTitle(tr("Options")) self.setSizeGripEnabled(False) self.setModal(True) self.mainVLayout = QVBoxLayout(self) self.tabwidget = QTabWidget() self.page_general = QWidget() self.page_display = QWidget() self.widgetsVLayout = QVBoxLayout() self.page_general.setLayout(self.widgetsVLayout) self.displayVLayout = QVBoxLayout() self.displayVLayout.setSpacing( 5) # arbitrary value, might conflict with style self.page_display.setLayout(self.displayVLayout) self._setupPreferenceWidgets() self._setupDisplayPage() # self.mainVLayout.addLayout(self.widgetsVLayout) self.buttonBox = QDialogButtonBox(self) self.buttonBox.setStandardButtons(QDialogButtonBox.Cancel | QDialogButtonBox.Ok | QDialogButtonBox.RestoreDefaults) self.mainVLayout.addWidget(self.tabwidget) self.mainVLayout.addWidget(self.buttonBox) self.layout().setSizeConstraint(QLayout.SetFixedSize) self.tabwidget.addTab(self.page_general, "General") self.tabwidget.addTab(self.page_display, "Display") self.displayVLayout.addStretch(0) self.widgetsVLayout.addStretch(0) def _load(self, prefs, setchecked, section): # Edition-specific pass def _save(self, prefs, ischecked): # Edition-specific pass def load(self, prefs=None, section=Sections.ALL): if prefs is None: prefs = self.app.prefs setchecked = lambda cb, b: cb.setCheckState(Qt.Checked if b else Qt.Unchecked) if section & Sections.GENERAL: self.filterHardnessSlider.setValue(prefs.filter_hardness) self.filterHardnessLabel.setNum(prefs.filter_hardness) setchecked(self.mixFileKindBox, prefs.mix_file_kind) setchecked(self.useRegexpBox, prefs.use_regexp) setchecked(self.removeEmptyFoldersBox, prefs.remove_empty_folders) setchecked(self.ignoreHardlinkMatches, prefs.ignore_hardlink_matches) setchecked(self.debugModeBox, prefs.debug_mode) self.copyMoveDestinationComboBox.setCurrentIndex( prefs.destination_type) self.customCommandEdit.setText(prefs.custom_command) if section & Sections.DISPLAY: setchecked(self.reference_bold_font, prefs.reference_bold_font) setchecked(self.tabs_default_pos, prefs.tabs_default_pos) setchecked(self.details_dialog_titlebar_enabled, prefs.details_dialog_titlebar_enabled) setchecked(self.details_dialog_vertical_titlebar, prefs.details_dialog_vertical_titlebar) self.fontSizeSpinBox.setValue(prefs.tableFontSize) self.details_table_delta_foreground_color.setColor( prefs.details_table_delta_foreground_color) self.result_table_ref_foreground_color.setColor( prefs.result_table_ref_foreground_color) self.result_table_ref_background_color.setColor( prefs.result_table_ref_background_color) self.result_table_delta_foreground_color.setColor( prefs.result_table_delta_foreground_color) try: langindex = self.supportedLanguages.index( self.app.prefs.language) except ValueError: langindex = 0 self.languageComboBox.setCurrentIndex(langindex) self._load(prefs, setchecked, section) def save(self): prefs = self.app.prefs prefs.filter_hardness = self.filterHardnessSlider.value() ischecked = lambda cb: cb.checkState() == Qt.Checked prefs.mix_file_kind = ischecked(self.mixFileKindBox) prefs.use_regexp = ischecked(self.useRegexpBox) prefs.remove_empty_folders = ischecked(self.removeEmptyFoldersBox) prefs.ignore_hardlink_matches = ischecked(self.ignoreHardlinkMatches) prefs.debug_mode = ischecked(self.debugModeBox) prefs.reference_bold_font = ischecked(self.reference_bold_font) prefs.details_dialog_titlebar_enabled = ischecked( self.details_dialog_titlebar_enabled) prefs.details_dialog_vertical_titlebar = ischecked( self.details_dialog_vertical_titlebar) prefs.details_table_delta_foreground_color = self.details_table_delta_foreground_color.color prefs.result_table_ref_foreground_color = self.result_table_ref_foreground_color.color prefs.result_table_ref_background_color = self.result_table_ref_background_color.color prefs.result_table_delta_foreground_color = self.result_table_delta_foreground_color.color prefs.destination_type = self.copyMoveDestinationComboBox.currentIndex( ) prefs.custom_command = str(self.customCommandEdit.text()) prefs.tableFontSize = self.fontSizeSpinBox.value() prefs.tabs_default_pos = ischecked(self.tabs_default_pos) lang = self.supportedLanguages[self.languageComboBox.currentIndex()] oldlang = self.app.prefs.language if oldlang not in self.supportedLanguages: oldlang = "en" if lang != oldlang: QMessageBox.information( self, "", tr("dupeGuru has to restart for language changes to take effect." ), ) self.app.prefs.language = lang self._save(prefs, ischecked) def resetToDefaults(self, section_to_update): self.load(Preferences(), section_to_update) # --- Events def buttonClicked(self, button): role = self.buttonBox.buttonRole(button) if role == QDialogButtonBox.ResetRole: current_tab = self.tabwidget.currentWidget() section_to_update = Sections.ALL if current_tab is self.page_general: section_to_update = Sections.GENERAL if current_tab is self.page_display: section_to_update = Sections.DISPLAY self.resetToDefaults(section_to_update)
class PreferencesDialogBase(QDialog): def __init__(self, parent, app, **kwargs): flags = Qt.CustomizeWindowHint | Qt.WindowTitleHint | Qt.WindowSystemMenuHint super().__init__(parent, flags, **kwargs) self.app = app self._setupUi() self.filterHardnessSlider.valueChanged['int'].connect(self.filterHardnessLabel.setNum) self.buttonBox.clicked.connect(self.buttonClicked) self.buttonBox.accepted.connect(self.accept) self.buttonBox.rejected.connect(self.reject) def _setupScanTypeBox(self, labels): self.scanTypeHLayout = QHBoxLayout() self.scanTypeLabel = QLabel(self) self.scanTypeLabel.setText(tr("Scan Type:")) self.scanTypeLabel.setMinimumSize(QSize(100, 0)) self.scanTypeLabel.setMaximumSize(QSize(100, 16777215)) self.scanTypeHLayout.addWidget(self.scanTypeLabel) self.scanTypeComboBox = QComboBox(self) for label in labels: self.scanTypeComboBox.addItem(label) self.scanTypeHLayout.addWidget(self.scanTypeComboBox) self.widgetsVLayout.addLayout(self.scanTypeHLayout) def _setupFilterHardnessBox(self): self.filterHardnessHLayout = QHBoxLayout() self.filterHardnessLabel = QLabel(self) self.filterHardnessLabel.setText(tr("Filter Hardness:")) self.filterHardnessLabel.setMinimumSize(QSize(0, 0)) self.filterHardnessHLayout.addWidget(self.filterHardnessLabel) self.filterHardnessVLayout = QVBoxLayout() self.filterHardnessVLayout.setSpacing(0) self.filterHardnessHLayoutSub1 = QHBoxLayout() self.filterHardnessHLayoutSub1.setSpacing(12) self.filterHardnessSlider = QSlider(self) sizePolicy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.filterHardnessSlider.sizePolicy().hasHeightForWidth()) self.filterHardnessSlider.setSizePolicy(sizePolicy) self.filterHardnessSlider.setMinimum(1) self.filterHardnessSlider.setMaximum(100) self.filterHardnessSlider.setTracking(True) self.filterHardnessSlider.setOrientation(Qt.Horizontal) self.filterHardnessHLayoutSub1.addWidget(self.filterHardnessSlider) self.filterHardnessLabel = QLabel(self) self.filterHardnessLabel.setText("100") self.filterHardnessLabel.setMinimumSize(QSize(21, 0)) self.filterHardnessHLayoutSub1.addWidget(self.filterHardnessLabel) self.filterHardnessVLayout.addLayout(self.filterHardnessHLayoutSub1) self.filterHardnessHLayoutSub2 = QHBoxLayout() self.filterHardnessHLayoutSub2.setContentsMargins(-1, 0, -1, -1) self.moreResultsLabel = QLabel(self) self.moreResultsLabel.setText(tr("More Results")) self.filterHardnessHLayoutSub2.addWidget(self.moreResultsLabel) spacerItem = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) self.filterHardnessHLayoutSub2.addItem(spacerItem) self.fewerResultsLabel = QLabel(self) self.fewerResultsLabel.setText(tr("Fewer Results")) self.filterHardnessHLayoutSub2.addWidget(self.fewerResultsLabel) self.filterHardnessVLayout.addLayout(self.filterHardnessHLayoutSub2) self.filterHardnessHLayout.addLayout(self.filterHardnessVLayout) def _setupBottomPart(self): # The bottom part of the pref panel is always the same in all editions. self.fontSizeLabel = QLabel(tr("Font size:")) self.fontSizeSpinBox = QSpinBox() self.fontSizeSpinBox.setMinimum(5) self.widgetsVLayout.addLayout(horizontalWrap([self.fontSizeLabel, self.fontSizeSpinBox, None])) self.languageLabel = QLabel(tr("Language:"), self) self.languageComboBox = QComboBox(self) for lang in SUPPORTED_LANGUAGES: self.languageComboBox.addItem(LANGNAMES[lang]) self.widgetsVLayout.addLayout(horizontalWrap([self.languageLabel, self.languageComboBox, None])) self.copyMoveLabel = QLabel(self) self.copyMoveLabel.setText(tr("Copy and Move:")) self.widgetsVLayout.addWidget(self.copyMoveLabel) self.copyMoveDestinationComboBox = QComboBox(self) self.copyMoveDestinationComboBox.addItem(tr("Right in destination")) self.copyMoveDestinationComboBox.addItem(tr("Recreate relative path")) self.copyMoveDestinationComboBox.addItem(tr("Recreate absolute path")) self.widgetsVLayout.addWidget(self.copyMoveDestinationComboBox) self.customCommandLabel = QLabel(self) self.customCommandLabel.setText(tr("Custom Command (arguments: %d for dupe, %r for ref):")) self.widgetsVLayout.addWidget(self.customCommandLabel) self.customCommandEdit = QLineEdit(self) self.widgetsVLayout.addWidget(self.customCommandEdit) def _setupAddCheckbox(self, name, label, parent=None): if parent is None: parent = self cb = QCheckBox(parent) cb.setText(label) setattr(self, name, cb) def _setupPreferenceWidgets(self): # Edition-specific pass def _setupUi(self): self.setWindowTitle(tr("Preferences")) self.resize(304, 263) self.setSizeGripEnabled(False) self.setModal(True) self.mainVLayout = QVBoxLayout(self) self.widgetsVLayout = QVBoxLayout() self._setupPreferenceWidgets() self.mainVLayout.addLayout(self.widgetsVLayout) self.buttonBox = QDialogButtonBox(self) self.buttonBox.setStandardButtons(QDialogButtonBox.Cancel|QDialogButtonBox.Ok|QDialogButtonBox.RestoreDefaults) self.mainVLayout.addWidget(self.buttonBox) if (not ISOSX) and (not ISLINUX): self.mainVLayout.removeWidget(self.ignoreHardlinkMatches) self.ignoreHardlinkMatches.setHidden(True) def _load(self, prefs, setchecked): # Edition-specific pass def _save(self, prefs, ischecked): # Edition-specific pass def load(self, prefs=None): if prefs is None: prefs = self.app.prefs self.filterHardnessSlider.setValue(prefs.filter_hardness) self.filterHardnessLabel.setNum(prefs.filter_hardness) setchecked = lambda cb, b: cb.setCheckState(Qt.Checked if b else Qt.Unchecked) setchecked(self.mixFileKindBox, prefs.mix_file_kind) setchecked(self.useRegexpBox, prefs.use_regexp) setchecked(self.removeEmptyFoldersBox, prefs.remove_empty_folders) setchecked(self.ignoreHardlinkMatches, prefs.ignore_hardlink_matches) setchecked(self.debugModeBox, prefs.debug_mode) self.copyMoveDestinationComboBox.setCurrentIndex(prefs.destination_type) self.customCommandEdit.setText(prefs.custom_command) self.fontSizeSpinBox.setValue(prefs.tableFontSize) try: langindex = SUPPORTED_LANGUAGES.index(self.app.prefs.language) except ValueError: langindex = 0 self.languageComboBox.setCurrentIndex(langindex) self._load(prefs, setchecked) def save(self): prefs = self.app.prefs prefs.filter_hardness = self.filterHardnessSlider.value() ischecked = lambda cb: cb.checkState() == Qt.Checked prefs.mix_file_kind = ischecked(self.mixFileKindBox) prefs.use_regexp = ischecked(self.useRegexpBox) prefs.remove_empty_folders = ischecked(self.removeEmptyFoldersBox) prefs.ignore_hardlink_matches = ischecked(self.ignoreHardlinkMatches) prefs.debug_mode = ischecked(self.debugModeBox) prefs.destination_type = self.copyMoveDestinationComboBox.currentIndex() prefs.custom_command = str(self.customCommandEdit.text()) prefs.tableFontSize = self.fontSizeSpinBox.value() lang = SUPPORTED_LANGUAGES[self.languageComboBox.currentIndex()] oldlang = self.app.prefs.language if oldlang not in SUPPORTED_LANGUAGES: oldlang = 'en' if lang != oldlang: QMessageBox.information(self, "", tr("dupeGuru has to restart for language changes to take effect.")) self.app.prefs.language = lang self._save(prefs, ischecked) #--- Events def buttonClicked(self, button): role = self.buttonBox.buttonRole(button) if role == QDialogButtonBox.ResetRole: self.resetToDefaults()
class OptionsDialog(QDialog): def __init__(self, setting: Settings, have_dutils, parent=None): super(OptionsDialog, self).__init__(parent) self.settings = setting self.enabled_video = True # temporary toggle to disable video features as they do not exist self.enabled_logging = True self.enabled_keybindings = True self.enabled_dutils = have_dutils self.setWindowTitle("Tcam-Capture Options") self.layout = QVBoxLayout(self) self.setLayout(self.layout) self.tabs = QTabWidget() self.general_widget = QWidget() self.keybindings_widget = QWidget() self.logging_widget = QWidget() self.saving_widget = QWidget() self._setup_general_ui() self.tabs.addTab(self.general_widget, "General") self._setup_saving_ui() self.tabs.addTab(self.saving_widget, "Image/Video") self.layout.addWidget(self.tabs) # OK and Cancel buttons self.buttons = QDialogButtonBox( QDialogButtonBox.Reset | QDialogButtonBox.Ok | QDialogButtonBox.Cancel, Qt.Horizontal, self) self.layout.addWidget(self.buttons) self.buttons.accepted.connect(self.accept) self.buttons.rejected.connect(self.reject) self.buttons.clicked.connect(self.clicked) def _setup_general_ui(self): """ Create everything related to the general tab """ layout = QFormLayout() layout.setSpacing(20) layout.setVerticalSpacing(20) self.device_dialog_checkbox = QCheckBox(self) device_dialog_label = QLabel("Open device dialog on start:") layout.addRow(device_dialog_label, self.device_dialog_checkbox) self.reopen_device_checkbox = QCheckBox(self) reopen_device_label = QLabel( "Reopen device on start(ignores device dialog):", self) layout.addRow(reopen_device_label, self.reopen_device_checkbox) self.use_dutils_checkbox = QCheckBox(self) self.use_dutils_label = QLabel("Use tiscamera dutils, if present:", self) layout.addRow(self.use_dutils_label, self.use_dutils_checkbox) if not self.enabled_dutils: self.use_dutils_label.setToolTip( "Enabled when tiscamera-dutils are installed") self.use_dutils_label.setEnabled(False) self.use_dutils_checkbox.setToolTip( "Enabled when tiscamera-dutils are installed") self.use_dutils_checkbox.setEnabled(False) self.general_widget.setLayout(layout) def _setup_saving_ui(self): """ Create everything related to the image/video saving tab """ encoder_dict = Encoder.get_encoder_dict() form_layout = QFormLayout() layout = QVBoxLayout() layout.addLayout(form_layout) location_layout = QHBoxLayout() location_label = QLabel("Where to save images/videos:", self) self.location_edit = QLineEdit(self) location_dialog_button = QPushButton("...", self) location_dialog_button.clicked.connect(self.open_file_dialog) location_layout.addWidget(self.location_edit) location_layout.addWidget(location_dialog_button) # maintain descriptions as own labels # pyqt seems to loose the descriptions somewhere # when simple strings are used or the qlabel does not have self as owner form_layout.addRow(location_label, location_layout) self.image_type_combobox = QComboBox(self) for key, value in encoder_dict.items(): if value.encoder_type == Encoder.MediaType.image: self.image_type_combobox.addItem(key) image_type_label = QLabel("Save images as:") self.image_type_combobox.currentIndexChanged['QString'].connect( self.image_name_suffix_changed) form_layout.addRow(image_type_label, self.image_type_combobox) if self.enabled_video: self.video_type_combobox = QComboBox(self) for key, value in encoder_dict.items(): if value.encoder_type == Encoder.MediaType.video: self.video_type_combobox.addItem(key) self.video_type_combobox.currentIndexChanged['QString'].connect( self.video_name_suffix_changed) video_type_label = QLabel("Save videos as:", self) form_layout.addRow(video_type_label, self.video_type_combobox) image_name_groupbox = QGroupBox("Image File Names") groupbox_layout = QFormLayout() image_name_groupbox.setLayout(groupbox_layout) self.image_name_preview = QLabel( "<USER-PREFIX>-<SERIAL>-<FORMAT>-<TIMESTAMP>-<COUNTER>.png") self.image_name_preview_description = QLabel( "Images will be named like:") groupbox_layout.addRow(self.image_name_preview_description, self.image_name_preview) self.image_name_prefix = QLineEdit() self.image_name_prefix.textChanged.connect( self.image_name_prefix_changed) self.image_name_prefix.setMaxLength(100) self.image_name_prefix_description = QLabel("User Prefix:", self) groupbox_layout.addRow(self.image_name_prefix_description, self.image_name_prefix) self.image_name_serial = QCheckBox(self) self.image_name_serial.toggled.connect( self.image_name_properties_toggled) self.image_name_serial_description = QLabel("Include Serial:") groupbox_layout.addRow(self.image_name_serial_description, self.image_name_serial) self.image_name_format = QCheckBox(self) self.image_name_format.toggled.connect( self.image_name_properties_toggled) self.image_name_format_description = QLabel("Include Format:") groupbox_layout.addRow(self.image_name_format_description, self.image_name_format) self.image_name_counter = QCheckBox(self) self.image_name_counter.toggled.connect( self.image_name_properties_toggled) self.image_name_counter_description = QLabel("Include Counter:") groupbox_layout.addRow(self.image_name_counter_description, self.image_name_counter) self.image_name_counter_box = QSpinBox(self) self.image_name_counter_box.setRange(1, 10) self.image_name_counter_box.valueChanged.connect( self.image_name_counter_changed) self.image_name_counter_box_description = QLabel("Counter Size:") groupbox_layout.addRow(self.image_name_counter_box_description, self.image_name_counter_box) self.image_name_counter.toggled.connect( self.toggle_image_counter_box_availability) self.image_name_counter.toggled.connect( self.image_name_properties_toggled) self.image_name_timestamp = QCheckBox(self) self.image_name_timestamp.toggled.connect( self.image_name_properties_toggled) self.image_name_timestamp_description = QLabel("Include Timestamp:") groupbox_layout.addRow(self.image_name_timestamp_description, self.image_name_timestamp) layout.addWidget(image_name_groupbox) video_groupbox = QGroupBox("Video File Names") video_layout = QFormLayout() video_groupbox.setLayout(video_layout) self.video_name_preview = QLabel( "<USER-PREFIX>-<SERIAL>-<FORMAT>-<TIMESTAMP>-<COUNTER>.png") self.video_name_preview_description = QLabel( "Videos will be named like:") video_layout.addRow(self.video_name_preview_description, self.video_name_preview) self.video_name_prefix = QLineEdit() self.video_name_prefix.textChanged.connect( self.video_name_prefix_changed) self.video_name_prefix.setMaxLength(100) self.video_name_prefix_description = QLabel("User Prefix:", self) video_layout.addRow(self.video_name_prefix_description, self.video_name_prefix) self.video_name_serial = QCheckBox(self) self.video_name_serial.toggled.connect( self.video_name_properties_toggled) self.video_name_serial_description = QLabel("Include Serial:") video_layout.addRow(self.video_name_serial_description, self.video_name_serial) self.video_name_format = QCheckBox(self) self.video_name_format.toggled.connect( self.video_name_properties_toggled) self.video_name_format_description = QLabel("Include Format:") video_layout.addRow(self.video_name_format_description, self.video_name_format) self.video_name_counter = QCheckBox(self) self.video_name_counter.toggled.connect( self.video_name_properties_toggled) self.video_name_counter_description = QLabel("Include Counter:") video_layout.addRow(self.video_name_counter_description, self.video_name_counter) self.video_name_counter_box = QSpinBox(self) self.video_name_counter_box.setRange(1, 10) self.video_name_counter_box.valueChanged.connect( self.video_name_counter_changed) self.video_name_counter_box_description = QLabel("Counter Size:") video_layout.addRow(self.video_name_counter_box_description, self.video_name_counter_box) self.video_name_counter.toggled.connect( self.toggle_video_counter_box_availability) self.video_name_counter.toggled.connect( self.video_name_properties_toggled) self.video_name_timestamp = QCheckBox(self) self.video_name_timestamp.toggled.connect( self.video_name_properties_toggled) self.video_name_timestamp_description = QLabel("Include Timestamp:") video_layout.addRow(self.video_name_timestamp_description, self.video_name_timestamp) layout.addWidget(video_groupbox) self.saving_widget.setLayout(layout) def image_name_prefix_changed(self, name: str): """""" self.settings.image_name.user_prefix = self.image_name_prefix.text() self.update_image_name_preview() def image_name_suffix_changed(self, suffix: str): """""" self.update_image_name_preview() def image_name_counter_changed(self, name: str): """""" self.settings.image_name.counter_size = self.image_name_counter_box.value( ) self.update_image_name_preview() def image_name_properties_toggled(self): """""" self.settings.image_name.include_timestamp = self.image_name_timestamp.isChecked( ) self.settings.image_name.include_counter = self.image_name_counter.isChecked( ) self.settings.image_name.include_format = self.image_name_format.isChecked( ) self.settings.image_name.include_serial = self.image_name_serial.isChecked( ) self.update_image_name_preview() def update_image_name_preview(self): preview_string = "" if self.settings.image_name.user_prefix != "": max_prefix_length = 15 prefix = ( self.settings.image_name.user_prefix[:max_prefix_length] + '..') if len( self.settings.image_name.user_prefix ) > max_prefix_length else self.settings.image_name.user_prefix preview_string += prefix if self.settings.image_name.include_serial: if preview_string != "": preview_string += "-" preview_string += "00001234" if self.settings.image_name.include_format: if preview_string != "": preview_string += "-" preview_string += "gbrg_1920x1080_15_1" if self.settings.image_name.include_timestamp: if preview_string != "": preview_string += "-" preview_string += "19701230T125503" if self.settings.image_name.include_counter: if preview_string != "": preview_string += "-" preview_string += '{message:0>{fill}}'.format( message=1, fill=self.settings.image_name.counter_size) if preview_string == "": preview_string = "image" preview_string += "." + self.image_type_combobox.currentText() self.image_name_preview.setText(preview_string) def video_name_prefix_changed(self, name: str): """""" self.settings.video_name.user_prefix = self.video_name_prefix.text() self.update_video_name_preview() def video_name_suffix_changed(self, suffix: str): """""" self.update_video_name_preview() def video_name_counter_changed(self, name: str): """""" self.settings.video_name.counter_size = self.video_name_counter_box.value( ) self.update_video_name_preview() def video_name_properties_toggled(self): """""" self.settings.video_name.include_timestamp = self.video_name_timestamp.isChecked( ) self.settings.video_name.include_counter = self.video_name_counter.isChecked( ) self.settings.video_name.include_format = self.video_name_format.isChecked( ) self.settings.video_name.include_serial = self.video_name_serial.isChecked( ) self.update_video_name_preview() def update_video_name_preview(self): preview_string = "" if self.settings.video_name.user_prefix != "": # This is a convenience change to the displayed string. # We only display an amount of max_prefix_length # chars to save screen space max_prefix_length = 15 prefix = ( self.settings.video_name.user_prefix[:max_prefix_length] + '..') if len( self.settings.video_name.user_prefix ) > max_prefix_length else self.settings.video_name.user_prefix preview_string += prefix if self.settings.video_name.include_serial: if preview_string != "": preview_string += "-" preview_string += "00001234" if self.settings.video_name.include_format: if preview_string != "": preview_string += "-" preview_string += "gbrg_1920x1080_15_1" if self.settings.video_name.include_timestamp: if preview_string != "": preview_string += "-" preview_string += "19701230T125503" if self.settings.video_name.include_counter: if preview_string != "": preview_string += "-" preview_string += '{message:0>{fill}}'.format( message=1, fill=self.settings.video_name.counter_size) if preview_string == "": preview_string = "video" preview_string += "." + self.video_type_combobox.currentText() self.video_name_preview.setText(preview_string) def toggle_image_counter_box_availability(self): """""" if self.image_name_counter.isChecked(): self.image_name_counter_box.setEnabled(True) else: self.image_name_counter_box.setEnabled(False) def toggle_video_counter_box_availability(self): """""" if self.video_name_counter.isChecked(): self.video_name_counter_box.setEnabled(True) else: self.video_name_counter_box.setEnabled(False) def set_settings(self, settings: Settings): self.location_edit.setText(settings.get_save_location()) self.image_type_combobox.setCurrentText(settings.get_image_type()) if self.enabled_video: self.video_type_combobox.setCurrentText(settings.get_video_type()) self.device_dialog_checkbox.setChecked( settings.show_device_dialog_on_startup) self.reopen_device_checkbox.setChecked( settings.reopen_device_on_startup) self.use_dutils_checkbox.setChecked(settings.use_dutils) if settings.image_name.include_timestamp: self.image_name_timestamp.blockSignals(True) self.image_name_timestamp.toggle() self.image_name_timestamp.blockSignals(False) if settings.image_name.include_counter: self.image_name_counter.blockSignals(True) self.image_name_counter.toggle() self.image_name_counter.blockSignals(False) self.image_name_counter_box.blockSignals(True) self.image_name_counter_box.setValue(settings.image_name.counter_size) self.image_name_counter_box.blockSignals(False) self.toggle_image_counter_box_availability() if settings.image_name.include_format: self.image_name_format.blockSignals(True) self.image_name_format.toggle() self.image_name_format.blockSignals(False) if settings.image_name.include_serial: self.image_name_serial.blockSignals(True) self.image_name_serial.toggle() self.image_name_serial.blockSignals(False) self.image_name_prefix.blockSignals(True) self.image_name_prefix.setText(settings.image_name.user_prefix) self.image_name_prefix.blockSignals(False) self.update_image_name_preview() if settings.video_name.include_timestamp: self.video_name_timestamp.blockSignals(True) self.video_name_timestamp.toggle() self.video_name_timestamp.blockSignals(False) if settings.video_name.include_counter: self.video_name_counter.blockSignals(True) self.video_name_counter.toggle() self.video_name_counter.blockSignals(False) self.video_name_counter_box.blockSignals(True) self.video_name_counter_box.setValue(settings.video_name.counter_size) self.video_name_counter_box.blockSignals(False) self.toggle_video_counter_box_availability() if settings.video_name.include_format: self.video_name_format.blockSignals(True) self.video_name_format.toggle() self.video_name_format.blockSignals(False) if settings.video_name.include_serial: self.video_name_serial.blockSignals(True) self.video_name_serial.toggle() self.video_name_serial.blockSignals(False) self.video_name_prefix.blockSignals(True) self.video_name_prefix.setText(settings.video_name.user_prefix) self.video_name_prefix.blockSignals(False) self.update_video_name_preview() def save_settings(self): self.settings.save_location = self.location_edit.text() self.settings.image_type = self.image_type_combobox.currentText() if self.enabled_video: self.settings.video_type = self.video_type_combobox.currentText() self.settings.show_device_dialog_on_startup = self.device_dialog_checkbox.isChecked( ) self.settings.reopen_device_on_startup = self.reopen_device_checkbox.isChecked( ) self.settings.use_dutils = self.use_dutils_checkbox.isChecked() self.settings.image_name.include_timestamp = self.image_name_timestamp.isChecked( ) self.settings.image_name.include_counter = self.image_name_counter.isChecked( ) if self.image_name_counter.isChecked(): self.settings.image_name.counter_size = self.image_name_counter_box.value( ) self.settings.image_name.include_format = self.image_name_format.isChecked( ) self.settings.image_name.include_serial = self.image_name_serial.isChecked( ) self.settings.image_name.user_prefix = self.image_name_prefix.text() self.settings.video_name.include_timestamp = self.video_name_timestamp.isChecked( ) self.settings.video_name.include_counter = self.video_name_counter.isChecked( ) if self.video_name_counter.isChecked(): self.settings.video_name.counter_size = self.video_name_counter_box.value( ) self.settings.video_name.include_format = self.video_name_format.isChecked( ) self.settings.video_name.include_serial = self.video_name_serial.isChecked( ) self.settings.video_name.user_prefix = self.video_name_prefix.text() def open_file_dialog(self): fdia = QFileDialog() fdia.setFileMode(QFileDialog.Directory) fdia.setWindowTitle("Select Directory for saving images and videos") if fdia.exec_(): self.location_edit.setText(fdia.selectedFiles()[0]) def get_location(self): return self.location_edit.text() def get_image_format(self): return self.image_type_combobox.currentText() def get_video_format(self): return self.video_type_combobox.currentText() def clicked(self, button): if self.buttons.buttonRole(button) == QDialogButtonBox.ResetRole: self.reset() def reset(self): """""" log.info("reset called") self.settings.reset() self.set_settings(self.settings) @staticmethod def get_options(settings, parent=None): dialog = OptionsDialog(settings, parent) if settings is not None: dialog.set_settings(settings) result = dialog.exec_() if result == QDialog.Accepted: dialog.save_settings() settings.save() return result == QDialog.Accepted
class SettingsWindow(QDialog): apply_setting_signal = pyqtSignal() def __init__(self, slave_cmb: QComboBox, setting_obj: SettingWrapper, parent: QObject = None): super().__init__(parent=parent) self.setting_obj = setting_obj init_idx = slave_cmb.currentIndex() top_left_side = QtWidgets.QHBoxLayout() new_file_icon = QIcon('designer_files/icon/plus-rectangle.svg') new_file = QtWidgets.QPushButton(new_file_icon, '') delete_file_icon = QIcon('designer_files/icon/trash.svg') delete_file = QtWidgets.QPushButton(delete_file_icon, '') save_file_icon = QIcon('designer_files/icon/save.svg') save_file = QtWidgets.QPushButton(save_file_icon, '') self.drop_down_list = QtWidgets.QComboBox() new_file.clicked.connect(self.create_new_setting) delete_file.clicked.connect(self.delete_setting) save_file.clicked.connect(self.save_setting) top_left_side.addWidget(new_file) top_left_side.addWidget(save_file) top_left_side.addWidget(delete_file) top_left_side.addWidget(self.drop_down_list) top_left_side.insertSpacing(-1, 20) ls_settings = setting_obj.setting self.stacked_widget = QtWidgets.QStackedWidget() self.drop_down_list.currentIndexChanged.connect( self.stacked_widget.setCurrentIndex) for name, setting_dict in ls_settings.items(): self.drop_down_list.addItem(name) widget = self.init_tab(setting_dict) self.stacked_widget.addWidget(widget) self.drop_down_list.setCurrentIndex(init_idx) self.drop_down_list.currentIndexChanged.connect( slave_cmb.setCurrentIndex) layout = QtWidgets.QVBoxLayout() layout.addLayout(top_left_side) layout.addWidget(self.stacked_widget) self.button_dialog = QDialogButtonBox(Qt.Horizontal) self.button_dialog.addButton(QDialogButtonBox.Apply) self.button_dialog.addButton(QDialogButtonBox.Ok) self.button_dialog.addButton(QDialogButtonBox.Cancel) self.button_dialog.clicked.connect(self.button_clicked) layout.addWidget(self.button_dialog) self.setLayout(layout) @pyqtSlot() def create_new_setting(self) -> None: new_name, ok = QInputDialog.getText(self, 'New Setting', 'Enter new name:') idx = self.drop_down_list.currentIndex() is_duplicate = self.drop_down_list.findText(new_name) != -1 if len(new_name) != 0 and ok and not is_duplicate: setting_dict = self.setting_obj.clone(idx, new_name) self.drop_down_list.addItem(new_name) widget = self.init_tab(setting_dict) self.stacked_widget.addWidget(widget) self.drop_down_list.setCurrentIndex(self.drop_down_list.count() - 1) elif len(new_name) == 0: msg_box = QMessageBox(self) msg_box.setText("Empty string, please specify name :") msg_box.exec() elif is_duplicate: msg_box = QMessageBox(self) msg_box.setText("Deplicate string, please specify another name :") msg_box.exec() @pyqtSlot() def save_setting(self) -> None: setting_idx = self.drop_down_list.currentIndex() self.setting_obj.save(setting_idx) @pyqtSlot() def delete_setting(self) -> None: setting_idx = self.drop_down_list.currentIndex() self.setting_obj.remove(setting_idx) self.drop_down_list.removeItem(setting_idx) widget = self.stacked_widget.widget(setting_idx) self.stacked_widget.removeWidget(widget) @pyqtSlot(QAbstractButton) def button_clicked(self, button: QAbstractButton) -> None: role = self.button_dialog.buttonRole(button) if role == QDialogButtonBox.ApplyRole: self.apply_setting_signal.emit() elif role == QDialogButtonBox.AcceptRole: self.apply_setting_signal.emit() self.accept() elif role == QDialogButtonBox.RejectRole: self.reject() def init_tab(self, setting_dict: PrintSetting) -> QtWidgets.QWidget: layout = QtWidgets.QHBoxLayout() menu_widget = QtWidgets.QListWidget() layout.addWidget(menu_widget) sub_stacked_page = QtWidgets.QStackedWidget() menu_widget.currentRowChanged.connect(sub_stacked_page.setCurrentIndex) layout.addWidget(sub_stacked_page) cat_frame = {} sec_frame = {} for entry in attr.asdict(setting_dict, recurse=False).values(): if isinstance(entry, SingleEntry): cat = entry.ui['category'] if not cat in cat_frame.keys(): single_frame = QtWidgets.QWidget() single_frame.setLayout(QtWidgets.QVBoxLayout()) cat_frame[cat] = single_frame menu_widget.addItem(cat) sec_frame[cat] = {} sub_stacked_page.addWidget(single_frame) sec = entry.ui['section'] if not sec in sec_frame[cat].keys(): box_layout = QtWidgets.QVBoxLayout() qbox = QtWidgets.QGroupBox(sec) qbox.setLayout(box_layout) sec_frame[cat][sec] = qbox cat_frame[cat].layout().addWidget(qbox) q_entry = entry.create_ui_entry() self.apply_setting_signal.connect(entry.commit_value) sec_frame[cat][sec].layout().addWidget(q_entry) widget = QtWidgets.QWidget() widget.setLayout(layout) return widget
class OptionsDialog(QDialog): def __init__(self, setting: Settings, have_dutils, parent=None): super(OptionsDialog, self).__init__(parent) self.settings = setting self.enabled_video = True # temporary toggle to disable video features as they do not exist self.enabled_logging = True self.enabled_keybindings = True self.enabled_dutils = have_dutils self.setWindowTitle("Tcam-Capture Options") self.layout = QVBoxLayout(self) self.setLayout(self.layout) self.tabs = QTabWidget() self.general_widget = QWidget() self.keybindings_widget = QWidget() self.logging_widget = QWidget() self.saving_widget = QWidget() self._setup_general_ui() self.tabs.addTab(self.general_widget, "General") if self.enabled_keybindings: self._setup_keybindings_ui() self.tabs.addTab(self.keybindings_widget, "Keybindings") self._setup_saving_ui() self.tabs.addTab(self.saving_widget, "Image/Video") self.layout.addWidget(self.tabs) # OK and Cancel buttons self.buttons = QDialogButtonBox( QDialogButtonBox.Reset | QDialogButtonBox.Ok | QDialogButtonBox.Cancel, Qt.Horizontal, self) self.layout.addWidget(self.buttons) self.buttons.accepted.connect(self.accept) self.buttons.rejected.connect(self.reject) self.buttons.clicked.connect(self.clicked) def _setup_general_ui(self): """ Create everything related to the general tab """ layout = QFormLayout() layout.setSpacing(20) layout.setVerticalSpacing(20) self.device_dialog_checkbox = QCheckBox(self) device_dialog_label = QLabel("Open device dialog on start:") layout.addRow(device_dialog_label, self.device_dialog_checkbox) self.reopen_device_checkbox = QCheckBox(self) reopen_device_label = QLabel("Reopen device on start(ignores device dialog):", self) layout.addRow(reopen_device_label, self.reopen_device_checkbox) self.use_dutils_checkbox = QCheckBox(self) self.use_dutils_label = QLabel("Use tiscamera dutils, if present:", self) layout.addRow(self.use_dutils_label, self.use_dutils_checkbox) if not self.enabled_dutils: self.use_dutils_label.setToolTip("Enabled when tiscamera-dutils are installed") self.use_dutils_label.setEnabled(False) self.use_dutils_checkbox.setToolTip("Enabled when tiscamera-dutils are installed") self.use_dutils_checkbox.setEnabled(False) self.general_widget.setLayout(layout) def _setup_saving_ui(self): """ Create everything related to the image/video saving tab """ encoder_dict = Encoder.get_encoder_dict() form_layout = QFormLayout() layout = QVBoxLayout() layout.addLayout(form_layout) location_layout = QHBoxLayout() location_label = QLabel("Where to save images/videos:", self) self.location_edit = QLineEdit(self) location_dialog_button = QPushButton("...", self) location_dialog_button.clicked.connect(self.open_file_dialog) location_layout.addWidget(self.location_edit) location_layout.addWidget(location_dialog_button) # maintain descriptions as own labels # pyqt seems to loose the descriptions somewhere # when simple strings are used or the qlabel does not have self as owner form_layout.addRow(location_label, location_layout) self.image_type_combobox = QComboBox(self) for key, value in encoder_dict.items(): if value.encoder_type == Encoder.MediaType.image: self.image_type_combobox.addItem(key) image_type_label = QLabel("Save images as:") self.image_type_combobox.currentIndexChanged['QString'].connect(self.image_name_suffix_changed) form_layout.addRow(image_type_label, self.image_type_combobox) if self.enabled_video: self.video_type_combobox = QComboBox(self) for key, value in encoder_dict.items(): if value.encoder_type == Encoder.MediaType.video: self.video_type_combobox.addItem(key) self.video_type_combobox.currentIndexChanged['QString'].connect(self.video_name_suffix_changed) video_type_label = QLabel("Save videos as:", self) form_layout.addRow(video_type_label, self.video_type_combobox) image_name_groupbox = QGroupBox("Image File Names") groupbox_layout = QFormLayout() image_name_groupbox.setLayout(groupbox_layout) self.image_name_preview = QLabel("<USER-PREFIX>-<SERIAL>-<FORMAT>-<TIMESTAMP>-<COUNTER>.png") self.image_name_preview_description = QLabel("Images will be named like:") groupbox_layout.addRow(self.image_name_preview_description, self.image_name_preview) self.image_name_prefix = QLineEdit() self.image_name_prefix.textChanged.connect(self.image_name_prefix_changed) self.image_name_prefix.setMaxLength(100) self.image_name_prefix_description = QLabel("User Prefix:", self) groupbox_layout.addRow(self.image_name_prefix_description, self.image_name_prefix) self.image_name_serial = QCheckBox(self) self.image_name_serial.toggled.connect(self.image_name_properties_toggled) self.image_name_serial_description = QLabel("Include Serial:") groupbox_layout.addRow(self.image_name_serial_description, self.image_name_serial) self.image_name_format = QCheckBox(self) self.image_name_format.toggled.connect(self.image_name_properties_toggled) self.image_name_format_description = QLabel("Include Format:") groupbox_layout.addRow(self.image_name_format_description, self.image_name_format) self.image_name_counter = QCheckBox(self) self.image_name_counter.toggled.connect(self.image_name_properties_toggled) self.image_name_counter_description = QLabel("Include Counter:") groupbox_layout.addRow(self.image_name_counter_description, self.image_name_counter) self.image_name_counter_box = QSpinBox(self) self.image_name_counter_box.setRange(1, 10) self.image_name_counter_box.valueChanged.connect(self.image_name_counter_changed) self.image_name_counter_box_description = QLabel("Counter Size:") groupbox_layout.addRow(self.image_name_counter_box_description, self.image_name_counter_box) self.image_name_counter.toggled.connect(self.toggle_image_counter_box_availability) self.image_name_counter.toggled.connect(self.image_name_properties_toggled) self.image_name_timestamp = QCheckBox(self) self.image_name_timestamp.toggled.connect(self.image_name_properties_toggled) self.image_name_timestamp_description = QLabel("Include Timestamp:") groupbox_layout.addRow(self.image_name_timestamp_description, self.image_name_timestamp) layout.addWidget(image_name_groupbox) video_groupbox = QGroupBox("Video File Names") video_layout = QFormLayout() video_groupbox.setLayout(video_layout) self.video_name_preview = QLabel("<USER-PREFIX>-<SERIAL>-<FORMAT>-<TIMESTAMP>-<COUNTER>.png") self.video_name_preview_description = QLabel("Videos will be named like:") video_layout.addRow(self.video_name_preview_description, self.video_name_preview) self.video_name_prefix = QLineEdit() self.video_name_prefix.textChanged.connect(self.video_name_prefix_changed) self.video_name_prefix.setMaxLength(100) self.video_name_prefix_description = QLabel("User Prefix:", self) video_layout.addRow(self.video_name_prefix_description, self.video_name_prefix) self.video_name_serial = QCheckBox(self) self.video_name_serial.toggled.connect(self.video_name_properties_toggled) self.video_name_serial_description = QLabel("Include Serial:") video_layout.addRow(self.video_name_serial_description, self.video_name_serial) self.video_name_format = QCheckBox(self) self.video_name_format.toggled.connect(self.video_name_properties_toggled) self.video_name_format_description = QLabel("Include Format:") video_layout.addRow(self.video_name_format_description, self.video_name_format) self.video_name_counter = QCheckBox(self) self.video_name_counter.toggled.connect(self.video_name_properties_toggled) self.video_name_counter_description = QLabel("Include Counter:") video_layout.addRow(self.video_name_counter_description, self.video_name_counter) self.video_name_counter_box = QSpinBox(self) self.video_name_counter_box.setRange(1, 10) self.video_name_counter_box.valueChanged.connect(self.video_name_counter_changed) self.video_name_counter_box_description = QLabel("Counter Size:") video_layout.addRow(self.video_name_counter_box_description, self.video_name_counter_box) self.video_name_counter.toggled.connect(self.toggle_video_counter_box_availability) self.video_name_counter.toggled.connect(self.video_name_properties_toggled) self.video_name_timestamp = QCheckBox(self) self.video_name_timestamp.toggled.connect(self.video_name_properties_toggled) self.video_name_timestamp_description = QLabel("Include Timestamp:") video_layout.addRow(self.video_name_timestamp_description, self.video_name_timestamp) layout.addWidget(video_groupbox) self.saving_widget.setLayout(layout) def image_name_prefix_changed(self, name: str): """""" self.settings.image_name.user_prefix = self.image_name_prefix.text() self.update_image_name_preview() def image_name_suffix_changed(self, suffix: str): """""" self.update_image_name_preview() def image_name_counter_changed(self, name: str): """""" self.settings.image_name.counter_size = self.image_name_counter_box.value() self.update_image_name_preview() def image_name_properties_toggled(self): """""" self.settings.image_name.include_timestamp = self.image_name_timestamp.isChecked() self.settings.image_name.include_counter = self.image_name_counter.isChecked() self.settings.image_name.include_format = self.image_name_format.isChecked() self.settings.image_name.include_serial = self.image_name_serial.isChecked() self.update_image_name_preview() def update_image_name_preview(self): preview_string = "" if self.settings.image_name.user_prefix != "": max_prefix_length = 15 prefix = (self.settings.image_name.user_prefix[:max_prefix_length] + '..') if len(self.settings.image_name.user_prefix) > max_prefix_length else self.settings.image_name.user_prefix preview_string += prefix if self.settings.image_name.include_serial: if preview_string != "": preview_string += "-" preview_string += "00001234" if self.settings.image_name.include_format: if preview_string != "": preview_string += "-" preview_string += "gbrg_1920x1080_15_1" if self.settings.image_name.include_timestamp: if preview_string != "": preview_string += "-" preview_string += "19701230T125503" if self.settings.image_name.include_counter: if preview_string != "": preview_string += "-" preview_string += '{message:0>{fill}}'.format(message=1, fill=self.settings.image_name.counter_size) if preview_string == "": preview_string = "image" preview_string += "." + self.image_type_combobox.currentText() self.image_name_preview.setText(preview_string) def video_name_prefix_changed(self, name: str): """""" self.settings.video_name.user_prefix = self.video_name_prefix.text() self.update_video_name_preview() def video_name_suffix_changed(self, suffix: str): """""" self.update_video_name_preview() def video_name_counter_changed(self, name: str): """""" self.settings.video_name.counter_size = self.video_name_counter_box.value() self.update_video_name_preview() def video_name_properties_toggled(self): """""" self.settings.video_name.include_timestamp = self.video_name_timestamp.isChecked() self.settings.video_name.include_counter = self.video_name_counter.isChecked() self.settings.video_name.include_format = self.video_name_format.isChecked() self.settings.video_name.include_serial = self.video_name_serial.isChecked() self.update_video_name_preview() def update_video_name_preview(self): preview_string = "" if self.settings.video_name.user_prefix != "": # This is a convenience change to the displayed string. # We only display an amount of max_prefix_length # chars to save screen space max_prefix_length = 15 prefix = (self.settings.video_name.user_prefix[:max_prefix_length] + '..') if len(self.settings.video_name.user_prefix) > max_prefix_length else self.settings.video_name.user_prefix preview_string += prefix if self.settings.video_name.include_serial: if preview_string != "": preview_string += "-" preview_string += "00001234" if self.settings.video_name.include_format: if preview_string != "": preview_string += "-" preview_string += "gbrg_1920x1080_15_1" if self.settings.video_name.include_timestamp: if preview_string != "": preview_string += "-" preview_string += "19701230T125503" if self.settings.video_name.include_counter: if preview_string != "": preview_string += "-" preview_string += '{message:0>{fill}}'.format(message=1, fill=self.settings.video_name.counter_size) if preview_string == "": preview_string = "video" preview_string += "." + self.video_type_combobox.currentText() self.video_name_preview.setText(preview_string) def toggle_image_counter_box_availability(self): """""" if self.image_name_counter.isChecked(): self.image_name_counter_box.setEnabled(True) else: self.image_name_counter_box.setEnabled(False) def toggle_video_counter_box_availability(self): """""" if self.video_name_counter.isChecked(): self.video_name_counter_box.setEnabled(True) else: self.video_name_counter_box.setEnabled(False) def _setup_keybindings_ui(self): """ Create everything related to the keybindings tab """ layout = QFormLayout() self.keybinding_fullscreen_label = QLabel("Toggle Fullscreen:") self.keybinding_fullscreen = QKeySequenceEdit() layout.addRow(self.keybinding_fullscreen_label, self.keybinding_fullscreen) self.keybinding_save_image_label = QLabel("Save image:") self.keybinding_save_image = QKeySequenceEdit(QKeySequence(self.settings.keybinding_save_image)) layout.addRow(self.keybinding_save_image_label, self.keybinding_save_image) self.keybinding_trigger_image_label = QLabel("Trigger images via softwaretrigger:") self.keybinding_trigger_image = QKeySequenceEdit(QKeySequence(self.settings.keybinding_trigger_image)) layout.addRow(self.keybinding_trigger_image_label, self.keybinding_trigger_image) self.keybinding_open_dialog_label = QLabel("Open device dialog:") self.keybinding_open_dialog = QKeySequenceEdit(QKeySequence(self.settings.keybinding_open_dialog)) layout.addRow(self.keybinding_open_dialog_label, self.keybinding_open_dialog) self.keybindings_widget.setLayout(layout) def set_settings(self, settings: Settings): self.location_edit.setText(settings.get_save_location()) self.image_type_combobox.setCurrentText(settings.get_image_type()) if self.enabled_video: self.video_type_combobox.setCurrentText(settings.get_video_type()) self.device_dialog_checkbox.setChecked(settings.show_device_dialog_on_startup) self.reopen_device_checkbox.setChecked(settings.reopen_device_on_startup) self.use_dutils_checkbox.setChecked(settings.use_dutils) # # keybindings # if self.enabled_keybindings: self.keybinding_fullscreen.setKeySequence(QKeySequence(self.settings.keybinding_fullscreen)) self.keybinding_save_image.setKeySequence(QKeySequence(self.settings.keybinding_save_image)) self.keybinding_trigger_image.setKeySequence(QKeySequence(self.settings.keybinding_trigger_image)) self.keybinding_open_dialog.setKeySequence(QKeySequence(self.settings.keybinding_open_dialog)) # # image saving # if settings.image_name.include_timestamp: self.image_name_timestamp.blockSignals(True) self.image_name_timestamp.toggle() self.image_name_timestamp.blockSignals(False) if settings.image_name.include_counter: self.image_name_counter.blockSignals(True) self.image_name_counter.toggle() self.image_name_counter.blockSignals(False) self.image_name_counter_box.blockSignals(True) self.image_name_counter_box.setValue(settings.image_name.counter_size) self.image_name_counter_box.blockSignals(False) self.toggle_image_counter_box_availability() if settings.image_name.include_format: self.image_name_format.blockSignals(True) self.image_name_format.toggle() self.image_name_format.blockSignals(False) if settings.image_name.include_serial: self.image_name_serial.blockSignals(True) self.image_name_serial.toggle() self.image_name_serial.blockSignals(False) self.image_name_prefix.blockSignals(True) self.image_name_prefix.setText(settings.image_name.user_prefix) self.image_name_prefix.blockSignals(False) self.update_image_name_preview() # # video saving # if settings.video_name.include_timestamp: self.video_name_timestamp.blockSignals(True) self.video_name_timestamp.toggle() self.video_name_timestamp.blockSignals(False) if settings.video_name.include_counter: self.video_name_counter.blockSignals(True) self.video_name_counter.toggle() self.video_name_counter.blockSignals(False) self.video_name_counter_box.blockSignals(True) self.video_name_counter_box.setValue(settings.video_name.counter_size) self.video_name_counter_box.blockSignals(False) self.toggle_video_counter_box_availability() if settings.video_name.include_format: self.video_name_format.blockSignals(True) self.video_name_format.toggle() self.video_name_format.blockSignals(False) if settings.video_name.include_serial: self.video_name_serial.blockSignals(True) self.video_name_serial.toggle() self.video_name_serial.blockSignals(False) self.video_name_prefix.blockSignals(True) self.video_name_prefix.setText(settings.video_name.user_prefix) self.video_name_prefix.blockSignals(False) self.update_video_name_preview() def save_settings(self): self.settings.save_location = self.location_edit.text() self.settings.image_type = self.image_type_combobox.currentText() if self.enabled_video: self.settings.video_type = self.video_type_combobox.currentText() self.settings.show_device_dialog_on_startup = self.device_dialog_checkbox.isChecked() self.settings.reopen_device_on_startup = self.reopen_device_checkbox.isChecked() self.settings.use_dutils = self.use_dutils_checkbox.isChecked() # # keybindings # if self.enabled_keybindings: self.settings.keybinding_fullscreen = self.keybinding_fullscreen.keySequence().toString() self.settings.keybinding_save_image = self.keybinding_save_image.keySequence().toString() self.settings.keybinding_trigger_image = self.keybinding_trigger_image.keySequence().toString() self.settings.keybinding_open_dialog = self.keybinding_open_dialog.keySequence().toString() # # image saving # self.settings.image_name.include_timestamp = self.image_name_timestamp.isChecked() self.settings.image_name.include_counter = self.image_name_counter.isChecked() if self.image_name_counter.isChecked(): self.settings.image_name.counter_size = self.image_name_counter_box.value() self.settings.image_name.include_format = self.image_name_format.isChecked() self.settings.image_name.include_serial = self.image_name_serial.isChecked() self.settings.image_name.user_prefix = self.image_name_prefix.text() # # video saving # self.settings.video_name.include_timestamp = self.video_name_timestamp.isChecked() self.settings.video_name.include_counter = self.video_name_counter.isChecked() if self.video_name_counter.isChecked(): self.settings.video_name.counter_size = self.video_name_counter_box.value() self.settings.video_name.include_format = self.video_name_format.isChecked() self.settings.video_name.include_serial = self.video_name_serial.isChecked() self.settings.video_name.user_prefix = self.video_name_prefix.text() def open_file_dialog(self): fdia = QFileDialog() fdia.setFileMode(QFileDialog.Directory) fdia.setWindowTitle("Select Directory for saving images and videos") if fdia.exec_(): self.location_edit.setText(fdia.selectedFiles()[0]) def get_location(self): return self.location_edit.text() def get_image_format(self): return self.image_type_combobox.currentText() def get_video_format(self): return self.video_type_combobox.currentText() def clicked(self, button): if self.buttons.buttonRole(button) == QDialogButtonBox.ResetRole: self.reset() def reset(self): """""" log.info("reset called") self.settings.reset() self.set_settings(self.settings) @staticmethod def get_options(settings, parent=None): dialog = OptionsDialog(settings, parent) if settings is not None: dialog.set_settings(settings) result = dialog.exec_() if result == QDialog.Accepted: dialog.save_settings() settings.save() return result == QDialog.Accepted
class Dialog(QWidget): ''' UI ''' def __init__(self, upgrades, security_upgrades, reboot_required, upg_path): QWidget.__init__(self) self.upgrades = upgrades self.security_upgrades = security_upgrades self.upg_path = upg_path self.reboot_required = reboot_required apt_pkg.init() try: self.cache = apt_pkg.Cache() except SystemError as e: sys.stderr.write(_("Error: Opening the cache (%s)") % e) sys.exit(-1) self.depcache = apt_pkg.DepCache(self.cache) self.records = apt_pkg.PackageRecords(self.cache) self.initUI() self.buttonBox.rejected.connect(self.call_reject) self.buttonBox.clicked.connect(self.call_upgrade) def initUI(self): ''' UI initialization ''' self.label = QLabel() self.label.setAlignment(Qt.AlignHCenter) self.tw = QTreeWidget() if self.security_upgrades > 0: self.tw.setColumnCount(2) self.tw.setHeaderLabels([_('Affected Packages'), _('Security')]) self.tw.header().setSectionResizeMode(0, QHeaderView.Stretch) self.tw.header().setStretchLastSection(False) else: self.tw.setColumnCount(1) self.tw.setHeaderLabels([_('Affected Packages')]) self.tw.setHeaderHidden(True) self.buttonBox = QDialogButtonBox(QDialogButtonBox.Cancel | QDialogButtonBox.Apply) text = "" hbox = QHBoxLayout() hbox.addStretch(1) hbox.addWidget(self.buttonBox) hbox.addStretch(1) vbox = QVBoxLayout() vbox.addWidget(self.label) vbox.addWidget(self.tw) vbox.addLayout(hbox) self.tw.setVisible(False) if self.upg_path is None: self.buttonBox.button(QDialogButtonBox.Apply).setVisible(False) self.setLayout(vbox) self.setGeometry(300, 300, 500, 150) self.setWindowTitle("Update Notifier") self.center() if self.upgrades > 0: self.tw.setVisible(True) self.depcache.upgrade(True) # True for non safe. pkg_install = list() pkg_upgrade = list() pkg_delete = list() for p in self.cache.packages: if self.depcache.marked_delete(p): pkg_delete.append(p) elif self.depcache.marked_install(p): pkg_install.append([p, self.depcache.get_candidate_ver(p)]) elif self.depcache.marked_upgrade(p): pkg_upgrade.append([p, self.depcache.get_candidate_ver(p)]) text = _("There are upgrades available. Do you want to do a system" " upgrade?") text += "\n" text += _("This will mean packages could be upgraded, installed or" " removed.") if self.security_upgrades > 0: text += "\n" + str(self.security_upgrades) if self.security_upgrades == 1: text += _(" is a security upgrade.") else: text += _(" are security upgrades.") if len(pkg_delete) > 0: toDelete = QTreeWidgetItem([_('Remove')]) for p in pkg_delete: td_child = QTreeWidgetItem(p.name) toDelete.addChild(td_child) toDelete.setIcon(0, QIcon.fromTheme("edit-delete")) self.tw.addTopLevelItem(toDelete) if len(pkg_install) > 0: toInstall = QTreeWidgetItem([_('Install')]) for p in pkg_install: td_child = QTreeWidgetItem( [p[0].name + " / " + p[1].ver_str]) if apt_check.isSecurityUpgrade(p[1]): td_child.setIcon(1, QIcon.fromTheme("security-high")) toInstall.setIcon(1, QIcon.fromTheme("security-high")) toInstall.addChild(td_child) self.records.lookup(p[1].file_list[0]) short = QTreeWidgetItem([self.records.short_desc]) td_child.addChild(short) toInstall.setIcon(0, QIcon.fromTheme("system-software-install")) self.tw.addTopLevelItem(toInstall) if len(pkg_upgrade) > 0: toUpgrade = QTreeWidgetItem([_('Upgrade')]) for p in pkg_upgrade: td_child = QTreeWidgetItem([ p[0].name + " / " + p[0].current_ver.ver_str + " -> " + p[1].ver_str ]) if apt_check.isSecurityUpgrade(p[1]): td_child.setIcon(1, QIcon.fromTheme("security-high")) toUpgrade.setIcon(1, QIcon.fromTheme("security-high")) toUpgrade.addChild(td_child) self.records.lookup(p[1].file_list[0]) short = QTreeWidgetItem([self.records.short_desc]) td_child.addChild(short) toUpgrade.setIcon(0, QIcon.fromTheme("system-software-update")) self.tw.addTopLevelItem(toUpgrade) if self.reboot_required: if text == "": text = _("Reboot required") self.buttonBox.button(QDialogButtonBox.Apply).setVisible(False) else: text += "\n" text += _("Reboot required") self.label.setText(text) def center(self): ''' puts UI in center of screen ''' frameGm = self.frameGeometry() screen = QApplication.desktop().screenNumber( QApplication.desktop().cursor().pos()) centerPoint = QApplication.desktop().screenGeometry(screen).center() frameGm.moveCenter(centerPoint) self.move(frameGm.topLeft()) def call_reject(self): ''' when close button is pressed, quit ''' app.quit() def call_upgrade(self, btnClicked): if (self.buttonBox.buttonRole(btnClicked) == QDialogButtonBox.ApplyRole ): ''' starts upgrade process ''' self.label.setText(_("Upgrading...")) # TODO maybe open another thread so notifier won't freeze cmd = ['lxqt-sudo', self.upg_path, '--full-upgrade'] self.buttonBox.button(QDialogButtonBox.Apply).setEnabled(False) self.buttonBox.button(QDialogButtonBox.Apply).setVisible(False) self.tw.setVisible(False) process = subprocess.Popen(cmd) process.wait() if self.upg_path == "terminal": text = _("Upgrade finished") reboot_required_path = Path("/var/run/reboot-required") if reboot_required_path.exists(): text += "\n" + _("Reboot required") self.label.setText(text) self.closeBtn.setVisible(True) self.closeBtn.setEnabled(True) else: app.quit()