Merge remote-tracking branch 'origin/master' into libArachne_rebased

This commit is contained in:
Jelle Spijker 2021-02-05 08:48:57 +01:00
commit 55e3b858d6
No known key found for this signature in database
GPG key ID: 6662DC033BE6B99A
207 changed files with 3493 additions and 183 deletions

View file

@ -81,7 +81,8 @@ class Account(QObject):
CLIENT_ID="um----------------------------ultimaker_cura",
CLIENT_SCOPES="account.user.read drive.backup.read drive.backup.write packages.download "
"packages.rating.read packages.rating.write connect.cluster.read connect.cluster.write "
"cura.printjob.read cura.printjob.write cura.mesh.read cura.mesh.write",
"library.project.read library.project.write cura.printjob.read cura.printjob.write "
"cura.mesh.read cura.mesh.write",
AUTH_DATA_PREFERENCE_KEY="general/ultimaker_auth_data",
AUTH_SUCCESS_REDIRECT="{}/app/auth-success".format(self._oauth_root),
AUTH_FAILED_REDIRECT="{}/app/auth-error".format(self._oauth_root)

View file

@ -1068,7 +1068,14 @@ class BuildVolume(SceneNode):
adhesion_type = adhesion_override
if adhesion_type is None:
adhesion_type = container_stack.getProperty("adhesion_type", "value")
skirt_brim_line_width = self._global_container_stack.getProperty("skirt_brim_line_width", "value")
# Skirt_brim_line_width is a bit of an odd one out. The primary bit of the skirt/brim is printed
# with the adhesion extruder, but it also prints one extra line by all other extruders. As such, the
# setting does *not* have a limit_to_extruder setting (which means that we can't ask the global extruder what
# the value is.
adhesion_extruder = self._global_container_stack.getProperty("adhesion_extruder_nr", "value")
skirt_brim_line_width = self._global_container_stack.extruderList[int(adhesion_extruder)].getProperty("skirt_brim_line_width", "value")
initial_layer_line_width_factor = self._global_container_stack.getProperty("initial_layer_line_width_factor", "value")
# Use brim width if brim is enabled OR the prime tower has a brim.
if adhesion_type == "brim":

View file

@ -1,8 +1,9 @@
# Copyright (c) 2020 Ultimaker B.V.
# Copyright (c) 2021 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher.
import os
import sys
import tempfile
import time
from typing import cast, TYPE_CHECKING, Optional, Callable, List, Any, Dict
@ -30,6 +31,7 @@ from UM.Operations.SetTransformOperation import SetTransformOperation
from UM.Platform import Platform
from UM.PluginError import PluginNotFoundError
from UM.Preferences import Preferences
from UM.Qt.Bindings.FileProviderModel import FileProviderModel
from UM.Qt.QtApplication import QtApplication # The class we're inheriting from.
from UM.Resources import Resources
from UM.Scene.Camera import Camera
@ -822,6 +824,9 @@ class CuraApplication(QtApplication):
self._add_printer_pages_model_without_cancel.initialize(cancellable = False)
self._whats_new_pages_model.initialize()
# Initialize the FileProviderModel
self._file_provider_model.initialize(self._onFileProviderEnabledChanged)
# Detect in which mode to run and execute that mode
if self._is_headless:
self.runWithoutGUI()
@ -1051,6 +1056,13 @@ class CuraApplication(QtApplication):
self._simple_mode_settings_manager = SimpleModeSettingsManager()
return self._simple_mode_settings_manager
@pyqtSlot(result = QObject)
def getFileProviderModel(self) -> FileProviderModel:
return self._file_provider_model
def _onFileProviderEnabledChanged(self):
self._file_provider_model.update()
def event(self, event):
"""Handle Qt events"""
@ -1466,7 +1478,8 @@ class CuraApplication(QtApplication):
for file_name, nodes in objects_in_filename.items():
for node in nodes:
job = ReadMeshJob(file_name)
file_path = os.path.normpath(os.path.dirname(file_name))
job = ReadMeshJob(file_name, add_to_recent_files = file_path != tempfile.gettempdir()) # Don't add temp files to the recent files list
job._node = node # type: ignore
job.finished.connect(self._reloadMeshFinished)
if has_merged_nodes:
@ -1722,9 +1735,10 @@ class CuraApplication(QtApplication):
openProjectFile = pyqtSignal(QUrl, arguments = ["project_file"]) # Emitted when a project file is about to open.
@pyqtSlot(QUrl, str, bool)
@pyqtSlot(QUrl, str)
@pyqtSlot(QUrl)
def readLocalFile(self, file: QUrl, project_mode: Optional[str] = None):
def readLocalFile(self, file: QUrl, project_mode: Optional[str] = None, add_to_recent_files: bool = True):
"""Open a local file
:param project_mode: How to handle project files. Either None(default): Follow user preference, "open_as_model"
@ -1749,7 +1763,7 @@ class CuraApplication(QtApplication):
if is_project_file and project_mode == "open_as_project":
# open as project immediately without presenting a dialog
workspace_handler = self.getWorkspaceFileHandler()
workspace_handler.readLocalFile(file)
workspace_handler.readLocalFile(file, add_to_recent_files_hint = add_to_recent_files)
return
if is_project_file and project_mode == "always_ask":
@ -1790,7 +1804,7 @@ class CuraApplication(QtApplication):
if extension in self._non_sliceable_extensions:
self.deleteAll(only_selectable = False)
job = ReadMeshJob(f)
job = ReadMeshJob(f, add_to_recent_files = add_to_recent_files)
job.finished.connect(self._readMeshFinished)
job.start()
@ -1905,6 +1919,11 @@ class CuraApplication(QtApplication):
arrange(nodes_to_arrange, self.getBuildVolume(), fixed_nodes)
except:
Logger.logException("e", "Failed to arrange the models")
# Ensure that we don't have any weird floaty objects (CURA-7855)
for node in nodes_to_arrange:
node.translate(Vector(0, -node.getBoundingBox().bottom, 0), SceneNode.TransformSpace.World)
self.fileCompleted.emit(file_name)
def addNonSliceableExtension(self, extension):

View file

@ -88,8 +88,10 @@ class MaterialNode(ContainerNode):
variant = self.variant.variant_name)
else:
qualities_any_material = container_registry.findInstanceContainersMetadata(type = "quality", definition = self.variant.machine.quality_definition)
for material_metadata in container_registry.findInstanceContainersMetadata(type = "material", material = my_material_type):
qualities.extend((quality for quality in qualities_any_material if quality.get("material") == material_metadata["base_file"]))
all_material_base_files = {material_metadata["base_file"] for material_metadata in container_registry.findInstanceContainersMetadata(type = "material", material = my_material_type)}
qualities.extend((quality for quality in qualities_any_material if quality.get("material") in all_material_base_files))
if not qualities: # No quality profiles found. Go by GUID then.
my_guid = self.guid

View file

@ -58,7 +58,7 @@ class AuthorizationHelpers:
:return: An AuthenticationResponse object.
"""
Logger.log("d", "Refreshing the access token.")
Logger.log("d", "Refreshing the access token for [%s]", self._settings.OAUTH_SERVER_URL)
data = {
"client_id": self._settings.CLIENT_ID if self._settings.CLIENT_ID is not None else "",
"redirect_uri": self._settings.CALLBACK_URL if self._settings.CALLBACK_URL is not None else "",
@ -69,7 +69,9 @@ class AuthorizationHelpers:
try:
return self.parseTokenResponse(requests.post(self._token_url, data = data)) # type: ignore
except requests.exceptions.ConnectionError:
return AuthenticationResponse(success=False, err_message="Unable to connect to remote server")
return AuthenticationResponse(success = False, err_message = "Unable to connect to remote server")
except OSError as e:
return AuthenticationResponse(success = False, err_message = "Operating system is unable to set up a secure connection: {err}".format(err = str(e)))
@staticmethod
def parseTokenResponse(token_response: requests.models.Response) -> "AuthenticationResponse":
@ -108,7 +110,9 @@ class AuthorizationHelpers:
"""
try:
token_request = requests.get("{}/check-token".format(self._settings.OAUTH_SERVER_URL), headers = {
check_token_url = "{}/check-token".format(self._settings.OAUTH_SERVER_URL)
Logger.log("d", "Checking the access token for [%s]", check_token_url)
token_request = requests.get(check_token_url, headers = {
"Authorization": "Bearer {}".format(access_token)
})
except requests.exceptions.ConnectionError:

View file

@ -1,4 +1,4 @@
# Copyright (c) 2019 Ultimaker B.V.
# Copyright (c) 2021 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher.
import json
@ -241,13 +241,13 @@ class AuthorizationService:
self._unable_to_get_data_message = Message(i18n_catalog.i18nc("@info", "Unable to reach the Ultimaker account server."), title = i18n_catalog.i18nc("@info:title", "Warning"))
self._unable_to_get_data_message.show()
except ValueError:
except (ValueError, TypeError):
Logger.logException("w", "Could not load auth data from preferences")
def _storeAuthData(self, auth_data: Optional[AuthenticationResponse] = None) -> None:
"""Store authentication data in preferences."""
Logger.log("d", "Attempting to store the auth data")
Logger.log("d", "Attempting to store the auth data for [%s]", self._settings.OAUTH_SERVER_URL)
if self._preferences is None:
Logger.log("e", "Unable to save authentication data, since no preference has been set!")
return

View file

@ -221,6 +221,7 @@ class ContainerManager(QObject):
except OSError:
return {"status": "error", "message": "Unable to write to this location.", "path": file_url}
Logger.info("Successfully exported container to {path}".format(path = file_url))
return {"status": "success", "message": "Successfully exported container", "path": file_url}
@pyqtSlot(QUrl, result = "QVariantMap")

View file

@ -400,7 +400,9 @@ class CuraContainerRegistry(ContainerRegistry):
try:
if int(metadata["setting_version"]) != cura.CuraApplication.CuraApplication.SettingVersion:
return False
except ValueError: #Not parsable as int.
except ValueError: # Not parsable as int.
return False
except TypeError: # Expecting string input here, not e.g. list or anything.
return False
return True

View file

@ -1,4 +1,4 @@
# Copyright (c) 2016 Ultimaker B.V.
# Copyright (c) 2021 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher.
from PyQt5.QtCore import pyqtSlot, pyqtProperty, QObject, pyqtSignal, QRegExp
@ -23,7 +23,7 @@ class MachineNameValidator(QObject):
#Compute the validation regex for printer names. This is limited by the maximum file name length.
try:
filename_max_length = os.statvfs(Resources.getDataStoragePath()).f_namemax
except AttributeError: #Doesn't support statvfs. Probably because it's not a Unix system.
except (AttributeError, EnvironmentError): # Doesn't support statvfs. Probably because it's not a Unix system. Or perhaps there is no permission or it doesn't exist.
filename_max_length = 255 #Assume it's Windows on NTFS.
machine_name_max_length = filename_max_length - len("_current_settings.") - len(ContainerRegistry.getMimeTypeForContainer(InstanceContainer).preferredSuffix)
# Characters that urllib.parse.quote_plus escapes count for 12! So now

View file

@ -1,4 +1,4 @@
# Copyright (c) 2018 Ultimaker B.V.
# Copyright (c) 2021 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher.
import numpy
@ -42,8 +42,8 @@ class Snapshot:
"""
scene = Application.getInstance().getController().getScene()
active_camera = scene.getActiveCamera()
render_width, render_height = active_camera.getWindowSize()
active_camera = scene.getActiveCamera() or scene.findCamera("3d")
render_width, render_height = (width, height) if active_camera is None else active_camera.getWindowSize()
render_width = int(render_width)
render_height = int(render_height)
preview_pass = PreviewPass(render_width, render_height)