Merge branch 'master' of github.com:Ultimaker/Cura

This commit is contained in:
Jaime van Kessel 2020-07-07 10:47:58 +02:00
commit 82ecc95c22
No known key found for this signature in database
GPG key ID: 3710727397403C91
6 changed files with 64 additions and 26 deletions

View file

@ -99,7 +99,7 @@ class ExtruderOutputModel(QObject):
self._is_preheating = pre_heating self._is_preheating = pre_heating
self.isPreheatingChanged.emit() self.isPreheatingChanged.emit()
@pyqtProperty(bool, notify=isPreheatingChanged) @pyqtProperty(bool, notify = isPreheatingChanged)
def isPreheating(self) -> bool: def isPreheating(self) -> bool:
return self._is_preheating return self._is_preheating

View file

@ -39,7 +39,7 @@ except ImportError:
parser = argparse.ArgumentParser(prog = "cura", parser = argparse.ArgumentParser(prog = "cura",
add_help = False) add_help = False)
parser.add_argument("--debug", parser.add_argument("--debug",
action="store_true", action = "store_true",
default = False, default = False,
help = "Turn on the debug mode by setting this option." help = "Turn on the debug mode by setting this option."
) )
@ -49,7 +49,7 @@ known_args = vars(parser.parse_known_args()[0])
if with_sentry_sdk: if with_sentry_sdk:
sentry_env = "unknown" # Start off with a "IDK" sentry_env = "unknown" # Start off with a "IDK"
if hasattr(sys, "frozen"): if hasattr(sys, "frozen"):
sentry_env = "production" # A frozen build has the posibility to be a "real" distribution. sentry_env = "production" # A frozen build has the possibility to be a "real" distribution.
if ApplicationMetadata.CuraVersion == "master": if ApplicationMetadata.CuraVersion == "master":
sentry_env = "development" # Master is always a development version. sentry_env = "development" # Master is always a development version.

View file

@ -127,6 +127,7 @@ class ThreeMFWorkspaceWriter(WorkspaceWriter):
file_name = "Cura/%s.%s" % (container.getId(), file_suffix) file_name = "Cura/%s.%s" % (container.getId(), file_suffix)
try:
if file_name in archive.namelist(): if file_name in archive.namelist():
return # File was already saved, no need to do it again. Uranium guarantees unique ID's, so this should hold. return # File was already saved, no need to do it again. Uranium guarantees unique ID's, so this should hold.
@ -139,3 +140,6 @@ class ThreeMFWorkspaceWriter(WorkspaceWriter):
serialized_data = container.serialize(ignored_metadata_keys = ignore_keys) serialized_data = container.serialize(ignored_metadata_keys = ignore_keys)
archive.writestr(file_in_archive, serialized_data) archive.writestr(file_in_archive, serialized_data)
except (FileNotFoundError, EnvironmentError):
Logger.error("File became inaccessible while writing to it: {archive_filename}".format(archive_filename = archive.fp.name))
return

View file

@ -120,6 +120,10 @@ class DownloadPresenter:
received += item["received"] received += item["received"]
total += item["total"] total += item["total"]
if total == 0: # Total download size is 0, or unknown, or there are no progress items at all.
self._progress_message.setProgress(100.0)
return
self._progress_message.setProgress(100.0 * (received / total)) # [0 .. 100] % self._progress_message.setProgress(100.0 * (received / total)) # [0 .. 100] %
def _onError(self, package_id: str) -> None: def _onError(self, package_id: str) -> None:

View file

@ -1,18 +1,20 @@
#Copyright (c) 2020 Ultimaker B.V. # Copyright (c) 2020 Ultimaker B.V.
#Cura is released under the terms of the LGPLv3 or higher. # Cura is released under the terms of the LGPLv3 or higher.
from typing import cast from typing import cast, List, Dict
from Charon.VirtualFile import VirtualFile #To open UFP files. from Charon.VirtualFile import VirtualFile # To open UFP files.
from Charon.OpenMode import OpenMode #To indicate that we want to write to UFP files. from Charon.OpenMode import OpenMode # To indicate that we want to write to UFP files.
from io import StringIO #For converting g-code to bytes. from io import StringIO # For converting g-code to bytes.
from UM.Logger import Logger from UM.Logger import Logger
from UM.Mesh.MeshWriter import MeshWriter #The writer we need to implement. from UM.Mesh.MeshWriter import MeshWriter # The writer we need to implement.
from UM.MimeTypeDatabase import MimeTypeDatabase, MimeType from UM.MimeTypeDatabase import MimeTypeDatabase, MimeType
from UM.PluginRegistry import PluginRegistry #To get the g-code writer. from UM.PluginRegistry import PluginRegistry # To get the g-code writer.
from PyQt5.QtCore import QBuffer from PyQt5.QtCore import QBuffer
from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator
from UM.Scene.SceneNode import SceneNode
from cura.CuraApplication import CuraApplication from cura.CuraApplication import CuraApplication
from cura.Snapshot import Snapshot from cura.Snapshot import Snapshot
from cura.Utils.Threading import call_on_qt_thread from cura.Utils.Threading import call_on_qt_thread
@ -58,12 +60,12 @@ class UFPWriter(MeshWriter):
self._writeObjectList(archive) self._writeObjectList(archive)
#Store the g-code from the scene. # Store the g-code from the scene.
archive.addContentType(extension = "gcode", mime_type = "text/x-gcode") archive.addContentType(extension = "gcode", mime_type = "text/x-gcode")
gcode_textio = StringIO() #We have to convert the g-code into bytes. gcode_textio = StringIO() # We have to convert the g-code into bytes.
gcode_writer = cast(MeshWriter, PluginRegistry.getInstance().getPluginObject("GCodeWriter")) gcode_writer = cast(MeshWriter, PluginRegistry.getInstance().getPluginObject("GCodeWriter"))
success = gcode_writer.write(gcode_textio, None) success = gcode_writer.write(gcode_textio, None)
if not success: #Writing the g-code failed. Then I can also not write the gzipped g-code. if not success: # Writing the g-code failed. Then I can also not write the gzipped g-code.
self.setInformation(gcode_writer.getInformation()) self.setInformation(gcode_writer.getInformation())
return False return False
gcode = archive.getStream("/3D/model.gcode") gcode = archive.getStream("/3D/model.gcode")
@ -72,7 +74,7 @@ class UFPWriter(MeshWriter):
self._createSnapshot() self._createSnapshot()
#Store the thumbnail. # Store the thumbnail.
if self._snapshot: if self._snapshot:
archive.addContentType(extension = "png", mime_type = "image/png") archive.addContentType(extension = "png", mime_type = "image/png")
thumbnail = archive.getStream("/Metadata/thumbnail.png") thumbnail = archive.getStream("/Metadata/thumbnail.png")
@ -83,7 +85,9 @@ class UFPWriter(MeshWriter):
thumbnail_image.save(thumbnail_buffer, "PNG") thumbnail_image.save(thumbnail_buffer, "PNG")
thumbnail.write(thumbnail_buffer.data()) thumbnail.write(thumbnail_buffer.data())
archive.addRelation(virtual_path = "/Metadata/thumbnail.png", relation_type = "http://schemas.openxmlformats.org/package/2006/relationships/metadata/thumbnail", origin = "/3D/model.gcode") archive.addRelation(virtual_path = "/Metadata/thumbnail.png",
relation_type = "http://schemas.openxmlformats.org/package/2006/relationships/metadata/thumbnail",
origin = "/3D/model.gcode")
else: else:
Logger.log("d", "Thumbnail not created, cannot save it") Logger.log("d", "Thumbnail not created, cannot save it")
@ -151,8 +155,25 @@ class UFPWriter(MeshWriter):
To retrieve, use: `archive.getMetadata(METADATA_OBJECTS_PATH)` To retrieve, use: `archive.getMetadata(METADATA_OBJECTS_PATH)`
""" """
objects_model = CuraApplication.getInstance().getObjectsModel() objects_model = CuraApplication.getInstance().getObjectsModel()
object_metas = [{"name": item["name"]} for item in objects_model.items] object_metas = []
for item in objects_model.items:
object_metas.extend(UFPWriter._getObjectMetadata(item["node"]))
data = {METADATA_OBJECTS_PATH: object_metas} data = {METADATA_OBJECTS_PATH: object_metas}
archive.setMetadata(data) archive.setMetadata(data)
@staticmethod
def _getObjectMetadata(node: SceneNode) -> List[Dict[str, str]]:
"""Get object metadata to write for a Node.
:return: List of object metadata dictionaries.
Might contain > 1 element in case of a group node.
Might be empty in case of nonPrintingMesh
"""
return [{"name": item.getName()}
for item in DepthFirstIterator(node)
if item.getMeshData() is not None and not item.callDecoration("isNonPrintingMesh")]

View file

@ -4,6 +4,8 @@
import configparser import configparser
from typing import Tuple, List, Dict, Set from typing import Tuple, List, Dict, Set
import io import io
from UM.Util import parseBool
from UM.VersionUpgrade import VersionUpgrade from UM.VersionUpgrade import VersionUpgrade
@ -42,6 +44,13 @@ class VersionUpgrade462to47(VersionUpgrade):
parser["general"]["visible_settings"] = ";".join( parser["general"]["visible_settings"] = ";".join(
set(parser["general"]["visible_settings"].split(";")).difference(_removed_settings)) set(parser["general"]["visible_settings"].split(";")).difference(_removed_settings))
if "cura" in parser and "jobname_prefix" in parser["cura"]:
if not parseBool(parser["cura"]["jobname_prefix"]):
parser["cura"]["job_name_template"] = "{project_name}"
del parser["cura"]["jobname_prefix"]
# else: When the jobname_prefix preference is True or not set,
# the default value for job_name_template ("{machine_name_short}_{project_name}") will be used
result = io.StringIO() result = io.StringIO()
parser.write(result) parser.write(result)
return [filename], [result.getvalue()] return [filename], [result.getvalue()]