Exemple #1
0
 def new_set(self):
     dialog = QtWidgets.QDialog(parent=self)
     dialog.setWindowTitle(translate('FlickrTab',
                                     'Create new Flickr album'))
     dialog.setLayout(QtWidgets.QFormLayout())
     title = SingleLineEdit(spell_check=True)
     dialog.layout().addRow(translate('FlickrTab', 'Title'), title)
     description = MultiLineEdit(spell_check=True)
     dialog.layout().addRow(translate('FlickrTab', 'Description'),
                            description)
     dialog.layout().addRow(
         QtWidgets.QLabel(
             translate('FlickrTab',
                       '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, None, index=0)
     widget.setChecked(True)
Exemple #2
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,
         })
Exemple #3
0
 def __init__(self, *arg, **kw):
     super(KeywordsEditor, self).__init__(*arg, **kw)
     self.config_store = QtWidgets.QApplication.instance().config_store
     self.league_table = defaultdict(int)
     for keyword, score in eval(
             self.config_store.get('descriptive', 'keywords',
                                   '{}')).items():
         self.league_table[keyword] = score
     layout = QtWidgets.QHBoxLayout()
     layout.setContentsMargins(0, 0, 0, 0)
     self.setLayout(layout)
     # line edit box
     self.edit = SingleLineEdit(spell_check=True)
     layout.addWidget(self.edit)
     # favourites drop down
     self.favourites = ComboBox()
     self.update_favourites()
     self.favourites.setFixedWidth(self.favourites.title_width())
     self.favourites.currentIndexChanged.connect(self.add_favourite)
     layout.addWidget(self.favourites)
     # adopt child widget methods and signals
     self.get_value = self.edit.get_value
     self.set_value = self.edit.set_value
     self.set_multiple = self.edit.set_multiple
     self.is_multiple = self.edit.is_multiple
     self.editingFinished = self.edit.editingFinished
Exemple #4
0
 def __init__(self, **kw):
     super(KeywordsEditor, self).__init__()
     self.config_store = QtWidgets.QApplication.instance().config_store
     self.league_table = {}
     for keyword, score in self.config_store.get('descriptive', 'keywords',
                                                 {}).items():
         if isinstance(score, int):
             # old style keyword list
             self.league_table[keyword] = date.min.isoformat(), score // 50
         else:
             # new style keyword list
             self.league_table[keyword] = score
     layout = QtWidgets.QHBoxLayout()
     layout.setContentsMargins(0, 0, 0, 0)
     self.setLayout(layout)
     # line edit box
     self.edit = SingleLineEdit(**kw)
     layout.addWidget(self.edit)
     # favourites drop down
     self.favourites = ComboBox()
     self.favourites.addItem(translate('DescriptiveTab', '<favourites>'))
     self.favourites.setFixedWidth(
         self.favourites.minimumSizeHint().width())
     self.update_favourites()
     self.favourites.currentIndexChanged.connect(self.add_favourite)
     layout.addWidget(self.favourites)
     # adopt child widget methods and signals
     self.get_value = self.edit.get_value
     self.set_value = self.edit.set_value
     self.set_multiple = self.edit.set_multiple
     self.is_multiple = self.edit.is_multiple
     self.editingFinished = self.edit.editingFinished
Exemple #5
0
 def __init__(self, *args, **kw):
     super(LocationInfo, self).__init__(*args, **kw)
     layout = QtWidgets.QGridLayout()
     self.setLayout(layout)
     layout.setContentsMargins(0, 0, 0, 0)
     self.members = {}
     for key in ('sublocation', 'city', 'province_state', 'country_name',
                 'country_code', 'world_region'):
         self.members[key] = SingleLineEdit()
         self.members[key].editingFinished.connect(self.editing_finished)
     self.members['country_code'].setMaximumWidth(40)
     for j, text in enumerate((
             translate('AddressTab', 'Street'),
             translate('AddressTab', 'City'),
             translate('AddressTab', 'Province'),
             translate('AddressTab', 'Country'),
             translate('AddressTab', 'Region'),
     )):
         label = QtWidgets.QLabel(text)
         label.setAlignment(Qt.AlignRight)
         layout.addWidget(label, j, 0)
     layout.addWidget(self.members['sublocation'], 0, 1, 1, 2)
     layout.addWidget(self.members['city'], 1, 1, 1, 2)
     layout.addWidget(self.members['province_state'], 2, 1, 1, 2)
     layout.addWidget(self.members['country_name'], 3, 1)
     layout.addWidget(self.members['country_code'], 3, 2)
     layout.addWidget(self.members['world_region'], 4, 1, 1, 2)
     layout.setRowStretch(5, 1)
Exemple #6
0
 def __init__(self, *args, **kw):
     super(LocationInfo, self).__init__(*args, **kw)
     layout = QtWidgets.QGridLayout()
     self.setLayout(layout)
     layout.setContentsMargins(0, 0, 0, 0)
     self.members = {}
     for key in ('SubLocation', 'City', 'ProvinceState', 'CountryName',
                 'CountryCode', 'WorldRegion'):
         self.members[key] = SingleLineEdit(
             length_check=ImageMetadata.max_bytes(key))
         self.members[key].editingFinished.connect(self.editing_finished)
     self.members['CountryCode'].setMaximumWidth(
         width_for_text(self.members['CountryCode'], 'W' * 4))
     self.members['SubLocation'].setToolTip(
         translate('AddressTab', 'Enter the name of the sublocation.'))
     self.members['City'].setToolTip(
         translate('AddressTab', 'Enter the name of the city.'))
     self.members['ProvinceState'].setToolTip(
         translate('AddressTab',
                   'Enter the name of the province or state.'))
     self.members['CountryName'].setToolTip(
         translate('AddressTab', 'Enter the name of the country.'))
     self.members['CountryCode'].setToolTip(
         translate(
             'AddressTab',
             'Enter the 2 or 3 letter ISO 3166 country code of the country.'
         ))
     self.members['WorldRegion'].setToolTip(
         translate('AddressTab', 'Enter the name of the world region.'))
     for j, text in enumerate((
             translate('AddressTab', 'Street'),
             translate('AddressTab', 'City'),
             translate('AddressTab', 'Province'),
             translate('AddressTab', 'Country'),
             translate('AddressTab', 'Region'),
     )):
         label = QtWidgets.QLabel(text)
         label.setAlignment(Qt.AlignRight)
         layout.addWidget(label, j, 0)
     layout.addWidget(self.members['SubLocation'], 0, 1, 1, 2)
     layout.addWidget(self.members['City'], 1, 1, 1, 2)
     layout.addWidget(self.members['ProvinceState'], 2, 1, 1, 2)
     layout.addWidget(self.members['CountryName'], 3, 1)
     layout.addWidget(self.members['CountryCode'], 3, 2)
     layout.addWidget(self.members['WorldRegion'], 4, 1, 1, 2)
     layout.setRowStretch(5, 1)
Exemple #7
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.form = QtWidgets.QFormLayout()
     self.setLayout(self.form)
     # construct widgets
     self.widgets = {}
     # title
     self.widgets['title'] = SingleLineEdit(spell_check=True)
     self.widgets['title'].editingFinished.connect(self.new_title)
     self.form.addRow(translate('DescriptiveTab', '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(translate('DescriptiveTab', 'Description / Caption'),
                      self.widgets['description'])
     # keywords
     self.widgets['keywords'] = KeywordsEditor()
     self.widgets['keywords'].editingFinished.connect(self.new_keywords)
     self.form.addRow(translate('DescriptiveTab', 'Keywords'),
                      self.widgets['keywords'])
     self.image_list.image_list_changed.connect(self.image_list_changed)
     # rating
     self.widgets['rating'] = RatingWidget()
     self.widgets['rating'].editing_finished.connect(self.new_rating)
     self.form.addRow(translate('DescriptiveTab', 'Rating'),
                      self.widgets['rating'])
     # copyright
     self.widgets['copyright'] = LineEditWithAuto()
     self.widgets['copyright'].editingFinished.connect(self.new_copyright)
     self.widgets['copyright'].autoComplete.connect(self.auto_copyright)
     self.form.addRow(translate('DescriptiveTab', '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(translate('DescriptiveTab', 'Creator / Artist'),
                      self.widgets['creator'])
     # disable until an image is selected
     self.setEnabled(False)
Exemple #8
0
 def __init__(self, **kw):
     super(LineEditWithAuto, self).__init__()
     self._is_multiple = False
     layout = QtWidgets.QHBoxLayout()
     layout.setContentsMargins(0, 0, 0, 0)
     self.setLayout(layout)
     # line edit box
     self.edit = SingleLineEdit(**kw)
     layout.addWidget(self.edit)
     # auto complete button
     self.auto = QtWidgets.QPushButton(translate('DescriptiveTab', 'Auto'))
     layout.addWidget(self.auto)
     # adopt child widget methods and signals
     self.set_value = self.edit.set_value
     self.get_value = self.edit.get_value
     self.set_multiple = self.edit.set_multiple
     self.is_multiple = self.edit.is_multiple
     self.editingFinished = self.edit.editingFinished
     self.autoComplete = self.auto.clicked
Exemple #9
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'])
Exemple #10
0
 def __init__(self, *args, **kw):
     super(LocationWidgets, self).__init__(*args, **kw)
     self.members = {
         'sublocation': SingleLineEdit(),
         'city': SingleLineEdit(),
         'province_state': SingleLineEdit(),
         'country_name': SingleLineEdit(),
         'country_code': SingleLineEdit(),
         'world_region': SingleLineEdit(),
     }
     self.members['sublocation'].editingFinished.connect(
         self.new_sublocation)
     self.members['city'].editingFinished.connect(self.new_city)
     self.members['province_state'].editingFinished.connect(
         self.new_province_state)
     self.members['country_name'].editingFinished.connect(
         self.new_country_name)
     self.members['country_code'].editingFinished.connect(
         self.new_country_code)
     self.members['world_region'].editingFinished.connect(
         self.new_world_region)
     self.members['country_code'].setMaximumWidth(40)
Exemple #11
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)
Exemple #12
0
class PhotiniMap(QtWidgets.QSplitter):
    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)

    @QtCore.pyqtSlot(int, six.text_type)
    def log(self, level, message):
        self.logger.log(level, message)

    @QtCore.pyqtSlot(int, int)
    def new_split(self, pos, index):
        self.app.config_store.set('map', 'split', str(self.sizes()))

    @QtCore.pyqtSlot()
    def java_script_window_object_cleared(self):
        self.map.page().mainFrame().addToJavaScriptWindowObject("python", self)

    @QtCore.pyqtSlot(QtCore.QUrl)
    def link_clicked(self, url):
        if url.isLocalFile():
            url.setScheme('http')
        webbrowser.open_new(url.toString())

    @QtCore.pyqtSlot()
    def image_list_changed(self):
        self.redraw_markers()
        self.display_coords()
        self.display_location()
        self.see_selection()

    @QtCore.pyqtSlot()
    def initialise(self):
        page = '''
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
    <style type="text/css">
      html, body {{ height: 100%; margin: 0; padding: 0 }}
      #mapDiv {{ position: relative; width: 100%; height: 100% }}
    </style>
{initialize}
{head}
    <script type="text/javascript" src="script.js"></script>
  </head>
  <body ondragstart="return false">
    <div id="mapDiv"></div>
    <script type="text/javascript">
      var initData = {data};
    </script>
{body}
  </body>
</html>
'''
        lat, lng = eval(self.config_store.get('map', 'centre', '(51.0, 0.0)'))
        zoom = eval(self.config_store.get('map', 'zoom', '11'))
        data = {'lat': lat, 'lng': lng, 'zoom': zoom}
        if QtWebEngineWidgets:
            initialize = '''
    <script type="text/javascript"
      src="qrc:///qtwebchannel/qwebchannel.js">
    </script>
    <script type="text/javascript">
      var python;
      function initialize()
      {
          new QWebChannel(qt.webChannelTransport, function (channel) {
              python = channel.objects.python;
              loadMap();
              });
      }
    </script>
'''
        else:
            initialize = '''
    <script type="text/javascript">
      function initialize()
      {
          loadMap();
      }
    </script>
'''
        page = page.format(data=str(data),
                           initialize=initialize,
                           **self.get_page_elements())
        QtWidgets.QApplication.setOverrideCursor(Qt.WaitCursor)
        self.map.setHtml(page, QtCore.QUrl.fromLocalFile(self.script_dir))

    @QtCore.pyqtSlot()
    def initialize_finished(self):
        QtWidgets.QApplication.restoreOverrideCursor()
        self.map_loaded = True
        self.grid.removeWidget(self.load_map)
        self.load_map.setParent(None)
        show_terms = self.show_terms()
        self.grid.addLayout(show_terms, 7, 0, 1, 2)
        self.edit_box.setEnabled(True)
        self.map.setAcceptDrops(True)
        self.image_list.set_drag_to_map(self.drag_icon)
        self.redraw_markers()
        self.display_coords()

    def refresh(self):
        self.setSizes(
            eval(self.app.config_store.get('map', 'split', str(self.sizes()))))
        if not self.map_loaded:
            return
        lat, lng = eval(self.config_store.get('map', 'centre'))
        zoom = eval(self.config_store.get('map', 'zoom'))
        self.JavaScript('setView({0}, {1}, {2:d})'.format(
            repr(lat), repr(lng), zoom))
        self.redraw_markers()
        self.image_list.set_drag_to_map(self.drag_icon)

    def do_not_close(self):
        return False

    @QtCore.pyqtSlot(QtCore.QVariant)
    def new_status(self, status):
        self.map_status = status
        self.config_store.set('map', 'centre', str(self.map_status['centre']))
        self.config_store.set('map', 'zoom', str(int(self.map_status['zoom'])))

    @QtCore.pyqtSlot(int, int, six.text_type)
    def drop_text(self, x, y, text):
        self.JavaScript('markerDrop({:d},{:d},{:s})'.format(x, y, text))

    @QtCore.pyqtSlot(float, float, QtCore.QVariant)
    def marker_drop(self, lat, lng, path_list):
        for path in path_list:
            image = self.image_list.get_image(path)
            self._remove_image(image)
            self._set_metadata(image, lat, lng)
            self._add_image(image)
        self.display_coords()
        self.see_selection()

    @QtCore.pyqtSlot()
    def new_coords(self):
        text = self.coords.get_value().strip()
        if not text:
            for image in self.image_list.get_selected_images():
                self._remove_image(image)
                image.metadata.latlong = None
            return
        try:
            lat, lng = list(map(float, text.split(',')))
        except Exception:
            self.display_coords()
            return
        for image in self.image_list.get_selected_images():
            self._remove_image(image)
            self._set_metadata(image, lat, lng)
            self._add_image(image)
        self.display_coords()
        self.see_selection()

    def see_selection(self):
        locations = []
        for image in self.image_list.get_selected_images():
            latlong = image.metadata.latlong
            if not latlong:
                continue
            location = [latlong.lat, latlong.lon]
            if location not in locations:
                locations.append(location)
        if not locations:
            return
        self.JavaScript('fitPoints({})'.format(repr(locations)))

    @QtCore.pyqtSlot(six.text_type, six.text_type, six.text_type,
                     six.text_type, six.text_type, six.text_type)
    def set_location_taken(self, world_region, country_code, country_name,
                           province_state, city, sublocation):
        for image in self.image_list.get_selected_images():
            image.metadata.location_taken = (sublocation, city, province_state,
                                             country_name, country_code,
                                             world_region)
        self.display_location()

    @QtCore.pyqtSlot()
    def swap_locations(self):
        for image in self.image_list.get_selected_images():
            taken = image.metadata.location_taken
            if taken:
                taken = taken.value
            shown = image.metadata.location_shown
            if shown:
                shown = shown.value
            image.metadata.location_taken = shown
            image.metadata.location_shown = taken
        self.display_location()

    @QtCore.pyqtSlot(six.text_type, six.text_type)
    def new_location_taken(self, key, value):
        self._new_location('location_taken', key, value)

    @QtCore.pyqtSlot(six.text_type, six.text_type)
    def new_location_shown(self, key, value):
        self._new_location('location_shown', key, value)

    def _new_location(self, taken_shown, key, value):
        for image in self.image_list.get_selected_images():
            location = getattr(image.metadata, taken_shown)
            if location:
                new_value = dict(location.value)
            else:
                new_value = dict.fromkeys(
                    ('sublocation', 'city', 'province_state', 'country_name',
                     'country_code', 'world_region'))
            new_value[key] = value
            if not any(new_value.values()):
                new_value = None
            setattr(image.metadata, taken_shown, new_value)
        self.display_location()

    def display_coords(self):
        images = self.image_list.get_selected_images()
        if not images:
            self.coords.set_value(None)
            self.auto_location.setEnabled(False)
            return
        latlong = images[0].metadata.latlong
        for image in images[1:]:
            if image.metadata.latlong != latlong:
                self.coords.set_multiple()
                self.auto_location.setEnabled(False)
                return
        self.coords.set_value(latlong)
        self.auto_location.setEnabled(self.map_loaded and bool(latlong))

    def display_location(self):
        images = self.image_list.get_selected_images()
        if not images:
            for widget_group in (self.location_info['taken'],
                                 self.location_info['shown']):
                for attr in widget_group.members:
                    widget_group[attr].set_value(None)
            return
        for taken_shown in 'taken', 'shown':
            widget_group = self.location_info[taken_shown]
            for attr in widget_group.members:
                value = getattr(images[0].metadata, 'location_' + taken_shown)
                if value:
                    value = value.value[attr]
                for image in images[1:]:
                    other = getattr(image.metadata, 'location_' + taken_shown)
                    if other:
                        other = other.value[attr]
                    if other != value:
                        widget_group[attr].set_multiple()
                        break
                else:
                    widget_group[attr].set_value(value)

    @QtCore.pyqtSlot(list)
    def new_selection(self, selection):
        self.coords.setEnabled(bool(selection))
        self.location_info.setEnabled(bool(selection))
        for marker_id, images in list(self.marker_images.items()):
            self.JavaScript('enableMarker("{}", {:d})'.format(
                marker_id, any([image.selected for image in images])))
        self.display_coords()
        self.display_location()
        self.see_selection()

    def redraw_markers(self):
        self.JavaScript('removeMarkers()')
        self.marker_images = {}
        for image in self.image_list.get_images():
            self._add_image(image)

    def _add_image(self, image):
        if not self.map_loaded:
            return
        latlong = image.metadata.latlong
        if not latlong:
            return
        for marker_id in self.marker_images:
            if self.marker_images[marker_id][0].metadata.latlong == latlong:
                self.marker_images[marker_id].append(image)
                if image.selected:
                    self.JavaScript('enableMarker("{}", {:d})'.format(
                        marker_id, True))
                break
        else:
            for i in range(len(self.marker_images) + 2):
                marker_id = str(i)
                if marker_id not in self.marker_images:
                    break
            self.marker_images[marker_id] = [image]
            self.JavaScript('addMarker("{}", {!r}, {!r}, {:d})'.format(
                marker_id, latlong.lat, latlong.lon, image.selected))

    def _remove_image(self, image):
        for marker_id in self.marker_images:
            if image in self.marker_images[marker_id]:
                break
        else:
            return
        self.marker_images[marker_id].remove(image)
        if self.marker_images[marker_id]:
            self.JavaScript('enableMarker("{}", {:d})'.format(
                marker_id,
                any([
                    image.selected for image in self.marker_images[marker_id]
                ])))
        else:
            self.JavaScript('delMarker("{}")'.format(marker_id))
            del self.marker_images[marker_id]

    @QtCore.pyqtSlot()
    def get_address(self):
        latlng = self.coords.get_value()
        self.JavaScript('reverseGeocode({})'.format(latlng))

    @QtCore.pyqtSlot()
    def search(self, search_string=None):
        if not search_string:
            search_string = self.edit_box.lineEdit().text()
            self.edit_box.clearEditText()
        if not search_string:
            return
        self.search_string = search_string
        self.clear_search()
        self.JavaScript('search("{0}")'.format(search_string))

    def clear_search(self):
        self.edit_box.clear()
        self.edit_box.addItem('')
        if self.search_string:
            self.edit_box.addItem(translate('PhotiniMap', '<repeat search>'))

    @QtCore.pyqtSlot(float, float, float, float, six.text_type)
    def search_result(self, lat0, lng0, lat1, lng1, name):
        self.edit_box.addItem(name, (lat0, lng0, lat1, lng1))
        self.edit_box.showPopup()

    @QtCore.pyqtSlot(int)
    def goto_search_result(self, idx):
        self.edit_box.setCurrentIndex(0)
        self.edit_box.clearFocus()
        if idx == 0:
            return
        if self.search_string and idx == 1:
            # repeat search
            self.search(self.search_string)
            return
        view = self.edit_box.itemData(idx)
        self.JavaScript('adjustBounds({},{},{},{})'.format(*view))

    @QtCore.pyqtSlot(six.text_type)
    def marker_click(self, marker_id):
        self.image_list.select_images(self.marker_images[marker_id])

    @QtCore.pyqtSlot(float, float, six.text_type)
    def marker_drag(self, lat, lng, marker_id):
        for image in self.marker_images[marker_id]:
            self._set_metadata(image, lat, lng)
        self.display_coords()

    def _set_metadata(self, image, lat, lng):
        image.metadata.latlong = lat, lng

    def JavaScript(self, command):
        if self.map_loaded:
            command = command.replace('\\', '\\\\')
            if QtWebEngineWidgets:
                self.map.page().runJavaScript(command)
            else:
                self.map.page().mainFrame().evaluateJavaScript(command)
Exemple #13
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)
Exemple #14
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
Exemple #15
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.form = QtWidgets.QFormLayout()
     self.setLayout(QtWidgets.QVBoxLayout())
     self.layout().addLayout(self.form)
     self.layout().addStretch(1)
     # construct widgets
     self.widgets = {}
     # title
     self.widgets['title'] = SingleLineEdit(
         spell_check=True, length_check=ImageMetadata.max_bytes('title'))
     self.widgets['title'].setToolTip(
         translate(
             'DescriptiveTab',
             'Enter a short verbal and human readable name'
             ' for the image, this may be the file name.'))
     self.widgets['title'].editingFinished.connect(self.new_title)
     self.form.addRow(translate('DescriptiveTab', 'Title / Object Name'),
                      self.widgets['title'])
     # description
     self.widgets['description'] = MultiLineEdit(
         spell_check=True,
         length_check=ImageMetadata.max_bytes('description'))
     self.widgets['description'].setToolTip(
         translate(
             'DescriptiveTab', 'Enter a "caption" describing the who, what,'
             ' and why of what is happening in this image,\nthis might include'
             ' names of people, and/or their role in the action that is taking'
             ' place within the image.'))
     self.widgets['description'].editingFinished.connect(
         self.new_description)
     self.form.addRow(translate('DescriptiveTab', 'Description / Caption'),
                      self.widgets['description'])
     # keywords
     self.widgets['keywords'] = KeywordsEditor(
         spell_check=True,
         length_check=ImageMetadata.max_bytes('keywords'),
         multi_string=True)
     self.widgets['keywords'].setToolTip(
         translate(
             'DescriptiveTab',
             'Enter any number of keywords, terms or phrases'
             ' used to express the subject matter in the image.'
             '\nSeparate them with ";" characters.'))
     self.widgets['keywords'].editingFinished.connect(self.new_keywords)
     self.form.addRow(translate('DescriptiveTab', 'Keywords'),
                      self.widgets['keywords'])
     self.image_list.image_list_changed.connect(self.image_list_changed)
     # rating
     self.widgets['rating'] = RatingWidget()
     self.widgets['rating'].editing_finished.connect(self.new_rating)
     self.form.addRow(translate('DescriptiveTab', 'Rating'),
                      self.widgets['rating'])
     # copyright
     self.widgets['copyright'] = LineEditWithAuto(
         length_check=ImageMetadata.max_bytes('copyright'))
     self.widgets['copyright'].setToolTip(
         translate(
             'OwnerTab', 'Enter a notice on the current owner of the'
             ' copyright for this image, such as "©2008 Jane Doe".'))
     self.widgets['copyright'].editingFinished.connect(self.new_copyright)
     self.widgets['copyright'].autoComplete.connect(self.auto_copyright)
     self.form.addRow(translate('DescriptiveTab', 'Copyright'),
                      self.widgets['copyright'])
     # creator
     self.widgets['creator'] = LineEditWithAuto(
         length_check=ImageMetadata.max_bytes('creator'), multi_string=True)
     self.widgets['creator'].setToolTip(
         translate('OwnerTab',
                   'Enter the name of the person that created this image.'))
     self.widgets['creator'].editingFinished.connect(self.new_creator)
     self.widgets['creator'].autoComplete.connect(self.auto_creator)
     self.form.addRow(translate('DescriptiveTab', 'Creator / Artist'),
                      self.widgets['creator'])
     # disable until an image is selected
     self.setEnabled(False)
Exemple #16
0
class PhotiniMap(QtWidgets.QSplitter):
    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)

    def search_terms(self):
        return None

    @QtCore.pyqtSlot()
    @catch_all
    def load_tou_opencage(self):
        QtGui.QDesktopServices.openUrl(
            QtCore.QUrl('https://geocoder.opencagedata.com/'))

    @QtCore.pyqtSlot()
    @catch_all
    def load_tou_osm(self):
        QtGui.QDesktopServices.openUrl(
            QtCore.QUrl('http://www.openstreetmap.org/copyright'))

    @QtCore.pyqtSlot(int, int)
    @catch_all
    def new_split(self, pos, index):
        self.app.config_store.set('map', 'split', str(self.sizes()))

    @QtCore.pyqtSlot()
    @catch_all
    def image_list_changed(self):
        self.redraw_markers()
        self.display_coords()
        self.display_location()
        self.see_selection()

    @QtCore.pyqtSlot()
    @catch_all
    def initialise(self):
        page = '''
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
    <style type="text/css">
      html, body {{ height: 100%; margin: 0; padding: 0 }}
      #mapDiv {{ position: relative; width: 100%; height: 100% }}
    </style>
    <script type="text/javascript">
      var initData = {{key: "{key}", lat: {lat}, lng: {lng}, zoom: {zoom}}};
    </script>
{initialize}
{head}
    <script type="text/javascript" src="script.js" async></script>
  </head>
  <body ondragstart="return false">
    <div id="mapDiv"></div>
  </body>
</html>
'''
        lat, lng = eval(
            self.app.config_store.get('map', 'centre', '(51.0, 0.0)'))
        zoom = int(eval(self.app.config_store.get('map', 'zoom', '11')))
        if using_qtwebengine:
            initialize = '''
    <script type="text/javascript"
      src="qrc:///qtwebchannel/qwebchannel.js">
    </script>
    <script type="text/javascript">
      var python;
      function initialize()
      {
          new QWebChannel(qt.webChannelTransport, function (channel) {
              python = channel.objects.python;
              loadMap();
              });
      }
    </script>
'''
        else:
            initialize = '''
    <script type="text/javascript">
      function initialize()
      {
          loadMap();
      }
    </script>
'''
        page = page.format(lat=lat,
                           lng=lng,
                           zoom=zoom,
                           initialize=initialize,
                           key=self.api_key,
                           head=self.get_head())
        QtWidgets.QApplication.setOverrideCursor(Qt.WaitCursor)
        self.map.setHtml(page, QtCore.QUrl.fromLocalFile(self.script_dir))

    @catch_all
    def initialize_finished(self):
        QtWidgets.QApplication.restoreOverrideCursor()
        self.map_loaded = True
        self.edit_box.setEnabled(True)
        self.map.setAcceptDrops(True)
        self.redraw_markers()
        self.display_coords()

    def refresh(self):
        self.setSizes(
            eval(self.app.config_store.get('map', 'split', str(self.sizes()))))
        self.image_list.set_drag_to_map(self.drag_icon, self.drag_hotspot)
        if not self.map_loaded:
            self.initialise()
            return
        lat, lng = eval(self.app.config_store.get('map', 'centre'))
        zoom = int(eval(self.app.config_store.get('map', 'zoom')))
        self.JavaScript('setView({!r},{!r},{:d})'.format(lat, lng, zoom))

    def do_not_close(self):
        return False

    @catch_all
    def new_status(self, status):
        self.map_status.update(status)
        for key in ('centre', 'zoom'):
            if key in status:
                self.app.config_store.set('map', key,
                                          repr(self.map_status[key]))

    @QtCore.pyqtSlot(int, int, six.text_type)
    @catch_all
    def drop_text(self, x, y, text):
        self.dropped_images = eval(text)
        self.JavaScript('markerDrop({:d},{:d})'.format(x, y))

    @catch_all
    def marker_drop(self, lat, lng):
        for path in self.dropped_images:
            image = self.image_list.get_image(path)
            image.metadata.latlong = lat, lng
        self.dropped_images = []
        self.redraw_markers()
        self.display_coords()
        self.see_selection()

    @QtCore.pyqtSlot()
    @catch_all
    def new_coords(self):
        text = self.coords.get_value().strip()
        if not text:
            for image in self.image_list.get_selected_images():
                image.metadata.latlong = None
            self.redraw_markers()
            return
        try:
            lat, lng = map(float, text.split(','))
        except Exception:
            self.display_coords()
            return
        for image in self.image_list.get_selected_images():
            image.metadata.latlong = lat, lng
        self.redraw_markers()
        self.display_coords()
        self.see_selection()

    def see_selection(self):
        locations = []
        for image in self.image_list.get_selected_images():
            latlong = image.metadata.latlong
            if not latlong:
                continue
            location = [latlong.lat, latlong.lon]
            if location not in locations:
                locations.append(location)
        if not locations:
            return
        self.JavaScript('fitPoints({})'.format(repr(locations)))

    @QtCore.pyqtSlot(QtGui.QContextMenuEvent)
    @catch_all
    def location_tab_context_menu(self, event):
        idx = self.location_info.tabBar().tabAt(event.pos())
        self.location_info.setCurrentIndex(idx)
        menu = QtWidgets.QMenu(self)
        menu.addAction(self.tr('Duplicate location'), self.duplicate_location)
        menu.addAction(self.tr('Delete location'), self.delete_location)
        action = menu.exec_(event.globalPos())

    @QtCore.pyqtSlot()
    @catch_all
    def duplicate_location(self):
        idx = self.location_info.currentIndex()
        for image in self.image_list.get_selected_images():
            # duplicate data
            location = Location(self._get_location(image, idx) or {})
            # shuffle data up
            location_list = list(image.metadata.location_shown or [])
            location_list.insert(idx, location)
            image.metadata.location_shown = location_list
        # display data
        self.display_location()

    @QtCore.pyqtSlot()
    @catch_all
    def delete_location(self):
        idx = self.location_info.currentIndex()
        for image in self.image_list.get_selected_images():
            # shuffle data down
            location_list = list(image.metadata.location_shown or [])
            if idx == 0:
                if location_list:
                    location = location_list[0]
                else:
                    location = None
                image.metadata.location_taken = location
            if idx <= len(location_list):
                del location_list[max(idx - 1, 0)]
            image.metadata.location_shown = location_list
        # display data
        self.display_location()

    @QtCore.pyqtSlot(int, int)
    @catch_all
    def location_tab_moved(self, idx_a, idx_b):
        self.pending_move = idx_a, idx_b
        # do actual swap when idle to avoid seg fault
        QtCore.QTimer.singleShot(0, self._location_tab_moved)

    @QtCore.pyqtSlot()
    @catch_all
    def _location_tab_moved(self):
        idx_a, idx_b = self.pending_move
        # swap data
        for image in self.image_list.get_selected_images():
            temp_a = self._get_location(image, idx_a)
            temp_b = self._get_location(image, idx_b)
            self._set_location(image, idx_a, temp_b)
            self._set_location(image, idx_b, temp_a)
        # adjust tab names
        for idx in range(min(idx_a, idx_b), max(idx_a, idx_b) + 1):
            self.set_tab_text(idx)
        # display data
        self.display_location()

    def _get_location(self, image, idx):
        if idx == 0:
            return image.metadata.location_taken
        elif not image.metadata.location_shown:
            return None
        elif idx <= len(image.metadata.location_shown):
            return image.metadata.location_shown[idx - 1]
        return None

    def _set_location(self, image, idx, location):
        if idx == 0:
            image.metadata.location_taken = location
        else:
            location_list = list(image.metadata.location_shown or [])
            while len(location_list) < idx:
                location_list.append(None)
            location_list[idx - 1] = location
            image.metadata.location_shown = location_list

    @QtCore.pyqtSlot(object, dict)
    @catch_all
    def new_location(self, widget, new_value):
        idx = self.location_info.indexOf(widget)
        for image in self.image_list.get_selected_images():
            temp = dict(self._get_location(image, idx) or {})
            temp.update(new_value)
            self._set_location(image, idx, temp)
        # new_location can be called when changing tab, so don't delete
        # tabs until later
        QtCore.QTimer.singleShot(0, self.display_location)

    def display_coords(self):
        images = self.image_list.get_selected_images()
        if not images:
            self.coords.set_value(None)
            self.auto_location.setEnabled(False)
            return
        values = []
        for image in images:
            value = image.metadata.latlong
            if value not in values:
                values.append(value)
        if len(values) > 1:
            self.coords.set_multiple(choices=filter(None, values))
            self.auto_location.setEnabled(False)
        else:
            self.coords.set_value(values[0])
            self.auto_location.setEnabled(
                bool(values[0]) and not self.block_timer.isActive())

    def set_tab_text(self, idx):
        if idx == 0:
            text = self.tr('camera')
        else:
            text = self.tr('subject {}').format(idx)
        self.location_info.setTabText(idx, text)

    @QtCore.pyqtSlot()
    @catch_all
    def display_location(self):
        images = self.image_list.get_selected_images()
        # get required number of tabs
        count = 0
        for image in images:
            if image.metadata.location_shown:
                count = max(count, len(image.metadata.location_shown))
        count += 2
        # add or remove tabs
        if self.location_info.currentIndex() >= count:
            self.location_info.setCurrentIndex(count - 1)
        idx = self.location_info.count()
        while idx < count:
            if not self.location_widgets:
                widget = LocationInfo()
                widget.new_value.connect(self.new_location)
                self.location_widgets.append(widget)
            self.location_info.addTab(self.location_widgets.pop(), '')
            self.set_tab_text(idx)
            idx += 1
        while idx > count:
            idx -= 1
            self.location_widgets.append(self.location_info.widget(idx))
            self.location_info.removeTab(idx)
        # display data
        for idx in range(count):
            widget = self.location_info.widget(idx)
            if images:
                values = defaultdict(list)
                for image in images:
                    location = self._get_location(image, idx) or {}
                    for key in widget.members:
                        value = None
                        if key in location:
                            value = location[key]
                        if value not in values[key]:
                            values[key].append(value)
                for key in widget.members:
                    if len(values[key]) > 1:
                        widget.members[key].set_multiple(
                            choices=filter(None, values[key]))
                    else:
                        widget.members[key].set_value(values[key][0])
            else:
                for key in widget.members:
                    widget.members[key].set_value(None)

    @QtCore.pyqtSlot(list)
    @catch_all
    def new_selection(self, selection):
        self.coords.setEnabled(bool(selection))
        self.location_info.setEnabled(bool(selection))
        self.redraw_markers()
        self.display_coords()
        self.display_location()
        self.see_selection()

    def redraw_markers(self):
        if not self.map_loaded:
            return
        for info in self.marker_info.values():
            info['images'] = []
        for image in self.image_list.get_images():
            latlong = image.metadata.latlong
            if not latlong:
                continue
            for info in self.marker_info.values():
                if info['latlong'] == latlong:
                    info['images'].append(image)
                    break
            else:
                for i in range(len(self.marker_info) + 2):
                    marker_id = i
                    if marker_id not in self.marker_info:
                        break
                self.marker_info[marker_id] = {
                    'images': [image],
                    'latlong': LatLon(latlong),
                    'selected': image.selected,
                }
                self.JavaScript('addMarker({:d},{!r},{!r},{:d})'.format(
                    marker_id, latlong.lat, latlong.lon, image.selected))
        for marker_id in list(self.marker_info.keys()):
            info = self.marker_info[marker_id]
            if not info['images']:
                self.JavaScript('delMarker({:d})'.format(marker_id))
                del self.marker_info[marker_id]
            elif info['selected'] != any([x.selected for x in info['images']]):
                info['selected'] = not info['selected']
                self.JavaScript('enableMarker({:d},{:d})'.format(
                    marker_id, info['selected']))

    def plot_track(self, tracks):
        latlngs = []
        for t in tracks:
            latlngs.append([[x[1], x[2]] for x in t])
        self.JavaScript('plotTrack({!r})'.format(latlngs))

    @QtCore.pyqtSlot()
    @catch_all
    def enable_search(self):
        self.block_timer.stop()
        self.edit_box.lineEdit().setEnabled(self.map_loaded)
        if self.search_string:
            item = self.edit_box.model().item(1)
            item.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled)
            item = self.edit_box.model().item(2)
            item.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled)
        self.display_coords()

    def disable_search(self):
        self.edit_box.lineEdit().setEnabled(False)
        if self.search_string:
            item = self.edit_box.model().item(1)
            item.setFlags(~(Qt.ItemIsSelectable | Qt.ItemIsEnabled))
            item = self.edit_box.model().item(2)
            item.setFlags(~(Qt.ItemIsSelectable | Qt.ItemIsEnabled))
        self.auto_location.setEnabled(False)
        self.block_timer.start()
        focus = QtWidgets.QApplication.focusWidget()
        if focus:
            focus.clearFocus()

    def do_geocode(self, params):
        cache_key = params['q']
        if 'bounds' in params:
            cache_key += params['bounds']
        if cache_key in self.geocode_cache:
            return self.geocode_cache[cache_key]
        self.disable_search()
        params['key'] = self.search_key
        params['abbrv'] = '1'
        params['no_annotations'] = '1'
        lang, encoding = locale.getdefaultlocale()
        if lang:
            params['language'] = lang
        with Busy():
            try:
                rsp = requests.get(
                    'https://api.opencagedata.com/geocode/v1/json',
                    params=params,
                    timeout=5)
            except Exception as ex:
                logger.error(str(ex))
                return []
        if rsp.status_code >= 400:
            logger.error('Search error %d', rsp.status_code)
            return []
        rsp = rsp.json()
        status = rsp['status']
        if status['code'] != 200:
            logger.error('Search error %d: %s', status['code'],
                         status['message'])
            return []
        if rsp['total_results'] < 1:
            logger.error('No results found')
            return []
        rate = rsp['rate']
        self.block_timer.setInterval(5000 * rate['limit'] //
                                     max(rate['remaining'], 1))
        self.geocode_cache[cache_key] = rsp['results']
        while len(self.geocode_cache) > 20:
            self.geocode_cache.popitem(last=False)
        return rsp['results']

    def geocode(self, search_string, bounds=None):
        params = {
            'q': search_string,
            'limit': '20',
        }
        if bounds:
            north, east, south, west = bounds
            w = east - west
            h = north - south
            if min(w, h) < 10.0:
                lat, lon = self.map_status['centre']
                north = min(lat + 5.0, 90.0)
                south = max(lat - 5.0, -90.0)
                east = lon + 5.0
                west = lon - 5.0
            params['bounds'] = '{!r},{!r},{!r},{!r}'.format(
                west, south, east, north)
        for result in self.do_geocode(params):
            yield (result['bounds']['northeast']['lat'],
                   result['bounds']['northeast']['lng'],
                   result['bounds']['southwest']['lat'],
                   result['bounds']['southwest']['lng'], result['formatted'])

    # Map OpenCage address components to IPTC address heirarchy. There
    # are many possible components (user generated data) so any
    # unrecognised ones are put in 'sublocation'. See
    # https://github.com/OpenCageData/address-formatting/blob/master/conf/components.yaml
    address_map = {
        'world_region': ('continent', ),
        'country_code':
        ('ISO_3166-1_alpha-3', 'ISO_3166-1_alpha-2', 'country_code'),
        'country_name': ('country', 'country_name'),
        'province_state':
        ('county', 'county_code', 'local_administrative_area',
         'state_district', 'state', 'state_code', 'province', 'region',
         'island'),
        'city': ('village', 'locality', 'hamlet', 'neighbourhood',
                 'city_district', 'suburb', 'city', 'town', 'postcode'),
        'sublocation':
        ('house_number', 'street_number', 'house', 'public_building',
         'building', 'water', 'road', 'pedestrian', 'path', 'residential',
         'street_name', 'street', 'cycleway', 'footway', 'place'),
        'ignore': ('political_union', 'road_reference', 'road_reference_intl',
                   'road_type', '_type'),
    }

    @QtCore.pyqtSlot()
    @catch_all
    def get_address(self):
        results = self.do_geocode(
            {'q': self.coords.get_value().replace(' ', '')})
        if not results:
            return
        address = dict(results[0]['components'])
        if 'county_code' in address and 'county' in address:
            del address['county_code']
        if 'state_code' in address and 'state' in address:
            del address['state_code']
        self.new_location(self.location_info.currentWidget(),
                          Location.from_address(address, self.address_map))

    @QtCore.pyqtSlot()
    @catch_all
    def search(self, search_string=None, bounded=True):
        if not search_string:
            search_string = self.edit_box.lineEdit().text()
            self.edit_box.clearEditText()
        if not search_string:
            return
        self.search_string = search_string
        self.clear_search()
        if bounded:
            bounds = self.map_status['bounds']
        else:
            bounds = None
        for result in self.geocode(search_string, bounds=bounds):
            north, east, south, west, name = result
            self.edit_box.addItem(name, (north, east, south, west))
        self.edit_box.set_dropdown_width()
        self.edit_box.showPopup()

    def clear_search(self):
        self.edit_box.clear()
        self.edit_box.addItem('')
        if self.search_string:
            self.edit_box.addItem(translate('PhotiniMap', '<widen search>'))
            self.edit_box.addItem(translate('PhotiniMap', '<repeat search>'))

    @QtCore.pyqtSlot(int)
    @catch_all
    def goto_search_result(self, idx):
        self.edit_box.setCurrentIndex(0)
        self.edit_box.clearFocus()
        if idx == 0:
            return
        if self.search_string and idx == 1:
            # widen search
            self.search(search_string=self.search_string, bounded=False)
            return
        if self.search_string and idx == 2:
            # repeat search
            self.search(search_string=self.search_string)
            return
        view = self.edit_box.itemData(idx)
        if view[-1] is None:
            self.JavaScript('setView({},{},{})'.format(
                view[0], view[1], self.map_status['zoom']))
        else:
            self.JavaScript('adjustBounds({},{},{},{})'.format(*view))

    @catch_all
    def marker_click(self, marker_id):
        self.image_list.select_images(self.marker_info[marker_id]['images'])

    @catch_all
    def marker_drag(self, lat, lng):
        self.coords.set_value('{:.6f}, {:.6f}'.format(lat, lng))

    @catch_all
    def marker_drag_end(self, lat, lng, marker_id):
        info = self.marker_info[marker_id]
        for image in info['images']:
            image.metadata.latlong = lat, lng
        info['latlong'] = LatLon((lat, lng))
        self.display_coords()

    def JavaScript(self, command):
        if self.map_loaded:
            self.map.page().do_java_script(command)
Exemple #17
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)
Exemple #18
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 = self.config_store.get('files', 'force_iptc', False)
     self.write_iptc = QtWidgets.QCheckBox(self.tr('Always write'))
     self.write_iptc.setChecked(force_iptc)
     panel.layout().addRow(self.tr('IPTC-IIM metadata'), self.write_iptc)
     # show IPTC-IIM length limits
     length_warning = self.config_store.get('files', 'length_warning', True)
     self.length_warning = QtWidgets.QCheckBox(
         self.tr('Show IPTC-IIM length limits'))
     self.length_warning.setChecked(length_warning)
     panel.layout().addRow('', self.length_warning)
     # sidecar files
     if_mode = self.config_store.get('files', 'image', True)
     sc_mode = self.config_store.get('files', 'sidecar', 'auto')
     if not if_mode:
         sc_mode = 'always'
     button_group = QtWidgets.QButtonGroup(parent=self)
     self.sc_always = QtWidgets.QRadioButton(self.tr('Always create'))
     button_group.addButton(self.sc_always)
     self.sc_always.setChecked(sc_mode == 'always')
     panel.layout().addRow(self.tr('Sidecar files'), self.sc_always)
     self.sc_auto = QtWidgets.QRadioButton(self.tr('Create if necessary'))
     button_group.addButton(self.sc_auto)
     self.sc_auto.setChecked(sc_mode == 'auto')
     self.sc_auto.setEnabled(if_mode)
     panel.layout().addRow('', self.sc_auto)
     self.sc_delete = QtWidgets.QRadioButton(
         self.tr('Delete when possible'))
     button_group.addButton(self.sc_delete)
     self.sc_delete.setChecked(sc_mode == 'delete')
     self.sc_delete.setEnabled(if_mode)
     panel.layout().addRow('', self.sc_delete)
     # image file locking
     self.write_if = QtWidgets.QCheckBox(self.tr('(when possible)'))
     self.write_if.setChecked(if_mode)
     self.write_if.clicked.connect(self.new_write_if)
     panel.layout().addRow(self.tr('Write to image file'), self.write_if)
     # preserve file timestamps
     keep_time = self.config_store.get('files', 'preserve_timestamps',
                                       'now')
     if isinstance(keep_time, bool):
         # old config format
         keep_time = ('now', 'keep')[keep_time]
     button_group = QtWidgets.QButtonGroup(parent=self)
     self.keep_time = QtWidgets.QRadioButton(self.tr('Keep original'))
     button_group.addButton(self.keep_time)
     self.keep_time.setChecked(keep_time == 'keep')
     panel.layout().addRow(self.tr('File timestamps'), self.keep_time)
     self.time_taken = QtWidgets.QRadioButton(
         self.tr('Set to when photo was taken'))
     button_group.addButton(self.time_taken)
     self.time_taken.setChecked(keep_time == 'taken')
     panel.layout().addRow('', self.time_taken)
     button = QtWidgets.QRadioButton(self.tr('Set to when file is saved'))
     button_group.addButton(button)
     button.setChecked(keep_time == 'now')
     panel.layout().addRow('', button)
     # add panel to scroll area after its size is known
     scroll_area.setWidget(panel)