mirror of
https://git.mirrors.martin98.com/https://github.com/Ultimaker/Cura
synced 2025-08-12 11:49:01 +08:00
Merge branch 'bak' into 3.2
This commit is contained in:
commit
1e1f49ad53
@ -1,7 +1,6 @@
|
|||||||
# Copyright (c) 2017 Ultimaker B.V.
|
# Copyright (c) 2017 Ultimaker B.V.
|
||||||
# Cura is released under the terms of the LGPLv3 or higher.
|
# Cura is released under the terms of the LGPLv3 or higher.
|
||||||
|
|
||||||
import sys
|
|
||||||
import platform
|
import platform
|
||||||
import traceback
|
import traceback
|
||||||
import faulthandler
|
import faulthandler
|
||||||
@ -13,9 +12,11 @@ import json
|
|||||||
import ssl
|
import ssl
|
||||||
import urllib.request
|
import urllib.request
|
||||||
import urllib.error
|
import urllib.error
|
||||||
|
import shutil
|
||||||
|
import sys
|
||||||
|
|
||||||
from PyQt5.QtCore import QT_VERSION_STR, PYQT_VERSION_STR, QCoreApplication
|
from PyQt5.QtCore import QT_VERSION_STR, PYQT_VERSION_STR
|
||||||
from PyQt5.QtWidgets import QDialog, QDialogButtonBox, QVBoxLayout, QLabel, QTextEdit, QGroupBox
|
from PyQt5.QtWidgets import QDialog, QDialogButtonBox, QVBoxLayout, QLabel, QTextEdit, QGroupBox, QCheckBox, QPushButton
|
||||||
|
|
||||||
from UM.Application import Application
|
from UM.Application import Application
|
||||||
from UM.Logger import Logger
|
from UM.Logger import Logger
|
||||||
@ -49,10 +50,11 @@ fatal_exception_types = [
|
|||||||
class CrashHandler:
|
class CrashHandler:
|
||||||
crash_url = "https://stats.ultimaker.com/api/cura"
|
crash_url = "https://stats.ultimaker.com/api/cura"
|
||||||
|
|
||||||
def __init__(self, exception_type, value, tb):
|
def __init__(self, exception_type, value, tb, has_started = True):
|
||||||
self.exception_type = exception_type
|
self.exception_type = exception_type
|
||||||
self.value = value
|
self.value = value
|
||||||
self.traceback = tb
|
self.traceback = tb
|
||||||
|
self.has_started = has_started
|
||||||
self.dialog = None # Don't create a QDialog before there is a QApplication
|
self.dialog = None # Don't create a QDialog before there is a QApplication
|
||||||
|
|
||||||
# While we create the GUI, the information will be stored for sending afterwards
|
# While we create the GUI, the information will be stored for sending afterwards
|
||||||
@ -64,21 +66,130 @@ class CrashHandler:
|
|||||||
for part in line.rstrip("\n").split("\n"):
|
for part in line.rstrip("\n").split("\n"):
|
||||||
Logger.log("c", part)
|
Logger.log("c", part)
|
||||||
|
|
||||||
if not CuraDebugMode and exception_type not in fatal_exception_types:
|
# If Cura has fully started, we only show fatal errors.
|
||||||
|
# If Cura has not fully started yet, we always show the early crash dialog. Otherwise, Cura will just crash
|
||||||
|
# without any information.
|
||||||
|
if has_started and exception_type not in fatal_exception_types:
|
||||||
return
|
return
|
||||||
|
|
||||||
application = QCoreApplication.instance()
|
if not has_started:
|
||||||
if not application:
|
self._send_report_checkbox = None
|
||||||
sys.exit(1)
|
self.early_crash_dialog = self._createEarlyCrashDialog()
|
||||||
|
|
||||||
self.dialog = QDialog()
|
self.dialog = QDialog()
|
||||||
self._createDialog()
|
self._createDialog()
|
||||||
|
|
||||||
|
def _createEarlyCrashDialog(self):
|
||||||
|
dialog = QDialog()
|
||||||
|
dialog.setMinimumWidth(500)
|
||||||
|
dialog.setMinimumHeight(170)
|
||||||
|
dialog.setWindowTitle(catalog.i18nc("@title:window", "Cura Crashed"))
|
||||||
|
dialog.finished.connect(self._closeEarlyCrashDialog)
|
||||||
|
|
||||||
|
layout = QVBoxLayout(dialog)
|
||||||
|
|
||||||
|
label = QLabel()
|
||||||
|
label.setText(catalog.i18nc("@label crash message", """<p><b>A fatal error has occurred.</p></b>
|
||||||
|
<p>Unfortunately, Cura encountered an unrecoverable error during start up. It was possibly caused by some incorrect configuration files. We suggest to backup and reset your configuration.</p>
|
||||||
|
<p>Please send us this Crash Report to fix the problem.</p>
|
||||||
|
"""))
|
||||||
|
label.setWordWrap(True)
|
||||||
|
layout.addWidget(label)
|
||||||
|
|
||||||
|
# "send report" check box and show details
|
||||||
|
self._send_report_checkbox = QCheckBox(catalog.i18nc("@action:button", "Send crash report to Ultimaker"), dialog)
|
||||||
|
self._send_report_checkbox.setChecked(True)
|
||||||
|
|
||||||
|
show_details_button = QPushButton(catalog.i18nc("@action:button", "Show detailed crash report"), dialog)
|
||||||
|
show_details_button.setMaximumWidth(200)
|
||||||
|
show_details_button.clicked.connect(self._showDetailedReport)
|
||||||
|
|
||||||
|
layout.addWidget(self._send_report_checkbox)
|
||||||
|
layout.addWidget(show_details_button)
|
||||||
|
|
||||||
|
# "backup and start clean" and "close" buttons
|
||||||
|
buttons = QDialogButtonBox()
|
||||||
|
buttons.addButton(QDialogButtonBox.Close)
|
||||||
|
buttons.addButton(catalog.i18nc("@action:button", "Backup and Reset Configuration"), QDialogButtonBox.AcceptRole)
|
||||||
|
buttons.rejected.connect(self._closeEarlyCrashDialog)
|
||||||
|
buttons.accepted.connect(self._backupAndStartClean)
|
||||||
|
|
||||||
|
layout.addWidget(buttons)
|
||||||
|
|
||||||
|
return dialog
|
||||||
|
|
||||||
|
def _closeEarlyCrashDialog(self):
|
||||||
|
if self._send_report_checkbox.isChecked():
|
||||||
|
self._sendCrashReport()
|
||||||
|
os._exit(1)
|
||||||
|
|
||||||
|
def _backupAndStartClean(self):
|
||||||
|
# backup the current cura directories and create clean ones
|
||||||
|
from cura.CuraVersion import CuraVersion
|
||||||
|
from UM.Resources import Resources
|
||||||
|
# The early crash may happen before those information is set in Resources, so we need to set them here to
|
||||||
|
# make sure that Resources can find the correct place.
|
||||||
|
Resources.ApplicationIdentifier = "cura"
|
||||||
|
Resources.ApplicationVersion = CuraVersion
|
||||||
|
config_path = Resources.getConfigStoragePath()
|
||||||
|
data_path = Resources.getDataStoragePath()
|
||||||
|
cache_path = Resources.getCacheStoragePath()
|
||||||
|
|
||||||
|
folders_to_backup = []
|
||||||
|
folders_to_remove = [] # only cache folder needs to be removed
|
||||||
|
|
||||||
|
folders_to_backup.append(config_path)
|
||||||
|
if data_path != config_path:
|
||||||
|
folders_to_backup.append(data_path)
|
||||||
|
|
||||||
|
# Only remove the cache folder if it's not the same as data or config
|
||||||
|
if cache_path not in (config_path, data_path):
|
||||||
|
folders_to_remove.append(cache_path)
|
||||||
|
|
||||||
|
for folder in folders_to_remove:
|
||||||
|
shutil.rmtree(folder, ignore_errors = True)
|
||||||
|
for folder in folders_to_backup:
|
||||||
|
base_name = os.path.basename(folder)
|
||||||
|
root_dir = os.path.dirname(folder)
|
||||||
|
|
||||||
|
import datetime
|
||||||
|
date_now = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
|
||||||
|
idx = 0
|
||||||
|
file_name = base_name + "_" + date_now
|
||||||
|
zip_file_path = os.path.join(root_dir, file_name + ".zip")
|
||||||
|
while os.path.exists(zip_file_path):
|
||||||
|
idx += 1
|
||||||
|
file_name = base_name + "_" + date_now + "_" + idx
|
||||||
|
zip_file_path = os.path.join(root_dir, file_name + ".zip")
|
||||||
|
try:
|
||||||
|
# remove the .zip extension because make_archive() adds it
|
||||||
|
zip_file_path = zip_file_path[:-4]
|
||||||
|
shutil.make_archive(zip_file_path, "zip", root_dir = root_dir, base_dir = base_name)
|
||||||
|
|
||||||
|
# remove the folder only when the backup is successful
|
||||||
|
shutil.rmtree(folder, ignore_errors = True)
|
||||||
|
# create an empty folder so Resources will not try to copy the old ones
|
||||||
|
os.makedirs(folder, 0o0755, exist_ok=True)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
Logger.logException("e", "Failed to backup [%s] to file [%s]", folder, zip_file_path)
|
||||||
|
if not self.has_started:
|
||||||
|
print("Failed to backup [%s] to file [%s]: %s", folder, zip_file_path, e)
|
||||||
|
|
||||||
|
self.early_crash_dialog.close()
|
||||||
|
|
||||||
|
def _showDetailedReport(self):
|
||||||
|
self.dialog.exec_()
|
||||||
|
|
||||||
## Creates a modal dialog.
|
## Creates a modal dialog.
|
||||||
def _createDialog(self):
|
def _createDialog(self):
|
||||||
self.dialog.setMinimumWidth(640)
|
self.dialog.setMinimumWidth(640)
|
||||||
self.dialog.setMinimumHeight(640)
|
self.dialog.setMinimumHeight(640)
|
||||||
self.dialog.setWindowTitle(catalog.i18nc("@title:window", "Crash Report"))
|
self.dialog.setWindowTitle(catalog.i18nc("@title:window", "Crash Report"))
|
||||||
|
# if the application has not fully started, this will be a detailed report dialog which should not
|
||||||
|
# close the application when it's closed.
|
||||||
|
if self.has_started:
|
||||||
|
self.dialog.finished.connect(self._close)
|
||||||
|
|
||||||
layout = QVBoxLayout(self.dialog)
|
layout = QVBoxLayout(self.dialog)
|
||||||
|
|
||||||
@ -89,6 +200,9 @@ class CrashHandler:
|
|||||||
layout.addWidget(self._userDescriptionWidget())
|
layout.addWidget(self._userDescriptionWidget())
|
||||||
layout.addWidget(self._buttonsWidget())
|
layout.addWidget(self._buttonsWidget())
|
||||||
|
|
||||||
|
def _close(self):
|
||||||
|
os._exit(1)
|
||||||
|
|
||||||
def _messageWidget(self):
|
def _messageWidget(self):
|
||||||
label = QLabel()
|
label = QLabel()
|
||||||
label.setText(catalog.i18nc("@label crash message", """<p><b>A fatal error has occurred. Please send us this Crash Report to fix the problem</p></b>
|
label.setText(catalog.i18nc("@label crash message", """<p><b>A fatal error has occurred. Please send us this Crash Report to fix the problem</p></b>
|
||||||
@ -249,9 +363,13 @@ class CrashHandler:
|
|||||||
def _buttonsWidget(self):
|
def _buttonsWidget(self):
|
||||||
buttons = QDialogButtonBox()
|
buttons = QDialogButtonBox()
|
||||||
buttons.addButton(QDialogButtonBox.Close)
|
buttons.addButton(QDialogButtonBox.Close)
|
||||||
buttons.addButton(catalog.i18nc("@action:button", "Send report"), QDialogButtonBox.AcceptRole)
|
# Like above, this will be served as a separate detailed report dialog if the application has not yet been
|
||||||
|
# fully loaded. In this case, "send report" will be a check box in the early crash dialog, so there is no
|
||||||
|
# need for this extra button.
|
||||||
|
if self.has_started:
|
||||||
|
buttons.addButton(catalog.i18nc("@action:button", "Send report"), QDialogButtonBox.AcceptRole)
|
||||||
|
buttons.accepted.connect(self._sendCrashReport)
|
||||||
buttons.rejected.connect(self.dialog.close)
|
buttons.rejected.connect(self.dialog.close)
|
||||||
buttons.accepted.connect(self._sendCrashReport)
|
|
||||||
|
|
||||||
return buttons
|
return buttons
|
||||||
|
|
||||||
@ -269,15 +387,23 @@ class CrashHandler:
|
|||||||
kwoptions["context"] = ssl._create_unverified_context()
|
kwoptions["context"] = ssl._create_unverified_context()
|
||||||
|
|
||||||
Logger.log("i", "Sending crash report info to [%s]...", self.crash_url)
|
Logger.log("i", "Sending crash report info to [%s]...", self.crash_url)
|
||||||
|
if not self.has_started:
|
||||||
|
print("Sending crash report info to [%s]...\n" % self.crash_url)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
f = urllib.request.urlopen(self.crash_url, **kwoptions)
|
f = urllib.request.urlopen(self.crash_url, **kwoptions)
|
||||||
Logger.log("i", "Sent crash report info.")
|
Logger.log("i", "Sent crash report info.")
|
||||||
|
if not self.has_started:
|
||||||
|
print("Sent crash report info.\n")
|
||||||
f.close()
|
f.close()
|
||||||
except urllib.error.HTTPError:
|
except urllib.error.HTTPError as e:
|
||||||
Logger.logException("e", "An HTTP error occurred while trying to send crash report")
|
Logger.logException("e", "An HTTP error occurred while trying to send crash report")
|
||||||
except Exception: # We don't want any exception to cause problems
|
if not self.has_started:
|
||||||
|
print("An HTTP error occurred while trying to send crash report: %s" % e)
|
||||||
|
except Exception as e: # We don't want any exception to cause problems
|
||||||
Logger.logException("e", "An exception occurred while trying to send crash report")
|
Logger.logException("e", "An exception occurred while trying to send crash report")
|
||||||
|
if not self.has_started:
|
||||||
|
print("An exception occurred while trying to send crash report: %s" % e)
|
||||||
|
|
||||||
os._exit(1)
|
os._exit(1)
|
||||||
|
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
# Copyright (c) 2017 Ultimaker B.V.
|
# Copyright (c) 2017 Ultimaker B.V.
|
||||||
# Copyright (c) 2017 Ultimaker B.V.
|
|
||||||
# Cura is released under the terms of the LGPLv3 or higher.
|
# Cura is released under the terms of the LGPLv3 or higher.
|
||||||
from PyQt5.QtNetwork import QLocalServer
|
from PyQt5.QtNetwork import QLocalServer
|
||||||
from PyQt5.QtNetwork import QLocalSocket
|
from PyQt5.QtNetwork import QLocalSocket
|
||||||
@ -113,6 +112,8 @@ class CuraApplication(QtApplication):
|
|||||||
# changes of the settings.
|
# changes of the settings.
|
||||||
SettingVersion = 4
|
SettingVersion = 4
|
||||||
|
|
||||||
|
Created = False
|
||||||
|
|
||||||
class ResourceTypes:
|
class ResourceTypes:
|
||||||
QmlFiles = Resources.UserType + 1
|
QmlFiles = Resources.UserType + 1
|
||||||
Firmware = Resources.UserType + 2
|
Firmware = Resources.UserType + 2
|
||||||
@ -133,7 +134,6 @@ class CuraApplication(QtApplication):
|
|||||||
stacksValidationFinished = pyqtSignal() # Emitted whenever a validation is finished
|
stacksValidationFinished = pyqtSignal() # Emitted whenever a validation is finished
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
|
|
||||||
# this list of dir names will be used by UM to detect an old cura directory
|
# this list of dir names will be used by UM to detect an old cura directory
|
||||||
for dir_name in ["extruders", "machine_instances", "materials", "plugins", "quality", "user", "variants"]:
|
for dir_name in ["extruders", "machine_instances", "materials", "plugins", "quality", "user", "variants"]:
|
||||||
Resources.addExpectedDirNameInData(dir_name)
|
Resources.addExpectedDirNameInData(dir_name)
|
||||||
@ -223,6 +223,10 @@ class CuraApplication(QtApplication):
|
|||||||
tray_icon_name = "cura-icon-32.png",
|
tray_icon_name = "cura-icon-32.png",
|
||||||
**kwargs)
|
**kwargs)
|
||||||
|
|
||||||
|
# FOR TESTING ONLY
|
||||||
|
if kwargs["parsed_command_line"].get("trigger_early_crash", False):
|
||||||
|
1/0
|
||||||
|
|
||||||
self.default_theme = "cura-light"
|
self.default_theme = "cura-light"
|
||||||
|
|
||||||
self.setWindowIcon(QIcon(Resources.getPath(Resources.Images, "cura-icon.png")))
|
self.setWindowIcon(QIcon(Resources.getPath(Resources.Images, "cura-icon.png")))
|
||||||
@ -256,7 +260,7 @@ class CuraApplication(QtApplication):
|
|||||||
self._center_after_select = False
|
self._center_after_select = False
|
||||||
self._camera_animation = None
|
self._camera_animation = None
|
||||||
self._cura_actions = None
|
self._cura_actions = None
|
||||||
self._started = False
|
self.started = False
|
||||||
|
|
||||||
self._message_box_callback = None
|
self._message_box_callback = None
|
||||||
self._message_box_callback_arguments = []
|
self._message_box_callback_arguments = []
|
||||||
@ -409,6 +413,8 @@ class CuraApplication(QtApplication):
|
|||||||
|
|
||||||
self.getCuraSceneController().setActiveBuildPlate(0) # Initialize
|
self.getCuraSceneController().setActiveBuildPlate(0) # Initialize
|
||||||
|
|
||||||
|
CuraApplication.Created = True
|
||||||
|
|
||||||
def _onEngineCreated(self):
|
def _onEngineCreated(self):
|
||||||
self._engine.addImageProvider("camera", CameraImageProvider.CameraImageProvider())
|
self._engine.addImageProvider("camera", CameraImageProvider.CameraImageProvider())
|
||||||
|
|
||||||
@ -503,7 +509,7 @@ class CuraApplication(QtApplication):
|
|||||||
#
|
#
|
||||||
# Note that the AutoSave plugin also calls this method.
|
# Note that the AutoSave plugin also calls this method.
|
||||||
def saveSettings(self):
|
def saveSettings(self):
|
||||||
if not self._started: # Do not do saving during application start
|
if not self.started: # Do not do saving during application start
|
||||||
return
|
return
|
||||||
|
|
||||||
ContainerRegistry.getInstance().saveDirtyContainers()
|
ContainerRegistry.getInstance().saveDirtyContainers()
|
||||||
@ -732,7 +738,7 @@ class CuraApplication(QtApplication):
|
|||||||
for file_name in self._open_file_queue: #Open all the files that were queued up while plug-ins were loading.
|
for file_name in self._open_file_queue: #Open all the files that were queued up while plug-ins were loading.
|
||||||
self._openFile(file_name)
|
self._openFile(file_name)
|
||||||
|
|
||||||
self._started = True
|
self.started = True
|
||||||
|
|
||||||
self.exec_()
|
self.exec_()
|
||||||
|
|
||||||
|
49
cura_app.py
49
cura_app.py
@ -16,6 +16,12 @@ parser.add_argument('--debug',
|
|||||||
default = False,
|
default = False,
|
||||||
help = "Turn on the debug mode by setting this option."
|
help = "Turn on the debug mode by setting this option."
|
||||||
)
|
)
|
||||||
|
parser.add_argument('--trigger-early-crash',
|
||||||
|
dest = 'trigger_early_crash',
|
||||||
|
action = 'store_true',
|
||||||
|
default = False,
|
||||||
|
help = "FOR TESTING ONLY. Trigger an early crash to show the crash dialog."
|
||||||
|
)
|
||||||
known_args = vars(parser.parse_known_args()[0])
|
known_args = vars(parser.parse_known_args()[0])
|
||||||
|
|
||||||
if not known_args["debug"]:
|
if not known_args["debug"]:
|
||||||
@ -26,7 +32,7 @@ if not known_args["debug"]:
|
|||||||
return os.path.expanduser("~/.local/share/cura")
|
return os.path.expanduser("~/.local/share/cura")
|
||||||
elif Platform.isOSX():
|
elif Platform.isOSX():
|
||||||
return os.path.expanduser("~/Library/Logs/cura")
|
return os.path.expanduser("~/Library/Logs/cura")
|
||||||
|
|
||||||
if hasattr(sys, "frozen"):
|
if hasattr(sys, "frozen"):
|
||||||
dirpath = get_cura_dir_path()
|
dirpath = get_cura_dir_path()
|
||||||
os.makedirs(dirpath, exist_ok = True)
|
os.makedirs(dirpath, exist_ok = True)
|
||||||
@ -71,8 +77,45 @@ if "PYTHONPATH" in os.environ.keys(): # If PYTHONPATH is u
|
|||||||
|
|
||||||
def exceptHook(hook_type, value, traceback):
|
def exceptHook(hook_type, value, traceback):
|
||||||
from cura.CrashHandler import CrashHandler
|
from cura.CrashHandler import CrashHandler
|
||||||
_crash_handler = CrashHandler(hook_type, value, traceback)
|
from cura.CuraApplication import CuraApplication
|
||||||
_crash_handler.show()
|
has_started = False
|
||||||
|
if CuraApplication.Created:
|
||||||
|
has_started = CuraApplication.getInstance().started
|
||||||
|
|
||||||
|
#
|
||||||
|
# When the exception hook is triggered, the QApplication may not have been initialized yet. In this case, we don't
|
||||||
|
# have an QApplication to handle the event loop, which is required by the Crash Dialog.
|
||||||
|
# The flag "CuraApplication.Created" is set to True when CuraApplication finishes its constructor call.
|
||||||
|
#
|
||||||
|
# Before the "started" flag is set to True, the Qt event loop has not started yet. The event loop is a blocking
|
||||||
|
# call to the QApplication.exec_(). In this case, we need to:
|
||||||
|
# 1. Remove all scheduled events so no more unnecessary events will be processed, such as loading the main dialog,
|
||||||
|
# loading the machine, etc.
|
||||||
|
# 2. Start the Qt event loop with exec_() and show the Crash Dialog.
|
||||||
|
#
|
||||||
|
# If the application has finished its initialization and was running fine, and then something causes a crash,
|
||||||
|
# we run the old routine to show the Crash Dialog.
|
||||||
|
#
|
||||||
|
from PyQt5.Qt import QApplication
|
||||||
|
if CuraApplication.Created:
|
||||||
|
_crash_handler = CrashHandler(hook_type, value, traceback, has_started)
|
||||||
|
if CuraApplication.splash is not None:
|
||||||
|
CuraApplication.splash.close()
|
||||||
|
if not has_started:
|
||||||
|
CuraApplication.getInstance().removePostedEvents(None)
|
||||||
|
_crash_handler.early_crash_dialog.show()
|
||||||
|
sys.exit(CuraApplication.getInstance().exec_())
|
||||||
|
else:
|
||||||
|
_crash_handler.show()
|
||||||
|
else:
|
||||||
|
application = QApplication(sys.argv)
|
||||||
|
application.removePostedEvents(None)
|
||||||
|
_crash_handler = CrashHandler(hook_type, value, traceback, has_started)
|
||||||
|
# This means the QtApplication could be created and so the splash screen. Then Cura closes it
|
||||||
|
if CuraApplication.splash is not None:
|
||||||
|
CuraApplication.splash.close()
|
||||||
|
_crash_handler.early_crash_dialog.show()
|
||||||
|
sys.exit(application.exec_())
|
||||||
|
|
||||||
if not known_args["debug"]:
|
if not known_args["debug"]:
|
||||||
sys.excepthook = exceptHook
|
sys.excepthook = exceptHook
|
||||||
|
@ -9,6 +9,7 @@ from UM.Application import Application
|
|||||||
from UM.Resources import Resources
|
from UM.Resources import Resources
|
||||||
from UM.Logger import Logger
|
from UM.Logger import Logger
|
||||||
|
|
||||||
|
|
||||||
class AutoSave(Extension):
|
class AutoSave(Extension):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
@ -16,18 +17,40 @@ class AutoSave(Extension):
|
|||||||
Preferences.getInstance().preferenceChanged.connect(self._triggerTimer)
|
Preferences.getInstance().preferenceChanged.connect(self._triggerTimer)
|
||||||
|
|
||||||
self._global_stack = None
|
self._global_stack = None
|
||||||
Application.getInstance().globalContainerStackChanged.connect(self._onGlobalStackChanged)
|
|
||||||
self._onGlobalStackChanged()
|
|
||||||
|
|
||||||
Preferences.getInstance().addPreference("cura/autosave_delay", 1000 * 10)
|
Preferences.getInstance().addPreference("cura/autosave_delay", 1000 * 10)
|
||||||
|
|
||||||
self._change_timer = QTimer()
|
self._change_timer = QTimer()
|
||||||
self._change_timer.setInterval(Preferences.getInstance().getValue("cura/autosave_delay"))
|
self._change_timer.setInterval(Preferences.getInstance().getValue("cura/autosave_delay"))
|
||||||
self._change_timer.setSingleShot(True)
|
self._change_timer.setSingleShot(True)
|
||||||
self._change_timer.timeout.connect(self._onTimeout)
|
|
||||||
|
|
||||||
self._saving = False
|
self._saving = False
|
||||||
|
|
||||||
|
# At this point, the Application instance has not finished its constructor call yet, so directly using something
|
||||||
|
# like Application.getInstance() is not correct. The initialisation now will only gets triggered after the
|
||||||
|
# application finishes its start up successfully.
|
||||||
|
self._init_timer = QTimer()
|
||||||
|
self._init_timer.setInterval(1000)
|
||||||
|
self._init_timer.setSingleShot(True)
|
||||||
|
self._init_timer.timeout.connect(self.initialize)
|
||||||
|
self._init_timer.start()
|
||||||
|
|
||||||
|
def initialize(self):
|
||||||
|
# only initialise if the application is created and has started
|
||||||
|
from cura.CuraApplication import CuraApplication
|
||||||
|
if not CuraApplication.Created:
|
||||||
|
self._init_timer.start()
|
||||||
|
return
|
||||||
|
if not CuraApplication.getInstance().started:
|
||||||
|
self._init_timer.start()
|
||||||
|
return
|
||||||
|
|
||||||
|
self._change_timer.timeout.connect(self._onTimeout)
|
||||||
|
Application.getInstance().globalContainerStackChanged.connect(self._onGlobalStackChanged)
|
||||||
|
self._onGlobalStackChanged()
|
||||||
|
|
||||||
|
self._triggerTimer()
|
||||||
|
|
||||||
def _triggerTimer(self, *args):
|
def _triggerTimer(self, *args):
|
||||||
if not self._saving:
|
if not self._saving:
|
||||||
self._change_timer.start()
|
self._change_timer.start()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user