mirror of
https://git.mirrors.martin98.com/https://github.com/Ultimaker/Cura
synced 2025-08-14 05:45:55 +08:00
Merge pull request #3666 from Ultimaker/CURA-5204_send_anonymous_data
Show information dialogue on what usage data is sent
This commit is contained in:
commit
5333ca5aa8
@ -1727,3 +1727,7 @@ class CuraApplication(QtApplication):
|
|||||||
node = node.getParent()
|
node = node.getParent()
|
||||||
|
|
||||||
Selection.add(node)
|
Selection.add(node)
|
||||||
|
|
||||||
|
@pyqtSlot()
|
||||||
|
def showMoreInformationDialogForAnonymousDataCollection(self):
|
||||||
|
self._plugin_registry.getPluginObject("SliceInfoPlugin").showMoreInfoDialog()
|
||||||
|
151
plugins/SliceInfoPlugin/MoreInfoWindow.qml
Normal file
151
plugins/SliceInfoPlugin/MoreInfoWindow.qml
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
// Copyright (c) 2018 Ultimaker B.V.
|
||||||
|
// Cura 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: true // 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
|
||||||
|
{
|
||||||
|
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 to Ultimaker in order to improve the print quality and user experience. Below is an example of all the data that is sent.")
|
||||||
|
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 data")
|
||||||
|
exclusiveGroup: group
|
||||||
|
onClicked:
|
||||||
|
{
|
||||||
|
baseDialog.allowSendData = !checked;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RadioButton
|
||||||
|
{
|
||||||
|
id: allowSendButton
|
||||||
|
text: catalog.i18nc("@text:window", "Allow sending these data to Ultimaker and help us 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,8 +1,12 @@
|
|||||||
# 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.
|
||||||
|
|
||||||
from cura.CuraApplication import CuraApplication
|
import json
|
||||||
from cura.Settings.ExtruderManager import ExtruderManager
|
import os
|
||||||
|
import platform
|
||||||
|
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
|
||||||
@ -11,18 +15,11 @@ 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
|
||||||
import time
|
|
||||||
|
|
||||||
from UM.Qt.Duration import DurationFormat
|
from UM.Qt.Duration import DurationFormat
|
||||||
|
|
||||||
from .SliceInfoJob import SliceInfoJob
|
from .SliceInfoJob import SliceInfoJob
|
||||||
|
|
||||||
import platform
|
|
||||||
import math
|
|
||||||
import urllib.request
|
|
||||||
import urllib.parse
|
|
||||||
import json
|
|
||||||
|
|
||||||
catalog = i18nCatalog("cura")
|
catalog = i18nCatalog("cura")
|
||||||
|
|
||||||
@ -30,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,
|
||||||
@ -47,32 +48,64 @@ 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":
|
||||||
Preferences.getInstance().addPreference("info/send_slice_info", False)
|
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"):
|
||||||
Logger.log("d", "'info/send_slice_info' is turned off.")
|
Logger.log("d", "'info/send_slice_info' is turned off.")
|
||||||
return # Do nothing, user does not want to send data
|
return # Do nothing, user does not want to send data
|
||||||
|
|
||||||
global_container_stack = Application.getInstance().getGlobalContainerStack()
|
application = Application.getInstance()
|
||||||
print_information = Application.getInstance().getPrintInformation()
|
machine_manager = application.getMachineManager()
|
||||||
|
print_information = application.getPrintInformation()
|
||||||
|
|
||||||
|
global_stack = machine_manager.activeMachine
|
||||||
|
|
||||||
data = dict() # The data that we're going to submit.
|
data = dict() # The data that we're going to submit.
|
||||||
data["time_stamp"] = time.time()
|
data["time_stamp"] = time.time()
|
||||||
data["schema_version"] = 0
|
data["schema_version"] = 0
|
||||||
data["cura_version"] = Application.getInstance().getVersion()
|
data["cura_version"] = application.getVersion()
|
||||||
|
|
||||||
active_mode = Preferences.getInstance().getValue("cura/active_mode")
|
active_mode = Preferences.getInstance().getValue("cura/active_mode")
|
||||||
if active_mode == 0:
|
if active_mode == 0:
|
||||||
@ -80,7 +113,7 @@ class SliceInfo(Extension):
|
|||||||
else:
|
else:
|
||||||
data["active_mode"] = "custom"
|
data["active_mode"] = "custom"
|
||||||
|
|
||||||
definition_changes = global_container_stack.definitionChanges
|
definition_changes = global_stack.definitionChanges
|
||||||
machine_settings_changed_by_user = False
|
machine_settings_changed_by_user = False
|
||||||
if definition_changes.getId() != "empty":
|
if definition_changes.getId() != "empty":
|
||||||
# Now a definition_changes container will always be created for a stack,
|
# Now a definition_changes container will always be created for a stack,
|
||||||
@ -92,16 +125,17 @@ class SliceInfo(Extension):
|
|||||||
data["language"] = Preferences.getInstance().getValue("general/language")
|
data["language"] = Preferences.getInstance().getValue("general/language")
|
||||||
data["os"] = {"type": platform.system(), "version": platform.version()}
|
data["os"] = {"type": platform.system(), "version": platform.version()}
|
||||||
|
|
||||||
data["active_machine"] = {"definition_id": global_container_stack.definition.getId(), "manufacturer": global_container_stack.definition.getMetaData().get("manufacturer","")}
|
data["active_machine"] = {"definition_id": global_stack.definition.getId(),
|
||||||
|
"manufacturer": global_stack.definition.getMetaDataEntry("manufacturer", "")}
|
||||||
|
|
||||||
# add extruder specific data to slice info
|
# add extruder specific data to slice info
|
||||||
data["extruders"] = []
|
data["extruders"] = []
|
||||||
extruders = list(ExtruderManager.getInstance().getMachineExtruders(global_container_stack.getId()))
|
extruders = list(global_stack.extruders.values())
|
||||||
extruders = sorted(extruders, key = lambda extruder: extruder.getMetaDataEntry("position"))
|
extruders = sorted(extruders, key = lambda extruder: extruder.getMetaDataEntry("position"))
|
||||||
|
|
||||||
for extruder in extruders:
|
for extruder in extruders:
|
||||||
extruder_dict = dict()
|
extruder_dict = dict()
|
||||||
extruder_dict["active"] = ExtruderManager.getInstance().getActiveExtruderStack() == extruder
|
extruder_dict["active"] = machine_manager.activeStack == extruder
|
||||||
extruder_dict["material"] = {"GUID": extruder.material.getMetaData().get("GUID", ""),
|
extruder_dict["material"] = {"GUID": extruder.material.getMetaData().get("GUID", ""),
|
||||||
"type": extruder.material.getMetaData().get("material", ""),
|
"type": extruder.material.getMetaData().get("material", ""),
|
||||||
"brand": extruder.material.getMetaData().get("brand", "")
|
"brand": extruder.material.getMetaData().get("brand", "")
|
||||||
@ -123,11 +157,11 @@ class SliceInfo(Extension):
|
|||||||
extruder_dict["extruder_settings"] = extruder_settings
|
extruder_dict["extruder_settings"] = extruder_settings
|
||||||
data["extruders"].append(extruder_dict)
|
data["extruders"].append(extruder_dict)
|
||||||
|
|
||||||
data["quality_profile"] = global_container_stack.quality.getMetaData().get("quality_type")
|
data["quality_profile"] = global_stack.quality.getMetaData().get("quality_type")
|
||||||
|
|
||||||
data["models"] = []
|
data["models"] = []
|
||||||
# Listing all files placed on the build plate
|
# Listing all files placed on the build plate
|
||||||
for node in DepthFirstIterator(CuraApplication.getInstance().getController().getScene().getRoot()):
|
for node in DepthFirstIterator(application.getController().getScene().getRoot()):
|
||||||
if node.callDecoration("isSliceable"):
|
if node.callDecoration("isSliceable"):
|
||||||
model = dict()
|
model = dict()
|
||||||
model["hash"] = node.getMeshData().getHash()
|
model["hash"] = node.getMeshData().getHash()
|
||||||
@ -173,28 +207,28 @@ class SliceInfo(Extension):
|
|||||||
"total": int(print_information.currentPrintTime.getDisplayString(DurationFormat.Format.Seconds))}
|
"total": int(print_information.currentPrintTime.getDisplayString(DurationFormat.Format.Seconds))}
|
||||||
|
|
||||||
print_settings = dict()
|
print_settings = dict()
|
||||||
print_settings["layer_height"] = global_container_stack.getProperty("layer_height", "value")
|
print_settings["layer_height"] = global_stack.getProperty("layer_height", "value")
|
||||||
|
|
||||||
# Support settings
|
# Support settings
|
||||||
print_settings["support_enabled"] = global_container_stack.getProperty("support_enable", "value")
|
print_settings["support_enabled"] = global_stack.getProperty("support_enable", "value")
|
||||||
print_settings["support_extruder_nr"] = int(global_container_stack.getExtruderPositionValueWithDefault("support_extruder_nr"))
|
print_settings["support_extruder_nr"] = int(global_stack.getExtruderPositionValueWithDefault("support_extruder_nr"))
|
||||||
|
|
||||||
# Platform adhesion settings
|
# Platform adhesion settings
|
||||||
print_settings["adhesion_type"] = global_container_stack.getProperty("adhesion_type", "value")
|
print_settings["adhesion_type"] = global_stack.getProperty("adhesion_type", "value")
|
||||||
|
|
||||||
# Shell settings
|
# Shell settings
|
||||||
print_settings["wall_line_count"] = global_container_stack.getProperty("wall_line_count", "value")
|
print_settings["wall_line_count"] = global_stack.getProperty("wall_line_count", "value")
|
||||||
print_settings["retraction_enable"] = global_container_stack.getProperty("retraction_enable", "value")
|
print_settings["retraction_enable"] = global_stack.getProperty("retraction_enable", "value")
|
||||||
|
|
||||||
# Prime tower settings
|
# Prime tower settings
|
||||||
print_settings["prime_tower_enable"] = global_container_stack.getProperty("prime_tower_enable", "value")
|
print_settings["prime_tower_enable"] = global_stack.getProperty("prime_tower_enable", "value")
|
||||||
|
|
||||||
# Infill settings
|
# Infill settings
|
||||||
print_settings["infill_sparse_density"] = global_container_stack.getProperty("infill_sparse_density", "value")
|
print_settings["infill_sparse_density"] = global_stack.getProperty("infill_sparse_density", "value")
|
||||||
print_settings["infill_pattern"] = global_container_stack.getProperty("infill_pattern", "value")
|
print_settings["infill_pattern"] = global_stack.getProperty("infill_pattern", "value")
|
||||||
print_settings["gradual_infill_steps"] = global_container_stack.getProperty("gradual_infill_steps", "value")
|
print_settings["gradual_infill_steps"] = global_stack.getProperty("gradual_infill_steps", "value")
|
||||||
|
|
||||||
print_settings["print_sequence"] = global_container_stack.getProperty("print_sequence", "value")
|
print_settings["print_sequence"] = global_stack.getProperty("print_sequence", "value")
|
||||||
|
|
||||||
data["print_settings"] = print_settings
|
data["print_settings"] = print_settings
|
||||||
|
|
||||||
|
113
plugins/SliceInfoPlugin/example_data.json
Normal file
113
plugins/SliceInfoPlugin/example_data.json
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
{
|
||||||
|
"time_stamp": 1523973715.486928,
|
||||||
|
"schema_version": 0,
|
||||||
|
"cura_version": "3.3",
|
||||||
|
"active_mode": "custom",
|
||||||
|
"machine_settings_changed_by_user": true,
|
||||||
|
"language": "en_US",
|
||||||
|
"os": {
|
||||||
|
"type": "Linux",
|
||||||
|
"version": "#43~16.04.1-Ubuntu SMP Wed Mar 14 17:48:43 UTC 2018"
|
||||||
|
},
|
||||||
|
"active_machine": {
|
||||||
|
"definition_id": "ultimaker3",
|
||||||
|
"manufacturer": "Ultimaker B.V."
|
||||||
|
},
|
||||||
|
"extruders": [
|
||||||
|
{
|
||||||
|
"active": true,
|
||||||
|
"material": {
|
||||||
|
"GUID": "506c9f0d-e3aa-4bd4-b2d2-23e2425b1aa9",
|
||||||
|
"type": "PLA",
|
||||||
|
"brand": "Generic"
|
||||||
|
},
|
||||||
|
"material_used": 0.84,
|
||||||
|
"variant": "AA 0.4",
|
||||||
|
"nozzle_size": 0.4,
|
||||||
|
"extruder_settings": {
|
||||||
|
"wall_line_count": 3,
|
||||||
|
"retraction_enable": true,
|
||||||
|
"infill_sparse_density": 30,
|
||||||
|
"infill_pattern": "triangles",
|
||||||
|
"gradual_infill_steps": 0,
|
||||||
|
"default_material_print_temperature": 200,
|
||||||
|
"material_print_temperature": 200
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"active": false,
|
||||||
|
"material": {
|
||||||
|
"GUID": "86a89ceb-4159-47f6-ab97-e9953803d70f",
|
||||||
|
"type": "PVA",
|
||||||
|
"brand": "Generic"
|
||||||
|
},
|
||||||
|
"material_used": 0.5,
|
||||||
|
"variant": "BB 0.4",
|
||||||
|
"nozzle_size": 0.4,
|
||||||
|
"extruder_settings": {
|
||||||
|
"wall_line_count": 3,
|
||||||
|
"retraction_enable": true,
|
||||||
|
"infill_sparse_density": 20,
|
||||||
|
"infill_pattern": "triangles",
|
||||||
|
"gradual_infill_steps": 0,
|
||||||
|
"default_material_print_temperature": 215,
|
||||||
|
"material_print_temperature": 220
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"quality_profile": "fast",
|
||||||
|
"models": [
|
||||||
|
{
|
||||||
|
"hash": "b72789b9beb5366dff20b1cf501020c3d4d4df7dc2295ecd0fddd0a6436df070",
|
||||||
|
"bounding_box": {
|
||||||
|
"minimum": {
|
||||||
|
"x": -10.0,
|
||||||
|
"y": 0.0,
|
||||||
|
"z": -5.0
|
||||||
|
},
|
||||||
|
"maximum": {
|
||||||
|
"x": 9.999999046325684,
|
||||||
|
"y": 40.0,
|
||||||
|
"z": 5.0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"transformation": {
|
||||||
|
"data": "[[ 1. 0. 0. 0.] [ 0. 1. 0. 20.] [ 0. 0. 1. 0.] [ 0. 0. 0. 1.]]"
|
||||||
|
},
|
||||||
|
"extruder": 0,
|
||||||
|
"model_settings": {
|
||||||
|
"support_enabled": true,
|
||||||
|
"support_extruder_nr": 1,
|
||||||
|
"infill_mesh": false,
|
||||||
|
"cutting_mesh": false,
|
||||||
|
"support_mesh": false,
|
||||||
|
"anti_overhang_mesh": false,
|
||||||
|
"wall_line_count": 3,
|
||||||
|
"retraction_enable": true,
|
||||||
|
"infill_sparse_density": 30,
|
||||||
|
"infill_pattern": "triangles",
|
||||||
|
"gradual_infill_steps": 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"print_times": {
|
||||||
|
"travel": 187,
|
||||||
|
"support": 825,
|
||||||
|
"infill": 351,
|
||||||
|
"total": 7234
|
||||||
|
},
|
||||||
|
"print_settings": {
|
||||||
|
"layer_height": 0.15,
|
||||||
|
"support_enabled": true,
|
||||||
|
"support_extruder_nr": 1,
|
||||||
|
"adhesion_type": "brim",
|
||||||
|
"wall_line_count": 3,
|
||||||
|
"retraction_enable": true,
|
||||||
|
"prime_tower_enable": true,
|
||||||
|
"infill_sparse_density": 20,
|
||||||
|
"infill_pattern": "triangles",
|
||||||
|
"gradual_infill_steps": 0,
|
||||||
|
"print_sequence": "all_at_once"
|
||||||
|
},
|
||||||
|
"output_to": "LocalFileOutputDevice"
|
||||||
|
}
|
@ -7,6 +7,7 @@ import QtQuick.Layouts 1.1
|
|||||||
import QtQuick.Controls.Styles 1.1
|
import QtQuick.Controls.Styles 1.1
|
||||||
|
|
||||||
import UM 1.1 as UM
|
import UM 1.1 as UM
|
||||||
|
import Cura 1.0 as Cura
|
||||||
|
|
||||||
UM.PreferencesPage
|
UM.PreferencesPage
|
||||||
{
|
{
|
||||||
@ -97,16 +98,26 @@ UM.PreferencesPage
|
|||||||
UM.Preferences.resetPreference("cura/choice_on_open_project")
|
UM.Preferences.resetPreference("cura/choice_on_open_project")
|
||||||
setDefaultOpenProjectOption(UM.Preferences.getValue("cura/choice_on_open_project"))
|
setDefaultOpenProjectOption(UM.Preferences.getValue("cura/choice_on_open_project"))
|
||||||
|
|
||||||
if (plugins.find("id", "SliceInfoPlugin") > -1) {
|
if (pluginExistsAndEnabled("SliceInfoPlugin")) {
|
||||||
UM.Preferences.resetPreference("info/send_slice_info")
|
UM.Preferences.resetPreference("info/send_slice_info")
|
||||||
sendDataCheckbox.checked = boolCheck(UM.Preferences.getValue("info/send_slice_info"))
|
sendDataCheckbox.checked = boolCheck(UM.Preferences.getValue("info/send_slice_info"))
|
||||||
}
|
}
|
||||||
if (plugins.find("id", "UpdateChecker") > -1) {
|
if (pluginExistsAndEnabled("UpdateChecker")) {
|
||||||
UM.Preferences.resetPreference("info/automatic_update_check")
|
UM.Preferences.resetPreference("info/automatic_update_check")
|
||||||
checkUpdatesCheckbox.checked = boolCheck(UM.Preferences.getValue("info/automatic_update_check"))
|
checkUpdatesCheckbox.checked = boolCheck(UM.Preferences.getValue("info/automatic_update_check"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function pluginExistsAndEnabled(pluginName)
|
||||||
|
{
|
||||||
|
var pluginItem = plugins.find("id", pluginName)
|
||||||
|
if (pluginItem > -1)
|
||||||
|
{
|
||||||
|
return plugins.getItem(pluginItem).enabled
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
ScrollView
|
ScrollView
|
||||||
{
|
{
|
||||||
width: parent.width
|
width: parent.width
|
||||||
@ -366,7 +377,8 @@ UM.PreferencesPage
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
UM.TooltipArea {
|
UM.TooltipArea
|
||||||
|
{
|
||||||
width: childrenRect.width;
|
width: childrenRect.width;
|
||||||
height: childrenRect.height;
|
height: childrenRect.height;
|
||||||
text: catalog.i18nc("@info:tooltip", "Should zooming move in the direction of the mouse?")
|
text: catalog.i18nc("@info:tooltip", "Should zooming move in the direction of the mouse?")
|
||||||
@ -380,7 +392,8 @@ UM.PreferencesPage
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
UM.TooltipArea {
|
UM.TooltipArea
|
||||||
|
{
|
||||||
width: childrenRect.width
|
width: childrenRect.width
|
||||||
height: childrenRect.height
|
height: childrenRect.height
|
||||||
text: catalog.i18nc("@info:tooltip", "Should models on the platform be moved so that they no longer intersect?")
|
text: catalog.i18nc("@info:tooltip", "Should models on the platform be moved so that they no longer intersect?")
|
||||||
@ -393,7 +406,8 @@ UM.PreferencesPage
|
|||||||
onCheckedChanged: UM.Preferences.setValue("physics/automatic_push_free", checked)
|
onCheckedChanged: UM.Preferences.setValue("physics/automatic_push_free", checked)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
UM.TooltipArea {
|
UM.TooltipArea
|
||||||
|
{
|
||||||
width: childrenRect.width
|
width: childrenRect.width
|
||||||
height: childrenRect.height
|
height: childrenRect.height
|
||||||
text: catalog.i18nc("@info:tooltip", "Should models on the platform be moved down to touch the build plate?")
|
text: catalog.i18nc("@info:tooltip", "Should models on the platform be moved down to touch the build plate?")
|
||||||
@ -426,7 +440,8 @@ UM.PreferencesPage
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
UM.TooltipArea {
|
UM.TooltipArea
|
||||||
|
{
|
||||||
width: childrenRect.width
|
width: childrenRect.width
|
||||||
height: childrenRect.height
|
height: childrenRect.height
|
||||||
text: catalog.i18nc("@info:tooltip", "Should layer be forced into compatibility mode?")
|
text: catalog.i18nc("@info:tooltip", "Should layer be forced into compatibility mode?")
|
||||||
@ -453,7 +468,8 @@ UM.PreferencesPage
|
|||||||
text: catalog.i18nc("@label","Opening and saving files")
|
text: catalog.i18nc("@label","Opening and saving files")
|
||||||
}
|
}
|
||||||
|
|
||||||
UM.TooltipArea {
|
UM.TooltipArea
|
||||||
|
{
|
||||||
width: childrenRect.width
|
width: childrenRect.width
|
||||||
height: childrenRect.height
|
height: childrenRect.height
|
||||||
text: catalog.i18nc("@info:tooltip","Should models be scaled to the build volume if they are too large?")
|
text: catalog.i18nc("@info:tooltip","Should models be scaled to the build volume if they are too large?")
|
||||||
@ -467,7 +483,8 @@ UM.PreferencesPage
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
UM.TooltipArea {
|
UM.TooltipArea
|
||||||
|
{
|
||||||
width: childrenRect.width
|
width: childrenRect.width
|
||||||
height: childrenRect.height
|
height: childrenRect.height
|
||||||
text: catalog.i18nc("@info:tooltip","An model may appear extremely small if its unit is for example in meters rather than millimeters. Should these models be scaled up?")
|
text: catalog.i18nc("@info:tooltip","An model may appear extremely small if its unit is for example in meters rather than millimeters. Should these models be scaled up?")
|
||||||
@ -481,7 +498,8 @@ UM.PreferencesPage
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
UM.TooltipArea {
|
UM.TooltipArea
|
||||||
|
{
|
||||||
width: childrenRect.width
|
width: childrenRect.width
|
||||||
height: childrenRect.height
|
height: childrenRect.height
|
||||||
text: catalog.i18nc("@info:tooltip", "Should a prefix based on the printer name be added to the print job name automatically?")
|
text: catalog.i18nc("@info:tooltip", "Should a prefix based on the printer name be added to the print job name automatically?")
|
||||||
@ -495,7 +513,8 @@ UM.PreferencesPage
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
UM.TooltipArea {
|
UM.TooltipArea
|
||||||
|
{
|
||||||
width: childrenRect.width
|
width: childrenRect.width
|
||||||
height: childrenRect.height
|
height: childrenRect.height
|
||||||
text: catalog.i18nc("@info:tooltip", "Should a summary be shown when saving a project file?")
|
text: catalog.i18nc("@info:tooltip", "Should a summary be shown when saving a project file?")
|
||||||
@ -508,7 +527,8 @@ UM.PreferencesPage
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
UM.TooltipArea {
|
UM.TooltipArea
|
||||||
|
{
|
||||||
width: childrenRect.width
|
width: childrenRect.width
|
||||||
height: childrenRect.height
|
height: childrenRect.height
|
||||||
text: catalog.i18nc("@info:tooltip", "Default behavior when opening a project file")
|
text: catalog.i18nc("@info:tooltip", "Default behavior when opening a project file")
|
||||||
@ -531,7 +551,8 @@ UM.PreferencesPage
|
|||||||
{
|
{
|
||||||
id: openProjectOptionModel
|
id: openProjectOptionModel
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted:
|
||||||
|
{
|
||||||
append({ text: catalog.i18nc("@option:openProject", "Always ask"), code: "always_ask" })
|
append({ text: catalog.i18nc("@option:openProject", "Always ask"), code: "always_ask" })
|
||||||
append({ text: catalog.i18nc("@option:openProject", "Always open as a project"), code: "open_as_project" })
|
append({ text: catalog.i18nc("@option:openProject", "Always open as a project"), code: "open_as_project" })
|
||||||
append({ text: catalog.i18nc("@option:openProject", "Always import models"), code: "open_as_model" })
|
append({ text: catalog.i18nc("@option:openProject", "Always import models"), code: "open_as_model" })
|
||||||
@ -591,7 +612,8 @@ UM.PreferencesPage
|
|||||||
{
|
{
|
||||||
id: discardOrKeepProfileListModel
|
id: discardOrKeepProfileListModel
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted:
|
||||||
|
{
|
||||||
append({ text: catalog.i18nc("@option:discardOrKeep", "Always ask me this"), code: "always_ask" })
|
append({ text: catalog.i18nc("@option:discardOrKeep", "Always ask me this"), code: "always_ask" })
|
||||||
append({ text: catalog.i18nc("@option:discardOrKeep", "Discard and never ask again"), code: "always_discard" })
|
append({ text: catalog.i18nc("@option:discardOrKeep", "Discard and never ask again"), code: "always_discard" })
|
||||||
append({ text: catalog.i18nc("@option:discardOrKeep", "Keep and never ask again"), code: "always_keep" })
|
append({ text: catalog.i18nc("@option:discardOrKeep", "Keep and never ask again"), code: "always_keep" })
|
||||||
@ -631,8 +653,9 @@ UM.PreferencesPage
|
|||||||
text: catalog.i18nc("@label","Privacy")
|
text: catalog.i18nc("@label","Privacy")
|
||||||
}
|
}
|
||||||
|
|
||||||
UM.TooltipArea {
|
UM.TooltipArea
|
||||||
visible: plugins.find("id", "UpdateChecker") > -1
|
{
|
||||||
|
visible: pluginExistsAndEnabled("UpdateChecker")
|
||||||
width: childrenRect.width
|
width: childrenRect.width
|
||||||
height: visible ? childrenRect.height : 0
|
height: visible ? childrenRect.height : 0
|
||||||
text: catalog.i18nc("@info:tooltip","Should Cura check for updates when the program is started?")
|
text: catalog.i18nc("@info:tooltip","Should Cura check for updates when the program is started?")
|
||||||
@ -646,8 +669,9 @@ UM.PreferencesPage
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
UM.TooltipArea {
|
UM.TooltipArea
|
||||||
visible: plugins.find("id", "SliceInfoPlugin") > -1
|
{
|
||||||
|
visible: pluginExistsAndEnabled("SliceInfoPlugin")
|
||||||
width: childrenRect.width
|
width: childrenRect.width
|
||||||
height: visible ? childrenRect.height : 0
|
height: visible ? childrenRect.height : 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.")
|
||||||
@ -659,6 +683,17 @@ 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
|
||||||
|
text: catalog.i18nc("@action:button", "More information")
|
||||||
|
onClicked:
|
||||||
|
{
|
||||||
|
CuraApplication.showMoreInformationDialogForAnonymousDataCollection();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Item
|
Item
|
||||||
@ -674,7 +709,8 @@ UM.PreferencesPage
|
|||||||
text: catalog.i18nc("@label","Experimental")
|
text: catalog.i18nc("@label","Experimental")
|
||||||
}
|
}
|
||||||
|
|
||||||
UM.TooltipArea {
|
UM.TooltipArea
|
||||||
|
{
|
||||||
width: childrenRect.width
|
width: childrenRect.width
|
||||||
height: childrenRect.height
|
height: childrenRect.height
|
||||||
text: catalog.i18nc("@info:tooltip","Use multi build plate functionality")
|
text: catalog.i18nc("@info:tooltip","Use multi build plate functionality")
|
||||||
@ -688,21 +724,29 @@ UM.PreferencesPage
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
UM.TooltipArea {
|
UM.TooltipArea
|
||||||
|
{
|
||||||
width: childrenRect.width
|
width: childrenRect.width
|
||||||
height: childrenRect.height
|
height: childrenRect.height
|
||||||
text: catalog.i18nc("@info:tooltip","Should newly loaded models be arranged on the build plate? Used in conjunction with multi build plate (EXPERIMENTAL)")
|
text: catalog.i18nc("@info:tooltip", "Should newly loaded models be arranged on the build plate? Used in conjunction with multi build plate (EXPERIMENTAL)")
|
||||||
|
|
||||||
CheckBox
|
CheckBox
|
||||||
{
|
{
|
||||||
id: arrangeOnLoadCheckbox
|
id: arrangeOnLoadCheckbox
|
||||||
text: catalog.i18nc("@option:check","Do not arrange objects on load")
|
text: catalog.i18nc("@option:check", "Do not arrange objects on load")
|
||||||
checked: boolCheck(UM.Preferences.getValue("cura/not_arrange_objects_on_load"))
|
checked: boolCheck(UM.Preferences.getValue("cura/not_arrange_objects_on_load"))
|
||||||
onCheckedChanged: UM.Preferences.setValue("cura/not_arrange_objects_on_load", checked)
|
onCheckedChanged: UM.Preferences.setValue("cura/not_arrange_objects_on_load", checked)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Connections
|
||||||
|
{
|
||||||
|
target: UM.Preferences
|
||||||
|
onPreferenceChanged:
|
||||||
|
{
|
||||||
|
sendDataCheckbox.checked = boolCheck(UM.Preferences.getValue("info/send_slice_info"))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user