mirror of
https://github.com/Ultimaker/Cura.git
synced 2025-08-08 22:35:03 -06:00
Merge branch 'master' into CURA-5204_send_anonymous_data
This commit is contained in:
commit
4e53f219f0
100 changed files with 4143 additions and 4744 deletions
|
@ -7,6 +7,7 @@ import os
|
|||
import threading
|
||||
from typing import List, Tuple
|
||||
|
||||
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
from UM.Workspace.WorkspaceReader import WorkspaceReader
|
||||
|
@ -15,6 +16,7 @@ from UM.Application import Application
|
|||
from UM.Logger import Logger
|
||||
from UM.i18n import i18nCatalog
|
||||
from UM.Signal import postponeSignals, CompressTechnique
|
||||
from UM.Settings.ContainerFormatError import ContainerFormatError
|
||||
from UM.Settings.ContainerStack import ContainerStack
|
||||
from UM.Settings.DefinitionContainer import DefinitionContainer
|
||||
from UM.Settings.InstanceContainer import InstanceContainer
|
||||
|
@ -28,43 +30,13 @@ from cura.Settings.ExtruderStack import ExtruderStack
|
|||
from cura.Settings.GlobalStack import GlobalStack
|
||||
from cura.Settings.CuraContainerStack import _ContainerIndexes
|
||||
from cura.CuraApplication import CuraApplication
|
||||
from cura.Utils.Threading import call_on_qt_thread
|
||||
|
||||
from .WorkspaceDialog import WorkspaceDialog
|
||||
|
||||
i18n_catalog = i18nCatalog("cura")
|
||||
|
||||
|
||||
#
|
||||
# HACK:
|
||||
#
|
||||
# In project loading, when override the existing machine is selected, the stacks and containers that are correctly
|
||||
# active in the system will be overridden at runtime. Because the project loading is done in a different thread than
|
||||
# the Qt thread, something else can kick in the middle of the process. One of them is the rendering. It will access
|
||||
# the current stacks and container, which have not completely been updated yet, so Cura will crash in this case.
|
||||
#
|
||||
# This "@call_on_qt_thread" decorator makes sure that a function will always be called on the Qt thread (blocking).
|
||||
# It is applied to the read() function of project loading so it can be guaranteed that only after the project loading
|
||||
# process is completely done, everything else that needs to occupy the QT thread will be executed.
|
||||
#
|
||||
class InterCallObject:
|
||||
def __init__(self):
|
||||
self.finish_event = threading.Event()
|
||||
self.result = None
|
||||
|
||||
|
||||
def call_on_qt_thread(func):
|
||||
def _call_on_qt_thread_wrapper(*args, **kwargs):
|
||||
def _handle_call(ico, *args, **kwargs):
|
||||
ico.result = func(*args, **kwargs)
|
||||
ico.finish_event.set()
|
||||
inter_call_object = InterCallObject()
|
||||
new_args = tuple([inter_call_object] + list(args)[:])
|
||||
CuraApplication.getInstance().callLater(_handle_call, *new_args, **kwargs)
|
||||
inter_call_object.finish_event.wait()
|
||||
return inter_call_object.result
|
||||
return _call_on_qt_thread_wrapper
|
||||
|
||||
|
||||
class ContainerInfo:
|
||||
def __init__(self, file_name: str, serialized: str, parser: ConfigParser):
|
||||
self.file_name = file_name
|
||||
|
@ -332,7 +304,12 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
|
|||
containers_found_dict["quality_changes"] = True
|
||||
# Check if there really is a conflict by comparing the values
|
||||
instance_container = InstanceContainer(container_id)
|
||||
instance_container.deserialize(serialized, file_name = instance_container_file_name)
|
||||
try:
|
||||
instance_container.deserialize(serialized, file_name = instance_container_file_name)
|
||||
except ContainerFormatError:
|
||||
Logger.logException("e", "Failed to deserialize InstanceContainer %s from project file %s",
|
||||
instance_container_file_name, file_name)
|
||||
return ThreeMFWorkspaceReader.PreReadResult.failed
|
||||
if quality_changes[0] != instance_container:
|
||||
quality_changes_conflict = True
|
||||
elif container_type == "quality":
|
||||
|
@ -639,8 +616,15 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
|
|||
definitions = self._container_registry.findDefinitionContainersMetadata(id = container_id)
|
||||
if not definitions:
|
||||
definition_container = DefinitionContainer(container_id)
|
||||
definition_container.deserialize(archive.open(definition_container_file).read().decode("utf-8"),
|
||||
file_name = definition_container_file)
|
||||
try:
|
||||
definition_container.deserialize(archive.open(definition_container_file).read().decode("utf-8"),
|
||||
file_name = definition_container_file)
|
||||
except ContainerFormatError:
|
||||
# We cannot just skip the definition file because everything else later will just break if the
|
||||
# machine definition cannot be found.
|
||||
Logger.logException("e", "Failed to deserialize definition file %s in project file %s",
|
||||
definition_container_file, file_name)
|
||||
definition_container = self._container_registry.findDefinitionContainers(id = "fdmprinter")[0] #Fall back to defaults.
|
||||
self._container_registry.addContainer(definition_container)
|
||||
Job.yieldThread()
|
||||
|
||||
|
@ -679,8 +663,13 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
|
|||
|
||||
if to_deserialize_material:
|
||||
material_container = xml_material_profile(container_id)
|
||||
material_container.deserialize(archive.open(material_container_file).read().decode("utf-8"),
|
||||
file_name = container_id + "." + self._material_container_suffix)
|
||||
try:
|
||||
material_container.deserialize(archive.open(material_container_file).read().decode("utf-8"),
|
||||
file_name = container_id + "." + self._material_container_suffix)
|
||||
except ContainerFormatError:
|
||||
Logger.logException("e", "Failed to deserialize material file %s in project file %s",
|
||||
material_container_file, file_name)
|
||||
continue
|
||||
if need_new_name:
|
||||
new_name = ContainerRegistry.getInstance().uniqueName(material_container.getName())
|
||||
material_container.setName(new_name)
|
||||
|
@ -704,7 +693,7 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
|
|||
# To solve this, we schedule _updateActiveMachine() for later so it will have the latest data.
|
||||
self._updateActiveMachine(global_stack)
|
||||
|
||||
# Load all the nodes / meshdata of the workspace
|
||||
# Load all the nodes / mesh data of the workspace
|
||||
nodes = self._3mf_mesh_reader.read(file_name)
|
||||
if nodes is None:
|
||||
nodes = []
|
||||
|
|
|
@ -6,16 +6,18 @@ from io import StringIO
|
|||
import zipfile
|
||||
|
||||
from UM.Application import Application
|
||||
from UM.Logger import Logger
|
||||
from UM.Preferences import Preferences
|
||||
from UM.Settings.ContainerRegistry import ContainerRegistry
|
||||
from UM.Workspace.WorkspaceWriter import WorkspaceWriter
|
||||
|
||||
from cura.Utils.Threading import call_on_qt_thread
|
||||
|
||||
|
||||
class ThreeMFWorkspaceWriter(WorkspaceWriter):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
@call_on_qt_thread
|
||||
def write(self, stream, nodes, mode=WorkspaceWriter.OutputMode.BinaryMode):
|
||||
application = Application.getInstance()
|
||||
machine_manager = application.getMachineManager()
|
||||
|
|
|
@ -23,9 +23,9 @@ class ChangeLog(Extension, QObject,):
|
|||
self._changelog_context = None
|
||||
version_string = Application.getInstance().getVersion()
|
||||
if version_string is not "master":
|
||||
self._version = Version(version_string)
|
||||
self._current_app_version = Version(version_string)
|
||||
else:
|
||||
self._version = None
|
||||
self._current_app_version = None
|
||||
|
||||
self._change_logs = None
|
||||
Application.getInstance().engineCreatedSignal.connect(self._onEngineCreated)
|
||||
|
@ -76,7 +76,7 @@ class ChangeLog(Extension, QObject,):
|
|||
self._change_logs[open_version][open_header].append(line)
|
||||
|
||||
def _onEngineCreated(self):
|
||||
if not self._version:
|
||||
if not self._current_app_version:
|
||||
return #We're on dev branch.
|
||||
|
||||
if Preferences.getInstance().getValue("general/latest_version_changelog_shown") == "master":
|
||||
|
@ -91,7 +91,7 @@ class ChangeLog(Extension, QObject,):
|
|||
if not Application.getInstance().getGlobalContainerStack():
|
||||
return
|
||||
|
||||
if self._version > latest_version_shown:
|
||||
if self._current_app_version > latest_version_shown:
|
||||
self.showChangelog()
|
||||
|
||||
def showChangelog(self):
|
||||
|
|
|
@ -121,7 +121,7 @@ class CuraEngineBackend(QObject, Backend):
|
|||
self._slice_start_time = None
|
||||
self._is_disabled = False
|
||||
|
||||
Preferences.getInstance().addPreference("general/auto_slice", True)
|
||||
Preferences.getInstance().addPreference("general/auto_slice", False)
|
||||
|
||||
self._use_timer = False
|
||||
# When you update a setting and other settings get changed through inheritance, many propertyChanged signals are fired.
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
# Copyright (c) 2016 Ultimaker B.V.
|
||||
# Copyright (c) 2018 Ultimaker B.V.
|
||||
# Cura is released under the terms of the LGPLv3 or higher.
|
||||
import configparser
|
||||
|
||||
from UM.PluginRegistry import PluginRegistry
|
||||
from UM.Logger import Logger
|
||||
from UM.Settings.ContainerFormatError import ContainerFormatError
|
||||
from UM.Settings.InstanceContainer import InstanceContainer # The new profile to make.
|
||||
from cura.ProfileReader import ProfileReader
|
||||
|
||||
|
@ -77,7 +78,10 @@ class CuraProfileReader(ProfileReader):
|
|||
profile.addMetaDataEntry("type", "quality_changes")
|
||||
try:
|
||||
profile.deserialize(serialized)
|
||||
except Exception as e: # Parsing error. This is not a (valid) Cura profile then.
|
||||
except ContainerFormatError as e:
|
||||
Logger.log("e", "Error in the format of a container: %s", str(e))
|
||||
return None
|
||||
except Exception as e:
|
||||
Logger.log("e", "Error while trying to parse profile: %s", str(e))
|
||||
return None
|
||||
return profile
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
# Copyright (c) 2015 Ultimaker B.V.
|
||||
# Copyright (c) 2018 Ultimaker B.V.
|
||||
# Cura is released under the terms of the LGPLv3 or higher.
|
||||
|
||||
import re #Regular expressions for parsing escape characters in the settings.
|
||||
import json
|
||||
|
||||
from UM.Settings.ContainerFormatError import ContainerFormatError
|
||||
from UM.Settings.InstanceContainer import InstanceContainer
|
||||
from UM.Logger import Logger
|
||||
from UM.i18n import i18nCatalog
|
||||
|
@ -113,6 +114,9 @@ def readQualityProfileFromString(profile_string):
|
|||
profile = InstanceContainer("")
|
||||
try:
|
||||
profile.deserialize(profile_string)
|
||||
except ContainerFormatError as e:
|
||||
Logger.log("e", "Corrupt profile in this g-code file: %s", str(e))
|
||||
return None
|
||||
except Exception as e: # Not a valid g-code file.
|
||||
Logger.log("e", "Unable to serialise the profile: %s", str(e))
|
||||
return None
|
||||
|
|
|
@ -41,11 +41,11 @@ class FlavorParser:
|
|||
self._is_layers_in_file = False # Does the Gcode have the layers comment?
|
||||
self._extruder_offsets = {} # Offsets for multi extruders. key is index, value is [x-offset, y-offset]
|
||||
self._current_layer_thickness = 0.2 # default
|
||||
self._filament_diameter = 2.85 # default
|
||||
|
||||
Preferences.getInstance().addPreference("gcodereader/show_caution", True)
|
||||
|
||||
def _clearValues(self):
|
||||
self._filament_diameter = 2.85
|
||||
self._extruder_number = 0
|
||||
self._extrusion_length_offset = [0]
|
||||
self._layer_type = LayerPolygon.Inset0Type
|
||||
|
@ -289,8 +289,9 @@ class FlavorParser:
|
|||
def processGCodeStream(self, stream):
|
||||
Logger.log("d", "Preparing to load GCode")
|
||||
self._cancelled = False
|
||||
# We obtain the filament diameter from the selected printer to calculate line widths
|
||||
self._filament_diameter = Application.getInstance().getGlobalContainerStack().getProperty("material_diameter", "value")
|
||||
# We obtain the filament diameter from the selected extruder to calculate line widths
|
||||
global_stack = Application.getInstance().getGlobalContainerStack()
|
||||
self._filament_diameter = global_stack.extruders[str(self._extruder_number)].getProperty("material_diameter", "value")
|
||||
|
||||
scene_node = CuraSceneNode()
|
||||
# Override getBoundingBox function of the sceneNode, as this node should return a bounding box, but there is no
|
||||
|
@ -309,10 +310,9 @@ class FlavorParser:
|
|||
current_line = 0
|
||||
for line in stream.split("\n"):
|
||||
file_lines += 1
|
||||
gcode_list.append(line)
|
||||
gcode_list.append(line + "\n")
|
||||
if not self._is_layers_in_file and line[:len(self._layer_keyword)] == self._layer_keyword:
|
||||
self._is_layers_in_file = True
|
||||
# stream.seek(0)
|
||||
|
||||
file_step = max(math.floor(file_lines / 100), 1)
|
||||
|
||||
|
|
|
@ -18,10 +18,10 @@ class RepRapFlavorParser(FlavorParser.FlavorParser):
|
|||
self._is_absolute_extrusion = False
|
||||
|
||||
## Set the absolute positioning
|
||||
# RepRapFlavor code G90 sets position of X, Y, Z, and E to absolute
|
||||
# RepRapFlavor code G90 sets position of X, Y, Z to absolute
|
||||
# For absolute E, M82 is used
|
||||
def _gCode90(self, position, params, path):
|
||||
self._is_absolute_positioning = True
|
||||
self._is_absolute_extrusion = True
|
||||
return position
|
||||
|
||||
## Set the relative positioning
|
||||
|
|
|
@ -42,6 +42,8 @@ class GCodeWriter(MeshWriter):
|
|||
re.escape("\r"): "\\r" # Carriage return. Windows users may need this for visualisation in their editors.
|
||||
}
|
||||
|
||||
_setting_keyword = ";SETTING_"
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
|
@ -69,11 +71,15 @@ class GCodeWriter(MeshWriter):
|
|||
return False
|
||||
gcode_list = gcode_dict.get(active_build_plate, None)
|
||||
if gcode_list is not None:
|
||||
has_settings = False
|
||||
for gcode in gcode_list:
|
||||
if gcode[:len(self._setting_keyword)] == self._setting_keyword:
|
||||
has_settings = True
|
||||
stream.write(gcode)
|
||||
# Serialise the current container stack and put it at the end of the file.
|
||||
settings = self._serialiseSettings(Application.getInstance().getGlobalContainerStack())
|
||||
stream.write(settings)
|
||||
if not has_settings:
|
||||
settings = self._serialiseSettings(Application.getInstance().getGlobalContainerStack())
|
||||
stream.write(settings)
|
||||
return True
|
||||
|
||||
return False
|
||||
|
@ -108,7 +114,7 @@ class GCodeWriter(MeshWriter):
|
|||
container_registry = self._application.getContainerRegistry()
|
||||
quality_manager = self._application.getQualityManager()
|
||||
|
||||
prefix = ";SETTING_" + str(GCodeWriter.version) + " " # The prefix to put before each line.
|
||||
prefix = self._setting_keyword + str(GCodeWriter.version) + " " # The prefix to put before each line.
|
||||
prefix_length = len(prefix)
|
||||
|
||||
quality_type = stack.quality.getMetaDataEntry("quality_type")
|
||||
|
|
|
@ -49,6 +49,13 @@ class ModelChecker(QObject, Extension):
|
|||
warning_size_xy = 150 #The horizontal size of a model that would be too large when dealing with shrinking materials.
|
||||
warning_size_z = 100 #The vertical size of a model that would be too large when dealing with shrinking materials.
|
||||
|
||||
# This function can be triggered in the middle of a machine change, so do not proceed if the machine change
|
||||
# has not done yet.
|
||||
global_container_stack = Application.getInstance().getGlobalContainerStack()
|
||||
if global_container_stack is None:
|
||||
Application.getInstance().callLater(lambda: self.onChanged.emit())
|
||||
return False
|
||||
|
||||
material_shrinkage = self._getMaterialShrinkage()
|
||||
|
||||
warning_nodes = []
|
||||
|
@ -56,6 +63,13 @@ class ModelChecker(QObject, Extension):
|
|||
# Check node material shrinkage and bounding box size
|
||||
for node in self.sliceableNodes():
|
||||
node_extruder_position = node.callDecoration("getActiveExtruderPosition")
|
||||
|
||||
# This function can be triggered in the middle of a machine change, so do not proceed if the machine change
|
||||
# has not done yet.
|
||||
if str(node_extruder_position) not in global_container_stack.extruders:
|
||||
Application.getInstance().callLater(lambda: self.onChanged.emit())
|
||||
return False
|
||||
|
||||
if material_shrinkage[node_extruder_position] > shrinkage_threshold:
|
||||
bbox = node.getBoundingBox()
|
||||
if bbox.width >= warning_size_xy or bbox.depth >= warning_size_xy or bbox.height >= warning_size_z:
|
||||
|
@ -63,11 +77,11 @@ class ModelChecker(QObject, Extension):
|
|||
|
||||
self._caution_message.setText(catalog.i18nc(
|
||||
"@info:status",
|
||||
"Some models may not be printed optimally due to object size and chosen material for models: {model_names}.\n"
|
||||
"Tips that may be useful to improve the print quality:\n"
|
||||
"1) Use rounded corners.\n"
|
||||
"2) Turn the fan off (only if there are no tiny details on the model).\n"
|
||||
"3) Use a different material.").format(model_names = ", ".join([n.getName() for n in warning_nodes])))
|
||||
"<p>One or more 3D models may not print optimally due to the model size and material configuration:</p>\n"
|
||||
"<p>{model_names}</p>\n"
|
||||
"<p>Find out how to ensure the best possible print quality and reliability.</p>\n"
|
||||
"<p><a href=\"https://ultimaker.com/3D-model-assistant\">View print quality guide</a></p>"
|
||||
).format(model_names = ", ".join([n.getName() for n in warning_nodes])))
|
||||
|
||||
return len(warning_nodes) > 0
|
||||
|
||||
|
@ -92,9 +106,8 @@ class ModelChecker(QObject, Extension):
|
|||
Logger.log("d", "Model checker view created.")
|
||||
|
||||
@pyqtProperty(bool, notify = onChanged)
|
||||
def runChecks(self):
|
||||
def hasWarnings(self):
|
||||
danger_shrinkage = self.checkObjectsForShrinkage()
|
||||
|
||||
return any((danger_shrinkage, )) #If any of the checks fail, show the warning button.
|
||||
|
||||
@pyqtSlot()
|
||||
|
|
|
@ -18,7 +18,7 @@ Button
|
|||
|
||||
UM.I18nCatalog{id: catalog; name:"cura"}
|
||||
|
||||
visible: manager.runChecks
|
||||
visible: manager.hasWarnings
|
||||
tooltip: catalog.i18nc("@info:tooltip", "Some things could be problematic in this print. Click to see tips for adjustment.")
|
||||
onClicked: manager.showWarnings()
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@ Window {
|
|||
id: base
|
||||
|
||||
title: catalog.i18nc("@title:tab", "Plugins");
|
||||
modality: Qt.ApplicationModal
|
||||
width: 800 * screenScaleFactor
|
||||
height: 640 * screenScaleFactor
|
||||
minimumWidth: 350 * screenScaleFactor
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
# Copyright (c) 2015 Jaime van Kessel
|
||||
# Copyright (c) 2017 Ultimaker B.V.
|
||||
# Copyright (c) 2018 Ultimaker B.V.
|
||||
# The PostProcessingPlugin is released under the terms of the AGPLv3 or higher.
|
||||
from UM.Logger import Logger
|
||||
from UM.Signal import Signal, signalemitter
|
||||
from UM.i18n import i18nCatalog
|
||||
|
||||
# Setting stuff import
|
||||
from UM.Application import Application
|
||||
from UM.Settings.ContainerFormatError import ContainerFormatError
|
||||
from UM.Settings.ContainerStack import ContainerStack
|
||||
from UM.Settings.InstanceContainer import InstanceContainer
|
||||
from UM.Settings.DefinitionContainer import DefinitionContainer
|
||||
|
@ -39,8 +39,12 @@ class Script:
|
|||
self._definition = definitions[0]
|
||||
else:
|
||||
self._definition = DefinitionContainer(setting_data["key"])
|
||||
self._definition.deserialize(json.dumps(setting_data))
|
||||
ContainerRegistry.getInstance().addContainer(self._definition)
|
||||
try:
|
||||
self._definition.deserialize(json.dumps(setting_data))
|
||||
ContainerRegistry.getInstance().addContainer(self._definition)
|
||||
except ContainerFormatError:
|
||||
self._definition = None
|
||||
return
|
||||
self._stack.addContainer(self._definition)
|
||||
self._instance = InstanceContainer(container_id="ScriptInstanceContainer")
|
||||
self._instance.setDefinition(self._definition.getId())
|
||||
|
|
|
@ -84,7 +84,10 @@ class SolidView(View):
|
|||
|
||||
per_mesh_stack = node.callDecoration("getStack")
|
||||
|
||||
extruder_index = int(node.callDecoration("getActiveExtruderPosition"))
|
||||
extruder_index = node.callDecoration("getActiveExtruderPosition")
|
||||
if extruder_index is None:
|
||||
extruder_index = "0"
|
||||
extruder_index = int(extruder_index)
|
||||
|
||||
# Use the support extruder instead of the active extruder if this is a support_mesh
|
||||
if per_mesh_stack:
|
||||
|
|
|
@ -19,8 +19,10 @@ from cura.Scene.CuraSceneNode import CuraSceneNode
|
|||
|
||||
from cura.PickingPass import PickingPass
|
||||
|
||||
from UM.Operations.GroupedOperation import GroupedOperation
|
||||
from UM.Operations.AddSceneNodeOperation import AddSceneNodeOperation
|
||||
from UM.Operations.RemoveSceneNodeOperation import RemoveSceneNodeOperation
|
||||
from cura.Operations.SetParentOperation import SetParentOperation
|
||||
|
||||
from cura.Scene.SliceableObjectDecorator import SliceableObjectDecorator
|
||||
from cura.Scene.BuildPlateDecorator import BuildPlateDecorator
|
||||
|
@ -56,7 +58,7 @@ class SupportEraser(Tool):
|
|||
modifiers = QApplication.keyboardModifiers()
|
||||
ctrl_is_active = modifiers & Qt.ControlModifier
|
||||
|
||||
if event.type == Event.MousePressEvent and self._controller.getToolsEnabled():
|
||||
if event.type == Event.MousePressEvent and MouseEvent.LeftButton in event.buttons and self._controller.getToolsEnabled():
|
||||
if ctrl_is_active:
|
||||
self._controller.setActiveTool("TranslateTool")
|
||||
return
|
||||
|
@ -117,7 +119,10 @@ class SupportEraser(Tool):
|
|||
new_instance.resetState() # Ensure that the state is not seen as a user state.
|
||||
settings.addInstance(new_instance)
|
||||
|
||||
op = AddSceneNodeOperation(node, parent)
|
||||
op = GroupedOperation()
|
||||
# First add node to the scene at the correct position/scale, before parenting, so the eraser mesh does not get scaled with the parent
|
||||
op.addOperation(AddSceneNodeOperation(node, self._controller.getScene().getRoot()))
|
||||
op.addOperation(SetParentOperation(node, parent))
|
||||
op.push()
|
||||
node.setPosition(position, CuraSceneNode.TransformSpace.World)
|
||||
|
||||
|
|
|
@ -104,6 +104,9 @@ class USBPrinterOutputDevice(PrinterOutputDevice):
|
|||
if self._is_printing:
|
||||
return # Aleady printing
|
||||
|
||||
# cancel any ongoing preheat timer before starting a print
|
||||
self._printers[0].getController().stopPreheatTimers()
|
||||
|
||||
Application.getInstance().getController().setActiveStage("MonitorStage")
|
||||
|
||||
# find the G-code for the active build plate to print
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
import configparser #To parse preference files.
|
||||
import io #To serialise the preference files afterwards.
|
||||
import os
|
||||
import urllib.parse
|
||||
import re
|
||||
|
||||
from UM.VersionUpgrade import VersionUpgrade #We're inheriting from this.
|
||||
|
||||
|
@ -118,6 +120,12 @@ class VersionUpgrade27to30(VersionUpgrade):
|
|||
if not parser.has_section("general"):
|
||||
parser.add_section("general")
|
||||
|
||||
# Clean up the filename
|
||||
file_base_name = os.path.basename(filename)
|
||||
file_base_name = urllib.parse.unquote_plus(file_base_name)
|
||||
|
||||
um2_pattern = re.compile(r"^ultimaker[^a-zA-Z\\d\\s:]2_.*$")
|
||||
|
||||
# The ultimaker 2 family
|
||||
ultimaker2_prefix_list = ["ultimaker2_extended_",
|
||||
"ultimaker2_go_",
|
||||
|
@ -127,9 +135,8 @@ class VersionUpgrade27to30(VersionUpgrade):
|
|||
"ultimaker2_plus_"]
|
||||
|
||||
# set machine definition to "ultimaker2" for the custom quality profiles that can be for the ultimaker 2 family
|
||||
file_base_name = os.path.basename(filename)
|
||||
is_ultimaker2_family = False
|
||||
if not any(file_base_name.startswith(ep) for ep in exclude_prefix_list):
|
||||
is_ultimaker2_family = um2_pattern.match(file_base_name) is not None
|
||||
if not is_ultimaker2_family and not any(file_base_name.startswith(ep) for ep in exclude_prefix_list):
|
||||
is_ultimaker2_family = any(file_base_name.startswith(ep) for ep in ultimaker2_prefix_list)
|
||||
|
||||
# ultimaker2 family quality profiles used to set as "fdmprinter" profiles
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue