Esempio n. 1
0
 def __init__(self, image_list, *arg, **kw):
     super(Descriptive, self).__init__(*arg, **kw)
     self.config_store = QtWidgets.QApplication.instance().config_store
     self.image_list = image_list
     self.form = QtWidgets.QFormLayout()
     self.setLayout(self.form)
     if qt_version_info >= (5, 0):
         self.trUtf8 = self.tr
     # construct widgets
     self.widgets = {}
     # title
     self.widgets['title'] = SingleLineEdit(spell_check=True)
     self.widgets['title'].editingFinished.connect(self.new_title)
     self.form.addRow(self.tr('Title / Object Name'), self.widgets['title'])
     # description
     self.widgets['description'] = MultiLineEdit(spell_check=True)
     self.widgets['description'].editingFinished.connect(self.new_description)
     self.form.addRow(
         self.tr('Description / Caption'), self.widgets['description'])
     # keywords
     self.widgets['keywords'] = KeywordsEditor()
     self.widgets['keywords'].editingFinished.connect(self.new_keywords)
     self.form.addRow(self.tr('Keywords'), self.widgets['keywords'])
     self.image_list.image_list_changed.connect(self.image_list_changed)
     # copyright
     self.widgets['copyright'] = LineEditWithAuto()
     self.widgets['copyright'].editingFinished.connect(self.new_copyright)
     self.widgets['copyright'].autoComplete.connect(self.auto_copyright)
     self.form.addRow(self.tr('Copyright'), self.widgets['copyright'])
     # creator
     self.widgets['creator'] = LineEditWithAuto()
     self.widgets['creator'].editingFinished.connect(self.new_creator)
     self.widgets['creator'].autoComplete.connect(self.auto_creator)
     self.form.addRow(self.tr('Creator / Artist'), self.widgets['creator'])
     # disable until an image is selected
     self.setEnabled(False)
Esempio n. 2
0
 def __init__(self, *arg, **kw):
     super(GoogleUploadConfig, self).__init__(*arg, **kw)
     self.setLayout(QtWidgets.QGridLayout())
     self.layout().setContentsMargins(0, 0, 0, 0)
     # create new set
     new_set_button = QtWidgets.QPushButton(self.tr('New album'))
     new_set_button.clicked.connect(self.new_set)
     self.layout().addWidget(new_set_button, 2, 1)
     # list of sets widget
     sets_group = QtWidgets.QGroupBox(self.tr('Add to albums'))
     sets_group.setLayout(QtWidgets.QVBoxLayout())
     scrollarea = QtWidgets.QScrollArea()
     scrollarea.setFrameStyle(QtWidgets.QFrame.NoFrame)
     scrollarea.setStyleSheet("QScrollArea { background-color: transparent }")
     self.sets_widget = QtWidgets.QWidget()
     self.sets_widget.setLayout(QtWidgets.QVBoxLayout())
     self.sets_widget.layout().setSpacing(0)
     self.sets_widget.layout().setSizeConstraint(
         QtWidgets.QLayout.SetMinAndMaxSize)
     scrollarea.setWidget(self.sets_widget)
     self.sets_widget.setAutoFillBackground(False)
     sets_group.layout().addWidget(scrollarea)
     self.layout().addWidget(sets_group, 0, 2, 3, 1)
     self.layout().setColumnStretch(2, 1)
Esempio n. 3
0
 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)
Esempio n. 4
0
 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 = int(
         self.app.config_store.get('controls', 'thumb_size', '80'))
     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)
     layout.addWidget(self.scroll_area, 0, 0, 1, 6)
     self.thumbnails = QtWidgets.QWidget()
     self.thumbnails.setLayout(FlowLayout())
     self.scroll_area.setWidget(self.thumbnails)
     QtWidgets.QShortcut(QtGui.QKeySequence.MoveToPreviousChar,
                     self.scroll_area, self.move_to_prev_thumb)
     QtWidgets.QShortcut(QtGui.QKeySequence.MoveToNextChar,
                     self.scroll_area, self.move_to_next_thumb)
     QtWidgets.QShortcut(QtGui.QKeySequence.SelectPreviousChar,
                     self.scroll_area, self.select_prev_thumb)
     QtWidgets.QShortcut(QtGui.QKeySequence.SelectNextChar,
                     self.scroll_area, self.select_next_thumb)
     QtWidgets.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 eval(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 / 20)
     self.size_slider.setTickPosition(QtWidgets.QSlider.TicksBelow)
     self.size_slider.setMinimumWidth(140)
     self.size_slider.valueChanged.connect(self._new_thumb_size)
     layout.addWidget(self.size_slider, 1, 5)
Esempio n. 5
0
 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)
Esempio n. 6
0
 def diff_metadata(self):
     dialog = QtWidgets.QDialog(parent=self)
     dialog.setWindowTitle(translate('ImageList', 'Metadata differences'))
     dialog.setLayout(QtWidgets.QVBoxLayout())
     table = TableWidget()
     table.setSizePolicy(QtWidgets.QSizePolicy.Expanding,
                         QtWidgets.QSizePolicy.Expanding)
     table.setColumnCount(3)
     table.setHorizontalHeaderLabels([
         translate('ImageList', 'new value'),
         translate('ImageList', 'undo'),
         translate('ImageList', 'old value')
     ])
     labels = []
     row = 0
     undo = {}
     new_md = self.metadata
     old_md = Metadata(self.path)
     for key in ('title', 'description', 'keywords', 'rating', 'copyright',
                 'creator', 'date_taken', 'date_digitised', 'date_modified',
                 'orientation', 'lens_model', 'lens_make', 'lens_serial',
                 '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
         table.setRowCount(row + 1)
         for n, value in enumerate(values):
             if not value:
                 value = ''
             elif isinstance(value, MultiString):
                 value = '\n'.join(value)
             else:
                 value = six.text_type(value)
             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(False)
         table.setItem(row, 1, undo[key])
         labels.append(key)
         row += 1
     table.setVerticalHeaderLabels(labels)
     table.resizeColumnsToContents()
     table.resizeRowsToContents()
     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)
     if dialog.exec_() != QtWidgets.QDialog.Accepted:
         return
     changed = False
     dirty = False
     for key, widget in undo.items():
         if widget.checkState() == Qt.Checked:
             setattr(new_md, key, getattr(old_md, key))
             changed = True
         else:
             dirty = True
     if not dirty:
         self.reload_metadata()
     elif changed:
         self.image_list.emit_selection()
Esempio n. 7
0
 def _replace_dialog(self, image):
     # has image already been uploaded?
     for keyword in image.metadata.keywords or []:
         name_pred, sep, photo_id = keyword.partition('=')
         if name_pred == ID_TAG:
             break
     else:
         # new upload
         return {
             'set_metadata'  : True,
             'set_visibility': True,
             'set_type'      : True,
             'set_albums'    : True,
             'replace_image' : False,
             'new_photo'     : True,
             }, None
     # get user preferences
     dialog = QtWidgets.QDialog(parent=self)
     dialog.setWindowTitle(translate('FlickrTab', 'Replace photo'))
     dialog.setLayout(QtWidgets.QVBoxLayout())
     message = QtWidgets.QLabel(translate(
         'FlickrTab', 'File {0} has already been uploaded to Flickr.'
         ' How would you like to update it?').format(
             os.path.basename(image.path)))
     message.setWordWrap(True)
     dialog.layout().addWidget(message)
     widget = {}
     widget['set_metadata'] = QtWidgets.QCheckBox(
         translate('FlickrTab', 'Replace metadata'))
     widget['set_visibility'] = QtWidgets.QCheckBox(
         translate('FlickrTab', 'Change who can see it'))
     widget['set_type'] = QtWidgets.QCheckBox(
         translate('FlickrTab', 'Change content type'))
     widget['set_albums'] = QtWidgets.QCheckBox(
         translate('FlickrTab', 'Change album membership'))
     widget['replace_image'] = QtWidgets.QCheckBox(
         translate('FlickrTab', 'Replace image'))
     widget['new_photo'] = QtWidgets.QCheckBox(
         translate('FlickrTab', 'Upload as new photo'))
     widget['new_photo'].toggled.connect(widget['set_metadata'].setDisabled)
     widget['new_photo'].toggled.connect(widget['set_visibility'].setDisabled)
     widget['new_photo'].toggled.connect(widget['set_type'].setDisabled)
     widget['new_photo'].toggled.connect(widget['set_albums'].setDisabled)
     no_upload = QtWidgets.QCheckBox(
         translate('FlickrTab', 'No image upload'))
     no_upload.setChecked(True)
     button_group = QtWidgets.QButtonGroup()
     button_group.addButton(widget['replace_image'])
     button_group.addButton(widget['new_photo'])
     button_group.addButton(no_upload)
     for key in ('set_metadata', 'set_visibility', 'set_type',
                 'set_albums', 'replace_image', 'new_photo'):
         dialog.layout().addWidget(widget[key])
         widget[key].setChecked(self.replace_prefs[key])
     dialog.layout().addWidget(no_upload)
     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 None, photo_id
     for key in self.replace_prefs:
         self.replace_prefs[key] = widget[key].isChecked()
     return dict(self.replace_prefs), photo_id
Esempio n. 8
0
 def __init__(self, image_list, *arg, **kw):
     super(Technical, self).__init__(*arg, **kw)
     self.image_list = image_list
     self.setLayout(QtWidgets.QGridLayout())
     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(self.tr('Date and time'))
     date_group.setLayout(QtWidgets.QFormLayout())
     # taken
     self.date_widget['taken'] = DateAndTimeWidget()
     self.date_widget['taken'].new_value.connect(self.new_date_taken)
     date_group.layout().addRow(self.tr('Taken'), self.date_widget['taken'])
     # link taken & digitised
     self.link_widget['taken', 'digitised'] = QtWidgets.QCheckBox(
         self.tr("Link 'taken' and 'digitised'"))
     self.link_widget['taken',
                      'digitised'].clicked.connect(self.new_link_digitised)
     date_group.layout().addRow('', self.link_widget['taken', 'digitised'])
     # digitised
     self.date_widget['digitised'] = DateAndTimeWidget()
     self.date_widget['digitised'].new_value.connect(
         self.new_date_digitised)
     date_group.layout().addRow(self.tr('Digitised'),
                                self.date_widget['digitised'])
     # link digitised & modified
     self.link_widget['digitised', 'modified'] = QtWidgets.QCheckBox(
         self.tr("Link 'digitised' and 'modified'"))
     self.link_widget['digitised',
                      'modified'].clicked.connect(self.new_link_modified)
     date_group.layout().addRow('', self.link_widget['digitised',
                                                     'modified'])
     # modified
     self.date_widget['modified'] = DateAndTimeWidget()
     self.date_widget['modified'].new_value.connect(self.new_date_modified)
     date_group.layout().addRow(self.tr('Modified'),
                                self.date_widget['modified'])
     # offset
     self.offset_widget = OffsetWidget()
     self.offset_widget.apply_offset.connect(self.apply_offset)
     date_group.layout().addRow(self.tr('Adjust times'), self.offset_widget)
     self.layout().addWidget(date_group, 0, 0)
     # other
     other_group = QtWidgets.QGroupBox(self.tr('Other'))
     other_group.setLayout(QtWidgets.QFormLayout())
     # orientation
     self.widgets['orientation'] = DropdownEdit()
     self.widgets['orientation'].add_item(self.tr('normal'), 1)
     self.widgets['orientation'].add_item(self.tr('rotate -90'), 6)
     self.widgets['orientation'].add_item(self.tr('rotate +90'), 8)
     self.widgets['orientation'].add_item(self.tr('rotate 180'), 3)
     self.widgets['orientation'].add_item(self.tr('reflect left-right'), 2)
     self.widgets['orientation'].add_item(self.tr('reflect top-bottom'), 4)
     self.widgets['orientation'].add_item(self.tr('reflect tr-bl'), 5)
     self.widgets['orientation'].add_item(self.tr('reflect tl-br'), 7)
     self.widgets['orientation'].new_value.connect(self.new_orientation)
     other_group.layout().addRow(self.tr('Orientation'),
                                 self.widgets['orientation'])
     # lens model
     self.widgets['lens_model'] = DropdownEdit()
     self.widgets['lens_model'].setContextMenuPolicy(Qt.CustomContextMenu)
     self.widgets['lens_model'].add_item(self.tr('<define new lens>'),
                                         '<add lens>')
     for model in self.lens_data.lenses:
         self.widgets['lens_model'].add_item(model, model)
     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(self.tr('Lens model'),
                                 self.widgets['lens_model'])
     # lens specification
     self.widgets['lens_spec'] = LensSpecWidget()
     other_group.layout().addRow(self.tr('Lens details'),
                                 self.widgets['lens_spec'])
     # focal length
     self.widgets['focal_length'] = FloatEdit()
     self.widgets['focal_length'].validator().setBottom(0.1)
     self.widgets['focal_length'].editingFinished.connect(
         self.new_focal_length)
     other_group.layout().addRow(self.tr('Focal length (mm)'),
                                 self.widgets['focal_length'])
     # 35mm equivalent focal length
     self.widgets['focal_length_35'] = IntEdit()
     self.widgets['focal_length_35'].validator().setBottom(1)
     self.widgets['focal_length_35'].editingFinished.connect(
         self.new_focal_length_35)
     other_group.layout().addRow(self.tr('35mm equiv (mm)'),
                                 self.widgets['focal_length_35'])
     # aperture
     self.widgets['aperture'] = FloatEdit()
     self.widgets['aperture'].validator().setBottom(0.1)
     self.widgets['aperture'].editingFinished.connect(self.new_aperture)
     other_group.layout().addRow(self.tr('Aperture f/'),
                                 self.widgets['aperture'])
     self.layout().addWidget(other_group, 0, 1)
     self.layout().setColumnStretch(0, 1)
     self.layout().setColumnStretch(1, 1)
     # disable until an image is selected
     self.setEnabled(False)
Esempio n. 9
0
 def __init__(self, image_list, parent=None):
     super(PhotiniMap, self).__init__(parent)
     self.app = QtWidgets.QApplication.instance()
     self.image_list = image_list
     self.geocode_cache = OrderedDict()
     name = self.__module__.split('.')[-1]
     self.api_key = key_store.get(name, 'api_key')
     self.search_key = key_store.get('opencage', 'api_key')
     self.script_dir = pkg_resources.resource_filename(
         'photini', 'data/' + name + '/')
     self.drag_icon = QtGui.QPixmap(
         os.path.join(self.script_dir, '../map_pin_grey.png'))
     self.drag_hotspot = 11, 35
     self.search_string = None
     self.map_loaded = False
     self.marker_info = {}
     self.map_status = {}
     self.dropped_images = []
     self.setChildrenCollapsible(False)
     left_side = QtWidgets.QWidget()
     self.addWidget(left_side)
     left_side.setLayout(QtWidgets.QFormLayout())
     left_side.layout().setContentsMargins(0, 0, 0, 0)
     left_side.layout().setFieldGrowthPolicy(
         QtWidgets.QFormLayout.AllNonFixedFieldsGrow)
     # map
     # create handler for calls from JavaScript
     self.call_handler = CallHandler(parent=self)
     self.map = MapWebView(self.call_handler)
     self.map.drop_text.connect(self.drop_text)
     self.map.setAcceptDrops(False)
     self.addWidget(self.map)
     # search
     search_layout = QtWidgets.QFormLayout()
     search_layout.setContentsMargins(0, 0, 0, 0)
     search_layout.setVerticalSpacing(0)
     search_layout.setFieldGrowthPolicy(
         QtWidgets.QFormLayout.AllNonFixedFieldsGrow)
     self.edit_box = ComboBox()
     self.edit_box.setEditable(True)
     self.edit_box.setInsertPolicy(QtWidgets.QComboBox.NoInsert)
     self.edit_box.lineEdit().setPlaceholderText(
         translate('PhotiniMap', '<new search>'))
     self.edit_box.lineEdit().returnPressed.connect(self.search)
     self.edit_box.activated.connect(self.goto_search_result)
     self.clear_search()
     self.edit_box.setEnabled(False)
     search_layout.addRow(translate('PhotiniMap', 'Search'), self.edit_box)
     # search terms and conditions
     terms = self.search_terms()
     if terms:
         search_layout.addRow(*terms)
     left_side.layout().addRow(search_layout)
     if terms:
         divider = QtWidgets.QFrame()
         divider.setFrameStyle(QtWidgets.QFrame.HLine)
         left_side.layout().addRow(divider)
     left_side.layout().addItem(
         QtWidgets.QSpacerItem(1,
                               1000,
                               vPolicy=QtWidgets.QSizePolicy.Expanding))
     # latitude & longitude
     layout = QtWidgets.QHBoxLayout()
     self.coords = SingleLineEdit()
     self.coords.editingFinished.connect(self.new_coords)
     self.coords.setEnabled(False)
     layout.addWidget(self.coords)
     # convert lat/lng to location info
     self.auto_location = QtWidgets.QPushButton(
         translate('PhotiniMap',
                   six.unichr(0x21e8) + ' address'))
     self.auto_location.setFixedHeight(self.coords.height())
     self.auto_location.setEnabled(False)
     self.auto_location.clicked.connect(self.get_address)
     layout.addWidget(self.auto_location)
     left_side.layout().addRow(translate('PhotiniMap', 'Lat, long'), layout)
     # location info
     self.location_widgets = []
     self.location_info = QtWidgets.QTabWidget()
     tab_bar = QTabBar()
     self.location_info.setTabBar(tab_bar)
     tab_bar.context_menu.connect(self.location_tab_context_menu)
     tab_bar.tabMoved.connect(self.location_tab_moved)
     self.location_info.setElideMode(Qt.ElideLeft)
     self.location_info.setMovable(True)
     self.location_info.setEnabled(False)
     left_side.layout().addRow(self.location_info)
     # address lookup (and default search) terms and conditions
     layout = QtWidgets.QHBoxLayout()
     if terms:
         widget = CompactButton(
             self.tr('Address lookup\npowered by OpenCage'))
     else:
         widget = CompactButton(
             self.tr('Search && lookup\npowered by OpenCage'))
     widget.clicked.connect(self.load_tou_opencage)
     layout.addWidget(widget)
     widget = CompactButton(
         self.tr('Geodata © OpenStreetMap\ncontributors'))
     widget.clicked.connect(self.load_tou_osm)
     layout.addWidget(widget)
     left_side.layout().addRow(layout)
     # other init
     self.image_list.image_list_changed.connect(self.image_list_changed)
     self.splitterMoved.connect(self.new_split)
     self.block_timer = QtCore.QTimer(self)
     self.block_timer.setInterval(5000)
     self.block_timer.setSingleShot(True)
     self.block_timer.timeout.connect(self.enable_search)
Esempio n. 10
0
 def __init__(self, image_list, parent=None):
     super(PhotiniMap, self).__init__(parent)
     self.logger = logging.getLogger(self.__class__.__name__)
     self.app = QtWidgets.QApplication.instance()
     self.config_store = self.app.config_store
     self.image_list = image_list
     self.multiple_values = multiple_values()
     self.script_dir = pkg_resources.resource_filename(
         'photini', 'data/' + self.__class__.__name__.lower() + '/')
     self.drag_icon = QtGui.QPixmap(
         os.path.join(self.script_dir, 'grey_marker.png'))
     self.location = {}
     self.search_string = None
     self.map_loaded = False
     self.marker_images = {}
     layout = QtWidgets.QGridLayout()
     layout.setContentsMargins(0, 0, 0, 0)
     layout.setRowStretch(6, 1)
     layout.setColumnStretch(1, 1)
     self.setLayout(layout)
     # map
     self.map = WebView()
     self.map.setPage(WebPage(parent=self.map))
     self.map.setAcceptDrops(False)
     self.map.page().setLinkDelegationPolicy(
         QtWebKitWidgets.QWebPage.DelegateAllLinks)
     self.map.page().linkClicked.connect(self.link_clicked)
     self.map.page().loadFinished.connect(self.load_finished)
     self.map.page().mainFrame().javaScriptWindowObjectCleared.connect(
         self.java_script_window_object_cleared)
     self.map.drop_text.connect(self.drop_text)
     self.layout().addWidget(self.map, 0, 1, 8, 1)
     # search
     self.layout().addWidget(
         QtWidgets.QLabel(translate('PhotiniMap', 'Search:')), 0, 0)
     self.edit_box = QtWidgets.QComboBox()
     self.edit_box.setMinimumWidth(200)
     self.edit_box.setEditable(True)
     self.edit_box.setInsertPolicy(QtWidgets.QComboBox.NoInsert)
     self.edit_box.lineEdit().setPlaceholderText(
         translate('PhotiniMap', '<new search>'))
     self.edit_box.lineEdit().returnPressed.connect(self.search)
     self.edit_box.activated.connect(self.goto_search_result)
     self.clear_search()
     self.edit_box.setEnabled(False)
     self.layout().addWidget(self.edit_box, 1, 0)
     # latitude & longitude
     self.layout().addWidget(
         QtWidgets.QLabel(translate('PhotiniMap', 'Latitude, longitude:')),
         2, 0)
     self.coords = QtWidgets.QLineEdit()
     self.coords.editingFinished.connect(self.new_coords)
     self.coords.setEnabled(False)
     self.layout().addWidget(self.coords, 3, 0)
     # load map button
     self.load_map = QtWidgets.QPushButton(
         translate('PhotiniMap', '\nLoad map\n'))
     self.load_map.clicked.connect(self.initialise)
     self.layout().addWidget(self.load_map, 7, 0)
     # other init
     self.image_list.image_list_changed.connect(self.image_list_changed)
Esempio n. 11
0
 def diff_selected_metadata(self):
     dialog = QtWidgets.QDialog(parent=self)
     dialog.setLayout(QtWidgets.QVBoxLayout())
     dialog.setFixedSize(min(800,
                             self.window().width()),
                         min(400,
                             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)
         for key in ('title', 'description', 'keywords', 'rating',
                     'copyright', 'creator', '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 dialog.exec_() != 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()
Esempio n. 12
0
 def contextMenuEvent(self, event):
     menu = QtWidgets.QMenu(self)
     self.image_list.add_selected_actions(menu)
     menu.exec_(event.globalPos())
Esempio n. 13
0
 def data_form(self):
     widgets = {}
     scrollarea = QtWidgets.QScrollArea()
     scrollarea.setFrameStyle(QtWidgets.QFrame.NoFrame)
     scrollarea.setWidgetResizable(True)
     form = QtWidgets.QWidget()
     form.setLayout(QtWidgets.QFormLayout())
     # creator
     widgets['creator'] = SingleLineEdit(
         length_check=ImageMetadata.max_bytes('creator'),
         spell_check=True,
         multi_string=True)
     widgets['creator'].setToolTip(
         translate('OwnerTab',
                   'Enter the name of the person that created this image.'))
     form.layout().addRow(translate('OwnerTab', 'Creator'),
                          widgets['creator'])
     # creator title
     widgets['creator_title'] = SingleLineEdit(
         length_check=ImageMetadata.max_bytes('creator_title'),
         spell_check=True,
         multi_string=True)
     widgets['creator_title'].setToolTip(
         translate(
             'OwnerTab',
             'Enter the job title of the person listed in the Creator field.'
         ))
     form.layout().addRow(translate('OwnerTab', "Creator's Jobtitle"),
                          widgets['creator_title'])
     # credit line
     widgets['credit_line'] = SingleLineEdit(
         length_check=ImageMetadata.max_bytes('credit_line'),
         spell_check=True)
     widgets['credit_line'].setToolTip(
         translate(
             'OwnerTab',
             'Enter who should be credited when this image is published.'))
     form.layout().addRow(translate('OwnerTab', 'Credit Line'),
                          widgets['credit_line'])
     # copyright
     widgets['copyright'] = SingleLineEdit(
         length_check=ImageMetadata.max_bytes('copyright'),
         spell_check=True)
     widgets['copyright'].setToolTip(
         translate(
             'OwnerTab', 'Enter a notice on the current owner of the'
             ' copyright for this image, such as "©2008 Jane Doe".'))
     form.layout().addRow(translate('OwnerTab', 'Copyright Notice'),
                          widgets['copyright'])
     # usage terms
     widgets['usageterms'] = SingleLineEdit(
         length_check=ImageMetadata.max_bytes('usageterms'),
         spell_check=True)
     widgets['usageterms'].setToolTip(
         translate(
             'OwnerTab',
             'Enter instructions on how this image can legally be used.'))
     form.layout().addRow(translate('OwnerTab', 'Rights Usage Terms'),
                          widgets['usageterms'])
     # special instructions
     widgets['instructions'] = SingleLineEdit(
         length_check=ImageMetadata.max_bytes('instructions'),
         spell_check=True)
     widgets['instructions'].setToolTip(
         translate(
             'OwnerTab', 'Enter information about embargoes, or other'
             ' restrictions not covered by the Rights Usage Terms field.'))
     form.layout().addRow(translate('OwnerTab', 'Instructions'),
                          widgets['instructions'])
     ## contact information
     contact_group = QtWidgets.QGroupBox()
     contact_group.setLayout(QtWidgets.QFormLayout())
     # email addresses
     widgets['CiEmailWork'] = SingleLineEdit()
     widgets['CiEmailWork'].setToolTip(
         translate(
             'OwnerTab', 'Enter the work email address(es) for the person'
             ' that created this image, such as [email protected].'))
     contact_group.layout().addRow(translate('OwnerTab', 'Email(s)'),
                                   widgets['CiEmailWork'])
     # URLs
     widgets['CiUrlWork'] = SingleLineEdit()
     widgets['CiUrlWork'].setToolTip(
         translate(
             'OwnerTab', 'Enter the work Web URL(s) for the person'
             ' that created this image, such as http://www.domain.com/.'))
     contact_group.layout().addRow(translate('OwnerTab', 'Web URL(s)'),
                                   widgets['CiUrlWork'])
     # phone numbers
     widgets['CiTelWork'] = SingleLineEdit()
     widgets['CiTelWork'].setToolTip(
         translate(
             'OwnerTab', 'Enter the work phone number(s) for the person'
             ' that created this image, using the international format,'
             ' such as +1 (123) 456789.'))
     contact_group.layout().addRow(translate('OwnerTab', 'Phone(s)'),
                                   widgets['CiTelWork'])
     # address
     widgets['CiAdrExtadr'] = MultiLineEdit(
         length_check=ImageMetadata.max_bytes('contact_info'),
         spell_check=True)
     widgets['CiAdrExtadr'].setToolTip(
         translate('OwnerTab',
                   'Enter address for the person that created this image.'))
     contact_group.layout().addRow(translate('OwnerTab', 'Address'),
                                   widgets['CiAdrExtadr'])
     # city
     widgets['CiAdrCity'] = SingleLineEdit(spell_check=True)
     widgets['CiAdrCity'].setToolTip(
         translate(
             'OwnerTab', 'Enter the city for the address of the person'
             ' that created this image.'))
     contact_group.layout().addRow(translate('OwnerTab', 'City'),
                                   widgets['CiAdrCity'])
     # postcode
     widgets['CiAdrPcode'] = SingleLineEdit()
     widgets['CiAdrPcode'].setToolTip(
         translate(
             'OwnerTab',
             'Enter the postal code for the address of the person'
             ' that created this image.'))
     contact_group.layout().addRow(translate('OwnerTab', 'Postal Code'),
                                   widgets['CiAdrPcode'])
     # region
     widgets['CiAdrRegion'] = SingleLineEdit(spell_check=True)
     widgets['CiAdrRegion'].setToolTip(
         translate(
             'OwnerTab', 'Enter the state for the address of the person'
             ' that created this image.'))
     contact_group.layout().addRow(translate('OwnerTab', 'State/Province'),
                                   widgets['CiAdrRegion'])
     # country
     widgets['CiAdrCtry'] = SingleLineEdit(spell_check=True)
     widgets['CiAdrCtry'].setToolTip(
         translate(
             'OwnerTab',
             'Enter the country name for the address of the person'
             ' that created this image.'))
     contact_group.layout().addRow(translate('OwnerTab', 'Country'),
                                   widgets['CiAdrCtry'])
     form.layout().addRow(translate('OwnerTab', 'Contact Information'),
                          contact_group)
     scrollarea.setWidget(form)
     return scrollarea, widgets
Esempio n. 14
0
 def __init__(self, *arg, **kw):
     super(PicasaUploadConfig, self).__init__(*arg, **kw)
     self.setLayout(QtWidgets.QHBoxLayout())
     self.layout().setContentsMargins(0, 0, 0, 0)
     self.widgets = {}
     ## album details, left hand side
     album_group = QtWidgets.QGroupBox(self.tr('Collection / Album'))
     album_group.setLayout(QtWidgets.QHBoxLayout())
     album_form_left = QtWidgets.QFormLayout()
     album_form_left.setFieldGrowthPolicy(
         QtWidgets.QFormLayout.AllNonFixedFieldsGrow)
     album_group.layout().addLayout(album_form_left)
     # album title / selector
     self.albums = QtWidgets.QComboBox()
     self.albums.setEditable(True)
     self.albums.setInsertPolicy(QtWidgets.QComboBox.NoInsert)
     self.albums.activated.connect(self.switch_album)
     self.albums.lineEdit().editingFinished.connect(self.new_title)
     album_form_left.addRow(self.tr('Title'), self.albums)
     # album description
     self.widgets['description'] = MultiLineEdit(spell_check=True)
     self.widgets['description'].editingFinished.connect(
         self.new_album_details)
     album_form_left.addRow(self.tr('Description'),
                            self.widgets['description'])
     # album location
     self.widgets['location'] = QtWidgets.QLineEdit()
     self.widgets['location'].editingFinished.connect(
         self.new_album_details)
     album_form_left.addRow(self.tr('Place taken'),
                            self.widgets['location'])
     # album visibility
     self.widgets['access'] = QtWidgets.QComboBox()
     self.widgets['access'].addItem(self.tr('Public on the web'), 'public')
     self.widgets['access'].addItem(
         self.tr('Limited, anyone with the link'), 'private')
     self.widgets['access'].addItem(self.tr('Only you'), 'protected')
     self.widgets['access'].currentIndexChanged.connect(self.new_access)
     album_form_left.addRow(self.tr('Visibility'), self.widgets['access'])
     ## album buttons
     buttons = QtWidgets.QHBoxLayout()
     buttons.addStretch(stretch=60)
     album_form_left.addRow(buttons)
     # new album
     new_album_button = QtWidgets.QPushButton(self.tr('New album'))
     new_album_button.clicked.connect(self.new_album)
     buttons.addWidget(new_album_button, stretch=20)
     # delete album
     delete_album_button = QtWidgets.QPushButton(self.tr('Delete album'))
     delete_album_button.clicked.connect(self.delete_album)
     buttons.addWidget(delete_album_button, stretch=20)
     ## album details, right hand side
     album_form_right = QtWidgets.QFormLayout()
     album_form_right.setFieldGrowthPolicy(
         QtWidgets.QFormLayout.AllNonFixedFieldsGrow)
     album_group.layout().addLayout(album_form_right)
     # album date
     self.widgets['timestamp'] = QtWidgets.QDateEdit()
     self.widgets['timestamp'].setMinimumDateTime(
         QtCore.QDateTime.fromTime_t(0))
     self.widgets['timestamp'].setCalendarPopup(True)
     self.widgets['timestamp'].editingFinished.connect(
         self.new_album_details)
     album_form_right.addRow(self.tr('Date'), self.widgets['timestamp'])
     # album thumbnail
     self.album_thumb = QtWidgets.QLabel()
     self.album_thumb.setFixedWidth(160)
     album_form_right.addRow(self.album_thumb)
     self.layout().addWidget(album_group)
Esempio n. 15
0
 def search_terms(self):
     widget = QtWidgets.QLabel(self.tr('Search powered by Google'))
     scale_font(widget, 80)
     return '', widget
Esempio n. 16
0
 def __init__(self, image_list, parent=None):
     super(TabWidget, self).__init__(parent)
     app = QtWidgets.QApplication.instance()
     app.aboutToQuit.connect(self.shutdown)
     if gp and app.test_mode:
         self.gp_log = gp.check_result(gp.use_python_logging())
     self.config_store = app.config_store
     self.image_list = image_list
     self.setLayout(QtWidgets.QGridLayout())
     form = QtWidgets.QFormLayout()
     form.setFieldGrowthPolicy(QtWidgets.QFormLayout.AllNonFixedFieldsGrow)
     self.nm = NameMangler()
     self.file_data = {}
     self.file_list = []
     self.source = None
     self.file_reader = None
     self.file_writer = None
     # source selector
     box = QtWidgets.QHBoxLayout()
     box.setContentsMargins(0, 0, 0, 0)
     self.source_selector = QtWidgets.QComboBox()
     self.source_selector.currentIndexChanged.connect(self.new_source)
     box.addWidget(self.source_selector)
     refresh_button = QtWidgets.QPushButton(self.tr('refresh'))
     refresh_button.clicked.connect(self.refresh)
     box.addWidget(refresh_button)
     box.setStretch(0, 1)
     form.addRow(self.tr('Source'), box)
     # path format
     self.path_format = QtWidgets.QLineEdit()
     self.path_format.setValidator(PathFormatValidator())
     self.path_format.textChanged.connect(self.nm.new_format)
     self.path_format.editingFinished.connect(self.path_format_finished)
     form.addRow(self.tr('Target format'), self.path_format)
     # path example
     self.path_example = QtWidgets.QLabel()
     self.nm.new_example.connect(self.path_example.setText)
     form.addRow('=>', self.path_example)
     self.layout().addLayout(form, 0, 0)
     # file list
     self.file_list_widget = QtWidgets.QListWidget()
     self.file_list_widget.setSelectionMode(
         QtWidgets.QAbstractItemView.ExtendedSelection)
     self.file_list_widget.itemSelectionChanged.connect(self.selection_changed)
     self.layout().addWidget(self.file_list_widget, 1, 0)
     # selection buttons
     buttons = QtWidgets.QVBoxLayout()
     buttons.addStretch(1)
     self.selected_count = QtWidgets.QLabel()
     self.selection_changed()
     buttons.addWidget(self.selected_count)
     select_all = QtWidgets.QPushButton(self.tr('Select\nall'))
     select_all.clicked.connect(self.select_all)
     buttons.addWidget(select_all)
     select_new = QtWidgets.QPushButton(self.tr('Select\nnew'))
     select_new.clicked.connect(self.select_new)
     buttons.addWidget(select_new)
     self.copy_button = StartStopButton(self.tr('Copy\nphotos'),
                                        self.tr('Stop\nimport'))
     self.copy_button.click_start.connect(self.copy_selected)
     self.copy_button.click_stop.connect(self.stop_copy)
     buttons.addWidget(self.copy_button)
     self.layout().addLayout(buttons, 0, 1, 2, 1)
     # final initialisation
     self.image_list.sort_order_changed.connect(self.sort_file_list)
     path = os.path.expanduser('~/Pictures')
     if not os.path.isdir(path) and sys.platform == 'win32':
         try:
             import win32com.shell as ws
             path = ws.shell.SHGetFolderPath(
                 0, ws.shellcon.CSIDL_MYPICTURES, None, 0)
         except ImportError:
             pass
     self.path_format.setText(
         os.path.join(path, '%Y', '%Y_%m_%d', '{name}'))
     self.refresh()
     self.list_files()
Esempio n. 17
0
 def __init__(self, images, *arg, **kw):
     super(NewLensDialog, self).__init__(*arg, **kw)
     self.setWindowTitle(self.tr('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())
     # 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(250)
     panel.layout().addRow(self.tr('Model name'), self.lens_model)
     # maker
     self.lens_make = QtWidgets.QLineEdit()
     panel.layout().addRow(self.tr("Maker's name"), self.lens_make)
     # serial number
     self.lens_serial = QtWidgets.QLineEdit()
     panel.layout().addRow(self.tr('Serial number'), self.lens_serial)
     ## spec has four items
     self.lens_spec = {}
     # min focal length
     self.lens_spec['min_fl'] = QtWidgets.QLineEdit()
     self.lens_spec['min_fl'].setValidator(
         QtGui.QDoubleValidator(bottom=0.0))
     panel.layout().addRow(self.tr('Minimum focal length (mm)'),
                           self.lens_spec['min_fl'])
     # min focal length aperture
     self.lens_spec['min_fl_fn'] = QtWidgets.QLineEdit()
     self.lens_spec['min_fl_fn'].setValidator(DoubleValidator(bottom=0.0))
     panel.layout().addRow(self.tr('Aperture at min. focal length f/'),
                           self.lens_spec['min_fl_fn'])
     # max focal length
     self.lens_spec['max_fl'] = QtWidgets.QLineEdit()
     self.lens_spec['max_fl'].setValidator(
         QtGui.QDoubleValidator(bottom=0.0))
     panel.layout().addRow(self.tr('Maximum focal length (mm)'),
                           self.lens_spec['max_fl'])
     # max focal length aperture
     self.lens_spec['max_fl_fn'] = QtWidgets.QLineEdit()
     self.lens_spec['max_fl_fn'].setValidator(DoubleValidator(bottom=0.0))
     panel.layout().addRow(self.tr('Aperture at max. focal length f/'),
                           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.value)
         if image.metadata.lens_make:
             self.lens_make.setText(image.metadata.lens_make.value)
         if image.metadata.lens_serial:
             self.lens_serial.setText(image.metadata.lens_serial.value)
         spec = image.metadata.lens_spec
         for key in self.lens_spec:
             if spec and spec.value[key]:
                 self.lens_spec[key].setText('{:g}'.format(
                     float(spec.value[key])))
Esempio n. 18
0
 def __init__(self, image_list, *arg, **kw):
     super(Technical, 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(self.tr('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(
         self.tr("Link 'taken' and 'digitised'"))
     self.link_widget['digitised', 'modified'].setText(
         self.tr("Link 'digitised' and 'modified'"))
     # add to layout
     date_group.layout().addRow(self.tr('Taken'),
                                self.date_widget['taken'])
     date_group.layout().addRow('', self.link_widget['taken', 'digitised'])
     date_group.layout().addRow(self.tr('Digitised'),
                                self.date_widget['digitised'])
     date_group.layout().addRow('', self.link_widget['digitised', 'modified'])
     date_group.layout().addRow(self.tr('Modified'),
                                self.date_widget['modified'])
     # offset
     self.offset_widget = OffsetWidget()
     self.offset_widget.apply_offset.connect(self.apply_offset)
     date_group.layout().addRow(self.tr('Adjust times'), self.offset_widget)
     self.layout().addWidget(date_group)
     # other
     other_group = QtWidgets.QGroupBox(self.tr('Other'))
     other_group.setLayout(QtWidgets.QFormLayout())
     other_group.layout().setFieldGrowthPolicy(
         QtWidgets.QFormLayout.AllNonFixedFieldsGrow)
     # orientation
     self.widgets['orientation'] = DropdownEdit()
     self.widgets['orientation'].add_item(self.tr('normal'), 1)
     self.widgets['orientation'].add_item(self.tr('rotate -90'), 6)
     self.widgets['orientation'].add_item(self.tr('rotate +90'), 8)
     self.widgets['orientation'].add_item(self.tr('rotate 180'), 3)
     self.widgets['orientation'].add_item(self.tr('reflect left-right'), 2)
     self.widgets['orientation'].add_item(self.tr('reflect top-bottom'), 4)
     self.widgets['orientation'].add_item(self.tr('reflect tr-bl'), 5)
     self.widgets['orientation'].add_item(self.tr('reflect tl-br'), 7)
     self.widgets['orientation'].new_value.connect(self.new_orientation)
     other_group.layout().addRow(
         self.tr('Orientation'), self.widgets['orientation'])
     # lens model
     self.widgets['lens_model'] = DropdownEdit()
     self.widgets['lens_model'].setMinimumWidth(
         self.widgets['lens_model'].fontMetrics().width('x' * 30))
     self.widgets['lens_model'].setContextMenuPolicy(Qt.CustomContextMenu)
     self.widgets['lens_model'].add_item(
         self.tr('<define new lens>'), '<add lens>')
     for model in self.lens_data.lenses:
         self.widgets['lens_model'].add_item(model, model)
     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(
         self.tr('Lens model'), self.widgets['lens_model'])
     # lens specification
     self.widgets['lens_spec'] = LensSpecWidget()
     other_group.layout().addRow(
         self.tr('Lens details'), self.widgets['lens_spec'])
     # focal length
     self.widgets['focal_length'] = NumberEdit()
     self.widgets['focal_length'].setValidator(DoubleValidator())
     self.widgets['focal_length'].validator().setBottom(0.1)
     self.widgets['focal_length'].new_value.connect(self.new_focal_length)
     other_group.layout().addRow(
         self.tr('Focal length (mm)'), self.widgets['focal_length'])
     # 35mm equivalent focal length
     self.widgets['focal_length_35'] = NumberEdit()
     self.widgets['focal_length_35'].setValidator(IntValidator())
     self.widgets['focal_length_35'].validator().setBottom(1)
     self.widgets['focal_length_35'].new_value.connect(self.new_focal_length_35)
     other_group.layout().addRow(
         self.tr('35mm equiv (mm)'), self.widgets['focal_length_35'])
     # aperture
     self.widgets['aperture'] = NumberEdit()
     self.widgets['aperture'].setValidator(DoubleValidator())
     self.widgets['aperture'].validator().setBottom(0.1)
     self.widgets['aperture'].new_value.connect(self.new_aperture)
     other_group.layout().addRow(
         self.tr('Aperture f/'), self.widgets['aperture'])
     self.layout().addWidget(other_group, stretch=1)
     # disable until an image is selected
     self.setEnabled(False)
Esempio n. 19
0
 def __init__(self, *arg, **kw):
     super(FlickrUploadConfig, self).__init__(*arg, **kw)
     self.setLayout(QtWidgets.QGridLayout())
     self.layout().setContentsMargins(0, 0, 0, 0)
     # privacy settings
     self.privacy = {}
     privacy_group = QtWidgets.QGroupBox(
         translate('FlickrTab', 'Who can see the photos?'))
     privacy_group.setLayout(QtWidgets.QVBoxLayout())
     self.privacy['private'] = QtWidgets.QRadioButton(
         translate('FlickrTab', 'Only you'))
     privacy_group.layout().addWidget(self.privacy['private'])
     ff_group = QtWidgets.QGroupBox()
     ff_group.setFlat(True)
     ff_group.setLayout(QtWidgets.QVBoxLayout())
     ff_group.layout().setContentsMargins(10, 0, 0, 0)
     self.privacy['friends'] = QtWidgets.QCheckBox(
         translate('FlickrTab', 'Your friends'))
     ff_group.layout().addWidget(self.privacy['friends'])
     self.privacy['family'] = QtWidgets.QCheckBox(
         translate('FlickrTab', 'Your family'))
     ff_group.layout().addWidget(self.privacy['family'])
     privacy_group.layout().addWidget(ff_group)
     self.privacy['public'] = QtWidgets.QRadioButton(
         translate('FlickrTab', 'Anyone'))
     self.privacy['public'].toggled.connect(self.enable_ff)
     self.privacy['public'].setChecked(True)
     privacy_group.layout().addWidget(self.privacy['public'])
     self.hidden = QtWidgets.QCheckBox(
         translate('FlickrTab', 'Hidden from search'))
     privacy_group.layout().addWidget(self.hidden)
     privacy_group.layout().addStretch(1)
     self.layout().addWidget(privacy_group, 0, 0, 3, 1)
     # content type
     self.content_type = {}
     content_group = QtWidgets.QGroupBox(
         translate('FlickrTab', 'Content type'))
     content_group.setLayout(QtWidgets.QVBoxLayout())
     self.content_type['photo'] = QtWidgets.QRadioButton(
         translate('FlickrTab', 'Photo'))
     self.content_type['photo'].setChecked(True)
     content_group.layout().addWidget(self.content_type['photo'])
     self.content_type['screenshot'] = QtWidgets.QRadioButton(
         translate('FlickrTab', 'Screenshot'))
     content_group.layout().addWidget(self.content_type['screenshot'])
     self.content_type['other'] = QtWidgets.QRadioButton(
         translate('FlickrTab', 'Art/Illustration'))
     content_group.layout().addWidget(self.content_type['other'])
     content_group.layout().addStretch(1)
     self.layout().addWidget(content_group, 0, 1)
     # synchronise metadata
     self.sync_button = QtWidgets.QPushButton(
         translate('FlickrTab', 'Synchronise'))
     self.sync_button.clicked.connect(self.sync_metadata)
     self.layout().addWidget(self.sync_button, 1, 1)
     # create new set
     new_set_button = QtWidgets.QPushButton(
         translate('FlickrTab', 'New album'))
     new_set_button.clicked.connect(self.new_set)
     self.layout().addWidget(new_set_button, 2, 1)
     # list of sets widget
     sets_group = QtWidgets.QGroupBox(
         translate('FlickrTab', 'Add to albums'))
     sets_group.setLayout(QtWidgets.QVBoxLayout())
     scrollarea = QtWidgets.QScrollArea()
     scrollarea.setFrameStyle(QtWidgets.QFrame.NoFrame)
     scrollarea.setStyleSheet("QScrollArea { background-color: transparent }")
     self.sets_widget = QtWidgets.QWidget()
     self.sets_widget.setLayout(QtWidgets.QVBoxLayout())
     self.sets_widget.layout().setSpacing(0)
     self.sets_widget.layout().setSizeConstraint(
         QtWidgets.QLayout.SetMinAndMaxSize)
     scrollarea.setWidget(self.sets_widget)
     self.sets_widget.setAutoFillBackground(False)
     sets_group.layout().addWidget(scrollarea)
     self.layout().addWidget(sets_group, 0, 2, 3, 1)
     self.layout().setColumnStretch(2, 1)
Esempio n. 20
0
 def __init__(self, image_list, parent=None):
     super(PhotiniMap, self).__init__(parent)
     self.app = QtWidgets.QApplication.instance()
     self.image_list = image_list
     name = self.__module__.split('.')[-1]
     self.script_dir = pkg_resources.resource_filename(
         'photini', 'data/' + name + '/')
     self.drag_icon = QtGui.QPixmap(
         os.path.join(self.script_dir, '../map_pin_grey.png'))
     self.drag_hotspot = 11, 35
     self.search_string = None
     self.map_loaded = 0     # not loaded
     self.marker_info = {}
     self.map_status = {}
     self.dropped_images = []
     self.geocoder = self.get_geocoder()
     self.gpx_ids = []
     self.widgets = {}
     self.setLayout(QtWidgets.QHBoxLayout())
     ## left side
     left_side = QtWidgets.QGridLayout()
     # latitude & longitude
     self.widgets['latlon'] = LatLongDisplay(self.image_list)
     left_side.addWidget(self.widgets['latlon'].label, 0, 0)
     self.widgets['latlon'].changed.connect(self.new_coords)
     left_side.addWidget(self.widgets['latlon'], 0, 1)
     # altitude
     label = QtWidgets.QLabel(translate('MapTabsAll', 'Altitude'))
     label.setAlignment(Qt.AlignRight)
     left_side.addWidget(label, 1, 0)
     self.widgets['altitude'] = DoubleSpinBox()
     self.widgets['altitude'].setSuffix(' m')
     self.widgets['altitude'].new_value.connect(self.new_altitude)
     left_side.addWidget(self.widgets['altitude'], 1, 1)
     if hasattr(self.geocoder, 'get_altitude'):
         self.widgets['get_altitude'] = QtWidgets.QPushButton(
             translate('MapTabsAll', 'Get altitude from map'))
         self.widgets['get_altitude'].clicked.connect(self.get_altitude)
         left_side.addWidget(self.widgets['get_altitude'], 2, 1)
     else:
         self.widgets['get_altitude'] = None
     # search
     label = QtWidgets.QLabel(translate('MapTabsAll', 'Search'))
     label.setAlignment(Qt.AlignRight)
     left_side.addWidget(label, 3, 0)
     self.widgets['search'] = ComboBox()
     self.widgets['search'].setEditable(True)
     self.widgets['search'].setInsertPolicy(QtWidgets.QComboBox.NoInsert)
     self.widgets['search'].lineEdit().setPlaceholderText(
         translate('MapTabsAll', '<new search>'))
     self.widgets['search'].lineEdit().returnPressed.connect(self.search)
     self.widgets['search'].activated.connect(self.goto_search_result)
     self.clear_search()
     self.widgets['search'].setEnabled(False)
     left_side.addWidget(self.widgets['search'], 3, 1)
     # search terms and conditions
     for n, widget in enumerate(self.geocoder.search_terms()):
         left_side.addWidget(widget, n+4, 0, 1, 2)
     left_side.setColumnStretch(1, 1)
     left_side.setRowStretch(7, 1)
     # GPX importer
     if self.app.gpx_importer:
         button = QtWidgets.QPushButton(
             translate('MapTabsAll', 'Load GPX file'))
         button.clicked.connect(self.load_gpx)
         left_side.addWidget(button, 8, 1)
         self.widgets['set_from_gpx'] = QtWidgets.QPushButton(
             translate('MapTabsAll', 'Set coords from GPX'))
         self.widgets['set_from_gpx'].setEnabled(False)
         self.widgets['set_from_gpx'].clicked.connect(self.set_from_gpx)
         left_side.addWidget(self.widgets['set_from_gpx'], 9, 1)
         self.widgets['clear_gpx'] = QtWidgets.QPushButton(
             translate('MapTabsAll', 'Remove GPX data'))
         self.widgets['clear_gpx'].setEnabled(False)
         self.widgets['clear_gpx'].clicked.connect(self.clear_gpx)
         left_side.addWidget(self.widgets['clear_gpx'], 10, 1)
     self.layout().addLayout(left_side)
     # map
     # create handler for calls from JavaScript
     self.call_handler = CallHandler(parent=self)
     self.widgets['map'] = MapWebView(self.call_handler)
     self.widgets['map'].drop_text.connect(self.drop_text)
     self.widgets['map'].setAcceptDrops(False)
     self.layout().addWidget(self.widgets['map'])
     self.layout().setStretch(1, 1)
     # other init
     self.image_list.image_list_changed.connect(self.image_list_changed)
Esempio n. 21
0
 def _find_local(self, photo, unknowns):
     granularity = int(photo['datetakengranularity'])
     min_taken_date = datetime.strptime(
         photo['datetaken'], '%Y-%m-%d %H:%M:%S')
     if granularity <= 0:
         max_taken_date = min_taken_date + timedelta(seconds=1)
     elif granularity <= 4:
         max_taken_date = min_taken_date + timedelta(days=31)
     else:
         max_taken_date = min_taken_date + timedelta(days=366)
     candidates = []
     for candidate in unknowns:
         if not candidate.metadata.date_taken:
             continue
         date_taken = candidate.metadata.date_taken['datetime']
         if date_taken < min_taken_date or date_taken > max_taken_date:
             continue
         candidates.append(candidate)
     if not candidates:
         return None
     rsp = requests.get(photo['url_t'])
     if rsp.status_code == 200:
         flickr_icon = rsp.content
     else:
         logger.error('HTTP error %d (%s)', rsp.status_code, photo['url_t'])
         return None
     # get user to choose matching image file
     dialog = QtWidgets.QDialog(parent=self)
     dialog.setWindowTitle(translate('FlickrTab', 'Select an image'))
     dialog.setLayout(QtWidgets.QFormLayout())
     dialog.layout().setFieldGrowthPolicy(
         QtWidgets.QFormLayout.AllNonFixedFieldsGrow)
     pixmap = QtGui.QPixmap()
     pixmap.loadFromData(flickr_icon)
     label = QtWidgets.QLabel()
     label.setPixmap(pixmap)
     dialog.layout().addRow(label, QtWidgets.QLabel(translate(
         'FlickrTab', 'Which image file matches\nthis picture on Flickr?')))
     divider = QtWidgets.QFrame()
     divider.setFrameStyle(QtWidgets.QFrame.HLine)
     dialog.layout().addRow(divider)
     buttons = {}
     for candidate in candidates:
         label = QtWidgets.QLabel()
         pixmap = candidate.image.pixmap()
         if pixmap:
             label.setPixmap(pixmap)
         else:
             label.setText(candidate.image.text())
         button = QtWidgets.QPushButton(
             os.path.basename(candidate.path))
         button.setToolTip(candidate.path)
         button.setCheckable(True)
         button.clicked.connect(dialog.accept)
         dialog.layout().addRow(label, button)
         buttons[button] = candidate
     button = QtWidgets.QPushButton(translate('FlickrTab', 'No match'))
     button.setDefault(True)
     button.clicked.connect(dialog.reject)
     dialog.layout().addRow('', button)
     if dialog.exec_() == QtWidgets.QDialog.Accepted:
         for button, candidate in buttons.items():
             if button.isChecked():
                 return candidate
     return None
Esempio n. 22
0
 def do_import(self, parent):
     args = [
         parent,
         self.tr('Import GPX file'),
         parent.app.config_store.get('paths', 'gpx', ''),
         self.tr("GPX files (*.gpx *.GPX *.Gpx);;All files (*)")
     ]
     if eval(parent.app.config_store.get('pyqt', 'native_dialog', 'True')):
         pass
     else:
         args += [None, QtWidgets.QFileDialog.DontUseNativeDialog]
     path = QtWidgets.QFileDialog.getOpenFileName(*args)
     path = path[0]
     if not path:
         return
     parent.app.config_store.set('paths', 'gpx',
                                 os.path.dirname(os.path.abspath(path)))
     # get user options
     config_store = QtWidgets.QApplication.instance().config_store
     dialog = QtWidgets.QDialog(parent=parent)
     dialog.setWindowTitle(self.tr('GPX options'))
     dialog.setLayout(QtWidgets.QFormLayout())
     max_interval = QtWidgets.QSpinBox()
     max_interval.setRange(60, 300)
     max_interval.setValue(
         int(config_store.get('gpx_importer', 'interval', '120')))
     max_interval.setSuffix(self.tr(' secs'))
     dialog.layout().addRow(self.tr('Max time between points'),
                            max_interval)
     max_dilution = QtWidgets.QDoubleSpinBox()
     max_dilution.setRange(1.0, 100.0)
     max_dilution.setValue(
         float(config_store.get('gpx_importer', 'dilution', '2.5')))
     max_dilution.setSingleStep(0.1)
     dialog.layout().addRow(self.tr('Max dilution of precision'),
                            max_dilution)
     if hasattr(parent.tabs.currentWidget(), 'plot_track'):
         plot_track = QtWidgets.QCheckBox()
         plot_track.setChecked(
             bool(config_store.get('gpx_importer', 'plot', 'True')))
         dialog.layout().addRow(self.tr('Plot track on map'), plot_track)
     else:
         plot_track = False
     button_box = QtWidgets.QDialogButtonBox(QtWidgets.QDialogButtonBox.Ok)
     button_box.accepted.connect(dialog.accept)
     dialog.layout().addWidget(button_box)
     dialog.exec_()
     max_interval = max_interval.value()
     max_dilution = max_dilution.value()
     config_store.set('gpx_importer', 'interval', max_interval)
     config_store.set('gpx_importer', 'dilution', max_dilution)
     if plot_track:
         plot_track = plot_track.isChecked()
         config_store.set('gpx_importer', 'plot', plot_track)
     # make a list of all points in the file
     points = []
     discards = 0
     for p in self.read_file(path):
         if p.horizontal_dilution and p.horizontal_dilution > max_dilution:
             discards += 1
             continue
         time_stamp = p.time
         if time_stamp.tzinfo is not None:
             # convert timestamp to UTC
             utc_offset = time_stamp.utcoffset()
             time_stamp = (time_stamp - utc_offset).replace(tzinfo=None)
         # add point to list
         points.append((time_stamp, p.latitude, p.longitude))
     if discards:
         logger.warning('Discarded %d low accuracy points', discards)
     if not points:
         logger.warning('No points found in file "%s"', path)
         return
     logger.warning('Using %d points', len(points))
     # sort points by timestamp
     points.sort(key=lambda x: x[0])
     # display on map
     if plot_track:
         # divide points into contiguous tracks
         tracks = []
         t = []
         for p in points:
             if t and (p[0] - t[-1][0]).total_seconds() > max_interval:
                 tracks.append(t)
                 t = []
             t.append(p)
         if t:
             tracks.append(t)
         parent.tabs.currentWidget().plot_track(tracks)
     # set image coordinates
     max_interval = max_interval / 2.0
     for image in parent.image_list.get_selected_images():
         if not image.metadata.date_taken:
             continue
         time_stamp = image.metadata.date_taken.to_utc()
         if len(points) < 2:
             lo, hi = 0, 0
         elif time_stamp < points[0][0]:
             lo, hi = 0, 1
         elif time_stamp > points[-1][0]:
             lo, hi = -2, -1
         else:
             # binary search for points with nearest timestamps
             lo, hi = 0, len(points) - 1
             while hi - lo > 1:
                 mid = (lo + hi) // 2
                 if time_stamp >= points[mid][0]:
                     lo = mid
                 elif time_stamp <= points[mid][0]:
                     hi = mid
         # use linear interpolation (or extrapolation) to set lat & long
         dt_lo = (time_stamp - points[lo][0]).total_seconds()
         dt_hi = (time_stamp - points[hi][0]).total_seconds()
         if abs(dt_lo) > max_interval and abs(dt_hi) > max_interval:
             logger.info('No point for time %s', image.metadata.date_taken)
             continue
         if dt_lo == dt_hi:
             beta = 0.5
         else:
             beta = dt_lo / (dt_lo - dt_hi)
         lat = points[lo][1] + (beta * (points[hi][1] - points[lo][1]))
         lng = points[lo][2] + (beta * (points[hi][2] - points[lo][2]))
         image.metadata.latlong = lat, lng
     parent.image_list.emit_selection()
Esempio n. 23
0
 def __init__(self, parent):
     QtWidgets.QDialog.__init__(self, parent)
     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())
     # 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 = QtWidgets.QLineEdit()
     self.copyright_name.setText(
         self.config_store.get('user', 'copyright_name', ''))
     self.copyright_name.setMinimumWidth(200)
     panel.layout().addRow(self.tr('Copyright holder'), self.copyright_name)
     # creator name
     self.creator_name = QtWidgets.QLineEdit()
     self.creator_name.setText(
         self.config_store.get('user', 'creator_name', ''))
     panel.layout().addRow(self.tr('Creator'), self.creator_name)
     # reset flickr
     self.reset_flickr = QtWidgets.QCheckBox()
     panel.layout().addRow(self.tr('Disconnect from Flickr'),
                           self.reset_flickr)
     if not keyring or keyring.get_password('photini', 'flickr') is None:
         self.reset_flickr.setDisabled(True)
         panel.layout().labelForField(self.reset_flickr).setDisabled(True)
     # reset picasa
     self.reset_picasa = QtWidgets.QCheckBox()
     panel.layout().addRow(self.tr('Disconnect from Google Photos'),
                           self.reset_picasa)
     if not keyring or keyring.get_password('photini', 'picasa') is None:
         self.reset_picasa.setDisabled(True)
         panel.layout().labelForField(self.reset_picasa).setDisabled(True)
     # reset facebook
     self.reset_facebook = QtWidgets.QCheckBox()
     panel.layout().addRow(self.tr('Disconnect from Facebook'),
                           self.reset_facebook)
     if not keyring or keyring.get_password('photini', 'facebook') is None:
         self.reset_facebook.setDisabled(True)
         panel.layout().labelForField(self.reset_facebook).setDisabled(True)
     # IPTC data
     force_iptc = eval(self.config_store.get('files', 'force_iptc',
                                             'False'))
     self.write_iptc = QtWidgets.QCheckBox(self.tr('Write unconditionally'))
     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'), self.write_if)
     # add panel to scroll area after its size is known
     scroll_area.setWidget(panel)
Esempio n. 24
0
 def show_terms(self):
     # return widgets to display map terms and conditions
     load_tou = QtWidgets.QPushButton(self.tr('Terms of Use'))
     load_tou.clicked.connect(self.load_tou)
     yield load_tou
Esempio n. 25
0
def main(argv=None):
    if argv:
        sys.argv = argv
    # let PyQt handle its options (need at least one argument after options)
    sys.argv.append('xxx')
    app = QtWidgets.QApplication(sys.argv)
    del sys.argv[-1]
    # install translations
    if qt_version_info < (5, 0):
        QtCore.QTextCodec.setCodecForTr(
            QtCore.QTextCodec.codecForName('utf-8'))
    # English translation as a fallback (to get correct plurals)
    lang_dir = pkg_resources.resource_filename('photini', 'data/lang')
    translator = QtCore.QTranslator(parent=app)
    if translator.load('photini.en', lang_dir):
        app.installTranslator(translator)
        translator = QtCore.QTranslator(parent=app)
    # localised translation, if it exists
    locale = QtCore.QLocale.system()
    if translator.load(locale, 'photini', '.', lang_dir):
        app.installTranslator(translator)
        translator = QtCore.QTranslator(parent=app)
    # Qt's own translation, e.g. for 'apply' or 'cancel' buttons
    if qt_version_info < (5, 0):
        if translator.load(
                locale, 'qt', '_',
                QtCore.QLibraryInfo.location(
                    QtCore.QLibraryInfo.TranslationsPath)):
            app.installTranslator(translator)
    # parse remaining arguments
    version = 'Photini ' + __version__ + ', build ' + build
    version += '\n  Python ' + sys.version
    version += '\n  ' + gi_version
    version += '\n  PyQt {}, Qt {}, using {}'.format(
        QtCore.PYQT_VERSION_STR, QtCore.QT_VERSION_STR,
        ('QtWebKit', 'QtWebEngine')[using_qtwebengine])
    if spelling_version:
        version += '\n  ' + spelling_version
    if FlickrUploader:
        from photini.flickr import flickr_version
        version += '\n  ' + flickr_version
    version += '\n  available styles: {}'.format(', '.join(
        QtWidgets.QStyleFactory.keys()))
    version += '\n  using style: {}'.format(
        QtWidgets.QApplication.style().objectName())
    parser = OptionParser(usage=six.text_type(
        QtCore.QCoreApplication.translate(
            'main', 'Usage: %prog [options] [file_name, ...]')),
                          version=version,
                          description=six.text_type(
                              QtCore.QCoreApplication.translate(
                                  'main', 'Photini photo metadata editor')))
    parser.add_option('-t',
                      '--test',
                      action='store_true',
                      help=six.text_type(
                          QtCore.QCoreApplication.translate(
                              'main', 'test new features or API versions')))
    parser.add_option('-v',
                      '--verbose',
                      action='count',
                      default=0,
                      help=six.text_type(
                          QtCore.QCoreApplication.translate(
                              'main', 'increase number of logging messages')))
    options, args = parser.parse_args()
    # create GUI and run application event loop
    main = MainWindow(options, args)
    main.show()
    return app.exec_()
Esempio n. 26
0
 def __init__(self, image_list, parent=None):
     super(TabWidget, self).__init__(parent)
     self.app = QtWidgets.QApplication.instance()
     self.app.aboutToQuit.connect(self.stop_copy)
     if gp and self.app.options.test:
         self.gp_log = gp.check_result(gp.use_python_logging())
     self.config_store = self.app.config_store
     self.image_list = image_list
     self.setLayout(QtWidgets.QGridLayout())
     form = QtWidgets.QFormLayout()
     form.setFieldGrowthPolicy(QtWidgets.QFormLayout.AllNonFixedFieldsGrow)
     self.nm = NameMangler()
     self.file_data = {}
     self.file_list = []
     self.source = None
     self.file_copier = None
     self.updating = QtCore.QMutex()
     # source selector
     box = QtWidgets.QHBoxLayout()
     box.setContentsMargins(0, 0, 0, 0)
     self.source_selector = QtWidgets.QComboBox()
     self.source_selector.currentIndexChanged.connect(self.new_source)
     self.source_selector.setContextMenuPolicy(Qt.CustomContextMenu)
     self.source_selector.customContextMenuRequested.connect(
         self.remove_folder)
     box.addWidget(self.source_selector)
     refresh_button = QtWidgets.QPushButton(
         translate('ImporterTab', 'refresh'))
     refresh_button.clicked.connect(self.refresh)
     box.addWidget(refresh_button)
     box.setStretch(0, 1)
     form.addRow(translate('ImporterTab', 'Source'), box)
     # update config
     self.config_store.delete('importer', 'folders')
     for section in self.config_store.config.sections():
         if not section.startswith('importer'):
             continue
         path_format = self.config_store.get(section, 'path_format')
         if not (path_format and '(' in path_format):
             continue
         path_format = path_format.replace('(', '{').replace(')', '}')
         self.config_store.set(section, 'path_format', path_format)
     # path format
     self.path_format = QtWidgets.QLineEdit()
     self.path_format.setValidator(PathFormatValidator())
     self.path_format.textChanged.connect(self.nm.new_format)
     self.path_format.editingFinished.connect(self.path_format_finished)
     form.addRow(translate('ImporterTab', 'Target format'),
                 self.path_format)
     # path example
     self.path_example = QtWidgets.QLabel()
     self.nm.new_example.connect(self.path_example.setText)
     form.addRow('=>', self.path_example)
     self.layout().addLayout(form, 0, 0)
     # file list
     self.file_list_widget = QtWidgets.QListWidget()
     self.file_list_widget.setSelectionMode(
         QtWidgets.QAbstractItemView.ExtendedSelection)
     self.file_list_widget.itemSelectionChanged.connect(
         self.selection_changed)
     self.layout().addWidget(self.file_list_widget, 1, 0)
     # selection buttons
     buttons = QtWidgets.QVBoxLayout()
     buttons.addStretch(1)
     self.selected_count = QtWidgets.QLabel()
     buttons.addWidget(self.selected_count)
     select_all = QtWidgets.QPushButton(
         translate('ImporterTab', 'Select\nall'))
     select_all.clicked.connect(self.select_all)
     buttons.addWidget(select_all)
     select_new = QtWidgets.QPushButton(
         translate('ImporterTab', 'Select\nnew'))
     select_new.clicked.connect(self.select_new)
     buttons.addWidget(select_new)
     # copy buttons
     self.move_button = StartStopButton(
         translate('ImporterTab', 'Move\nphotos'),
         translate('ImporterTab', 'Stop\nmove'))
     self.move_button.click_start.connect(self.move_selected)
     self.move_button.click_stop.connect(self.stop_copy)
     buttons.addWidget(self.move_button)
     self.copy_button = StartStopButton(
         translate('ImporterTab', 'Copy\nphotos'),
         translate('ImporterTab', 'Stop\ncopy'))
     self.copy_button.click_start.connect(self.copy_selected)
     self.copy_button.click_stop.connect(self.stop_copy)
     buttons.addWidget(self.copy_button)
     self.layout().addLayout(buttons, 0, 1, 2, 1)
     self.selection_changed()
     # final initialisation
     self.image_list.sort_order_changed.connect(self.sort_file_list)
     path = QtCore.QStandardPaths.writableLocation(
         QtCore.QStandardPaths.PicturesLocation)
     self.path_format.setText(os.path.join(path, '%Y', '%Y_%m_%d',
                                           '{name}'))
Esempio n. 27
0
 def __init__(self, path, image_list, thumb_size=80, *arg, **kw):
     super(Image, self).__init__(*arg, **kw)
     self.path = path
     self.image_list = image_list
     self.name, ext = os.path.splitext(os.path.basename(self.path))
     self.selected = False
     self.thumb_size = thumb_size
     # read image
     with open(self.path, 'rb') as pf:
         image_data = pf.read()
     # read metadata
     self.metadata = Metadata(
         self.path, image_data, new_status=self.show_status)
     # set file type
     ext = ext.lower()
     self.file_type = imghdr.what(self.path) or 'raw'
     if self.file_type == 'tiff' and ext not in ('.tif', '.tiff'):
         self.file_type = 'raw'
     # make 'master' thumbnail
     self.pixmap = QtGui.QPixmap()
     self.pixmap.loadFromData(image_data)
     unrotate = self.file_type == 'raw'
     if self.pixmap.isNull():
         # image read failed so attempt to use exif thumbnail
         thumb = self.metadata.get_exif_thumbnail()
         if thumb:
             self.pixmap.loadFromData(bytearray(thumb))
             unrotate = False
     if not self.pixmap.isNull():
         if max(self.pixmap.width(), self.pixmap.height()) > 450:
             # store a scaled down version of image to save memory
             self.pixmap = self.pixmap.scaled(
                 300, 300, Qt.KeepAspectRatio, Qt.SmoothTransformation)
         if unrotate:
             # loading preview which is already re-oriented
             orientation = self.metadata.orientation
             if orientation and orientation.value > 1:
                 # need to unrotate and or unreflect image
                 transform = QtGui.QTransform()
                 if orientation.value in (3, 4):
                     transform = transform.rotate(180.0)
                 elif orientation.value in (5, 6):
                     transform = transform.rotate(-90.0)
                 elif orientation.value in (7, 8):
                     transform = transform.rotate(90.0)
                 if orientation.value in (2, 4, 5, 7):
                     transform = transform.scale(-1.0, 1.0)
                 self.pixmap = self.pixmap.transformed(transform)
     # sub widgets
     layout = QtWidgets.QGridLayout()
     layout.setSpacing(0)
     layout.setContentsMargins(3, 3, 3, 3)
     self.setLayout(layout)
     self.setToolTip(self.path)
     # label to display image
     self.image = QtWidgets.QLabel()
     self.image.setAlignment(Qt.AlignHCenter | Qt.AlignVCenter)
     layout.addWidget(self.image, 0, 0, 1, 2)
     # label to display file name
     self.label = QtWidgets.QLabel()
     self.label.setAlignment(Qt.AlignRight)
     self.label.setStyleSheet("QLabel { font-size: 12px }")
     layout.addWidget(self.label, 1, 1)
     # label to display status
     self.status = QtWidgets.QLabel()
     self.status.setAlignment(Qt.AlignLeft)
     self.status.setStyleSheet("QLabel { font-size: 12px }")
     self.status.setFont(QtGui.QFont("Dejavu Sans"))
     if not self.status.fontInfo().exactMatch():
         # probably on Windows, try a different font
         self.status.setFont(QtGui.QFont("Segoe UI Symbol"))
     layout.addWidget(self.status, 1, 0)
     self.setFrameStyle(QtWidgets.QFrame.Panel | QtWidgets.QFrame.Plain)
     self.setObjectName("thumbnail")
     self.set_selected(False)
     self.show_status(False)
     self._set_thumb_size(self.thumb_size)
Esempio n. 28
0
 def __init__(self, image_list, parent=None):
     super(PhotiniMap, self).__init__(parent)
     self.logger = logging.getLogger(self.__class__.__name__)
     self.app = QtWidgets.QApplication.instance()
     self.config_store = self.app.config_store
     self.image_list = image_list
     self.script_dir = pkg_resources.resource_filename(
         'photini', 'data/' + self.__class__.__name__.lower() + '/')
     self.drag_icon = QtGui.QPixmap(
         os.path.join(self.script_dir, 'grey_marker.png'))
     self.search_string = None
     self.map_loaded = False
     self.marker_images = {}
     self.map_status = {}
     self.setChildrenCollapsible(False)
     left_side = QtWidgets.QWidget()
     self.addWidget(left_side)
     self.grid = QtWidgets.QGridLayout()
     self.grid.setContentsMargins(0, 0, 0, 0)
     self.grid.setRowStretch(6, 1)
     self.grid.setColumnStretch(1, 1)
     left_side.setLayout(self.grid)
     # map
     self.map = WebView()
     self.map.setPage(WebPage(parent=self.map))
     if QtWebEngineWidgets:
         self.web_channel = QtWebChannel.QWebChannel()
         self.map.page().setWebChannel(self.web_channel)
         self.web_channel.registerObject('python', self)
     else:
         self.map.page().setLinkDelegationPolicy(
             QtWebKitWidgets.QWebPage.DelegateAllLinks)
         self.map.page().linkClicked.connect(self.link_clicked)
         self.map.page().mainFrame().javaScriptWindowObjectCleared.connect(
             self.java_script_window_object_cleared)
     self.map.setAcceptDrops(False)
     self.map.drop_text.connect(self.drop_text)
     self.addWidget(self.map)
     # search
     self.grid.addWidget(
         QtWidgets.QLabel(translate('PhotiniMap', 'Search:')), 0, 0)
     self.edit_box = QtWidgets.QComboBox()
     self.edit_box.setMinimumWidth(200)
     self.edit_box.setEditable(True)
     self.edit_box.setInsertPolicy(QtWidgets.QComboBox.NoInsert)
     self.edit_box.lineEdit().setPlaceholderText(
         translate('PhotiniMap', '<new search>'))
     self.edit_box.lineEdit().returnPressed.connect(self.search)
     self.edit_box.activated.connect(self.goto_search_result)
     self.clear_search()
     self.edit_box.setEnabled(False)
     self.grid.addWidget(self.edit_box, 0, 1)
     # latitude & longitude
     self.grid.addWidget(
         QtWidgets.QLabel(translate('PhotiniMap', 'Lat, long:')), 1, 0)
     self.coords = SingleLineEdit()
     self.coords.editingFinished.connect(self.new_coords)
     self.coords.setEnabled(False)
     self.grid.addWidget(self.coords, 1, 1)
     # convert lat/lng to location info
     self.auto_location = QtWidgets.QPushButton(
         translate('PhotiniMap', 'Lat, long -> location'))
     self.auto_location.setEnabled(False)
     self.auto_location.clicked.connect(self.get_address)
     self.grid.addWidget(self.auto_location, 2, 1)
     # location info
     self.location_info = LocationInfo()
     self.location_info['taken'].new_value.connect(self.new_location_taken)
     self.location_info['shown'].new_value.connect(self.new_location_shown)
     self.location_info.swap.clicked.connect(self.swap_locations)
     self.location_info.setEnabled(False)
     self.grid.addWidget(self.location_info, 3, 0, 1, 2)
     # load map button
     self.load_map = QtWidgets.QPushButton(
         translate('PhotiniMap', '\nLoad map\n'))
     self.load_map.clicked.connect(self.initialise)
     self.grid.addWidget(self.load_map, 7, 0, 1, 2)
     # other init
     self.image_list.image_list_changed.connect(self.image_list_changed)
     self.splitterMoved.connect(self.new_split)
Esempio n. 29
0
 def __init__(self, options, initial_files):
     super(MainWindow, self).__init__()
     self.setWindowTitle(self.tr("Photini photo metadata editor"))
     pixmap = QtGui.QPixmap()
     pixmap.loadFromData(
         pkg_resources.resource_string('photini',
                                       'data/icons/48/photini.png'))
     icon = QtGui.QIcon(pixmap)
     self.setWindowIcon(icon)
     self.selection = list()
     # logger window
     self.loggerwindow = LoggerWindow(options.verbose)
     self.loggerwindow.setWindowIcon(icon)
     self.logger = logging.getLogger(self.__class__.__name__)
     # set network proxy
     proxies = getproxies()
     if 'http' in proxies:
         parsed = urlparse(proxies['http'])
         QNetworkProxy.setApplicationProxy(
             QNetworkProxy(QNetworkProxy.HttpProxy, parsed.hostname,
                           parsed.port))
     # create shared global objects
     self.app = QtWidgets.QApplication.instance()
     self.app.config_store = ConfigStore('editor', parent=self)
     self.app.spell_check = SpellCheck(parent=self)
     self.app.test_mode = options.test
     # set debug mode
     if self.app.test_mode:
         debug_metadata()
     # restore size
     size = self.width(), self.height()
     self.resize(
         *eval(self.app.config_store.get('main_window', 'size', str(size))))
     # image selector
     self.image_list = ImageList()
     self.image_list.selection_changed.connect(self.new_selection)
     self.image_list.new_metadata.connect(self.new_metadata)
     # prepare list of tabs and associated stuff
     self.tab_list = (
         {
             'name': self.tr('&Descriptive metadata'),
             'key': 'descriptive_metadata',
             'class': Descriptive
         },
         {
             'name': self.tr('&Technical metadata'),
             'key': 'technical_metadata',
             'class': Technical
         },
         {
             'name': self.tr('Map (&Google)'),
             'key': 'map_google',
             'class': GoogleMap
         },
         {
             'name': self.tr('Map (&Bing)'),
             'key': 'map_bing',
             'class': BingMap
         },
         {
             'name': self.tr('Map (&OSM)'),
             'key': 'map_osm',
             'class': OpenStreetMap
         },
         {
             'name': self.tr('&Flickr upload'),
             'key': 'flickr_upload',
             'class': FlickrUploader
         },
         {
             'name': self.tr('Google &Photos upload'),
             'key': 'picasa_upload',
             'class': PicasaUploader
         },
         {
             'name': self.tr('Faceboo&k upload'),
             'key': 'facebook_upload',
             'class': FacebookUploader
         },
         {
             'name': self.tr('&Import photos'),
             'key': 'import_photos',
             'class': Importer
         },
     )
     # file menu
     file_menu = self.menuBar().addMenu(self.tr('File'))
     open_action = QtWidgets.QAction(self.tr('Open images'), self)
     open_action.setShortcuts(QtGui.QKeySequence.Open)
     open_action.triggered.connect(self.image_list.open_files)
     file_menu.addAction(open_action)
     self.save_action = QtWidgets.QAction(
         self.tr('Save images with new data'), self)
     self.save_action.setShortcuts(QtGui.QKeySequence.Save)
     self.save_action.setEnabled(False)
     self.save_action.triggered.connect(self.image_list.save_files)
     file_menu.addAction(self.save_action)
     self.close_action = QtWidgets.QAction(self.tr('Close selected images'),
                                           self)
     self.close_action.setEnabled(False)
     self.close_action.triggered.connect(self.close_files)
     file_menu.addAction(self.close_action)
     close_all_action = QtWidgets.QAction(self.tr('Close all images'), self)
     close_all_action.triggered.connect(self.close_all_files)
     file_menu.addAction(close_all_action)
     file_menu.addSeparator()
     quit_action = QtWidgets.QAction(self.tr('Quit'), self)
     quit_action.setShortcuts(
         [QtGui.QKeySequence.Quit, QtGui.QKeySequence.Close])
     quit_action.triggered.connect(
         QtWidgets.QApplication.instance().closeAllWindows)
     file_menu.addAction(quit_action)
     # options menu
     options_menu = self.menuBar().addMenu(self.tr('Options'))
     settings_action = QtWidgets.QAction(self.tr('Settings'), self)
     settings_action.triggered.connect(self.edit_settings)
     options_menu.addAction(settings_action)
     options_menu.addSeparator()
     for tab in self.tab_list:
         name = tab['name'].replace('&', '')
         tab['action'] = QtWidgets.QAction(name, self)
         tab['action'].setCheckable(True)
         if tab['class']:
             tab['action'].setChecked(
                 eval(self.app.config_store.get('tabs', tab['key'],
                                                'True')))
         else:
             tab['action'].setEnabled(False)
         tab['action'].triggered.connect(self.add_tabs)
         options_menu.addAction(tab['action'])
     # spelling menu
     languages = self.app.spell_check.available_languages()
     spelling_menu = self.menuBar().addMenu(self.tr('Spelling'))
     enable_action = QtWidgets.QAction(self.tr('Enable spell check'), self)
     enable_action.setEnabled(bool(languages))
     enable_action.setCheckable(True)
     enable_action.setChecked(self.app.spell_check.enabled)
     enable_action.toggled.connect(self.app.spell_check.enable)
     spelling_menu.addAction(enable_action)
     language_menu = QtWidgets.QMenu(self.tr('Choose language'), self)
     language_menu.setEnabled(bool(languages))
     language_group = QtWidgets.QActionGroup(self)
     current_language = self.app.spell_check.current_language()
     for tag in languages:
         language_action = QtWidgets.QAction(tag, self)
         language_action.setCheckable(True)
         language_action.setChecked(tag == current_language)
         language_action.setActionGroup(language_group)
         language_menu.addAction(language_action)
     language_group.triggered.connect(self.app.spell_check.set_language)
     spelling_menu.addMenu(language_menu)
     # help menu
     help_menu = self.menuBar().addMenu(self.tr('Help'))
     about_action = QtWidgets.QAction(self.tr('About Photini'), self)
     about_action.triggered.connect(self.about)
     help_menu.addAction(about_action)
     help_menu.addSeparator()
     help_action = QtWidgets.QAction(self.tr('Photini documentation'), self)
     help_action.triggered.connect(self.open_docs)
     help_menu.addAction(help_action)
     # main application area
     self.central_widget = QtWidgets.QSplitter()
     self.central_widget.setOrientation(Qt.Vertical)
     self.central_widget.setChildrenCollapsible(False)
     self.tabs = QtWidgets.QTabWidget()
     self.tabs.setTabBar(QTabBar())
     self.tabs.setElideMode(Qt.ElideRight)
     self.tabs.currentChanged.connect(self.new_tab)
     self.add_tabs()
     self.central_widget.addWidget(self.tabs)
     self.central_widget.addWidget(self.image_list)
     size = self.central_widget.sizes()
     self.central_widget.setSizes(
         eval(self.app.config_store.get('main_window', 'split', str(size))))
     self.central_widget.splitterMoved.connect(self.new_split)
     self.setCentralWidget(self.central_widget)
     # open files given on command line, after GUI is displayed
     self.initial_files = initial_files
     if self.initial_files:
         QtCore.QTimer.singleShot(0, self.open_initial_files)
Esempio n. 30
0
 def __init__(self, options, initial_files):
     super(MainWindow, self).__init__()
     self.setWindowTitle(self.tr("Photini photo metadata editor"))
     pixmap = QtGui.QPixmap()
     pixmap.loadFromData(pkg_resources.resource_string(
         'photini', 'data/icons/48/photini.png'))
     icon = QtGui.QIcon(pixmap)
     self.setWindowIcon(icon)
     self.selection = list()
     # logger window
     self.loggerwindow = LoggerWindow(options.verbose)
     self.loggerwindow.setWindowIcon(icon)
     # set network proxy
     proxies = getproxies()
     if 'http' in proxies:
         parsed = urlparse(proxies['http'])
         QNetworkProxy.setApplicationProxy(QNetworkProxy(
             QNetworkProxy.HttpProxy, parsed.hostname, parsed.port))
     # create shared global objects
     self.app = QtWidgets.QApplication.instance()
     self.app.config_store = ConfigStore('editor', parent=self)
     self.app.spell_check = SpellCheck(parent=self)
     self.app.test_mode = options.test
     # restore size
     size = self.width(), self.height()
     self.resize(*eval(
         self.app.config_store.get('main_window', 'size', str(size))))
     # image selector
     self.image_list = ImageList()
     self.image_list.selection_changed.connect(self.new_selection)
     self.image_list.new_metadata.connect(self.new_metadata)
     # update config file
     if self.app.config_store.config.has_section('tabs'):
         conv = {
             'descriptive_metadata': 'photini.descriptive',
             'technical_metadata'  : 'photini.technical',
             'map_google'          : 'photini.googlemap',
             'map_bing'            : 'photini.bingmap',
             'map_mapbox'          : 'photini.mapboxmap',
             'map_osm'             : 'photini.openstreetmap',
             'flickr_upload'       : 'photini.flickr',
             'import_photos'       : 'photini.importer',
             }
         for key in self.app.config_store.config.options('tabs'):
             if key in conv:
                 self.app.config_store.set(
                     'tabs', conv[key],
                     self.app.config_store.get('tabs', key))
                 self.app.config_store.config.remove_option('tabs', key)
     # prepare list of tabs and associated stuff
     self.tab_list = []
     modules = ('photini.descriptive', 'photini.technical',
                'photini.googlemap',   'photini.bingmap',
                'photini.mapboxmap',   'photini.openstreetmap',
                'photini.flickr',      'photini.googlephotos',
                'photini.importer')
     modules = eval(self.app.config_store.get(
         'tabs', 'modules', pprint.pformat(modules)))
     for module in modules:
         tab = {'module': module}
         try:
             mod = importlib.import_module(tab['module'])
             tab['class'] = mod.TabWidget
             tab['name'] = tab['class'].tab_name()
         except ImportError as ex:
             print(str(ex))
             tab['class'] = None
         self.tab_list.append(tab)
     # file menu
     file_menu = self.menuBar().addMenu(self.tr('File'))
     open_action = QtWidgets.QAction(self.tr('Open images'), self)
     open_action.setShortcuts(QtGui.QKeySequence.Open)
     open_action.triggered.connect(self.image_list.open_files)
     file_menu.addAction(open_action)
     self.save_action = QtWidgets.QAction(
         self.tr('Save images with new data'), self)
     self.save_action.setShortcuts(QtGui.QKeySequence.Save)
     self.save_action.setEnabled(False)
     self.save_action.triggered.connect(self.image_list.save_files)
     file_menu.addAction(self.save_action)
     self.close_action = QtWidgets.QAction(
         self.tr('Close selected images'), self)
     self.close_action.setEnabled(False)
     self.close_action.triggered.connect(self.close_files)
     file_menu.addAction(self.close_action)
     close_all_action = QtWidgets.QAction(self.tr('Close all images'), self)
     close_all_action.triggered.connect(self.close_all_files)
     file_menu.addAction(close_all_action)
     if GpxImporter:
         file_menu.addSeparator()
         self.import_gpx_action = QtWidgets.QAction(
             self.tr('Import GPX file'), self)
         self.import_gpx_action.triggered.connect(self.import_pgx_file)
         file_menu.addAction(self.import_gpx_action)
     else:
         self.import_gpx_action = None
     file_menu.addSeparator()
     quit_action = QtWidgets.QAction(self.tr('Quit'), self)
     quit_action.setShortcuts(
         [QtGui.QKeySequence.Quit, QtGui.QKeySequence.Close])
     quit_action.triggered.connect(
         QtWidgets.QApplication.instance().closeAllWindows)
     file_menu.addAction(quit_action)
     # options menu
     options_menu = self.menuBar().addMenu(self.tr('Options'))
     settings_action = QtWidgets.QAction(self.tr('Settings'), self)
     settings_action.triggered.connect(self.edit_settings)
     options_menu.addAction(settings_action)
     options_menu.addSeparator()
     for tab in self.tab_list:
         if tab['class']:
             name = tab['name'].replace('&', '')
         else:
             name = tab['module']
         tab['action'] = QtWidgets.QAction(name, self)
         tab['action'].setCheckable(True)
         if tab['class']:
             tab['action'].setChecked(eval(
                 self.app.config_store.get('tabs', tab['module'], 'True')))
         else:
             tab['action'].setEnabled(False)
         tab['action'].triggered.connect(self.add_tabs)
         options_menu.addAction(tab['action'])
     # spelling menu
     languages = self.app.spell_check.available_languages()
     spelling_menu = self.menuBar().addMenu(self.tr('Spelling'))
     enable_action = QtWidgets.QAction(self.tr('Enable spell check'), self)
     enable_action.setEnabled(languages is not None)
     enable_action.setCheckable(True)
     enable_action.setChecked(self.app.spell_check.enabled)
     enable_action.toggled.connect(self.app.spell_check.enable)
     spelling_menu.addAction(enable_action)
     language_menu = QtWidgets.QMenu(self.tr('Choose language'), self)
     language_menu.setEnabled(languages is not None)
     current_language = self.app.spell_check.current_language()
     if languages:
         language_group = QtWidgets.QActionGroup(self)
         for name, code in languages:
             if name != code:
                 name = code + ': ' + name
             language_action = QtWidgets.QAction(name, self)
             language_action.setCheckable(True)
             language_action.setChecked(code == current_language)
             language_action.setData(code)
             language_action.setActionGroup(language_group)
             language_menu.addAction(language_action)
         language_group.triggered.connect(self.set_language)
     else:
         language_action = QtWidgets.QAction(
             self.tr('No dictionary installed'), self)
         language_action.setEnabled(False)
         language_menu.addAction(language_action)
     spelling_menu.addMenu(language_menu)
     # help menu
     help_menu = self.menuBar().addMenu(self.tr('Help'))
     about_action = QtWidgets.QAction(self.tr('About Photini'), self)
     about_action.triggered.connect(self.about)
     help_menu.addAction(about_action)
     help_menu.addSeparator()
     help_action = QtWidgets.QAction(self.tr('Photini documentation'), self)
     help_action.triggered.connect(self.open_docs)
     help_menu.addAction(help_action)
     # main application area
     self.central_widget = QtWidgets.QSplitter()
     self.central_widget.setOrientation(Qt.Vertical)
     self.central_widget.setChildrenCollapsible(False)
     self.tabs = QtWidgets.QTabWidget()
     self.tabs.setTabBar(QTabBar())
     self.tabs.setElideMode(Qt.ElideRight)
     self.tabs.currentChanged.connect(self.new_tab)
     self.add_tabs(False)
     self.central_widget.addWidget(self.tabs)
     self.central_widget.addWidget(self.image_list)
     size = self.central_widget.sizes()
     self.central_widget.setSizes(eval(
         self.app.config_store.get('main_window', 'split', str(size))))
     self.central_widget.splitterMoved.connect(self.new_split)
     self.setCentralWidget(self.central_widget)
     # open files given on command line, after GUI is displayed
     self.initial_files = initial_files
     if self.initial_files:
         QtCore.QTimer.singleShot(0, self.open_initial_files)