Ejemplo n.º 1
0
class DetailView(QWidget):
    def __init__(self, context):
        super().__init__()
        self.context = context
        self.resize(300, 200)
        self.move(1000, 100)

        self.textbox = QPlainTextEdit(self)
        self.textbox.setPlainText(self.context)
        self.textbox.move(20, 20)
        self.textbox.resize(100, 100)

        self.search_button = QPushButton(self)
        self.search_button.setText("Search")
        self.search_button.clicked.connect(self._search)

        self.search_box = QLineEdit(self)
        self.search_box.returnPressed.connect(self.search_button.click)

        self.lay = QGridLayout(self)
        self.lay.addWidget(self.textbox, 0, 0)
        self.lay.addWidget(self.search_box, 1, 0)
        self.lay.addWidget(self.search_button, 2, 0)
        self.setLayout(self.lay)
        self.show()

    def _search(self):
        searchstring = self.search_box.text()
        #positions = [m.start() for m in re.finditer(searchstring, self.context)]
        self.textbox.find(searchstring)
        self.textbox.setBackgroundVisible(False)
Ejemplo n.º 2
0
class MainWindow(QWidget):
    def __init__(self, width, height):
        super().__init__()
        self.resize(width, height)  # устанавливаем размер окна по размеру экрана
        self.setWindowTitle('FormulaVoiceInput')  # заголовок

        self.tex = QPlainTextEdit()  # редактируемое текстовое поле, в котором будут выводиться команды TEX
        self.set_tex()  # настройка начального текста, необходимого для компиляции из tex в pdf

        self.image = QLabel()  # здесь выводится картинка с формулой
        self.pixmap = QPixmap()  # пиксельная карта для картинки
        self.scale = 1  # текущий к-т масштабирования картинки
        self.scroll = QScrollArea()  # область с полосами прокрутки

        self.slider = QSlider(Qt.Horizontal)  # ползунок для изменения масштаба
        self.set_slider()

        self.status_bar = QStatusBar()  # нижняя строка состояния
        self.status_bar.addWidget(self.slider)  # добавляем ползунок для изменения масштаба
        self.grid = QGridLayout()  # макет сетки для виджетов
        self.set_layout()  # установка макета

        self.words = SpeechProcessing(self.tex)  # для обработки распознанной речи
        self.subprocess = QProcess(self)  # подпроцесс для получения текста из pocketsphinx
        self.speech_to_text()  # распознавание речи

        self.show()

    def set_tex(self):
        # начальная строка
        start_line = "\\documentclass{article}\n\
\\usepackage[left=0mm,right=0mm,top=0mm,bottom=0mm,bindingoffset=0mm]{geometry}\n\
\\usepackage[fleqn]{amsmath}\n\
\\begin{document}\n\
\\begin{gather*}\n\n\
\\end{gather*}\n\
\\end{document}"
        self.tex.insertPlainText(start_line)  # вставка начальной строки
        self.tex.find('begin{gather*}',
                      QTextDocument.FindBackward)  # находим место фрагмента begin{gather*}
        self.tex.moveCursor(QTextCursor.Down)  # устанавливаем курсор внутри

    def set_slider(self):
        self.slider.setMinimum(0)  # минимальный масштаб
        self.slider.setMaximum(200)  # максимальный масштаб
        self.slider.setValue(100)  # устанавливаем ползунок посередине
        self.slider.valueChanged[int].\
            connect(self.scale_img)  # обработчик изменений положения ползунка

    def scale_img(self, scale):  # масштабирование картинки с формулой
        self.scale = scale / 100
        self.image = QLabel()  # создаем новый виджет для картинки
        # устанавливаем масштабированную картинку
        self.image.setPixmap(self.pixmap.scaledToWidth(self.pixmap.size().width() * self.scale))
        self.scroll.setWidget(self.image)  # добавляем новый виджет в область прокрутки

    def set_layout(self):
        self.grid.addWidget(self.tex, 1, 0)
        self.grid.setSpacing(20)
        self.grid.addWidget(self.scroll, 1, 1)
        self.grid.addWidget(self.status_bar, 2, 1)
        self.setLayout(self.grid)  # устанавливаем макет сетки для окна

    def speech_to_text(self):  # распознавание речи с микрофона с помощью pocketsphinx
        logs = open('speech/pocketsphinx_logs', 'w')  # создаем файл, в который будут записываться логи от pocketsphinx
        cmd = "pocketsphinx_continuous\
        -hmm speech/map \
        -dict speech/math.dict \
        -jsgf speech/math.jsgf \
        -logfn speech/pocketsphinx_logs \
              -inmic yes"
        args = shlex.split(cmd)
        self.subprocess.\
            readyReadStandardOutput.connect(self.stdout_ready)
        self.subprocess.start(args[0], args[1:])

    def stdout_ready(self):
        # меняем кодировку текста, полученного в рез-те распознавания
        text = bytearray(self.subprocess.readAllStandardOutput()).decode("utf-8").rstrip()
        if text == 'новая формула':
            self.words.new_formula()
        elif text == 'обновить':
            self.create_img()
            self.update_img()
        else:
            self.words.queue.extend(text.split())  # добавляем новые слова
            self.words.parsing()  # анализ распознанных слов
            self.create_img()
            self.update_img()

    def create_img(self):  # получение pdf из файла tex
        tex_file = open('tex_file.tex', 'w')  # создаем файл tex_file.tex
        tex_file.write(self.tex.toPlainText())  # запись текста из self.tex в tex_file
        tex_file.close()
        self.start_subprocess('pdflatex tex_file.tex', 1000)
        if path.isfile('tex_file.pdf'):
            self.start_subprocess('pdftoppm -png tex_file.pdf formula', 500)

    # запуск подпроцесса с параметрами, указанными в cmd и временем ожидания завершения delay(в миллисекундах)
    def start_subprocess(self, cmd, delay):
        args = shlex.split(cmd)
        p = QProcess(self)
        p.start(args[0], args[1:])
        p.waitForFinished(delay)
        p.close()

    # загрузка новой картинки при добавлении новых символов
    def update_img(self):
        if path.isfile('formula-1.png'):
            self.pixmap.load('formula-1.png')
            self.image = QLabel()
            w = self.pixmap.size().width()
            self.image.setPixmap(self.pixmap.scaledToWidth(w * self.scale))
            self.scroll.setWidget(self.image)
Ejemplo n.º 3
0
class myEditor(QMainWindow):
    def __init__(self, parent=None):
        super(myEditor, self).__init__(parent)
        self.MaxRecentFiles = 5
        self.windowList = []
        self.recentFileActs = []
        self.setAttribute(Qt.WA_DeleteOnClose)
        # Editor Widget ...
        QIcon.setThemeName('Faenza-Dark')
        self.editor = QPlainTextEdit()
        self.editor.setStyleSheet(stylesheet2(self))
        self.editor.setFrameStyle(QFrame.NoFrame)
        self.editor.setTabStopWidth(14)
        self.extra_selections = []
        self.fname = ""
        self.filename = ""
        # Line Numbers ...
        self.numbers = NumberBar(self.editor)

        self.createActions()
        # Laying out...
        layoutH = QHBoxLayout()
        layoutH.setSpacing(1.5)
        layoutH.addWidget(self.numbers)
        layoutH.addWidget(self.editor)

        ### begin toolbar
        tb = QToolBar(self)
        tb.setWindowTitle("File Toolbar")

        self.newAct = QAction("&New",
                              self,
                              shortcut=QKeySequence.New,
                              statusTip="Create a new file",
                              triggered=self.newFile)
        self.newAct.setIcon(QIcon.fromTheme("document-new"))

        self.openAct = QAction("&Open",
                               self,
                               shortcut=QKeySequence.Open,
                               statusTip="open file",
                               triggered=self.openFile)
        self.openAct.setIcon(QIcon.fromTheme("document-open"))

        self.saveAct = QAction("&Save",
                               self,
                               shortcut=QKeySequence.Save,
                               statusTip="save file",
                               triggered=self.fileSave)
        self.saveAct.setIcon(QIcon.fromTheme("document-save"))

        self.saveAsAct = QAction("&Save as ...",
                                 self,
                                 shortcut=QKeySequence.SaveAs,
                                 statusTip="save file as ...",
                                 triggered=self.fileSaveAs)
        self.saveAsAct.setIcon(QIcon.fromTheme("document-save-as"))

        self.exitAct = QAction("Exit",
                               self,
                               shortcut=QKeySequence.Quit,
                               toolTip="Exit",
                               triggered=self.handleQuit)
        self.exitAct.setIcon(QIcon.fromTheme("application-exit"))

        ### find / replace toolbar
        self.tbf = QToolBar(self)
        self.tbf.setWindowTitle("Find Toolbar")
        self.findfield = QLineEdit()
        self.findfield.addAction(QIcon.fromTheme("edit-find"),
                                 QLineEdit.LeadingPosition)
        self.findfield.setClearButtonEnabled(True)
        self.findfield.setFixedWidth(150)
        self.findfield.setPlaceholderText("find")
        self.findfield.setToolTip("press RETURN to find")
        self.findfield.setText("")
        ft = self.findfield.text()
        self.findfield.returnPressed.connect(self.findText)
        self.tbf.addWidget(self.findfield)
        self.replacefield = QLineEdit()
        self.replacefield.addAction(QIcon.fromTheme("edit-find-and-replace"),
                                    QLineEdit.LeadingPosition)
        self.replacefield.setClearButtonEnabled(True)
        self.replacefield.setFixedWidth(150)
        self.replacefield.setPlaceholderText("replace with")
        self.replacefield.setToolTip("press RETURN to replace the first")
        self.replacefield.returnPressed.connect(self.replaceOne)
        self.tbf.addSeparator()
        self.tbf.addWidget(self.replacefield)
        self.tbf.addSeparator()

        self.tbf.addAction("replace all", self.replaceAll)
        self.tbf.addSeparator()

        layoutV = QVBoxLayout()

        bar = self.menuBar()

        self.filemenu = bar.addMenu("File")
        self.separatorAct = self.filemenu.addSeparator()
        self.filemenu.addAction(self.newAct)
        self.filemenu.addAction(self.openAct)
        self.filemenu.addAction(self.saveAct)
        self.filemenu.addAction(self.saveAsAct)
        self.filemenu.addSeparator()
        for i in range(self.MaxRecentFiles):
            self.filemenu.addAction(self.recentFileActs[i])
        self.updateRecentFileActions()
        self.filemenu.addSeparator()
        self.filemenu.addAction(self.exitAct)
        bar.setStyleSheet(stylesheet2(self))
        editmenu = bar.addMenu("Edit")
        editmenu.addAction(
            QAction(QIcon.fromTheme('edit-copy'),
                    "Copy",
                    self,
                    triggered=self.editor.copy,
                    shortcut=QKeySequence.Copy))
        editmenu.addAction(
            QAction(QIcon.fromTheme('edit-cut'),
                    "Cut",
                    self,
                    triggered=self.editor.cut,
                    shortcut=QKeySequence.Cut))
        editmenu.addAction(
            QAction(QIcon.fromTheme('edit-paste'),
                    "Paste",
                    self,
                    triggered=self.editor.paste,
                    shortcut=QKeySequence.Paste))
        editmenu.addAction(
            QAction(QIcon.fromTheme('edit-delete'),
                    "Delete",
                    self,
                    triggered=self.editor.cut,
                    shortcut=QKeySequence.Delete))
        editmenu.addSeparator()
        editmenu.addAction(
            QAction(QIcon.fromTheme('edit-select-all'),
                    "Select All",
                    self,
                    triggered=self.editor.selectAll,
                    shortcut=QKeySequence.SelectAll))

        layoutV.addWidget(bar)
        layoutV.addWidget(self.tbf)
        layoutV.addLayout(layoutH)

        ### main window
        mq = QWidget(self)
        mq.setLayout(layoutV)
        self.setCentralWidget(mq)

        # Event Filter ...
        self.installEventFilter(self)
        self.editor.setFocus()
        self.cursor = QTextCursor()
        self.editor.setPlainText("hello")
        self.editor.moveCursor(self.cursor.End)
        self.editor.document().modificationChanged.connect(
            self.setWindowModified)

        # Brackets ExtraSelection ...
        self.left_selected_bracket = QTextEdit.ExtraSelection()
        self.right_selected_bracket = QTextEdit.ExtraSelection()

    def createActions(self):
        for i in range(self.MaxRecentFiles):
            self.recentFileActs.append(
                QAction(self, visible=False, triggered=self.openRecentFile))

    def openRecentFile(self):
        action = self.sender()
        if action:
            if (self.maybeSave()):
                self.openFileOnStart(action.data())

        ### New File
    def newFile(self):
        if self.maybeSave():
            self.editor.clear()
            self.editor.setPlainText("")
            self.filename = ""
            self.setModified(False)
            self.editor.moveCursor(self.cursor.End)

    ### open File
    def openFileOnStart(self, path=None):
        if path:
            inFile = QFile(path)
            if inFile.open(QFile.ReadWrite | QFile.Text):
                text = inFile.readAll()

                try:
                    # Python v3.
                    text = str(text, encoding='utf8')
                except TypeError:
                    # Python v2.
                    text = str(text)
                self.editor.setPlainText(text)
                self.filename = path
                self.setModified(False)
                self.fname = QFileInfo(path).fileName()
                self.setWindowTitle(self.fname + "[*]")
                self.document = self.editor.document()
                self.setCurrentFile(self.filename)

        ### open File
    def openFile(self, path=None):
        if self.maybeSave():
            if not path:
                path, _ = QFileDialog.getOpenFileName(
                    self, "Open File",
                    QDir.homePath() + "/Documents/",
                    "Text Files (*.txt *.csv *.py);;All Files (*.*)")

            if path:
                inFile = QFile(path)
                if inFile.open(QFile.ReadWrite | QFile.Text):
                    text = inFile.readAll()

                    try:
                        # Python v3.
                        text = str(text, encoding='utf8')
                    except TypeError:
                        # Python v2.
                        text = str(text)
                    self.editor.setPlainText(text)
                    self.filename = path
                    self.setModified(False)
                    self.fname = QFileInfo(path).fileName()
                    self.setWindowTitle(self.fname + "[*]")
                    self.document = self.editor.document()
                    self.setCurrentFile(self.filename)

    def fileSave(self):
        if (self.filename != ""):
            file = QFile(self.filename)
            print(self.filename)
            if not file.open(QFile.WriteOnly | QFile.Text):
                QMessageBox.warning(
                    self, "Error", "Cannot write file %s:\n%s." %
                    (self.filename, file.errorString()))
                return

            outstr = QTextStream(file)
            QApplication.setOverrideCursor(Qt.WaitCursor)
            outstr << self.editor.toPlainText()
            QApplication.restoreOverrideCursor()
            self.setModified(False)
            self.fname = QFileInfo(self.filename).fileName()
            self.setWindowTitle(self.fname + "[*]")
            self.setCurrentFile(self.filename)

        else:
            self.fileSaveAs()

            ### save File
    def fileSaveAs(self):
        fn, _ = QFileDialog.getSaveFileName(self, "Save as...", self.filename,
                                            "Python files (*.py)")

        if not fn:
            print("Error saving")
            return False

        lfn = fn.lower()
        if not lfn.endswith('.py'):
            fn += '.py'

        self.filename = fn
        self.fname = os.path.splitext(str(fn))[0].split("/")[-1]
        return self.fileSave()

    def closeEvent(self, e):
        if self.maybeSave():
            e.accept()
        else:
            e.ignore()

        ### ask to save
    def maybeSave(self):
        if not self.isModified():
            return True

        if self.filename.startswith(':/'):
            return True

        ret = QMessageBox.question(self, "Message",
                "<h4><p>The document was modified.</p>\n" \
                "<p>Do you want to save changes?</p></h4>",
                QMessageBox.Yes | QMessageBox.No | QMessageBox.Cancel)

        if ret == QMessageBox.Yes:
            if self.filename == "":
                self.fileSaveAs()
                return False
            else:
                self.fileSave()
                return True

        if ret == QMessageBox.Cancel:
            return False

        return True

    def findText(self):
        ft = self.findfield.text()
        if self.editor.find(ft):
            return
        else:
            self.editor.moveCursor(1)
            if self.editor.find(ft):
                self.editor.moveCursor(QTextCursor.Start,
                                       QTextCursor.MoveAnchor)

    def handleQuit(self):
        print("Goodbye ...")
        app.quit()

    def set_numbers_visible(self, value=True):
        self.numbers.setVisible(False)

    def match_left(self, block, character, start, found):
        map = {'{': '}', '(': ')', '[': ']'}

        while block.isValid():
            data = block.userData()
            if data is not None:
                braces = data.braces
                N = len(braces)

                for k in range(start, N):
                    if braces[k].character == character:
                        found += 1

                    if braces[k].character == map[character]:
                        if not found:
                            return braces[k].position + block.position()
                        else:
                            found -= 1

                block = block.next()
                start = 0

    def match_right(self, block, character, start, found):
        map = {'}': '{', ')': '(', ']': '['}

        while block.isValid():
            data = block.userData()

            if data is not None:
                braces = data.braces

                if start is None:
                    start = len(braces)
                for k in range(start - 1, -1, -1):
                    if braces[k].character == character:
                        found += 1
                    if braces[k].character == map[character]:
                        if found == 0:
                            return braces[k].position + block.position()
                        else:
                            found -= 1
            block = block.previous()
            start = None
#    '''

        cursor = self.editor.textCursor()
        block = cursor.block()
        data = block.userData()
        previous, next = None, None

        if data is not None:
            position = cursor.position()
            block_position = cursor.block().position()
            braces = data.braces
            N = len(braces)

            for k in range(0, N):
                if braces[k].position == position - block_position or braces[
                        k].position == position - block_position - 1:
                    previous = braces[k].position + block_position
                    if braces[k].character in ['{', '(', '[']:
                        next = self.match_left(block, braces[k].character,
                                               k + 1, 0)
                    elif braces[k].character in ['}', ')', ']']:
                        next = self.match_right(block, braces[k].character, k,
                                                0)
                    if next is None:
                        next = -1

        if next is not None and next > 0:
            if next == 0 and next >= 0:
                format = QTextCharFormat()

            cursor.setPosition(previous)
            cursor.movePosition(QTextCursor.NextCharacter,
                                QTextCursor.KeepAnchor)

            format.setBackground(QColor('white'))
            self.left_selected_bracket.format = format
            self.left_selected_bracket.cursor = cursor

            cursor.setPosition(next)
            cursor.movePosition(QTextCursor.NextCharacter,
                                QTextCursor.KeepAnchor)

            format.setBackground(QColor('white'))
            self.right_selected_bracket.format = format
            self.right_selected_bracket.cursor = cursor


#            '''

    def paintEvent(self, event):
        highlighted_line = QTextEdit.ExtraSelection()
        highlighted_line.format.setBackground(lineHighlightColor)
        highlighted_line.format.setProperty(QTextFormat.FullWidthSelection,
                                            QVariant(True))
        highlighted_line.cursor = self.editor.textCursor()
        highlighted_line.cursor.clearSelection()
        self.editor.setExtraSelections([
            highlighted_line, self.left_selected_bracket,
            self.right_selected_bracket
        ])

    def document(self):
        return self.editor.document

    def isModified(self):
        return self.editor.document().isModified()

    def setModified(self, modified):
        self.editor.document().setModified(modified)

    def setLineWrapMode(self, mode):
        self.editor.setLineWrapMode(mode)

    def clear(self):
        self.editor.clear()

    def setPlainText(self, *args, **kwargs):
        self.editor.setPlainText(*args, **kwargs)

    def setDocumentTitle(self, *args, **kwargs):
        self.editor.setDocumentTitle(*args, **kwargs)

    def set_number_bar_visible(self, value):
        self.numbers.setVisible(value)

    def replaceAll(self):
        print("replacing all")
        oldtext = self.editor.document().toPlainText()
        newtext = oldtext.replace(self.findfield.text(),
                                  self.replacefield.text())
        self.editor.setPlainText(newtext)
        self.setModified(True)

    def replaceOne(self):
        print("replacing all")
        oldtext = self.editor.document().toPlainText()
        newtext = oldtext.replace(self.findfield.text(),
                                  self.replacefield.text(), 1)
        self.editor.setPlainText(newtext)
        self.setModified(True)

    def setCurrentFile(self, fileName):
        self.curFile = fileName
        if self.curFile:
            self.setWindowTitle("%s - Recent Files" %
                                self.strippedName(self.curFile))
        else:
            self.setWindowTitle("Recent Files")

        settings = QSettings('Axel Schneider', 'PTEdit')
        files = settings.value('recentFileList')

        try:
            files.remove(fileName)
        except ValueError:
            pass

        files.insert(0, fileName)
        del files[self.MaxRecentFiles:]

        settings.setValue('recentFileList', files)

        for widget in QApplication.topLevelWidgets():
            if isinstance(widget, myEditor):
                widget.updateRecentFileActions()

    def updateRecentFileActions(self):
        mytext = ""
        settings = QSettings('Axel Schneider', 'PTEdit')
        files = settings.value('recentFileList')
        files = files if files else []
        numRecentFiles = min(len(files), self.MaxRecentFiles)

        for i in range(numRecentFiles):
            text = "&%d %s" % (i + 1, self.strippedName(files[i]))
            self.recentFileActs[i].setText(text)
            self.recentFileActs[i].setData(files[i])
            self.recentFileActs[i].setVisible(True)

        for j in range(numRecentFiles, self.MaxRecentFiles):
            self.recentFileActs[j].setVisible(False)

        self.separatorAct.setVisible((numRecentFiles > 0))

    def clearRecentFileList(self, fileName):
        self.rmenu.clear()

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