def minimumSize(self): size = QtCore.QSize() for item in self.item_list: size = size.expandedTo(item.minimumSize()) left, top, right, bottom = self.getContentsMargins() size += QtCore.QSize(left + right, top + bottom) return size
def _do_layout(self, origin): left, top, right, bottom = self.getContentsMargins() width_hint = left + right height_hint = top + bottom if self.item_list: item_size = self.item_list[0].sizeHint() item_h = item_size.height() item_w = item_size.width() multi_row = self.viewport_size.height() - height_hint > item_h if multi_row: columns = max( (self.viewport_size.width() - width_hint) // item_w, 1) rows = (len(self.item_list) + columns - 1) // columns else: columns = len(self.item_list) rows = 1 width_hint += columns * item_w height_hint += rows * item_h self.size_hint = QtCore.QSize(width_hint, height_hint) if not self.item_list: return x = origin.x() + left y = origin.y() + top for n, item in enumerate(self.item_list): i, j = n % columns, n // columns item.setGeometry( QtCore.QRect(QtCore.QPoint(x + (i * item_w), y + (j * item_h)), item_size)) self.scroll_area.set_multi_row(multi_row)
def convert(value): if value['data'] and not value['image']: buf = QtCore.QBuffer() buf.setData(value['data']) reader = QtGui.QImageReader(buf) reader.setAutoTransform(False) value['fmt'] = reader.format().data().decode().upper() value['image'] = reader.read() if value['image'].isNull(): logger.error('thumbnail: %s', reader.errorString()) value['image'] = None # don't keep reference to what might be an entire image file value['data'] = None if value['image'] and not value['data']: buf = QtCore.QBuffer() buf.open(buf.WriteOnly) value['fmt'] = 'JPEG' value['image'].save(buf, value['fmt']) value['data'] = buf.data().data() if value['image']: value['w'] = value['image'].width() value['h'] = value['image'].height() else: value['w'] = 0 value['h'] = 0 return value
def main(argv=None): if argv: sys.argv = argv # let PyQt handle its options (need at least one argument after options) sys.argv.append('xxx') app = QtWidgets.QApplication(sys.argv) del sys.argv[-1] # install translation if qt_version_info < (5, 0): QtCore.QTextCodec.setCodecForTr( QtCore.QTextCodec.codecForName('utf-8')) locale = QtCore.QLocale.system() translator = QtCore.QTranslator(parent=app) translator.load(locale, 'photini', '.', pkg_resources.resource_filename('photini', 'data/lang'), '.qm') app.installTranslator(translator) qt_translator = QtCore.QTranslator(parent=app) qt_translator.load( locale, 'qt', '_', QtCore.QLibraryInfo.location(QtCore.QLibraryInfo.TranslationsPath)) app.installTranslator(qt_translator) # parse remaining arguments version = 'Photini ' + __version__ + ', build ' + build version += '\n Python ' + sys.version version += '\n ' + gexiv2_version version += '\n PyQt {}, Qt {}'.format(QtCore.PYQT_VERSION_STR, QtCore.QT_VERSION_STR) if QtWebEngineWidgets: version += ', using QtWebEngineWidgets' if enchant_version: version += '\n ' + enchant_version if FlickrUploader: from photini.flickr import flickr_version version += '\n ' + flickr_version parser = OptionParser(usage=six.text_type( QtCore.QCoreApplication.translate( 'main', 'Usage: %prog [options] [file_name, ...]')), version=version, description=six.text_type( QtCore.QCoreApplication.translate( 'main', 'Photini photo metadata editor'))) parser.add_option('-t', '--test', action='store_true', help=six.text_type( QtCore.QCoreApplication.translate( 'main', 'test new features or API versions'))) parser.add_option('-v', '--verbose', action='count', default=0, help=six.text_type( QtCore.QCoreApplication.translate( 'main', 'increase number of logging messages'))) options, args = parser.parse_args() # create GUI and run application event loop main = MainWindow(options, args) main.show() return app.exec_()
def mouseMoveEvent(self, event): if not self.image_list.drag_icon: return if qt_version_info >= (6, 0): pos = event.position() else: pos = event.pos() if ((pos - self.drag_start_pos).manhattanLength() < QtWidgets.QApplication.startDragDistance()): return if not self.get_selected(): # user has started dragging an unselected image self.image_list.select_image(self) paths = [] for image in self.image_list.get_selected_images(): paths.append(image.path) if not paths: return drag = QtGui.QDrag(self) # construct icon count = min(len(paths), 8) src_icon = self.image_list.drag_icon src_w = src_icon.width() src_h = src_icon.height() margin = (count - 1) * 4 if count == 1: icon = src_icon else: icon = QtGui.QPixmap(src_w + margin, src_h + margin) icon.fill(Qt.transparent) try: paint = QtGui.QPainter(icon) for i in range(count): paint.drawPixmap(QtCore.QPoint(margin - (i * 4), i * 4), src_icon) finally: del paint drag.setPixmap(icon) if self.image_list.drag_hotspot: x, y = self.image_list.drag_hotspot else: x, y = src_w // 2, src_h drag.setHotSpot(QtCore.QPoint(x, y + margin)) mimeData = QtCore.QMimeData() mimeData.setData(DRAG_MIMETYPE, repr(paths).encode('utf-8')) drag.setMimeData(mimeData) if qt_version_info >= (6, 0): drag.exec(Qt.CopyAction) else: drag.exec_(Qt.CopyAction)
class StreamProxy(QtCore.QObject): # only the GUI thread is allowed to write messages in the # LoggerWindow, so this class acts as a proxy, passing messages # over Qt signal/slot for thread safety flush_text = QtCore.pyqtSignal() write_text = QtCore.pyqtSignal(str) def write(self, msg): msg = msg.strip() if msg: self.write_text.emit(msg) def flush(self): self.flush_text.emit()
def __init__(self, *arg, **kw): self.default_value = QtCore.QDateTime( QtCore.QDate.currentDate(), QtCore.QTime()) self.multiple = multiple_values() # rename some methods for compatibility with AugmentSpinBox self.minimum = self.minimumDateTime self.setValue = self.setDateTime self.textFromValue = self.textFromDateTime self.value = self.dateTime super(DateTimeEdit, self).__init__(*arg, **kw) self.init_augment() self.setCalendarPopup(True) self.setCalendarWidget(CalendarWidget()) self.precision = 1 self.set_precision(7)
def main(argv=None): root = os.path.dirname(os.path.dirname(os.path.realpath(__file__))) lang_dir = os.path.join(root, 'src', 'photini', 'data', 'lang') translator = QtCore.QTranslator() cmd = [] for name in os.listdir(lang_dir): lang = name.split('.')[1] if lang == 'en': continue if not translator.load('photini.' + lang, lang_dir): print('load failed:', lang) continue text = translator.translate('MenuBar', 'Photini photo metadata editor') if text: cmd += ['--set-key=GenericName[{}]'.format(lang), '--set-value={}'.format(text.strip())] text = translator.translate('MenuBar', 'An easy to use digital photograph metadata' ' (Exif, IPTC, XMP) editing application.') if text: cmd += ['--set-key=Comment[{}]'.format(lang), '--set-value={}'.format(text.strip())] if not cmd: return 0 desktop_file = os.path.join( root, 'src', 'photini', 'data', 'linux', 'photini.desktop') cmd = ['desktop-file-edit'] + cmd + [desktop_file] return subprocess.call(cmd)
def __init__(self, *args, **kwds): super(GeocoderBase, self).__init__(*args, **kwds) self.app = QtWidgets.QApplication.instance() self.block_timer = QtCore.QTimer(self) self.block_timer.setInterval(self.interval) self.block_timer.setSingleShot(True) self.query_cache = OrderedDict()
def start_upload(self): if not self.image_list.unsaved_files_dialog(with_discard=False): return # make list of items to upload upload_list = [] for image in self.image_list.get_selected_images(): params = self.get_upload_params(image) if not params: continue convert = self.get_conversion_function(image, params) if convert == 'omit': continue upload_list.append((image, convert, params)) if not upload_list: self.upload_button.setChecked(False) return self.upload_button.set_checked(True) self.upload_config.setEnabled(False) self.user_connect.setEnabled(False) # do uploading in separate thread, so GUI can continue self.upload_worker = UploadWorker(self.session_factory, upload_list) thread = QtCore.QThread(self) self.upload_worker.moveToThread(thread) self.upload_worker.upload_error.connect( self.upload_error, Qt.BlockingQueuedConnection) self.abort_upload.connect( self.upload_worker.abort_upload, Qt.DirectConnection) self.upload_worker.upload_progress.connect(self.upload_progress) thread.started.connect(self.upload_worker.start) self.upload_worker.finished.connect(self.uploader_finished) self.upload_worker.finished.connect(thread.quit) self.upload_worker.finished.connect(self.upload_worker.deleteLater) thread.finished.connect(thread.deleteLater) thread.start()
class NumberEdit(QtWidgets.QLineEdit): new_value = QtCore.pyqtSignal(six.text_type) def __init__(self, *arg, **kw): super(NumberEdit, self).__init__(*arg, **kw) self.multiple = multiple_values() self.textEdited.connect(self.text_edited) self.editingFinished.connect(self.editing_finished) @QtCore.pyqtSlot(six.text_type) @catch_all def text_edited(self, text): self.setPlaceholderText('') @QtCore.pyqtSlot() @catch_all def editing_finished(self): if self.placeholderText() != self.multiple: self.new_value.emit(self.text()) def set_value(self, value): self.setPlaceholderText('') if value: self.setText(str(value)) else: self.clear() def set_multiple(self): self.setPlaceholderText(self.multiple) self.clear()
def copy_selected(self, move=False): copy_list = [] for item in self.file_list_widget.selectedItems(): name = item.data(Qt.UserRole) info = self.file_data[name] if (move and 'path' in info and self.image_list.get_image(info['path'])): # don't rename an open file logger.warning('Please close image %s before moving it', info['name']) else: copy_list.append(info) if not copy_list: return if move: self.move_button.set_checked(True) self.copy_button.setEnabled(False) else: self.copy_button.set_checked(True) self.move_button.setEnabled(False) self.last_file_copied = None, datetime.min # start file copier in a separate thread self.file_copier = FileCopier(self.source, copy_list, move, self.updating) self.file_copier_thread = QtCore.QThread(self) self.file_copier.moveToThread(self.file_copier_thread) self.file_copier.output.connect(self.file_copied) self.file_copier_thread.started.connect(self.file_copier.start) self.file_copier_thread.start()
class FileCopier(QtCore.QObject): output = QtCore.pyqtSignal(dict, six.text_type) def __init__(self, source, copy_list, move, updating, *args, **kwds): super(FileCopier, self).__init__(*args, **kwds) self.source = source self.copy_list = copy_list self.move = move self.updating = updating self.running = True @QtCore.pyqtSlot() @catch_all def start(self): status = 'ok' try: for info in self.source.copy_files(self.copy_list, self.move): # don't display image until previous one has been displayed self.updating.lock() self.output.emit(info, status) self.updating.unlock() if not self.running: break except Exception as ex: status = str(ex) logger.error(status) self.output.emit({}, status)
def __init__(self, *arg, **kw): super(OpenStreetMap, self).__init__(*arg, **kw) self.block_timer = QtCore.QTimer(self) self.block_timer.setInterval(10000) self.block_timer.setSingleShot(True) self.block_timer.timeout.connect(self.enable_search) self.api_key = key_store.get('opencagedata', 'api_key')
class MapWebView(QWebView): drop_text = QtCore.pyqtSignal(int, int, six.text_type) def __init__(self, call_handler, *args, **kwds): super(MapWebView, self).__init__(*args, **kwds) # set view's page if using_qtwebengine: self.setPage(MapWebEnginePage(call_handler, parent=self)) self.settings().setAttribute( QWebSettings.Accelerated2dCanvasEnabled, False) else: self.setPage(MapWebKitPage(call_handler, parent=self)) self.settings().setAttribute( QWebSettings.LocalContentCanAccessRemoteUrls, True) self.settings().setAttribute( QWebSettings.LocalContentCanAccessFileUrls, True) @catch_all def dragEnterEvent(self, event): if not event.mimeData().hasFormat(DRAG_MIMETYPE): return super(MapWebView, self).dragEnterEvent(event) event.acceptProposedAction() @catch_all def dragMoveEvent(self, event): if not event.mimeData().hasFormat(DRAG_MIMETYPE): return super(MapWebView, self).dragMoveEvent(event) @catch_all def dropEvent(self, event): if not event.mimeData().hasFormat(DRAG_MIMETYPE): return super(MapWebView, self).dropEvent(event) text = event.mimeData().data(DRAG_MIMETYPE).data().decode('utf-8') if text: self.drop_text.emit(event.pos().x(), event.pos().y(), text)
def start_upload(self): if not self.image_list.unsaved_files_dialog(with_discard=False): return # make list of items to upload self.upload_list = [] for image in self.image_list.get_selected_images(): params = self.get_upload_params(image) if not params: continue convert = self.get_conversion_function(image, params) if convert == 'omit': continue self.upload_list.append((image, convert, params)) if not self.upload_list: self.upload_button.setChecked(False) return self.upload_button.set_checked(True) # start uploading in separate thread, so GUI can continue self.upload_worker = UploadWorker(self.session_factory) self.upload_worker_thread = QtCore.QThread(self) self.upload_worker.moveToThread(self.upload_worker_thread) self.upload_file.connect(self.upload_worker.upload_file) self.upload_worker.upload_progress.connect( self.total_progress.setValue) self.upload_worker.upload_file_done.connect(self.upload_file_done) self.upload_worker_thread.started.connect(self.upload_worker.start) self.upload_worker_thread.start() self.upload_config.setEnabled(False) self.user_connect.setEnabled(False) self.uploads_done = 0 self.next_upload()
def available_languages(): result = defaultdict(list) if Gspell: for lang in Gspell.Language.get_available(): code = lang.get_code() name = lang.get_name() match = re.match('(.+)\s+\((.+?)\)', name) if match: language = match.group(1) country = match.group(2) if country == 'any': country = '' else: language = name country = '' result[language].append((country, code)) elif enchant: for code in enchant.list_languages(): locale = QtCore.QLocale(code) language = locale.languageToString(locale.language()) if '_' in code and '_ANY' not in code: country = locale.countryToString(locale.country()) else: country = '' result[language].append((country, code)) else: return None for value in result.values(): value.sort() return dict(result) or None
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)
def __init__(self, name, *arg, **kw): super(ConfigStore, self).__init__(name, *arg, **kw) QtCore.QCoreApplication.instance().aboutToQuit.connect(self.save) self.timer = QtCore.QTimer(self) self.timer.setSingleShot(True) self.timer.setInterval(3000) self.timer.timeout.connect(self.save)
def __init__(self, session_factory, params): super(UploadWorker, self).__init__() self.session = session_factory(auto_refresh=False) self.params = params self.fileobj = None self.thread = QtCore.QThread(self) self.moveToThread(self.thread)
class OffsetWidget(QtWidgets.QWidget): apply_offset = QtCore.pyqtSignal(timedelta, object) 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) @QtCore.pyqtSlot() def new_value(self): value = self.offset.time() value = (value.hour(), value.minute(), value.second(), self.time_zone.get_value()) self.config_store.set('technical', 'offset', str(value)) @QtCore.pyqtSlot() def add(self): value = self.offset.time() offset = timedelta(hours=value.hour(), minutes=value.minute(), seconds=value.second()) self.apply_offset.emit(offset, self.time_zone.get_value()) @QtCore.pyqtSlot() def sub(self): value = self.offset.time() offset = timedelta(hours=value.hour(), minutes=value.minute(), seconds=value.second()) tz_offset = self.time_zone.get_value() if isinstance(tz_offset, int): tz_offset = -tz_offset self.apply_offset.emit(-offset, tz_offset)
def _do_layout(self, rect, test_only): left, top, right, bottom = self.getContentsMargins() effective_rect = rect.adjusted(left, top, -right, -bottom) x = effective_rect.x() y = effective_rect.y() row_height = 0 for item in self.item_list: item_size = item.sizeHint() if x + item_size.width() > effective_rect.right() and row_height > 0: x = effective_rect.x() y += row_height row_height = 0 if not test_only: item.setGeometry(QtCore.QRect(QtCore.QPoint(x, y), item_size)) x += item_size.width() row_height = max(row_height, item_size.height()) return y + row_height - rect.y() + bottom
class MultiLineEdit(QtWidgets.QPlainTextEdit): editingFinished = QtCore.pyqtSignal() def __init__(self, spell_check=False, *arg, **kw): super(MultiLineEdit, self).__init__(*arg, **kw) self.multiple_values = multiple_values() self.setTabChangesFocus(True) self._is_multiple = False if spell_check: self.spell_check = SpellingHighlighter(self.document()) else: self.spell_check = None def focusOutEvent(self, event): self.editingFinished.emit() super(MultiLineEdit, self).focusOutEvent(event) def contextMenuEvent(self, event): menu = self.createStandardContextMenu() suggestion_group = QtWidgets.QActionGroup(menu) if self.spell_check: cursor = self.cursorForPosition(event.pos()) cursor.select(QtGui.QTextCursor.WordUnderCursor) word = cursor.selectedText() suggestions = self.spell_check.suggestions(word) if suggestions: sep = menu.insertSeparator(menu.actions()[0]) for suggestion in suggestions: action = QtWidgets.QAction(suggestion, suggestion_group) menu.insertAction(sep, action) action = menu.exec_(event.globalPos()) if action and action.actionGroup() == suggestion_group: cursor = self.cursorForPosition(event.pos()) cursor.select(QtGui.QTextCursor.WordUnderCursor) cursor.insertText(action.text()) def set_value(self, value): self._is_multiple = False if not value: self.clear() if qt_version_info >= (5, 3): self.setPlaceholderText('') else: self.setPlainText(six.text_type(value)) def get_value(self): return self.toPlainText() def set_multiple(self): self._is_multiple = True if qt_version_info >= (5, 3): self.setPlaceholderText(self.multiple_values) self.clear() else: self.setPlainText(self.multiple_values) def is_multiple(self): return self._is_multiple and not bool(self.get_value())
class AuthServer(QtCore.QObject): finished = QtCore.Signal() response = QtCore.Signal(dict) @QtCore.Slot() @catch_all def handle_requests(self): self.server.timeout = 10 self.server.result = None # allow user 5 minutes to finish the process timeout = time.time() + 300 while time.time() < timeout: self.server.handle_request() if self.server.result: self.response.emit(self.server.result) break self.server.server_close() self.finished.emit()
def authorise(self): with Busy(): # do full authentication procedure if self.auth_server: self.auth_server.running = False self.auth_server_thread.quit() self.auth_server = AuthServer() self.auth_server_thread = QtCore.QThread(self) self.auth_server.moveToThread(self.auth_server_thread) self.auth_server.response.connect(self.auth_response) self.auth_server_thread.started.connect(self.auth_server.start) self.auth_server_thread.start() redirect_uri = 'http://127.0.0.1:' + str(self.auth_server.port) auth_url = self.session.get_auth_url(redirect_uri) if not QtGui.QDesktopServices.openUrl(QtCore.QUrl(auth_url)): logger.error('Failed to open web browser') self.auth_server.running = False self.auth_server = None self.auth_server_thread.quit()
class UploadWorker(QtCore.QObject): upload_progress = QtCore.pyqtSignal(float) upload_file_done = QtCore.pyqtSignal(object, six.text_type) def __init__(self, session_factory, *args, **kwds): super(UploadWorker, self).__init__(*args, **kwds) self.session_factory = session_factory self.session = None self.fileobj = None @QtCore.pyqtSlot() @catch_all def start(self): self.session = self.session_factory() self.session.connect() def abort_upload(self): if self.fileobj: self.fileobj.close() self.fileobj = None @QtCore.pyqtSlot(object, object, object) @catch_all def upload_file(self, image, convert, params): if convert: path = convert(image) else: path = image.path with open(path, 'rb') as f: self.fileobj = FileObjWithCallback(f, self.upload_progress.emit) try: error = self.session.do_upload(self.fileobj, imghdr.what(path), image, params) except Exception as ex: error = str(ex) if convert: os.unlink(path) if self.fileobj: self.fileobj = None self.upload_file_done.emit(image, error) else: # upload was aborted self.upload_file_done.emit(None, '')
class LocationWidgets(QtCore.QObject): new_value = QtCore.pyqtSignal(str, str) 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) def __getitem__(self, key): return self.members[key] @QtCore.pyqtSlot() def new_sublocation(self): self.send_value('sublocation') @QtCore.pyqtSlot() def new_city(self): self.send_value('city') @QtCore.pyqtSlot() def new_province_state(self): self.send_value('province_state') @QtCore.pyqtSlot() def new_country_name(self): self.send_value('country_name') @QtCore.pyqtSlot() def new_country_code(self): self.send_value('country_code') @QtCore.pyqtSlot() def new_world_region(self): self.send_value('world_region') def send_value(self, key): self.new_value.emit(key, self.members[key].get_value())
class NameMangler(QtCore.QObject): number_parser = re.compile('\D*(\d+)') new_example = QtCore.pyqtSignal(str) def __init__(self, parent=None): super(NameMangler, self).__init__(parent) self.example = None self.format_string = None @QtCore.pyqtSlot(str) def new_format(self, format_string): self.format_string = format_string # extract bracket delimited words from string self.parts = [] while format_string: parts = format_string.split('(', 1) if len(parts) > 1: parts[1:] = parts[1].split(')', 1) if len(parts) < 3: self.parts.append((format_string, '')) break self.parts.append((parts[0], parts[1])) format_string = parts[2] self.refresh_example() def set_example(self, example): self.example = example self.refresh_example() def refresh_example(self): if self.format_string and self.example: self.new_example.emit(self.transform(self.example)) def transform(self, file_data): name = file_data['name'] subst = {'name': name} match = self.number_parser.match(name) if match: subst['number'] = match.group(1) else: subst['number'] = '' subst['root'], subst['ext'] = os.path.splitext(name) subst['camera'] = file_data['camera'] or 'unknown_camera' subst['camera'] = subst['camera'].replace(' ', '_') result = '' # process (...) parts first for left, right in self.parts: result += left if right in subst: result += subst[right] else: result += right # then do timestamp return file_data['timestamp'].strftime(result)
def resizeEvent(self, event): super(ScrollArea, self).resizeEvent(event) width = event.size().width() height = event.size().height() if not self.multi_row: scrollbar = self.verticalScrollBar() width -= scrollbar.width() scrollbar = self.horizontalScrollBar() if not scrollbar.isVisible(): height -= scrollbar.height() self.thumbs.set_viewport_size(QtCore.QSize(width, height))
class DateAndTimeWidget(QtWidgets.QGridLayout): new_value = QtCore.pyqtSignal(object) def __init__(self, *arg, **kw): super(DateAndTimeWidget, self).__init__(*arg, **kw) self.setContentsMargins(0, 0, 0, 0) self.setColumnStretch(3, 1) # date & time self.datetime = DateTimeEdit() self.datetime.setCalendarPopup(True) self.addWidget(self.datetime, 0, 0, 1, 2) # time zone self.time_zone = TimeZoneWidget() self.addWidget(self.time_zone, 0, 2) # precision self.addWidget(QtWidgets.QLabel(self.tr('Precision:')), 1, 0) self.precision = Slider(Qt.Horizontal) self.precision.setRange(0, 7) self.precision.setPageStep(1) self.addWidget(self.precision, 1, 1) # connections self.datetime.editingFinished.connect(self.new_datetime) self.time_zone.editingFinished.connect(self.new_time_zone) self.precision.valueChanged.connect(self.datetime.set_precision) self.precision.editing_finished.connect(self.new_precision) def get_value(self): return (self.datetime.get_value(), self.precision.value(), self.time_zone.get_value()) def set_value(self, date_time, precision, tz_offset): blocked = self.precision.blockSignals(True) self.precision.setValue(precision) self.precision.blockSignals(blocked) self.datetime.set_precision(precision) self.datetime.set_value(date_time) self.time_zone.set_value(tz_offset) def set_enabled(self, enabled): self.datetime.setEnabled(enabled) self.time_zone.setEnabled(enabled) self.precision.setEnabled(enabled) @QtCore.pyqtSlot() def new_precision(self): self.new_value.emit((MULTI, self.precision.value(), MULTI)) @QtCore.pyqtSlot() def new_datetime(self): self.new_value.emit(self.get_value()) @QtCore.pyqtSlot() def new_time_zone(self): self.new_value.emit((MULTI, MULTI, self.time_zone.get_value()))