mirror of
https://github.com/Ultimaker/Cura.git
synced 2025-08-05 21:13:58 -06:00
Merge branch 'master' of github.com:Ultimaker/Cura
This commit is contained in:
commit
08b79a93be
28 changed files with 352 additions and 97 deletions
|
@ -117,6 +117,8 @@ from cura.UI.AddPrinterPagesModel import AddPrinterPagesModel
|
|||
from cura.UI.WelcomePagesModel import WelcomePagesModel
|
||||
from cura.UI.WhatsNewPagesModel import WhatsNewPagesModel
|
||||
|
||||
from cura.Utils.NetworkingUtil import NetworkingUtil
|
||||
|
||||
from .SingleInstance import SingleInstance
|
||||
from .AutoSave import AutoSave
|
||||
from . import PlatformPhysics
|
||||
|
@ -1028,6 +1030,8 @@ class CuraApplication(QtApplication):
|
|||
qmlRegisterSingletonType(SimpleModeSettingsManager, "Cura", 1, 0, "SimpleModeSettingsManager", self.getSimpleModeSettingsManager)
|
||||
qmlRegisterSingletonType(MachineActionManager.MachineActionManager, "Cura", 1, 0, "MachineActionManager", self.getMachineActionManager)
|
||||
|
||||
qmlRegisterType(NetworkingUtil, "Cura", 1, 5, "NetworkingUtil")
|
||||
|
||||
qmlRegisterType(WelcomePagesModel, "Cura", 1, 0, "WelcomePagesModel")
|
||||
qmlRegisterType(WhatsNewPagesModel, "Cura", 1, 0, "WhatsNewPagesModel")
|
||||
qmlRegisterType(AddPrinterPagesModel, "Cura", 1, 0, "AddPrinterPagesModel")
|
||||
|
|
|
@ -192,7 +192,7 @@ class DiscoveredPrintersModel(QObject):
|
|||
def discoveredPrintersByAddress(self) -> Dict[str, DiscoveredPrinter]:
|
||||
return self._discovered_printer_by_ip_dict
|
||||
|
||||
@pyqtProperty(list, notify = discoveredPrintersChanged)
|
||||
@pyqtProperty("QVariantList", notify = discoveredPrintersChanged)
|
||||
def discoveredPrinters(self) -> List["DiscoveredPrinter"]:
|
||||
item_list = list(
|
||||
x for x in self._discovered_printer_by_ip_dict.values() if not parseBool(x.device.getProperty("temporary")))
|
||||
|
|
|
@ -35,6 +35,8 @@ class FirstStartMachineActionsModel(ListModel):
|
|||
self._application = application
|
||||
self._application.initializationFinished.connect(self._initialize)
|
||||
|
||||
self._previous_global_stack = None
|
||||
|
||||
def _initialize(self) -> None:
|
||||
self._application.getMachineManager().globalContainerChanged.connect(self._update)
|
||||
self._update()
|
||||
|
@ -86,6 +88,12 @@ class FirstStartMachineActionsModel(ListModel):
|
|||
self.setItems([])
|
||||
return
|
||||
|
||||
# Do not update if the machine has not been switched. This can cause the SettingProviders on the Machine
|
||||
# Setting page to do a force update, but they can use potential outdated cached values.
|
||||
if self._previous_global_stack is not None and global_stack.getId() == self._previous_global_stack.getId():
|
||||
return
|
||||
self._previous_global_stack = global_stack
|
||||
|
||||
definition_id = global_stack.definition.getId()
|
||||
first_start_actions = self._application.getMachineActionManager().getFirstStartActions(definition_id)
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ from PyQt5.QtCore import Qt, QTimer
|
|||
|
||||
from UM.Qt.ListModel import ListModel
|
||||
from UM.i18n import i18nCatalog
|
||||
from UM.Util import parseBool
|
||||
|
||||
from cura.PrinterOutput.PrinterOutputDevice import ConnectionType
|
||||
from cura.Settings.CuraContainerRegistry import CuraContainerRegistry
|
||||
|
@ -54,7 +55,6 @@ class GlobalStacksModel(ListModel):
|
|||
items = []
|
||||
|
||||
container_stacks = CuraContainerRegistry.getInstance().findContainerStacks(type = "machine")
|
||||
|
||||
for container_stack in container_stacks:
|
||||
has_remote_connection = False
|
||||
|
||||
|
@ -62,7 +62,7 @@ class GlobalStacksModel(ListModel):
|
|||
has_remote_connection |= connection_type in [ConnectionType.NetworkConnection.value,
|
||||
ConnectionType.CloudConnection.value]
|
||||
|
||||
if container_stack.getMetaDataEntry("hidden", False) in ["True", True]:
|
||||
if parseBool(container_stack.getMetaDataEntry("hidden", False)):
|
||||
continue
|
||||
|
||||
section_name = "Network enabled printers" if has_remote_connection else "Local printers"
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
from collections import defaultdict
|
||||
import threading
|
||||
from typing import Any, Dict, Optional, Set, TYPE_CHECKING, List
|
||||
import uuid
|
||||
|
||||
from PyQt5.QtCore import pyqtProperty, pyqtSlot, pyqtSignal
|
||||
|
||||
from UM.Decorators import override
|
||||
|
@ -34,6 +36,12 @@ class GlobalStack(CuraContainerStack):
|
|||
|
||||
self.setMetaDataEntry("type", "machine") # For backward compatibility
|
||||
|
||||
# TL;DR: If Cura is looking for printers that belong to the same group, it should use "group_id".
|
||||
# Each GlobalStack by default belongs to a group which is identified via "group_id". This group_id is used to
|
||||
# figure out which GlobalStacks are in the printer cluster for example without knowing the implementation
|
||||
# details such as the um_network_key or some other identifier that's used by the underlying device plugin.
|
||||
self.setMetaDataEntry("group_id", str(uuid.uuid4())) # Assign a new GlobalStack to a unique group by default
|
||||
|
||||
self._extruders = {} # type: Dict[str, "ExtruderStack"]
|
||||
|
||||
# This property is used to track which settings we are calculating the "resolve" for
|
||||
|
|
|
@ -797,7 +797,6 @@ class MachineManager(QObject):
|
|||
self.setActiveMachine(other_machine_stacks[0]["id"])
|
||||
|
||||
metadata = CuraContainerRegistry.getInstance().findContainerStacksMetadata(id = machine_id)[0]
|
||||
network_key = metadata.get("um_network_key", None)
|
||||
ExtruderManager.getInstance().removeMachineExtruders(machine_id)
|
||||
containers = CuraContainerRegistry.getInstance().findInstanceContainersMetadata(type = "user", machine = machine_id)
|
||||
for container in containers:
|
||||
|
@ -805,8 +804,9 @@ class MachineManager(QObject):
|
|||
CuraContainerRegistry.getInstance().removeContainer(machine_id)
|
||||
|
||||
# If the printer that is being removed is a network printer, the hidden printers have to be also removed
|
||||
if network_key:
|
||||
metadata_filter = {"um_network_key": network_key}
|
||||
group_id = metadata.get("group_id", None)
|
||||
if group_id:
|
||||
metadata_filter = {"group_id": group_id}
|
||||
hidden_containers = CuraContainerRegistry.getInstance().findContainerStacks(type = "machine", **metadata_filter)
|
||||
if hidden_containers:
|
||||
# This reuses the method and remove all printers recursively
|
||||
|
@ -1360,21 +1360,24 @@ class MachineManager(QObject):
|
|||
# Get the definition id corresponding to this machine name
|
||||
machine_definition_id = CuraContainerRegistry.getInstance().findDefinitionContainers(name = machine_name)[0].getId()
|
||||
# Try to find a machine with the same network key
|
||||
new_machine = self.getMachine(machine_definition_id, metadata_filter = {"um_network_key": self.activeMachineNetworkKey()})
|
||||
metadata_filter = {"group_id": self._global_container_stack.getMetaDataEntry("group_id"),
|
||||
"um_network_key": self.activeMachineNetworkKey(),
|
||||
}
|
||||
new_machine = self.getMachine(machine_definition_id, metadata_filter = metadata_filter)
|
||||
# If there is no machine, then create a new one and set it to the non-hidden instance
|
||||
if not new_machine:
|
||||
new_machine = CuraStackBuilder.createMachine(machine_definition_id + "_sync", machine_definition_id)
|
||||
if not new_machine:
|
||||
return
|
||||
new_machine.setMetaDataEntry("group_id", self._global_container_stack.getMetaDataEntry("group_id"))
|
||||
new_machine.setMetaDataEntry("um_network_key", self.activeMachineNetworkKey())
|
||||
new_machine.setMetaDataEntry("group_name", self.activeMachineNetworkGroupName)
|
||||
new_machine.setMetaDataEntry("hidden", False)
|
||||
new_machine.setMetaDataEntry("connection_type", self._global_container_stack.getMetaDataEntry("connection_type"))
|
||||
else:
|
||||
Logger.log("i", "Found a %s with the key %s. Let's use it!", machine_name, self.activeMachineNetworkKey())
|
||||
new_machine.setMetaDataEntry("hidden", False)
|
||||
|
||||
# Set the current printer instance to hidden (the metadata entry must exist)
|
||||
new_machine.setMetaDataEntry("hidden", False)
|
||||
self._global_container_stack.setMetaDataEntry("hidden", True)
|
||||
|
||||
self.setActiveMachine(new_machine.getId())
|
||||
|
@ -1654,3 +1657,7 @@ class MachineManager(QObject):
|
|||
if results:
|
||||
machine_type_name = results[0]["name"]
|
||||
return machine_type_name
|
||||
|
||||
# Gets all machines that belong to the given group_id.
|
||||
def getMachinesInGroup(self, group_id: str) -> List["GlobalStack"]:
|
||||
return self._container_registry.findContainerStacks(type = "machine", group_id = group_id)
|
||||
|
|
|
@ -15,6 +15,7 @@ class AddPrinterPagesModel(WelcomePagesModel):
|
|||
"page_url": self._getBuiltinWelcomePagePath("AddNetworkOrLocalPrinterContent.qml"),
|
||||
"next_page_id": "machine_actions",
|
||||
"next_page_button_text": self._catalog.i18nc("@action:button", "Add"),
|
||||
"previous_page_button_text": self._catalog.i18nc("@action:button", "Cancel"),
|
||||
})
|
||||
self._pages.append({"id": "add_printer_by_ip",
|
||||
"page_url": self._getBuiltinWelcomePagePath("AddPrinterByIpContent.qml"),
|
||||
|
|
|
@ -39,6 +39,7 @@ class WelcomePagesModel(ListModel):
|
|||
PageUrlRole = Qt.UserRole + 2 # URL to the page's QML file
|
||||
NextPageIdRole = Qt.UserRole + 3 # The next page ID it should go to
|
||||
NextPageButtonTextRole = Qt.UserRole + 4 # The text for the next page button
|
||||
PreviousPageButtonTextRole = Qt.UserRole + 5 # The text for the previous page button
|
||||
|
||||
def __init__(self, application: "CuraApplication", parent: Optional["QObject"] = None) -> None:
|
||||
super().__init__(parent)
|
||||
|
@ -47,6 +48,7 @@ class WelcomePagesModel(ListModel):
|
|||
self.addRoleName(self.PageUrlRole, "page_url")
|
||||
self.addRoleName(self.NextPageIdRole, "next_page_id")
|
||||
self.addRoleName(self.NextPageButtonTextRole, "next_page_button_text")
|
||||
self.addRoleName(self.PreviousPageButtonTextRole, "previous_page_button_text")
|
||||
|
||||
self._application = application
|
||||
self._catalog = i18nCatalog("cura")
|
||||
|
|
44
cura/Utils/NetworkingUtil.py
Normal file
44
cura/Utils/NetworkingUtil.py
Normal file
|
@ -0,0 +1,44 @@
|
|||
# Copyright (c) 2019 Ultimaker B.V.
|
||||
# Cura is released under the terms of the LGPLv3 or higher.
|
||||
|
||||
import socket
|
||||
from typing import Optional
|
||||
|
||||
from PyQt5.QtCore import QObject, pyqtSlot
|
||||
|
||||
|
||||
#
|
||||
# This is a QObject because some of the functions can be used (and are useful) in QML.
|
||||
#
|
||||
class NetworkingUtil(QObject):
|
||||
|
||||
def __init__(self, parent: Optional["QObject"] = None) -> None:
|
||||
super().__init__(parent = parent)
|
||||
|
||||
# Checks if the given string is a valid IPv4 address.
|
||||
@pyqtSlot(str, result = bool)
|
||||
def isIPv4(self, address: str) -> bool:
|
||||
try:
|
||||
socket.inet_pton(socket.AF_INET, address)
|
||||
result = True
|
||||
except:
|
||||
result = False
|
||||
return result
|
||||
|
||||
# Checks if the given string is a valid IPv6 address.
|
||||
@pyqtSlot(str, result = bool)
|
||||
def isIPv6(self, address: str) -> bool:
|
||||
try:
|
||||
socket.inet_pton(socket.AF_INET6, address)
|
||||
result = True
|
||||
except:
|
||||
result = False
|
||||
return result
|
||||
|
||||
# Checks if the given string is a valid IPv4 or IPv6 address.
|
||||
@pyqtSlot(str, result = bool)
|
||||
def isValidIP(self, address: str) -> bool:
|
||||
return self.isIPv4(address) or self.isIPv6(address)
|
||||
|
||||
|
||||
__all__ = ["NetworkingUtil"]
|
|
@ -285,18 +285,30 @@ Item
|
|||
optionModel: ListModel
|
||||
{
|
||||
id: extruderCountModel
|
||||
|
||||
Component.onCompleted:
|
||||
{
|
||||
extruderCountModel.clear()
|
||||
update()
|
||||
}
|
||||
|
||||
function update()
|
||||
{
|
||||
clear()
|
||||
for (var i = 1; i <= Cura.MachineManager.activeMachine.maxExtruderCount; i++)
|
||||
{
|
||||
// Use String as value. JavaScript only has Number. PropertyProvider.setPropertyValue()
|
||||
// takes a QVariant as value, and Number gets translated into a float. This will cause problem
|
||||
// for integer settings such as "Number of Extruders".
|
||||
extruderCountModel.append({ text: String(i), value: String(i) })
|
||||
append({ text: String(i), value: String(i) })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Connections
|
||||
{
|
||||
target: Cura.MachineManager
|
||||
onGlobalContainerChanged: extruderCountModel.update()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -71,7 +71,7 @@ Window
|
|||
left: parent.left
|
||||
right: parent.right
|
||||
}
|
||||
text: catalog.i18nc("@text:window", "Ultimaker Cura collects anonymous data in order to improve the print quality and user experience. Below is an example of all the data that is sent:")
|
||||
text: catalog.i18nc("@text:window", "Ultimaker Cura collects anonymous data in order to improve the print quality and user experience. Below is an example of all the data that is shared:")
|
||||
wrapMode: Text.WordWrap
|
||||
renderType: Text.NativeRendering
|
||||
}
|
||||
|
@ -106,7 +106,7 @@ Window
|
|||
Cura.RadioButton
|
||||
{
|
||||
id: dontSendButton
|
||||
text: catalog.i18nc("@text:window", "I don't want to send this data")
|
||||
text: catalog.i18nc("@text:window", "I don't want to send anonymous data")
|
||||
onClicked:
|
||||
{
|
||||
baseDialog.allowSendData = !checked
|
||||
|
@ -115,7 +115,7 @@ Window
|
|||
Cura.RadioButton
|
||||
{
|
||||
id: allowSendButton
|
||||
text: catalog.i18nc("@text:window", "Allow sending this data to Ultimaker and help us improve Cura")
|
||||
text: catalog.i18nc("@text:window", "Allow sending anonymous data")
|
||||
onClicked:
|
||||
{
|
||||
baseDialog.allowSendData = checked
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
// Copyright (c) 2018 Ultimaker B.V.
|
||||
// Copyright (c) 2019 Ultimaker B.V.
|
||||
// Cura is released under the terms of the LGPLv3 or higher.
|
||||
|
||||
import UM 1.2 as UM
|
||||
import Cura 1.0 as Cura
|
||||
import Cura 1.5 as Cura
|
||||
|
||||
import QtQuick 2.2
|
||||
import QtQuick.Controls 1.1
|
||||
|
@ -14,9 +14,13 @@ Cura.MachineAction
|
|||
{
|
||||
id: base
|
||||
anchors.fill: parent;
|
||||
property alias currentItemIndex: listview.currentIndex
|
||||
property var selectedDevice: null
|
||||
property bool completeProperties: true
|
||||
|
||||
// For validating IP addresses
|
||||
property var networkingUtil: Cura.NetworkingUtil {}
|
||||
|
||||
function connectToPrinter()
|
||||
{
|
||||
if(base.selectedDevice && base.completeProperties)
|
||||
|
@ -342,6 +346,17 @@ Cura.MachineAction
|
|||
}
|
||||
}
|
||||
|
||||
MessageDialog
|
||||
{
|
||||
id: invalidIPAddressMessageDialog
|
||||
x: (parent.x + (parent.width) / 2) | 0
|
||||
y: (parent.y + (parent.height) / 2) | 0
|
||||
title: catalog.i18nc("@title:window", "Invalid IP address")
|
||||
text: catalog.i18nc("@text", "Please enter a valid IP address.")
|
||||
icon: StandardIcon.Warning
|
||||
standardButtons: StandardButton.Ok
|
||||
}
|
||||
|
||||
UM.Dialog
|
||||
{
|
||||
id: manualPrinterDialog
|
||||
|
@ -404,6 +419,26 @@ Cura.MachineAction
|
|||
text: catalog.i18nc("@action:button", "OK")
|
||||
onClicked:
|
||||
{
|
||||
// Validate the input first
|
||||
if (!networkingUtil.isValidIP(manualPrinterDialog.addressText))
|
||||
{
|
||||
invalidIPAddressMessageDialog.open()
|
||||
return
|
||||
}
|
||||
|
||||
// if the entered IP address has already been discovered, switch the current item to that item
|
||||
// and do nothing else.
|
||||
for (var i = 0; i < manager.foundDevices.length; i++)
|
||||
{
|
||||
var device = manager.foundDevices[i]
|
||||
if (device.address == manualPrinterDialog.addressText)
|
||||
{
|
||||
currentItemIndex = i
|
||||
manualPrinterDialog.hide()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
manager.setManualDevice(manualPrinterDialog.printerKey, manualPrinterDialog.addressText)
|
||||
manualPrinterDialog.hide()
|
||||
}
|
||||
|
|
|
@ -110,14 +110,12 @@ class DiscoverUM3Action(MachineAction):
|
|||
Logger.log("d", "Attempting to set the group name of the active machine to %s", group_name)
|
||||
global_container_stack = CuraApplication.getInstance().getGlobalContainerStack()
|
||||
if global_container_stack:
|
||||
meta_data = global_container_stack.getMetaData()
|
||||
if "group_name" in meta_data:
|
||||
previous_connect_group_name = meta_data["group_name"]
|
||||
global_container_stack.setMetaDataEntry("group_name", group_name)
|
||||
# Find all the places where there is the same group name and change it accordingly
|
||||
self._replaceContainersMetadata(key = "group_name", value = previous_connect_group_name, new_value = group_name)
|
||||
else:
|
||||
global_container_stack.setMetaDataEntry("group_name", group_name)
|
||||
# Update a GlobalStacks in the same group with the new group name.
|
||||
group_id = global_container_stack.getMetaDataEntry("group_id")
|
||||
machine_manager = CuraApplication.getInstance().getMachineManager()
|
||||
for machine in machine_manager.getMachinesInGroup(group_id):
|
||||
machine.setMetaDataEntry("group_name", group_name)
|
||||
|
||||
# Set the default value for "hidden", which is used when you have a group with multiple types of printers
|
||||
global_container_stack.setMetaDataEntry("hidden", False)
|
||||
|
||||
|
@ -125,13 +123,6 @@ class DiscoverUM3Action(MachineAction):
|
|||
# Ensure that the connection states are refreshed.
|
||||
self._network_plugin.refreshConnections()
|
||||
|
||||
## Find all container stacks that has the pair 'key = value' in its metadata and replaces the value with 'new_value'
|
||||
def _replaceContainersMetadata(self, key: str, value: str, new_value: str) -> None:
|
||||
machines = CuraContainerRegistry.getInstance().findContainerStacks(type="machine")
|
||||
for machine in machines:
|
||||
if machine.getMetaDataEntry(key) == value:
|
||||
machine.setMetaDataEntry(key, new_value)
|
||||
|
||||
# Associates the currently active machine with the given printer device. The network connection information will be
|
||||
# stored into the metadata of the currently active machine.
|
||||
@pyqtSlot(QObject)
|
||||
|
|
|
@ -283,34 +283,24 @@ class UM3OutputDevicePlugin(OutputDevicePlugin):
|
|||
|
||||
Logger.log("d", "Attempting to set the network key of the active machine to %s", printer_device.key)
|
||||
|
||||
global_container_stack = CuraApplication.getInstance().getGlobalContainerStack()
|
||||
machine_manager = CuraApplication.getInstance().getMachineManager()
|
||||
global_container_stack = machine_manager.activeMachine
|
||||
if not global_container_stack:
|
||||
return
|
||||
|
||||
meta_data = global_container_stack.getMetaData()
|
||||
for machine in machine_manager.getMachinesInGroup(global_container_stack.getMetaDataEntry("group_id")):
|
||||
machine.setMetaDataEntry("um_network_key", printer_device.key)
|
||||
machine.setMetaDataEntry("group_name", printer_device.name)
|
||||
|
||||
if "um_network_key" in meta_data: # Global stack already had a connection, but it's changed.
|
||||
old_network_key = meta_data["um_network_key"]
|
||||
# Since we might have a bunch of hidden stacks, we also need to change it there.
|
||||
metadata_filter = {"um_network_key": old_network_key}
|
||||
containers = self._application.getContainerRegistry().findContainerStacks(type = "machine", **metadata_filter)
|
||||
# Delete old authentication data.
|
||||
Logger.log("d", "Removing old authentication id %s for device %s",
|
||||
global_container_stack.getMetaDataEntry("network_authentication_id", None), printer_device.key)
|
||||
|
||||
for container in containers:
|
||||
container.setMetaDataEntry("um_network_key", printer_device.key)
|
||||
machine.removeMetaDataEntry("network_authentication_id")
|
||||
machine.removeMetaDataEntry("network_authentication_key")
|
||||
|
||||
# Delete old authentication data.
|
||||
Logger.log("d", "Removing old authentication id %s for device %s",
|
||||
global_container_stack.getMetaDataEntry("network_authentication_id", None), printer_device.key)
|
||||
|
||||
container.removeMetaDataEntry("network_authentication_id")
|
||||
container.removeMetaDataEntry("network_authentication_key")
|
||||
|
||||
# Ensure that these containers do know that they are configured for network connection
|
||||
container.addConfiguredConnectionType(printer_device.connectionType.value)
|
||||
|
||||
else: # Global stack didn't have a connection yet, configure it.
|
||||
global_container_stack.setMetaDataEntry("um_network_key", printer_device.key)
|
||||
global_container_stack.addConfiguredConnectionType(printer_device.connectionType.value)
|
||||
# Ensure that these containers do know that they are configured for network connection
|
||||
machine.addConfiguredConnectionType(printer_device.connectionType.value)
|
||||
|
||||
self.refreshConnections()
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
import configparser
|
||||
import io
|
||||
import uuid
|
||||
from typing import Dict, List, Tuple
|
||||
|
||||
from UM.VersionUpgrade import VersionUpgrade
|
||||
|
@ -18,6 +19,7 @@ _renamed_quality_profiles = {
|
|||
"gmax15plus_pla_very_thick": "gmax15plus_global_very_thick"
|
||||
} # type: Dict[str, str]
|
||||
|
||||
|
||||
## Upgrades configurations from the state they were in at version 4.0 to the
|
||||
# state they should be in at version 4.1.
|
||||
class VersionUpgrade40to41(VersionUpgrade):
|
||||
|
@ -95,6 +97,13 @@ class VersionUpgrade40to41(VersionUpgrade):
|
|||
if parser["containers"]["4"] in _renamed_quality_profiles:
|
||||
parser["containers"]["4"] = _renamed_quality_profiles[parser["containers"]["4"]]
|
||||
|
||||
# Assign a GlobalStack to a unique group_id. If the GlobalStack has a UM network connection, use the UM network
|
||||
# key as the group_id.
|
||||
if "um_network_key" in parser["metadata"]:
|
||||
parser["metadata"]["group_id"] = parser["metadata"]["um_network_key"]
|
||||
elif "group_id" not in parser["metadata"]:
|
||||
parser["metadata"]["group_id"] = str(uuid.uuid4())
|
||||
|
||||
result = io.StringIO()
|
||||
parser.write(result)
|
||||
return [filename], [result.getvalue()]
|
||||
|
|
45
resources/definitions/anet_a6.def.json
Normal file
45
resources/definitions/anet_a6.def.json
Normal file
|
@ -0,0 +1,45 @@
|
|||
{
|
||||
"version": 2,
|
||||
"name": "Anet A6",
|
||||
"inherits": "fdmprinter",
|
||||
"metadata": {
|
||||
"visible": true,
|
||||
"author": "Mark",
|
||||
"manufacturer": "Anet",
|
||||
"file_formats": "text/x-gcode",
|
||||
"platform": "aneta6_platform.stl",
|
||||
"platform_offset": [0, -3.4, 0],
|
||||
"machine_extruder_trains":
|
||||
{
|
||||
"0": "anet_a6_extruder_0"
|
||||
}
|
||||
},
|
||||
|
||||
"overrides": {
|
||||
"machine_name": { "default_value": "Anet A6" },
|
||||
"machine_heated_bed": {
|
||||
"default_value": true
|
||||
},
|
||||
"machine_width": {
|
||||
"default_value": 220
|
||||
},
|
||||
"machine_height": {
|
||||
"default_value": 250
|
||||
},
|
||||
"machine_depth": {
|
||||
"default_value": 220
|
||||
},
|
||||
"machine_center_is_zero": {
|
||||
"default_value": false
|
||||
},
|
||||
"gantry_height": {
|
||||
"default_value": 55
|
||||
},
|
||||
"machine_start_gcode": {
|
||||
"default_value": "G21 ;metric values\nG90 ;absolute positioning\nM82 ;set extruder to absolute mode\nM107 ;start with the fan off\nG28 X0 Y0 ;move X/Y to min endstops\nG28 Z0 ;move Z to min endstops\nM84 ;steppers off\nM0 S12 ;wait 12 seconds\nM17 ;turn steppers on\nG1 Z10.0 F300 ;move the platform down 10mm\nG92 E0 ;zero the extruded length\nG1 F200 E8 ;extrude 8mm of feed stock\nG92 E0 ;zero the extruded length again\nM0 S5 ;wait 5 seconds\nG1 F9000\nM117 Printing..."
|
||||
},
|
||||
"machine_end_gcode": {
|
||||
"default_value": "M104 S0 ;extruder heater off\nM140 S0 ;heated bed heater off (if you have it)\nG91 ;relative positioning\nG1 E-1 F300 ;retract the filament a bit before lifting the nozzle, to release some of the pressure\nG1 Z+4 E-5 X-20 Y-20 F9000 ;move Z up a bit and retract filament even more\nG28 X0 Y0 ;move X/Y to min endstops, so the head is out of the way\nG1 Y210 F9000 ;move out to get part off\nM84 ;steppers off\nG90 ;absolute positioning"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5248,7 +5248,7 @@
|
|||
"type": "bool",
|
||||
"enabled": "extruders_enabled_count > 1",
|
||||
"default_value": false,
|
||||
"resolve": "any(extruderValues('prime_tower_enable'))",
|
||||
"resolve": "any(extruderValues('prime_tower_enable')) or (adhesion_type in ('none', 'skirt'))",
|
||||
"settable_per_mesh": false,
|
||||
"settable_per_extruder": false
|
||||
},
|
||||
|
|
16
resources/extruders/anet_a6_extruder_0.def.json
Normal file
16
resources/extruders/anet_a6_extruder_0.def.json
Normal file
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"id": "anet_a6_extruder_0",
|
||||
"version": 2,
|
||||
"name": "Extruder 1",
|
||||
"inherits": "fdmextruder",
|
||||
"metadata": {
|
||||
"machine": "anet_a6",
|
||||
"position": "0"
|
||||
},
|
||||
|
||||
"overrides": {
|
||||
"extruder_nr": { "default_value": 0 },
|
||||
"machine_nozzle_size": { "default_value": 0.4 },
|
||||
"material_diameter": { "default_value": 1.75 }
|
||||
}
|
||||
}
|
BIN
resources/meshes/aneta6_platform.stl
Normal file
BIN
resources/meshes/aneta6_platform.stl
Normal file
Binary file not shown.
|
@ -795,7 +795,6 @@ UM.MainWindow
|
|||
title: catalog.i18nc("@title:window", "Add Printer")
|
||||
model: CuraApplication.getAddPrinterPagesModel()
|
||||
progressBarVisible: false
|
||||
hasCancelButton: true
|
||||
}
|
||||
|
||||
Cura.WizardDialog
|
||||
|
@ -804,7 +803,6 @@ UM.MainWindow
|
|||
title: catalog.i18nc("@title:window", "What's New")
|
||||
model: CuraApplication.getWhatsNewPagesModel()
|
||||
progressBarVisible: false
|
||||
hasCancelButton: false
|
||||
}
|
||||
|
||||
Connections
|
||||
|
|
|
@ -3,7 +3,26 @@
|
|||
|
||||
import QtQuick 2.10
|
||||
import QtQuick.Controls 2.3
|
||||
import QtGraphicalEffects 1.0 // For the dropshadow
|
||||
|
||||
import UM 1.2 as UM
|
||||
|
||||
// Empty placeholder
|
||||
Item { }
|
||||
Rectangle
|
||||
{
|
||||
color: UM.Theme.getColor("disabled")
|
||||
|
||||
DropShadow
|
||||
{
|
||||
id: shadow
|
||||
// Don't blur the shadow
|
||||
radius: 0
|
||||
anchors.fill: parent
|
||||
source: parent
|
||||
verticalOffset: 2
|
||||
visible: true
|
||||
color: UM.Theme.getColor("action_button_shadow")
|
||||
// Should always be drawn behind the background.
|
||||
z: parent.z - 1
|
||||
}
|
||||
}
|
||||
|
|
|
@ -76,6 +76,4 @@ NumericTextFieldWithUnit
|
|||
forceUpdateOnChangeFunction()
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: add forceUpdateOnChangeFunction:
|
||||
}
|
||||
|
|
|
@ -32,16 +32,7 @@ ListView
|
|||
width: listView.width
|
||||
outputDevice: Cura.MachineManager.printerOutputDevices.length >= 1 ? Cura.MachineManager.printerOutputDevices[0] : null
|
||||
|
||||
checked:
|
||||
{
|
||||
// If the machine has a remote connection
|
||||
var result = Cura.MachineManager.activeMachineId == model.id
|
||||
if (Cura.MachineManager.activeMachineHasRemoteConnection)
|
||||
{
|
||||
result |= Cura.MachineManager.activeMachineNetworkGroupName == model.metadata["group_name"]
|
||||
}
|
||||
return result
|
||||
}
|
||||
checked: Cura.MachineManager.activeMachineId == model.id
|
||||
|
||||
onClicked:
|
||||
{
|
||||
|
|
|
@ -98,6 +98,20 @@ Item
|
|||
}
|
||||
}
|
||||
|
||||
// This "Back" button only shows in the "Add Machine" dialog, which has "previous_page_button_text" set to "Cancel"
|
||||
Cura.SecondaryButton
|
||||
{
|
||||
id: backButton
|
||||
anchors.left: parent.left
|
||||
anchors.bottom: parent.bottom
|
||||
visible: base.currentItem.previous_page_button_text ? true : false
|
||||
text: base.currentItem.previous_page_button_text ? base.currentItem.previous_page_button_text : ""
|
||||
onClicked:
|
||||
{
|
||||
base.endWizard()
|
||||
}
|
||||
}
|
||||
|
||||
Cura.PrimaryButton
|
||||
{
|
||||
id: nextButton
|
||||
|
|
|
@ -76,15 +76,28 @@ Item
|
|||
|
||||
Component.onCompleted:
|
||||
{
|
||||
// Select the first one that's not "unknown" by default.
|
||||
var toSelectIndex = -1
|
||||
// Select the first one that's not "unknown" and is the host a group by default.
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
if (!model[i].isUnknownMachineType)
|
||||
if (!model[i].isUnknownMachineType && model[i].isHostOfGroup)
|
||||
{
|
||||
currentIndex = i
|
||||
toSelectIndex = i
|
||||
break
|
||||
}
|
||||
}
|
||||
currentIndex = toSelectIndex
|
||||
}
|
||||
|
||||
// CURA-6483 For some reason currentIndex can be reset to 0. This check is here to prevent automatically
|
||||
// selecting an unknown or non-host printer.
|
||||
onCurrentIndexChanged:
|
||||
{
|
||||
var item = model[currentIndex]
|
||||
if (!item || item.isUnknownMachineType || !item.isHostOfGroup)
|
||||
{
|
||||
currentIndex = -1
|
||||
}
|
||||
}
|
||||
|
||||
Component
|
||||
|
|
|
@ -6,7 +6,7 @@ import QtQuick.Controls 2.3
|
|||
import QtQuick.Layouts 1.3
|
||||
|
||||
import UM 1.3 as UM
|
||||
import Cura 1.1 as Cura
|
||||
import Cura 1.5 as Cura
|
||||
|
||||
|
||||
//
|
||||
|
@ -22,9 +22,35 @@ Item
|
|||
property bool hasRequestInProgress: CuraApplication.getDiscoveredPrintersModel().hasManualDeviceRequestInProgress
|
||||
// Indicates if a request has finished.
|
||||
property bool hasRequestFinished: false
|
||||
property string currentRequestAddress: ""
|
||||
|
||||
property var discoveredPrinter: null
|
||||
property var isPrinterDiscovered: discoveredPrinter != null
|
||||
property bool isPrinterDiscovered: discoveredPrinter != null
|
||||
// A printer can only be added if it doesn't have an unknown type and it's the host of a group.
|
||||
property bool canAddPrinter: isPrinterDiscovered && !discoveredPrinter.isUnknownMachineType && discoveredPrinter.isHostOfGroup
|
||||
|
||||
// For validating IP address
|
||||
property var networkingUtil: Cura.NetworkingUtil {}
|
||||
|
||||
// CURA-6483
|
||||
// For a manually added UM printer, the UM3OutputDevicePlugin will first create a LegacyUM device for it. Later,
|
||||
// when it gets more info from the printer, it will first REMOVE the LegacyUM device and then add a ClusterUM device.
|
||||
// The Add-by-IP page needs to make sure that the user do not add an unknown printer or a printer that's not the
|
||||
// host of a group. Because of the device list change, this page needs to react upon DiscoveredPrintersChanged so
|
||||
// it has the correct information.
|
||||
Connections
|
||||
{
|
||||
target: CuraApplication.getDiscoveredPrintersModel()
|
||||
onDiscoveredPrintersChanged:
|
||||
{
|
||||
if (hasRequestFinished && currentRequestAddress)
|
||||
{
|
||||
var printer = CuraApplication.getDiscoveredPrintersModel().discoveredPrintersByAddress[currentRequestAddress]
|
||||
printer = printer ? printer : null
|
||||
discoveredPrinter = printer
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure to cancel the current request when this page closes.
|
||||
onVisibleChanged:
|
||||
|
@ -93,17 +119,36 @@ Item
|
|||
anchors.verticalCenter: addPrinterButton.verticalCenter
|
||||
anchors.left: parent.left
|
||||
|
||||
signal invalidInputDetected()
|
||||
|
||||
onInvalidInputDetected: invalidInputLabel.visible = true
|
||||
|
||||
validator: RegExpValidator
|
||||
{
|
||||
regExp: /((^\s*((([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))\s*$)|(^\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*$))?/
|
||||
regExp: /([a-fA-F0-9.:]+)?/
|
||||
}
|
||||
|
||||
onTextEdited: invalidInputLabel.visible = false
|
||||
|
||||
placeholderText: catalog.i18nc("@text", "Place enter your printer's IP address.")
|
||||
|
||||
enabled: { ! (addPrinterByIpScreen.hasRequestInProgress || addPrinterByIpScreen.isPrinterDiscovered) }
|
||||
onAccepted: addPrinterButton.clicked()
|
||||
}
|
||||
|
||||
Label
|
||||
{
|
||||
id: invalidInputLabel
|
||||
anchors.top: hostnameField.bottom
|
||||
anchors.topMargin: UM.Theme.getSize("default_margin").height
|
||||
anchors.left: parent.left
|
||||
visible: false
|
||||
text: catalog.i18nc("@text", "Please enter a valid IP address.")
|
||||
font: UM.Theme.getFont("default")
|
||||
color: UM.Theme.getColor("text")
|
||||
renderType: Text.NativeRendering
|
||||
}
|
||||
|
||||
Cura.SecondaryButton
|
||||
{
|
||||
id: addPrinterButton
|
||||
|
@ -115,14 +160,21 @@ Item
|
|||
onClicked:
|
||||
{
|
||||
const address = hostnameField.text
|
||||
if (!networkingUtil.isValidIP(address))
|
||||
{
|
||||
hostnameField.invalidInputDetected()
|
||||
return
|
||||
}
|
||||
|
||||
// This address is already in the discovered printer model, no need to add a manual discovery.
|
||||
if (CuraApplication.getDiscoveredPrintersModel().discoveredPrintersByAddress[address])
|
||||
{
|
||||
addPrinterByIpScreen.discoveredPrinter = CuraApplication.getDiscoveredPrintersModel().discoveredPrintersByAddress[address]
|
||||
addPrinterByIpScreen.hasRequestFinished = true
|
||||
return
|
||||
}
|
||||
|
||||
addPrinterByIpScreen.currentRequestAddress = address
|
||||
CuraApplication.getDiscoveredPrintersModel().checkManualDevice(address)
|
||||
}
|
||||
busy: addPrinterByIpScreen.hasRequestInProgress
|
||||
|
@ -161,6 +213,8 @@ Item
|
|||
Item
|
||||
{
|
||||
id: printerInfoLabels
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.top: parent.top
|
||||
anchors.margins: UM.Theme.getSize("default_margin").width
|
||||
|
||||
|
@ -177,10 +231,24 @@ Item
|
|||
text: !addPrinterByIpScreen.isPrinterDiscovered ? "???" : addPrinterByIpScreen.discoveredPrinter.name
|
||||
}
|
||||
|
||||
Label
|
||||
{
|
||||
id: printerCannotBeAddedLabel
|
||||
width: parent.width
|
||||
anchors.top: printerNameLabel.bottom
|
||||
anchors.topMargin: UM.Theme.getSize("default_margin").height
|
||||
text: catalog.i18nc("@label", "This printer cannot be added because it's an unknown printer or it's not the host of a group.")
|
||||
visible: addPrinterByIpScreen.hasRequestFinished && !addPrinterByIpScreen.canAddPrinter
|
||||
font: UM.Theme.getFont("default_bold")
|
||||
color: UM.Theme.getColor("text")
|
||||
renderType: Text.NativeRendering
|
||||
wrapMode: Text.WordWrap
|
||||
}
|
||||
|
||||
GridLayout
|
||||
{
|
||||
id: printerInfoGrid
|
||||
anchors.top: printerNameLabel.bottom
|
||||
anchors.top: printerCannotBeAddedLabel ? printerCannotBeAddedLabel.bottom : printerNameLabel.bottom
|
||||
anchors.margins: UM.Theme.getSize("default_margin").width
|
||||
columns: 2
|
||||
columnSpacing: UM.Theme.getSize("default_margin").width
|
||||
|
@ -253,7 +321,7 @@ Item
|
|||
}
|
||||
}
|
||||
|
||||
Cura.PrimaryButton
|
||||
Cura.SecondaryButton
|
||||
{
|
||||
id: backButton
|
||||
anchors.left: parent.left
|
||||
|
@ -278,6 +346,6 @@ Item
|
|||
base.showNextPage()
|
||||
}
|
||||
|
||||
enabled: addPrinterByIpScreen.isPrinterDiscovered
|
||||
enabled: addPrinterByIpScreen.canAddPrinter
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@ Item
|
|||
horizontalAlignment: Text.AlignHCenter
|
||||
text: catalog.i18nc("@label", "Ultimaker Cloud")
|
||||
color: UM.Theme.getColor("primary_button")
|
||||
font: UM.Theme.getFont("large_bold")
|
||||
font: UM.Theme.getFont("huge")
|
||||
renderType: Text.NativeRendering
|
||||
}
|
||||
|
||||
|
|
|
@ -31,7 +31,6 @@ Window
|
|||
|
||||
property var model: null // Needs to be set by whoever is using this dialog.
|
||||
property alias progressBarVisible: wizardPanel.progressBarVisible
|
||||
property alias hasCancelButton: cancelButton.visible
|
||||
|
||||
onVisibilityChanged:
|
||||
{
|
||||
|
@ -54,21 +53,4 @@ Window
|
|||
target: model
|
||||
onAllFinished: dialog.hide()
|
||||
}
|
||||
|
||||
Cura.SecondaryButton
|
||||
{
|
||||
id: cancelButton
|
||||
|
||||
text: catalog.i18nc("@button", "Cancel")
|
||||
|
||||
visible: false
|
||||
|
||||
anchors.left: parent.left
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.margins: UM.Theme.getSize("default_margin").width
|
||||
anchors.leftMargin: UM.Theme.getSize("wide_margin").width
|
||||
|
||||
enabled: true
|
||||
onClicked: dialog.visible = false
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue