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

- added a detection if any values are changed in the Edit -> Preferences window and on close it will ask the user if he wants to save the changes or not
- created a new menu entry in the File menu named Recent projects that will hold the recent projects and the previous "Recent files" will hold only the previous loaded files

Marius Stanciu 6 лет назад
Родитель
Сommit
33344b6626
4 измененных файлов с 204 добавлено и 33 удалено
  1. 187 25
      FlatCAMApp.py
  2. 2 0
      README.md
  3. 10 6
      flatcamGUI/FlatCAMGUI.py
  4. 5 2
      flatcamGUI/GUIElements.py

+ 187 - 25
FlatCAMApp.py

@@ -255,6 +255,15 @@ class App(QtCore.QObject):
             json.dump([], f)
             f.close()
 
+        try:
+            fp = open(self.data_path + '/recent_projects.json')
+            fp.close()
+        except IOError:
+            App.log.debug('Creating empty recent_projects.json')
+            fp = open(self.data_path + '/recent_projects.json', 'w')
+            json.dump([], fp)
+            fp.close()
+
         # Application directory. CHDIR to it. Otherwise, trying to load
         # GUI icons will fail as their path is relative.
         # This will fail under cx_freeze ...
@@ -294,6 +303,8 @@ class App(QtCore.QObject):
         # ### Data ####
         # #############
         self.recent = []
+        self.recent_projects = []
+
         self.clipboard = QtWidgets.QApplication.clipboard()
         self.proc_container = FCVisibleProcessContainer(self.ui.activity_view)
 
@@ -1499,6 +1510,7 @@ class App(QtCore.QObject):
         self.ui.general_defaults_form.general_app_group.units_radio.activated_custom.connect(
             lambda: self.on_toggle_units(no_pref=False))
 
+
         # ##############################
         # ### GUI PREFERENCES SIGNALS ##
         # ##############################
@@ -1960,6 +1972,9 @@ class App(QtCore.QObject):
         # Variable to store the GCODE that was edited
         self.gcode_edited = ""
 
+        # if Preferences are changed in the Edit -> Preferences tab the value will be set to True
+        self.preferences_changed_flag = False
+
         self.grb_list = ['gbr', 'ger', 'gtl', 'gbl', 'gts', 'gbs', 'gtp', 'gbp', 'gto', 'gbo', 'gm1', 'gm2', 'gm3',
                          'gko', 'cmp', 'sol', 'stc', 'sts', 'plc', 'pls', 'crc', 'crs', 'tsm', 'bsm', 'ly2', 'ly15',
                          'dim', 'mil', 'grb', 'top', 'bot', 'smt', 'smb', 'sst', 'ssb', 'spt', 'spb', 'pho', 'gdo',
@@ -2922,12 +2937,19 @@ class App(QtCore.QObject):
         record = {'kind': str(kind), 'filename': str(filename)}
         if record in self.recent:
             return
-
-        self.recent.insert(0, record)
+        if record in self.recent_projects:
+            return
+        if record['kind'] == 'project':
+            self.recent_projects.insert(0, record)
+        else:
+            self.recent.insert(0, record)
 
         if len(self.recent) > self.defaults['global_recent_limit']:  # Limit reached
             self.recent.pop()
 
+        if len(self.recent_projects) > self.defaults['global_recent_limit']:  # Limit reached
+            self.recent_projects.pop()
+
         try:
             f = open(self.data_path + '/recent.json', 'w')
         except IOError:
@@ -2938,6 +2960,16 @@ class App(QtCore.QObject):
         json.dump(self.recent, f, default=to_dict, indent=2, sort_keys=True)
         f.close()
 
+        try:
+            fp = open(self.data_path + '/recent_projects.json', 'w')
+        except IOError:
+            App.log.error("Failed to open recent items file for writing.")
+            self.inform.emit(_('[ERROR_NOTCL] Failed to open recent projects file for writing.'))
+            return
+
+        json.dump(self.recent_projects, fp, default=to_dict, indent=2, sort_keys=True)
+        fp.close()
+
         # Re-build the recent items menu
         self.setup_recent_items()
 
@@ -4541,6 +4573,7 @@ class App(QtCore.QObject):
 
     def on_save_button(self):
         log.debug("App.on_save_button() --> Saving preferences to file.")
+        self.preferences_changed_flag = False
 
         self.save_defaults(silent=False)
         # load the defaults so they are updated into the app
@@ -5133,7 +5166,6 @@ class App(QtCore.QObject):
                 self.draw_selection_shape(curr_sel_obj)
 
     def on_preferences(self):
-
         # add the tab if it was closed
         self.ui.plot_tab_area.addTab(self.ui.preferences_tab, _("Preferences"))
 
@@ -5145,6 +5177,115 @@ class App(QtCore.QObject):
         self.ui.plot_tab_area.setCurrentWidget(self.ui.preferences_tab)
         self.ui.show()
 
+        # this disconnect() is done so the slot will be connected only once
+        try:
+            self.ui.plot_tab_area.tab_closed_signal.disconnect(self.on_preferences_closed)
+        except TypeError:
+            pass
+        self.ui.plot_tab_area.tab_closed_signal.connect(self.on_preferences_closed)
+
+        # detect changes in the preferences
+        for idx in range(self.ui.pref_tab_area.count()):
+            for tb in self.ui.pref_tab_area.widget(idx).findChildren(QtCore.QObject):
+                try:
+                    try:
+                        tb.textEdited.disconnect()
+                    except TypeError:
+                        pass
+                    tb.textEdited.connect(self.on_preferences_edited)
+                except AttributeError:
+                    pass
+
+                try:
+                    try:
+                        tb.modificationChanged.disconnect()
+                    except TypeError:
+                        pass
+                    tb.modificationChanged.connect(self.on_preferences_edited)
+                except AttributeError:
+                    pass
+
+                try:
+                    try:
+                        tb.toggled.disconnect()
+                    except TypeError:
+                        pass
+                    tb.toggled.connect(self.on_preferences_edited)
+                except AttributeError:
+                    pass
+
+                try:
+                    try:
+                        tb.valueChanged.disconnect()
+                    except TypeError:
+                        pass
+                    tb.valueChanged.connect(self.on_preferences_edited)
+                except AttributeError:
+                    pass
+
+                try:
+                    try:
+                        tb.currentIndexChanged.disconnect()
+                    except TypeError:
+                        pass
+                    tb.currentIndexChanged.connect(self.on_preferences_edited)
+                except AttributeError:
+                    pass
+
+    def on_preferences_edited(self):
+        self.inform.emit(_("[WARNING_NOTCL] Preferences edited but not saved."))
+        self.preferences_changed_flag = True
+
+    def on_preferences_closed(self):
+        # disconnect
+        for idx in range(self.ui.pref_tab_area.count()):
+            for tb in self.ui.pref_tab_area.widget(idx).findChildren(QtCore.QObject):
+                try:
+                    tb.textEdited.disconnect()
+                except (TypeError, AttributeError):
+                    pass
+
+                try:
+                    tb.modificationChanged.disconnect()
+                except (TypeError, AttributeError):
+                    pass
+
+                try:
+                    tb.toggled.disconnect()
+                except (TypeError, AttributeError):
+                    pass
+
+                try:
+                    tb.valueChanged.disconnect()
+                except (TypeError, AttributeError):
+                    pass
+
+                try:
+                    tb.currentIndexChanged.disconnect()
+                except (TypeError, AttributeError):
+                    pass
+
+        if self.preferences_changed_flag is True:
+            msgbox = QtWidgets.QMessageBox()
+            msgbox.setText(_("One or more values are changed.\n"
+                             "Do you want to save the Preferences?"))
+            msgbox.setWindowTitle(_("Save Preferences"))
+            msgbox.setWindowIcon(QtGui.QIcon('share/save_as.png'))
+
+            bt_yes = msgbox.addButton(_('Yes'), QtWidgets.QMessageBox.YesRole)
+            bt_no = msgbox.addButton(_('No'), QtWidgets.QMessageBox.NoRole)
+
+            msgbox.setDefaultButton(bt_yes)
+            msgbox.exec_()
+            response = msgbox.clickedButton()
+
+            if response == bt_yes:
+                self.on_save_button()
+                self.inform.emit(_("[success] Defaults saved."))
+            else:
+                self.preferences_changed_flag = False
+                return
+
     def on_flipy(self):
         self.report_usage("on_flipy()")
 
@@ -8253,7 +8394,7 @@ class App(QtCore.QObject):
             'pdf': lambda fname: self.worker_task.emit({'fcn': self.pdf_tool.open_pdf, 'params': [fname]})
         }
 
-        # Open file
+        # Open recent file for files
         try:
             f = open(self.data_path + '/recent.json')
         except IOError:
@@ -8270,6 +8411,23 @@ class App(QtCore.QObject):
             return
         f.close()
 
+        # Open recent file for projects
+        try:
+            fp = open(self.data_path + '/recent_projects.json')
+        except IOError:
+            App.log.error("Failed to load recent project item list.")
+            self.inform.emit(_("[ERROR_NOTCL] Failed to load recent projects item list."))
+            return
+
+        try:
+            self.recent_projects = json.load(fp)
+        except json.scanner.JSONDecodeError:
+            App.log.error("Failed to parse recent project item list.")
+            self.inform.emit(_("[ERROR_NOTCL] Failed to parse recent project item list."))
+            fp.close()
+            return
+        fp.close()
+
         # Closure needed to create callbacks in a loop.
         # Otherwise late binding occurs.
         def make_callback(func, fname):
@@ -8277,7 +8435,7 @@ class App(QtCore.QObject):
                 func(fname)
             return opener
 
-        def reset_recent():
+        def reset_recent_files():
             # Reset menu
             self.ui.recent.clear()
             self.recent = []
@@ -8289,18 +8447,25 @@ class App(QtCore.QObject):
 
             json.dump(self.recent, f)
 
+        def reset_recent_projects():
+            # Reset menu
+            self.ui.recent_projects.clear()
+            self.recent_projects = []
+
+            try:
+                fp = open(self.data_path + '/recent_projects.json', 'w')
+            except IOError:
+                App.log.error("Failed to open recent projects items file for writing.")
+                return
+
+            json.dump(self.recent, fp)
+
         # Reset menu
         self.ui.recent.clear()
+        self.ui.recent_projects.clear()
 
-        # Create menu items
-        # First add tbe projects
-        # Title
-        action = QtWidgets.QAction("Recent Projects", self)
-        myFont = QtGui.QFont()
-        myFont.setBold(True)
-        action.setFont(myFont)
-        self.ui.recent.addAction(action)
-        for recent in self.recent:
+        # Create menu items for projects
+        for recent in self.recent_projects:
             filename = recent['filename'].split('/')[-1].split('\\')[-1]
 
             if recent['kind'] == 'project':
@@ -8311,21 +8476,18 @@ class App(QtCore.QObject):
                     o = make_callback(openers[recent["kind"]], recent['filename'])
                     action.triggered.connect(o)
 
-                    self.ui.recent.addAction(action)
+                    self.ui.recent_projects.addAction(action)
 
                 except KeyError:
                     App.log.error("Unsupported file type: %s" % recent["kind"])
 
-        # Second, add a separator in the menu
-        self.ui.recent.addSeparator()
+        # Last action in Recent Files menu is one that Clear the content
+        clear_action_proj = QtWidgets.QAction(QtGui.QIcon('share/trash32.png'), (_("Clear Recent files")), self)
+        clear_action_proj.triggered.connect(reset_recent_projects)
+        self.ui.recent_projects.addSeparator()
+        self.ui.recent_projects.addAction(clear_action_proj)
 
-        # Then add tbe rest of the files
-        # Title
-        action = QtWidgets.QAction("Recent Files", self)
-        myFont = QtGui.QFont()
-        myFont.setBold(True)
-        action.setFont(myFont)
-        self.ui.recent.addAction(action)
+        # Create menu items for files
         for recent in self.recent:
             filename = recent['filename'].split('/')[-1].split('\\')[-1]
 
@@ -8344,7 +8506,7 @@ class App(QtCore.QObject):
 
         # Last action in Recent Files menu is one that Clear the content
         clear_action = QtWidgets.QAction(QtGui.QIcon('share/trash32.png'), (_("Clear Recent files")), self)
-        clear_action.triggered.connect(reset_recent)
+        clear_action.triggered.connect(reset_recent_files)
         self.ui.recent.addSeparator()
         self.ui.recent.addAction(clear_action)
 

+ 2 - 0
README.md

@@ -15,6 +15,8 @@ CAD program, and create G-Code for Isolation routing.
 - organized the list of recent files so the Project entries are to the top and separated from the other types of file
 - work on identification of changes in Preferences tab
 - added categories names for the recent files
+- added a detection if any values are changed in the Edit -> Preferences window and on close it will ask the user if he wants to save the changes or not
+- created a new menu entry in the File menu named Recent projects that will hold the recent projects and the previous "Recent files" will hold only the previous loaded files
 
 30.07.2019
 

+ 10 - 6
flatcamGUI/FlatCAMGUI.py

@@ -105,6 +105,7 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
         self.menufile_open.addAction(self.menufileopenconfig)
 
         # Recent
+        self.recent_projects = self.menufile.addMenu(QtGui.QIcon('share/recent_files.png'), _("Recent projects"))
         self.recent = self.menufile.addMenu(QtGui.QIcon('share/recent_files.png'), _("Recent files"))
 
         # Separator
@@ -756,10 +757,9 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
         self.snap_max_dist_entry.setToolTip(_("Max. magnet distance"))
         self.snap_magnet = self.snap_toolbar.addWidget(self.snap_max_dist_entry)
 
-
-        ############## ##
+        # ############# ##
         # ## Notebook # ##
-        ############## ##
+        # ############# ##
 
         # ## Project # ##
         # self.project_tab = QtWidgets.QWidget()
@@ -827,9 +827,9 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
         # remove the close button from the Plot Area tab (first tab index = 0) as this one will always be ON
         self.plot_tab_area.protectTab(0)
 
-        ###################################### ##
+        # ##################################### ##
         # ## HERE WE BUILD THE PREF. TAB AREA # ##
-        ###################################### ##
+        # ##################################### ##
         self.preferences_tab = QtWidgets.QWidget()
         self.pref_tab_layout = QtWidgets.QVBoxLayout(self.preferences_tab)
         self.pref_tab_layout.setContentsMargins(2, 2, 2, 2)
@@ -842,6 +842,7 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
         self.pref_tab_layout.addWidget(self.pref_tab_area)
 
         self.general_tab = QtWidgets.QWidget()
+        self.general_tab.setObjectName("general_tab")
         self.pref_tab_area.addTab(self.general_tab, _("General"))
         self.general_tab_lay = QtWidgets.QVBoxLayout()
         self.general_tab_lay.setContentsMargins(2, 2, 2, 2)
@@ -863,6 +864,7 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
         self.general_tab_lay.addWidget(self.general_scroll_area)
 
         self.gerber_tab = QtWidgets.QWidget()
+        self.gerber_tab.setObjectName("gerber_tab")
         self.pref_tab_area.addTab(self.gerber_tab, _("GERBER"))
         self.gerber_tab_lay = QtWidgets.QVBoxLayout()
         self.gerber_tab_lay.setContentsMargins(2, 2, 2, 2)
@@ -872,6 +874,7 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
         self.gerber_tab_lay.addWidget(self.gerber_scroll_area)
 
         self.excellon_tab = QtWidgets.QWidget()
+        self.excellon_tab.setObjectName("excellon_tab")
         self.pref_tab_area.addTab(self.excellon_tab, _("EXCELLON"))
         self.excellon_tab_lay = QtWidgets.QVBoxLayout()
         self.excellon_tab_lay.setContentsMargins(2, 2, 2, 2)
@@ -881,6 +884,7 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
         self.excellon_tab_lay.addWidget(self.excellon_scroll_area)
 
         self.geometry_tab = QtWidgets.QWidget()
+        self.geometry_tab.setObjectName("geometry_tab")
         self.pref_tab_area.addTab(self.geometry_tab, _("GEOMETRY"))
         self.geometry_tab_lay = QtWidgets.QVBoxLayout()
         self.geometry_tab_lay.setContentsMargins(2, 2, 2, 2)
@@ -2483,7 +2487,7 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
                 if key == QtCore.Qt.Key_3 or key == '3':
                     self.app.on_select_tab('tool')
 
-                if self.app.geo_editor.active_tool is not None and self.geo_select_btn.isChecked() == False:
+                if self.app.geo_editor.active_tool is not None and self.geo_select_btn.isChecked() is False:
                     response = self.app.geo_editor.active_tool.on_key(key=key)
                     if response is not None:
                         self.app.inform.emit(response)

+ 5 - 2
flatcamGUI/GUIElements.py

@@ -1350,6 +1350,7 @@ class FCDetachableTab(QtWidgets.QTabWidget):
 
 
 class FCDetachableTab2(FCDetachableTab):
+    tab_closed_signal = pyqtSignal()
 
     def __init__(self, protect=None, protect_by_name=None, parent=None):
         super(FCDetachableTab2, self).__init__(protect=protect, protect_by_name=protect_by_name, parent=parent)
@@ -1362,12 +1363,14 @@ class FCDetachableTab2(FCDetachableTab):
         :return:
         """
         idx = self.currentIndex()
+
+        # emit the signal only if the name is the one we want; the name should be a parameter somehow
         if self.tabText(idx) == _("Preferences"):
-            #TODO work on this, identify if widget changed and print a status message
-            pass
+            self.tab_closed_signal.emit()
 
         self.removeTab(currentIndex)
 
+
 class VerticalScrollArea(QtWidgets.QScrollArea):
     """
     This widget extends QtGui.QScrollArea to make a vertical-only