def _initFromConf(self, conf): """ Initalise the download window from the stored configuration Keyword Arguments: conf - Configuration object """ self.__conf = conf self.nb = NameBuilder() self.srcFolder = self.__conf['sourceFolder'] if not os.path.isdir(self.srcFolder): self.srcFolder = os.path.dirname(__file__) self.entSourceFolder.set_text(self.srcFolder) self.entDestFolder.set_text(self.destFolder) self.chkDelete.set_active(self.__conf['delete'] == 1) w, h = self.__conf['width'] or 800, self.__conf['height'] or 400 # work arround for bug in pygtk/gtk 2.10.6 on windows set default size # then reshow with initial (default) size instead of simple resize self.main_widget.set_default_size(w, h) self.main_widget.reshow_with_initial_size() self.main_widget.resize_children() if self.__conf['promptJobCode'] == 1: newJobCode = InputBox(self.main_widget, _('Please enter the new Job Code'), '%s' % self.__conf['jobCode']) if newJobCode is not None: self.__conf['jobCode'] = newJobCode
def _initFromConf(self, conf): """ Initalise the download window from the stored configuration Keyword Arguments: conf - Configuration object """ self.__conf = conf self.nb = NameBuilder() self.srcFolder = self.__conf['sourceFolder'] if not os.path.isdir(self.srcFolder): self.srcFolder = os.path.dirname(__file__) self.entSourceFolder.set_text(self.srcFolder) self.entDestFolder.set_text(self.destFolder) self.chkDelete.set_active(self.__conf['delete'] == 1) w,h = self.__conf['width'] or 800,self.__conf['height'] or 400 # work arround for bug in pygtk/gtk 2.10.6 on windows set default size # then reshow with initial (default) size instead of simple resize self.main_widget.set_default_size(w,h) self.main_widget.reshow_with_initial_size() self.main_widget.resize_children() if self.__conf['promptJobCode'] == 1: newJobCode = InputBox(self.main_widget, _('Please enter the new Job Code'), '%s' % self.__conf['jobCode']) if newJobCode != None: self.__conf['jobCode'] = newJobCode
class WinDownload(GladeApp): """Class to handle main download window""" glade = os.path.join(os.path.dirname(__file__), 'download.glade') window = "winDownloadStart" def init(self, conf, nodeFolder): """Initalises the main download window and builds download table""" self.btnSourceFolder.drag_dest_set( gtk.DEST_DEFAULT_ALL, [('text/uri-list', 0, 1), ('text/plain', 0, 1)], # drag from os gtk.gdk.ACTION_COPY | gtk.gdk.ACTION_MOVE) txtRdr = gtk.CellRendererText() columns = ( (_('Source'), [(txtRdr, gobject.TYPE_STRING)], (dc.C_SRC, ), True), (_('Size'), [(txtRdr, gobject.TYPE_STRING)], (dc.C_SZ_RAW, ), True), (None, [(None, gobject.TYPE_STRING)], (None, ), False), # Raw size (None, [(None, gobject.TYPE_PYOBJECT)], (None, ), False), # Datetime object (_('Date/Time'), [(txtRdr, gobject.TYPE_STRING)], (dc.C_DATE, ), True), # Date for display (None, [(None, gobject.TYPE_PYOBJECT)], (None, ), False), # EXIF (_('Destination'), [(txtRdr, gobject.TYPE_STRING)], (dc.C_DEST, ), True), (_('Status'), [(txtRdr, gobject.TYPE_STRING)], (dc.C_STAT, ), True), (None, [(None, gobject.TYPE_STRING)], (None, ), False), # Short Status (_('Rotation'), [(txtRdr, gobject.TYPE_STRING)], (dc.C_ROT, ), True), (None, [(None, gobject.TYPE_STRING)], (None, ), False)) self.imLst = extListview.ExtListView(columns) self.imLst.enableDNDReordering() self.swFileList.add(self.imLst) self.swFileList.show_all() self.destFolder = nodeFolder.file self.cidStatusBar = self.statusBar.get_context_id( _("Download Photos From Camera")) self._initFromConf(conf) self.invalidSource = True self.invalidDest = True self.badPattern = False self.buildListRunning = False self.quitNow = False task = self._bgWork() gobject.idle_add(task.next) def _initFromConf(self, conf): """ Initalise the download window from the stored configuration Keyword Arguments: conf - Configuration object """ self.__conf = conf self.nb = NameBuilder() self.srcFolder = self.__conf['sourceFolder'] if not os.path.isdir(self.srcFolder): self.srcFolder = os.path.dirname(__file__) self.entSourceFolder.set_text(self.srcFolder) self.entDestFolder.set_text(self.destFolder) self.chkDelete.set_active(self.__conf['delete'] == 1) w, h = self.__conf['width'] or 800, self.__conf['height'] or 400 # work arround for bug in pygtk/gtk 2.10.6 on windows set default size # then reshow with initial (default) size instead of simple resize self.main_widget.set_default_size(w, h) self.main_widget.reshow_with_initial_size() self.main_widget.resize_children() if self.__conf['promptJobCode'] == 1: newJobCode = InputBox(self.main_widget, _('Please enter the new Job Code'), '%s' % self.__conf['jobCode']) if newJobCode is not None: self.__conf['jobCode'] = newJobCode def _bgWork(self): """Backgroud task to build/update image download table""" while not self.quitNow: if self.invalidSource and not self.buildListRunning: self.btnExecute.set_sensitive(False) self.buildListRunning = True task = self._buildListSource() gobject.idle_add(task.next) yield True (self.invalidSource, self.invalidDest, self.buildListRunning) if self.invalidDest and\ not self.invalidSource and\ not self.buildListRunning and\ not self.badPattern: self.buildListRunning = True self.btnExecute.set_sensitive(False) task = self._buildListDest() gobject.idle_add(task.next) yield True yield False def _buildListSource(self): """Builds list of files to be downloaded""" self.invalidSource = False self.invalidDest = True self.imLst.clear() self.statusBar.push(self.cidStatusBar, _('Finding source files in "%s"') % self.srcFolder) yield True self.imgInfs = [] fileList = self._listFiles(self.srcFolder) fileList.sort() self.statusBar.pop(self.cidStatusBar) self.statusBar.push( self.cidStatusBar, _('Reading source file information from "%s"') % self.srcFolder) yield True model = self.imLst.get_model() self.imLst.set_model(None) if self.invalidSource or self.quitNow: self.statusBar.pop(self.cidStatusBar) self.buildListRunning = False yield False for srcFile in fileList: exifData = pyexiv.Exiv2Metadata(pyexiv2.ImageMetadata(srcFile)) exifData.readMetadata() size = os.path.getsize(srcFile) if 'Exif.Photo.DateTimeOriginal' in exifData.exifKeys(): date = ed2d( exifData.interpretedExifValue( 'Exif.Photo.DateTimeOriginal')) else: date = datetime.datetime.fromtimestamp( os.path.getmtime(srcFile)) row = [ srcFile[len(self.srcFolder) + 1:], format_file_size_for_display(size), size, date, date, exifData, '', '', '', '', '' ] self.imgInfs.append(row[:-4]) self.imLst.appendRows([row]) if self.invalidSource or self.quitNow: self.statusBar.pop(self.cidStatusBar) self.buildListRunning = False yield False yield True self.imLst.set_model(model) self.buildListRunning = False self.statusBar.pop(self.cidStatusBar) yield False def _buildListDest(self): """Adds destination file name, download status and rotation to a list of files to be downloaded""" self.invalidDest = False # Check that the list is not empty if self.imLst.getCount() == 0: self.buildListRunning = False yield False model = self.imLst.get_model() self.imLst.set_model(None) # Start new # Build image Names # Build names without seralisation self.statusBar.push(self.cidStatusBar, _('Building destination Names')) yield True # Clear all destination information for rowIdx in range(self.imLst.getCount()): self.imLst.setItem(rowIdx, dc.C_SS, '') self.imLst.setItem(rowIdx, dc.C_STAT, '') self.imLst.setItem(rowIdx, dc.C_RS, '') self.imLst.setItem(rowIdx, dc.C_ROT, '') for imageInfo in self.imgInfs: imageInfo[dc.C_DEST] = self.nb.name( imageInfo[dc.C_SRC], '', # Dest folder blank as not needed here self.__conf['nameFormat'], imageInfo[dc.C_EXIF], imageInfo[dc.C_DATE], self.__conf['jobCode']) if not self.nb.seralize(self.imgInfs, dc.C_SRC, dc.C_DATE, dc.C_DEST): MessageBox( self.main_widget, _("More than one serialisation tag used please use preferencess to remove from File Naming > Parttern" )) self.statusBar.pop(self.cidStatusBar) self.invalidDest - True self.badPattern = True self.buildListRunning = False yield False if self.invalidSource or self.invalidDest or self.quitNow: self.statusBar.pop(self.cidStatusBar) self.buildListRunning = False yield False yield True # Note need to make sure self.imgInfs is sorted by source file # for the below to work # Write destination names into imList for imgIdx, imgInf in enumerate(self.imgInfs): if self.imLst.getItem(imgIdx, dc.C_SRC) != imgInf[dc.C_SRC]: print "No Match at %d ?" % (imgIdx) print "List: %s" % self.imLst.getItem(imageIndex, dc.C_SRC) print "Source: %s" % imgInf[dc.C_SRC] else: self.imLst.setItem(imgIdx, dc.C_DEST, imgInf[dc.C_DEST]) if self.invalidSource or self.invalidDest or self.quitNow: self.statusBar.pop(self.cidStatusBar) self.buildListRunning = False yield False yield True self.statusBar.pop(self.cidStatusBar) # Check Status self.statusBar.push(self.cidStatusBar, _('Checking Status of Images')) yield True for rowIdx, row in enumerate(self.imLst.iterAllRows()): destFile = os.path.join(self.destFolder, row[dc.C_DEST]) count = 0 for chkRow in self.imLst.iterAllRows(): if chkRow[dc.C_DEST] == row[dc.C_DEST]: count += 1 if count > 1: statS = 'C' statL = _('Collision with New') elif os.path.isfile(destFile): destExif = pyexiv.Exiv2Metadata( pyexiv2.ImageMetadata(destFile)) destExif.readMetadata() if 'Image DateTime' in destExif.exifKeys(): destDate = ed2d( destExif.interpretedExifValue( 'Exif.Photo.DateTimeOriginal')) else: destDate = datetime.datetime.fromtimestamp( os.path.getmtime(destFile)) if destDate.timetuple() == row[dc.C_DATE].timetuple(): statS = 'D' statL = _('Downloaded') else: statS = 'C' statL = _('Collision with Existing') else: statS = 'N' statL = _('New') if self.invalidSource or self.invalidDest or self.quitNow: self.statusBar.pop(self.cidStatusBar) self.buildListRunning = False yield False self.imLst.setItem(rowIdx, dc.C_SS, statS) self.imLst.setItem(rowIdx, dc.C_STAT, statL) yield True self.statusBar.pop(self.cidStatusBar) # Check Rotation self.statusBar.push(self.cidStatusBar, _('Checking Rotation Required for Images')) yield True for rowIdx, row in enumerate(self.imLst.iterAllRows()): if self.__conf["autoRotate"] == 1: try: rotS = autoTrans[int( row[dc.C_EXIF]['Exif.Image.Orientation'])][0] rotL = autoTrans[int( row[dc.C_EXIF]['Exif.Image.Orientation'])][1] except KeyError: rotS = autoTrans[1][0] rotL = autoTrans[1][1] else: rotS = autoTrans[1][0] rotL = _('Disabled') if self.invalidSource or self.invalidDest or self.quitNow: self.statusBar.pop(self.cidStatusBar) self.buildListRunning = False yield False self.imLst.setItem(rowIdx, dc.C_RS, rotS) self.imLst.setItem(rowIdx, dc.C_ROT, rotL) yield True self.statusBar.pop(self.cidStatusBar) self.imLst.set_model(model) # Completed exiting self.btnExecute.set_sensitive(True) self.buildListRunning = False yield False def _listFiles(self, dir): """ Recursivley builds and returns a list of valid image files in a given directory Keyword Arguments: dir - Folder to recursivley list image files from """ fileList = [] for name in os.listdir(dir): path = os.path.join(dir, name) if (os.path.isfile(path) and os.path.splitext(name)[1] in sup_ext()): fileList += [path] elif (os.path.isdir(path)): fileList += self._listFiles(path) return fileList def on_btnSourceFolder_clicked(self, widget, *args): """Handles the chanmge source folder button (...), gets the new source folder and initiates the update of the download list""" dialog = gtk.FileChooserDialog(_('Select source folder'), self.main_widget, gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER, (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OPEN, gtk.RESPONSE_OK)) dialog.set_default_response(gtk.RESPONSE_OK) dialog.set_filename(self.srcFolder) response = dialog.run() if response == gtk.RESPONSE_OK: if dialog.get_filename != self.srcFolder: self.srcFolder = dialog.get_filename() self.invalidSource = True self.entSourceFolder.set_text(self.srcFolder) dialog.destroy() def on_btnSourceFolder_drag_data_received(self, widget, *args): list = dnd_args_to_dir_list(args) if list: self.srcFolder = list[0] self.invalidSource = True self.entSourceFolder.set_text(self.srcFolder) def on_btnPreferences_clicked(self, widget, *args): """Handles the Preferences button, loads the preferences dialog and initiates the update of the download list""" if self.imLst.getCount() == 0: preferences = WinDownloadPreferences( self.__conf, self.destFolder, os.path.join(os.path.dirname(__file__), '123camera', 'img_4567.jpg'), dict(), datetime.datetime.now()) else: if self.imLst.getSelectedRowsCount() == 0: selIdx = 0 else: selIdx = self.imLst.getFirstSelectedRowIndex() preferences = WinDownloadPreferences( self.__conf, self.destFolder, self.imLst.getItem(selIdx, dc.C_SRC), self.imLst.getItem(selIdx, dc.C_EXIF), self.imLst.getItem(selIdx, dc.C_DATE)) response = preferences.loop()[0] if response: self.badPattern = False self.invalidDest = True def on_btnExecute_clicked(self, widget, *args): """Handles the Execute button and starts the download process""" # Save settings self.quitNow = True self.__conf["sourceFolder"] = self.entSourceFolder.get_text() if self.chkDelete.get_active(): self.__conf['delete'] = 1 else: self.__conf['delete'] = 0 self.__conf["width"], self.__conf["height"] = \ self.main_widget.get_size() # Build the list of images to download noRowsSelected = self.imLst.getSelectedRowsCount() if noRowsSelected == 0 or noRowsSelected == len(self.imgInfs): self.toDownload = self.imLst.getAllRows() else: self.toDownload = self.imLst.getSelectedRows() self.quit(True) def on_chkDelete_toggled(self, widget, *args): """Handles toggling of the delete check box""" pass def on_winDownloadStart_delete_event(self, *args): """Handles programatically closing the window""" self.quitNow = True self.quit(False) def on_btnCancel_clicked(self, widget, *args): """Handles the Cancle button and closes the window""" self.quitNow = True self.quit(False) def getToDownload(self): """Returns the list of 'selected' images to be downloaded (can be run after the window has been closed)""" return self.toDownload
def init(self, conf, destination, exSource, exExif, exDate): """ Initalise the Download preferences window Keyword arguments: conf - configuration object destination - destination folder for downloaded images exSource - source file name (used for generating examples) exExif - source EXIF data (used for generating examples) exDate - source date (used for generating examples) """ self.__conf = conf self.exSource = exSource self.exExif = exExif self.exDate = exDate self.nb = NameBuilder() self.tbufComment = self.txtComment.get_buffer() # Init general page self.chkAutoRotate.set_active(self.__conf["autoRotate"] == 1) self.chkCopyOther.set_active(self.__conf["copyOther"] == 1) self.chkAutoComment.set_active( not len(self.__conf["autoComment"]) == 0) comment = self.__conf["autoComment"] self.tbufComment.set_text(comment.replace("\\n", "\n")) # Init naming page self.entDestination.set_text(destination) self.entFilename.set_text(self.__conf["nameFormat"]) self.origJobCode = self.__conf["jobCode"] self.entJobCode.set_text(self.__conf["jobCode"]) self.chkJobCode.set_active(self.__conf["promptJobCode"] == 1) self.updateExample() # Init Auto Tag page self.ltags = eval('%s' % self.__conf['autoTag']) def filename(column, cell, model, iter): cell.set_property('text', model.get_value(iter, 0)) cell.set_property('foreground', model.get_value(iter, 2)) cell.set_property('xalign', 0) # ~ cell.set_property('xpad', 1) def pixbuf(column, cell, model, iter): node = model.get_value(iter, 1) if node.__class__.__name__ == "TagNode": if model.get_value(iter, 3) == 0: cell.set_property('pixbuf', Buffer.pbCheckEmpty) elif model.get_value(iter, 3) == 1: cell.set_property('pixbuf', Buffer.pbCheckInclude) elif model.get_value(iter, 3) == 2: cell.set_property('pixbuf', Buffer.pbCheckExclude) else: cell.set_property('pixbuf', Buffer.pbCheckDisabled) else: cell.set_property('pixbuf', None) cell.set_property('width', 16) cell.set_property('xalign', 0) cellpb = gtk.CellRendererPixbuf() cell = gtk.CellRendererText() column = gtk.TreeViewColumn() column.pack_start(cellpb, False) column.pack_start(cell, True) column.set_cell_data_func(cellpb, pixbuf) column.set_cell_data_func(cell, filename) self.tvTags.append_column(column) treeselection = self.tvTags.get_selection() treeselection.set_mode(gtk.SELECTION_NONE) storeTags = TreeTags() self.tvTags.set_model(storeTags) self.tvTags.set_enable_search(False) self.tvTags.set_state(gtk.CAN_FOCUS) storeTags.expander(self.tvTags) storeTags.cleanSelections() storeTags.setSelected(self.ltags) tags = ", ".join(self.ltags) self.lblTags.set_label("Tags: %s" % tags) # Init Conversion Page self.chkDcraw.set_active(self.__conf["dcraw"] == 1) self.chkDcrawCopyMetaData.set_active( self.__conf["dcrawCopyMetaData"] == 1) self.chkDcrawCopyRaw.set_active(self.__conf["dcrawCopyRaw"] == 1) # Remove un-implemented pages self.ntbkPreferences.remove_page(4) # Conversion self.ntbkPreferences.remove_page(3) # Camera Mapping
class WinDownloadPreferences(GladeApp): """Class to handle the Download Preferences window""" # TODO: implement camera tagging settings glade = os.path.join(os.path.dirname(__file__), 'download.glade') window = "winDownloadPreferences" def init(self, conf, destination, exSource, exExif, exDate): """ Initalise the Download preferences window Keyword arguments: conf - configuration object destination - destination folder for downloaded images exSource - source file name (used for generating examples) exExif - source EXIF data (used for generating examples) exDate - source date (used for generating examples) """ self.__conf = conf self.exSource = exSource self.exExif = exExif self.exDate = exDate self.nb = NameBuilder() self.tbufComment = self.txtComment.get_buffer() # Init general page self.chkAutoRotate.set_active(self.__conf["autoRotate"] == 1) self.chkCopyOther.set_active(self.__conf["copyOther"] == 1) self.chkAutoComment.set_active( not len(self.__conf["autoComment"]) == 0) comment = self.__conf["autoComment"] self.tbufComment.set_text(comment.replace("\\n", "\n")) # Init naming page self.entDestination.set_text(destination) self.entFilename.set_text(self.__conf["nameFormat"]) self.origJobCode = self.__conf["jobCode"] self.entJobCode.set_text(self.__conf["jobCode"]) self.chkJobCode.set_active(self.__conf["promptJobCode"] == 1) self.updateExample() # Init Auto Tag page self.ltags = eval('%s' % self.__conf['autoTag']) def filename(column, cell, model, iter): cell.set_property('text', model.get_value(iter, 0)) cell.set_property('foreground', model.get_value(iter, 2)) cell.set_property('xalign', 0) # ~ cell.set_property('xpad', 1) def pixbuf(column, cell, model, iter): node = model.get_value(iter, 1) if node.__class__.__name__ == "TagNode": if model.get_value(iter, 3) == 0: cell.set_property('pixbuf', Buffer.pbCheckEmpty) elif model.get_value(iter, 3) == 1: cell.set_property('pixbuf', Buffer.pbCheckInclude) elif model.get_value(iter, 3) == 2: cell.set_property('pixbuf', Buffer.pbCheckExclude) else: cell.set_property('pixbuf', Buffer.pbCheckDisabled) else: cell.set_property('pixbuf', None) cell.set_property('width', 16) cell.set_property('xalign', 0) cellpb = gtk.CellRendererPixbuf() cell = gtk.CellRendererText() column = gtk.TreeViewColumn() column.pack_start(cellpb, False) column.pack_start(cell, True) column.set_cell_data_func(cellpb, pixbuf) column.set_cell_data_func(cell, filename) self.tvTags.append_column(column) treeselection = self.tvTags.get_selection() treeselection.set_mode(gtk.SELECTION_NONE) storeTags = TreeTags() self.tvTags.set_model(storeTags) self.tvTags.set_enable_search(False) self.tvTags.set_state(gtk.CAN_FOCUS) storeTags.expander(self.tvTags) storeTags.cleanSelections() storeTags.setSelected(self.ltags) tags = ", ".join(self.ltags) self.lblTags.set_label("Tags: %s" % tags) # Init Conversion Page self.chkDcraw.set_active(self.__conf["dcraw"] == 1) self.chkDcrawCopyMetaData.set_active( self.__conf["dcrawCopyMetaData"] == 1) self.chkDcrawCopyRaw.set_active(self.__conf["dcrawCopyRaw"] == 1) # Remove un-implemented pages self.ntbkPreferences.remove_page(4) # Conversion self.ntbkPreferences.remove_page(3) # Camera Mapping # Main Window handlers def on_winDownloadPreferences_delete_event(self, widget, *args): """Handles programatically closing the window""" self.quit(False) def on_btnOk_clicked(self, widget, *args): """Handles the Ok button and saves the preferences""" # Save general page if self.chkAutoRotate.get_active(): self.__conf["autoRotate"] = 1 else: self.__conf["autoRotate"] = 0 if self.chkCopyOther.get_active(): self.__conf["copyOther"] = 1 else: self.__conf["copyOther"] = 0 comment = self.tbufComment.get_text(self.tbufComment.get_start_iter(), self.tbufComment.get_end_iter()) self.__conf["autoComment"] = comment.replace("\n", "\\n") # Save naming page self.__conf["nameFormat"] = self.entFilename.get_text() self.__conf["jobCode"] = self.entJobCode.get_text() if self.chkJobCode.get_active(): self.__conf["promptJobCode"] = 1 else: self.__conf["promptJobCode"] = 0 self.quit(True) # Save Auto Tag page self.__conf['autoTag'] = self.ltags # Save Conversion page if self.chkDcraw.get_active(): self.__conf["dcraw"] = 1 else: self.__conf["dcraw"] = 0 if self.chkDcrawCopyMetaData.get_active(): self.__conf["dcrawCopyMetaData"] = 1 else: self.__conf["dcrawCopyMetaData"] = 0 if self.chkDcrawCopyRaw.get_active(): self.__conf["dcrawCopyRaw"] = 1 else: self.__conf["dcrawCopyRaw"] = 0 def on_btnCancel_clicked(self, widget, *args): """Handles the Cancel button""" self.quit(False) # # General tab handlers def on_chkAutoComment_toggled(self, widget, *args): """handles toggling of the Auto Comment tick-box and en/disables the comment text entry""" if self.chkAutoComment.get_active(): self.txtComment.set_editable(True) self.txtComment.set_flags(gtk.CAN_FOCUS) self.txtComment.set_flags(gtk.SENSITIVE) else: self.txtComment.set_editable(False) self.txtComment.unset_flags(gtk.CAN_FOCUS) self.txtComment.unset_flags(gtk.SENSITIVE) self.tbufComment.set_text("") # # Naming tab handlers def on_entFilename_changed(self, widget, *args): """Detects changes in the destination file name pattern and initates an update of the example""" self.updateExample() def on_entJobCode_changed(self, widget, *args): """Detects changes in the job code and initates an update of the example""" self.updateExample() def on_btnTokens_clicked(self, widget, *args): """Handles the Show all Tokens buttons & launches the list of tokens""" tokens = WinNameBuilderTokens(self.exSource, self.exExif, self.exDate, self.entJobCode.get_text()) tokens.loop() def updateExample(self): """Updates the example destination file name""" self.entExample.set_text( self.nb.singleSeralize( self.nb.name(self.exSource, self.entDestination.get_text(), self.entFilename.get_text(), self.exExif, self.exDate, self.entJobCode.get_text()))) # # Auto Tag Tab Handlers def on_tvTags_button_press_event(self, widget, *args): """Handles button presses in the AutoTag list""" event = args[0] tup = widget.get_path_at_pos(int(event.x), int(event.y)) if tup: path, obj, x, y = tup if path: model = widget.get_model() iterTo = model.get_iter(path) node = model.get(iterTo) # let's find the x beginning of the cell xcell = widget.get_cell_area(path, widget.get_column(0)).x if node.__class__.__name__ == "TagNode": if x > xcell: # click on the cell (not on the arrow) if event.button == 1: cv = model.get_value(iterTo, 3) if cv == 1: # Delete tag self.ltags.remove(node.name) else: # Add tag self.ltags.append(node.name) self.ltags.sort() model = self.tvTags.get_model() model.setSelected(self.ltags) tags = ", ".join(self.ltags) self.lblTags.set_label("Tags: %s" % tags) return 1 # stop the propagation of the event def on_tvTags_row_activated(self, widget, *args): """handles activation of rows in the auto tag list""" treeselection = widget.get_selection() model, iter0 = treeselection.get_selected() if iter0: model.switch(iter0) # # Conversion Tab Handlers def on_chkDcraw_toggled(self, widget, *args): """handles toggling of the dcraw tick-box and en/disables the the associated options""" if self.chkDcraw.get_active(): self.chkDcrawCopyMetaData.set_flags(gtk.CAN_FOCUS) self.chkDcrawCopyMetaData.set_flags(gtk.SENSITIVE) self.chkDcrawCopyRaw.set_flags(gtk.CAN_FOCUS) self.chkDcrawCopyRaw.set_flags(gtk.SENSITIVE) else: self.chkDcrawCopyMetaData.unset_flags(gtk.CAN_FOCUS) self.chkDcrawCopyMetaData.unset_flags(gtk.SENSITIVE) self.chkDcrawCopyMetaData.set_active(False) self.chkDcrawCopyRaw.unset_flags(gtk.CAN_FOCUS) self.chkDcrawCopyRaw.unset_flags(gtk.SENSITIVE) self.chkDcrawCopyRaw.set_active(False) # # Camera mapping Tab Handlers def on_btnMappingAdd_clicked(self, *args): """Handles the Add Mapping button and adds a new camera mapping from the classes in example file & exif information (future)""" pass def on_btnMappingAddFile_clicked(self, *args): """Handles the Add Mapping from File button and adds a new camera mapping from the user selected image file (future)""" pass def btnMappingDelete_clicked_cb(self, *args): """Handles the Delete Mapping button and deletes the selected mappings (future)""" pass def on_btnMappingEdit_clicked(self, *args): """Handles the Edit Mapping button and initiates alwos the used to edit the selected mappings (future)""" pass def on_chkMappingIdentify_toggled(self, *args): """Handles toggling of the additional information in Mapping check-box and updates the current camer information (future)""" pass
class WinDownload(GladeApp): """Class to handle main download window""" glade = os.path.join(os.path.dirname(__file__), 'download.glade') window = "winDownloadStart" def init(self, conf, nodeFolder): """Initalises the main download window and builds download table""" self.btnSourceFolder.drag_dest_set( gtk.DEST_DEFAULT_ALL, [( 'text/uri-list', 0, 1 ),('text/plain', 0, 1)], # drag from os gtk.gdk.ACTION_COPY | gtk.gdk.ACTION_MOVE) txtRdr = gtk.CellRendererText() columns = ((_('Source'), [(txtRdr, gobject.TYPE_STRING)], (dc.C_SRC,), True), (_('Size'), [(txtRdr, gobject.TYPE_STRING)], (dc.C_SZ_RAW,), True), (None, [(None, gobject.TYPE_STRING)], (None,), False),# Raw size (None, [(None, gobject.TYPE_PYOBJECT)], (None,), False), # Datetime object (_('Date/Time'), [(txtRdr, gobject.TYPE_STRING)], (dc.C_DATE,), True), # Date for display (None, [(None, gobject.TYPE_PYOBJECT)], (None,), False),# EXIF (_('Destination'), [(txtRdr, gobject.TYPE_STRING)], (dc.C_DEST,), True), (_('Status'), [(txtRdr, gobject.TYPE_STRING)], (dc.C_STAT,), True), (None, [(None, gobject.TYPE_STRING)], (None,), False),# Short Status (_('Rotation'), [(txtRdr, gobject.TYPE_STRING)], (dc.C_ROT,), True), (None, [(None, gobject.TYPE_STRING)], (None,), False)) self.imLst = extListview.ExtListView(columns) self.imLst.enableDNDReordering() self.swFileList.add(self.imLst) self.swFileList.show_all() self.destFolder = nodeFolder.file self.cidStatusBar = self.statusBar.get_context_id( _("Download Photos From Camera")) self._initFromConf(conf) self.invalidSource = True self.invalidDest = True self.badPattern = False self.buildListRunning = False self.quitNow = False task = self._bgWork() gobject.idle_add(task.next) def _initFromConf(self, conf): """ Initalise the download window from the stored configuration Keyword Arguments: conf - Configuration object """ self.__conf = conf self.nb = NameBuilder() self.srcFolder = self.__conf['sourceFolder'] if not os.path.isdir(self.srcFolder): self.srcFolder = os.path.dirname(__file__) self.entSourceFolder.set_text(self.srcFolder) self.entDestFolder.set_text(self.destFolder) self.chkDelete.set_active(self.__conf['delete'] == 1) w,h = self.__conf['width'] or 800,self.__conf['height'] or 400 # work arround for bug in pygtk/gtk 2.10.6 on windows set default size # then reshow with initial (default) size instead of simple resize self.main_widget.set_default_size(w,h) self.main_widget.reshow_with_initial_size() self.main_widget.resize_children() if self.__conf['promptJobCode'] == 1: newJobCode = InputBox(self.main_widget, _('Please enter the new Job Code'), '%s' % self.__conf['jobCode']) if newJobCode != None: self.__conf['jobCode'] = newJobCode def _bgWork(self): """Backgroud task to build/update image download table""" while not self.quitNow: if self.invalidSource and not self.buildListRunning: self.btnExecute.set_sensitive(False) self.buildListRunning = True task = self._buildListSource() gobject.idle_add(task.next) yield True (self.invalidSource, self.invalidDest,self.buildListRunning) if self.invalidDest and\ not self.invalidSource and\ not self.buildListRunning and\ not self.badPattern: self.buildListRunning = True self.btnExecute.set_sensitive(False) task = self._buildListDest() gobject.idle_add(task.next) yield True yield False def _buildListSource(self): """Builds list of files to be downloaded""" self.invalidSource = False self.invalidDest = True self.imLst.clear() self.statusBar.push(self.cidStatusBar, _('Finding source files in "%s"') % self.srcFolder) yield True self.imgInfs = [] fileList = self._listFiles(self.srcFolder) fileList.sort() self.statusBar.pop(self.cidStatusBar) self.statusBar.push(self.cidStatusBar, _('Reading source file information from "%s"') % self.srcFolder) yield True model = self.imLst.get_model() self.imLst.set_model(None) if self.invalidSource or self.quitNow: self.statusBar.pop(self.cidStatusBar) self.buildListRunning = False yield False for srcFile in fileList: exifData=pyexiv.Image(srcFile) exifData.readMetadata() size=os.path.getsize(srcFile) if 'Exif.Photo.DateTimeOriginal' in exifData.exifKeys(): date = ed2d(exifData.interpretedExifValue('Exif.Photo.DateTimeOriginal')) else: date = datetime.datetime.fromtimestamp(os.path.getmtime(srcFile)) row=[ srcFile[len(self.srcFolder)+1:], format_file_size_for_display(size), size, date, date, exifData, '', '', '', '', ''] self.imgInfs.append(row[:-4]) self.imLst.appendRows([row]) if self.invalidSource or self.quitNow: self.statusBar.pop(self.cidStatusBar) self.buildListRunning = False yield False yield True self.imLst.set_model(model) self.buildListRunning = False self.statusBar.pop(self.cidStatusBar) yield False def _buildListDest (self): """Adds destination file name, download status and rotation to a list of files to be downloaded""" self.invalidDest = False # Check that the list is not empty if self.imLst.getCount() == 0: self.buildListRunning = False yield False model = self.imLst.get_model() self.imLst.set_model(None) # Start new # Build image Names # Build names without seralisation self.statusBar.push(self.cidStatusBar, _('Building destination Names')) yield True # Clear all destination information for rowIdx in range(self.imLst.getCount()): self.imLst.setItem(rowIdx, dc.C_SS, '') self.imLst.setItem(rowIdx, dc.C_STAT, '') self.imLst.setItem(rowIdx, dc.C_RS, '') self.imLst.setItem(rowIdx, dc.C_ROT, '') for imageInfo in self.imgInfs: imageInfo[dc.C_DEST] = self.nb.name( imageInfo[dc.C_SRC], '', # Dest folder blank as not needed here self.__conf['nameFormat'], imageInfo[dc.C_EXIF], imageInfo[dc.C_DATE], self.__conf['jobCode']) if not self.nb.seralize(self.imgInfs,dc.C_SRC,dc.C_DATE,dc.C_DEST): MessageBox(self.main_widget, _("More than one serialisation tag used please use preferencess to remove from File Naming > Parttern")) self.statusBar.pop(self.cidStatusBar) self.invalidDest - True self.badPattern = True self.buildListRunning = False yield False if self.invalidSource or self.invalidDest or self.quitNow: self.statusBar.pop(self.cidStatusBar) self.buildListRunning = False yield False yield True # Note need to make sure self.imgInfs is sorted by source file # for the below to work # Write destination names into imList for imgIdx, imgInf in enumerate(self.imgInfs): if self.imLst.getItem(imgIdx,dc.C_SRC) != imgInf[dc.C_SRC]: print "No Match at %d ?" % (imgIdx) print "List: %s" % self.imLst.getItem(imageIndex,dc.C_SRC) print "Source: %s" % imgInf[dc.C_SRC] else: self.imLst.setItem(imgIdx, dc.C_DEST, imgInf[dc.C_DEST]) if self.invalidSource or self.invalidDest or self.quitNow: self.statusBar.pop(self.cidStatusBar) self.buildListRunning = False yield False yield True self.statusBar.pop(self.cidStatusBar) # Check Status self.statusBar.push(self.cidStatusBar, _('Checking Status of Images')) yield True for rowIdx, row in enumerate(self.imLst.iterAllRows()): destFile = os.path.join(self.destFolder,row[dc.C_DEST]) count = 0 for chkRow in self.imLst.iterAllRows(): if chkRow[dc.C_DEST] == row[dc.C_DEST]: count += 1 if count > 1: statS = 'C' statL = _('Collision with New') elif os.path.isfile(destFile): destExif = pyexiv.Image(destFile) destExif.readMetadata() if 'Image DateTime' in destExif.exifKeys(): destDate = ed2d(destExif.interpretedExifValue('Exif.Photo.DateTimeOriginal')) else: destDate = datetime.datetime.fromtimestamp( os.path.getmtime(destFile)) if destDate.timetuple() == row[dc.C_DATE].timetuple(): statS = 'D' statL = _('Downloaded') else: statS = 'C' statL = _('Collision with Existing') else: statS = 'N' statL = _('New') if self.invalidSource or self.invalidDest or self.quitNow: self.statusBar.pop(self.cidStatusBar) self.buildListRunning = False yield False self.imLst.setItem(rowIdx, dc.C_SS, statS) self.imLst.setItem(rowIdx, dc.C_STAT, statL) yield True self.statusBar.pop(self.cidStatusBar) # Check Rotation self.statusBar.push(self.cidStatusBar, _('Checking Rotation Required for Images')) yield True for rowIdx, row in enumerate(self.imLst.iterAllRows()): if self.__conf["autoRotate"] == 1: try: rotS = autoTrans[int(row[dc.C_EXIF]['Exif.Image.Orientation'])][0] rotL = autoTrans[int(row[dc.C_EXIF]['Exif.Image.Orientation'])][1] except KeyError: rotS = autoTrans[1][0] rotL = autoTrans[1][1] else: rotS = autoTrans[1][0] rotL = _('Disabled') if self.invalidSource or self.invalidDest or self.quitNow: self.statusBar.pop(self.cidStatusBar) self.buildListRunning = False yield False self.imLst.setItem(rowIdx, dc.C_RS, rotS) self.imLst.setItem(rowIdx, dc.C_ROT, rotL) yield True self.statusBar.pop(self.cidStatusBar) self.imLst.set_model(model) # Completed exiting self.btnExecute.set_sensitive(True) self.buildListRunning = False yield False def _listFiles(self, dir): """ Recursivley builds and returns a list of valid image files in a given directory Keyword Arguments: dir - Folder to recursivley list image files from """ fileList=[] for name in os.listdir(dir): path = os.path.join(dir, name) if ( os.path.isfile( path) and os.path.splitext( name )[1] in sup_ext() ): fileList +=[path] elif (os.path.isdir(path)): fileList += self._listFiles(path) return fileList def on_btnSourceFolder_clicked(self, widget, *args): """Handles the chanmge source folder button (...), gets the new source folder and initiates the update of the download list""" dialog = gtk.FileChooserDialog(_('Select source folder'), self.main_widget, gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER, (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OPEN, gtk.RESPONSE_OK)) dialog.set_default_response(gtk.RESPONSE_OK) dialog.set_filename(self.srcFolder) response = dialog.run() if response == gtk.RESPONSE_OK: if dialog.get_filename != self.srcFolder: self.srcFolder = dialog.get_filename() self.invalidSource = True self.entSourceFolder.set_text(self.srcFolder) dialog.destroy() def on_btnSourceFolder_drag_data_received(self, widget, *args): list = dnd_args_to_dir_list(args) if list: self.srcFolder = list[0] self.invalidSource = True self.entSourceFolder.set_text(self.srcFolder) def on_btnPreferences_clicked(self, widget, *args): """Handles the Preferences button, loads the preferences dialog and initiates the update of the download list""" if self.imLst.getCount() == 0: preferences = WinDownloadPreferences( self.__conf, self.destFolder, os.path.join(os.path.dirname(__file__), '123camera', 'img_4567.jpg'), dict(), datetime.datetime.now()) else: if self.imLst.getSelectedRowsCount() == 0: selIdx = 0 else: selIdx = self.imLst.getFirstSelectedRowIndex() preferences = WinDownloadPreferences( self.__conf, self.destFolder, self.imLst.getItem(selIdx, dc.C_SRC), self.imLst.getItem(selIdx, dc.C_EXIF), self.imLst.getItem(selIdx, dc.C_DATE)) response = preferences.loop()[0] if response: self.badPattern = False self.invalidDest = True def on_btnExecute_clicked(self, widget, *args): """Handles the Execute button and starts the download process""" # Save settings self.quitNow = True self.__conf["sourceFolder"]=self.entSourceFolder.get_text() if self.chkDelete.get_active(): self.__conf['delete'] = 1 else: self.__conf['delete'] = 0 self.__conf["width"],self.__conf["height"] = self.main_widget.get_size() # Build the list of images to download noRowsSelected = self.imLst.getSelectedRowsCount() if noRowsSelected == 0 or noRowsSelected == len(self.imgInfs): self.toDownload = self.imLst.getAllRows() else: self.toDownload = self.imLst.getSelectedRows() self.quit(True) def on_chkDelete_toggled(self, widget, *args): """Handles toggling of the delete check box""" pass def on_winDownloadStart_delete_event(self,*args): """Handles programatically closing the window""" self.quitNow = True self.quit(False) def on_btnCancel_clicked(self, widget, *args): """Handles the Cancle button and closes the window""" self.quitNow = True self.quit(False) def getToDownload(self): """Returns the list of 'selected' images to be downloaded (can be run after the window has been closed)""" return self.toDownload
def init(self, conf, destination, exSource, exExif, exDate): """ Initalise the Download preferences window Keyword arguments: conf - configuration object destination - destination folder for downloaded images exSource - source file name (used for generating examples) exExif - source EXIF data (used for generating examples) exDate - source date (used for generating examples) """ self.__conf = conf self.exSource = exSource self.exExif = exExif self.exDate = exDate self.nb = NameBuilder() self.tbufComment = self.txtComment.get_buffer() # Init general page self.chkAutoRotate.set_active(self.__conf["autoRotate"]==1) self.chkCopyOther.set_active(self.__conf["copyOther"]==1) self.chkAutoComment.set_active(not len(self.__conf["autoComment"])==0) comment = self.__conf["autoComment"] self.tbufComment.set_text(comment.replace("\\n", "\n")) # Init naming page self.entDestination.set_text(destination) self.entFilename.set_text(self.__conf["nameFormat"]) self.origJobCode = self.__conf["jobCode"] self.entJobCode.set_text(self.__conf["jobCode"]) self.chkJobCode.set_active(self.__conf["promptJobCode"]==1) self.updateExample() # Init Auto Tag page self.ltags = eval('%s' % self.__conf['autoTag']) def filename(column, cell, model, iter): cell.set_property('text', model.get_value(iter, 0)) cell.set_property('foreground', model.get_value(iter, 2)) cell.set_property('xalign', 0) #~ cell.set_property('xpad', 1) def pixbuf(column, cell, model, iter): node=model.get_value(iter,1) if node.__class__.__name__ == "TagNode": if model.get_value(iter, 3)==0: cell.set_property('pixbuf', Buffer.pbCheckEmpty) elif model.get_value(iter, 3)==1: cell.set_property('pixbuf', Buffer.pbCheckInclude) elif model.get_value(iter, 3)==2: cell.set_property('pixbuf', Buffer.pbCheckExclude) else: cell.set_property('pixbuf', Buffer.pbCheckDisabled) else: cell.set_property('pixbuf', None) cell.set_property('width', 16) cell.set_property('xalign', 0) cellpb = gtk.CellRendererPixbuf() cell = gtk.CellRendererText() column = gtk.TreeViewColumn() column.pack_start(cellpb, False) column.pack_start(cell, True) column.set_cell_data_func(cellpb, pixbuf) column.set_cell_data_func(cell, filename) self.tvTags.append_column(column) treeselection = self.tvTags.get_selection() treeselection.set_mode(gtk.SELECTION_NONE) storeTags = TreeTags() self.tvTags.set_model( storeTags ) self.tvTags.set_enable_search(False) self.tvTags.set_state(gtk.CAN_FOCUS) storeTags.expander(self.tvTags) storeTags.cleanSelections() storeTags.setSelected(self.ltags) tags = ", ".join(self.ltags) self.lblTags.set_label("Tags: %s" %tags) # Init Conversion Page self.chkDcraw.set_active(self.__conf["dcraw"]==1) self.chkDcrawCopyMetaData.set_active(self.__conf["dcrawCopyMetaData"]==1) self.chkDcrawCopyRaw.set_active(self.__conf["dcrawCopyRaw"]==1) # Remove un-implemented pages self.ntbkPreferences.remove_page(4) # Conversion self.ntbkPreferences.remove_page(3) # Camera Mapping
class WinDownloadPreferences(GladeApp): """Class to handle the Download Preferences window""" # TODO: implement camera tagging settings glade = os.path.join(os.path.dirname(__file__), 'download.glade') window = "winDownloadPreferences" def init(self, conf, destination, exSource, exExif, exDate): """ Initalise the Download preferences window Keyword arguments: conf - configuration object destination - destination folder for downloaded images exSource - source file name (used for generating examples) exExif - source EXIF data (used for generating examples) exDate - source date (used for generating examples) """ self.__conf = conf self.exSource = exSource self.exExif = exExif self.exDate = exDate self.nb = NameBuilder() self.tbufComment = self.txtComment.get_buffer() # Init general page self.chkAutoRotate.set_active(self.__conf["autoRotate"]==1) self.chkCopyOther.set_active(self.__conf["copyOther"]==1) self.chkAutoComment.set_active(not len(self.__conf["autoComment"])==0) comment = self.__conf["autoComment"] self.tbufComment.set_text(comment.replace("\\n", "\n")) # Init naming page self.entDestination.set_text(destination) self.entFilename.set_text(self.__conf["nameFormat"]) self.origJobCode = self.__conf["jobCode"] self.entJobCode.set_text(self.__conf["jobCode"]) self.chkJobCode.set_active(self.__conf["promptJobCode"]==1) self.updateExample() # Init Auto Tag page self.ltags = eval('%s' % self.__conf['autoTag']) def filename(column, cell, model, iter): cell.set_property('text', model.get_value(iter, 0)) cell.set_property('foreground', model.get_value(iter, 2)) cell.set_property('xalign', 0) #~ cell.set_property('xpad', 1) def pixbuf(column, cell, model, iter): node=model.get_value(iter,1) if node.__class__.__name__ == "TagNode": if model.get_value(iter, 3)==0: cell.set_property('pixbuf', Buffer.pbCheckEmpty) elif model.get_value(iter, 3)==1: cell.set_property('pixbuf', Buffer.pbCheckInclude) elif model.get_value(iter, 3)==2: cell.set_property('pixbuf', Buffer.pbCheckExclude) else: cell.set_property('pixbuf', Buffer.pbCheckDisabled) else: cell.set_property('pixbuf', None) cell.set_property('width', 16) cell.set_property('xalign', 0) cellpb = gtk.CellRendererPixbuf() cell = gtk.CellRendererText() column = gtk.TreeViewColumn() column.pack_start(cellpb, False) column.pack_start(cell, True) column.set_cell_data_func(cellpb, pixbuf) column.set_cell_data_func(cell, filename) self.tvTags.append_column(column) treeselection = self.tvTags.get_selection() treeselection.set_mode(gtk.SELECTION_NONE) storeTags = TreeTags() self.tvTags.set_model( storeTags ) self.tvTags.set_enable_search(False) self.tvTags.set_state(gtk.CAN_FOCUS) storeTags.expander(self.tvTags) storeTags.cleanSelections() storeTags.setSelected(self.ltags) tags = ", ".join(self.ltags) self.lblTags.set_label("Tags: %s" %tags) # Init Conversion Page self.chkDcraw.set_active(self.__conf["dcraw"]==1) self.chkDcrawCopyMetaData.set_active(self.__conf["dcrawCopyMetaData"]==1) self.chkDcrawCopyRaw.set_active(self.__conf["dcrawCopyRaw"]==1) # Remove un-implemented pages self.ntbkPreferences.remove_page(4) # Conversion self.ntbkPreferences.remove_page(3) # Camera Mapping # Main Window handlers def on_winDownloadPreferences_delete_event(self, widget, *args): """Handles programatically closing the window""" self.quit(False) def on_btnOk_clicked(self, widget, *args): """Handles the Ok button and saves the preferences""" # Save general page if self.chkAutoRotate.get_active(): self.__conf["autoRotate"] = 1 else: self.__conf["autoRotate"] = 0 if self.chkCopyOther.get_active(): self.__conf["copyOther"] = 1 else: self.__conf["copyOther"] = 0 comment = self.tbufComment.get_text(self.tbufComment.get_start_iter(), self.tbufComment.get_end_iter()) self.__conf["autoComment"] = comment.replace("\n", "\\n") # Save naming page self.__conf["nameFormat"] = self.entFilename.get_text() self.__conf["jobCode"] = self.entJobCode.get_text() if self.chkJobCode.get_active(): self.__conf["promptJobCode"] = 1 else: self.__conf["promptJobCode"] = 0 self.quit(True) # Save Auto Tag page self.__conf['autoTag']=self.ltags # Save Conversion page if self.chkDcraw.get_active(): self.__conf["dcraw"] = 1 else: self.__conf["dcraw"] = 0 if self.chkDcrawCopyMetaData.get_active(): self.__conf["dcrawCopyMetaData"] = 1 else: self.__conf["dcrawCopyMetaData"] = 0 if self.chkDcrawCopyRaw.get_active(): self.__conf["dcrawCopyRaw"] = 1 else: self.__conf["dcrawCopyRaw"] = 0 def on_btnCancel_clicked(self, widget, *args): """Handles the Cancel button""" self.quit(False) ## General tab handlers def on_chkAutoComment_toggled(self, widget, *args): """handles toggling of the Auto Comment tick-box and en/disables the comment text entry""" if self.chkAutoComment.get_active(): self.txtComment.set_editable(True) self.txtComment.set_flags(gtk.CAN_FOCUS) self.txtComment.set_flags(gtk.SENSITIVE) else: self.txtComment.set_editable(False) self.txtComment.unset_flags(gtk.CAN_FOCUS) self.txtComment.unset_flags(gtk.SENSITIVE) self.tbufComment.set_text("") ## Naming tab handlers def on_entFilename_changed(self, widget, *args): """Detects changes in the destination file name pattern and initates an update of the example""" self.updateExample() def on_entJobCode_changed(self, widget, *args): """Detects changes in the job code and initates an update of the example""" self.updateExample() def on_btnTokens_clicked(self, widget, *args): """Handles the Show all Tokens buttons & launches the list of tokens""" tokens=WinNameBuilderTokens(self.exSource, self.exExif, self.exDate, self.entJobCode.get_text()) tokens.loop() def updateExample(self): """Updates the example destination file name""" self.entExample.set_text( self.nb.singleSeralize( self.nb.name( self.exSource, self.entDestination.get_text(), self.entFilename.get_text(), self.exExif, self.exDate, self.entJobCode.get_text()))) ## Auto Tag Tab Handlers def on_tvTags_button_press_event(self, widget, *args): """Handles button presses in the AutoTag list""" event=args[0] tup= widget.get_path_at_pos( int(event.x), int(event.y) ) if tup: path,obj,x,y = tup if path: model = widget.get_model() iterTo = model.get_iter(path) node = model.get(iterTo) # let's find the x beginning of the cell xcell = widget.get_cell_area(path, widget.get_column(0) ).x if node.__class__.__name__ == "TagNode": if x>xcell: # click on the cell (not on the arrow) if event.button==1: cv = model.get_value(iterTo,3) if cv == 1: # Delete tag self.ltags.remove(node.name) else: # Add tag self.ltags.append(node.name) self.ltags.sort() model=self.tvTags.get_model() model.setSelected(self.ltags) tags = ", ".join(self.ltags) self.lblTags.set_label("Tags: %s" %tags) return 1 # stop the propagation of the event def on_tvTags_row_activated(self, widget, *args): """handles activation of rows in the auto tag list""" treeselection = widget.get_selection() model, iter0 = treeselection.get_selected() if iter0: model.switch(iter0) ## Conversion Tab Handlers def on_chkDcraw_toggled(self, widget, *args): """handles toggling of the dcraw tick-box and en/disables the the associated options""" if self.chkDcraw.get_active(): self.chkDcrawCopyMetaData.set_flags(gtk.CAN_FOCUS) self.chkDcrawCopyMetaData.set_flags(gtk.SENSITIVE) self.chkDcrawCopyRaw.set_flags(gtk.CAN_FOCUS) self.chkDcrawCopyRaw.set_flags(gtk.SENSITIVE) else: self.chkDcrawCopyMetaData.unset_flags(gtk.CAN_FOCUS) self.chkDcrawCopyMetaData.unset_flags(gtk.SENSITIVE) self.chkDcrawCopyMetaData.set_active(False) self.chkDcrawCopyRaw.unset_flags(gtk.CAN_FOCUS) self.chkDcrawCopyRaw.unset_flags(gtk.SENSITIVE) self.chkDcrawCopyRaw.set_active(False) ## Camera mapping Tab Handlers def on_btnMappingAdd_clicked(self,*args): """Handles the Add Mapping button and adds a new camera mapping from the classes in example file & exif information (future)""" pass def on_btnMappingAddFile_clicked(self,*args): """Handles the Add Mapping from File button and adds a new camera mapping from the user selected image file (future)""" pass def btnMappingDelete_clicked_cb(self,*args): """Handles the Delete Mapping button and deletes the selected mappings (future)""" pass def on_btnMappingEdit_clicked(self,*args): """Handles the Edit Mapping button and initiates alwos the used to edit the selected mappings (future)""" pass def on_chkMappingIdentify_toggled(self,*args): """Handles toggling of the additional information in Mapping check-box and updates the current camer information (future)""" pass