예제 #1
0
 def __init__(self, *arg, **kw):
     super(OffsetWidget, self).__init__(*arg, **kw)
     self.config_store = QtWidgets.QApplication.instance().config_store
     self.setLayout(QtWidgets.QHBoxLayout())
     self.layout().setContentsMargins(0, 0, 0, 0)
     # offset value
     self.offset = QtWidgets.QTimeEdit()
     self.offset.setDisplayFormat("'h:'hh 'm:'mm 's:'ss")
     self.layout().addWidget(self.offset)
     # time zone
     self.time_zone = TimeZoneWidget()
     self.time_zone.set_value(None)
     self.layout().addWidget(self.time_zone)
     # add offset button
     add_button = SquareButton('+')
     add_button.clicked.connect(self.add)
     self.layout().addWidget(add_button)
     # subtract offset button
     sub_button = SquareButton('-')
     sub_button.clicked.connect(self.sub)
     self.layout().addWidget(sub_button)
     self.layout().addStretch(1)
     # restore stored values
     value = eval(self.config_store.get('technical', 'offset', 'None'))
     if value:
         self.offset.setTime(QtCore.QTime(*value[0:3]))
         self.time_zone.set_value(value[3])
     # connections
     self.offset.editingFinished.connect(self.new_value)
     self.time_zone.editingFinished.connect(self.new_value)
예제 #2
0
 def __init__(self, image_list, *arg, **kw):
     super(TabWidget, self).__init__(*arg, **kw)
     self.config_store = QtWidgets.QApplication.instance().config_store
     self.image_list = image_list
     self.setLayout(QtWidgets.QHBoxLayout())
     self.layout().setContentsMargins(0, 0, 0, 0)
     # construct widgets
     self.enableable = []
     ## data fields
     form, self.widgets = self.data_form()
     self.enableable.append(form.widget())
     for key in self.widgets:
         self.widgets[key].editingFinished.connect(
             getattr(self, 'new_' + key))
     self.layout().addWidget(form)
     ## buttons
     buttons = QtWidgets.QVBoxLayout()
     buttons.addStretch(1)
     edit_template = QtWidgets.QPushButton(
         translate('OwnerTab', 'Edit\ntemplate'))
     edit_template.clicked.connect(self.edit_template)
     buttons.addWidget(edit_template)
     apply_template = QtWidgets.QPushButton(
         translate('OwnerTab', 'Apply\ntemplate'))
     apply_template.clicked.connect(self.apply_template)
     self.enableable.append(apply_template)
     buttons.addWidget(apply_template)
     self.layout().addLayout(buttons)
     # disable data entry until an image is selected
     self.set_enabled(False)
예제 #3
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
예제 #4
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
예제 #5
0
 def __init__(self, *arg, **kw):
     super(OffsetWidget, self).__init__(*arg, **kw)
     self.setLayout(QtWidgets.QHBoxLayout())
     self.layout().setContentsMargins(0, 0, 0, 0)
     # offset value
     self.offset = QtWidgets.QTimeEdit()
     self.offset.setDisplayFormat("'h:'hh 'm:'mm 's:'ss")
     self.layout().addWidget(self.offset)
     # add offset button
     add_button = SquareButton('+')
     add_button.clicked.connect(self.add)
     self.layout().addWidget(add_button)
     # subtract offset button
     sub_button = SquareButton('-')
     sub_button.clicked.connect(self.sub)
     self.layout().addWidget(sub_button)
     self.layout().addStretch(1)
예제 #6
0
 def __init__(self, *arg, **kw):
     super(OffsetWidget, self).__init__(*arg, **kw)
     self.config_store = QtWidgets.QApplication.instance().config_store
     self.setLayout(QtWidgets.QHBoxLayout())
     self.layout().setContentsMargins(0, 0, 0, 0)
     spacing = self.layout().spacing()
     self.layout().setSpacing(0)
     # offset value
     self.offset = QtWidgets.QTimeEdit()
     self.offset.setDisplayFormat("'h:'hh 'm:'mm 's:'ss")
     self.layout().addWidget(self.offset)
     self.layout().addSpacing(spacing)
     # time zone
     self.time_zone = TimeZoneWidget()
     self.time_zone.set_value(None)
     self.layout().addWidget(self.time_zone)
     self.layout().addSpacing(spacing)
     # add offset button
     add_button = QtWidgets.QPushButton(chr(0x002b))
     add_button.setStyleSheet('QPushButton {padding: 0px}')
     set_symbol_font(add_button)
     scale_font(add_button, 170)
     add_button.setFixedWidth(self.offset.sizeHint().height())
     add_button.setFixedHeight(self.offset.sizeHint().height())
     add_button.clicked.connect(self.add)
     self.layout().addWidget(add_button)
     # subtract offset button
     sub_button = QtWidgets.QPushButton(chr(0x2212))
     sub_button.setStyleSheet('QPushButton {padding: 0px}')
     set_symbol_font(sub_button)
     scale_font(sub_button, 170)
     sub_button.setFixedWidth(self.offset.sizeHint().height())
     sub_button.setFixedHeight(self.offset.sizeHint().height())
     sub_button.clicked.connect(self.sub)
     self.layout().addWidget(sub_button)
     self.layout().addStretch(1)
     # restore stored values
     value = self.config_store.get('technical', 'offset')
     if value:
         self.offset.setTime(QtCore.QTime(*value[0:3]))
         self.time_zone.set_value(value[3])
     # connections
     self.offset.editingFinished.connect(self.new_value)
     self.time_zone.editingFinished.connect(self.new_value)
예제 #7
0
 def __init__(self, *arg, **kw):
     super(LineEditWithAuto, self).__init__(*arg, **kw)
     self._is_multiple = False
     layout = QtWidgets.QHBoxLayout()
     layout.setContentsMargins(0, 0, 0, 0)
     self.setLayout(layout)
     # line edit box
     self.edit = LineEdit()
     layout.addWidget(self.edit)
     # auto complete button
     self.auto = QtWidgets.QPushButton(self.tr('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
예제 #8
0
 def __init__(self, *arg, **kw):
     super(RatingWidget, self).__init__(*arg, **kw)
     self.multiple_values = multiple_values()
     self.setLayout(QtWidgets.QHBoxLayout())
     self.layout().setContentsMargins(0, 0, 0, 0)
     # slider
     self.slider = Slider(Qt.Horizontal)
     self.slider.setFixedWidth(200)
     self.slider.setRange(-2, 5)
     self.slider.setPageStep(1)
     self.slider.valueChanged.connect(self.set_display)
     self.layout().addWidget(self.slider)
     # display
     self.display = QtWidgets.QLineEdit()
     self.display.setFrame(False)
     self.display.setReadOnly(True)
     self.layout().addWidget(self.display)
     # adopt child methods/signals
     self.is_multiple = self.slider.is_multiple
     self.editing_finished = self.slider.editing_finished
예제 #9
0
 def __init__(self, image_list, parent=None):
     super(TabWidget, self).__init__(parent)
     self.app = QtWidgets.QApplication.instance()
     self.geocoder = self.app.open_cage
     self.image_list = image_list
     self.setLayout(QtWidgets.QHBoxLayout())
     ## left side
     left_side = QtWidgets.QGridLayout()
     # latitude & longitude
     self.coords = LatLongDisplay(self.image_list)
     left_side.addWidget(self.coords.label, 0, 0)
     self.coords.changed.connect(self.new_coords)
     left_side.addWidget(self.coords, 0, 1)
     # convert lat/lng to location info
     self.auto_location = QtWidgets.QPushButton(
         translate('AddressTab', 'Get address from lat, long'))
     self.auto_location.setEnabled(False)
     self.auto_location.clicked.connect(self.get_address)
     left_side.addWidget(self.auto_location, 1, 0, 1, 2)
     # terms and conditions
     terms = self.geocoder.search_terms(search=False)
     left_side.addWidget(terms[0], 3, 0, 1, 2)
     left_side.addWidget(terms[1], 4, 0, 1, 2)
     left_side.setColumnStretch(1, 1)
     left_side.setRowStretch(2, 1)
     self.layout().addLayout(left_side)
     ## right side
     # 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)
     self.layout().addWidget(self.location_info, stretch=1)
     # other init
     self.image_list.image_list_changed.connect(self.image_list_changed)
예제 #10
0
 def __init__(self, *arg, **kw):
     super(RatingWidget, self).__init__(*arg, **kw)
     self.multiple_values = multiple_values()
     self.setLayout(QtWidgets.QHBoxLayout())
     self.layout().setContentsMargins(0, 0, 0, 0)
     # slider
     self.slider = Slider(Qt.Horizontal)
     self.slider.setFixedWidth(width_for_text(self.slider, 'x' * 25))
     self.slider.setRange(-2, 5)
     self.slider.setPageStep(1)
     self.slider.valueChanged.connect(self.set_display)
     self.layout().addWidget(self.slider)
     # display
     self.display = QtWidgets.QLineEdit()
     self.display.setStyleSheet("* {background-color:rgba(0,0,0,0);}")
     self.display.setFrame(False)
     self.display.setReadOnly(True)
     self.display.setContextMenuPolicy(Qt.NoContextMenu)
     self.display.setFocusPolicy(Qt.NoFocus)
     self.layout().addWidget(self.display)
     # adopt child methods/signals
     self.is_multiple = self.slider.is_multiple
     self.editing_finished = self.slider.editing_finished
예제 #11
0
 def __init__(self, image_list, parent=None):
     super(TabWidget, self).__init__(parent)
     app = QtWidgets.QApplication.instance()
     app.aboutToQuit.connect(self.shutdown)
     if gp and app.test_mode:
         self.gp_log = gp.check_result(gp.use_python_logging())
     self.config_store = app.config_store
     self.image_list = image_list
     self.setLayout(QtWidgets.QGridLayout())
     form = QtWidgets.QFormLayout()
     form.setFieldGrowthPolicy(QtWidgets.QFormLayout.AllNonFixedFieldsGrow)
     self.nm = NameMangler()
     self.file_data = {}
     self.file_list = []
     self.source = None
     self.file_copier = None
     # source selector
     box = QtWidgets.QHBoxLayout()
     box.setContentsMargins(0, 0, 0, 0)
     self.source_selector = QtWidgets.QComboBox()
     self.source_selector.currentIndexChanged.connect(self.new_source)
     box.addWidget(self.source_selector)
     refresh_button = QtWidgets.QPushButton(self.tr('refresh'))
     refresh_button.clicked.connect(self.refresh)
     box.addWidget(refresh_button)
     box.setStretch(0, 1)
     form.addRow(self.tr('Source'), box)
     # path format
     self.path_format = QtWidgets.QLineEdit()
     self.path_format.setValidator(PathFormatValidator())
     self.path_format.textChanged.connect(self.nm.new_format)
     self.path_format.editingFinished.connect(self.path_format_finished)
     form.addRow(self.tr('Target format'), self.path_format)
     # path example
     self.path_example = QtWidgets.QLabel()
     self.nm.new_example.connect(self.path_example.setText)
     form.addRow('=>', self.path_example)
     self.layout().addLayout(form, 0, 0)
     # file list
     self.file_list_widget = QtWidgets.QListWidget()
     self.file_list_widget.setSelectionMode(
         QtWidgets.QAbstractItemView.ExtendedSelection)
     self.file_list_widget.itemSelectionChanged.connect(
         self.selection_changed)
     self.layout().addWidget(self.file_list_widget, 1, 0)
     # selection buttons
     buttons = QtWidgets.QVBoxLayout()
     buttons.addStretch(1)
     self.selected_count = QtWidgets.QLabel()
     buttons.addWidget(self.selected_count)
     select_all = QtWidgets.QPushButton(self.tr('Select\nall'))
     select_all.clicked.connect(self.select_all)
     buttons.addWidget(select_all)
     select_new = QtWidgets.QPushButton(self.tr('Select\nnew'))
     select_new.clicked.connect(self.select_new)
     buttons.addWidget(select_new)
     # copy buttons
     self.move_button = StartStopButton(self.tr('Move\nphotos'),
                                        self.tr('Stop\nmove'))
     self.move_button.click_start.connect(self.move_selected)
     self.move_button.click_stop.connect(self.stop_copy)
     buttons.addWidget(self.move_button)
     self.copy_button = StartStopButton(self.tr('Copy\nphotos'),
                                        self.tr('Stop\ncopy'))
     self.copy_button.click_start.connect(self.copy_selected)
     self.copy_button.click_stop.connect(self.stop_copy)
     buttons.addWidget(self.copy_button)
     self.layout().addLayout(buttons, 0, 1, 2, 1)
     self.selection_changed()
     # final initialisation
     self.image_list.sort_order_changed.connect(self.sort_file_list)
     if qt_version_info >= (5, 0):
         path = QtCore.QStandardPaths.writableLocation(
             QtCore.QStandardPaths.PicturesLocation)
     else:
         path = QtGui.QDesktopServices.storageLocation(
             QtGui.QDesktopServices.PicturesLocation)
     self.path_format.setText(os.path.join(path, '%Y', '%Y_%m_%d',
                                           '{name}'))
     self.refresh()
     self.list_files()
예제 #12
0
 def __init__(self, image_list, *arg, **kw):
     super(TabWidget, self).__init__(*arg, **kw)
     self.config_store = QtWidgets.QApplication.instance().config_store
     self.image_list = image_list
     self.setLayout(QtWidgets.QHBoxLayout())
     self.widgets = {}
     self.date_widget = {}
     self.link_widget = {}
     # date and time
     date_group = QtWidgets.QGroupBox(
         translate('TechnicalTab', 'Date and time'))
     date_group.setLayout(QtWidgets.QFormLayout())
     # create date and link widgets
     for master in self._master_slave:
         self.date_widget[master] = DateAndTimeWidget(master)
         self.date_widget[master].new_value.connect(self.new_date_value)
         slave = self._master_slave[master]
         if slave:
             self.link_widget[master, slave] = DateLink(master)
             self.link_widget[master, slave].new_link.connect(self.new_link)
     self.link_widget['taken', 'digitised'].setText(
         translate('TechnicalTab', "Link 'taken' and 'digitised'"))
     self.link_widget['digitised', 'modified'].setText(
         translate('TechnicalTab', "Link 'digitised' and 'modified'"))
     # add to layout
     date_group.layout().addRow(translate('TechnicalTab', 'Taken'),
                                self.date_widget['taken'])
     date_group.layout().addRow('', self.link_widget['taken', 'digitised'])
     date_group.layout().addRow(translate('TechnicalTab', 'Digitised'),
                                self.date_widget['digitised'])
     date_group.layout().addRow('', self.link_widget['digitised', 'modified'])
     date_group.layout().addRow(translate('TechnicalTab', 'Modified'),
                                self.date_widget['modified'])
     # offset
     self.offset_widget = OffsetWidget()
     self.offset_widget.apply_offset.connect(self.apply_offset)
     date_group.layout().addRow(
         translate('TechnicalTab', 'Adjust times'), self.offset_widget)
     self.layout().addWidget(date_group)
     # other
     other_group = QtWidgets.QGroupBox(translate('TechnicalTab', 'Other'))
     other_group.setLayout(QtWidgets.QFormLayout())
     other_group.layout().setFieldGrowthPolicy(
         QtWidgets.QFormLayout.AllNonFixedFieldsGrow)
     # orientation
     self.widgets['orientation'] = DropdownEdit()
     self.widgets['orientation'].add_item(
         translate('TechnicalTab', 'normal'), 1, ordered=False)
     self.widgets['orientation'].add_item(
         translate('TechnicalTab', 'rotate -90'), 6, ordered=False)
     self.widgets['orientation'].add_item(
         translate('TechnicalTab', 'rotate +90'), 8, ordered=False)
     self.widgets['orientation'].add_item(
         translate('TechnicalTab', 'rotate 180'), 3, ordered=False)
     self.widgets['orientation'].add_item(
         translate('TechnicalTab', 'reflect left-right'), 2, ordered=False)
     self.widgets['orientation'].add_item(
         translate('TechnicalTab', 'reflect top-bottom'), 4, ordered=False)
     self.widgets['orientation'].add_item(
         translate('TechnicalTab', 'reflect tr-bl'), 5, ordered=False)
     self.widgets['orientation'].add_item(
         translate('TechnicalTab', 'reflect tl-br'), 7, ordered=False)
     self.widgets['orientation'].new_value.connect(self.new_orientation)
     other_group.layout().addRow(translate(
         'TechnicalTab', 'Orientation'), self.widgets['orientation'])
     # camera model
     self.widgets['camera_model'] = CameraList(extendable=True)
     self.widgets['camera_model'].setMinimumWidth(
         width_for_text(self.widgets['camera_model'], 'x' * 30))
     self.widgets['camera_model'].new_value.connect(self.new_camera_model)
     self.widgets['camera_model'].extend_list.connect(self.add_camera_model)
     other_group.layout().addRow(translate(
         'TechnicalTab', 'Camera'), self.widgets['camera_model'])
     # lens model
     self.widgets['lens_model'] = LensList(extendable=True)
     self.widgets['lens_model'].setMinimumWidth(
         width_for_text(self.widgets['lens_model'], 'x' * 30))
     self.widgets['lens_model'].new_value.connect(self.new_lens_model)
     self.widgets['lens_model'].extend_list.connect(self.add_lens_model)
     other_group.layout().addRow(translate(
         'TechnicalTab', 'Lens model'), self.widgets['lens_model'])
     # focal length
     self.widgets['focal_length'] = DoubleSpinBox()
     self.widgets['focal_length'].setMinimum(0.0)
     self.widgets['focal_length'].setSuffix(' mm')
     self.widgets['focal_length'].new_value.connect(self.new_focal_length)
     other_group.layout().addRow(translate(
         'TechnicalTab', 'Focal length'), self.widgets['focal_length'])
     # 35mm equivalent focal length
     self.widgets['focal_length_35'] = IntSpinBox()
     self.widgets['focal_length_35'].setMinimum(0)
     self.widgets['focal_length_35'].setSuffix(' mm')
     self.widgets['focal_length_35'].new_value.connect(self.new_focal_length_35)
     other_group.layout().addRow(translate(
         'TechnicalTab', '35mm equiv'), self.widgets['focal_length_35'])
     # aperture
     self.widgets['aperture'] = DoubleSpinBox()
     self.widgets['aperture'].setMinimum(0.0)
     self.widgets['aperture'].setPrefix('ƒ/')
     self.widgets['aperture'].new_value.connect(self.new_aperture)
     other_group.layout().addRow(translate(
         'TechnicalTab', 'Aperture'), self.widgets['aperture'])
     self.layout().addWidget(other_group, stretch=1)
     # disable until an image is selected
     self.setEnabled(False)
예제 #13
0
 def __init__(self, image_list, parent=None):
     super(TabWidget, self).__init__(parent)
     app = QtWidgets.QApplication.instance()
     app.aboutToQuit.connect(self.shutdown)
     if gp and app.test_mode:
         self.gp_log = gp.check_result(gp.use_python_logging())
     self.config_store = app.config_store
     self.image_list = image_list
     self.setLayout(QtWidgets.QGridLayout())
     form = QtWidgets.QFormLayout()
     form.setFieldGrowthPolicy(QtWidgets.QFormLayout.AllNonFixedFieldsGrow)
     self.nm = NameMangler()
     self.file_data = {}
     self.file_list = []
     self.source = None
     self.file_reader = None
     self.file_writer = None
     # source selector
     box = QtWidgets.QHBoxLayout()
     box.setContentsMargins(0, 0, 0, 0)
     self.source_selector = QtWidgets.QComboBox()
     self.source_selector.currentIndexChanged.connect(self.new_source)
     box.addWidget(self.source_selector)
     refresh_button = QtWidgets.QPushButton(self.tr('refresh'))
     refresh_button.clicked.connect(self.refresh)
     box.addWidget(refresh_button)
     box.setStretch(0, 1)
     form.addRow(self.tr('Source'), box)
     # path format
     self.path_format = QtWidgets.QLineEdit()
     self.path_format.setValidator(PathFormatValidator())
     self.path_format.textChanged.connect(self.nm.new_format)
     self.path_format.editingFinished.connect(self.path_format_finished)
     form.addRow(self.tr('Target format'), self.path_format)
     # path example
     self.path_example = QtWidgets.QLabel()
     self.nm.new_example.connect(self.path_example.setText)
     form.addRow('=>', self.path_example)
     self.layout().addLayout(form, 0, 0)
     # file list
     self.file_list_widget = QtWidgets.QListWidget()
     self.file_list_widget.setSelectionMode(
         QtWidgets.QAbstractItemView.ExtendedSelection)
     self.file_list_widget.itemSelectionChanged.connect(self.selection_changed)
     self.layout().addWidget(self.file_list_widget, 1, 0)
     # selection buttons
     buttons = QtWidgets.QVBoxLayout()
     buttons.addStretch(1)
     self.selected_count = QtWidgets.QLabel()
     self.selection_changed()
     buttons.addWidget(self.selected_count)
     select_all = QtWidgets.QPushButton(self.tr('Select\nall'))
     select_all.clicked.connect(self.select_all)
     buttons.addWidget(select_all)
     select_new = QtWidgets.QPushButton(self.tr('Select\nnew'))
     select_new.clicked.connect(self.select_new)
     buttons.addWidget(select_new)
     self.copy_button = StartStopButton(self.tr('Copy\nphotos'),
                                        self.tr('Stop\nimport'))
     self.copy_button.click_start.connect(self.copy_selected)
     self.copy_button.click_stop.connect(self.stop_copy)
     buttons.addWidget(self.copy_button)
     self.layout().addLayout(buttons, 0, 1, 2, 1)
     # final initialisation
     self.image_list.sort_order_changed.connect(self.sort_file_list)
     path = os.path.expanduser('~/Pictures')
     if not os.path.isdir(path) and sys.platform == 'win32':
         try:
             import win32com.shell as ws
             path = ws.shell.SHGetFolderPath(
                 0, ws.shellcon.CSIDL_MYPICTURES, None, 0)
         except ImportError:
             pass
     self.path_format.setText(
         os.path.join(path, '%Y', '%Y_%m_%d', '{name}'))
     self.refresh()
     self.list_files()
예제 #14
0
 def __init__(self, *arg, **kw):
     super(PicasaUploadConfig, self).__init__(*arg, **kw)
     self.setLayout(QtWidgets.QHBoxLayout())
     self.layout().setContentsMargins(0, 0, 0, 0)
     self.widgets = {}
     ## album details, left hand side
     album_group = QtWidgets.QGroupBox(self.tr('Collection / Album'))
     album_group.setLayout(QtWidgets.QHBoxLayout())
     album_form_left = QtWidgets.QFormLayout()
     album_form_left.setFieldGrowthPolicy(
         QtWidgets.QFormLayout.AllNonFixedFieldsGrow)
     album_group.layout().addLayout(album_form_left)
     # album title / selector
     self.albums = QtWidgets.QComboBox()
     self.albums.setEditable(True)
     self.albums.setInsertPolicy(QtWidgets.QComboBox.NoInsert)
     self.albums.activated.connect(self.switch_album)
     self.albums.lineEdit().editingFinished.connect(self.new_title)
     album_form_left.addRow(self.tr('Title'), self.albums)
     # album description
     self.widgets['description'] = MultiLineEdit(spell_check=True)
     self.widgets['description'].editingFinished.connect(
         self.new_album_details)
     album_form_left.addRow(self.tr('Description'),
                            self.widgets['description'])
     # album location
     self.widgets['location'] = QtWidgets.QLineEdit()
     self.widgets['location'].editingFinished.connect(
         self.new_album_details)
     album_form_left.addRow(self.tr('Place taken'),
                            self.widgets['location'])
     # album visibility
     self.widgets['access'] = QtWidgets.QComboBox()
     self.widgets['access'].addItem(self.tr('Public on the web'), 'public')
     self.widgets['access'].addItem(
         self.tr('Limited, anyone with the link'), 'private')
     self.widgets['access'].addItem(self.tr('Only you'), 'protected')
     self.widgets['access'].currentIndexChanged.connect(self.new_access)
     album_form_left.addRow(self.tr('Visibility'), self.widgets['access'])
     ## album buttons
     buttons = QtWidgets.QHBoxLayout()
     buttons.addStretch(stretch=60)
     album_form_left.addRow(buttons)
     # new album
     new_album_button = QtWidgets.QPushButton(self.tr('New album'))
     new_album_button.clicked.connect(self.new_album)
     buttons.addWidget(new_album_button, stretch=20)
     # delete album
     delete_album_button = QtWidgets.QPushButton(self.tr('Delete album'))
     delete_album_button.clicked.connect(self.delete_album)
     buttons.addWidget(delete_album_button, stretch=20)
     ## album details, right hand side
     album_form_right = QtWidgets.QFormLayout()
     album_form_right.setFieldGrowthPolicy(
         QtWidgets.QFormLayout.AllNonFixedFieldsGrow)
     album_group.layout().addLayout(album_form_right)
     # album date
     self.widgets['timestamp'] = QtWidgets.QDateEdit()
     self.widgets['timestamp'].setMinimumDateTime(
         QtCore.QDateTime.fromTime_t(0))
     self.widgets['timestamp'].setCalendarPopup(True)
     self.widgets['timestamp'].editingFinished.connect(
         self.new_album_details)
     album_form_right.addRow(self.tr('Date'), self.widgets['timestamp'])
     # album thumbnail
     self.album_thumb = QtWidgets.QLabel()
     self.album_thumb.setFixedWidth(160)
     album_form_right.addRow(self.album_thumb)
     self.layout().addWidget(album_group)
예제 #15
0
 def __init__(self, image_list, parent=None):
     super(TabWidget, self).__init__(parent)
     self.app = QtWidgets.QApplication.instance()
     self.app.aboutToQuit.connect(self.stop_copy)
     if gp and self.app.options.test:
         self.gp_log = gp.check_result(gp.use_python_logging())
     self.config_store = self.app.config_store
     self.image_list = image_list
     self.setLayout(QtWidgets.QGridLayout())
     form = QtWidgets.QFormLayout()
     form.setFieldGrowthPolicy(QtWidgets.QFormLayout.AllNonFixedFieldsGrow)
     self.nm = NameMangler()
     self.file_data = {}
     self.file_list = []
     self.source = None
     self.file_copier = None
     self.updating = QtCore.QMutex()
     # source selector
     box = QtWidgets.QHBoxLayout()
     box.setContentsMargins(0, 0, 0, 0)
     self.source_selector = QtWidgets.QComboBox()
     self.source_selector.currentIndexChanged.connect(self.new_source)
     self.source_selector.setContextMenuPolicy(Qt.CustomContextMenu)
     self.source_selector.customContextMenuRequested.connect(
         self.remove_folder)
     box.addWidget(self.source_selector)
     refresh_button = QtWidgets.QPushButton(
         translate('ImporterTab', 'refresh'))
     refresh_button.clicked.connect(self.refresh)
     box.addWidget(refresh_button)
     box.setStretch(0, 1)
     form.addRow(translate('ImporterTab', 'Source'), box)
     # update config
     self.config_store.delete('importer', 'folders')
     for section in self.config_store.config.sections():
         if not section.startswith('importer'):
             continue
         path_format = self.config_store.get(section, 'path_format')
         if not (path_format and '(' in path_format):
             continue
         path_format = path_format.replace('(', '{').replace(')', '}')
         self.config_store.set(section, 'path_format', path_format)
     # path format
     self.path_format = QtWidgets.QLineEdit()
     self.path_format.setValidator(PathFormatValidator())
     self.path_format.textChanged.connect(self.nm.new_format)
     self.path_format.editingFinished.connect(self.path_format_finished)
     form.addRow(translate('ImporterTab', 'Target format'),
                 self.path_format)
     # path example
     self.path_example = QtWidgets.QLabel()
     self.nm.new_example.connect(self.path_example.setText)
     form.addRow('=>', self.path_example)
     self.layout().addLayout(form, 0, 0)
     # file list
     self.file_list_widget = QtWidgets.QListWidget()
     self.file_list_widget.setSelectionMode(
         QtWidgets.QAbstractItemView.ExtendedSelection)
     self.file_list_widget.itemSelectionChanged.connect(
         self.selection_changed)
     self.layout().addWidget(self.file_list_widget, 1, 0)
     # selection buttons
     buttons = QtWidgets.QVBoxLayout()
     buttons.addStretch(1)
     self.selected_count = QtWidgets.QLabel()
     buttons.addWidget(self.selected_count)
     select_all = QtWidgets.QPushButton(
         translate('ImporterTab', 'Select\nall'))
     select_all.clicked.connect(self.select_all)
     buttons.addWidget(select_all)
     select_new = QtWidgets.QPushButton(
         translate('ImporterTab', 'Select\nnew'))
     select_new.clicked.connect(self.select_new)
     buttons.addWidget(select_new)
     # copy buttons
     self.move_button = StartStopButton(
         translate('ImporterTab', 'Move\nphotos'),
         translate('ImporterTab', 'Stop\nmove'))
     self.move_button.click_start.connect(self.move_selected)
     self.move_button.click_stop.connect(self.stop_copy)
     buttons.addWidget(self.move_button)
     self.copy_button = StartStopButton(
         translate('ImporterTab', 'Copy\nphotos'),
         translate('ImporterTab', 'Stop\ncopy'))
     self.copy_button.click_start.connect(self.copy_selected)
     self.copy_button.click_stop.connect(self.stop_copy)
     buttons.addWidget(self.copy_button)
     self.layout().addLayout(buttons, 0, 1, 2, 1)
     self.selection_changed()
     # final initialisation
     self.image_list.sort_order_changed.connect(self.sort_file_list)
     path = QtCore.QStandardPaths.writableLocation(
         QtCore.QStandardPaths.PicturesLocation)
     self.path_format.setText(os.path.join(path, '%Y', '%Y_%m_%d',
                                           '{name}'))
예제 #16
0
 def __init__(self, image_list, parent=None):
     super(PhotiniMap, self).__init__(parent)
     self.app = QtWidgets.QApplication.instance()
     self.image_list = image_list
     name = self.__module__.split('.')[-1]
     self.script_dir = pkg_resources.resource_filename(
         'photini', 'data/' + name + '/')
     self.drag_icon = QtGui.QPixmap(
         os.path.join(self.script_dir, '../map_pin_grey.png'))
     self.drag_hotspot = 11, 35
     self.search_string = None
     self.map_loaded = 0     # not loaded
     self.marker_info = {}
     self.map_status = {}
     self.dropped_images = []
     self.geocoder = self.get_geocoder()
     self.gpx_ids = []
     self.widgets = {}
     self.setLayout(QtWidgets.QHBoxLayout())
     ## left side
     left_side = QtWidgets.QGridLayout()
     # latitude & longitude
     self.widgets['latlon'] = LatLongDisplay(self.image_list)
     left_side.addWidget(self.widgets['latlon'].label, 0, 0)
     self.widgets['latlon'].changed.connect(self.new_coords)
     left_side.addWidget(self.widgets['latlon'], 0, 1)
     # altitude
     label = QtWidgets.QLabel(translate('MapTabsAll', 'Altitude'))
     label.setAlignment(Qt.AlignRight)
     left_side.addWidget(label, 1, 0)
     self.widgets['altitude'] = DoubleSpinBox()
     self.widgets['altitude'].setSuffix(' m')
     self.widgets['altitude'].new_value.connect(self.new_altitude)
     left_side.addWidget(self.widgets['altitude'], 1, 1)
     if hasattr(self.geocoder, 'get_altitude'):
         self.widgets['get_altitude'] = QtWidgets.QPushButton(
             translate('MapTabsAll', 'Get altitude from map'))
         self.widgets['get_altitude'].clicked.connect(self.get_altitude)
         left_side.addWidget(self.widgets['get_altitude'], 2, 1)
     else:
         self.widgets['get_altitude'] = None
     # search
     label = QtWidgets.QLabel(translate('MapTabsAll', 'Search'))
     label.setAlignment(Qt.AlignRight)
     left_side.addWidget(label, 3, 0)
     self.widgets['search'] = ComboBox()
     self.widgets['search'].setEditable(True)
     self.widgets['search'].setInsertPolicy(QtWidgets.QComboBox.NoInsert)
     self.widgets['search'].lineEdit().setPlaceholderText(
         translate('MapTabsAll', '<new search>'))
     self.widgets['search'].lineEdit().returnPressed.connect(self.search)
     self.widgets['search'].activated.connect(self.goto_search_result)
     self.clear_search()
     self.widgets['search'].setEnabled(False)
     left_side.addWidget(self.widgets['search'], 3, 1)
     # search terms and conditions
     for n, widget in enumerate(self.geocoder.search_terms()):
         left_side.addWidget(widget, n+4, 0, 1, 2)
     left_side.setColumnStretch(1, 1)
     left_side.setRowStretch(7, 1)
     # GPX importer
     if self.app.gpx_importer:
         button = QtWidgets.QPushButton(
             translate('MapTabsAll', 'Load GPX file'))
         button.clicked.connect(self.load_gpx)
         left_side.addWidget(button, 8, 1)
         self.widgets['set_from_gpx'] = QtWidgets.QPushButton(
             translate('MapTabsAll', 'Set coords from GPX'))
         self.widgets['set_from_gpx'].setEnabled(False)
         self.widgets['set_from_gpx'].clicked.connect(self.set_from_gpx)
         left_side.addWidget(self.widgets['set_from_gpx'], 9, 1)
         self.widgets['clear_gpx'] = QtWidgets.QPushButton(
             translate('MapTabsAll', 'Remove GPX data'))
         self.widgets['clear_gpx'].setEnabled(False)
         self.widgets['clear_gpx'].clicked.connect(self.clear_gpx)
         left_side.addWidget(self.widgets['clear_gpx'], 10, 1)
     self.layout().addLayout(left_side)
     # map
     # create handler for calls from JavaScript
     self.call_handler = CallHandler(parent=self)
     self.widgets['map'] = MapWebView(self.call_handler)
     self.widgets['map'].drop_text.connect(self.drop_text)
     self.widgets['map'].setAcceptDrops(False)
     self.layout().addWidget(self.widgets['map'])
     self.layout().setStretch(1, 1)
     # other init
     self.image_list.image_list_changed.connect(self.image_list_changed)
예제 #17
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)
예제 #18
0
 def __init__(self, image_list, *arg, **kw):
     super(Technical, self).__init__(*arg, **kw)
     self.config_store = QtWidgets.QApplication.instance().config_store
     self.image_list = image_list
     self.setLayout(QtWidgets.QHBoxLayout())
     self.widgets = {}
     self.date_widget = {}
     self.link_widget = {}
     # store lens data in another object
     self.lens_data = LensData()
     # date and time
     date_group = QtWidgets.QGroupBox(self.tr('Date and time'))
     date_group.setLayout(QtWidgets.QFormLayout())
     # create date and link widgets
     for master in self._master_slave:
         self.date_widget[master] = DateAndTimeWidget(master)
         self.date_widget[master].new_value.connect(self.new_date_value)
         slave = self._master_slave[master]
         if slave:
             self.link_widget[master, slave] = DateLink(master)
             self.link_widget[master, slave].new_link.connect(self.new_link)
     self.link_widget['taken', 'digitised'].setText(
         self.tr("Link 'taken' and 'digitised'"))
     self.link_widget['digitised', 'modified'].setText(
         self.tr("Link 'digitised' and 'modified'"))
     # add to layout
     date_group.layout().addRow(self.tr('Taken'),
                                self.date_widget['taken'])
     date_group.layout().addRow('', self.link_widget['taken', 'digitised'])
     date_group.layout().addRow(self.tr('Digitised'),
                                self.date_widget['digitised'])
     date_group.layout().addRow('', self.link_widget['digitised', 'modified'])
     date_group.layout().addRow(self.tr('Modified'),
                                self.date_widget['modified'])
     # offset
     self.offset_widget = OffsetWidget()
     self.offset_widget.apply_offset.connect(self.apply_offset)
     date_group.layout().addRow(self.tr('Adjust times'), self.offset_widget)
     self.layout().addWidget(date_group)
     # other
     other_group = QtWidgets.QGroupBox(self.tr('Other'))
     other_group.setLayout(QtWidgets.QFormLayout())
     other_group.layout().setFieldGrowthPolicy(
         QtWidgets.QFormLayout.AllNonFixedFieldsGrow)
     # orientation
     self.widgets['orientation'] = DropdownEdit()
     self.widgets['orientation'].add_item(self.tr('normal'), 1)
     self.widgets['orientation'].add_item(self.tr('rotate -90'), 6)
     self.widgets['orientation'].add_item(self.tr('rotate +90'), 8)
     self.widgets['orientation'].add_item(self.tr('rotate 180'), 3)
     self.widgets['orientation'].add_item(self.tr('reflect left-right'), 2)
     self.widgets['orientation'].add_item(self.tr('reflect top-bottom'), 4)
     self.widgets['orientation'].add_item(self.tr('reflect tr-bl'), 5)
     self.widgets['orientation'].add_item(self.tr('reflect tl-br'), 7)
     self.widgets['orientation'].new_value.connect(self.new_orientation)
     other_group.layout().addRow(
         self.tr('Orientation'), self.widgets['orientation'])
     # lens model
     self.widgets['lens_model'] = DropdownEdit()
     self.widgets['lens_model'].setMinimumWidth(
         self.widgets['lens_model'].fontMetrics().width('x' * 30))
     self.widgets['lens_model'].setContextMenuPolicy(Qt.CustomContextMenu)
     self.widgets['lens_model'].add_item(
         self.tr('<define new lens>'), '<add lens>')
     for model in self.lens_data.lenses:
         self.widgets['lens_model'].add_item(model, model)
     self.widgets['lens_model'].new_value.connect(self.new_lens_model)
     self.widgets['lens_model'].customContextMenuRequested.connect(
         self.remove_lens_model)
     other_group.layout().addRow(
         self.tr('Lens model'), self.widgets['lens_model'])
     # lens specification
     self.widgets['lens_spec'] = LensSpecWidget()
     other_group.layout().addRow(
         self.tr('Lens details'), self.widgets['lens_spec'])
     # focal length
     self.widgets['focal_length'] = NumberEdit()
     self.widgets['focal_length'].setValidator(DoubleValidator())
     self.widgets['focal_length'].validator().setBottom(0.1)
     self.widgets['focal_length'].new_value.connect(self.new_focal_length)
     other_group.layout().addRow(
         self.tr('Focal length (mm)'), self.widgets['focal_length'])
     # 35mm equivalent focal length
     self.widgets['focal_length_35'] = NumberEdit()
     self.widgets['focal_length_35'].setValidator(IntValidator())
     self.widgets['focal_length_35'].validator().setBottom(1)
     self.widgets['focal_length_35'].new_value.connect(self.new_focal_length_35)
     other_group.layout().addRow(
         self.tr('35mm equiv (mm)'), self.widgets['focal_length_35'])
     # aperture
     self.widgets['aperture'] = NumberEdit()
     self.widgets['aperture'].setValidator(DoubleValidator())
     self.widgets['aperture'].validator().setBottom(0.1)
     self.widgets['aperture'].new_value.connect(self.new_aperture)
     other_group.layout().addRow(
         self.tr('Aperture f/'), self.widgets['aperture'])
     self.layout().addWidget(other_group, stretch=1)
     # disable until an image is selected
     self.setEnabled(False)
예제 #19
0
 def __init__(self, *arg, **kw):
     super(FacebookUploadConfig, self).__init__(*arg, **kw)
     self.setLayout(QtWidgets.QHBoxLayout())
     self.layout().setContentsMargins(0, 0, 0, 0)
     self.widgets = {}
     ## upload config
     config_group = QtWidgets.QGroupBox(self.tr('Options'))
     config_group.setLayout(QtWidgets.QFormLayout())
     self.layout().addWidget(config_group)
     # suppress feed story
     self.widgets['no_story'] = QtWidgets.QCheckBox()
     config_group.layout().addRow(self.tr('Suppress news feed story'),
                                  self.widgets['no_story'])
     label = config_group.layout().labelForField(self.widgets['no_story'])
     label.setWordWrap(True)
     label.setFixedWidth(90)
     # geotagging
     self.widgets['geo_tag'] = QtWidgets.QCheckBox()
     config_group.layout().addRow(
         self.tr('Set "city" from map coordinates'),
         self.widgets['geo_tag'])
     self.widgets['geo_tag'].setChecked(True)
     label = config_group.layout().labelForField(self.widgets['geo_tag'])
     label.setWordWrap(True)
     label.setFixedWidth(90)
     # optimise
     self.widgets['optimise'] = QtWidgets.QCheckBox()
     config_group.layout().addRow(self.tr('Optimise image size'),
                                  self.widgets['optimise'])
     label = config_group.layout().labelForField(self.widgets['optimise'])
     label.setWordWrap(True)
     label.setFixedWidth(90)
     if PIL:
         self.widgets['optimise'].setChecked(True)
     else:
         self.widgets['optimise'].setEnabled(False)
         label.setEnabled(False)
     ## album details
     album_group = QtWidgets.QGroupBox(self.tr('Album'))
     album_group.setLayout(QtWidgets.QHBoxLayout())
     # left hand side
     album_form_left = QtWidgets.QFormLayout()
     album_form_left.setFieldGrowthPolicy(
         QtWidgets.QFormLayout.AllNonFixedFieldsGrow)
     album_group.layout().addLayout(album_form_left)
     # album title / selector
     self.widgets['album_choose'] = QtWidgets.QComboBox()
     self.widgets['album_choose'].activated.connect(self.select_album)
     album_form_left.addRow(self.tr('Title'), self.widgets['album_choose'])
     # album description
     self.widgets['album_description'] = QtWidgets.QPlainTextEdit()
     self.widgets['album_description'].setReadOnly(True)
     policy = self.widgets['album_description'].sizePolicy()
     policy.setVerticalStretch(1)
     self.widgets['album_description'].setSizePolicy(policy)
     album_form_left.addRow(self.tr('Description'),
                            self.widgets['album_description'])
     # album location
     self.widgets['album_location'] = QtWidgets.QLineEdit()
     self.widgets['album_location'].setReadOnly(True)
     album_form_left.addRow(self.tr('Location'),
                            self.widgets['album_location'])
     # right hand side
     album_form_right = QtWidgets.QVBoxLayout()
     album_group.layout().addLayout(album_form_right)
     # album thumbnail
     self.widgets['album_thumb'] = QtWidgets.QLabel()
     self.widgets['album_thumb'].setFixedSize(150, 150)
     self.widgets['album_thumb'].setAlignment(Qt.AlignHCenter | Qt.AlignTop)
     album_form_right.addWidget(self.widgets['album_thumb'])
     album_form_right.addStretch(1)
     # new album
     new_album_button = QtWidgets.QPushButton(self.tr('New album'))
     new_album_button.clicked.connect(self.new_album)
     album_form_right.addWidget(new_album_button)
     self.layout().addWidget(album_group, stretch=1)