From 58e18ded18e4b7508020f11f5cb9b996cf874cfb Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Mon, 16 Apr 2018 15:24:17 +0200 Subject: [PATCH 1/9] Remove unneeded code CURA-5202 --- cura/CuraApplication.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 12ccb6a5b6..c9529f8025 100755 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -501,11 +501,6 @@ class CuraApplication(QtApplication): def getStaticVersion(cls): return CuraVersion - ## Handle removing the unneeded plugins - # \sa PluginRegistry - def _removePlugins(self): - self._plugin_registry.removePlugins() - ## Handle loading of all plugin types (and the backend explicitly) # \sa PluginRegistry def _loadPlugins(self): From 62521e93db9d91d9071ac60bdb2a60e0c2e5c070 Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Mon, 16 Apr 2018 15:32:10 +0200 Subject: [PATCH 2/9] Make sure that project writer runs on Qt thread CURA-5229 - Move @call_on_qt_thread to a separate module - Make sure that project writer runs on Qt thread because itself and the calls it makes can create new QObjects such as InstanceContainers, and this must happen on the Qt thread. --- cura/Utils/Threading.py | 34 +++++++++++++++++++++ plugins/3MFReader/ThreeMFWorkspaceReader.py | 33 +------------------- plugins/3MFWriter/ThreeMFWorkspaceWriter.py | 4 ++- 3 files changed, 38 insertions(+), 33 deletions(-) create mode 100644 cura/Utils/Threading.py diff --git a/cura/Utils/Threading.py b/cura/Utils/Threading.py new file mode 100644 index 0000000000..3cd6200513 --- /dev/null +++ b/cura/Utils/Threading.py @@ -0,0 +1,34 @@ +import threading + +from cura.CuraApplication import CuraApplication + + +# +# HACK: +# +# In project loading, when override the existing machine is selected, the stacks and containers that are correctly +# active in the system will be overridden at runtime. Because the project loading is done in a different thread than +# the Qt thread, something else can kick in the middle of the process. One of them is the rendering. It will access +# the current stacks and container, which have not completely been updated yet, so Cura will crash in this case. +# +# This "@call_on_qt_thread" decorator makes sure that a function will always be called on the Qt thread (blocking). +# It is applied to the read() function of project loading so it can be guaranteed that only after the project loading +# process is completely done, everything else that needs to occupy the QT thread will be executed. +# +class InterCallObject: + def __init__(self): + self.finish_event = threading.Event() + self.result = None + + +def call_on_qt_thread(func): + def _call_on_qt_thread_wrapper(*args, **kwargs): + def _handle_call(ico, *args, **kwargs): + ico.result = func(*args, **kwargs) + ico.finish_event.set() + inter_call_object = InterCallObject() + new_args = tuple([inter_call_object] + list(args)[:]) + CuraApplication.getInstance().callLater(_handle_call, *new_args, **kwargs) + inter_call_object.finish_event.wait() + return inter_call_object.result + return _call_on_qt_thread_wrapper diff --git a/plugins/3MFReader/ThreeMFWorkspaceReader.py b/plugins/3MFReader/ThreeMFWorkspaceReader.py index 633142187c..212df59294 100755 --- a/plugins/3MFReader/ThreeMFWorkspaceReader.py +++ b/plugins/3MFReader/ThreeMFWorkspaceReader.py @@ -4,7 +4,6 @@ from configparser import ConfigParser import zipfile import os -import threading import xml.etree.ElementTree as ET @@ -27,43 +26,13 @@ from cura.Settings.ExtruderStack import ExtruderStack from cura.Settings.GlobalStack import GlobalStack from cura.Settings.CuraContainerStack import _ContainerIndexes from cura.CuraApplication import CuraApplication +from cura.Utils.Threading import call_on_qt_thread from .WorkspaceDialog import WorkspaceDialog i18n_catalog = i18nCatalog("cura") -# -# HACK: -# -# In project loading, when override the existing machine is selected, the stacks and containers that are correctly -# active in the system will be overridden at runtime. Because the project loading is done in a different thread than -# the Qt thread, something else can kick in the middle of the process. One of them is the rendering. It will access -# the current stacks and container, which have not completely been updated yet, so Cura will crash in this case. -# -# This "@call_on_qt_thread" decorator makes sure that a function will always be called on the Qt thread (blocking). -# It is applied to the read() function of project loading so it can be guaranteed that only after the project loading -# process is completely done, everything else that needs to occupy the QT thread will be executed. -# -class InterCallObject: - def __init__(self): - self.finish_event = threading.Event() - self.result = None - - -def call_on_qt_thread(func): - def _call_on_qt_thread_wrapper(*args, **kwargs): - def _handle_call(ico, *args, **kwargs): - ico.result = func(*args, **kwargs) - ico.finish_event.set() - inter_call_object = InterCallObject() - new_args = tuple([inter_call_object] + list(args)[:]) - CuraApplication.getInstance().callLater(_handle_call, *new_args, **kwargs) - inter_call_object.finish_event.wait() - return inter_call_object.result - return _call_on_qt_thread_wrapper - - class ContainerInfo: def __init__(self, file_name: str, serialized: str, parser: ConfigParser): self.file_name = file_name diff --git a/plugins/3MFWriter/ThreeMFWorkspaceWriter.py b/plugins/3MFWriter/ThreeMFWorkspaceWriter.py index 3f5e69317e..e948f62337 100644 --- a/plugins/3MFWriter/ThreeMFWorkspaceWriter.py +++ b/plugins/3MFWriter/ThreeMFWorkspaceWriter.py @@ -6,16 +6,18 @@ from io import StringIO import zipfile from UM.Application import Application -from UM.Logger import Logger from UM.Preferences import Preferences from UM.Settings.ContainerRegistry import ContainerRegistry from UM.Workspace.WorkspaceWriter import WorkspaceWriter +from cura.Utils.Threading import call_on_qt_thread + class ThreeMFWorkspaceWriter(WorkspaceWriter): def __init__(self): super().__init__() + @call_on_qt_thread def write(self, stream, nodes, mode=WorkspaceWriter.OutputMode.BinaryMode): application = Application.getInstance() machine_manager = application.getMachineManager() From 4bb69623026e058add33101fa1cc4ae789e43d6b Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Mon, 16 Apr 2018 17:20:38 +0200 Subject: [PATCH 3/9] Rename model checker property to hasWarnings CURA-5237 --- plugins/ModelChecker/ModelChecker.py | 3 +-- plugins/ModelChecker/ModelChecker.qml | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/plugins/ModelChecker/ModelChecker.py b/plugins/ModelChecker/ModelChecker.py index 65d7c2e35d..f1e2b5d3e9 100644 --- a/plugins/ModelChecker/ModelChecker.py +++ b/plugins/ModelChecker/ModelChecker.py @@ -92,9 +92,8 @@ class ModelChecker(QObject, Extension): Logger.log("d", "Model checker view created.") @pyqtProperty(bool, notify = onChanged) - def runChecks(self): + def hasWarnings(self): danger_shrinkage = self.checkObjectsForShrinkage() - return any((danger_shrinkage, )) #If any of the checks fail, show the warning button. @pyqtSlot() diff --git a/plugins/ModelChecker/ModelChecker.qml b/plugins/ModelChecker/ModelChecker.qml index 3db54d4387..98db233bf8 100644 --- a/plugins/ModelChecker/ModelChecker.qml +++ b/plugins/ModelChecker/ModelChecker.qml @@ -18,7 +18,7 @@ Button UM.I18nCatalog{id: catalog; name:"cura"} - visible: manager.runChecks + visible: manager.hasWarnings tooltip: catalog.i18nc("@info:tooltip", "Some things could be problematic in this print. Click to see tips for adjustment.") onClicked: manager.showWarnings() From e5d795cc0b31b6818e048812c35f3a810e1b1ea5 Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Mon, 16 Apr 2018 17:21:09 +0200 Subject: [PATCH 4/9] Update model checker text CURA-5237 --- plugins/ModelChecker/ModelChecker.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/plugins/ModelChecker/ModelChecker.py b/plugins/ModelChecker/ModelChecker.py index f1e2b5d3e9..c7d36e9916 100644 --- a/plugins/ModelChecker/ModelChecker.py +++ b/plugins/ModelChecker/ModelChecker.py @@ -63,11 +63,11 @@ class ModelChecker(QObject, Extension): self._caution_message.setText(catalog.i18nc( "@info:status", - "Some models may not be printed optimally due to object size and chosen material for models: {model_names}.\n" - "Tips that may be useful to improve the print quality:\n" - "1) Use rounded corners.\n" - "2) Turn the fan off (only if there are no tiny details on the model).\n" - "3) Use a different material.").format(model_names = ", ".join([n.getName() for n in warning_nodes]))) + "

One or more 3D models may not print optimally due to the model size and material configuration:

\n" + "

{model_names}

\n" + "

Find out how to ensure the best possible print quality and reliability.

\n" + "

View print quality guide

" + ).format(model_names = ", ".join([n.getName() for n in warning_nodes]))) return len(warning_nodes) > 0 From c381f3707b4e87a7518c0d16b1f3943512458f2f Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Mon, 16 Apr 2018 17:33:12 +0200 Subject: [PATCH 5/9] Schedule model check for later if a machine change has not done yet CURA-5239 --- plugins/ModelChecker/ModelChecker.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/plugins/ModelChecker/ModelChecker.py b/plugins/ModelChecker/ModelChecker.py index c7d36e9916..f85a7a249a 100644 --- a/plugins/ModelChecker/ModelChecker.py +++ b/plugins/ModelChecker/ModelChecker.py @@ -49,6 +49,13 @@ class ModelChecker(QObject, Extension): warning_size_xy = 150 #The horizontal size of a model that would be too large when dealing with shrinking materials. warning_size_z = 100 #The vertical size of a model that would be too large when dealing with shrinking materials. + # This function can be triggered in the middle of a machine change, so do not proceed if the machine change + # has not done yet. + global_container_stack = Application.getInstance().getGlobalContainerStack() + if global_container_stack is None: + Application.getInstance().callLater(lambda: self.onChanged.emit()) + return False + material_shrinkage = self._getMaterialShrinkage() warning_nodes = [] @@ -56,6 +63,13 @@ class ModelChecker(QObject, Extension): # Check node material shrinkage and bounding box size for node in self.sliceableNodes(): node_extruder_position = node.callDecoration("getActiveExtruderPosition") + + # This function can be triggered in the middle of a machine change, so do not proceed if the machine change + # has not done yet. + if str(node_extruder_position) not in global_container_stack.extruders: + Application.getInstance().callLater(lambda: self.onChanged.emit()) + return False + if material_shrinkage[node_extruder_position] > shrinkage_threshold: bbox = node.getBoundingBox() if bbox.width >= warning_size_xy or bbox.depth >= warning_size_xy or bbox.height >= warning_size_z: From b78b6b2c01103d98a5b2fc1d1a5e63343a6905e3 Mon Sep 17 00:00:00 2001 From: Mark Date: Tue, 17 Apr 2018 10:37:07 +0200 Subject: [PATCH 6/9] Change default auto_slice setting to False CURA-5188 --- plugins/CuraEngineBackend/CuraEngineBackend.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/CuraEngineBackend/CuraEngineBackend.py b/plugins/CuraEngineBackend/CuraEngineBackend.py index 314983404c..654c1024bb 100755 --- a/plugins/CuraEngineBackend/CuraEngineBackend.py +++ b/plugins/CuraEngineBackend/CuraEngineBackend.py @@ -121,7 +121,7 @@ class CuraEngineBackend(QObject, Backend): self._slice_start_time = None self._is_disabled = False - Preferences.getInstance().addPreference("general/auto_slice", True) + Preferences.getInstance().addPreference("general/auto_slice", False) self._use_timer = False # When you update a setting and other settings get changed through inheritance, many propertyChanged signals are fired. From 0f5f059a7c38796da033590cadc583099eb7a1e5 Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Tue, 17 Apr 2018 11:05:54 +0200 Subject: [PATCH 7/9] Add missing __init__.py CURA-5242 --- cura/Utils/__init__.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 cura/Utils/__init__.py diff --git a/cura/Utils/__init__.py b/cura/Utils/__init__.py new file mode 100644 index 0000000000..e69de29bb2 From a111dda82e4e5ef5695f2042a83e060733adc7e2 Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Tue, 17 Apr 2018 11:14:14 +0200 Subject: [PATCH 8/9] Revert "Custom qualities are always checkable" CURA-5218 This reverts commit fdd78077697f9e3ff9f0fe654eff8af36a1623d9. --- resources/qml/Menus/ProfileMenu.qml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/resources/qml/Menus/ProfileMenu.qml b/resources/qml/Menus/ProfileMenu.qml index ffd3c556b6..5b9a5a3b73 100644 --- a/resources/qml/Menus/ProfileMenu.qml +++ b/resources/qml/Menus/ProfileMenu.qml @@ -51,7 +51,8 @@ Menu MenuItem { text: model.name - checkable: true + checkable: model.available + enabled: model.available checked: Cura.MachineManager.activeQualityOrQualityChangesName == model.name exclusiveGroup: group onTriggered: Cura.MachineManager.setQualityChangesGroup(model.quality_changes_group) From 819d1ac4e7cf23f0a8d343778410d7e68c5e9554 Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Tue, 17 Apr 2018 11:24:11 +0200 Subject: [PATCH 9/9] CURA-5202 Add modality to PluginBrowser window --- plugins/PluginBrowser/PluginBrowser.qml | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/PluginBrowser/PluginBrowser.qml b/plugins/PluginBrowser/PluginBrowser.qml index ec4c2a9135..6e5f532709 100644 --- a/plugins/PluginBrowser/PluginBrowser.qml +++ b/plugins/PluginBrowser/PluginBrowser.qml @@ -15,6 +15,7 @@ Window { id: base title: catalog.i18nc("@title:tab", "Plugins"); + modality: Qt.ApplicationModal width: 800 * screenScaleFactor height: 640 * screenScaleFactor minimumWidth: 350 * screenScaleFactor