From 63e22cf3ee7202a1bd6e0e1e0ef4157bcac51c23 Mon Sep 17 00:00:00 2001 From: Marius Stanciu Date: Wed, 13 Nov 2019 02:06:16 +0200 Subject: [PATCH] - trying to improve the performance of View CNC Code command by using QPlainTextEdit; made the mods for it - when using the Find function in the TextEditor and the result reach the bottom of the document, the next find will be the first in the document (before it defaulted to the beginning of the document) --- FlatCAMObj.py | 8 +- README.md | 5 + flatcamEditors/FlatCAMTextEditor.py | 23 ++-- flatcamGUI/GUIElements.py | 172 ++++++++++++++++++++++++++++ postprocessors/PP_ISEL_CNC.py | 2 +- 5 files changed, 197 insertions(+), 13 deletions(-) diff --git a/FlatCAMObj.py b/FlatCAMObj.py index 03ab1921..f003d9f2 100644 --- a/FlatCAMObj.py +++ b/FlatCAMObj.py @@ -6099,7 +6099,7 @@ class FlatCAMCNCjob(FlatCAMObj, CNCjob): else: self.app.gcode_edited = gco - self.gcode_editor_tab = TextEditor(app=self.app) + self.gcode_editor_tab = TextEditor(app=self.app, plain_text=True) # add the tab if it was closed self.app.ui.plot_tab_area.addTab(self.gcode_editor_tab, '%s' % _("Code Editor")) @@ -6129,8 +6129,7 @@ class FlatCAMCNCjob(FlatCAMObj, CNCjob): self.gcode_editor_tab.code_editor.append(proc_line) except Exception as e: log.debug('FlatCAMCNNJob.on_edit_code_click() -->%s' % str(e)) - self.app.inform.emit('[ERROR] %s %s' % - ('FlatCAMCNNJob.on_edit_code_click() -->', str(e))) + self.app.inform.emit('[ERROR] %s %s' % ('FlatCAMCNNJob.on_edit_code_click() -->', str(e))) return self.gcode_editor_tab.code_editor.moveCursor(QtGui.QTextCursor.Start) @@ -6328,8 +6327,7 @@ class FlatCAMCNCjob(FlatCAMObj, CNCjob): # if it did not find 'G20' and it did not find 'G21' then there is an error and return if g_idx == -1: - self.app.inform.emit('[ERROR_NOTCL] %s' % - _("G-code does not have a units code: either G20 or G21")) + self.app.inform.emit('[ERROR_NOTCL] %s' % _("G-code does not have a units code: either G20 or G21")) return footer = self.app.defaults['cncjob_footer'] diff --git a/README.md b/README.md index ede42df3..26cf390b 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,11 @@ CAD program, and create G-Code for Isolation routing. ================================================= +13.11.2019 + +- trying to improve the performance of View CNC Code command by using QPlainTextEdit; made the mods for it +- when using the Find function in the TextEditor and the result reach the bottom of the document, the next find will be the first in the document (before it defaulted to the beginning of the document) + 12.11.2019 - added two new postprocessor files for ISEL CNC and for BERTA CNC diff --git a/flatcamEditors/FlatCAMTextEditor.py b/flatcamEditors/FlatCAMTextEditor.py index 4cf271f3..fd7ab3e5 100644 --- a/flatcamEditors/FlatCAMTextEditor.py +++ b/flatcamEditors/FlatCAMTextEditor.py @@ -19,7 +19,7 @@ if '_' not in builtins.__dict__: class TextEditor(QtWidgets.QWidget): - def __init__(self, app, text=None): + def __init__(self, app, text=None, plain_text=None): super().__init__() self.app = app @@ -39,12 +39,20 @@ class TextEditor(QtWidgets.QWidget): self.work_editor_layout.setContentsMargins(2, 2, 2, 2) self.t_frame.setLayout(self.work_editor_layout) - self.code_editor = FCTextAreaExtended() - stylesheet = """ - QTextEdit { selection-background-color:yellow; - selection-color:black; - } - """ + if plain_text: + self.code_editor = FCPlainTextAreaExtended() + stylesheet = """ + QPlainTextEdit { selection-background-color:yellow; + selection-color:black; + } + """ + else: + self.code_editor = FCTextAreaExtended() + stylesheet = """ + QTextEdit { selection-background-color:yellow; + selection-color:black; + } + """ self.code_editor.setStyleSheet(stylesheet) @@ -233,6 +241,7 @@ class TextEditor(QtWidgets.QWidget): r = self.code_editor.find(str(text_to_be_found), flags) if r is False: self.code_editor.moveCursor(QtGui.QTextCursor.Start) + r = self.code_editor.find(str(text_to_be_found), flags) def handleReplaceGCode(self): self.app.report_usage("handleReplaceGCode()") diff --git a/flatcamGUI/GUIElements.py b/flatcamGUI/GUIElements.py index 5a93b096..63d9d515 100644 --- a/flatcamGUI/GUIElements.py +++ b/flatcamGUI/GUIElements.py @@ -884,6 +884,178 @@ class FCTextAreaExtended(QtWidgets.QTextEdit): self.setTextCursor(cursor) +class FCPlainTextAreaExtended(QtWidgets.QPlainTextEdit): + def __init__(self, parent=None): + super().__init__(parent) + + self.completer = MyCompleter() + + self.model = QtCore.QStringListModel() + self.completer.setModel(self.model) + self.set_model_data(keyword_list=[]) + self.completer.insertText.connect(self.insertCompletion) + + self.completer_enable = False + + def append(self, text): + """ + Added this to make this subclass compatible with FCTextAreaExtended + :param text: string + :return: + """ + self.appendPlainText(text) + + def set_model_data(self, keyword_list): + self.model.setStringList(keyword_list) + + def insertCompletion(self, completion): + tc = self.textCursor() + extra = (len(completion) - len(self.completer.completionPrefix())) + + # don't insert if the word is finished but add a space instead + if extra == 0: + tc.insertText(' ') + self.completer.popup().hide() + return + + tc.movePosition(QTextCursor.Left) + tc.movePosition(QTextCursor.EndOfWord) + tc.insertText(completion[-extra:]) + # add a space after inserting the word + tc.insertText(' ') + self.setTextCursor(tc) + self.completer.popup().hide() + + def focusInEvent(self, event): + if self.completer: + self.completer.setWidget(self) + QtWidgets.QPlainTextEdit.focusInEvent(self, event) + + def set_value(self, val): + self.setPlainText(val) + + def get_value(self): + self.toPlainText() + + def insertFromMimeData(self, data): + """ + Reimplemented such that when SHIFT is pressed and doing click Paste in the contextual menu, the '\' symbol + is replaced with the '/' symbol. That's because of the difference in path separators in Windows and TCL + :param data: + :return: + """ + modifier = QtWidgets.QApplication.keyboardModifiers() + if modifier == Qt.ShiftModifier: + text = data.text() + text = text.replace('\\', '/') + self.insertPlainText(text) + else: + self.insertPlainText(data.text()) + + def keyPressEvent(self, event): + """ + Reimplemented so the CTRL + SHIFT + V shortcut key combo will paste the text but replacing '\' with '/' + :param event: + :return: + """ + key = event.key() + modifier = QtWidgets.QApplication.keyboardModifiers() + + if modifier & Qt.ControlModifier and modifier & Qt.ShiftModifier: + if key == QtCore.Qt.Key_V: + clipboard = QtWidgets.QApplication.clipboard() + clip_text = clipboard.text() + clip_text = clip_text.replace('\\', '/') + self.insertPlainText(clip_text) + + if modifier & Qt.ControlModifier and key == Qt.Key_Slash: + self.comment() + + tc = self.textCursor() + if (key == Qt.Key_Tab or key == Qt.Key_Enter or key == Qt.Key_Return) and self.completer.popup().isVisible(): + self.completer.insertText.emit(self.completer.getSelected()) + self.completer.setCompletionMode(QCompleter.PopupCompletion) + return + elif key == Qt.Key_BraceLeft: + tc.insertText('{}') + self.moveCursor(QtGui.QTextCursor.Left) + elif key == Qt.Key_BracketLeft: + tc.insertText('[]') + self.moveCursor(QtGui.QTextCursor.Left) + elif key == Qt.Key_ParenLeft: + tc.insertText('()') + self.moveCursor(QtGui.QTextCursor.Left) + + elif key == Qt.Key_BraceRight: + tc.select(QtGui.QTextCursor.WordUnderCursor) + if tc.selectedText() == '}': + tc.movePosition(QTextCursor.Right) + self.setTextCursor(tc) + else: + tc.clearSelection() + self.textCursor().insertText('}') + elif key == Qt.Key_BracketRight: + tc.select(QtGui.QTextCursor.WordUnderCursor) + if tc.selectedText() == ']': + tc.movePosition(QTextCursor.Right) + self.setTextCursor(tc) + else: + tc.clearSelection() + self.textCursor().insertText(']') + elif key == Qt.Key_ParenRight: + tc.select(QtGui.QTextCursor.WordUnderCursor) + if tc.selectedText() == ')': + tc.movePosition(QTextCursor.Right) + self.setTextCursor(tc) + else: + tc.clearSelection() + self.textCursor().insertText(')') + else: + super(FCPlainTextAreaExtended, self).keyPressEvent(event) + + if self.completer_enable: + tc.select(QTextCursor.WordUnderCursor) + cr = self.cursorRect() + + if len(tc.selectedText()) > 0: + self.completer.setCompletionPrefix(tc.selectedText()) + popup = self.completer.popup() + popup.setCurrentIndex(self.completer.completionModel().index(0, 0)) + + cr.setWidth(self.completer.popup().sizeHintForColumn(0) + + self.completer.popup().verticalScrollBar().sizeHint().width()) + self.completer.complete(cr) + else: + self.completer.popup().hide() + + def comment(self): + """ + Got it from here: + https://stackoverflow.com/questions/49898820/how-to-get-text-next-to-cursor-in-qtextedit-in-pyqt4 + :return: + """ + pos = self.textCursor().position() + self.moveCursor(QtGui.QTextCursor.StartOfLine) + line_text = self.textCursor().block().text() + if self.textCursor().block().text().startswith(" "): + # skip the white space + self.moveCursor(QtGui.QTextCursor.NextWord) + self.moveCursor(QtGui.QTextCursor.NextCharacter, QtGui.QTextCursor.KeepAnchor) + character = self.textCursor().selectedText() + if character == "#": + # delete # + self.textCursor().deletePreviousChar() + # delete white space + self.moveCursor(QtGui.QTextCursor.NextWord, QtGui.QTextCursor.KeepAnchor) + self.textCursor().removeSelectedText() + else: + self.moveCursor(QtGui.QTextCursor.PreviousCharacter, QtGui.QTextCursor.KeepAnchor) + self.textCursor().insertText("# ") + cursor = QtGui.QTextCursor(self.textCursor()) + cursor.setPosition(pos) + self.setTextCursor(cursor) + + class FCComboBox(QtWidgets.QComboBox): def __init__(self, parent=None, callback=None): diff --git a/postprocessors/PP_ISEL_CNC.py b/postprocessors/PP_ISEL_CNC.py index d23693d7..69d4e76b 100644 --- a/postprocessors/PP_ISEL_CNC.py +++ b/postprocessors/PP_ISEL_CNC.py @@ -9,7 +9,7 @@ from FlatCAMPostProc import * -class default(FlatCAMPostProc): +class PP_ISEL_CNC(FlatCAMPostProc): coordinate_format = "%.*f" feedrate_format = '%.*f'