Explorar el Código

- moved all the new_object related methods in their own class AppObjects.AppObject

Marius Stanciu hace 5 años
padre
commit
2bcdeff7ef
Se han modificado 55 ficheros con 579 adiciones y 554 borrados
  1. 2 2
      AppEditors/FlatCAMExcEditor.py
  2. 1 1
      AppEditors/FlatCAMGeoEditor.py
  3. 2 2
      AppEditors/FlatCAMGrbEditor.py
  4. 3 3
      AppGUI/MainGUI.py
  5. 3 3
      AppGUI/PlotCanvasLegacy.py
  6. 1 1
      AppGUI/preferences/PreferencesUIManager.py
  7. 56 422
      AppMain.py
  8. 393 0
      AppObjects/AppObject.py
  9. 9 9
      AppObjects/FlatCAMExcellon.py
  10. 12 12
      AppObjects/FlatCAMGeometry.py
  11. 5 5
      AppObjects/FlatCAMGerber.py
  12. 4 4
      AppObjects/FlatCAMObj.py
  13. 1 1
      AppObjects/ObjectCollection.py
  14. 1 1
      AppParsers/ParseExcellon.py
  15. 1 1
      AppTool.py
  16. 3 3
      AppTools/ToolCalibration.py
  17. 1 1
      AppTools/ToolCopperThieving.py
  18. 3 3
      AppTools/ToolCutOut.py
  19. 4 4
      AppTools/ToolDblSided.py
  20. 1 1
      AppTools/ToolExtractDrills.py
  21. 2 2
      AppTools/ToolFilm.py
  22. 1 1
      AppTools/ToolImage.py
  23. 1 1
      AppTools/ToolInvertGerber.py
  24. 5 5
      AppTools/ToolNCC.py
  25. 2 2
      AppTools/ToolPDF.py
  26. 5 5
      AppTools/ToolPaint.py
  27. 2 2
      AppTools/ToolPanelize.py
  28. 1 1
      AppTools/ToolPcbWizard.py
  29. 4 4
      AppTools/ToolPunchGerber.py
  30. 1 1
      AppTools/ToolRulesCheck.py
  31. 6 6
      AppTools/ToolSolderPaste.py
  32. 2 2
      AppTools/ToolSub.py
  33. 6 6
      AppTools/ToolTransform.py
  34. 2 1
      CHANGELOG.md
  35. 1 1
      FlatCAM.py
  36. 2 2
      tclCommands/TclCommand.py
  37. 2 2
      tclCommands/TclCommandAlignDrill.py
  38. 1 1
      tclCommands/TclCommandAlignDrillGrid.py
  39. 1 1
      tclCommands/TclCommandBbox.py
  40. 1 1
      tclCommands/TclCommandCutout.py
  41. 1 1
      tclCommands/TclCommandDrillcncjob.py
  42. 1 1
      tclCommands/TclCommandExteriors.py
  43. 2 5
      tclCommands/TclCommandGeoCutout.py
  44. 1 1
      tclCommands/TclCommandImportSvg.py
  45. 1 1
      tclCommands/TclCommandInteriors.py
  46. 1 1
      tclCommands/TclCommandJoinExcellon.py
  47. 1 1
      tclCommands/TclCommandJoinGeometry.py
  48. 1 1
      tclCommands/TclCommandNewExcellon.py
  49. 1 1
      tclCommands/TclCommandNewGeometry.py
  50. 1 1
      tclCommands/TclCommandNewGerber.py
  51. 1 1
      tclCommands/TclCommandNregions.py
  52. 2 2
      tclCommands/TclCommandOpenDXF.py
  53. 2 2
      tclCommands/TclCommandOpenSVG.py
  54. 6 6
      tclCommands/TclCommandPanelize.py
  55. 3 3
      tclCommands/TclCommandWriteGCode.py

+ 2 - 2
AppEditors/FlatCAMExcEditor.py

@@ -2239,7 +2239,7 @@ class FlatCAMExcEditor(QtCore.QObject):
 
         # store the status of the editor so the Delete at object level will not work until the edit is finished
         self.editor_active = False
-        log.debug("Initialization of the FlatCAM Excellon Editor is finished ...")
+        log.debug("Initialization of the Excellon Editor is finished ...")
 
     def pool_recreated(self, pool):
         self.shapes.pool = pool
@@ -3336,7 +3336,7 @@ class FlatCAMExcEditor(QtCore.QObject):
         with self.app.proc_container.new(_("Creating Excellon.")):
 
             try:
-                edited_obj = self.app.new_object("excellon", outname, obj_init)
+                edited_obj = self.app.app_obj.new_object("excellon", outname, obj_init)
                 edited_obj.source_file = self.app.export_excellon(obj_name=edited_obj.options['name'],
                                                                   local_use=edited_obj,
                                                                   filename=None,

+ 1 - 1
AppEditors/FlatCAMGeoEditor.py

@@ -3552,7 +3552,7 @@ class FlatCAMGeoEditor(QtCore.QObject):
 
         # store the status of the editor so the Delete at object level will not work until the edit is finished
         self.editor_active = False
-        log.debug("Initialization of the FlatCAM Geometry Editor is finished ...")
+        log.debug("Initialization of the Geometry Editor is finished ...")
 
     def pool_recreated(self, pool):
         self.shapes.pool = pool

+ 2 - 2
AppEditors/FlatCAMGrbEditor.py

@@ -3110,7 +3110,7 @@ class FlatCAMGrbEditor(QtCore.QObject):
         self.complete = True
 
         self.set_ui()
-        log.debug("Initialization of the FlatCAM Gerber Editor is finished ...")
+        log.debug("Initialization of the Gerber Editor is finished ...")
 
     def pool_recreated(self, pool):
         self.shapes.pool = pool
@@ -4346,7 +4346,7 @@ class FlatCAMGrbEditor(QtCore.QObject):
 
         with self.app.proc_container.new(_("Creating Gerber.")):
             try:
-                self.app.new_object("gerber", outname, obj_init)
+                self.app.app_obj.new_object("gerber", outname, obj_init)
             except Exception as e:
                 log.error("Error on Edited object creation: %s" % str(e))
                 # make sure to clean the previous results

+ 3 - 3
AppGUI/MainGUI.py

@@ -2477,7 +2477,7 @@ class MainGUI(QtWidgets.QMainWindow):
 
                 # New Geometry
                 if key == QtCore.Qt.Key_B:
-                    self.app.new_gerber_object()
+                    self.app.app_obj.new_gerber_object()
 
                 # New Geometry
                 if key == QtCore.Qt.Key_D:
@@ -2497,7 +2497,7 @@ class MainGUI(QtWidgets.QMainWindow):
 
                 # New Excellon
                 if key == QtCore.Qt.Key_L:
-                    self.app.new_excellon_object()
+                    self.app.app_obj.new_excellon_object()
 
                 # Move tool toggle
                 if key == QtCore.Qt.Key_M:
@@ -2505,7 +2505,7 @@ class MainGUI(QtWidgets.QMainWindow):
 
                 # New Geometry
                 if key == QtCore.Qt.Key_N:
-                    self.app.new_geometry_object()
+                    self.app.app_obj.new_geometry_object()
 
                 # Set Origin
                 if key == QtCore.Qt.Key_O:

+ 3 - 3
AppGUI/PlotCanvasLegacy.py

@@ -48,9 +48,9 @@ class CanvasCache(QtCore.QObject):
     Case story #1:
 
     1) No objects in the project.
-    2) Object is created (new_object() emits object_created(obj)).
+    2) Object is created (app_obj.new_object() emits object_created(obj)).
        on_object_created() adds (i) object to collection and emits
-       (ii) new_object_available() then calls (iii) object.plot()
+       (ii) app_obj.new_object_available() then calls (iii) object.plot()
     3) object.plot() creates axes if necessary on
        app.collection.figure. Then plots on it.
     4) Plots on a cache-size canvas (in background).
@@ -116,7 +116,7 @@ class CanvasCache(QtCore.QObject):
 
         # Continue to update the cache.
 
-    # def on_new_object_available(self):
+    # def on_app_obj.new_object_available(self):
     #
     #     log.debug("A new object is available. Should plot it!")
 

+ 1 - 1
AppGUI/preferences/PreferencesUIManager.py

@@ -43,7 +43,7 @@ class PreferencesUIManager:
         self.preferences_changed_flag = False
 
         # when adding entries here read the comments in the  method found below named:
-        # def new_object(self, kind, name, initialize, active=True, fit=True, plot=True)
+        # def app_obj.new_object(self, kind, name, initialize, active=True, fit=True, plot=True)
         self.defaults_form_fields = {
             # General App
             "decimals_inch": self.ui.general_defaults_form.general_app_group.precision_inch_entry,

+ 56 - 422
App.py → AppMain.py

@@ -4,6 +4,7 @@
 # Author: Juan Pablo Caram (c)                              #
 # Date: 2/5/2014                                            #
 # MIT Licence                                               #
+# Modified by Marius Stanciu (2019)                         #
 # ###########################################################
 
 import urllib.request
@@ -55,12 +56,7 @@ from AppGUI.preferences.OptionsGroupUI import OptionsGroupUI
 from AppGUI.preferences.PreferencesUIManager import PreferencesUIManager
 from AppObjects.ObjectCollection import *
 from AppObjects.FlatCAMObj import FlatCAMObj
-from AppObjects.FlatCAMCNCJob import CNCJobObject
-from AppObjects.FlatCAMDocument import DocumentObject
-from AppObjects.FlatCAMExcellon import ExcellonObject
-from AppObjects.FlatCAMGeometry import GeometryObject
-from AppObjects.FlatCAMGerber import GerberObject
-from AppObjects.FlatCAMScript import ScriptObject
+from AppObjects.AppObject import AppObject
 
 # FlatCAM Parsing files
 from AppParsers.ParseExcellon import Excellon
@@ -226,20 +222,6 @@ class App(QtCore.QObject):
     # Percentage of progress
     progress = QtCore.pyqtSignal(int)
 
-    plots_updated = QtCore.pyqtSignal()
-
-    # Emitted by new_object() and passes the new object as argument, plot flag.
-    # on_object_created() adds the object to the collection, plots on appropriate flag
-    # and emits new_object_available.
-    object_created = QtCore.pyqtSignal(object, bool, bool)
-
-    # Emitted when a object has been changed (like scaled, mirrored)
-    object_changed = QtCore.pyqtSignal(object)
-
-    # Emitted after object has been plotted.
-    # Calls 'on_zoom_fit' method to fit object in scene view in main thread to prevent drawing glitches.
-    object_plotted = QtCore.pyqtSignal(object)
-
     # Emitted when a new object has been added or deleted from/to the collection
     object_status_changed = QtCore.pyqtSignal(object, str, str)
 
@@ -674,9 +656,11 @@ class App(QtCore.QObject):
         # #################################### SETUP OBJECT COLLECTION ##############################################
         # ###########################################################################################################
 
-        self.collection = ObjectCollection(self)
+        self.collection = ObjectCollection(app=self)
         self.ui.project_tab_layout.addWidget(self.collection.view)
 
+        self.app_obj = AppObject(app=self)
+
         # ### Adjust tabs width ## ##
         # self.collection.view.setMinimumWidth(self.ui.options_scroll_area.widget().sizeHint().width() +
         #     self.ui.options_scroll_area.verticalScrollBar().sizeHint().width())
@@ -779,12 +763,6 @@ class App(QtCore.QObject):
         self.message.connect(lambda: message_dialog(parent=self.ui))
         # self.progress.connect(self.set_progress_bar)
 
-        # signals that are emitted when object state changes
-        self.object_created.connect(self.on_object_created)
-        self.object_changed.connect(self.on_object_changed)
-        self.object_plotted.connect(self.on_object_plotted)
-        self.plots_updated.connect(self.on_plots_updated)
-
         # signals emitted when file state change
         self.file_opened.connect(self.register_recent)
         self.file_opened.connect(lambda kind, filename: self.register_folder(filename))
@@ -793,10 +771,10 @@ class App(QtCore.QObject):
         # ########################################## Standard signals ###############################################
         # ### Menu
         self.ui.menufilenewproject.triggered.connect(self.on_file_new_click)
-        self.ui.menufilenewgeo.triggered.connect(self.new_geometry_object)
-        self.ui.menufilenewgrb.triggered.connect(self.new_gerber_object)
-        self.ui.menufilenewexc.triggered.connect(self.new_excellon_object)
-        self.ui.menufilenewdoc.triggered.connect(self.new_document_object)
+        self.ui.menufilenewgeo.triggered.connect(self.app_obj.new_geometry_object)
+        self.ui.menufilenewgrb.triggered.connect(self.app_obj.new_gerber_object)
+        self.ui.menufilenewexc.triggered.connect(self.app_obj.new_excellon_object)
+        self.ui.menufilenewdoc.triggered.connect(self.app_obj.new_document_object)
 
         self.ui.menufileopengerber.triggered.connect(self.on_fileopengerber)
         self.ui.menufileopenexcellon.triggered.connect(self.on_fileopenexcellon)
@@ -935,9 +913,9 @@ class App(QtCore.QObject):
         self.ui.popmenu_disable.triggered.connect(lambda: self.toggle_plots(self.collection.get_selected()))
         self.ui.popmenu_panel_toggle.triggered.connect(self.ui.on_toggle_notebook)
 
-        self.ui.popmenu_new_geo.triggered.connect(self.new_geometry_object)
-        self.ui.popmenu_new_grb.triggered.connect(self.new_gerber_object)
-        self.ui.popmenu_new_exc.triggered.connect(self.new_excellon_object)
+        self.ui.popmenu_new_geo.triggered.connect(self.app_obj.new_geometry_object)
+        self.ui.popmenu_new_grb.triggered.connect(self.app_obj.new_gerber_object)
+        self.ui.popmenu_new_exc.triggered.connect(self.app_obj.new_excellon_object)
         self.ui.popmenu_new_prj.triggered.connect(self.on_file_new)
 
         self.ui.zoomfit.triggered.connect(self.on_zoom_fit)
@@ -1918,7 +1896,7 @@ class App(QtCore.QObject):
         self.calculator_tool = ToolCalculator(self)
         self.calculator_tool.install(icon=QtGui.QIcon(self.resource_location + '/calculator16.png'), separator=True)
 
-        self.sub_tool = ToolSub(self)
+        self.sub_tool = ToolSub(app=self)
         self.sub_tool.install(icon=QtGui.QIcon(self.resource_location + '/sub32.png'),
                               pos=self.ui.menutool, separator=True)
 
@@ -2071,9 +2049,9 @@ class App(QtCore.QObject):
         self.ui.zoom_out_btn.triggered.connect(lambda: self.plotcanvas.zoom(1.5))
 
         # Edit Toolbar Signals
-        self.ui.newgeo_btn.triggered.connect(self.new_geometry_object)
-        self.ui.newgrb_btn.triggered.connect(self.new_gerber_object)
-        self.ui.newexc_btn.triggered.connect(self.new_excellon_object)
+        self.ui.newgeo_btn.triggered.connect(self.app_obj.new_geometry_object)
+        self.ui.newgrb_btn.triggered.connect(self.app_obj.new_gerber_object)
+        self.ui.newexc_btn.triggered.connect(self.app_obj.new_excellon_object)
         self.ui.editgeo_btn.triggered.connect(self.object2editor)
         self.ui.update_obj_btn.triggered.connect(lambda: self.editor2object())
         self.ui.copy_btn.triggered.connect(self.on_copy_command)
@@ -2665,347 +2643,6 @@ class App(QtCore.QObject):
         # Re-build the recent items menu
         self.setup_recent_items()
 
-    def new_object(self, kind, name, initialize, plot=True, autoselected=True):
-        """
-        Creates a new specialized FlatCAMObj and attaches it to the application,
-        this is, updates the GUI accordingly, any other records and plots it.
-        This method is thread-safe.
-
-        Notes:
-            * If the name is in use, the self.collection will modify it
-              when appending it to the collection. There is no need to handle
-              name conflicts here.
-
-        :param kind: The kind of object to create. One of 'gerber', 'excellon', 'cncjob' and 'geometry'.
-        :type kind: str
-        :param name: Name for the object.
-        :type name: str
-        :param initialize: Function to run after creation of the object but before it is attached to the application.
-        The function is called with 2 parameters: the new object and the App instance.
-        :type initialize: function
-        :param plot: If to plot the resulting object
-        :param autoselected: if the resulting object is autoselected in the Project tab and therefore in the
-        self.collection
-        :return: None
-        :rtype: None
-        """
-
-        App.log.debug("new_object()")
-        obj_plot = plot
-        obj_autoselected = autoselected
-
-        t0 = time.time()  # Debug
-
-        # ## Create object
-        classdict = {
-            "gerber": GerberObject,
-            "excellon": ExcellonObject,
-            "cncjob": CNCJobObject,
-            "geometry": GeometryObject,
-            "script": ScriptObject,
-            "document": DocumentObject
-        }
-
-        App.log.debug("Calling object constructor...")
-
-        # Object creation/instantiation
-        obj = classdict[kind](name)
-
-        obj.units = self.options["units"]
-
-        # IMPORTANT
-        # The key names in defaults and options dictionary's are not random:
-        # they have to have in name first the type of the object (geometry, excellon, cncjob and gerber) or how it's
-        # called here, the 'kind' followed by an underline. Above the App default values from self.defaults are
-        # copied to self.options. After that, below, depending on the type of
-        # object that is created, it will strip the name of the object and the underline (if the original key was
-        # let's say "excellon_toolchange", it will strip the excellon_) and to the obj.options the key will become
-        # "toolchange"
-
-        for option in self.options:
-            if option.find(kind + "_") == 0:
-                oname = option[len(kind) + 1:]
-                obj.options[oname] = self.options[option]
-
-        obj.isHovering = False
-        obj.notHovering = True
-
-        # Initialize as per user request
-        # User must take care to implement initialize
-        # in a thread-safe way as is is likely that we
-        # have been invoked in a separate thread.
-        t1 = time.time()
-        self.log.debug("%f seconds before initialize()." % (t1 - t0))
-        try:
-            return_value = initialize(obj, self)
-        except Exception as e:
-            msg = '[ERROR_NOTCL] %s' % _("An internal error has occurred. See shell.\n")
-            msg += _("Object ({kind}) failed because: {error} \n\n").format(kind=kind, error=str(e))
-            msg += traceback.format_exc()
-            self.inform.emit(msg)
-            return "fail"
-
-        t2 = time.time()
-        self.log.debug("%f seconds executing initialize()." % (t2 - t1))
-
-        if return_value == 'fail':
-            log.debug("Object (%s) parsing and/or geometry creation failed." % kind)
-            return "fail"
-
-        # Check units and convert if necessary
-        # This condition CAN be true because initialize() can change obj.units
-        if self.options["units"].upper() != obj.units.upper():
-            self.inform.emit('%s: %s' % (_("Converting units to "), self.options["units"]))
-            obj.convert_units(self.options["units"])
-            t3 = time.time()
-            self.log.debug("%f seconds converting units." % (t3 - t2))
-
-        # Create the bounding box for the object and then add the results to the obj.options
-        # But not for Scripts or for Documents
-        if kind != 'document' and kind != 'script':
-            try:
-                xmin, ymin, xmax, ymax = obj.bounds()
-                obj.options['xmin'] = xmin
-                obj.options['ymin'] = ymin
-                obj.options['xmax'] = xmax
-                obj.options['ymax'] = ymax
-            except Exception as e:
-                log.warning("App.new_object() -> The object has no bounds properties. %s" % str(e))
-                return "fail"
-
-            try:
-                if kind == 'excellon':
-                    obj.fill_color = self.defaults["excellon_plot_fill"]
-                    obj.outline_color = self.defaults["excellon_plot_line"]
-
-                if kind == 'gerber':
-                    obj.fill_color = self.defaults["gerber_plot_fill"]
-                    obj.outline_color = self.defaults["gerber_plot_line"]
-            except Exception as e:
-                log.warning("App.new_object() -> setting colors error. %s" % str(e))
-
-        # update the KeyWords list with the name of the file
-        self.myKeywords.append(obj.options['name'])
-
-        log.debug("Moving new object back to main thread.")
-
-        # Move the object to the main thread and let the app know that it is available.
-        obj.moveToThread(self.main_thread)
-        self.object_created.emit(obj, obj_plot, obj_autoselected)
-
-        return obj
-
-    def new_excellon_object(self):
-        """
-        Creates a new, blank Excellon object.
-
-        :return: None
-        """
-        self.defaults.report_usage("new_excellon_object()")
-
-        self.new_object('excellon', 'new_exc', lambda x, y: None, plot=False)
-
-    def new_geometry_object(self):
-        """
-        Creates a new, blank and single-tool Geometry object.
-
-        :return: None
-        """
-        self.defaults.report_usage("new_geometry_object()")
-
-        def initialize(obj, app):
-            obj.multitool = False
-
-        self.new_object('geometry', 'new_geo', initialize, plot=False)
-
-    def new_gerber_object(self):
-        """
-        Creates a new, blank Gerber object.
-
-        :return: None
-        """
-        self.defaults.report_usage("new_gerber_object()")
-
-        def initialize(grb_obj, app):
-            grb_obj.multitool = False
-            grb_obj.source_file = []
-            grb_obj.multigeo = False
-            grb_obj.follow = False
-            grb_obj.apertures = {}
-            grb_obj.solid_geometry = []
-
-            try:
-                grb_obj.options['xmin'] = 0
-                grb_obj.options['ymin'] = 0
-                grb_obj.options['xmax'] = 0
-                grb_obj.options['ymax'] = 0
-            except KeyError:
-                pass
-
-        self.new_object('gerber', 'new_grb', initialize, plot=False)
-
-    def new_script_object(self):
-        """
-        Creates a new, blank TCL Script object.
-
-        :return: None
-        """
-        self.defaults.report_usage("new_script_object()")
-
-        # commands_list = "# AddCircle, AddPolygon, AddPolyline, AddRectangle, AlignDrill, " \
-        #                 "AlignDrillGrid, Bbox, Bounds, ClearShell, CopperClear,\n" \
-        #                 "# Cncjob, Cutout, Delete, Drillcncjob, ExportDXF, ExportExcellon, ExportGcode,\n" \
-        #                 "# ExportGerber, ExportSVG, Exteriors, Follow, GeoCutout, GeoUnion, GetNames,\n" \
-        #                 "# GetSys, ImportSvg, Interiors, Isolate, JoinExcellon, JoinGeometry, " \
-        #                 "ListSys, MillDrills,\n" \
-        #                 "# MillSlots, Mirror, New, NewExcellon, NewGeometry, NewGerber, Nregions, " \
-        #                 "Offset, OpenExcellon, OpenGCode, OpenGerber, OpenProject,\n" \
-        #                 "# Options, Paint, Panelize, PlotAl, PlotObjects, SaveProject, " \
-        #                 "SaveSys, Scale, SetActive, SetSys, SetOrigin, Skew, SubtractPoly,\n" \
-        #                 "# SubtractRectangle, Version, WriteGCode\n"
-
-        new_source_file = '# %s\n' % _('CREATE A NEW FLATCAM TCL SCRIPT') + \
-                          '# %s:\n' % _('TCL Tutorial is here') + \
-                          '# https://www.tcl.tk/man/tcl8.5/tutorial/tcltutorial.html\n' + '\n\n' + \
-                          '# %s:\n' % _("FlatCAM commands list")
-        new_source_file += '# %s\n\n' % _("Type >help< followed by Run Code for a list of FlatCAM Tcl Commands "
-                                          "(displayed in Tcl Shell).")
-
-        def initialize(obj, app):
-            obj.source_file = deepcopy(new_source_file)
-
-        outname = 'new_script'
-        self.new_object('script', outname, initialize, plot=False)
-
-    def new_document_object(self):
-        """
-        Creates a new, blank Document object.
-
-        :return: None
-        """
-        self.defaults.report_usage("new_document_object()")
-
-        def initialize(obj, app):
-            obj.source_file = ""
-
-        self.new_object('document', 'new_document', initialize, plot=False)
-
-    def on_object_created(self, obj, plot, auto_select):
-        """
-        Event callback for object creation.
-        It will add the new object to the collection. After that it will plot the object in a threaded way
-
-        :param obj: The newly created FlatCAM object.
-        :param plot: if the newly create object t obe plotted
-        :param auto_select: if the newly created object to be autoselected after creation
-        :return: None
-        """
-        t0 = time.time()  # DEBUG
-        self.log.debug("on_object_created()")
-
-        # The Collection might change the name if there is a collision
-        self.collection.append(obj)
-
-        # after adding the object to the collection always update the list of objects that are in the collection
-        self.all_objects_list = self.collection.get_list()
-
-        # self.inform.emit('[selected] %s created & selected: %s' %
-        #                  (str(obj.kind).capitalize(), str(obj.options['name'])))
-        if obj.kind == 'gerber':
-            self.inform.emit('[selected] {kind} {tx}: <span style="color:{color};">{name}</span>'.format(
-                kind=obj.kind.capitalize(),
-                color='green',
-                name=str(obj.options['name']), tx=_("created/selected"))
-            )
-        elif obj.kind == 'excellon':
-            self.inform.emit('[selected] {kind} {tx}: <span style="color:{color};">{name}</span>'.format(
-                kind=obj.kind.capitalize(),
-                color='brown',
-                name=str(obj.options['name']), tx=_("created/selected"))
-            )
-        elif obj.kind == 'cncjob':
-            self.inform.emit('[selected] {kind} {tx}: <span style="color:{color};">{name}</span>'.format(
-                kind=obj.kind.capitalize(),
-                color='blue',
-                name=str(obj.options['name']), tx=_("created/selected"))
-            )
-        elif obj.kind == 'geometry':
-            self.inform.emit('[selected] {kind} {tx}: <span style="color:{color};">{name}</span>'.format(
-                kind=obj.kind.capitalize(),
-                color='red',
-                name=str(obj.options['name']), tx=_("created/selected"))
-            )
-        elif obj.kind == 'script':
-            self.inform.emit('[selected] {kind} {tx}: <span style="color:{color};">{name}</span>'.format(
-                kind=obj.kind.capitalize(),
-                color='orange',
-                name=str(obj.options['name']), tx=_("created/selected"))
-            )
-        elif obj.kind == 'document':
-            self.inform.emit('[selected] {kind} {tx}: <span style="color:{color};">{name}</span>'.format(
-                kind=obj.kind.capitalize(),
-                color='darkCyan',
-                name=str(obj.options['name']), tx=_("created/selected"))
-            )
-
-        # update the SHELL auto-completer model with the name of the new object
-        self.shell._edit.set_model_data(self.myKeywords)
-
-        if auto_select:
-            # select the just opened object but deselect the previous ones
-            self.collection.set_all_inactive()
-            self.collection.set_active(obj.options["name"])
-        else:
-            self.collection.set_all_inactive()
-
-        # here it is done the object plotting
-        def worker_task(t_obj):
-            with self.proc_container.new(_("Plotting")):
-                if isinstance(t_obj, CNCJobObject):
-                    t_obj.plot(kind=self.defaults["cncjob_plot_kind"])
-                else:
-                    t_obj.plot()
-                t1 = time.time()  # DEBUG
-                self.log.debug("%f seconds adding object and plotting." % (t1 - t0))
-                self.object_plotted.emit(t_obj)
-
-        # Send to worker
-        # self.worker.add_task(worker_task, [self])
-        if plot is True:
-            self.worker_task.emit({'fcn': worker_task, 'params': [obj]})
-
-    def on_object_changed(self, obj):
-        """
-        Called whenever the geometry of the object was changed in some way.
-        This require the update of it's bounding values so it can be the selected on canvas.
-        Update the bounding box data from obj.options
-
-        :param obj: the object that was changed
-        :return: None
-        """
-
-        try:
-            xmin, ymin, xmax, ymax = obj.bounds()
-        except TypeError:
-            return
-        obj.options['xmin'] = xmin
-        obj.options['ymin'] = ymin
-        obj.options['xmax'] = xmax
-        obj.options['ymax'] = ymax
-
-        log.debug("Object changed, updating the bounding box data on self.options")
-        # delete the old selection shape
-        self.delete_selection_shape()
-        self.should_we_save = True
-
-    def on_object_plotted(self):
-        """
-        Callback called whenever the plotted object needs to be fit into the viewport (canvas)
-
-        :return: None
-        """
-        self.on_zoom_fit(None)
-
     def on_about(self):
         """
         Displays the "about" dialog found in the Menu --> Help.
@@ -3976,7 +3613,7 @@ class App(QtCore.QObject):
                 for v in geo_obj.tools.values():
                     v['data']['name'] = obj_name_multi
 
-            self.new_object("geometry", obj_name_multi, initialize)
+            self.app_obj.new_object("geometry", obj_name_multi, initialize)
         else:
             def initialize(geo_obj, app):
                 GeometryObject.merge(geo_list=objs, geo_final=geo_obj, multigeo=False)
@@ -3986,7 +3623,7 @@ class App(QtCore.QObject):
                 for v in geo_obj.tools.values():
                     v['data']['name'] = obj_name_single
 
-            self.new_object("geometry", obj_name_single, initialize)
+            self.app_obj.new_object("geometry", obj_name_single, initialize)
 
         self.should_we_save = True
 
@@ -4015,7 +3652,7 @@ class App(QtCore.QObject):
             ExcellonObject.merge(exc_list=objs, exc_final=exc_obj, decimals=self.decimals)
             app.inform.emit('[success] %s.' % _("Excellon merging finished"))
 
-        self.new_object("excellon", 'Combo_Excellon', initialize)
+        self.app_obj.new_object("excellon", 'Combo_Excellon', initialize)
         self.should_we_save = True
 
     def on_edit_join_grb(self):
@@ -4043,7 +3680,7 @@ class App(QtCore.QObject):
             GerberObject.merge(grb_list=objs, grb_final=grb_obj)
             app.inform.emit('[success] %s.' % _("Gerber merging finished"))
 
-        self.new_object("gerber", 'Combo_Gerber', initialize)
+        self.app_obj.new_object("gerber", 'Combo_Gerber', initialize)
         self.should_we_save = True
 
     def on_convert_singlegeo_to_multigeo(self):
@@ -4352,7 +3989,7 @@ class App(QtCore.QObject):
                 obj.convert_units(new_units)
 
                 # make that the properties stored in the object are also updated
-                self.object_changed.emit(obj)
+                self.app_obj.object_changed.emit(obj)
                 # rebuild the object UI
                 obj.build_ui()
 
@@ -5017,7 +4654,7 @@ class App(QtCore.QObject):
 
                 for obj in obj_list:
                     obj.offset((x, y))
-                    self.object_changed.emit(obj)
+                    self.app_obj.object_changed.emit(obj)
 
                     # Update the object bounding box options
                     a, b, c, d = obj.bounds()
@@ -5105,7 +4742,7 @@ class App(QtCore.QObject):
 
                 for obj in obj_list:
                     obj.offset((-x, -y))
-                    self.object_changed.emit(obj)
+                    self.app_obj.object_changed.emit(obj)
 
                     # Update the object bounding box options
                     a, b, c, d = obj.bounds()
@@ -5468,15 +5105,15 @@ class App(QtCore.QObject):
 
             try:
                 if isinstance(obj, ExcellonObject):
-                    self.new_object("excellon", str(obj_name) + "_copy", initialize_excellon)
+                    self.app_obj.new_object("excellon", str(obj_name) + "_copy", initialize_excellon)
                 elif isinstance(obj, GerberObject):
-                    self.new_object("gerber", str(obj_name) + "_copy", initialize)
+                    self.app_obj.new_object("gerber", str(obj_name) + "_copy", initialize)
                 elif isinstance(obj, GeometryObject):
-                    self.new_object("geometry", str(obj_name) + "_copy", initialize)
+                    self.app_obj.new_object("geometry", str(obj_name) + "_copy", initialize)
                 elif isinstance(obj, ScriptObject):
-                    self.new_object("script", str(obj_name) + "_copy", initialize_script)
+                    self.app_obj.new_object("script", str(obj_name) + "_copy", initialize_script)
                 elif isinstance(obj, DocumentObject):
-                    self.new_object("document", str(obj_name) + "_copy", initialize_document)
+                    self.app_obj.new_object("document", str(obj_name) + "_copy", initialize_document)
             except Exception as e:
                 return "Operation failed: %s" % str(e)
 
@@ -5517,11 +5154,11 @@ class App(QtCore.QObject):
             obj_name = obj.options["name"]
             try:
                 if isinstance(obj, ExcellonObject):
-                    self.new_object("excellon", str(obj_name) + custom_name, initialize_excellon)
+                    self.app_obj.new_object("excellon", str(obj_name) + custom_name, initialize_excellon)
                 elif isinstance(obj, GerberObject):
-                    self.new_object("gerber", str(obj_name) + custom_name, initialize_gerber)
+                    self.app_obj.new_object("gerber", str(obj_name) + custom_name, initialize_gerber)
                 elif isinstance(obj, GeometryObject):
-                    self.new_object("geometry", str(obj_name) + custom_name, initialize_geometry)
+                    self.app_obj.new_object("geometry", str(obj_name) + custom_name, initialize_geometry)
             except Exception as er:
                 return "Operation failed: %s" % str(er)
 
@@ -5588,9 +5225,9 @@ class App(QtCore.QObject):
 
             try:
                 if isinstance(obj, ExcellonObject):
-                    self.new_object("geometry", str(obj_name) + "_conv", initialize_excellon)
+                    self.app_obj.new_object("geometry", str(obj_name) + "_conv", initialize_excellon)
                 else:
-                    self.new_object("geometry", str(obj_name) + "_conv", initialize)
+                    self.app_obj.new_object("geometry", str(obj_name) + "_conv", initialize)
             except Exception as e:
                 return "Operation failed: %s" % str(e)
 
@@ -5666,9 +5303,9 @@ class App(QtCore.QObject):
 
             try:
                 if isinstance(obj, ExcellonObject):
-                    self.new_object("gerber", str(obj_name) + "_conv", initialize_excellon)
+                    self.app_obj.new_object("gerber", str(obj_name) + "_conv", initialize_excellon)
                 elif isinstance(obj, GeometryObject):
-                    self.new_object("gerber", str(obj_name) + "_conv", initialize_geometry)
+                    self.app_obj.new_object("gerber", str(obj_name) + "_conv", initialize_geometry)
                 else:
                     log.warning("App.convert_any2gerber --> This is no vaild object for conversion.")
 
@@ -5960,7 +5597,7 @@ class App(QtCore.QObject):
                 for obj in obj_list:
                     obj.mirror('X', [px, py])
                     obj.plot()
-                    self.object_changed.emit(obj)
+                    self.app_obj.object_changed.emit(obj)
                 self.inform.emit('[success] %s' %
                                  _("Flip on Y axis done."))
             except Exception as e:
@@ -6008,7 +5645,7 @@ class App(QtCore.QObject):
                 for obj in obj_list:
                     obj.mirror('Y', [px, py])
                     obj.plot()
-                    self.object_changed.emit(obj)
+                    self.app_obj.object_changed.emit(obj)
                 self.inform.emit('[success] %s' %
                                  _("Flip on X axis done."))
             except Exception as e:
@@ -6064,7 +5701,7 @@ class App(QtCore.QObject):
                     for sel_obj in obj_list:
                         sel_obj.rotate(-float(num), point=(px, py))
                         sel_obj.plot()
-                        self.object_changed.emit(sel_obj)
+                        self.app_obj.object_changed.emit(sel_obj)
                     self.inform.emit('[success] %s' % _("Rotation done."))
                 except Exception as e:
                     self.inform.emit('[ERROR_NOTCL] %s: %s' % (_("Rotation movement was not executed."), str(e)))
@@ -6104,7 +5741,7 @@ class App(QtCore.QObject):
                 for obj in obj_list:
                     obj.skew(num, 0, point=(xminimal, yminimal))
                     obj.plot()
-                    self.object_changed.emit(obj)
+                    self.app_obj.object_changed.emit(obj)
                 self.inform.emit('[success] %s' % _("Skew on X axis done."))
 
     def on_skewy(self):
@@ -6141,7 +5778,7 @@ class App(QtCore.QObject):
                 for obj in obj_list:
                     obj.skew(0, num, point=(xminimal, yminimal))
                     obj.plot()
-                    self.object_changed.emit(obj)
+                    self.app_obj.object_changed.emit(obj)
                 self.inform.emit('[success] %s' % _("Skew on Y axis done."))
 
     def on_plots_updated(self):
@@ -7970,7 +7607,7 @@ class App(QtCore.QObject):
         self.ui.position_label.setText("")
         # self.ui.rel_position_label.setText("")
 
-        self.new_script_object()
+        self.app_obj.new_script_object()
 
         # script_text = script_obj.source_file
         #
@@ -8891,7 +8528,7 @@ class App(QtCore.QObject):
             # Object name
             name = outname or filename.split('/')[-1].split('\\')[-1]
 
-            ret = self.new_object(obj_type, name, obj_init, autoselected=False, plot=plot)
+            ret = self.app_obj.new_object(obj_type, name, obj_init, autoselected=False, plot=plot)
 
             if ret == 'fail':
                 self.inform.emit('[ERROR_NOTCL]%s' % _('Import failed.'))
@@ -8937,7 +8574,7 @@ class App(QtCore.QObject):
             # Object name
             name = outname or filename.split('/')[-1].split('\\')[-1]
 
-            ret = self.new_object(obj_type, name, obj_init, autoselected=False, plot=plot)
+            ret = self.app_obj.new_object(obj_type, name, obj_init, autoselected=False, plot=plot)
 
             if ret == 'fail':
                 self.inform.emit('[ERROR_NOTCL]%s' % _('Import failed.'))
@@ -8998,11 +8635,11 @@ class App(QtCore.QObject):
             name = outname or filename.split('/')[-1].split('\\')[-1]
 
             # # ## Object creation # ##
-            ret_val = self.new_object("gerber", name, obj_init, autoselected=False, plot=plot)
+            ret_val = self.app_obj.new_object("gerber", name, obj_init, autoselected=False, plot=plot)
             if ret_val == 'fail':
                 if from_tcl:
                     filename = self.defaults['global_tcl_path'] + '/' + name
-                    ret_val = self.new_object("gerber", name, obj_init, autoselected=False, plot=plot)
+                    ret_val = self.app_obj.new_object("gerber", name, obj_init, autoselected=False, plot=plot)
                 if ret_val == 'fail':
                     self.inform.emit('[ERROR_NOTCL]%s' % _('Open Gerber failed. Probable not a Gerber file.'))
                     return 'fail'
@@ -9064,11 +8701,11 @@ class App(QtCore.QObject):
         with self.proc_container.new(_("Opening Excellon.")):
             # Object name
             name = outname or filename.split('/')[-1].split('\\')[-1]
-            ret_val = self.new_object("excellon", name, obj_init, autoselected=False, plot=plot)
+            ret_val = self.app_obj.new_object("excellon", name, obj_init, autoselected=False, plot=plot)
             if ret_val == 'fail':
                 if from_tcl:
                     filename = self.defaults['global_tcl_path'] + '/' + name
-                    ret_val = self.new_object("excellon", name, obj_init, autoselected=False, plot=plot)
+                    ret_val = self.app_obj.new_object("excellon", name, obj_init, autoselected=False, plot=plot)
                 if ret_val == 'fail':
                     self.inform.emit('[ERROR_NOTCL] %s' %
                                      _('Open Excellon file failed. Probable not an Excellon file.'))
@@ -9127,11 +8764,11 @@ class App(QtCore.QObject):
             name = outname or filename.split('/')[-1].split('\\')[-1]
 
             # New object creation and file processing
-            ret_val = self.new_object("cncjob", name, obj_init, autoselected=False, plot=plot)
+            ret_val = self.app_obj.new_object("cncjob", name, obj_init, autoselected=False, plot=plot)
             if ret_val == 'fail':
                 if from_tcl:
                     filename = self.defaults['global_tcl_path'] + '/' + name
-                    ret_val = self.new_object("cncjob", name, obj_init, autoselected=False, plot=plot)
+                    ret_val = self.app_obj.new_object("cncjob", name, obj_init, autoselected=False, plot=plot)
                 if ret_val == 'fail':
                     self.inform.emit('[ERROR_NOTCL] %s' %
                                      _("Failed to create CNCJob Object. Probable not a GCode file. "
@@ -9200,7 +8837,7 @@ class App(QtCore.QObject):
             name = outname or filename.split('/')[-1].split('\\')[-1]
 
             # # ## Object creation # ##
-            ret = self.new_object("geometry", name, obj_init, autoselected=False)
+            ret = self.app_obj.new_object("geometry", name, obj_init, autoselected=False)
             if ret == 'fail':
                 self.inform.emit('[ERROR_NOTCL]%s' % _(' Open HPGL2 failed. Probable not a HPGL2 file.'))
                 return 'fail'
@@ -9254,10 +8891,10 @@ class App(QtCore.QObject):
             script_name = outname or filename.split('/')[-1].split('\\')[-1]
 
             # Object creation
-            ret_val = self.new_object("script", script_name, obj_init, autoselected=False, plot=False)
+            ret_val = self.app_obj.new_object("script", script_name, obj_init, autoselected=False, plot=False)
             if ret_val == 'fail':
                 filename = self.defaults['global_tcl_path'] + '/' + script_name
-                ret_val = self.new_object("script", script_name, obj_init, autoselected=False, plot=False)
+                ret_val = self.app_obj.new_object("script", script_name, obj_init, autoselected=False, plot=False)
                 if ret_val == 'fail':
                     self.inform.emit('[ERROR_NOTCL]%s' % _('Failed to open TCL Script.'))
                     return 'fail'
@@ -9320,7 +8957,7 @@ class App(QtCore.QObject):
         2) Registers the file as recently opened.
         3) Calls on_file_new()
         4) Updates options
-        5) Calls new_object() with the object's from_dict() as init method.
+        5) Calls app_obj.new_object() with the object's from_dict() as init method.
         6) Calls plot_all() if plot=True
 
         :param filename:        Name of the file from which to load.
@@ -9422,7 +9059,7 @@ class App(QtCore.QObject):
                                                               )
                                       )
 
-                self.new_object(obj['kind'], obj['options']['name'], obj_init, plot=plot)
+                self.app_obj.new_object(obj['kind'], obj['options']['name'], obj_init, plot=plot)
             except Exception as e:
                 print('App.open_project() --> ' + str(e))
 
@@ -9459,7 +9096,7 @@ class App(QtCore.QObject):
                 with self.proc_container.new("Plotting"):
                     obj.plot(kind=self.defaults["cncjob_plot_kind"])
                     if fit_view is True:
-                        self.object_plotted.emit(obj)
+                        self.app_obj.object_plotted.emit(obj)
 
             if use_thread is True:
                 # Send to worker
@@ -10044,8 +9681,6 @@ class App(QtCore.QObject):
 
         self.worker_task.emit({'fcn': worker_task, 'params': [objects]})
 
-        # self.plots_updated.emit()
-
     def disable_plots(self, objects):
         """
         Disables plots
@@ -10084,7 +9719,6 @@ class App(QtCore.QObject):
         except Exception as e:
             log.debug("App.disable_plots() --> %s" % str(e))
 
-        # self.plots_updated.emit()
         def worker_task(objs):
             with self.proc_container.new(_("Disabling plots ...")):
                 for plot_obj in objs:
@@ -10115,7 +9749,7 @@ class App(QtCore.QObject):
                 obj.options['plot'] = True
             else:
                 obj.options['plot'] = False
-        self.plots_updated.emit()
+        self.app_obj.plots_updated.emit()
 
     def clear_plots(self):
         """

+ 393 - 0
AppObjects/AppObject.py

@@ -0,0 +1,393 @@
+# ###########################################################
+# FlatCAM: 2D Post-processing for Manufacturing             #
+# http://flatcam.org                                        #
+# Author: Juan Pablo Caram (c)                              #
+# Date: 2/5/2014                                            #
+# MIT Licence                                               #
+# Modified by Marius Stanciu (2020)                         #
+# ###########################################################
+
+from PyQt5 import QtCore
+from AppObjects.ObjectCollection import *
+from AppObjects.FlatCAMCNCJob import CNCJobObject
+from AppObjects.FlatCAMDocument import DocumentObject
+from AppObjects.FlatCAMExcellon import ExcellonObject
+from AppObjects.FlatCAMGeometry import GeometryObject
+from AppObjects.FlatCAMGerber import GerberObject
+from AppObjects.FlatCAMScript import ScriptObject
+
+import time
+import traceback
+
+# FlatCAM Translation
+import gettext
+import AppTranslation as fcTranslate
+import builtins
+
+fcTranslate.apply_language('strings')
+if '_' not in builtins.__dict__:
+    _ = gettext.gettext
+
+
+class AppObject(QtCore.QObject):
+
+    # Emitted by app_obj.new_object() and passes the new object as argument, plot flag.
+    # on_object_created() adds the object to the collection, plots on appropriate flag
+    # and emits app_obj.new_object_available.
+    object_created = QtCore.pyqtSignal(object, bool, bool)
+
+    # Emitted when a object has been changed (like scaled, mirrored)
+    object_changed = QtCore.pyqtSignal(object)
+
+    # Emitted after object has been plotted.
+    # Calls 'on_zoom_fit' method to fit object in scene view in main thread to prevent drawing glitches.
+    object_plotted = QtCore.pyqtSignal(object)
+
+    plots_updated = QtCore.pyqtSignal()
+
+    def __init__(self, app):
+        super(AppObject, self).__init__()
+        self.app = app
+
+        # signals that are emitted when object state changes
+        self.object_created.connect(self.on_object_created)
+        self.object_changed.connect(self.on_object_changed)
+        self.object_plotted.connect(self.on_object_plotted)
+        self.plots_updated.connect(self.app.on_plots_updated)
+
+    def new_object(self, kind, name, initialize, plot=True, autoselected=True):
+        """
+        Creates a new specialized FlatCAMObj and attaches it to the application,
+        this is, updates the GUI accordingly, any other records and plots it.
+        This method is thread-safe.
+
+        Notes:
+            * If the name is in use, the self.collection will modify it
+              when appending it to the collection. There is no need to handle
+              name conflicts here.
+
+        :param kind: The kind of object to create. One of 'gerber', 'excellon', 'cncjob' and 'geometry'.
+        :type kind: str
+        :param name: Name for the object.
+        :type name: str
+        :param initialize: Function to run after creation of the object but before it is attached to the application.
+        The function is called with 2 parameters: the new object and the App instance.
+        :type initialize: function
+        :param plot: If to plot the resulting object
+        :param autoselected: if the resulting object is autoselected in the Project tab and therefore in the
+        self.collection
+        :return: None
+        :rtype: None
+        """
+
+        log.debug("AppObject.new_object()")
+        obj_plot = plot
+        obj_autoselected = autoselected
+
+        t0 = time.time()  # Debug
+
+        # ## Create object
+        classdict = {
+            "gerber": GerberObject,
+            "excellon": ExcellonObject,
+            "cncjob": CNCJobObject,
+            "geometry": GeometryObject,
+            "script": ScriptObject,
+            "document": DocumentObject
+        }
+
+        log.debug("Calling object constructor...")
+
+        # Object creation/instantiation
+        obj = classdict[kind](name)
+
+        obj.units = self.app.options["units"]
+
+        # IMPORTANT
+        # The key names in defaults and options dictionary's are not random:
+        # they have to have in name first the type of the object (geometry, excellon, cncjob and gerber) or how it's
+        # called here, the 'kind' followed by an underline. Above the App default values from self.defaults are
+        # copied to self.options. After that, below, depending on the type of
+        # object that is created, it will strip the name of the object and the underline (if the original key was
+        # let's say "excellon_toolchange", it will strip the excellon_) and to the obj.options the key will become
+        # "toolchange"
+
+        for option in self.app.options:
+            if option.find(kind + "_") == 0:
+                oname = option[len(kind) + 1:]
+                obj.options[oname] = self.app.options[option]
+
+        obj.isHovering = False
+        obj.notHovering = True
+
+        # Initialize as per user request
+        # User must take care to implement initialize
+        # in a thread-safe way as is is likely that we
+        # have been invoked in a separate thread.
+        t1 = time.time()
+        log.debug("%f seconds before initialize()." % (t1 - t0))
+        try:
+            return_value = initialize(obj, self)
+        except Exception as e:
+            msg = '[ERROR_NOTCL] %s' % _("An internal error has occurred. See shell.\n")
+            msg += _("Object ({kind}) failed because: {error} \n\n").format(kind=kind, error=str(e))
+            msg += traceback.format_exc()
+            self.app.inform.emit(msg)
+            return "fail"
+
+        t2 = time.time()
+        log.debug("%f seconds executing initialize()." % (t2 - t1))
+
+        if return_value == 'fail':
+            log.debug("Object (%s) parsing and/or geometry creation failed." % kind)
+            return "fail"
+
+        # Check units and convert if necessary
+        # This condition CAN be true because initialize() can change obj.units
+        if self.app.options["units"].upper() != obj.units.upper():
+            self.app.inform.emit('%s: %s' % (_("Converting units to "), self.app.options["units"]))
+            obj.convert_units(self.app.options["units"])
+            t3 = time.time()
+            log.debug("%f seconds converting units." % (t3 - t2))
+
+        # Create the bounding box for the object and then add the results to the obj.options
+        # But not for Scripts or for Documents
+        if kind != 'document' and kind != 'script':
+            try:
+                xmin, ymin, xmax, ymax = obj.bounds()
+                obj.options['xmin'] = xmin
+                obj.options['ymin'] = ymin
+                obj.options['xmax'] = xmax
+                obj.options['ymax'] = ymax
+            except Exception as e:
+                log.warning("AppObject.new_object() -> The object has no bounds properties. %s" % str(e))
+                return "fail"
+
+            try:
+                if kind == 'excellon':
+                    obj.fill_color = self.app.defaults["excellon_plot_fill"]
+                    obj.outline_color = self.app.defaults["excellon_plot_line"]
+
+                if kind == 'gerber':
+                    obj.fill_color = self.app.defaults["gerber_plot_fill"]
+                    obj.outline_color = self.app.defaults["gerber_plot_line"]
+            except Exception as e:
+                log.warning("AppObject.new_object() -> setting colors error. %s" % str(e))
+
+        # update the KeyWords list with the name of the file
+        self.app.myKeywords.append(obj.options['name'])
+
+        log.debug("Moving new object back to main thread.")
+
+        # Move the object to the main thread and let the app know that it is available.
+        obj.moveToThread(self.app.main_thread)
+        self.object_created.emit(obj, obj_plot, obj_autoselected)
+
+        return obj
+
+    def new_excellon_object(self):
+        """
+        Creates a new, blank Excellon object.
+
+        :return: None
+        """
+
+        self.new_object('excellon', 'new_exc', lambda x, y: None, plot=False)
+
+    def new_geometry_object(self):
+        """
+        Creates a new, blank and single-tool Geometry object.
+
+        :return: None
+        """
+
+        def initialize(obj, app):
+            obj.multitool = False
+
+        self.new_object('geometry', 'new_geo', initialize, plot=False)
+
+    def new_gerber_object(self):
+        """
+        Creates a new, blank Gerber object.
+
+        :return: None
+        """
+
+        def initialize(grb_obj, app):
+            grb_obj.multitool = False
+            grb_obj.source_file = []
+            grb_obj.multigeo = False
+            grb_obj.follow = False
+            grb_obj.apertures = {}
+            grb_obj.solid_geometry = []
+
+            try:
+                grb_obj.options['xmin'] = 0
+                grb_obj.options['ymin'] = 0
+                grb_obj.options['xmax'] = 0
+                grb_obj.options['ymax'] = 0
+            except KeyError:
+                pass
+
+        self.new_object('gerber', 'new_grb', initialize, plot=False)
+
+    def new_script_object(self):
+        """
+        Creates a new, blank TCL Script object.
+
+        :return: None
+        """
+
+        # commands_list = "# AddCircle, AddPolygon, AddPolyline, AddRectangle, AlignDrill, " \
+        #                 "AlignDrillGrid, Bbox, Bounds, ClearShell, CopperClear,\n" \
+        #                 "# Cncjob, Cutout, Delete, Drillcncjob, ExportDXF, ExportExcellon, ExportGcode,\n" \
+        #                 "# ExportGerber, ExportSVG, Exteriors, Follow, GeoCutout, GeoUnion, GetNames,\n" \
+        #                 "# GetSys, ImportSvg, Interiors, Isolate, JoinExcellon, JoinGeometry, " \
+        #                 "ListSys, MillDrills,\n" \
+        #                 "# MillSlots, Mirror, New, NewExcellon, NewGeometry, NewGerber, Nregions, " \
+        #                 "Offset, OpenExcellon, OpenGCode, OpenGerber, OpenProject,\n" \
+        #                 "# Options, Paint, Panelize, PlotAl, PlotObjects, SaveProject, " \
+        #                 "SaveSys, Scale, SetActive, SetSys, SetOrigin, Skew, SubtractPoly,\n" \
+        #                 "# SubtractRectangle, Version, WriteGCode\n"
+
+        new_source_file = '# %s\n' % _('CREATE A NEW FLATCAM TCL SCRIPT') + \
+                          '# %s:\n' % _('TCL Tutorial is here') + \
+                          '# https://www.tcl.tk/man/tcl8.5/tutorial/tcltutorial.html\n' + '\n\n' + \
+                          '# %s:\n' % _("FlatCAM commands list")
+        new_source_file += '# %s\n\n' % _("Type >help< followed by Run Code for a list of FlatCAM Tcl Commands "
+                                          "(displayed in Tcl Shell).")
+
+        def initialize(obj, app):
+            obj.source_file = deepcopy(new_source_file)
+
+        outname = 'new_script'
+        self.new_object('script', outname, initialize, plot=False)
+
+    def new_document_object(self):
+        """
+        Creates a new, blank Document object.
+
+        :return: None
+        """
+
+        def initialize(obj, app):
+            obj.source_file = ""
+
+        self.new_object('document', 'new_document', initialize, plot=False)
+
+    def on_object_created(self, obj, plot, auto_select):
+        """
+        Event callback for object creation.
+        It will add the new object to the collection. After that it will plot the object in a threaded way
+
+        :param obj: The newly created FlatCAM object.
+        :param plot: if the newly create object t obe plotted
+        :param auto_select: if the newly created object to be autoselected after creation
+        :return: None
+        """
+        t0 = time.time()  # DEBUG
+        log.debug("on_object_created()")
+
+        # The Collection might change the name if there is a collision
+        self.app.collection.append(obj)
+
+        # after adding the object to the collection always update the list of objects that are in the collection
+        self.all_objects_list = self.app.collection.get_list()
+
+        # self.app.inform.emit('[selected] %s created & selected: %s' %
+        #                  (str(obj.kind).capitalize(), str(obj.options['name'])))
+        if obj.kind == 'gerber':
+            self.app.inform.emit('[selected] {kind} {tx}: <span style="color:{color};">{name}</span>'.format(
+                kind=obj.kind.capitalize(),
+                color='green',
+                name=str(obj.options['name']), tx=_("created/selected"))
+            )
+        elif obj.kind == 'excellon':
+            self.app.inform.emit('[selected] {kind} {tx}: <span style="color:{color};">{name}</span>'.format(
+                kind=obj.kind.capitalize(),
+                color='brown',
+                name=str(obj.options['name']), tx=_("created/selected"))
+            )
+        elif obj.kind == 'cncjob':
+            self.app.inform.emit('[selected] {kind} {tx}: <span style="color:{color};">{name}</span>'.format(
+                kind=obj.kind.capitalize(),
+                color='blue',
+                name=str(obj.options['name']), tx=_("created/selected"))
+            )
+        elif obj.kind == 'geometry':
+            self.app.inform.emit('[selected] {kind} {tx}: <span style="color:{color};">{name}</span>'.format(
+                kind=obj.kind.capitalize(),
+                color='red',
+                name=str(obj.options['name']), tx=_("created/selected"))
+            )
+        elif obj.kind == 'script':
+            self.app.inform.emit('[selected] {kind} {tx}: <span style="color:{color};">{name}</span>'.format(
+                kind=obj.kind.capitalize(),
+                color='orange',
+                name=str(obj.options['name']), tx=_("created/selected"))
+            )
+        elif obj.kind == 'document':
+            self.app.inform.emit('[selected] {kind} {tx}: <span style="color:{color};">{name}</span>'.format(
+                kind=obj.kind.capitalize(),
+                color='darkCyan',
+                name=str(obj.options['name']), tx=_("created/selected"))
+            )
+
+        # update the SHELL auto-completer model with the name of the new object
+        self.app.shell._edit.set_model_data(self.app.myKeywords)
+
+        if auto_select:
+            # select the just opened object but deselect the previous ones
+            self.app.collection.set_all_inactive()
+            self.app.collection.set_active(obj.options["name"])
+        else:
+            self.app.collection.set_all_inactive()
+
+        # here it is done the object plotting
+        def task(t_obj):
+            with self.app.proc_container.new(_("Plotting")):
+                if t_obj.kind == 'cncjob':
+                    t_obj.plot(kind=self.defaults["cncjob_plot_kind"])
+                else:
+                    t_obj.plot()
+
+                t1 = time.time()  # DEBUG
+                log.debug("%f seconds adding object and plotting." % (t1 - t0))
+                self.object_plotted.emit(t_obj)
+
+        # Send to worker
+        # self.worker.add_task(worker_task, [self])
+        if plot is True:
+            self.worker_task.emit({'fcn': task, 'params': [obj]})
+
+    def on_object_changed(self, obj):
+        """
+        Called whenever the geometry of the object was changed in some way.
+        This require the update of it's bounding values so it can be the selected on canvas.
+        Update the bounding box data from obj.options
+
+        :param obj: the object that was changed
+        :return: None
+        """
+
+        try:
+            xmin, ymin, xmax, ymax = obj.bounds()
+        except TypeError:
+            return
+        obj.options['xmin'] = xmin
+        obj.options['ymin'] = ymin
+        obj.options['xmax'] = xmax
+        obj.options['ymax'] = ymax
+
+        log.debug("Object changed, updating the bounding box data on self.options")
+        # delete the old selection shape
+        self.app.delete_selection_shape()
+        self.app.should_we_save = True
+
+    def on_object_plotted(self):
+        """
+        Callback called whenever the plotted object needs to be fit into the viewport (canvas)
+
+        :return: None
+        """
+        self.app.on_zoom_fit(None)

+ 9 - 9
AppObjects/FlatCAMExcellon.py

@@ -1196,8 +1196,8 @@ class ExcellonObject(FlatCAMObj, Excellon):
                             Point(hole['point']).buffer(buffer_value).exterior)
 
         if use_thread:
-            def geo_thread(app_obj):
-                app_obj.new_object("geometry", outname, geo_init, plot=plot)
+            def geo_thread(a_obj):
+                a_obj.app_obj.new_object("geometry", outname, geo_init, plot=plot)
 
             # Create a promise with the new name
             self.app.collection.promise(outname)
@@ -1205,7 +1205,7 @@ class ExcellonObject(FlatCAMObj, Excellon):
             # Send to worker
             self.app.worker_task.emit({'fcn': geo_thread, 'params': [self.app]})
         else:
-            self.app.new_object("geometry", outname, geo_init, plot=plot)
+            self.app.app_obj.new_object("geometry", outname, geo_init, plot=plot)
 
         return True, ""
 
@@ -1300,8 +1300,8 @@ class ExcellonObject(FlatCAMObj, Excellon):
                         geo_obj.solid_geometry.append(poly)
 
         if use_thread:
-            def geo_thread(app_obj):
-                app_obj.new_object("geometry", outname + '_slot', geo_init, plot=plot)
+            def geo_thread(a_obj):
+                a_obj.app_obj.new_object("geometry", outname + '_slot', geo_init, plot=plot)
 
             # Create a promise with the new name
             self.app.collection.promise(outname)
@@ -1309,7 +1309,7 @@ class ExcellonObject(FlatCAMObj, Excellon):
             # Send to worker
             self.app.worker_task.emit({'fcn': geo_thread, 'params': [self.app]})
         else:
-            self.app.new_object("geometry", outname + '_slot', geo_init, plot=plot)
+            self.app.app_obj.new_object("geometry", outname + '_slot', geo_init, plot=plot)
 
         return True, ""
 
@@ -1443,7 +1443,7 @@ class ExcellonObject(FlatCAMObj, Excellon):
         job_name = self.options["name"] + "_cnc"
         pp_excellon_name = self.options["ppname_e"]
 
-        # Object initialization function for app.new_object()
+        # Object initialization function for app.app_obj.new_object()
         def job_init(job_obj, app_obj):
             assert job_obj.kind == 'cncjob', "Initializer expected a CNCJobObject, got %s" % type(job_obj)
 
@@ -1506,9 +1506,9 @@ class ExcellonObject(FlatCAMObj, Excellon):
             job_obj.create_geometry()
 
         # To be run in separate thread
-        def job_thread(app_obj):
+        def job_thread(a_obj):
             with self.app.proc_container.new(_("Generating CNC Code")):
-                app_obj.new_object("cncjob", job_name, job_init)
+                a_obj.app_obj.new_object("cncjob", job_name, job_init)
 
         # Create promise for the new name.
         self.app.collection.promise(job_name)

+ 12 - 12
AppObjects/FlatCAMGeometry.py

@@ -1778,7 +1778,7 @@ class GeometryObject(FlatCAMObj, Geometry):
             self.app.inform.emit(msg)
             return
 
-        # Object initialization function for app.new_object()
+        # Object initialization function for app.app_obj.new_object()
         # RUNNING ON SEPARATE THREAD!
         def job_init_single_geometry(job_obj, app_obj):
             log.debug("Creating a CNCJob out of a single-geometry")
@@ -1918,7 +1918,7 @@ class GeometryObject(FlatCAMObj, Geometry):
                 })
                 dia_cnc_dict.clear()
 
-        # Object initialization function for app.new_object()
+        # Object initialization function for app.app_obj.new_object()
         # RUNNING ON SEPARATE THREAD!
         def job_init_multi_geometry(job_obj, app_obj):
             log.debug("Creating a CNCJob out of a multi-geometry")
@@ -2072,15 +2072,15 @@ class GeometryObject(FlatCAMObj, Geometry):
 
         if use_thread:
             # To be run in separate thread
-            def job_thread(app_obj):
+            def job_thread(a_obj):
                 if self.multigeo is False:
                     with self.app.proc_container.new(_("Generating CNC Code")):
-                        if app_obj.new_object("cncjob", outname, job_init_single_geometry, plot=plot) != 'fail':
-                            app_obj.inform.emit('[success] %s: %s' % (_("CNCjob created"), outname))
+                        if a_obj.app_obj.new_object("cncjob", outname, job_init_single_geometry, plot=plot) != 'fail':
+                            a_obj.inform.emit('[success] %s: %s' % (_("CNCjob created"), outname))
                 else:
                     with self.app.proc_container.new(_("Generating CNC Code")):
-                        if app_obj.new_object("cncjob", outname, job_init_multi_geometry) != 'fail':
-                            app_obj.inform.emit('[success] %s: %s' % (_("CNCjob created"), outname))
+                        if a_obj.app_obj.new_object("cncjob", outname, job_init_multi_geometry) != 'fail':
+                            a_obj.inform.emit('[success] %s: %s' % (_("CNCjob created"), outname))
 
             # Create a promise with the name
             self.app.collection.promise(outname)
@@ -2088,9 +2088,9 @@ class GeometryObject(FlatCAMObj, Geometry):
             self.app.worker_task.emit({'fcn': job_thread, 'params': [self.app]})
         else:
             if self.solid_geometry:
-                self.app.new_object("cncjob", outname, job_init_single_geometry, plot=plot)
+                self.app.app_obj.new_object("cncjob", outname, job_init_single_geometry, plot=plot)
             else:
-                self.app.new_object("cncjob", outname, job_init_multi_geometry, plot=plot)
+                self.app.app_obj.new_object("cncjob", outname, job_init_multi_geometry, plot=plot)
 
     def generatecncjob(self, outname=None, dia=None, offset=None, z_cut=None, z_move=None,
             feedrate=None, feedrate_z=None, feedrate_rapid=None, spindlespeed=None, dwell=None, dwelltime=None,
@@ -2181,7 +2181,7 @@ class GeometryObject(FlatCAMObj, Geometry):
 
         ppname_g = pp if pp else self.options["ppname_g"]
 
-        # Object initialization function for app.new_object()
+        # Object initialization function for app.app_obj.new_object()
         # RUNNING ON SEPARATE THREAD!
         def job_init(job_obj, app_obj):
             assert job_obj.kind == 'cncjob', "Initializer expected a CNCJobObject, got %s" % type(job_obj)
@@ -2230,7 +2230,7 @@ class GeometryObject(FlatCAMObj, Geometry):
             # To be run in separate thread
             def job_thread(app_obj):
                 with self.app.proc_container.new(_("Generating CNC Code")):
-                    app_obj.new_object("cncjob", outname, job_init, plot=plot)
+                    app_obj.app_obj.new_object("cncjob", outname, job_init, plot=plot)
                     app_obj.inform.emit('[success] %s: %s' % (_("CNCjob created")), outname)
 
             # Create a promise with the name
@@ -2238,7 +2238,7 @@ class GeometryObject(FlatCAMObj, Geometry):
             # Send to worker
             self.app.worker_task.emit({'fcn': job_thread, 'params': [self.app]})
         else:
-            self.app.new_object("cncjob", outname, job_init, plot=plot)
+            self.app.app_obj.new_object("cncjob", outname, job_init, plot=plot)
 
     # def on_plot_cb_click(self, *args):
     #     if self.muted_ui:

+ 5 - 5
AppObjects/FlatCAMGerber.py

@@ -530,7 +530,7 @@ class GerberObject(FlatCAMObj, Gerber):
                 return "fail"
             geo_obj.solid_geometry = non_copper
 
-        self.app.new_object("geometry", name, geo_init)
+        self.app.app_obj.new_object("geometry", name, geo_init)
 
     def on_generatebb_button_click(self, *args):
         self.app.defaults.report_usage("gerber_on_generatebb_button")
@@ -556,7 +556,7 @@ class GerberObject(FlatCAMObj, Gerber):
                 return "fail"
             geo_obj.solid_geometry = bounding_box
 
-        self.app.new_object("geometry", name, geo_init)
+        self.app.app_obj.new_object("geometry", name, geo_init)
 
     def on_iso_button_click(self, *args):
 
@@ -605,7 +605,7 @@ class GerberObject(FlatCAMObj, Gerber):
 
         # TODO: Do something if this is None. Offer changing name?
         try:
-            self.app.new_object("geometry", follow_name, follow_init)
+            self.app.app_obj.new_object("geometry", follow_name, follow_init)
         except Exception as e:
             return "Operation failed: %s" % str(e)
 
@@ -942,7 +942,7 @@ class GerberObject(FlatCAMObj, Gerber):
                     geo_obj.solid_geometry = self.area_subtraction(geo_obj.solid_geometry)
 
             # TODO: Do something if this is None. Offer changing name?
-            self.app.new_object("geometry", iso_name, iso_init, plot=plot)
+            self.app.app_obj.new_object("geometry", iso_name, iso_init, plot=plot)
         else:
             for i in range(passes):
 
@@ -1072,7 +1072,7 @@ class GerberObject(FlatCAMObj, Gerber):
                         geo_obj.solid_geometry = self.area_subtraction(geo_obj.solid_geometry)
 
                 # TODO: Do something if this is None. Offer changing name?
-                self.app.new_object("geometry", iso_name, iso_init, plot=plot)
+                self.app.app_obj.new_object("geometry", iso_name, iso_init, plot=plot)
 
     def generate_envelope(self, offset, invert, geometry=None, env_iso_type=2, follow=None, nr_passes=0):
         # isolation_geometry produces an envelope that is going on the left of the geometry

+ 4 - 4
AppObjects/FlatCAMObj.py

@@ -245,7 +245,7 @@ class FlatCAMObj(QtCore.QObject):
             self.app.proc_container.update_view_text('')
             with self.app.proc_container.new('%s...' % _("Plotting")):
                 self.plot()
-            self.app.object_changed.emit(self)
+            self.app.app_obj.object_changed.emit(self)
 
         self.app.worker_task.emit({'fcn': worker_task, 'params': []})
 
@@ -276,7 +276,7 @@ class FlatCAMObj(QtCore.QObject):
             self.app.proc_container.update_view_text('')
             with self.app.proc_container.new('%s...' % _("Plotting")):
                 self.plot()
-            self.app.object_changed.emit(self)
+            self.app.app_obj.object_changed.emit(self)
 
         self.app.worker_task.emit({'fcn': worker_task, 'params': []})
 
@@ -292,7 +292,7 @@ class FlatCAMObj(QtCore.QObject):
             self.app.proc_container.update_view_text('')
             with self.app.proc_container.new('%s...' % _("Plotting")):
                 self.plot()
-            self.app.object_changed.emit(self)
+            self.app.app_obj.object_changed.emit(self)
 
         self.app.worker_task.emit({'fcn': worker_task, 'params': []})
 
@@ -372,7 +372,7 @@ class FlatCAMObj(QtCore.QObject):
         def plot_task():
             with self.app.proc_container.new('%s...' % _("Plotting")):
                 self.plot()
-            self.app.object_changed.emit(self)
+            self.app.app_obj.object_changed.emit(self)
 
         self.app.worker_task.emit({'fcn': plot_task, 'params': []})
 

+ 1 - 1
AppObjects/ObjectCollection.py

@@ -553,7 +553,7 @@ class ObjectCollection(QtCore.QAbstractItemModel):
         while name in self.get_names():
             # ## Create a new name
             # Ends with number?
-            log.debug("new_object(): Object name (%s) exists, changing." % name)
+            log.debug("app_obj.new_object(): Object name (%s) exists, changing." % name)
             match = re.search(r'(.*[^\d])?(\d+)$', name)
             if match:  # Yes: Increment the number!
                 base = match.group(1) or ''

+ 1 - 1
AppParsers/ParseExcellon.py

@@ -1069,7 +1069,7 @@ class Excellon(Geometry):
         This function first convert to the the units found in the Excellon file but it converts tools that
         are not there yet so it has no effect other than it signal that the units are the ones in the file.
 
-        On object creation, in new_object(), true conversion is done because this is done at the end of the
+        On object creation, in app_obj.new_object(), true conversion is done because this is done at the end of the
         Excellon file parsing, the tools are inside and self.tools is really converted from the units found
         inside the file to the FlatCAM units.
 

+ 1 - 1
AppTool.py

@@ -28,7 +28,7 @@ class AppTool(QtWidgets.QWidget):
         """
 
         :param app: The application this tool will run in.
-        :type app: App
+        :type app: AppMain
         :param parent: Qt Parent
         :return: AppTool
         """

+ 3 - 3
AppTools/ToolCalibration.py

@@ -1352,11 +1352,11 @@ class ToolCalibration(AppTool):
 
         try:
             if obj.kind.lower() == 'excellon':
-                self.app.new_object("excellon", str(obj_name), initialize_excellon)
+                self.app.app_obj.new_object("excellon", str(obj_name), initialize_excellon)
             elif obj.kind.lower() == 'gerber':
-                self.app.new_object("gerber", str(obj_name), initialize_gerber)
+                self.app.app_obj.new_object("gerber", str(obj_name), initialize_gerber)
             elif obj.kind.lower() == 'geometry':
-                self.app.new_object("geometry", str(obj_name), initialize_geometry)
+                self.app.app_obj.new_object("geometry", str(obj_name), initialize_geometry)
         except Exception as e:
             log.debug("ToolCalibration.new_calibrated_object() --> %s" % str(e))
             return "Operation failed: %s" % str(e)

+ 1 - 1
AppTools/ToolCopperThieving.py

@@ -1474,7 +1474,7 @@ class ToolCopperThieving(AppTool):
         obj_name, separatpr, obj_extension = self.sm_object.options['name'].rpartition('.')
         name = '%s_%s.%s' % (obj_name, 'plating_mask', obj_extension)
 
-        self.app.new_object('gerber', name, obj_init, autoselected=False)
+        self.app.app_obj.new_object('gerber', name, obj_init, autoselected=False)
 
         # Register recent file
         self.app.file_opened.emit("gerber", name)

+ 3 - 3
AppTools/ToolCutOut.py

@@ -700,7 +700,7 @@ class CutOut(AppTool):
             geo_obj.tools[1]['data']['depthperpass'] = self.maxdepth_entry.get_value()
 
         outname = cutout_obj.options["name"] + "_cutout"
-        self.app.new_object('geometry', outname, geo_init)
+        self.app.app_obj.new_object('geometry', outname, geo_init)
 
         cutout_obj.plot()
         self.app.inform.emit('[success] %s' % _("Any form CutOut operation finished."))
@@ -896,7 +896,7 @@ class CutOut(AppTool):
             geo_obj.tools[1]['data']['depthperpass'] = self.maxdepth_entry.get_value()
 
         outname = cutout_obj.options["name"] + "_cutout"
-        ret = self.app.new_object('geometry', outname, geo_init)
+        ret = self.app.app_obj.new_object('geometry', outname, geo_init)
 
         if ret != 'fail':
             # cutout_obj.plot()
@@ -1056,7 +1056,7 @@ class CutOut(AppTool):
             geo_obj.tools[1]['data']['depthperpass'] = self.maxdepth_entry.get_value()
 
         outname = cutout_obj.options["name"] + "_cutout"
-        self.app.new_object('geometry', outname, geo_init)
+        self.app.app_obj.new_object('geometry', outname, geo_init)
 
     def cutting_geo(self, pos):
         self.cutting_dia = float(self.dia.get_value())

+ 4 - 4
AppTools/ToolDblSided.py

@@ -643,7 +643,7 @@ class DblSidedTool(AppTool):
             obj_inst.source_file = app_inst.export_excellon(obj_name=obj_inst.options['name'], local_use=obj_inst,
                                                             filename=None, use_thread=False)
 
-        self.app.new_object("excellon", "Alignment Drills", obj_init)
+        self.app.app_obj.new_object("excellon", "Alignment Drills", obj_init)
         self.drill_values = ''
         self.app.inform.emit('[success] %s' % _("Excellon object with alignment drills created..."))
 
@@ -686,7 +686,7 @@ class DblSidedTool(AppTool):
             py = 0.5 * (ymin + ymax)
 
         fcobj.mirror(axis, [px, py])
-        self.app.object_changed.emit(fcobj)
+        self.app.app_obj.object_changed.emit(fcobj)
         fcobj.plot()
         self.app.inform.emit('[success] Gerber %s %s...' % (str(fcobj.options['name']), _("was mirrored")))
 
@@ -730,7 +730,7 @@ class DblSidedTool(AppTool):
             py = 0.5 * (ymin + ymax)
 
         fcobj.mirror(axis, [px, py])
-        self.app.object_changed.emit(fcobj)
+        self.app.app_obj.object_changed.emit(fcobj)
         fcobj.plot()
         self.app.inform.emit('[success] Excellon %s %s...' % (str(fcobj.options['name']), _("was mirrored")))
 
@@ -767,7 +767,7 @@ class DblSidedTool(AppTool):
             py = 0.5 * (ymin + ymax)
 
         fcobj.mirror(axis, [px, py])
-        self.app.object_changed.emit(fcobj)
+        self.app.app_obj.object_changed.emit(fcobj)
         fcobj.plot()
         self.app.inform.emit('[success] Geometry %s %s...' % (str(fcobj.options['name']), _("was mirrored")))
 

+ 1 - 1
AppTools/ToolExtractDrills.py

@@ -655,7 +655,7 @@ class ToolExtractDrills(AppTool):
             obj_inst.source_file = self.app.export_excellon(obj_name=outname, local_use=obj_inst, filename=None,
                                                             use_thread=False)
 
-        self.app.new_object("excellon", outname, obj_init)
+        self.app.app_obj.new_object("excellon", outname, obj_init)
 
     def on_hole_size_toggle(self, val):
         if val == "fixed":

+ 2 - 2
AppTools/ToolFilm.py

@@ -775,7 +775,7 @@ class Film(AppTool):
                 new_obj.solid_geometry = deepcopy(punched_solid_geometry)
 
             outname = name + "_punched"
-            self.app.new_object('gerber', outname, init_func)
+            self.app.app_obj.new_object('gerber', outname, init_func)
 
             self.generate_positive_normal_film(outname, boxname, factor=factor, ftype=ftype)
         else:
@@ -826,7 +826,7 @@ class Film(AppTool):
                 new_obj.solid_geometry = deepcopy(punched_solid_geometry)
 
             outname = name + "_punched"
-            self.app.new_object('gerber', outname, init_func)
+            self.app.app_obj.new_object('gerber', outname, init_func)
 
             self.generate_positive_normal_film(outname, boxname, factor=factor, ftype=ftype)
 

+ 1 - 1
AppTools/ToolImage.py

@@ -288,7 +288,7 @@ class ToolImage(AppTool):
             name = outname or filename.split('/')[-1].split('\\')[-1]
             units = self.app.defaults['units']
 
-            self.app.new_object(obj_type, name, obj_init)
+            self.app.app_obj.new_object(obj_type, name, obj_init)
 
             # Register recent file
             self.app.file_opened.emit("image", filename)

+ 1 - 1
AppTools/ToolInvertGerber.py

@@ -293,7 +293,7 @@ class ToolInvertGerber(AppTool):
             new_obj.source_file = self.app.export_gerber(obj_name=outname, filename=None,
                                                          local_use=new_obj, use_thread=False)
 
-        self.app.new_object('gerber', outname, init_func)
+        self.app.app_obj.new_object('gerber', outname, init_func)
 
     def reset_fields(self):
         self.gerber_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))

+ 5 - 5
AppTools/ToolNCC.py

@@ -2881,12 +2881,12 @@ class NonCopperClear(AppTool, Gerber):
         # ###########################################################################################
         # Create the Job function and send it to the worker to be processed in another thread #######
         # ###########################################################################################
-        def job_thread(app_obj):
+        def job_thread(a_obj):
             try:
                 if rest_machining_choice is True:
-                    app_obj.new_object("geometry", name, gen_clear_area_rest)
+                    a_obj.app_obj.new_object("geometry", name, gen_clear_area_rest)
                 else:
-                    app_obj.new_object("geometry", name, gen_clear_area)
+                    a_obj.app_obj.new_object("geometry", name, gen_clear_area)
             except grace:
                 if run_threaded:
                     proc.done()
@@ -3881,9 +3881,9 @@ class NonCopperClear(AppTool, Gerber):
         def job_thread(app_obj):
             try:
                 if rest_machining_choice is True:
-                    app_obj.new_object("geometry", name, gen_clear_area_rest, plot=plot)
+                    app_obj.app_obj.new_object("geometry", name, gen_clear_area_rest, plot=plot)
                 else:
-                    app_obj.new_object("geometry", name, gen_clear_area, plot=plot)
+                    app_obj.app_obj.new_object("geometry", name, gen_clear_area, plot=plot)
             except grace:
                 if run_threaded:
                     proc.done()

+ 2 - 2
AppTools/ToolPDF.py

@@ -205,7 +205,7 @@ class ToolPDF(AppTool):
 
         with self.app.proc_container.new(_("Rendering PDF layer #%d ...") % int(layer_nr)):
 
-            ret_val = self.app.new_object("excellon", outname, obj_init, autoselected=False)
+            ret_val = self.app.app_obj.new_object("excellon", outname, obj_init, autoselected=False)
             if ret_val == 'fail':
                 self.app.inform.emit('[ERROR_NOTCL] %s' % _('Open PDF file failed.'))
                 return
@@ -278,7 +278,7 @@ class ToolPDF(AppTool):
 
         with self.app.proc_container.new(_("Rendering PDF layer #%d ...") % int(layer_nr)):
 
-            ret = self.app.new_object('gerber', outname, obj_init, autoselected=False)
+            ret = self.app.app_obj.new_object('gerber', outname, obj_init, autoselected=False)
             if ret == 'fail':
                 self.app.inform.emit('[ERROR_NOTCL] %s' % _('Open PDF file failed.'))
                 return

+ 5 - 5
AppTools/ToolPaint.py

@@ -2315,7 +2315,7 @@ class ToolPaint(AppTool, Gerber):
 
         def job_thread(app_obj):
             try:
-                ret = app_obj.new_object("geometry", name, job_init, plot=plot)
+                ret = app_obj.app_obj.new_object("geometry", name, job_init, plot=plot)
             except grace:
                 proc.done()
                 return
@@ -2823,9 +2823,9 @@ class ToolPaint(AppTool, Gerber):
         def job_thread(app_obj):
             try:
                 if self.rest_cb.isChecked():
-                    ret = app_obj.new_object("geometry", name, gen_paintarea_rest_machining, plot=plot)
+                    ret = app_obj.app_obj.new_object("geometry", name, gen_paintarea_rest_machining, plot=plot)
                 else:
-                    ret = app_obj.new_object("geometry", name, gen_paintarea, plot=plot)
+                    ret = app_obj.app_obj.new_object("geometry", name, gen_paintarea, plot=plot)
             except grace:
                 proc.done()
                 return
@@ -3320,9 +3320,9 @@ class ToolPaint(AppTool, Gerber):
         def job_thread(app_obj):
             try:
                 if self.rest_cb.isChecked():
-                    ret = app_obj.new_object("geometry", name, gen_paintarea_rest_machining, plot=plot)
+                    ret = app_obj.app_obj.new_object("geometry", name, gen_paintarea_rest_machining, plot=plot)
                 else:
-                    ret = app_obj.new_object("geometry", name, gen_paintarea, plot=plot)
+                    ret = app_obj.app_obj.new_object("geometry", name, gen_paintarea, plot=plot)
             except grace:
                 proc.done()
                 return

+ 2 - 2
AppTools/ToolPanelize.py

@@ -794,9 +794,9 @@ class Panelize(AppTool):
 
                 self.app.inform.emit('%s: %d' % (_("Generating panel... Spawning copies"), (int(rows * columns))))
                 if panel_source_obj.kind == 'excellon':
-                    self.app.new_object("excellon", self.outname, job_init_excellon, plot=True, autoselected=True)
+                    self.app.app_obj.new_object("excellon", self.outname, job_init_excellon, plot=True, autoselected=True)
                 else:
-                    self.app.new_object(panel_type, self.outname, job_init_geometry, plot=True, autoselected=True)
+                    self.app.app_obj.new_object(panel_type, self.outname, job_init_geometry, plot=True, autoselected=True)
 
         if self.constrain_flag is False:
             self.app.inform.emit('[success] %s' % _("Panel done..."))

+ 1 - 1
AppTools/ToolPcbWizard.py

@@ -452,7 +452,7 @@ class PcbWizard(AppTool):
                     # Object name
                     name = self.outname
 
-                    ret_val = self.app.new_object("excellon", name, obj_init, autoselected=False)
+                    ret_val = self.app.app_obj.new_object("excellon", name, obj_init, autoselected=False)
                     if ret_val == 'fail':
                         self.app.inform.emit('[ERROR_NOTCL] %s' % _('Import Excellon file failed.'))
                         return

+ 4 - 4
AppTools/ToolPunchGerber.py

@@ -591,7 +591,7 @@ class ToolPunchGerber(AppTool):
                 new_obj.source_file = self.app.export_gerber(obj_name=outname, filename=None,
                                                              local_use=new_obj, use_thread=False)
 
-            self.app.new_object('gerber', outname, init_func)
+            self.app.app_obj.new_object('gerber', outname, init_func)
         elif punch_method == 'fixed':
             punch_size = float(self.dia_entry.get_value())
 
@@ -705,7 +705,7 @@ class ToolPunchGerber(AppTool):
                 new_obj.source_file = self.app.export_gerber(obj_name=outname, filename=None,
                                                              local_use=new_obj, use_thread=False)
 
-            self.app.new_object('gerber', outname, init_func)
+            self.app.app_obj.new_object('gerber', outname, init_func)
         elif punch_method == 'ring':
             circ_r_val = self.circular_ring_entry.get_value()
             oblong_r_val = self.oblong_ring_entry.get_value()
@@ -847,7 +847,7 @@ class ToolPunchGerber(AppTool):
                 new_obj.source_file = self.app.export_gerber(obj_name=outname, filename=None,
                                                              local_use=new_obj, use_thread=False)
 
-            self.app.new_object('gerber', outname, init_func)
+            self.app.app_obj.new_object('gerber', outname, init_func)
 
         elif punch_method == 'prop':
             prop_factor = self.factor_entry.get_value() / 100.0
@@ -986,7 +986,7 @@ class ToolPunchGerber(AppTool):
                 new_obj.source_file = self.app.export_gerber(obj_name=outname, filename=None,
                                                              local_use=new_obj, use_thread=False)
 
-            self.app.new_object('gerber', outname, init_func)
+            self.app.app_obj.new_object('gerber', outname, init_func)
 
     def reset_fields(self):
         self.gerber_object_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))

+ 1 - 1
AppTools/ToolRulesCheck.py

@@ -1625,7 +1625,7 @@ class RulesCheck(AppTool):
             new_obj.source_file = txt
             new_obj.read_only = True
 
-        self.app.new_object('document', name='Rules Check results', initialize=init, plot=False)
+        self.app.app_obj.new_object('document', name='Rules Check results', initialize=init, plot=False)
 
     def reset_fields(self):
         # self.object_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))

+ 6 - 6
AppTools/ToolSolderPaste.py

@@ -9,7 +9,7 @@ from AppTool import AppTool
 from Common import LoudDict
 from AppGUI.GUIElements import FCComboBox, FCEntry, FCTable, \
     FCInputDialog, FCDoubleSpinner, FCSpinner, FCFileSaveDialog
-from App import log
+from AppMain import log
 from camlib import distance
 from AppEditors.FlatCAMTextEditor import TextEditor
 
@@ -1257,7 +1257,7 @@ class SolderPaste(AppTool):
         if use_thread:
             def job_thread(app_obj):
                 try:
-                    app_obj.new_object("geometry", name + "_solderpaste", geo_init)
+                    app_obj.app_obj.new_object("geometry", name + "_solderpaste", geo_init)
                 except Exception as e:
                     log.error("SolderPaste.on_create_geo() --> %s" % str(e))
                     proc.done()
@@ -1271,7 +1271,7 @@ class SolderPaste(AppTool):
             # Background
             self.app.worker_task.emit({'fcn': job_thread, 'params': [self.app]})
         else:
-            self.app.new_object("geometry", name + "_solderpaste", geo_init)
+            self.app.app_obj.new_object("geometry", name + "_solderpaste", geo_init)
 
     def on_create_gcode_click(self, signal):
         """
@@ -1331,7 +1331,7 @@ class SolderPaste(AppTool):
             self.app.inform.emit(msg)
             return
 
-        # Object initialization function for app.new_object()
+        # Object initialization function for app.app_obj.new_object()
         # RUNNING ON SEPARATE THREAD!
         def job_init(job_obj):
             assert job_obj.kind == 'cncjob', \
@@ -1388,7 +1388,7 @@ class SolderPaste(AppTool):
             # To be run in separate thread
             def job_thread(app_obj):
                 with self.app.proc_container.new("Generating CNC Code"):
-                    if app_obj.new_object("cncjob", name, job_init) != 'fail':
+                    if app_obj.app_obj.new_object("cncjob", name, job_init) != 'fail':
                         app_obj.inform.emit('[success] [success] %s: %s' %
                                             (_("ToolSolderPaste CNCjob created"), name))
             # Create a promise with the name
@@ -1396,7 +1396,7 @@ class SolderPaste(AppTool):
             # Send to worker
             self.app.worker_task.emit({'fcn': job_thread, 'params': [self.app]})
         else:
-            self.app.new_object("cncjob", name, job_init)
+            self.app.app_obj.new_object("cncjob", name, job_init)
 
     def on_view_gcode(self):
         """

+ 2 - 2
AppTools/ToolSub.py

@@ -456,7 +456,7 @@ class ToolSub(AppTool):
             grb_obj.follow_geometry = deepcopy(follow_buff)
 
         with self.app.proc_container.new(_("Generating new object ...")):
-            ret = self.app.new_object('gerber', outname, obj_init, autoselected=False)
+            ret = self.app.app_obj.new_object('gerber', outname, obj_init, autoselected=False)
             if ret == 'fail':
                 self.app.inform.emit('[ERROR_NOTCL] %s' %
                                      _('Generating new object failed.'))
@@ -659,7 +659,7 @@ class ToolSub(AppTool):
                 geo_obj.multigeo = False
 
         with self.app.proc_container.new(_("Generating new object ...")):
-            ret = self.app.new_object('geometry', outname, obj_init, autoselected=False)
+            ret = self.app.app_obj.new_object('geometry', outname, obj_init, autoselected=False)
             if ret == 'fail':
                 self.app.inform.emit('[ERROR_NOTCL] %s' %
                                      _('Generating new object failed.'))

+ 6 - 6
AppTools/ToolTransform.py

@@ -702,7 +702,7 @@ class ToolTransform(AppTool):
                             self.app.inform.emit(_("CNCJob objects can't be rotated."))
                         else:
                             sel_obj.rotate(-num, point=(px, py))
-                            self.app.object_changed.emit(sel_obj)
+                            self.app.app_obj.object_changed.emit(sel_obj)
 
                         # add information to the object that it was changed and how much
                         sel_obj.options['rotate'] = num
@@ -776,7 +776,7 @@ class ToolTransform(AppTool):
                                 else:
                                     sel_obj.options['mirror_x'] = True
                                 self.app.inform.emit('[success] %s...' % _('Flip on the X axis done'))
-                            self.app.object_changed.emit(sel_obj)
+                            self.app.app_obj.object_changed.emit(sel_obj)
                         sel_obj.plot()
                 except Exception as e:
                     self.app.inform.emit('[ERROR_NOTCL] %s %s, %s.' %
@@ -825,7 +825,7 @@ class ToolTransform(AppTool):
                                 sel_obj.skew(0, num, point=(xminimal, yminimal))
                                 # add information to the object that it was changed and how much
                                 sel_obj.options['skew_y'] = num
-                            self.app.object_changed.emit(sel_obj)
+                            self.app.app_obj.object_changed.emit(sel_obj)
                         sel_obj.plot()
                     self.app.inform.emit('[success] %s %s %s...' % (_('Skew on the'),  str(axis), _("axis done")))
                 except Exception as e:
@@ -878,7 +878,7 @@ class ToolTransform(AppTool):
                             # add information to the object that it was changed and how much
                             sel_obj.options['scale_x'] = xfactor
                             sel_obj.options['scale_y'] = yfactor
-                            self.app.object_changed.emit(sel_obj)
+                            self.app.app_obj.object_changed.emit(sel_obj)
                         sel_obj.plot()
 
                     self.app.inform.emit('[success] %s %s %s...' % (_('Scale on the'), str(axis), _('axis done')))
@@ -908,7 +908,7 @@ class ToolTransform(AppTool):
                                 sel_obj.offset((0, num))
                                 # add information to the object that it was changed and how much
                                 sel_obj.options['offset_y'] = num
-                            self.app.object_changed.emit(sel_obj)
+                            self.app.app_obj.object_changed.emit(sel_obj)
                         sel_obj.plot()
 
                     self.app.inform.emit('[success] %s %s %s...' % (_('Offset on the'), str(axis), _('axis done')))
@@ -942,7 +942,7 @@ class ToolTransform(AppTool):
                         elif sel_obj.kind.lower() == 'geometry':
                             sel_obj.buffer(value, join, factor)
 
-                        self.app.object_changed.emit(sel_obj)
+                        self.app.app_obj.object_changed.emit(sel_obj)
                         sel_obj.plot()
 
                     self.app.inform.emit('[success] %s...' % _('Buffer done'))

+ 2 - 1
CHANGELOG.md

@@ -20,6 +20,7 @@ CHANGELOG for FlatCAM beta
 - removed reference to postprocessors and replaced it with preprocessors
 - more refactoring class names
 - moved some of the methods from the App class to the ObjectCollection class
+- moved all the new_object related methods in their own class AppObjects.AppObject
 
 17.05.2020
 
@@ -4239,7 +4240,7 @@ still copper leftovers.
 - modified generate_milling method which had issues from the Python3 port (it could not sort the tools due of dict to dict comparison no longer possible).
 - modified the 'default' preprocessor in order to include a space between the value of Xcoord and the following Y
 - made optional the using of threads for the milling command; by default it is OFF (False) because in the current configuration it creates issues when it is using threads
-- modified the Panelize function and Tcl command Panelize. It was having issues due to multithreading (kept trying to modify a dictionary in redraw() method)and automatically selecting the last created object (feature introduced by me). I've added a parameter to the new_object method, named autoselected (by default it is True) and in the panelize method I initialized it with False.
+- modified the Panelize function and Tcl command Panelize. It was having issues due to multithreading (kept trying to modify a dictionary in redraw() method)and automatically selecting the last created object (feature introduced by me). I've added a parameter to the app_obj.new_object method, named autoselected (by default it is True) and in the panelize method I initialized it with False.
 By initializing the plot parameter with False for the temporary objects, I have increased dramatically the  generation speed of the panel because now the temporary object are no longer ploted which consumed time.
 - replaced log.warn() with log.warning() in camlib.py. Reason: deprecated
 - fixed the issue that the "Defaults" button was having no effect when clicked and Options Combo was in Project Options

+ 1 - 1
FlatCAM.py

@@ -3,7 +3,7 @@ import os
 
 from PyQt5 import QtWidgets
 from PyQt5.QtCore import QSettings, Qt
-from App import App
+from AppMain import App
 from AppGUI import VisPyPatches
 
 from multiprocessing import freeze_support

+ 2 - 2
tclCommands/TclCommand.py

@@ -1,6 +1,6 @@
 import sys
 import re
-import App
+import AppMain
 import abc
 import collections
 from PyQt5 import QtCore
@@ -53,7 +53,7 @@ class TclCommand(object):
         if self.app is None:
             raise TypeError('Expected app to be FlatCAMApp instance.')
 
-        if not isinstance(self.app, App.App):
+        if not isinstance(self.app, AppMain.App):
             raise TypeError('Expected FlatCAMApp, got %s.' % type(app))
 
         self.log = self.app.log

+ 2 - 2
tclCommands/TclCommandAlignDrill.py

@@ -189,7 +189,7 @@ class TclCommandAlignDrill(TclCommandSignaled):
                 px = 0.5 * (xmin + xmax)
                 py = 0.5 * (ymin + ymax)
 
-                obj.app.new_object("excellon", outname, alligndrill_init_me, plot=False)
+                obj.app.app_obj.new_object("excellon", outname, alligndrill_init_me, plot=False)
 
             except Exception as e:
                 return "Operation failed: %s" % str(e)
@@ -205,7 +205,7 @@ class TclCommandAlignDrill(TclCommandSignaled):
             try:
                 px = dist
                 py = dist
-                obj.app.new_object("excellon", outname, alligndrill_init_me, plot=False)
+                obj.app.app_obj.new_object("excellon", outname, alligndrill_init_me, plot=False)
             except Exception as e:
                 return "Operation failed: %s" % str(e)
 

+ 1 - 1
tclCommands/TclCommandAlignDrillGrid.py

@@ -111,4 +111,4 @@ class TclCommandAlignDrillGrid(TclCommandSignaled):
             init_obj.create_geometry()
 
         # Create the new object
-        self.app.new_object("excellon", outname, aligndrillgrid_init_me, plot=False)
+        self.app.app_obj.new_object("excellon", outname, aligndrillgrid_init_me, plot=False)

+ 1 - 1
tclCommands/TclCommandBbox.py

@@ -100,6 +100,6 @@ class TclCommandBbox(TclCommand):
                     bounding_box = bounding_box.envelope
                 geo_obj.solid_geometry = bounding_box
 
-            self.app.new_object("geometry", args['outname'], geo_init, plot=False)
+            self.app.app_obj.new_object("geometry", args['outname'], geo_init, plot=False)
         except Exception as e:
             return "Operation failed: %s" % str(e)

+ 1 - 1
tclCommands/TclCommandCutout.py

@@ -137,7 +137,7 @@ class TclCommandCutout(TclCommand):
             geo_obj.solid_geometry = cascaded_union([LineString(segment) for segment in cuts])
 
         try:
-            self.app.new_object("geometry", outname, geo_init_me, plot=False)
+            self.app.app_obj.new_object("geometry", outname, geo_init_me, plot=False)
             self.app.inform.emit("[success] Rectangular-form Cutout operation finished.")
         except Exception as e:
             return "Operation failed: %s" % str(e)

+ 1 - 1
tclCommands/TclCommandDrillcncjob.py

@@ -343,4 +343,4 @@ class TclCommandDrillcncjob(TclCommandSignaled):
             job_obj.gcode_parse()
             job_obj.create_geometry()
 
-        self.app.new_object("cncjob", args['outname'], job_init, plot=False)
+        self.app.app_obj.new_object("cncjob", args['outname'], job_init, plot=False)

+ 1 - 1
tclCommands/TclCommandExteriors.py

@@ -66,4 +66,4 @@ class TclCommandExteriors(TclCommandSignaled):
             geo_obj.solid_geometry = obj_exteriors
 
         obj_exteriors = obj.get_exteriors()
-        self.app.new_object('geometry', outname, geo_init, plot=False)
+        self.app.app_obj.new_object('geometry', outname, geo_init, plot=False)

+ 2 - 5
tclCommands/TclCommandGeoCutout.py

@@ -300,11 +300,8 @@ class TclCommandGeoCutout(TclCommandSignaled):
 
                 app_obj.inform.emit("[success] %s" % _("Any-form Cutout operation finished."))
 
-            self.app.new_object('geometry', outname, geo_init, plot=False)
+            self.app.app_obj.new_object('geometry', outname, geo_init, plot=False)
 
-            # cutout_obj.plot()
-            # self.app.inform.emit("[success] Any-form Cutout operation finished.")
-            # self.app.plots_updated.emit()
         elif cutout_obj.kind == 'gerber':
 
             def geo_init(geo_obj, app_obj):
@@ -358,7 +355,7 @@ class TclCommandGeoCutout(TclCommandSignaled):
                 geo_obj.options['ymax'] = cutout_obj.options['ymax']
                 app_obj.inform.emit("[success] %s" % _("Any-form Cutout operation finished."))
 
-            self.app.new_object('geometry', outname, geo_init, plot=False)
+            self.app.app_obj.new_object('geometry', outname, geo_init, plot=False)
 
             cutout_obj = self.app.collection.get_by_name(outname)
         else:

+ 1 - 1
tclCommands/TclCommandImportSvg.py

@@ -76,7 +76,7 @@ class TclCommandImportSvg(TclCommandSignaled):
         with self.app.proc_container.new("Import SVG"):
 
             # Object creation
-            self.app.new_object(obj_type, outname, obj_init, plot=False)
+            self.app.app_obj.new_object(obj_type, outname, obj_init, plot=False)
 
             # Register recent file
             self.app.file_opened.emit("svg", filename)

+ 1 - 1
tclCommands/TclCommandInteriors.py

@@ -67,4 +67,4 @@ class TclCommandInteriors(TclCommandSignaled):
             geo_obj.solid_geometry = obj_interiors
 
         obj_interiors = obj.get_interiors()
-        self.app.new_object('geometry', outname, geo_init)
+        self.app.app_obj.new_object('geometry', outname, geo_init)

+ 1 - 1
tclCommands/TclCommandJoinExcellon.py

@@ -65,6 +65,6 @@ class TclCommandJoinExcellon(TclCommand):
             ExcellonObject.merge(objs, obj_, decimals=self.app.decimals)
 
         if objs and len(objs) >= 2:
-            self.app.new_object("excellon", outname, initialize, plot=False)
+            self.app.app_obj.new_object("excellon", outname, initialize, plot=False)
         else:
             return "No Excellon objects to be joined or less than two Excellon objects specified for merging."

+ 1 - 1
tclCommands/TclCommandJoinGeometry.py

@@ -65,6 +65,6 @@ class TclCommandJoinGeometry(TclCommand):
             GeometryObject.merge(objs, obj_)
 
         if objs and len(objs) >= 2:
-            self.app.new_object("geometry", outname, initialize, plot=False)
+            self.app.app_obj.new_object("geometry", outname, initialize, plot=False)
         else:
             return "No Geometry objects to be joined or less than two Geometry objects specified for merging."

+ 1 - 1
tclCommands/TclCommandNewExcellon.py

@@ -58,4 +58,4 @@ class TclCommandNewExcellon(TclCommandSignaled):
             name = args['name']
         else:
             name = 'new_exc'
-        self.app.new_object('excellon', name, lambda x, y: None, plot=False)
+        self.app.app_obj.new_object('excellon', name, lambda x, y: None, plot=False)

+ 1 - 1
tclCommands/TclCommandNewGeometry.py

@@ -52,4 +52,4 @@ class TclCommandNewGeometry(TclCommandSignaled):
         else:
             name = 'new_geo'
 
-        self.app.new_object('geometry', str(name), lambda x, y: None, plot=False)
+        self.app.app_obj.new_object('geometry', str(name), lambda x, y: None, plot=False)

+ 1 - 1
tclCommands/TclCommandNewGerber.py

@@ -75,4 +75,4 @@ class TclCommandNewGerber(TclCommandSignaled):
             except KeyError:
                 pass
 
-        self.app.new_object('gerber', name, initialize, plot=False)
+        self.app.app_obj.new_object('gerber', name, initialize, plot=False)

+ 1 - 1
tclCommands/TclCommandNregions.py

@@ -100,7 +100,7 @@ class TclCommandNregions(TclCommand):
                 non_copper = bounding_box.difference(geo)
                 geo_obj.solid_geometry = non_copper
 
-            self.app.new_object("geometry", args['outname'], geo_init, plot=False)
+            self.app.app_obj.new_object("geometry", args['outname'], geo_init, plot=False)
         except Exception as e:
             return "Operation failed: %s" % str(e)
 

+ 2 - 2
tclCommands/TclCommandOpenDXF.py

@@ -77,10 +77,10 @@ class TclCommandOpenDXF(TclCommandSignaled):
         with self.app.proc_container.new("Open DXF"):
 
             # Object creation
-            ret_val = self.app.new_object(obj_type, outname, obj_init, plot=False)
+            ret_val = self.app.app_obj.new_object(obj_type, outname, obj_init, plot=False)
             if ret_val == 'fail':
                 filename = self.app.defaults['global_tcl_path'] + '/' + outname
-                ret_val = self.app.new_object(obj_type, outname, obj_init, plot=False)
+                ret_val = self.app.app_obj.new_object(obj_type, outname, obj_init, plot=False)
                 self.app.shell.append_output(
                     "No path provided or path is wrong. Using the default Path... \n")
 

+ 2 - 2
tclCommands/TclCommandOpenSVG.py

@@ -77,10 +77,10 @@ class TclCommandOpenSVG(TclCommandSignaled):
         with self.app.proc_container.new("Import SVG"):
 
             # Object creation
-            ret_val = self.app.new_object(obj_type, outname, obj_init, plot=False)
+            ret_val = self.app.app_obj.new_object(obj_type, outname, obj_init, plot=False)
             if ret_val == 'fail':
                 filename = self.app.defaults['global_tcl_path'] + '/' + outname
-                ret_val = self.app.new_object(obj_type, outname, obj_init, plot=False)
+                ret_val = self.app.app_obj.new_object(obj_type, outname, obj_init, plot=False)
                 self.app.shell.append_output(
                     "No path provided or path is wrong. Using the default Path... \n")
                 if ret_val == 'fail':

+ 6 - 6
tclCommands/TclCommandPanelize.py

@@ -167,19 +167,19 @@ class TclCommandPanelize(TclCommand):
         #             for col in range(columns):
         #                 local_outname = outname + ".tmp." + str(col) + "." + str(row)
         #                 if isinstance(obj, ExcellonObject):
-        #                     self.app.new_object("excellon", local_outname, initialize_local_excellon, plot=False,
+        #                     self.app.app_obj.new_object("excellon", local_outname, initialize_local_excellon, plot=False,
         #                                         autoselected=False)
         #                 else:
-        #                     self.app.new_object("geometry", local_outname, initialize_local, plot=False,
+        #                     self.app.app_obj.new_object("geometry", local_outname, initialize_local, plot=False,
         #                                         autoselected=False)
         #
         #                 currentx += lenghtx
         #             currenty += lenghty
         #
         #         if isinstance(obj, ExcellonObject):
-        #             self.app.new_object("excellon", outname, initialize_excellon)
+        #             self.app.app_obj.new_object("excellon", outname, initialize_excellon)
         #         else:
-        #             self.app.new_object("geometry", outname, initialize_geometry)
+        #             self.app.app_obj.new_object("geometry", outname, initialize_geometry)
         #
         #         # deselect all  to avoid  delete selected object when run  delete  from  shell
         #         self.app.collection.set_all_inactive()
@@ -287,9 +287,9 @@ class TclCommandPanelize(TclCommand):
                         currenty += lenghty
 
                 if obj.kind == 'excellon':
-                    self.app.new_object("excellon", outname, job_init_excellon, plot=False, autoselected=True)
+                    self.app.app_obj.new_object("excellon", outname, job_init_excellon, plot=False, autoselected=True)
                 else:
-                    self.app.new_object("geometry", outname, job_init_geometry, plot=False, autoselected=True)
+                    self.app.app_obj.new_object("geometry", outname, job_init_geometry, plot=False, autoselected=True)
 
         if threaded is True:
             proc = self.app.proc_container.new("Generating panel ... Please wait.")

+ 3 - 3
tclCommands/TclCommandWriteGCode.py

@@ -80,15 +80,15 @@ class TclCommandWriteGCode(TclCommandSignaled):
         # This is not needed any more? All targets should be present.
         # If there are promised objects, wait until all promises have been fulfilled.
         # if self.collection.has_promises():
-        #     def write_gcode_on_object(new_object):
+        #     def write_gcode_on_object(app_obj.new_object):
         #         self.log.debug("write_gcode_on_object(): Disconnecting %s" % write_gcode_on_object)
-        #         self.new_object_available.disconnect(write_gcode_on_object)
+        #         self.app_obj.new_object_available.disconnect(write_gcode_on_object)
         #         write_gcode(obj_name, filename, preamble, postamble)
         #
         #     # Try again when a new object becomes available.
         #     self.log.debug("write_gcode(): Collection has promises. Queued for %s." % obj_name)
         #     self.log.debug("write_gcode(): Queued function: %s" % write_gcode_on_object)
-        #     self.new_object_available.connect(write_gcode_on_object)
+        #     self.app_obj.new_object_available.connect(write_gcode_on_object)
         #
         #     return