mirror of
https://github.com/Ultimaker/Cura.git
synced 2025-12-05 16:51:12 -07:00
Merge branch 'master' into bremco-graphics_buffer_update
This commit is contained in:
commit
a987b9972a
660 changed files with 20420 additions and 11012 deletions
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
}
|
||||
}
|
||||
|
|
|
|||
17
plugins/DigitalLibrary/src/BackwardsCompatibleMessage.py
Normal file
17
plugins/DigitalLibrary/src/BackwardsCompatibleMessage.py
Normal 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)
|
||||
|
|
@ -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")
|
||||
|
|
|
|||
|
|
@ -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"]
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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!)
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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"]
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
}
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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 |
|
|
@ -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 |
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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":
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
||||
|
|
|
|||
|
|
@ -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": {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue