WIP: Make application initialization and start up more clear

- Create SingleInstance class to handling single instance stuff.
 - Instead of calling getInstance() everywhere, initialize each object
   explicitly in order when application starts and getInstance()s do not
   create instances any more and they merely return the created
   instances.
 - Only set initial values in construtor functions __init__(). Move the
   initialization of context-aware (i.e. things that depend on other
   things) to separate functions.
 - Split application creation and initialziation into several steps and
   them should be called explicitly in the correct order.
This commit is contained in:
Lipu Fei 2018-04-30 16:47:14 +02:00
parent c8f73d303e
commit 051dd7a6e9
14 changed files with 521 additions and 471 deletions

View file

@ -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")
## Initialise the version upgrade manager with Cura's storage paths.
# Needs to be here to prevent circular dependencies.
import UM.VersionUpgradeManager
Resources.addType(self.ResourceTypes.QmlFiles, "qml")
Resources.addType(self.ResourceTypes.Firmware, "firmware")
UM.VersionUpgradeManager.VersionUpgradeManager.getInstance().setCurrentVersions(
# 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
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
# 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()