Example #1
0
class MainWindow(KXmlGuiWindow):
    CHOOSER_PLUGINS = [
        # TODO reenable
        (radicalpage.RadicalPage, ki18n('&Radicals')),
        (componentpage.ComponentPage, ki18n('&Components')),
        (handwritingpage.HandwritingPage, ki18n('Hand&writing')),
        (vocabularypage.VocabularyPage, ki18n('&Vocabulary')),
        ]
    """Plugins loaded into the side panel."""

    def __init__(self):
        QMainWindow.__init__(self)

        self.miniMode = False
        self.initialised = False

        # set i18n language for libeclectus
        setTranslationLanguage(unicode(KGlobal.locale().language()))

        # start rendering thread
        self.renderThread = renderthread.SQLRenderThread(g_app)
        self.connect(g_app, SIGNAL("aboutToQuit()"),
            self.renderThread.quit)
        self.renderThread.start()

        self.connect(self.renderThread, SIGNAL("queueEmpty"), self.queueEmpty)
        self.connect(self.renderThread, SIGNAL("jobEnqueued"), self.jobEnqueued)
        self.connect(self.renderThread, SIGNAL("jobErrorneous"),
            lambda jobId, classObject, method, args, param, e, stacktrace: \
                showDebug(stacktrace.decode('utf8')))

        self.updateDialog = update.UpdateDialog(self, self.renderThread)
        #self.updateDialog = None # set to None to disable updating
        if self.updateDialog:
            self.connect(self.updateDialog, SIGNAL("databaseChanged()"),
                lambda: self.emit(SIGNAL("databaseChanged()")))

        # set up UI
        self.setupUi()
        self.setupActions()

        # finally build gui
        xmlFile = os.path.join(os.getcwd(), 'eclectusqt', 'eclectusui.rc')
        if os.path.exists(xmlFile):
            self.setupGUI(KXmlGuiWindow.StandardWindowOption(
                KXmlGuiWindow.Default ^ KXmlGuiWindow.StatusBar), xmlFile)
        else:
            self.setupGUI(KXmlGuiWindow.StandardWindowOption(
                KXmlGuiWindow.Default ^ KXmlGuiWindow.StatusBar))

        self.restoreWindowState()

        self.setCentralWidget(self.splitterFrame)
        self.splitterFrame.setVisible(True)

        self.initialised = True

        if (GeneralConfig.readEntry("Show installer on startup", 'True')
            == 'True') and self.updateAction:
            self.updateAction.trigger()

    def setupUi(self):
        self.setWindowIcon(QIcon(util.getIcon('eclectus.png')))

        self.splitterFrame = QtGui.QSplitter(self)
        self.splitterFrame.setOrientation(QtCore.Qt.Horizontal)
        self.characterChooser = QtGui.QToolBox(self.splitterFrame)
        self.characterChooser.setFrameShape(QtGui.QFrame.StyledPanel)

        self.dictionaryPage = dictionarypage.DictionaryPage(self,
            self.renderThread, PluginConfig)
        self.connect(self.dictionaryPage,
            SIGNAL('pageChanged(const QString &)'), self.slotPageChanged)
        # forward settingsChanged
        self.connect(self.dictionaryPage, SIGNAL("settingsChanged()"),
            lambda: self.emit(SIGNAL("settingsChanged()")))
        # TODO make this modular
        self.connect(self.dictionaryPage,
            SIGNAL("vocabularyAdded(const QString &, const QString &, const QString &, const QString &)"),
            self.slotVocabularyAdded)
        self.connect(self.dictionaryPage, SIGNAL("modeChanged(bool)"),
            self.slotMiniMode)

        self.splitterFrame.addWidget(self.characterChooser)
        self.splitterFrame.addWidget(self.dictionaryPage)

        # load sidebar plugins
        self.plugins = []
        self.vocabularyPlugin = None
        for classObj, heading in self.CHOOSER_PLUGINS:
            page = classObj(self, self.renderThread, PluginConfig)
            if not self.vocabularyPlugin \
                and isinstance(page, vocabularypage.VocabularyPage):
                self.vocabularyPlugin = len(self.plugins)

            self.characterChooser.addItem(page, heading.toString())
            self.connect(page, SIGNAL('inputReceived(const QString &)'),
                self.dictionaryPage.load)

            self.plugins.append(page)

        self.splitterFrame.setVisible(False)
        self.setCentralWidget(QLabel(i18n('Installing basic tables...')))

    def setupActions(self):
        """Sets up all actions (signal/slot combinations)."""
        # standard action
        KStandardAction.quit(g_app.quit, self.actionCollection())

        # dictionary actions
        self.dictionaryPage.registerGlobalActions(self.actionCollection())
        # update dictionaries
        if self.updateDialog:
            self.updateAction = self.updateDialog.updateAction(
                self.actionCollection())
            # optimise database
            self.updateDialog.optimiseAction(self.actionCollection())
        else:
            self.updateAction = None

        # search bar
        self.characterCombo = KHistoryComboBox()
        self.characterCombo.setSizePolicy(QSizePolicy.Expanding,
            QSizePolicy.Fixed)
        font = QFont()
        font.setPointSize(13)
        self.characterCombo.setFont(font)
        self.characterCombo.setObjectName("characterCombo")
        self.connect(self.characterCombo, SIGNAL("activated(const QString &)"),
            self.slotCharacterComboActivated)

        comboAction = KAction(self)
        comboAction.setText(i18n("Search bar"))
        comboAction.setShortcut(Qt.Key_F6)
        self.connect(comboAction, SIGNAL("triggered()"),
            self.slotSearchComboActivated)
        comboAction.setDefaultWidget(self.characterCombo)
        comboAction.setWhatsThis(
            i18n("<html>Search bar<br/><br/>Enter character of search string</html>"))
        self.actionCollection().addAction("searchbar", comboAction)

        goUrl = self.actionCollection().addAction("go_search")
        goUrl.setIcon(KIcon("go-jump-locationbar"))
        goUrl.setText(i18n("Go"))
        self.connect(goUrl, SIGNAL("triggered()"),
            lambda: self.slotCharacterComboActivated(
                self.characterCombo.currentText()))
        goUrl.setWhatsThis(
            i18n("<html>Go<br /><br />Searches for the string given in the search bar.</html>"))

        # clear search bar action
        clearLocationAction = KAction(KIcon("edit-clear-locationbar-ltr"),
            i18n("Clear &Location Bar"), self)
        clearLocationAction.setShortcut(Qt.CTRL + Qt.Key_L)
        clearLocationAction.setWhatsThis(
            i18n("Clears the location bar and places the cursor inside"))
        self.actionCollection().addAction("clearlocationbar",
            clearLocationAction)
        self.connect(clearLocationAction, SIGNAL("triggered(bool)"),
            self.characterCombo.clearEditText)
        self.connect(clearLocationAction, SIGNAL("triggered(bool)"),
            self.characterCombo.setFocus)

        # show/hide character page
        self.toggleToolboxAction = KToggleAction(KIcon("view-sidetree"),
            i18n("Show Character Toolbox"), self)
        self.toggleToolboxAction.setShortcut(Qt.Key_F9)
        self.toggleToolboxAction.setWhatsThis(
            i18n("Shows and Hides the character choosing toolbox"))
        self.actionCollection().addAction("showtoolbox",
            self.toggleToolboxAction)
        self.connect(self.toggleToolboxAction, SIGNAL("triggered(bool)"),
            self.slotToggleToolbox)

        # auto-lookup clipboard
        self.autoLookupAction = KToggleAction(i18n("&Auto-Lookup"), self)
        self.autoLookupAction.setToolTip(
            i18n("Automatically look up text selected by the mouse cursor."))
        self.autoLookupAction.setWhatsThis(
            i18n("Automatically look up text selected by the mouse cursor."))
        self.actionCollection().addAction("autolookup", self.autoLookupAction)
        self.connect(self.autoLookupAction, SIGNAL("triggered(bool)"),
            self.setAutoLookup)
        self.autoLookupAction.setIcon(
            QIcon(util.getIcon('auto-lookup-selection.png')))

        self.connect(QApplication.clipboard(), SIGNAL("selectionChanged()"),
            self.slotSelectionChanged)

    def restoreWindowState(self):
        # GUI settings
        history = util.readConfigString(GeneralConfig, "Url History", '')\
            .split(',')
        self.characterCombo.insertItems(history)
        self.historyLength = util.readConfigInt(GeneralConfig, "History Length",
            20)
        self.autoLookup = util.readConfigString(GeneralConfig,
            "Auto-Lookup clipboard", str(False)) != "False"
        self.autoLookupAction.setChecked(self.autoLookup)
        self.onlyAutoLookupCJKCharacters = util.readConfigString(GeneralConfig,
            "Auto-Lookup only Chinese characters", str(False)) != "False"

        self.splitterFrame.restoreState(QByteArray.fromBase64(
            str(util.readConfigString(GeneralConfig, "Splitter", ""))))
        self.splitterSizes = [int(i) for i \
            in util.readConfigString(GeneralConfig, "Splitter sizes",
                "220,426").split(',')]

        self.toolbarOriginalState = QByteArray.fromBase64(
            str(util.readConfigString(GeneralConfig, "Toolbar original state",
                "")))
        self.restoreState(self.toolbarOriginalState)
        self.menuBar().setVisible(True)

        self.characterChooser.setCurrentIndex(util.readConfigInt(GeneralConfig,
            "Toolbox current", 0))

        visible = GeneralConfig.readEntry("Toolbox visibile", str(True))
        if visible == "False":
            self.characterChooserOriginalVisibility = False
        else:
            self.splitterFrame.setSizes(self.splitterSizes)
            self.characterChooserOriginalVisibility = True
        self.characterChooser.setVisible(
            self.characterChooserOriginalVisibility)
        self.toggleToolboxAction.setChecked(
            self.characterChooserOriginalVisibility)

        w = util.readConfigInt(GeneralConfig, "Width", 640)
        h = util.readConfigInt(GeneralConfig, "Height", 420)
        self.defaultWindowSize = QSize(w, h)
        x = util.readConfigInt(GeneralConfig, "LastX", 0)
        y = util.readConfigInt(GeneralConfig, "LastY", 0)

        mini_w = util.readConfigInt(GeneralConfig, "Mini-mode Width", 400)
        mini_h = util.readConfigInt(GeneralConfig, "Mini-mode Height", 200)
        self.miniModeWindowSize = QSize(mini_w, mini_h)

        self.setGeometry(x, y, w, h)

    def queryExit(self):
        """
        save config data before exiting
        """
        self.emit(SIGNAL("writeSettings()"))

        if self.miniMode:
            self.miniModeWindowSize = self.size()
        else:
            self.defaultWindowSize = self.size()

        GeneralConfig.writeEntry("Width", str(self.defaultWindowSize.width()))
        GeneralConfig.writeEntry("Height", str(self.defaultWindowSize.height()))
        GeneralConfig.writeEntry("LastX", str(self.x()))
        GeneralConfig.writeEntry("LastY", str(self.y()))
        GeneralConfig.writeEntry("Mini-mode Width",
            str(self.miniModeWindowSize.width()))
        GeneralConfig.writeEntry("Mini-mode Height",
            str(self.miniModeWindowSize.height()))

        GeneralConfig.writeEntry("Show installer on startup", 'False')
        GeneralConfig.writeEntry("Url History",
            self.characterCombo.historyItems()[:self.historyLength])
        GeneralConfig.writeEntry("Splitter",
            QByteArray.toBase64(self.splitterFrame.saveState()))

        GeneralConfig.writeEntry("Auto-Lookup clipboard", str(self.autoLookup))
        GeneralConfig.writeEntry("Auto-Lookup only Chinese characters",
            str(self.onlyAutoLookupCJKCharacters))

        # toolbox
        if self.characterChooser.isVisible():
            self.splitterSizes = self.splitterFrame.sizes()
        GeneralConfig.writeEntry("Splitter sizes", ",".join(
            [str(i) for i in self.splitterSizes]))

        if not self.miniMode:
            self.toolbarOriginalState = self.saveState(0)
        GeneralConfig.writeEntry("Toolbar original state",
            QByteArray.toBase64(self.toolbarOriginalState))

        GeneralConfig.writeEntry("Toolbox current",
            str(self.characterChooser.currentIndex()))
        GeneralConfig.writeEntry("Toolbox visibile",
            str(self.characterChooserOriginalVisibility))

        return True

    def settings(self):
        return self.dictionaryPage.settings()

    def slotToggleToolbox(self, show):
        if not self.miniMode:
            self.showToolbox(show)

            self.characterChooserOriginalVisibility = show

    def showToolbox(self, show):
        # save / restore size as hiding makes Qt forget
        if self.characterChooser.isVisible():
            self.splitterSizes = self.splitterFrame.sizes()
        else:
            self.splitterFrame.setSizes(self.splitterSizes)

        self.characterChooser.setVisible(show)

    def slotMiniMode(self, miniMode):
        self.miniMode = miniMode

        if not self.miniMode:
            # restore original state if given
            if self.toolbarOriginalState:
                self.restoreState(self.toolbarOriginalState, 0)
            self.menuBar().setVisible(True)

            self.showToolbox(self.characterChooserOriginalVisibility)

            self.miniModeWindowSize = self.size()
            self.resize(self.defaultWindowSize)
        else:
            # save original state of toolbars
            self.toolbarOriginalState = self.saveState(0)
            for toolbar in self.toolBars():
                toolbar.setVisible(False)
            self.menuBar().setVisible(False)

            self.characterChooserOriginalVisibility \
                = self.characterChooser.isVisible()
            self.showToolbox(False)

            self.defaultWindowSize = self.size()
            self.resize(self.miniModeWindowSize)

            # tell user what to do
            # TODO renable
            #miniModeShortcut = unicode(i18n(
                #self.miniModeAction.shortcut().toString()))
            #text = unicode(i18n("Mini-mode hides your menubar and toolbars. Press %1 again to get back to normal mode.", miniModeShortcut))
            #lookupShortcut = self.lookupClipboardAction.globalShortcut()\
                #.toString(QtGui.QKeySequence.NativeText)
            #if lookupShortcut:
                #text = text + "\n\n" \
                    #+ unicode(i18n("You may look up entries by selecting a word and pressing %1. Alternatively you can turn on auto-lookup or paste from the clipboard by pressing the middle mouse button.",
                    #i18n(lookupShortcut)))

            #KMessageBox.information(self, text, i18n("Mini-mode"),
                #"show_mini-mode_notice")

    def slotCharacterComboActivated(self, inputString):
        self.characterCombo.addToHistory(inputString)
        self.dictionaryPage.load(inputString)
        self.dictionaryPage.setFocus()

    def slotSearchComboActivated(self):
        self.characterCombo.setFocus()
        self.characterCombo.lineEdit().selectAll()

    def setAutoLookup(self, selected):
        self.autoLookup = selected

    def slotSelectionChanged(self):
        if self.autoLookup:
            # don't auto lookup when user is editing one of our edit widgets
            focusWidget = QApplication.focusWidget()
            if focusWidget:
                for editWidgetCls in [kdeui.KHistoryComboBox, kdeui.KLineEdit]:
                    if isinstance(focusWidget, editWidgetCls):
                        return

            clipboardText = unicode(QApplication.clipboard().text(
                QClipboard.Selection).simplified()).strip()
            if not clipboardText or len(clipboardText) >= 20:
                return
            if (self.onlyAutoLookupCJKCharacters and
                not MainWindow.hasCJKCharacter(clipboardText)):
                    return

            self.dictionaryPage.load(clipboardText)
            # make window flash in taskbar
            self.activateWindow()

    @staticmethod
    def hasCJKCharacter(string):
        """
        Simple function for telling if a Chinese character or other CJK script
        is present.
        """
        for char in string:
            if getCJKScriptClass(char) != None:
                return True
        return False

    def slotPageChanged(self, pageName):
        # dictionary page changed
        self.emit(SIGNAL("pageRequested(const QString &)"), pageName)

        # Temporarily hide default internal pageTypes
        if unicode(pageName).count(':'):
            pageType, page = unicode(pageName).split(':')
        if pageType in ['character', 'word']:
            pageName = page
        self.characterCombo.setEditText(pageName) # TODO mask page type

    def slotVocabularyAdded(self, headword, reading, translation, audio):
        self.emit(SIGNAL("vocabularyAdded(const QString &, const QString &, const QString &, const QString &)"),
            headword, reading, translation, audio)
        if self.vocabularyPlugin != None:
            self.characterChooser.setCurrentIndex(self.vocabularyPlugin)

    def queueEmpty(self):
        QApplication.restoreOverrideCursor()

    def jobEnqueued(self, jobId):
        if not QApplication.overrideCursor():
            QApplication.setOverrideCursor(QCursor(Qt.BusyCursor))
Example #2
0
class MainWindow(KMainWindow, Ui_MainWindow, MjpegStreamingConsumerInterface):
    def __init__(self, args, parent=None):
        self.args = args
        #super(MainWindow, self).__init__()
        #PsyQtClientBase.__init__(self)
        KMainWindow.__init__(self, parent)
        self.is_streaming = False

        self.live_center_action = None
        self.preview_center_action = None
        self.live_size_action = None
        self.preview_font_action = None
        self.live_font_action = None
        self.preview_size_action = None
        self.default_size = 28
        self.default_align_text = "format_align_center"
        self.preview_actions = list()
        self.live_actions = list()
        self.current = 0
        self.model = TextModel(self)
        self.animation = TextAnimation(self)
        self.db_dirty = False
        self.is_animate = False
        self.fade_animation = None
        self.dialog = None
        self.current_object = None
        self.current_index = -1

        self.is_auto_publish = False

        self.setupUi(self)
        self.win_id = self.live_text.winId()

        self.fps = 12.5
        self.http_server = MjpegStreamingServer(
            (args.http_host, args.http_port), self, self.fps)

        self.live_text.setLineWrapMode(
            QtGui.QTextEdit.LineWrapMode(QtGui.QTextEdit.FixedPixelWidth))
        self.live_text.setLineWrapColumnOrWidth(768)

        self.font = QtGui.QFont("monospace", self.default_size)
        self.font.setStyleHint(QtGui.QFont.TypeWriter)

        self.previous_action = None
        self.next_action = None
        self.publish_action = None
        self.auto_publish_action = None
        self.save_live_action = None
        self.save_preview_action = None
        self.save_action = None
        self.dialog_widget = None
        self.action_collection = None
        self.streaming_action = None
        self.text_combo = None
        self.clear_live_action = None
        self.clear_preview_action = None
        self.toolbar = None
        self.typer_animation_action = None
        self.text_editor_action = None

        self.preview_text.setFont(self.font)
        self.preview_text.setRichTextSupport(
            KRichTextWidget.RichTextSupport(0xffffffff))
        self.preview_editor_collection = KActionCollection(self)
        self.preview_text.createActions(self.preview_editor_collection)

        self.live_text.setRichTextSupport(
            KRichTextWidget.RichTextSupport(0xffffffff))
        self.live_text.setFont(self.font)
        self.live_editor_collection = KActionCollection(self)
        self.live_text.createActions(self.live_editor_collection)
        self.filter_editor_actions()
        self.create_toolbar()
        self.slot_load()

        qtapp.focusChanged.connect(self.focusChanged)
        self.start_streaming()

        self.show()
        timer = QtCore.QTimer()
        timer.start(2000)
        timer.timeout.connect(lambda: None)

    def pubdir(self):
        return os.path.dirname(os.path.abspath(__file__))

    def getPreviewCoords(self):
        public_rect = self.preview_text.geometry()
        global_rect = QtCore.QRect(self.mapToGlobal(public_rect.topLeft()),
                                   self.mapToGlobal(public_rect.bottomRight()))
        return global_rect.x(), global_rect.y()

    def render_image(self):
        public_rect = self.live_text_rect()
        #global_rect = QtCore.QRect(self.mapToGlobal(public_rect.topLeft()), self.mapToGlobal(public_rect.bottomRight()))
        pixmap = QPixmap.grabWindow(self.win_id,
                                    public_rect.x() + 1,
                                    public_rect.y() + 1, 768, 576)
        buf = QBuffer()
        buf.open(QIODevice.WriteOnly)
        pixmap.save(buf, "JPG", 75)
        return buf.data()

    def filter_editor_actions(self):
        disabled_action_names = [
            "action_to_plain_text", "format_painter", "direction_ltr",
            "direction_rtl", "format_font_family",
            "format_text_background_color", "format_list_style",
            "format_list_indent_more", "format_list_indent_less",
            "format_text_bold", "format_text_underline",
            "format_text_strikeout", "format_text_italic",
            "format_align_right", "manage_link", "format_text_subscript",
            "format_text_superscript", "insert_horizontal_rule"
        ]

        for action in self.live_editor_collection.actions():
            text = str(action.objectName())
            if text in disabled_action_names:
                action.setVisible(False)

            if text == self.default_align_text:
                self.live_center_action = action
            elif text == "format_font_size":
                self.live_size_action = action
            elif text == "format_font_family":
                self.live_font_action = action

        for action in self.preview_editor_collection.actions():
            text = str(action.objectName())
            if text in disabled_action_names:
                action.setVisible(False)

            if text == self.default_align_text:
                self.preview_center_action = action
            elif text == "format_font_size":
                self.preview_size_action = action
            elif text == "format_font_family":
                self.preview_font_action = action

        self.slot_set_preview_defaults()
        self.slot_set_live_defaults()

    def create_toolbar(self):

        self.toolbar = KToolBar(self, True, True)
        self.toolbar.setIconDimensions(16)
        self.toolbar.setAllowedAreas(QtCore.Qt.BottomToolBarArea)
        self.toolbar.setMovable(False)
        self.toolbar.setFloatable(False)
        self.toolbar.setToolButtonStyle(QtCore.Qt.ToolButtonTextUnderIcon)
        self.addToolBar(QtCore.Qt.BottomToolBarArea, self.toolbar)

        self.toolbar.show()
        self.action_collection = KActionCollection(self)
        self.action_collection.addAssociatedWidget(self.toolbar)

        self.clear_live_action = self.action_collection.addAction(
            "clear_live_action")
        icon = QtGui.QIcon(":texter/images/edit-clear.png")
        self.clear_live_action.setIcon(icon)
        self.clear_live_action.setIconText("clear live")
        self.clear_live_action.setShortcut(
            KShortcut(QtGui.QKeySequence(QtCore.Qt.ALT + QtCore.Qt.Key_Q)),
            KAction.ShortcutTypes(KAction.ActiveShortcut
                                  | KAction.DefaultShortcut))

        self.save_live_action = self.action_collection.addAction(
            "save_live_action")
        icon = QtGui.QIcon(":texter/images/document-new.png")
        self.save_live_action.setIcon(icon)
        self.save_live_action.setIconText("save live")
        self.save_live_action.setShortcut(
            KShortcut(QtGui.QKeySequence(QtCore.Qt.ALT + QtCore.Qt.Key_W)),
            KAction.ShortcutTypes(KAction.ActiveShortcut
                                  | KAction.DefaultShortcut))

        self.clear_preview_action = self.action_collection.addAction(
            "clear_preview_action")
        icon = QtGui.QIcon(":texter/images/edit-clear.png")
        self.clear_preview_action.setIcon(icon)
        self.clear_preview_action.setIconText("clear preview")
        self.clear_preview_action.setShortcut(
            KShortcut(QtGui.QKeySequence(QtCore.Qt.ALT + QtCore.Qt.Key_A)),
            KAction.ShortcutTypes(KAction.ActiveShortcut
                                  | KAction.DefaultShortcut))

        self.save_preview_action = self.action_collection.addAction(
            "save_preview_action")
        icon = QtGui.QIcon(":texter/images/document-new.png")
        self.save_preview_action.setIcon(icon)
        self.save_preview_action.setIconText("save preview")
        self.save_preview_action.setShortcut(
            KShortcut(QtGui.QKeySequence(QtCore.Qt.ALT + QtCore.Qt.Key_S)),
            KAction.ShortcutTypes(KAction.ActiveShortcut
                                  | KAction.DefaultShortcut))

        self.publish_action = self.action_collection.addAction(
            "publish_action")
        icon = QtGui.QIcon(":texter/images/edit-copy.png")
        self.publish_action.setIcon(icon)
        self.publish_action.setIconText("publish")
        self.publish_action.setShortcutConfigurable(True)
        self.publish_action.setShortcut(
            KShortcut(QtGui.QKeySequence(QtCore.Qt.ALT +
                                         QtCore.Qt.Key_Return)),
            KAction.ShortcutTypes(KAction.ActiveShortcut
                                  | KAction.DefaultShortcut))

        self.toolbar.insertSeparator(self.publish_action)

        self.auto_publish_action = KToggleAction(self.action_collection)
        self.action_collection.addAction("auto publish",
                                         self.auto_publish_action)
        icon = QtGui.QIcon(":texter/images/view-refresh.png")
        self.auto_publish_action.setIcon(icon)
        self.auto_publish_action.setObjectName("auto_publish_action")
        self.auto_publish_action.setIconText("auto publish")
        self.auto_publish_action.setShortcut(
            KShortcut(QtGui.QKeySequence(QtCore.Qt.ALT + QtCore.Qt.Key_P)),
            KAction.ShortcutTypes(KAction.ActiveShortcut
                                  | KAction.DefaultShortcut))

        self.typer_animation_action = KToggleAction(self.action_collection)
        icon = QtGui.QIcon(":texter/images/media-playback-stop.png")
        self.typer_animation_action.setIcon(icon)
        self.typer_animation_action.setIconText("animate")
        self.typer_animation_action.setObjectName("typer_animation_action")
        self.typer_animation_action.setShortcut(
            KShortcut(QtGui.QKeySequence(QtCore.Qt.ALT + QtCore.Qt.Key_M)),
            KAction.ShortcutTypes(KAction.ActiveShortcut
                                  | KAction.DefaultShortcut))
        self.action_collection.addAction("typer_animation_action",
                                         self.typer_animation_action)

        self.text_editor_action = self.action_collection.addAction(
            "text_editor_action")
        icon = QtGui.QIcon(":texter/images/document-open-data.png")
        self.text_editor_action.setIcon(icon)
        self.text_editor_action.setIconText("edit")
        self.text_editor_action.setShortcut(
            KShortcut(QtGui.QKeySequence(QtCore.Qt.CTRL + QtCore.Qt.Key_O)),
            KAction.ShortcutTypes(KAction.ActiveShortcut
                                  | KAction.DefaultShortcut))

        self.toolbar.insertSeparator(self.text_editor_action)

        self.save_action = self.action_collection.addAction("save_action")
        icon = QtGui.QIcon(":texter/images/document-save.png")
        self.save_action.setIcon(icon)
        self.save_action.setIconText("save")
        self.save_action.setShortcut(
            KShortcut(QtGui.QKeySequence(QtCore.Qt.CTRL + QtCore.Qt.Key_S)),
            KAction.ShortcutTypes(KAction.ActiveShortcut
                                  | KAction.DefaultShortcut))

        self.streaming_action = KToggleAction(self.action_collection)
        icon = QtGui.QIcon(":texter/images/media-record.png")
        self.streaming_action.setIcon(icon)
        self.streaming_action.setIconText("stream")
        self.streaming_action.setObjectName("stream")
        self.streaming_action.setShortcut(
            KShortcut(QtGui.QKeySequence(QtCore.Qt.CTRL + QtCore.Qt.Key_1)),
            KAction.ShortcutTypes(KAction.ActiveShortcut
                                  | KAction.DefaultShortcut))
        self.action_collection.addAction("stream", self.streaming_action)

        spacer = KToolBarSpacerAction(self.action_collection)
        self.action_collection.addAction("1_spacer", spacer)

        self.previous_action = self.action_collection.addAction(
            "previous_action")
        icon = QtGui.QIcon(":texter/images/go-previous-view-page.png")
        self.previous_action.setIcon(icon)
        self.previous_action.setIconText("previous")
        self.previous_action.setShortcut(
            KShortcut(QtGui.QKeySequence(QtCore.Qt.ALT + QtCore.Qt.Key_Left)),
            KAction.ShortcutTypes(KAction.ActiveShortcut
                                  | KAction.DefaultShortcut))

        self.text_combo = KSelectAction(self.action_collection)
        self.text_combo.setEditable(False)
        icon = QtGui.QIcon(":texter/images/document-open-recent.png")
        self.text_combo.setIcon(icon)
        self.text_combo.setIconText("saved texts")
        self.text_combo.setObjectName("text_combo")
        self.action_collection.addAction("saved texts", self.text_combo)

        self.next_action = self.action_collection.addAction("next_action")
        icon = QtGui.QIcon(":texter/images/go-next-view-page.png")
        self.next_action.setIcon(icon)
        self.next_action.setIconText("next")
        self.next_action.setShortcut(
            KShortcut(QtGui.QKeySequence(QtCore.Qt.ALT + QtCore.Qt.Key_Right)),
            KAction.ShortcutTypes(KAction.ActiveShortcut
                                  | KAction.DefaultShortcut))

        self.toolbar.addSeparator()

        self.save_action.triggered.connect(self.slot_save)

        self.publish_action.triggered.connect(self.slot_publish)
        self.clear_live_action.triggered.connect(self.slot_clear_live)
        self.clear_preview_action.triggered.connect(self.slot_clear_preview)
        self.text_combo.triggered[int].connect(self.slot_load_preview_text)
        self.text_editor_action.triggered.connect(self.slot_open_dialog)
        self.save_live_action.triggered.connect(self.slot_save_live_text)
        self.save_preview_action.triggered.connect(self.slot_save_preview_text)
        self.streaming_action.triggered.connect(self.slot_toggle_streaming)
        self.auto_publish_action.toggled.connect(self.slot_auto_publish)
        self.typer_animation_action.toggled.connect(self.slot_toggle_animation)
        self.preview_size_action.triggered[QtGui.QAction].connect(
            self.slot_preview_font_size)
        self.live_size_action.triggered[QtGui.QAction].connect(
            self.slot_live_font_size)

        self.next_action.triggered.connect(self.slot_next_item)
        self.previous_action.triggered.connect(self.slot_previous_item)
        self.streaming_action.setChecked(True)

    def closeEvent(self, event):
        logger.info("closeEvent")
        if self.db_dirty:
            self.dialog = KDialog(self)
            self.dialog.setCaption("4.48 texter - text db not saved")
            label = QtGui.QLabel(
                "The Text database is not saved. Do you want to save before exit?",
                self.dialog)
            self.dialog.setMainWidget(label)
            self.dialog.setButtons(
                KDialog.ButtonCodes(KDialog.Ok | KDialog.Cancel))
            self.dialog.okClicked.connect(self.slot_save)
            self.dialog.exec_()
        event.accept()

    def live_text_rect(self):
        return self.live_text.geometry()

    def stop_streaming(self):
        self.is_streaming = False
        self.http_server.stop()

    def start_streaming(self):
        self.http_server.listen(port=self.args.http_port)
        self.is_streaming = True

    def fill_combo_box(self):
        if self.dialog is not None:
            self.dialog.deleteLater()
            self.dialog = None

        self.text_combo.clear()
        current_row = -1
        for index, list_obj in enumerate(self.model.text_db):
            preview, text = list_obj
            self.text_combo.addAction(preview)
            if list_obj == self.current_object:
                current_row = index

        if current_row == -1:
            current_row = self.current_index
            self.slot_load_preview_text(current_row)
        self.text_combo.setCurrentItem(current_row)

    def focusChanged(self, old, new):
        if new == self.preview_text:
            self.live_editor_collection.clearAssociatedWidgets()
            self.preview_editor_collection.addAssociatedWidget(self.toolbar)
        elif new == self.live_text:
            self.preview_editor_collection.clearAssociatedWidgets()
            self.live_editor_collection.addAssociatedWidget(self.toolbar)

    def slot_auto_publish(self, state):
        self.is_auto_publish = bool(state)

    def slot_toggle_animation(self, state):
        self.is_animate = bool(state)

    def slot_toggle_streaming(self):
        if self.is_streaming:
            self.stop_streaming()
        else:
            self.start_streaming()

    def slot_next_item(self):
        try:
            self.current = (self.text_combo.currentItem() + 1) % len(
                self.model.text_db)
            self.text_combo.setCurrentItem(self.current)
            self.slot_load_preview_text(self.current)
        except ZeroDivisionError:
            pass

    def slot_previous_item(self):
        try:
            self.current = (self.text_combo.currentItem() - 1) % len(
                self.model.text_db)
            self.text_combo.setCurrentItem(self.current)
            self.slot_load_preview_text(self.current)
        except ZeroDivisionError:
            pass

    def slot_publish(self):
        if self.is_animate:
            self.animation.start_animation(self.preview_text, self.live_text,
                                           0)
        else:
            self.live_text.setTextOrHtml(self.preview_text.textOrHtml())

    def slot_live_font_size(self, action):
        self.default_size = self.live_size_action.fontSize()
        self.slot_set_preview_defaults()
        self.slot_set_live_defaults()

    def slot_preview_font_size(self, action):
        self.default_size = self.preview_size_action.fontSize()
        self.slot_set_live_defaults()
        self.slot_set_preview_defaults()

    def slot_toggle_publish(self, state=None):

        if state:
            self.slot_publish()
        else:
            self.slot_clear_live()

    def slot_set_preview_defaults(self):
        self.preview_center_action.setChecked(True)
        self.preview_text.alignCenter()
        self.font.setPointSize(self.default_size)
        self.preview_text.setFontSize(self.default_size)
        self.preview_text.setFont(self.font)
        self.preview_size_action.setFontSize(self.default_size)
        self.preview_text.document().setDefaultFont(self.font)

    def slot_set_live_defaults(self):
        self.live_center_action.setChecked(True)
        self.live_text.alignCenter()
        self.live_text.setFontSize(self.default_size)
        self.live_size_action.setFontSize(self.default_size)
        self.live_text.document().setDefaultFont(self.font)

    def slot_clear_live(self):
        self.live_text.clear()
        self.slot_set_live_defaults()

    def slot_clear_preview(self):
        self.preview_text.clear()
        self.slot_set_preview_defaults()

    def slot_fade(self):
        if self.fade_animation.timer is None:
            self.fade_animation.start_animation()

    def slot_load_preview_text(self, index):
        try:
            preview, text = self.model.text_db[index]
        except IndexError:
            return
        self.preview_text.setTextOrHtml(text)
        if self.is_auto_publish:
            self.slot_publish()

    def slot_save_live_text(self):
        text = self.live_text.toHtml()
        preview = get_preview_text(unicode(self.live_text.toPlainText()))
        if not preview:
            return
        old_item = self.model.text_by_preview(preview)
        if old_item is not None:
            suffix = 1
            while 1:
                tmp_preview = "%s_%d" % (preview, suffix)
                tmp = self.model.text_by_preview(tmp_preview)
                if tmp is None:
                    preview = tmp_preview
                    break
                else:
                    suffix += 1

        self.model.text_db.append([preview, text])
        self.model.modelReset.emit()
        action = self.text_combo.addAction(preview)
        self.text_combo.setCurrentAction(action)
        self.db_dirty = True

    def slot_save_preview_text(self):
        text = self.preview_text.toHtml()
        preview = get_preview_text(unicode(self.preview_text.toPlainText()))

        if not preview:
            return
        old_item = self.model.text_by_preview(preview)
        if old_item is not None:
            ix, old_preview, old_text = old_item
            self.model.text_db[ix][1] = text
        else:
            self.model.text_db.append([preview, text])
            action = self.text_combo.addAction(preview)
            self.model.modelReset.emit()
            self.text_combo.setCurrentAction(action)
        self.db_dirty = True

    def slot_save(self):
        path = os.path.expanduser("~/.texter")
        if not os.path.isdir(path):
            os.mkdir(path)
        try:
            f = open(os.path.join(path, "texter.db"), "w")
        except IOError:
            return
        else:
            cPickle.dump(self.model.text_db, f, cPickle.HIGHEST_PROTOCOL)
        self.db_dirty = False

    def slot_open_dialog(self):
        self.current_index = self.text_combo.currentItem()
        self.current_object = self.model.text_db[self.current_index]
        if self.dialog is not None:
            self.dialog.deleteLater()
            self.dialog = None

        self.dialog = KDialog(self)
        self.dialog.setButtons(KDialog.Close)
        self.dialog_widget = EditDialog(self.dialog)
        self.dialog.setMainWidget(self.dialog_widget)
        pos_x, pos_y = self.getPreviewCoords()
        self.dialog.move(pos_x, self.pos().y())
        self.dialog.exec_()
        self.fill_combo_box()

    def slot_load(self):
        path = os.path.expanduser("~/.texter")
        if not os.path.isdir(path):
            os.mkdir(path)
        try:
            db_file = open(os.path.join(path, "texter.db"))
        except IOError:
            return

        try:
            self.model.text_db = [list(i) for i in cPickle.load(db_file)]
        except ValueError, error:
            logger.exception(error)

        self.fill_combo_box()
        self.text_combo.setCurrentItem(0)
        self.slot_load_preview_text(0)