class Config(QDialog): ''' Configuration dialog for single book conversion. If accepted, has the following important attributes output_format - Output format (without a leading .) input_format - Input format (without a leading .) opf_path - Path to OPF file with user specified metadata cover_path - Path to user specified cover (can be None) recommendations - A pickled list of 3 tuples in the same format as the recommendations member of the Input/Output plugins. ''' def __init__(self, parent, db, book_id, preferred_input_format=None, preferred_output_format=None): QDialog.__init__(self, parent) self.setupUi() self.opt_individual_saved_settings.setVisible(False) self.db, self.book_id = db, book_id self.setup_input_output_formats(self.db, self.book_id, preferred_input_format, preferred_output_format) self.setup_pipeline() self.input_formats.currentIndexChanged[native_string_type].connect( self.setup_pipeline) self.output_formats.currentIndexChanged[native_string_type].connect( self.setup_pipeline) self.groups.setSpacing(5) self.groups.activated[(QModelIndex)].connect(self.show_pane) self.groups.clicked[(QModelIndex)].connect(self.show_pane) self.groups.entered[(QModelIndex)].connect(self.show_group_help) rb = self.buttonBox.button(self.buttonBox.RestoreDefaults) rb.setText(_('Restore &defaults')) rb.clicked.connect(self.restore_defaults) self.groups.setMouseTracking(True) geom = gprefs.get('convert_single_dialog_geom', None) if geom: self.restoreGeometry(geom) else: self.resize(self.sizeHint()) def setupUi(self): self.setObjectName("Dialog") self.resize(1024, 700) self.setWindowIcon(QIcon(I('convert.png'))) self.gridLayout = QGridLayout(self) self.gridLayout.setObjectName("gridLayout") self.horizontalLayout = QHBoxLayout() self.horizontalLayout.setObjectName("horizontalLayout") self.input_label = QLabel(self) self.input_label.setObjectName("input_label") self.horizontalLayout.addWidget(self.input_label) self.input_formats = QComboBox(self) self.input_formats.setSizeAdjustPolicy( QComboBox.AdjustToMinimumContentsLengthWithIcon) self.input_formats.setMinimumContentsLength(5) self.input_formats.setObjectName("input_formats") self.horizontalLayout.addWidget(self.input_formats) self.opt_individual_saved_settings = QCheckBox(self) self.opt_individual_saved_settings.setObjectName( "opt_individual_saved_settings") self.horizontalLayout.addWidget(self.opt_individual_saved_settings) spacerItem = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) self.horizontalLayout.addItem(spacerItem) self.label_2 = QLabel(self) self.label_2.setObjectName("label_2") self.horizontalLayout.addWidget(self.label_2) self.output_formats = QComboBox(self) self.output_formats.setSizeAdjustPolicy( QComboBox.AdjustToMinimumContentsLengthWithIcon) self.output_formats.setMinimumContentsLength(5) self.output_formats.setObjectName("output_formats") self.horizontalLayout.addWidget(self.output_formats) self.gridLayout.addLayout(self.horizontalLayout, 0, 0, 1, 2) self.groups = QListView(self) sizePolicy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) sizePolicy.setHorizontalStretch(1) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth( self.groups.sizePolicy().hasHeightForWidth()) self.groups.setSizePolicy(sizePolicy) self.groups.setTabKeyNavigation(True) self.groups.setIconSize(QSize(48, 48)) self.groups.setWordWrap(True) self.groups.setObjectName("groups") self.gridLayout.addWidget(self.groups, 1, 0, 3, 1) self.scrollArea = QScrollArea(self) sizePolicy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) sizePolicy.setHorizontalStretch(4) sizePolicy.setVerticalStretch(10) sizePolicy.setHeightForWidth( self.scrollArea.sizePolicy().hasHeightForWidth()) self.scrollArea.setSizePolicy(sizePolicy) self.scrollArea.setFrameShape(QFrame.NoFrame) self.scrollArea.setLineWidth(0) self.scrollArea.setWidgetResizable(True) self.scrollArea.setObjectName("scrollArea") self.scrollAreaWidgetContents = QWidget() self.scrollAreaWidgetContents.setGeometry(QRect(0, 0, 810, 494)) self.scrollAreaWidgetContents.setObjectName("scrollAreaWidgetContents") self.verticalLayout_3 = QVBoxLayout(self.scrollAreaWidgetContents) self.verticalLayout_3.setContentsMargins(0, 0, 0, 0) self.verticalLayout_3.setObjectName("verticalLayout_3") self.stack = QStackedWidget(self.scrollAreaWidgetContents) sizePolicy = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth( self.stack.sizePolicy().hasHeightForWidth()) self.stack.setSizePolicy(sizePolicy) self.stack.setObjectName("stack") self.page = QWidget() self.page.setObjectName("page") self.stack.addWidget(self.page) self.page_2 = QWidget() self.page_2.setObjectName("page_2") self.stack.addWidget(self.page_2) self.verticalLayout_3.addWidget(self.stack) self.scrollArea.setWidget(self.scrollAreaWidgetContents) self.gridLayout.addWidget(self.scrollArea, 1, 1, 1, 1) self.buttonBox = QDialogButtonBox(self) self.buttonBox.setOrientation(Qt.Horizontal) self.buttonBox.setStandardButtons(QDialogButtonBox.Cancel | QDialogButtonBox.Ok | QDialogButtonBox.RestoreDefaults) self.buttonBox.setObjectName("buttonBox") self.gridLayout.addWidget(self.buttonBox, 3, 1, 1, 1) self.help = QTextEdit(self) sizePolicy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth( self.help.sizePolicy().hasHeightForWidth()) self.help.setSizePolicy(sizePolicy) self.help.setMaximumHeight(80) self.help.setObjectName("help") self.gridLayout.addWidget(self.help, 2, 1, 1, 1) self.input_label.setBuddy(self.input_formats) self.label_2.setBuddy(self.output_formats) self.input_label.setText(_("&Input format:")) self.opt_individual_saved_settings.setText( _("Use &saved conversion settings for individual books")) self.label_2.setText(_("&Output format:")) self.buttonBox.accepted.connect(self.accept) self.buttonBox.rejected.connect(self.reject) def sizeHint(self): desktop = QCoreApplication.instance().desktop() geom = desktop.availableGeometry(self) nh, nw = max(300, geom.height() - 100), max(400, geom.width() - 70) return QSize(nw, nh) def restore_defaults(self): delete_specifics(self.db, self.book_id) self.setup_pipeline() @property def input_format(self): return unicode_type(self.input_formats.currentText()).lower() @property def output_format(self): return unicode_type(self.output_formats.currentText()).lower() @property def manually_fine_tune_toc(self): for i in range(self.stack.count()): w = self.stack.widget(i) if hasattr(w, 'manually_fine_tune_toc'): return w.manually_fine_tune_toc.isChecked() def setup_pipeline(self, *args): oidx = self.groups.currentIndex().row() input_format = self.input_format output_format = self.output_format self.plumber = create_dummy_plumber(input_format, output_format) def widget_factory(cls): return cls(self.stack, self.plumber.get_option_by_name, self.plumber.get_option_help, self.db, self.book_id) self.mw = widget_factory(MetadataWidget) self.setWindowTitle( _('Convert') + ' ' + unicode_type(self.mw.title.text())) lf = widget_factory(LookAndFeelWidget) hw = widget_factory(HeuristicsWidget) sr = widget_factory(SearchAndReplaceWidget) ps = widget_factory(PageSetupWidget) sd = widget_factory(StructureDetectionWidget) toc = widget_factory(TOCWidget) from calibre.gui2.actions.toc_edit import SUPPORTED toc.manually_fine_tune_toc.setVisible( output_format.upper() in SUPPORTED) debug = widget_factory(DebugWidget) output_widget = self.plumber.output_plugin.gui_configuration_widget( self.stack, self.plumber.get_option_by_name, self.plumber.get_option_help, self.db, self.book_id) input_widget = self.plumber.input_plugin.gui_configuration_widget( self.stack, self.plumber.get_option_by_name, self.plumber.get_option_help, self.db, self.book_id) while True: c = self.stack.currentWidget() if not c: break self.stack.removeWidget(c) widgets = [self.mw, lf, hw, ps, sd, toc, sr] if input_widget is not None: widgets.append(input_widget) if output_widget is not None: widgets.append(output_widget) widgets.append(debug) for w in widgets: self.stack.addWidget(w) w.set_help_signal.connect(self.help.setPlainText) self._groups_model = GroupModel(widgets) self.groups.setModel(self._groups_model) idx = oidx if -1 < oidx < self._groups_model.rowCount() else 0 self.groups.setCurrentIndex(self._groups_model.index(idx)) self.stack.setCurrentIndex(idx) try: shutil.rmtree(self.plumber.archive_input_tdir, ignore_errors=True) except: pass def setup_input_output_formats(self, db, book_id, preferred_input_format, preferred_output_format): if preferred_output_format: preferred_output_format = preferred_output_format.upper() output_formats = get_output_formats(preferred_output_format) input_format, input_formats = get_input_format_for_book( db, book_id, preferred_input_format) preferred_output_format = preferred_output_format if \ preferred_output_format in output_formats else \ sort_formats_by_preference(output_formats, [prefs['output_format']])[0] self.input_formats.addItems( (unicode_type(x.upper()) for x in input_formats)) self.output_formats.addItems( (unicode_type(x.upper()) for x in output_formats)) self.input_formats.setCurrentIndex(input_formats.index(input_format)) self.output_formats.setCurrentIndex( output_formats.index(preferred_output_format)) def show_pane(self, index): self.stack.setCurrentIndex(index.row()) def accept(self): recs = GuiRecommendations() for w in self._groups_model.widgets: if not w.pre_commit_check(): return x = w.commit(save_defaults=False) recs.update(x) self.opf_file, self.cover_file = self.mw.opf_file, self.mw.cover_file self._recommendations = recs if self.db is not None: recs['gui_preferred_input_format'] = self.input_format save_specifics(self.db, self.book_id, recs) self.break_cycles() QDialog.accept(self) def reject(self): self.break_cycles() QDialog.reject(self) def done(self, r): if self.isVisible(): gprefs['convert_single_dialog_geom'] = \ bytearray(self.saveGeometry()) return QDialog.done(self, r) def break_cycles(self): for i in range(self.stack.count()): w = self.stack.widget(i) w.break_cycles() @property def recommendations(self): recs = [(k, v, OptionRecommendation.HIGH) for k, v in self._recommendations.items()] return recs def show_group_help(self, index): widget = self._groups_model.widgets[index.row()] self.help.setPlainText(widget.HELP)
def FillPhotosByFilter(self, filter): # it's tempting to think that we could use the insertPhotoIntoTable routine, # but we can't here, because if we're filling photos by filter, we already know # each photo's meta data. The insertPhotoIntoTable routine tries to guess the # location, time, species, etc. from the photo file's embedded meta data. QApplication.setOverrideCursor(QCursor(Qt.WaitCursor)) self.scaleMe() self.resizeMe() self.fillingCombos = True # save the filter settings passed to this routine to the form itself for future use self.filter = filter photoSightings = self.mdiParent.db.GetSightingsWithPhotos(filter) if len(photoSightings) == 0: return False row = 0 # count photos for message display photoCount = 0 for s in photoSightings: photoCount = photoCount + len(s["photos"]) photoCount = str(photoCount) for s in photoSightings: for p in s["photos"]: self.mdiParent.lblStatusBarMessage.setVisible(True) self.mdiParent.lblStatusBarMessage.setText( "Processing photo " + str(row + 1) + " of " + photoCount) # p is a filename. Use it to add the image to the label as a pixmap buttonPhoto = QPushButton() buttonPhoto.setMinimumHeight(281) buttonPhoto.setMinimumWidth(500) # get thumbnail from file to display pixMap = self.GetPixmapForThumbnail(p["fileName"]) buttonPhoto.setIcon(QIcon(pixMap)) # size to 500x281 buttonPhoto.setIconSize(QSize(500, 281)) buttonPhoto.setStyleSheet( "QPushButton {background-color: #343333; border: 0px}") # display thumbnail to new row in grid self.gridPhotos.addWidget(buttonPhoto, row, 0) # set up layout in second column of row to house combo boxes # give each object a name according to the row so we can access them later container = QWidget() container.setObjectName("container" + str(row)) detailsLayout = QVBoxLayout(container) detailsLayout.setObjectName("layout" + str(row)) detailsLayout.setAlignment(Qt.AlignTop) self.gridPhotos.addWidget(container, row, 1) # create combo boxes for details # add connection for when user changes a combo box cboLocation = QComboBox() cboLocation.currentIndexChanged.connect( partial(self.cboLocationChanged, row)) cboDate = QComboBox() cboDate.currentIndexChanged.connect( partial(self.cboDateChanged, row)) cboTime = QComboBox() cboTime.currentIndexChanged.connect( partial(self.cboTimeChanged, row)) cboCommonName = QComboBox() cboCommonName.currentIndexChanged.connect( partial(self.cboCommonNameChanged, row)) cboRating = QComboBox() cboRating.addItems(["Not Rated", "1", "2", "3", "4", "5"]) cboRating.currentIndexChanged.connect( partial(self.cboRatingChanged, row)) # set stylesheet for cmbo boxes for c in [ cboLocation, cboDate, cboTime, cboCommonName, cboRating ]: self.removeHighlight(c) # fill location combo box with all locations in db locations = self.mdiParent.db.locationList cboLocation.addItems(locations) # set location combo box to the photo's location index = cboLocation.findText(s["location"]) if index >= 0: cboLocation.setCurrentIndex(index) # fill date combo box with all dates associated with selected location filterForThisPhoto = code_Filter.Filter() filterForThisPhoto.setLocationName(s["location"]) filterForThisPhoto.setLocationType("Location") dates = self.mdiParent.db.GetDates(filterForThisPhoto) cboDate.addItems(dates) # set date combo box to the photo's associated date index = cboDate.findText(s["date"]) if index >= 0: cboDate.setCurrentIndex(index) # fill time combo box with all times associated with selected location and date filterForThisPhoto.setStartDate(s["date"]) filterForThisPhoto.setEndDate(s["date"]) startTimes = self.mdiParent.db.GetStartTimes( filterForThisPhoto) cboTime.addItems(startTimes) # set time combo box to the photo's associated checklist time index = cboTime.findText(s["time"]) if index >= 0: cboTime.setCurrentIndex(index) # get common names from checklist associated with photo filterForThisPhoto.setChecklistID(s["checklistID"]) commonNames = self.mdiParent.db.GetSpecies(filterForThisPhoto) cboCommonName.addItem("**Detach Photo**") cboCommonName.addItems(commonNames) # set combo box to common name index = cboCommonName.findText(s["commonName"]) if index >= 0: cboCommonName.setCurrentIndex(index) # set combo box to rating value index = int(p["rating"]) cboRating.setCurrentIndex(index) # assign names to combo boxes for future access cboLocation.setObjectName("cboLocation" + str(row)) cboDate.setObjectName("cboDate" + str(row)) cboTime.setObjectName("cboTime" + str(row)) cboCommonName.setObjectName("cboCommonName" + str(row)) cboRating.setObjectName("cboRating" + str(row)) # add combo boxes to the layout in second column detailsLayout.addWidget(cboLocation) detailsLayout.addWidget(cboDate) detailsLayout.addWidget(cboTime) detailsLayout.addWidget(cboCommonName) detailsLayout.addWidget(cboRating) # create and add resent button btnReset = QPushButton() btnReset.setText("Reset") btnReset.clicked.connect(partial(self.btnResetClicked, row)) detailsLayout.addWidget(btnReset) # save meta data for future use when user clicks cbo boxes thisPhotoMetaData = {} thisPhotoMetaData["photoFileName"] = p["fileName"] thisPhotoMetaData["location"] = s["location"] thisPhotoMetaData["date"] = s["date"] thisPhotoMetaData["time"] = s["time"] thisPhotoMetaData["commonName"] = s["commonName"] thisPhotoMetaData["photoData"] = p thisPhotoMetaData["rating"] = p["rating"] self.metaDataByRow[row] = thisPhotoMetaData # initialize the "new" data so that there are values there, even if they're not really new # user can change the cbo boxes later, which will also change the "new" data self.saveNewMetaData(row) row = row + 1 qApp.processEvents() self.mdiParent.lblStatusBarMessage.setText("") self.mdiParent.lblStatusBarMessage.setVisible(False) QApplication.processEvents() icon = QIcon() icon.addPixmap(QPixmap(":/icon_camera.png"), QIcon.Normal, QIcon.Off) self.setWindowIcon(icon) self.setWindowTitle("Manage Photos") self.fillingCombos = False QApplication.restoreOverrideCursor() # tell MainWindow that we succeeded filling the list return (True)
class TempleItem (QtWidgets.QGraphicsItem): SIZE_MULTIPLICATOR = 2 def __init__(self,view, scene_coord,temple,size,parent=None): super (TempleItem,self).__init__(parent) #self.polygon = self.getTriangle (size) self.rotation = 0.0 self.color = QColor(0,0,125) self.name_visible = True self.name = temple.name self.model = temple self.view = view self.size = QSize(32,32) self.scene_coord = scene_coord #set flags self.setFlag(QGraphicsItem.ItemIgnoresTransformations) self.setFlag(QGraphicsItem.ItemSendsGeometryChanges) self.setFlag(QGraphicsItem.ItemIsSelectable) self.setFlag(QGraphicsItem.ItemIsMovable) # self.graphics_effect = QGraphicsColorizeEffect() # color = self.model.kingdom().color # self.graphics_effect.setColor(QColor(color.red(),color.green(),color.blue(),125)) # self.setGraphicsEffect(self.graphics_effect ) # self.graphics_effect.setEnabled(True) def boundingRect(self): return QtCore.QRectF(0,0,self.size.width(),self.size.height()) def itemChange(self, change, value): if change == QGraphicsItem.ItemPositionHasChanged : self.model.position = value #pos = self.view.mapToScene(value.x(),value.y()) lat,lon = self.scene_coord.SceneToLatLon(value.x(),value.y()) self.model.changePosition (lat,lon) print ('new position ',self.model.position) else: return QGraphicsItem.itemChange(self,change,value) def paint (self,painter,option, widget): painter.setRenderHints(QtGui.QPainter.Antialiasing) painter.rotate(self.rotation) painter.translate(-16,-16) # taille fixe correspondant a la pixmap utilisee pour generer la geometry painter.scale(1.5,1.5) if self.isSelected() == True : pen = QPen(QtCore.Qt.red) pen.setWidth(1) else: pen = QPen(QtCore.Qt.black) pen.setWidth(1) painter.setPen(pen) radialGradient = QRadialGradient(self.size.width()/2, self.size.height()/2,self.size.width()*0.8, self.size.width(), self.size.height()) radialGradient.setColorAt(0.0, QtCore.Qt.white) #radialGradient.setColorAt(0.2, self.heros.kingdom().color) if self.view.color_mode == ColorMode.Empire : color = self.model.empire().color else : color = self.model.kingdom().color radialGradient.setColorAt(0.2, color) radialGradient.setColorAt(1.0, QtCore.Qt.black) painter.setBrush(QBrush(radialGradient)) #brush = QBrush(self.color) #painter.setBrush(brush) geometry = self.model.empire().geometry #qDebug("info : map_item Temple : nombre de polygones %d"%len(geometry['polygon'])) for p in geometry['polygon']: painter.drawPolygon(QPolygon(p)) # # painter.drawPolygon(self.polygon) # path = os.path.join(Config().instance.path_to_icons(),'kingdom','32x32') # path+="/temple_artemis.png" # print ('path icon',path) # pix = QPixmap(path) # # painter.drawPixmap(-pix.width()/2.0,-pix.height()/2.0,pix) if self.name_visible == True : painter.setPen(QPen(QColor('black'))) painter.translate(0,10) painter.drawText (self.boundingRect(),QtCore.Qt.AlignHCenter|QtCore.Qt.AlignBottom, self.name) def contextMenuEvent(self, event): menu = QMenu() testAction = QAction('Go Inside', None) testAction.triggered.connect(self.showTempleView) menu.addAction(testAction) menu.exec_(event.screenPos()) event.accept() def showTempleView (self): self.frame = QFrame() self.frame.setWindowTitle(self.kingdom.name) self.frame.setObjectName("Frame") self.frame.resize(400, 300) self.frame.setFrameShape(QFrame.StyledPanel) self.frame.setFrameShadow(QFrame.Raised) self.verticalLayout = QVBoxLayout(self.frame) self.verticalLayout.setObjectName("verticalLayout") self.view = TempleView(self.frame) self.view.setTemple(self.kingdom) self.verticalLayout.addWidget(self.view) self.frame.show()
def insertPhotoIntoTable(self, row, photoData, photoMatchData, pixMap): QApplication.processEvents() self.fillingCombos = True photoLocation = photoMatchData["photoLocation"] photoDate = photoMatchData["photoDate"] photoTime = photoMatchData["photoTime"] photoCommonName = photoMatchData["photoCommonName"] # p is a filename. Use it to add the image to the label as a pixmap buttonPhoto = QPushButton() buttonPhoto.setMinimumHeight(281) buttonPhoto.setMinimumWidth(500) buttonPhoto.setIcon(QIcon(pixMap)) # size to 500x281 buttonPhoto.setIconSize(QSize(500, 281)) buttonPhoto.setStyleSheet( "QPushButton {background-color: #343333; border: 0px}") # display thumbnail to new row in grid self.gridPhotos.addWidget(buttonPhoto, row, 0) # set up layout in second column of row to house combo boxes # give each object a name according to the row so we can access them later container = QWidget() container.setObjectName("container" + str(row)) detailsLayout = QVBoxLayout(container) detailsLayout.setObjectName("layout" + str(row)) detailsLayout.setAlignment(Qt.AlignTop) self.gridPhotos.addWidget(container, row, 1) # create combo boxes for details # add connection for when user changes a combo box cboLocation = QComboBox() cboLocation.currentIndexChanged.connect( partial(self.cboLocationChanged, row)) cboDate = QComboBox() cboDate.currentIndexChanged.connect(partial(self.cboDateChanged, row)) cboTime = QComboBox() cboTime.currentIndexChanged.connect(partial(self.cboTimeChanged, row)) cboCommonName = QComboBox() cboCommonName.currentIndexChanged.connect( partial(self.cboCommonNameChanged, row)) cboRating = QComboBox() cboRating.addItems(["Not Rated", "1", "2", "3", "4", "5"]) cboRating.currentIndexChanged.connect( partial(self.cboRatingChanged, row)) # set stylesheet for cbo boxes for c in [cboLocation, cboDate, cboTime, cboCommonName, cboRating]: self.removeHighlight(c) # fill location combo box with all locations in db locations = self.mdiParent.db.locationList cboLocation.addItems(locations) # set location combo box to the photo's location if photoLocation != "": index = cboLocation.findText(photoLocation) if index >= 0: cboLocation.setCurrentIndex(index) # fill date combo box with all dates associated with selected location filterForThisPhoto = code_Filter.Filter() filterForThisPhoto.setLocationName(photoLocation) filterForThisPhoto.setLocationType("Location") dates = self.mdiParent.db.GetDates(filterForThisPhoto) cboDate.addItems(dates) # set date combo box to the photo's associated date index = cboDate.findText(photoDate) if index >= 0: cboDate.setCurrentIndex(index) # fill time combo box with all times associated with selected location and date filterForThisPhoto.setStartDate(photoDate) filterForThisPhoto.setEndDate(photoDate) startTimes = self.mdiParent.db.GetStartTimes( filterForThisPhoto) cboTime.addItems(startTimes) # set time combo box to the photo's associated checklist time index = cboTime.findText(photoTime) if index >= 0: cboTime.setCurrentIndex(index) # get common names from checklist associated with photo filterForThisPhoto.setTime(photoTime) commonNames = self.mdiParent.db.GetSpecies(filterForThisPhoto) cboCommonName.addItem("**Detach Photo**") cboCommonName.addItems(commonNames) # set combo box to common name index = cboCommonName.findText(photoCommonName) if index >= 0: cboCommonName.setCurrentIndex(index) # assign names to combo boxes for future access cboLocation.setObjectName("cboLocation" + str(row)) cboDate.setObjectName("cboDate" + str(row)) cboTime.setObjectName("cboTime" + str(row)) cboCommonName.setObjectName("cboCommonName" + str(row)) cboRating.setObjectName("cboRating" + str(row)) lblFileName = QLabel() lblFileName.setText("File: " + os.path.basename(photoData["fileName"])) lblFileDate = QLabel() lblFileDate.setText("Date: " + photoData["date"]) lblFileTime = QLabel() lblFileTime.setText("Time: " + photoData["time"]) # add combo boxes to the layout in second column detailsLayout.addWidget(lblFileName) detailsLayout.addWidget(lblFileDate) detailsLayout.addWidget(lblFileTime) detailsLayout.addWidget(cboLocation) detailsLayout.addWidget(cboDate) detailsLayout.addWidget(cboTime) detailsLayout.addWidget(cboCommonName) detailsLayout.addWidget(cboRating) # create and add resent button btnReset = QPushButton() btnReset.setText("Reset") btnReset.clicked.connect(partial(self.btnResetClicked, row)) detailsLayout.addWidget(btnReset) # save meta data for future use when user clicks cbo boxes thisPhotoMetaData = {} thisPhotoMetaData["photoFileName"] = photoData["fileName"] thisPhotoMetaData["location"] = photoLocation thisPhotoMetaData["date"] = photoDate thisPhotoMetaData["time"] = cboTime.currentText() thisPhotoMetaData["commonName"] = photoCommonName thisPhotoMetaData["photoData"] = photoData thisPhotoMetaData["rating"] = thisPhotoMetaData["photoData"]["rating"] self.metaDataByRow[row] = thisPhotoMetaData # initialize the "new" data so that there are values there, even if they're not really new # user can change the cbo boxes later, which will also change the "new" data self.saveNewMetaData(row) self.fillingCombos = False