FlatCAMTextEditor.py 11 KB

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