def unsaved_files_dialog( self, all_files=False, with_cancel=True, with_discard=True): """Return true if OK to continue with close or quit or whatever""" for image in self.images: if image.metadata.changed() and (all_files or image.selected): break else: return True dialog = QtWidgets.QMessageBox() dialog.setWindowTitle(self.tr('Photini: unsaved data')) dialog.setText(self.tr('<h3>Some images have unsaved metadata.</h3>')) dialog.setInformativeText(self.tr('Do you want to save your changes?')) dialog.setIcon(QtWidgets.QMessageBox.Warning) buttons = QtWidgets.QMessageBox.Save if with_cancel: buttons |= QtWidgets.QMessageBox.Cancel if with_discard: buttons |= QtWidgets.QMessageBox.Discard dialog.setStandardButtons(buttons) dialog.setDefaultButton(QtWidgets.QMessageBox.Save) result = dialog.exec_() if result == QtWidgets.QMessageBox.Save: self.save_files() return True return result == QtWidgets.QMessageBox.Discard
def about(self): text = self.tr(""" <table width="100%"><tr> <td align="center" width="70%"> <h1>Photini</h1> <h3>version {0}</h3> <h4>build {1}</h4> </td> <td align="center"><img src="{2}" /></td> </tr></table> <p>© Jim Easterbrook <a href="mailto:[email protected]"> [email protected]</a><br /><br /> An easy to use digital photograph metadata editor.<br /> Open source package available from <a href="https://github.com/jim-easterbrook/Photini"> github.com/jim-easterbrook/Photini</a>.</p> <p>This program is released with a GNU General Public License. For details click the 'show details' button.</p> """).format( __version__, build, pkg_resources.resource_filename('photini', 'data/icons/128/photini.png')) dialog = QtWidgets.QMessageBox(self) dialog.setWindowTitle(self.tr('Photini: about')) dialog.setText(text) licence = pkg_resources.resource_string('photini', 'data/LICENSE.txt') dialog.setDetailedText(licence.decode('utf-8')) dialog.exec_()
def get_conversion_function(self, image, params): if not params['function']: return None convert = super( TabWidget, self).get_conversion_function(image, params) if convert == 'omit': return convert max_size = 2 ** 30 size = os.stat(image.path).st_size if size < max_size: return convert dialog = QtWidgets.QMessageBox(parent=self) dialog.setWindowTitle( translate('FlickrTab', 'Photini: too large')) dialog.setText( translate('FlickrTab', '<h3>File too large.</h3>')) dialog.setInformativeText( translate('FlickrTab', 'File "{0}" has {1} bytes and exceeds Flickr\'s limit' + ' of {2} bytes.').format( os.path.basename(image.path), size, max_size)) dialog.setIcon(QtWidgets.QMessageBox.Warning) dialog.setStandardButtons(QtWidgets.QMessageBox.Ignore) dialog.exec_() return 'omit'
def upload_file_done(self, image, error): if error: dialog = QtWidgets.QMessageBox(self) dialog.setWindowTitle(self.tr('Photini: upload error')) dialog.setText( self.tr('<h3>File "{}" upload failed.</h3>').format( os.path.basename(image.path))) dialog.setInformativeText(error) dialog.setIcon(QtWidgets.QMessageBox.Warning) dialog.setStandardButtons(QtWidgets.QMessageBox.Abort | QtWidgets.QMessageBox.Retry) dialog.setDefaultButton(QtWidgets.QMessageBox.Retry) if dialog.exec_() == QtWidgets.QMessageBox.Abort: self.upload_button.setChecked(False) else: self.uploads_done += 1 if (self.upload_button.isChecked() and self.uploads_done < len(self.upload_list)): # start uploading next file (or retry same file) self.next_upload() return self.upload_button.setChecked(False) self.total_progress.setValue(0) self.total_progress.setFormat('%p%') self.upload_config.setEnabled(True) self.user_connect.setEnabled(True) self.upload_finished() self.upload_file.disconnect() self.upload_worker.upload_progress.disconnect() self.upload_worker.upload_file_done.disconnect() self.upload_worker.thread.quit() self.upload_worker.thread.wait() self.upload_worker = None # enable or disable upload button self.new_selection(self.image_list.get_selected_images())
def get_conversion_function(self, image): if image.file_type in self.image_types['accepted']: if image.metadata._sc or not image.metadata.has_iptc(): # need to create file without sidecar and with IPTC return self.copy_file_and_metadata return None if not self.is_convertible(image): msg = self.tr('File "{0}" is of type "{1}", which {2} does not' + ' accept and Photini cannot convert.') buttons = QtWidgets.QMessageBox.Ignore elif (self.image_types['rejected'] == '*' or image.file_type in self.image_types['rejected']): msg = self.tr('File "{0}" is of type "{1}", which {2} does not' + ' accept. Would you like to convert it to JPEG?') buttons = QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.Ignore else: msg = self.tr( 'File "{0}" is of type "{1}", which {2} may not' + ' handle correctly. Would you like to convert it to JPEG?') buttons = QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No dialog = QtWidgets.QMessageBox(parent=self) dialog.setWindowTitle(self.tr('Photini: incompatible type')) dialog.setText(self.tr('<h3>Incompatible image type.</h3>')) dialog.setInformativeText( msg.format(os.path.basename(image.path), image.file_type, self.service_name)) dialog.setIcon(QtWidgets.QMessageBox.Warning) dialog.setStandardButtons(buttons) dialog.setDefaultButton(QtWidgets.QMessageBox.Yes) result = dialog.exec_() if result == QtWidgets.QMessageBox.Ignore: return 'omit' if result == QtWidgets.QMessageBox.Yes: return self.convert_to_jpeg return None
def upload_error(self, name, error): dialog = QtWidgets.QMessageBox(self) dialog.setWindowTitle(translate( 'UploaderTabsAll', 'Photini: upload error')) dialog.setText(translate( 'UploaderTabsAll', '<h3>File "{}" upload failed.</h3>').format( name)) dialog.setInformativeText(error) dialog.setIcon(QtWidgets.QMessageBox.Warning) dialog.setStandardButtons(QtWidgets.QMessageBox.Abort | QtWidgets.QMessageBox.Retry) dialog.setDefaultButton(QtWidgets.QMessageBox.Retry) self.abort_upload.emit(dialog.exec_() == QtWidgets.QMessageBox.Retry)
def do_not_close(self): if not self.file_reader: return False dialog = QtWidgets.QMessageBox() dialog.setWindowTitle(self.tr('Photini: import in progress')) dialog.setText(self.tr('<h3>Importing photos has not finished.</h3>')) dialog.setInformativeText( self.tr('Closing now will terminate the import.')) dialog.setIcon(QtWidgets.QMessageBox.Warning) dialog.setStandardButtons( QtWidgets.QMessageBox.Close | QtWidgets.QMessageBox.Cancel) dialog.setDefaultButton(QtWidgets.QMessageBox.Cancel) result = dialog.exec_() return result == QtWidgets.QMessageBox.Cancel
def do_not_close(self): if not self.upload_worker: return False dialog = QtWidgets.QMessageBox(parent=self) dialog.setWindowTitle(self.tr('Photini: upload in progress')) dialog.setText( self.tr('<h3>Upload to {} has not finished.</h3>').format( self.service_name)) dialog.setInformativeText( self.tr('Closing now will terminate the upload.')) dialog.setIcon(QtWidgets.QMessageBox.Warning) dialog.setStandardButtons(QtWidgets.QMessageBox.Close | QtWidgets.QMessageBox.Cancel) dialog.setDefaultButton(QtWidgets.QMessageBox.Cancel) result = dialog.exec_() return result == QtWidgets.QMessageBox.Cancel
def do_not_close(self): if not self.file_copier: return False dialog = QtWidgets.QMessageBox(parent=self) dialog.setWindowTitle( translate('ImporterTab', 'Photini: import in progress')) dialog.setText( translate('ImporterTab', '<h3>Importing photos has not finished.</h3>')) dialog.setInformativeText( translate('ImporterTab', 'Closing now will terminate the import.')) dialog.setIcon(QtWidgets.QMessageBox.Warning) dialog.setStandardButtons(QtWidgets.QMessageBox.Close | QtWidgets.QMessageBox.Cancel) dialog.setDefaultButton(QtWidgets.QMessageBox.Cancel) result = dialog.exec_() if result == QtWidgets.QMessageBox.Close: self.stop_copy() return result == QtWidgets.QMessageBox.Cancel
def about(self): text = """ <table width="100%"><tr> <td align="center" width="70%"> <h1>Photini</h1> <h3>version {0}</h3> <h4>build {1}</h4> </td> <td align="center"><img src="{2}" /></td> </tr></table> <p>© Jim Easterbrook <a href="mailto:[email protected]"> [email protected]</a><br /><br /> {3}<br /> {4}</p> """.format( __version__, build, pkg_resources.resource_filename('photini', 'data/icons/photini_128.png'), translate( 'MenuBar', 'An easy to use digital photograph metadata' ' (Exif, IPTC, XMP) editing application.'), translate( 'MenuBar', 'Open source package available from {}.').format( '<a href="https://github.com/jim-easterbrook/Photini">' 'github.com/jim-easterbrook/Photini</a>'), ) dialog = QtWidgets.QMessageBox(self) dialog.setWindowTitle(translate('MenuBar', 'Photini: about')) dialog.setText(text) licence = pkg_resources.resource_string('photini', 'data/LICENSE.txt') dialog.setDetailedText(licence.decode('utf-8')) dialog.setInformativeText( translate( 'MenuBar', 'This program is released with a GNU General Public' ' License. For details click the "{}" button.').format( dialog.buttons()[0].text())) if qt_version_info >= (6, 0): dialog.exec() else: dialog.exec_()
def new_camera_model(self, value): delete_makernote = 'ask' for image in self.image_list.get_selected_images(): if not image.metadata.camera_change_ok(value): if delete_makernote == 'ask': msg = QtWidgets.QMessageBox(parent=self) msg.setWindowTitle(translate( 'TechnicalTab', 'Photini: maker name change')) msg.setText(translate( 'TechnicalTab', '<h3>Changing maker name will' ' invalidate Exif makernote information.</h3>')) msg.setInformativeText(translate( 'TechnicalTab', 'Do you want to delete the Exif makernote?')) msg.setIcon(msg.Warning) msg.setStandardButtons(msg.YesToAll | msg.NoToAll) msg.setDefaultButton(msg.NoToAll) delete_makernote = msg.exec_() == msg.YesToAll if delete_makernote: image.metadata.set_delete_makernote() image.metadata.camera_model = value self._update_camera_model()
def get_conversion_function(self, image, params): convert = super(TabWidget, self).get_conversion_function(image, params) if convert == 'omit': return convert max_size = 25 * 1024 * 1024 size = os.stat(image.path).st_size if size < max_size: return convert dialog = QtWidgets.QMessageBox(parent=self) dialog.setWindowTitle( translate('GooglePhotosTab', 'Photini: large file')) dialog.setText(translate('GooglePhotosTab', '<h3>Large file.</h3>')) dialog.setInformativeText( translate( 'GooglePhotosTab', 'File "{0}" is over 25MB. Remember that Photini ' 'uploads count towards storage in your Google Account. ' 'Upload it anyway?').format(os.path.basename(image.path))) dialog.setIcon(QtWidgets.QMessageBox.Warning) dialog.setStandardButtons(QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.Ignore) dialog.exec_() return 'omit'
def check_update(self): import requests with Busy(): try: rsp = requests.get('https://pypi.org/pypi/photini/json', timeout=20) except: logger.error(str(ex)) return if rsp.status_code != 200: logger.error('HTTP error %d', rsp.status_code) return release = rsp.json()['info']['version'] dialog = QtWidgets.QMessageBox(self) dialog.setWindowTitle(translate('MenuBar', 'Photini: version check')) dialog.setText( translate( 'MenuBar', 'You are currently running Photini version {0}. The' ' latest release is {1}.').format(__version__, release)) if qt_version_info >= (6, 0): dialog.exec() else: dialog.exec_()