Ejemplo n.º 1
0
class GestorPortapapelesVentana(QMainWindow):
    def __init__(self):
        super().__init__()

        self.inicializarGui()

    def inicializarGui(self):
        self.setWindowTitle('Gestor Portapapeles')
        self.setFixedSize(400, 300)

        self.txt_texto_fuente = QPlainTextEdit(self)
        self.txt_texto_fuente.move(30, 10)
        self.txt_texto_fuente.setFixedWidth(340)
        self.txt_texto_fuente.setFixedHeight(100)

        self.btn_copiar = QPushButton('Copiar', self)
        self.btn_copiar.move(30, 110)
        self.btn_copiar.setFixedWidth(340)
        self.btn_copiar.clicked.connect(self.copiar)

        self.txt_texto_destino = QPlainTextEdit(self)
        self.txt_texto_destino.move(30, 150)
        self.txt_texto_destino.setFixedWidth(340)
        self.txt_texto_destino.setFixedHeight(100)

        self.btn_pegar = QPushButton('Pegar', self)
        self.btn_pegar.move(30, 250)
        self.btn_pegar.setFixedWidth(340)
        self.btn_pegar.clicked.connect(self.pegar)

    def copiar(self):
        self.txt_texto_fuente.copy()

    def pegar(self):
        self.txt_texto_destino.paste()
Ejemplo n.º 2
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.º 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 App(QMainWindow):
    '''
    The main Qt application for the writer.
    '''
    def __init__(self):
        super().__init__()

        self.working_file_name = ''

        self.InitUI()

    def InitUI(self):

        # Set up window & settings
        self.setMinimumSize(300, 200)
        self.resize(800, 600)
        self.move(400, 100)
        self.setWindowTitle(WINDOW_TITLE)

        # == Widgets and Layout ==
        # Create the central widget
        self.widget = QWidget(self)
        self.widget.setStyleSheet('background-color:' + BACKGROUND_COLOR + ';')

        # Create default text font
        self.input_font = get_monospaced_font(FONT_SIZE)

        # Create info bar font
        self.info_font = get_monospaced_font(INFO_FONT_SIZE)

        # Create LineEdit for the top info bar
        # This bar is for displaying info about
        # the current file
        self.top_info_bar = QLineEdit(self.widget)
        self.top_info_bar.setReadOnly(True)
        self.top_info_bar.setMaximumWidth(MAXIMUM_WIDTH)

        # Set font and style
        self.top_info_bar.setStyleSheet('qproperty-alignment: AlignCenter;')
        self.top_info_bar.setFont(self.info_font)
        self.top_info_bar.setFrame(QFrame.NoFrame)
        self.update_top_info_bar()

        # Create text feild
        self.center_text = QPlainTextEdit(self.widget)
        self.center_text.setMaximumWidth(MAXIMUM_WIDTH)
        self.center_text.setFont(self.input_font)

        # Disable frame style
        self.center_text.setFrameStyle(QFrame.NoFrame)

        # Text feild custom context menu
        self.center_text.setContextMenuPolicy(Qt.CustomContextMenu)
        self.center_text.customContextMenuRequested.connect(
            self.context_menu_event)

        # Create VBox and set it as layout
        self.widget.setLayout(QVBoxLayout())

        # Layout settings
        self.widget.layout().addWidget(self.top_info_bar)
        self.widget.layout().addWidget(self.center_text)
        self.widget.layout().setContentsMargins(0, 0, 0, 0)
        self.widget.layout().setAlignment(Qt.AlignCenter)

        self.setCentralWidget(self.widget)

        # Init keyboard shortcuts
        self.InitKeyboard()

    def InitKeyboard(self):
        ''' Init keyboard shortcuts '''
        # == KEYBOARD SHORTCUTS ==

        # Save, (Ctrl+S)
        self.save_keyboard_shortcut = QShortcut(QKeySequence('Ctrl+S'), self)
        self.save_keyboard_shortcut.activated.connect(self.save_text_file)

        self.saveas_keyboard_shortcut = QShortcut(
            QKeySequence(Qt.SHIFT + Qt.CTRL + Qt.Key_S), self)
        self.saveas_keyboard_shortcut.activated.connect(self.saveas_text_file)

        # Open file (Ctrl+O)
        self.open_keyboard_shortcut = QShortcut(QKeySequence('Ctrl+O'), self)
        self.open_keyboard_shortcut.activated.connect(self.open_text_file)

        # Export to browser
        self.export_keyboard_shortcut = QShortcut(
            QKeySequence(Qt.SHIFT + Qt.CTRL + Qt.Key_E), self)
        self.export_keyboard_shortcut.activated.connect(self.export_to_browser)

        # Fullscreen toggle (F11)
        self.fullscreen_keyboard_shortcut = QShortcut(QKeySequence(Qt.Key_F11),
                                                      self)
        self.fullscreen_keyboard_shortcut.activated.connect(
            self.toggle_fullscreen)

    def save_text_file(self):
        '''
        Saves the written text to a file
        '''
        text_to_save = self.center_text.toPlainText()
        if self.working_file_name:
            with open(self.working_file_name, 'w',
                      encoding='utf-8') as save_file:
                save_file.write(text_to_save)
        else:
            name = QFileDialog.getSaveFileName(
                self, 'Save as...', self.working_file_name,
                'All Files (*);;Text Files (*.txt)')[0]

            if name:
                with open(name, 'w', encoding='utf-8') as save_file:
                    save_file.write(text_to_save)

                # Show the new file path
                self.working_file_name = name

                # Update info bar
                self.update_top_info_bar()

    def saveas_text_file(self):
        # Set file name to '' to save as new file
        self.working_file_name = ''
        self.save_text_file()

    def open_text_file(self):
        ''' Opens a file and '''
        name = QFileDialog.getOpenFileName(
            self, 'Open a File', self.working_file_name,
            'All Files (*);;Text Files (*.txt);;HTML Files (*.html)')[0]

        if name:
            with open(name, 'r', encoding='utf-8') as new_file:
                new_text = new_file.read()

            self.center_text.setPlainText(new_text)

            # Set current file name to the opened one.
            self.working_file_name = name

            # Update info bar
            self.update_top_info_bar()

    def export_to_browser(self):
        # Grab the raw markdown text
        markdown_text = self.center_text.toPlainText()
        # Convert it to html using the markdown module
        markdown_html = markdown.markdown(markdown_text)

        # Create tempfile for the html
        # The tuple consists of file descriptor and path
        temp_file_descriptor, temp_file_path = tempfile.mkstemp(suffix='.html',
                                                                text=True)

        # Write html to temp file
        os.write(temp_file_descriptor, markdown_html.encode(encoding='utf-8'))

        # Open the temp file in the browser
        webbrowser.open('file://' + os.path.realpath(temp_file_path))

        # Close the temp file
        os.close(temp_file_descriptor)

    def context_menu_event(self, event):
        '''
        This function defines the context menu that
        appears on right-click. 
        '''

        context_menu = QMenu(self)

        copy_action = context_menu.addAction(
            'Copy\t(Ctrl+C)')  # Copy to clipboard
        paste_action = context_menu.addAction(
            'Paste\t(Ctrl+V)')  # Paste clipboard

        # Save file
        save_action = context_menu.addAction('Save\t(Ctrl+S)')
        # Save file as...
        save_as_action = context_menu.addAction('Save as...\t(Ctrl+Shift+S)')
        # Open file
        open_action = context_menu.addAction('Open file\t(Ctrl+O)')

        # Export and open in browser
        export_action = context_menu.addAction(
            'Export to browser\t(Ctrl+Shift+E)')

        action = context_menu.exec_(self.center_text.mapToGlobal(event))

        # Copy and paste actions
        if action == copy_action:
            self.center_text.copy()
        elif action == paste_action:
            self.center_text.paste()

        # File managment actions
        elif action == save_as_action:
            self.saveas_text_file()
        elif action == save_action:
            self.save_text_file()
        elif action == open_action:
            self.open_text_file()

        # Markdown actions
        elif action == export_action:
            self.export_to_browser()

    def update_top_info_bar(self):
        if self.working_file_name != '':
            self.top_info_bar.setText(self.working_file_name)
        else:
            self.top_info_bar.setText('New File')

    def toggle_fullscreen(self):
        ''' Toggles fullscreen on and off '''

        if self.isFullScreen():
            self.showNormal()
        else:
            self.showFullScreen()
Ejemplo n.º 5
0
class MainWindow12(QMainWindow):
    def __init__(self):
        super(MainWindow12, self).__init__()

        self.commandslist = []
        self.tracker = 0
        os.chdir(os.path.expanduser(path12))
        #        print(os.getcwd())
        self.name = (str(getpass.getuser()) + "@" + str(socket.gethostname()) +
                     ":" + str(os.getcwd()) + "$ ")
        self.setWindowTitle('PyQt5Terminal')
        self.setWindowIcon(QIcon.fromTheme("terminal-emulator"))
        self.process = QProcess(self)
        self.process.setProcessChannelMode(QProcess.MergedChannels)
        self.process.readyRead.connect(self.dataReady)
        self.process.readyReadStandardError.connect(
            self.onReadyReadStandardError)
        self.process.readyReadStandardOutput.connect(
            self.onReadyReadStandardOutput)
        self.process.finished.connect(self.isFinished)
        self.process.setWorkingDirectory(os.getcwd())
        self.createStatusBar()

        self.commandfield = QPlainTextEdit()
        self.commandfield.setLineWrapMode(QPlainTextEdit.NoWrap)
        self.commandfield.setFixedHeight(44)
        self.commandfield.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.commandfield.setAcceptDrops(True)
        self.cursor = self.commandfield.textCursor()

        self.textWindow = QPlainTextEdit(self)
        #self.setStyleSheet(mystylesheet(self))

        self.textWindow.setReadOnly(True)
        layout = QVBoxLayout()
        layout.addWidget(self.textWindow)
        layout.addWidget(self.commandfield)
        self.wid = QWidget()
        self.wid.setLayout(layout)
        self.setCentralWidget(self.wid)
        self.setGeometry(0, 0, 600, 500)
        self.commandfield.setPlainText(self.name)
        self.cursorEnd()
        self.commandfield.setFocus()

        self.copySelectedTextAction = QAction(QIcon.fromTheme("edit-copy"),
                                              "Copy",
                                              shortcut="Shift+Ctrl+c",
                                              triggered=self.copyText)
        self.textWindow.addAction(self.copySelectedTextAction)
        self.pasteTextAction = QAction(QIcon.fromTheme("edit-paste"),
                                       "Copy",
                                       shortcut="Shift+Ctrl+v",
                                       triggered=self.pasteText)
        self.commandfield.addAction(self.pasteTextAction)

        self.cancelAction = QAction("Cancel",
                                    shortcut="Ctrl+c",
                                    triggered=self.killProcess)
        self.textWindow.addAction(self.cancelAction)

        self.commandfield.installEventFilter(self)
        #        self.textWindow.installEventFilter(self)
        QApplication.setCursorFlashTime(1000)
        self.cursorEnd()
        print(self.process.workingDirectory())
        self.settings = QSettings("QTerminal", "QTerminal")
        self.readSettings()

    def closeEvent(self, e):
        self.writeSettings()

    def cursorEnd(self):
        self.name = (str(getpass.getuser()) + "@" + str(socket.gethostname()) +
                     ":" + str(os.getcwd()) + "$ ")
        self.commandfield.setPlainText(self.name)
        cursor = self.commandfield.textCursor()
        cursor.movePosition(11, 0)
        self.commandfield.setTextCursor(cursor)
        self.commandfield.setFocus()

    def eventFilter(self, source, event):
        if source == self.commandfield:
            if (event.type() == QEvent.DragEnter):
                event.accept()
                return True
            elif (event.type() == QEvent.Drop):
                print('Drop')
                self.setDropEvent(event)
                return True
            elif (event.type() == QEvent.KeyPress):
                cursor = self.commandfield.textCursor()
                #                print('key press:', (event.key(), event.text()))
                if event.key() == Qt.Key_Backspace:
                    if cursor.positionInBlock() <= len(self.name):
                        return True
                    else:
                        return False

                elif event.key() == Qt.Key_Return:
                    self.run()
                    return True

                elif event.key() == Qt.Key_Left:
                    if cursor.positionInBlock() <= len(self.name):
                        return True
                    else:
                        return False

                elif event.key() == Qt.Key_Delete:
                    if cursor.positionInBlock() <= len(self.name) - 1:
                        return True
                    else:
                        return False

                elif event.modifiers() == Qt.ControlModifier and event.key(
                ) == Qt.Key_C:
                    self.killProcess()
                    return True

                elif event.key() == Qt.Key_Up:
                    try:
                        if self.tracker != 0:
                            cursor.select(QTextCursor.BlockUnderCursor)
                            cursor.removeSelectedText()
                            self.commandfield.appendPlainText(self.name)

                        self.commandfield.insertPlainText(
                            self.commandslist[self.tracker])
                        self.tracker -= 1

                    except IndexError:
                        self.tracker = 0
                    return True

                elif event.key() == Qt.Key_Down:
                    try:
                        if self.tracker != 0:
                            cursor.select(QTextCursor.BlockUnderCursor)
                            cursor.removeSelectedText()
                            self.commandfield.appendPlainText(self.name)

                        self.commandfield.insertPlainText(
                            self.commandslist[self.tracker])
                        self.tracker += 1

                    except IndexError:
                        self.tracker = 0
                    return True

                else:
                    return False
            else:
                return False
        else:
            return False

    def copyText(self):
        self.textWindow.copy()

    def pasteText(self):
        self.commandfield.paste()

    def killProcess(self):
        print("cancelled")
        self.process.kill()
        self.textWindow.appendPlainText("cancelled")
        self.cursorEnd()

    def createStatusBar(self):
        sysinfo = QSysInfo()
        myMachine = "current CPU Architecture: " + sysinfo.currentCpuArchitecture(
        ) + " *** " + sysinfo.prettyProductName(
        ) + " *** " + sysinfo.kernelType() + " " + sysinfo.kernelVersion()
        self.statusBar().showMessage(myMachine, 0)

    def setDropEvent(self, event):
        self.commandfield.setFocus()
        if event.mimeData().hasUrls():
            f = str(event.mimeData().urls()[0].toLocalFile())
            print("is file:", f)
            if " " in f:
                self.commandfield.insertPlainText("'{}'".format(f))
            else:
                self.commandfield.insertPlainText(f)
            event.accept()
        elif event.mimeData().hasText():
            ft = event.mimeData().text()
            print("is text:", ft)
            if " " in ft:
                self.commandfield.insertPlainText("'{}'".format(ft))
            else:
                self.commandfield.insertPlainText(ft)
        else:
            event.ignore()

    def run(self):
        print("started")
        cli = []
        cmd = ""
        t = ""
        self.textWindow.setFocus()
        self.textWindow.appendPlainText(self.commandfield.toPlainText())
        cli = shlex.split(self.commandfield.toPlainText().replace(
            self.name, '').replace("'", '"'),
                          posix=False)
        cmd = str(cli[0])  ### is the executable

        if cmd == "exit":
            quit()

        elif cmd == "cd":
            del cli[0]
            path = " ".join(cli)
            os.chdir(os.path.abspath(path))
            self.process.setWorkingDirectory(os.getcwd())
            print("workingDirectory:", self.process.workingDirectory())
            self.cursorEnd()
        else:
            self.process.setWorkingDirectory(os.getcwd())
            print("workingDirectory", self.process.workingDirectory())
            del cli[0]
            if (QStandardPaths.findExecutable(cmd)):
                self.commandslist.append(
                    self.commandfield.toPlainText().replace(self.name, ""))
                print("command", cmd, "found")
                t = " ".join(cli)
                if self.process.state() != 2:
                    #self.process.waitForStarted()
                    self.process.waitForReadyRead()
                    self.process.waitForFinished()
                    if "|" in t or ">" in t or "<" in t:
                        print("special characters")
                        self.process.start('sh -c "' + cmd + ' ' + t + '"')
                        print("running", ('sh -c "' + cmd + ' ' + t + '"'))
                    else:
                        self.process.start(cmd + " " + t)
                        print("running", (cmd + " " + t))
            else:
                print("command not found ...")
                self.textWindow.appendPlainText("command not found ...")
                self.cursorEnd()

    def dataReady(self):
        out = ""
        try:
            out = str(self.process.readAll(), encoding='utf8').rstrip()
        except TypeError:
            out = str(self.process.readAll()).rstrip()
            self.textWindow.moveCursor(self.cursor.Start)  ### changed
        self.textWindow.appendPlainText(out)

    def onReadyReadStandardError(self):
        self.error = self.process.readAllStandardError().data().decode()
        self.textWindow.appendPlainText(self.error.strip('\n'))
        self.cursorEnd()

    def onReadyReadStandardOutput(self):
        self.result = self.process.readAllStandardOutput().data().decode()
        self.textWindow.appendPlainText(self.result.strip('\n'))
        self.cursorEnd()
        self.state = self.process.state()

    def isFinished(self):
        print("finished")
        self.name = (str(getpass.getuser()) + "@" + str(socket.gethostname()) +
                     ":" + str(os.getcwd()) + "$ ")
        self.commandfield.setPlainText(self.name)
        self.cursorEnd()

    def readSettings(self):
        if self.settings.contains("commands"):
            self.commandslist = self.settings.value("commands")
        if self.settings.contains("pos"):
            pos = self.settings.value("pos", QPoint(200, 200))
            self.move(pos)
        if self.settings.contains("size"):
            size = self.settings.value("size", QSize(400, 400))
            self.resize(size)

    def writeSettings(self):
        self.settings.setValue("commands", self.commandslist)
        self.settings.setValue("pos", self.pos())
        self.settings.setValue("size", self.size())
Ejemplo n.º 6
0
class LogWindow(QMainWindow):
    emit_msg = pyqtSignal(str)

    def __init__(self,
                 level: int = logging.INFO,
                 window_title: str = "Python log",
                 logger: logging.Logger = None,
                 min_width: int = 800,
                 min_height: int = 400,
                 maximum_block_count: int = 1000) -> None:
        super().__init__()
        self.setStyleSheet(LOGEDIT_STYLESHEET)

        self.handler = HtmlColorHandler(self.log_message, level)
        self.may_close = False
        self.set_may_close(self.may_close)

        self.setWindowTitle(window_title)
        if min_width:
            self.setMinimumWidth(min_width)
        if min_height:
            self.setMinimumHeight(min_height)

        log_group = StyledQGroupBox("Log")
        log_layout_1 = QVBoxLayout()
        log_layout_2 = QHBoxLayout()
        self.log = QPlainTextEdit()
        # QPlainTextEdit better than QTextEdit because it supports
        # maximumBlockCount while still allowing HTML (via appendHtml,
        # not insertHtml).
        self.log.setReadOnly(True)
        self.log.setLineWrapMode(QPlainTextEdit.NoWrap)
        self.log.setMaximumBlockCount(maximum_block_count)
        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()
        log_layout_1.addWidget(self.log)
        log_layout_1.addLayout(log_layout_2)
        log_group.setLayout(log_layout_1)

        main_widget = QWidget(self)
        self.setCentralWidget(main_widget)
        main_layout = QVBoxLayout(main_widget)
        main_layout.addWidget(log_group)

        self.emit_msg.connect(self.log_internal)

        if logger:
            logger.addHandler(self.get_handler())

    def get_handler(self) -> logging.Handler:
        return self.handler

    def set_may_close(self, may_close: bool) -> None:
        # log.debug("LogWindow: may_close({})".format(may_close))
        self.may_close = may_close
        # return
        if may_close:
            self.setWindowFlags(self.windowFlags() | Qt.WindowCloseButtonHint)
        else:
            self.setWindowFlags(self.windowFlags() & ~Qt.WindowCloseButtonHint)
        self.show()
        # ... or it will be hidden (in a logical not a real way!) by
        # setWindowFlags(), and thus mess up the logic for the whole Qt app
        # exiting (since qt_app.exec_() runs until there are no more windows
        # being shown).

    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)

    # noinspection PyPep8Naming
    def closeEvent(self, event: QCloseEvent) -> None:
        """Trap exit."""
        if not self.may_close:
            # log.debug("LogWindow: ignore closeEvent")
            event.ignore()
        else:
            # log.debug("LogWindow: accept closeEvent")
            event.accept()

    def log_message(self, html: str) -> None:
        # Jump threads via a signal
        self.emit_msg.emit(html)

    @pyqtSlot(str)
    def log_internal(self, html: str) -> None:
        # self.log.moveCursor(QTextCursor.End)
        # self.log.insertHtml(html)
        self.log.appendHtml(html)
        # self.scroll_to_end_of_log()
        # ... unnecessary; if you're at the end, it scrolls, and if you're at
        # the top, it doesn't bug you.

    @pyqtSlot()
    def exit(self) -> None:
        # log.debug("LogWindow: exit")
        self.may_close = True
        # closed = QMainWindow.close(self)
        # log.debug("closed: {}".format(closed))
        QMainWindow.close(self)

    @pyqtSlot()
    def may_exit(self) -> None:
        # log.debug("LogWindow: may_exit")
        self.set_may_close(True)
Ejemplo n.º 7
0
class TextboxWindow(QDialog):
    def __init__(self,
                 text="",
                 file_extension="txt",
                 file_type="Text file",
                 encoding="utf-8"):
        super().__init__()

        self.text = text
        self.file_extension = file_extension
        self.file_type = file_type
        self.encoding = encoding

        self.control_held = False

        self.setWindowFlags(self.windowFlags()
                            & ~Qt.WindowContextHelpButtonHint)

        vbox = QVBoxLayout()

        self.macrotext = QPlainTextEdit()
        self.macrotext.setPlainText(text)
        self.macrotext.selectAll()

        self.btn_apply = QToolButton()
        self.btn_apply.setText(tr("TextboxWindow", "Apply"))
        self.btn_apply.setToolButtonStyle(Qt.ToolButtonTextOnly)
        self.btn_apply.clicked.connect(self.on_apply)

        self.btn_cancel = QToolButton()
        self.btn_cancel.setText(tr("TextboxWindow", "Cancel"))
        self.btn_cancel.setToolButtonStyle(Qt.ToolButtonTextOnly)
        self.btn_cancel.clicked.connect(self.on_cancel)

        self.btn_copy = QToolButton()
        self.btn_copy.setText(tr("TextboxWindow", "Copy"))
        self.btn_copy.setToolButtonStyle(Qt.ToolButtonTextOnly)
        self.btn_copy.clicked.connect(self.on_copy)

        self.btn_paste = QToolButton()
        self.btn_paste.setText(tr("TextboxWindow", "Paste"))
        self.btn_paste.setToolButtonStyle(Qt.ToolButtonTextOnly)
        self.btn_paste.clicked.connect(self.on_paste)

        bottom_buttons = QHBoxLayout()
        bottom_buttons.setContentsMargins(0, 0, 0, 0)
        bottom_buttons.addWidget(self.btn_copy)
        bottom_buttons.addWidget(self.btn_paste)
        bottom_buttons.addSpacing(15)
        bottom_buttons.addStretch()
        bottom_buttons.addWidget(self.btn_apply)
        bottom_buttons.addWidget(self.btn_cancel)

        self.bottom_widget = QWidget()
        self.bottom_widget.setLayout(bottom_buttons)

        vbox.addWidget(self.macrotext, stretch=1)
        vbox.addWidget(self.bottom_widget)

        self.setLayout(vbox)
        self.setWindowFlags(self.windowFlags())

    def on_apply(self):
        self.accept()

    def on_cancel(self):
        self.reject()

    def on_select_all(self):
        self.macrotext.selectAll()

    def on_copy(self):
        self.macrotext.copy()

    def on_paste(self):
        self.macrotext.paste()

    def on_export(self):
        dialog = QFileDialog()
        dialog.setDefaultSuffix(self.file_extension)
        dialog.setAcceptMode(QFileDialog.AcceptSave)
        dialog.setNameFilters(
            ["{} (*.{})".format(self.file_type, self.file_extension)])

        if dialog.exec_() == QDialog.Accepted:
            with open(dialog.selectedFiles()[0], "wb") as outf:
                outf.write(self.macrotext.toPlainText().encode(self.encoding))

    def on_import(self):
        dialog = QFileDialog()
        dialog.setDefaultSuffix(self.file_extension)
        dialog.setAcceptMode(QFileDialog.AcceptOpen)
        dialog.setNameFilters(
            ["{} (*.{})".format(self.file_type, self.file_extension)])

        if dialog.exec_() == QDialog.Accepted:
            with open(dialog.selectedFiles()[0], "rb") as inf:
                self.macrotext.setPlainText(inf.read().decode(self.encoding))

    def getText(self):
        return self.macrotext.toPlainText()

    def keyPressEvent(self, ev):
        if ev.key() == Qt.Key_Escape:
            self.reject()

        if ev.key() == Qt.Key_Control:
            self.control_held = True

        if self.control_held:
            if ev.key() == Qt.Key_O:
                self.on_import()

            if ev.key() == Qt.Key_S:
                self.on_export()

    def keyReleaseEvent(self, ev):
        if ev.key() == Qt.Key_Control:
            self.control_held = False
Ejemplo n.º 8
0
class LogWindow(QMainWindow):
    emit_msg = pyqtSignal(str)

    def __init__(self,
                 level: int = logging.INFO,
                 window_title: str = "Python log",
                 logger: logging.Logger = None,
                 min_width: int = 800,
                 min_height: int = 400,
                 maximum_block_count: int = 1000) -> None:
        super().__init__()
        self.setStyleSheet(LOGEDIT_STYLESHEET)

        self.handler = HtmlColorHandler(self.log_message, level)
        self.may_close = False
        self.set_may_close(self.may_close)

        self.setWindowTitle(window_title)
        if min_width:
            self.setMinimumWidth(min_width)
        if min_height:
            self.setMinimumHeight(min_height)

        log_group = StyledQGroupBox("Log")
        log_layout_1 = QVBoxLayout()
        log_layout_2 = QHBoxLayout()
        self.log = QPlainTextEdit()
        # QPlainTextEdit better than QTextEdit because it supports
        # maximumBlockCount while still allowing HTML (via appendHtml,
        # not insertHtml).
        self.log.setReadOnly(True)
        self.log.setLineWrapMode(QPlainTextEdit.NoWrap)
        self.log.setMaximumBlockCount(maximum_block_count)
        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()
        log_layout_1.addWidget(self.log)
        log_layout_1.addLayout(log_layout_2)
        log_group.setLayout(log_layout_1)

        main_widget = QWidget(self)
        self.setCentralWidget(main_widget)
        main_layout = QVBoxLayout(main_widget)
        main_layout.addWidget(log_group)

        self.emit_msg.connect(self.log_internal)

        if logger:
            logger.addHandler(self.get_handler())

    def get_handler(self) -> logging.Handler:
        return self.handler

    def set_may_close(self, may_close: bool) -> None:
        # log.debug("LogWindow: may_close({})".format(may_close))
        self.may_close = may_close
        # return
        if may_close:
            self.setWindowFlags(self.windowFlags() | Qt.WindowCloseButtonHint)
        else:
            self.setWindowFlags(self.windowFlags() & ~Qt.WindowCloseButtonHint)
        self.show()
        # ... or it will be hidden (in a logical not a real way!) by
        # setWindowFlags(), and thus mess up the logic for the whole Qt app
        # exiting (since qt_app.exec_() runs until there are no more windows
        # being shown).

    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)

    # noinspection PyPep8Naming
    def closeEvent(self, event: QCloseEvent) -> None:
        """Trap exit."""
        if not self.may_close:
            # log.debug("LogWindow: ignore closeEvent")
            event.ignore()
        else:
            # log.debug("LogWindow: accept closeEvent")
            event.accept()

    def log_message(self, html: str) -> None:
        # Jump threads via a signal
        self.emit_msg.emit(html)

    @pyqtSlot(str)
    def log_internal(self, html: str) -> None:
        # self.log.moveCursor(QTextCursor.End)
        # self.log.insertHtml(html)
        self.log.appendHtml(html)
        # self.scroll_to_end_of_log()
        # ... unnecessary; if you're at the end, it scrolls, and if you're at
        # the top, it doesn't bug you.

    @pyqtSlot()
    def exit(self) -> None:
        # log.debug("LogWindow: exit")
        self.may_close = True
        # closed = QMainWindow.close(self)
        # log.debug("closed: {}".format(closed))
        QMainWindow.close(self)

    @pyqtSlot()
    def may_exit(self) -> None:
        # log.debug("LogWindow: may_exit")
        self.set_may_close(True)