<s> import ctypes <EOL> import re <EOL> from PyQt4 import Qt <EOL> from PyQt4 import QtGui <EOL> from PyQt4 import QtCore <EOL> try : <EOL> import pxss <EOL> except : <EOL> pass <EOL> try : <EOL> import enchant <EOL> except ImportError : <EOL> enchant = None <EOL> class SpellTextEditor ( Qt . QPlainTextEdit ) : <EOL> '''<STR_LIT>''' <EOL> MINIMUM_VIEWABLE_LINES = <NUM_LIT:3> <EOL> MAXIMUM_VIEWABLE_LINES = <NUM_LIT:8> <EOL> def __init__ ( self , lang = True , mainFrame = None , * args ) : <EOL> super ( SpellTextEditor , self ) . __init__ ( * args ) <EOL> self . _mainFrame = mainFrame <EOL> self . _dict = None <EOL> self . _defaultDict = None <EOL> self . _highlighter = None <EOL> if lang : <EOL> self . enableSpell ( lang ) <EOL> self . setFixedHeight ( self . fontMetrics ( ) . height ( ) * self . MINIMUM_VIEWABLE_LINES ) <EOL> self . installEventFilter ( EditorKeyPressEventFilter ( mainFrame , self ) ) <EOL> self . connect ( self , QtCore . SIGNAL ( '<STR_LIT>' ) , self . _onTextChanged ) <EOL> @ staticmethod <EOL> def canSpell ( ) : <EOL> can = True if enchant else False <EOL> if can : <EOL> try : <EOL> dict = enchant . Dict ( ) <EOL> except enchant . DictNotFoundError : <EOL> can = False <EOL> return can <EOL> @ staticmethod <EOL> def languages ( ) : <EOL> return enchant . list_languages ( ) if enchant else None <EOL> @ staticmethod <EOL> def defaultLanguage ( ) : <EOL> tag = None <EOL> if enchant : <EOL> try : <EOL> tag = enchant . Dict ( ) . tag <EOL> except enchant . DictNotFoundError : <EOL> pass <EOL> return tag <EOL> def enableSpell ( self , lang = None ) : <EOL> if SpellTextEditor . canSpell ( ) : <EOL> if lang : <EOL> self . _dict = enchant . Dict ( lang ) <EOL> else : <EOL> self . _dict = enchant . Dict ( ) <EOL> else : <EOL> self . _dict = None <EOL> self . _highlighter = SpellHighlighter ( self . document ( ) ) <EOL> if self . _dict : <EOL> self . _highlighter . setDict ( self . _dict ) <EOL> self . _highlighter . rehighlight ( ) <EOL> def disableSpell ( self ) : <EOL> self . _dict = None <EOL> if self . _highlighter : <EOL> self . _highlighter . setDocument ( None ) <EOL> def mousePressEvent ( self , event ) : <EOL> if event . button ( ) == QtCore . Qt . RightButton : <EOL> event = Qt . QMouseEvent ( Qt . QEvent . MouseButtonPress , event . pos ( ) , <EOL> QtCore . Qt . LeftButton , QtCore . Qt . LeftButton , QtCore . Qt . NoModifier ) <EOL> super ( SpellTextEditor , self ) . mousePressEvent ( event ) <EOL> def contextMenuEvent ( self , event ) : <EOL> popup_menu = self . createStandardContextMenu ( ) <EOL> cursor = self . textCursor ( ) <EOL> cursor . select ( Qt . QTextCursor . WordUnderCursor ) <EOL> self . setTextCursor ( cursor ) <EOL> if enchant and self . _dict : <EOL> if self . textCursor ( ) . hasSelection ( ) : <EOL> text = unicode ( self . textCursor ( ) . selectedText ( ) ) <EOL> if not self . _dict . check ( text ) : <EOL> spell_menu = Qt . QMenu ( self . _mainFrame . _ ( '<STR_LIT>' ) if self . _mainFrame else QtCore . QCoreApplication . translate ( '<STR_LIT>' , '<STR_LIT>' ) , self ) <EOL> for word in self . _dict . suggest ( text ) : <EOL> action = SpellAction ( word , spell_menu ) <EOL> action . correct . connect ( self . correctWord ) <EOL> spell_menu . addAction ( action ) <EOL> if len ( spell_menu . actions ( ) ) != <NUM_LIT:0> : <EOL> popup_menu . insertSeparator ( popup_menu . actions ( ) [ <NUM_LIT:0> ] ) <EOL> popup_menu . insertMenu ( popup_menu . actions ( ) [ <NUM_LIT:0> ] , spell_menu ) <EOL> popup_menu . exec_ ( event . globalPos ( ) ) <EOL> def correctWord ( self , word ) : <EOL> '''<STR_LIT>''' <EOL> cursor = self . textCursor ( ) <EOL> cursor . beginEditBlock ( ) <EOL> cursor . removeSelectedText ( ) <EOL> cursor . insertText ( word ) <EOL> cursor . endEditBlock ( ) <EOL> def _onTextChanged ( self ) : <EOL> text = self . document ( ) . toPlainText ( ) <EOL> viewableLines = self . height ( ) / self . fontMetrics ( ) . height ( ) <EOL> hasNewLine = text . indexOf ( "<STR_LIT:\n>" ) > <NUM_LIT:0> <EOL> if ( hasNewLine and viewableLines < self . MAXIMUM_VIEWABLE_LINES ) or ( not hasNewLine and viewableLines > self . MINIMUM_VIEWABLE_LINES ) : <EOL> viewableLines = self . MAXIMUM_VIEWABLE_LINES if hasNewLine else self . MINIMUM_VIEWABLE_LINES <EOL> self . setFixedHeight ( self . fontMetrics ( ) . height ( ) * viewableLines ) <EOL> class SpellHighlighter ( Qt . QSyntaxHighlighter ) : <EOL> WORDS = u'<STR_LIT>' <EOL> def __init__ ( self , * args ) : <EOL> super ( SpellHighlighter , self ) . __init__ ( * args ) <EOL> self . dict = None <EOL> def setDict ( self , dict ) : <EOL> self . dict = dict <EOL> def highlightBlock ( self , text ) : <EOL> if not self . dict : <EOL> return <EOL> text = unicode ( text ) <EOL> format = Qt . QTextCharFormat ( ) <EOL> format . setUnderlineColor ( QtCore . Qt . red ) <EOL> format . setUnderlineStyle ( Qt . QTextCharFormat . DotLine ) <EOL> for word_object in re . finditer ( self . WORDS , text ) : <EOL> if not self . dict . check ( word_object . group ( ) ) : <EOL> self . setFormat ( word_object . start ( ) , <EOL> word_object . end ( ) - word_object . start ( ) , format ) <EOL> class SpellAction ( Qt . QAction ) : <EOL> '''<STR_LIT>''' <EOL> correct = QtCore . pyqtSignal ( unicode ) <EOL> def __init__ ( self , * args ) : <EOL> super ( SpellAction , self ) . __init__ ( * args ) <EOL> self . triggered . connect ( lambda x : self . correct . emit ( <EOL> unicode ( self . toolTip ( ) ) ) ) <EOL> class IdleTimer ( QtCore . QThread ) : <EOL> def __init__ ( self , parent , idleSeconds ) : <EOL> super ( IdleTimer , self ) . __init__ ( parent ) <EOL> if not self . supported ( ) : <EOL> raise OSError ( "<STR_LIT>" ) <EOL> self . _idleSeconds = idleSeconds <EOL> self . _finish = False <EOL> self . _mutex = QtCore . QMutex ( ) <EOL> self . _tracker = pxss . IdleTracker ( idle_threshold = idleSeconds * <NUM_LIT:1000> ) <EOL> @ staticmethod <EOL> def supported ( ) : <EOL> supported = False <EOL> for lib in [ '<STR_LIT>' , '<STR_LIT>' ] : <EOL> try : <EOL> if ctypes . CDLL ( lib ) : <EOL> supported = True <EOL> break <EOL> except OSError : <EOL> pass <EOL> return supported <EOL> def stop ( self ) : <EOL> self . _mutex . lock ( ) <EOL> self . _finish = True <EOL> self . _mutex . unlock ( ) <EOL> def run ( self ) : <EOL> isIdle = False <EOL> while not self . _finish : <EOL> ( state , nextCheck , idle ) = self . _tracker . check_idle ( ) <EOL> if state == '<STR_LIT>' and not isIdle and idle >= ( self . _idleSeconds * <NUM_LIT:1000> ) : <EOL> self . emit ( QtCore . SIGNAL ( "<STR_LIT>" ) ) <EOL> elif state is not None and isIdle : <EOL> self . emit ( QtCore . SIGNAL ( '<STR_LIT>' ) ) <EOL> if state is not None : <EOL> isIdle = ( state == '<STR_LIT>' ) <EOL> self . usleep ( nextCheck * <NUM_LIT:1000> ) <EOL> class RowPushButton ( QtGui . QPushButton ) : <EOL> def __init__ ( self , row , text , parent = None ) : <EOL> super ( RowPushButton , self ) . __init__ ( parent ) <EOL> self . _row = row <EOL> self . setIcon ( self . style ( ) . standardIcon ( self . style ( ) . SP_TrashIcon ) ) <EOL> self . setToolTip ( text ) <EOL> self . connect ( self , QtCore . SIGNAL ( "<STR_LIT>" ) , self . _clicked ) <EOL> def _clicked ( self ) : <EOL> self . emit ( QtCore . SIGNAL ( "<STR_LIT>" ) , self . _row ) <EOL> class ClickableQLabel ( QtGui . QLabel ) : <EOL> def __init__ ( self , text = None , parent = None , flags = QtCore . Qt . WindowFlags ( ) ) : <EOL> if text : <EOL> super ( ClickableQLabel , self ) . __init__ ( text , parent , flags ) <EOL> else : <EOL> super ( ClickableQLabel , self ) . __init__ ( parent , flags ) <EOL> self . _setupUI ( ) <EOL> def mouseReleaseEvent ( self , event ) : <EOL> self . emit ( QtCore . SIGNAL ( "<STR_LIT>" ) ) <EOL> def _setupUI ( self ) : <EOL> self . setCursor ( QtCore . Qt . PointingHandCursor ) <EOL> class Suggester ( QtCore . QObject ) : <EOL> def __init__ ( self , editor ) : <EOL> super ( Suggester , self ) . __init__ ( ) <EOL> self . _editor = editor <EOL> self . _room = None <EOL> def setRoom ( self , room ) : <EOL> self . _room = room <EOL> def suggest ( self ) : <EOL> pattern = QtCore . QRegExp ( '<STR_LIT>' ) <EOL> cursor = self . _editor . textCursor ( ) <EOL> block = cursor . block ( ) <EOL> text = block . text ( ) <EOL> if not self . _room or not self . _room . users or not text or cursor . hasSelection ( ) : <EOL> return False <EOL> blockText = QtCore . QString ( text [ : cursor . position ( ) - block . position ( ) ] ) <EOL> matchPosition = blockText . indexOf ( pattern ) <EOL> if matchPosition < <NUM_LIT:0> : <EOL> return False <EOL> word = blockText [ matchPosition : ] <EOL> if word . trimmed ( ) . isEmpty ( ) : <EOL> return False <EOL> matchingUserNames = [ ] <EOL> for user in self . _room . users : <EOL> if QtCore . QString ( user [ "<STR_LIT:name>" ] ) . startsWith ( word , QtCore . Qt . CaseInsensitive ) : <EOL> matchingUserNames . append ( user [ "<STR_LIT:name>" ] ) <EOL> if len ( matchingUserNames ) == <NUM_LIT:1> : <EOL> self . _replace ( cursor , word , matchingUserNames [ <NUM_LIT:0> ] + ( "<STR_LIT>" if matchPosition == <NUM_LIT:0> else "<STR_LIT:U+0020>" ) ) <EOL> else : <EOL> menu = QtGui . QMenu ( '<STR_LIT>' , self . _editor ) <EOL> for userName in matchingUserNames : <EOL> action = QtGui . QAction ( userName , menu ) <EOL> action . setData ( ( cursor , word , userName , matchPosition ) ) <EOL> self . connect ( action , QtCore . SIGNAL ( "<STR_LIT>" ) , self . _userSelected ) <EOL> menu . addAction ( action ) <EOL> menu . popup ( self . _editor . mapToGlobal ( self . _editor . cursorRect ( ) . center ( ) ) ) <EOL> def _userSelected ( self ) : <EOL> action = self . sender ( ) <EOL> cursor , word , userName , matchPosition = action . data ( ) . toPyObject ( ) <EOL> self . _replace ( cursor , word , userName + ( "<STR_LIT>" if matchPosition == <NUM_LIT:0> else "<STR_LIT:U+0020>" ) ) <EOL> def _replace ( self , cursor , word , replacement ) : <EOL> cursor . beginEditBlock ( ) <EOL> for i in range ( len ( word ) ) : <EOL> cursor . deletePreviousChar ( ) <EOL> cursor . insertText ( replacement ) <EOL> cursor . endEditBlock ( ) <EOL> class EditorKeyPressEventFilter ( QtCore . QObject ) : <EOL> def __init__ ( self , mainFrame , editor ) : <EOL> super ( EditorKeyPressEventFilter , self ) . __init__ ( mainFrame ) <EOL> self . _mainFrame = mainFrame <EOL> self . _editor = editor <EOL> self . _suggester = Suggester ( self . _editor ) <EOL> def eventFilter ( self , widget , event ) : <EOL> if event . type ( ) == QtCore . QEvent . KeyPress : <EOL> key = event . key ( ) <EOL> if key == QtCore . Qt . Key_Tab : <EOL> self . _suggester . setRoom ( self . _mainFrame . getCurrentRoom ( ) ) <EOL> if self . _suggester . suggest ( ) != False : <EOL> return True <EOL> elif key in [ QtCore . Qt . Key_Enter , QtCore . Qt . Key_Return ] : <EOL> if event . modifiers ( ) & QtCore . Qt . ShiftModifier : <EOL> return False <EOL> self . _mainFrame . speak ( ) <EOL> return True <EOL> return False <EOL> class TabWidgetFocusEventFilter ( QtCore . QObject ) : <EOL> def __init__ ( self , mainFrame ) : <EOL> super ( TabWidgetFocusEventFilter , self ) . __init__ ( mainFrame ) <EOL> self . _mainFrame = mainFrame <EOL> def eventFilter ( self , widget , event ) : <EOL> if event . type ( ) in [ QtCore . QEvent . FocusIn , QtCore . QEvent . WindowActivate ] : <EOL> self . emit ( QtCore . SIGNAL ( "<STR_LIT>" ) ) <EOL> return False </s>
