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

This commit is contained in:
Jaime van Kessel 2020-02-17 17:01:38 +01:00
commit 238dd733ea
No known key found for this signature in database
GPG Key ID: 3710727397403C91
8 changed files with 64 additions and 28 deletions

View File

@ -114,7 +114,10 @@ class IntentModel(ListModel):
Logger.log("w", "Could not find the variant %s", active_variant_name) Logger.log("w", "Could not find the variant %s", active_variant_name)
continue continue
active_variant_node = machine_node.variants[active_variant_name] active_variant_node = machine_node.variants[active_variant_name]
active_material_node = active_variant_node.materials[extruder.material.getMetaDataEntry("base_file")] active_material_node = active_variant_node.materials.get(extruder.material.getMetaDataEntry("base_file"))
if active_material_node is None:
Logger.log("w", "Could not find the material %s", extruder.material.getMetaDataEntry("base_file"))
continue
nodes.add(active_material_node) nodes.add(active_material_node)
return nodes return nodes

View File

@ -1,13 +1,18 @@
# Copyright (c) 2019 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.
import threading import threading
from typing import Optional, Callable, Any, TYPE_CHECKING from typing import Any, Callable, Optional, TYPE_CHECKING
from UM.Logger import Logger from UM.Logger import Logger
from cura.OAuth2.AuthorizationRequestServer import AuthorizationRequestServer got_server_type = False
from cura.OAuth2.AuthorizationRequestHandler import AuthorizationRequestHandler try:
from cura.OAuth2.AuthorizationRequestServer import AuthorizationRequestServer
from cura.OAuth2.AuthorizationRequestHandler import AuthorizationRequestHandler
got_server_type = True
except PermissionError: # Bug in http.server: Can't access MIME types. This will prevent the user from logging in. See Sentry bug Cura-3Q.
Logger.error("Can't start a server due to a PermissionError when starting the http.server.")
if TYPE_CHECKING: if TYPE_CHECKING:
from cura.OAuth2.Models import AuthenticationResponse from cura.OAuth2.Models import AuthenticationResponse
@ -50,15 +55,16 @@ class LocalAuthorizationServer:
Logger.log("d", "Starting local web server to handle authorization callback on port %s", self._web_server_port) Logger.log("d", "Starting local web server to handle authorization callback on port %s", self._web_server_port)
# Create the server and inject the callback and code. # Create the server and inject the callback and code.
self._web_server = AuthorizationRequestServer(("0.0.0.0", self._web_server_port), AuthorizationRequestHandler) if got_server_type:
self._web_server.setAuthorizationHelpers(self._auth_helpers) self._web_server = AuthorizationRequestServer(("0.0.0.0", self._web_server_port), AuthorizationRequestHandler)
self._web_server.setAuthorizationCallback(self._auth_state_changed_callback) self._web_server.setAuthorizationHelpers(self._auth_helpers)
self._web_server.setVerificationCode(verification_code) self._web_server.setAuthorizationCallback(self._auth_state_changed_callback)
self._web_server.setState(state) self._web_server.setVerificationCode(verification_code)
self._web_server.setState(state)
# Start the server on a new thread. # Start the server on a new thread.
self._web_server_thread = threading.Thread(None, self._web_server.serve_forever, daemon = self._daemon) self._web_server_thread = threading.Thread(None, self._web_server.serve_forever, daemon = self._daemon)
self._web_server_thread.start() self._web_server_thread.start()
## Stops the web server if it was running. It also does some cleanup. ## Stops the web server if it was running. It also does some cleanup.
def stop(self) -> None: def stop(self) -> None:

View File

@ -31,10 +31,11 @@ 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 is a "real" distribution. sentry_env = "production" # A frozen build has the posibility to be a "real" distribution.
elif ApplicationMetadata.CuraVersion == "master":
sentry_env = "development" if ApplicationMetadata.CuraVersion == "master":
elif "beta" in ApplicationMetadata.CuraVersion or "BETA" in ApplicationMetadata.CuraVersion: sentry_env = "development" # Master is always a development version.
elif ApplicationMetadata.CuraVersion in ["beta", "BETA"]:
sentry_env = "beta" sentry_env = "beta"
try: try:
if ApplicationMetadata.CuraVersion.split(".")[2] == "99": if ApplicationMetadata.CuraVersion.split(".")[2] == "99":

View File

@ -47,7 +47,10 @@ class WindowsRemovableDrivePlugin(RemovableDrivePlugin.RemovableDrivePlugin):
def checkRemovableDrives(self): def checkRemovableDrives(self):
drives = {} drives = {}
# The currently available disk drives, e.g.: bitmask = ...1100 <-- ...DCBA
bitmask = ctypes.windll.kernel32.GetLogicalDrives() bitmask = ctypes.windll.kernel32.GetLogicalDrives()
# Since we are ignoring drives A and B, the bitmask has has to shift twice to the right
bitmask >>= 2
# Check possible drive letters, from C to Z # Check possible drive letters, from C to Z
# Note: using ascii_uppercase because we do not want this to change with locale! # Note: using ascii_uppercase because we do not want this to change with locale!
# Skip A and B, since those drives are typically reserved for floppy disks. # Skip A and B, since those drives are typically reserved for floppy disks.

View File

@ -83,7 +83,7 @@ class CloudPackageChecker(QObject):
package_discrepancy = list(set(user_subscribed_packages).difference(user_installed_packages)) package_discrepancy = list(set(user_subscribed_packages).difference(user_installed_packages))
if package_discrepancy: if package_discrepancy:
self._model.addDiscrepancies(package_discrepancy) self._model.addDiscrepancies(package_discrepancy)
self._model.initialize(subscribed_packages_payload) self._model.initialize(self._package_manager, subscribed_packages_payload)
self._handlePackageDiscrepancies() self._handlePackageDiscrepancies()
def _handlePackageDiscrepancies(self) -> None: def _handlePackageDiscrepancies(self) -> None:

View File

@ -4,6 +4,7 @@ from typing import Dict, Optional, List, Any
from PyQt5.QtCore import QObject, pyqtSlot from PyQt5.QtCore import QObject, pyqtSlot
from UM.Logger import Logger
from UM.PackageManager import PackageManager from UM.PackageManager import PackageManager
from UM.Signal import Signal from UM.Signal import Signal
from cura.CuraApplication import CuraApplication from cura.CuraApplication import CuraApplication
@ -12,12 +13,19 @@ from UM.i18n import i18nCatalog
from .LicenseModel import LicenseModel from .LicenseModel import LicenseModel
## Call present() to show a licenseDialog for a set of packages
# licenseAnswers emits a list of Dicts containing answers when the user has made a choice for all provided packages
class LicensePresenter(QObject): class LicensePresenter(QObject):
"""Presents licenses for a set of packages for the user to accept or reject.
Call present() exactly once to show a licenseDialog for a set of packages
Before presenting another set of licenses, create a new instance using resetCopy().
licenseAnswers emits a list of Dicts containing answers when the user has made a choice for all provided packages.
"""
def __init__(self, app: CuraApplication) -> None: def __init__(self, app: CuraApplication) -> None:
super().__init__() super().__init__()
self._presented = False
"""Whether present() has been called and state is expected to be initialized"""
self._catalog = i18nCatalog("cura") self._catalog = i18nCatalog("cura")
self._dialog = None # type: Optional[QObject] self._dialog = None # type: Optional[QObject]
self._package_manager = app.getPackageManager() # type: PackageManager self._package_manager = app.getPackageManager() # type: PackageManager
@ -39,6 +47,10 @@ class LicensePresenter(QObject):
# \param plugin_path: Root directory of the Toolbox plugin # \param plugin_path: Root directory of the Toolbox plugin
# \param packages: Dict[package id, file path] # \param packages: Dict[package id, file path]
def present(self, plugin_path: str, packages: Dict[str, Dict[str, str]]) -> None: def present(self, plugin_path: str, packages: Dict[str, Dict[str, str]]) -> None:
if self._presented:
Logger.error("{clazz} is single-use. Create a new {clazz} instead", clazz=self.__class__.__name__)
return
path = os.path.join(plugin_path, self._compatibility_dialog_path) path = os.path.join(plugin_path, self._compatibility_dialog_path)
self._initState(packages) self._initState(packages)
@ -56,6 +68,14 @@ class LicensePresenter(QObject):
} }
self._dialog = self._app.createQmlComponent(path, context_properties) self._dialog = self._app.createQmlComponent(path, context_properties)
self._presentCurrentPackage() self._presentCurrentPackage()
self._presented = True
def resetCopy(self) -> "LicensePresenter":
"""Clean up and return a new copy with the same settings such as app"""
if self._dialog:
self._dialog.close()
self.licenseAnswers.disconnectAll()
return LicensePresenter(self._app)
@pyqtSlot() @pyqtSlot()
def onLicenseAccepted(self) -> None: def onLicenseAccepted(self) -> None:

View File

@ -2,9 +2,12 @@
# Cura is released under the terms of the LGPLv3 or higher. # Cura is released under the terms of the LGPLv3 or higher.
from PyQt5.QtCore import Qt, pyqtProperty, pyqtSlot from PyQt5.QtCore import Qt, pyqtProperty, pyqtSlot
from UM.PackageManager import PackageManager
from UM.Qt.ListModel import ListModel from UM.Qt.ListModel import ListModel
from UM.Version import Version
from cura import ApplicationMetadata from cura import ApplicationMetadata
from UM.Logger import Logger
from typing import List, Dict, Any from typing import List, Dict, Any
@ -46,7 +49,7 @@ class SubscribedPackagesModel(ListModel):
def getIncompatiblePackages(self) -> List[str]: def getIncompatiblePackages(self) -> List[str]:
return [package["package_id"] for package in self._items if not package["is_compatible"]] return [package["package_id"] for package in self._items if not package["is_compatible"]]
def initialize(self, subscribed_packages_payload: List[Dict[str, Any]]) -> None: def initialize(self, package_manager: PackageManager, subscribed_packages_payload: List[Dict[str, Any]]) -> None:
self._items.clear() self._items.clear()
for item in subscribed_packages_payload: for item in subscribed_packages_payload:
if item["package_id"] not in self._discrepancies: if item["package_id"] not in self._discrepancies:
@ -59,15 +62,13 @@ class SubscribedPackagesModel(ListModel):
"md5_hash": item["md5_hash"], "md5_hash": item["md5_hash"],
"is_dismissed": False, "is_dismissed": False,
} }
if self._sdk_version not in item["sdk_versions"]:
package.update({"is_compatible": False}) compatible = any(package_manager.isPackageCompatible(Version(version)) for version in item["sdk_versions"])
else: package.update({"is_compatible": compatible})
package.update({"is_compatible": True})
try: try:
package.update({"icon_url": item["icon_url"]}) package.update({"icon_url": item["icon_url"]})
except KeyError: # There is no 'icon_url" in the response payload for this package except KeyError: # There is no 'icon_url" in the response payload for this package
package.update({"icon_url": ""}) package.update({"icon_url": ""})
self._items.append(package) self._items.append(package)
self.setItems(self._items) self.setItems(self._items)

View File

@ -72,6 +72,8 @@ class SyncOrchestrator(Extension):
self._showErrorMessage(message) self._showErrorMessage(message)
plugin_path = cast(str, PluginRegistry.getInstance().getPluginPath(self.getPluginId())) plugin_path = cast(str, PluginRegistry.getInstance().getPluginPath(self.getPluginId()))
self._license_presenter = self._license_presenter.resetCopy()
self._license_presenter.licenseAnswers.connect(self._onLicenseAnswers)
self._license_presenter.present(plugin_path, success_items) self._license_presenter.present(plugin_path, success_items)
# Called when user has accepted / declined all licenses for the downloaded packages # Called when user has accepted / declined all licenses for the downloaded packages