diff --git a/CHANGELOG.md b/CHANGELOG.md index 72d64762..ad909e0c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ CHANGELOG for FlatCAM beta ================================================= +22.04.2020 + +- added a new feature, project auto-saving controlled from Edit -> Preferences -> General -> APP. Preferences -> Enable Auto Save checkbox + 20.04.2020 - made the Grid icon in the status bar clickable and it will toggle the snap to grid function diff --git a/FlatCAMApp.py b/FlatCAMApp.py index e7d1d430..e9f4affc 100644 --- a/FlatCAMApp.py +++ b/FlatCAMApp.py @@ -437,6 +437,8 @@ class App(QtCore.QObject): "global_tpdf_bmargin": 10.0, "global_tpdf_lmargin": 20.0, "global_tpdf_rmargin": 20.0, + "global_autosave": False, + "global_autosave_timeout": 300000, # General "global_graphic_engine": '3D', @@ -1197,6 +1199,8 @@ class App(QtCore.QObject): "global_compression_level": self.ui.general_defaults_form.general_app_group.compress_spinner, "global_save_compressed": self.ui.general_defaults_form.general_app_group.save_type_cb, + "global_autosave": self.ui.general_defaults_form.general_app_group.autosave_cb, + "global_autosave_timeout": self.ui.general_defaults_form.general_app_group.autosave_entry, "global_tpdf_tmargin": self.ui.general_defaults_form.general_app_group.tmargin_entry, "global_tpdf_bmargin": self.ui.general_defaults_form.general_app_group.bmargin_entry, @@ -1956,6 +1960,15 @@ class App(QtCore.QObject): self.worker_task.connect(self.workers.add_task) self.log.debug("Finished creating Workers crew.") + # ############################################################################# + # ################################ AUTOSAVE SETUP ############################# + # ############################################################################# + + self.block_autosave = False + self.autosave_timer = QtCore.QTimer(self) + self.save_project_auto_update() + self.autosave_timer.timeout.connect(self.save_project_auto) + # ############################################################################# # ################################# Activity Monitor ########################## # ############################################################################# @@ -5161,6 +5174,9 @@ class App(QtCore.QObject): if not silent: self.inform.emit('[success] %s' % _("Preferences saved.")) + # update the autosave timer + self.save_project_auto_update() + def save_toolbar_view(self): """ Will save the toolbar view state to the defaults @@ -11651,6 +11667,9 @@ class App(QtCore.QObject): """ App.log.debug("Opening project: " + filename) + # block autosaving while a project is loaded + self.block_autosave = True + # 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) if cli is None: @@ -11739,6 +11758,9 @@ class App(QtCore.QObject): self.should_we_save = False self.file_opened.emit("project", filename) + # restore autosaving after a project was loaded + self.block_autosave = False + # 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) if cli is None: @@ -12920,8 +12942,7 @@ class App(QtCore.QObject): if silent is False: if 'version' in saved_d: - self.inform.emit('[success] %s: %s' % - (_("Project saved to"), filename)) + self.inform.emit('[success] %s: %s' % (_("Project saved to"), filename)) else: self.inform.emit('[ERROR_NOTCL] %s: %s %s' % (_("Failed to parse saved project file"), filename, _("Retry to save it."))) @@ -12969,7 +12990,36 @@ class App(QtCore.QObject): except Exception: traceback.print_exc() + def save_project_auto(self): + """ + Called periodically to save the project. + It will save if there is no block on the save, if the project was saved at least once and if there is no save in + # progress. + + :return: + """ + + if self.block_autosave is False and self.should_we_save is True and self.save_in_progress is False: + self.on_file_saveproject() + + def save_project_auto_update(self): + """ + Update the auto save time interval value. + :return: + """ + log.debug("App.save_project_auto_update() --> updated the interval timeout.") + if self.autosave_timer.isActive(): + self.autosave_timer.stop() + if self.defaults['global_autosave'] is True: + self.autosave_timer.setInterval(int(self.defaults['global_autosave_timeout'])) + self.autosave_timer.start() + def on_plotarea_tab_closed(self, tab_idx): + """ + + :param tab_idx: Index of the Tab from the plotarea that was closed + :return: + """ widget = self.ui.plot_tab_area.widget(tab_idx) if widget is not None: diff --git a/flatcamGUI/PreferencesUI.py b/flatcamGUI/PreferencesUI.py index d8659eeb..8ad23154 100644 --- a/flatcamGUI/PreferencesUI.py +++ b/flatcamGUI/PreferencesUI.py @@ -1818,16 +1818,42 @@ class GeneralAppPrefGroupUI(OptionsGroupUI): self.proj_ois = OptionalInputSection(self.save_type_cb, [self.compress_label, self.compress_spinner], True) + # Auto save CB + self.autosave_cb = FCCheckBox(_('Enable Auto Save')) + self.autosave_cb.setToolTip( + _("Check to enable the autosave feature.\n" + "When enabled, the application will try to save a project\n" + "at the set interval.") + ) + + grid0.addWidget(self.autosave_cb, 31, 0, 1, 2) + + # Auto Save Timeout Interval + self.autosave_entry = FCSpinner() + self.autosave_entry.set_range(0, 9999999) + self.autosave_label = QtWidgets.QLabel('%s:' % _('Interval')) + self.autosave_label.setToolTip( + _("Time interval for autosaving. In milliseconds.\n" + "The application will try to save periodically but only\n" + "if the project was saved manually at least once.\n" + "While active, some operations may block this feature.") + ) + + grid0.addWidget(self.autosave_label, 32, 0) + grid0.addWidget(self.autosave_entry, 32, 1) + + # self.as_ois = OptionalInputSection(self.autosave_cb, [self.autosave_label, self.autosave_entry], True) + separator_line = QtWidgets.QFrame() separator_line.setFrameShape(QtWidgets.QFrame.HLine) separator_line.setFrameShadow(QtWidgets.QFrame.Sunken) - grid0.addWidget(separator_line, 31, 0, 1, 2) + grid0.addWidget(separator_line, 33, 0, 1, 2) self.pdf_param_label = QtWidgets.QLabel('%s:' % _("Text to PDF parameters")) self.pdf_param_label.setToolTip( _("Used when saving text in Code Editor or in FlatCAM Document objects.") ) - grid0.addWidget(self.pdf_param_label, 32, 0, 1, 2) + grid0.addWidget(self.pdf_param_label, 34, 0, 1, 2) # Top Margin value self.tmargin_entry = FCDoubleSpinner() @@ -1839,8 +1865,8 @@ class GeneralAppPrefGroupUI(OptionsGroupUI): _("Distance between text body and the top of the PDF file.") ) - grid0.addWidget(self.tmargin_label, 33, 0) - grid0.addWidget(self.tmargin_entry, 33, 1) + grid0.addWidget(self.tmargin_label, 35, 0) + grid0.addWidget(self.tmargin_entry, 35, 1) # Bottom Margin value self.bmargin_entry = FCDoubleSpinner() @@ -1852,8 +1878,8 @@ class GeneralAppPrefGroupUI(OptionsGroupUI): _("Distance between text body and the bottom of the PDF file.") ) - grid0.addWidget(self.bmargin_label, 34, 0) - grid0.addWidget(self.bmargin_entry, 34, 1) + grid0.addWidget(self.bmargin_label, 36, 0) + grid0.addWidget(self.bmargin_entry, 36, 1) # Left Margin value self.lmargin_entry = FCDoubleSpinner() @@ -1865,8 +1891,8 @@ class GeneralAppPrefGroupUI(OptionsGroupUI): _("Distance between text body and the left of the PDF file.") ) - grid0.addWidget(self.lmargin_label, 35, 0) - grid0.addWidget(self.lmargin_entry, 35, 1) + grid0.addWidget(self.lmargin_label, 37, 0) + grid0.addWidget(self.lmargin_entry, 37, 1) # Right Margin value self.rmargin_entry = FCDoubleSpinner() @@ -1878,8 +1904,8 @@ class GeneralAppPrefGroupUI(OptionsGroupUI): _("Distance between text body and the right of the PDF file.") ) - grid0.addWidget(self.rmargin_label, 36, 0) - grid0.addWidget(self.rmargin_entry, 36, 1) + grid0.addWidget(self.rmargin_label, 38, 0) + grid0.addWidget(self.rmargin_entry, 38, 1) self.layout.addStretch()