From 0c4db90b7bc3460a21a9edbe505e639af5313824 Mon Sep 17 00:00:00 2001 From: Ruben D Date: Tue, 28 Nov 2017 00:20:43 +0100 Subject: [PATCH 1/6] Add button to disable sending info directly Convenient and easy. --- plugins/SliceInfoPlugin/SliceInfo.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/plugins/SliceInfoPlugin/SliceInfo.py b/plugins/SliceInfoPlugin/SliceInfo.py index 79963a4740..4399b0a450 100755 --- a/plugins/SliceInfoPlugin/SliceInfo.py +++ b/plugins/SliceInfoPlugin/SliceInfo.py @@ -40,16 +40,21 @@ class SliceInfo(Extension): Preferences.getInstance().addPreference("info/asked_send_slice_info", False) if not Preferences.getInstance().getValue("info/asked_send_slice_info"): - self.send_slice_info_message = Message(catalog.i18nc("@info", "Cura collects anonymised slicing statistics. You can disable this in the preferences."), + self.send_slice_info_message = Message(catalog.i18nc("@info", "Cura collects anonymized usage statistics."), lifetime = 0, dismissable = False, title = catalog.i18nc("@info:title", "Collecting Data")) - self.send_slice_info_message.addAction("Dismiss", catalog.i18nc("@action:button", "Dismiss"), None, "") + self.send_slice_info_message.addAction("Dismiss", name = catalog.i18nc("@action:button", "Allow"), icon = None, + description = catalog.i18nc("@action:tooltip", "Allow Cura to send anonymized usage statistics to help prioritize future improvements to Cura. Some of your preferences and settings are sent, the Cura version and a hash of the models you're slicing.")) + self.send_slice_info_message.addAction("Disable", name = catalog.i18nc("@action:button", "Disable"), icon = None, + description = catalog.i18nc("@action:tooltip", "Don't allow Cura to send anonymized usage statistics. You can enable it again in the preferences.")) self.send_slice_info_message.actionTriggered.connect(self.messageActionTriggered) self.send_slice_info_message.show() def messageActionTriggered(self, message_id, action_id): + if action_id == "Disable": + Preferences.getInstance().setValue("info/send_slice_info", False) self.send_slice_info_message.hide() Preferences.getInstance().setValue("info/asked_send_slice_info", True) From df1d3bf569102e2bd8645b83f436d35b65eb003f Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Thu, 21 Dec 2017 15:42:48 +0100 Subject: [PATCH 2/6] Add fix and doc for Mac OpenGL crash CURA-4726 --- plugins/SimulationView/SimulationView.py | 20 ++++++++++++++++++++ plugins/XRayView/XRayView.py | 22 ++++++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/plugins/SimulationView/SimulationView.py b/plugins/SimulationView/SimulationView.py index 44f472129f..6fc362725e 100644 --- a/plugins/SimulationView/SimulationView.py +++ b/plugins/SimulationView/SimulationView.py @@ -4,6 +4,7 @@ import sys from PyQt5.QtCore import Qt +from PyQt5.QtGui import QOpenGLContext from PyQt5.QtWidgets import QApplication from UM.Application import Application @@ -13,6 +14,7 @@ from UM.Logger import Logger from UM.Math.Color import Color from UM.Mesh.MeshBuilder import MeshBuilder from UM.Message import Message +from UM.Platform import Platform from UM.PluginRegistry import PluginRegistry from UM.Preferences import Preferences from UM.Resources import Resources @@ -24,6 +26,7 @@ from UM.View.GL.OpenGLContext import OpenGLContext from UM.View.View import View from UM.i18n import i18nCatalog from cura.ConvexHullNode import ConvexHullNode +from cura.CuraApplication import CuraApplication from .NozzleNode import NozzleNode from .SimulationPass import SimulationPass @@ -414,6 +417,23 @@ class SimulationView(View): return True if event.type == Event.ViewActivateEvent: + # FIX: on Max OS X, somehow QOpenGLContext.currentContext() can become None during View switching. + # This can happen when you do the following steps: + # 1. Start Cura + # 2. Load a model + # 3. Switch to Custom mode + # 4. Select the model and click on the per-object tool icon + # 5. Switch view to Layer view or X-Ray + # 6. Cura will very likely crash + # It seems to be a timing issue that the currentContext can somehow be empty, but I have no clue why. + # This fix tries to reschedule the view changing event call on the Qt thread again if the current OpenGL + # context is None. + if Platform.isOSX(): + if QOpenGLContext.currentContext() is None: + Logger.log("d", "current context of OpenGL is empty on Mac OS X, will try to create shaders later") + CuraApplication.getInstance().callLater(lambda e=event: self.event(e)) + return + # Make sure the SimulationPass is created layer_pass = self.getSimulationPass() self.getRenderer().addRenderPass(layer_pass) diff --git a/plugins/XRayView/XRayView.py b/plugins/XRayView/XRayView.py index 35509a9715..0c4035c62d 100644 --- a/plugins/XRayView/XRayView.py +++ b/plugins/XRayView/XRayView.py @@ -2,10 +2,13 @@ # Cura is released under the terms of the LGPLv3 or higher. import os.path +from PyQt5.QtGui import QOpenGLContext from UM.Application import Application +from UM.Logger import Logger from UM.Math.Color import Color from UM.PluginRegistry import PluginRegistry +from UM.Platform import Platform from UM.Event import Event from UM.View.View import View from UM.Scene.Iterator.BreadthFirstIterator import BreadthFirstIterator @@ -13,6 +16,8 @@ from UM.Scene.Iterator.BreadthFirstIterator import BreadthFirstIterator from UM.View.RenderBatch import RenderBatch from UM.View.GL.OpenGL import OpenGL +from cura.CuraApplication import CuraApplication + from . import XRayPass ## View used to display a see-through version of objects with errors highlighted. @@ -52,6 +57,23 @@ class XRayView(View): def event(self, event): if event.type == Event.ViewActivateEvent: + # FIX: on Max OS X, somehow QOpenGLContext.currentContext() can become None during View switching. + # This can happen when you do the following steps: + # 1. Start Cura + # 2. Load a model + # 3. Switch to Custom mode + # 4. Select the model and click on the per-object tool icon + # 5. Switch view to Layer view or X-Ray + # 6. Cura will very likely crash + # It seems to be a timing issue that the currentContext can somehow be empty, but I have no clue why. + # This fix tries to reschedule the view changing event call on the Qt thread again if the current OpenGL + # context is None. + if Platform.isOSX(): + if QOpenGLContext.currentContext() is None: + Logger.log("d", "current context of OpenGL is empty on Mac OS X, will try to create shaders later") + CuraApplication.getInstance().callLater(lambda e = event: self.event(e)) + return + if not self._xray_pass: # Currently the RenderPass constructor requires a size > 0 # This should be fixed in RenderPass's constructor. From 4e902046208b2c2a31542ab8b3cce38b873f1443 Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Thu, 21 Dec 2017 15:51:24 +0100 Subject: [PATCH 3/6] Only push aways other objects if they are printing meshes CURA-4705 --- cura/PlatformPhysics.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/cura/PlatformPhysics.py b/cura/PlatformPhysics.py index 23197dac24..471e54dba6 100755 --- a/cura/PlatformPhysics.py +++ b/cura/PlatformPhysics.py @@ -76,7 +76,8 @@ class PlatformPhysics: if not node.getDecorator(ConvexHullDecorator): node.addDecorator(ConvexHullDecorator()) - if Preferences.getInstance().getValue("physics/automatic_push_free"): + # only push away objects if this node is a printing mesh + if not node.callDecoration("isNonPrintingMesh") and Preferences.getInstance().getValue("physics/automatic_push_free"): # Check for collisions between convex hulls for other_node in BreadthFirstIterator(root): # Ignore root, ourselves and anything that is not a normal SceneNode. @@ -98,6 +99,9 @@ class PlatformPhysics: if other_node in transformed_nodes: continue # Other node is already moving, wait for next pass. + if other_node.callDecoration("isNonPrintingMesh"): + continue + overlap = (0, 0) # Start loop with no overlap current_overlap_checks = 0 # Continue to check the overlap until we no longer find one. From 447c6e7e2360d89fd00a7926ee8059d70c4b7635 Mon Sep 17 00:00:00 2001 From: Aleksei S Date: Thu, 21 Dec 2017 16:25:13 +0100 Subject: [PATCH 4/6] Added Disable link style CURA-4630 --- cura/CuraApplication.py | 8 ++++++++ plugins/SliceInfoPlugin/SliceInfo.py | 4 ++-- resources/qml/Cura.qml | 6 ++++++ 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 18d1bde57e..036369aed7 100755 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -1426,3 +1426,11 @@ class CuraApplication(QtApplication): node = node.getParent() Selection.add(node) + + + triggerPreferenceWindow = pyqtSignal() + + # This event has a simple logic, display pereference window if user decided to disable "collect information" + @pyqtProperty(bool, notify = triggerPreferenceWindow) + def showMyTest(self): + return True \ No newline at end of file diff --git a/plugins/SliceInfoPlugin/SliceInfo.py b/plugins/SliceInfoPlugin/SliceInfo.py index 9bd99cae2b..28bcc763c7 100755 --- a/plugins/SliceInfoPlugin/SliceInfo.py +++ b/plugins/SliceInfoPlugin/SliceInfo.py @@ -48,13 +48,13 @@ class SliceInfo(Extension): self.send_slice_info_message.addAction("Dismiss", name = catalog.i18nc("@action:button", "Allow"), icon = None, description = catalog.i18nc("@action:tooltip", "Allow Cura to send anonymized usage statistics to help prioritize future improvements to Cura. Some of your preferences and settings are sent, the Cura version and a hash of the models you're slicing.")) self.send_slice_info_message.addAction("Disable", name = catalog.i18nc("@action:button", "Disable"), icon = None, - description = catalog.i18nc("@action:tooltip", "Don't allow Cura to send anonymized usage statistics. You can enable it again in the preferences.")) + description = catalog.i18nc("@action:tooltip", "Don't allow Cura to send anonymized usage statistics. You can enable it again in the preferences."), button_style = Message.ActionButtonStyle.LINK) self.send_slice_info_message.actionTriggered.connect(self.messageActionTriggered) self.send_slice_info_message.show() def messageActionTriggered(self, message_id, action_id): if action_id == "Disable": - Preferences.getInstance().setValue("info/send_slice_info", False) + CuraApplication.getInstance().triggerPreferenceWindow.emit() self.send_slice_info_message.hide() Preferences.getInstance().setValue("info/asked_send_slice_info", True) diff --git a/resources/qml/Cura.qml b/resources/qml/Cura.qml index 91098bbb29..40fc88c975 100644 --- a/resources/qml/Cura.qml +++ b/resources/qml/Cura.qml @@ -528,6 +528,12 @@ UM.MainWindow onTriggered: preferences.visible = true } + Connections + { + target: CuraApplication + onShowMyTestChanged: preferences.visible = true + } + MessageDialog { id: newProjectDialog From b29047abd32195666b989adc50ce49545f073a44 Mon Sep 17 00:00:00 2001 From: ChrisTerBeke Date: Fri, 22 Dec 2017 11:38:56 +0100 Subject: [PATCH 5/6] Small fixes for disable user data triggering preferences window --- cura/CuraApplication.py | 16 ++++++++-------- plugins/SliceInfoPlugin/SliceInfo.py | 8 +++++--- resources/qml/Cura.qml | 2 +- 3 files changed, 14 insertions(+), 12 deletions(-) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 036369aed7..e9e2282be6 100755 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -409,6 +409,14 @@ class CuraApplication(QtApplication): else: self.exit(0) + ## Signal to connect preferences action in QML + showPreferencesWindow = pyqtSignal() + + ## Show the preferences window + @pyqtSlot() + def showPreferences(self): + self.showPreferencesWindow.emit() + ## A reusable dialogbox # showMessageBox = pyqtSignal(str, str, str, str, int, int, arguments = ["title", "text", "informativeText", "detailedText", "buttons", "icon"]) @@ -1426,11 +1434,3 @@ class CuraApplication(QtApplication): node = node.getParent() Selection.add(node) - - - triggerPreferenceWindow = pyqtSignal() - - # This event has a simple logic, display pereference window if user decided to disable "collect information" - @pyqtProperty(bool, notify = triggerPreferenceWindow) - def showMyTest(self): - return True \ No newline at end of file diff --git a/plugins/SliceInfoPlugin/SliceInfo.py b/plugins/SliceInfoPlugin/SliceInfo.py index 28bcc763c7..753e00091b 100755 --- a/plugins/SliceInfoPlugin/SliceInfo.py +++ b/plugins/SliceInfoPlugin/SliceInfo.py @@ -52,11 +52,13 @@ class SliceInfo(Extension): self.send_slice_info_message.actionTriggered.connect(self.messageActionTriggered) self.send_slice_info_message.show() + ## Perform action based on user input. + # Note that clicking "Disable" won't actually disable the data sending, but rather take the user to preferences where they can disable it. def messageActionTriggered(self, message_id, action_id): - if action_id == "Disable": - CuraApplication.getInstance().triggerPreferenceWindow.emit() - self.send_slice_info_message.hide() Preferences.getInstance().setValue("info/asked_send_slice_info", True) + if action_id == "Disable": + CuraApplication.getInstance().showPreferences() + self.send_slice_info_message.hide() def _onWriteStarted(self, output_device): try: diff --git a/resources/qml/Cura.qml b/resources/qml/Cura.qml index 40fc88c975..efe956939b 100644 --- a/resources/qml/Cura.qml +++ b/resources/qml/Cura.qml @@ -531,7 +531,7 @@ UM.MainWindow Connections { target: CuraApplication - onShowMyTestChanged: preferences.visible = true + onShowPreferencesWindow: preferences.visible = true } MessageDialog From f75d91071a3fd8b3262d42e809bc0c548d960207 Mon Sep 17 00:00:00 2001 From: ChrisTerBeke Date: Fri, 22 Dec 2017 11:39:58 +0100 Subject: [PATCH 6/6] Remove invisible flag from allowed command line options to trigger non-gui mode --- cura/CuraApplication.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index e9e2282be6..e90dfd70d3 100755 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -691,7 +691,7 @@ class CuraApplication(QtApplication): self.setMainQml(Resources.getPath(self.ResourceTypes.QmlFiles, "Cura.qml")) self._qml_import_paths.append(Resources.getPath(self.ResourceTypes.QmlFiles)) - run_without_gui = self.getCommandLineOption("headless", False) or self.getCommandLineOption("invisible", False) + run_without_gui = self.getCommandLineOption("headless", False) if not run_without_gui: self.initializeEngine() controller.setActiveStage("PrepareStage")