mirror of
https://github.com/Ultimaker/Cura.git
synced 2025-07-07 06:57:28 -06:00
Add more info dialog
CURA-5204
This commit is contained in:
parent
0fbb067508
commit
40eedbcf70
6 changed files with 337 additions and 9 deletions
9
cura/CuraAppSignals.py
Normal file
9
cura/CuraAppSignals.py
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
from PyQt5.QtCore import pyqtSignal, QObject
|
||||||
|
|
||||||
|
|
||||||
|
class CuraAppSignals(QObject):
|
||||||
|
|
||||||
|
showMoreInfoOnAnonymousDataCollection = pyqtSignal()
|
||||||
|
|
||||||
|
def __init__(self, parent = None):
|
||||||
|
super().__init__(parent)
|
|
@ -74,6 +74,7 @@ from cura.Settings.SimpleModeSettingsManager import SimpleModeSettingsManager
|
||||||
|
|
||||||
from cura.Machines.VariantManager import VariantManager
|
from cura.Machines.VariantManager import VariantManager
|
||||||
|
|
||||||
|
from .CuraAppSignals import CuraAppSignals
|
||||||
from . import PlatformPhysics
|
from . import PlatformPhysics
|
||||||
from . import BuildVolume
|
from . import BuildVolume
|
||||||
from . import CameraAnimation
|
from . import CameraAnimation
|
||||||
|
@ -645,6 +646,8 @@ class CuraApplication(QtApplication):
|
||||||
def run(self):
|
def run(self):
|
||||||
self.preRun()
|
self.preRun()
|
||||||
|
|
||||||
|
self._app_signals = CuraAppSignals(self)
|
||||||
|
|
||||||
container_registry = ContainerRegistry.getInstance()
|
container_registry = ContainerRegistry.getInstance()
|
||||||
|
|
||||||
Logger.log("i", "Initializing variant manager")
|
Logger.log("i", "Initializing variant manager")
|
||||||
|
@ -780,6 +783,10 @@ class CuraApplication(QtApplication):
|
||||||
def hasGui(self):
|
def hasGui(self):
|
||||||
return self._use_gui
|
return self._use_gui
|
||||||
|
|
||||||
|
@pyqtSlot(result = QObject)
|
||||||
|
def getCuraAppSignals(self, *args) -> CuraAppSignals:
|
||||||
|
return self._app_signals
|
||||||
|
|
||||||
@pyqtSlot(result = QObject)
|
@pyqtSlot(result = QObject)
|
||||||
def getSettingVisibilityPresetsModel(self, *args) -> SettingVisibilityPresetsModel:
|
def getSettingVisibilityPresetsModel(self, *args) -> SettingVisibilityPresetsModel:
|
||||||
return self._setting_visibility_presets_model
|
return self._setting_visibility_presets_model
|
||||||
|
|
158
plugins/SliceInfoPlugin/MoreInfoWindow.qml
Normal file
158
plugins/SliceInfoPlugin/MoreInfoWindow.qml
Normal file
|
@ -0,0 +1,158 @@
|
||||||
|
// Copyright (c) 2018 Ultimaker B.V.
|
||||||
|
// PluginBrowser is released under the terms of the LGPLv3 or higher.
|
||||||
|
|
||||||
|
import QtQuick 2.7
|
||||||
|
import QtQuick.Window 2.2
|
||||||
|
import QtQuick.Controls 1.4
|
||||||
|
import QtQuick.Controls.Styles 1.4
|
||||||
|
|
||||||
|
import UM 1.3 as UM
|
||||||
|
import Cura 1.0 as Cura
|
||||||
|
|
||||||
|
|
||||||
|
UM.Dialog
|
||||||
|
{
|
||||||
|
id: baseDialog
|
||||||
|
title: catalog.i18nc("@title:window", "More information on anonymous data collection")
|
||||||
|
visible: false
|
||||||
|
|
||||||
|
minimumWidth: 500 * screenScaleFactor
|
||||||
|
minimumHeight: 400 * screenScaleFactor
|
||||||
|
width: minimumWidth
|
||||||
|
height: minimumHeight
|
||||||
|
|
||||||
|
property bool allowSendData: false // for saving the user's choice
|
||||||
|
|
||||||
|
onAccepted: manager.setSendSliceInfo(allowSendData)
|
||||||
|
|
||||||
|
onVisibilityChanged:
|
||||||
|
{
|
||||||
|
if (visible)
|
||||||
|
{
|
||||||
|
baseDialog.allowSendData = UM.Preferences.getValue("info/send_slice_info");
|
||||||
|
if (baseDialog.allowSendData)
|
||||||
|
{
|
||||||
|
allowSendButton.checked = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dontSendButton.checked = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Item
|
||||||
|
{
|
||||||
|
Connections
|
||||||
|
{
|
||||||
|
target: CuraApplication.getCuraAppSignals()
|
||||||
|
onShowMoreInfoOnAnonymousDataCollection:
|
||||||
|
{
|
||||||
|
baseDialog.show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
id: textRow
|
||||||
|
anchors
|
||||||
|
{
|
||||||
|
top: parent.top
|
||||||
|
bottom: radioButtonsRow.top
|
||||||
|
bottomMargin: UM.Theme.getSize("default_margin").height
|
||||||
|
left: parent.left
|
||||||
|
right: parent.right
|
||||||
|
}
|
||||||
|
|
||||||
|
Label
|
||||||
|
{
|
||||||
|
id: headerText
|
||||||
|
anchors
|
||||||
|
{
|
||||||
|
top: parent.top
|
||||||
|
left: parent.left
|
||||||
|
right: parent.right
|
||||||
|
}
|
||||||
|
|
||||||
|
text: catalog.i18nc("@text:window", "Cura sends anonymous data so we can improve the print quality and user experience. Below is an example of all the data we send.")
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
|
}
|
||||||
|
|
||||||
|
TextArea
|
||||||
|
{
|
||||||
|
id: exampleData
|
||||||
|
anchors
|
||||||
|
{
|
||||||
|
top: headerText.bottom
|
||||||
|
topMargin: UM.Theme.getSize("default_margin").height
|
||||||
|
bottom: parent.bottom
|
||||||
|
bottomMargin: UM.Theme.getSize("default_margin").height
|
||||||
|
left: parent.left
|
||||||
|
right: parent.right
|
||||||
|
}
|
||||||
|
|
||||||
|
text: manager.getExampleData()
|
||||||
|
readOnly: true
|
||||||
|
textFormat: TextEdit.PlainText
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Column
|
||||||
|
{
|
||||||
|
id: radioButtonsRow
|
||||||
|
width: parent.width
|
||||||
|
anchors.bottom: buttonRow.top
|
||||||
|
anchors.bottomMargin: UM.Theme.getSize("default_margin").height
|
||||||
|
|
||||||
|
ExclusiveGroup { id: group }
|
||||||
|
|
||||||
|
RadioButton
|
||||||
|
{
|
||||||
|
id: dontSendButton
|
||||||
|
text: catalog.i18nc("@text:window", "I don't want to send these settings")
|
||||||
|
exclusiveGroup: group
|
||||||
|
onClicked:
|
||||||
|
{
|
||||||
|
baseDialog.allowSendData = !checked;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RadioButton
|
||||||
|
{
|
||||||
|
id: allowSendButton
|
||||||
|
text: catalog.i18nc("@text:window", "Allow sending these settings to improve Cura")
|
||||||
|
exclusiveGroup: group
|
||||||
|
onClicked:
|
||||||
|
{
|
||||||
|
baseDialog.allowSendData = checked;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Item
|
||||||
|
{
|
||||||
|
id: buttonRow
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
width: parent.width
|
||||||
|
anchors.bottomMargin: UM.Theme.getSize("default_margin").height
|
||||||
|
|
||||||
|
UM.I18nCatalog { id: catalog; name: "cura" }
|
||||||
|
|
||||||
|
Button
|
||||||
|
{
|
||||||
|
anchors.right: parent.right
|
||||||
|
text: catalog.i18nc("@action:button", "Ok")
|
||||||
|
onClicked: {
|
||||||
|
baseDialog.accepted()
|
||||||
|
baseDialog.hide()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Button
|
||||||
|
{
|
||||||
|
anchors.left: parent.left
|
||||||
|
text: catalog.i18nc("@action:button", "Cancel")
|
||||||
|
onClicked: {
|
||||||
|
baseDialog.rejected()
|
||||||
|
baseDialog.hide()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,10 +1,13 @@
|
||||||
# Copyright (c) 2015 Ultimaker B.V.
|
# Copyright (c) 2018 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 json
|
import json
|
||||||
|
import os
|
||||||
import platform
|
import platform
|
||||||
import time
|
import time
|
||||||
|
|
||||||
|
from PyQt5.QtCore import pyqtSlot, QObject
|
||||||
|
|
||||||
from UM.Extension import Extension
|
from UM.Extension import Extension
|
||||||
from UM.Application import Application
|
from UM.Application import Application
|
||||||
from UM.Preferences import Preferences
|
from UM.Preferences import Preferences
|
||||||
|
@ -12,6 +15,7 @@ from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator
|
||||||
from UM.Message import Message
|
from UM.Message import Message
|
||||||
from UM.i18n import i18nCatalog
|
from UM.i18n import i18nCatalog
|
||||||
from UM.Logger import Logger
|
from UM.Logger import Logger
|
||||||
|
from UM.PluginRegistry import PluginRegistry
|
||||||
from UM.Qt.Duration import DurationFormat
|
from UM.Qt.Duration import DurationFormat
|
||||||
|
|
||||||
from .SliceInfoJob import SliceInfoJob
|
from .SliceInfoJob import SliceInfoJob
|
||||||
|
@ -23,15 +27,19 @@ catalog = i18nCatalog("cura")
|
||||||
## This Extension runs in the background and sends several bits of information to the Ultimaker servers.
|
## This Extension runs in the background and sends several bits of information to the Ultimaker servers.
|
||||||
# The data is only sent when the user in question gave permission to do so. All data is anonymous and
|
# The data is only sent when the user in question gave permission to do so. All data is anonymous and
|
||||||
# no model files are being sent (Just a SHA256 hash of the model).
|
# no model files are being sent (Just a SHA256 hash of the model).
|
||||||
class SliceInfo(Extension):
|
class SliceInfo(QObject, Extension):
|
||||||
info_url = "https://stats.ultimaker.com/api/cura"
|
info_url = "https://stats.ultimaker.com/api/cura"
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self, parent = None):
|
||||||
super().__init__()
|
QObject.__init__(self, parent)
|
||||||
|
Extension.__init__(self)
|
||||||
Application.getInstance().getOutputDeviceManager().writeStarted.connect(self._onWriteStarted)
|
Application.getInstance().getOutputDeviceManager().writeStarted.connect(self._onWriteStarted)
|
||||||
Preferences.getInstance().addPreference("info/send_slice_info", True)
|
Preferences.getInstance().addPreference("info/send_slice_info", True)
|
||||||
Preferences.getInstance().addPreference("info/asked_send_slice_info", False)
|
Preferences.getInstance().addPreference("info/asked_send_slice_info", False)
|
||||||
|
|
||||||
|
self._more_info_dialog = None
|
||||||
|
self._example_data_content = None
|
||||||
|
|
||||||
if not Preferences.getInstance().getValue("info/asked_send_slice_info"):
|
if not Preferences.getInstance().getValue("info/asked_send_slice_info"):
|
||||||
self.send_slice_info_message = Message(catalog.i18nc("@info", "Cura collects anonymized usage statistics."),
|
self.send_slice_info_message = Message(catalog.i18nc("@info", "Cura collects anonymized usage statistics."),
|
||||||
lifetime = 0,
|
lifetime = 0,
|
||||||
|
@ -40,19 +48,48 @@ class SliceInfo(Extension):
|
||||||
|
|
||||||
self.send_slice_info_message.addAction("Dismiss", name = catalog.i18nc("@action:button", "Allow"), icon = 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."))
|
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,
|
self.send_slice_info_message.addAction("MoreInfo", name = catalog.i18nc("@action:button", "More info"), icon = None,
|
||||||
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)
|
description = catalog.i18nc("@action:tooltip", "See more information on what data Cura sends."), button_style = Message.ActionButtonStyle.LINK)
|
||||||
self.send_slice_info_message.actionTriggered.connect(self.messageActionTriggered)
|
self.send_slice_info_message.actionTriggered.connect(self.messageActionTriggered)
|
||||||
self.send_slice_info_message.show()
|
self.send_slice_info_message.show()
|
||||||
|
|
||||||
|
Application.getInstance().initializationFinished.connect(self._onAppInitialized)
|
||||||
|
|
||||||
|
def _onAppInitialized(self):
|
||||||
|
if self._more_info_dialog is None:
|
||||||
|
self._more_info_dialog = self._createDialog("MoreInfoWindow.qml")
|
||||||
|
|
||||||
## Perform action based on user input.
|
## 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.
|
# 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):
|
def messageActionTriggered(self, message_id, action_id):
|
||||||
Preferences.getInstance().setValue("info/asked_send_slice_info", True)
|
Preferences.getInstance().setValue("info/asked_send_slice_info", True)
|
||||||
if action_id == "Disable":
|
if action_id == "MoreInfo":
|
||||||
Application.getInstance().showPreferences()
|
self._showMoreInfoDialog()
|
||||||
self.send_slice_info_message.hide()
|
self.send_slice_info_message.hide()
|
||||||
|
|
||||||
|
def _showMoreInfoDialog(self):
|
||||||
|
if self._more_info_dialog is None:
|
||||||
|
self._more_info_dialog = self._createDialog("MoreInfoWindow.qml")
|
||||||
|
self._more_info_dialog.open()
|
||||||
|
|
||||||
|
def _createDialog(self, qml_name):
|
||||||
|
Logger.log("d", "Creating dialog [%s]", qml_name)
|
||||||
|
file_path = os.path.join(PluginRegistry.getInstance().getPluginPath(self.getPluginId()), qml_name)
|
||||||
|
dialog = Application.getInstance().createQmlComponent(file_path, {"manager": self})
|
||||||
|
return dialog
|
||||||
|
|
||||||
|
@pyqtSlot(result = str)
|
||||||
|
def getExampleData(self) -> str:
|
||||||
|
if self._example_data_content is None:
|
||||||
|
file_path = os.path.join(PluginRegistry.getInstance().getPluginPath(self.getPluginId()), "example_data.json")
|
||||||
|
with open(file_path, "r", encoding = "utf-8") as f:
|
||||||
|
self._example_data_content = f.read()
|
||||||
|
return self._example_data_content
|
||||||
|
|
||||||
|
@pyqtSlot(bool)
|
||||||
|
def setSendSliceInfo(self, enabled: bool):
|
||||||
|
Preferences.getInstance().setValue("info/send_slice_info", enabled)
|
||||||
|
|
||||||
def _onWriteStarted(self, output_device):
|
def _onWriteStarted(self, output_device):
|
||||||
try:
|
try:
|
||||||
if not Preferences.getInstance().getValue("info/send_slice_info"):
|
if not Preferences.getInstance().getValue("info/send_slice_info"):
|
||||||
|
|
101
plugins/SliceInfoPlugin/example_data.json
Normal file
101
plugins/SliceInfoPlugin/example_data.json
Normal file
|
@ -0,0 +1,101 @@
|
||||||
|
{
|
||||||
|
"extruders": [
|
||||||
|
{
|
||||||
|
"material": {
|
||||||
|
"GUID": "506c9f0d-e3aa-4bd4-b2d2-23e2425b1aa9",
|
||||||
|
"brand": "Generic",
|
||||||
|
"type": "PLA"
|
||||||
|
},
|
||||||
|
"active": true,
|
||||||
|
"material_used": 4.82,
|
||||||
|
"nozzle_size": 0.4,
|
||||||
|
"variant": "AA 0.4",
|
||||||
|
"extruder_settings": {
|
||||||
|
"infill_pattern": "triangles",
|
||||||
|
"wall_line_count": 4,
|
||||||
|
"retraction_enable": true,
|
||||||
|
"infill_sparse_density": 0.0,
|
||||||
|
"gradual_infill_steps": 0.0,
|
||||||
|
"default_material_print_temperature": 200,
|
||||||
|
"material_print_temperature": 200
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"material": {
|
||||||
|
"GUID": "86a89ceb-4159-47f6-ab97-e9953803d70f",
|
||||||
|
"brand": "Generic",
|
||||||
|
"type": "PVA"
|
||||||
|
},
|
||||||
|
"active": false,
|
||||||
|
"material_used": 0.0,
|
||||||
|
"nozzle_size": 0.4,
|
||||||
|
"variant": "BB 0.4",
|
||||||
|
"extruder_settings": {
|
||||||
|
"infill_pattern": "triangles",
|
||||||
|
"wall_line_count": 3,
|
||||||
|
"retraction_enable": true,
|
||||||
|
"infill_sparse_density": 20,
|
||||||
|
"gradual_infill_steps": 0,
|
||||||
|
"default_material_print_temperature": 215,
|
||||||
|
"material_print_temperature": 215
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"active_mode": "custom",
|
||||||
|
"schema_version": 0,
|
||||||
|
"print_times": {
|
||||||
|
"support": 0,
|
||||||
|
"infill": 0,
|
||||||
|
"total": 44548,
|
||||||
|
"travel": 5063
|
||||||
|
},
|
||||||
|
"machine_settings_changed_by_user": false,
|
||||||
|
"language": "en",
|
||||||
|
"cura_version": "2.7.0-master.20170721034526",
|
||||||
|
"os": {
|
||||||
|
"version": "10.0.14393",
|
||||||
|
"type": "Windows"
|
||||||
|
},
|
||||||
|
"time_stamp": 1500629879.3985891,
|
||||||
|
"quality_profile": "normal",
|
||||||
|
"print_settings": {
|
||||||
|
"print_sequence": "all_at_once",
|
||||||
|
"infill_pattern": "triangles",
|
||||||
|
"layer_height": 0.1,
|
||||||
|
"infill_sparse_density": 20,
|
||||||
|
"wall_line_count": 3,
|
||||||
|
"retraction_enable": true,
|
||||||
|
"gradual_infill_steps": 0,
|
||||||
|
"adhesion_type": "none",
|
||||||
|
"prime_tower_enable": false,
|
||||||
|
"support_enabled": false,
|
||||||
|
"support_extruder_nr": 0
|
||||||
|
},
|
||||||
|
"models": [
|
||||||
|
{
|
||||||
|
"extruder": 0,
|
||||||
|
"transformation": {
|
||||||
|
"data": "[[ 1.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00] [ 0.00000000e+00 8.96267878e-08 -9.99999881e-01 1.00000038e+01] [ 0.00000000e+00 9.99999881e-01 8.96267878e-08 1.77869296e-07] [ 0.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00]]"
|
||||||
|
},
|
||||||
|
"bounding_box": {
|
||||||
|
"minimum": {
|
||||||
|
"x": -80.0,
|
||||||
|
"y": -4.0903287974458635e-06,
|
||||||
|
"z": -101.49998861865569
|
||||||
|
},
|
||||||
|
"maximum": {
|
||||||
|
"x": 80.0,
|
||||||
|
"y": 20.000011181962602,
|
||||||
|
"z": 101.49998897439428
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"model_settings": {
|
||||||
|
},
|
||||||
|
"hash": "ca1a12e57ddf990fabc25d9105fc28eea266937c3f907d0e58edf9cc43f28551"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"active_machine": {
|
||||||
|
"definition_id": "ultimaker3",
|
||||||
|
"manufacturer": "Ultimaker"
|
||||||
|
}
|
||||||
|
}
|
|
@ -649,7 +649,7 @@ UM.PreferencesPage
|
||||||
UM.TooltipArea {
|
UM.TooltipArea {
|
||||||
visible: plugins.find("id", "SliceInfoPlugin") > -1
|
visible: plugins.find("id", "SliceInfoPlugin") > -1
|
||||||
width: childrenRect.width
|
width: childrenRect.width
|
||||||
height: visible ? childrenRect.height : 0
|
height: visible ? childrenRect.height * 2 : 0
|
||||||
text: catalog.i18nc("@info:tooltip","Should anonymous data about your print be sent to Ultimaker? Note, no models, IP addresses or other personally identifiable information is sent or stored.")
|
text: catalog.i18nc("@info:tooltip","Should anonymous data about your print be sent to Ultimaker? Note, no models, IP addresses or other personally identifiable information is sent or stored.")
|
||||||
|
|
||||||
CheckBox
|
CheckBox
|
||||||
|
@ -659,6 +659,22 @@ UM.PreferencesPage
|
||||||
checked: boolCheck(UM.Preferences.getValue("info/send_slice_info"))
|
checked: boolCheck(UM.Preferences.getValue("info/send_slice_info"))
|
||||||
onCheckedChanged: UM.Preferences.setValue("info/send_slice_info", checked)
|
onCheckedChanged: UM.Preferences.setValue("info/send_slice_info", checked)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Button
|
||||||
|
{
|
||||||
|
id: showMoreInfo
|
||||||
|
anchors
|
||||||
|
{
|
||||||
|
top: sendDataCheckbox.bottom
|
||||||
|
bottom: parent.bottom
|
||||||
|
}
|
||||||
|
|
||||||
|
text: catalog.i18nc("@action:button", "Show more information on anonymous data collection")
|
||||||
|
onClicked:
|
||||||
|
{
|
||||||
|
CuraApplication.getCuraAppSignals().showMoreInfoOnAnonymousDataCollection();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Item
|
Item
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue