|
@@ -1,9 +1,19 @@
|
|
|
# Copyright (c) 2018 Ultimaker B.V.
|
|
|
# Cura is released under the terms of the LGPLv3 or higher.
|
|
|
|
|
|
-from PyQt5.QtCore import QObject, QTimer
|
|
|
+import copy
|
|
|
+import json
|
|
|
+import os
|
|
|
+import sys
|
|
|
+import time
|
|
|
+
|
|
|
+import numpy
|
|
|
+
|
|
|
+from PyQt5.QtCore import QObject, QTimer, QUrl, pyqtSignal, pyqtProperty, QEvent, Q_ENUMS
|
|
|
from PyQt5.QtNetwork import QLocalServer
|
|
|
-from PyQt5.QtNetwork import QLocalSocket
|
|
|
+from PyQt5.QtGui import QColor, QIcon
|
|
|
+from PyQt5.QtWidgets import QMessageBox
|
|
|
+from PyQt5.QtQml import qmlRegisterUncreatableType, qmlRegisterSingletonType, qmlRegisterType
|
|
|
|
|
|
from UM.Qt.QtApplication import QtApplication
|
|
|
from UM.Scene.SceneNode import SceneNode
|
|
@@ -74,6 +84,7 @@ from cura.Settings.SimpleModeSettingsManager import SimpleModeSettingsManager
|
|
|
|
|
|
from cura.Machines.VariantManager import VariantManager
|
|
|
|
|
|
+from .SingleInstance import SingleInstance
|
|
|
from . import PlatformPhysics
|
|
|
from . import BuildVolume
|
|
|
from . import CameraAnimation
|
|
@@ -93,22 +104,10 @@ from cura.Settings.ContainerManager import ContainerManager
|
|
|
|
|
|
from cura.ObjectsModel import ObjectsModel
|
|
|
|
|
|
-from PyQt5.QtCore import QUrl, pyqtSignal, pyqtProperty, QEvent, Q_ENUMS
|
|
|
from UM.FlameProfiler import pyqtSlot
|
|
|
-from PyQt5.QtGui import QColor, QIcon
|
|
|
-from PyQt5.QtWidgets import QMessageBox
|
|
|
-from PyQt5.QtQml import qmlRegisterUncreatableType, qmlRegisterSingletonType, qmlRegisterType
|
|
|
-
|
|
|
-import sys
|
|
|
-import numpy
|
|
|
-import copy
|
|
|
-import os
|
|
|
-import argparse
|
|
|
-import json
|
|
|
-import time
|
|
|
|
|
|
|
|
|
-numpy.seterr(all="ignore")
|
|
|
+numpy.seterr(all = "ignore")
|
|
|
|
|
|
MYPY = False
|
|
|
if not MYPY:
|
|
@@ -143,19 +142,164 @@ class CuraApplication(QtApplication):
|
|
|
|
|
|
Q_ENUMS(ResourceTypes)
|
|
|
|
|
|
- def __init__(self, **kwargs):
|
|
|
+ def __init__(self, *args, **kwargs):
|
|
|
+ super().__init__(name = "cura",
|
|
|
+ version = CuraVersion,
|
|
|
+ buildtype = CuraBuildType,
|
|
|
+ is_debug_mode = CuraDebugMode,
|
|
|
+ tray_icon_name = "cura-icon-32.png",
|
|
|
+ **kwargs)
|
|
|
+
|
|
|
+ self.default_theme = "cura-light"
|
|
|
+
|
|
|
self._boot_loading_time = time.time()
|
|
|
+
|
|
|
+ self._currently_loading_files = []
|
|
|
+ self._non_sliceable_extensions = []
|
|
|
+
|
|
|
+ # Variables set from CLI
|
|
|
+ self._files_to_open = []
|
|
|
+ self._use_single_instance = False
|
|
|
+ self._trigger_early_crash = False # For debug only
|
|
|
+
|
|
|
+ self._single_instance = None
|
|
|
+
|
|
|
+ self._cura_package_manager = None
|
|
|
+
|
|
|
+ self._machine_action_manager = None
|
|
|
+
|
|
|
+ self.empty_container = None
|
|
|
+ self.empty_definition_changes_container = None
|
|
|
+ self.empty_variant_container = None
|
|
|
+ self.empty_material_container = None
|
|
|
+ self.empty_quality_container = None
|
|
|
+ self.empty_quality_changes_container = None
|
|
|
+
|
|
|
+ self._variant_manager = None
|
|
|
+ self._material_manager = None
|
|
|
+ self._quality_manager = None
|
|
|
+ self._machine_manager = None
|
|
|
+ self._extruder_manager = None
|
|
|
+ self._container_manager = None
|
|
|
+
|
|
|
+ self._object_manager = None
|
|
|
+ self._build_plate_model = None
|
|
|
+ self._multi_build_plate_model = None
|
|
|
+ self._setting_visibility_presets_model = None
|
|
|
+ self._setting_inheritance_manager = None
|
|
|
+ self._simple_mode_settings_manager = None
|
|
|
+ self._cura_scene_controller = None
|
|
|
+ self._machine_error_checker = None
|
|
|
+
|
|
|
+ self._quality_profile_drop_down_menu_model = None
|
|
|
+ self._custom_quality_profile_drop_down_menu_model = None
|
|
|
+
|
|
|
+ self._physics = None
|
|
|
+ self._volume = None
|
|
|
+ self._output_devices = {}
|
|
|
+ self._print_information = None
|
|
|
+ self._previous_active_tool = None
|
|
|
+ self._platform_activity = False
|
|
|
+ self._scene_bounding_box = AxisAlignedBox.Null
|
|
|
+
|
|
|
+ self._job_name = None
|
|
|
+ self._center_after_select = False
|
|
|
+ self._camera_animation = None
|
|
|
+ self._cura_actions = None
|
|
|
+ self.started = False
|
|
|
+
|
|
|
+ self._message_box_callback = None
|
|
|
+ self._message_box_callback_arguments = []
|
|
|
+ self._preferred_mimetype = ""
|
|
|
+ self._i18n_catalog = None
|
|
|
+
|
|
|
+ self._currently_loading_files = []
|
|
|
+ self._non_sliceable_extensions = []
|
|
|
+ self._additional_components = {} # Components to add to certain areas in the interface
|
|
|
+
|
|
|
+ self._open_file_queue = [] # A list of files to open (after the application has started)
|
|
|
+
|
|
|
+ self._update_platform_activity_timer = None
|
|
|
+
|
|
|
+ self._need_to_show_user_agreement = True
|
|
|
+
|
|
|
+ from cura.Settings.CuraContainerRegistry import CuraContainerRegistry
|
|
|
+ self._container_registry_class = CuraContainerRegistry
|
|
|
+
|
|
|
+ # Adds command line options to the command line parser. This should be called after the application is created and
|
|
|
+ # before the pre-start.
|
|
|
+ def addCommandLineOptions(self):
|
|
|
+ super().addCommandLineOptions()
|
|
|
+ self._cli_parser.add_argument("--help", "-h",
|
|
|
+ action = "store_true",
|
|
|
+ default = False,
|
|
|
+ help = "Show this help message and exit.")
|
|
|
+ self._cli_parser.add_argument("--single-instance",
|
|
|
+ dest = "single_instance",
|
|
|
+ action = "store_true",
|
|
|
+ default = False)
|
|
|
+ # >> For debugging
|
|
|
+ # Trigger an early crash, i.e. a crash that happens before the application enters its event loop.
|
|
|
+ self._cli_parser.add_argument("--trigger-early-crash",
|
|
|
+ dest = "trigger_early_crash",
|
|
|
+ action = "store_true",
|
|
|
+ default = False,
|
|
|
+ help = "FOR TESTING ONLY. Trigger an early crash to show the crash dialog.")
|
|
|
+ self._cli_parser.add_argument("file", nargs = "*", help = "Files to load after starting the application.")
|
|
|
+
|
|
|
+ def parseCliOptions(self):
|
|
|
+ super().parseCliOptions()
|
|
|
+
|
|
|
+ if self._cli_args.help:
|
|
|
+ self._cli_parser.print_help()
|
|
|
+ sys.exit(0)
|
|
|
+
|
|
|
+ self._use_single_instance = self._cli_args.single_instance
|
|
|
+ self._trigger_early_crash = self._cli_args.trigger_early_crash
|
|
|
+ for filename in self._cli_args.file:
|
|
|
+ self._files_to_open.append(os.path.abspath(filename))
|
|
|
+
|
|
|
+ def initialize(self) -> None:
|
|
|
+ super().initialize()
|
|
|
+
|
|
|
+ # Initialize the package manager to remove and install scheduled packages.
|
|
|
+ from cura.CuraPackageManager import CuraPackageManager
|
|
|
+ self._cura_package_manager = CuraPackageManager(self)
|
|
|
+ self._cura_package_manager.initialize()
|
|
|
+
|
|
|
+ self.__sendCommandToSingleInstance()
|
|
|
+ self.__addExpectedResourceDirsAndSearchPaths()
|
|
|
+ self.__initializeSettingDefinitionsAndFunctions()
|
|
|
+ self.__addAllResourcesAndContainerResources()
|
|
|
+ self.__addAllEmptyContainers()
|
|
|
+ self.__setLatestResouceVersionsForVersionUpgrade()
|
|
|
+
|
|
|
+ self._machine_action_manager = MachineActionManager.MachineActionManager(self)
|
|
|
+ self._machine_action_manager.initialize()
|
|
|
+
|
|
|
+ def __sendCommandToSingleInstance(self):
|
|
|
+ self._single_instance = SingleInstance(self, self._files_to_open)
|
|
|
+
|
|
|
+ # If we use single instance, try to connect to the single instance server, send commands, and then exit.
|
|
|
+ # If we cannot find an existing single instance server, this is the only instance, so just keep going.
|
|
|
+ if self._use_single_instance:
|
|
|
+ if self._single_instance.startClient():
|
|
|
+ Logger.log("i", "Single instance commands were sent, exiting")
|
|
|
+ sys.exit(0)
|
|
|
+
|
|
|
+ # Adds expected directory names and search paths for Resources.
|
|
|
+ def __addExpectedResourceDirsAndSearchPaths(self):
|
|
|
# this list of dir names will be used by UM to detect an old cura directory
|
|
|
for dir_name in ["extruders", "machine_instances", "materials", "plugins", "quality", "quality_changes", "user", "variants"]:
|
|
|
Resources.addExpectedDirNameInData(dir_name)
|
|
|
|
|
|
- Resources.addSearchPath(os.path.join(QtApplication.getInstallPrefix(), "share", "cura", "resources"))
|
|
|
+ Resources.addSearchPath(os.path.join(self._app_install_dir, "share", "cura", "resources"))
|
|
|
if not hasattr(sys, "frozen"):
|
|
|
Resources.addSearchPath(os.path.join(os.path.abspath(os.path.dirname(__file__)), "..", "resources"))
|
|
|
|
|
|
- self._use_gui = True
|
|
|
- self._open_file_queue = [] # Files to open when plug-ins are loaded.
|
|
|
-
|
|
|
+ # Adds custom property types, settings types, and extra operators (functions) that need to be registered in
|
|
|
+ # SettingDefinition and SettingFunction.
|
|
|
+ def __initializeSettingDefinitionsAndFunctions(self):
|
|
|
# Need to do this before ContainerRegistry tries to load the machines
|
|
|
SettingDefinition.addSupportedProperty("settable_per_mesh", DefinitionPropertyType.Any, default = True, read_only = True)
|
|
|
SettingDefinition.addSupportedProperty("settable_per_extruder", DefinitionPropertyType.Any, default = True, read_only = True)
|
|
@@ -180,7 +324,8 @@ class CuraApplication(QtApplication):
|
|
|
SettingFunction.registerOperator("extruderValue", ExtruderManager.getExtruderValue)
|
|
|
SettingFunction.registerOperator("resolveOrValue", ExtruderManager.getResolveOrValue)
|
|
|
|
|
|
- ## Add the 4 types of profiles to storage.
|
|
|
+ # Adds all resources and container related resources.
|
|
|
+ def __addAllResourcesAndContainerResources(self) -> None:
|
|
|
Resources.addStorageType(self.ResourceTypes.QualityInstanceContainer, "quality")
|
|
|
Resources.addStorageType(self.ResourceTypes.QualityChangesInstanceContainer, "quality_changes")
|
|
|
Resources.addStorageType(self.ResourceTypes.VariantInstanceContainer, "variants")
|
|
@@ -191,20 +336,64 @@ class CuraApplication(QtApplication):
|
|
|
Resources.addStorageType(self.ResourceTypes.DefinitionChangesContainer, "definition_changes")
|
|
|
Resources.addStorageType(self.ResourceTypes.SettingVisibilityPreset, "setting_visibility")
|
|
|
|
|
|
- ContainerRegistry.getInstance().addResourceType(self.ResourceTypes.QualityInstanceContainer, "quality")
|
|
|
- ContainerRegistry.getInstance().addResourceType(self.ResourceTypes.QualityChangesInstanceContainer, "quality_changes")
|
|
|
- ContainerRegistry.getInstance().addResourceType(self.ResourceTypes.VariantInstanceContainer, "variant")
|
|
|
- ContainerRegistry.getInstance().addResourceType(self.ResourceTypes.MaterialInstanceContainer, "material")
|
|
|
- ContainerRegistry.getInstance().addResourceType(self.ResourceTypes.UserInstanceContainer, "user")
|
|
|
- ContainerRegistry.getInstance().addResourceType(self.ResourceTypes.ExtruderStack, "extruder_train")
|
|
|
- ContainerRegistry.getInstance().addResourceType(self.ResourceTypes.MachineStack, "machine")
|
|
|
- ContainerRegistry.getInstance().addResourceType(self.ResourceTypes.DefinitionChangesContainer, "definition_changes")
|
|
|
+ self._container_registry.addResourceType(self.ResourceTypes.QualityInstanceContainer, "quality")
|
|
|
+ self._container_registry.addResourceType(self.ResourceTypes.QualityChangesInstanceContainer, "quality_changes")
|
|
|
+ self._container_registry.addResourceType(self.ResourceTypes.VariantInstanceContainer, "variant")
|
|
|
+ self._container_registry.addResourceType(self.ResourceTypes.MaterialInstanceContainer, "material")
|
|
|
+ self._container_registry.addResourceType(self.ResourceTypes.UserInstanceContainer, "user")
|
|
|
+ self._container_registry.addResourceType(self.ResourceTypes.ExtruderStack, "extruder_train")
|
|
|
+ self._container_registry.addResourceType(self.ResourceTypes.MachineStack, "machine")
|
|
|
+ self._container_registry.addResourceType(self.ResourceTypes.DefinitionChangesContainer, "definition_changes")
|
|
|
+
|
|
|
+ Resources.addType(self.ResourceTypes.QmlFiles, "qml")
|
|
|
+ Resources.addType(self.ResourceTypes.Firmware, "firmware")
|
|
|
+
|
|
|
+ # Adds all empty containers.
|
|
|
+ def __addAllEmptyContainers(self) -> None:
|
|
|
+ # Add empty variant, material and quality containers.
|
|
|
+ # Since they are empty, they should never be serialized and instead just programmatically created.
|
|
|
+ # We need them to simplify the switching between materials.
|
|
|
+ empty_container = self._container_registry.getEmptyInstanceContainer()
|
|
|
+ self.empty_container = empty_container
|
|
|
+
|
|
|
+ empty_definition_changes_container = copy.deepcopy(empty_container)
|
|
|
+ empty_definition_changes_container.setMetaDataEntry("id", "empty_definition_changes")
|
|
|
+ empty_definition_changes_container.addMetaDataEntry("type", "definition_changes")
|
|
|
+ self._container_registry.addContainer(empty_definition_changes_container)
|
|
|
+ self.empty_definition_changes_container = empty_definition_changes_container
|
|
|
+
|
|
|
+ empty_variant_container = copy.deepcopy(empty_container)
|
|
|
+ empty_variant_container.setMetaDataEntry("id", "empty_variant")
|
|
|
+ empty_variant_container.addMetaDataEntry("type", "variant")
|
|
|
+ self._container_registry.addContainer(empty_variant_container)
|
|
|
+ self.empty_variant_container = empty_variant_container
|
|
|
+
|
|
|
+ empty_material_container = copy.deepcopy(empty_container)
|
|
|
+ empty_material_container.setMetaDataEntry("id", "empty_material")
|
|
|
+ empty_material_container.addMetaDataEntry("type", "material")
|
|
|
+ self._container_registry.addContainer(empty_material_container)
|
|
|
+ self.empty_material_container = empty_material_container
|
|
|
+
|
|
|
+ empty_quality_container = copy.deepcopy(empty_container)
|
|
|
+ empty_quality_container.setMetaDataEntry("id", "empty_quality")
|
|
|
+ empty_quality_container.setName("Not Supported")
|
|
|
+ empty_quality_container.addMetaDataEntry("quality_type", "not_supported")
|
|
|
+ empty_quality_container.addMetaDataEntry("type", "quality")
|
|
|
+ empty_quality_container.addMetaDataEntry("supported", False)
|
|
|
+ self._container_registry.addContainer(empty_quality_container)
|
|
|
+ self.empty_quality_container = empty_quality_container
|
|
|
|
|
|
- ## Initialise the version upgrade manager with Cura's storage paths.
|
|
|
- # Needs to be here to prevent circular dependencies.
|
|
|
- import UM.VersionUpgradeManager
|
|
|
+ empty_quality_changes_container = copy.deepcopy(empty_container)
|
|
|
+ empty_quality_changes_container.setMetaDataEntry("id", "empty_quality_changes")
|
|
|
+ empty_quality_changes_container.addMetaDataEntry("type", "quality_changes")
|
|
|
+ empty_quality_changes_container.addMetaDataEntry("quality_type", "not_supported")
|
|
|
+ self._container_registry.addContainer(empty_quality_changes_container)
|
|
|
+ self.empty_quality_changes_container = empty_quality_changes_container
|
|
|
|
|
|
- UM.VersionUpgradeManager.VersionUpgradeManager.getInstance().setCurrentVersions(
|
|
|
+ # Initializes the version upgrade manager with by providing the paths for each resource type and the latest
|
|
|
+ # versions.
|
|
|
+ def __setLatestResouceVersionsForVersionUpgrade(self):
|
|
|
+ self._version_upgrade_manager.setCurrentVersions(
|
|
|
{
|
|
|
("quality_changes", InstanceContainer.Version * 1000000 + self.SettingVersion): (self.ResourceTypes.QualityChangesInstanceContainer, "application/x-uranium-instancecontainer"),
|
|
|
("machine_stack", ContainerStack.Version * 1000000 + self.SettingVersion): (self.ResourceTypes.MachineStack, "application/x-cura-globalstack"),
|
|
@@ -216,46 +405,9 @@ class CuraApplication(QtApplication):
|
|
|
}
|
|
|
)
|
|
|
|
|
|
- self._currently_loading_files = []
|
|
|
- self._non_sliceable_extensions = []
|
|
|
-
|
|
|
- self._machine_action_manager = MachineActionManager.MachineActionManager()
|
|
|
- self._machine_manager = None # This is initialized on demand.
|
|
|
- self._extruder_manager = None
|
|
|
- self._material_manager = None
|
|
|
- self._quality_manager = None
|
|
|
- self._object_manager = None
|
|
|
- self._build_plate_model = None
|
|
|
- self._multi_build_plate_model = None
|
|
|
- self._setting_visibility_presets_model = None
|
|
|
- self._setting_inheritance_manager = None
|
|
|
- self._simple_mode_settings_manager = None
|
|
|
- self._cura_scene_controller = None
|
|
|
- self._machine_error_checker = None
|
|
|
-
|
|
|
- self._additional_components = {} # Components to add to certain areas in the interface
|
|
|
-
|
|
|
- super().__init__(name = "cura",
|
|
|
- version = CuraVersion,
|
|
|
- buildtype = CuraBuildType,
|
|
|
- is_debug_mode = CuraDebugMode,
|
|
|
- tray_icon_name = "cura-icon-32.png",
|
|
|
- **kwargs)
|
|
|
-
|
|
|
- # Initialize the package manager to remove and install scheduled packages.
|
|
|
- from cura.CuraPackageManager import CuraPackageManager
|
|
|
- self._cura_package_manager = CuraPackageManager(self)
|
|
|
- self._cura_package_manager.initialize()
|
|
|
-
|
|
|
- self.initialize()
|
|
|
-
|
|
|
- # FOR TESTING ONLY
|
|
|
- if kwargs["parsed_command_line"].get("trigger_early_crash", False):
|
|
|
- assert not "This crash is triggered by the trigger_early_crash command line argument."
|
|
|
-
|
|
|
- self._variant_manager = None
|
|
|
-
|
|
|
- self.default_theme = "cura-light"
|
|
|
+ # Runs preparations that needs to be done before the starting process.
|
|
|
+ def startSlashWindowPhase(self):
|
|
|
+ super().startSlashWindowPhase()
|
|
|
|
|
|
self.setWindowIcon(QIcon(Resources.getPath(Resources.Images, "cura-icon.png")))
|
|
|
|
|
@@ -289,23 +441,6 @@ class CuraApplication(QtApplication):
|
|
|
"SelectionTool",
|
|
|
"TranslateTool"
|
|
|
])
|
|
|
- self._physics = None
|
|
|
- self._volume = None
|
|
|
- self._output_devices = {}
|
|
|
- self._print_information = None
|
|
|
- self._previous_active_tool = None
|
|
|
- self._platform_activity = False
|
|
|
- self._scene_bounding_box = AxisAlignedBox.Null
|
|
|
-
|
|
|
- self._job_name = None
|
|
|
- self._center_after_select = False
|
|
|
- self._camera_animation = None
|
|
|
- self._cura_actions = None
|
|
|
- self.started = False
|
|
|
-
|
|
|
- self._message_box_callback = None
|
|
|
- self._message_box_callback_arguments = []
|
|
|
- self._preferred_mimetype = ""
|
|
|
self._i18n_catalog = i18nCatalog("cura")
|
|
|
|
|
|
self._update_platform_activity_timer = QTimer()
|
|
@@ -318,53 +453,10 @@ class CuraApplication(QtApplication):
|
|
|
self.getController().contextMenuRequested.connect(self._onContextMenuRequested)
|
|
|
self.getCuraSceneController().activeBuildPlateChanged.connect(self.updatePlatformActivityDelayed)
|
|
|
|
|
|
- Resources.addType(self.ResourceTypes.QmlFiles, "qml")
|
|
|
- Resources.addType(self.ResourceTypes.Firmware, "firmware")
|
|
|
-
|
|
|
self.showSplashMessage(self._i18n_catalog.i18nc("@info:progress", "Loading machines..."))
|
|
|
|
|
|
- # Add empty variant, material and quality containers.
|
|
|
- # Since they are empty, they should never be serialized and instead just programmatically created.
|
|
|
- # We need them to simplify the switching between materials.
|
|
|
- empty_container = ContainerRegistry.getInstance().getEmptyInstanceContainer()
|
|
|
- self.empty_container = empty_container
|
|
|
-
|
|
|
- empty_definition_changes_container = copy.deepcopy(empty_container)
|
|
|
- empty_definition_changes_container.setMetaDataEntry("id", "empty_definition_changes")
|
|
|
- empty_definition_changes_container.addMetaDataEntry("type", "definition_changes")
|
|
|
- ContainerRegistry.getInstance().addContainer(empty_definition_changes_container)
|
|
|
- self.empty_definition_changes_container = empty_definition_changes_container
|
|
|
-
|
|
|
- empty_variant_container = copy.deepcopy(empty_container)
|
|
|
- empty_variant_container.setMetaDataEntry("id", "empty_variant")
|
|
|
- empty_variant_container.addMetaDataEntry("type", "variant")
|
|
|
- ContainerRegistry.getInstance().addContainer(empty_variant_container)
|
|
|
- self.empty_variant_container = empty_variant_container
|
|
|
-
|
|
|
- empty_material_container = copy.deepcopy(empty_container)
|
|
|
- empty_material_container.setMetaDataEntry("id", "empty_material")
|
|
|
- empty_material_container.addMetaDataEntry("type", "material")
|
|
|
- ContainerRegistry.getInstance().addContainer(empty_material_container)
|
|
|
- self.empty_material_container = empty_material_container
|
|
|
-
|
|
|
- empty_quality_container = copy.deepcopy(empty_container)
|
|
|
- empty_quality_container.setMetaDataEntry("id", "empty_quality")
|
|
|
- empty_quality_container.setName("Not Supported")
|
|
|
- empty_quality_container.addMetaDataEntry("quality_type", "not_supported")
|
|
|
- empty_quality_container.addMetaDataEntry("type", "quality")
|
|
|
- empty_quality_container.addMetaDataEntry("supported", False)
|
|
|
- ContainerRegistry.getInstance().addContainer(empty_quality_container)
|
|
|
- self.empty_quality_container = empty_quality_container
|
|
|
-
|
|
|
- empty_quality_changes_container = copy.deepcopy(empty_container)
|
|
|
- empty_quality_changes_container.setMetaDataEntry("id", "empty_quality_changes")
|
|
|
- empty_quality_changes_container.addMetaDataEntry("type", "quality_changes")
|
|
|
- empty_quality_changes_container.addMetaDataEntry("quality_type", "not_supported")
|
|
|
- ContainerRegistry.getInstance().addContainer(empty_quality_changes_container)
|
|
|
- self.empty_quality_changes_container = empty_quality_changes_container
|
|
|
-
|
|
|
- with ContainerRegistry.getInstance().lockFile():
|
|
|
- ContainerRegistry.getInstance().loadAllMetadata()
|
|
|
+ with self._container_registry.lockFile():
|
|
|
+ self._container_registry.loadAllMetadata()
|
|
|
|
|
|
# set the setting version for Preferences
|
|
|
preferences = Preferences.getInstance()
|
|
@@ -411,13 +503,10 @@ class CuraApplication(QtApplication):
|
|
|
|
|
|
self.getCuraSceneController().setActiveBuildPlate(0) # Initialize
|
|
|
|
|
|
- self._quality_profile_drop_down_menu_model = None
|
|
|
- self._custom_quality_profile_drop_down_menu_model = None
|
|
|
-
|
|
|
CuraApplication.Created = True
|
|
|
|
|
|
def _onEngineCreated(self):
|
|
|
- self._engine.addImageProvider("camera", CameraImageProvider.CameraImageProvider())
|
|
|
+ self._qml_engine.addImageProvider("camera", CameraImageProvider.CameraImageProvider())
|
|
|
|
|
|
@pyqtProperty(bool)
|
|
|
def needToShowUserAgreement(self):
|
|
@@ -515,10 +604,6 @@ class CuraApplication(QtApplication):
|
|
|
def setDefaultPath(self, key, default_path):
|
|
|
Preferences.getInstance().setValue("local_file/%s" % key, QUrl(default_path).toLocalFile())
|
|
|
|
|
|
- @classmethod
|
|
|
- def getStaticVersion(cls):
|
|
|
- return CuraVersion
|
|
|
-
|
|
|
## Handle loading of all plugin types (and the backend explicitly)
|
|
|
# \sa PluginRegistry
|
|
|
def _loadPlugins(self):
|
|
@@ -543,127 +628,8 @@ class CuraApplication(QtApplication):
|
|
|
|
|
|
self._plugins_loaded = True
|
|
|
|
|
|
- @classmethod
|
|
|
- def addCommandLineOptions(cls, parser, parsed_command_line = None):
|
|
|
- if parsed_command_line is None:
|
|
|
- parsed_command_line = {}
|
|
|
- super().addCommandLineOptions(parser, parsed_command_line = parsed_command_line)
|
|
|
- parser.add_argument("file", nargs="*", help="Files to load after starting the application.")
|
|
|
- parser.add_argument("--single-instance", action="store_true", default=False)
|
|
|
-
|
|
|
- # Set up a local socket server which listener which coordinates single instances Curas and accepts commands.
|
|
|
- def _setUpSingleInstanceServer(self):
|
|
|
- if self.getCommandLineOption("single_instance", False):
|
|
|
- self.__single_instance_server = QLocalServer()
|
|
|
- self.__single_instance_server.newConnection.connect(self._singleInstanceServerNewConnection)
|
|
|
- self.__single_instance_server.listen("ultimaker-cura")
|
|
|
-
|
|
|
- def _singleInstanceServerNewConnection(self):
|
|
|
- Logger.log("i", "New connection recevied on our single-instance server")
|
|
|
- remote_cura_connection = self.__single_instance_server.nextPendingConnection()
|
|
|
-
|
|
|
- if remote_cura_connection is not None:
|
|
|
- def readCommands():
|
|
|
- line = remote_cura_connection.readLine()
|
|
|
- while len(line) != 0: # There is also a .canReadLine()
|
|
|
- try:
|
|
|
- payload = json.loads(str(line, encoding="ASCII").strip())
|
|
|
- command = payload["command"]
|
|
|
-
|
|
|
- # Command: Remove all models from the build plate.
|
|
|
- if command == "clear-all":
|
|
|
- self.deleteAll()
|
|
|
-
|
|
|
- # Command: Load a model file
|
|
|
- elif command == "open":
|
|
|
- self._openFile(payload["filePath"])
|
|
|
- # WARNING ^ this method is async and we really should wait until
|
|
|
- # the file load is complete before processing more commands.
|
|
|
-
|
|
|
- # Command: Activate the window and bring it to the top.
|
|
|
- elif command == "focus":
|
|
|
- # Operating systems these days prevent windows from moving around by themselves.
|
|
|
- # 'alert' or flashing the icon in the taskbar is the best thing we do now.
|
|
|
- self.getMainWindow().alert(0)
|
|
|
-
|
|
|
- # Command: Close the socket connection. We're done.
|
|
|
- elif command == "close-connection":
|
|
|
- remote_cura_connection.close()
|
|
|
-
|
|
|
- else:
|
|
|
- Logger.log("w", "Received an unrecognized command " + str(command))
|
|
|
- except json.decoder.JSONDecodeError as ex:
|
|
|
- Logger.log("w", "Unable to parse JSON command in _singleInstanceServerNewConnection(): " + repr(ex))
|
|
|
- line = remote_cura_connection.readLine()
|
|
|
-
|
|
|
- remote_cura_connection.readyRead.connect(readCommands)
|
|
|
-
|
|
|
- ## Perform any checks before creating the main application.
|
|
|
- #
|
|
|
- # This should be called directly before creating an instance of CuraApplication.
|
|
|
- # \returns \type{bool} True if the whole Cura app should continue running.
|
|
|
- @classmethod
|
|
|
- def preStartUp(cls, parser = None, parsed_command_line = None):
|
|
|
- if parsed_command_line is None:
|
|
|
- parsed_command_line = {}
|
|
|
-
|
|
|
- # Peek the arguments and look for the 'single-instance' flag.
|
|
|
- if not parser:
|
|
|
- parser = argparse.ArgumentParser(prog = "cura", add_help = False) # pylint: disable=bad-whitespace
|
|
|
- CuraApplication.addCommandLineOptions(parser, parsed_command_line = parsed_command_line)
|
|
|
- # Important: It is important to keep this line here!
|
|
|
- # In Uranium we allow to pass unknown arguments to the final executable or script.
|
|
|
- parsed_command_line.update(vars(parser.parse_known_args()[0]))
|
|
|
-
|
|
|
- if parsed_command_line["single_instance"]:
|
|
|
- Logger.log("i", "Checking for the presence of an ready running Cura instance.")
|
|
|
- single_instance_socket = QLocalSocket()
|
|
|
- Logger.log("d", "preStartUp(): full server name: " + single_instance_socket.fullServerName())
|
|
|
- single_instance_socket.connectToServer("ultimaker-cura")
|
|
|
- single_instance_socket.waitForConnected()
|
|
|
- if single_instance_socket.state() == QLocalSocket.ConnectedState:
|
|
|
- Logger.log("i", "Connection has been made to the single-instance Cura socket.")
|
|
|
-
|
|
|
- # Protocol is one line of JSON terminated with a carriage return.
|
|
|
- # "command" field is required and holds the name of the command to execute.
|
|
|
- # Other fields depend on the command.
|
|
|
-
|
|
|
- payload = {"command": "clear-all"}
|
|
|
- single_instance_socket.write(bytes(json.dumps(payload) + "\n", encoding="ASCII"))
|
|
|
-
|
|
|
- payload = {"command": "focus"}
|
|
|
- single_instance_socket.write(bytes(json.dumps(payload) + "\n", encoding="ASCII"))
|
|
|
-
|
|
|
- if len(parsed_command_line["file"]) != 0:
|
|
|
- for filename in parsed_command_line["file"]:
|
|
|
- payload = {"command": "open", "filePath": filename}
|
|
|
- single_instance_socket.write(bytes(json.dumps(payload) + "\n", encoding="ASCII"))
|
|
|
-
|
|
|
- payload = {"command": "close-connection"}
|
|
|
- single_instance_socket.write(bytes(json.dumps(payload) + "\n", encoding="ASCII"))
|
|
|
-
|
|
|
- single_instance_socket.flush()
|
|
|
- single_instance_socket.waitForDisconnected()
|
|
|
- return False
|
|
|
- return True
|
|
|
-
|
|
|
- def preRun(self):
|
|
|
- # Last check for unknown commandline arguments
|
|
|
- parser = self.getCommandlineParser()
|
|
|
- parser.add_argument("--help", "-h",
|
|
|
- action='store_true',
|
|
|
- default = False,
|
|
|
- help = "Show this help message and exit."
|
|
|
- )
|
|
|
- parsed_args = vars(parser.parse_args()) # This won't allow unknown arguments
|
|
|
- if parsed_args["help"]:
|
|
|
- parser.print_help()
|
|
|
- sys.exit(0)
|
|
|
-
|
|
|
def run(self):
|
|
|
- self.preRun()
|
|
|
-
|
|
|
- container_registry = ContainerRegistry.getInstance()
|
|
|
+ container_registry = self._container_registry
|
|
|
|
|
|
Logger.log("i", "Initializing variant manager")
|
|
|
self._variant_manager = VariantManager(container_registry)
|
|
@@ -682,20 +648,25 @@ class CuraApplication(QtApplication):
|
|
|
Logger.log("i", "Initializing machine manager")
|
|
|
self._machine_manager = MachineManager(self)
|
|
|
|
|
|
+ Logger.log("i", "Initializing container manager")
|
|
|
+ self._container_manager = ContainerManager(self)
|
|
|
+
|
|
|
Logger.log("i", "Initializing machine error checker")
|
|
|
self._machine_error_checker = MachineErrorChecker(self)
|
|
|
self._machine_error_checker.initialize()
|
|
|
|
|
|
- # Check if we should run as single instance or not
|
|
|
- self._setUpSingleInstanceServer()
|
|
|
+ # Check if we should run as single instance or not. If so, set up a local socket server which listener which
|
|
|
+ # coordinates multiple Cura instances and accepts commands.
|
|
|
+ if self._use_single_instance:
|
|
|
+ self.__setUpSingleInstanceServer()
|
|
|
|
|
|
# Setup scene and build volume
|
|
|
root = self.getController().getScene().getRoot()
|
|
|
- self._volume = BuildVolume.BuildVolume(self.getController().getScene().getRoot())
|
|
|
+ self._volume = BuildVolume.BuildVolume(self, root)
|
|
|
Arrange.build_volume = self._volume
|
|
|
|
|
|
# initialize info objects
|
|
|
- self._print_information = PrintInformation.PrintInformation()
|
|
|
+ self._print_information = PrintInformation.PrintInformation(self)
|
|
|
self._cura_actions = CuraActions.CuraActions(self)
|
|
|
|
|
|
# Initialize setting visibility presets model
|
|
@@ -704,7 +675,7 @@ class CuraApplication(QtApplication):
|
|
|
Preferences.getInstance().setDefault("general/visible_settings", ";".join(default_visibility_profile["settings"]))
|
|
|
|
|
|
# Detect in which mode to run and execute that mode
|
|
|
- if self.getCommandLineOption("headless", False):
|
|
|
+ if self._is_headless:
|
|
|
self.runWithoutGUI()
|
|
|
else:
|
|
|
self.runWithGUI()
|
|
@@ -713,7 +684,6 @@ class CuraApplication(QtApplication):
|
|
|
self.initializationFinished.emit()
|
|
|
Logger.log("d", "Booting Cura took %s seconds", time.time() - self._boot_loading_time)
|
|
|
|
|
|
-
|
|
|
# For now use a timer to postpone some things that need to be done after the application and GUI are
|
|
|
# initialized, for example opening files because they may show dialogs which can be closed due to incomplete
|
|
|
# GUI initialization.
|
|
@@ -725,8 +695,12 @@ class CuraApplication(QtApplication):
|
|
|
|
|
|
self.exec_()
|
|
|
|
|
|
+ def __setUpSingleInstanceServer(self):
|
|
|
+ if self._use_single_instance:
|
|
|
+ self._single_instance.startServer()
|
|
|
+
|
|
|
def _onPostStart(self):
|
|
|
- for file_name in self.getCommandLineOption("file", []):
|
|
|
+ for file_name in self._files_to_open:
|
|
|
self.callLater(self._openFile, file_name)
|
|
|
for file_name in self._open_file_queue: # Open all the files that were queued up while plug-ins were loading.
|
|
|
self.callLater(self._openFile, file_name)
|
|
@@ -735,13 +709,10 @@ class CuraApplication(QtApplication):
|
|
|
|
|
|
## Run Cura without GUI elements and interaction (server mode).
|
|
|
def runWithoutGUI(self):
|
|
|
- self._use_gui = False
|
|
|
self.closeSplash()
|
|
|
|
|
|
## Run Cura with GUI (desktop mode).
|
|
|
def runWithGUI(self):
|
|
|
- self._use_gui = True
|
|
|
-
|
|
|
self.showSplashMessage(self._i18n_catalog.i18nc("@info:progress", "Setting up scene..."))
|
|
|
|
|
|
controller = self.getController()
|
|
@@ -791,9 +762,6 @@ class CuraApplication(QtApplication):
|
|
|
# Hide the splash screen
|
|
|
self.closeSplash()
|
|
|
|
|
|
- def hasGui(self):
|
|
|
- return self._use_gui
|
|
|
-
|
|
|
@pyqtSlot(result = QObject)
|
|
|
def getSettingVisibilityPresetsModel(self, *args) -> SettingVisibilityPresetsModel:
|
|
|
return self._setting_visibility_presets_model
|
|
@@ -808,7 +776,7 @@ class CuraApplication(QtApplication):
|
|
|
|
|
|
def getExtruderManager(self, *args):
|
|
|
if self._extruder_manager is None:
|
|
|
- self._extruder_manager = ExtruderManager.createExtruderManager()
|
|
|
+ self._extruder_manager = ExtruderManager()
|
|
|
return self._extruder_manager
|
|
|
|
|
|
@pyqtSlot(result = QObject)
|
|
@@ -932,7 +900,7 @@ class CuraApplication(QtApplication):
|
|
|
qmlRegisterType(QualitySettingsModel, "Cura", 1, 0, "QualitySettingsModel")
|
|
|
qmlRegisterType(MachineNameValidator, "Cura", 1, 0, "MachineNameValidator")
|
|
|
qmlRegisterType(UserChangesModel, "Cura", 1, 0, "UserChangesModel")
|
|
|
- qmlRegisterSingletonType(ContainerManager, "Cura", 1, 0, "ContainerManager", ContainerManager.createContainerManager)
|
|
|
+ qmlRegisterSingletonType(ContainerManager, "Cura", 1, 0, "ContainerManager", ContainerManager.getInstance)
|
|
|
|
|
|
# As of Qt5.7, it is necessary to get rid of any ".." in the path for the singleton to work.
|
|
|
actions_url = QUrl.fromLocalFile(os.path.abspath(Resources.getPath(CuraApplication.ResourceTypes.QmlFiles, "Actions.qml")))
|
|
@@ -1520,8 +1488,7 @@ class CuraApplication(QtApplication):
|
|
|
# see GroupDecorator._onChildrenChanged
|
|
|
|
|
|
def _createSplashScreen(self):
|
|
|
- run_headless = self.getCommandLineOption("headless", False)
|
|
|
- if run_headless:
|
|
|
+ if self._is_headless:
|
|
|
return None
|
|
|
return CuraSplashScreen.CuraSplashScreen()
|
|
|
|