Ejemplo n.º 1
0
class Example(QMainWindow):
    def __init__(self):
        super().__init__()
        self.text_editor = QPlainTextEdit()
        self.syntax = PythonHighlighter(self.text_editor.document())

        self.init_ui()

    def init_ui(self):

        background_color = QColor()
        background_color.setNamedColor('#282821')

        color_palette = self.text_editor.palette()
        color_palette.setColor(QPalette.Text, Qt.white)
        color_palette.setColor(QPalette.Base, background_color)
        self.text_editor.setPalette(color_palette)

        default_font = self.text_editor.font()
        default_font.setPointSize(9)
        self.text_editor.setFont(default_font)

        self.setWindowTitle('Example')
        self.setCentralWidget(self.text_editor)
        self.setGeometry(500, 500, 500, 500)

        self.show()
Ejemplo n.º 2
0
class Example(QMainWindow):
    def __init__(self):
        super().__init__()
        self.text_editor = QPlainTextEdit()
        self.syntax = PythonHighlighter(self.text_editor.document())

        self.init_ui()

    def init_ui(self):

        background_color = QColor()
        background_color.setNamedColor('#282821')

        color_palette = self.text_editor.palette()
        color_palette.setColor(QPalette.Text, Qt.white)
        color_palette.setColor(QPalette.Base, background_color)
        self.text_editor.setPalette(color_palette)

        default_font = self.text_editor.font()
        default_font.setPointSize(9)
        self.text_editor.setFont(default_font)

        self.setWindowTitle('Example')
        self.setCentralWidget(self.text_editor)
        self.setGeometry(500, 500, 500, 500)

        self.show()
Ejemplo n.º 3
0
class TextLogElement(object):
    def __init__(self,
                 maximum_block_count: int = 1000,
                 font_size_pt: int = 10,
                 font_family: str = "Courier",
                 title: str = "Log") -> None:
        # For nested layouts: (1) create everything, (2) lay out
        self.log_group = StyledQGroupBox(title)
        log_layout_1 = QVBoxLayout()
        log_layout_2 = QHBoxLayout()
        self.log = QPlainTextEdit()
        self.log.setReadOnly(True)
        self.log.setLineWrapMode(QPlainTextEdit.NoWrap)
        self.log.setMaximumBlockCount(maximum_block_count)

        font = self.log.font()
        font.setFamily(font_family)
        font.setPointSize(font_size_pt)

        log_clear_button = QPushButton('Clear log')
        log_clear_button.clicked.connect(self.log.clear)
        log_copy_button = QPushButton('Copy to clipboard')
        log_copy_button.clicked.connect(self.copy_whole_log)
        log_layout_2.addWidget(log_clear_button)
        log_layout_2.addWidget(log_copy_button)
        log_layout_2.addStretch(1)
        log_layout_1.addWidget(self.log)
        log_layout_1.addLayout(log_layout_2)
        self.log_group.setLayout(log_layout_1)

    def get_widget(self) -> QWidget:
        return self.log_group

    def add(self, msg: str) -> None:
        # http://stackoverflow.com/questions/16568451
        # self.log.moveCursor(QTextCursor.End)
        self.log.appendPlainText(msg)
        # ... will append it as a *paragraph*, i.e. no need to add a newline
        # self.scroll_to_end_of_log()

    def copy_whole_log(self) -> None:
        # Ctrl-C will copy the selected parts.
        # log.copy() will copy the selected parts.
        self.log.selectAll()
        self.log.copy()
        self.log.moveCursor(QTextCursor.End)
        self.scroll_to_end_of_log()

    def scroll_to_end_of_log(self) -> None:
        vsb = self.log.verticalScrollBar()
        vsb.setValue(vsb.maximum())
        hsb = self.log.horizontalScrollBar()
        hsb.setValue(0)
Ejemplo n.º 4
0
class TextLogElement(object):
    def __init__(self,
                 maximum_block_count: int = 1000,
                 font_size_pt: int = 10,
                 font_family: str = "Courier",
                 title: str = "Log") -> None:
        # For nested layouts: (1) create everything, (2) lay out
        self.log_group = StyledQGroupBox(title)
        log_layout_1 = QVBoxLayout()
        log_layout_2 = QHBoxLayout()
        self.log = QPlainTextEdit()
        self.log.setReadOnly(True)
        self.log.setLineWrapMode(QPlainTextEdit.NoWrap)
        self.log.setMaximumBlockCount(maximum_block_count)

        font = self.log.font()
        font.setFamily(font_family)
        font.setPointSize(font_size_pt)

        log_clear_button = QPushButton('Clear log')
        log_clear_button.clicked.connect(self.log.clear)
        log_copy_button = QPushButton('Copy to clipboard')
        log_copy_button.clicked.connect(self.copy_whole_log)
        log_layout_2.addWidget(log_clear_button)
        log_layout_2.addWidget(log_copy_button)
        log_layout_2.addStretch(1)
        log_layout_1.addWidget(self.log)
        log_layout_1.addLayout(log_layout_2)
        self.log_group.setLayout(log_layout_1)

    def get_widget(self) -> QWidget:
        return self.log_group

    def add(self, msg: str) -> None:
        # http://stackoverflow.com/questions/16568451
        # self.log.moveCursor(QTextCursor.End)
        self.log.appendPlainText(msg)
        # ... will append it as a *paragraph*, i.e. no need to add a newline
        # self.scroll_to_end_of_log()

    def copy_whole_log(self) -> None:
        # Ctrl-C will copy the selected parts.
        # log.copy() will copy the selected parts.
        self.log.selectAll()
        self.log.copy()
        self.log.moveCursor(QTextCursor.End)
        self.scroll_to_end_of_log()

    def scroll_to_end_of_log(self) -> None:
        vsb = self.log.verticalScrollBar()
        vsb.setValue(vsb.maximum())
        hsb = self.log.horizontalScrollBar()
        hsb.setValue(0)
class SystemLog:
    def __init__(self, display_name, source_name):
        self.display_name = display_name
        self.source_name = source_name  # FIXME: need to handle rotated logs
        self.last_filename = os.path.join(get_home_path(), display_name)
        self.content = ''
        self.edit = QPlainTextEdit()
        self.normal_font = self.edit.font()
        self.monospace_font = QFont('monospace')

        self.edit.setUndoRedoEnabled(False)
        self.edit.setReadOnly(True)
        self.edit.setWordWrapMode(QTextOption.NoWrap)
        self.edit.setPlainText(
            'Click "Refresh" to download {0}.'.format(display_name))

        self.monospace_font.setStyleHint(QFont.TypeWriter)

    def log(self, message, bold=False, pre=False):
        if bold:
            self.edit.appendHtml('<b>{0}</b>'.format(html.escape(message)))
        elif pre:
            self.edit.appendHtml('<pre>{0}</pre>'.format(message))
        else:
            self.edit.appendPlainText(message)

    def reset(self):
        self.content = None

        self.edit.setPlainText('')
        self.edit.setFont(self.normal_font)

    def set_content(self, content):
        self.content = content

        self.edit.setPlainText('')
        self.edit.setFont(self.monospace_font)
        self.edit.setPlainText(content)
Ejemplo n.º 6
0
class Notepad(QMainWindow):
    def __init__(self):
        self.judgeConfigFile()
        self.clipboard = QApplication.clipboard()
        self.lastSearchText = ""
        self.lastReplaceSearchText = ""
        self.reset = False
        self.config = parser.ConfigParser()
        self.config.read(CONFIG_FILE_PATH)

        QMainWindow.__init__(self)
        self.initUI()

    def initUI(self):
        self.setWindowTitle("无标题 - 记事本")

        self.initEditText()

        self.createActions()
        self.createStatusBar()
        self.createMenubars()

        self.readSettings()

        self.text.document().contentsChanged.connect(self.documentWasModified)

        self.setCurrentFile('')

    def initEditText(self):
        self.text = QPlainTextEdit()
        self.text.setContextMenuPolicy(Qt.CustomContextMenu)
        self.text.customContextMenuRequested.connect(self.customContextMenu)
        self.setCentralWidget(self.text)

    def customContextMenu(self):
        menu = QMenu(self)
        menu.addAction(self.undoAction)
        menu.addSeparator()
        menu.addAction(self.cutAction)
        menu.addAction(self.copyAction)
        menu.addAction(self.pasteAction)
        menu.addAction(self.deleteAction)
        menu.addSeparator()
        menu.addAction(self.selectAllAction)
        menu.exec_(QCursor.pos())

        return menu

    def documentWasModified(self):
        self.setWindowModified(self.text.document().isModified())
        if "" != self.text.toPlainText():
            self.findAction.setEnabled(True)
            self.findNextAction.setEnabled(True)
        else:
            self.findAction.setEnabled(False)
            self.findNextAction.setEnabled(False)

    def readSettings(self):
        width = getConfig(self.config, "Display", "width", "1000")
        height = getConfig(self.config, "Display", "height", "600")
        size = QSize(int(width), int(height))

        screen = QDesktopWidget().screenGeometry()
        pos_x = getConfig(self.config, "Display", "x",
                          (screen.width() - 1000) // 2)
        pos_y = getConfig(self.config, "Display", "y",
                          (screen.height() - 600) // 2)
        pos = QPoint(int(pos_x), int(pos_y))

        toolbar = getConfig(self.config, "Display", "toolbar", "True")

        wrapMode = getConfig(self.config, "TextEdit", "wrapmode", "True")

        fontFamile = getConfig(self.config, "TextEdit", "font", "Consolas")
        fontSize = getConfig(self.config, "TextEdit", "size", 14)
        fonts = QFont(fontFamile, int(fontSize))

        if "True" == wrapMode:
            wrapMode = QPlainTextEdit.WidgetWidth
        else:
            wrapMode = QPlainTextEdit.NoWrap

        self.resize(size)
        self.move(pos)
        self.text.setLineWrapMode(wrapMode)
        self.text.setFont(fonts)

    def resetSettings(self):
        writeConfig(self.config, "Display", "width", "1000")
        writeConfig(self.config, "Display", "height", "600")
        screen = QDesktopWidget().screenGeometry()
        writeConfig(self.config, "Display", "x",
                    str((screen.width() - 1000) // 2))
        writeConfig(self.config, "Display", "y",
                    str((screen.height() - 600) // 2))
        writeConfig(self.config, "Display", "toolbar", "True")
        writeConfig(self.config, "TextEdit", "wrapmode", "True")
        writeConfig(self.config, "TextEdit", "font", "Consolas")
        writeConfig(self.config, "TextEdit", "size", "14")

        self.config.write(open(CONFIG_FILE_PATH, "w"))

        QMessageBox.information(self, "记事本", "重置成功,请重启记事本!")
        self.reset = True
        self.close()

    def writeSettings(self):
        writeConfig(self.config, "Display", "height",
                    str(self.size().height()))
        writeConfig(self.config, "Display", "width", str(self.size().width()))
        writeConfig(self.config, "Display", "x", str(self.pos().x()))
        writeConfig(self.config, "Display", "y", str(self.pos().y()))
        writeConfig(
            self.config, "TextEdit", "wrapmode",
            str(self.text.lineWrapMode() == QPlainTextEdit.WidgetWidth))
        writeConfig(self.config, "TextEdit", "font", self.text.font().family())
        writeConfig(self.config, "TextEdit", "size",
                    str(self.text.font().pointSize()))

        self.config.write(open(CONFIG_FILE_PATH, "w"))

    def judgeConfigFile(self):
        if not os.path.exists(CONFIG_FILE_PATH):
            f = open(CONFIG_FILE_PATH, mode="w", encoding="UTF-8")
            f.close()

    def createActions(self):

        self.saveAction = QAction("&保存",
                                  self,
                                  shortcut=QKeySequence.Save,
                                  statusTip="保存文件",
                                  triggered=self.save)

        self.exitAction = QAction("退出",
                                  self,
                                  shortcut="Ctrl+Q",
                                  statusTip="退出程序",
                                  triggered=self.close)

        self.undoAction = QAction("撤销",
                                  self,
                                  shortcut=QKeySequence.Undo,
                                  statusTip="撤销编辑",
                                  triggered=self.text.undo)

        self.cutAction = QAction("剪切",
                                 self,
                                 shortcut=QKeySequence.Cut,
                                 statusTip="剪切选中的文本",
                                 triggered=self.text.cut)

        self.copyAction = QAction("复制",
                                  self,
                                  shortcut=QKeySequence.Copy,
                                  statusTip="复制选中的文本",
                                  triggered=self.text.copy)

        self.pasteAction = QAction("粘贴",
                                   self,
                                   shortcut=QKeySequence.Paste,
                                   statusTip="粘贴剪切板的文本",
                                   triggered=self.text.paste)

        self.clearAction = QAction("清空剪切板",
                                   self,
                                   statusTip="清空剪切板",
                                   triggered=self.clearClipboard)

        self.deleteAction = QAction("删除",
                                    self,
                                    statusTip="删除选中的文本",
                                    triggered=self.delete)

        self.findAction = QAction("查找",
                                  self,
                                  statusTip="查找文本",
                                  triggered=self.findText,
                                  shortcut=QKeySequence.Find)

        self.findNextAction = QAction("查找下一个",
                                      self,
                                      statusTip="查找文本",
                                      triggered=self.findNextText,
                                      shortcut=QKeySequence.FindNext)

        self.replaceAction = QAction("替换",
                                     self,
                                     statusTip="替换文本",
                                     triggered=self.replaceText,
                                     shortcut=QKeySequence.Replace)

        self.selectAllAction = QAction("全选",
                                       self,
                                       shortcut=QKeySequence.SelectAll,
                                       statusTip="全选",
                                       triggered=self.text.selectAll)

        self.autoWrapAction = QAction("自动换行",
                                      self,
                                      statusTip="设置自动换行",
                                      triggered=self.setWrap)

        self.fontAction = QAction("字体",
                                  self,
                                  statusTip="设置字体",
                                  triggered=self.setFont_)

        self.aboutQtAction = QAction("关于Qt",
                                     self,
                                     triggered=QApplication.instance().aboutQt)

        self.undoAction.setEnabled(False)
        self.cutAction.setEnabled(False)
        self.copyAction.setEnabled(False)
        self.deleteAction.setEnabled(False)
        if "" == self.clipboard.text():
            self.pasteAction.setEnabled(False)
            self.clearAction.setEnabled(False)
        if "" == self.text.toPlainText():
            self.findAction.setEnabled(False)
            self.findNextAction.setEnabled(False)

        self.text.undoAvailable.connect(self.undoAction.setEnabled)
        self.text.copyAvailable.connect(self.cutAction.setEnabled)
        self.text.copyAvailable.connect(self.copyAction.setEnabled)
        self.text.copyAvailable.connect(self.deleteAction.setEnabled)

        self.clipboard.dataChanged.connect(self.enabledSomeActionByClipboard)

    def enabledSomeActionByClipboard(self):
        if ("" != self.clipboard.text()):
            self.pasteAction.setEnabled(True)
            self.clearAction.setEnabled(True)

    def clearClipboard(self):
        self.clipboard.clear()
        self.pasteAction.setEnabled(False)
        self.clearAction.setEnabled(False)

    def createStatusBar(self):
        self.statusBar().showMessage("准备就绪")

    def createMenubars(self):
        file = self.menuBar().addMenu("文件")
        file.addAction(self.saveAction)
        file.addSeparator()
        file.addSeparator()
        file.addAction(self.exitAction)

        edit = self.menuBar().addMenu("编辑")
        edit.addAction(self.undoAction)
        edit.addSeparator()
        edit.addAction(self.cutAction)
        edit.addAction(self.copyAction)
        edit.addAction(self.pasteAction)
        edit.addAction(self.clearAction)
        edit.addAction(self.deleteAction)
        edit.addSeparator()
        edit.addAction(self.findAction)
        edit.addAction(self.findNextAction)
        edit.addAction(self.replaceAction)
        edit.addSeparator()
        edit.addAction(self.selectAllAction)

        style = self.menuBar().addMenu("格式")
        style.addAction(self.autoWrapAction)
        style.addAction(self.fontAction)

        help = self.menuBar().addMenu("帮助")
        help.addAction(self.aboutQtAction)

    def maybeSave(self):
        if self.text.document().isModified():
            ret = self.tip()

            if 0 == ret:
                return self.save()

            if 2 == ret:
                return False

        return True

    def openFile(self, fileName):
        file = QFile(fileName)
        if not file.open(QFile.ReadOnly | QFile.Text):
            QMessageBox.warning(
                self, "记事本",
                "文件%s不能被读取:\n%s." % (fileName, file.errorString()))
            return

        inf = QTextStream(file)
        QApplication.setOverrideCursor(Qt.WaitCursor)
        self.text.setPlainText(inf.readAll())
        QApplication.restoreOverrideCursor()

        self.setCurrentFile(fileName)
        self.show()
        self.statusBar().showMessage("文件读取成功", 2000)

    def setCurrentFile(self, fileName):
        self.curFile = fileName
        self.text.document().setModified(False)
        self.setWindowModified(False)

        if self.curFile:
            shownName = self.strippedName(self.curFile)
        else:
            shownName = '未命名.txt'

        self.setWindowTitle("%s[*] - 记事本" % shownName)

    def strippedName(self, fullFileName):
        return QFileInfo(fullFileName).fileName()

    def save(self):
        if self.curFile:
            return self.saveFile(self.curFile)
        else:
            return self.saveAs()

    def saveFile(self, fileName):
        file = QFile(fileName)
        if not file.open(QFile.WriteOnly | QFile.Text):
            QMessageBox.warning(
                self, "记事本",
                "文件%s不能被写入:\n%s." % (fileName, file.errorString()))
            return False

        outf = QTextStream(file)
        QApplication.setOverrideCursor(Qt.WaitCursor)
        outf << self.text.toPlainText()
        QApplication.restoreOverrideCursor()

        self.setCurrentFile(fileName)
        self.statusBar().showMessage("写入文件成功", 2000)
        return True

    def closeEvent(self, event):
        if not self.maybeSave():
            event.ignore()
        else:
            if not self.reset:
                self.writeSettings()
            event.accept()

    def tip(self, title="记事本", content="文件已被修改,是否保存?"):
        alertBox = QMessageBox(self)
        saveButton = alertBox.addButton("保存", QMessageBox.ActionRole)
        unSaveButton = alertBox.addButton("不保存", QMessageBox.ActionRole)
        cancelButton = alertBox.addButton("取消", QMessageBox.ActionRole)

        alertBox.setWindowTitle(title)
        alertBox.setText(content)
        alertBox.exec_()
        button = alertBox.clickedButton()

        if saveButton == button:
            return 0
        elif unSaveButton == button:
            return 1
        elif cancelButton == button:
            return 2
        else:
            return -1

    def delete(self):
        cursor = self.text.textCursor()
        if not cursor.isNull():
            cursor.removeSelectedText()
            self.statusBar().showMessage("删除成功", 2000)

    def findText(self):
        self.displayFindDialog()

    def findNextText(self):
        if "" == self.lastSearchText:
            self.displayFindDialog()
        else:
            self.searchText()

    def displayFindDialog(self):
        self.findDialog = QDialog(self)

        label = QLabel("查找内容:")
        self.lineEdit = QLineEdit()
        self.lineEdit.setText(self.lastSearchText)
        label.setBuddy(self.lineEdit)

        self.findButton = QPushButton("查找下一个")
        self.findButton.setDefault(True)
        self.findButton.clicked.connect(self.searchText)

        buttonBox = QDialogButtonBox(Qt.Vertical)
        buttonBox.addButton(self.findButton, QDialogButtonBox.ActionRole)

        topLeftLayout = QHBoxLayout()
        topLeftLayout.addWidget(label)
        topLeftLayout.addWidget(self.lineEdit)

        leftLayout = QVBoxLayout()
        leftLayout.addLayout(topLeftLayout)

        mainLayout = QGridLayout()
        mainLayout.setSizeConstraint(QLayout.SetFixedSize)
        mainLayout.addLayout(leftLayout, 0, 0)
        mainLayout.addWidget(buttonBox, 0, 1)
        mainLayout.setRowStretch(2, 1)
        self.findDialog.setLayout(mainLayout)

        self.findDialog.setWindowTitle("查找")
        self.findDialog.show()

    def searchText(self):
        cursor = self.text.textCursor()
        findIndex = cursor.anchor()
        text = self.lineEdit.text()
        content = self.text.toPlainText()
        length = len(text)

        self.lastSearchText = text
        index = content.find(text, findIndex)

        if -1 == index:
            errorDialog = QMessageBox(self)
            errorDialog.addButton("取消", QMessageBox.ActionRole)

            errorDialog.setWindowTitle("记事本")
            errorDialog.setText("找不到\"%s\"." % text)
            errorDialog.setIcon(QMessageBox.Critical)
            errorDialog.exec_()
        else:
            start = index

            cursor = self.text.textCursor()
            cursor.clearSelection()
            cursor.movePosition(QTextCursor.Start, QTextCursor.MoveAnchor)
            cursor.movePosition(QTextCursor.Right, QTextCursor.MoveAnchor,
                                start + length)
            cursor.movePosition(QTextCursor.Left, QTextCursor.KeepAnchor,
                                length)
            cursor.selectedText()
            self.text.setTextCursor(cursor)

    def replaceText(self):
        replaceDialog = QDialog(self)

        replaceLabel = QLabel("替换内容:")
        self.replaceText = QLineEdit()
        self.replaceText.setText(self.lastReplaceSearchText)
        replaceLabel.setBuddy(self.replaceText)

        replaceToLabel = QLabel("替换为  :")
        self.replaceToText = QLineEdit()
        replaceToLabel.setBuddy(self.replaceToText)

        findNextButton = QPushButton("查找下一个")
        findNextButton.setDefault(True)
        replaceButton = QPushButton("替换")
        replaceAllButton = QPushButton("全部替换")
        cancelAllButton = QPushButton("取消")

        findNextButton.clicked.connect(lambda: self.replaceOrSearch(False))
        cancelAllButton.clicked.connect(replaceDialog.close)
        replaceButton.clicked.connect(lambda: self.replaceOrSearch(True))
        replaceAllButton.clicked.connect(self.replaceAllText)

        buttonBox = QDialogButtonBox(Qt.Vertical)
        buttonBox.addButton(findNextButton, QDialogButtonBox.ActionRole)
        buttonBox.addButton(replaceButton, QDialogButtonBox.ActionRole)
        buttonBox.addButton(replaceAllButton, QDialogButtonBox.ActionRole)
        buttonBox.addButton(cancelAllButton, QDialogButtonBox.ActionRole)

        topLeftLayout = QHBoxLayout()

        topLeftLayout.addWidget(replaceLabel)
        topLeftLayout.addWidget(self.replaceText)

        topLeftLayout2 = QHBoxLayout()
        topLeftLayout2.addWidget(replaceToLabel)
        topLeftLayout2.addWidget(self.replaceToText)

        leftLayout = QVBoxLayout()
        leftLayout.addLayout(topLeftLayout)
        leftLayout.addLayout(topLeftLayout2)

        mainLayout = QGridLayout()
        mainLayout.setSizeConstraint(QLayout.SetFixedSize)
        mainLayout.addLayout(leftLayout, 0, 0)
        mainLayout.addWidget(buttonBox, 0, 1)
        mainLayout.setRowStretch(2, 1)
        replaceDialog.setLayout(mainLayout)

        replaceDialog.setWindowTitle("替换")
        replaceDialog.show()

    def replaceOrSearch(self, isReplace):
        cursor = self.text.textCursor()
        findIndex = cursor.anchor()
        text = self.replaceText.text()
        content = self.text.toPlainText()
        length = len(text)
        index = content.find(text, findIndex)
        self.lastReplaceSearchText = text
        if -1 == index:
            errorDialog = QMessageBox(self)
            errorDialog.addButton("取消", QMessageBox.ActionRole)

            errorDialog.setWindowTitle("记事本")
            errorDialog.setText("找不到\"%s\"." % text)
            errorDialog.setIcon(QMessageBox.Critical)
            errorDialog.exec_()
        else:
            start = index
            if isReplace:
                toReplaceText = self.replaceToText.text()
                prefix = content[0:start]
                postfix = content[start + length:]
                newText = prefix + toReplaceText + postfix
                self.text.setPlainText(newText)
                length = len(toReplaceText)
                self.text.document().setModified(True)

            cursor = self.text.textCursor()
            cursor.clearSelection()
            cursor.movePosition(QTextCursor.Start, QTextCursor.MoveAnchor)
            cursor.movePosition(QTextCursor.Right, QTextCursor.MoveAnchor,
                                start + length)
            cursor.movePosition(QTextCursor.Left, QTextCursor.KeepAnchor,
                                length)
            cursor.selectedText()
            self.text.setTextCursor(cursor)

    def replaceAllText(self):
        text = self.replaceText.text()
        content = self.text.toPlainText()
        toReplaceText = self.replaceToText.text()
        content = content.replace(text, toReplaceText)
        self.text.setPlainText(content)
        self.text.document().setModified(True)

    def setWrap(self):
        mode = self.text.lineWrapMode()
        if 1 == mode:
            self.text.setLineWrapMode(QPlainTextEdit.NoWrap)
        else:
            self.text.setLineWrapMode(QPlainTextEdit.WidgetWidth)

    def toggleToolBar(self):
        if self.toolBar.isHidden():
            self.toolBar.show()
        else:
            self.toolBar.hide()

    def preferences(self):
        print("")

    def setFont_(self):
        font, ok = QFontDialog.getFont(QFont(self.text.toPlainText()), self)
        if ok:
            self.text.setFont(font)
Ejemplo n.º 7
0
class ParameterDialog(QDialog):
    def __init__(self,
                 file_name='',
                 sep=',',
                 decimal='.',
                 header=True,
                 index=False):
        super().__init__()
        self.setMinimumSize(520, 200)
        self.separator = sep
        self.decimal = decimal
        self.header = header
        self.index = index
        QBtn = QDialogButtonBox.Ok | QDialogButtonBox.Cancel
        self.buttonBox = QDialogButtonBox(QBtn)
        self.buttonBox.accepted.connect(self.validate)
        self.buttonBox.rejected.connect(self.reject)
        self.preview = QPlainTextEdit()
        # set font to monospaced
        font = self.preview.font()
        font.setFamily("Courier New")
        self.preview.setFont(font)

        self.layout = QVBoxLayout()

        groupbox_file = QGroupBox("Path to CSV file:")
        self.layout.addWidget(groupbox_file)
        self.layout_file = QHBoxLayout()
        groupbox_file.setLayout(self.layout_file)

        self.layout_file.addWidget(QLabel("File:"))
        self.filename = QLineEdit()
        self.filename.textChanged.connect(self.onFileNameTextChange)
        self.filename.setText(file_name)
        self.layout_file.addWidget(self.filename)
        self.btn_file = QPushButton("...")
        self.btn_file.setMaximumWidth(25)
        self.btn_file.clicked.connect(self.onBtnFileClicked)
        self.layout_file.addWidget(self.btn_file)

        # separator and decimal group
        self.layout_sepdec = QHBoxLayout()

        # separator (delimiter)
        groupbox_sep = QGroupBox("Separator:")
        self.layout_sepdec.addWidget(groupbox_sep)
        self.layout_sep = QVBoxLayout()
        self.layout_sep.setAlignment(QtCore.Qt.AlignCenter)
        groupbox_sep.setLayout(self.layout_sep)

        self.radio_comma = QRadioButton("Comma")
        self.radio_comma.setChecked(sep == ',')
        self.radio_comma.separator = ","
        self.radio_comma.toggled.connect(self.onClicked)

        self.radio_semicol = QRadioButton("Semicolon")
        self.radio_semicol.setChecked(sep == ';')
        self.radio_semicol.separator = ";"
        self.radio_semicol.toggled.connect(self.onClicked)

        self.radio_tab = QRadioButton("Tab")
        self.radio_tab.setChecked(sep == '\t')
        self.radio_tab.separator = "\t"
        self.radio_tab.toggled.connect(self.onClicked)

        self.layout_sep.addWidget(self.radio_comma)
        self.layout_sep.addWidget(self.radio_semicol)
        self.layout_sep.addWidget(self.radio_tab)

        # decimal point
        groupbox_dp = QGroupBox("Decimal point:")
        self.layout_sepdec.addWidget(groupbox_dp)
        self.layout_dp = QVBoxLayout()
        self.layout_dp.setAlignment(QtCore.Qt.AlignCenter)

        groupbox_dp.setLayout(self.layout_dp)

        self.radio_dp_dot = QRadioButton("Dot")
        self.radio_dp_dot.setChecked(decimal == '.')
        self.radio_dp_dot.decimal = "."
        self.radio_dp_dot.toggled.connect(self.onClickedDecimal)

        self.radio_dp_comma = QRadioButton("Comma")
        self.radio_dp_comma.setChecked(decimal == ',')
        self.radio_dp_comma.decimal = ","
        self.radio_dp_comma.toggled.connect(self.onClickedDecimal)

        self.layout_dp.addWidget(self.radio_dp_dot)
        self.layout_dp.addWidget(self.radio_dp_comma)
        #
        self.layout.addLayout(self.layout_sepdec)

        # header and index column
        groupbox_header = QGroupBox("Header and row labels:")
        self.layout.addWidget(groupbox_header)
        self.layout_header = QVBoxLayout()
        groupbox_header.setLayout(self.layout_header)

        self.chk_header = QCheckBox("Header (column name) in first row")
        self.chk_header.setChecked(self.header)
        self.layout_header.addWidget(self.chk_header)
        self.chk_header.stateChanged.connect(self.onClickedHeader)

        self.chk_index = QCheckBox("Row label in first column")
        self.chk_index.setChecked(self.index)
        self.layout_header.addWidget(self.chk_index)
        self.chk_index.stateChanged.connect(self.onClickedIndex)

        # preview csv file
        groupbox_pre = QGroupBox("Preview:")
        self.layout.addWidget(groupbox_pre)
        self.layout_pre = QHBoxLayout()
        groupbox_pre.setLayout(self.layout_pre)

        file_head = self.file_preview(self.filename.text())
        self.preview.document().setPlainText(file_head)
        self.preview.setReadOnly(True)
        self.layout_pre.addWidget(self.preview)

        self.layout.addWidget(self.buttonBox)

        self.setLayout(self.layout)

    def file_preview(self, path: str, n=8) -> str:
        """ return first n lines from csv file, if file exists """
        file_head = ''
        if path != '' and os.path.isfile(path):
            with open(path, 'r') as f:
                for i in range(1, n):
                    file_head += f.readline()

        return file_head

    def validate(self):
        if self.filename.text() == '':
            QMessageBox.about(self, 'Error', 'Path to CSV file is mandatory.')
            self.filename.setFocus()
        else:
            self.accept()

    def onClicked(self):
        radio = self.sender()
        if radio.isChecked():
            self.separator = radio.separator

    def onClickedDecimal(self):
        radio = self.sender()
        if radio.isChecked():
            self.decimal = radio.decimal

    def onClickedHeader(self, state):
        if state == QtCore.Qt.Checked:
            self.header = True
        else:
            self.header = False

    def onClickedIndex(self, state):
        if state == QtCore.Qt.Checked:
            self.index = True
        else:
            self.index = False

    def onBtnFileClicked(self):
        file_name, _ = QFileDialog.getOpenFileName(
            self, "Open CSV file...", "", "CSV (*.csv);;All Files (*)")
        if file_name:
            self.filename.setText(file_name)
            file_head = self.file_preview(self.filename.text())
            self.preview.document().setPlainText(file_head)

    def onFileNameTextChange(self):
        """ on text change in field filename (QLineEdit) - clear and set new preview"""
        file_head = self.file_preview(self.filename.text())
        self.preview.document().setPlainText(file_head)
Ejemplo n.º 8
0
class Editor(QMainWindow):
    def __init__(self):
        super().__init__()
        self.currentpath = ''
        self.font = QFont("Monaco", 14)
        self.font.setFixedPitch(True)
        self.title = 'simple text editor'
        self.textEditor = QPlainTextEdit()
        self.textEditor.setFont(self.font)
        # set tab length 4 spaces
        self.textEditor.setTabStopDistance(
            QFontMetricsF(self.textEditor.font()).width(' ') * 4)
        self.menubar = self.menuBar()
        self.menubar.setFont(self.font)
        self.init_ui()

    def setFileMenu(self):
        # fileMenu setting
        fileMenu = self.menubar.addMenu('File')
        fileMenu.setFont(self.font)

        # action
        newAct = QAction('New', self)
        openAct = QAction('Open', self)
        autoSave = QAction('AutoSavle', self, checkable=True)
        exitAct = QAction('Exit', self)
        saveAct = QAction('Save', self)
        exitAct.triggered.connect(qApp.quit)

        newAct.setShortcut('Ctrl+N')
        openAct.setShortcut('Ctrl+O')
        exitAct.setShortcut('Ctrl+Q')
        saveAct.setShortcut('Ctrl+S')

        # action detail
        openAct.triggered.connect(self.openFile)
        newAct.triggered.connect(self.newFile)
        saveAct.triggered.connect(self.saveFile)

        # autoSave set default False
        autoSave.setChecked(False)

        # add action on fileMenu
        fileMenu.addAction(newAct)
        fileMenu.addAction(openAct)
        fileMenu.addAction(saveAct)
        fileMenu.addAction(autoSave)
        fileMenu.addAction(exitAct)

    def newFile(self):
        fname = QFileDialog.getSaveFileName(self, 'Save file')
        context = self.textEditor.toPlainText()
        if fname[0]:
            with open(fname[0], 'w') as f:
                f.write(context)
            self.currentpath = fname[0]

    def saveFile(self):
        path = self.currentpath
        context = self.textEditor.toPlainText()
        if path:
            with open(path, 'w') as f:
                f.write(context)

    def setSettingMenu(self):
        # settingMenu setting
        settingMenu = self.menubar.addMenu('Setting')
        settingMenu.setFont(self.font)

        # action
        fontAct = QAction('Font', self)

        # action detail
        settingMenu.addAction(fontAct)

        # add action on settingMenu
        fontAct.triggered.connect(self.selectFont)

    def selectFont(self):
        font, ok = QFontDialog.getFont()

        if ok:
            self.textEditor.setFont(font)

    def init_ui(self):
        self.setFileMenu()
        self.setSettingMenu()
        self.setCentralWidget(self.textEditor)

        # setting window
        self.setGeometry(500, 300, 800, 600)
        self.setWindowTitle(self.title)
        self.show()

    def contextMenuEvent(self, event):
        cmenu = QMenu(self)

        newAct = cmenu.addAction("New")
        openAct = cmenu.addAction("Open")
        quitAct = cmenu.addAction("Quit")
        action = cmenu.exec_(self.mapToGlobal(event.pos()))

        if action == newAct:
            pass

        if action == quitAct:
            qApp.quit()

        if action == openAct:
            pass

    def openFile(self):
        # get current use main home full path as string
        main_home = Path.home().absolute().as_posix()
        fname = QFileDialog.getOpenFileName(self, 'Open File', main_home)
        if fname[0]:
            with open(fname[0], 'r') as f:
                content = f.read()
                self.textEditor.setPlainText(content)
                self.currentpath = fname[0]
Ejemplo n.º 9
0
class App(QMainWindow):
 
    def __init__(self):
        super().__init__()
        self.title = 'Resolution theorem prover'
        self.left = 300
        self.top = 300
        self.width = 600
        self.height = 600
        self.init_ui()
 
    def init_ui(self):
        self.setWindowTitle(self.title)
        self.setGeometry(self.left, self.top, self.width, self.height)

        # Create textboxGivens
        self.textboxExpr = QLineEdit(self)
        self.textboxExpr.move(20, 20)
        self.textboxExpr.resize(300, 30)

        font = self.textboxExpr.font()
        font.setPointSize(10)
        self.textboxExpr.setFont(font)

        # Create textboxConclusion
        self.textboxConc = QLineEdit(self)
        self.textboxConc.move(330, 20)
        self.textboxConc.resize(50, 30)
        font = self.textboxConc.font()
        font.setPointSize(10)
        self.textboxConc.setFont(font)

        self.verboseText = QPlainTextEdit(self)
        self.verboseText.setReadOnly(True)
        self.verboseText.move(20, 60)
        self.verboseText.resize(550, 500)
        font = self.verboseText.font()
        font.setPointSize(12)
        self.verboseText.setFont(font)


        # Create a button in the window
        self.button = QPushButton('Resolute', self)
        self.button.move(400, 20)
 
        # connect button to function on_click
        self.button.clicked.connect(self.on_click)
        self.show()

    def print_expr(self, idx : int, expr, val_to_names : dict, parents = ()):
        self.verboseText.appendPlainText(str(idx) + ') ' + ' ∨ '.join(
            ('¬' if x < 0 else '') + str(val_to_names[abs(x)]) for x in expr) +
                                         ('\t resolvent of ' + str(parents) if parents else '') + '\n')

    def print_expr_str(self, idx : int, expr_str : str, parents = ()):
        self.verboseText.appendPlainText(str(idx) + ') ' + expr_str +
                                         ('\t resolvent of ' + str(parents) if parents else '') + '\n')
 
    @pyqtSlot()
    def on_click(self):
        if self.textboxConc.text() is '' or self.textboxExpr.text() is '':
            return
        try:
            text = '(' + (self.textboxExpr.text() + ', ~' + self.textboxConc.text())\
                .replace(' ', '').replace(',', ')/\\(') + ')'
            givens = expr( text )
            concl = expr( self.textboxConc.text() )

            simplified_str = str( simplify(givens))

            self.verboseText.setPlainText('Expression: ' + simplified_str + '\n')

            simplified_str = simplified_str.split('∧')

            expressions = []
            simplified_str = [simplified_str[-1]] + simplified_str[:-1]
            liters = []
            expr_parts = []
            b = '() '
            for let in simplified_str:
                for s in b:
                    let = let.replace(s, '')
                if len(let) == 1 or len(let) == 2 and let[0] == '¬':
                    liters.append(let)
                else:
                    expr_parts.append(let)
            simplified_str = liters + expr_parts

            dict_letters = dict()
            dict_values = dict()
            for ex in simplified_str:
                cur = ex.split('∨')
                cur_exp = set()
                for symb in cur:
                    letter = symb.replace('¬', '')

                    if letter not in dict_letters:
                        dict_letters[letter] = len(dict_letters) + 1
                        dict_values[dict_letters[letter]] = letter
                    cur_exp.add(dict_letters[letter] * (-1 if '¬' in symb else 1))
                expressions.append(cur_exp)
                self.print_expr(len(expressions), cur_exp, dict_values)

            i = 0
            result = False

            while (not result) and (i < len(expressions) - 1):
                for j in range(i + 1, len(expressions)):
                    if not (expressions[j] <= expressions[i]):
                        tmp = expressions[i].union(expressions[j])
                        new_exp = set()
                        has_conc_pair = False
                        for l in tmp:
                            if -l in tmp:
                                has_conc_pair = True
                            else:
                                new_exp.add(l)

                        if has_conc_pair and new_exp not in expressions:
                            if len(new_exp) == 0:
                                result = True
                                self.print_expr_str(len(expressions) + 1, '▯', (i + 1, j + 1))
                                break
                            else:
                                expressions.append(new_exp)
                                self.print_expr(len(expressions), new_exp, dict_values, (i + 1, j + 1))
                i += 1
            if result:
                self.verboseText.appendPlainText('Theorem proved.')
            else:
                self.verboseText.appendPlainText('Theorem was not proved.')
        except:
            self.verboseText.appendPlainText('Incorrect expression.')
Ejemplo n.º 10
0
class InputDock(QDockWidget):
    def __init__(self):
        super().__init__()
        self._methods = {}
        self.setWindowFlags(Qt.WindowTitleHint)

        central_widget = QWidget()
        self._layout = QVBoxLayout()
        central_widget.setLayout(self._layout)
        self.setWidget(central_widget)

        self._general_box = QGroupBox("General")
        size_policy = QSizePolicy(QSizePolicy.Expanding,
                                  QSizePolicy.MinimumExpanding)

        self._general_layout = QVBoxLayout()
        self._general_box.setLayout(self._general_layout)
        self._layout.addWidget(self._general_box)

        self._measurement_box = QGroupBox("Measurement")
        size_policy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        self._measurement_box.setSizePolicy(size_policy)
        self._measurement_layout = QVBoxLayout()
        self._measurement_box.setLayout(self._measurement_layout)
        self._layout.addWidget(self._measurement_box)

        self._init_dir_picker()
        self._init_comment()
        self._init_contacts_picker()
        self._init_sample_config()
        self._init_measurement_box()
        self._init_input_area()
        self._init_controls()

    def _init_comment(self):

        self._comment_box = QPlainTextEdit()

        metrics = QFontMetrics(self._comment_box.font())
        row_height = metrics.lineSpacing()
        # four rows
        self._comment_box.setFixedHeight(4 * row_height)

        self._general_layout.addWidget(QLabel("Comment:"))
        self._general_layout.addWidget(self._comment_box)

    def _init_controls(self):
        self._play_string = "\u25b6"
        self._pause_string = "\u23F8"

        button_layout = QHBoxLayout()
        self._measure_button = QPushButton(self._play_string)
        self._measure_button.setDisabled(True)
        font = self._measure_button.font()
        font.setPointSize(20)
        font.setWeight(100)
        self._measure_button.setFont(font)
        self._measure_button.setToolTip("start/pause a measurement")

        self._abort_button = QPushButton("\u2716")
        self._abort_button.setDisabled(True)
        font = self._abort_button.font()
        font.setPointSize(20)
        font.setWeight(100)
        self._abort_button.setFont(font)
        self._abort_button.setToolTip("abort the current measurement")

        self._next_button = QPushButton("\u2192")
        self._next_button.setDisabled(True)
        font = self._next_button.font()
        font.setPointSize(20)
        font.setWeight(100)
        self._next_button.setFont(font)
        self._next_button.setToolTip("next contacts")

        button_layout.addStretch()
        button_layout.addWidget(self._measure_button)
        button_layout.addWidget(self._abort_button)
        button_layout.addWidget(self._next_button)

        self._layout.addLayout(button_layout)

    def _init_dir_picker(self):
        self._dir_picker = DirectoryPicker()
        self._general_layout.addWidget(self._dir_picker)

    def _init_contacts_picker(self):
        self._contacts_picker = ContactsSelector()
        self._general_layout.addWidget(self._contacts_picker)

        self._contacts_picker.save_triggered.connect(self._on_new_group)

    def _on_new_group(self):
        contacts = self._contacts_picker.contacts
        name, okay = QInputDialog.getText(self, "New Group",
                                          "Enter Group Name")

        if name != "" and okay:
            result = self._sample_config.add_config(name, contacts)

            if result == False:
                error = QErrorMessage()
                error.showMessage("Name is already in use")

    def _init_sample_config(self):
        self._sample_config = SampleConfig()
        self._general_layout.addWidget(self._sample_config)

    def _init_measurement_box(self):
        self._method_selection_box = QComboBox()

        self._method_selection_box.currentTextChanged.connect(
            self._method_changed)

        self._method_model = self._method_selection_box.model()

        default_item = QStandardItem("-- Select a method --")
        default_item.setEnabled(False)

        self._method_model.appendRow(default_item)

        self._measurement_layout.addWidget(self._method_selection_box)

    def _init_input_area(self):
        self._scroll_area = QScrollArea()
        self._scroll_area.setWidgetResizable(True)
        self._scroll_area.setFrameShape(QFrame.NoFrame)
        self._scroll_layout = QVBoxLayout()
        scroll_widget = QWidget()
        self._scroll_area.setWidget(scroll_widget)
        scroll_widget.setLayout(self._scroll_layout)
        self._layout.addWidget(self._scroll_area)

        self._measurement_layout.addWidget(self._scroll_area)

    def add_method(self, method_name: str, method):
        if not method_name in self._methods:
            dynamic_layout = DynamicInputLayout(method.inputs())
            dynamic_layout.setContentsMargins(0, 0, 0, 0)

            container = QWidget()
            container.hide()
            container.setLayout(dynamic_layout)

            self._scroll_layout.addWidget(container)
            self._methods[method_name] = (container, method)

            self._method_selection_box.addItem(method_name)

    def load_sample_config(self, file_name):
        self._sample_config.load_from_file(file_name)

    def save_sample_config(self, file_name):
        self._sample_config.save_to_file(file_name)

    @property
    def comment(self):
        text = self._comment_box.toPlainText()
        text = text.replace("\n", "\n# ")

        return "# " + text

    @property
    def directory_path(self):
        self._dir_picker.directory

    @property
    def contacts(self):
        self._contacts_picker.contacts

    @property
    def method(self):
        self._method_selection_box.currentText()

    @property
    def inputs(self):
        widget, _ = self._methods[self.method]
        method_layout = widget.layout()
        return method_layout.get_inputs()

    def _method_changed(self):
        selected_method = self._method_selection_box.currentText()
        self._hide_all_methods()
        self._show_method(selected_method)

    def _hide_all_methods(self):
        [widget.hide() for _, (widget, _) in self._methods.items()]

    def _show_method(self, name):
        if name in self._methods:
            widget, method = self._methods[name]
            widget.show()

            self._contacts_picker.set_number_of_contacts(
                method.number_of_contacts())
Ejemplo n.º 11
0
class DebugWindow(QMainWindow):
    """A main window to edit text and examine the generated token structure.

    Example::

        from PyQt5.Qt import *
        a=QApplication([])

        from parceqt.debug import DebugWindow
        w = DebugWindow()
        w.resize(1200,900)
        w.show()

        w.set_theme("default", True)

        from parce.lang.css import *
        w.set_root_lexicon(Css.root)
        w.set_text(open("path/to/parce/themes/default.css").read())

    In the debug window you can edit the text at the left and directly at the
    right examine the tree structure. Along the top of the window the path to
    the token at the current cursor position is displayed, from the root
    lexicon upto the token, from which the action is displayed.

    Clicking a button selects the associated range of the context or token in
    the text view. Clicking an item in the tree also selects that range in the
    text.

    Moving the cursor in the text updates the current item in the tree,
    and the displayed ancestor path.

    """

    show_updated_region_enabled = False

    def __init__(self, parent=None):
        super().__init__(parent, windowTitle="parceqt debugger")

        f = self._updated_format = QTextCharFormat()
        c = QColor("palegreen")
        c.setAlpha(64)
        f.setBackground(c)
        f = self._currentline_format = QTextCharFormat()
        f.setProperty(QTextCharFormat.FullWidthSelection, True)

        self._actions = Actions(self)
        self._actions.add_menus(self.menuBar())

        widget = QWidget(self)
        self.setCentralWidget(widget)
        layout = QVBoxLayout(margin=4, spacing=2)
        widget.setLayout(layout)

        top_layout = QHBoxLayout(margin=0, spacing=0)

        self.guessButton = QToolButton(self,
                                       clicked=self.guess_root_lexicon,
                                       toolTip="Guess Language",
                                       icon=self.style().standardIcon(
                                           QStyle.SP_BrowserReload))
        self.lexiconChooser = LexiconChooser(self)
        self.ancestorView = AncestorView(self)
        top_layout.addWidget(self.guessButton)
        top_layout.addWidget(self.lexiconChooser)
        top_layout.addWidget(self.ancestorView)
        top_layout.addStretch(10)
        layout.addLayout(top_layout)
        self.guessButton.setFixedHeight(
            self.lexiconChooser.sizeHint().height())

        splitter = QSplitter(self, orientation=Qt.Horizontal)
        layout.addWidget(splitter, 100)

        self.textEdit = QPlainTextEdit(lineWrapMode=QPlainTextEdit.NoWrap,
                                       cursorWidth=2)
        self.treeView = QTreeView()

        splitter.addWidget(self.textEdit)
        splitter.addWidget(self.treeView)
        splitter.setStretchFactor(0, 3)
        splitter.setStretchFactor(1, 2)

        self.extraSelectionManager = ExtraSelectionManager(self.textEdit)

        self.document = d = self.textEdit.document()
        self.textEdit.setDocument(self.document)

        self.worker = w = parceqt.worker(d)
        self.builder = b = w.builder()
        w.debugging = True

        self.setStatusBar(QStatusBar())
        self.create_model()

        # signal connections
        self.textEdit.viewport().installEventFilter(self)
        self.textEdit.installEventFilter(self)
        self.lexiconChooser.lexicon_changed.connect(
            self.slot_root_lexicon_changed)
        self.ancestorView.node_clicked.connect(self.slot_node_clicked)
        w.started.connect(self.slot_build_started)
        w.tree_updated.connect(self.slot_build_updated)
        self.textEdit.cursorPositionChanged.connect(
            self.slot_cursor_position_changed)
        self.treeView.clicked.connect(self.slot_item_clicked)

        self.textEdit.setFocus()
        self.set_theme()

        # somewhat larger font by default
        font = self.textEdit.font()
        font.setPointSizeF(11)
        self.textEdit.setFont(font)

    def create_model(self):
        """Instantiate a tree model for the tree view."""
        m = self.treeView.model()
        if not m:
            m = parceqt.treemodel.TreeModel(self.builder.root)
            m.connect_debugging_builder(self.builder)
            self.treeView.setModel(m)

    def delete_model(self):
        """Delete the model and remove it from the tree."""
        m = self.treeView.model()
        if m:
            m.disconnect_debugging_builder(self.builder)
            self.treeView.setModel(None)
            m.deleteLater()

    def set_text(self, text):
        """Set the text in the text edit."""
        self.document.setPlainText(text)

    def set_root_lexicon(self, lexicon):
        """Set the root lexicon to use."""
        self.lexiconChooser.set_root_lexicon(lexicon)

    def guess_root_lexicon(self):
        """Again choose the root lexicon based on the text."""
        text = self.document.toPlainText()
        if text:
            self.set_root_lexicon(parce.find(contents=text))

    def open_file(self, filename):
        """Read a file from disk and guess the language."""
        text = read_file(filename)
        root_lexicon = parce.find(filename=filename, contents=text)
        self.set_text(text)
        self.set_root_lexicon(root_lexicon)
        c = self.textEdit.textCursor()
        c.setPosition(0)
        self.textEdit.setTextCursor(c)

    def set_theme(self, theme="default", adjust_widget=True):
        """Set the theme to use for the text edit."""
        if isinstance(theme, str):
            theme = parce.theme_by_name(theme)
        formatter = parceqt.formatter.Formatter(theme) if theme else None
        if adjust_widget:
            if formatter:
                font = formatter.font(self)
                self.textEdit.setPalette(formatter.palette(self))
            else:
                font = QApplication.font(self)
                self.textEdit.setPalette(QApplication.palette(self))
            font.setPointSizeF(self.textEdit.font().pointSizeF())  # keep size
            self.textEdit.setFont(font)
            self.highlight_current_line()
        h = parceqt.highlighter.SyntaxHighlighter.instance(self.worker)
        h.set_formatter(formatter)

    def slot_build_started(self):
        """Called when the tree builder has started a build."""
        self.treeView.setCursor(Qt.BusyCursor)

    def slot_build_updated(self):
        """Called when the tree builder has finished a build."""
        self.treeView.unsetCursor()
        self.slot_cursor_position_changed()
        self.statusBar().showMessage(", ".join(
            lexicon_names(self.builder.lexicons)))
        tree = self.worker.get_root()
        self.lexiconChooser.setToolTip(
            parceqt.treemodel.TreeModel.node_tooltip(tree))
        if self.show_updated_region_enabled:
            self.show_updated_region()

    def slot_cursor_position_changed(self):
        """Called when the text cursor moved."""
        tree = self.worker.get_root()
        if tree:
            pos = self.textEdit.textCursor().position()
            doc = parceqt.document.Document(self.document)
            token = doc.token(pos)
            if token:
                self.ancestorView.set_token_path(token)
                model = self.treeView.model()
                if model:
                    index = model.get_model_index(token)
                    self.treeView.setCurrentIndex(index)
        elif tree is not None:
            self.ancestorView.clear()
        self.highlight_current_line()

    def slot_item_clicked(self, index):
        """Called when a node in the tree view is clicked."""
        tree = self.worker.get_root()
        if tree:
            model = self.treeView.model()
            if model:
                node = self.treeView.model().get_node(index)
                cursor = self.textEdit.textCursor()
                cursor.setPosition(node.end)
                cursor.setPosition(node.pos, QTextCursor.KeepAnchor)
                self.textEdit.setTextCursor(cursor)
        self.textEdit.setFocus()

    def slot_node_clicked(self, node):
        """Called when a button in the ancestor view is clicked."""
        tree = self.worker.get_root()
        if tree and node.root() is tree:
            cursor = self.textEdit.textCursor()
            cursor.setPosition(node.end)
            cursor.setPosition(node.pos, QTextCursor.KeepAnchor)
            self.textEdit.setTextCursor(cursor)
            self.textEdit.setFocus()
            model = self.treeView.model()
            if model:
                index = model.get_model_index(node)
                self.treeView.expand(index)
                self.treeView.setCurrentIndex(index)

    def slot_root_lexicon_changed(self, lexicon):
        """Called when the root lexicon is changed."""
        parceqt.set_root_lexicon(self.document, lexicon)

    def highlight_current_line(self):
        """Highlight the current line."""
        group = QPalette.Active if self.textEdit.hasFocus(
        ) else QPalette.Inactive
        p = self.textEdit.palette()
        color = p.color(group, QPalette.AlternateBase)
        self._currentline_format.setBackground(color)
        if color != p.color(group, QPalette.Base):
            c = self.textEdit.textCursor()
            c.clearSelection()
            self.extraSelectionManager.highlight(self._currentline_format, [c])
        else:
            self.extraSelectionManager.clear(self._currentline_format)

    def show_updated_region(self):
        """Highlight the updated region for 2 seconds."""
        end = self.builder.end
        if end >= self.document.characterCount() - 1:
            end = self.document.characterCount() - 1
            if self.builder.start == 0:
                return
        c = QTextCursor(self.document)
        c.setPosition(end)
        c.setPosition(self.builder.start, QTextCursor.KeepAnchor)
        self.extraSelectionManager.highlight(self._updated_format, [c],
                                             msec=2000)

    def clear_updated_region(self):
        self.extraSelectionManager.clear(self._updated_format)

    def eventFilter(self, obj, ev):
        """Implemented to support Ctrl+wheel zooming and keybfocus handling."""
        if obj == self.textEdit:
            if ev.type() in (QEvent.FocusIn, QEvent.FocusOut):
                self.highlight_current_line()
        else:  # viewport
            if ev.type() == QEvent.Wheel and ev.modifiers(
            ) == Qt.ControlModifier:
                if ev.angleDelta().y() > 0:
                    self.textEdit.zoomIn()
                elif ev.angleDelta().y() < 0:
                    self.textEdit.zoomOut()
                return True
        return False