Example #1
0
 def new_set(self):
     dialog = QtWidgets.QDialog(parent=self)
     dialog.setWindowTitle(self.tr('Create new Flickr album'))
     dialog.setLayout(QtWidgets.QFormLayout())
     title = SingleLineEdit(spell_check=True)
     dialog.layout().addRow(self.tr('Title'), title)
     description = MultiLineEdit(spell_check=True)
     dialog.layout().addRow(self.tr('Description'), description)
     dialog.layout().addRow(QtWidgets.QLabel(
         self.tr('Album will be created when photos are uploaded')))
     button_box = QtWidgets.QDialogButtonBox(
         QtWidgets.QDialogButtonBox.Ok | QtWidgets.QDialogButtonBox.Cancel)
     button_box.accepted.connect(dialog.accept)
     button_box.rejected.connect(dialog.reject)
     dialog.layout().addRow(button_box)
     if dialog.exec_() != QtWidgets.QDialog.Accepted:
         return
     title = title.toPlainText()
     if not title:
         return
     description = description.toPlainText()
     widget = self.upload_config.add_set(title, description, index=0)
     widget.setChecked(True)
     self.photosets.insert(0, {
         'id'          : None,
         'title'       : title,
         'description' : description,
         'widget'      : widget,
         })
Example #2
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(self.tr('Replace photo'))
     dialog.setLayout(QtWidgets.QVBoxLayout())
     message = QtWidgets.QLabel(self.tr(
         '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(
         self.tr('Replace metadata'))
     widget['set_visibility'] = QtWidgets.QCheckBox(
         self.tr('Change who can see it'))
     widget['set_type'] = QtWidgets.QCheckBox(
         self.tr('Change content type'))
     widget['set_albums'] = QtWidgets.QCheckBox(
         self.tr('Change album membership'))
     widget['replace_image'] = QtWidgets.QCheckBox(
         self.tr('Replace image'))
     widget['new_photo'] = QtWidgets.QCheckBox(
         self.tr('Upload as new photo'))
     no_upload = QtWidgets.QCheckBox(self.tr('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
Example #3
0
 def new_album(self):
     dialog = QtWidgets.QDialog(parent=self)
     dialog.setWindowTitle(self.tr('Create new Facebook album'))
     dialog.setLayout(QtWidgets.QFormLayout())
     name = SingleLineEdit(spell_check=True)
     dialog.layout().addRow(self.tr('Title'), name)
     message = MultiLineEdit(spell_check=True)
     dialog.layout().addRow(self.tr('Description'), message)
     location = SingleLineEdit(spell_check=True)
     dialog.layout().addRow(self.tr('Location'), location)
     privacy = QtWidgets.QComboBox()
     for display_name, value in (
         (self.tr('Only me'), '{value: "SELF"}'),
         (self.tr('All friends'), '{value: "ALL_FRIENDS"}'),
         (self.tr('Friends of friends'), '{value: "FRIENDS_OF_FRIENDS"}'),
         (self.tr('Friends + networks'), '{value: "NETWORKS_FRIENDS"}'),
         (self.tr('Everyone'), '{value: "EVERYONE"}'),
     ):
         privacy.addItem(display_name, value)
     dialog.layout().addRow(self.tr('Privacy'), privacy)
     button_box = QtWidgets.QDialogButtonBox(
         QtWidgets.QDialogButtonBox.Ok | QtWidgets.QDialogButtonBox.Cancel)
     button_box.accepted.connect(dialog.accept)
     button_box.rejected.connect(dialog.reject)
     dialog.layout().addRow(button_box)
     if dialog.exec_() != QtWidgets.QDialog.Accepted:
         return
     if not self.authorise('write'):
         self.refresh(force=True)
         return
     name = name.toPlainText().strip()
     if not name:
         return
     data = {'name': name}
     message = message.toPlainText().strip()
     if message:
         data['message'] = message
     location = location.toPlainText().strip()
     if location:
         data['location'] = location
     data['privacy'] = privacy.itemData(privacy.currentIndex())
     try:
         album = self.session.post('https://graph.facebook.com/me/albums',
                                   data=data)
     except Exception as ex:
         self.logger.error(str(ex))
         self.refresh(force=True)
         return
     self.load_user_data(album_id=album['id'])
Example #4
0
 def edit_template(self):
     dialog = QtWidgets.QDialog(parent=self)
     width = width_for_text(dialog, 'x' * 120)
     dialog.setFixedSize(min(width,
                             self.window().width()),
                         min(width * 3 // 4,
                             self.window().height()))
     dialog.setWindowTitle(self.tr('Photini: ownership template'))
     dialog.setLayout(QtWidgets.QVBoxLayout())
     # main dialog area
     form, widgets = self.data_form()
     widgets['copyright'].setToolTip(
         widgets['copyright'].toolTip() + ' ' +
         translate('OwnerTab',
                   'Use %Y to insert the year the photograph was taken.'))
     for key in widgets:
         value = self.config_store.get('ownership', key)
         if key == 'copyright' and not value:
             name = self.config_store.get('user', 'copyright_name') or ''
             text = (self.config_store.get('user', 'copyright_text')
                     or translate(
                         'DescriptiveTab', 'Copyright ©{year} {name}.'
                         ' All rights reserved.'))
             value = text.format(year='%Y', name=name)
         elif key == 'creator' and not value:
             value = self.config_store.get('user', 'creator_name')
         widgets[key].set_value(value)
     dialog.layout().addWidget(form)
     # apply & cancel buttons
     button_box = QtWidgets.QDialogButtonBox(
         QtWidgets.QDialogButtonBox.Ok | QtWidgets.QDialogButtonBox.Cancel)
     button_box.accepted.connect(dialog.accept)
     button_box.rejected.connect(dialog.reject)
     dialog.layout().addWidget(button_box)
     if dialog.exec_() != QtWidgets.QDialog.Accepted:
         return
     for key in widgets:
         value = widgets[key].get_value()
         if value:
             self.config_store.set('ownership', key, value)
         else:
             self.config_store.delete('ownership', key)
Example #5
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()
Example #6
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
Example #7
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()
Example #8
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()