| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373 |
- # ##########################################################
- # FlatCAM: 2D Post-processing for Manufacturing #
- # File Author: Marius Adrian Stanciu (c) #
- # Date: 10/10/2019 #
- # MIT Licence #
- # ##########################################################
- from appGUI.GUIElements import FCFileSaveDialog, FCEntry, FCTextAreaExtended, FCTextAreaLineNumber, FCButton
- from PyQt5 import QtPrintSupport, QtWidgets, QtCore, QtGui
- from reportlab.platypus import SimpleDocTemplate, Paragraph
- from reportlab.lib.styles import getSampleStyleSheet
- from reportlab.lib.units import inch, mm
- # from io import StringIO
- import gettext
- import appTranslation as fcTranslate
- import builtins
- fcTranslate.apply_language('strings')
- if '_' not in builtins.__dict__:
- _ = gettext.gettext
- class AppTextEditor(QtWidgets.QWidget):
- def __init__(self, app, text=None, plain_text=None, parent=None):
- super().__init__(parent=parent)
- self.app = app
- self.plain_text = plain_text
- self.callback = lambda x: None
- self.setSizePolicy(
- QtWidgets.QSizePolicy.MinimumExpanding,
- QtWidgets.QSizePolicy.MinimumExpanding
- )
- # UI Layout
- self.main_editor_layout = QtWidgets.QVBoxLayout(self)
- self.main_editor_layout.setContentsMargins(0, 0, 0, 0)
- self.t_frame = QtWidgets.QFrame()
- self.t_frame.setContentsMargins(0, 0, 0, 0)
- self.main_editor_layout.addWidget(self.t_frame)
- self.work_editor_layout = QtWidgets.QGridLayout(self.t_frame)
- self.work_editor_layout.setContentsMargins(2, 2, 2, 2)
- self.t_frame.setLayout(self.work_editor_layout)
- # CODE Editor
- if self.plain_text:
- self.editor_class = FCTextAreaLineNumber()
- self.code_editor = self.editor_class.edit
- stylesheet = """
- QPlainTextEdit { selection-background-color:yellow;
- selection-color:black;
- }
- """
- self.work_editor_layout.addWidget(self.editor_class, 0, 0, 1, 5)
- else:
- self.code_editor = FCTextAreaExtended()
- stylesheet = """
- QTextEdit { selection-background-color:yellow;
- selection-color:black;
- }
- """
- self.work_editor_layout.addWidget(self.code_editor, 0, 0, 1, 5)
- self.code_editor.setStyleSheet(stylesheet)
- if text:
- self.code_editor.setPlainText(text)
- # #############################################################################################################
- # UI SETUP
- # #############################################################################################################
- control_lay = QtWidgets.QHBoxLayout()
- self.work_editor_layout.addLayout(control_lay, 1, 0, 1, 5)
- # FIND
- self.buttonFind = FCButton(_('Find'))
- self.buttonFind.setIcon(QtGui.QIcon(self.app.resource_location + '/find32.png'))
- self.buttonFind.setToolTip(_("Will search and highlight in yellow the string in the Find box."))
- control_lay.addWidget(self.buttonFind)
- # Entry FIND
- self.entryFind = FCEntry()
- self.entryFind.setToolTip(_("Find box. Enter here the strings to be searched in the text."))
- control_lay.addWidget(self.entryFind)
- # REPLACE
- self.buttonReplace = FCButton(_('Replace With'))
- self.buttonReplace.setIcon(QtGui.QIcon(self.app.resource_location + '/replace32.png'))
- self.buttonReplace.setToolTip(_("Will replace the string from the Find box with the one in the Replace box."))
- control_lay.addWidget(self.buttonReplace)
- # Entry REPLACE
- self.entryReplace = FCEntry()
- self.entryReplace.setToolTip(_("String to replace the one in the Find box throughout the text."))
- control_lay.addWidget(self.entryReplace)
- # Select All
- self.sel_all_cb = QtWidgets.QCheckBox(_('All'))
- self.sel_all_cb.setToolTip(_("When checked it will replace all instances in the 'Find' box\n"
- "with the text in the 'Replace' box.."))
- control_lay.addWidget(self.sel_all_cb)
- # COPY All
- # self.button_copy_all = FCButton(_('Copy All'))
- # self.button_copy_all.setIcon(QtGui.QIcon(self.app.resource_location + '/copy_file32.png'))
- # self.button_copy_all.setToolTip(_("Will copy all the text in the Code Editor to the clipboard."))
- # control_lay.addWidget(self.button_copy_all)
- # Update
- self.button_update_code = QtWidgets.QToolButton()
- self.button_update_code.setIcon(QtGui.QIcon(self.app.resource_location + '/save_as.png'))
- self.button_update_code.setToolTip(_("Save changes internally."))
- self.button_update_code.hide()
- control_lay.addWidget(self.button_update_code)
- # Print PREVIEW
- self.buttonPreview = QtWidgets.QToolButton()
- self.buttonPreview.setIcon(QtGui.QIcon(self.app.resource_location + '/preview32.png'))
- self.buttonPreview.setToolTip(_("Open a OS standard Preview Print window."))
- control_lay.addWidget(self.buttonPreview)
- # PRINT
- self.buttonPrint = QtWidgets.QToolButton()
- self.buttonPrint.setIcon(QtGui.QIcon(self.app.resource_location + '/printer32.png'))
- self.buttonPrint.setToolTip(_("Open a OS standard Print window."))
- control_lay.addWidget(self.buttonPrint)
- # OPEN
- self.buttonOpen = QtWidgets.QToolButton()
- self.buttonOpen.setIcon(QtGui.QIcon(self.app.resource_location + '/folder32_bis.png'))
- self.buttonOpen.setToolTip(_("Will open a text file in the editor."))
- control_lay.addWidget(self.buttonOpen)
- # SAVE
- self.buttonSave = QtWidgets.QToolButton()
- self.buttonSave.setIcon(QtGui.QIcon(self.app.resource_location + '/save_as.png'))
- self.buttonSave.setToolTip(_("Will save the text in the editor into a file."))
- control_lay.addWidget(self.buttonSave)
- # RUN
- self.buttonRun = FCButton(_('Run'))
- self.buttonRun.setToolTip(_("Will run the TCL commands found in the text file, one by one."))
- self.buttonRun.hide()
- control_lay.addWidget(self.buttonRun)
- # #############################################################################################################
- # ################### SIGNALS #################################################################################
- # #############################################################################################################
- self.code_editor.textChanged.connect(self.handleTextChanged)
- self.buttonOpen.clicked.connect(self.handleOpen)
- self.buttonSave.clicked.connect(self.handleSaveGCode)
- self.buttonPrint.clicked.connect(self.handlePrint)
- self.buttonPreview.clicked.connect(self.handlePreview)
- self.buttonFind.clicked.connect(self.handleFindGCode)
- self.buttonReplace.clicked.connect(self.handleReplaceGCode)
- # self.button_copy_all.clicked.connect(self.handleCopyAll)
- self.code_editor.set_model_data(self.app.myKeywords)
- self.code_edited = ''
- def set_callback(self, callback):
- self.callback = callback
- def handlePrint(self):
- dialog = QtPrintSupport.QPrintDialog()
- if dialog.exec() == QtWidgets.QDialog.Accepted:
- self.code_editor.document().print_(dialog.printer())
- def handlePreview(self):
- dialog = QtPrintSupport.QPrintPreviewDialog()
- dialog.paintRequested.connect(self.code_editor.print)
- dialog.exec()
- def handleTextChanged(self):
- # enable = not self.ui.code_editor.document().isEmpty()
- # self.ui.buttonPrint.setEnabled(enable)
- # self.ui.buttonPreview.setEnabled(enable)
- self.buttonSave.setStyleSheet("QPushButton {color: red;}")
- self.buttonSave.setIcon(QtGui.QIcon(self.app.resource_location + '/save_as_red.png'))
- def load_text(self, text, move_to_start=False, move_to_end=False, clear_text=True, as_html=False):
- self.code_editor.textChanged.disconnect()
- if clear_text:
- # first clear previous text in text editor (if any)
- self.code_editor.clear()
- self.code_editor.setReadOnly(False)
- if as_html is False:
- self.code_editor.setPlainText(text)
- else:
- self.code_editor.setHtml(text)
- if move_to_start:
- self.code_editor.moveCursor(QtGui.QTextCursor.Start)
- elif move_to_end:
- self.code_editor.moveCursor(QtGui.QTextCursor.End)
- self.code_editor.textChanged.connect(self.handleTextChanged)
- def handleOpen(self, filt=None):
- self.app.defaults.report_usage("handleOpen()")
- if filt:
- _filter_ = filt
- else:
- _filter_ = "G-Code Files (*.nc);; G-Code Files (*.txt);; G-Code Files (*.tap);; G-Code Files (*.cnc);; " \
- "All Files (*.*)"
- path, _f = QtWidgets.QFileDialog.getOpenFileName(
- caption=_('Open file'), directory=self.app.get_last_folder(), filter=_filter_)
- if path:
- file = QtCore.QFile(path)
- if file.open(QtCore.QIODevice.ReadOnly):
- stream = QtCore.QTextStream(file)
- self.code_edited = stream.readAll()
- self.code_editor.setPlainText(self.code_edited)
- file.close()
- def handleSaveGCode(self, name=None, filt=None, callback=None):
- self.app.defaults.report_usage("handleSaveGCode()")
- if filt:
- _filter_ = filt
- else:
- _filter_ = "G-Code Files (*.nc);; G-Code Files (*.txt);; G-Code Files (*.tap);; G-Code Files (*.cnc);; " \
- "PDF Files (*.pdf);;All Files (*.*)"
- if name:
- obj_name = name
- else:
- try:
- obj_name = self.app.collection.get_active().options['name']
- except AttributeError:
- obj_name = 'file'
- if filt is None:
- _filter_ = "FlatConfig Files (*.FlatConfig);;PDF Files (*.pdf);;All Files (*.*)"
- try:
- filename = str(FCFileSaveDialog.get_saved_filename(
- caption=_("Export Code ..."),
- directory=self.app.defaults["global_last_folder"] + '/' + str(obj_name),
- ext_filter=_filter_
- )[0])
- except TypeError:
- filename = str(FCFileSaveDialog.get_saved_filename(
- caption=_("Export Code ..."),
- ext_filter=_filter_)[0])
- if filename == "":
- self.app.inform.emit('[WARNING_NOTCL] %s' % _("Cancelled."))
- return
- else:
- try:
- my_gcode = self.code_editor.toPlainText()
- if filename.rpartition('.')[2].lower() == 'pdf':
- page_size = (
- self.app.plotcanvas.pagesize_dict[self.app.defaults['global_workspaceT']][0] * mm,
- self.app.plotcanvas.pagesize_dict[self.app.defaults['global_workspaceT']][1] * mm
- )
- # add new line after each line
- lined_gcode = my_gcode.replace("\n", "<br />")
- styles = getSampleStyleSheet()
- styleN = styles['Normal']
- # styleH = styles['Heading1']
- story = []
- if self.app.defaults['units'].lower() == 'mm':
- bmargin = self.app.defaults['global_tpdf_bmargin'] * mm
- tmargin = self.app.defaults['global_tpdf_tmargin'] * mm
- rmargin = self.app.defaults['global_tpdf_rmargin'] * mm
- lmargin = self.app.defaults['global_tpdf_lmargin'] * mm
- else:
- bmargin = self.app.defaults['global_tpdf_bmargin'] * inch
- tmargin = self.app.defaults['global_tpdf_tmargin'] * inch
- rmargin = self.app.defaults['global_tpdf_rmargin'] * inch
- lmargin = self.app.defaults['global_tpdf_lmargin'] * inch
- doc = SimpleDocTemplate(
- filename,
- pagesize=page_size,
- bottomMargin=bmargin,
- topMargin=tmargin,
- rightMargin=rmargin,
- leftMargin=lmargin)
- P = Paragraph(lined_gcode, styleN)
- story.append(P)
- doc.build(
- story,
- )
- else:
- with open(filename, 'w') as f:
- for line in my_gcode:
- f.write(line)
- self.buttonSave.setStyleSheet("")
- self.buttonSave.setIcon(QtGui.QIcon(self.app.resource_location + '/save_as.png'))
- except FileNotFoundError:
- self.app.inform.emit('[WARNING] %s' % _("No such file or directory"))
- return
- except PermissionError:
- self.app.inform.emit('[WARNING] %s' %
- _("Permission denied, saving not possible.\n"
- "Most likely another app is holding the file open and not accessible."))
- return
- # Just for adding it to the recent files list.
- if self.app.defaults["global_open_style"] is False:
- self.app.file_opened.emit("cncjob", filename)
- self.app.file_saved.emit("cncjob", filename)
- self.app.inform.emit('%s: %s' % (_("Saved to"), str(filename)))
- if callback is not None:
- callback()
- def handleFindGCode(self):
- flags = QtGui.QTextDocument.FindCaseSensitively
- text_to_be_found = self.entryFind.get_value()
- r = self.code_editor.find(str(text_to_be_found), flags)
- if r is False:
- self.code_editor.moveCursor(QtGui.QTextCursor.Start)
- self.code_editor.find(str(text_to_be_found), flags)
- def handleReplaceGCode(self):
- old = self.entryFind.get_value()
- new = self.entryReplace.get_value()
- if self.sel_all_cb.isChecked():
- while True:
- cursor = self.code_editor.textCursor()
- cursor.beginEditBlock()
- flags = QtGui.QTextDocument.FindCaseSensitively
- # self.ui.editor is the QPlainTextEdit
- r = self.code_editor.find(str(old), flags)
- if r:
- qc = self.code_editor.textCursor()
- if qc.hasSelection():
- qc.insertText(new)
- else:
- self.code_editor.moveCursor(QtGui.QTextCursor.Start)
- break
- # Mark end of undo block
- cursor.endEditBlock()
- else:
- cursor = self.code_editor.textCursor()
- cursor.beginEditBlock()
- qc = self.code_editor.textCursor()
- if qc.hasSelection():
- qc.insertText(new)
- # Mark end of undo block
- cursor.endEditBlock()
- # def handleCopyAll(self):
- # text = self.code_editor.toPlainText()
- # self.app.clipboard.setText(text)
- # self.app.inform.emit(_("Content copied to clipboard ..."))
- # def closeEvent(self, QCloseEvent):
- # super().closeEvent(QCloseEvent)
|