FlatCAMScript.py 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. # ##########################################################
  2. # FlatCAM: 2D Post-processing for Manufacturing #
  3. # http://flatcam.org #
  4. # Author: Juan Pablo Caram (c) #
  5. # Date: 2/5/2014 #
  6. # MIT Licence #
  7. # ##########################################################
  8. # ##########################################################
  9. # File modified by: Marius Stanciu #
  10. # ##########################################################
  11. from flatcamEditors.FlatCAMTextEditor import TextEditor
  12. from flatcamObjects.FlatCAMObj import *
  13. from flatcamGUI.ObjectUI import *
  14. import tkinter as tk
  15. import sys
  16. from copy import deepcopy
  17. import gettext
  18. import FlatCAMTranslation as fcTranslate
  19. import builtins
  20. fcTranslate.apply_language('strings')
  21. if '_' not in builtins.__dict__:
  22. _ = gettext.gettext
  23. class ScriptObject(FlatCAMObj):
  24. """
  25. Represents a TCL script object.
  26. """
  27. optionChanged = QtCore.pyqtSignal(str)
  28. ui_type = ScriptObjectUI
  29. def __init__(self, name):
  30. self.decimals = self.app.decimals
  31. log.debug("Creating a ScriptObject object...")
  32. FlatCAMObj.__init__(self, name)
  33. self.kind = "script"
  34. self.options.update({
  35. "plot": True,
  36. "type": 'Script',
  37. "source_file": '',
  38. })
  39. self.units = ''
  40. self.ser_attrs = ['options', 'kind', 'source_file']
  41. self.source_file = ''
  42. self.script_code = ''
  43. self.units_found = self.app.defaults['units']
  44. # self.script_editor_tab = TextEditor(app=self.app, plain_text=True)
  45. self.script_editor_tab = TextEditor(app=self.app, plain_text=True)
  46. def set_ui(self, ui):
  47. """
  48. Sets the Object UI in Selected Tab for the FlatCAM Script type of object.
  49. :param ui:
  50. :return:
  51. """
  52. FlatCAMObj.set_ui(self, ui)
  53. log.debug("ScriptObject.set_ui()")
  54. assert isinstance(self.ui, ScriptObjectUI), \
  55. "Expected a ScriptObjectUI, got %s" % type(self.ui)
  56. self.units = self.app.defaults['units'].upper()
  57. self.units_found = self.app.defaults['units']
  58. # Fill form fields only on object create
  59. self.to_form()
  60. # Show/Hide Advanced Options
  61. if self.app.defaults["global_app_level"] == 'b':
  62. self.ui.level.setText(_(
  63. '<span style="color:green;"><b>Basic</b></span>'
  64. ))
  65. else:
  66. self.ui.level.setText(_(
  67. '<span style="color:red;"><b>Advanced</b></span>'
  68. ))
  69. # tab_here = False
  70. # # try to not add too many times a tab that it is already installed
  71. # for idx in range(self.app.ui.plot_tab_area.count()):
  72. # if self.app.ui.plot_tab_area.widget(idx).objectName() == self.options['name']:
  73. # tab_here = True
  74. # break
  75. #
  76. # # add the tab if it is not already added
  77. # if tab_here is False:
  78. # self.app.ui.plot_tab_area.addTab(self.script_editor_tab, '%s' % _("Script Editor"))
  79. # self.script_editor_tab.setObjectName(self.options['name'])
  80. self.app.ui.plot_tab_area.addTab(self.script_editor_tab, '%s' % _("Script Editor"))
  81. self.script_editor_tab.setObjectName(self.options['name'])
  82. # first clear previous text in text editor (if any)
  83. # self.script_editor_tab.code_editor.clear()
  84. # self.script_editor_tab.code_editor.setReadOnly(False)
  85. self.ui.autocomplete_cb.set_value(self.app.defaults['script_autocompleter'])
  86. self.on_autocomplete_changed(state=self.app.defaults['script_autocompleter'])
  87. self.script_editor_tab.buttonRun.show()
  88. # Switch plot_area to CNCJob tab
  89. self.app.ui.plot_tab_area.setCurrentWidget(self.script_editor_tab)
  90. flt = "FlatCAM Scripts (*.FlatScript);;All Files (*.*)"
  91. self.script_editor_tab.buttonOpen.clicked.disconnect()
  92. self.script_editor_tab.buttonOpen.clicked.connect(lambda: self.script_editor_tab.handleOpen(filt=flt))
  93. self.script_editor_tab.buttonSave.clicked.disconnect()
  94. self.script_editor_tab.buttonSave.clicked.connect(lambda: self.script_editor_tab.handleSaveGCode(filt=flt))
  95. self.script_editor_tab.buttonRun.clicked.connect(self.handle_run_code)
  96. self.script_editor_tab.handleTextChanged()
  97. self.ui.autocomplete_cb.stateChanged.connect(self.on_autocomplete_changed)
  98. self.ser_attrs = ['options', 'kind', 'source_file']
  99. # ---------------------------------------------------- #
  100. # ----------- LOAD THE TEXT SOURCE FILE -------------- #
  101. # ---------------------------------------------------- #
  102. self.app.proc_container.view.set_busy(_("Loading..."))
  103. self.script_editor_tab.t_frame.hide()
  104. try:
  105. self.script_editor_tab.code_editor.setPlainText(self.source_file)
  106. # for line in self.source_file.splitlines():
  107. # QtWidgets.QApplication.processEvents()
  108. # self.script_editor_tab.code_editor.append(line)
  109. except Exception as e:
  110. log.debug("ScriptObject.set_ui() --> %s" % str(e))
  111. self.script_editor_tab.code_editor.moveCursor(QtGui.QTextCursor.End)
  112. self.script_editor_tab.t_frame.show()
  113. self.app.proc_container.view.set_idle()
  114. self.build_ui()
  115. def build_ui(self):
  116. FlatCAMObj.build_ui(self)
  117. def handle_run_code(self):
  118. # trying to run a Tcl command without having the Shell open will create some warnings because the Tcl Shell
  119. # tries to print on a hidden widget, therefore show the dock if hidden
  120. if self.app.ui.shell_dock.isHidden():
  121. self.app.ui.shell_dock.show()
  122. self.script_code = deepcopy(self.script_editor_tab.code_editor.toPlainText())
  123. old_line = ''
  124. for tcl_command_line in self.script_code.splitlines():
  125. # do not process lines starting with '#' = comment and empty lines
  126. if not tcl_command_line.startswith('#') and tcl_command_line != '':
  127. # id FlatCAM is run in Windows then replace all the slashes with
  128. # the UNIX style slash that TCL understands
  129. if sys.platform == 'win32':
  130. if "open" in tcl_command_line:
  131. tcl_command_line = tcl_command_line.replace('\\', '/')
  132. if old_line != '':
  133. new_command = old_line + tcl_command_line + '\n'
  134. else:
  135. new_command = tcl_command_line
  136. # execute the actual Tcl command
  137. try:
  138. self.app.shell.open_processing() # Disables input box.
  139. result = self.app.shell.tcl.eval(str(new_command))
  140. if result != 'None':
  141. self.app.shell.append_output(result + '\n')
  142. old_line = ''
  143. except tk.TclError:
  144. old_line = old_line + tcl_command_line + '\n'
  145. except Exception as e:
  146. log.debug("ScriptObject.handleRunCode() --> %s" % str(e))
  147. if old_line != '':
  148. # it means that the script finished with an error
  149. result = self.app.shell.tcl.eval("set errorInfo")
  150. log.error("Exec command Exception: %s\n" % result)
  151. self.app.shell.append_error('ERROR: %s\n '% result)
  152. self.app.shell.close_processing()
  153. def on_autocomplete_changed(self, state):
  154. if state:
  155. self.script_editor_tab.code_editor.completer_enable = True
  156. else:
  157. self.script_editor_tab.code_editor.completer_enable = False
  158. def to_dict(self):
  159. """
  160. Returns a representation of the object as a dictionary.
  161. Attributes to include are listed in ``self.ser_attrs``.
  162. :return: A dictionary-encoded copy of the object.
  163. :rtype: dict
  164. """
  165. d = {}
  166. for attr in self.ser_attrs:
  167. d[attr] = getattr(self, attr)
  168. return d
  169. def from_dict(self, d):
  170. """
  171. Sets object's attributes from a dictionary.
  172. Attributes to include are listed in ``self.ser_attrs``.
  173. This method will look only for only and all the
  174. attributes in ``self.ser_attrs``. They must all
  175. be present. Use only for deserializing saved
  176. objects.
  177. :param d: Dictionary of attributes to set in the object.
  178. :type d: dict
  179. :return: None
  180. """
  181. for attr in self.ser_attrs:
  182. setattr(self, attr, d[attr])