Просмотр исходного кода

- fixed issues in the Tools Database due of recent changes in how the data structure is created
- made sure that the right tools go only to the intended use, in Tools Database otherwise an error status message is created and Tools DB is closed on adding a wrong tool
- fixed the usage for Tools Database in Unix-like OS's
- done some modest refactoring
- fixed the Search and Add feature in Geometry Object UI

Marius Stanciu 5 лет назад
Родитель
Сommit
38abfa4f31

+ 5 - 0
CHANGELOG.md

@@ -18,6 +18,11 @@ CHANGELOG for FlatCAM beta
 - fixed the sizePolicy for the FCComboBox widgets in the Preferences that holds the preprocessors
 - fixed the sizePolicy for the FCComboBox widgets in the Preferences that holds the preprocessors
 - fixed issue with how the preamble / postamble GCode were inserted into the final GCode
 - fixed issue with how the preamble / postamble GCode were inserted into the final GCode
 - fixed a small issue in GCode Editor where the signals for the buttons were attached again at each launch of the GCode Editor
 - fixed a small issue in GCode Editor where the signals for the buttons were attached again at each launch of the GCode Editor
+- fixed issues in the Tools Database due of recent changes in how the data structure is created
+- made sure that the right tools go only to the intended use, in Tools Database otherwise an error status message is created and Tools DB is closed on adding a wrong tool
+- fixed the usage for Tools Database in Unix-like OS's
+- done some modest refactoring
+- fixed the Search and Add feature in Geometry Object UI
 
 
 28.10.2020
 28.10.2020
 
 

+ 26 - 24
appDatabase.py

@@ -1,6 +1,6 @@
 from PyQt5 import QtGui, QtCore, QtWidgets
 from PyQt5 import QtGui, QtCore, QtWidgets
 from appGUI.GUIElements import FCEntry, FCButton, FCDoubleSpinner, FCComboBox, FCCheckBox, FCSpinner, \
 from appGUI.GUIElements import FCEntry, FCButton, FCDoubleSpinner, FCComboBox, FCCheckBox, FCSpinner, \
-    FCTree, RadioSet, FCFileSaveDialog, FCLabel
+    FCTree, RadioSet, FCFileSaveDialog, FCLabel, FCComboBox2
 from camlib import to_dict
 from camlib import to_dict
 
 
 import sys
 import sys
@@ -25,6 +25,10 @@ class ToolsDB2UI:
         self.app = app
         self.app = app
         self.decimals = self.app.decimals
         self.decimals = self.app.decimals
 
 
+        self.offset_item_options = ["Path", "In", "Out", "Custom"]
+        self.type_item_options = [_("Iso"), _("Rough"), _("Finish")]
+        self.tool_type_item_options = ["C1", "C2", "C3", "C4", "B", "V"]
+
         settings = QtCore.QSettings("Open Source", "FlatCAM")
         settings = QtCore.QSettings("Open Source", "FlatCAM")
         if settings.contains("machinist"):
         if settings.contains("machinist"):
             self.machinist_setting = settings.value('machinist', type=int)
             self.machinist_setting = settings.value('machinist', type=int)
@@ -269,7 +273,7 @@ class ToolsDB2UI:
         self.tool_op_label.setToolTip(
         self.tool_op_label.setToolTip(
             _("The kind of Application Tool where this tool is to be used."))
             _("The kind of Application Tool where this tool is to be used."))
 
 
-        self.tool_op_combo = FCComboBox()
+        self.tool_op_combo = FCComboBox2()
         self.tool_op_combo.addItems(
         self.tool_op_combo.addItems(
             [_("General"), _("Milling"), _("Drilling"), _('Isolation'), _('Paint'), _('NCC'), _('Cutout')])
             [_("General"), _("Milling"), _("Drilling"), _('Isolation'), _('Paint'), _('NCC'), _('Cutout')])
         self.tool_op_combo.setObjectName('gdb_tool_target')
         self.tool_op_combo.setObjectName('gdb_tool_target')
@@ -296,7 +300,7 @@ class ToolsDB2UI:
               "V = v-shape milling tool"))
               "V = v-shape milling tool"))
 
 
         self.mill_shape_combo = FCComboBox()
         self.mill_shape_combo = FCComboBox()
-        self.mill_shape_combo.addItems(["C1", "C2", "C3", "C4", "B", "V"])
+        self.mill_shape_combo.addItems(self.tool_type_item_options)
         self.mill_shape_combo.setObjectName('gdb_shape')
         self.mill_shape_combo.setObjectName('gdb_shape')
 
 
         self.grid0.addWidget(self.shape_label, 2, 0)
         self.grid0.addWidget(self.shape_label, 2, 0)
@@ -345,7 +349,7 @@ class ToolsDB2UI:
               "Finish = finishing cut, high feedrate"))
               "Finish = finishing cut, high feedrate"))
 
 
         self.mill_type_combo = FCComboBox()
         self.mill_type_combo = FCComboBox()
-        self.mill_type_combo.addItems(["Iso", "Rough", "Finish"])
+        self.mill_type_combo.addItems(self.type_item_options)
         self.mill_type_combo.setObjectName('gdb_type')
         self.mill_type_combo.setObjectName('gdb_type')
 
 
         self.grid0.addWidget(self.type_label, 10, 0)
         self.grid0.addWidget(self.type_label, 10, 0)
@@ -362,7 +366,7 @@ class ToolsDB2UI:
               "Custom = custom offset using the Custom Offset value"))
               "Custom = custom offset using the Custom Offset value"))
 
 
         self.mill_tooloffset_combo = FCComboBox()
         self.mill_tooloffset_combo = FCComboBox()
-        self.mill_tooloffset_combo.addItems(["Path", "In", "Out", "Custom"])
+        self.mill_tooloffset_combo.addItems(self.offset_item_options)
         self.mill_tooloffset_combo.setObjectName('gdb_tool_offset')
         self.mill_tooloffset_combo.setObjectName('gdb_tool_offset')
 
 
         self.grid0.addWidget(self.tooloffset_label, 12, 0)
         self.grid0.addWidget(self.tooloffset_label, 12, 0)
@@ -663,7 +667,7 @@ class ToolsDB2UI:
               "- Line-based: Parallel lines.")
               "- Line-based: Parallel lines.")
         )
         )
 
 
-        self.ncc_method_combo = FCComboBox()
+        self.ncc_method_combo = FCComboBox2()
         self.ncc_method_combo.addItems(
         self.ncc_method_combo.addItems(
             [_("Standard"), _("Seed"), _("Lines"), _("Combo")]
             [_("Standard"), _("Seed"), _("Lines"), _("Combo")]
         )
         )
@@ -778,7 +782,7 @@ class ToolsDB2UI:
               "in the order specified.")
               "in the order specified.")
         )
         )
 
 
-        self.paint_method_combo = FCComboBox()
+        self.paint_method_combo = FCComboBox2()
         self.paint_method_combo.addItems(
         self.paint_method_combo.addItems(
             [_("Standard"), _("Seed"), _("Lines"), _("Laser_lines"), _("Combo")]
             [_("Standard"), _("Seed"), _("Lines"), _("Laser_lines"), _("Combo")]
         )
         )
@@ -876,8 +880,8 @@ class ToolsDB2UI:
 
 
         self.iso_follow_cb = FCCheckBox()
         self.iso_follow_cb = FCCheckBox()
         self.iso_follow_cb.setToolTip(_("Generate a 'Follow' geometry.\n"
         self.iso_follow_cb.setToolTip(_("Generate a 'Follow' geometry.\n"
-                                    "This means that it will cut through\n"
-                                    "the middle of the trace."))
+                                        "This means that it will cut through\n"
+                                        "the middle of the trace."))
         self.iso_follow_cb.setObjectName("gdb_i_follow")
         self.iso_follow_cb.setObjectName("gdb_i_follow")
 
 
         self.grid4.addWidget(self.follow_label, 6, 0)
         self.grid4.addWidget(self.follow_label, 6, 0)
@@ -1402,9 +1406,7 @@ class ToolsDB2(QtWidgets.QWidget):
 
 
         self.on_tool_request = callback_on_tool_request
         self.on_tool_request = callback_on_tool_request
 
 
-        self.offset_item_options = ["Path", "In", "Out", "Custom"]
-        self.type_item_options = ["Iso", "Rough", "Finish"]
-        self.tool_type_item_options = ["C1", "C2", "C3", "C4", "B", "V"]
+        self.tools_db_changed_flag = False
 
 
         '''
         '''
         dict to hold all the tools in the Tools DB
         dict to hold all the tools in the Tools DB
@@ -1717,7 +1719,7 @@ class ToolsDB2(QtWidgets.QWidget):
         self.ui_connect()
         self.ui_connect()
 
 
     def setup_db_ui(self):
     def setup_db_ui(self):
-        filename = self.app.data_path + '\\tools_db.FlatDB'
+        filename = self.app.tools_database_path()
 
 
         # load the database tools from the file
         # load the database tools from the file
         try:
         try:
@@ -1809,7 +1811,7 @@ class ToolsDB2(QtWidgets.QWidget):
 
 
         self.ui.tool_description_box.setEnabled(True)
         self.ui.tool_description_box.setEnabled(True)
         if self.db_tool_dict:
         if self.db_tool_dict:
-            if tool_target == _("General"):
+            if tool_target == 0:    # _("General")
                 self.ui.milling_box.setEnabled(True)
                 self.ui.milling_box.setEnabled(True)
                 self.ui.ncc_box.setEnabled(True)
                 self.ui.ncc_box.setEnabled(True)
                 self.ui.paint_box.setEnabled(True)
                 self.ui.paint_box.setEnabled(True)
@@ -1831,33 +1833,33 @@ class ToolsDB2(QtWidgets.QWidget):
                 self.ui.drill_box.hide()
                 self.ui.drill_box.hide()
                 self.ui.cutout_box.hide()
                 self.ui.cutout_box.hide()
 
 
-                if tool_target == _("Milling"):
+                if tool_target == 1:    # _("Milling")
                     self.ui.milling_box.setEnabled(True)
                     self.ui.milling_box.setEnabled(True)
                     self.ui.milling_box.show()
                     self.ui.milling_box.show()
 
 
-                if tool_target == _("Drilling"):
+                if tool_target == 2:    # _("Drilling")
                     self.ui.drill_box.setEnabled(True)
                     self.ui.drill_box.setEnabled(True)
                     self.ui.drill_box.show()
                     self.ui.drill_box.show()
 
 
-                if tool_target == _("Isolation"):
+                if tool_target == 3:    # _("Isolation")
                     self.ui.iso_box.setEnabled(True)
                     self.ui.iso_box.setEnabled(True)
                     self.ui.iso_box.show()
                     self.ui.iso_box.show()
                     self.ui.milling_box.setEnabled(True)
                     self.ui.milling_box.setEnabled(True)
                     self.ui.milling_box.show()
                     self.ui.milling_box.show()
 
 
-                if tool_target == _("Paint"):
+                if tool_target == 4:    # _("Paint")
                     self.ui.paint_box.setEnabled(True)
                     self.ui.paint_box.setEnabled(True)
                     self.ui.paint_box.show()
                     self.ui.paint_box.show()
                     self.ui.milling_box.setEnabled(True)
                     self.ui.milling_box.setEnabled(True)
                     self.ui.milling_box.show()
                     self.ui.milling_box.show()
 
 
-                if tool_target == _("NCC"):
+                if tool_target == 5:    # _("NCC")
                     self.ui.ncc_box.setEnabled(True)
                     self.ui.ncc_box.setEnabled(True)
                     self.ui.ncc_box.show()
                     self.ui.ncc_box.show()
                     self.ui.milling_box.setEnabled(True)
                     self.ui.milling_box.setEnabled(True)
                     self.ui.milling_box.show()
                     self.ui.milling_box.show()
 
 
-                if tool_target == _("Cutout"):
+                if tool_target == 6:    # _("Cutout")
                     self.ui.cutout_box.setEnabled(True)
                     self.ui.cutout_box.setEnabled(True)
                     self.ui.cutout_box.show()
                     self.ui.cutout_box.show()
                     self.ui.milling_box.setEnabled(True)
                     self.ui.milling_box.setEnabled(True)
@@ -1872,7 +1874,7 @@ class ToolsDB2(QtWidgets.QWidget):
         default_data = {}
         default_data = {}
         default_data.update({
         default_data.update({
             "plot":             True,
             "plot":             True,
-            "tool_target": _("General"),
+            "tool_target": 0,   # _("General")
             "tol_min": 0.0,
             "tol_min": 0.0,
             "tol_max": 0.0,
             "tol_max": 0.0,
 
 
@@ -2148,7 +2150,7 @@ class ToolsDB2(QtWidgets.QWidget):
     def on_save_tools_db(self, silent=False):
     def on_save_tools_db(self, silent=False):
         self.app.log.debug("ToolsDB.on_save_button() --> Saving Tools Database to file.")
         self.app.log.debug("ToolsDB.on_save_button() --> Saving Tools Database to file.")
 
 
-        filename = self.app.data_path + "/tools_db.FlatDB"
+        filename = self.app.tools_database_path()
 
 
         # Preferences save, update the color of the Tools DB Tab text
         # Preferences save, update the color of the Tools DB Tab text
         for idx in range(self.app_ui.plot_tab_area.count()):
         for idx in range(self.app_ui.plot_tab_area.count()):
@@ -2884,7 +2886,7 @@ class ToolsDB2(QtWidgets.QWidget):
 #               "A position on Z plane to move immediately after job stop."))
 #               "A position on Z plane to move immediately after job stop."))
 #
 #
 #     def setup_db_ui(self):
 #     def setup_db_ui(self):
-#         filename = self.app.data_path + '/tools_db.FlatDB'
+#         filename = self.app.tools_database_path()
 #
 #
 #         # load the database tools from the file
 #         # load the database tools from the file
 #         try:
 #         try:
@@ -3321,7 +3323,7 @@ class ToolsDB2(QtWidgets.QWidget):
 #     def on_save_tools_db(self, silent=False):
 #     def on_save_tools_db(self, silent=False):
 #         self.app.log.debug("ToolsDB.on_save_button() --> Saving Tools Database to file.")
 #         self.app.log.debug("ToolsDB.on_save_button() --> Saving Tools Database to file.")
 #
 #
-#         filename = self.app.data_path + "/tools_db.FlatDB"
+#         filename = self.app.tools_database_path()
 #
 #
 #         # Preferences save, update the color of the Tools DB Tab text
 #         # Preferences save, update the color of the Tools DB Tab text
 #         for idx in range(self.app_ui.plot_tab_area.count()):
 #         for idx in range(self.app_ui.plot_tab_area.count()):

+ 38 - 26
appGUI/MainGUI.py

@@ -1885,6 +1885,17 @@ class MainGUI(QtWidgets.QMainWindow):
         self.infobar.setContextMenuPolicy(QtCore.Qt.ActionsContextMenu)
         self.infobar.setContextMenuPolicy(QtCore.Qt.ActionsContextMenu)
         self.build_infobar_context_menu()
         self.build_infobar_context_menu()
 
 
+    def set_ui_title(self, name):
+        """
+        Sets the title of the main window.
+
+        :param name: String that store the project path and project name
+        :return: None
+        """
+        title = 'FlatCAM %s %s - %s - [%s]    %s' % (
+            self.app.version, ('BETA' if self.app.beta else ''), platform.architecture()[0], self.app.engine, name)
+        self.setWindowTitle(title)
+
     def save_geometry(self, x, y, width, height, notebook_width):
     def save_geometry(self, x, y, width, height, notebook_width):
         """
         """
         Will save the application geometry and positions in the defaults dicitionary to be restored at the next
         Will save the application geometry and positions in the defaults dicitionary to be restored at the next
@@ -2089,6 +2100,7 @@ class MainGUI(QtWidgets.QMainWindow):
         resource_loc = self.app.resource_location
         resource_loc = self.app.resource_location
 
 
         response = None
         response = None
+        bt_yes = None
         if forced_clear is False:
         if forced_clear is False:
             msgbox = QtWidgets.QMessageBox()
             msgbox = QtWidgets.QMessageBox()
             msgbox.setText(_("Are you sure you want to delete the GUI Settings? \n"))
             msgbox.setText(_("Are you sure you want to delete the GUI Settings? \n"))
@@ -4449,32 +4461,32 @@ class ShortcutsTab(QtWidgets.QWidget):
 
 
                     # ALT section
                     # ALT section
                     _('Alt+A'), _("Align Objects Tool"),
                     _('Alt+A'), _("Align Objects Tool"),
-                    _('Alt+C'),_("Calculators Tool"),
-                    _('Alt+D'),_("2-Sided PCB Tool"),
-                    _('Alt+E'),_("Extract Drills Tool"),
-                    _('Alt+F'),_("Fiducials Tool"),
-                    _('Alt+G'),_("Invert Gerber Tool"),
-                    _('Alt+H'),_("Punch Gerber Tool"),
-                    _('Alt+I'),_("Isolation Tool"),
-                    _('Alt+J'),_("Copper Thieving Tool"),
-                    _('Alt+K'),_("Solder Paste Dispensing Tool"),
-                    _('Alt+L'),_("Film PCB Tool"),
-                    _('Alt+M'),_("Corner Markers Tool"),
-                    _('Alt+N'),_("Non-Copper Clearing Tool"),
-                    _('Alt+O'),_("Optimal Tool"),
-                    _('Alt+P'),_("Paint Area Tool"),
-                    _('Alt+Q'),_("QRCode Tool"),
-                    _('Alt+R'),_("Rules Check Tool"),
-                    _('Alt+S'),_("View File Source"),
-                    _('Alt+T'),_("Transformations Tool"),
-                    _('Alt+W'),_("Subtract Tool"),
-                    _('Alt+X'),_("Cutout PCB Tool"),
-                    _('Alt+Z'),_("Panelize PCB"),
-                    _('Alt+1'),_("Enable all"),
-                    _('Alt+2'),_("Disable all"),
-                    _('Alt+3'),_("Enable Non-selected Objects"),
-                    _('Alt+4'),_("Disable Non-selected Objects"),
-                    _('Alt+F10'),_("Toggle Full Screen"),
+                    _('Alt+C'), _("Calculators Tool"),
+                    _('Alt+D'), _("2-Sided PCB Tool"),
+                    _('Alt+E'), _("Extract Drills Tool"),
+                    _('Alt+F'), _("Fiducials Tool"),
+                    _('Alt+G'), _("Invert Gerber Tool"),
+                    _('Alt+H'), _("Punch Gerber Tool"),
+                    _('Alt+I'), _("Isolation Tool"),
+                    _('Alt+J'), _("Copper Thieving Tool"),
+                    _('Alt+K'), _("Solder Paste Dispensing Tool"),
+                    _('Alt+L'), _("Film PCB Tool"),
+                    _('Alt+M'), _("Corner Markers Tool"),
+                    _('Alt+N'), _("Non-Copper Clearing Tool"),
+                    _('Alt+O'), _("Optimal Tool"),
+                    _('Alt+P'), _("Paint Area Tool"),
+                    _('Alt+Q'), _("QRCode Tool"),
+                    _('Alt+R'), _("Rules Check Tool"),
+                    _('Alt+S'), _("View File Source"),
+                    _('Alt+T'), _("Transformations Tool"),
+                    _('Alt+W'), _("Subtract Tool"),
+                    _('Alt+X'), _("Cutout PCB Tool"),
+                    _('Alt+Z'), _("Panelize PCB"),
+                    _('Alt+1'), _("Enable all"),
+                    _('Alt+2'), _("Disable all"),
+                    _('Alt+3'), _("Enable Non-selected Objects"),
+                    _('Alt+4'), _("Disable Non-selected Objects"),
+                    _('Alt+F10'), _("Toggle Full Screen"),
 
 
                     # CTRL + ALT section
                     # CTRL + ALT section
                     _('Ctrl+Alt+X'), _("Abort current task (gracefully)"),
                     _('Ctrl+Alt+X'), _("Abort current task (gracefully)"),

+ 4 - 4
appGUI/ObjectUI.py

@@ -1093,9 +1093,9 @@ class GeometryObjectUI(ObjectUI):
 
 
         bhlay = QtWidgets.QHBoxLayout()
         bhlay = QtWidgets.QHBoxLayout()
 
 
-        self.addtool_btn = QtWidgets.QPushButton(_('Search and Add'))
-        self.addtool_btn.setIcon(QtGui.QIcon(self.app.resource_location + '/plus16.png'))
-        self.addtool_btn.setToolTip(
+        self.search_and_add_btn = QtWidgets.QPushButton(_('Search and Add'))
+        self.search_and_add_btn.setIcon(QtGui.QIcon(self.app.resource_location + '/plus16.png'))
+        self.search_and_add_btn.setToolTip(
             _("Add a new tool to the Tool Table\n"
             _("Add a new tool to the Tool Table\n"
               "with the diameter specified above.")
               "with the diameter specified above.")
         )
         )
@@ -1109,7 +1109,7 @@ class GeometryObjectUI(ObjectUI):
               "Menu: Options -> Tools Database")
               "Menu: Options -> Tools Database")
         )
         )
 
 
-        bhlay.addWidget(self.addtool_btn)
+        bhlay.addWidget(self.search_and_add_btn)
         bhlay.addWidget(self.addtool_from_db_btn)
         bhlay.addWidget(self.addtool_from_db_btn)
 
 
         grid1.addLayout(bhlay, 5, 0, 1, 2)
         grid1.addLayout(bhlay, 5, 0, 1, 2)

+ 145 - 11
appObjects/FlatCAMGeometry.py

@@ -25,6 +25,8 @@ import traceback
 from collections import defaultdict
 from collections import defaultdict
 from functools import reduce
 from functools import reduce
 
 
+import simplejson as json
+
 import gettext
 import gettext
 import appTranslation as fcTranslate
 import appTranslation as fcTranslate
 import builtins
 import builtins
@@ -585,7 +587,7 @@ class GeometryObject(FlatCAMObj, Geometry):
             # self.ui.geo_tools_table.setColumnHidden(4, True)
             # self.ui.geo_tools_table.setColumnHidden(4, True)
             self.ui.addtool_entry_lbl.hide()
             self.ui.addtool_entry_lbl.hide()
             self.ui.addtool_entry.hide()
             self.ui.addtool_entry.hide()
-            self.ui.addtool_btn.hide()
+            self.ui.search_and_add_btn.hide()
             self.ui.deltool_btn.hide()
             self.ui.deltool_btn.hide()
             # self.ui.endz_label.hide()
             # self.ui.endz_label.hide()
             # self.ui.endz_entry.hide()
             # self.ui.endz_entry.hide()
@@ -745,10 +747,9 @@ class GeometryObject(FlatCAMObj, Geometry):
                 self.ui.geo_tools_table.cellWidget(row, col).currentIndexChanged.connect(
                 self.ui.geo_tools_table.cellWidget(row, col).currentIndexChanged.connect(
                     self.on_tooltable_cellwidget_change)
                     self.on_tooltable_cellwidget_change)
 
 
-        # I use lambda's because the connected functions have parameters that could be used in certain scenarios
-        self.ui.addtool_btn.clicked.connect(lambda: self.on_tool_add())
+        self.ui.search_and_add_btn.clicked.connect(self.on_tool_add)
 
 
-        self.ui.deltool_btn.clicked.connect(lambda: self.on_tool_delete())
+        self.ui.deltool_btn.clicked.connect(self.on_tool_delete)
 
 
         self.ui.geo_tools_table.clicked.connect(self.on_row_selection_change)
         self.ui.geo_tools_table.clicked.connect(self.on_row_selection_change)
         self.ui.geo_tools_table.horizontalHeader().sectionClicked.connect(self.on_toggle_all_rows)
         self.ui.geo_tools_table.horizontalHeader().sectionClicked.connect(self.on_toggle_all_rows)
@@ -808,7 +809,7 @@ class GeometryObject(FlatCAMObj, Geometry):
                     pass
                     pass
 
 
         try:
         try:
-            self.ui.addtool_btn.clicked.disconnect()
+            self.ui.search_and_add_btn.clicked.disconnect()
         except (TypeError, AttributeError):
         except (TypeError, AttributeError):
             pass
             pass
 
 
@@ -1015,18 +1016,150 @@ class GeometryObject(FlatCAMObj, Geometry):
         self.ui_connect()
         self.ui_connect()
 
 
     def on_tool_add(self, dia=None, new_geo=None):
     def on_tool_add(self, dia=None, new_geo=None):
+        log.debug("GeometryObject.on_add_tool()")
+
         self.ui_disconnect()
         self.ui_disconnect()
 
 
-        self.units = self.app.defaults['units'].upper()
+        filename = self.app.tools_database_path()
 
 
-        tooldia = dia if dia is not None else float(self.ui.addtool_entry.get_value())
+        tool_dia = dia if dia is not None else self.ui.addtool_entry.get_value()
+        # construct a list of all 'tooluid' in the self.iso_tools
+        tool_uid_list = [int(tooluid_key) for tooluid_key in self.tools]
+
+        # find maximum from the temp_uid, add 1 and this is the new 'tooluid'
+        max_uid = 0 if not tool_uid_list else max(tool_uid_list)
+        tooluid = int(max_uid) + 1
+
+        new_tools_dict = deepcopy(self.default_data)
+        updated_tooldia = None
+
+        # determine the new tool diameter
+        if tool_dia is None or tool_dia == 0:
+            self.build_ui()
+            self.app.inform.emit('[WARNING_NOTCL] %s' % _("Please enter a tool diameter with non-zero value, "
+                                                          "in Float format."))
+            self.ui_connect()
+            return
+        truncated_tooldia = self.app.dec_format(tool_dia, self.decimals)
+
+        # load the database tools from the file
+        try:
+            with open(filename) as f:
+                tools = f.read()
+        except IOError:
+            self.app.log.error("Could not load tools DB file.")
+            self.app.inform.emit('[ERROR] %s' % _("Could not load Tools DB file."))
+            self.ui_connect()
+            self.on_tool_default_add(dia=tool_dia)
+            return
+
+        try:
+            # store here the tools from Tools Database when searching in Tools Database
+            tools_db_dict = json.loads(tools)
+        except Exception:
+            e = sys.exc_info()[0]
+            self.app.log.error(str(e))
+            self.app.inform.emit('[ERROR] %s' % _("Failed to parse Tools DB file."))
+            self.ui_connect()
+            self.on_tool_default_add(dia=tool_dia)
+            return
+
+        tool_found = 0
+
+        offset = 'Path'
+        offset_val = 0.0
+        typ = _("Rough")
+        tool_type = 'C1'
+        # look in database tools
+        for db_tool, db_tool_val in tools_db_dict.items():
+            offset = db_tool_val['offset']
+            offset_val = db_tool_val['offset_value']
+            typ = db_tool_val['type']
+            tool_type = db_tool_val['tool_type']
+
+            db_tooldia = db_tool_val['tooldia']
+            low_limit = float(db_tool_val['data']['tol_min'])
+            high_limit = float(db_tool_val['data']['tol_max'])
+
+            # we need only tool marked for Milling Tool (Geometry Object)
+            if db_tool_val['data']['tool_target'] != 1:     # _('Milling')
+                continue
+
+            # if we find a tool with the same diameter in the Tools DB just update it's data
+            if truncated_tooldia == db_tooldia:
+                tool_found += 1
+                for d in db_tool_val['data']:
+                    if d.find('tools_mill_') == 0:
+                        new_tools_dict[d] = db_tool_val['data'][d]
+                    elif d.find('tools_') == 0:
+                        # don't need data for other App Tools; this tests after 'tools_mill_'
+                        continue
+                    else:
+                        new_tools_dict[d] = db_tool_val['data'][d]
+            # search for a tool that has a tolerance that the tool fits in
+            elif high_limit >= truncated_tooldia >= low_limit:
+                tool_found += 1
+                updated_tooldia = db_tooldia
+                for d in db_tool_val['data']:
+                    if d.find('tools_iso') == 0:
+                        new_tools_dict[d] = db_tool_val['data'][d]
+                    elif d.find('tools_') == 0:
+                        # don't need data for other App Tools; this tests after 'tools_drill_'
+                        continue
+                    else:
+                        new_tools_dict[d] = db_tool_val['data'][d]
+
+        # test we found a suitable tool in Tools Database or if multiple ones
+        if tool_found == 0:
+            self.app.inform.emit('[WARNING_NOTCL] %s' % _("Tool not in Tools Database. Adding a default tool."))
+            self.on_tool_default_add(dia=tool_dia, new_geo=new_geo)
+            self.ui_connect()
+            return
+
+        if tool_found > 1:
+            self.app.inform.emit(
+                '[WARNING_NOTCL] %s' % _("Cancelled.\n"
+                                         "Multiple tools for one tool diameter found in Tools Database."))
+            self.ui_connect()
+            return
+
+        new_tdia = deepcopy(updated_tooldia) if updated_tooldia is not None else deepcopy(truncated_tooldia)
+        self.tools.update({
+            tooluid: {
+                'tooldia': new_tdia,
+                'offset': deepcopy(offset),
+                'offset_value': deepcopy(offset_val),
+                'type': deepcopy(typ),
+                'tool_type': deepcopy(tool_type),
+                'data': deepcopy(new_tools_dict),
+                'solid_geometry': self.solid_geometry
+            }
+        })
+        self.ui_connect()
+        self.build_ui()
+
+        # select the tool just added
+        for row in range(self.ui.geo_tools_table.rowCount()):
+            if int(self.ui.geo_tools_table.item(row, 5).text()) == tooluid:
+                self.ui.geo_tools_table.selectRow(row)
+                break
+
+        # update the UI form
+        self.update_ui()
+
+        self.app.inform.emit('[success] %s' % _("New tool added to Tool Table from Tools Database."))
+
+    def on_tool_default_add(self, dia=None, new_geo=None, muted=None):
+        self.ui_disconnect()
+
+        tooldia = dia if dia is not None else self.ui.addtool_entry.get_value()
         tool_uid_list = [int(tooluid_key) for tooluid_key in self.tools]
         tool_uid_list = [int(tooluid_key) for tooluid_key in self.tools]
 
 
         # find maximum from the temp_uid, add 1 and this is the new 'tooluid'
         # find maximum from the temp_uid, add 1 and this is the new 'tooluid'
         max_uid = max(tool_uid_list) if tool_uid_list else 0
         max_uid = max(tool_uid_list) if tool_uid_list else 0
-        self.tooluid = max_uid + 1
+        self.tooluid = int(max_uid) + 1
 
 
-        tooldia = float('%.*f' % (self.decimals, tooldia))
+        tooldia = self.app.dec_format(tooldia, self.decimals)
 
 
         # here we actually add the new tool; if there is no tool in the tool table we add a tool with default data
         # here we actually add the new tool; if there is no tool in the tool table we add a tool with default data
         # otherwise we add a tool with data copied from last tool
         # otherwise we add a tool with data copied from last tool
@@ -1080,7 +1213,8 @@ class GeometryObject(FlatCAMObj, Geometry):
             pass
             pass
         self.ser_attrs.append('tools')
         self.ser_attrs.append('tools')
 
 
-        self.app.inform.emit('[success] %s' % _("Tool added in Tool Table."))
+        if muted is None:
+            self.app.inform.emit('[success] %s' % _("Tool added in Tool Table."))
         self.ui_connect()
         self.ui_connect()
         self.build_ui()
         self.build_ui()
 
 
@@ -2782,7 +2916,7 @@ class GeometryObject(FlatCAMObj, Geometry):
             tooldia = float('%.*f' % (self.decimals, tooldia))
             tooldia = float('%.*f' % (self.decimals, tooldia))
 
 
             self.ui.addtool_entry.set_value(tooldia)
             self.ui.addtool_entry.set_value(tooldia)
-        self.ui.addtool_entry.returnPressed.connect(self.on_tool_add)
+        self.ui.addtool_entry.returnPressed.connect(self.on_tool_default_add)
 
 
         return factor
         return factor
 
 

+ 8 - 3
appTools/ToolCutOut.py

@@ -266,7 +266,7 @@ class CutOut(AppTool):
     def on_tool_add(self, custom_dia=None):
     def on_tool_add(self, custom_dia=None):
         self.blockSignals(True)
         self.blockSignals(True)
 
 
-        filename = self.app.data_path + '\\tools_db.FlatDB'
+        filename = self.app.tools_database_path()
 
 
         new_tools_dict = deepcopy(self.default_data)
         new_tools_dict = deepcopy(self.default_data)
         updated_tooldia = None
         updated_tooldia = None
@@ -311,7 +311,7 @@ class CutOut(AppTool):
 
 
         offset = 'Path'
         offset = 'Path'
         offset_val = 0.0
         offset_val = 0.0
-        typ = "Rough"
+        typ = _("Rough")
         tool_type = 'V'
         tool_type = 'V'
         # look in database tools
         # look in database tools
         for db_tool, db_tool_val in tools_db_dict.items():
         for db_tool, db_tool_val in tools_db_dict.items():
@@ -462,7 +462,12 @@ class CutOut(AppTool):
         :return:
         :return:
         """
         """
 
 
-        if tool['data']['tool_target'] != _("Cutout"):
+        if tool['data']['tool_target'] not in [0, 6]:   # [General, Cutout Tool]
+            for idx in range(self.app.ui.plot_tab_area.count()):
+                if self.app.ui.plot_tab_area.tabText(idx) == _("Tools Database"):
+                    wdg = self.app.ui.plot_tab_area.widget(idx)
+                    wdg.deleteLater()
+                    self.app.ui.plot_tab_area.removeTab(idx)
             self.app.inform.emit('[ERROR_NOTCL] %s' % _("Selected tool can't be used here. Pick another."))
             self.app.inform.emit('[ERROR_NOTCL] %s' % _("Selected tool can't be used here. Pick another."))
             return
             return
         tool_from_db = deepcopy(self.default_data)
         tool_from_db = deepcopy(self.default_data)

+ 2 - 2
appTools/ToolDrilling.py

@@ -884,7 +884,7 @@ class ToolDrilling(AppTool, Excellon):
 
 
     def on_tool_db_load(self):
     def on_tool_db_load(self):
 
 
-        filename = self.app.data_path + '\\tools_db.FlatDB'
+        filename = self.app.tools_database_path()
 
 
         # load the database tools from the file
         # load the database tools from the file
         try:
         try:
@@ -1213,7 +1213,7 @@ class ToolDrilling(AppTool, Excellon):
         # if the sender is in the column with index 2 then we update the tool_type key
         # if the sender is in the column with index 2 then we update the tool_type key
         if cw_col == 2:
         if cw_col == 2:
             tt = cw.currentText()
             tt = cw.currentText()
-            typ = 'Iso' if tt == 'V' else "Rough"
+            typ = 'Iso' if tt == 'V' else _("Rough")
 
 
             self.excellon_tools[current_uid].update({
             self.excellon_tools[current_uid].update({
                 'type': typ,
                 'type': typ,

+ 22 - 24
appTools/ToolIsolation.py

@@ -208,7 +208,7 @@ class ToolIsolation(AppTool, Gerber):
         self.ui.apply_param_to_all.clicked.connect(self.on_apply_param_to_all_clicked)
         self.ui.apply_param_to_all.clicked.connect(self.on_apply_param_to_all_clicked)
 
 
         # adding Tools
         # adding Tools
-        self.ui.add_newtool_button.clicked.connect(lambda: self.on_tool_add())
+        self.ui.search_and_add_btn.clicked.connect(lambda: self.on_tool_add())
         self.ui.addtool_from_db_btn.clicked.connect(self.on_tool_add_from_db_clicked)
         self.ui.addtool_from_db_btn.clicked.connect(self.on_tool_add_from_db_clicked)
 
 
         self.ui.generate_iso_button.clicked.connect(self.on_iso_button_click)
         self.ui.generate_iso_button.clicked.connect(self.on_iso_button_click)
@@ -899,7 +899,7 @@ class ToolIsolation(AppTool, Gerber):
         # if the sender is in the column with index 2 then we update the tool_type key
         # if the sender is in the column with index 2 then we update the tool_type key
         if cw_col == 2:
         if cw_col == 2:
             tt = cw.currentText()
             tt = cw.currentText()
-            typ = 'Iso' if tt == 'V' else "Rough"
+            typ = 'Iso' if tt == 'V' else _("Rough")
 
 
             self.iso_tools[currenuid].update({
             self.iso_tools[currenuid].update({
                 'type': typ,
                 'type': typ,
@@ -1034,29 +1034,26 @@ class ToolIsolation(AppTool, Gerber):
     def on_tool_add(self, custom_dia=None):
     def on_tool_add(self, custom_dia=None):
         self.blockSignals(True)
         self.blockSignals(True)
 
 
-        filename = self.app.data_path + '\\tools_db.FlatDB'
-
-        new_tools_dict = deepcopy(self.default_data)
-        updated_tooldia = None
+        filename = self.app.tools_database_path()
 
 
+        tool_dia = custom_dia if custom_dia is not None else self.ui.new_tooldia_entry.get_value()
         # construct a list of all 'tooluid' in the self.iso_tools
         # construct a list of all 'tooluid' in the self.iso_tools
         tool_uid_list = [int(tooluid_key) for tooluid_key in self.iso_tools]
         tool_uid_list = [int(tooluid_key) for tooluid_key in self.iso_tools]
 
 
         # find maximum from the temp_uid, add 1 and this is the new 'tooluid'
         # find maximum from the temp_uid, add 1 and this is the new 'tooluid'
         max_uid = 0 if not tool_uid_list else max(tool_uid_list)
         max_uid = 0 if not tool_uid_list else max(tool_uid_list)
-        tooluid = int(max_uid + 1)
+        tooluid = int(max_uid) + 1
+
+        new_tools_dict = deepcopy(self.default_data)
+        updated_tooldia = None
 
 
         tool_dias = []
         tool_dias = []
         for k, v in self.iso_tools.items():
         for k, v in self.iso_tools.items():
             for tool_v in v.keys():
             for tool_v in v.keys():
                 if tool_v == 'tooldia':
                 if tool_v == 'tooldia':
-                    tool_dias.append(self.app.dec_format(v[tool_v], self.decimals))
+                    tool_dias.append(self.app.dec_format(v['tooldia'], self.decimals))
 
 
         # determine the new tool diameter
         # determine the new tool diameter
-        if custom_dia is None:
-            tool_dia = self.ui.new_tooldia_entry.get_value()
-        else:
-            tool_dia = custom_dia
         if tool_dia is None or tool_dia == 0:
         if tool_dia is None or tool_dia == 0:
             self.build_ui()
             self.build_ui()
             self.app.inform.emit('[WARNING_NOTCL] %s' % _("Please enter a tool diameter with non-zero value, "
             self.app.inform.emit('[WARNING_NOTCL] %s' % _("Please enter a tool diameter with non-zero value, "
@@ -1097,7 +1094,7 @@ class ToolIsolation(AppTool, Gerber):
 
 
         offset = 'Path'
         offset = 'Path'
         offset_val = 0.0
         offset_val = 0.0
-        typ = "Rough"
+        typ = _("Rough")
         tool_type = 'V'
         tool_type = 'V'
         # look in database tools
         # look in database tools
         for db_tool, db_tool_val in tools_db_dict.items():
         for db_tool, db_tool_val in tools_db_dict.items():
@@ -1111,7 +1108,7 @@ class ToolIsolation(AppTool, Gerber):
             high_limit = float(db_tool_val['data']['tol_max'])
             high_limit = float(db_tool_val['data']['tol_max'])
 
 
             # we need only tool marked for Isolation Tool
             # we need only tool marked for Isolation Tool
-            if db_tool_val['data']['tool_target'] != _('Isolation'):
+            if db_tool_val['data']['tool_target'] != 3:     # _('Isolation')
                 continue
                 continue
 
 
             # if we find a tool with the same diameter in the Tools DB just update it's data
             # if we find a tool with the same diameter in the Tools DB just update it's data
@@ -1186,12 +1183,8 @@ class ToolIsolation(AppTool, Gerber):
 
 
     def on_tool_default_add(self, dia=None, muted=None):
     def on_tool_default_add(self, dia=None, muted=None):
         self.blockSignals(True)
         self.blockSignals(True)
-        self.units = self.app.defaults['units'].upper()
 
 
-        if dia:
-            tool_dia = dia
-        else:
-            tool_dia = self.ui.new_tooldia_entry.get_value()
+        tool_dia = dia if dia is not None else self.ui.new_tooldia_entry.get_value()
 
 
         if tool_dia is None or tool_dia == 0:
         if tool_dia is None or tool_dia == 0:
             self.build_ui()
             self.build_ui()
@@ -2586,7 +2579,12 @@ class ToolIsolation(AppTool, Gerber):
         """
         """
         tool_from_db = deepcopy(tool)
         tool_from_db = deepcopy(tool)
 
 
-        if tool['data']['tool_target'] != _("Isolation"):
+        if tool['data']['tool_target'] not in [0, 3]:   # [General, Isolation]
+            for idx in range(self.app.ui.plot_tab_area.count()):
+                if self.app.ui.plot_tab_area.tabText(idx) == _("Tools Database"):
+                    wdg = self.app.ui.plot_tab_area.widget(idx)
+                    wdg.deleteLater()
+                    self.app.ui.plot_tab_area.removeTab(idx)
             self.app.inform.emit('[ERROR_NOTCL] %s' % _("Selected tool can't be used here. Pick another."))
             self.app.inform.emit('[ERROR_NOTCL] %s' % _("Selected tool can't be used here. Pick another."))
             return
             return
 
 
@@ -3134,16 +3132,16 @@ class IsoUI:
 
 
         bhlay = QtWidgets.QHBoxLayout()
         bhlay = QtWidgets.QHBoxLayout()
 
 
-        self.add_newtool_button = FCButton(_('Search and Add'))
-        self.add_newtool_button.setIcon(QtGui.QIcon(self.app.resource_location + '/plus16.png'))
-        self.add_newtool_button.setToolTip(
+        self.search_and_add_btn = FCButton(_('Search and Add'))
+        self.search_and_add_btn.setIcon(QtGui.QIcon(self.app.resource_location + '/plus16.png'))
+        self.search_and_add_btn.setToolTip(
             _("Add a new tool to the Tool Table\n"
             _("Add a new tool to the Tool Table\n"
               "with the diameter specified above.\n"
               "with the diameter specified above.\n"
               "This is done by a background search\n"
               "This is done by a background search\n"
               "in the Tools Database. If nothing is found\n"
               "in the Tools Database. If nothing is found\n"
               "in the Tools DB then a default tool is added.")
               "in the Tools DB then a default tool is added.")
         )
         )
-        bhlay.addWidget(self.add_newtool_button)
+        bhlay.addWidget(self.search_and_add_btn)
 
 
         self.addtool_from_db_btn = FCButton(_('Pick from DB'))
         self.addtool_from_db_btn = FCButton(_('Pick from DB'))
         self.addtool_from_db_btn.setIcon(QtGui.QIcon(self.app.resource_location + '/search_db32.png'))
         self.addtool_from_db_btn.setIcon(QtGui.QIcon(self.app.resource_location + '/search_db32.png'))

+ 1 - 1
appTools/ToolMilling.py

@@ -980,7 +980,7 @@ class ToolMilling(AppTool, Excellon):
         # if the sender is in the column with index 2 then we update the tool_type key
         # if the sender is in the column with index 2 then we update the tool_type key
         if cw_col == 2:
         if cw_col == 2:
             tt = cw.currentText()
             tt = cw.currentText()
-            typ = 'Iso' if tt == 'V' else "Rough"
+            typ = 'Iso' if tt == 'V' else _("Rough")
 
 
             self.iso_tools[current_uid].update({
             self.iso_tools[current_uid].update({
                 'type': typ,
                 'type': typ,

+ 9 - 4
appTools/ToolNCC.py

@@ -836,7 +836,7 @@ class NonCopperClear(AppTool, Gerber):
         # if the sender is in the column with index 2 then we update the tool_type key
         # if the sender is in the column with index 2 then we update the tool_type key
         if cw_col == 2:
         if cw_col == 2:
             tt = cw.currentText()
             tt = cw.currentText()
-            typ = 'Iso' if tt == 'V' else "Rough"
+            typ = 'Iso' if tt == 'V' else _("Rough")
 
 
             self.ncc_tools[current_uid].update({
             self.ncc_tools[current_uid].update({
                 'type': typ,
                 'type': typ,
@@ -976,7 +976,7 @@ class NonCopperClear(AppTool, Gerber):
     def on_tool_add(self, custom_dia=None):
     def on_tool_add(self, custom_dia=None):
         self.blockSignals(True)
         self.blockSignals(True)
 
 
-        filename = self.app.data_path + '\\tools_db.FlatDB'
+        filename = self.app.tools_database_path()
 
 
         new_tools_dict = deepcopy(self.default_data)
         new_tools_dict = deepcopy(self.default_data)
         updated_tooldia = None
         updated_tooldia = None
@@ -1042,7 +1042,7 @@ class NonCopperClear(AppTool, Gerber):
 
 
         offset = 'Path'
         offset = 'Path'
         offset_val = 0.0
         offset_val = 0.0
-        typ = "Rough"
+        typ = _("Rough")
         tool_type = 'V'
         tool_type = 'V'
         # look in database tools
         # look in database tools
         for db_tool, db_tool_val in tools_db_dict.items():
         for db_tool, db_tool_val in tools_db_dict.items():
@@ -3721,7 +3721,12 @@ class NonCopperClear(AppTool, Gerber):
         """
         """
         tool_from_db = deepcopy(tool)
         tool_from_db = deepcopy(tool)
 
 
-        if tool['data']['tool_target'] != _("NCC"):
+        if tool['data']['tool_target'] not in [0, 5]:   # [General, NCC]
+            for idx in range(self.app.ui.plot_tab_area.count()):
+                if self.app.ui.plot_tab_area.tabText(idx) == _("Tools Database"):
+                    wdg = self.app.ui.plot_tab_area.widget(idx)
+                    wdg.deleteLater()
+                    self.app.ui.plot_tab_area.removeTab(idx)
             self.app.inform.emit('[ERROR_NOTCL] %s' % _("Selected tool can't be used here. Pick another."))
             self.app.inform.emit('[ERROR_NOTCL] %s' % _("Selected tool can't be used here. Pick another."))
             return
             return
 
 

+ 9 - 4
appTools/ToolPaint.py

@@ -411,7 +411,7 @@ class ToolPaint(AppTool, Gerber):
         # if the sender is in the column with index 2 then we update the tool_type key
         # if the sender is in the column with index 2 then we update the tool_type key
         if cw_col == 2:
         if cw_col == 2:
             tt = cw.currentText()
             tt = cw.currentText()
-            typ = 'Iso' if tt == 'V' else "Rough"
+            typ = 'Iso' if tt == 'V' else _("Rough")
 
 
             self.paint_tools[current_uid].update({
             self.paint_tools[current_uid].update({
                 'type': typ,
                 'type': typ,
@@ -666,7 +666,7 @@ class ToolPaint(AppTool, Gerber):
     def on_tool_add(self, custom_dia=None):
     def on_tool_add(self, custom_dia=None):
         self.blockSignals(True)
         self.blockSignals(True)
 
 
-        filename = self.app.data_path + '\\tools_db.FlatDB'
+        filename = self.app.tools_database_path()
 
 
         new_tools_dict = deepcopy(self.default_data)
         new_tools_dict = deepcopy(self.default_data)
         updated_tooldia = None
         updated_tooldia = None
@@ -729,7 +729,7 @@ class ToolPaint(AppTool, Gerber):
 
 
         offset = 'Path'
         offset = 'Path'
         offset_val = 0.0
         offset_val = 0.0
-        typ = "Rough"
+        typ = _("Rough")
         tool_type = 'V'
         tool_type = 'V'
         # look in database tools
         # look in database tools
         for db_tool, db_tool_val in tools_db_dict.items():
         for db_tool, db_tool_val in tools_db_dict.items():
@@ -2626,7 +2626,12 @@ class ToolPaint(AppTool, Gerber):
         """
         """
         tool_from_db = deepcopy(tool)
         tool_from_db = deepcopy(tool)
 
 
-        if tool['data']['tool_target'] != _("Paint"):
+        if tool['data']['tool_target'] not in [0, 4]:   # [General, Paint]
+            for idx in range(self.app.ui.plot_tab_area.count()):
+                if self.app.ui.plot_tab_area.tabText(idx) == _("Tools Database"):
+                    wdg = self.app.ui.plot_tab_area.widget(idx)
+                    wdg.deleteLater()
+                    self.app.ui.plot_tab_area.removeTab(idx)
             self.app.inform.emit('[ERROR_NOTCL] %s' % _("Selected tool can't be used here. Pick another."))
             self.app.inform.emit('[ERROR_NOTCL] %s' % _("Selected tool can't be used here. Pick another."))
             return
             return
 
 

+ 58 - 32
app_Main.py

@@ -359,54 +359,59 @@ class App(QtCore.QObject):
         if not os.path.exists(self.data_path):
         if not os.path.exists(self.data_path):
             os.makedirs(self.data_path)
             os.makedirs(self.data_path)
             self.log.debug('Created data folder: ' + self.data_path)
             self.log.debug('Created data folder: ' + self.data_path)
+
             os.makedirs(os.path.join(self.data_path, 'preprocessors'))
             os.makedirs(os.path.join(self.data_path, 'preprocessors'))
             self.log.debug('Created data preprocessors folder: ' + os.path.join(self.data_path, 'preprocessors'))
             self.log.debug('Created data preprocessors folder: ' + os.path.join(self.data_path, 'preprocessors'))
 
 
-        self.preprocessorpaths = os.path.join(self.data_path, 'preprocessors')
+        self.preprocessorpaths = self.preprocessors_path()
         if not os.path.exists(self.preprocessorpaths):
         if not os.path.exists(self.preprocessorpaths):
             os.makedirs(self.preprocessorpaths)
             os.makedirs(self.preprocessorpaths)
             self.log.debug('Created preprocessors folder: ' + self.preprocessorpaths)
             self.log.debug('Created preprocessors folder: ' + self.preprocessorpaths)
 
 
         # create tools_db.FlatDB file if there is none
         # create tools_db.FlatDB file if there is none
+        db_path = self.tools_database_path()
         try:
         try:
-            f = open(self.data_path + '/tools_db.FlatDB')
+            f = open(db_path)
             f.close()
             f.close()
         except IOError:
         except IOError:
             self.log.debug('Creating empty tools_db.FlatDB')
             self.log.debug('Creating empty tools_db.FlatDB')
-            f = open(self.data_path + '/tools_db.FlatDB', 'w')
+            f = open(db_path, 'w')
             json.dump({}, f)
             json.dump({}, f)
             f.close()
             f.close()
 
 
         # create current_defaults.FlatConfig file if there is none
         # create current_defaults.FlatConfig file if there is none
+        def_path = self.defaults_path()
         try:
         try:
-            f = open(self.data_path + '/current_defaults.FlatConfig')
+            f = open(def_path)
             f.close()
             f.close()
         except IOError:
         except IOError:
             self.log.debug('Creating empty current_defaults.FlatConfig')
             self.log.debug('Creating empty current_defaults.FlatConfig')
-            f = open(self.data_path + '/current_defaults.FlatConfig', 'w')
+            f = open(def_path, 'w')
             json.dump({}, f)
             json.dump({}, f)
             f.close()
             f.close()
 
 
         # the factory defaults are written only once at the first launch of the application after installation
         # the factory defaults are written only once at the first launch of the application after installation
-        FlatCAMDefaults.save_factory_defaults(os.path.join(self.data_path, "factory_defaults.FlatConfig"), self.version)
+        FlatCAMDefaults.save_factory_defaults(self.factory_defaults_path(), self.version)
 
 
         # create a recent files json file if there is none
         # create a recent files json file if there is none
+        rec_f_path = self.recent_files_path()
         try:
         try:
-            f = open(self.data_path + '/recent.json')
+            f = open(rec_f_path)
             f.close()
             f.close()
         except IOError:
         except IOError:
             self.log.debug('Creating empty recent.json')
             self.log.debug('Creating empty recent.json')
-            f = open(self.data_path + '/recent.json', 'w')
+            f = open(rec_f_path, 'w')
             json.dump([], f)
             json.dump([], f)
             f.close()
             f.close()
 
 
         # create a recent projects json file if there is none
         # create a recent projects json file if there is none
+        rec_proj_path = self.recent_projects_path()
         try:
         try:
-            fp = open(self.data_path + '/recent_projects.json')
+            fp = open(rec_proj_path)
             fp.close()
             fp.close()
         except IOError:
         except IOError:
             self.log.debug('Creating empty recent_projects.json')
             self.log.debug('Creating empty recent_projects.json')
-            fp = open(self.data_path + '/recent_projects.json', 'w')
+            fp = open(rec_proj_path, 'w')
             json.dump([], fp)
             json.dump([], fp)
             fp.close()
             fp.close()
 
 
@@ -1275,7 +1280,7 @@ class App(QtCore.QObject):
 
 
         self.log.debug("Finished adding FlatCAM Editor's.")
         self.log.debug("Finished adding FlatCAM Editor's.")
 
 
-        self.set_ui_title(name=_("New Project - Not saved"))
+        self.ui.set_ui_title(name=_("New Project - Not saved"))
 
 
         current_platform = platform.architecture()[0]
         current_platform = platform.architecture()[0]
         if current_platform != '64bit':
         if current_platform != '64bit':
@@ -1865,20 +1870,23 @@ class App(QtCore.QObject):
         #     else:
         #     else:
         #         sys.exit(2)
         #         sys.exit(2)
 
 
-    def set_ui_title(self, name):
-        """
-        Sets the title of the main window.
+    def tools_database_path(self):
+        return os.path.join(self.data_path, 'tools_db.FlatDB')
 
 
-        :param name: String that store the project path and project name
-        :return: None
-        """
-        self.ui.setWindowTitle('FlatCAM %s %s - %s - [%s]    %s' %
-                               (self.version,
-                                ('BETA' if self.beta else ''),
-                                platform.architecture()[0],
-                                self.engine,
-                                name)
-                               )
+    def defaults_path(self):
+        return os.path.join(self.data_path, 'current_defaults.FlatConfig')
+
+    def factory_defaults_path(self):
+        return os.path.join(self.data_path, 'factory_defaults.FlatConfig')
+
+    def recent_files_path(self):
+        return os.path.join(self.data_path, 'recent.json')
+
+    def recent_projects_path(self):
+        return os.path.join(self.data_path, 'recent_projects.json')
+
+    def preprocessors_path(self):
+        return os.path.join(self.data_path, 'preprocessors')
 
 
     def on_app_restart(self):
     def on_app_restart(self):
 
 
@@ -5651,7 +5659,7 @@ class App(QtCore.QObject):
 
 
         :return:
         :return:
         """
         """
-        filename = self.data_path + '\\tools_db.FlatDB'
+        filename = self.tools_database_path()
 
 
         # load the database tools from the file
         # load the database tools from the file
         try:
         try:
@@ -5731,9 +5739,18 @@ class App(QtCore.QObject):
         :return:
         :return:
         """
         """
         tool_from_db = deepcopy(tool)
         tool_from_db = deepcopy(tool)
-
         obj = self.collection.get_active()
         obj = self.collection.get_active()
         if obj.kind == 'geometry':
         if obj.kind == 'geometry':
+            if tool['data']['tool_target'] not in [0, 1]:    # General, Milling Type
+                # close the tab and delete it
+                for idx in range(self.ui.plot_tab_area.count()):
+                    if self.ui.plot_tab_area.tabText(idx) == _("Tools Database"):
+                        wdg = self.ui.plot_tab_area.widget(idx)
+                        wdg.deleteLater()
+                        self.ui.plot_tab_area.removeTab(idx)
+                self.inform.emit('[ERROR_NOTCL] %s' % _("Selected tool can't be used here. Pick another."))
+                return
+
             obj.on_tool_from_db_inserted(tool=tool_from_db)
             obj.on_tool_from_db_inserted(tool=tool_from_db)
 
 
             # close the tab and delete it
             # close the tab and delete it
@@ -5744,6 +5761,15 @@ class App(QtCore.QObject):
                     self.ui.plot_tab_area.removeTab(idx)
                     self.ui.plot_tab_area.removeTab(idx)
             self.inform.emit('[success] %s' % _("Tool from DB added in Tool Table."))
             self.inform.emit('[success] %s' % _("Tool from DB added in Tool Table."))
         elif obj.kind == 'gerber':
         elif obj.kind == 'gerber':
+            if tool['data']['tool_target'] not in [0, 3]:    # General, Isolation Type
+                # close the tab and delete it
+                for idx in range(self.ui.plot_tab_area.count()):
+                    if self.ui.plot_tab_area.tabText(idx) == _("Tools Database"):
+                        wdg = self.ui.plot_tab_area.widget(idx)
+                        wdg.deleteLater()
+                        self.ui.plot_tab_area.removeTab(idx)
+                self.inform.emit('[ERROR_NOTCL] %s' % _("Selected tool can't be used here. Pick another."))
+                return
             self.isolation_tool.on_tool_from_db_inserted(tool=tool_from_db)
             self.isolation_tool.on_tool_from_db_inserted(tool=tool_from_db)
 
 
             # close the tab and delete it
             # close the tab and delete it
@@ -8894,7 +8920,7 @@ class MenuFileHandlers(QtCore.QObject):
         # take the focus of the Notebook on Project Tab.
         # take the focus of the Notebook on Project Tab.
         self.app.ui.notebook.setCurrentWidget(self.app.ui.project_tab)
         self.app.ui.notebook.setCurrentWidget(self.app.ui.project_tab)
 
 
-        self.app.set_ui_title(name=_("New Project - Not saved"))
+        self.app.ui.set_ui_title(name=_("New Project - Not saved"))
 
 
     def on_filenewscript(self, silent=False):
     def on_filenewscript(self, silent=False):
         """
         """
@@ -9055,7 +9081,7 @@ class MenuFileHandlers(QtCore.QObject):
                 self.app.file_opened.emit("project", self.project_filename)
                 self.app.file_opened.emit("project", self.project_filename)
             self.app.file_saved.emit("project", self.project_filename)
             self.app.file_saved.emit("project", self.project_filename)
 
 
-        self.app.set_ui_title(name=self.app.project_filename)
+        self.app.ui.set_ui_title(name=self.app.project_filename)
 
 
         self.app.should_we_save = False
         self.app.should_we_save = False
 
 
@@ -9107,7 +9133,7 @@ class MenuFileHandlers(QtCore.QObject):
         if not make_copy:
         if not make_copy:
             self.app.project_filename = filename
             self.app.project_filename = filename
 
 
-        self.app.set_ui_title(name=self.app.project_filename)
+        self.app.ui.set_ui_title(name=self.app.project_filename)
         self.app.should_we_save = False
         self.app.should_we_save = False
 
 
     def on_file_save_objects_pdf(self, use_thread=True):
     def on_file_save_objects_pdf(self, use_thread=True):
@@ -10316,7 +10342,7 @@ class MenuFileHandlers(QtCore.QObject):
         # for some reason, setting ui_title does not work when this method is called from Tcl Shell
         # for some reason, setting ui_title does not work when this method is called from Tcl Shell
         # it's because the TclCommand is run in another thread (it inherit TclCommandSignaled)
         # it's because the TclCommand is run in another thread (it inherit TclCommandSignaled)
         if cli is None:
         if cli is None:
-            self.app.set_ui_title(name=_("Loading Project ... Please Wait ..."))
+            self.app.ui.set_ui_title(name=_("Loading Project ... Please Wait ..."))
 
 
         if run_from_arg:
         if run_from_arg:
             self.splash.showMessage('%s: %ssec\n%s' % (_("Canvas initialization started.\n"
             self.splash.showMessage('%s: %ssec\n%s' % (_("Canvas initialization started.\n"
@@ -10398,7 +10424,7 @@ class MenuFileHandlers(QtCore.QObject):
             # for some reason, setting ui_title does not work when this method is called from Tcl Shell
             # for some reason, setting ui_title does not work when this method is called from Tcl Shell
             # it's because the TclCommand is run in another thread (it inherit TclCommandSignaled)
             # it's because the TclCommand is run in another thread (it inherit TclCommandSignaled)
             if cli is None:
             if cli is None:
-                self.app.set_ui_title(name="{} {}: {}".format(
+                self.app.ui.set_ui_title(name="{} {}: {}".format(
                     _("Loading Project ... restoring"), obj['kind'].upper(), obj['options']['name']))
                     _("Loading Project ... restoring"), obj['kind'].upper(), obj['options']['name']))
 
 
             self.app.app_obj.new_object(obj['kind'], obj['options']['name'], obj_init, plot=plot)
             self.app.app_obj.new_object(obj['kind'], obj['options']['name'], obj_init, plot=plot)
@@ -10414,7 +10440,7 @@ class MenuFileHandlers(QtCore.QObject):
         # for some reason, setting ui_title does not work when this method is called from Tcl Shell
         # for some reason, setting ui_title does not work when this method is called from Tcl Shell
         # it's because the TclCommand is run in another thread (it inherit TclCommandSignaled)
         # it's because the TclCommand is run in another thread (it inherit TclCommandSignaled)
         if cli is None:
         if cli is None:
-            self.app.set_ui_title(name=self.app.project_filename)
+            self.app.ui.set_ui_title(name=self.app.project_filename)
 
 
         self.app.log.debug(" **************** Finished PROJECT loading... **************** ")
         self.app.log.debug(" **************** Finished PROJECT loading... **************** ")