FlatCAMTextEditor.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. # ##########################################################
  2. # FlatCAM: 2D Post-processing for Manufacturing #
  3. # File Author: Marius Adrian Stanciu (c) #
  4. # Date: 10/10/2019 #
  5. # MIT Licence #
  6. # ##########################################################
  7. from flatcamGUI.GUIElements import *
  8. from PyQt5 import QtPrintSupport
  9. import gettext
  10. import FlatCAMTranslation as fcTranslate
  11. import builtins
  12. fcTranslate.apply_language('strings')
  13. if '_' not in builtins.__dict__:
  14. _ = gettext.gettext
  15. class TextEditor(QtWidgets.QWidget):
  16. def __init__(self, app, text=None):
  17. super().__init__()
  18. self.app = app
  19. self.setSizePolicy(
  20. QtWidgets.QSizePolicy.MinimumExpanding,
  21. QtWidgets.QSizePolicy.MinimumExpanding
  22. )
  23. self.main_editor_layout = QtWidgets.QVBoxLayout(self)
  24. self.main_editor_layout.setContentsMargins(0, 0, 0, 0)
  25. self.t_frame = QtWidgets.QFrame()
  26. self.t_frame.setContentsMargins(0, 0, 0, 0)
  27. self.main_editor_layout.addWidget(self.t_frame)
  28. self.work_editor_layout = QtWidgets.QGridLayout(self.t_frame)
  29. self.work_editor_layout.setContentsMargins(2, 2, 2, 2)
  30. self.t_frame.setLayout(self.work_editor_layout)
  31. self.code_editor = FCTextAreaExtended()
  32. stylesheet = """
  33. QTextEdit { selection-background-color:yellow;
  34. selection-color:black;
  35. }
  36. """
  37. self.code_editor.setStyleSheet(stylesheet)
  38. if text:
  39. self.code_editor.setPlainText(text)
  40. self.buttonPreview = QtWidgets.QPushButton(_('Print Preview'))
  41. self.buttonPreview.setToolTip(_("Open a OS standard Preview Print window."))
  42. self.buttonPreview.setMinimumWidth(100)
  43. self.buttonPrint = QtWidgets.QPushButton(_('Print Code'))
  44. self.buttonPrint.setToolTip(_("Open a OS standard Print window."))
  45. self.buttonFind = QtWidgets.QPushButton(_('Find in Code'))
  46. self.buttonFind.setToolTip(_("Will search and highlight in yellow the string in the Find box."))
  47. self.buttonFind.setMinimumWidth(100)
  48. self.entryFind = FCEntry()
  49. self.entryFind.setToolTip(_("Find box. Enter here the strings to be searched in the text."))
  50. self.buttonReplace = QtWidgets.QPushButton(_('Replace With'))
  51. self.buttonReplace.setToolTip(_("Will replace the string from the Find box with the one in the Replace box."))
  52. self.buttonReplace.setMinimumWidth(100)
  53. self.entryReplace = FCEntry()
  54. self.entryReplace.setToolTip(_("String to replace the one in the Find box throughout the text."))
  55. self.sel_all_cb = QtWidgets.QCheckBox(_('All'))
  56. self.sel_all_cb.setToolTip(_("When checked it will replace all instances in the 'Find' box\n"
  57. "with the text in the 'Replace' box.."))
  58. self.button_copy_all = QtWidgets.QPushButton(_('Copy All'))
  59. self.button_copy_all.setToolTip(_("Will copy all the text in the Code Editor to the clipboard."))
  60. self.button_copy_all.setMinimumWidth(100)
  61. self.buttonOpen = QtWidgets.QPushButton(_('Open Code'))
  62. self.buttonOpen.setToolTip(_("Will open a text file in the editor."))
  63. self.buttonSave = QtWidgets.QPushButton(_('Save Code'))
  64. self.buttonSave.setToolTip(_("Will save the text in the editor into a file."))
  65. self.buttonRun = QtWidgets.QPushButton(_('Run Code'))
  66. self.buttonRun.setToolTip(_("Will run the TCL commands found in the text file, one by one."))
  67. self.buttonRun.hide()
  68. self.work_editor_layout.addWidget(self.code_editor, 0, 0, 1, 5)
  69. editor_hlay_1 = QtWidgets.QHBoxLayout()
  70. # cnc_tab_lay_1.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter)
  71. editor_hlay_1.addWidget(self.buttonFind)
  72. editor_hlay_1.addWidget(self.entryFind)
  73. editor_hlay_1.addWidget(self.buttonReplace)
  74. editor_hlay_1.addWidget(self.entryReplace)
  75. editor_hlay_1.addWidget(self.sel_all_cb)
  76. editor_hlay_1.addWidget(self.button_copy_all)
  77. self.work_editor_layout.addLayout(editor_hlay_1, 1, 0, 1, 5)
  78. editor_hlay_2 = QtWidgets.QHBoxLayout()
  79. editor_hlay_2.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter)
  80. editor_hlay_2.addWidget(self.buttonPreview)
  81. editor_hlay_2.addWidget(self.buttonPrint)
  82. self.work_editor_layout.addLayout(editor_hlay_2, 2, 0, 1, 1, QtCore.Qt.AlignLeft)
  83. cnc_tab_lay_4 = QtWidgets.QHBoxLayout()
  84. cnc_tab_lay_4.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
  85. cnc_tab_lay_4.addWidget(self.buttonOpen)
  86. cnc_tab_lay_4.addWidget(self.buttonSave)
  87. cnc_tab_lay_4.addWidget(self.buttonRun)
  88. self.work_editor_layout.addLayout(cnc_tab_lay_4, 2, 4, 1, 1)
  89. # #################################################################################
  90. # ################### SIGNALS #####################################################
  91. # #################################################################################
  92. self.code_editor.textChanged.connect(self.handleTextChanged)
  93. self.buttonOpen.clicked.connect(self.handleOpen)
  94. self.buttonSave.clicked.connect(self.handleSaveGCode)
  95. self.buttonPrint.clicked.connect(self.handlePrint)
  96. self.buttonPreview.clicked.connect(self.handlePreview)
  97. self.buttonFind.clicked.connect(self.handleFindGCode)
  98. self.buttonReplace.clicked.connect(self.handleReplaceGCode)
  99. self.button_copy_all.clicked.connect(self.handleCopyAll)
  100. self.code_editor.set_model_data(self.app.myKeywords)
  101. self.gcode_edited = ''
  102. def handlePrint(self):
  103. self.app.report_usage("handlePrint()")
  104. dialog = QtPrintSupport.QPrintDialog()
  105. if dialog.exec_() == QtWidgets.QDialog.Accepted:
  106. self.code_editor.document().print_(dialog.printer())
  107. def handlePreview(self):
  108. self.app.report_usage("handlePreview()")
  109. dialog = QtPrintSupport.QPrintPreviewDialog()
  110. dialog.paintRequested.connect(self.code_editor.print_)
  111. dialog.exec_()
  112. def handleTextChanged(self):
  113. # enable = not self.ui.code_editor.document().isEmpty()
  114. # self.ui.buttonPrint.setEnabled(enable)
  115. # self.ui.buttonPreview.setEnabled(enable)
  116. pass
  117. def handleOpen(self, filt=None):
  118. self.app.report_usage("handleOpen()")
  119. if filt:
  120. _filter_ = filt
  121. else:
  122. _filter_ = "G-Code Files (*.nc);; G-Code Files (*.txt);; G-Code Files (*.tap);; G-Code Files (*.cnc);; " \
  123. "All Files (*.*)"
  124. path, _f = QtWidgets.QFileDialog.getOpenFileName(
  125. caption=_('Open file'), directory=self.app.get_last_folder(), filter=_filter_)
  126. if path:
  127. file = QtCore.QFile(path)
  128. if file.open(QtCore.QIODevice.ReadOnly):
  129. stream = QtCore.QTextStream(file)
  130. self.gcode_edited = stream.readAll()
  131. self.code_editor.setPlainText(self.gcode_edited)
  132. file.close()
  133. def handleSaveGCode(self, name=None, filt=None):
  134. self.app.report_usage("handleSaveGCode()")
  135. if filt:
  136. _filter_ = filt
  137. else:
  138. _filter_ = "G-Code Files (*.nc);; G-Code Files (*.txt);; G-Code Files (*.tap);; G-Code Files (*.cnc);; " \
  139. "All Files (*.*)"
  140. if name:
  141. obj_name = name
  142. else:
  143. try:
  144. obj_name = self.app.collection.get_active().options['name']
  145. except AttributeError:
  146. obj_name = 'file'
  147. if filt is None:
  148. _filter_ = "FlatConfig Files (*.FlatConfig);;All Files (*.*)"
  149. try:
  150. filename = str(QtWidgets.QFileDialog.getSaveFileName(
  151. caption=_("Export G-Code ..."),
  152. directory=self.app.defaults["global_last_folder"] + '/' + str(obj_name),
  153. filter=_filter_
  154. )[0])
  155. except TypeError:
  156. filename = str(QtWidgets.QFileDialog.getSaveFileName(caption=_("Export G-Code ..."), filter=_filter_)[0])
  157. if filename == "":
  158. self.app.inform.emit('[WARNING_NOTCL] %s' % _("Export Code cancelled."))
  159. return
  160. else:
  161. try:
  162. my_gcode = self.code_editor.toPlainText()
  163. with open(filename, 'w') as f:
  164. for line in my_gcode:
  165. f.write(line)
  166. except FileNotFoundError:
  167. self.app.inform.emit('[WARNING] %s' % _("No such file or directory"))
  168. return
  169. except PermissionError:
  170. self.app.inform.emit('[WARNING] %s' %
  171. _("Permission denied, saving not possible.\n"
  172. "Most likely another app is holding the file open and not accessible."))
  173. return
  174. # Just for adding it to the recent files list.
  175. if self.app.defaults["global_open_style"] is False:
  176. self.app.file_opened.emit("cncjob", filename)
  177. self.app.file_saved.emit("cncjob", filename)
  178. self.app.inform.emit('%s: %s' % (_("Saved to"), str(filename)))
  179. def handleFindGCode(self):
  180. self.app.report_usage("handleFindGCode()")
  181. flags = QtGui.QTextDocument.FindCaseSensitively
  182. text_to_be_found = self.entryFind.get_value()
  183. r = self.code_editor.find(str(text_to_be_found), flags)
  184. if r is False:
  185. self.code_editor.moveCursor(QtGui.QTextCursor.Start)
  186. def handleReplaceGCode(self):
  187. self.app.report_usage("handleReplaceGCode()")
  188. old = self.entryFind.get_value()
  189. new = self.entryReplace.get_value()
  190. if self.sel_all_cb.isChecked():
  191. while True:
  192. cursor = self.code_editor.textCursor()
  193. cursor.beginEditBlock()
  194. flags = QtGui.QTextDocument.FindCaseSensitively
  195. # self.ui.editor is the QPlainTextEdit
  196. r = self.code_editor.find(str(old), flags)
  197. if r:
  198. qc = self.code_editor.textCursor()
  199. if qc.hasSelection():
  200. qc.insertText(new)
  201. else:
  202. self.ui.code_editor.moveCursor(QtGui.QTextCursor.Start)
  203. break
  204. # Mark end of undo block
  205. cursor.endEditBlock()
  206. else:
  207. cursor = self.code_editor.textCursor()
  208. cursor.beginEditBlock()
  209. qc = self.code_editor.textCursor()
  210. if qc.hasSelection():
  211. qc.insertText(new)
  212. # Mark end of undo block
  213. cursor.endEditBlock()
  214. def handleCopyAll(self):
  215. text = self.code_editor.toPlainText()
  216. self.app.clipboard.setText(text)
  217. self.app.inform.emit(_("Code Editor content copied to clipboard ..."))
  218. # def closeEvent(self, QCloseEvent):
  219. # super().closeEvent(QCloseEvent)