Ejemplo n.º 1
0
    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)
Ejemplo n.º 2
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()
Ejemplo n.º 3
0
    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)
Ejemplo n.º 4
0
    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()
Ejemplo n.º 5
0
    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
Ejemplo n.º 6
0
    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])
Ejemplo n.º 7
0
    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)
Ejemplo n.º 8
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()
Ejemplo n.º 9
0
    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)
Ejemplo n.º 10
0
    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)
Ejemplo n.º 11
0
    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()
Ejemplo n.º 12
0
    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()