def __init__(self, *arg, **kw): super(NewItemDialog, self).__init__(*arg, **kw) self.setLayout(QtWidgets.QVBoxLayout()) # main dialog area scroll_area = QtWidgets.QScrollArea() scroll_area.setWidgetResizable(True) self.layout().addWidget(scroll_area) self.panel = QtWidgets.QWidget() self.panel.setLayout(QtWidgets.QFormLayout()) self.panel.layout().setFieldGrowthPolicy( QtWidgets.QFormLayout.AllNonFixedFieldsGrow) # ok & cancel buttons button_box = QtWidgets.QDialogButtonBox( QtWidgets.QDialogButtonBox.Ok | QtWidgets.QDialogButtonBox.Cancel) button_box.accepted.connect(self.accept) button_box.rejected.connect(self.reject) self.layout().addWidget(button_box) # common data items self.model_widgets = {} for key, label in ( ('make', translate('TechnicalTab', "Maker's name")), ('model', translate('TechnicalTab', 'Model name')), ('serial_no', translate('TechnicalTab', 'Serial number')), ): self.model_widgets[key] = QtWidgets.QLineEdit() self.model_widgets[key].setMinimumWidth( width_for_text(self.model_widgets[key], 'x' * 35)) self.panel.layout().addRow(label, self.model_widgets[key]) # add any other data items self.extend_data() # add panel to scroll area now its size is known scroll_area.setWidget(self.panel)
def __init__(self, image_list, *args, **kwds): super(LatLongDisplay, self).__init__(*args, **kwds) self.image_list = image_list self.label = QtWidgets.QLabel(translate('MapTabsAll', 'Lat, long')) self.label.setAlignment(Qt.AlignRight) self.setFixedWidth(width_for_text(self, '8' * 23)) self.setEnabled(False) self.editingFinished.connect(self.editing_finished)
def __init__(self, upload_config_widget, image_list, *arg, **kw): super(PhotiniUploader, self).__init__(*arg, **kw) self.app = QtWidgets.QApplication.instance() self.app.aboutToQuit.connect(self.shutdown) logger.debug('using %s', keyring.get_keyring().__module__) self.image_list = image_list self.setLayout(QtWidgets.QGridLayout()) self.session = self.session_factory() self.session.connection_changed.connect(self.connection_changed) self.upload_worker = None # user details self.user = {} user_group = QtWidgets.QGroupBox(translate('UploaderTabsAll', 'User')) user_group.setLayout(QtWidgets.QVBoxLayout()) self.user_photo = QtWidgets.QLabel() self.user_photo.setAlignment(Qt.AlignHCenter | Qt.AlignTop) user_group.layout().addWidget(self.user_photo) self.user_name = QtWidgets.QLabel() self.user_name.setWordWrap(True) self.user_name.setMinimumWidth(width_for_text(self.user_name, 'x' * 12)) user_group.layout().addWidget(self.user_name) user_group.layout().addStretch(1) self.layout().addWidget(user_group, 0, 0, 1, 2) # connect / disconnect button self.user_connect = StartStopButton( translate('UploaderTabsAll', 'Log in'), translate('UploaderTabsAll', 'Log out')) self.user_connect.click_start.connect(self.log_in) self.user_connect.click_stop.connect(self.session.log_out) self.layout().addWidget(self.user_connect, 1, 0, 1, 2) # 'service' specific widget self.layout().addWidget(upload_config_widget, 0, 2, 2, 2) # upload button self.upload_button = StartStopButton( translate('UploaderTabsAll', 'Start upload'), translate('UploaderTabsAll', 'Stop upload')) self.upload_button.setEnabled(False) self.upload_button.click_start.connect(self.start_upload) self.upload_button.click_stop.connect(self.stop_upload) self.layout().addWidget(self.upload_button, 2, 3) # progress bar self.layout().addWidget( QtWidgets.QLabel(translate('UploaderTabsAll', 'Progress')), 2, 0) self.total_progress = QtWidgets.QProgressBar() self.layout().addWidget(self.total_progress, 2, 1, 1, 2) # adjust spacing self.layout().setColumnStretch(2, 1) self.layout().setRowStretch(0, 1) # initialise as not connected self.connection_changed(False)
def __init__(self, *args, **kw): super(LocationInfo, self).__init__(*args, **kw) layout = QtWidgets.QGridLayout() self.setLayout(layout) layout.setContentsMargins(0, 0, 0, 0) self.members = {} for key in ('SubLocation', 'City', 'ProvinceState', 'CountryName', 'CountryCode', 'WorldRegion'): self.members[key] = SingleLineEdit( length_check=ImageMetadata.max_bytes(key)) self.members[key].editingFinished.connect(self.editing_finished) self.members['CountryCode'].setMaximumWidth( width_for_text(self.members['CountryCode'], 'W' * 4)) self.members['SubLocation'].setToolTip( translate('AddressTab', 'Enter the name of the sublocation.')) self.members['City'].setToolTip( translate('AddressTab', 'Enter the name of the city.')) self.members['ProvinceState'].setToolTip( translate('AddressTab', 'Enter the name of the province or state.')) self.members['CountryName'].setToolTip( translate('AddressTab', 'Enter the name of the country.')) self.members['CountryCode'].setToolTip( translate( 'AddressTab', 'Enter the 2 or 3 letter ISO 3166 country code of the country.' )) self.members['WorldRegion'].setToolTip( translate('AddressTab', 'Enter the name of the world region.')) for j, text in enumerate(( translate('AddressTab', 'Street'), translate('AddressTab', 'City'), translate('AddressTab', 'Province'), translate('AddressTab', 'Country'), translate('AddressTab', 'Region'), )): label = QtWidgets.QLabel(text) label.setAlignment(Qt.AlignRight) layout.addWidget(label, j, 0) layout.addWidget(self.members['SubLocation'], 0, 1, 1, 2) layout.addWidget(self.members['City'], 1, 1, 1, 2) layout.addWidget(self.members['ProvinceState'], 2, 1, 1, 2) layout.addWidget(self.members['CountryName'], 3, 1) layout.addWidget(self.members['CountryCode'], 3, 2) layout.addWidget(self.members['WorldRegion'], 4, 1, 1, 2) layout.setRowStretch(5, 1)
def edit_template(self): dialog = QtWidgets.QDialog(parent=self) width = width_for_text(dialog, 'x' * 120) dialog.setFixedSize(min(width, self.window().width()), min(width * 3 // 4, self.window().height())) dialog.setWindowTitle(self.tr('Photini: ownership template')) dialog.setLayout(QtWidgets.QVBoxLayout()) # main dialog area form, widgets = self.data_form() widgets['copyright'].setToolTip( widgets['copyright'].toolTip() + ' ' + translate('OwnerTab', 'Use %Y to insert the year the photograph was taken.')) for key in widgets: value = self.config_store.get('ownership', key) if key == 'copyright' and not value: name = self.config_store.get('user', 'copyright_name') or '' text = (self.config_store.get('user', 'copyright_text') or translate( 'DescriptiveTab', 'Copyright ©{year} {name}.' ' All rights reserved.')) value = text.format(year='%Y', name=name) elif key == 'creator' and not value: value = self.config_store.get('user', 'creator_name') widgets[key].set_value(value) dialog.layout().addWidget(form) # apply & cancel buttons button_box = QtWidgets.QDialogButtonBox( QtWidgets.QDialogButtonBox.Ok | QtWidgets.QDialogButtonBox.Cancel) button_box.accepted.connect(dialog.accept) button_box.rejected.connect(dialog.reject) dialog.layout().addWidget(button_box) if dialog.exec_() != QtWidgets.QDialog.Accepted: return for key in widgets: value = widgets[key].get_value() if value: self.config_store.set('ownership', key, value) else: self.config_store.delete('ownership', key)
def __init__(self, verbose, *arg, **kw): super(LoggerWindow, self).__init__(*arg, **kw) QtWidgets.QApplication.instance().aboutToQuit.connect(self.shutdown) self.setWindowTitle(self.tr("Photini error logging")) self.setLayout(QtWidgets.QVBoxLayout()) # main dialog area self.text = QtWidgets.QTextEdit() self.text.setReadOnly(True) self.text.setMinimumWidth(width_for_text(self.text, 'x' * 70)) self.layout().addWidget(self.text) # buttons button_box = QtWidgets.QDialogButtonBox( QtWidgets.QDialogButtonBox.Save | QtWidgets.QDialogButtonBox.Close) button_box.button(QtWidgets.QDialogButtonBox.Save).clicked.connect( self.save) button_box.button(QtWidgets.QDialogButtonBox.Close).clicked.connect( self.hide) self.layout().addWidget(button_box) # Python logger self.logger = logging.getLogger('') for handler in list(self.logger.handlers): self.logger.removeHandler(handler) threshold = logging.ERROR - (verbose * 10) self.logger.setLevel(max(threshold, 1)) self.stream_proxy = StreamProxy(self) self.stream_proxy.write_text.connect(self.write) self.stream_proxy.flush_text.connect(self.flush) handler = logging.StreamHandler(self.stream_proxy) handler.setFormatter( logging.Formatter( '%(asctime)s: %(levelname)s: %(name)s: %(message)s', datefmt='%H:%M:%S')) handler.addFilter(LoggerFilter(threshold)) self.logger.addHandler(handler) # intercept stdout and stderr, if they exist if sys.stderr: sys.stderr = OutputInterceptor('stderr', sys.stderr) if sys.stdout: sys.stdout = OutputInterceptor('stdout', sys.stdout)
def __init__(self, *arg, **kw): super(RatingWidget, self).__init__(*arg, **kw) self.multiple_values = multiple_values() self.setLayout(QtWidgets.QHBoxLayout()) self.layout().setContentsMargins(0, 0, 0, 0) # slider self.slider = Slider(Qt.Horizontal) self.slider.setFixedWidth(width_for_text(self.slider, 'x' * 25)) self.slider.setRange(-2, 5) self.slider.setPageStep(1) self.slider.valueChanged.connect(self.set_display) self.layout().addWidget(self.slider) # display self.display = QtWidgets.QLineEdit() self.display.setStyleSheet("* {background-color:rgba(0,0,0,0);}") self.display.setFrame(False) self.display.setReadOnly(True) self.display.setContextMenuPolicy(Qt.NoContextMenu) self.display.setFocusPolicy(Qt.NoFocus) self.layout().addWidget(self.display) # adopt child methods/signals self.is_multiple = self.slider.is_multiple self.editing_finished = self.slider.editing_finished
def __init__(self, *arg, **kw): super(EditSettings, self).__init__(*arg, **kw) self.config_store = QtWidgets.QApplication.instance().config_store self.setWindowTitle(self.tr('Photini: settings')) self.setLayout(QtWidgets.QVBoxLayout()) # main dialog area scroll_area = QtWidgets.QScrollArea() self.layout().addWidget(scroll_area) panel = QtWidgets.QWidget() panel.setLayout(QtWidgets.QFormLayout()) panel.layout().setRowWrapPolicy( max(QtWidgets.QFormLayout.WrapLongRows, panel.layout().rowWrapPolicy())) # apply & cancel buttons self.button_box = QtWidgets.QDialogButtonBox( QtWidgets.QDialogButtonBox.Apply | QtWidgets.QDialogButtonBox.Cancel) self.button_box.clicked.connect(self.button_clicked) self.layout().addWidget(self.button_box) # copyright holder name self.copyright_name = SingleLineEdit(spell_check=True) self.copyright_name.set_value( self.config_store.get('user', 'copyright_name', '')) panel.layout().addRow(self.tr('Copyright holder name'), self.copyright_name) # copyright text self.copyright_text = SingleLineEdit(spell_check=True) self.copyright_text.set_value( self.config_store.get('user', 'copyright_text', '')) self.copyright_text.setMinimumWidth( width_for_text(self.copyright_text, 'x' * 50)) panel.layout().addRow(self.tr('Copyright text'), self.copyright_text) # creator name self.creator_name = SingleLineEdit(spell_check=True) self.creator_name.set_value( self.config_store.get('user', 'creator_name', '')) panel.layout().addRow(self.tr('Creator name'), self.creator_name) # IPTC data force_iptc = eval(self.config_store.get('files', 'force_iptc', 'False')) self.write_iptc = QtWidgets.QCheckBox(self.tr('Always write')) self.write_iptc.setChecked(force_iptc) panel.layout().addRow(self.tr('IPTC metadata'), self.write_iptc) # sidecar files if_mode = eval(self.config_store.get('files', 'image', 'True')) sc_mode = self.config_store.get('files', 'sidecar', 'auto') if not if_mode: sc_mode = 'always' self.sc_always = QtWidgets.QRadioButton(self.tr('Always create')) self.sc_always.setChecked(sc_mode == 'always') panel.layout().addRow(self.tr('Sidecar files'), self.sc_always) self.sc_auto = QtWidgets.QRadioButton(self.tr('Create if necessary')) self.sc_auto.setChecked(sc_mode == 'auto') self.sc_auto.setEnabled(if_mode) panel.layout().addRow('', self.sc_auto) self.sc_delete = QtWidgets.QRadioButton( self.tr('Delete when possible')) self.sc_delete.setChecked(sc_mode == 'delete') self.sc_delete.setEnabled(if_mode) panel.layout().addRow('', self.sc_delete) # image file locking self.write_if = QtWidgets.QCheckBox(self.tr('(when possible)')) self.write_if.setChecked(if_mode) self.write_if.clicked.connect(self.new_write_if) panel.layout().addRow(self.tr('Write to image file'), self.write_if) # preserve file timestamps keep_time = eval( self.config_store.get('files', 'preserve_timestamps', 'False')) self.keep_time = QtWidgets.QCheckBox() self.keep_time.setChecked(keep_time) panel.layout().addRow(self.tr('Preserve file timestamps'), self.keep_time) # add panel to scroll area after its size is known scroll_area.setWidget(panel)
def __init__(self, image_list, *arg, **kw): super(TabWidget, self).__init__(*arg, **kw) self.config_store = QtWidgets.QApplication.instance().config_store self.image_list = image_list self.setLayout(QtWidgets.QHBoxLayout()) self.widgets = {} self.date_widget = {} self.link_widget = {} # date and time date_group = QtWidgets.QGroupBox( translate('TechnicalTab', 'Date and time')) date_group.setLayout(QtWidgets.QFormLayout()) # create date and link widgets for master in self._master_slave: self.date_widget[master] = DateAndTimeWidget(master) self.date_widget[master].new_value.connect(self.new_date_value) slave = self._master_slave[master] if slave: self.link_widget[master, slave] = DateLink(master) self.link_widget[master, slave].new_link.connect(self.new_link) self.link_widget['taken', 'digitised'].setText( translate('TechnicalTab', "Link 'taken' and 'digitised'")) self.link_widget['digitised', 'modified'].setText( translate('TechnicalTab', "Link 'digitised' and 'modified'")) # add to layout date_group.layout().addRow(translate('TechnicalTab', 'Taken'), self.date_widget['taken']) date_group.layout().addRow('', self.link_widget['taken', 'digitised']) date_group.layout().addRow(translate('TechnicalTab', 'Digitised'), self.date_widget['digitised']) date_group.layout().addRow('', self.link_widget['digitised', 'modified']) date_group.layout().addRow(translate('TechnicalTab', 'Modified'), self.date_widget['modified']) # offset self.offset_widget = OffsetWidget() self.offset_widget.apply_offset.connect(self.apply_offset) date_group.layout().addRow( translate('TechnicalTab', 'Adjust times'), self.offset_widget) self.layout().addWidget(date_group) # other other_group = QtWidgets.QGroupBox(translate('TechnicalTab', 'Other')) other_group.setLayout(QtWidgets.QFormLayout()) other_group.layout().setFieldGrowthPolicy( QtWidgets.QFormLayout.AllNonFixedFieldsGrow) # orientation self.widgets['orientation'] = DropdownEdit() self.widgets['orientation'].add_item( translate('TechnicalTab', 'normal'), 1, ordered=False) self.widgets['orientation'].add_item( translate('TechnicalTab', 'rotate -90'), 6, ordered=False) self.widgets['orientation'].add_item( translate('TechnicalTab', 'rotate +90'), 8, ordered=False) self.widgets['orientation'].add_item( translate('TechnicalTab', 'rotate 180'), 3, ordered=False) self.widgets['orientation'].add_item( translate('TechnicalTab', 'reflect left-right'), 2, ordered=False) self.widgets['orientation'].add_item( translate('TechnicalTab', 'reflect top-bottom'), 4, ordered=False) self.widgets['orientation'].add_item( translate('TechnicalTab', 'reflect tr-bl'), 5, ordered=False) self.widgets['orientation'].add_item( translate('TechnicalTab', 'reflect tl-br'), 7, ordered=False) self.widgets['orientation'].new_value.connect(self.new_orientation) other_group.layout().addRow(translate( 'TechnicalTab', 'Orientation'), self.widgets['orientation']) # camera model self.widgets['camera_model'] = CameraList(extendable=True) self.widgets['camera_model'].setMinimumWidth( width_for_text(self.widgets['camera_model'], 'x' * 30)) self.widgets['camera_model'].new_value.connect(self.new_camera_model) self.widgets['camera_model'].extend_list.connect(self.add_camera_model) other_group.layout().addRow(translate( 'TechnicalTab', 'Camera'), self.widgets['camera_model']) # lens model self.widgets['lens_model'] = LensList(extendable=True) self.widgets['lens_model'].setMinimumWidth( width_for_text(self.widgets['lens_model'], 'x' * 30)) self.widgets['lens_model'].new_value.connect(self.new_lens_model) self.widgets['lens_model'].extend_list.connect(self.add_lens_model) other_group.layout().addRow(translate( 'TechnicalTab', 'Lens model'), self.widgets['lens_model']) # focal length self.widgets['focal_length'] = DoubleSpinBox() self.widgets['focal_length'].setMinimum(0.0) self.widgets['focal_length'].setSuffix(' mm') self.widgets['focal_length'].new_value.connect(self.new_focal_length) other_group.layout().addRow(translate( 'TechnicalTab', 'Focal length'), self.widgets['focal_length']) # 35mm equivalent focal length self.widgets['focal_length_35'] = IntSpinBox() self.widgets['focal_length_35'].setMinimum(0) self.widgets['focal_length_35'].setSuffix(' mm') self.widgets['focal_length_35'].new_value.connect(self.new_focal_length_35) other_group.layout().addRow(translate( 'TechnicalTab', '35mm equiv'), self.widgets['focal_length_35']) # aperture self.widgets['aperture'] = DoubleSpinBox() self.widgets['aperture'].setMinimum(0.0) self.widgets['aperture'].setPrefix('ƒ/') self.widgets['aperture'].new_value.connect(self.new_aperture) other_group.layout().addRow(translate( 'TechnicalTab', 'Aperture'), self.widgets['aperture']) self.layout().addWidget(other_group, stretch=1) # disable until an image is selected self.setEnabled(False)
def diff_selected_metadata(self): dialog = QtWidgets.QDialog(parent=self) dialog.setLayout(QtWidgets.QVBoxLayout()) width = width_for_text(dialog, 'x' * 120) dialog.setFixedSize(min(width, self.window().width()), min(width // 2, self.window().height())) table = QtWidgets.QTableWidget() table.setColumnCount(3) table.setHorizontalHeaderLabels([ translate('ImageList', 'new value'), translate('ImageList', 'undo'), translate('ImageList', 'old value') ]) table.horizontalHeader().setSectionResizeMode( 0, QtWidgets.QHeaderView.Stretch) table.horizontalHeader().setSectionResizeMode( 2, QtWidgets.QHeaderView.Stretch) dialog.layout().addWidget(table) button_box = QtWidgets.QDialogButtonBox( QtWidgets.QDialogButtonBox.Ok | QtWidgets.QDialogButtonBox.Cancel) button_box.accepted.connect(dialog.accept) button_box.rejected.connect(dialog.reject) dialog.layout().addWidget(button_box) changed = False position = None for image in self.get_selected_images(): if not image.metadata.changed(): continue dialog.setWindowTitle( translate('ImageList', 'Metadata differences: {}').format(image.name)) labels = [] row = 0 undo = {} table.clearContents() new_md = image.metadata old_md = Metadata(image.path, utf_safe=self.app.options.utf_safe) for key in ('title', 'description', 'keywords', 'rating', 'creator', 'creator_title', 'credit_line', 'copyright', 'usageterms', 'instructions', 'contact_info', 'date_taken', 'date_digitised', 'date_modified', 'orientation', 'camera_model', 'lens_model', 'lens_spec', 'focal_length', 'focal_length_35', 'aperture', 'latlong', 'altitude', 'location_taken', 'location_shown', 'thumbnail'): values = getattr(new_md, key), getattr(old_md, key) if values[0] == values[1]: continue values = [str(x or '') for x in values] table.setRowCount(row + 1) for n, value in enumerate(values): item = QtWidgets.QTableWidgetItem(value) table.setItem(row, n * 2, item) undo[key] = QtWidgets.QTableWidgetItem() undo[key].setFlags(undo[key].flags() | Qt.ItemIsUserCheckable) undo[key].setCheckState(Qt.Unchecked) table.setItem(row, 1, undo[key]) labels.append(key) row += 1 if not row: continue table.setVerticalHeaderLabels(labels) table.resizeColumnsToContents() table.resizeRowsToContents() if position: dialog.move(position) if qt_version_info >= (6, 0): result = dialog.exec() else: result = dialog.exec_() if result != QtWidgets.QDialog.Accepted: return position = dialog.pos() undo_all = True for key, widget in undo.items(): if widget.checkState() == Qt.Checked: setattr(new_md, key, getattr(old_md, key)) changed = True else: undo_all = False if undo_all: image.reload_metadata() if changed: self.emit_selection()
def __init__(self, parent=None): super(ImageList, self).__init__(parent) self.app = QtWidgets.QApplication.instance() self.drag_icon = None self.images = [] self.last_selected = None self.selection_anchor = None self.thumb_size = self.app.config_store.get('controls', 'thumb_size', 4) if self.thumb_size > 20: # old config, in pixels self.thumb_size = self.thumb_size // 20 layout = QtWidgets.QGridLayout() layout.setSpacing(0) layout.setRowStretch(0, 1) layout.setColumnStretch(3, 1) self.setLayout(layout) layout.setContentsMargins(0, 0, 0, 0) # thumbnail display self.scroll_area = ScrollArea() self.scroll_area.dropped_images.connect(self.open_file_list) self.scroll_area.multi_row_changed.connect( self._ensure_selected_visible) layout.addWidget(self.scroll_area, 0, 0, 1, 6) QtGui2.QShortcut(QtGui.QKeySequence.MoveToPreviousChar, self.scroll_area, self.move_to_prev_thumb) QtGui2.QShortcut(QtGui.QKeySequence.MoveToNextChar, self.scroll_area, self.move_to_next_thumb) QtGui2.QShortcut(QtGui.QKeySequence.MoveToStartOfLine, self.scroll_area, self.move_to_first_thumb) QtGui2.QShortcut(QtGui.QKeySequence.MoveToEndOfLine, self.scroll_area, self.move_to_last_thumb) QtGui2.QShortcut(QtGui.QKeySequence.SelectPreviousChar, self.scroll_area, self.select_prev_thumb) QtGui2.QShortcut(QtGui.QKeySequence.SelectNextChar, self.scroll_area, self.select_next_thumb) QtGui2.QShortcut(QtGui.QKeySequence.SelectAll, self.scroll_area, self.select_all) # sort key selector layout.addWidget(QtWidgets.QLabel(self.tr('sort by: ')), 1, 0) self.sort_name = QtWidgets.QRadioButton(self.tr('file name')) self.sort_name.clicked.connect(self._new_sort_order) layout.addWidget(self.sort_name, 1, 1) self.sort_date = QtWidgets.QRadioButton(self.tr('date taken')) layout.addWidget(self.sort_date, 1, 2) self.sort_date.clicked.connect(self._new_sort_order) if self.app.config_store.get('controls', 'sort_date', False): self.sort_date.setChecked(True) else: self.sort_name.setChecked(True) # size selector layout.addWidget(QtWidgets.QLabel(self.tr('thumbnail size: ')), 1, 4) self.size_slider = QtWidgets.QSlider(Qt.Horizontal) self.size_slider.setTracking(False) self.size_slider.setRange(4, 9) self.size_slider.setPageStep(1) self.size_slider.setValue(self.thumb_size) self.size_slider.setTickPosition(QtWidgets.QSlider.TicksBelow) self.size_slider.setMinimumWidth( width_for_text(self.size_slider, 'x' * 20)) self.size_slider.valueChanged.connect(self._new_thumb_size) layout.addWidget(self.size_slider, 1, 5)
def _set_thumb_size(self, thumb_size): width = width_for_text(self.label, 'X' * thumb_size * 20) // 6 self.image.setFixedSize(width, width) self._elide_name()
def __init__(self, image_list, *arg, **kw): super(TabWidget, self).__init__(*arg, **kw) self.config_store = QtWidgets.QApplication.instance().config_store self.image_list = image_list self.setLayout(QtWidgets.QHBoxLayout()) self.widgets = {} self.date_widget = {} self.link_widget = {} # store lens data in another object self.lens_data = LensData() # date and time date_group = QtWidgets.QGroupBox( translate('TechnicalTab', 'Date and time')) date_group.setLayout(QtWidgets.QFormLayout()) # create date and link widgets for master in self._master_slave: self.date_widget[master] = DateAndTimeWidget(master) self.date_widget[master].new_value.connect(self.new_date_value) slave = self._master_slave[master] if slave: self.link_widget[master, slave] = DateLink(master) self.link_widget[master, slave].new_link.connect(self.new_link) self.link_widget['taken', 'digitised'].setText( translate('TechnicalTab', "Link 'taken' and 'digitised'")) self.link_widget['digitised', 'modified'].setText( translate('TechnicalTab', "Link 'digitised' and 'modified'")) # add to layout date_group.layout().addRow(translate('TechnicalTab', 'Taken'), self.date_widget['taken']) date_group.layout().addRow('', self.link_widget['taken', 'digitised']) date_group.layout().addRow(translate('TechnicalTab', 'Digitised'), self.date_widget['digitised']) date_group.layout().addRow('', self.link_widget['digitised', 'modified']) date_group.layout().addRow(translate('TechnicalTab', 'Modified'), self.date_widget['modified']) # offset self.offset_widget = OffsetWidget() self.offset_widget.apply_offset.connect(self.apply_offset) date_group.layout().addRow(translate('TechnicalTab', 'Adjust times'), self.offset_widget) self.layout().addWidget(date_group) # other other_group = QtWidgets.QGroupBox(translate('TechnicalTab', 'Other')) other_group.setLayout(QtWidgets.QFormLayout()) other_group.layout().setFieldGrowthPolicy( QtWidgets.QFormLayout.AllNonFixedFieldsGrow) # orientation self.widgets['orientation'] = DropdownEdit() self.widgets['orientation'].add_item( translate('TechnicalTab', 'normal'), 1) self.widgets['orientation'].add_item( translate('TechnicalTab', 'rotate -90'), 6) self.widgets['orientation'].add_item( translate('TechnicalTab', 'rotate +90'), 8) self.widgets['orientation'].add_item( translate('TechnicalTab', 'rotate 180'), 3) self.widgets['orientation'].add_item( translate('TechnicalTab', 'reflect left-right'), 2) self.widgets['orientation'].add_item( translate('TechnicalTab', 'reflect top-bottom'), 4) self.widgets['orientation'].add_item( translate('TechnicalTab', 'reflect tr-bl'), 5) self.widgets['orientation'].add_item( translate('TechnicalTab', 'reflect tl-br'), 7) self.widgets['orientation'].new_value.connect(self.new_orientation) other_group.layout().addRow(translate('TechnicalTab', 'Orientation'), self.widgets['orientation']) # lens model self.widgets['lens_model'] = DropdownEdit() self.widgets['lens_model'].setMinimumWidth( width_for_text(self.widgets['lens_model'], 'x' * 30)) self.widgets['lens_model'].setContextMenuPolicy(Qt.CustomContextMenu) self.widgets['lens_model'].add_item( translate('TechnicalTab', '<define new lens>'), '<add lens>') for lens_id in self.lens_data.lenses: self.widgets['lens_model'].add_item( self.lens_data.get_name(lens_id), lens_id) self.widgets['lens_model'].new_value.connect(self.new_lens_model) self.widgets['lens_model'].customContextMenuRequested.connect( self.remove_lens_model) other_group.layout().addRow(translate('TechnicalTab', 'Lens model'), self.widgets['lens_model']) # lens specification self.widgets['lens_spec'] = LensSpecWidget() other_group.layout().addRow(translate('TechnicalTab', 'Lens details'), self.widgets['lens_spec']) # focal length self.widgets['focal_length'] = DoubleSpinBox() self.widgets['focal_length'].setMinimum(0.0) self.widgets['focal_length'].setSuffix(' mm') self.widgets['focal_length'].new_value.connect(self.new_focal_length) other_group.layout().addRow(translate('TechnicalTab', 'Focal length'), self.widgets['focal_length']) # 35mm equivalent focal length self.widgets['focal_length_35'] = IntSpinBox() self.widgets['focal_length_35'].setMinimum(0) self.widgets['focal_length_35'].setSuffix(' mm') self.widgets['focal_length_35'].new_value.connect( self.new_focal_length_35) other_group.layout().addRow(translate('TechnicalTab', '35mm equiv'), self.widgets['focal_length_35']) # aperture self.widgets['aperture'] = DoubleSpinBox() self.widgets['aperture'].setMinimum(0.0) self.widgets['aperture'].setPrefix('ƒ/') self.widgets['aperture'].new_value.connect(self.new_aperture) other_group.layout().addRow(translate('TechnicalTab', 'Aperture'), self.widgets['aperture']) self.layout().addWidget(other_group, stretch=1) # disable until an image is selected self.setEnabled(False)
def __init__(self, images, *arg, **kw): super(NewLensDialog, self).__init__(*arg, **kw) self.setWindowTitle(translate('TechnicalTab', 'Photini: define lens')) self.setLayout(QtWidgets.QVBoxLayout()) # main dialog area scroll_area = QtWidgets.QScrollArea() scroll_area.setWidgetResizable(True) self.layout().addWidget(scroll_area) panel = QtWidgets.QWidget() panel.setLayout(QtWidgets.QFormLayout()) panel.layout().setFieldGrowthPolicy( QtWidgets.QFormLayout.AllNonFixedFieldsGrow) # ok & cancel buttons button_box = QtWidgets.QDialogButtonBox( QtWidgets.QDialogButtonBox.Ok | QtWidgets.QDialogButtonBox.Cancel) button_box.accepted.connect(self.accept) button_box.rejected.connect(self.reject) self.layout().addWidget(button_box) # model self.lens_model = QtWidgets.QLineEdit() self.lens_model.setMinimumWidth( width_for_text(self.lens_model, 'x' * 35)) panel.layout().addRow(translate('TechnicalTab', 'Model name'), self.lens_model) # maker self.lens_make = QtWidgets.QLineEdit() panel.layout().addRow(translate('TechnicalTab', "Maker's name"), self.lens_make) # serial number self.lens_serial = QtWidgets.QLineEdit() panel.layout().addRow(translate('TechnicalTab', 'Serial number'), self.lens_serial) ## spec has four items self.lens_spec = {} # min focal length self.lens_spec['min_fl'] = DoubleSpinBox() self.lens_spec['min_fl'].setMinimum(0.0) self.lens_spec['min_fl'].setSingleStep(1.0) self.lens_spec['min_fl'].setSuffix(' mm') panel.layout().addRow( translate('TechnicalTab', 'Minimum focal length'), self.lens_spec['min_fl']) # min focal length aperture self.lens_spec['min_fl_fn'] = DoubleSpinBox() self.lens_spec['min_fl_fn'].setMinimum(0.0) self.lens_spec['min_fl_fn'].setPrefix('ƒ/') panel.layout().addRow( translate('TechnicalTab', 'Aperture at min. focal length'), self.lens_spec['min_fl_fn']) # max focal length self.lens_spec['max_fl'] = DoubleSpinBox() self.lens_spec['max_fl'].setMinimum(0.0) self.lens_spec['max_fl'].setSingleStep(1.0) self.lens_spec['max_fl'].setSuffix(' mm') panel.layout().addRow( translate('TechnicalTab', 'Maximum focal length'), self.lens_spec['max_fl']) # max focal length aperture self.lens_spec['max_fl_fn'] = DoubleSpinBox() self.lens_spec['max_fl_fn'].setMinimum(0.0) self.lens_spec['max_fl_fn'].setPrefix('ƒ/') panel.layout().addRow( translate('TechnicalTab', 'Aperture at max. focal length'), self.lens_spec['max_fl_fn']) # add panel to scroll area after its size is known scroll_area.setWidget(panel) # fill in any values we can from existing metadata for image in images: if image.metadata.lens_model: self.lens_model.setText(image.metadata.lens_model) if image.metadata.lens_make: self.lens_make.setText(image.metadata.lens_make) if image.metadata.lens_serial: self.lens_serial.setText(image.metadata.lens_serial) spec = image.metadata.lens_spec for key in self.lens_spec: if spec and spec[key]: self.lens_spec[key].set_value(spec[key])
def tabSizeHint(self, index): size = super(QTabBar, self).tabSizeHint(index) size.setWidth(max(size.width(), width_for_text(self, 'x' * 10))) return size
def __init__(self, *arg, **kw): super(EditSettings, self).__init__(*arg, **kw) self.config_store = QtWidgets.QApplication.instance().config_store self.setWindowTitle(self.tr('Photini: settings')) self.setLayout(QtWidgets.QVBoxLayout()) # main dialog area scroll_area = QtWidgets.QScrollArea() self.layout().addWidget(scroll_area) panel = QtWidgets.QWidget() panel.setLayout(QtWidgets.QFormLayout()) panel.layout().setRowWrapPolicy( max(QtWidgets.QFormLayout.WrapLongRows, panel.layout().rowWrapPolicy())) # apply & cancel buttons self.button_box = QtWidgets.QDialogButtonBox( QtWidgets.QDialogButtonBox.Apply | QtWidgets.QDialogButtonBox.Cancel) self.button_box.clicked.connect(self.button_clicked) self.layout().addWidget(self.button_box) # copyright holder name self.copyright_name = SingleLineEdit(spell_check=True) self.copyright_name.set_value( self.config_store.get('user', 'copyright_name', '')) panel.layout().addRow(self.tr('Copyright holder name'), self.copyright_name) # copyright text self.copyright_text = SingleLineEdit(spell_check=True) self.copyright_text.set_value( self.config_store.get('user', 'copyright_text', '')) self.copyright_text.setMinimumWidth( width_for_text(self.copyright_text, 'x' * 50)) panel.layout().addRow(self.tr('Copyright text'), self.copyright_text) # creator name self.creator_name = SingleLineEdit(spell_check=True) self.creator_name.set_value( self.config_store.get('user', 'creator_name', '')) panel.layout().addRow(self.tr('Creator name'), self.creator_name) # IPTC data force_iptc = self.config_store.get('files', 'force_iptc', False) self.write_iptc = QtWidgets.QCheckBox(self.tr('Always write')) self.write_iptc.setChecked(force_iptc) panel.layout().addRow(self.tr('IPTC-IIM metadata'), self.write_iptc) # show IPTC-IIM length limits length_warning = self.config_store.get('files', 'length_warning', True) self.length_warning = QtWidgets.QCheckBox( self.tr('Show IPTC-IIM length limits')) self.length_warning.setChecked(length_warning) panel.layout().addRow('', self.length_warning) # sidecar files if_mode = self.config_store.get('files', 'image', True) sc_mode = self.config_store.get('files', 'sidecar', 'auto') if not if_mode: sc_mode = 'always' button_group = QtWidgets.QButtonGroup(parent=self) self.sc_always = QtWidgets.QRadioButton(self.tr('Always create')) button_group.addButton(self.sc_always) self.sc_always.setChecked(sc_mode == 'always') panel.layout().addRow(self.tr('Sidecar files'), self.sc_always) self.sc_auto = QtWidgets.QRadioButton(self.tr('Create if necessary')) button_group.addButton(self.sc_auto) self.sc_auto.setChecked(sc_mode == 'auto') self.sc_auto.setEnabled(if_mode) panel.layout().addRow('', self.sc_auto) self.sc_delete = QtWidgets.QRadioButton( self.tr('Delete when possible')) button_group.addButton(self.sc_delete) self.sc_delete.setChecked(sc_mode == 'delete') self.sc_delete.setEnabled(if_mode) panel.layout().addRow('', self.sc_delete) # image file locking self.write_if = QtWidgets.QCheckBox(self.tr('(when possible)')) self.write_if.setChecked(if_mode) self.write_if.clicked.connect(self.new_write_if) panel.layout().addRow(self.tr('Write to image file'), self.write_if) # preserve file timestamps keep_time = self.config_store.get('files', 'preserve_timestamps', 'now') if isinstance(keep_time, bool): # old config format keep_time = ('now', 'keep')[keep_time] button_group = QtWidgets.QButtonGroup(parent=self) self.keep_time = QtWidgets.QRadioButton(self.tr('Keep original')) button_group.addButton(self.keep_time) self.keep_time.setChecked(keep_time == 'keep') panel.layout().addRow(self.tr('File timestamps'), self.keep_time) self.time_taken = QtWidgets.QRadioButton( self.tr('Set to when photo was taken')) button_group.addButton(self.time_taken) self.time_taken.setChecked(keep_time == 'taken') panel.layout().addRow('', self.time_taken) button = QtWidgets.QRadioButton(self.tr('Set to when file is saved')) button_group.addButton(button) button.setChecked(keep_time == 'now') panel.layout().addRow('', button) # add panel to scroll area after its size is known scroll_area.setWidget(panel)