def Refresh(self): """ This method allows up to update all data when this tab is displayed. This is necessary as the objects may have been changed since they were originally loaded. """ try: # If a Library Object is defined, reload it if self.seriesObj != None: self.seriesObj = Library.Library(self.seriesObj.number) # If an Episode Object is defined, reload it if self.episodeObj != None: self.episodeObj = Episode.Episode(self.episodeObj.number) # if a Documetn Object is defined, reload it if self.documentObj != None: self.documentObj = Document.Document(self.documentObj.number) # If a Collection Object is defined, reload it if self.collectionObj != None: self.collectionObj = Collection.Collection( self.collectionObj.number) # If a Clip Object is defined, reload it. if self.clipObj != None: self.clipObj = Clip.Clip(self.clipObj.number) # If a Quote Object is defined, reload it. if self.quoteObj != None: self.quoteObj = Quote.Quote(self.quoteObj.number) # Get the local keyword list pointer aimed at the appropriate source object. # NOTE: If a Clip is defined use it (whether an episode is defined or not.) If # no clip is defined but an episode is defined, use that. if self.clipObj != None: self.kwlist = self.clipObj.keyword_list elif self.episodeObj != None: self.kwlist = self.episodeObj.keyword_list elif self.documentObj != None: self.kwlist = self.documentObj.keyword_list elif self.quoteObj != None: self.kwlist = self.quoteObj.keyword_list # Update the Tab Display self.UpdateKeywords() except TransanaExceptions.RecordNotFoundError: msg = _( "The appropriate Keyword data could not be loaded from the database." ) if not TransanaConstants.singleUserVersion: msg += '\n' + _( "This data may have been deleted by another user.") tmpDlg = Dialogs.ErrorDialog(self.parent, msg) tmpDlg.ShowModal() tmpDlg.Destroy() # Return to the database tab self.parent.parent.ControlObject.ShowDataTab(0)
from Clip import * from CopyEraser import * from Eraser import * from Folder import * from Marker import * from Pen import * from PostIt import * from ReamOfPaper import * from Staple import * from Stapler import * from Tape import * from Box import * from Shelf import * #creando algunos objetos clip1 = Clip("Sifap", "Mediano") eraser1 = Eraser("Milan", "Grande") eraser2 = Eraser("Pelikan", "Pequeño") pen1 = Pen("Bic", "2HB") pen2 = Pen("Bic", "4HB") pen3 = Pen("Stabilo", "4HB") pen4 = Pen("Studio", "4HB") marker1 = Marker("Sharpie", "Permanente") marker2 = Marker("Bic", "Permanente") reamOfPaper1 = ReamOfPaper("Chamex", "Hoja carta", "200") folder1 = Folder("Econofile", "grande", "200") tape1 = Tape("Tesa", "Transparente") stapler1 = Stapler("King", "200", "Grande") #creando caja1 box1 = Box()
def OnEdit(self, event): """ Selecting 'Edit' from the popup menu takes you to the Keyword List Edit Form """ # Lock the appropriate record # NOTE: If a Clip is defined use it (whether an episode is defined or not.) If # no clip is defined but an episode is defined, use that. if self.clipObj != None: obj = self.clipObj elif self.episodeObj != None: obj = self.episodeObj elif self.documentObj != None: obj = self.documentObj elif self.quoteObj != None: obj = self.quoteObj try: obj.lock_record() # Create/define the Keyword List Edit Form dlg = KeywordListEditForm.KeywordListEditForm( self.parent.parent, -1, _("Edit Keyword List"), obj, self.kwlist) # Set the "continue" flag to True (used to redisplay the dialog if an exception is raised) contin = True # While the "continue" flag is True ... while contin: # if the user pressed "OK" ... try: # Show the Keyword List Edit Form and process it if the user selects OK if dlg.ShowModal() == wx.ID_OK: # Clear the local keywords list and repopulate it from the Keyword List Edit Form self.kwlist = [] for kw in dlg.keywords: self.kwlist.append(kw) # Copy the local keywords list into the appropriate object and save that object obj.keyword_list = self.kwlist if isinstance(obj, Clip.Clip): for (keywordGroup, keyword, clipNum) in dlg.keywordExamplesToDelete: # Load the specified Clip record. Save time by skipping the Clip Transcript, which we don't need. tempClip = Clip.Clip(clipNum, skipText=True) # Prepare the Node List for removing the Keyword Example Node nodeList = (_('Keywords'), keywordGroup, keyword, tempClip.id) # Call the DB Tree's delete_Node method. Include the Clip Record Number so the correct Clip entry will be removed. self.parent.GetPage(0).tree.delete_Node( nodeList, 'KeywordExampleNode', tempClip.number) # If we are dealing with an Episode ... if isinstance(obj, Episode.Episode): # Check to see if there are keywords to be propagated self.parent.parent.ControlObject.PropagateObjectKeywords( _('Episode'), obj.number, obj.keyword_list) # If we're dealing with a Document ... elif isinstance(obj, Document.Document): # Check to see if there are keywords to be propagated self.parent.parent.ControlObject.PropagateObjectKeywords( _('Document'), obj.number, obj.keyword_list) obj.db_save() # Now let's communicate with other Transana instances if we're in Multi-user mode if not TransanaConstants.singleUserVersion: if isinstance(obj, Episode.Episode): msg = 'Episode %d' % obj.number elif isinstance(obj, Clip.Clip): msg = 'Clip %d' % obj.number elif isinstance(obj, Document.Document): msg = 'Document %d' % obj.number elif isinstance(obj, Quote.Quote): msg = 'Quote %d' % obj.number else: msg = '' if msg != '': if DEBUG: print 'Message to send = "UKL %s"' % msg if TransanaGlobal.chatWindow != None: # Send the "Update Keyword List" message TransanaGlobal.chatWindow.SendMessage( "UKL %s" % msg) # Update the display to reflect changes in the Keyword List self.UpdateKeywords(sendMUMessage=True) # If we do all this, we don't need to continue any more. contin = False # If the user pressed Cancel ... else: # ... then we don't need to continue any more. contin = False # Handle "SaveError" exception except TransanaExceptions.SaveError: # Display the Error Message, allow "continue" flag to remain true errordlg = Dialogs.ErrorDialog(None, sys.exc_info()[1].reason) errordlg.ShowModal() errordlg.Destroy() # Refresh the Keyword List, if it's a changed Keyword error dlg.refresh_keywords() # Highlight the first non-existent keyword in the Keywords control dlg.highlight_bad_keyword() # Handle other exceptions except: if DEBUG: import traceback traceback.print_exc(file=sys.stdout) # Display the Exception Message, allow "continue" flag to remain true if 'unicode' in wx.PlatformInfo: # Encode with UTF-8 rather than TransanaGlobal.encoding because this is a prompt, not DB Data. prompt = unicode(_("Exception %s: %s"), 'utf8') else: prompt = _("Exception %s: %s") errordlg = Dialogs.ErrorDialog( None, prompt % (sys.exc_info()[0], sys.exc_info()[1])) errordlg.ShowModal() errordlg.Destroy() # Unlock the appropriate record obj.unlock_record() # Free the memory used for the Keyword List Edit Form dlg.Destroy() except TransanaExceptions.RecordLockedError, e: self.handleRecordLock(e)
def Export(self): """ Export the Analytic Data to a Tab-delimited file """ # Initialize values for data structures for this report # The Episode List is the list of Episodes to be sent to the Filter Dialog for the Library report episodeList = [] # The Document List is the list of Documents to be sent to the Filter Dialog for the Library report documentList = [] # The Quote List is the list of Quotes to be sent to the Filter Dialog quoteList = [] # The Quote Lookup allows us to find the Quote Number based on the data from the Quote List quoteLookup = {} # The Clip List is the list of Clips to be sent to the Filter Dialog clipList = [] # The Clip Lookup allows us to find the Clip Number based on the data from the Clip List clipLookup = {} # The Keyword List is the list of Keywords to be sent to the Filter Dialog keywordList = [] # Show a WAIT cursor. Assembling the data can take noticable time in some cases. TransanaGlobal.menuWindow.SetCursor(wx.StockCursor(wx.CURSOR_WAIT)) # If we have an Library Number, we set up the Library Analytic Data Export if self.libraryNum <> 0: # Get the Library record tempLibrary = Library.Library(self.libraryNum) # obtain a list of all Documents in the Library tempDocumentList = DBInterface.list_of_documents( tempLibrary.number) # initialize the temporary Quote List tempQuoteList = [] # iterate through the Document List ... for documentRecord in tempDocumentList: # ... and add each Document's Quotes to the Temporary Quote list tempQuoteList += DBInterface.list_of_quotes_by_document( documentRecord[0]) # Add the Document data to the Filter Dialog's Document List documentList.append((documentRecord[1], tempLibrary.id, True)) # For all the Quotes ... for quoteRecord in tempQuoteList: # ... add the Quote to the Quote List for filtering ... quoteList.append( (quoteRecord['QuoteID'], quoteRecord['CollectNum'], True)) # ... retain a pointer to the Quote Number keyed to the Quote ID and Collection Number ... quoteLookup[( quoteRecord['QuoteID'], quoteRecord['CollectNum'])] = quoteRecord['QuoteNum'] # ... now get all the keywords for this Quote ... quoteKeywordList = DBInterface.list_of_keywords( Quote=quoteRecord['QuoteNum']) # ... and iterate through the list of Quote keywords. for quoteKeyword in quoteKeywordList: # If the keyword isn't already in the Keyword List ... if (quoteKeyword[0], quoteKeyword[1], True) not in keywordList: # ... add the keyword to the keyword list for filtering. keywordList.append( (quoteKeyword[0], quoteKeyword[1], True)) # obtain a list of all Episodes in that Library tempEpisodeList = DBInterface.list_of_episodes_for_series( tempLibrary.id) # initialize the temporary clip List tempClipList = [] # iterate through the Episode List ... for episodeRecord in tempEpisodeList: # ... and add each Episode's Clips to the Temporary clip list tempClipList += DBInterface.list_of_clips_by_episode( episodeRecord[0]) # Add the Episode data to the Filter Dialog's Episode List episodeList.append((episodeRecord[1], tempLibrary.id, True)) # For all the Clips ... for clipRecord in tempClipList: # ... add the Clip to the Clip List for filtering ... clipList.append( (clipRecord['ClipID'], clipRecord['CollectNum'], True)) # ... retain a pointer to the Clip Number keyed to the Clip ID and Collection Number ... clipLookup[(clipRecord['ClipID'], clipRecord['CollectNum'])] = clipRecord['ClipNum'] # ... now get all the keywords for this Clip ... clipKeywordList = DBInterface.list_of_keywords( Clip=clipRecord['ClipNum']) # ... and iterate through the list of clip keywords. for clipKeyword in clipKeywordList: # If the keyword isn't already in the Keyword List ... if (clipKeyword[0], clipKeyword[1], True) not in keywordList: # ... add the keyword to the keyword list for filtering. keywordList.append( (clipKeyword[0], clipKeyword[1], True)) # If we have a Document Number, we set up the Document Analytic Data Export elif self.documentNum <> 0: # First, we get a list of all the Quotes for the Document specified tempQuoteList = DBInterface.list_of_quotes_by_document( self.documentNum) # For all the Quotes ... for quoteRecord in tempQuoteList: # ... add the Quote to the Quote List for filtering ... quoteList.append( (quoteRecord['QuoteID'], quoteRecord['CollectNum'], True)) # ... retain a pointer to the Quote Number keyed to the Quote ID and Collection Number ... quoteLookup[( quoteRecord['QuoteID'], quoteRecord['CollectNum'])] = quoteRecord['QuoteNum'] # ... now get all the keywords for this Quote ... quoteKeywordList = DBInterface.list_of_keywords( Quote=quoteRecord['QuoteNum']) # ... and iterate through the list of Quote keywords. for quoteKeyword in quoteKeywordList: # If the keyword isn't already in the Keyword List ... if (quoteKeyword[0], quoteKeyword[1], True) not in keywordList: # ... add the keyword to the keyword list for filtering. keywordList.append( (quoteKeyword[0], quoteKeyword[1], True)) # If we have an Episode Number, we set up the Episode Analytic Data Export elif self.episodeNum <> 0: # First, we get a list of all the Clips for the Episode specified tempClipList = DBInterface.list_of_clips_by_episode( self.episodeNum) # For all the Clips ... for clipRecord in tempClipList: # ... add the Clip to the Clip List for filtering ... clipList.append( (clipRecord['ClipID'], clipRecord['CollectNum'], True)) # ... retain a pointer to the Clip Number keyed to the Clip ID and Collection Number ... clipLookup[(clipRecord['ClipID'], clipRecord['CollectNum'])] = clipRecord['ClipNum'] # ... now get all the keywords for this Clip ... clipKeywordList = DBInterface.list_of_keywords( Clip=clipRecord['ClipNum']) # ... and iterate through the list of clip keywords. for clipKeyword in clipKeywordList: # If the keyword isn't already in the Keyword List ... if (clipKeyword[0], clipKeyword[1], True) not in keywordList: # ... add the keyword to the keyword list for filtering. keywordList.append( (clipKeyword[0], clipKeyword[1], True)) # If we don't have Library Number, Document Number, or Episode number, but DO have a Collection Number, we set # up the Clips for the Collection specified. If we have neither, it's the GLOBAL Analytic Data Export, # requesting ALL the Quotes and Clips in the database! We can handle both of these cases together. else: # If we have a specific collection specified ... if self.collectionNum <> 0: # ... load the specified collection. We need its data. tempCollection = Collection.Collection(self.collectionNum) # Put the selected Collection's data into the Collection List as a starting place. tempCollectionList = [ (tempCollection.number, tempCollection.id, tempCollection.parent) ] # If we don't have any selected collection ... else: # ... then we should initialise the Collection List with data for all top-level collections, with parent = 0 tempCollectionList = DBInterface.list_of_collections() # Iterate through the Collection List as long as it has entries while len(tempCollectionList) > 0: # Get the list of Quotes for the current Collection tempQuoteList = DBInterface.list_of_quotes_by_collectionnum( tempCollectionList[0][0]) # For all the Quotes ... for (quoteNo, quoteName, collNo, sourceDocNo) in tempQuoteList: # ... add the Quote to the Quote List for filtering ... quoteList.append((quoteName, collNo, True)) # ... retain a pointer to the Quote Number keyed to the Quote ID and Collection Number ... quoteLookup[(quoteName, collNo)] = quoteNo # ... now get all the keywords for this Quote ... quoteKeywordList = DBInterface.list_of_keywords( Quote=quoteNo) # ... and iterate through the list of Quote keywords. for quoteKeyword in quoteKeywordList: # If the keyword isn't already in the Keyword List ... if (quoteKeyword[0], quoteKeyword[1], True) not in keywordList: # ... add the keyword to the keyword list for filtering. keywordList.append( (quoteKeyword[0], quoteKeyword[1], True)) # Get the list of Clips for the current Collection tempClipList = DBInterface.list_of_clips_by_collection( tempCollectionList[0][1], tempCollectionList[0][2]) # For all the Clips ... for (clipNo, clipName, collNo) in tempClipList: # ... add the Clip to the Clip List for filtering ... clipList.append((clipName, collNo, True)) # ... retain a pointer to the Clip Number keyed to the Clip ID and Collection Number ... clipLookup[(clipName, collNo)] = clipNo # ... now get all the keywords for this Clip ... clipKeywordList = DBInterface.list_of_keywords(Clip=clipNo) # ... and iterate through the list of clip keywords. for clipKeyword in clipKeywordList: # If the keyword isn't already in the Keyword List ... if (clipKeyword[0], clipKeyword[1], True) not in keywordList: # ... add the keyword to the keyword list for filtering. keywordList.append( (clipKeyword[0], clipKeyword[1], True)) # Get the nested collections for the current collection and add them to the Collection List tempCollectionList += DBInterface.list_of_collections( tempCollectionList[0][0]) # Remove the current Collection from the list. We're done with it. del (tempCollectionList[0]) # Put the Quote List in alphabetical order in preparation for Filtering.. quoteList.sort() # Put the Clip List in alphabetical order in preparation for Filtering.. clipList.sort() # Put the Keyword List in alphabetical order in preparation for Filtering. keywordList.sort() # Prepare the Filter Dialog. # Set the title for the Filter Dialog title = unicode(_("Analytic Data Export Filter Dialog"), 'utf8') # If we have a Library-based report ... if self.libraryNum != 0: # ... reportType 14 indicates Library Analytic Data Export to the Filter Dialog reportType = 14 # ... the reportScope is the Library Number. reportScope = self.libraryNum # If we have a Document-based report ... elif self.documentNum != 0: # ... reportType 20 indicates Document Analytic Data Export to the Filter Dialog reportType = 20 # ... the reportScope is the Document Number. reportScope = self.documentNum # If we have an Episode-based report ... elif self.episodeNum != 0: # ... reportType 3 indicates Episode Analytic Data Export to the Filter Dialog reportType = 3 # ... the reportScope is the Episode Number. reportScope = self.episodeNum # If we have a Collection-based report ... else: # ... reportType 4 indicates Collection Analytic Data Export to the Filter Dialog reportType = 4 # ... the reportScope is the Collection Number. reportScope = self.collectionNum showDocuments = (len(documentList) > 0) showEpisodes = (len(episodeList) > 0) showQuotes = (len(quoteList) > 0) showClips = (len(clipList) > 0) # If we are basing the report on a Library ... if self.libraryNum != 0: # ... create a Filter Dialog, passing all the necessary parameters. We want to include the Episode List dlgFilter = FilterDialog.FilterDialog(None, -1, title, reportType=reportType, reportScope=reportScope, documentFilter=showDocuments, episodeFilter=showEpisodes, quoteFilter=showQuotes, clipFilter=showClips, keywordFilter=True) # If we are basing the report on a Collection (but not the Collection Root) ... elif self.collectionNum != 0: # ... create a Filter Dialog, passing all the necessary parameters. We want to be able to include Nested Collections dlgFilter = FilterDialog.FilterDialog(None, -1, title, reportType=reportType, reportScope=reportScope, quoteFilter=showQuotes, clipFilter=showClips, keywordFilter=True, reportContents=True, showNestedData=True) # If we are basing the report on a Document ... elif self.documentNum != 0: # ... create a Filter Dialog, passing all the necessary parameters. We DON'T need Nested Collections dlgFilter = FilterDialog.FilterDialog(None, -1, title, reportType=reportType, reportScope=reportScope, quoteFilter=True, keywordFilter=True) # If we are basing the report on an Episode ... elif self.episodeNum != 0: # ... create a Filter Dialog, passing all the necessary parameters. We DON'T need Nested Collections dlgFilter = FilterDialog.FilterDialog(None, -1, title, reportType=reportType, reportScope=reportScope, clipFilter=True, keywordFilter=True) # If we are doing the report on the Collection Root report, which MUST have nested data) ... else: # ... create a Filter Dialog, passing all the necessary parameters. We DON'T need Nested Collections dlgFilter = FilterDialog.FilterDialog(None, -1, title, reportType=reportType, reportScope=reportScope, quoteFilter=showQuotes, clipFilter=showClips, keywordFilter=True) # If we have a Library-based report ... if self.libraryNum != 0: if showDocuments: # ... populate the Document Data Structure dlgFilter.SetDocuments(documentList) if showEpisodes: # ... populate the Episode Data Structure dlgFilter.SetEpisodes(episodeList) # Populate the Quote, Clip and Keyword Data Structures if showQuotes: dlgFilter.SetQuotes(quoteList) if showClips: dlgFilter.SetClips(clipList) dlgFilter.SetKeywords(keywordList) # ... get the list of existing configuration names. profileList = dlgFilter.GetConfigNames() # If (translated) "Default" is in the list ... # (NOTE that the default config name is stored in English, but gets translated by GetConfigNames!) if unicode(_('Default'), 'utf8') in profileList: # ... set the Filter Dialog to use this filter dlgFilter.configName = unicode(_('Default'), TransanaGlobal.encoding) # Temporarily set loadDefault to True for the Filter Dialog. This disables the Filter Load dialog. # (We don't use the FilterDialog parameter, as that disables loading other Filters!) dlgFilter.loadDefault = True # We need to load the config dlgFilter.OnFileOpen(None) # Now we turn loadDefault back off so we can load other filters if we want. dlgFilter.loadDefault = False # restore the cursor, now that the data is set up for the filter dialog TransanaGlobal.menuWindow.SetCursor(wx.StockCursor(wx.CURSOR_ARROW)) # If the user clicks OK ... if dlgFilter.ShowModal() == wx.ID_OK: # Set the WAIT cursor. It can take a while to build the data file. TransanaGlobal.menuWindow.SetCursor(wx.StockCursor(wx.CURSOR_WAIT)) # If we have a Library-based report ... if self.libraryNum != 0: if showDocuments: documentList = dlgFilter.GetDocuments() if showEpisodes: # ... get the revised Episode data from the Filter Dialog episodeList = dlgFilter.GetEpisodes() # Get the revised Quote, Clip, and Keyword data from the Filter Dialog if showQuotes: quoteList = dlgFilter.GetQuotes() if showClips: clipList = dlgFilter.GetClips() keywordList = dlgFilter.GetKeywords() # If we have a Collection-based report ... if self.collectionNum != 0: # ... get the setting for including nested collections (not relevant for other reports) showNested = dlgFilter.GetShowNestedData() # If we have a report other than based on a Collection ... else: # ... nesting is meaningless, so we can just initialize this variable to False. showNested = False # Get the user-specified File Name fs = self.exportFile.GetValue() # Ensure that the file name has the proper extension. if fs[-4:].lower() != '.txt': fs = fs + '.txt' # On the Mac, if no path is specified, the data is exported to a file INSIDE the application bundle, # where no one will be able to find it. Let's put it in the user's HOME directory instead. # I'm okay with not handling this on Windows, where it will be placed in the Program's folder # but it CAN be found. (There's no easy way on Windows to determine the location of "My Documents" # especially if the user has moved it.) if "__WXMAC__" in wx.PlatformInfo: # if the specified file has no path specification ... if fs.find(os.sep) == -1: # ... then prepend the HOME folder fs = os.getenv("HOME") + os.sep + fs # Open the output file for writing. f = codecs.open(fs, 'w', 'utf8') # file(fs, 'w') prompt = unicode( _('Collection Name\tItem Type\tItem Name\tSource File\tStart\tStop\tLength' ), 'utf8') # Write the Header line. We're creating a tab-delimited file, so we'll use tabs to separate the items. f.write(prompt) # Add keywords to the Header. Iterate through the Keyword List. for keyword in keywordList: # See if the user has left the keyword "checked" in the filter dialog. if keyword[2]: # Encode and write all "checked" keywords to the Header. kwg = keyword[0] kw = keyword[1] f.write('\t%s : %s' % (kwg, kw)) # Add a line break to signal the end of the Header line. f.write('\n') # Now iterate through the Quote List for quoteRec in quoteList: # See if the user has left the Quote "checked" in the filter dialog. # Also, if we are using a collection report, either Nested Data should be requested OR the current # Quote should be from the main collection if it is to be included in the report. if quoteRec[2] and ((self.collectionNum == 0) or (showNested) or (quoteRec[1] == self.collectionNum)): # Load the Quote data. The QuoteLookup dictionary allows this easily. # No need to load the Quote Text, which can be slow to load. quote = Quote.Quote(quoteLookup[quoteRec[0], quoteRec[1]], skipText=True) # Get the collection the Quote is from. collection = Collection.Collection(quote.collection_num) # Encode string values using the Export Encoding collectionID = collection.GetNodeString() quoteID = quote.id try: document = Document.Document(quote.source_document_num) documentID = document.id quoteSourceFilename = document.imported_file # If we're doing a Library report, we need the Quote's source document and Library for Document Filter comparison. if self.libraryNum != 0: library = Library.Library(document.library_num) libraryID = library.id # If we have an orphaned Quote ... except TransanaExceptions.RecordNotFoundError, e: # ... then we don't know these values! documentID = '' quoteSourceFilename = _('Source Document unknown') libraryID = 0 # Implement Document filtering if needed. If we have a Library Report, we need to confirm that the Source Document # is "checked" in the filter list. (If we don't have a Library Report, this check isn't needed.) if (self.libraryNum == 0) or ( (documentID == '') and (libraryID == '')) or ((documentID, libraryID, True) in documentList): # Write the Quote's data values to the output file. We're creating a tab-delimited file, # so we'll use tabs to separate the items. f.write( '%s\t%s\t%s\t%s\t%s\t%s\t%d' % (collectionID, '1', quoteID, quoteSourceFilename, quote.start_char, quote.end_char, (quote.end_char - quote.start_char))) # Now we iterate through the keyword list ... for keyword in keywordList: # ... looking only at those keywords the user left "checked" in the filter dialog ... if keyword[2]: # ... and check to see if the Quote HAS the keyword. if quote.has_keyword(keyword[0], keyword[1]): # If so, we write a "1", indicating True. f.write('\t1') else: # If not, we write a "0", indicating False. f.write('\t0') # Add a line break to signal the end of the Quote record f.write('\n') # Now iterate through the Clip List for clipRec in clipList: # See if the user has left the clip "checked" in the filter dialog. # Also, if we are using a collection report, either Nested Data should be requested OR the current # clip should be from the main collection if it is to be included in the report. if clipRec[2] and ((self.collectionNum == 0) or (showNested) or (clipRec[1] == self.collectionNum)): # Load the Clip data. The ClipLookup dictionary allows this easily. # No need to load the Clip Transcripts, which can be slow to load. clip = Clip.Clip(clipLookup[clipRec[0], clipRec[1]], skipText=True) # Get the collection the clip is from. collection = Collection.Collection(clip.collection_num) # Encode string values using the Export Encoding collectionID = collection.GetNodeString() clipID = clip.id clipMediaFilename = clip.media_filename # If we're doing a Library report, we need the clip's source episode and Library for Episode Filter comparison. if self.libraryNum != 0: episode = Episode.Episode(clip.episode_num) library = Library.Library(episode.series_num) # Implement Episode filtering if needed. If we have a Library Report, we need to confirm that the Source Episode # is "checked" in the filter list. (If we don't have a Library Report, this check isn't needed.) if (self.libraryNum == 0) or ((episode.id, library.id, True) in episodeList): # Write the Clip's data values to the output file. We're creating a tab-delimited file, # so we'll use tabs to separate the items. f.write('%s\t%s\t%s\t%s\t%s\t%s\t%10.4f' % (collectionID, '2', clipID, clipMediaFilename, Misc.time_in_ms_to_str(clip.clip_start), Misc.time_in_ms_to_str(clip.clip_stop), (clip.clip_stop - clip.clip_start) / 1000.0)) # Now we iterate through the keyword list ... for keyword in keywordList: # ... looking only at those keywords the user left "checked" in the filter dialog ... if keyword[2]: # ... and check to see if the Clip HAS the keyword. if clip.has_keyword(keyword[0], keyword[1]): # If so, we write a "1", indicating True. f.write('\t1') else: # If not, we write a "0", indicating False. f.write('\t0') # Add a line break to signal the end of the Clip record f.write('\n') # Flush the output file's buffer (probably unnecessary) f.flush() # Close the output file. f.close() # Restore the cursor when we're done. TransanaGlobal.menuWindow.SetCursor(wx.StockCursor( wx.CURSOR_ARROW)) # If so, create a prompt to inform the user and ask to overwrite the file. if 'unicode' in wx.PlatformInfo: # Encode with UTF-8 rather than TransanaGlobal.encoding because this is a prompt, not DB Data. prompt = unicode( _('Clip Data has been exported to file "%s".'), 'utf8') else: prompt = _('Clip Data has been exported to file "%s".') # Create the dialog to inform the user dlg2 = Dialogs.InfoDialog(self, prompt % fs) # Show the Info dialog. dlg2.ShowModal() # Destroy the Information dialog dlg2.Destroy()
def db_delete(self, use_transactions=1): """Delete this object record from the database. Raises RecordLockedError exception if the record is locked and unable to be deleted.""" result = 1 try: # Initialize delete operation, begin transaction if necessary (db, c) = self._db_start_delete(use_transactions) if (db == None): return # Abort delete # Delete all Collection-based Filter Configurations # Delete Collection Clip Data Export records DBInterface.delete_filter_records(4, self.number) # Delete Collection Report records DBInterface.delete_filter_records(12, self.number) # Delete Collection Map records DBInterface.delete_filter_records(16, self.number) # Detect, Load, and Delete all Collection Notes notes = self.get_note_nums() for note_num in notes: note = Note.Note(note_num) result = result and note.db_delete(0) del note del notes # Delete Clips, which in turn will delete Clip transcripts/notes/kws clips = DBInterface.list_of_clips_by_collection( self.id, self.parent) for (clipNo, clip_id, collNo) in clips: clip = Clip.Clip(clipNo) result = result and clip.db_delete(0) del clip del clips # Delete Quotes, which in turn will delete Quote notes/kws quotes = DBInterface.list_of_quotes_by_collectionnum(self.number) for (quoteNo, quote_id, collNo, sourceDocNo) in quotes: quote = Quote.Quote(num=quoteNo) result = result and quote.db_delete(0) del quote del quotes # Delete Snapshots, which in turn will delete Snapshot Coding and Keywords snapshots = DBInterface.list_of_snapshots_by_collectionnum( self.number) for (snapshotNo, snapshotID, collNo) in snapshots: # Since we intend to delete the snapshot, we can suppress the error message about missing Episodes snapshot = Snapshot.Snapshot(snapshotNo, suppressEpisodeError=True) result = result and snapshot.db_delete(0) del snapshot del snapshots # Delete all Nested Collections for (collNo, collID, parentCollNo) in DBInterface.list_of_collections(self.number): tempCollection = Collection(collNo) result = result and tempCollection.db_delete(0) del tempCollection # Delete the actual record self._db_do_delete(use_transactions, c, result) # Cleanup c.close() self.clear() except RecordLockedError, e: if DEBUG: print "Collection: RecordLocked Error", e # if a sub-record is locked, we may need to unlock the Collection record (after rolling back the Transaction) if self.isLocked: # c (the database cursor) only exists if the record lock was obtained! # We must roll back the transaction before we unlock the record. c.execute("ROLLBACK") if DEBUG: print "Collection: roll back Transaction" c.close() self.unlock_record() if DEBUG: print "Collection: unlocking record" raise e
def OnItemSelected(self, event): """ Process the selection of a clip to be merged with the original clip """ # Identify the selected item self.mergeItemIndex = event.GetIndex() # Get the Clip Data for the selected item mergeClip = Clip.Clip(self.mergeList[self.mergeItemIndex][0]) # re-initialize the TRANSCRIPT start and stop times self.transcript_clip_start = [] self.transcript_clip_stop = [] # Merge the clips. # First, determine whether the merging clip comes BEFORE or after the original if mergeClip.clip_start < self.obj.clip_start: # The start value comes from the merge clip self.clip_start_edit.SetValue(Misc.time_in_ms_to_str(mergeClip.clip_start)) # Update the merged clip Start Time self.clip_start = mergeClip.clip_start # The stop value comes from the original clip self.clip_stop_edit.SetValue(Misc.time_in_ms_to_str(self.obj.clip_stop)) # Update the Clip Length self.clip_length_edit.SetValue(Misc.time_in_ms_to_str(self.obj.clip_stop - mergeClip.clip_start)) # Update the merged clip Stop Time self.clip_stop = self.obj.clip_stop # For each of the original clip's Transcripts ... for x in range(len(self.obj.transcripts)): # We get the TRANSCRIPT start time from the merge clip self.transcript_clip_start.append(mergeClip.transcripts[x].clip_start) # We get the TRANSCRIPT end time from the original clip self.transcript_clip_stop.append(self.obj.transcripts[x].clip_stop) # If we're using the Rich Text Ctrl ... if TransanaConstants.USESRTC: ## print "ClipPropertiesForm.OnItemSelected(1):", x ## print self.text_edit[x].GetFormattedSelection('XML') ## print # ... clear the transcript ... self.text_edit[x].ClearDoc(skipUnlock = True) # ... turn off read-only ... self.text_edit[x].SetReadOnly(0) # Create the Transana XML to RTC Import Parser. This is needed so that we can # pull XML transcripts into the existing RTC. Pass the RTC to be edited. handler = PyXML_RTCImportParser.XMLToRTCHandler(self.text_edit[x]) # Parse the merge clip transcript text, adding it to the RTC xml.sax.parseString(mergeClip.transcripts[x].text, handler) # Add a blank line self.text_edit[x].Newline() # ... trap exceptions here ... try: # ... insert a time code at the position of the clip break ... self.text_edit[x].insert_timecode(self.obj.clip_start) # If there were exceptions (duplicating time codes, for example), just skip it. except: pass # Parse the original transcript text, adding it to the RTC xml.sax.parseString(self.obj.transcripts[x].text, handler) # If we're using the Styled Text Ctrl else: # ... clear the transcript ... self.text_edit[x].ClearDoc() # ... turn off read-only ... self.text_edit[x].SetReadOnly(0) # ... insert the merge clip's text, skipping whitespace at the end ... self.text_edit[x].InsertRTFText(mergeClip.transcripts[x].text.rstrip()) # ... add a couple of line breaks ... self.text_edit[x].InsertStyledText('\n\n', len('\n\n')) # ... trap exceptions here ... try: # ... insert a time code at the position of the clip break ... self.text_edit[x].insert_timecode(self.obj.clip_start) # If there were exceptions (duplicating time codes, for example), just skip it. except: pass # ... now add the original clip's text ... self.text_edit[x].InsertRTFText(self.obj.transcripts[x].text) # ... signal that time codes will be visible, which they always are in the Clip Properties ... self.text_edit[x].codes_vis = 0 # ... scan transcript for Time Codes ... self.text_edit[x].load_timecodes() # ... display the time codes self.text_edit[x].show_codes() # If the merging clip comes AFTER the original ... else: # The start value comes from the original clip self.clip_start_edit.SetValue(Misc.time_in_ms_to_str(self.obj.clip_start)) # Update the merged clip Start Time self.clip_start = self.obj.clip_start # The stop value comes from the merge clip self.clip_stop_edit.SetValue(Misc.time_in_ms_to_str(mergeClip.clip_stop)) # Update the Clip Length self.clip_length_edit.SetValue(Misc.time_in_ms_to_str(mergeClip.clip_stop - self.obj.clip_start)) # Update the merged clip Stop Time self.clip_stop = mergeClip.clip_stop # For each of the original clip's Transcripts ... for x in range(len(self.obj.transcripts)): # We get the TRANSCRIPT start time from the original clip self.transcript_clip_start.append(self.obj.transcripts[x].clip_start) # We get the TRANSCRIPT end time from the merge clip self.transcript_clip_stop.append(mergeClip.transcripts[x].clip_stop) # If we're using the Rich Text Ctrl ... if TransanaConstants.USESRTC: ## print "ClipPropertiesForm.OnItemSelected(2):", x ## print self.text_edit[x].GetFormattedSelection('XML') ## print # ... clear the transcript ... self.text_edit[x].ClearDoc(skipUnlock = True) # ... turn off read-only ... self.text_edit[x].SetReadOnly(0) # Create the Transana XML to RTC Import Parser. This is needed so that we can # pull XML transcripts into the existing RTC. Pass the RTC in. handler = PyXML_RTCImportParser.XMLToRTCHandler(self.text_edit[x]) # Parse the original clip transcript text, adding it to the reportText RTC xml.sax.parseString(self.obj.transcripts[x].text, handler) # Add a blank line self.text_edit[x].Newline() # ... trap exceptions here ... try: # ... insert a time code at the position of the clip break ... self.text_edit[x].insert_timecode(mergeClip.clip_start) # If there were exceptions (duplicating time codes, for example), just skip it. except: pass # ... now add the merge clip's text ... # Parse the merge clip transcript text, adding it to the RTC xml.sax.parseString(mergeClip.transcripts[x].text, handler) # If we're using the Styled Text Ctrl else: # ... clear the transcript ... self.text_edit[x].ClearDoc() # ... turn off read-only ... self.text_edit[x].SetReadOnly(0) # ... insert the original clip's text, skipping whitespace at the end ... self.text_edit[x].InsertRTFText(self.obj.transcripts[x].text.rstrip()) # ... add a couple of line breaks ... self.text_edit[x].InsertStyledText('\n\n', len('\n\n')) # ... trap exceptions here ... try: # ... insert a time code at the position of the clip break ... self.text_edit[x].insert_timecode(mergeClip.clip_start) # If there were exceptions (duplicating time codes, for example), just skip it. except: pass # ... now add the merge clip's text ... self.text_edit[x].InsertRTFText(mergeClip.transcripts[x].text) # ... signal that time codes will be visible, which they always are in the Clip Properties ... self.text_edit[x].codes_vis = 0 # ... scan transcript for Time Codes ... self.text_edit[x].load_timecodes() # ... display the time codes self.text_edit[x].show_codes() # Remember the Merged Clip's Clip Number self.obj.mergeNumber = mergeClip.number # Create a list object for merging the keywords kwList = [] # Add all the original keywords for kws in self.obj.keyword_list: kwList.append(kws.keywordPair) # Iterate through the merge clip keywords. for kws in mergeClip.keyword_list: # If they're not already in the list, add them. if not kws.keywordPair in kwList: kwList.append(kws.keywordPair) # Sort the keyword list kwList.sort() # Clear the keyword list box. self.ekw_lb.Clear() # Add the merged keywords to the list box. for kws in kwList: self.ekw_lb.Append(kws) # Get the Keyword Examples for the merged clip, if any. kwExamples = DBInterface.list_all_keyword_examples_for_a_clip(mergeClip.number) # Initialize a variable to hold merged keyword examples. (This clears the variable if the user changes merge clips.) self.mergedKeywordExamples = [] # Iterate through the keyword examples and add them to the list. for kw in kwExamples: self.mergedKeywordExamples.append(kw[:2])
def DisplayCells(self, TimeCode): """ Get data from the database and populate the Episode Clips / Selected Clips Grid """ # Get clip data from the database clipData = DBInterface.list_of_clips_by_episode(self.episodeObj.number, TimeCode) if TransanaConstants.proVersion: # Get the snapshot data from the database snapshotData = DBInterface.list_of_snapshots_by_episode(self.episodeObj.number, TimeCode) # Combine the two lists cellData = {} # For each Clip ... for clip in clipData: # load the Clip tmpObj = Clip.Clip(clip['ClipNum']) # add the Clip to the cellData cellData[(clip['ClipStart'], clip['ClipStop'], tmpObj.GetNodeString(True).upper())] = tmpObj if TransanaConstants.proVersion: # for each Snapshot ... for snapshot in snapshotData: # load the Snapshot tmpObj = Snapshot.Snapshot(snapshot['SnapshotNum']) # add the Snapshot to the cellData cellData[(snapshot['SnapshotStart'], snapshot['SnapshotStop'], tmpObj.GetNodeString(True).upper())] = tmpObj # Get the Keys for the cellData sortedKeys = cellData.keys() # Sort the keys for the cellData into the right order sortedKeys.sort() # Add rows to the Grid to accomodate the amount of data returned, or delete rows if we have too many if len(cellData) > self.gridClips.GetNumberRows(): self.gridClips.AppendRows(len(cellData) - self.gridClips.GetNumberRows(), False) elif len(cellData) < self.gridClips.GetNumberRows(): self.gridClips.DeleteRows(numRows = self.gridClips.GetNumberRows() - len(cellData)) # Initialize the Row Counter loop = 0 # Add the data to the Grid for keyVals in sortedKeys: # If we have a Clip ... if isinstance(cellData[keyVals], Clip.Clip): # ... get the start, stop times and the object type startTime = cellData[keyVals].clip_start stopTime = cellData[keyVals].clip_stop objType = 'Clip' # Initialize the string for all the Keywords to blank kwString = unicode('', 'utf8') # Initialize the prompt for building the keyword string kwPrompt = '%s' # If we have a Snapshot ... elif isinstance(cellData[keyVals], Snapshot.Snapshot): # ... get the start, stop times and the object type startTime = cellData[keyVals].episode_start stopTime = cellData[keyVals].episode_start + cellData[keyVals].episode_duration objType = 'Snapshot' # if there are whole snapshot keywords ... if len(cellData[keyVals].keyword_list) > 0: # ... initialize the string for all the Keywords to indicate this kwString = unicode(_('Whole:'), 'utf8') + '\n' # If there are NOT whole snapshot keywords ... else: # ... initialize the string for all the Keywords to blank kwString = unicode('', 'utf8') # Initialize the prompt for building the keyword string kwPrompt = ' %s' # For each Keyword in the Keyword List ... for kws in cellData[keyVals].keyword_list: # ... add the Keyword to the Keyword List kwString += kwPrompt % kws.keywordPair # If we have a Clip ... if isinstance(cellData[keyVals], Clip.Clip): # After the first keyword, we need a NewLine in front of the Keywords. This accompishes that! kwPrompt = '\n%s' # If we have a Snapshot ... elif isinstance(cellData[keyVals], Snapshot.Snapshot): # After the first keyword, we need a NewLine in front of the Keywords. This accompishes that! kwPrompt = '\n %s' # If we have a Snapshot, we also want to display CODED Keywords in addition to the WHOLE Snapshot keywords # we've already included if isinstance(cellData[keyVals], Snapshot.Snapshot): # Keep a list of the coded keywords we've already displayed codedKeywords = [] # Modify the template for additional keywords kwPrompt = '\n %s : %s' # For each of the Snapshot's Coding Objects ... for x in range(len(cellData[keyVals].codingObjects)): # ... if the Coding Object is visible and if it is not already in the codedKeywords list ... if (cellData[keyVals].codingObjects[x]['visible']) and \ (not (cellData[keyVals].codingObjects[x]['keywordGroup'], cellData[keyVals].codingObjects[x]['keyword']) in codedKeywords): # ... if this is the FIRST Coded Keyword ... if len(codedKeywords) == 0: # ... and if there WERE Whole Snapshot Keywords ... if len(kwString) > 0: # ... then add a line break to the Keywords String ... kwString += '\n' # ... add the indicator to the Keywords String that we're starting to show Coded Keywords kwString += unicode(_('Coded:'), 'utf8') # ... add the coded keyword to the Keywords String ... kwString += kwPrompt % (cellData[keyVals].codingObjects[x]['keywordGroup'], cellData[keyVals].codingObjects[x]['keyword']) # ... add the keyword to the Coded Keywords list codedKeywords.append((cellData[keyVals].codingObjects[x]['keywordGroup'], cellData[keyVals].codingObjects[x]['keyword'])) # Insert the data values into the Grid Row # Start and Stop time in column 0 self.gridClips.SetCellValue(loop, 0, "%s -\n %s" % (Misc.time_in_ms_to_str(startTime), Misc.time_in_ms_to_str(stopTime))) # Node String (including Item name) in column 1 self.gridClips.SetCellValue(loop, 1, cellData[keyVals].GetNodeString(True)) # make the Collection / Item ID line auto-word-wrap self.gridClips.SetCellRenderer(loop, 1, grid.GridCellAutoWrapStringRenderer()) # Keywords in column 2 self.gridClips.SetCellValue(loop, 2, kwString) # Item Number (hidden) in column 3. Convert value to a string self.gridClips.SetCellValue(loop, 3, "%s" % cellData[keyVals].number) # Item Type (hidden) in column 4 self.gridClips.SetCellValue(loop, 4, "%s" % objType) # Auto-size THIS row self.gridClips.AutoSizeRow(loop, True) # Increment the Row Counter loop += 1 # Select the first cell self.gridClips.SetGridCursor(0, 0)
def __init__(self, parent, id, title, note_object): # Make the Keyword Edit List resizable by passing wx.RESIZE_BORDER style Dialogs.GenForm.__init__(self, parent, id, title, size=(400, 260), style=wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER, useSizers = True, HelpContext='Notes') # 'Notes' is the Help Context for Notes. There is no entry for Note Properties at this time self.obj = note_object seriesID = '' episodeID = '' transcriptID = '' collectionID = '' clipID = '' snapshotID = '' documentID = '' quoteID = '' if (self.obj.series_num != 0) and (self.obj.series_num != None): tempLibrary = Library.Library(self.obj.series_num) seriesID = tempLibrary.id elif (self.obj.episode_num != 0) and (self.obj.episode_num != None): tempEpisode = Episode.Episode(self.obj.episode_num) episodeID = tempEpisode.id tempLibrary = Library.Library(tempEpisode.series_num) seriesID = tempLibrary.id elif (self.obj.transcript_num != 0) and (self.obj.transcript_num != None): # To save time here, we can skip loading the actual transcript text, which can take time once we start dealing with images! tempTranscript = Transcript.Transcript(self.obj.transcript_num, skipText=True) transcriptID = tempTranscript.id tempEpisode = Episode.Episode(tempTranscript.episode_num) episodeID = tempEpisode.id tempLibrary = Library.Library(tempEpisode.series_num) seriesID = tempLibrary.id elif (self.obj.collection_num != 0) and (self.obj.collection_num != None): tempCollection = Collection.Collection(self.obj.collection_num) collectionID = tempCollection.GetNodeString() elif (self.obj.clip_num != 0) and (self.obj.clip_num != None): # We can skip loading the Clip Transcript to save load time tempClip = Clip.Clip(self.obj.clip_num, skipText=True) clipID = tempClip.id tempCollection = Collection.Collection(tempClip.collection_num) collectionID = tempCollection.GetNodeString() elif (self.obj.snapshot_num != 0) and (self.obj.snapshot_num != None): tempSnapshot = Snapshot.Snapshot(self.obj.snapshot_num) snapshotID = tempSnapshot.id tempCollection = Collection.Collection(tempSnapshot.collection_num) collectionID = tempCollection.GetNodeString() elif (self.obj.document_num != 0) and (self.obj.document_num != None): tempDocument = Document.Document(self.obj.document_num) documentID = tempDocument.id tempLibrary = Library.Library(tempDocument.library_num) seriesID = tempLibrary.id elif (self.obj.quote_num != 0) and (self.obj.quote_num != None): tempQuote = Quote.Quote(num=self.obj.quote_num, skipText=True) quoteID = tempQuote.id tempCollection = Collection.Collection(tempQuote.collection_num) collectionID = tempCollection.GetNodeString() # Create the form's main VERTICAL sizer mainSizer = wx.BoxSizer(wx.VERTICAL) # Create a HORIZONTAL sizer for the first row r1Sizer = wx.BoxSizer(wx.HORIZONTAL) # Create a VERTICAL sizer for the next element v1 = wx.BoxSizer(wx.VERTICAL) # Note ID id_edit = self.new_edit_box(_("Note ID"), v1, self.obj.id, maxLen=100) # Add the element to the sizer r1Sizer.Add(v1, 1, wx.EXPAND) # Add the row sizer to the main vertical sizer mainSizer.Add(r1Sizer, 0, wx.EXPAND) # Add a vertical spacer to the main sizer mainSizer.Add((0, 10)) # Create a HORIZONTAL sizer for the next row r2Sizer = wx.BoxSizer(wx.HORIZONTAL) # Create a VERTICAL sizer for the next element v2 = wx.BoxSizer(wx.VERTICAL) # Library ID seriesID_edit = self.new_edit_box(_("Library ID"), v2, seriesID) # Add the element to the row sizer r2Sizer.Add(v2, 1, wx.EXPAND) seriesID_edit.Enable(False) # Add the row sizer to the main vertical sizer mainSizer.Add(r2Sizer, 0, wx.EXPAND) # Add a vertical spacer to the main sizer mainSizer.Add((0, 10)) # Create a HORIZONTAL sizer for the next row r3Sizer = wx.BoxSizer(wx.HORIZONTAL) if TransanaConstants.proVersion: # Create a VERTICAL sizer for the next element v9 = wx.BoxSizer(wx.VERTICAL) # Document ID documentID_edit = self.new_edit_box(_("Document ID"), v9, documentID) # Add the element to the row sizer r3Sizer.Add(v9, 1, wx.EXPAND) documentID_edit.Enable(False) # Add a horizontal spacer to the row sizer r3Sizer.Add((10, 0)) # Create a VERTICAL sizer for the next element v3 = wx.BoxSizer(wx.VERTICAL) # Episode ID episodeID_edit = self.new_edit_box(_("Episode ID"), v3, episodeID) # Add the element to the row sizer r3Sizer.Add(v3, 1, wx.EXPAND) episodeID_edit.Enable(False) # Add a horizontal spacer to the row sizer r3Sizer.Add((10, 0)) # Create a VERTICAL sizer for the next element v4 = wx.BoxSizer(wx.VERTICAL) # Transcript ID transcriptID_edit = self.new_edit_box(_("Transcript ID"), v4, transcriptID) # Add the element to the row sizer r3Sizer.Add(v4, 1, wx.EXPAND) transcriptID_edit.Enable(False) # Add the row sizer to the main vertical sizer mainSizer.Add(r3Sizer, 0, wx.EXPAND) # Add a vertical spacer to the main sizer mainSizer.Add((0, 10)) # Create a HORIZONTAL sizer for the next row r5Sizer = wx.BoxSizer(wx.HORIZONTAL) # Create a VERTICAL sizer for the next element v5 = wx.BoxSizer(wx.VERTICAL) # Collection ID collectionID_edit = self.new_edit_box(_("Collection ID"), v5, collectionID) # Add the element to the row sizer r5Sizer.Add(v5, 2, wx.EXPAND) collectionID_edit.Enable(False) # Add the row sizer to the main vertical sizer mainSizer.Add(r5Sizer, 0, wx.EXPAND) # Add a vertical spacer to the main sizer mainSizer.Add((0, 10)) # Create a HORIZONTAL sizer for the next row r6Sizer = wx.BoxSizer(wx.HORIZONTAL) if TransanaConstants.proVersion: # Create a VERTICAL sizer for the next element v7 = wx.BoxSizer(wx.VERTICAL) # Quote ID quoteID_edit = self.new_edit_box(_("Quote ID"), v7, quoteID) # Add the element to the row sizer r6Sizer.Add(v7, 1, wx.EXPAND) quoteID_edit.Enable(False) # Add a horizontal spacer to the row sizer r6Sizer.Add((10, 0)) # Create a VERTICAL sizer for the next element v6 = wx.BoxSizer(wx.VERTICAL) # Clip ID clipID_edit = self.new_edit_box(_("Clip ID"), v6, clipID) # Add the element to the row sizer r6Sizer.Add(v6, 1, wx.EXPAND) clipID_edit.Enable(False) if TransanaConstants.proVersion: # Add a horizontal spacer to the row sizer r6Sizer.Add((10, 0)) # Create a VERTICAL sizer for the next element v8 = wx.BoxSizer(wx.VERTICAL) # Snapshot ID snapshotID_edit = self.new_edit_box(_("Snapshot ID"), v8, snapshotID) # Add the element to the row sizer r6Sizer.Add(v8, 1, wx.EXPAND) snapshotID_edit.Enable(False) # Add the row sizer to the main vertical sizer mainSizer.Add(r6Sizer, 0, wx.EXPAND) # Add a vertical spacer to the main sizer mainSizer.Add((0, 10)) # Create a HORIZONTAL sizer for the next row r8Sizer = wx.BoxSizer(wx.HORIZONTAL) # Create a VERTICAL sizer for the next element v8 = wx.BoxSizer(wx.VERTICAL) # Comment layout noteTaker_edit = self.new_edit_box(_("Note Taker"), v8, self.obj.author, maxLen=100) # Add the element to the row sizer r8Sizer.Add(v8, 2, wx.EXPAND) # Add the row sizer to the main vertical sizer mainSizer.Add(r8Sizer, 0, wx.EXPAND) # Add a vertical spacer to the main sizer mainSizer.Add((0, 10)) # Create a sizer for the buttons btnSizer = wx.BoxSizer(wx.HORIZONTAL) # Add the buttons self.create_buttons(sizer=btnSizer) # Add the button sizer to the main sizer mainSizer.Add(btnSizer, 0, wx.EXPAND) # If Mac ... if 'wxMac' in wx.PlatformInfo: # ... add a spacer to avoid control clipping mainSizer.Add((0, 2)) # Set the PANEL's main sizer self.panel.SetSizer(mainSizer) # Tell the PANEL to auto-layout self.panel.SetAutoLayout(True) # Lay out the Panel self.panel.Layout() # Lay out the panel on the form self.Layout() # Resize the form to fit the contents self.Fit() # Get the new size of the form (width, height) = self.GetSizeTuple() # Reset the form's size to be at least the specified minimum width self.SetSize(wx.Size(max(400, width), height)) # Define the minimum size for this dialog as the current size, and define height as unchangeable self.SetSizeHints(max(400, width), height, -1, height) # Center the form on screen TransanaGlobal.CenterOnPrimary(self) # Set focus to the Note ID id_edit.SetFocus()
def OnDisplay(self, reportText): """ This method, required by TextReport, populates the TextReport. The reportText parameter is the wxSTC control from the TextReport object. It needs to be in the report parent because the TextReport doesn't know anything about the actual data. """ # Determine if we need to populate the Filter Lists. If it hasn't already been done, we should do it. # If it has already been done, no need to do it again. if self.filterList == []: populateFilterList = True else: populateFilterList = False # Make the control writable reportText.SetReadOnly(False) # Set the font for the Report Title reportText.SetTxtStyle(fontFace='Courier New', fontSize=16, fontBold=True, fontUnderline=True, parAlign=wx.TEXT_ALIGNMENT_CENTER, parSpacingAfter=12) # Add the Report Title reportText.WriteText(self.title) # Turn off underlining and bold reportText.SetTxtStyle(fontBold=False, fontUnderline=False) reportText.Newline() if self.searchText != None: # ... add a subtitle if 'unicode' in wx.PlatformInfo: # Encode with UTF-8 rather than TransanaGlobal.encoding because this is a prompt, not DB Data. prompt = unicode(_("Search Text: %s"), 'utf8') else: prompt = _("Search Text: %s") self.subtitle = prompt % self.searchText # ... set the font for the subtitle ... reportText.SetTxtStyle(fontSize=10) # ... and insert the spacer and the subtitle. reportText.WriteText(self.subtitle) reportText.Newline() if self.configName != '': # ... add a subtitle if 'unicode' in wx.PlatformInfo: # Encode with UTF-8 rather than TransanaGlobal.encoding because this is a prompt, not DB Data. prompt = unicode(_("Filter Configuration: %s"), 'utf8') else: prompt = _("Filter Configuration: %s") self.configLine = prompt % self.configName # ... set the font for the subtitle ... reportText.SetTxtStyle(fontSize=10) # ... and insert the subtitle. reportText.WriteText(self.configLine) reportText.Newline() # If a Root Node flag is passed in ... if self.reportType == 'RootNode': # ... we want to group notes by category. (They will be alphabetical within each category.) majorList = DBInterface.list_of_all_notes( reportType='LibraryNode', searchText=self.searchText) if TransanaConstants.proVersion: majorList += DBInterface.list_of_all_notes( reportType='DocumentNode', searchText=self.searchText) majorList += DBInterface.list_of_all_notes( reportType='EpisodeNode', searchText=self.searchText) majorList += DBInterface.list_of_all_notes( reportType='TranscriptNode', searchText=self.searchText) majorList += DBInterface.list_of_all_notes( reportType='CollectionNode', searchText=self.searchText) if TransanaConstants.proVersion: majorList += DBInterface.list_of_all_notes( reportType='QuoteNode', searchText=self.searchText) majorList += DBInterface.list_of_all_notes( reportType='ClipNode', searchText=self.searchText) if TransanaConstants.proVersion: majorList += DBInterface.list_of_all_notes( reportType='SnapshotNode', searchText=self.searchText) # if a specific Node flag is passed in ... else: # ... and use the Notes from the requested Report Type for the majorList. majorList = DBInterface.list_of_all_notes( reportType=self.reportType, searchText=self.searchText) # Initialize the initial data structure that will be turned into the report self.data = [] # We need a list of all checked NoteNums to apply the Filter. Initialize it here. checkedRecords = [] # Now populate it based on the Filter List. (The filterList will be empty if not populate yet, but that's OK.) # Iterate through the filter list ... for noteRecord in self.filterList: # ... pull out the filter list record elements. (noteNum, noteID, noteParent, checked) = noteRecord # If an item is checked ... if checked: # ... add it to the list of checked items! checkedRecords.append(noteNum) # Iterate through the major list for noteRecord in majorList: # If the current item from the Major List is in the list of checked records from the filter dialog # OR if we're going through the list for the first time (populateFilterList == True) .... if (noteRecord['NoteNum'] in checkedRecords) or populateFilterList: # ... load each note ... tempNote = Note.Note(noteRecord['NoteNum']) # Turn bold on. reportText.SetTxtStyle(fontBold=True, fontSize=12, parAlign=wx.TEXT_ALIGNMENT_LEFT, parLeftIndent=0, parSpacingBefore=36, parSpacingAfter=12) # Add the note ID to the report reportText.WriteText('%s' % tempNote.id) reportText.Newline() # Initialize all temporary objects to None so we can detect their presence or absence tempLibrary = None tempDocument = None tempEpisode = None tempTranscript = None tempCollection = None tempQuote = None tempClip = None tempSnapshot = None # If we have a Library Note ... if tempNote.series_num > 0: # ... load the Library data tempLibrary = Library.Library(tempNote.series_num) noteParent = unicode(_('Libraries'), 'utf8') + ' ' + tempLibrary.id # If we have a Document Note ... elif tempNote.document_num > 0: # ... load the Document and Library data tempDocument = Document.Document(tempNote.document_num) tempLibrary = Library.Library(tempDocument.library_num) noteParent = unicode( _('Document'), 'utf8' ) + ' ' + tempLibrary.id + ' > ' + tempDocument.id # If we have an Episode Note ... elif tempNote.episode_num > 0: # ... load the Episode and Library data tempEpisode = Episode.Episode(tempNote.episode_num) tempLibrary = Library.Library(tempEpisode.series_num) noteParent = unicode( _('Episode'), 'utf8') + ' ' + tempLibrary.id + ' > ' + tempEpisode.id # If we have a Transcript Note ... elif tempNote.transcript_num > 0: # ... load the Transcript, Episode, and Library data # To save time here, we can skip loading the actual transcript text, which can take time once we start dealing with images! tempTranscript = Transcript.Transcript( tempNote.transcript_num, skipText=True) tempEpisode = Episode.Episode(tempTranscript.episode_num) tempLibrary = Library.Library(tempEpisode.series_num) noteParent = unicode( _('Transcript'), 'utf8' ) + ' ' + tempLibrary.id + ' > ' + tempEpisode.id + ' > ' + tempTranscript.id # If we have a Collection Note ... elif tempNote.collection_num > 0: # ... load the Collection data tempCollection = Collection.Collection( tempNote.collection_num) noteParent = unicode( _('Collection'), 'utf8') + ' ' + tempCollection.GetNodeString() # If we have a Quote Note ... elif tempNote.quote_num > 0: # ... load the Quote and Collection data. We can skip loading the Quote text to save load time tempQuote = Quote.Quote(tempNote.quote_num, skipText=True) tempCollection = Collection.Collection( tempQuote.collection_num) noteParent = unicode( _('Quote'), 'utf8') + ' ' + tempCollection.GetNodeString( ) + ' > ' + tempQuote.id # If we have a Clip Note ... elif tempNote.clip_num > 0: # ... load the Clip and Collection data. We can skip loading the Clip Transcript to save load time tempClip = Clip.Clip(tempNote.clip_num, skipText=True) tempCollection = Collection.Collection( tempClip.collection_num) noteParent = unicode( _('Clip'), 'utf8') + ' ' + tempCollection.GetNodeString( ) + ' > ' + tempClip.id # If we have a Snapshot Note ... elif tempNote.snapshot_num > 0: # ... load the Snapshot and Collection data. tempSnapshot = Snapshot.Snapshot(tempNote.snapshot_num) tempCollection = Collection.Collection( tempSnapshot.collection_num) noteParent = unicode( _('Snapshot'), 'utf8') + ' ' + tempCollection.GetNodeString( ) + ' > ' + tempSnapshot.id # If we have Library data ... if tempLibrary != None: # Turn bold on. reportText.SetTxtStyle(fontSize=10, fontBold=True, parLeftIndent=63, parSpacingBefore=0, parSpacingAfter=0) # Add the note ID to the report reportText.WriteText(_('Library: ')) # Turn bold off. reportText.SetTxtStyle(fontBold=False) # Add the Library ID reportText.WriteText('%s' % tempLibrary.id) reportText.Newline() # If we have Document data ... if tempDocument != None: # Turn bold on. reportText.SetTxtStyle(fontBold=True) # Add the note ID to the report reportText.WriteText(_('Document: ')) # Turn bold off. reportText.SetTxtStyle(fontBold=False) # Add the Document ID reportText.WriteText('%s' % tempDocument.id) reportText.Newline() # If we have Episode data ... if tempEpisode != None: # Turn bold on. reportText.SetTxtStyle(fontBold=True) # Add the note ID to the report reportText.WriteText(_('Episode: ')) # Turn bold off. reportText.SetTxtStyle(fontBold=False) # Add the Episode ID reportText.WriteText('%s' % tempEpisode.id) reportText.Newline() # If we have Transcript data ... if tempTranscript != None: # Turn bold on. reportText.SetTxtStyle(fontBold=True) # Add the note ID to the report reportText.WriteText(_('Transcript: ')) # Turn bold off. reportText.SetTxtStyle(fontBold=False) # Add the Transcript ID reportText.WriteText('%s' % tempTranscript.id) reportText.Newline() # If we have Collection data ... if tempCollection != None: # Turn bold on. reportText.SetTxtStyle(fontSize=10, fontBold=True, parLeftIndent=63, parSpacingBefore=0, parSpacingAfter=0) # Add the note ID to the report reportText.WriteText(_('Collection: ')) # Turn bold off. reportText.SetTxtStyle(fontBold=False) # Add the Collection ID reportText.WriteText('%s' % tempCollection.GetNodeString()) reportText.Newline() # If we have Quote data ... if tempQuote != None: # Turn bold on. reportText.SetTxtStyle(fontBold=True) # Add the note ID to the report reportText.WriteText(_('Quote: ')) # Turn bold off. reportText.SetTxtStyle(fontBold=False) # Add the Quote ID reportText.WriteText('%s' % tempQuote.id) reportText.Newline() # If we have Clip data ... if tempClip != None: # Turn bold on. reportText.SetTxtStyle(fontBold=True) # Add the note ID to the report reportText.WriteText(_('Clip: ')) # Turn bold off. reportText.SetTxtStyle(fontBold=False) # Add the Clip ID reportText.WriteText('%s' % tempClip.id) reportText.Newline() # If we have Snapshot data ... if tempSnapshot != None: # Turn bold on. reportText.SetTxtStyle(fontBold=True) # Add the note ID to the report reportText.WriteText(_('Snapshot: ')) # Turn bold off. reportText.SetTxtStyle(fontBold=False) # Add the Snapshot ID reportText.WriteText('%s' % tempSnapshot.id) reportText.Newline() # If we're going through the list for the first time and need to populate the filter list ... if populateFilterList: # ... add the note number, note ID, note parent info, and checked=True to the filter list. self.filterList.append( (tempNote.number, tempNote.id, noteParent, True)) # Turn bold on. reportText.SetTxtStyle(fontBold=True) # Add the note ID to the report reportText.WriteText(_('Note Taker: ')) # Turn bold off. reportText.SetTxtStyle(fontBold=False) # Add the Note's author reportText.WriteText('%s' % tempNote.author) reportText.Newline() # Turn bold on. reportText.SetTxtStyle(fontBold=True) # Add the note ID to the report reportText.WriteText(_('Note Text:')) reportText.Newline() # Turn bold off. reportText.SetTxtStyle(fontBold=False, parLeftIndent=127) # Add the note text to the report (rstrip() prevents formatting problems when notes end with blank lines) reportText.WriteText('%s' % tempNote.text.rstrip()) reportText.Newline() # Make the control read only, now that it's done reportText.SetReadOnly(True)
def OnEditKeywords(self, evt): """ Implement the Edit Keywords button """ # Determine if a Transcript is loaded, and if so, what kind if self.parent.editor.TranscriptObj != None: # Initialize a list where we can keep track of clip transcripts that are locked because they are in Edit mode. TranscriptLocked = [] try: # If an episode/clip has multiple transcripts, we could run into lock problems. Let's try to detect that. # (This is probably poor form from an object-oriented standpoint, but I don't know a better way.) # For each currently-open Transcript window ... for trWin in self.parent.ControlObject.TranscriptWindow: # ... note if the transcript is currently locked. TranscriptLocked.append(trWin.dlg.editor.TranscriptObj.isLocked) # If it is locked ... if trWin.dlg.editor.TranscriptObj.isLocked: # Leave Edit Mode, which will prompt about saving the Transcript. # a) toggle the button trWin.dlg.toolbar.ToggleTool(trWin.dlg.toolbar.CMD_READONLY_ID, not trWin.dlg.toolbar.GetToolState(trWin.dlg.toolbar.CMD_READONLY_ID)) # b) call the event that responds to the button state change trWin.dlg.toolbar.OnReadOnlySelect(evt) # If the underlying Transcript object has a clip number, we're working with a CLIP. if self.parent.editor.TranscriptObj.clip_num > 0: # Finally, we can load the Clip object. obj = Clip.Clip(self.parent.editor.TranscriptObj.clip_num) # Otherwise ... else: # ... load the Episode obj = Episode.Episode(self.parent.editor.TranscriptObj.episode_num) # Process Record Not Found exception except TransanaExceptions.RecordNotFoundError, e: msg = _('You cannot proceed because the %s cannot be found.') # If the Transcript does not have a clip number, if self.parent.editor.TranscriptObj.clip_num == 0: prompt = _('Episode') else: prompt = _('Clip') if 'unicode' in wx.PlatformInfo: # Encode with UTF-8 rather than TransanaGlobal.encoding because this is a prompt, not DB Data. msg = unicode(msg, 'utf8') % unicode(prompt, 'utf8') + \ unicode(_('\nIt may have been deleted by another user.'), 'utf8') else: msg = msg % prompt + _('\nIt may have been deleted by another user.') dlg = Dialogs.ErrorDialog(self.parent, msg) dlg.ShowModal() dlg.Destroy() # Clear the deleted objects from the Transana Interface. Otherwise, problems arise. self.parent.ControlObject.ClearAllWindows() return try: # Lock the data record obj.lock_record() # Determine the title for the KeywordListEditForm Dialog Box if 'unicode' in wx.PlatformInfo: # Encode with UTF-8 rather than TransanaGlobal.encoding because this is a prompt, not DB Data. prompt = unicode(_("Keywords for %s"), 'utf8') else: prompt = _("Keywords for %s") dlgTitle = prompt % obj.id # Extract the keyword List from the Data object kwlist = [] for kw in obj.keyword_list: kwlist.append(kw) # Create/define the Keyword List Edit Form dlg = KeywordListEditForm.KeywordListEditForm(self.parent, -1, dlgTitle, obj, kwlist) # Set the "continue" flag to True (used to redisplay the dialog if an exception is raised) contin = True # While the "continue" flag is True ... while contin: # if the user pressed "OK" ... try: # Show the Keyword List Edit Form and process it if the user selects OK if dlg.ShowModal() == wx.ID_OK: # Clear the local keywords list and repopulate it from the Keyword List Edit Form kwlist = [] for kw in dlg.keywords: kwlist.append(kw) # Copy the local keywords list into the appropriate object obj.keyword_list = kwlist # If we are dealing with an Episode ... if isinstance(obj, Episode.Episode): # Check to see if there are keywords to be propagated self.parent.ControlObject.PropagateEpisodeKeywords(obj.number, obj.keyword_list) # Save the Data object obj.db_save() # Now let's communicate with other Transana instances if we're in Multi-user mode if not TransanaConstants.singleUserVersion: if isinstance(obj, Episode.Episode): msg = 'Episode %d' % obj.number msgObjType = 'Episode' msgObjClipEpNum = 0 elif isinstance(obj, Clip.Clip): msg = 'Clip %d' % obj.number msgObjType = 'Clip' msgObjClipEpNum = obj.episode_num else: msg = '' msgObjType = 'None' msgObjClipEpNum = 0 if msg != '': if TransanaGlobal.chatWindow != None: # Send the "Update Keyword List" message TransanaGlobal.chatWindow.SendMessage("UKL %s" % msg) # If any Keyword Examples were removed, remove them from the Database Tree for (keywordGroup, keyword, clipNum) in dlg.keywordExamplesToDelete: self.parent.ControlObject.RemoveDataWindowKeywordExamples(keywordGroup, keyword, clipNum) # Update the Data Window Keywords Tab (this must be done AFTER the Save) self.parent.ControlObject.UpdateDataWindowKeywordsTab() # Update the Keyword Visualizations self.parent.ControlObject.UpdateKeywordVisualization() # Notify other computers to update the Keyword Visualization as well. if not TransanaConstants.singleUserVersion: if TransanaGlobal.chatWindow != None: TransanaGlobal.chatWindow.SendMessage("UKV %s %s %s" % (msgObjType, obj.number, msgObjClipEpNum)) # If we do all this, we don't need to continue any more. contin = False # If the user pressed Cancel ... else: # ... then we don't need to continue any more. contin = False # Handle "SaveError" exception except TransanaExceptions.SaveError: # Display the Error Message, allow "continue" flag to remain true errordlg = Dialogs.ErrorDialog(None, sys.exc_info()[1].reason) errordlg.ShowModal() errordlg.Destroy() # Refresh the Keyword List, if it's a changed Keyword error dlg.refresh_keywords() # Highlight the first non-existent keyword in the Keywords control dlg.highlight_bad_keyword() # Handle other exceptions except: if DEBUG: import traceback traceback.print_exc(file=sys.stdout) # Display the Exception Message, allow "continue" flag to remain true if 'unicode' in wx.PlatformInfo: # Encode with UTF-8 rather than TransanaGlobal.encoding because this is a prompt, not DB Data. prompt = unicode(_("Exception %s: %s"), 'utf8') else: prompt = _("Exception %s: %s") errordlg = Dialogs.ErrorDialog(None, prompt % (sys.exc_info()[0], sys.exc_info()[1])) errordlg.ShowModal() errordlg.Destroy() # Unlock the Data Object obj.unlock_record() except TransanaExceptions.RecordLockedError, e: """Handle the RecordLockedError exception.""" if isinstance(obj, Episode.Episode): rtype = _('Episode') elif isinstance(obj, Clip.Clip): rtype = _('Clip') idVal = obj.id TransanaExceptions.ReportRecordLockedException(rtype, idVal, e)
def OnConvert(self): """ Perform the Plain Text Extraction operation """ # Get the database connection (required for Transactions) db = DBInterface.get_db() # Get a Database Cursor dbCursor = db.cursor() # Initialize a Record Counter counter = 0 # Get a list of the Documents that need Plain Text extraction documents = DBInterface.list_of_documents(withoutPlainText=True) # Update User Info self.txtCtrl.AppendText("%5d Document Records\n" % len(documents)) # Iterate through the list for document in documents: # Update User Info self.txtCtrl.AppendText("%5d Document: %s\n" % (self.numRecords - counter, document[1])) # Load the Document Object tmpDocument = Document.Document(num=document[0]) # I'm not sure why I have to use a Transaction here. But records are remaining locked # without this. This at least makes things work! dbCursor.execute("BEGIN") # Lock the record tmpDocument.lock_record() # Load the record into the hidden RichTextCtrl. Don't show the popup, as too many of these crashes the program! self.richTextCtrl.load_transcript(tmpDocument, showPopup=False) # Save the record. This causes the PlainText to be added! Don't show the popup, as too many of these crashes the program! self.richTextCtrl.save_transcript(use_transactions=False, showPopup=False) # Unlock the record tmpDocument.unlock_record() # Commit the Transaction dbCursor.execute("COMMIT") # Update the Record Counter counter += 1 # Update the Progress Bar self.gauge.SetValue(counter) # This form can freeze up and appear non-responsive. Every 20 items, we should avoid that if counter % 20 == 0: wx.YieldIfNeeded() # Get a list of the Episode Transcripts that need Plain Text extraction episodeTranscripts = DBInterface.list_of_episode_transcripts( withoutPlainText=True) # Update User Info self.txtCtrl.AppendText("%5d Episode Transcript Records\n" % len(episodeTranscripts)) # Iterate through the list for episodeTranscript in episodeTranscripts: # Update User Info self.txtCtrl.AppendText( "%5d Episode Transcript: %s\n" % (self.numRecords - counter, episodeTranscript[1])) # Load the Transcript Object tmpEpisodeTranscript = Transcript.Transcript( id_or_num=episodeTranscript[0]) # I'm not sure why I have to use a Transaction here. But the transaction from the Transcript # object doesn't seem to be cutting it. This at least makes things work! dbCursor.execute("BEGIN") # Lock the record tmpEpisodeTranscript.lock_record() # Load the record into the hidden RichTextCtrl. Don't show the popup, as too many of these crashes the program! self.richTextCtrl.load_transcript(tmpEpisodeTranscript, showPopup=False) # Save the record. This causes the PlainText to be added! Don't show the popup, as too many of these crashes the program! self.richTextCtrl.save_transcript(use_transactions=False, showPopup=False) # Unlock the record tmpEpisodeTranscript.unlock_record() # Commit the Transaction dbCursor.execute("COMMIT") # Update the Record Counter counter += 1 # Update the Progress Bar self.gauge.SetValue(counter) # This form can freeze up and appear non-responsive. We should avoid that with every Episode Transcript (they are big). wx.YieldIfNeeded() # Get a list of the Quotes that need Plain Text extraction quotes = DBInterface.list_of_quotes(withoutPlainText=True) # Update User Info self.txtCtrl.AppendText("%5d Quote Records\n" % len(quotes)) # Iterate through the list for quote in quotes: # Update User Info self.txtCtrl.AppendText("%5d Quote: %s\n" % (self.numRecords - counter, quote[1])) # Load the Quote Object tmpQuote = Quote.Quote(num=quote[0]) # I'm not sure why I have to use a Transaction here. But the transaction from the Transcript # object doesn't seem to be cutting it. This at least makes things work! dbCursor.execute("BEGIN") # Lock the record tmpQuote.lock_record() # Load the record into the hidden RichTextCtrl. Don't show the popup, as too many of these crashes the program! self.richTextCtrl.load_transcript(tmpQuote, showPopup=False) # Save the record. This causes the PlainText to be added! Don't show the popup, as too many of these crashes the program! self.richTextCtrl.save_transcript(use_transactions=False, showPopup=False) # Unlock the record tmpQuote.unlock_record() # Commit the Transaction dbCursor.execute("COMMIT") # Update the Record Counter counter += 1 # Update the Progress Bar self.gauge.SetValue(counter) # This form can freeze up and appear non-responsive. Every 20 items, we should avoid that if counter % 20 == 0: wx.YieldIfNeeded() # Get a list of the Clips that need Plain Text extraction clips = DBInterface.list_of_clips(withoutPlainText=True) # Update User Info self.txtCtrl.AppendText("%5d Clip Records\n" % len(clips)) # Iterate through the list for clip in clips: # Update User Info self.txtCtrl.AppendText( "%5d Clip: %d %s\n" % (self.numRecords - counter, clip[0], clip[1])) # Load the Clip Object tmpClip = Clip.Clip(id_or_num=clip[0]) # For each Transcript in the Clip ... for tmpClipTranscript in tmpClip.transcripts: # I'm not sure why I have to use a Transaction here. But the transaction from the Transcript # object doesn't seem to be cutting it. This at least makes things work! dbCursor.execute("BEGIN") # Lock the record tmpClipTranscript.lock_record() # Load the record into the hidden RichTextCtrl. Don't show the popup, as too many of these crashes the program! self.richTextCtrl.load_transcript(tmpClipTranscript, showPopup=False) # Save the record. This causes the PlainText to be added! Don't show the popup, as too many of these crashes the program! self.richTextCtrl.save_transcript(use_transactions=False, showPopup=False) ## This alternate method also works, and is slightly faster, but is less object friendly. ## The speed difference is about 10 - 15 seconds in a 3 minute processing of 1400 clips. ## import re ## plaintext = self.richTextCtrl.GetValue() ## # Strip Time Codes ## regex = "%s<[\d]*>" % TransanaConstants.TIMECODE_CHAR ## reg = re.compile(regex) ## pos = 0 ## for x in reg.findall(plaintext): ## pos = plaintext.find(x, pos, len(plaintext)) ## plaintext = plaintext[ : pos] + plaintext[pos + len(x) : ] ## query = "UPDATE Transcripts2 SET PlainText = %s WHERE TranscriptNum = %s" ## values = (plaintext.encode('utf8'), tmpClipTranscript.number) ## query = DBInterface.FixQuery(query) ## result = dbCursor.execute(query, values) # Unlock the record tmpClipTranscript.unlock_record() # Commit the Transaction dbCursor.execute("COMMIT") # Update the Record Counter counter += 1 # Update the Progress Bar self.gauge.SetValue(counter) # This form can freeze up and appear non-responsive. Every 20 items, we should avoid that if counter % 20 == 0: wx.YieldIfNeeded() dbCursor.close()
def __init__(self, seriesName=None, episodeName=None, collection=None, searchSeries=None, searchColl=None, treeCtrl=None): # Specify the Report Title self.title = _("Keyword Usage Report") # Create minorList as a blank Dictionary Object minorList = {} # If a Collection Name is passed in ... if collection != None: # ... add a subtitle and ... if 'unicode' in wx.PlatformInfo: # Encode with UTF-8 rather than TransanaGlobal.encoding because this is a prompt, not DB Data. prompt = unicode(_("Collection: %s"), 'utf8') else: prompt = _("Collection: %s") self.subtitle = prompt % collection.id majorLabel = _('Clip:') # ... use the Clips in the Collection for the majorList. majorList = DBInterface.list_of_clips_by_collection( collection.id, collection.parent) # Put all the Keywords for the Clips in the majorList in the minorList for (clipNo, clipName, collNo) in majorList: minorList[clipName] = DBInterface.list_of_keywords(Clip=clipNo) # If an Episode Name is passed in ... elif episodeName != None: # ... add a subtitle and ... if 'unicode' in wx.PlatformInfo: # Encode with UTF-8 rather than TransanaGlobal.encoding because this is a prompt, not DB Data. prompt = unicode(_("Episode: %s"), 'utf8') else: prompt = _("Episode: %s") self.subtitle = prompt % episodeName # ... use the Clips from the Episode for the majorList epObj = Episode.Episode(series=seriesName, episode=episodeName) majorList = DBInterface.list_of_clips_by_episode(epObj.number) # Put all the Keywords for the Clips in the majorList in the minorList for clipRecord in majorList: clipObj = Clip.Clip(clipRecord['ClipID'], clipRecord['CollectID'], clipRecord['ParentCollectNum']) minorList[(clipRecord['ClipID'], clipRecord['CollectID'], clipRecord['ParentCollectNum'] )] = DBInterface.list_of_keywords( Clip=clipObj.number) # If a Series Name is passed in ... elif seriesName != None: # ... add a subtitle and ... if 'unicode' in wx.PlatformInfo: # Encode with UTF-8 rather than TransanaGlobal.encoding because this is a prompt, not DB Data. prompt = unicode(_("Series: %s"), 'utf8') else: prompt = _("Series: %s") self.subtitle = prompt % seriesName majorLabel = _('Episode:') # ... use the Episodes from the Series for the majorList majorList = DBInterface.list_of_episodes_for_series(seriesName) # Put all the Keywords for the Episodes in the majorList in the minorList for (EpNo, epName, epParentNo) in majorList: epObj = Episode.Episode(series=seriesName, episode=epName) minorList[epName] = DBInterface.list_of_keywords( Episode=epObj.number) # If this report is called for a SearchSeriesResult, we build the majorList based on the contents of the Tree Control. elif (searchSeries != None) and (treeCtrl != None): # Get the Search Result Name for the subtitle searchResultNode = searchSeries while 1: searchResultNode = treeCtrl.GetItemParent(searchResultNode) tempData = treeCtrl.GetPyData(searchResultNode) if tempData.nodetype == 'SearchResultsNode': break if 'unicode' in wx.PlatformInfo: # Encode with UTF-8 rather than TransanaGlobal.encoding because this is a prompt, not DB Data. prompt = unicode(_("Search Result: %s Series: %s"), 'utf8') else: prompt = _("Search Result: %s Series: %s") self.subtitle = prompt % (treeCtrl.GetItemText(searchResultNode), treeCtrl.GetItemText(searchSeries)) # The majorLabel is for Episodes in this case majorLabel = _('Episode:') # Initialize the majorList to an empty list majorList = [] # Get the first Child node from the searchColl collection (item, cookie) = treeCtrl.GetFirstChild(searchSeries) # Process all children in the searchSeries Series. (IsOk() fails when all children are processed.) while item.IsOk(): # Get the item's Name itemText = treeCtrl.GetItemText(item) # Get the item's Node Data itemData = treeCtrl.GetPyData(item) # See if the item is an Episode if itemData.nodetype == 'SearchEpisodeNode': # If it's an Episode, add the Episode's Node Data to the majorList majorList.append( (itemData.recNum, itemText, itemData.parent)) # Get the next Child Item and continue the loop (item, cookie) = treeCtrl.GetNextChild(searchSeries, cookie) # Once we have the Episodes in the majorList, we can gather their keywords into the minorList for (EpNo, epName, epParentNo) in majorList: epObj = Episode.Episode( series=treeCtrl.GetItemText(searchSeries), episode=epName) minorList[epName] = DBInterface.list_of_keywords( Episode=epObj.number) # If this report is called for a SearchCollectionResult, we build the majorList based on the contents of the Tree Control. elif (searchColl != None) and (treeCtrl != None): # Get the Search Result Name for the subtitle searchResultNode = searchColl while 1: searchResultNode = treeCtrl.GetItemParent(searchResultNode) tempData = treeCtrl.GetPyData(searchResultNode) if tempData.nodetype == 'SearchResultsNode': break if 'unicode' in wx.PlatformInfo: # Encode with UTF-8 rather than TransanaGlobal.encoding because this is a prompt, not DB Data. prompt = unicode(_("Search Result: %s Collection: %s"), 'utf8') else: prompt = _("Search Result: %s Collection: %s") self.subtitle = prompt % (treeCtrl.GetItemText(searchResultNode), treeCtrl.GetItemText(searchColl)) # The majorLabel is for Clips in this case majorLabel = _('Clip:') # Initialize the majorList to an empty list majorList = [] # Extracting data from the treeCtrl requires a "cookie" value, which is initialized to 0 cookie = 0 # Get the first Child node from the searchColl collection (item, cookie) = treeCtrl.GetFirstChild(searchColl) # Process all children in the searchColl collection while item.IsOk(): # Get the item's Name itemText = treeCtrl.GetItemText(item) # Get the item's Node Data itemData = treeCtrl.GetPyData(item) # See if the item is a Clip if itemData.nodetype == 'SearchClipNode': # If it's a Clip, add the Clip's Node Data to the majorList majorList.append( (itemData.recNum, itemText, itemData.parent)) # When we get to the last Child Item, stop looping if item == treeCtrl.GetLastChild(searchColl): break # If we're not at the Last Child Item, get the next Child Item and continue the loop else: (item, cookie) = treeCtrl.GetNextChild(searchColl, cookie) # Once we have the Clips in the majorList, we can gather their keywords into the minorList for (clipNo, clipName, collNo) in majorList: minorList[clipName] = DBInterface.list_of_keywords(Clip=clipNo) # Initialize and fill the initial data structure that will be turned into the report self.data = [] # Create a Dictionary Data Structure to accumulate Keyword Counts keywordCounts = {} # The majorList and minorList are constructed differently for the Episode version of the report, # and so the report must be built differently here too! if episodeName == None: if 'unicode' in wx.PlatformInfo: # Encode with UTF-8 rather than TransanaGlobal.encoding because this is a prompt, not DB Data. majorLabel = unicode(majorLabel, 'utf8') # Iterate through the major list for (groupNo, group, parentCollNo) in majorList: # Use the group name as a Heading self.data.append( (('Subheading', '%s %s' % (majorLabel, group)), )) # Iterate through the list of Keywords for the group for (keywordGroup, keyword, example) in minorList[group]: # Use the Keyword name as a Subheading self.data.append( (('Subtext', '%s : %s' % (keywordGroup, keyword)), )) # Add this Keyword to the Keyword Counts if keywordCounts.has_key('%s : %s' % (keywordGroup, keyword)): keywordCounts['%s : %s' % (keywordGroup, keyword)] = keywordCounts[ '%s : %s' % (keywordGroup, keyword)] + 1 else: keywordCounts['%s : %s' % (keywordGroup, keyword)] = 1 # Add a blank line after each group self.data.append((('Normal', ''), )) else: # Iterate through the major list for clipRecord in majorList: # Use the group name as a Heading if 'unicode' in wx.PlatformInfo: # Encode with UTF-8 rather than TransanaGlobal.encoding because this is a prompt, not DB Data. prompt = unicode(_('Collection: %s, Clip: %s'), 'utf8') else: prompt = _('Collection: %s, Clip: %s') self.data.append( (('Subheading', prompt % (clipRecord['CollectID'], clipRecord['ClipID'])), ('NormalRight', '(%s - %s)' % (Misc.time_in_ms_to_str(clipRecord['ClipStart']), Misc.time_in_ms_to_str(clipRecord['ClipStop']))))) # Iterate through the list of Keywords for the group for (keywordGroup, keyword, example) in minorList[(clipRecord['ClipID'], clipRecord['CollectID'], clipRecord['ParentCollectNum'])]: # Use the Keyword name as a Subheading self.data.append( (('Subtext', '%s : %s' % (keywordGroup, keyword)), )) # Add this Keyword to the Keyword Counts if keywordCounts.has_key('%s : %s' % (keywordGroup, keyword)): keywordCounts['%s : %s' % (keywordGroup, keyword)] = keywordCounts[ '%s : %s' % (keywordGroup, keyword)] + 1 else: keywordCounts['%s : %s' % (keywordGroup, keyword)] = 1 # Add a blank line after each group self.data.append((('Normal', ''), )) # If there's data in the majorList ... if len(majorList) != 0: # Now add the Report Summary self.data.append((('Subheading', _('Summary')), )) # Get a list of the Keyword Group : Keyword pairs that have been used countKeys = keywordCounts.keys() # Sort the list countKeys.sort() # Add the sorted keywords to the summary with their counts for key in countKeys: self.data.append((('Subtext', key), ('NormalRight', '%s' % keywordCounts[key]))) # The initial data structure needs to be prepared. What PrepareData() does is to create a graphic # object that is the correct size and dimensions for the type of paper selected, and to create # a datastructure that breaks the data sent in into separate pages, again based on the dimensions # of the paper currently selected. (self.graphic, self.pageData) = ReportPrintoutClass.PrepareData( TransanaGlobal.printData, self.title, self.data, self.subtitle) # Send the results of the PrepareData() call to the MyPrintout object, once for the print preview # version and once for the printer version. printout = ReportPrintoutClass.MyPrintout(self.title, self.graphic, self.pageData, self.subtitle) printout2 = ReportPrintoutClass.MyPrintout(self.title, self.graphic, self.pageData, self.subtitle) # Create the Print Preview Object self.preview = wx.PrintPreview(printout, printout2, TransanaGlobal.printData) # Check for errors during Print preview construction if not self.preview.Ok(): dlg = Dialogs.ErrorDialog(None, _("Print Preview Problem")) dlg.ShowModal() dlg.Destroy() return # Create the Frame for the Print Preview theWidth = max(wx.ClientDisplayRect()[2] - 180, 760) theHeight = max(wx.ClientDisplayRect()[3] - 200, 560) frame = wx.PreviewFrame(self.preview, None, _("Print Preview"), size=(theWidth, theHeight)) frame.Centre() # Initialize the Frame for the Print Preview frame.Initialize() # Display the Print Preview Frame frame.Show(True) # If there's NO data in the majorList ... else: # If there are no clips to report, display an error message. if 'unicode' in wx.PlatformInfo: # Encode with UTF-8 rather than TransanaGlobal.encoding because this is a prompt, not DB Data. prompt = unicode( _('%s has no data for the Keyword Usage Report.'), 'utf8') else: prompt = _('%s has no data for the Keyword Usage Report.') dlg = wx.MessageDialog(None, prompt % self.subtitle, style=wx.OK | wx.ICON_EXCLAMATION) dlg.ShowModal() dlg.Destroy()