Merge branch 'master' into bremco-graphics_buffer_update

This commit is contained in:
Remco Burema 2021-09-16 22:27:52 +02:00
commit a987b9972a
No known key found for this signature in database
GPG key ID: 215C49431D43F98C
660 changed files with 20420 additions and 11012 deletions

View file

@ -159,7 +159,8 @@ class CuraEngineBackend(QObject, Backend):
self._slicing_error_message = Message(
text = catalog.i18nc("@message", "Slicing failed with an unexpected error. Please consider reporting a bug on our issue tracker."),
title = catalog.i18nc("@message:title", "Slicing failed")
title = catalog.i18nc("@message:title", "Slicing failed"),
message_type = Message.MessageType.ERROR
)
self._slicing_error_message.addAction(
action_id = "report_bug",
@ -467,6 +468,7 @@ class CuraEngineBackend(QObject, Backend):
self._error_message.show()
self.setState(BackendState.Error)
self.backendError.emit(job)
return
else:
self.setState(BackendState.NotStarted)
@ -645,7 +647,7 @@ class CuraEngineBackend(QObject, Backend):
for node in DepthFirstIterator(self._scene.getRoot()):
if node.callDecoration("getLayerData"):
if not build_plate_numbers or node.callDecoration("getBuildPlateNumber") in build_plate_numbers:
# We can asume that all nodes have a parent as we're looping through the scene (and filter out root)
# We can assume that all nodes have a parent as we're looping through the scene (and filter out root)
cast(SceneNode, node.getParent()).removeChild(node)
def markSliceAll(self) -> None:

View file

@ -195,7 +195,7 @@ class StartSliceJob(Job):
# Remove old layer data.
for node in DepthFirstIterator(self._scene.getRoot()):
if node.callDecoration("getLayerData") and node.callDecoration("getBuildPlateNumber") == self._build_plate_number:
# Singe we walk through all nodes in the scene, they always have a parent.
# Since we walk through all nodes in the scene, they always have a parent.
cast(SceneNode, node.getParent()).removeChild(node)
break

View file

@ -2,7 +2,7 @@
"name": "Ultimaker Digital Library",
"author": "Ultimaker B.V.",
"description": "Connects to the Digital Library, allowing Cura to open files from and save files to the Digital Library.",
"version": "1.0.0",
"version": "1.1.0",
"api": 7,
"i18n-catalog": "cura"
}

View file

@ -200,7 +200,7 @@ Item
anchors.bottom: parent.bottom
anchors.right: parent.right
text: "Save"
enabled: (asProjectCheckbox.checked || asSlicedCheckbox.checked) && dfFilenameTextfield.text.length >= 1
enabled: (asProjectCheckbox.checked || asSlicedCheckbox.checked) && dfFilenameTextfield.text.length >= 1 && dfFilenameTextfield.state !== 'invalid'
onClicked:
{

View file

@ -49,11 +49,27 @@ Item
id: searchBar
Layout.fillWidth: true
implicitHeight: createNewProjectButton.height
leftPadding: searchIcon.width + UM.Theme.getSize("default_margin").width * 2
onTextEdited: manager.projectFilter = text //Update the search filter when editing this text field.
leftIcon: UM.Theme.getIcon("Magnifier")
placeholderText: "Search"
UM.RecolorImage
{
id: searchIcon
anchors
{
verticalCenter: parent.verticalCenter
left: parent.left
leftMargin: UM.Theme.getSize("default_margin").width
}
source: UM.Theme.getIcon("search")
height: UM.Theme.getSize("small_button_icon").height
width: height
color: UM.Theme.getColor("text")
}
}
Cura.SecondaryButton
@ -76,12 +92,11 @@ Item
id: upgradePlanButton
text: "Upgrade plan"
iconSource: UM.Theme.getIcon("LinkExternal")
iconSource: UM.Theme.getIcon("external_link")
visible: createNewProjectButtonVisible && !manager.userAccountCanCreateNewLibraryProject && (manager.retrievingProjectsStatus == DF.RetrievalStatus.Success || manager.retrievingProjectsStatus == DF.RetrievalStatus.Failed)
tooltip: "You have reached the maximum number of projects allowed by your subscription. Please upgrade to the Professional subscription to create more projects."
tooltipWidth: parent.width * 0.5
tooltip: "Maximum number of projects reached. Please upgrade your subscription to create more projects."
onClicked: Qt.openUrlExternally("https://ultimaker.com/software/ultimaker-essentials/sign-up-cura?utm_source=cura&utm_medium=software&utm_campaign=lib-max")
onClicked: Qt.openUrlExternally("https://ultimaker.com/software/enterprise-software?utm_source=cura&utm_medium=software&utm_campaign=MaxProjLink")
}
}
@ -124,7 +139,7 @@ Item
id: visitDigitalLibraryButton
anchors.horizontalCenter: parent.horizontalCenter
text: "Visit Digital Library"
onClicked: Qt.openUrlExternally(CuraApplication.ultimakerDigitalFactoryUrl + "/app/library")
onClicked: Qt.openUrlExternally(CuraApplication.ultimakerDigitalFactoryUrl + "/app/library?utm_source=cura&utm_medium=software&utm_campaign=empty-library")
visible: searchBar.text === "" //Show the link to Digital Library when there are no projects in the user's Library.
}
}

View file

@ -0,0 +1,17 @@
# Copyright (c) 2021 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher.
from typing import Optional
from cura.CuraApplication import CuraApplication
from UM.Message import Message
from UM.Version import Version
def getBackwardsCompatibleMessage(text: str, title: str, message_type_str: str, lifetime: Optional[int] = 30) -> Message:
if CuraApplication.getInstance().getAPIVersion() < Version("7.7.0"):
return Message(text=text, title=title, lifetime=lifetime)
else:
message_type = Message.MessageType.NEUTRAL
if ("MessageType." + message_type_str) in [str(item) for item in Message.MessageType]:
message_type = Message.MessageType[message_type_str]
return Message(text=text, title=title, lifetime=lifetime, message_type=message_type)

View file

@ -14,6 +14,7 @@ from UM.Logger import Logger
from UM.Message import Message
from UM.Scene.SceneNode import SceneNode
from cura.CuraApplication import CuraApplication
from .BackwardsCompatibleMessage import getBackwardsCompatibleMessage
from .DFLibraryFileUploadRequest import DFLibraryFileUploadRequest
from .DFLibraryFileUploadResponse import DFLibraryFileUploadResponse
from .DFPrintJobUploadRequest import DFPrintJobUploadRequest
@ -69,11 +70,11 @@ class DFFileExportAndUploadManager:
use_inactivity_timer = False
)
self._generic_success_message = Message(
self._generic_success_message = getBackwardsCompatibleMessage(
text = "Your {} uploaded to '{}'.".format("file was" if len(self._file_upload_job_metadata) <= 1 else "files were", self._library_project_name),
title = "Upload successful",
lifetime = 0,
message_type = Message.MessageType.POSITIVE
lifetime = 30,
message_type_str = "POSITIVE"
)
self._generic_success_message.addAction(
"open_df_project",
@ -217,11 +218,11 @@ class DFFileExportAndUploadManager:
# Set the progress to 100% when the upload job fails, to avoid having the progress message stuck
self._file_upload_job_metadata[filename]["upload_status"] = "failed"
self._file_upload_job_metadata[filename]["upload_progress"] = 100
self._file_upload_job_metadata[filename]["file_upload_failed_message"] = Message(
self._file_upload_job_metadata[filename]["file_upload_failed_message"] = getBackwardsCompatibleMessage(
text = "Failed to export the file '{}'. The upload process is aborted.".format(filename),
title = "Export error",
lifetime = 0,
message_type = Message.MessageType.ERROR
message_type_str = "ERROR",
lifetime = 30
)
self._on_upload_error()
self._onFileUploadFinished(filename)
@ -240,11 +241,11 @@ class DFFileExportAndUploadManager:
self._file_upload_job_metadata[filename_3mf]["upload_progress"] = 100
human_readable_error = self.extractErrorTitle(reply_string)
self._file_upload_job_metadata[filename_3mf]["file_upload_failed_message"] = Message(
self._file_upload_job_metadata[filename_3mf]["file_upload_failed_message"] = getBackwardsCompatibleMessage(
text = "Failed to upload the file '{}' to '{}'. {}".format(filename_3mf, self._library_project_name, human_readable_error),
title = "File upload error",
lifetime = 0,
message_type = Message.MessageType.ERROR
message_type_str = "ERROR",
lifetime = 30
)
self._on_upload_error()
self._onFileUploadFinished(filename_3mf)
@ -263,11 +264,11 @@ class DFFileExportAndUploadManager:
self._file_upload_job_metadata[filename_ufp]["upload_progress"] = 100
human_readable_error = self.extractErrorTitle(reply_string)
self._file_upload_job_metadata[filename_ufp]["file_upload_failed_message"] = Message(
self._file_upload_job_metadata[filename_ufp]["file_upload_failed_message"] = getBackwardsCompatibleMessage(
title = "File upload error",
text = "Failed to upload the file '{}' to '{}'. {}".format(filename_ufp, self._library_project_name, human_readable_error),
lifetime = 0,
message_type = Message.MessageType.ERROR
message_type_str = "ERROR",
lifetime = 30
)
self._on_upload_error()
self._onFileUploadFinished(filename_ufp)
@ -300,11 +301,11 @@ class DFFileExportAndUploadManager:
self._file_upload_job_metadata[filename]["upload_status"] = "failed"
self._file_upload_job_metadata[filename]["upload_progress"] = 100
human_readable_error = self.extractErrorTitle(reply_string)
self._file_upload_job_metadata[filename]["file_upload_failed_message"] = Message(
self._file_upload_job_metadata[filename]["file_upload_failed_message"] = getBackwardsCompatibleMessage(
title = "File upload error",
text = "Failed to upload the file '{}' to '{}'. {}".format(self._file_name, self._library_project_name, human_readable_error),
lifetime = 0,
message_type = Message.MessageType.ERROR
message_type_str = "ERROR",
lifetime = 30
)
self._on_upload_error()
@ -319,7 +320,7 @@ class DFFileExportAndUploadManager:
def _onMessageActionTriggered(self, message, action):
if action == "open_df_project":
project_url = "{}/app/library/project/{}?wait_for_new_files=true".format(CuraApplication.getInstance().ultimakerDigitalFactoryUrl, self._library_project_id)
project_url = "{}/app/library/project/{}?wait_for_new_files=true&utm_source=cura&utm_medium=software&utm_campaign=saved-library-file-message".format(CuraApplication.getInstance().ultimakerDigitalFactoryUrl, self._library_project_id)
QDesktopServices.openUrl(QUrl(project_url))
message.hide()
@ -337,17 +338,17 @@ class DFFileExportAndUploadManager:
"upload_progress" : -1,
"upload_status" : "",
"file_upload_response": None,
"file_upload_success_message": Message(
"file_upload_success_message": getBackwardsCompatibleMessage(
text = "'{}' was uploaded to '{}'.".format(filename_3mf, self._library_project_name),
title = "Upload successful",
lifetime = 0,
message_type = Message.MessageType.POSITIVE
message_type_str = "POSITIVE",
lifetime = 30
),
"file_upload_failed_message": Message(
"file_upload_failed_message": getBackwardsCompatibleMessage(
text = "Failed to upload the file '{}' to '{}'.".format(filename_3mf, self._library_project_name),
title = "File upload error",
lifetime = 0,
message_type = Message.MessageType.ERROR
message_type_str = "ERROR",
lifetime = 30
)
}
job_3mf = ExportFileJob(self._file_handlers["3mf"], self._nodes, self._file_name, "3mf")
@ -361,17 +362,17 @@ class DFFileExportAndUploadManager:
"upload_progress" : -1,
"upload_status" : "",
"file_upload_response": None,
"file_upload_success_message": Message(
"file_upload_success_message": getBackwardsCompatibleMessage(
text = "'{}' was uploaded to '{}'.".format(filename_ufp, self._library_project_name),
title = "Upload successful",
lifetime = 0,
message_type = Message.MessageType.POSITIVE
message_type_str = "POSITIVE",
lifetime = 30,
),
"file_upload_failed_message": Message(
"file_upload_failed_message": getBackwardsCompatibleMessage(
text = "Failed to upload the file '{}' to '{}'.".format(filename_ufp, self._library_project_name),
title = "File upload error",
lifetime = 0,
message_type = Message.MessageType.ERROR
message_type_str = "ERROR",
lifetime = 30
)
}
job_ufp = ExportFileJob(self._file_handlers["ufp"], self._nodes, self._file_name, "ufp")

View file

@ -23,6 +23,7 @@ from UM.TaskManagement.HttpRequestManager import HttpRequestManager
from cura.API import Account
from cura.CuraApplication import CuraApplication
from cura.UltimakerCloud.UltimakerCloudScope import UltimakerCloudScope
from .BackwardsCompatibleMessage import getBackwardsCompatibleMessage
from .DFFileExportAndUploadManager import DFFileExportAndUploadManager
from .DigitalFactoryApiClient import DigitalFactoryApiClient
from .DigitalFactoryFileModel import DigitalFactoryFileModel
@ -527,11 +528,11 @@ class DigitalFactoryController(QObject):
except IOError as ex:
Logger.logException("e", "Can't write Digital Library file {0}/{1} download to temp-directory {2}.",
ex, project_name, file_name, temp_dir)
Message(
getBackwardsCompatibleMessage(
text = "Failed to write to temporary file for '{}'.".format(file_name),
title = "File-system error",
lifetime = 10,
message_type=Message.MessageType.ERROR
message_type_str="ERROR",
lifetime = 10
).show()
return
@ -542,11 +543,11 @@ class DigitalFactoryController(QObject):
f = file_name) -> None:
progress_message.hide()
Logger.error("An error {0} {1} occurred while downloading {2}/{3}".format(str(error), str(reply), p, f))
Message(
getBackwardsCompatibleMessage(
text = "Failed Digital Library download for '{}'.".format(f),
title = "Network error {}".format(error),
lifetime = 10,
message_type=Message.MessageType.ERROR
message_type_str="ERROR",
lifetime = 10
).show()
download_manager = HttpRequestManager.getInstance()
@ -591,17 +592,19 @@ class DigitalFactoryController(QObject):
if filename == "":
Logger.log("w", "The file name cannot be empty.")
Message(text = "Cannot upload file with an empty name to the Digital Library",
getBackwardsCompatibleMessage(
text = "Cannot upload file with an empty name to the Digital Library",
title = "Empty file name provided",
lifetime = 0,
message_type = Message.MessageType.ERROR).show()
message_type_str = "ERROR",
lifetime = 0
).show()
return
self._saveFileToSelectedProjectHelper(filename, formats)
def _saveFileToSelectedProjectHelper(self, filename: str, formats: List[str]) -> None:
# Indicate we have started sending a job.
self.uploadStarted.emit()
# Indicate we have started sending a job (and propagate any user file name changes back to the open project)
self.uploadStarted.emit(filename if "3mf" in formats else None)
library_project_id = self._project_model.items[self._selected_project_idx]["libraryProjectId"]
library_project_name = self._project_model.items[self._selected_project_idx]["displayName"]

View file

@ -8,6 +8,8 @@ from UM.Logger import Logger
from UM.OutputDevice import OutputDeviceError
from UM.OutputDevice.ProjectOutputDevice import ProjectOutputDevice
from UM.Scene.SceneNode import SceneNode
from UM.Version import Version
from cura import ApplicationMetadata
from cura.API import Account
from cura.CuraApplication import CuraApplication
from .DigitalFactoryController import DigitalFactoryController
@ -105,8 +107,11 @@ class DigitalFactoryOutputDevice(ProjectOutputDevice):
self.enabled = logged_in and self._controller.userAccountHasLibraryAccess()
self.enabledChanged.emit()
def _onWriteStarted(self) -> None:
def _onWriteStarted(self, new_name: Optional[str] = None) -> None:
self._writing = True
if new_name and Version(ApplicationMetadata.CuraSDKVersion) >= Version("7.8.0"):
# setLastOutputName is only supported in sdk version 7.8.0 and up
self.setLastOutputName(new_name)
self.writeStarted.emit(self)
def _onWriteFinished(self) -> None:

View file

@ -112,7 +112,7 @@ class FirmwareUpdateCheckerJob(Job):
# The first time we want to store the current version, the notification will not be shown,
# because the new version of Cura will be release before the firmware and we don't want to
# notify the user when no new firmware version is available.
if (checked_version != "") and (checked_version != current_version):
if checked_version != "" and checked_version != current_version:
Logger.log("i", "Showing firmware update message for new version: {version}".format(version = current_version))
message = FirmwareUpdateCheckerMessage(machine_id, self._machine_name, current_version,
self._lookups.getRedirectUserUrl())

View file

@ -14,12 +14,12 @@ class FirmwareUpdateCheckerMessage(Message):
def __init__(self, machine_id: int, machine_name: str, latest_version: str, download_url: str) -> None:
super().__init__(i18n_catalog.i18nc(
"@info Don't translate {machine_name}, since it gets replaced by a printer name!",
"New features or bug-fixes may be available for your {machine_name}! If not already at the latest version, "
"New features or bug-fixes may be available for your {machine_name}! If you haven't done so already, "
"it is recommended to update the firmware on your printer to version {latest_version}.").format(
machine_name = machine_name, latest_version = latest_version),
title = i18n_catalog.i18nc(
"@info:title The %s gets replaced with the printer name.",
"New %s firmware available") % machine_name)
"New %s stable firmware available") % machine_name)
self._machine_id = machine_id
self._download_url = download_url

View file

@ -1,4 +1,4 @@
# Copyright (c) 2020 Ultimaker B.V.
# Copyright (c) 2021 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher.
import math
@ -153,7 +153,7 @@ class FlavorParser:
Af = (self._filament_diameter / 2) ** 2 * numpy.pi
# Length of the extruded filament
de = current_extrusion - previous_extrusion
# Volumne of the extruded filament
# Volume of the extruded filament
dVe = de * Af
# Length of the printed line
dX = numpy.sqrt((current_point[0] - previous_point[0])**2 + (current_point[2] - previous_point[2])**2)
@ -428,7 +428,7 @@ class FlavorParser:
G = self._getInt(line, "G")
if G is not None:
# When find a movement, the new posistion is calculated and added to the current_path, but
# When find a movement, the new position is calculated and added to the current_path, but
# don't need to create a polygon until the end of the layer
current_position = self.processGCode(G, line, current_position, current_path)
continue

View file

@ -3,7 +3,7 @@
from . import FlavorParser
# This parser is intented for interpret the Marlin/Sprinter Firmware flavor
# This parser is intended to interpret the Marlin/Sprinter Firmware flavor
class MarlinFlavorParser(FlavorParser.FlavorParser):
def __init__(self):

View file

@ -159,7 +159,7 @@ Rectangle
{
anchors.fill: parent
hoverEnabled: true
onClicked: Qt.openUrlExternally("https://ultimaker.com/en/resources/manuals/ultimaker-3d-printers")
onClicked: Qt.openUrlExternally("https://ultimaker.com/in/cura/troubleshooting/network?utm_source=cura&utm_medium=software&utm_campaign=monitor-not-connected")
onEntered: manageQueueText.font.underline = true
onExited: manageQueueText.font.underline = false
}

View file

@ -312,7 +312,7 @@ Item
}
}
// Specialty provider that only watches global_inherits (we cant filter on what property changed we get events
// Specialty provider that only watches global_inherits (we can't filter on what property changed we get events
// so we bypass that to make a dedicated provider).
UM.SettingPropertyProvider
{

View file

@ -403,7 +403,7 @@ UM.Dialog
storeIndex: 0
}
// Specialty provider that only watches global_inherits (we cant filter on what property changed we get events
// Specialty provider that only watches global_inherits (we can't filter on what property changed we get events
// so we bypass that to make a dedicated provider).
UM.SettingPropertyProvider
{

View file

@ -31,7 +31,7 @@
# V4.9.93: Minor bugfixes (input settings) / documentation
# V4.9.94: Bugfix Combobox-selection; remove logger
# V5.0: Bugfix for fall back after one layer and doubled G0 commands when using print speed tweak, Initial version for Cura 2.x
# V5.0.1: Bugfix for calling unknown property 'bedTemp' of previous settings storage and unkown variable 'speed'
# V5.0.1: Bugfix for calling unknown property 'bedTemp' of previous settings storage and unknown variable 'speed'
# V5.1: API Changes included for use with Cura 2.2
# V5.2.0: Wes Hanney. Added support for changing Retract Length and Speed. Removed layer spread option. Fixed issue of cumulative ChangeZ
# mods so they can now properly be stacked on top of each other. Applied code refactoring to clean up various coding styles. Added comments.
@ -657,7 +657,7 @@ class ChangeAtZProcessor:
# Indicates if the user has opted for linear move retractions or firmware retractions
linearRetraction = True
# Indicates if we're targetting by layer or height value
# Indicates if we're targeting by layer or height value
targetByLayer = True
# Indicates if we have injected our changed values for the given layer yet
@ -1079,7 +1079,7 @@ class ChangeAtZProcessor:
else:
modified_gcode += line + "\n"
# if we're targetting by layer we want to add our values just after the layer label
# if we're targeting by layer we want to add our values just after the layer label
if ";LAYER:" in line:
modified_gcode += self.getInjectCode()
@ -1367,11 +1367,11 @@ class ChangeAtZProcessor:
# handle extruder temp changes
if command.command == "M104" or command.command == "M109":
# get our tempurature
tempurature = command.getArgumentAsFloat("S")
# get our temperature
temperature = command.getArgumentAsFloat("S")
# don't bother if we don't have a tempurature
if tempurature is None:
# don't bother if we don't have a temperature
if temperature is None:
return
# get our extruder, default to extruder one
@ -1379,10 +1379,10 @@ class ChangeAtZProcessor:
# set our extruder temp based on the extruder
if extruder is None or extruder == 0:
self.lastValues["extruderOne"] = tempurature
self.lastValues["extruderOne"] = temperature
if extruder is None or extruder == 1:
self.lastValues["extruderTwo"] = tempurature
self.lastValues["extruderTwo"] = temperature
# move to the next command
return
@ -1401,10 +1401,10 @@ class ChangeAtZProcessor:
if command.command == "M221":
# get our flow rate
tempurature = command.getArgumentAsFloat("S")
temperature = command.getArgumentAsFloat("S")
# don't bother if we don't have a flow rate (for some reason)
if tempurature is None:
if temperature is None:
return
# get our extruder, default to global
@ -1412,11 +1412,11 @@ class ChangeAtZProcessor:
# set our extruder temp based on the extruder
if extruder is None:
self.lastValues["flowrate"] = tempurature
self.lastValues["flowrate"] = temperature
elif extruder == 1:
self.lastValues["flowrateOne"] = tempurature
self.lastValues["flowrateOne"] = temperature
elif extruder == 1:
self.lastValues["flowrateTwo"] = tempurature
self.lastValues["flowrateTwo"] = temperature
# move to the next command
return

View file

@ -5,7 +5,7 @@
# Description: This plugin shows custom messages about your print on the Status bar...
# Please look at the 3 options
# - Scolling (SCROLL_LONG_FILENAMES) if enabled in Marlin and you arent printing a small item select this option.
# - Scrolling (SCROLL_LONG_FILENAMES) if enabled in Marlin and you aren't printing a small item select this option.
# - Name: By default it will use the name generated by Cura (EG: TT_Test_Cube) - Type a custom name in here
# - Max Layer: Enabling this will show how many layers are in the entire print (EG: Layer 1 of 265!)

View file

@ -54,10 +54,10 @@ class PauseAtHeight(Script):
"label": "Method",
"description": "The method or gcode command to use for pausing.",
"type": "enum",
"options": {"marlin": "Marlin (M0)", "griffin": "Griffin (M0, firmware retract)", "bq": "BQ (M25)", "reprap": "RepRap (M226)", "repetier": "Repetier (@pause)"},
"options": {"marlin": "Marlin (M0)", "griffin": "Griffin (M0, firmware retract)", "bq": "BQ (M25)", "reprap": "RepRap (M226)", "repetier": "Repetier/OctoPrint (@pause)"},
"default_value": "marlin",
"value": "\\\"griffin\\\" if machine_gcode_flavor==\\\"Griffin\\\" else \\\"reprap\\\" if machine_gcode_flavor==\\\"RepRap (RepRap)\\\" else \\\"repetier\\\" if machine_gcode_flavor==\\\"Repetier\\\" else \\\"bq\\\" if \\\"BQ\\\" in machine_name or \\\"Flying Bear Ghost 4S\\\" in machine_name else \\\"marlin\\\""
},
},
"disarm_timeout":
{
"label": "Disarm timeout",
@ -69,6 +69,14 @@ class PauseAtHeight(Script):
"maximum_value_warning": "1800",
"unit": "s"
},
"head_park_enabled":
{
"label": "Park Print",
"description": "Instruct the head to move to a safe location when pausing. Leave this unchecked if your printer handles parking for you.",
"type": "bool",
"default_value": true,
"enabled": "pause_method != \\\"griffin\\\""
},
"head_park_x":
{
"label": "Park Print Head X",
@ -76,7 +84,7 @@ class PauseAtHeight(Script):
"unit": "mm",
"type": "float",
"default_value": 190,
"enabled": "pause_method != \\\"griffin\\\""
"enabled": "head_park_enabled and pause_method != \\\"griffin\\\""
},
"head_park_y":
{
@ -85,7 +93,7 @@ class PauseAtHeight(Script):
"unit": "mm",
"type": "float",
"default_value": 190,
"enabled": "pause_method != \\\"griffin\\\""
"enabled": "head_park_enabled and pause_method != \\\"griffin\\\""
},
"head_move_z":
{
@ -94,7 +102,7 @@ class PauseAtHeight(Script):
"unit": "mm",
"type": "float",
"default_value": 15.0,
"enabled": "pause_method == \\\"repetier\\\""
"enabled": "head_park_enabled and pause_method == \\\"repetier\\\""
},
"retraction_amount":
{
@ -239,6 +247,7 @@ class PauseAtHeight(Script):
retraction_speed = self.getSettingValueByKey("retraction_speed")
extrude_amount = self.getSettingValueByKey("extrude_amount")
extrude_speed = self.getSettingValueByKey("extrude_speed")
park_enabled = self.getSettingValueByKey("head_park_enabled")
park_x = self.getSettingValueByKey("head_park_x")
park_y = self.getSettingValueByKey("head_park_y")
move_z = self.getSettingValueByKey("head_move_z")
@ -389,11 +398,12 @@ class PauseAtHeight(Script):
if retraction_amount != 0:
prepend_gcode += self.putValue(G = 1, E = -retraction_amount, F = 6000) + "\n"
#Move the head away
prepend_gcode += self.putValue(G = 1, Z = current_z + 1, F = 300) + " ; move up a millimeter to get out of the way\n"
prepend_gcode += self.putValue(G = 1, X = park_x, Y = park_y, F = 9000) + "\n"
if current_z < move_z:
prepend_gcode += self.putValue(G = 1, Z = current_z + move_z, F = 300) + "\n"
if park_enabled:
#Move the head away
prepend_gcode += self.putValue(G = 1, Z = current_z + 1, F = 300) + " ; move up a millimeter to get out of the way\n"
prepend_gcode += self.putValue(G = 1, X = park_x, Y = park_y, F = 9000) + "\n"
if current_z < move_z:
prepend_gcode += self.putValue(G = 1, Z = current_z + move_z, F = 300) + "\n"
#Disable the E steppers
prepend_gcode += self.putValue(M = 84, E = 0) + "\n"
@ -409,14 +419,15 @@ class PauseAtHeight(Script):
else:
prepend_gcode += self.putValue(G = 1, E = -retraction_amount, F = retraction_speed * 60) + "\n"
# Move the head away
prepend_gcode += self.putValue(G = 1, Z = current_z + 1, F = 300) + " ; move up a millimeter to get out of the way\n"
if park_enabled:
# Move the head away
prepend_gcode += self.putValue(G = 1, Z = current_z + 1, F = 300) + " ; move up a millimeter to get out of the way\n"
# This line should be ok
prepend_gcode += self.putValue(G = 1, X = park_x, Y = park_y, F = 9000) + "\n"
# This line should be ok
prepend_gcode += self.putValue(G = 1, X = park_x, Y = park_y, F = 9000) + "\n"
if current_z < 15:
prepend_gcode += self.putValue(G = 1, Z = 15, F = 300) + " ; too close to bed--move to at least 15mm\n"
if current_z < 15:
prepend_gcode += self.putValue(G = 1, Z = 15, F = 300) + " ; too close to bed--move to at least 15mm\n"
if control_temperatures:
# Set extruder standby temperature
@ -456,8 +467,10 @@ class PauseAtHeight(Script):
prepend_gcode += self.putValue(G = 1, E = -retraction_amount, F = 6000) + "\n"
#Move the head back
prepend_gcode += self.putValue(G = 1, Z = current_z, F = 300) + "\n"
prepend_gcode += self.putValue(G = 1, X = x, Y = y, F = 9000) + "\n"
if park_enabled:
prepend_gcode += self.putValue(G = 1, X = x, Y = y, F = 9000) + "\n"
prepend_gcode += self.putValue(G = 1, Z = current_z, F = 300) + "\n"
if retraction_amount != 0:
prepend_gcode += self.putValue(G = 1, E = retraction_amount, F = 6000) + "\n"
@ -490,10 +503,12 @@ class PauseAtHeight(Script):
prepend_gcode += self.putValue(G = 1, E = -retraction_amount, F = retraction_speed * 60) + "\n"
# Move the head back
if current_z < 15:
prepend_gcode += self.putValue(G = 1, Z = current_z + 1, F = 300) + "\n"
prepend_gcode += self.putValue(G = 1, X = x, Y = y, F = 9000) + "\n"
prepend_gcode += self.putValue(G = 1, Z = current_z, F = 300) + " ; move back down to resume height\n"
if park_enabled:
if current_z < 15:
prepend_gcode += self.putValue(G = 1, Z = current_z, F = 300) + "\n"
prepend_gcode += self.putValue(G = 1, X = x, Y = y, F = 9000) + "\n"
prepend_gcode += self.putValue(G = 1, Z = current_z, F = 300) + " ; move back down to resume height\n"
if retraction_amount != 0:
if firmware_retract: #Can't set the distance directly to what the user wants. We have to choose ourselves.
retraction_count = 1 if control_temperatures else 3 #Retract more if we don't control the temperature.

View file

@ -195,7 +195,7 @@ class Stretcher:
i.e. it is a travel move
"""
if i_pos == 0:
return True # Begining a layer always breaks filament (for simplicity)
return True # Beginning a layer always breaks filament (for simplicity)
step = layer_steps[i_pos]
prev_step = layer_steps[i_pos - 1]
if step.step_e != prev_step.step_e:

View file

@ -136,7 +136,7 @@ class RemovableDriveOutputDevice(OutputDevice):
self._stream.close()
self._stream = None
except:
Logger.logException("w", "An execption occured while trying to write to removable drive.")
Logger.logException("w", "An exception occurred while trying to write to removable drive.")
message = Message(catalog.i18nc("@info:status", "Could not save to removable drive {0}: {1}").format(self.getName(),str(job.getError())),
title = catalog.i18nc("@info:title", "Error"),
message_type = Message.MessageType.ERROR)

View file

@ -48,7 +48,7 @@ class RemovableDrivePlugin(OutputDevicePlugin):
result = False
if result:
Logger.log("i", "Succesfully ejected the device")
Logger.log("i", "Successfully ejected the device")
return result
def performEjectDevice(self, device):

View file

@ -187,7 +187,7 @@ Item
{
sliderRoot.manuallyChanged = true
// don't allow the lower handle to be heigher than the upper handle
// don't allow the lower handle to be higher than the upper handle
if (lowerHandle.y - (y + height) < sliderRoot.minimumRangeHandleSize)
{
lowerHandle.y = y + height + sliderRoot.minimumRangeHandleSize
@ -300,7 +300,7 @@ Item
// don't allow the upper handle to be lower than the lower handle
if (y - (upperHandle.y + upperHandle.height) < sliderRoot.minimumRangeHandleSize)
{
upperHandle.y = y - (upperHandle.heigth + sliderRoot.minimumRangeHandleSize)
upperHandle.y = y - (upperHandle.height + sliderRoot.minimumRangeHandleSize)
}
// update the range handle

View file

@ -59,7 +59,7 @@ UM.PointingRectangle {
text: sliderLabelRoot.value + startFrom // the current handle value, add 1 because layers is an array
horizontalAlignment: TextInput.AlignHCenter
// key bindings, work when label is currenctly focused (active handle in LayerSlider)
// key bindings, work when label is currently focused (active handle in LayerSlider)
Keys.onUpPressed: sliderLabelRoot.setValue(sliderLabelRoot.value + ((event.modifiers & Qt.ShiftModifier) ? 10 : 1))
Keys.onDownPressed: sliderLabelRoot.setValue(sliderLabelRoot.value - ((event.modifiers & Qt.ShiftModifier) ? 10 : 1))

View file

@ -190,11 +190,11 @@ Item
}
}
// Scrolls trough Z layers
// Scrolls through Z layers
LayerSlider
{
property var preferredHeight: UM.Theme.getSize("slider_layerview_size").height
property double heightMargin: UM.Theme.getSize("default_margin").height * 3 // extra margin to accomodate layer number tooltips
property double heightMargin: UM.Theme.getSize("default_margin").height * 3 // extra margin to accommodate layer number tooltips
property double layerSliderSafeHeight: layerSliderSafeYMax - layerSliderSafeYMin
id: layerSlider

View file

@ -8,7 +8,7 @@ import UM 1.1 as UM
Rectangle
{
color: UM.Theme.getColor("secondary")
color: UM.Theme.getColor("toolbox_premium_packages_background")
height: childrenRect.height
width: parent.width
Column
@ -39,7 +39,7 @@ Rectangle
text: catalog.i18nc("@info:tooltip", "Go to Web Marketplace")
Label
{
text: "<a href='%2'>".arg(toolbox.getWebMarketplaceUrl("materials")) + catalog.i18nc("@label", "Search materials") + "</a>"
text: "<a href='%2'>".arg(toolbox.getWebMarketplaceUrl("materials") + "?utm_source=cura&utm_medium=software&utm_campaign=marketplace-search") + catalog.i18nc("@label", "Search materials") + "</a>"
width: contentWidth
height: contentHeight
horizontalAlignment: Text.AlignRight

View file

@ -91,7 +91,7 @@ Item
verticalCenter: parent.verticalCenter
}
acceptedButtons: Qt.LeftButton
onClicked: Qt.openUrlExternally(toolbox.getWebMarketplaceUrl("plugins"))
onClicked: Qt.openUrlExternally(toolbox.getWebMarketplaceUrl("plugins") + "?utm_source=cura&utm_medium=software&utm_campaign=marketplace-button")
UM.RecolorImage
{
id: cloudMarketplaceButton

View file

@ -71,6 +71,7 @@ ScrollView
padding: UM.Theme.getSize("default_margin").width
text: catalog.i18nc("@info", "No plugin has been installed.")
font: UM.Theme.getFont("medium")
color: UM.Theme.getColor("lining")
renderType: Text.NativeRendering
}
}
@ -123,6 +124,7 @@ ScrollView
visible: toolbox.materialsInstalledModel.count < 1
padding: UM.Theme.getSize("default_margin").width
text: catalog.i18nc("@info", "No material has been installed.")
color: UM.Theme.getColor("lining")
font: UM.Theme.getFont("medium")
renderType: Text.NativeRendering
}

View file

@ -37,7 +37,7 @@ class CloudPackageChecker(QObject):
self._i18n_catalog = i18nCatalog("cura")
self._sdk_version = ApplicationMetadata.CuraSDKVersion
self._last_notified_packages = set() # type: Set[str]
"""Packages for which a notification has been shown. No need to bother the user twice fo equal content"""
"""Packages for which a notification has been shown. No need to bother the user twice for equal content"""
# This is a plugin, so most of the components required are not ready when
# this is initialized. Therefore, we wait until the application is ready.

View file

@ -6,7 +6,7 @@ from typing import Dict, List, Any
from PyQt5.QtNetwork import QNetworkReply
from UM import i18n_catalog
from UM.i18n import i18nCatalog
from UM.Logger import Logger
from UM.Message import Message
from UM.Signal import Signal
@ -15,6 +15,8 @@ from cura.CuraApplication import CuraApplication
from cura.UltimakerCloud.UltimakerCloudScope import UltimakerCloudScope
from .SubscribedPackagesModel import SubscribedPackagesModel
i18n_catalog = i18nCatalog("cura")
class DownloadPresenter:
"""Downloads a set of packages from the Ultimaker Cloud Marketplace
@ -90,7 +92,7 @@ class DownloadPresenter:
lifetime = 0,
use_inactivity_timer = False,
progress = 0.0,
title = i18n_catalog.i18nc("@info:title", "Changes detected from your Ultimaker account", ))
title = i18n_catalog.i18nc("@info:title", "Changes detected from your Ultimaker account"))
def _onFinished(self, package_id: str, reply: QNetworkReply) -> None:
self._progress[package_id]["received"] = self._progress[package_id]["total"]

View file

@ -58,7 +58,6 @@ class PackagesModel(ListModel):
items = []
if self._metadata is None:
Logger.logException("w", "Failed to load packages for Marketplace")
self.setItems(items)
return

View file

@ -183,12 +183,15 @@ class Toolbox(QObject, Extension):
self._application.getCuraAPI().account.loginStateChanged.connect(self._restart)
preferences = CuraApplication.getInstance().getPreferences()
preferences.addPreference("info/automatic_plugin_update_check", True)
# On boot we check which packages have updates.
if CuraApplication.getInstance().getPreferences().getValue("info/automatic_update_check") and len(installed_package_ids_with_versions) > 0:
if preferences.getValue("info/automatic_plugin_update_check") and len(installed_package_ids_with_versions) > 0:
# Request the latest and greatest!
self._makeRequestByType("updates")
def _fetchPackageData(self) -> None:
self._makeRequestByType("packages")
self._makeRequestByType("authors")
@ -648,8 +651,11 @@ class Toolbox(QObject, Extension):
self.resetDownload()
if reply.attribute(QNetworkRequest.HttpStatusCodeAttribute) != 200:
Logger.log("w", "Failed to download package. The following error was returned: %s",
json.loads(reply.readAll().data().decode("utf-8")))
try:
reply_error = json.loads(reply.readAll().data().decode("utf-8"))
except Exception as e:
reply_error = str(e)
Logger.log("w", "Failed to download package. The following error was returned: %s", reply_error)
return
# Must not delete the temporary file on Windows
self._temp_plugin_file = tempfile.NamedTemporaryFile(mode = "w+b", suffix = ".curapackage", delete = False)

View file

@ -3,6 +3,6 @@
"author": "Ultimaker B.V.",
"version": "1.0.0",
"description": "Provides support for reading Ultimaker Format Packages.",
"supported_sdk_versions": ["7.6.0"],
"supported_sdk_versions": ["7.7.0"],
"i18n-catalog": "cura"
}

View file

@ -30,7 +30,7 @@ Button
horizontalCenter: parent.horizontalCenter
verticalCenter: parent.verticalCenter
}
color: UM.Theme.getColor("primary")
color: enabled ? UM.Theme.getColor("primary") : UM.Theme.getColor("main_background")
height: width
source: iconSource
width: Math.round(parent.width / 2)

View file

@ -173,7 +173,7 @@ Cura.MachineAction
anchors.right: parent.right
wrapMode: Text.WordWrap
renderType: Text.NativeRendering
text: catalog.i18nc("@label", "If your printer is not listed, read the <a href='%1'>network printing troubleshooting guide</a>").arg("https://support.ultimaker.com/hc/en-us/articles/360012795419");
text: catalog.i18nc("@label", "If your printer is not listed, read the <a href='%1'>network printing troubleshooting guide</a>").arg("https://ultimaker.com/en/cura/troubleshooting/network?utm_source=cura&utm_medium=software&utm_campaign=manage-network-printer");
onLinkActivated: Qt.openUrlExternally(link)
}

View file

@ -51,7 +51,7 @@ Item
anchors.centerIn: parent
color: UM.Theme.getColor("monitor_icon_primary")
height: UM.Theme.getSize("medium_button_icon").width
source: "../svg/icons/Buildplate.svg"
source: UM.Theme.getIcon("Buildplate")
width: height
visible: buildplate
}

View file

@ -40,7 +40,6 @@ Item
width: 240 * screenScaleFactor // TODO: Theme!
color: UM.Theme.getColor("monitor_tooltip_text")
font: UM.Theme.getFont("default")
renderType: Text.NativeRendering
}
}
}

View file

@ -16,7 +16,7 @@ Item
{
id: base
// The print job which all other information is dervied from
// The print job which all other information is derived from
property var printJob: null
width: childrenRect.width

View file

@ -172,7 +172,7 @@ Item
MouseArea
{
anchors.fill: managePrinterLink
onClicked: OutputDevice.openPrintJobControlPanel()
onClicked: OutputDevice.openPrinterControlPanel()
onEntered:
{
manageQueueText.font.underline = true
@ -271,8 +271,8 @@ Item
}
// For cloud printing, add this mouse area over the disabled cameraButton to indicate that it's not available
//Warning message is commented out because it's factually incorrect. Fix CURA-7637 to allow camera connections via cloud.
/* MouseArea
// Fix CURA-7637 to allow camera connections via cloud.
MouseArea
{
id: cameraDisabledButtonArea
anchors.fill: cameraButton
@ -282,13 +282,13 @@ Item
enabled: !cameraButton.enabled
}
MonitorInfoBlurb
{
id: cameraDisabledInfo
text: catalog.i18nc("@info", "The webcam is not available because you are monitoring a cloud printer.")
text: catalog.i18nc("@info", "Webcam feeds for cloud printers cannot be viewed from Ultimaker Cura." +
" Click \"Manage printer\" to visit Ultimaker Digital Factory and view this webcam.")
target: cameraButton
}*/
}
}
// Divider

View file

@ -2,7 +2,9 @@
// Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.2
import QtQuick.Window 2.2
import QtQuick.Controls 1.2
import QtQuick.Controls 1.1
import QtQuick.Controls 2.15 as NewControls
import UM 1.1 as UM
UM.Dialog {
@ -82,8 +84,9 @@ UM.Dialog {
renderType: Text.NativeRendering;
}
ComboBox {
NewControls.ComboBox {
id: printerComboBox;
currentIndex: 0;
Behavior on height { NumberAnimation { duration: 100 } }
height: 40 * screenScaleFactor;
model: ListModel {

View file

@ -1,27 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="291px" height="209px" viewBox="0 0 291 209" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 52.5 (67469) - http://www.bohemiancoding.com/sketch -->
<title>Group 2</title>
<desc>Created with Sketch.</desc>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="CC--Cloud-connection-succes" transform="translate(-570.000000, -132.000000)">
<g id="Group-2" transform="translate(570.000000, 132.000000)">
<g id="Icon/-group-printer/-connected" fill="#08073F" fill-rule="nonzero">
<g id="printer-group">
<g id="Group-Copy" transform="translate(0.000000, 0.218255)">
<g id="UM3">
<path d="M151.645765,136.481718 C149.925833,142.069331 149,148.004918 149,154.156745 C149,157.125641 149.215633,160.044173 149.632091,162.897534 L94.5646946,162.897534 C92.6599327,163.073639 90.7551708,163.778061 89.3698894,165.010799 L88.3309283,166.067432 C87.2919673,167.828487 85.2140452,168.180697 83.1361231,168.180697 L73.7854738,168.180697 C73.2659933,168.180697 72.7465127,167.652381 72.7465127,167.124065 L72.7465127,152.918227 L19.3939394,152.918227 C17.7008177,153.074764 16.007696,153.700917 14.7763348,154.796684 L13.8528138,155.735914 C12.9292929,157.301296 11.0822511,157.614372 9.23520921,157.614372 L0.923520928,157.614372 C0.461760462,157.614372 1.42108547e-13,157.144757 1.42108547e-13,156.675142 L1.42108547e-13,9.0596475 C1.42108547e-13,8.59003299 0.461760462,8.12041848 0.923520928,8.12041848 L72.7465127,8.12041848 L72.7465127,1.05663265 C72.7465127,0.528316328 73.2659933,-2.84217094e-14 73.7854738,-2.84217094e-14 L216.815777,-2.84217094e-14 C217.335257,-2.84217094e-14 217.854738,0.528316328 217.854738,1.05663265 L217.854738,8.12041848 L289.677732,8.12041848 C290.139493,8.12041848 290.601253,8.59003299 290.601253,9.0596475 L290.601253,156.675142 C290.601253,157.144757 290.139493,157.614372 289.677732,157.614372 L281.366043,157.614372 C279.672922,157.457833 277.9798,156.831681 276.748439,155.735914 L275.824918,154.796684 C274.901397,153.231303 273.054355,152.918227 271.207313,152.918227 L268.987471,152.918227 C268.818229,144.560013 266.939851,136.621364 263.687558,129.437501 L268.590671,129.437501 C272.900435,129.437501 276.440598,125.837123 276.440598,121.454054 L276.594519,121.454054 L276.594519,24.5569264 C276.594519,22.8350065 275.209237,21.5827012 273.670035,21.5827012 L217.854738,21.5827012 L217.854738,94.8055789 C214.965144,94.3781586 212.008429,94.1567452 209,94.1567452 C206.665515,94.1567452 204.362169,94.2900687 202.097162,94.5495169 L202.097162,21.5827012 L202.097162,18.4910714 C202.097162,16.5539116 200.538721,15.145068 198.807119,15.145068 L161.616164,15.145068 L128.985089,15.145068 L91.6209717,15.145068 C89.7162098,15.145068 88.3309283,16.730017 88.3309283,18.4910714 L88.3309283,21.5827012 L88.3309283,127.50034 C88.3309283,128.164624 88.4032089,128.812928 88.5401496,129.437501 C89.4197136,133.449106 92.9667866,136.481718 97.1620971,136.481718 L128.985089,136.481718 L151.645765,136.481718 Z M72.7465127,129.437501 L72.7465127,21.5827012 L16.7772968,21.5827012 C15.0841751,21.5827012 13.8528138,22.9915447 13.8528138,24.5569264 L13.8528138,121.454054 C13.8528138,125.837123 17.3929774,129.437501 21.7027417,129.437501 L72.7465127,129.437501 Z" id="Combined-Shape"></path>
</g>
</g>
</g>
</g>
<g id="Group-cloud" transform="translate(156.000000, 103.000000)">
<g id="Group" transform="translate(0.394933, 0.724044)">
<circle id="Oval-Copy" fill="#3282FF" cx="52.6050671" cy="52.601776" r="52.1311475"></circle>
<path d="M74.8002981,45.4035747 C74.1684054,39.8133538 69.4292101,35.538479 63.7421759,35.538479 C62.1624441,35.538479 60.8986587,35.8673156 59.6348733,36.5249886 C56.7913562,31.9212773 51.7362146,28.9617486 46.3651267,28.9617486 C37.5186289,28.9617486 30.5678092,36.1961521 30.5678092,45.4035747 C30.5678092,45.4035747 30.5678092,45.4035747 30.5678092,45.7324112 C25.1967213,46.3900842 21.0894188,51.322632 21.0894188,56.9128529 C21.0894188,63.1607468 26.1445604,68.4221311 32.147541,68.4221311 C36.8867362,68.4221311 67.533532,68.4221311 73.2205663,68.4221311 C79.2235469,68.4221311 84.2786885,63.1607468 84.2786885,56.9128529 C84.2786885,50.9937956 80.171386,46.3900842 74.8002981,45.4035747 Z" id="Path" fill="#FFFFFF"></path>
</g>
</g>
</g>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 4.6 KiB

View file

@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<path d="M18,21H6c-1.7,0-3-1.3-3-3V6c0-1.7,1.3-3,3-3h12c1.7,0,3,1.3,3,3v12C21,19.7,19.7,21,18,21z M5,19h14
V5H5V19z M14.7,7.7l-1.4-1.4l-7,7l1.4,1.4L14.7,7.7z M9.7,7.7L8.3,6.3l-2,2l1.4,1.4L9.7,7.7z" />
</svg>

Before

Width:  |  Height:  |  Size: 323 B

View file

@ -262,7 +262,7 @@ class CloudOutputDevice(UltimakerNetworkedPrinterOutputDevice):
icon="",
description=I18N_CATALOG.i18nc("@action:tooltip", "Track the print in Ultimaker Digital Factory"),
button_align=message.ActionButtonAlignment.ALIGN_RIGHT)
df_url = f"https://digitalfactory.ultimaker.com/app/jobs/{self._cluster.cluster_id}?utm_source=cura&utm_medium=software&utm_campaign=monitor-button"
df_url = f"https://digitalfactory.ultimaker.com/app/jobs/{self._cluster.cluster_id}?utm_source=cura&utm_medium=software&utm_campaign=message-printjob-sent"
message.pyQtActionTriggered.connect(lambda message, action: (QDesktopServices.openUrl(QUrl(df_url)), message.hide()))
message.show()
@ -334,11 +334,11 @@ class CloudOutputDevice(UltimakerNetworkedPrinterOutputDevice):
@pyqtSlot(name="openPrintJobControlPanel")
def openPrintJobControlPanel(self) -> None:
QDesktopServices.openUrl(QUrl(self.clusterCloudUrl))
QDesktopServices.openUrl(QUrl(self.clusterCloudUrl + "?utm_source=cura&utm_medium=software&utm_campaign=monitor-manage-browser"))
@pyqtSlot(name="openPrinterControlPanel")
def openPrinterControlPanel(self) -> None:
QDesktopServices.openUrl(QUrl(self.clusterCloudUrl))
QDesktopServices.openUrl(QUrl(self.clusterCloudUrl + "?utm_source=cura&utm_medium=software&utm_campaign=monitor-manage-printer"))
@property
def clusterData(self) -> CloudClusterResponse:
@ -357,4 +357,4 @@ class CloudOutputDevice(UltimakerNetworkedPrinterOutputDevice):
"""Gets the URL on which to monitor the cluster via the cloud."""
root_url_prefix = "-staging" if self._account.is_staging else ""
return "https://mycloud{}.ultimaker.com/app/jobs/{}".format(root_url_prefix, self.clusterData.cluster_id)
return "https://digitalfactory{}.ultimaker.com/app/jobs/{}".format(root_url_prefix, self.clusterData.cluster_id)

View file

@ -216,11 +216,6 @@ class CloudOutputDeviceManager:
online_cluster_names = {c.friendly_name.lower() for c in clusters if c.is_online and not c.friendly_name is None}
new_devices.sort(key = lambda x: ("a{}" if x.name.lower() in online_cluster_names else "b{}").format(x.name.lower()))
image_path = os.path.join(
CuraApplication.getInstance().getPluginRegistry().getPluginPath("UM3NetworkPrinting") or "",
"resources", "svg", "cloud-flow-completed.svg"
)
message = Message(
title = self.i18n_catalog.i18ncp(
"info:status",
@ -230,7 +225,6 @@ class CloudOutputDeviceManager:
),
progress = 0,
lifetime = 0,
image_source = image_path,
message_type = Message.MessageType.POSITIVE
)
message.show()
@ -332,7 +326,7 @@ class CloudOutputDeviceManager:
message_text += self.i18n_catalog.i18nc(
"info:status",
"To establish a connection, please visit the {website_link}".format(website_link = "<a href='https://digitalfactory.ultimaker.com/'>{}</a>.".format(digital_factory_string))
"To establish a connection, please visit the {website_link}".format(website_link = "<a href='https://digitalfactory.ultimaker.com?utm_source=cura&utm_medium=software&utm_campaign=change-account-connect-printer'>{}</a>.".format(digital_factory_string))
)
self._removed_printers_message.setText(message_text)
self._removed_printers_message.addAction("keep_printer_configurations_action",
@ -419,7 +413,7 @@ class CloudOutputDeviceManager:
machine.setMetaDataEntry("group_name", device.name)
machine.setMetaDataEntry("group_size", device.clusterSize)
digital_factory_string = self.i18n_catalog.i18nc("info:name", "Ultimaker Digital Factory")
digital_factory_link = "<a href='https://digitalfactory.ultimaker.com/'>{digital_factory_string}</a>".format(digital_factory_string = digital_factory_string)
digital_factory_link = "<a href='https://digitalfactory.ultimaker.com?utm_source=cura&utm_medium=software&utm_campaign=change-account-remove-printer'>{digital_factory_string}</a>".format(digital_factory_string = digital_factory_string)
removal_warning_string = self.i18n_catalog.i18nc("@message {printer_name} is replaced with the name of the printer", "{printer_name} will be removed until the next account sync.").format(printer_name = device.name) \
+ "<br>" + self.i18n_catalog.i18nc("@message {printer_name} is replaced with the name of the printer", "To remove {printer_name} permanently, visit {digital_factory_link}").format(printer_name = device.name, digital_factory_link = digital_factory_link) \
+ "<br><br>" + self.i18n_catalog.i18nc("@message {printer_name} is replaced with the name of the printer", "Are you sure you want to remove {printer_name} temporarily?").format(printer_name = device.name)

View file

@ -52,11 +52,11 @@ class AvrFirmwareUpdater(FirmwareUpdater):
try:
programmer.programChip(hex_file)
except SerialException as e:
Logger.log("e", "A serial port exception occured during firmware update: %s" % e)
Logger.log("e", "A serial port exception occurred during firmware update: %s" % e)
self._setFirmwareUpdateState(FirmwareUpdateState.io_error)
return
except Exception as e:
Logger.log("e", "An unknown exception occured during firmware update: %s" % e)
Logger.log("e", "An unknown exception occurred during firmware update: %s" % e)
self._setFirmwareUpdateState(FirmwareUpdateState.unknown_error)
return

View file

@ -311,7 +311,7 @@ class USBPrinterOutputDevice(PrinterOutputDevice):
if line == b"":
# An empty line means that the firmware is idle
# Multiple empty lines probably means that the firmware and Cura are waiting
# for eachother due to a missed "ok", so we keep track of empty lines
# for each other due to a missed "ok", so we keep track of empty lines
self._firmware_idle_count += 1
else:
self._firmware_idle_count = 0

View file

@ -122,7 +122,7 @@ class VersionUpgrade42to43(VersionUpgrade):
# Update version number.
parser["metadata"]["setting_version"] = "9"
# Handle changes for the imade3d jellybox. The machine was split up into parts (eg; a 2 fan version and a single
# fan version. Perviously it used variants for this. The only upgrade we can do here is strip that variant.
# fan version. Previously it used variants for this. The only upgrade we can do here is strip that variant.
# This is because we only upgrade per stack (and to fully do these changes, we'd need to switch out something
# in the global container based on changes made to the extruder stack)
if parser["containers"]["6"] == "imade3d_jellybox_extruder_0":

View file

@ -104,6 +104,25 @@ class VersionUpgrade49to410(VersionUpgrade):
"g" : "D060"
}
def upgradePreferences(self, serialized: str, filename: str) -> Tuple[List[str], List[str]]:
"""
Upgrades preferences to have the new version number.
:param serialized: The original contents of the preferences file.
:param filename: The file name of the preferences file.
:return: A list of new file names, and a list of the new contents for
those files.
"""
parser = configparser.ConfigParser(interpolation = None)
parser.read_string(serialized)
# Update version number.
parser["metadata"]["setting_version"] = "17"
result = io.StringIO()
parser.write(result)
return [filename], [result.getvalue()]
def upgradeInstanceContainer(self, serialized: str, filename: str) -> Tuple[List[str], List[str]]:
"""Upgrades instance containers to have the new version number.

View file

@ -21,6 +21,7 @@ def getMetaData() -> Dict[str, Any]:
("quality_changes", 4000016): ("quality_changes", 4000017, upgrade.upgradeInstanceContainer),
("quality", 4000016): ("quality", 4000017, upgrade.upgradeInstanceContainer),
("user", 4000016): ("user", 4000017, upgrade.upgradeInstanceContainer),
("preferences", 7000016): ("preferences", 7000017, upgrade.upgradePreferences),
},
"sources": {
"machine_stack": {

View file

@ -250,7 +250,7 @@ class X3DReader(MeshReader):
else:
nr = ns = DEFAULT_SUBDIV
lau = pi / nr # Unit angle of latitude (rings) for the given tesselation
lau = pi / nr # Unit angle of latitude (rings) for the given tessellation
lou = 2 * pi / ns # Unit angle of longitude (segments)
self.reserveFaceAndVertexCount(ns*(nr*2 - 2), 2 + (nr - 1)*ns)