class ProgressWindow(FramelessWindow): def __init__(self, parent, generator): super(ProgressWindow, self).__init__(parent) self.__generator = generator self.__progress_view = QPlainTextEdit(self) self.__highlighter = Highlighter(self.__progress_view.document()) self.__progress_view.textChanged.connect(self.__on_progress_text) self.addContentWidget(self.__progress_view) self.menu = QMenu(self.__generator, self) close_action = QAction("Close", self.menu) close_action.triggered.connect(self.close) self.menu.addAction(close_action) self.addMenu(self.menu) def generator(self): return self.__generator @Slot(str) def appendProgress(self, text): self.__progress_view.appendPlainText(text) @Slot() def __on_progress_text(self): self.__progress_view.verticalScrollBar().setValue( self.__progress_view.verticalScrollBar().maximum())
class ShellWidget(QWidget): run_shell = Signal(Bot, str) def __init__(self, bot, parent): super(ShellWidget, self).__init__(parent) self.bot = bot self.widget_layout = QVBoxLayout(self) self.setLayout(self.widget_layout) self.output_widget = QPlainTextEdit(self) self.output_widget.setReadOnly(True) self.highlighter = ShellHighlighter(self.output_widget.document()) self.widget_layout.addWidget(self.output_widget) self.input_widget = QLineEdit(self) self.widget_layout.addWidget(self.input_widget) self.send_button = QPushButton(self) self.send_button.setText("Send") self.send_button.clicked.connect(self.on_send_button_clicked) self.widget_layout.addWidget(self.send_button) @Slot() def on_send_button_clicked(self): text = self.input_widget.text() self.output_widget.appendPlainText("$: {}".format(text)) self.run_shell.emit(self.bot, text) self.input_widget.clear() @Slot(Bot, str) def append_shell(self, bot, message): if self.bot == bot: self.output_widget.appendPlainText(message)
def __init__(self, parent, history): super().__init__(parent=parent) self.setWindowTitle("History") layout = QVBoxLayout() text = QPlainTextEdit() font = QFont() font.setFamily("monospace") font.setStyleHint(QFont.Monospace) text.setFont(font) highlighter = PythonHighlighter(text.document()) # noqa: F841 text.setReadOnly(True) text.setPlainText(history) layout.addWidget(text) buttonbox = QDialogButtonBox(QDialogButtonBox.Ok) clipboardbutton = QPushButton("Copy to clipboard") buttonbox.addButton(clipboardbutton, QDialogButtonBox.ActionRole) clipboard = QGuiApplication.clipboard() clipboardbutton.clicked.connect( lambda: clipboard.setText(history + "\n")) layout.addWidget(buttonbox) self.setLayout(layout) buttonbox.accepted.connect(self.accept) self.resize(700, 500)
class Terminal(QWidget): sigRunScript = Signal(str) def __init__(self, parent=None, options_button=None): QWidget.__init__(self, parent) self.setup_mainwidget() btn_layout = QHBoxLayout() for btn in self.setup_buttons(): btn.setIconSize(QSize(16, 16)) btn_layout.addWidget(btn) if options_button: btn_layout.addStretch() btn_layout.addWidget(options_button, Qt.AlignRight) layout = create_plugin_layout(btn_layout, self.mainwidget) self.setLayout(layout) def setup_mainwidget(self): lblRunFile = QLabel('Run File') self.lineRunFile = QLineEdit() lblOpenFile = QLabel('Open File') self.lineOpenFile = QLineEdit() fbox = QFormLayout() fbox.addRow(lblRunFile, self.lineRunFile) fbox.addRow(lblOpenFile, self.lineOpenFile) text = "# myprint(self.database) \n" +\ "# myprint(self.treebase)" self.code_view = QPlainTextEdit(text, self) # font = QFont() # font.setFamily(_fromUtf8("FreeMono")) # self.code_view.setFont(font) vbox = QVBoxLayout() vbox.addLayout(fbox) vbox.addWidget(self.code_view) self.mainwidget = QWidget(self) self.mainwidget.setLayout(vbox) # connect syntax highlighter self.pyhigh = PythonHighlighter(self.code_view.document()) self.code_view.textChanged.connect(self.highlightWhileTyping) def setup_buttons(self): # TODO how to fix this bug? # shortcut in plugin conflicts with shortcut in mainwindow # QAction::eventFilter: Ambiguous shortcut overload: Ctrl+O openfile_btn = create_toolbutton(self, icon=ima.icon('fileopen'), tip=_('Open file'), shortcut="Ctrl+O", triggered=self.open_file) savefile_btn = create_toolbutton(self, icon=ima.icon('filesave'), tip=_('Save to new file'), shortcut="Ctrl+S", triggered=self.save_file) runfile_btn = create_toolbutton(self, icon=ima.icon('run_file'), tip=_('Run code in file'), triggered=self.run_file) run_btn = create_toolbutton(self, icon=ima.icon('run'), tip=_('Run code in view'), shortcut="Ctrl+R", triggered=self.emit_script) help_btn = create_toolbutton_help(self, triggered=self.show_help) buttons = (openfile_btn, savefile_btn, runfile_btn, run_btn, help_btn) return buttons def show_help(self): QMessageBox.information( self, _('How to use'), _("The project console provides API to the project.<br>" "For example, try run myprint(self.database).<br>" "Due to Cython compiler, use myprint() for print().<br>" "<b>TODO</b> add more.<br>")) def highlightWhileTyping(self): # Instantiate class PythonHighlighter everytime text is changed # RecursionError: maximum recursion depth exceeded... # text = self.code_view.toPlainText() # highlight = PythonHighlighter(self.code_view.document()) # self.code_view.setPlainText(text) text = self.code_view.toPlainText() self.pyhigh.highlightBlock(text) def run_file(self): """Run a script file without open it. Assume edited in a user-favorite text editor. """ fn = self.lineRunFile.text() text = open(fn).read() self.sigRunScript.emit(text) def open_file(self): if hasattr(self, 'workdir'): workdir = self.workdir else: workdir = os.getcwd() fn = QFileDialog.getOpenFileName(self, 'Open File', workdir) # If hit Cancel at dialog, fn is string of length zero. # If still go ahead open(fn), receive FileNotFoundError. if len(fn) > 0: # Windows returns tuple fn = fn[0] if isinstance(fn, tuple) else fn self.lineOpenFile.setText(fn) text = open(fn).read() self.code_view.setPlainText(text) def save_file(self): if hasattr(self, 'workdir'): workdir = self.workdir else: workdir = os.getcwd() fn = QFileDialog.getSaveFileName(self, 'Save File', workdir) if len(fn) > 0: text = self.code_view.toPlainText() with open(fn, 'w') as f: f.write(text) def emit_script(self): """ Send script text to parent to run. """ text = self.code_view.toPlainText() print2logger = 'from ezcad.utils.functions import myprint \n' text = print2logger + text self.sigRunScript.emit(text) def run_script(self): """ Deprecated run at local with limited data access""" text = self.code_view.toPlainText() try: eval(text) except SyntaxError: exec(text) def set_work_dir(self, workdir): self.workdir = workdir
class FileDialog(QDialog): def __init__(self, file_name, job_name, job_number, realization, iteration, parent=None): super(FileDialog, self).__init__(parent) self.setWindowTitle("{} # {} Realization: {} Iteration: {}".format( job_name, job_number, realization, iteration)) try: self._file = open(file_name, "r") except OSError as error: self._mb = QMessageBox( QMessageBox.Critical, "Error opening file", error.strerror, QMessageBox.Ok, self, ) self._mb.finished.connect(self.accept) self._mb.show() return self._view = QPlainTextEdit() self._view.setReadOnly(True) self._view.setWordWrapMode(QTextOption.NoWrap) # for moving the actual slider self._view.verticalScrollBar().sliderMoved.connect(self._update_cursor) # for mouse wheel and keyboard arrows self._view.verticalScrollBar().valueChanged.connect( self._update_cursor) self._view.setFont(QFontDatabase.systemFont(QFontDatabase.FixedFont)) self._follow_mode = False self._init_layout() self._init_thread() self.show() @Slot() def _stop_thread(self): self._thread.quit() self._thread.wait() def _init_layout(self): self.setMinimumWidth(600) self.setMinimumHeight(400) dialog_buttons = QDialogButtonBox(QDialogButtonBox.Ok) dialog_buttons.accepted.connect(self.accept) self._copy_all_button = dialog_buttons.addButton( "Copy All", QDialogButtonBox.ActionRole) self._copy_all_button.clicked.connect(self._copy_all) self._follow_button = dialog_buttons.addButton( "Follow", QDialogButtonBox.ActionRole) self._follow_button.setCheckable(True) self._follow_button.toggled.connect(self._enable_follow_mode) self._enable_follow_mode(self._follow_mode) layout = QVBoxLayout(self) layout.addWidget(self._view) layout.addWidget(dialog_buttons) def _init_thread(self): self._thread = QThread() self._worker = FileUpdateWorker(self._file) self._worker.moveToThread(self._thread) self._worker.read.connect(self._append_text) self._thread.started.connect(self._worker.setup) self._thread.finished.connect(self._worker.stop) self._thread.finished.connect(self._worker.deleteLater) self.finished.connect(self._stop_thread) self._thread.start() def _copy_all(self) -> None: text = self._view.toPlainText() QApplication.clipboard().setText(text, QClipboard.Clipboard) pass def _update_cursor(self, value: int) -> None: if not self._view.textCursor().hasSelection(): block = self._view.document().findBlockByLineNumber(value) cursor = QTextCursor(block) self._view.setTextCursor(cursor) def _enable_follow_mode(self, enable: bool) -> None: if enable: self._view.moveCursor(QTextCursor.End) self._view.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self._view.verticalScrollBar().setDisabled(True) self._view.setTextInteractionFlags(Qt.NoTextInteraction) self._follow_mode = True else: self._view.verticalScrollBar().setDisabled(False) self._view.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded) self._view.setTextInteractionFlags(Qt.TextSelectableByMouse | Qt.TextSelectableByKeyboard) self._follow_mode = False def _append_text(self, text: str) -> None: # Remove trailing newline as appendPlainText adds this if text[-1:] == "\n": text = text[:-1] if self._follow_mode: self._view.moveCursor(QTextCursor.End) self._view.appendPlainText(text)