- working on Gerber Editor - added the key shortcuts: wip
- made saving of the project file non-blocking and also while saving the project file, if the user tries again to close the app while project file is being saved, the app will close only after saving is complete (the project file size is non zero)
This commit is contained in:
parent
f14246ae6a
commit
8fc916b746
@ -11,6 +11,7 @@ import getopt
|
||||
import random
|
||||
import simplejson as json
|
||||
import lzma
|
||||
import threading
|
||||
|
||||
from stat import S_IREAD, S_IRGRP, S_IROTH
|
||||
import subprocess
|
||||
@ -112,12 +113,13 @@ class App(QtCore.QObject):
|
||||
manual_url = "http://flatcam.org/manual/index.html"
|
||||
video_url = "https://www.youtube.com/playlist?list=PLVvP2SYRpx-AQgNlfoxw93tXUXon7G94_"
|
||||
|
||||
should_we_quit = True
|
||||
|
||||
# this variable will hold the project status
|
||||
# if True it will mean that the project was modified and not saved
|
||||
should_we_save = False
|
||||
|
||||
# flag is True if saving action has been triggered
|
||||
save_in_progress = False
|
||||
|
||||
##################
|
||||
## Signals ##
|
||||
##################
|
||||
@ -127,6 +129,8 @@ class App(QtCore.QObject):
|
||||
# * App.info() --> Print on the status bar
|
||||
inform = QtCore.pyqtSignal(str)
|
||||
|
||||
app_quit = QtCore.pyqtSignal()
|
||||
|
||||
# General purpose background task
|
||||
worker_task = QtCore.pyqtSignal(dict)
|
||||
|
||||
@ -1224,6 +1228,7 @@ class App(QtCore.QObject):
|
||||
### Signal handling ###
|
||||
## Custom signals
|
||||
self.inform.connect(self.info)
|
||||
self.app_quit.connect(self.quit_application)
|
||||
self.message.connect(self.message_dialog)
|
||||
self.progress.connect(self.set_progress_bar)
|
||||
self.object_created.connect(self.on_object_created)
|
||||
@ -3164,6 +3169,11 @@ class App(QtCore.QObject):
|
||||
self.inform.emit(_("Factory defaults saved."))
|
||||
|
||||
def final_save(self):
|
||||
|
||||
if self.save_in_progress:
|
||||
self.inform.emit(_("Application is saving the project. Please wait ..."))
|
||||
return
|
||||
|
||||
if self.should_we_save and self.collection.get_list():
|
||||
msgbox = QtWidgets.QMessageBox()
|
||||
msgbox.setText(_("There are files/objects modified in FlatCAM. "
|
||||
@ -3178,11 +3188,15 @@ class App(QtCore.QObject):
|
||||
response = msgbox.exec_()
|
||||
|
||||
if response == QtWidgets.QMessageBox.Yes:
|
||||
self.on_file_saveprojectas(thread=False)
|
||||
self.on_file_saveprojectas(thread=True, quit=True)
|
||||
elif response == QtWidgets.QMessageBox.No:
|
||||
QtWidgets.qApp.quit()
|
||||
elif response == QtWidgets.QMessageBox.Cancel:
|
||||
self.should_we_quit = False
|
||||
return
|
||||
else:
|
||||
QtWidgets.qApp.quit()
|
||||
|
||||
def quit_application(self):
|
||||
self.save_defaults()
|
||||
log.debug("App.final_save() --> App Defaults saved.")
|
||||
|
||||
@ -6218,7 +6232,7 @@ class App(QtCore.QObject):
|
||||
|
||||
self.should_we_save = False
|
||||
|
||||
def on_file_saveprojectas(self, make_copy=False, thread=True):
|
||||
def on_file_saveprojectas(self, make_copy=False, thread=True, quit=False):
|
||||
"""
|
||||
Callback for menu item File->Save Project As... Opens a file
|
||||
chooser and saves the project to the given file via
|
||||
@ -6253,9 +6267,9 @@ class App(QtCore.QObject):
|
||||
|
||||
if thread is True:
|
||||
self.worker_task.emit({'fcn': self.save_project,
|
||||
'params': [filename]})
|
||||
'params': [filename, quit]})
|
||||
else:
|
||||
self.save_project(filename)
|
||||
self.save_project(filename, quit)
|
||||
|
||||
# self.save_project(filename)
|
||||
self.file_opened.emit("project", filename)
|
||||
@ -7861,7 +7875,7 @@ The normal flow when working in FlatCAM is the following:</span></p>
|
||||
for obj in objects:
|
||||
obj.on_generatecnc_button_click()
|
||||
|
||||
def save_project(self, filename):
|
||||
def save_project(self, filename, quit=False):
|
||||
"""
|
||||
Saves the current project to the specified file.
|
||||
|
||||
@ -7871,6 +7885,8 @@ The normal flow when working in FlatCAM is the following:</span></p>
|
||||
"""
|
||||
self.log.debug("save_project()")
|
||||
|
||||
self.save_in_progress = True
|
||||
|
||||
with self.proc_container.new(_("Saving FlatCAM Project")) as proc:
|
||||
## Capture the latest changes
|
||||
# Current object
|
||||
@ -7927,6 +7943,27 @@ The normal flow when working in FlatCAM is the following:</span></p>
|
||||
else:
|
||||
self.inform.emit(_("[ERROR_NOTCL] Failed to save project file: %s. Retry to save it.") % filename)
|
||||
|
||||
if quit:
|
||||
t = threading.Thread(target=lambda: self.check_project_file_size(1, filename=filename))
|
||||
t.start()
|
||||
|
||||
# using Alfe's answer from here:
|
||||
# https://stackoverflow.com/questions/474528/what-is-the-best-way-to-repeatedly-execute-a-function-every-x-seconds-in-python
|
||||
def check_project_file_size(self, delay, filename):
|
||||
next_time = time.time() + delay
|
||||
while True:
|
||||
time.sleep(max(0, next_time - time.time()))
|
||||
try:
|
||||
statinfo = os.stat(filename)
|
||||
if statinfo:
|
||||
self.app_quit.emit()
|
||||
except Exception:
|
||||
traceback.print_exc()
|
||||
# in production code you might want to have this instead of course:
|
||||
# logger.exception("Problem while executing repetitive task.")
|
||||
# skip tasks if we are behind schedule:
|
||||
next_time += (time.time() - next_time) // delay * delay + delay
|
||||
|
||||
def on_options_app2project(self):
|
||||
"""
|
||||
Callback for Options->Transfer Options->App=>Project. Copies options
|
||||
|
@ -14,7 +14,9 @@ CAD program, and create G-Code for Isolation routing.
|
||||
- fixed plotting in Gerber Editor
|
||||
- working on GUI in Gerber Editor
|
||||
- added a Gcode end_command: default is M02
|
||||
- modified the calling of the editor2object() slot function
|
||||
- modified the calling of the editor2object() slot function to fix an issue with updating geometry imported from SVG file, after edut
|
||||
- working on Gerber Editor - added the key shortcuts: wip
|
||||
- made saving of the project file non-blocking and also while saving the project file, if the user tries again to close the app while project file is being saved, the app will close only after saving is complete (the project file size is non zero)
|
||||
|
||||
31.03.2019
|
||||
|
||||
|
@ -1365,7 +1365,7 @@ class FlatCAMGrbEditor(QtCore.QObject):
|
||||
else:
|
||||
self.edited_obj_name += "_edit"
|
||||
|
||||
self.app.worker_task.emit({'fcn': self.new_edited_excellon,
|
||||
self.app.worker_task.emit({'fcn': self.new_edited_gerber,
|
||||
'params': [self.edited_obj_name]})
|
||||
|
||||
if self.gerber_obj.slots:
|
||||
@ -1403,7 +1403,7 @@ class FlatCAMGrbEditor(QtCore.QObject):
|
||||
obj.options = {}
|
||||
return True
|
||||
|
||||
def new_edited_excellon(self, outname):
|
||||
def new_edited_gerber(self, outname):
|
||||
"""
|
||||
Creates a new Excellon object for the edited Excellon. Thread-safe.
|
||||
|
||||
|
@ -2383,6 +2383,177 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
|
||||
# Show Shortcut list
|
||||
if key == 'F3':
|
||||
self.app.on_shortcut_list()
|
||||
elif self.app.call_source == 'grb_editor':
|
||||
if modifiers == QtCore.Qt.ControlModifier:
|
||||
# save (update) the current geometry and return to the App
|
||||
if key == QtCore.Qt.Key_S or key == 'S':
|
||||
self.app.editor2object()
|
||||
return
|
||||
|
||||
# toggle the measurement tool
|
||||
if key == QtCore.Qt.Key_M or key == 'M':
|
||||
self.app.measurement_tool.run()
|
||||
return
|
||||
|
||||
elif modifiers == QtCore.Qt.ShiftModifier:
|
||||
pass
|
||||
elif modifiers == QtCore.Qt.AltModifier:
|
||||
pass
|
||||
elif modifiers == QtCore.Qt.NoModifier:
|
||||
# Abort the current action
|
||||
if key == QtCore.Qt.Key_Escape or key == 'Escape':
|
||||
# self.on_tool_select("select")
|
||||
self.app.inform.emit(_("[WARNING_NOTCL] Cancelled."))
|
||||
|
||||
self.app.grb_editor.delete_utility_geometry()
|
||||
|
||||
self.app.grb_editor.replot()
|
||||
# self.select_btn.setChecked(True)
|
||||
# self.on_tool_select('select')
|
||||
self.app.grb_editor.select_tool('select')
|
||||
return
|
||||
|
||||
# Delete selected object if delete key event comes out of canvas
|
||||
if key == 'Delete':
|
||||
self.app.grb_editor.launched_from_shortcuts = True
|
||||
if self.app.grb_editor.selected:
|
||||
self.app.grb_editor.delete_selected()
|
||||
self.app.grb_editor.replot()
|
||||
else:
|
||||
self.app.inform.emit(_("[WARNING_NOTCL] Cancelled. Nothing selected to delete."))
|
||||
return
|
||||
|
||||
# Delete aperture in apertures table if delete key event comes from the Selected Tab
|
||||
if key == QtCore.Qt.Key_Delete:
|
||||
self.app.grb_editor.launched_from_shortcuts = True
|
||||
self.app.grb_editor.on_tool_delete()
|
||||
return
|
||||
|
||||
if key == QtCore.Qt.Key_Minus or key == '-':
|
||||
self.app.grb_editor.launched_from_shortcuts = True
|
||||
self.app.plotcanvas.zoom(1 / self.app.defaults['zoom_ratio'],
|
||||
[self.app.grb_editor.snap_x, self.app.grb_editor.snap_y])
|
||||
return
|
||||
|
||||
if key == QtCore.Qt.Key_Equal or key == '=':
|
||||
self.app.grb_editor.launched_from_shortcuts = True
|
||||
self.app.plotcanvas.zoom(self.app.defaults['zoom_ratio'],
|
||||
[self.app.grb_editor.snap_x, self.app.grb_editor.snap_y])
|
||||
return
|
||||
|
||||
# toggle display of Notebook area
|
||||
if key == QtCore.Qt.Key_QuoteLeft or key == '`':
|
||||
self.app.grb_editor.launched_from_shortcuts = True
|
||||
self.app.on_toggle_notebook()
|
||||
return
|
||||
|
||||
# Switch to Project Tab
|
||||
if key == QtCore.Qt.Key_1 or key == '1':
|
||||
self.app.grb_editor.launched_from_shortcuts = True
|
||||
self.app.on_select_tab('project')
|
||||
return
|
||||
|
||||
# Switch to Selected Tab
|
||||
if key == QtCore.Qt.Key_2 or key == '2':
|
||||
self.app.grb_editor.launched_from_shortcuts = True
|
||||
self.app.on_select_tab('selected')
|
||||
return
|
||||
|
||||
# Switch to Tool Tab
|
||||
if key == QtCore.Qt.Key_3 or key == '3':
|
||||
self.app.grb_editor.launched_from_shortcuts = True
|
||||
self.app.on_select_tab('tool')
|
||||
return
|
||||
|
||||
# Copy
|
||||
if key == QtCore.Qt.Key_C or key == 'C':
|
||||
self.app.grb_editor.launched_from_shortcuts = True
|
||||
if self.app.grb_editor.selected:
|
||||
self.app.inform.emit(_("Click on target point."))
|
||||
self.app.ui.copy_aperture_btn.setChecked(True)
|
||||
self.app.grb_editor.on_tool_select('aperture_copy')
|
||||
self.app.grb_editor.active_tool.set_origin(
|
||||
(self.app.grb_editor.snap_x, self.app.grb_editor.snap_y))
|
||||
else:
|
||||
self.app.inform.emit(_("[WARNING_NOTCL] Cancelled. Nothing selected to copy."))
|
||||
return
|
||||
|
||||
# Add Aperture Tool
|
||||
if key == QtCore.Qt.Key_A or key == 'A':
|
||||
self.app.grb_editor.launched_from_shortcuts = True
|
||||
self.app.inform.emit(_("Click on target point."))
|
||||
self.app.ui.add_aperture_btn.setChecked(True)
|
||||
|
||||
self.app.grb_editor.x = self.app.mouse[0]
|
||||
self.app.grb_editor.y = self.app.mouse[1]
|
||||
|
||||
self.app.grb_editor.select_tool('aperture_add')
|
||||
return
|
||||
|
||||
# Grid Snap
|
||||
if key == QtCore.Qt.Key_G or key == 'G':
|
||||
self.app.grb_editor.launched_from_shortcuts = True
|
||||
# make sure that the cursor shape is enabled/disabled, too
|
||||
if self.app.grb_editor.options['grid_snap'] is True:
|
||||
self.app.app_cursor.enabled = False
|
||||
else:
|
||||
self.app.app_cursor.enabled = True
|
||||
self.app.ui.grid_snap_btn.trigger()
|
||||
return
|
||||
|
||||
# Jump to coords
|
||||
if key == QtCore.Qt.Key_J or key == 'J':
|
||||
self.app.on_jump_to()
|
||||
|
||||
# Corner Snap
|
||||
if key == QtCore.Qt.Key_K or key == 'K':
|
||||
self.app.grb_editor.launched_from_shortcuts = True
|
||||
self.app.ui.corner_snap_btn.trigger()
|
||||
return
|
||||
|
||||
# Move
|
||||
if key == QtCore.Qt.Key_M or key == 'M':
|
||||
self.app.grb_editor.launched_from_shortcuts = True
|
||||
if self.app.grb_editor.selected:
|
||||
self.app.inform.emit(_("Click on target point."))
|
||||
self.app.ui.move_aperture_btn.setChecked(True)
|
||||
self.app.exc_editor.on_tool_select('aperture_move')
|
||||
self.app.grb_editor.active_tool.set_origin(
|
||||
(self.app.grb_editor.snap_x, self.app.grb_editor.snap_y))
|
||||
else:
|
||||
self.app.inform.emit(_("[WARNING_NOTCL] Cancelled. Nothing selected to move."))
|
||||
return
|
||||
|
||||
# Resize Tool
|
||||
if key == QtCore.Qt.Key_R or key == 'R':
|
||||
self.app.grb_editor.launched_from_shortcuts = True
|
||||
self.app.grb_editor.select_tool('drill_resize')
|
||||
return
|
||||
|
||||
# Add Track
|
||||
if key == QtCore.Qt.Key_T or key == 'T':
|
||||
self.app.grb_editor.launched_from_shortcuts = True
|
||||
## Current application units in Upper Case
|
||||
self.units = self.general_defaults_group.general_app_group.units_radio.get_value().upper()
|
||||
return
|
||||
|
||||
# Zoom Fit
|
||||
if key == QtCore.Qt.Key_V or key == 'V':
|
||||
self.app.grb_editor.launched_from_shortcuts = True
|
||||
self.app.on_zoom_fit(None)
|
||||
return
|
||||
|
||||
# Propagate to tool
|
||||
response = None
|
||||
if self.app.grb_editor.active_tool is not None:
|
||||
response = self.app.grb_editor.active_tool.on_key(key=key)
|
||||
if response is not None:
|
||||
self.app.inform.emit(response)
|
||||
|
||||
# Show Shortcut list
|
||||
if key == QtCore.Qt.Key_F3 or key == 'F3':
|
||||
self.app.on_shortcut_list()
|
||||
return
|
||||
elif self.app.call_source == 'exc_editor':
|
||||
if modifiers == QtCore.Qt.ControlModifier:
|
||||
# save (update) the current geometry and return to the App
|
||||
@ -2640,16 +2811,17 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
|
||||
event.ignore()
|
||||
|
||||
def closeEvent(self, event):
|
||||
grect = self.geometry()
|
||||
if self.app.save_in_progress:
|
||||
self.app.inform.emit(_("[WARNING_NOTCL] Application is saving the project. Please wait ..."))
|
||||
else:
|
||||
grect = self.geometry()
|
||||
|
||||
# self.splitter.sizes()[0] is actually the size of the "notebook"
|
||||
if not self.isMaximized():
|
||||
self.geom_update.emit(grect.x(), grect.y(), grect.width(), grect.height(), self.splitter.sizes()[0])
|
||||
# self.splitter.sizes()[0] is actually the size of the "notebook"
|
||||
if not self.isMaximized():
|
||||
self.geom_update.emit(grect.x(), grect.y(), grect.width(), grect.height(), self.splitter.sizes()[0])
|
||||
|
||||
self.final_save.emit()
|
||||
|
||||
if self.app.should_we_quit is False:
|
||||
event.ignore()
|
||||
self.final_save.emit()
|
||||
event.ignore()
|
||||
|
||||
|
||||
class GeneralPreferencesUI(QtWidgets.QWidget):
|
||||
|
Loading…
Reference in New Issue
Block a user