mirror of
https://git.mirrors.martin98.com/https://github.com/Ultimaker/Cura
synced 2025-05-24 23:29:00 +08:00
Merge branch 'master' into feature_tree_support
This commit is contained in:
commit
eb1efc4928
@ -56,11 +56,6 @@ class ConvexHullDecorator(SceneNodeDecorator):
|
||||
if self._node is None:
|
||||
return None
|
||||
|
||||
if getattr(self._node, "_non_printing_mesh", False):
|
||||
# infill_mesh, cutting_mesh and anti_overhang_mesh do not need a convex hull
|
||||
# node._non_printing_mesh is set in SettingOverrideDecorator
|
||||
return None
|
||||
|
||||
hull = self._compute2DConvexHull()
|
||||
|
||||
if self._global_stack and self._node:
|
||||
|
@ -59,7 +59,7 @@ class CrashHandler:
|
||||
self.data = dict()
|
||||
self.data["time_stamp"] = time.time()
|
||||
|
||||
Logger.log("c", "An uncaught exception has occurred!")
|
||||
Logger.log("c", "An uncaught error has occurred!")
|
||||
for line in traceback.format_exception(exception_type, value, tb):
|
||||
for part in line.rstrip("\n").split("\n"):
|
||||
Logger.log("c", part)
|
||||
@ -90,7 +90,7 @@ class CrashHandler:
|
||||
|
||||
def _messageWidget(self):
|
||||
label = QLabel()
|
||||
label.setText(catalog.i18nc("@label crash message", """<p><b>A fatal exception has occurred. Please send us this Crash Report to fix the problem</p></b>
|
||||
label.setText(catalog.i18nc("@label crash message", """<p><b>A fatal error has occurred. Please send us this Crash Report to fix the problem</p></b>
|
||||
<p>Please use the "Send report" button to post a bug report automatically to our servers</p>
|
||||
"""))
|
||||
|
||||
@ -143,7 +143,7 @@ class CrashHandler:
|
||||
|
||||
def _exceptionInfoWidget(self):
|
||||
group = QGroupBox()
|
||||
group.setTitle(catalog.i18nc("@title:groupbox", "Exception traceback"))
|
||||
group.setTitle(catalog.i18nc("@title:groupbox", "Error traceback"))
|
||||
layout = QVBoxLayout()
|
||||
|
||||
text_area = QTextEdit()
|
||||
|
@ -127,7 +127,7 @@ class CuraApplication(QtApplication):
|
||||
# Cura will always show the Add Machine Dialog upon start.
|
||||
stacksValidationFinished = pyqtSignal() # Emitted whenever a validation is finished
|
||||
|
||||
def __init__(self):
|
||||
def __init__(self, **kwargs):
|
||||
|
||||
# this list of dir names will be used by UM to detect an old cura directory
|
||||
for dir_name in ["extruders", "machine_instances", "materials", "plugins", "quality", "user", "variants"]:
|
||||
@ -208,9 +208,12 @@ class CuraApplication(QtApplication):
|
||||
|
||||
self._additional_components = {} # Components to add to certain areas in the interface
|
||||
|
||||
super().__init__(name = "cura", version = CuraVersion, buildtype = CuraBuildType,
|
||||
super().__init__(name = "cura",
|
||||
version = CuraVersion,
|
||||
buildtype = CuraBuildType,
|
||||
is_debug_mode = CuraDebugMode,
|
||||
tray_icon_name = "cura-icon-32.png")
|
||||
tray_icon_name = "cura-icon-32.png",
|
||||
**kwargs)
|
||||
|
||||
self.default_theme = "cura-light"
|
||||
|
||||
@ -313,6 +316,7 @@ class CuraApplication(QtApplication):
|
||||
preferences.addPreference("cura/material_settings", "{}")
|
||||
|
||||
preferences.addPreference("view/invert_zoom", False)
|
||||
preferences.addPreference("cura/sidebar_collapse", False)
|
||||
|
||||
self._need_to_show_user_agreement = not Preferences.getInstance().getValue("general/accepted_user_agreement")
|
||||
|
||||
@ -399,7 +403,11 @@ class CuraApplication(QtApplication):
|
||||
@pyqtSlot()
|
||||
def closeApplication(self):
|
||||
Logger.log("i", "Close application")
|
||||
self._main_window.close()
|
||||
main_window = self.getMainWindow()
|
||||
if main_window is not None:
|
||||
main_window.close()
|
||||
else:
|
||||
self.exit(0)
|
||||
|
||||
## A reusable dialogbox
|
||||
#
|
||||
@ -507,11 +515,10 @@ class CuraApplication(QtApplication):
|
||||
self._plugins_loaded = True
|
||||
|
||||
@classmethod
|
||||
def addCommandLineOptions(self, parser):
|
||||
super().addCommandLineOptions(parser)
|
||||
def addCommandLineOptions(self, parser, parsed_command_line = {}):
|
||||
super().addCommandLineOptions(parser, parsed_command_line = parsed_command_line)
|
||||
parser.add_argument("file", nargs="*", help="Files to load after starting the application.")
|
||||
parser.add_argument("--single-instance", action="store_true", default=False)
|
||||
parser.add_argument("--headless", action = "store_true", default=False)
|
||||
|
||||
# Set up a local socket server which listener which coordinates single instances Curas and accepts commands.
|
||||
def _setUpSingleInstanceServer(self):
|
||||
@ -565,13 +572,16 @@ class CuraApplication(QtApplication):
|
||||
# This should be called directly before creating an instance of CuraApplication.
|
||||
# \returns \type{bool} True if the whole Cura app should continue running.
|
||||
@classmethod
|
||||
def preStartUp(cls):
|
||||
def preStartUp(cls, parser = None, parsed_command_line = {}):
|
||||
# Peek the arguments and look for the 'single-instance' flag.
|
||||
parser = argparse.ArgumentParser(prog="cura") # pylint: disable=bad-whitespace
|
||||
CuraApplication.addCommandLineOptions(parser)
|
||||
parsed_command_line = vars(parser.parse_args())
|
||||
if not parser:
|
||||
parser = argparse.ArgumentParser(prog = "cura", add_help = False) # pylint: disable=bad-whitespace
|
||||
CuraApplication.addCommandLineOptions(parser, parsed_command_line = parsed_command_line)
|
||||
# Important: It is important to keep this line here!
|
||||
# In Uranium we allow to pass unknown arguments to the final executable or script.
|
||||
parsed_command_line.update(vars(parser.parse_known_args()[0]))
|
||||
|
||||
if "single_instance" in parsed_command_line and parsed_command_line["single_instance"]:
|
||||
if parsed_command_line["single_instance"]:
|
||||
Logger.log("i", "Checking for the presence of an ready running Cura instance.")
|
||||
single_instance_socket = QLocalSocket()
|
||||
Logger.log("d", "preStartUp(): full server name: " + single_instance_socket.fullServerName())
|
||||
@ -603,7 +613,22 @@ class CuraApplication(QtApplication):
|
||||
return False
|
||||
return True
|
||||
|
||||
def preRun(self):
|
||||
# Last check for unknown commandline arguments
|
||||
parser = self.getCommandlineParser()
|
||||
parser.add_argument("--help", "-h",
|
||||
action='store_true',
|
||||
default = False,
|
||||
help = "Show this help message and exit."
|
||||
)
|
||||
parsed_args = vars(parser.parse_args()) # This won't allow unknown arguments
|
||||
if parsed_args["help"]:
|
||||
parser.print_help()
|
||||
sys.exit(0)
|
||||
|
||||
def run(self):
|
||||
self.preRun()
|
||||
|
||||
self.showSplashMessage(self._i18n_catalog.i18nc("@info:progress", "Setting up scene..."))
|
||||
|
||||
self._setUpSingleInstanceServer()
|
||||
@ -658,12 +683,12 @@ class CuraApplication(QtApplication):
|
||||
self.setMainQml(Resources.getPath(self.ResourceTypes.QmlFiles, "Cura.qml"))
|
||||
self._qml_import_paths.append(Resources.getPath(self.ResourceTypes.QmlFiles))
|
||||
|
||||
run_headless = self.getCommandLineOption("headless", False)
|
||||
if not run_headless:
|
||||
run_without_gui = self.getCommandLineOption("headless", False) or self.getCommandLineOption("invisible", False)
|
||||
if not run_without_gui:
|
||||
self.initializeEngine()
|
||||
controller.setActiveStage("PrepareStage")
|
||||
|
||||
if run_headless or self._engine.rootObjects:
|
||||
if run_without_gui or self._engine.rootObjects:
|
||||
self.closeSplash()
|
||||
|
||||
for file_name in self.getCommandLineOption("file", []):
|
||||
@ -1361,7 +1386,8 @@ class CuraApplication(QtApplication):
|
||||
# If a model is to small then it will not contain any points
|
||||
if offset_shape_arr is None and hull_shape_arr is None:
|
||||
Message(self._i18n_catalog.i18nc("@info:status", "The selected model was too small to load."),
|
||||
title=self._i18n_catalog.i18nc("@info:title", "Warning")).show()
|
||||
title=self._i18n_catalog.i18nc("@info:title", "Warning")
|
||||
).show()
|
||||
return
|
||||
|
||||
# Step is for skipping tests to make it a lot faster. it also makes the outcome somewhat rougher
|
||||
|
@ -16,6 +16,7 @@ import math
|
||||
import os.path
|
||||
import unicodedata
|
||||
import json
|
||||
import re #To create abbreviations for printer names.
|
||||
|
||||
from UM.i18n import i18nCatalog
|
||||
catalog = i18nCatalog("cura")
|
||||
@ -316,15 +317,14 @@ class PrintInformation(QObject):
|
||||
return
|
||||
|
||||
global_stack_name = global_container_stack.getName()
|
||||
split_name = global_stack_name.split(" ")
|
||||
abbr_machine = ""
|
||||
for word in split_name:
|
||||
for word in re.findall(r"[\w']+", global_stack_name):
|
||||
if word.lower() == "ultimaker":
|
||||
abbr_machine += "UM"
|
||||
elif word.isdigit():
|
||||
abbr_machine += word
|
||||
else:
|
||||
stripped_word = self._stripAccents(word.strip("()[]{}#").upper())
|
||||
stripped_word = self._stripAccents(word.upper())
|
||||
# - use only the first character if the word is too long (> 3 characters)
|
||||
# - use the whole word if it's not too long (<= 3 characters)
|
||||
if len(stripped_word) > 3:
|
||||
|
@ -36,6 +36,11 @@ class CuraContainerRegistry(ContainerRegistry):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
# We don't have all the machines loaded in the beginning, so in order to add the missing extruder stack
|
||||
# for single extrusion machines, we subscribe to the containerAdded signal, and whenever a global stack
|
||||
# is added, we check to see if an extruder stack needs to be added.
|
||||
self.containerAdded.connect(self._onContainerAdded)
|
||||
|
||||
## Overridden from ContainerRegistry
|
||||
#
|
||||
# Adds a container to the registry.
|
||||
@ -410,6 +415,17 @@ class CuraContainerRegistry(ContainerRegistry):
|
||||
if not extruder_stacks:
|
||||
self.addExtruderStackForSingleExtrusionMachine(machine, "fdmextruder")
|
||||
|
||||
def _onContainerAdded(self, container):
|
||||
# We don't have all the machines loaded in the beginning, so in order to add the missing extruder stack
|
||||
# for single extrusion machines, we subscribe to the containerAdded signal, and whenever a global stack
|
||||
# is added, we check to see if an extruder stack needs to be added.
|
||||
if not isinstance(container, ContainerStack) or container.getMetaDataEntry("type") != "machine":
|
||||
return
|
||||
|
||||
extruder_stacks = self.findContainerStacks(type = "extruder_train", machine = container.getId())
|
||||
if not extruder_stacks:
|
||||
self.addExtruderStackForSingleExtrusionMachine(container, "fdmextruder")
|
||||
|
||||
def addExtruderStackForSingleExtrusionMachine(self, machine, extruder_id):
|
||||
new_extruder_id = extruder_id
|
||||
|
||||
@ -425,7 +441,6 @@ class CuraContainerRegistry(ContainerRegistry):
|
||||
extruder_stack.setName(extruder_definition.getName())
|
||||
extruder_stack.setDefinition(extruder_definition)
|
||||
extruder_stack.addMetaDataEntry("position", extruder_definition.getMetaDataEntry("position"))
|
||||
extruder_stack.setNextStack(machine)
|
||||
|
||||
# create empty user changes container otherwise
|
||||
user_container = InstanceContainer(extruder_stack.id + "_user")
|
||||
@ -433,7 +448,7 @@ class CuraContainerRegistry(ContainerRegistry):
|
||||
user_container.addMetaDataEntry("machine", extruder_stack.getId())
|
||||
from cura.CuraApplication import CuraApplication
|
||||
user_container.addMetaDataEntry("setting_version", CuraApplication.SettingVersion)
|
||||
user_container.setDefinition(machine.definition)
|
||||
user_container.setDefinition(machine.definition.getId())
|
||||
|
||||
if machine.userChanges:
|
||||
# for the newly created extruder stack, we need to move all "per-extruder" settings to the user changes
|
||||
@ -444,8 +459,8 @@ class CuraContainerRegistry(ContainerRegistry):
|
||||
user_container.addInstance(machine.userChanges.getInstance(user_setting_key))
|
||||
machine.userChanges.removeInstance(user_setting_key, postpone_emit = True)
|
||||
|
||||
extruder_stack.setUserChanges(user_container)
|
||||
self.addContainer(user_container)
|
||||
extruder_stack.setUserChanges(user_container)
|
||||
|
||||
variant_id = "default"
|
||||
if machine.variant.getId() not in ("empty", "empty_variant"):
|
||||
@ -491,6 +506,9 @@ class CuraContainerRegistry(ContainerRegistry):
|
||||
|
||||
self.addContainer(extruder_stack)
|
||||
|
||||
# Set next stack at the end
|
||||
extruder_stack.setNextStack(machine)
|
||||
|
||||
return extruder_stack
|
||||
|
||||
def _findQualityChangesContainerInCuraFolder(self, name):
|
||||
|
@ -377,7 +377,7 @@ class CuraContainerStack(ContainerStack):
|
||||
if not container or not isinstance(container, DefinitionContainer):
|
||||
definition = self.findContainer(container_type = DefinitionContainer)
|
||||
if not definition:
|
||||
raise InvalidContainerStackError("Stack {id} does not have a definition!".format(id = self._id))
|
||||
raise InvalidContainerStackError("Stack {id} does not have a definition!".format(id = self.getId()))
|
||||
|
||||
new_containers[index] = definition
|
||||
continue
|
||||
@ -508,7 +508,7 @@ class CuraContainerStack(ContainerStack):
|
||||
def findDefaultQuality(self) -> Optional[ContainerInterface]:
|
||||
definition = self._getMachineDefinition()
|
||||
registry = ContainerRegistry.getInstance()
|
||||
material_container = self.material if self.material != self._empty_instance_container else None
|
||||
material_container = self.material if self.material.getId() not in (self._empty_material.getId(), self._empty_instance_container.getId()) else None
|
||||
|
||||
search_criteria = {"type": "quality"}
|
||||
|
||||
@ -552,7 +552,7 @@ class CuraContainerStack(ContainerStack):
|
||||
material_search_criteria = {"type": "material", "material": material_container.getMetaDataEntry("material"), "color_name": "Generic"}
|
||||
if definition.getMetaDataEntry("has_machine_quality"):
|
||||
if self.material != self._empty_instance_container:
|
||||
material_search_criteria["definition"] = material_container.getDefinition().id
|
||||
material_search_criteria["definition"] = material_container.getMetaDataEntry("definition")
|
||||
|
||||
if definition.getMetaDataEntry("has_variants"):
|
||||
material_search_criteria["variant"] = material_container.getMetaDataEntry("variant")
|
||||
|
@ -32,6 +32,7 @@ from .CuraStackBuilder import CuraStackBuilder
|
||||
from UM.i18n import i18nCatalog
|
||||
catalog = i18nCatalog("cura")
|
||||
|
||||
from cura.Settings.ProfilesModel import ProfilesModel
|
||||
from typing import TYPE_CHECKING, Optional
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@ -60,9 +61,11 @@ class MachineManager(QObject):
|
||||
self._instance_container_timer = QTimer()
|
||||
self._instance_container_timer.setInterval(250)
|
||||
self._instance_container_timer.setSingleShot(True)
|
||||
self._instance_container_timer.timeout.connect(self.__onInstanceContainersChanged)
|
||||
self._instance_container_timer.timeout.connect(self.__emitChangedSignals)
|
||||
|
||||
Application.getInstance().globalContainerStackChanged.connect(self._onGlobalContainerChanged)
|
||||
Application.getInstance().getContainerRegistry().containerLoadComplete.connect(self._onInstanceContainersChanged)
|
||||
self._connected_to_profiles_model = False
|
||||
|
||||
## When the global container is changed, active material probably needs to be updated.
|
||||
self.globalContainerChanged.connect(self.activeMaterialChanged)
|
||||
@ -333,14 +336,24 @@ class MachineManager(QObject):
|
||||
# on _active_container_stack. If it changes, then the properties change.
|
||||
self.activeQualityChanged.emit()
|
||||
|
||||
def __onInstanceContainersChanged(self):
|
||||
def __emitChangedSignals(self):
|
||||
self.activeQualityChanged.emit()
|
||||
self.activeVariantChanged.emit()
|
||||
self.activeMaterialChanged.emit()
|
||||
self._updateStacksHaveErrors() # Prevents unwanted re-slices after changing machine
|
||||
self._error_check_timer.start()
|
||||
|
||||
def _onProfilesModelChanged(self, *args):
|
||||
self.__emitChangedSignals()
|
||||
|
||||
def _onInstanceContainersChanged(self, container):
|
||||
# This should not trigger the ProfilesModel to be created, or there will be an infinite recursion
|
||||
if not self._connected_to_profiles_model and ProfilesModel.hasInstance():
|
||||
# This triggers updating the qualityModel in SidebarSimple whenever ProfilesModel is updated
|
||||
Logger.log("d", "Connecting profiles model...")
|
||||
ProfilesModel.getInstance().itemsChanged.connect(self._onProfilesModelChanged)
|
||||
self._connected_to_profiles_model = True
|
||||
|
||||
self._instance_container_timer.start()
|
||||
|
||||
def _onPropertyChanged(self, key: str, property_name: str):
|
||||
@ -356,11 +369,13 @@ class MachineManager(QObject):
|
||||
self.blurSettings.emit() # Ensure no-one has focus.
|
||||
self._cancelDelayedActiveContainerStackChanges()
|
||||
|
||||
containers = ContainerRegistry.getInstance().findContainerStacks(id = stack_id)
|
||||
container_registry = ContainerRegistry.getInstance()
|
||||
|
||||
containers = container_registry.findContainerStacks(id = stack_id)
|
||||
if containers:
|
||||
Application.getInstance().setGlobalContainerStack(containers[0])
|
||||
|
||||
self.__onInstanceContainersChanged()
|
||||
self.__emitChangedSignals()
|
||||
|
||||
@pyqtSlot(str, str)
|
||||
def addMachine(self, name: str, definition_id: str) -> None:
|
||||
|
@ -49,6 +49,10 @@ class ProfilesModel(InstanceContainersModel):
|
||||
ProfilesModel.__instance = cls()
|
||||
return ProfilesModel.__instance
|
||||
|
||||
@classmethod
|
||||
def hasInstance(cls) -> bool:
|
||||
return ProfilesModel.__instance is not None
|
||||
|
||||
__instance = None # type: "ProfilesModel"
|
||||
|
||||
## Fetch the list of containers to display.
|
||||
@ -91,7 +95,6 @@ class ProfilesModel(InstanceContainersModel):
|
||||
|
||||
## Re-computes the items in this model, and adds the layer height role.
|
||||
def _recomputeItems(self):
|
||||
|
||||
# Some globals that we can re-use.
|
||||
global_container_stack = Application.getInstance().getGlobalContainerStack()
|
||||
if global_container_stack is None:
|
||||
|
54
cura_app.py
54
cura_app.py
@ -2,13 +2,40 @@
|
||||
|
||||
# Copyright (c) 2015 Ultimaker B.V.
|
||||
# Cura is released under the terms of the LGPLv3 or higher.
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import sys
|
||||
import platform
|
||||
import faulthandler
|
||||
|
||||
from UM.Platform import Platform
|
||||
|
||||
parser = argparse.ArgumentParser(prog = "cura",
|
||||
add_help = False)
|
||||
parser.add_argument('--debug',
|
||||
action='store_true',
|
||||
default = False,
|
||||
help = "Turn on the debug mode by setting this option."
|
||||
)
|
||||
known_args = vars(parser.parse_known_args()[0])
|
||||
|
||||
if not known_args["debug"]:
|
||||
def get_cura_dir_path():
|
||||
if Platform.isWindows():
|
||||
return os.path.expanduser("~/AppData/Roaming/cura/")
|
||||
elif Platform.isLinux():
|
||||
return os.path.expanduser("~/.local/share/cura")
|
||||
elif Platform.isOSX():
|
||||
return os.path.expanduser("~/Library/Logs/cura")
|
||||
|
||||
if hasattr(sys, "frozen"):
|
||||
dirpath = get_cura_dir_path()
|
||||
os.makedirs(dirpath, exist_ok = True)
|
||||
sys.stdout = open(os.path.join(dirpath, "stdout.log"), "w")
|
||||
sys.stderr = open(os.path.join(dirpath, "stderr.log"), "w")
|
||||
|
||||
import platform
|
||||
import faulthandler
|
||||
|
||||
#WORKAROUND: GITHUB-88 GITHUB-385 GITHUB-612
|
||||
if Platform.isLinux(): # Needed for platform.linux_distribution, which is not available on Windows and OSX
|
||||
# For Ubuntu: https://bugs.launchpad.net/ubuntu/+source/python-qt4/+bug/941826
|
||||
@ -47,8 +74,8 @@ def exceptHook(hook_type, value, traceback):
|
||||
_crash_handler = CrashHandler(hook_type, value, traceback)
|
||||
_crash_handler.show()
|
||||
|
||||
|
||||
sys.excepthook = exceptHook
|
||||
if not known_args["debug"]:
|
||||
sys.excepthook = exceptHook
|
||||
|
||||
# Workaround for a race condition on certain systems where there
|
||||
# is a race condition between Arcus and PyQt. Importing Arcus
|
||||
@ -58,29 +85,14 @@ import Arcus #@UnusedImport
|
||||
import cura.CuraApplication
|
||||
import cura.Settings.CuraContainerRegistry
|
||||
|
||||
def get_cura_dir_path():
|
||||
if Platform.isWindows():
|
||||
return os.path.expanduser("~/AppData/Local/cura/")
|
||||
elif Platform.isLinux():
|
||||
return os.path.expanduser("~/.local/share/cura")
|
||||
elif Platform.isOSX():
|
||||
return os.path.expanduser("~/Library/Logs/cura")
|
||||
|
||||
|
||||
if hasattr(sys, "frozen"):
|
||||
dirpath = get_cura_dir_path()
|
||||
os.makedirs(dirpath, exist_ok = True)
|
||||
sys.stdout = open(os.path.join(dirpath, "stdout.log"), "w")
|
||||
sys.stderr = open(os.path.join(dirpath, "stderr.log"), "w")
|
||||
|
||||
faulthandler.enable()
|
||||
|
||||
# Force an instance of CuraContainerRegistry to be created and reused later.
|
||||
cura.Settings.CuraContainerRegistry.CuraContainerRegistry.getInstance()
|
||||
|
||||
# This pre-start up check is needed to determine if we should start the application at all.
|
||||
if not cura.CuraApplication.CuraApplication.preStartUp():
|
||||
if not cura.CuraApplication.CuraApplication.preStartUp(parser = parser, parsed_command_line = known_args):
|
||||
sys.exit(0)
|
||||
|
||||
app = cura.CuraApplication.CuraApplication.getInstance()
|
||||
app = cura.CuraApplication.CuraApplication.getInstance(parser = parser, parsed_command_line = known_args)
|
||||
app.run()
|
||||
|
@ -86,6 +86,7 @@ class CuraEngineBackend(QObject, Backend):
|
||||
#
|
||||
self._global_container_stack = None
|
||||
Application.getInstance().globalContainerStackChanged.connect(self._onGlobalStackChanged)
|
||||
Application.getInstance().getExtruderManager().activeExtruderChanged.connect(self._onGlobalStackChanged)
|
||||
self._onGlobalStackChanged()
|
||||
|
||||
Application.getInstance().stacksValidationFinished.connect(self._onStackErrorCheckFinished)
|
||||
|
@ -131,12 +131,21 @@ class StartSliceJob(Job):
|
||||
Logger.log("w", "No objects suitable for one at a time found, or no correct order found")
|
||||
else:
|
||||
temp_list = []
|
||||
has_printing_mesh = False
|
||||
for node in DepthFirstIterator(self._scene.getRoot()):
|
||||
if type(node) is SceneNode and node.getMeshData() and node.getMeshData().getVertices() is not None:
|
||||
if not getattr(node, "_outside_buildarea", False) or getattr(node, "_non_printing_mesh", False):
|
||||
_non_printing_mesh = getattr(node, "_non_printing_mesh", False)
|
||||
if not getattr(node, "_outside_buildarea", False) or _non_printing_mesh:
|
||||
temp_list.append(node)
|
||||
if not _non_printing_mesh:
|
||||
has_printing_mesh = True
|
||||
Job.yieldThread()
|
||||
|
||||
#If the list doesn't have any model with suitable settings then clean the list
|
||||
# otherwise CuraEngine will crash
|
||||
if not has_printing_mesh:
|
||||
temp_list.clear()
|
||||
|
||||
if temp_list:
|
||||
object_groups.append(temp_list)
|
||||
|
||||
@ -209,7 +218,7 @@ class StartSliceJob(Job):
|
||||
result[key] = stack.getProperty(key, "value")
|
||||
Job.yieldThread()
|
||||
|
||||
result["print_bed_temperature"] = result["material_bed_temperature"] #Renamed settings.
|
||||
result["print_bed_temperature"] = result["material_bed_temperature"] # Renamed settings.
|
||||
result["print_temperature"] = result["material_print_temperature"]
|
||||
result["time"] = time.strftime("%H:%M:%S") #Some extra settings.
|
||||
result["date"] = time.strftime("%d-%m-%Y")
|
||||
@ -237,10 +246,10 @@ class StartSliceJob(Job):
|
||||
|
||||
settings = self._buildReplacementTokens(stack)
|
||||
|
||||
#Also send the material GUID. This is a setting in fdmprinter, but we have no interface for it.
|
||||
# Also send the material GUID. This is a setting in fdmprinter, but we have no interface for it.
|
||||
settings["material_guid"] = stack.material.getMetaDataEntry("GUID", "")
|
||||
|
||||
#Replace the setting tokens in start and end g-code.
|
||||
# Replace the setting tokens in start and end g-code.
|
||||
settings["machine_extruder_start_code"] = self._expandGcodeTokens(settings["machine_extruder_start_code"], settings)
|
||||
settings["machine_extruder_end_code"] = self._expandGcodeTokens(settings["machine_extruder_end_code"], settings)
|
||||
|
||||
@ -260,18 +269,23 @@ class StartSliceJob(Job):
|
||||
def _buildGlobalSettingsMessage(self, stack):
|
||||
settings = self._buildReplacementTokens(stack)
|
||||
|
||||
# Pre-compute material material_bed_temp_prepend and material_print_temp_prepend
|
||||
start_gcode = settings["machine_start_gcode"]
|
||||
#Pre-compute material material_bed_temp_prepend and material_print_temp_prepend
|
||||
bed_temperature_settings = {"material_bed_temperature", "material_bed_temperature_layer_0"}
|
||||
settings["material_bed_temp_prepend"] = all(("{" + setting + "}" not in start_gcode for setting in bed_temperature_settings))
|
||||
print_temperature_settings = {"material_print_temperature", "material_print_temperature_layer_0", "default_material_print_temperature", "material_initial_print_temperature", "material_final_print_temperature", "material_standby_temperature"}
|
||||
settings["material_print_temp_prepend"] = all(("{" + setting + "}" not in start_gcode for setting in print_temperature_settings))
|
||||
|
||||
#Replace the setting tokens in start and end g-code.
|
||||
settings["machine_start_gcode"] = self._expandGcodeTokens(settings["machine_start_gcode"], settings)
|
||||
settings["machine_end_gcode"] = self._expandGcodeTokens(settings["machine_end_gcode"], settings)
|
||||
# Find the correct temperatures from the first used extruder
|
||||
extruder_stack = Application.getInstance().getExtruderManager().getUsedExtruderStacks()[0]
|
||||
extruder_0_settings = self._buildReplacementTokens(extruder_stack)
|
||||
|
||||
for key, value in settings.items(): #Add all submessages for each individual setting.
|
||||
# Replace the setting tokens in start and end g-code.
|
||||
settings["machine_start_gcode"] = self._expandGcodeTokens(settings["machine_start_gcode"], extruder_0_settings)
|
||||
settings["machine_end_gcode"] = self._expandGcodeTokens(settings["machine_end_gcode"], extruder_0_settings)
|
||||
|
||||
# Add all sub-messages for each individual setting.
|
||||
for key, value in settings.items():
|
||||
setting_message = self._slice_message.getMessage("global_settings").addRepeatedMessage("settings")
|
||||
setting_message.name = key
|
||||
setting_message.value = str(value).encode("utf-8")
|
||||
|
@ -92,7 +92,7 @@ class SimulationPass(RenderPass):
|
||||
|
||||
self.bind()
|
||||
|
||||
tool_handle_batch = RenderBatch(self._tool_handle_shader, type = RenderBatch.RenderType.Overlay)
|
||||
tool_handle_batch = RenderBatch(self._tool_handle_shader, type = RenderBatch.RenderType.Overlay, backface_cull = True)
|
||||
head_position = None # Indicates the current position of the print head
|
||||
nozzle_node = None
|
||||
|
||||
@ -149,7 +149,7 @@ class SimulationPass(RenderPass):
|
||||
self._current_shader = self._layer_shader
|
||||
self._switching_layers = True
|
||||
|
||||
layers_batch = RenderBatch(self._current_shader, type = RenderBatch.RenderType.Solid, mode = RenderBatch.RenderMode.Lines, range = (start, end))
|
||||
layers_batch = RenderBatch(self._current_shader, type = RenderBatch.RenderType.Solid, mode = RenderBatch.RenderMode.Lines, range = (start, end), backface_cull = True)
|
||||
layers_batch.addItem(node.getWorldTransformation(), layer_data)
|
||||
layers_batch.render(self._scene.getActiveCamera())
|
||||
|
||||
|
@ -187,20 +187,27 @@ geometry41core =
|
||||
myEmitVertex(v_vertex[1], v_color[1], g_vertex_normal_vert, u_viewProjectionMatrix * (gl_in[1].gl_Position - g_vertex_offset_horz + g_vertex_offset_vert));
|
||||
myEmitVertex(v_vertex[1], v_color[1], g_vertex_normal_vert, u_viewProjectionMatrix * (gl_in[1].gl_Position + g_vertex_offset_horz + g_vertex_offset_vert));
|
||||
myEmitVertex(v_vertex[1], v_color[1], g_vertex_normal_vert, u_viewProjectionMatrix * (gl_in[1].gl_Position - g_vertex_offset_horz_head + g_vertex_offset_vert));
|
||||
//And reverse so that the line is also visible from the back side.
|
||||
myEmitVertex(v_vertex[1], v_color[1], g_vertex_normal_vert, u_viewProjectionMatrix * (gl_in[1].gl_Position + g_vertex_offset_horz + g_vertex_offset_vert));
|
||||
myEmitVertex(v_vertex[1], v_color[1], g_vertex_normal_vert, u_viewProjectionMatrix * (gl_in[1].gl_Position - g_vertex_offset_horz + g_vertex_offset_vert));
|
||||
myEmitVertex(v_vertex[0], v_color[0], g_vertex_normal_vert, u_viewProjectionMatrix * (gl_in[0].gl_Position + g_vertex_offset_horz + g_vertex_offset_vert));
|
||||
myEmitVertex(v_vertex[0], v_color[0], g_vertex_normal_vert, u_viewProjectionMatrix * (gl_in[0].gl_Position - g_vertex_offset_horz + g_vertex_offset_vert));
|
||||
myEmitVertex(v_vertex[0], v_color[0], g_vertex_normal_vert, u_viewProjectionMatrix * (gl_in[0].gl_Position + g_vertex_offset_horz_head + g_vertex_offset_vert));
|
||||
myEmitVertex(v_vertex[0], v_color[0], g_vertex_normal_vert, u_viewProjectionMatrix * (gl_in[0].gl_Position + g_vertex_offset_horz + g_vertex_offset_vert));
|
||||
|
||||
EndPrimitive();
|
||||
} else {
|
||||
// All normal lines are rendered as 3d tubes.
|
||||
myEmitVertex(v_vertex[0], v_color[0], g_vertex_normal_horz, u_viewProjectionMatrix * (gl_in[0].gl_Position + g_vertex_offset_horz));
|
||||
myEmitVertex(v_vertex[1], v_color[1], g_vertex_normal_horz, u_viewProjectionMatrix * (gl_in[1].gl_Position + g_vertex_offset_horz));
|
||||
myEmitVertex(v_vertex[0], v_color[0], g_vertex_normal_vert, u_viewProjectionMatrix * (gl_in[0].gl_Position + g_vertex_offset_vert));
|
||||
myEmitVertex(v_vertex[1], v_color[1], g_vertex_normal_vert, u_viewProjectionMatrix * (gl_in[1].gl_Position + g_vertex_offset_vert));
|
||||
myEmitVertex(v_vertex[0], v_color[0], -g_vertex_normal_horz, u_viewProjectionMatrix * (gl_in[0].gl_Position - g_vertex_offset_horz));
|
||||
myEmitVertex(v_vertex[1], v_color[1], -g_vertex_normal_horz, u_viewProjectionMatrix * (gl_in[1].gl_Position - g_vertex_offset_horz));
|
||||
myEmitVertex(v_vertex[0], v_color[0], -g_vertex_normal_vert, u_viewProjectionMatrix * (gl_in[0].gl_Position - g_vertex_offset_vert));
|
||||
myEmitVertex(v_vertex[1], v_color[1], -g_vertex_normal_vert, u_viewProjectionMatrix * (gl_in[1].gl_Position - g_vertex_offset_vert));
|
||||
myEmitVertex(v_vertex[0], v_color[0], g_vertex_normal_vert, u_viewProjectionMatrix * (gl_in[0].gl_Position + g_vertex_offset_vert));
|
||||
myEmitVertex(v_vertex[1], v_color[1], g_vertex_normal_vert, u_viewProjectionMatrix * (gl_in[1].gl_Position + g_vertex_offset_vert));
|
||||
myEmitVertex(v_vertex[0], v_color[0], g_vertex_normal_horz, u_viewProjectionMatrix * (gl_in[0].gl_Position + g_vertex_offset_horz));
|
||||
myEmitVertex(v_vertex[1], v_color[1], g_vertex_normal_horz, u_viewProjectionMatrix * (gl_in[1].gl_Position + g_vertex_offset_horz));
|
||||
myEmitVertex(v_vertex[0], v_color[0], -g_vertex_normal_vert, u_viewProjectionMatrix * (gl_in[0].gl_Position - g_vertex_offset_vert));
|
||||
myEmitVertex(v_vertex[1], v_color[1], -g_vertex_normal_vert, u_viewProjectionMatrix * (gl_in[1].gl_Position - g_vertex_offset_vert));
|
||||
myEmitVertex(v_vertex[0], v_color[0], -g_vertex_normal_horz, u_viewProjectionMatrix * (gl_in[0].gl_Position - g_vertex_offset_horz));
|
||||
myEmitVertex(v_vertex[1], v_color[1], -g_vertex_normal_horz, u_viewProjectionMatrix * (gl_in[1].gl_Position - g_vertex_offset_horz));
|
||||
|
||||
EndPrimitive();
|
||||
|
||||
|
@ -99,7 +99,9 @@ class SliceInfo(Extension):
|
||||
"type": extruder.material.getMetaData().get("material", ""),
|
||||
"brand": extruder.material.getMetaData().get("brand", "")
|
||||
}
|
||||
extruder_dict["material_used"] = print_information.materialLengths[int(extruder.getMetaDataEntry("position", "0"))]
|
||||
extruder_position = int(extruder.getMetaDataEntry("position", "0"))
|
||||
if extruder_position in print_information.materialLengths:
|
||||
extruder_dict["material_used"] = print_information.materialLengths[extruder_position]
|
||||
extruder_dict["variant"] = extruder.variant.getName()
|
||||
extruder_dict["nozzle_size"] = extruder.getProperty("machine_nozzle_size", "value")
|
||||
|
||||
|
@ -43,6 +43,7 @@ class NetworkPrinterOutputDevicePlugin(QObject, OutputDevicePlugin):
|
||||
# List of old printer names. This is used to ensure that a refresh of zeroconf does not needlessly forces
|
||||
# authentication requests.
|
||||
self._old_printers = []
|
||||
self._excluded_addresses = ["127.0.0.1"] # Adding a list of not allowed IP addresses. At this moment, just localhost
|
||||
|
||||
# Because the model needs to be created in the same thread as the QMLEngine, we use a signal.
|
||||
self.addPrinterSignal.connect(self.addPrinter)
|
||||
@ -300,6 +301,9 @@ class NetworkPrinterOutputDevicePlugin(QObject, OutputDevicePlugin):
|
||||
if type_of_device:
|
||||
if type_of_device == b"printer":
|
||||
address = '.'.join(map(lambda n: str(n), info.address))
|
||||
if address in self._excluded_addresses:
|
||||
Logger.log("d", "The IP address %s of the printer \'%s\' is not correct. Trying to reconnect.", address, name)
|
||||
return False # When getting the localhost IP, then try to reconnect
|
||||
self.addPrinterSignal.emit(str(name), address, info.properties)
|
||||
else:
|
||||
Logger.log("w", "The type of the found device is '%s', not 'printer'! Ignoring.." % type_of_device )
|
||||
|
@ -122,6 +122,21 @@ class VersionUpgrade30to31(VersionUpgrade):
|
||||
if len(all_quality_changes) <= 1 and not parser.has_option("metadata", "extruder"):
|
||||
self._createExtruderQualityChangesForSingleExtrusionMachine(filename, parser)
|
||||
|
||||
if parser["metadata"]["type"] == "definition_changes":
|
||||
if parser["general"]["definition"] == "custom":
|
||||
|
||||
# We are only interested in machine_nozzle_size
|
||||
if parser.has_option("values", "machine_nozzle_size"):
|
||||
machine_nozzle_size = parser["values"]["machine_nozzle_size"]
|
||||
|
||||
definition_name = parser["general"]["name"]
|
||||
machine_extruders = self._getSingleExtrusionMachineExtruders(definition_name)
|
||||
|
||||
#For single extuder machine we nee only first extruder
|
||||
if len(machine_extruders) !=0:
|
||||
if self._updateSingleExtuderDefinitionFile(machine_extruders, machine_nozzle_size):
|
||||
parser.remove_option("values", "machine_nozzle_size")
|
||||
|
||||
# Update version numbers
|
||||
parser["general"]["version"] = "2"
|
||||
parser["metadata"]["setting_version"] = "4"
|
||||
@ -200,6 +215,133 @@ class VersionUpgrade30to31(VersionUpgrade):
|
||||
|
||||
return quality_changes_containers
|
||||
|
||||
def _getSingleExtrusionMachineExtruders(self, definition_name):
|
||||
|
||||
machine_instances_dir = Resources.getPath(CuraApplication.ResourceTypes.MachineStack)
|
||||
|
||||
machine_instances = []
|
||||
|
||||
#Find all machine instances
|
||||
for item in os.listdir(machine_instances_dir):
|
||||
file_path = os.path.join(machine_instances_dir, item)
|
||||
if not os.path.isfile(file_path):
|
||||
continue
|
||||
|
||||
parser = configparser.ConfigParser(interpolation=None)
|
||||
try:
|
||||
parser.read([file_path])
|
||||
except:
|
||||
# skip, it is not a valid stack file
|
||||
continue
|
||||
|
||||
if not parser.has_option("metadata", "type"):
|
||||
continue
|
||||
if "machine" != parser["metadata"]["type"]:
|
||||
continue
|
||||
|
||||
if not parser.has_option("general", "id"):
|
||||
continue
|
||||
|
||||
machine_instances.append(parser)
|
||||
|
||||
#Find for extruders
|
||||
extruders_instances_dir = Resources.getPath(CuraApplication.ResourceTypes.ExtruderStack)
|
||||
#"machine",[extruders]
|
||||
extruder_instances_per_machine = {}
|
||||
|
||||
#Find all custom extruders for founded machines
|
||||
for item in os.listdir(extruders_instances_dir):
|
||||
file_path = os.path.join(extruders_instances_dir, item)
|
||||
if not os.path.isfile(file_path):
|
||||
continue
|
||||
|
||||
parser = configparser.ConfigParser(interpolation=None)
|
||||
try:
|
||||
parser.read([file_path])
|
||||
except:
|
||||
# skip, it is not a valid stack file
|
||||
continue
|
||||
|
||||
if not parser.has_option("metadata", "type"):
|
||||
continue
|
||||
if "extruder_train" != parser["metadata"]["type"]:
|
||||
continue
|
||||
|
||||
if not parser.has_option("metadata", "machine"):
|
||||
continue
|
||||
if not parser.has_option("metadata", "position"):
|
||||
continue
|
||||
|
||||
|
||||
for machine_instace in machine_instances:
|
||||
|
||||
machine_id = machine_instace["general"]["id"]
|
||||
if machine_id != parser["metadata"]["machine"]:
|
||||
continue
|
||||
|
||||
if machine_id + "_settings" != definition_name:
|
||||
continue
|
||||
|
||||
if extruder_instances_per_machine.get(machine_id) is None:
|
||||
extruder_instances_per_machine.update({machine_id:[]})
|
||||
|
||||
extruder_instances_per_machine.get(machine_id).append(parser)
|
||||
#the extruder can be related only to one machine
|
||||
break
|
||||
|
||||
return extruder_instances_per_machine
|
||||
|
||||
#Find extruder defition at index 0 and update its values
|
||||
def _updateSingleExtuderDefinitionFile(self, extruder_instances_per_machine, machine_nozzle_size):
|
||||
|
||||
defintion_instances_dir = Resources.getPath(CuraApplication.ResourceTypes.DefinitionChangesContainer)
|
||||
|
||||
for item in os.listdir(defintion_instances_dir):
|
||||
file_path = os.path.join(defintion_instances_dir, item)
|
||||
if not os.path.isfile(file_path):
|
||||
continue
|
||||
|
||||
parser = configparser.ConfigParser(interpolation=None)
|
||||
try:
|
||||
parser.read([file_path])
|
||||
except:
|
||||
# skip, it is not a valid stack file
|
||||
continue
|
||||
|
||||
if not parser.has_option("general", "name"):
|
||||
continue
|
||||
name = parser["general"]["name"]
|
||||
custom_extruder_at_0_position = None
|
||||
for machine_extruders in extruder_instances_per_machine:
|
||||
for extruder_instance in extruder_instances_per_machine[machine_extruders]:
|
||||
|
||||
if extruder_instance["general"]["id"] + "_settings" == name:
|
||||
defition_position = extruder_instance["metadata"]["position"]
|
||||
|
||||
if defition_position == "0":
|
||||
custom_extruder_at_0_position = extruder_instance
|
||||
break
|
||||
if custom_extruder_at_0_position is not None:
|
||||
break
|
||||
|
||||
#If not null, then parsed file is for first extuder and then can be updated. I need to update only
|
||||
# first, because this update for single extuder machine
|
||||
if custom_extruder_at_0_position is not None:
|
||||
|
||||
#Add new value
|
||||
parser["values"]["machine_nozzle_size"] = machine_nozzle_size
|
||||
|
||||
definition_output = io.StringIO()
|
||||
parser.write(definition_output)
|
||||
|
||||
with open(file_path, "w") as f:
|
||||
f.write(definition_output.getvalue())
|
||||
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def _createExtruderQualityChangesForSingleExtrusionMachine(self, filename, global_quality_changes):
|
||||
suffix = "_" + quote_plus(global_quality_changes["general"]["name"].lower())
|
||||
machine_name = os.path.os.path.basename(filename).replace(".inst.cfg", "").replace(suffix, "")
|
||||
|
@ -212,11 +212,12 @@ class XmlMaterialProfile(InstanceContainer):
|
||||
|
||||
for definition_id, container in machine_container_map.items():
|
||||
definition = container.getDefinition()
|
||||
try:
|
||||
product = UM.Dictionary.findKey(product_id_map, definition_id)
|
||||
except ValueError:
|
||||
# An unknown product id; export it anyway
|
||||
product = definition_id
|
||||
|
||||
product = definition_id
|
||||
for product_name, product_id_list in product_id_map.items():
|
||||
if definition_id in product_id_list:
|
||||
product = product_name
|
||||
break
|
||||
|
||||
builder.start("machine")
|
||||
builder.start("machine_identifier", {
|
||||
@ -530,106 +531,112 @@ class XmlMaterialProfile(InstanceContainer):
|
||||
|
||||
identifiers = machine.iterfind("./um:machine_identifier", self.__namespaces)
|
||||
for identifier in identifiers:
|
||||
machine_id = product_id_map.get(identifier.get("product"), None)
|
||||
if machine_id is None:
|
||||
# Lets try again with some naive heuristics.
|
||||
machine_id = identifier.get("product").replace(" ", "").lower()
|
||||
machine_id_list = product_id_map.get(identifier.get("product"), [])
|
||||
if not machine_id_list:
|
||||
machine_id_list = self.getPossibleDefinitionIDsFromName(identifier.get("product"))
|
||||
|
||||
definitions = ContainerRegistry.getInstance().findDefinitionContainersMetadata(id = machine_id)
|
||||
if not definitions:
|
||||
Logger.log("w", "No definition found for machine ID %s", machine_id)
|
||||
continue
|
||||
|
||||
definition = definitions[0]
|
||||
|
||||
machine_manufacturer = identifier.get("manufacturer", definition.get("manufacturer", "Unknown")) #If the XML material doesn't specify a manufacturer, use the one in the actual printer definition.
|
||||
|
||||
if machine_compatibility:
|
||||
new_material_id = self.getId() + "_" + machine_id
|
||||
|
||||
# The child or derived material container may already exist. This can happen when a material in a
|
||||
# project file and the a material in Cura have the same ID.
|
||||
# In the case if a derived material already exists, override that material container because if
|
||||
# the data in the parent material has been changed, the derived ones should be updated too.
|
||||
if ContainerRegistry.getInstance().isLoaded(new_material_id):
|
||||
new_material = ContainerRegistry.getInstance().findContainers(id = new_material_id)[0]
|
||||
is_new_material = False
|
||||
else:
|
||||
new_material = XmlMaterialProfile(new_material_id)
|
||||
is_new_material = True
|
||||
|
||||
new_material.setMetaData(copy.deepcopy(self.getMetaData()))
|
||||
new_material.getMetaData()["id"] = new_material_id
|
||||
new_material.getMetaData()["name"] = self.getName()
|
||||
new_material.setDefinition(machine_id)
|
||||
# Don't use setMetadata, as that overrides it for all materials with same base file
|
||||
new_material.getMetaData()["compatible"] = machine_compatibility
|
||||
new_material.getMetaData()["machine_manufacturer"] = machine_manufacturer
|
||||
new_material.getMetaData()["definition"] = machine_id
|
||||
|
||||
new_material.setCachedValues(cached_machine_setting_properties)
|
||||
|
||||
new_material._dirty = False
|
||||
|
||||
if is_new_material:
|
||||
containers_to_add.append(new_material)
|
||||
|
||||
hotends = machine.iterfind("./um:hotend", self.__namespaces)
|
||||
for hotend in hotends:
|
||||
hotend_id = hotend.get("id")
|
||||
if hotend_id is None:
|
||||
for machine_id in machine_id_list:
|
||||
definitions = ContainerRegistry.getInstance().findDefinitionContainersMetadata(id = machine_id)
|
||||
if not definitions:
|
||||
Logger.log("w", "No definition found for machine ID %s", machine_id)
|
||||
continue
|
||||
|
||||
variant_containers = ContainerRegistry.getInstance().findInstanceContainersMetadata(id = hotend_id)
|
||||
if not variant_containers:
|
||||
# It is not really properly defined what "ID" is so also search for variants by name.
|
||||
variant_containers = ContainerRegistry.getInstance().findInstanceContainersMetadata(definition = definition["id"], name = hotend_id)
|
||||
Logger.log("d", "Found definition for machine ID %s", machine_id)
|
||||
definition = definitions[0]
|
||||
|
||||
if not variant_containers:
|
||||
continue
|
||||
machine_manufacturer = identifier.get("manufacturer", definition.get("manufacturer", "Unknown")) #If the XML material doesn't specify a manufacturer, use the one in the actual printer definition.
|
||||
|
||||
hotend_compatibility = machine_compatibility
|
||||
hotend_setting_values = {}
|
||||
settings = hotend.iterfind("./um:setting", self.__namespaces)
|
||||
for entry in settings:
|
||||
key = entry.get("key")
|
||||
if key in self.__material_settings_setting_map:
|
||||
hotend_setting_values[self.__material_settings_setting_map[key]] = entry.text
|
||||
elif key in self.__unmapped_settings:
|
||||
if key == "hardware compatible":
|
||||
hotend_compatibility = self._parseCompatibleValue(entry.text)
|
||||
if machine_compatibility:
|
||||
new_material_id = self.getId() + "_" + machine_id
|
||||
|
||||
# The child or derived material container may already exist. This can happen when a material in a
|
||||
# project file and the a material in Cura have the same ID.
|
||||
# In the case if a derived material already exists, override that material container because if
|
||||
# the data in the parent material has been changed, the derived ones should be updated too.
|
||||
if ContainerRegistry.getInstance().isLoaded(new_material_id):
|
||||
new_material = ContainerRegistry.getInstance().findContainers(id = new_material_id)[0]
|
||||
is_new_material = False
|
||||
else:
|
||||
Logger.log("d", "Unsupported material setting %s", key)
|
||||
new_material = XmlMaterialProfile(new_material_id)
|
||||
is_new_material = True
|
||||
|
||||
new_hotend_id = self.getId() + "_" + machine_id + "_" + hotend_id.replace(" ", "_")
|
||||
new_material.setMetaData(copy.deepcopy(self.getMetaData()))
|
||||
new_material.getMetaData()["id"] = new_material_id
|
||||
new_material.getMetaData()["name"] = self.getName()
|
||||
new_material.setDefinition(machine_id)
|
||||
# Don't use setMetadata, as that overrides it for all materials with same base file
|
||||
new_material.getMetaData()["compatible"] = machine_compatibility
|
||||
new_material.getMetaData()["machine_manufacturer"] = machine_manufacturer
|
||||
new_material.getMetaData()["definition"] = machine_id
|
||||
|
||||
# Same as machine compatibility, keep the derived material containers consistent with the parent
|
||||
# material
|
||||
if ContainerRegistry.getInstance().isLoaded(new_hotend_id):
|
||||
new_hotend_material = ContainerRegistry.getInstance().findContainers(id = new_hotend_id)[0]
|
||||
is_new_material = False
|
||||
else:
|
||||
new_hotend_material = XmlMaterialProfile(new_hotend_id)
|
||||
is_new_material = True
|
||||
new_material.setCachedValues(cached_machine_setting_properties)
|
||||
|
||||
new_hotend_material.setMetaData(copy.deepcopy(self.getMetaData()))
|
||||
new_hotend_material.getMetaData()["id"] = new_hotend_id
|
||||
new_hotend_material.getMetaData()["name"] = self.getName()
|
||||
new_hotend_material.getMetaData()["variant"] = variant_containers[0]["id"]
|
||||
# Don't use setMetadata, as that overrides it for all materials with same base file
|
||||
new_hotend_material.getMetaData()["compatible"] = hotend_compatibility
|
||||
new_hotend_material.getMetaData()["machine_manufacturer"] = machine_manufacturer
|
||||
new_hotend_material.getMetaData()["definition"] = machine_id
|
||||
new_material._dirty = False
|
||||
|
||||
cached_hotend_setting_properties = cached_machine_setting_properties.copy()
|
||||
cached_hotend_setting_properties.update(hotend_setting_values)
|
||||
if is_new_material:
|
||||
containers_to_add.append(new_material)
|
||||
|
||||
new_hotend_material.setCachedValues(cached_hotend_setting_properties)
|
||||
hotends = machine.iterfind("./um:hotend", self.__namespaces)
|
||||
for hotend in hotends:
|
||||
hotend_id = hotend.get("id")
|
||||
if hotend_id is None:
|
||||
continue
|
||||
|
||||
new_hotend_material._dirty = False
|
||||
variant_containers = ContainerRegistry.getInstance().findInstanceContainersMetadata(id = hotend_id)
|
||||
if not variant_containers:
|
||||
# It is not really properly defined what "ID" is so also search for variants by name.
|
||||
variant_containers = ContainerRegistry.getInstance().findInstanceContainersMetadata(definition = machine_id, name = hotend_id)
|
||||
|
||||
if is_new_material:
|
||||
containers_to_add.append(new_hotend_material)
|
||||
if not variant_containers:
|
||||
continue
|
||||
|
||||
hotend_compatibility = machine_compatibility
|
||||
hotend_setting_values = {}
|
||||
settings = hotend.iterfind("./um:setting", self.__namespaces)
|
||||
for entry in settings:
|
||||
key = entry.get("key")
|
||||
if key in self.__material_settings_setting_map:
|
||||
hotend_setting_values[self.__material_settings_setting_map[key]] = entry.text
|
||||
elif key in self.__unmapped_settings:
|
||||
if key == "hardware compatible":
|
||||
hotend_compatibility = self._parseCompatibleValue(entry.text)
|
||||
else:
|
||||
Logger.log("d", "Unsupported material setting %s", key)
|
||||
|
||||
new_hotend_id = self.getId() + "_" + machine_id + "_" + hotend_id.replace(" ", "_")
|
||||
|
||||
# Same as machine compatibility, keep the derived material containers consistent with the parent
|
||||
# material
|
||||
if ContainerRegistry.getInstance().isLoaded(new_hotend_id):
|
||||
new_hotend_material = ContainerRegistry.getInstance().findContainers(id = new_hotend_id)[0]
|
||||
is_new_material = False
|
||||
else:
|
||||
new_hotend_material = XmlMaterialProfile(new_hotend_id)
|
||||
is_new_material = True
|
||||
|
||||
new_hotend_material.setMetaData(copy.deepcopy(self.getMetaData()))
|
||||
new_hotend_material.getMetaData()["id"] = new_hotend_id
|
||||
new_hotend_material.getMetaData()["name"] = self.getName()
|
||||
new_hotend_material.getMetaData()["variant"] = variant_containers[0]["id"]
|
||||
new_hotend_material.setDefinition(machine_id)
|
||||
# Don't use setMetadata, as that overrides it for all materials with same base file
|
||||
new_hotend_material.getMetaData()["compatible"] = hotend_compatibility
|
||||
new_hotend_material.getMetaData()["machine_manufacturer"] = machine_manufacturer
|
||||
new_hotend_material.getMetaData()["definition"] = machine_id
|
||||
|
||||
cached_hotend_setting_properties = cached_machine_setting_properties.copy()
|
||||
cached_hotend_setting_properties.update(hotend_setting_values)
|
||||
|
||||
new_hotend_material.setCachedValues(cached_hotend_setting_properties)
|
||||
|
||||
new_hotend_material._dirty = False
|
||||
|
||||
if is_new_material:
|
||||
containers_to_add.append(new_hotend_material)
|
||||
|
||||
# there is only one ID for a machine. Once we have reached here, it means we have already found
|
||||
# a workable ID for that machine, so there is no need to continue
|
||||
break
|
||||
|
||||
for container_to_add in containers_to_add:
|
||||
ContainerRegistry.getInstance().addContainer(container_to_add)
|
||||
@ -720,79 +727,86 @@ class XmlMaterialProfile(InstanceContainer):
|
||||
machine_compatibility = cls._parseCompatibleValue(entry.text)
|
||||
|
||||
for identifier in machine.iterfind("./um:machine_identifier", cls.__namespaces):
|
||||
machine_id = product_id_map.get(identifier.get("product"), None)
|
||||
if machine_id is None:
|
||||
# Lets try again with some naive heuristics.
|
||||
machine_id = identifier.get("product").replace(" ", "").lower()
|
||||
definition_metadata = ContainerRegistry.getInstance().findDefinitionContainersMetadata(id = machine_id)
|
||||
if not definition_metadata:
|
||||
Logger.log("w", "No definition found for machine ID %s", machine_id)
|
||||
continue
|
||||
definition_metadata = definition_metadata[0]
|
||||
machine_id_list = product_id_map.get(identifier.get("product"), [])
|
||||
if not machine_id_list:
|
||||
machine_id_list = cls.getPossibleDefinitionIDsFromName(identifier.get("product"))
|
||||
|
||||
machine_manufacturer = identifier.get("manufacturer", definition_metadata.get("manufacturer", "Unknown")) #If the XML material doesn't specify a manufacturer, use the one in the actual printer definition.
|
||||
|
||||
if machine_compatibility:
|
||||
new_material_id = container_id + "_" + machine_id
|
||||
|
||||
# The child or derived material container may already exist. This can happen when a material in a
|
||||
# project file and the a material in Cura have the same ID.
|
||||
# In the case if a derived material already exists, override that material container because if
|
||||
# the data in the parent material has been changed, the derived ones should be updated too.
|
||||
found_materials = ContainerRegistry.getInstance().findInstanceContainersMetadata(id = new_material_id)
|
||||
if found_materials:
|
||||
new_material_metadata = found_materials[0]
|
||||
else:
|
||||
new_material_metadata = {}
|
||||
|
||||
new_material_metadata.update(base_metadata)
|
||||
new_material_metadata["id"] = new_material_id
|
||||
new_material_metadata["compatible"] = machine_compatibility
|
||||
new_material_metadata["machine_manufacturer"] = machine_manufacturer
|
||||
new_material_metadata["definition"] = machine_id
|
||||
|
||||
if len(found_materials) == 0: #This is a new material.
|
||||
result_metadata.append(new_material_metadata)
|
||||
|
||||
for hotend in machine.iterfind("./um:hotend", cls.__namespaces):
|
||||
hotend_id = hotend.get("id")
|
||||
if hotend_id is None:
|
||||
for machine_id in machine_id_list:
|
||||
definition_metadata = ContainerRegistry.getInstance().findDefinitionContainersMetadata(id = machine_id)
|
||||
if not definition_metadata:
|
||||
Logger.log("w", "No definition found for machine ID %s", machine_id)
|
||||
continue
|
||||
|
||||
variant_containers = ContainerRegistry.getInstance().findInstanceContainersMetadata(id = hotend_id)
|
||||
if not variant_containers:
|
||||
# It is not really properly defined what "ID" is so also search for variants by name.
|
||||
variant_containers = ContainerRegistry.getInstance().findInstanceContainersMetadata(definition = machine_id, name = hotend_id)
|
||||
Logger.log("d", "Found def for machine [%s]", machine_id)
|
||||
definition_metadata = definition_metadata[0]
|
||||
|
||||
hotend_compatibility = machine_compatibility
|
||||
for entry in hotend.iterfind("./um:setting", cls.__namespaces):
|
||||
key = entry.get("key")
|
||||
if key == "hardware compatible":
|
||||
hotend_compatibility = cls._parseCompatibleValue(entry.text)
|
||||
machine_manufacturer = identifier.get("manufacturer", definition_metadata.get("manufacturer", "Unknown")) #If the XML material doesn't specify a manufacturer, use the one in the actual printer definition.
|
||||
|
||||
new_hotend_id = container_id + "_" + machine_id + "_" + hotend_id.replace(" ", "_")
|
||||
if machine_compatibility:
|
||||
new_material_id = container_id + "_" + machine_id
|
||||
|
||||
# Same as machine compatibility, keep the derived material containers consistent with the parent
|
||||
# material
|
||||
found_materials = ContainerRegistry.getInstance().findInstanceContainersMetadata(id = new_hotend_id)
|
||||
if found_materials:
|
||||
new_hotend_material_metadata = found_materials[0]
|
||||
else:
|
||||
new_hotend_material_metadata = {}
|
||||
# The child or derived material container may already exist. This can happen when a material in a
|
||||
# project file and the a material in Cura have the same ID.
|
||||
# In the case if a derived material already exists, override that material container because if
|
||||
# the data in the parent material has been changed, the derived ones should be updated too.
|
||||
found_materials = ContainerRegistry.getInstance().findInstanceContainersMetadata(id = new_material_id)
|
||||
if found_materials:
|
||||
new_material_metadata = found_materials[0]
|
||||
else:
|
||||
new_material_metadata = {}
|
||||
|
||||
new_hotend_material_metadata.update(base_metadata)
|
||||
if variant_containers:
|
||||
new_hotend_material_metadata["variant"] = variant_containers[0]["id"]
|
||||
else:
|
||||
new_hotend_material_metadata["variant"] = hotend_id
|
||||
_with_missing_variants.append(new_hotend_material_metadata)
|
||||
new_hotend_material_metadata["compatible"] = hotend_compatibility
|
||||
new_hotend_material_metadata["machine_manufacturer"] = machine_manufacturer
|
||||
new_hotend_material_metadata["id"] = new_hotend_id
|
||||
new_hotend_material_metadata["definition"] = machine_id
|
||||
new_material_metadata.update(base_metadata)
|
||||
new_material_metadata["id"] = new_material_id
|
||||
new_material_metadata["compatible"] = machine_compatibility
|
||||
new_material_metadata["machine_manufacturer"] = machine_manufacturer
|
||||
new_material_metadata["definition"] = machine_id
|
||||
|
||||
if len(found_materials) == 0:
|
||||
result_metadata.append(new_hotend_material_metadata)
|
||||
if len(found_materials) == 0: #This is a new material.
|
||||
result_metadata.append(new_material_metadata)
|
||||
|
||||
for hotend in machine.iterfind("./um:hotend", cls.__namespaces):
|
||||
hotend_id = hotend.get("id")
|
||||
if hotend_id is None:
|
||||
continue
|
||||
|
||||
variant_containers = ContainerRegistry.getInstance().findInstanceContainersMetadata(id = hotend_id)
|
||||
if not variant_containers:
|
||||
# It is not really properly defined what "ID" is so also search for variants by name.
|
||||
variant_containers = ContainerRegistry.getInstance().findInstanceContainersMetadata(definition = machine_id, name = hotend_id)
|
||||
|
||||
hotend_compatibility = machine_compatibility
|
||||
for entry in hotend.iterfind("./um:setting", cls.__namespaces):
|
||||
key = entry.get("key")
|
||||
if key == "hardware compatible":
|
||||
hotend_compatibility = cls._parseCompatibleValue(entry.text)
|
||||
|
||||
new_hotend_id = container_id + "_" + machine_id + "_" + hotend_id.replace(" ", "_")
|
||||
|
||||
# Same as machine compatibility, keep the derived material containers consistent with the parent
|
||||
# material
|
||||
found_materials = ContainerRegistry.getInstance().findInstanceContainersMetadata(id = new_hotend_id)
|
||||
if found_materials:
|
||||
new_hotend_material_metadata = found_materials[0]
|
||||
else:
|
||||
new_hotend_material_metadata = {}
|
||||
|
||||
new_hotend_material_metadata.update(base_metadata)
|
||||
if variant_containers:
|
||||
new_hotend_material_metadata["variant"] = variant_containers[0]["id"]
|
||||
else:
|
||||
new_hotend_material_metadata["variant"] = hotend_id
|
||||
_with_missing_variants.append(new_hotend_material_metadata)
|
||||
new_hotend_material_metadata["compatible"] = hotend_compatibility
|
||||
new_hotend_material_metadata["machine_manufacturer"] = machine_manufacturer
|
||||
new_hotend_material_metadata["id"] = new_hotend_id
|
||||
new_hotend_material_metadata["definition"] = machine_id
|
||||
|
||||
if len(found_materials) == 0:
|
||||
result_metadata.append(new_hotend_material_metadata)
|
||||
|
||||
# there is only one ID for a machine. Once we have reached here, it means we have already found
|
||||
# a workable ID for that machine, so there is no need to continue
|
||||
break
|
||||
|
||||
return result_metadata
|
||||
|
||||
@ -813,15 +827,41 @@ class XmlMaterialProfile(InstanceContainer):
|
||||
else:
|
||||
return material_name
|
||||
|
||||
@classmethod
|
||||
def getPossibleDefinitionIDsFromName(cls, name):
|
||||
name_parts = name.lower().split(" ")
|
||||
merged_name_parts = []
|
||||
for part in name_parts:
|
||||
if len(part) == 0:
|
||||
continue
|
||||
if len(merged_name_parts) == 0:
|
||||
merged_name_parts.append(part)
|
||||
continue
|
||||
if part.isdigit():
|
||||
# for names with digit(s) such as Ultimaker 3 Extended, we generate an ID like
|
||||
# "ultimaker3_extended", ignoring the space between "Ultimaker" and "3".
|
||||
merged_name_parts[-1] = merged_name_parts[-1] + part
|
||||
else:
|
||||
merged_name_parts.append(part)
|
||||
|
||||
id_list = [name.lower().replace(" ", ""), # simply removing all spaces
|
||||
name.lower().replace(" ", "_"), # simply replacing all spaces with underscores
|
||||
"_".join(merged_name_parts),
|
||||
]
|
||||
|
||||
return id_list
|
||||
|
||||
## Gets a mapping from product names in the XML files to their definition
|
||||
# IDs.
|
||||
#
|
||||
# This loads the mapping from a file.
|
||||
@classmethod
|
||||
def getProductIdMap(cls) -> Dict[str, str]:
|
||||
def getProductIdMap(cls) -> Dict[str, List[str]]:
|
||||
product_to_id_file = os.path.join(os.path.dirname(sys.modules[cls.__module__].__file__), "product_to_id.json")
|
||||
with open(product_to_id_file) as f:
|
||||
return json.load(f)
|
||||
product_to_id_map = json.load(f)
|
||||
product_to_id_map = {key: [value] for key, value in product_to_id_map.items()}
|
||||
return product_to_id_map
|
||||
|
||||
## Parse the value of the "material compatible" property.
|
||||
@classmethod
|
||||
|
@ -46,7 +46,7 @@
|
||||
"default_value": "RepRap (Marlin/Sprinter)"
|
||||
},
|
||||
"machine_start_gcode": {
|
||||
"default_value": "G28 ; Home extruder\nM107 ; Turn off fan\nG90 ; Absolute positioning\nM82 ; Extruder in absolute mode\nM190 S{material_bed_temperature}\nM104 T0 S{material_print_temperature}\nM109 T0 S{material_print_temperature}\nM104 T1 S{material_print_temperature}\nM109 T1 S{material_print_temperature}\nG32 S3 ; auto level\nG92 E0 ; Reset extruder position"
|
||||
"default_value": "G28 ; Home extruder\nM107 ; Turn off fan\nG90 ; Absolute positioning\nM82 ; Extruder in absolute mode\nM190 S{material_bed_temperature}\nM104 T0 S{material_print_temperature}\nM109 T0 S{material_print_temperature}\nM104 T1 S{material_print_temperature}\nM109 T1 S{material_print_temperature}\n;G32 S3 ; auto level\nG92 E0 ; Reset extruder position"
|
||||
},
|
||||
"machine_end_gcode": {
|
||||
"default_value": "M104 S0 ; turn off extruders\nM140 S0 ; heated bed heater off\nG91 ; relative positioning\nG1 E-2 F5000; retract 2mm\nG28 Z; move bed down\nG90 ; absolute positioning\nM84 ; disable motors"
|
||||
|
@ -18,6 +18,7 @@ Item
|
||||
property alias redo: redoAction;
|
||||
|
||||
property alias homeCamera: homeCameraAction;
|
||||
property alias expandSidebar: expandSidebarAction;
|
||||
|
||||
property alias deleteSelection: deleteSelectionAction;
|
||||
property alias centerSelection: centerSelectionAction;
|
||||
@ -389,4 +390,11 @@ Item
|
||||
text: catalog.i18nc("@action:menu", "Installed plugins...");
|
||||
iconName: "plugins_configure"
|
||||
}
|
||||
|
||||
Action
|
||||
{
|
||||
id: expandSidebarAction;
|
||||
text: catalog.i18nc("@action:inmenu menubar:view","Expand/Collapse Sidebar");
|
||||
shortcut: "Ctrl+E";
|
||||
}
|
||||
}
|
||||
|
@ -34,6 +34,24 @@ UM.MainWindow
|
||||
}
|
||||
}
|
||||
|
||||
onWidthChanged:
|
||||
{
|
||||
// If slidebar is collapsed then it should be invisible
|
||||
// otherwise after the main_window resize the sidebar will be fully re-drawn
|
||||
if (sidebar.collapsed){
|
||||
if (sidebar.visible == true){
|
||||
sidebar.visible = false
|
||||
sidebar.initialWidth = 0
|
||||
}
|
||||
}
|
||||
else{
|
||||
if (sidebar.visible == false){
|
||||
sidebar.visible = true
|
||||
sidebar.initialWidth = UM.Theme.getSize("sidebar").width
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted:
|
||||
{
|
||||
CuraApplication.setMinimumWindowSize(UM.Theme.getSize("window_minimum_size"))
|
||||
@ -369,16 +387,59 @@ UM.MainWindow
|
||||
{
|
||||
id: sidebar
|
||||
|
||||
anchors
|
||||
{
|
||||
top: topbar.bottom
|
||||
bottom: parent.bottom
|
||||
right: parent.right
|
||||
property bool collapsed: false;
|
||||
property var initialWidth: UM.Theme.getSize("sidebar").width;
|
||||
|
||||
function callExpandOrCollapse() {
|
||||
if (collapsed) {
|
||||
sidebar.visible = true;
|
||||
sidebar.initialWidth = UM.Theme.getSize("sidebar").width;
|
||||
viewportRect = Qt.rect(0, 0, (base.width - sidebar.width) / base.width, 1.0);
|
||||
expandSidebarAnimation.start();
|
||||
} else {
|
||||
viewportRect = Qt.rect(0, 0, 1, 1.0);
|
||||
collapseSidebarAnimation.start();
|
||||
}
|
||||
collapsed = !collapsed;
|
||||
UM.Preferences.setValue("cura/sidebar_collapse", collapsed);
|
||||
}
|
||||
|
||||
width: UM.Theme.getSize("sidebar").width
|
||||
anchors
|
||||
{
|
||||
top: topbar.top
|
||||
bottom: parent.bottom
|
||||
}
|
||||
|
||||
width: initialWidth
|
||||
x: base.width - sidebar.width
|
||||
source: UM.Controller.activeStage.sidebarComponent
|
||||
|
||||
NumberAnimation {
|
||||
id: collapseSidebarAnimation
|
||||
target: sidebar
|
||||
properties: "x"
|
||||
to: base.width
|
||||
duration: 100
|
||||
}
|
||||
|
||||
NumberAnimation {
|
||||
id: expandSidebarAnimation
|
||||
target: sidebar
|
||||
properties: "x"
|
||||
to: base.width - sidebar.width
|
||||
duration: 100
|
||||
}
|
||||
|
||||
Component.onCompleted:
|
||||
{
|
||||
var sidebarCollapsed = UM.Preferences.getValue("cura/sidebar_collapse");
|
||||
|
||||
if (sidebarCollapsed) {
|
||||
sidebar.collapsed = true;
|
||||
viewportRect = Qt.rect(0, 0, 1, 1.0)
|
||||
collapseSidebarAnimation.start();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loader
|
||||
@ -417,6 +478,13 @@ UM.MainWindow
|
||||
}
|
||||
}
|
||||
|
||||
// Expand or collapse sidebar
|
||||
Connections
|
||||
{
|
||||
target: Cura.Actions.expandSidebar
|
||||
onTriggered: sidebar.callExpandOrCollapse()
|
||||
}
|
||||
|
||||
UM.PreferencesDialog
|
||||
{
|
||||
id: preferences
|
||||
|
71
resources/qml/MachineSelection.qml
Normal file
71
resources/qml/MachineSelection.qml
Normal file
@ -0,0 +1,71 @@
|
||||
// Copyright (c) 2017 Ultimaker B.V.
|
||||
// Cura is released under the terms of the LGPLv3 or higher.
|
||||
|
||||
import QtQuick 2.2
|
||||
import QtQuick.Controls 1.1
|
||||
import QtQuick.Controls.Styles 1.1
|
||||
import QtQuick.Layouts 1.1
|
||||
|
||||
import UM 1.2 as UM
|
||||
import Cura 1.0 as Cura
|
||||
import "Menus"
|
||||
|
||||
ToolButton
|
||||
{
|
||||
text: Cura.MachineManager.activeMachineName
|
||||
|
||||
tooltip: Cura.MachineManager.activeMachineName
|
||||
|
||||
style: ButtonStyle
|
||||
{
|
||||
background: Rectangle
|
||||
{
|
||||
color:
|
||||
{
|
||||
if(control.pressed)
|
||||
{
|
||||
return UM.Theme.getColor("sidebar_header_active");
|
||||
}
|
||||
else if(control.hovered)
|
||||
{
|
||||
return UM.Theme.getColor("sidebar_header_hover");
|
||||
}
|
||||
else
|
||||
{
|
||||
return UM.Theme.getColor("sidebar_header_bar");
|
||||
}
|
||||
}
|
||||
Behavior on color { ColorAnimation { duration: 50; } }
|
||||
|
||||
UM.RecolorImage
|
||||
{
|
||||
id: downArrow
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: UM.Theme.getSize("default_margin").width
|
||||
width: UM.Theme.getSize("standard_arrow").width
|
||||
height: UM.Theme.getSize("standard_arrow").height
|
||||
sourceSize.width: width
|
||||
sourceSize.height: width
|
||||
color: UM.Theme.getColor("text_emphasis")
|
||||
source: UM.Theme.getIcon("arrow_bottom")
|
||||
}
|
||||
Label
|
||||
{
|
||||
id: sidebarComboBoxLabel
|
||||
color: UM.Theme.getColor("sidebar_header_text_active")
|
||||
text: control.text;
|
||||
elide: Text.ElideRight;
|
||||
anchors.left: parent.left;
|
||||
anchors.leftMargin: UM.Theme.getSize("default_margin").width * 2
|
||||
anchors.right: downArrow.left;
|
||||
anchors.rightMargin: control.rightMargin;
|
||||
anchors.verticalCenter: parent.verticalCenter;
|
||||
font: UM.Theme.getFont("large")
|
||||
}
|
||||
}
|
||||
label: Label {}
|
||||
}
|
||||
|
||||
menu: PrinterMenu { }
|
||||
}
|
@ -32,4 +32,5 @@ Menu
|
||||
|
||||
MenuSeparator {}
|
||||
MenuItem { action: Cura.Actions.homeCamera; }
|
||||
MenuItem { action: Cura.Actions.expandSidebar; }
|
||||
}
|
||||
|
@ -1171,4 +1171,4 @@ Column
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -12,11 +12,9 @@ Item {
|
||||
id: base;
|
||||
UM.I18nCatalog { id: catalog; name:"cura"}
|
||||
|
||||
property real progress: UM.Backend.progress;
|
||||
property int backendState: UM.Backend.state;
|
||||
|
||||
property var backend: CuraApplication.getBackend();
|
||||
property bool activity: CuraApplication.platformActivity;
|
||||
property real progress: UM.Backend.progress
|
||||
property int backendState: UM.Backend.state
|
||||
property bool activity: CuraApplication.platformActivity
|
||||
|
||||
property alias buttonRowWidth: saveRow.width
|
||||
|
||||
@ -50,10 +48,14 @@ Item {
|
||||
}
|
||||
|
||||
function sliceOrStopSlicing() {
|
||||
if (backend != "undefined" && [1, 5].indexOf(UM.Backend.state) != -1) {
|
||||
backend.forceSlice();
|
||||
} else {
|
||||
backend.stopSlicing();
|
||||
try {
|
||||
if ([1, 5].indexOf(base.backendState) != -1) {
|
||||
CuraApplication.backend.forceSlice();
|
||||
} else {
|
||||
CuraApplication.backend.stopSlicing();
|
||||
}
|
||||
} catch (e) {
|
||||
console.log('Could not start or stop slicing', e)
|
||||
}
|
||||
}
|
||||
|
||||
@ -166,7 +168,7 @@ Item {
|
||||
Button {
|
||||
id: prepareButton
|
||||
|
||||
tooltip: [1, 5].indexOf(UM.Backend.state) != -1 ? catalog.i18nc("@info:tooltip","Slice current printjob") : catalog.i18nc("@info:tooltip","Cancel slicing process")
|
||||
tooltip: [1, 5].indexOf(base.backendState) != -1 ? catalog.i18nc("@info:tooltip","Slice current printjob") : catalog.i18nc("@info:tooltip","Cancel slicing process")
|
||||
// 1 = not started, 2 = Processing
|
||||
enabled: base.backendState != "undefined" && (base.backendState == 1 || base.backendState == 2) && base.activity == true
|
||||
visible: base.backendState != "undefined" && !autoSlice && (base.backendState == 1 || base.backendState == 2) && base.activity == true
|
||||
@ -178,7 +180,7 @@ Item {
|
||||
anchors.rightMargin: UM.Theme.getSize("sidebar_margin").width
|
||||
|
||||
// 1 = not started, 5 = disabled
|
||||
text: [1, 5].indexOf(UM.Backend.state) != -1 ? catalog.i18nc("@label:Printjob", "Prepare") : catalog.i18nc("@label:Printjob", "Cancel")
|
||||
text: [1, 5].indexOf(base.backendState) != -1 ? catalog.i18nc("@label:Printjob", "Prepare") : catalog.i18nc("@label:Printjob", "Cancel")
|
||||
onClicked:
|
||||
{
|
||||
sliceOrStopSlicing();
|
||||
|
@ -14,11 +14,13 @@ import "."
|
||||
Item {
|
||||
id: base;
|
||||
|
||||
height: UM.Theme.getSize("section").height;
|
||||
height: UM.Theme.getSize("section").height
|
||||
|
||||
property alias contents: controlContainer.children;
|
||||
property alias contents: controlContainer.children
|
||||
property alias hovered: mouse.containsMouse
|
||||
|
||||
property var resetHandler: false
|
||||
|
||||
property var showRevertButton: true
|
||||
property var showInheritButton: true
|
||||
property var showLinkedSettingIcon: true
|
||||
@ -179,8 +181,13 @@ Item {
|
||||
iconSource: UM.Theme.getIcon("reset")
|
||||
|
||||
onClicked: {
|
||||
revertButton.focus = true;
|
||||
Cura.MachineManager.clearUserSettingAllCurrentStacks(propertyProvider.key);
|
||||
revertButton.focus = true
|
||||
|
||||
if (resetHandler) {
|
||||
resetHandler(propertyProvider.key)
|
||||
} else {
|
||||
Cura.MachineManager.clearUserSettingAllCurrentStacks(propertyProvider.key)
|
||||
}
|
||||
}
|
||||
|
||||
onEntered: { hoverTimer.stop(); base.showTooltip(catalog.i18nc("@label", "This setting has a value that is different from the profile.\n\nClick to restore the value of the profile.")) }
|
||||
|
@ -22,7 +22,6 @@ Rectangle
|
||||
property bool printerConnected: Cura.MachineManager.printerOutputDevices.length != 0
|
||||
property bool printerAcceptsCommands: printerConnected && Cura.MachineManager.printerOutputDevices[0].acceptsCommands
|
||||
property var connectedPrinter: Cura.MachineManager.printerOutputDevices.length >= 1 ? Cura.MachineManager.printerOutputDevices[0] : null
|
||||
property int backendState: UM.Backend.state
|
||||
|
||||
property bool monitoringPrint: UM.Controller.activeStage.stageId == "MonitorStage"
|
||||
|
||||
@ -87,10 +86,19 @@ Rectangle
|
||||
}
|
||||
}
|
||||
|
||||
MachineSelection {
|
||||
id: machineSelection
|
||||
width: base.width
|
||||
height: UM.Theme.getSize("sidebar_header").height
|
||||
anchors.top: base.top
|
||||
anchors.right: parent.right
|
||||
}
|
||||
|
||||
SidebarHeader {
|
||||
id: header
|
||||
width: parent.width
|
||||
visible: machineExtruderCount.properties.value > 1 || Cura.MachineManager.hasMaterials || Cura.MachineManager.hasVariants
|
||||
anchors.top: machineSelection.bottom
|
||||
|
||||
onShowTooltip: base.showTooltip(item, location, text)
|
||||
onHideTooltip: base.hideTooltip()
|
||||
@ -263,7 +271,7 @@ Rectangle
|
||||
{
|
||||
id: controlItem
|
||||
anchors.bottom: footerSeparator.top
|
||||
anchors.top: monitoringPrint ? base.top : headerSeparator.bottom
|
||||
anchors.top: monitoringPrint ? machineSelection.bottom : headerSeparator.bottom
|
||||
anchors.left: base.left
|
||||
anchors.right: base.right
|
||||
sourceComponent:
|
||||
@ -282,7 +290,7 @@ Rectangle
|
||||
Loader
|
||||
{
|
||||
anchors.bottom: footerSeparator.top
|
||||
anchors.top: monitoringPrint ? base.top : headerSeparator.bottom
|
||||
anchors.top: monitoringPrint ? machineSelection.bottom : headerSeparator.bottom
|
||||
anchors.left: base.left
|
||||
anchors.right: base.right
|
||||
source:
|
||||
|
@ -21,6 +21,22 @@ Rectangle
|
||||
property bool printerConnected: Cura.MachineManager.printerOutputDevices.length != 0
|
||||
property bool printerAcceptsCommands: printerConnected && Cura.MachineManager.printerOutputDevices[0].acceptsCommands
|
||||
|
||||
property int rightMargin: UM.Theme.getSize("sidebar").width + UM.Theme.getSize("default_margin").width;
|
||||
property int allItemsWidth: 0;
|
||||
|
||||
function updateMarginsAndSizes() {
|
||||
if (UM.Preferences.getValue("cura/sidebar_collapse")) {
|
||||
rightMargin = UM.Theme.getSize("default_margin").width;
|
||||
} else {
|
||||
rightMargin = UM.Theme.getSize("sidebar").width + UM.Theme.getSize("default_margin").width;
|
||||
}
|
||||
allItemsWidth = (
|
||||
logo.width + UM.Theme.getSize("topbar_logo_right_margin").width +
|
||||
UM.Theme.getSize("topbar_logo_right_margin").width + stagesMenuContainer.width +
|
||||
UM.Theme.getSize("default_margin").width + viewModeButton.width +
|
||||
rightMargin);
|
||||
}
|
||||
|
||||
UM.I18nCatalog
|
||||
{
|
||||
id: catalog
|
||||
@ -44,10 +60,9 @@ Rectangle
|
||||
|
||||
Row
|
||||
{
|
||||
id: stagesMenuContainer
|
||||
anchors.left: logo.right
|
||||
anchors.leftMargin: UM.Theme.getSize("topbar_logo_right_margin").width
|
||||
anchors.right: machineSelection.left
|
||||
anchors.rightMargin: UM.Theme.getSize("default_margin").width
|
||||
spacing: UM.Theme.getSize("default_margin").width
|
||||
|
||||
// The topbar is dynamically filled with all available stages
|
||||
@ -76,71 +91,6 @@ Rectangle
|
||||
ExclusiveGroup { id: topbarMenuGroup }
|
||||
}
|
||||
|
||||
ToolButton
|
||||
{
|
||||
id: machineSelection
|
||||
text: Cura.MachineManager.activeMachineName
|
||||
|
||||
width: UM.Theme.getSize("sidebar").width
|
||||
height: UM.Theme.getSize("sidebar_header").height
|
||||
tooltip: Cura.MachineManager.activeMachineName
|
||||
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.right: parent.right
|
||||
style: ButtonStyle
|
||||
{
|
||||
background: Rectangle
|
||||
{
|
||||
color:
|
||||
{
|
||||
if(control.pressed)
|
||||
{
|
||||
return UM.Theme.getColor("sidebar_header_active");
|
||||
}
|
||||
else if(control.hovered)
|
||||
{
|
||||
return UM.Theme.getColor("sidebar_header_hover");
|
||||
}
|
||||
else
|
||||
{
|
||||
return UM.Theme.getColor("sidebar_header_bar");
|
||||
}
|
||||
}
|
||||
Behavior on color { ColorAnimation { duration: 50; } }
|
||||
|
||||
UM.RecolorImage
|
||||
{
|
||||
id: downArrow
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: UM.Theme.getSize("default_margin").width
|
||||
width: UM.Theme.getSize("standard_arrow").width
|
||||
height: UM.Theme.getSize("standard_arrow").height
|
||||
sourceSize.width: width
|
||||
sourceSize.height: width
|
||||
color: UM.Theme.getColor("text_emphasis")
|
||||
source: UM.Theme.getIcon("arrow_bottom")
|
||||
}
|
||||
Label
|
||||
{
|
||||
id: sidebarComboBoxLabel
|
||||
color: UM.Theme.getColor("sidebar_header_text_active")
|
||||
text: control.text;
|
||||
elide: Text.ElideRight;
|
||||
anchors.left: parent.left;
|
||||
anchors.leftMargin: UM.Theme.getSize("default_margin").width * 2
|
||||
anchors.right: downArrow.left;
|
||||
anchors.rightMargin: control.rightMargin;
|
||||
anchors.verticalCenter: parent.verticalCenter;
|
||||
font: UM.Theme.getFont("large")
|
||||
}
|
||||
}
|
||||
label: Label {}
|
||||
}
|
||||
|
||||
menu: PrinterMenu { }
|
||||
}
|
||||
|
||||
// View orientation Item
|
||||
Row
|
||||
{
|
||||
@ -152,8 +102,8 @@ Rectangle
|
||||
anchors
|
||||
{
|
||||
verticalCenter: base.verticalCenter
|
||||
right: viewModeButton.right
|
||||
rightMargin: UM.Theme.getSize("default_margin").width + viewModeButton.width
|
||||
right: viewModeButton.left
|
||||
rightMargin: UM.Theme.getSize("default_margin").width
|
||||
}
|
||||
|
||||
// #1 3d view
|
||||
@ -165,7 +115,7 @@ Rectangle
|
||||
onClicked:{
|
||||
UM.Controller.rotateView("3d", 0);
|
||||
}
|
||||
visible: base.width > 1100
|
||||
visible: base.width - allItemsWidth - 4 * this.width > 0;
|
||||
}
|
||||
|
||||
// #2 Front view
|
||||
@ -177,7 +127,7 @@ Rectangle
|
||||
onClicked:{
|
||||
UM.Controller.rotateView("home", 0);
|
||||
}
|
||||
visible: base.width > 1130
|
||||
visible: base.width - allItemsWidth - 3 * this.width > 0;
|
||||
}
|
||||
|
||||
// #3 Top view
|
||||
@ -189,7 +139,7 @@ Rectangle
|
||||
onClicked:{
|
||||
UM.Controller.rotateView("y", 90);
|
||||
}
|
||||
visible: base.width > 1160
|
||||
visible: base.width - allItemsWidth - 2 * this.width > 0;
|
||||
}
|
||||
|
||||
// #4 Left view
|
||||
@ -201,7 +151,7 @@ Rectangle
|
||||
onClicked:{
|
||||
UM.Controller.rotateView("x", 90);
|
||||
}
|
||||
visible: base.width > 1190
|
||||
visible: base.width - allItemsWidth - 1 * this.width > 0;
|
||||
}
|
||||
|
||||
// #5 Left view
|
||||
@ -213,7 +163,7 @@ Rectangle
|
||||
onClicked:{
|
||||
UM.Controller.rotateView("x", -90);
|
||||
}
|
||||
visible: base.width > 1210
|
||||
visible: base.width - allItemsWidth > 0;
|
||||
}
|
||||
}
|
||||
|
||||
@ -224,7 +174,7 @@ Rectangle
|
||||
anchors {
|
||||
verticalCenter: parent.verticalCenter
|
||||
right: parent.right
|
||||
rightMargin: UM.Theme.getSize("sidebar").width + UM.Theme.getSize("default_margin").width
|
||||
rightMargin: rightMargin
|
||||
}
|
||||
|
||||
style: UM.Theme.styles.combobox
|
||||
@ -284,4 +234,16 @@ Rectangle
|
||||
source: UM.ActiveView.valid ? UM.ActiveView.activeViewPanel : "";
|
||||
}
|
||||
|
||||
// Expand or collapse sidebar
|
||||
Connections
|
||||
{
|
||||
target: Cura.Actions.expandSidebar
|
||||
onTriggered: updateMarginsAndSizes()
|
||||
}
|
||||
|
||||
Component.onCompleted:
|
||||
{
|
||||
updateMarginsAndSizes();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,34 @@
|
||||
[general]
|
||||
version = 2
|
||||
name = Fine
|
||||
definition = ultimaker3
|
||||
|
||||
[metadata]
|
||||
type = quality
|
||||
quality_type = normal
|
||||
material = generic_bam_ultimaker3_AA_0.4
|
||||
weight = 0
|
||||
setting_version = 4
|
||||
|
||||
[values]
|
||||
cool_fan_full_at_height = =layer_height_0 + 2 * layer_height
|
||||
cool_fan_speed_max = =cool_fan_speed
|
||||
cool_min_speed = 7
|
||||
machine_nozzle_cool_down_speed = 0.75
|
||||
machine_nozzle_heat_up_speed = 1.6
|
||||
material_print_temperature = =default_material_print_temperature - 10
|
||||
prime_tower_enable = =min(extruderValues('material_surface_energy')) < 100
|
||||
skin_overlap = 10
|
||||
speed_layer_0 = 20
|
||||
support_interface_enable = True
|
||||
support_interface_density = =min(extruderValues('material_surface_energy'))
|
||||
support_interface_pattern = ='lines' if support_interface_density < 100 else 'concentric'
|
||||
support_top_distance = =math.ceil(min(extruderValues('material_adhesion_tendency')) / 1) * layer_height
|
||||
support_bottom_distance = =math.ceil(min(extruderValues('material_adhesion_tendency')) / 2) * layer_height
|
||||
support_angle = 45
|
||||
support_join_distance = 5
|
||||
support_offset = 2
|
||||
support_pattern = triangles
|
||||
support_infill_rate = 10
|
||||
top_bottom_thickness = 1
|
||||
wall_thickness = 1
|
@ -6,7 +6,9 @@ import pytest #This module contains unit tests.
|
||||
import shutil #To copy files to make a temporary file.
|
||||
import unittest.mock #To mock and monkeypatch stuff.
|
||||
import urllib.parse
|
||||
import copy
|
||||
|
||||
import cura.CuraApplication
|
||||
from cura.Settings.CuraContainerRegistry import CuraContainerRegistry #The class we're testing.
|
||||
from cura.Settings.ExtruderStack import ExtruderStack #Testing for returning the correct types of stacks.
|
||||
from cura.Settings.GlobalStack import GlobalStack #Testing for returning the correct types of stacks.
|
||||
@ -15,6 +17,32 @@ import UM.Settings.InstanceContainer #Creating instance containers to register.
|
||||
import UM.Settings.ContainerRegistry #Making empty container stacks.
|
||||
import UM.Settings.ContainerStack #Setting the container registry here properly.
|
||||
from UM.Settings.DefinitionContainer import DefinitionContainer
|
||||
from UM.Settings.ContainerRegistry import ContainerRegistry
|
||||
|
||||
def creteEmptyContainers():
|
||||
empty_container = ContainerRegistry.getInstance().getEmptyInstanceContainer()
|
||||
empty_variant_container = copy.deepcopy(empty_container)
|
||||
empty_variant_container.setMetaDataEntry("id", "empty_variant")
|
||||
empty_variant_container.addMetaDataEntry("type", "variant")
|
||||
ContainerRegistry.getInstance().addContainer(empty_variant_container)
|
||||
|
||||
empty_material_container = copy.deepcopy(empty_container)
|
||||
empty_material_container.setMetaDataEntry("id", "empty_material")
|
||||
empty_material_container.addMetaDataEntry("type", "material")
|
||||
ContainerRegistry.getInstance().addContainer(empty_material_container)
|
||||
|
||||
empty_quality_container = copy.deepcopy(empty_container)
|
||||
empty_quality_container.setMetaDataEntry("id", "empty_quality")
|
||||
empty_quality_container.setName("Not Supported")
|
||||
empty_quality_container.addMetaDataEntry("quality_type", "not_supported")
|
||||
empty_quality_container.addMetaDataEntry("type", "quality")
|
||||
empty_quality_container.addMetaDataEntry("supported", False)
|
||||
ContainerRegistry.getInstance().addContainer(empty_quality_container)
|
||||
|
||||
empty_quality_changes_container = copy.deepcopy(empty_container)
|
||||
empty_quality_changes_container.setMetaDataEntry("id", "empty_quality_changes")
|
||||
empty_quality_changes_container.addMetaDataEntry("type", "quality_changes")
|
||||
ContainerRegistry.getInstance().addContainer(empty_quality_changes_container)
|
||||
|
||||
## Gives a fresh CuraContainerRegistry instance.
|
||||
@pytest.fixture()
|
||||
@ -37,6 +65,7 @@ def teardown():
|
||||
|
||||
## Tests whether addContainer properly converts to ExtruderStack.
|
||||
def test_addContainerExtruderStack(container_registry, definition_container):
|
||||
creteEmptyContainers()
|
||||
container_registry.addContainer(definition_container)
|
||||
|
||||
container_stack = UM.Settings.ContainerStack.ContainerStack(stack_id = "Test Container Stack") #A container we're going to convert.
|
||||
@ -113,36 +142,36 @@ def test_addContainerBadSettingVersion(container_registry, definition_container)
|
||||
mock_super_add_container.assert_not_called() #Should not get passed on to UM.Settings.ContainerRegistry.addContainer, because the setting_version doesn't match its definition!
|
||||
|
||||
## Tests whether loading gives objects of the correct type.
|
||||
@pytest.mark.parametrize("filename, output_class", [
|
||||
("ExtruderLegacy.stack.cfg", ExtruderStack),
|
||||
("MachineLegacy.stack.cfg", GlobalStack),
|
||||
("Left.extruder.cfg", ExtruderStack),
|
||||
("Global.global.cfg", GlobalStack),
|
||||
("Global.stack.cfg", GlobalStack)
|
||||
])
|
||||
def test_loadTypes(filename, output_class, container_registry):
|
||||
#Mock some dependencies.
|
||||
Resources.getAllResourcesOfType = unittest.mock.MagicMock(return_value = [os.path.join(os.path.dirname(os.path.abspath(__file__)), "stacks", filename)]) #Return just this tested file.
|
||||
|
||||
def findContainers(container_type = 0, id = None):
|
||||
if id == "some_instance":
|
||||
return [UM.Settings.ContainerRegistry._EmptyInstanceContainer(id)]
|
||||
elif id == "some_definition":
|
||||
return [DefinitionContainer(container_id = id)]
|
||||
else:
|
||||
return []
|
||||
|
||||
container_registry.findContainers = findContainers
|
||||
|
||||
with unittest.mock.patch("cura.Settings.GlobalStack.GlobalStack.findContainer"):
|
||||
with unittest.mock.patch("os.remove"):
|
||||
container_registry.load()
|
||||
|
||||
#Check whether the resulting type was correct.
|
||||
stack_id = filename.split(".")[0]
|
||||
for container_id, container in container_registry._containers.items(): #Stupid ContainerRegistry class doesn't expose any way of getting at this except by prodding the privates.
|
||||
if container_id == stack_id: #This is the one we're testing.
|
||||
assert type(container) == output_class
|
||||
break
|
||||
else:
|
||||
assert False #Container stack with specified ID was not loaded.
|
||||
# @pytest.mark.parametrize("filename, output_class", [
|
||||
# ("ExtruderLegacy.stack.cfg", ExtruderStack),
|
||||
# ("MachineLegacy.stack.cfg", GlobalStack),
|
||||
# ("Left.extruder.cfg", ExtruderStack),
|
||||
# ("Global.global.cfg", GlobalStack),
|
||||
# ("Global.stack.cfg", GlobalStack)
|
||||
# ])
|
||||
# def test_loadTypes(filename, output_class, container_registry):
|
||||
# #Mock some dependencies.
|
||||
# Resources.getAllResourcesOfType = unittest.mock.MagicMock(return_value = [os.path.join(os.path.dirname(os.path.abspath(__file__)), "stacks", filename)]) #Return just this tested file.
|
||||
#
|
||||
# def findContainers(container_type = 0, id = None):
|
||||
# if id == "some_instance":
|
||||
# return [UM.Settings.ContainerRegistry._EmptyInstanceContainer(id)]
|
||||
# elif id == "some_definition":
|
||||
# return [DefinitionContainer(container_id = id)]
|
||||
# else:
|
||||
# return []
|
||||
#
|
||||
# container_registry.findContainers = findContainers
|
||||
#
|
||||
# with unittest.mock.patch("cura.Settings.GlobalStack.GlobalStack.findContainer"):
|
||||
# with unittest.mock.patch("os.remove"):
|
||||
# container_registry.load()
|
||||
#
|
||||
# #Check whether the resulting type was correct.
|
||||
# stack_id = filename.split(".")[0]
|
||||
# for container_id, container in container_registry._containers.items(): #Stupid ContainerRegistry class doesn't expose any way of getting at this except by prodding the privates.
|
||||
# if container_id == stack_id: #This is the one we're testing.
|
||||
# assert type(container) == output_class
|
||||
# break
|
||||
# else:
|
||||
# assert False #Container stack with specified ID was not loaded.
|
@ -3,7 +3,9 @@
|
||||
|
||||
import pytest #This module contains automated tests.
|
||||
import unittest.mock #For the mocking and monkeypatching functionality.
|
||||
import copy
|
||||
|
||||
import cura.CuraApplication
|
||||
import UM.Settings.ContainerRegistry #To create empty instance containers.
|
||||
import UM.Settings.ContainerStack #To set the container registry the container stacks use.
|
||||
from UM.Settings.DefinitionContainer import DefinitionContainer #To check against the class of DefinitionContainer.
|
||||
@ -12,6 +14,7 @@ import cura.Settings.ExtruderStack #The module we're testing.
|
||||
from cura.Settings.Exceptions import InvalidContainerError, InvalidOperationError #To check whether the correct exceptions are raised.
|
||||
|
||||
from cura.Settings.ExtruderManager import ExtruderManager
|
||||
from UM.Settings.ContainerRegistry import ContainerRegistry
|
||||
|
||||
## Fake container registry that always provides all containers you ask of.
|
||||
@pytest.yield_fixture()
|
||||
@ -32,6 +35,7 @@ def container_registry():
|
||||
## An empty extruder stack to test with.
|
||||
@pytest.fixture()
|
||||
def extruder_stack() -> cura.Settings.ExtruderStack.ExtruderStack:
|
||||
creteEmptyContainers()
|
||||
return cura.Settings.ExtruderStack.ExtruderStack("TestStack")
|
||||
|
||||
## Gets an instance container with a specified container type.
|
||||
@ -43,6 +47,31 @@ def getInstanceContainer(container_type) -> InstanceContainer:
|
||||
container.addMetaDataEntry("type", container_type)
|
||||
return container
|
||||
|
||||
def creteEmptyContainers():
|
||||
empty_container = ContainerRegistry.getInstance().getEmptyInstanceContainer()
|
||||
empty_variant_container = copy.deepcopy(empty_container)
|
||||
empty_variant_container.setMetaDataEntry("id", "empty_variant")
|
||||
empty_variant_container.addMetaDataEntry("type", "variant")
|
||||
ContainerRegistry.getInstance().addContainer(empty_variant_container)
|
||||
|
||||
empty_material_container = copy.deepcopy(empty_container)
|
||||
empty_material_container.setMetaDataEntry("id", "empty_material")
|
||||
empty_material_container.addMetaDataEntry("type", "material")
|
||||
ContainerRegistry.getInstance().addContainer(empty_material_container)
|
||||
|
||||
empty_quality_container = copy.deepcopy(empty_container)
|
||||
empty_quality_container.setMetaDataEntry("id", "empty_quality")
|
||||
empty_quality_container.setName("Not Supported")
|
||||
empty_quality_container.addMetaDataEntry("quality_type", "not_supported")
|
||||
empty_quality_container.addMetaDataEntry("type", "quality")
|
||||
empty_quality_container.addMetaDataEntry("supported", False)
|
||||
ContainerRegistry.getInstance().addContainer(empty_quality_container)
|
||||
|
||||
empty_quality_changes_container = copy.deepcopy(empty_container)
|
||||
empty_quality_changes_container.setMetaDataEntry("id", "empty_quality_changes")
|
||||
empty_quality_changes_container.addMetaDataEntry("type", "quality_changes")
|
||||
ContainerRegistry.getInstance().addContainer(empty_quality_changes_container)
|
||||
|
||||
class DefinitionContainerSubClass(DefinitionContainer):
|
||||
def __init__(self):
|
||||
super().__init__(container_id = "SubDefinitionContainer")
|
||||
|
@ -3,7 +3,9 @@
|
||||
|
||||
import pytest #This module contains unit tests.
|
||||
import unittest.mock #To monkeypatch some mocks in place of dependencies.
|
||||
import copy
|
||||
|
||||
import cura.CuraApplication
|
||||
import cura.Settings.GlobalStack #The module we're testing.
|
||||
import cura.Settings.CuraContainerStack #To get the list of container types.
|
||||
from cura.Settings.Exceptions import TooManyExtrudersError, InvalidContainerError, InvalidOperationError #To test raising these errors.
|
||||
@ -13,6 +15,7 @@ from UM.Settings.SettingInstance import InstanceState
|
||||
import UM.Settings.ContainerRegistry
|
||||
import UM.Settings.ContainerStack
|
||||
import UM.Settings.SettingDefinition #To add settings to the definition.
|
||||
from UM.Settings.ContainerRegistry import ContainerRegistry
|
||||
|
||||
## Fake container registry that always provides all containers you ask of.
|
||||
@pytest.yield_fixture()
|
||||
@ -33,6 +36,7 @@ def container_registry():
|
||||
#An empty global stack to test with.
|
||||
@pytest.fixture()
|
||||
def global_stack() -> cura.Settings.GlobalStack.GlobalStack:
|
||||
creteEmptyContainers()
|
||||
return cura.Settings.GlobalStack.GlobalStack("TestStack")
|
||||
|
||||
## Gets an instance container with a specified container type.
|
||||
@ -44,6 +48,31 @@ def getInstanceContainer(container_type) -> InstanceContainer:
|
||||
container.addMetaDataEntry("type", container_type)
|
||||
return container
|
||||
|
||||
def creteEmptyContainers():
|
||||
empty_container = ContainerRegistry.getInstance().getEmptyInstanceContainer()
|
||||
empty_variant_container = copy.deepcopy(empty_container)
|
||||
empty_variant_container.setMetaDataEntry("id", "empty_variant")
|
||||
empty_variant_container.addMetaDataEntry("type", "variant")
|
||||
ContainerRegistry.getInstance().addContainer(empty_variant_container)
|
||||
|
||||
empty_material_container = copy.deepcopy(empty_container)
|
||||
empty_material_container.setMetaDataEntry("id", "empty_material")
|
||||
empty_material_container.addMetaDataEntry("type", "material")
|
||||
ContainerRegistry.getInstance().addContainer(empty_material_container)
|
||||
|
||||
empty_quality_container = copy.deepcopy(empty_container)
|
||||
empty_quality_container.setMetaDataEntry("id", "empty_quality")
|
||||
empty_quality_container.setName("Not Supported")
|
||||
empty_quality_container.addMetaDataEntry("quality_type", "not_supported")
|
||||
empty_quality_container.addMetaDataEntry("type", "quality")
|
||||
empty_quality_container.addMetaDataEntry("supported", False)
|
||||
ContainerRegistry.getInstance().addContainer(empty_quality_container)
|
||||
|
||||
empty_quality_changes_container = copy.deepcopy(empty_container)
|
||||
empty_quality_changes_container.setMetaDataEntry("id", "empty_quality_changes")
|
||||
empty_quality_changes_container.addMetaDataEntry("type", "quality_changes")
|
||||
ContainerRegistry.getInstance().addContainer(empty_quality_changes_container)
|
||||
|
||||
class DefinitionContainerSubClass(DefinitionContainer):
|
||||
def __init__(self):
|
||||
super().__init__(container_id = "SubDefinitionContainer")
|
||||
|
Loading…
x
Reference in New Issue
Block a user