FlatCAMTextEditor.py 11 KB

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