mirror of
https://github.com/Ultimaker/Cura.git
synced 2025-07-10 00:07:51 -06:00
Merge remote-tracking branch 'origin/master' into CURA-6983_sync_packages
# Conflicts: # plugins/Toolbox/src/CloudSync/SubscribedPackagesModel.py # plugins/Toolbox/src/Toolbox.py
This commit is contained in:
commit
182bab6467
44 changed files with 343 additions and 161 deletions
116
.pylintrc
Normal file
116
.pylintrc
Normal file
|
@ -0,0 +1,116 @@
|
|||
# Copyright (c) 2019 Ultimaker B.V.
|
||||
# This file contains the Pylint rules used in the stardust projects.
|
||||
|
||||
# To configure PyLint as an external tool in PyCharm, create a new External Tool with the settings:
|
||||
#
|
||||
# Name: PyLint
|
||||
# Program: Check with 'which pylint'. For example: ~/.local/bin/pylint
|
||||
# Arguments: $FileDirName$ --rcfile=.pylintrc --msg-template='{abspath}:{line}:{column}:({symbol}):{msg_id}:{msg}'
|
||||
# Working directory: $ContentRoot$
|
||||
# Output filters: $FILE_PATH$:$LINE$:$COLUMN$:.*
|
||||
#
|
||||
# You can add a keyboard shortcut in the keymap settings. To run Pylint to a project, select the module
|
||||
# you want to check (e.g. cura folder) before running the external tool.
|
||||
#
|
||||
# If you find a better way to configure the external tool please edit this file.
|
||||
|
||||
[MASTER]
|
||||
# List of plugins (as comma separated values of python modules names) to load,
|
||||
# usually to register additional checkers.
|
||||
load-plugins=pylint_quotes
|
||||
|
||||
# We expect double string quotes
|
||||
string-quote=double-avoid-escape
|
||||
|
||||
# When enabled, pylint would attempt to guess common misconfiguration and emit
|
||||
# user-friendly hints instead of false-positive error messages.
|
||||
suggestion-mode=yes
|
||||
|
||||
# Add files or directories to the blacklist. They should be base names, not paths.
|
||||
ignore=tests
|
||||
|
||||
[REFACTORING]
|
||||
# Maximum number of nested blocks for function / method body
|
||||
max-nested-blocks=5
|
||||
|
||||
[MESSAGES CONTROL]
|
||||
# C0326: No space allowed around keyword argument assignment
|
||||
# C0411: Ignore import order because the rules are different than in PyCharm, so automatic imports break lots of builds
|
||||
# C0412: Ignore import order because the rules are different than in PyCharm, so automatic imports break lots of builds
|
||||
# C0413: Ignore import order because the rules are different than in PyCharm, so automatic imports break lots of builds
|
||||
# R0201: Method could be a function (no-self-use)
|
||||
# R0401: Cyclic imports (cyclic-import) are used for typing
|
||||
# R0801: Unfortunately the error is triggered for a lot of similar models (duplicate-code)
|
||||
# R1710: Either all return statements in a function should return an expression, or none of them should.
|
||||
# W0221: Parameters differ from overridden method (tornado http methods have a flexible number of parameters)
|
||||
# W0511: Ignore warnings generated for TODOs in the code
|
||||
# C0111: We don't use docstring
|
||||
# C0303: Trailing whitespace isn't something we care about
|
||||
# C4001: You can put " in a string if you escape it first...
|
||||
disable=C0326,C0411,C0412,C0413,R0201,R0401,R0801,R1710,W0221,W0511, C0111, C0303,C4001
|
||||
|
||||
[FORMAT]
|
||||
# Maximum number of characters on a single line.
|
||||
max-line-length=120
|
||||
|
||||
# Maximum number of lines in a module.
|
||||
max-module-lines=500
|
||||
|
||||
good-names=os
|
||||
|
||||
[BASIC]
|
||||
# allow modules and functions to use PascalCase
|
||||
module-rgx=[a-zA-Z0-9_]+$
|
||||
function-rgx=
|
||||
## Allowed methods:
|
||||
# getSomething
|
||||
# _getSomething
|
||||
# __getSomething
|
||||
# __new__
|
||||
## Disallowed:
|
||||
# _GET
|
||||
# GetSomething
|
||||
method-rgx=(_{,2}[a-z][A-Za-z0-9]*_{,2})$
|
||||
|
||||
[DESIGN]
|
||||
# Maximum number of arguments for function / method.
|
||||
max-args=7
|
||||
|
||||
# Maximum number of attributes for a class (see R0902).
|
||||
max-attributes=8
|
||||
|
||||
# Maximum number of boolean expressions in an if statement.
|
||||
max-bool-expr=5
|
||||
|
||||
# Maximum number of branch for function / method body.
|
||||
max-branches=12
|
||||
|
||||
# Maximum number of locals for function / method body.
|
||||
max-locals=15
|
||||
|
||||
# Maximum number of parents for a class (see R0901).
|
||||
max-parents=7
|
||||
|
||||
# Maximum number of public methods for a class (see R0904).
|
||||
max-public-methods=20
|
||||
|
||||
# Maximum number of return / yield for function / method body.
|
||||
max-returns=6
|
||||
|
||||
# Maximum number of statements in function / method body.
|
||||
max-statements=50
|
||||
|
||||
# Minimum number of public methods for a class (R0903).
|
||||
# We set this to 0 because our models and fields do not have methods.
|
||||
min-public-methods=0
|
||||
|
||||
ignored-argument-names=arg|args|kwargs|_
|
||||
|
||||
[CLASSES]
|
||||
defining-attr-methods=__init__,__new__,setUp,initialize
|
||||
|
||||
[TYPECHECK]
|
||||
ignored-classes=NotImplemented
|
||||
|
||||
[VARIABLES]
|
||||
dummy-variables-rgx=_+[a-z0-9_]{2,30}
|
|
@ -1,6 +1,6 @@
|
|||
# Copyright (c) 2018 Ultimaker B.V.
|
||||
# Cura is released under the terms of the LGPLv3 or higher.
|
||||
from typing import List
|
||||
from typing import List, Optional
|
||||
|
||||
from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator
|
||||
from UM.Logger import Logger
|
||||
|
@ -8,6 +8,7 @@ from UM.Math.Polygon import Polygon
|
|||
from UM.Math.Vector import Vector
|
||||
from UM.Scene.SceneNode import SceneNode
|
||||
from cura.Arranging.ShapeArray import ShapeArray
|
||||
from cura.BuildVolume import BuildVolume
|
||||
from cura.Scene import ZOffsetDecorator
|
||||
|
||||
from collections import namedtuple
|
||||
|
@ -27,7 +28,7 @@ LocationSuggestion = namedtuple("LocationSuggestion", ["x", "y", "penalty_points
|
|||
#
|
||||
# Note: Make sure the scale is the same between ShapeArray objects and the Arrange instance.
|
||||
class Arrange:
|
||||
build_volume = None
|
||||
build_volume = None # type: Optional[BuildVolume]
|
||||
|
||||
def __init__(self, x, y, offset_x, offset_y, scale= 0.5):
|
||||
self._scale = scale # convert input coordinates to arrange coordinates
|
||||
|
@ -68,7 +69,7 @@ class Arrange:
|
|||
points = copy.deepcopy(vertices._points)
|
||||
|
||||
# After scaling (like up to 0.1 mm) the node might not have points
|
||||
if len(points) == 0:
|
||||
if not points.size:
|
||||
continue
|
||||
|
||||
shape_arr = ShapeArray.fromPolygon(points, scale = scale)
|
||||
|
@ -113,7 +114,7 @@ class Arrange:
|
|||
found_spot = True
|
||||
self.place(x, y, offset_shape_arr) # place the object in arranger
|
||||
else:
|
||||
Logger.log("d", "Could not find spot!"),
|
||||
Logger.log("d", "Could not find spot!")
|
||||
found_spot = False
|
||||
node.setPosition(Vector(200, center_y, 100))
|
||||
return found_spot
|
||||
|
|
|
@ -29,7 +29,7 @@ class ArrangeArray:
|
|||
self._has_empty = False
|
||||
self._arrange = [] # type: List[Arrange]
|
||||
|
||||
def _update_first_empty(self):
|
||||
def _updateFirstEmpty(self):
|
||||
for i, a in enumerate(self._arrange):
|
||||
if a.isEmpty:
|
||||
self._first_empty = i
|
||||
|
@ -42,7 +42,7 @@ class ArrangeArray:
|
|||
new_arrange = Arrange.create(x = self._x, y = self._y, fixed_nodes = self._fixed_nodes)
|
||||
self._arrange.append(new_arrange)
|
||||
self._count += 1
|
||||
self._update_first_empty()
|
||||
self._updateFirstEmpty()
|
||||
|
||||
def count(self):
|
||||
return self._count
|
||||
|
|
|
@ -2,12 +2,16 @@
|
|||
# Cura is released under the terms of the LGPLv3 or higher.
|
||||
|
||||
from PyQt5.QtCore import QTimer
|
||||
from typing import Any, TYPE_CHECKING
|
||||
|
||||
from UM.Logger import Logger
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from cura.CuraApplication import CuraApplication
|
||||
|
||||
|
||||
class AutoSave:
|
||||
def __init__(self, application):
|
||||
def __init__(self, application: "CuraApplication") -> None:
|
||||
self._application = application
|
||||
self._application.getPreferences().preferenceChanged.connect(self._triggerTimer)
|
||||
|
||||
|
@ -22,14 +26,14 @@ class AutoSave:
|
|||
self._enabled = True
|
||||
self._saving = False
|
||||
|
||||
def initialize(self):
|
||||
def initialize(self) -> None:
|
||||
# only initialise if the application is created and has started
|
||||
self._change_timer.timeout.connect(self._onTimeout)
|
||||
self._application.globalContainerStackChanged.connect(self._onGlobalStackChanged)
|
||||
self._onGlobalStackChanged()
|
||||
self._triggerTimer()
|
||||
|
||||
def _triggerTimer(self, *args):
|
||||
def _triggerTimer(self, *args: Any) -> None:
|
||||
if not self._saving:
|
||||
self._change_timer.start()
|
||||
|
||||
|
@ -40,7 +44,7 @@ class AutoSave:
|
|||
else:
|
||||
self._change_timer.stop()
|
||||
|
||||
def _onGlobalStackChanged(self):
|
||||
def _onGlobalStackChanged(self) -> None:
|
||||
if self._global_stack:
|
||||
self._global_stack.propertyChanged.disconnect(self._triggerTimer)
|
||||
self._global_stack.containersChanged.disconnect(self._triggerTimer)
|
||||
|
@ -51,7 +55,7 @@ class AutoSave:
|
|||
self._global_stack.propertyChanged.connect(self._triggerTimer)
|
||||
self._global_stack.containersChanged.connect(self._triggerTimer)
|
||||
|
||||
def _onTimeout(self):
|
||||
def _onTimeout(self) -> None:
|
||||
self._saving = True # To prevent the save process from triggering another autosave.
|
||||
Logger.log("d", "Autosaving preferences, instances and profiles")
|
||||
|
||||
|
|
|
@ -1,15 +1,21 @@
|
|||
# Copyright (c) 2019 Ultimaker B.V.
|
||||
# Cura is released under the terms of the LGPLv3 or higher.
|
||||
|
||||
import numpy
|
||||
import math
|
||||
|
||||
from typing import List, Optional, TYPE_CHECKING, Any, Set, cast, Iterable, Dict
|
||||
|
||||
from UM.Mesh.MeshData import MeshData
|
||||
from cura.Scene.CuraSceneNode import CuraSceneNode
|
||||
from cura.Settings.ExtruderManager import ExtruderManager
|
||||
from UM.Mesh.MeshBuilder import MeshBuilder
|
||||
|
||||
from UM.Application import Application #To modify the maximum zoom level.
|
||||
from UM.i18n import i18nCatalog
|
||||
from UM.Scene.Platform import Platform
|
||||
from UM.Scene.Iterator.BreadthFirstIterator import BreadthFirstIterator
|
||||
from UM.Scene.SceneNode import SceneNode
|
||||
from UM.Resources import Resources
|
||||
from UM.Mesh.MeshBuilder import MeshBuilder
|
||||
|
||||
from UM.Math.Vector import Vector
|
||||
from UM.Math.Matrix import Matrix
|
||||
from UM.Math.Color import Color
|
||||
|
@ -17,23 +23,23 @@ from UM.Math.AxisAlignedBox import AxisAlignedBox
|
|||
from UM.Math.Polygon import Polygon
|
||||
from UM.Message import Message
|
||||
from UM.Signal import Signal
|
||||
from PyQt5.QtCore import QTimer
|
||||
from UM.View.RenderBatch import RenderBatch
|
||||
from UM.View.GL.OpenGL import OpenGL
|
||||
|
||||
from cura.Settings.GlobalStack import GlobalStack
|
||||
from cura.Scene.CuraSceneNode import CuraSceneNode
|
||||
from cura.Settings.ExtruderManager import ExtruderManager
|
||||
|
||||
catalog = i18nCatalog("cura")
|
||||
from PyQt5.QtCore import QTimer
|
||||
|
||||
import numpy
|
||||
import math
|
||||
|
||||
from typing import List, Optional, TYPE_CHECKING, Any, Set, cast, Iterable, Dict
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from cura.CuraApplication import CuraApplication
|
||||
from cura.Settings.ExtruderStack import ExtruderStack
|
||||
from UM.Settings.ContainerStack import ContainerStack
|
||||
|
||||
catalog = i18nCatalog("cura")
|
||||
|
||||
# Radius of disallowed area in mm around prime. I.e. how much distance to keep from prime position.
|
||||
PRIME_CLEARANCE = 6.5
|
||||
|
||||
|
@ -1012,13 +1018,13 @@ class BuildVolume(SceneNode):
|
|||
all_values = ExtruderManager.getInstance().getAllExtruderSettings(setting_key, "value")
|
||||
all_types = ExtruderManager.getInstance().getAllExtruderSettings(setting_key, "type")
|
||||
for i, (setting_value, setting_type) in enumerate(zip(all_values, all_types)):
|
||||
if not setting_value and (setting_type == "int" or setting_type == "float"):
|
||||
if not setting_value and setting_type in ["int", "float"]:
|
||||
all_values[i] = 0
|
||||
return all_values
|
||||
|
||||
def _calculateBedAdhesionSize(self, used_extruders):
|
||||
if self._global_container_stack is None:
|
||||
return
|
||||
return None
|
||||
|
||||
container_stack = self._global_container_stack
|
||||
adhesion_type = container_stack.getProperty("adhesion_type", "value")
|
||||
|
|
|
@ -58,6 +58,8 @@ class CrashHandler:
|
|||
self.traceback = tb
|
||||
self.has_started = has_started
|
||||
self.dialog = None # Don't create a QDialog before there is a QApplication
|
||||
self.cura_version = None
|
||||
self.cura_locale = None
|
||||
|
||||
Logger.log("c", "An uncaught error has occurred!")
|
||||
for line in traceback.format_exception(exception_type, value, tb):
|
||||
|
|
|
@ -3,17 +3,15 @@
|
|||
|
||||
from PyQt5.QtCore import QObject, QUrl
|
||||
from PyQt5.QtGui import QDesktopServices
|
||||
from typing import List, Optional, cast
|
||||
from typing import List, cast
|
||||
|
||||
from UM.Event import CallFunctionEvent
|
||||
from UM.FlameProfiler import pyqtSlot
|
||||
from UM.Math.Quaternion import Quaternion
|
||||
from UM.Math.Vector import Vector
|
||||
from UM.Scene.Selection import Selection
|
||||
from UM.Scene.Iterator.BreadthFirstIterator import BreadthFirstIterator
|
||||
from UM.Operations.GroupedOperation import GroupedOperation
|
||||
from UM.Operations.RemoveSceneNodeOperation import RemoveSceneNodeOperation
|
||||
from UM.Operations.RotateOperation import RotateOperation
|
||||
from UM.Operations.TranslateOperation import TranslateOperation
|
||||
|
||||
import cura.CuraApplication
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
import os
|
||||
import sys
|
||||
import time
|
||||
from typing import cast, TYPE_CHECKING, Optional, Callable, List
|
||||
from typing import cast, TYPE_CHECKING, Optional, Callable, List, Any
|
||||
|
||||
import numpy
|
||||
|
||||
|
@ -15,7 +15,7 @@ from PyQt5.QtQml import qmlRegisterUncreatableType, qmlRegisterSingletonType, qm
|
|||
|
||||
from UM.i18n import i18nCatalog
|
||||
from UM.Application import Application
|
||||
from UM.Decorators import override, deprecated
|
||||
from UM.Decorators import override
|
||||
from UM.FlameProfiler import pyqtSlot
|
||||
from UM.Logger import Logger
|
||||
from UM.Message import Message
|
||||
|
@ -193,7 +193,7 @@ class CuraApplication(QtApplication):
|
|||
|
||||
self._cura_package_manager = None
|
||||
|
||||
self._machine_action_manager = None
|
||||
self._machine_action_manager = None # type: Optional[MachineActionManager.MachineActionManager]
|
||||
|
||||
self.empty_container = None # type: EmptyInstanceContainer
|
||||
self.empty_definition_changes_container = None # type: EmptyInstanceContainer
|
||||
|
@ -266,7 +266,6 @@ class CuraApplication(QtApplication):
|
|||
# Backups
|
||||
self._auto_save = None # type: Optional[AutoSave]
|
||||
|
||||
from cura.Settings.CuraContainerRegistry import CuraContainerRegistry
|
||||
self._container_registry_class = CuraContainerRegistry
|
||||
# Redefined here in order to please the typing.
|
||||
self._container_registry = None # type: CuraContainerRegistry
|
||||
|
@ -699,7 +698,7 @@ class CuraApplication(QtApplication):
|
|||
self._message_box_callback_arguments = []
|
||||
|
||||
# Cura has multiple locations where instance containers need to be saved, so we need to handle this differently.
|
||||
def saveSettings(self):
|
||||
def saveSettings(self) -> None:
|
||||
if not self.started:
|
||||
# Do not do saving during application start or when data should not be saved on quit.
|
||||
return
|
||||
|
@ -989,8 +988,8 @@ class CuraApplication(QtApplication):
|
|||
## Get the machine action manager
|
||||
# We ignore any *args given to this, as we also register the machine manager as qml singleton.
|
||||
# It wants to give this function an engine and script engine, but we don't care about that.
|
||||
def getMachineActionManager(self, *args):
|
||||
return self._machine_action_manager
|
||||
def getMachineActionManager(self, *args: Any) -> MachineActionManager.MachineActionManager:
|
||||
return cast(MachineActionManager.MachineActionManager, self._machine_action_manager)
|
||||
|
||||
@pyqtSlot(result = QObject)
|
||||
def getMaterialManagementModel(self) -> MaterialManagementModel:
|
||||
|
@ -1443,7 +1442,7 @@ class CuraApplication(QtApplication):
|
|||
if center is not None:
|
||||
object_centers.append(center)
|
||||
|
||||
if object_centers and len(object_centers) > 0:
|
||||
if object_centers:
|
||||
middle_x = sum([v.x for v in object_centers]) / len(object_centers)
|
||||
middle_y = sum([v.y for v in object_centers]) / len(object_centers)
|
||||
middle_z = sum([v.z for v in object_centers]) / len(object_centers)
|
||||
|
@ -1493,7 +1492,7 @@ class CuraApplication(QtApplication):
|
|||
if center is not None:
|
||||
object_centers.append(center)
|
||||
|
||||
if object_centers and len(object_centers) > 0:
|
||||
if object_centers:
|
||||
middle_x = sum([v.x for v in object_centers]) / len(object_centers)
|
||||
middle_y = sum([v.y for v in object_centers]) / len(object_centers)
|
||||
middle_z = sum([v.z for v in object_centers]) / len(object_centers)
|
||||
|
@ -1675,7 +1674,7 @@ class CuraApplication(QtApplication):
|
|||
extension = os.path.splitext(f)[1]
|
||||
extension = extension.lower()
|
||||
filename = os.path.basename(f)
|
||||
if len(self._currently_loading_files) > 0:
|
||||
if self._currently_loading_files:
|
||||
# If a non-slicable file is already being loaded, we prevent loading of any further non-slicable files
|
||||
if extension in self._non_sliceable_extensions:
|
||||
message = Message(
|
||||
|
@ -1796,8 +1795,8 @@ class CuraApplication(QtApplication):
|
|||
node.addDecorator(build_plate_decorator)
|
||||
build_plate_decorator.setBuildPlateNumber(target_build_plate)
|
||||
|
||||
op = AddSceneNodeOperation(node, scene.getRoot())
|
||||
op.push()
|
||||
operation = AddSceneNodeOperation(node, scene.getRoot())
|
||||
operation.push()
|
||||
|
||||
node.callDecoration("setActiveExtruder", default_extruder_id)
|
||||
scene.sceneChanged.emit(node)
|
||||
|
@ -1871,7 +1870,6 @@ class CuraApplication(QtApplication):
|
|||
main_window = QtApplication.getInstance().getMainWindow()
|
||||
if main_window:
|
||||
return main_window.width()
|
||||
else:
|
||||
return 0
|
||||
|
||||
@pyqtSlot(result = int)
|
||||
|
@ -1879,7 +1877,6 @@ class CuraApplication(QtApplication):
|
|||
main_window = QtApplication.getInstance().getMainWindow()
|
||||
if main_window:
|
||||
return main_window.height()
|
||||
else:
|
||||
return 0
|
||||
|
||||
@pyqtSlot()
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# Copyright (c) 2018 Ultimaker B.V.
|
||||
# Cura is released under the terms of the LGPLv3 or higher.
|
||||
|
||||
from typing import List, Tuple
|
||||
from typing import List, Tuple, TYPE_CHECKING, Optional
|
||||
|
||||
from cura.CuraApplication import CuraApplication #To find some resource types.
|
||||
from cura.Settings.GlobalStack import GlobalStack
|
||||
|
@ -9,12 +9,16 @@ from cura.Settings.GlobalStack import GlobalStack
|
|||
from UM.PackageManager import PackageManager #The class we're extending.
|
||||
from UM.Resources import Resources #To find storage paths for some resource types.
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from UM.Qt.QtApplication import QtApplication
|
||||
from PyQt5.QtCore import QObject
|
||||
|
||||
|
||||
class CuraPackageManager(PackageManager):
|
||||
def __init__(self, application, parent = None):
|
||||
def __init__(self, application: "QtApplication", parent: Optional["QObject"] = None) -> None:
|
||||
super().__init__(application, parent)
|
||||
|
||||
def initialize(self):
|
||||
def initialize(self) -> None:
|
||||
self._installation_dirs_dict["materials"] = Resources.getStoragePath(CuraApplication.ResourceTypes.MaterialInstanceContainer)
|
||||
self._installation_dirs_dict["qualities"] = Resources.getStoragePath(CuraApplication.ResourceTypes.QualityInstanceContainer)
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@ class CuraView(View):
|
|||
def mainComponent(self) -> QUrl:
|
||||
return self.getDisplayComponent("main")
|
||||
|
||||
|
||||
@pyqtProperty(QUrl, constant = True)
|
||||
def stageMenuComponent(self) -> QUrl:
|
||||
url = self.getDisplayComponent("menu")
|
||||
|
|
|
@ -33,10 +33,10 @@ class Layer:
|
|||
def elementCount(self):
|
||||
return self._element_count
|
||||
|
||||
def setHeight(self, height):
|
||||
def setHeight(self, height: float) -> None:
|
||||
self._height = height
|
||||
|
||||
def setThickness(self, thickness):
|
||||
def setThickness(self, thickness: float) -> None:
|
||||
self._thickness = thickness
|
||||
|
||||
def lineMeshVertexCount(self) -> int:
|
||||
|
|
|
@ -16,7 +16,6 @@ class LayerData(MeshData):
|
|||
def getLayer(self, layer):
|
||||
if layer in self._layers:
|
||||
return self._layers[layer]
|
||||
else:
|
||||
return None
|
||||
|
||||
def getLayers(self):
|
||||
|
|
|
@ -9,7 +9,7 @@ from cura.LayerData import LayerData
|
|||
|
||||
## Simple decorator to indicate a scene node holds layer data.
|
||||
class LayerDataDecorator(SceneNodeDecorator):
|
||||
def __init__(self):
|
||||
def __init__(self) -> None:
|
||||
super().__init__()
|
||||
self._layer_data = None # type: Optional[LayerData]
|
||||
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
# Copyright (c) 2019 Ultimaker B.V.
|
||||
# Cura is released under the terms of the LGPLv3 or higher.
|
||||
|
||||
from UM.Qt.QtApplication import QtApplication
|
||||
from typing import Any, Optional
|
||||
import numpy
|
||||
|
||||
from typing import Optional, cast
|
||||
|
||||
from UM.Qt.Bindings.Theme import Theme
|
||||
from UM.Qt.QtApplication import QtApplication
|
||||
from UM.Logger import Logger
|
||||
|
||||
|
||||
|
@ -61,7 +62,7 @@ class LayerPolygon:
|
|||
|
||||
# When type is used as index returns true if type == LayerPolygon.InfillType or type == LayerPolygon.SkinType or type == LayerPolygon.SupportInfillType
|
||||
# Should be generated in better way, not hardcoded.
|
||||
self._isInfillOrSkinTypeMap = numpy.array([0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0], dtype = numpy.bool)
|
||||
self._is_infill_or_skin_type_map = numpy.array([0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0], dtype = numpy.bool)
|
||||
|
||||
self._build_cache_line_mesh_mask = None # type: Optional[numpy.ndarray]
|
||||
self._build_cache_needed_points = None # type: Optional[numpy.ndarray]
|
||||
|
@ -149,17 +150,17 @@ class LayerPolygon:
|
|||
def getColors(self):
|
||||
return self._colors
|
||||
|
||||
def mapLineTypeToColor(self, line_types):
|
||||
def mapLineTypeToColor(self, line_types: numpy.ndarray) -> numpy.ndarray:
|
||||
return self._color_map[line_types]
|
||||
|
||||
def isInfillOrSkinType(self, line_types):
|
||||
return self._isInfillOrSkinTypeMap[line_types]
|
||||
def isInfillOrSkinType(self, line_types: numpy.ndarray) -> numpy.ndarray:
|
||||
return self._is_infill_or_skin_type_map[line_types]
|
||||
|
||||
def lineMeshVertexCount(self):
|
||||
return (self._vertex_end - self._vertex_begin)
|
||||
def lineMeshVertexCount(self) -> int:
|
||||
return self._vertex_end - self._vertex_begin
|
||||
|
||||
def lineMeshElementCount(self):
|
||||
return (self._index_end - self._index_begin)
|
||||
def lineMeshElementCount(self) -> int:
|
||||
return self._index_end - self._index_begin
|
||||
|
||||
@property
|
||||
def extruder(self):
|
||||
|
@ -202,7 +203,7 @@ class LayerPolygon:
|
|||
return self._jump_count
|
||||
|
||||
# Calculate normals for the entire polygon using numpy.
|
||||
def getNormals(self):
|
||||
def getNormals(self) -> numpy.ndarray:
|
||||
normals = numpy.copy(self._data)
|
||||
normals[:, 1] = 0.0 # We are only interested in 2D normals
|
||||
|
||||
|
@ -226,13 +227,13 @@ class LayerPolygon:
|
|||
|
||||
return normals
|
||||
|
||||
__color_map = None # type: numpy.ndarray[Any]
|
||||
__color_map = None # type: numpy.ndarray
|
||||
|
||||
## Gets the instance of the VersionUpgradeManager, or creates one.
|
||||
@classmethod
|
||||
def getColorMap(cls):
|
||||
def getColorMap(cls) -> numpy.ndarray:
|
||||
if cls.__color_map is None:
|
||||
theme = QtApplication.getInstance().getTheme()
|
||||
theme = cast(Theme, QtApplication.getInstance().getTheme())
|
||||
cls.__color_map = numpy.array([
|
||||
theme.getColor("layerview_none").getRgbF(), # NoneType
|
||||
theme.getColor("layerview_inset_0").getRgbF(), # Inset0Type
|
||||
|
|
|
@ -26,7 +26,7 @@ class ContainerNode:
|
|||
## Gets the metadata of the container that this node represents.
|
||||
# Getting the metadata from the container directly is about 10x as fast.
|
||||
# \return The metadata of the container in this node.
|
||||
def getMetadata(self):
|
||||
def getMetadata(self) -> Dict[str, Any]:
|
||||
return ContainerRegistry.getInstance().findContainersMetadata(id = self.container_id)[0]
|
||||
|
||||
## Get an entry from the metadata of the container that this node contains.
|
||||
|
|
|
@ -30,7 +30,7 @@ if TYPE_CHECKING:
|
|||
# nodes that have children) but that child node may be a node representing the
|
||||
# empty instance container.
|
||||
class ContainerTree:
|
||||
__instance = None
|
||||
__instance = None # type: Optional["ContainerTree"]
|
||||
|
||||
@classmethod
|
||||
def getInstance(cls):
|
||||
|
@ -75,7 +75,7 @@ class ContainerTree:
|
|||
return self.machines[global_stack.definition.getId()].getQualityChangesGroups(variant_names, material_bases, extruder_enabled)
|
||||
|
||||
## Ran after completely starting up the application.
|
||||
def _onStartupFinished(self):
|
||||
def _onStartupFinished(self) -> None:
|
||||
currently_added = ContainerRegistry.getInstance().findContainerStacks() # Find all currently added global stacks.
|
||||
JobQueue.getInstance().add(self._MachineNodeLoadJob(self, currently_added))
|
||||
|
||||
|
@ -137,7 +137,7 @@ class ContainerTree:
|
|||
# \param container_stacks All of the stacks to pre-load the container
|
||||
# trees for. This needs to be provided from here because the stacks
|
||||
# need to be constructed on the main thread because they are QObject.
|
||||
def __init__(self, tree_root: "ContainerTree", container_stacks: List["ContainerStack"]):
|
||||
def __init__(self, tree_root: "ContainerTree", container_stacks: List["ContainerStack"]) -> None:
|
||||
self.tree_root = tree_root
|
||||
self.container_stacks = container_stacks
|
||||
super().__init__()
|
||||
|
|
|
@ -6,13 +6,13 @@ import time
|
|||
from collections import deque
|
||||
|
||||
from PyQt5.QtCore import QObject, QTimer, pyqtSignal, pyqtProperty
|
||||
from typing import Optional, Any, Set
|
||||
|
||||
from UM.Application import Application
|
||||
from UM.Logger import Logger
|
||||
from UM.Settings.SettingDefinition import SettingDefinition
|
||||
from UM.Settings.Validator import ValidatorState
|
||||
|
||||
|
||||
import cura.CuraApplication
|
||||
#
|
||||
# This class performs setting error checks for the currently active machine.
|
||||
#
|
||||
|
@ -24,25 +24,25 @@ from UM.Settings.Validator import ValidatorState
|
|||
#
|
||||
class MachineErrorChecker(QObject):
|
||||
|
||||
def __init__(self, parent = None):
|
||||
def __init__(self, parent: Optional[QObject] = None) -> None:
|
||||
super().__init__(parent)
|
||||
|
||||
self._global_stack = None
|
||||
|
||||
self._has_errors = True # Result of the error check, indicating whether there are errors in the stack
|
||||
self._error_keys = set() # A set of settings keys that have errors
|
||||
self._error_keys_in_progress = set() # The variable that stores the results of the currently in progress check
|
||||
self._error_keys = set() # type: Set[str] # A set of settings keys that have errors
|
||||
self._error_keys_in_progress = set() # type: Set[str] # The variable that stores the results of the currently in progress check
|
||||
|
||||
self._stacks_and_keys_to_check = None # a FIFO queue of tuples (stack, key) to check for errors
|
||||
self._stacks_and_keys_to_check = None # type: Optional[deque] # a FIFO queue of tuples (stack, key) to check for errors
|
||||
|
||||
self._need_to_check = False # Whether we need to schedule a new check or not. This flag is set when a new
|
||||
# error check needs to take place while there is already one running at the moment.
|
||||
self._check_in_progress = False # Whether there is an error check running in progress at the moment.
|
||||
|
||||
self._application = Application.getInstance()
|
||||
self._application = cura.CuraApplication.CuraApplication.getInstance()
|
||||
self._machine_manager = self._application.getMachineManager()
|
||||
|
||||
self._start_time = 0 # measure checking time
|
||||
self._start_time = 0. # measure checking time
|
||||
|
||||
# This timer delays the starting of error check so we can react less frequently if the user is frequently
|
||||
# changing settings.
|
||||
|
@ -94,13 +94,13 @@ class MachineErrorChecker(QObject):
|
|||
|
||||
# Start the error check for property changed
|
||||
# this is seperate from the startErrorCheck because it ignores a number property types
|
||||
def startErrorCheckPropertyChanged(self, key, property_name):
|
||||
def startErrorCheckPropertyChanged(self, key: str, property_name: str) -> None:
|
||||
if property_name != "value":
|
||||
return
|
||||
self.startErrorCheck()
|
||||
|
||||
# Starts the error check timer to schedule a new error check.
|
||||
def startErrorCheck(self, *args) -> None:
|
||||
def startErrorCheck(self, *args: Any) -> None:
|
||||
if not self._check_in_progress:
|
||||
self._need_to_check = True
|
||||
self.needToWaitForResultChanged.emit()
|
||||
|
|
|
@ -176,9 +176,9 @@ class MachineNode(ContainerNode):
|
|||
|
||||
# Find the global qualities for this printer.
|
||||
global_qualities = container_registry.findInstanceContainersMetadata(type = "quality", definition = self.quality_definition, global_quality = "True") # First try specific to this printer.
|
||||
if len(global_qualities) == 0: # This printer doesn't override the global qualities.
|
||||
if not global_qualities: # This printer doesn't override the global qualities.
|
||||
global_qualities = container_registry.findInstanceContainersMetadata(type = "quality", definition = "fdmprinter", global_quality = "True") # Otherwise pick the global global qualities.
|
||||
if len(global_qualities) == 0: # There are no global qualities either?! Something went very wrong, but we'll not crash and properly fill the tree.
|
||||
if not global_qualities: # There are no global qualities either?! Something went very wrong, but we'll not crash and properly fill the tree.
|
||||
global_qualities = [cura.CuraApplication.CuraApplication.getInstance().empty_quality_container.getMetaData()]
|
||||
for global_quality in global_qualities:
|
||||
self.global_qualities[global_quality["quality_type"]] = QualityNode(global_quality["id"], parent = self)
|
||||
|
|
|
@ -14,6 +14,7 @@ if TYPE_CHECKING:
|
|||
from typing import Dict
|
||||
from cura.Machines.VariantNode import VariantNode
|
||||
|
||||
|
||||
## Represents a material in the container tree.
|
||||
#
|
||||
# Its subcontainers are quality profiles.
|
||||
|
|
|
@ -34,7 +34,7 @@ class MaterialBrandsModel(BaseMaterialsModel):
|
|||
brand_item_list = []
|
||||
brand_group_dict = {}
|
||||
|
||||
# Part 1: Generate the entire tree of brands -> material types -> spcific materials
|
||||
# Part 1: Generate the entire tree of brands -> material types -> specific materials
|
||||
for root_material_id, container_node in self._available_materials.items():
|
||||
# Do not include the materials from a to-be-removed package
|
||||
if bool(container_node.getMetaDataEntry("removed", False)):
|
||||
|
|
|
@ -51,7 +51,7 @@ class VariantNode(ContainerNode):
|
|||
# Find all the materials for this variant's name.
|
||||
else: # Printer has its own material profiles. Look for material profiles with this printer's definition.
|
||||
base_materials = container_registry.findInstanceContainersMetadata(type = "material", definition = "fdmprinter")
|
||||
printer_specific_materials = container_registry.findInstanceContainersMetadata(type = "material", definition = self.machine.container_id, variant_name = None)
|
||||
printer_specific_materials = container_registry.findInstanceContainersMetadata(type = "material", definition = self.machine.container_id)
|
||||
variant_specific_materials = container_registry.findInstanceContainersMetadata(type = "material", definition = self.machine.container_id, variant_name = self.variant_name) # If empty_variant, this won't return anything.
|
||||
materials_per_base_file = {material["base_file"]: material for material in base_materials}
|
||||
materials_per_base_file.update({material["base_file"]: material for material in printer_specific_materials}) # Printer-specific profiles override global ones.
|
||||
|
|
|
@ -47,7 +47,7 @@ class MultiplyObjectsJob(Job):
|
|||
nodes = []
|
||||
|
||||
not_fit_count = 0
|
||||
|
||||
found_solution_for_all = False
|
||||
for node in self._objects:
|
||||
# If object is part of a group, multiply group
|
||||
current_node = node
|
||||
|
@ -66,7 +66,7 @@ class MultiplyObjectsJob(Job):
|
|||
|
||||
found_solution_for_all = True
|
||||
arranger.resetLastPriority()
|
||||
for i in range(self._count):
|
||||
for _ in range(self._count):
|
||||
# We do place the nodes one by one, as we want to yield in between.
|
||||
new_node = copy.deepcopy(node)
|
||||
solution_found = False
|
||||
|
@ -98,10 +98,10 @@ class MultiplyObjectsJob(Job):
|
|||
Job.yieldThread()
|
||||
|
||||
if nodes:
|
||||
op = GroupedOperation()
|
||||
operation = GroupedOperation()
|
||||
for new_node in nodes:
|
||||
op.addOperation(AddSceneNodeOperation(new_node, current_node.getParent()))
|
||||
op.push()
|
||||
operation.addOperation(AddSceneNodeOperation(new_node, current_node.getParent()))
|
||||
operation.push()
|
||||
status_message.hide()
|
||||
|
||||
if not found_solution_for_all:
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
# Copyright (c) 2019 Ultimaker B.V.
|
||||
# Cura is released under the terms of the LGPLv3 or higher.
|
||||
from typing import Optional
|
||||
from typing import Optional, Dict, Any
|
||||
|
||||
|
||||
class BaseModel:
|
||||
def __init__(self, **kwargs):
|
||||
def __init__(self, **kwargs: Any) -> None:
|
||||
self.__dict__.update(kwargs)
|
||||
|
||||
|
||||
|
@ -53,9 +53,10 @@ class ResponseData(BaseModel):
|
|||
redirect_uri = None # type: Optional[str]
|
||||
content_type = "text/html" # type: str
|
||||
|
||||
|
||||
## Possible HTTP responses.
|
||||
HTTP_STATUS = {
|
||||
"OK": ResponseStatus(code = 200, message = "OK"),
|
||||
"NOT_FOUND": ResponseStatus(code = 404, message = "NOT FOUND"),
|
||||
"REDIRECT": ResponseStatus(code = 302, message = "REDIRECT")
|
||||
}
|
||||
} # type: Dict[str, ResponseStatus]
|
||||
|
|
|
@ -122,6 +122,6 @@ class _ObjectOrder:
|
|||
# \param order List of indices in which to print objects, ordered by printing
|
||||
# order.
|
||||
# \param todo: List of indices which are not yet inserted into the order list.
|
||||
def __init__(self, order: List[SceneNode], todo: List[SceneNode]):
|
||||
def __init__(self, order: List[SceneNode], todo: List[SceneNode]) -> None:
|
||||
self.order = order
|
||||
self.todo = todo
|
||||
|
|
|
@ -1,26 +1,27 @@
|
|||
# Copyright (c) 2015 Ultimaker B.V.
|
||||
# Cura is released under the terms of the LGPLv3 or higher.
|
||||
|
||||
from UM.Math.Vector import Vector
|
||||
from UM.Operations.Operation import Operation
|
||||
from UM.Operations.GroupedOperation import GroupedOperation
|
||||
from UM.Scene.SceneNode import SceneNode
|
||||
|
||||
|
||||
## A specialised operation designed specifically to modify the previous operation.
|
||||
class PlatformPhysicsOperation(Operation):
|
||||
def __init__(self, node, translation):
|
||||
def __init__(self, node: SceneNode, translation: Vector) -> None:
|
||||
super().__init__()
|
||||
self._node = node
|
||||
self._old_transformation = node.getLocalTransformation()
|
||||
self._translation = translation
|
||||
self._always_merge = True
|
||||
|
||||
def undo(self):
|
||||
def undo(self) -> None:
|
||||
self._node.setTransformation(self._old_transformation)
|
||||
|
||||
def redo(self):
|
||||
def redo(self) -> None:
|
||||
self._node.translate(self._translation, SceneNode.TransformSpace.World)
|
||||
|
||||
def mergeWith(self, other):
|
||||
def mergeWith(self, other: Operation) -> GroupedOperation:
|
||||
group = GroupedOperation()
|
||||
|
||||
group.addOperation(other)
|
||||
|
@ -28,5 +29,5 @@ class PlatformPhysicsOperation(Operation):
|
|||
|
||||
return group
|
||||
|
||||
def __repr__(self):
|
||||
def __repr__(self) -> str:
|
||||
return "PlatformPhysicsOp.(trans.={0})".format(self._translation)
|
||||
|
|
|
@ -6,9 +6,9 @@ from UM.Operations.Operation import Operation
|
|||
|
||||
from cura.Settings.SettingOverrideDecorator import SettingOverrideDecorator
|
||||
|
||||
|
||||
## Simple operation to set the buildplate number of a scenenode.
|
||||
class SetBuildPlateNumberOperation(Operation):
|
||||
|
||||
def __init__(self, node: SceneNode, build_plate_nr: int) -> None:
|
||||
super().__init__()
|
||||
self._node = node
|
||||
|
@ -16,11 +16,11 @@ class SetBuildPlateNumberOperation(Operation):
|
|||
self._previous_build_plate_nr = None
|
||||
self._decorator_added = False
|
||||
|
||||
def undo(self):
|
||||
def undo(self) -> None:
|
||||
if self._previous_build_plate_nr:
|
||||
self._node.callDecoration("setBuildPlateNumber", self._previous_build_plate_nr)
|
||||
|
||||
def redo(self):
|
||||
def redo(self) -> None:
|
||||
stack = self._node.callDecoration("getStack") #Don't try to get the active extruder since it may be None anyway.
|
||||
if not stack:
|
||||
self._node.addDecorator(SettingOverrideDecorator())
|
||||
|
|
|
@ -1,36 +1,37 @@
|
|||
# Copyright (c) 2016 Ultimaker B.V.
|
||||
# Uranium is released under the terms of the LGPLv3 or higher.
|
||||
from typing import Optional
|
||||
|
||||
from UM.Scene.SceneNode import SceneNode
|
||||
from UM.Operations import Operation
|
||||
|
||||
from UM.Math.Vector import Vector
|
||||
|
||||
## An operation that parents a scene node to another scene node.
|
||||
|
||||
## An operation that parents a scene node to another scene node.
|
||||
class SetParentOperation(Operation.Operation):
|
||||
## Initialises this SetParentOperation.
|
||||
#
|
||||
# \param node The node which will be reparented.
|
||||
# \param parent_node The node which will be the parent.
|
||||
def __init__(self, node, parent_node):
|
||||
def __init__(self, node: SceneNode, parent_node: Optional[SceneNode]) -> None:
|
||||
super().__init__()
|
||||
self._node = node
|
||||
self._parent = parent_node
|
||||
self._old_parent = node.getParent() # To restore the previous parent in case of an undo.
|
||||
|
||||
## Undoes the set-parent operation, restoring the old parent.
|
||||
def undo(self):
|
||||
def undo(self) -> None:
|
||||
self._set_parent(self._old_parent)
|
||||
|
||||
## Re-applies the set-parent operation.
|
||||
def redo(self):
|
||||
def redo(self) -> None:
|
||||
self._set_parent(self._parent)
|
||||
|
||||
## Sets the parent of the node while applying transformations to the world-transform of the node stays the same.
|
||||
#
|
||||
# \param new_parent The new parent. Note: this argument can be None, which would hide the node from the scene.
|
||||
def _set_parent(self, new_parent):
|
||||
def _set_parent(self, new_parent: Optional[SceneNode]) -> None:
|
||||
if new_parent:
|
||||
current_parent = self._node.getParent()
|
||||
if current_parent:
|
||||
|
@ -59,5 +60,5 @@ class SetParentOperation(Operation.Operation):
|
|||
## Returns a programmer-readable representation of this operation.
|
||||
#
|
||||
# \return A programmer-readable representation of this operation.
|
||||
def __repr__(self):
|
||||
def __repr__(self) -> str:
|
||||
return "SetParentOperation(node = {0}, parent_node={1})".format(self._node, self._parent)
|
||||
|
|
|
@ -17,9 +17,6 @@ from cura.Scene.CuraSceneNode import CuraSceneNode
|
|||
|
||||
if TYPE_CHECKING:
|
||||
from UM.View.GL.ShaderProgram import ShaderProgram
|
||||
|
||||
MYPY = False
|
||||
if MYPY:
|
||||
from UM.Scene.Camera import Camera
|
||||
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@ from PyQt5.QtQuick import QQuickImageProvider
|
|||
from PyQt5.QtCore import QSize
|
||||
|
||||
from UM.Application import Application
|
||||
from typing import Tuple
|
||||
|
||||
|
||||
class PrintJobPreviewImageProvider(QQuickImageProvider):
|
||||
|
@ -10,7 +11,7 @@ class PrintJobPreviewImageProvider(QQuickImageProvider):
|
|||
super().__init__(QQuickImageProvider.Image)
|
||||
|
||||
## Request a new image.
|
||||
def requestImage(self, id: str, size: QSize) -> QImage:
|
||||
def requestImage(self, id: str, size: QSize) -> Tuple[QImage, QSize]:
|
||||
# The id will have an uuid and an increment separated by a slash. As we don't care about the value of the
|
||||
# increment, we need to strip that first.
|
||||
uuid = id[id.find("/") + 1:]
|
||||
|
@ -22,6 +23,6 @@ class PrintJobPreviewImageProvider(QQuickImageProvider):
|
|||
if print_job.key == uuid:
|
||||
if print_job.getPreviewImage():
|
||||
return print_job.getPreviewImage(), QSize(15, 15)
|
||||
else:
|
||||
|
||||
return QImage(), QSize(15, 15)
|
||||
return QImage(), QSize(15, 15)
|
||||
return QImage(), QSize(15,15)
|
|
@ -161,7 +161,7 @@ class PrintJobOutputModel(QObject):
|
|||
self._time_elapsed = new_time_elapsed
|
||||
self.timeElapsedChanged.emit()
|
||||
|
||||
def updateState(self, new_state):
|
||||
def updateState(self, new_state: str) -> None:
|
||||
if self._state != new_state:
|
||||
self._state = new_state
|
||||
self.stateChanged.emit()
|
||||
|
|
|
@ -148,7 +148,7 @@ class PrinterOutputDevice(QObject, OutputDevice):
|
|||
|
||||
@pyqtProperty(QObject, notify = printersChanged)
|
||||
def activePrinter(self) -> Optional["PrinterOutputModel"]:
|
||||
if len(self._printers):
|
||||
if self._printers:
|
||||
return self._printers[0]
|
||||
return None
|
||||
|
||||
|
|
|
@ -10,3 +10,6 @@ class BlockSlicingDecorator(SceneNodeDecorator):
|
|||
|
||||
def isBlockSlicing(self) -> bool:
|
||||
return True
|
||||
|
||||
def __deepcopy__(self, memo):
|
||||
return BlockSlicingDecorator()
|
|
@ -17,8 +17,8 @@ class GCodeListDecorator(SceneNodeDecorator):
|
|||
def getGCodeList(self) -> List[str]:
|
||||
return self._gcode_list
|
||||
|
||||
def setGCodeList(self, list: List[str]) -> None:
|
||||
self._gcode_list = list
|
||||
def setGCodeList(self, gcode_list: List[str]) -> None:
|
||||
self._gcode_list = gcode_list
|
||||
|
||||
def __deepcopy__(self, memo) -> "GCodeListDecorator":
|
||||
copied_decorator = GCodeListDecorator()
|
||||
|
|
|
@ -15,7 +15,6 @@ from UM.Settings.ContainerRegistry import ContainerRegistry
|
|||
from UM.Settings.ContainerStack import ContainerStack
|
||||
from UM.Settings.InstanceContainer import InstanceContainer
|
||||
from UM.Settings.SettingInstance import SettingInstance
|
||||
from UM.Application import Application
|
||||
from UM.Logger import Logger
|
||||
from UM.Message import Message
|
||||
from UM.Platform import Platform
|
||||
|
@ -176,7 +175,7 @@ class CuraContainerRegistry(ContainerRegistry):
|
|||
if not file_name:
|
||||
return { "status": "error", "message": catalog.i18nc("@info:status Don't translate the XML tags <filename>!", "Failed to import profile from <filename>{0}</filename>: {1}", file_name, "Invalid path")}
|
||||
|
||||
global_stack = Application.getInstance().getGlobalContainerStack()
|
||||
global_stack = cura.CuraApplication.CuraApplication.getInstance().getGlobalContainerStack()
|
||||
if not global_stack:
|
||||
return {"status": "error", "message": catalog.i18nc("@info:status Don't translate the XML tags <filename>!", "Can't import profile from <filename>{0}</filename> before a printer is added.", file_name)}
|
||||
container_tree = ContainerTree.getInstance()
|
||||
|
@ -384,7 +383,7 @@ class CuraContainerRegistry(ContainerRegistry):
|
|||
if not quality_type:
|
||||
return catalog.i18nc("@info:status", "Profile is missing a quality type.")
|
||||
|
||||
global_stack = Application.getInstance().getGlobalContainerStack()
|
||||
global_stack = cura.CuraApplication.CuraApplication.getInstance().getGlobalContainerStack()
|
||||
if global_stack is None:
|
||||
return None
|
||||
definition_id = ContainerTree.getInstance().machines[global_stack.definition.getId()].quality_definition
|
||||
|
|
|
@ -43,7 +43,7 @@ class MachineActionManager(QObject):
|
|||
# Dict of all actions that need to be done when first added by definition ID
|
||||
self._first_start_actions = {} # type: Dict[str, List[MachineAction]]
|
||||
|
||||
def initialize(self):
|
||||
def initialize(self) -> None:
|
||||
# Add machine_action as plugin type
|
||||
PluginRegistry.addType("machine_action", self.addMachineAction)
|
||||
|
||||
|
|
|
@ -35,7 +35,7 @@ class GCodeStep():
|
|||
Class to store the current value of each G_Code parameter
|
||||
for any G-Code step
|
||||
"""
|
||||
def __init__(self, step, in_relative_movement: bool = False):
|
||||
def __init__(self, step, in_relative_movement: bool = False) -> None:
|
||||
self.step = step
|
||||
self.step_x = 0
|
||||
self.step_y = 0
|
||||
|
|
|
@ -11,7 +11,7 @@ if TYPE_CHECKING:
|
|||
|
||||
|
||||
class SimulationViewProxy(QObject):
|
||||
def __init__(self, simulation_view: "SimulationView", parent=None):
|
||||
def __init__(self, simulation_view: "SimulationView", parent=None) -> None:
|
||||
super().__init__(parent)
|
||||
self._simulation_view = simulation_view
|
||||
self._current_layer = 0
|
||||
|
|
|
@ -74,7 +74,7 @@ UM.Dialog{
|
|||
}
|
||||
Label
|
||||
{
|
||||
text: model.name
|
||||
text: model.display_name
|
||||
font: UM.Theme.getFont("medium_bold")
|
||||
anchors.left: packageIcon.right
|
||||
anchors.leftMargin: UM.Theme.getSize("default_margin").width
|
||||
|
@ -104,7 +104,7 @@ UM.Dialog{
|
|||
{
|
||||
width: parent.width
|
||||
property int lineHeight: 60
|
||||
visible: !model.is_compatible
|
||||
visible: !model.is_compatible && !model.is_dismissed
|
||||
height: visible ? (lineHeight + UM.Theme.getSize("default_margin").height) : 0 // We only show the incompatible packages here
|
||||
Image
|
||||
{
|
||||
|
@ -117,7 +117,7 @@ UM.Dialog{
|
|||
}
|
||||
Label
|
||||
{
|
||||
text: model.name
|
||||
text: model.display_name
|
||||
font: UM.Theme.getFont("medium_bold")
|
||||
anchors.left: packageIcon.right
|
||||
anchors.leftMargin: UM.Theme.getSize("default_margin").width
|
||||
|
@ -125,6 +125,26 @@ UM.Dialog{
|
|||
color: UM.Theme.getColor("text")
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
UM.TooltipArea
|
||||
{
|
||||
width: childrenRect.width;
|
||||
height: childrenRect.height;
|
||||
text: catalog.i18nc("@info:tooltip", "Dismisses the package and won't be shown in this dialog anymore")
|
||||
anchors.right: parent.right
|
||||
anchors.verticalCenter: packageIcon.verticalCenter
|
||||
Label
|
||||
{
|
||||
text: "(Dismiss)"
|
||||
font: UM.Theme.getFont("small")
|
||||
color: UM.Theme.getColor("text")
|
||||
MouseArea
|
||||
{
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
anchors.fill: parent
|
||||
onClicked: toolbox.dismissIncompatiblePackage(model.package_id)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
# Copyright (c) 2020 Ultimaker B.V.
|
||||
# Cura is released under the terms of the LGPLv3 or higher.
|
||||
|
||||
from PyQt5.QtCore import Qt, pyqtProperty
|
||||
from PyQt5.QtCore import Qt, pyqtProperty, pyqtSlot
|
||||
from UM.Qt.ListModel import ListModel
|
||||
from cura import ApplicationMetadata
|
||||
from UM.Logger import Logger
|
||||
from typing import List, Dict, Any
|
||||
|
||||
|
||||
class SubscribedPackagesModel(ListModel):
|
||||
|
@ -15,9 +17,11 @@ class SubscribedPackagesModel(ListModel):
|
|||
self._discrepancies = None
|
||||
self._sdk_version = ApplicationMetadata.CuraSDKVersion
|
||||
|
||||
self.addRoleName(Qt.UserRole + 1, "name")
|
||||
self.addRoleName(Qt.UserRole + 2, "icon_url")
|
||||
self.addRoleName(Qt.UserRole + 3, "is_compatible")
|
||||
self.addRoleName(Qt.UserRole + 1, "package_id")
|
||||
self.addRoleName(Qt.UserRole + 2, "display_name")
|
||||
self.addRoleName(Qt.UserRole + 3, "icon_url")
|
||||
self.addRoleName(Qt.UserRole + 4, "is_compatible")
|
||||
self.addRoleName(Qt.UserRole + 5, "is_dismissed")
|
||||
|
||||
@pyqtProperty(bool, constant=True)
|
||||
def hasCompatiblePackages(self) -> bool:
|
||||
|
@ -33,29 +37,36 @@ class SubscribedPackagesModel(ListModel):
|
|||
return True
|
||||
return False
|
||||
|
||||
def setMetadata(self, data):
|
||||
if self._metadata != data:
|
||||
# Sets the "is_compatible" to True for the given package, in memory
|
||||
|
||||
@pyqtSlot()
|
||||
def dismissPackage(self, package_id: str) -> None:
|
||||
package = self.find(key="package_id", value=package_id)
|
||||
if package != -1:
|
||||
self.setProperty(package, property="is_dismissed", value=True)
|
||||
Logger.debug("Package {} has been dismissed".format(package_id))
|
||||
|
||||
def setMetadata(self, data: List[Dict[str, List[Any]]]) -> None:
|
||||
self._metadata = data
|
||||
|
||||
def addValue(self, discrepancy):
|
||||
if self._discrepancies != discrepancy:
|
||||
def addDiscrepancies(self, discrepancy: List[str]) -> None:
|
||||
self._discrepancies = discrepancy
|
||||
|
||||
def getCompatiblePackages(self):
|
||||
return [x for x in self._items if x["is_compatible"]]
|
||||
|
||||
def update(self):
|
||||
def initialize(self) -> None:
|
||||
self._items.clear()
|
||||
|
||||
for item in self._metadata:
|
||||
if item["package_id"] not in self._discrepancies:
|
||||
continue
|
||||
package = {
|
||||
"package_id": item["package_id"],
|
||||
"name": item["display_name"],
|
||||
"display_name": item["display_name"],
|
||||
"sdk_versions": item["sdk_versions"],
|
||||
"download_url": item["download_url"],
|
||||
"md5_hash": item["md5_hash"],
|
||||
"is_dismissed": False,
|
||||
}
|
||||
if self._sdk_version not in item["sdk_versions"]:
|
||||
package.update({"is_compatible": False})
|
||||
|
@ -65,7 +76,6 @@ class SubscribedPackagesModel(ListModel):
|
|||
package.update({"icon_url": item["icon_url"]})
|
||||
except KeyError: # There is no 'icon_url" in the response payload for this package
|
||||
package.update({"icon_url": ""})
|
||||
|
||||
self._items.append(package)
|
||||
self.setItems(self._items)
|
||||
|
||||
|
|
|
@ -528,6 +528,11 @@ class Toolbox(QObject, Extension):
|
|||
populated += 1
|
||||
return populated == len(self._server_response_data.items())
|
||||
|
||||
@pyqtSlot(str)
|
||||
def dismissIncompatiblePackage(self, package_id: str):
|
||||
self._models["subscribed_packages"].dismissPackage(package_id) # sets "is_compatible" to True, in-memory
|
||||
self._package_manager.dismissPackage(package_id) # adds this package_id as dismissed in the user config file
|
||||
|
||||
# Make API Calls
|
||||
# --------------------------------------------------------------------------
|
||||
def _makeRequestByType(self, request_type: str) -> None:
|
||||
|
|
|
@ -14,7 +14,7 @@ class ClusterPrinterMaterialStationSlot(ClusterPrintCoreConfiguration):
|
|||
# \param material_remaining: How much material is remaining on the spool (between 0 and 1, or -1 for missing data).
|
||||
# \param material_empty: Whether the material spool is too empty to be used.
|
||||
def __init__(self, slot_index: int, compatible: bool, material_remaining: float,
|
||||
material_empty: Optional[bool] = False, **kwargs):
|
||||
material_empty: Optional[bool] = False, **kwargs) -> None:
|
||||
self.slot_index = slot_index
|
||||
self.compatible = compatible
|
||||
self.material_remaining = material_remaining
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2019 Ultimaker B.V.
|
||||
// Copyright (c) 2020 Ultimaker B.V.
|
||||
// Cura is released under the terms of the LGPLv3 or higher.
|
||||
|
||||
import QtQuick 2.7
|
||||
|
@ -21,7 +21,16 @@ UM.MainWindow
|
|||
id: base
|
||||
|
||||
// Cura application window title
|
||||
title: PrintInformation.jobName + " - " + catalog.i18nc("@title:window", CuraApplication.applicationDisplayName)
|
||||
title:
|
||||
{
|
||||
let result = "";
|
||||
if(PrintInformation.jobName != "")
|
||||
{
|
||||
result += PrintInformation.jobName + " - ";
|
||||
}
|
||||
result += CuraApplication.applicationDisplayName;
|
||||
return result;
|
||||
}
|
||||
|
||||
backgroundColor: UM.Theme.getColor("viewport_background")
|
||||
|
||||
|
@ -244,23 +253,6 @@ UM.MainWindow
|
|||
}
|
||||
}
|
||||
|
||||
Toolbar
|
||||
{
|
||||
// The toolbar is the left bar that is populated by all the tools (which are dynamicly populated by
|
||||
// plugins)
|
||||
id: toolbar
|
||||
|
||||
property int mouseX: base.mouseX
|
||||
property int mouseY: base.mouseY
|
||||
|
||||
anchors
|
||||
{
|
||||
verticalCenter: parent.verticalCenter
|
||||
left: parent.left
|
||||
}
|
||||
visible: CuraApplication.platformActivity && !PrintInformation.preSliced
|
||||
}
|
||||
|
||||
ObjectSelector
|
||||
{
|
||||
id: objectSelector
|
||||
|
@ -302,6 +294,23 @@ UM.MainWindow
|
|||
}
|
||||
}
|
||||
|
||||
Toolbar
|
||||
{
|
||||
// The toolbar is the left bar that is populated by all the tools (which are dynamicly populated by
|
||||
// plugins)
|
||||
id: toolbar
|
||||
|
||||
property int mouseX: base.mouseX
|
||||
property int mouseY: base.mouseY
|
||||
|
||||
anchors
|
||||
{
|
||||
verticalCenter: parent.verticalCenter
|
||||
left: parent.left
|
||||
}
|
||||
visible: CuraApplication.platformActivity && !PrintInformation.preSliced
|
||||
}
|
||||
|
||||
// A hint for the loaded content view. Overlay items / controls can safely be placed in this area
|
||||
Item {
|
||||
id: mainSafeArea
|
||||
|
|
5
test-in-docker.sh
Executable file
5
test-in-docker.sh
Executable file
|
@ -0,0 +1,5 @@
|
|||
sudo rm -rf ./build ./Uranium
|
||||
sudo docker run -it --rm \
|
||||
-v "$(pwd):/srv/cura" ultimaker/cura-build-environment \
|
||||
/srv/cura/docker/build.sh
|
||||
sudo rm -rf ./build ./Uranium
|
Loading…
Add table
Add a link
Reference in a new issue