예제 #1
0
    def __init__(self, parent, contentType = 'ENG', readOnly = False, buttonLess = False):
        super(XTextBox, self).__init__()
        
        self.parent = parent
        self.Jpcon = sqlite3.connect('Resources/JPDictionary')
        self.Jpcur = self.Jpcon.cursor()
        self.modified = False
        self.setAcceptRichText( False )
        self.setMinimumSize( 0, 0 )
        self.setViewportMargins(0, 0, 0, 0)
        
        self.currentlySetStatus = 0
        self.contentType = contentType

        self.buttons = []

        self.readOnly = readOnly
        self.buttonLess = buttonLess

        if Globals.Audio:
            self.audioOutput = Phonon.AudioOutput(Phonon.MusicCategory)
            self.player = Phonon.MediaObject()
            Phonon.createPath(self.player, self.audioOutput)

        if contentType == 'ENG':
            self.StatusButtons = {}
            for i in range( 1, Globals.configData.TranslationStagesCount + 1 ):
                button = QtGui.QToolButton()
                button.setAutoRaise(True)
                button.setIcon(QtGui.QIcon('icons/status/{0}.png'.format(i)))
                if self.buttonLess:
                    button.hide()
                self.StatusButtons[i] = button
    
            self.AudioButtonJpn = QtGui.QToolButton()
            self.AudioButtonJpn.setIcon(self.style().standardIcon(QtGui.QStyle.SP_MediaPlay))
            self.AudioButtonJpn.setAutoRaise(True)
            self.AudioButtonJpn.released.connect(self.playAudioJpn)
            self.AudioButtonJpn.hide()
            self.AudioButtonEng = QtGui.QToolButton()
            self.AudioButtonEng.setIcon(self.style().standardIcon(QtGui.QStyle.SP_MediaPlay))
            self.AudioButtonEng.setAutoRaise(True)
            self.AudioButtonEng.released.connect(self.playAudioEng)
            self.AudioButtonEng.hide()

            topLayout = QtGui.QHBoxLayout()

            layout = HUDLayout()
            for i in range( Globals.configData.TranslationStagesCount, 0, -1 ):
                layout.addWidget(self.StatusButtons[i])
            layout.addWidget(self.AudioButtonEng)
            layout.addWidget(self.AudioButtonJpn)
            
            topLayout.setMargin(0)
            topLayout.addLayout(layout)
            self.setLayout(topLayout)

            if not self.readOnly:
                for i in range( 1, Globals.configData.TranslationStagesCount + 1 ):
                    self.StatusButtons[i].released.connect(self.ToggleStatusButtonClosure(i))

        elif contentType == 'JPN' or contentType == 'COM':
            self.jpflag = QtGui.QToolButton()
            self.jpflag.setCheckable(False)
            self.jpflag.setAutoRaise(True)
            
            if contentType == 'JPN':
                self.role = 1
                self.jpflag.setIcon(QtGui.QIcon('icons/japanflag.png'))
            if contentType == 'COM':
                self.role = 2
                self.jpflag.setIcon(QtGui.QIcon('icons/comment.png'))
            
            layout = HUDLayout()
            layout.addWidget(self.jpflag)
            self.setLayout(layout)
            
        self.highlighter = CustomHighlighter(self)

        if Globals.enchanted:
            import enchant
            self.dict = enchant.Dict("en_US")
            for word in Globals.configData.Dictionary:
                self.dict.add_to_session(word.strip())
            self.highlighter.setDict(self.dict)
        
        self.textChanged.connect(self.textChangedSignal)
        self.undoAvailable.connect(self.modifyTrue)
예제 #2
0
class XTextBox(QtGui.QTextEdit):

    #should be: manualEdit = QtCore.pyqtSignal(int, XTextBox, QtGui.QLabel) but I haven't figured out how to give the current class as parameter
    manualEdit = QtCore.pyqtSignal(int, object, QtGui.QLabel)
    currentEntry = -1


    def __init__(self, parent, contentType = 'ENG', readOnly = False, buttonLess = False):
        super(XTextBox, self).__init__()
        
        self.parent = parent
        self.Jpcon = sqlite3.connect('Resources/JPDictionary')
        self.Jpcur = self.Jpcon.cursor()
        self.modified = False
        self.setAcceptRichText( False )
        self.setMinimumSize( 0, 0 )
        self.setViewportMargins(0, 0, 0, 0)
        
        self.currentlySetStatus = 0
        self.contentType = contentType

        self.buttons = []

        self.readOnly = readOnly
        self.buttonLess = buttonLess

        if Globals.Audio:
            self.audioOutput = Phonon.AudioOutput(Phonon.MusicCategory)
            self.player = Phonon.MediaObject()
            Phonon.createPath(self.player, self.audioOutput)

        if contentType == 'ENG':
            self.StatusButtons = {}
            for i in range( 1, Globals.configData.TranslationStagesCount + 1 ):
                button = QtGui.QToolButton()
                button.setAutoRaise(True)
                button.setIcon(QtGui.QIcon('icons/status/{0}.png'.format(i)))
                if self.buttonLess:
                    button.hide()
                self.StatusButtons[i] = button
    
            self.AudioButtonJpn = QtGui.QToolButton()
            self.AudioButtonJpn.setIcon(self.style().standardIcon(QtGui.QStyle.SP_MediaPlay))
            self.AudioButtonJpn.setAutoRaise(True)
            self.AudioButtonJpn.released.connect(self.playAudioJpn)
            self.AudioButtonJpn.hide()
            self.AudioButtonEng = QtGui.QToolButton()
            self.AudioButtonEng.setIcon(self.style().standardIcon(QtGui.QStyle.SP_MediaPlay))
            self.AudioButtonEng.setAutoRaise(True)
            self.AudioButtonEng.released.connect(self.playAudioEng)
            self.AudioButtonEng.hide()

            topLayout = QtGui.QHBoxLayout()

            layout = HUDLayout()
            for i in range( Globals.configData.TranslationStagesCount, 0, -1 ):
                layout.addWidget(self.StatusButtons[i])
            layout.addWidget(self.AudioButtonEng)
            layout.addWidget(self.AudioButtonJpn)
            
            topLayout.setMargin(0)
            topLayout.addLayout(layout)
            self.setLayout(topLayout)

            if not self.readOnly:
                for i in range( 1, Globals.configData.TranslationStagesCount + 1 ):
                    self.StatusButtons[i].released.connect(self.ToggleStatusButtonClosure(i))

        elif contentType == 'JPN' or contentType == 'COM':
            self.jpflag = QtGui.QToolButton()
            self.jpflag.setCheckable(False)
            self.jpflag.setAutoRaise(True)
            
            if contentType == 'JPN':
                self.role = 1
                self.jpflag.setIcon(QtGui.QIcon('icons/japanflag.png'))
            if contentType == 'COM':
                self.role = 2
                self.jpflag.setIcon(QtGui.QIcon('icons/comment.png'))
            
            layout = HUDLayout()
            layout.addWidget(self.jpflag)
            self.setLayout(layout)
            
        self.highlighter = CustomHighlighter(self)

        if Globals.enchanted:
            import enchant
            self.dict = enchant.Dict("en_US")
            for word in Globals.configData.Dictionary:
                self.dict.add_to_session(word.strip())
            self.highlighter.setDict(self.dict)
        
        self.textChanged.connect(self.textChangedSignal)
        self.undoAvailable.connect(self.modifyTrue)
        
        
    def setFooter(self, footer):
        self.footer = footer
        
    def refreshFooter(self, text, prepend):
        if not Globals.FooterVisibleFlag:
            return
            
        feedCount = text.count('\f')
        sanitizedText = Globals.configData.ReplaceInGameString(text)
        splitOnFeeds = sanitizedText.split('\f')
        splitOnLines = sanitizedText.replace('\f', '\n').split('\n')
        longestLineChars = 0
        for s in splitOnLines:
            longestLineChars = max(longestLineChars, len(s))
        highestBoxNewlines = 0
        for s in splitOnFeeds:
            highestBoxNewlines = max(highestBoxNewlines, s.count('\n')+1)
        self.footer.setText(prepend + 'Textboxes: ' + str(feedCount+1) + ' / Highest Box: ' + str(highestBoxNewlines) + ' lines / Longest Line: ' + str(longestLineChars) + ' chars')

    def clearFooter(self):
        if not Globals.FooterVisibleFlag:
            return
        self.footer.setText('')
    
    def makePlaybackButtons(self, clipList):
        if not self.buttonLess:
            self.audioClips = clipList
            self.AudioButtonJpn.show()
            # only display the second button if there are actually two different voice clips
            if not ( Globals.configData.VoicePathEnPrefix == Globals.configData.VoicePathJpPrefix and Globals.configData.VoicePathEnPostfix == Globals.configData.VoicePathJpPostfix ):
                self.AudioButtonEng.show()
                
    def clearPlaybackButtons(self):
        self.audioClips = []
        self.AudioButtonJpn.hide()
        self.AudioButtonEng.hide()

                        
    def lookupAudioHash(self, name, forceAlternateLanguage):
        
        if not Globals.configData.UseGracesVoiceHash:
            if Globals.EnglishVoiceLanguageFlag or forceAlternateLanguage:
                return Globals.configData.VoicePathEnPrefix + name + Globals.configData.VoicePathEnPostfix
            return Globals.configData.VoicePathJpPrefix + name + Globals.configData.VoicePathJpPostfix
        
        if not Globals.HashTableExists:
            return ''
        
        import hashtable

        temphash = 0
        for i in name:
            temphash = ((temphash * 137) + ord(i)) % 0x100000000
        
        if name[:2] == 'VS':
            index = hashtable.hashtable[int(name[2])-1].index(temphash)
            filename = 'VOSCE0' + name[2] + '_' + str(index+1).zfill(5)
        
        elif name[:2] == 'VA':
            index = hashtable.hashtable[8].index(temphash)
            filename = 'VOSCE16' + '_' + str(index+1).zfill(5)
        
        if Globals.EnglishVoiceLanguageFlag or forceAlternateLanguage:
            return Globals.configData.VoicePathEnPrefix + filename + Globals.configData.VoicePathEnPostfix
        return Globals.configData.VoicePathJpPrefix + filename + Globals.configData.VoicePathJpPostfix

    def playAudioJpn(self):
        self.playAudio(self.audioClips, False)
    def playAudioEng(self):
        self.playAudio(self.audioClips, True)

    def playAudio(self, clips, forceAlternateLanguage):
    
        self.player.clear()
        playerQueue = []
    
        for clip in clips:
            filename = self.lookupAudioHash(clip, forceAlternateLanguage)
            if os.path.exists(filename):
                #print 'playing audio: "' + filename + '"'
                playerQueue.append(Phonon.MediaSource(filename))
            else:
                Globals.MainWindow.displayStatusMessage( 'couldn\'t find audio: "' + filename + '"' )
                
        if playerQueue:
            self.player.enqueue(playerQueue)
            self.player.play()

    def textChangedSignal(self):
        if self.modified:
            self.manualEdit.emit(-1, self, self.footer)
            
    def modifyTrue(self, set):
        self.modified = set

    def setText(self, string):
        self.modified = False
        QtGui.QTextEdit.setText(self, string)
        

    def mousePressEvent(self, event):
        if Globals.enchanted:
            if event.button() == QtCore.Qt.RightButton:
                event = QtGui.QMouseEvent(QtCore.QEvent.MouseButtonPress, event.pos(),
                    QtCore.Qt.LeftButton, QtCore.Qt.LeftButton, QtCore.Qt.NoModifier)
        QtGui.QTextEdit.mousePressEvent(self, event)


    def contextMenuEvent(self, event):
        popup_menu = self.createStandardContextMenu()
    
        # Select the word under the cursor.
        cursor = self.textCursor()
        if cursor.selectedText() == '':
            cursor.select(QtGui.QTextCursor.WordUnderCursor)
        self.setTextCursor(cursor)
    
        popup_menu.addSeparator()
        searchEntryAction = QtGui.QAction( 'Search for Entry', None )
        searchEntryAction.triggered.connect( self.SearchEntry )
        popup_menu.addAction( searchEntryAction )

        if self.textCursor().hasSelection():
            text = unicode(self.textCursor().selectedText())
            searchSelectionAction = TextAction( u'Search for "' + unicode(text) + u'"', popup_menu )
            searchSelectionAction.data = text
            searchSelectionAction.textActionTriggered.connect( self.SearchSelection )
            popup_menu.addAction( searchSelectionAction )
        popup_menu.addSeparator()
        
        if self.textCursor().hasSelection():
            # Check if the selected word is misspelled or JP and offer spelling
            # suggestions if it is.
            # JP Lookup
            if ord(text[0]) > 0x79:
                select = unicode(cursor.selectedText()) + u'%'

                # All matches
                self.Jpcur.execute(u'select * from Dictionary where Kanji LIKE ? OR Kana LIKE ?', (select, select))
                results = self.Jpcur.fetchall()

                if results != []:
                    
                    font = self.font()
                    font.setPixelSize(9)
                    
                    resultsMenu = []
                    i = 0
                    for result in results[:16]:
                        if result[1] != None:
                            yum = u' [' + unicode(result[1]) + u']'
                        else:
                            yum = ''
                        
                        menu = QtGui.QMenu(u'{0}{1}'.format(result[0], yum))
                        menu.setFont(font)
                        
                        actionList = self.DefSplit(unicode(result[2]))
                        for item in actionList:
                            menu.addAction(item)
                        resultsMenu.append(menu)
                    
                    theCookieMenu = QtGui.QMenu('{0} Partial Matches'.format(len(resultsMenu)))
                    popup_menu.insertSeparator(popup_menu.actions()[0])
                    popup_menu.insertMenu(popup_menu.actions()[0], theCookieMenu)
                    
                    for menu in resultsMenu:
                        theCookieMenu.addMenu(menu)
                        i += 1


                # Perfect Match
                self.Jpcur.execute(u'select * from Dictionary where Kanji=? OR Kana=?', (unicode(cursor.selectedText()), unicode(cursor.selectedText())))
                trueResults = self.Jpcur.fetchall()

                if trueResults != []:
                    if trueResults[0][1] != None:
                        yum = u' [' + unicode(trueResults[0][1]) + u']'
                    else:
                        yum = ''
                
                    amenu = QtGui.QMenu(u'{0}{1}'.format(trueResults[0][0], yum))
                    
                    actionList = self.DefSplit(unicode(trueResults[0][2]))
                    for item in actionList:
                        amenu.addAction(item)

                    popup_menu.insertSeparator(popup_menu.actions()[0])
                    popup_menu.insertMenu(popup_menu.actions()[0], amenu)

                if results == [] and trueResults == []:
                    menu = QtGui.QMenu('No JP-Eng Matches Found')
                    popup_menu.insertSeparator(popup_menu.actions()[0])
                    popup_menu.insertMenu(popup_menu.actions()[0], menu)

            # Enchant
            if Globals.enchanted:
                if not self.dict.check(text):
                    spell_menu = QtGui.QMenu('Spelling Suggestions')
                    for word in self.dict.suggest(text):
                        action = TextAction(word, spell_menu)
                        action.data = word
                        action.textActionTriggered.connect(self.correctWord)
                        spell_menu.addAction(action)
                    # Only add the spelling suggests to the menu if there are
                    # suggestions.
                    if len(spell_menu.actions()) != 0:
                        popup_menu.insertSeparator(popup_menu.actions()[0])
                        popup_menu.insertMenu(popup_menu.actions()[0], spell_menu)
            
            # offer a quick jump on [entrynumber] or [databasename] or [databasename/entrynumber]
            plaintext = self.toPlainText()
            selstart = cursor.selectionStart()-1
            selend = cursor.selectionEnd()+1
            textplus = unicode(plaintext[selstart : selend])
            if textplus.startswith('/'):
                while plaintext[selstart] != u'[':
                    selstart = selstart - 1
                textplus = unicode(plaintext[selstart : selend])
            elif textplus.endswith('/'):
                while plaintext[selend] != u']':
                    selend = selend + 1
                selend = selend + 1
                textplus = unicode(plaintext[selstart : selend])
            if textplus.startswith('[') and textplus.endswith(']'):
                popup_menu.addSeparator()
                action = TextAction(u'Jump to ' + unicode(textplus), popup_menu)
                action.data = textplus
                action.textActionTriggered.connect(self.jumpToDatabaseFromBracketString)
                popup_menu.addAction(action)
                


        popup_menu.exec_( event.globalPos() )

    def SearchSelection(self, text):
        self.parent.ShowMassReplace()
        self.parent.massDialog.original.setText( text )
        self.parent.massDialog.matchEngCheckbox.setChecked( True if self.contentType == 'ENG' else False )
        self.parent.massDialog.matchJpnCheckbox.setChecked( True if self.contentType == 'JPN' else False )
        self.parent.massDialog.matchEntryCheckbox.setChecked( False )
        self.parent.massDialog.matchCase.setChecked( False )
        self.parent.massDialog.searchDebug.setChecked( False )
        self.parent.massDialog.fileFilter.setText( '' )
        self.parent.massDialog.exceptions.setText( '' )
        self.parent.massDialog.Search()

    def SearchEntry(self):
        self.parent.ShowMassReplace()
        self.parent.massDialog.original.setText( self.toPlainText() )
        self.parent.massDialog.matchEngCheckbox.setChecked( True if self.contentType == 'ENG' else False )
        self.parent.massDialog.matchJpnCheckbox.setChecked( True if self.contentType == 'JPN' else False )
        self.parent.massDialog.matchEntryCheckbox.setChecked( True )
        self.parent.massDialog.matchCase.setChecked( True )
        self.parent.massDialog.searchDebug.setChecked( False )
        self.parent.massDialog.fileFilter.setText( '' )
        self.parent.massDialog.exceptions.setText( '' )
        self.parent.massDialog.Search()

    def DefSplit(self, string):
        
        cookielist = []
        pat = re.compile('([(].*?[)]) *(.*)')
        match = re.match(pat, string)

        
        cookieString = match.group(1)[1:-1] + ':'

        thinglist = [
        ['n', 'Noun'],
        ['aux', 'Auxiliary'],
        ['id', 'Idiom'],
        ['int', 'Interjection'],
        ['iv', 'Irregular Verb'],
        ['vi', 'Intransitive Verb'],
        ['adv', 'Adverb'],
        ['conj', 'Conjunction'],
        ['ctr', 'Counter'],
        ['exp', 'Expression'],
        ['pref', 'Prefix'],
        ['suf', 'Suffix'],
        ['adj-i', 'Adjective'],
        ['num', 'Numeric'],
        ['pn', 'Pronoun'],
        ['prt', 'Particle'],
        ['Noun-', 'n-'],
        ['n-pref', 'Noun Prefix'],
        ['n-suf', 'Noun Suffix'],
        ['n-t', 'Noun (Temporal)'],
        ['v5aru', 'Verb ~aru'],
        ['v5b', 'Verb ~bu'],
        ['v5g', 'Verb ~gu'],
        ['v5k-s', 'Verb ~iku/yuku'],
        ['v5k', 'Verb ~ku'],
        ['v5m', 'Verb ~mu'],
        ['v5n', 'Verb ~nu'],
        ['v5r-i', 'Verb ~ru (irregular)'],
        ['v5r', 'Verb ~ru'],
        ['v5s', 'Verb ~su'],
        ['v5t', 'Verb ~tsu'],
        ['v5u-s', 'Verb ~u (special)'],
        ['v5uru', 'Verb ~uru'],
        ['v5u', 'Verb ~u'],
        ['v5z', 'Verb ~zu'],
        ['vz', 'Ichidan verb ~zuru)'],
        ['vk', 'Kuru Verb'],
        ['vn', 'Irregular ~nu Verb'],
        ['vs-i', 'Suru Verb (irregular)'],
        ['vs-s', 'Suru Verb (special)'],
        ['vs', 'Noun with ~suru'],
        ['vt', 'Transitive Verb'],
        ['v1', 'Ichidan verb'],
        ['v5', 'Verb']]


        for thing in thinglist:
            cookieString = cookieString.replace(thing[0], thing[1])


        cookielist.append(cookieString)

        NewString = match.group(2)
        
        i = 1
        loop = True
        while loop:
            if NewString.count('({0})'.format(i)) == 1:
                if NewString.count('({0})'.format(i+1)) == 1:
                    cookielist.append(NewString[NewString.find('({0})'.format(i))+4:NewString.find('({0})'.format(i+1))])
                    i += 1
                else:
                    cookielist.append(NewString[NewString.find('({0})'.format(i))+4:])
                    loop = False
                    break
            else:
                cookielist.append(NewString)
                loop = False
                break
            
        return cookielist
    
    def jumpToDatabaseFromBracketString(self, word):
        # word is something like: "[DRBO1234/56]", "[1]", "[VItems]"
        word = unicode(word)
        word = word[word.index('[') + 1 : word.index(']')]
        words = word.split('/', 1)
        if len(words) == 2:
            db = words[0]
            entry = words[1]
        else:
            try:
                entry = int(word)
                db = ''
            except ValueError:
                db = word
                entry = 1
        
        self.parent.JumpToEntry(db, entry)

    def correctWord(self, word):
        '''
        Replaces the selected text with word.
        '''
        if not self.readOnly:
            cursor = self.textCursor()
            cursor.beginEditBlock()
 
            cursor.removeSelectedText()
            cursor.insertText(word)
 
            cursor.endEditBlock()



    def ToggleStatusButtonClosure(self, status):
        def callFunc():
            if not self.readOnly:
                if self.currentlySetStatus != status:
                    self.StatusButtons[status].setIcon(QtGui.QIcon('icons/status/{0}g.png'.format(status)))
                    self.currentlySetStatus = status
                    self.manualEdit.emit(status, self, self.footer)
                else:
                    self.StatusButtons[status].setIcon(QtGui.QIcon('icons/status/{0}.png'.format(status)))
                    self.currentlySetStatus = status - 1
                    self.manualEdit.emit(status - 1, self, self.footer)
        return callFunc

    def iconToggle(self, icon):
        if icon > Globals.configData.TranslationStagesCount:
            icon = Globals.configData.TranslationStagesCount
        for i in range( 1, Globals.configData.TranslationStagesCount + 1 ):
            self.StatusButtons[i].setIcon(QtGui.QIcon('icons/status/{0}.png'.format(i)))
        for i in range( 1, icon + 1 ):
            self.StatusButtons[i].setIcon(QtGui.QIcon('icons/status/{0}g.png'.format(i)))
        self.currentlySetStatus = icon