def container_registry(application): MimeTypeDatabase.addMimeType( MimeType( name = "application/x-uranium-definitioncontainer", comment = "Uranium Definition Container", suffixes = ["def.json"] ) ) MimeTypeDatabase.addMimeType( MimeType( name = "application/x-uranium-instancecontainer", comment = "Uranium Instance Container", suffixes = [ "inst.cfg" ] ) ) MimeTypeDatabase.addMimeType( MimeType( name = "application/x-uranium-containerstack", comment = "Uranium Container Stack", suffixes = [ "stack.cfg" ] ) ) Resources.addSearchPath(os.path.realpath(os.path.join(os.path.dirname(__file__), "..", "..", "Settings"))) ContainerRegistry._ContainerRegistry__instance = None # Reset the private instance variable every time PluginRegistry.getInstance().removeType("settings_container") ContainerRegistry.getInstance().load() return ContainerRegistry.getInstance()
def __init__(self, width, height): super().__init__("selection", width, height, -999) self._shader = OpenGL.getInstance().createShaderProgram(Resources.getPath(Resources.Shaders, "selection.shader")) self._tool_handle_shader = OpenGL.getInstance().createShaderProgram(Resources.getPath(Resources.Shaders, "default.shader")) self._gl = OpenGL.getInstance().getBindingsObject() self._scene = Application.getInstance().getController().getScene() self._renderer = Application.getInstance().getRenderer() self._selection_map = {} self._toolhandle_selection_map = { self._dropAlpha(ToolHandle.DisabledSelectionColor): ToolHandle.NoAxis, self._dropAlpha(ToolHandle.XAxisSelectionColor): ToolHandle.XAxis, self._dropAlpha(ToolHandle.YAxisSelectionColor): ToolHandle.YAxis, self._dropAlpha(ToolHandle.ZAxisSelectionColor): ToolHandle.ZAxis, self._dropAlpha(ToolHandle.AllAxisSelectionColor): ToolHandle.AllAxis, ToolHandle.DisabledSelectionColor: ToolHandle.NoAxis, ToolHandle.XAxisSelectionColor: ToolHandle.XAxis, ToolHandle.YAxisSelectionColor: ToolHandle.YAxis, ToolHandle.ZAxisSelectionColor: ToolHandle.ZAxis, ToolHandle.AllAxisSelectionColor: ToolHandle.AllAxis } self._output = None
def __init__(self): Resources.addResourcePath(os.path.join(QtApplication.getInstallPrefix(), "share", "cura")) if not hasattr(sys, "frozen"): Resources.addResourcePath(os.path.join(os.path.abspath(os.path.dirname(__file__)), "..")) super().__init__(name = "cura", version = "master") self.setRequiredPlugins([ "CuraEngineBackend", "MeshView", "LayerView", "STLReader", "SelectionTool", "CameraTool", "GCodeWriter", "LocalFileStorage" ]) self._physics = None self._volume = None self._platform = None self._output_devices = {} self._print_information = None self._i18n_catalog = None self.activeMachineChanged.connect(self._onActiveMachineChanged) Preferences.getInstance().addPreference("cura/active_machine", "") Preferences.getInstance().addPreference("cura/active_mode", "simple")
def registerObjects(self, engine): engine.rootContext().setContextProperty("Printer", self) engine.rootContext().setContextProperty("CuraApplication", self) self._print_information = PrintInformation.PrintInformation() engine.rootContext().setContextProperty("PrintInformation", self._print_information) self._cura_actions = CuraActions.CuraActions(self) engine.rootContext().setContextProperty("CuraActions", self._cura_actions) qmlRegisterUncreatableType(CuraApplication, "Cura", 1, 0, "ResourceTypes", "Just an Enum type") qmlRegisterType(cura.Settings.ExtrudersModel, "Cura", 1, 0, "ExtrudersModel") qmlRegisterType(cura.Settings.ContainerSettingsModel, "Cura", 1, 0, "ContainerSettingsModel") qmlRegisterType(cura.Settings.MaterialSettingsVisibilityHandler, "Cura", 1, 0, "MaterialSettingsVisibilityHandler") qmlRegisterSingletonType(cura.Settings.ContainerManager, "Cura", 1, 0, "ContainerManager", cura.Settings.ContainerManager.createContainerManager) qmlRegisterSingletonType(QUrl.fromLocalFile(Resources.getPath(CuraApplication.ResourceTypes.QmlFiles, "Actions.qml")), "Cura", 1, 0, "Actions") engine.rootContext().setContextProperty("ExtruderManager", cura.Settings.ExtruderManager.getInstance()) for path in Resources.getAllResourcesOfType(CuraApplication.ResourceTypes.QmlFiles): type_name = os.path.splitext(os.path.basename(path))[0] if type_name in ("Cura", "Actions"): continue qmlRegisterType(QUrl.fromLocalFile(path), "Cura", 1, 0, type_name)
def beginRendering(self): scene = self.getController().getScene() renderer = self.getRenderer() if not self._enabled_shader: self._enabled_shader = OpenGL.getInstance().createShaderProgram(Resources.getPath(Resources.Shaders, "overhang.shader")) if not self._disabled_shader: self._disabled_shader = OpenGL.getInstance().createShaderProgram(Resources.getPath(Resources.Shaders, "striped.shader")) self._disabled_shader.setUniformValue("u_diffuseColor1", [0.48, 0.48, 0.48, 1.0]) self._disabled_shader.setUniformValue("u_diffuseColor2", [0.68, 0.68, 0.68, 1.0]) self._disabled_shader.setUniformValue("u_width", 50.0) if Application.getInstance().getGlobalContainerStack(): if Preferences.getInstance().getValue("view/show_overhang"): angle = Application.getInstance().getGlobalContainerStack().getProperty("support_angle", "value") if angle is not None: self._enabled_shader.setUniformValue("u_overhangAngle", math.cos(math.radians(90 - angle))) else: self._enabled_shader.setUniformValue("u_overhangAngle", math.cos(math.radians(0))) #Overhang angle of 0 causes no area at all to be marked as overhang. else: self._enabled_shader.setUniformValue("u_overhangAngle", math.cos(math.radians(0))) for node in DepthFirstIterator(scene.getRoot()): if not node.render(renderer): if node.getMeshData() and node.isVisible(): # TODO: Find a better way to handle this #if node.getBoundingBoxMesh(): # renderer.queueNode(scene.getRoot(), mesh = node.getBoundingBoxMesh(),mode = Renderer.RenderLines) uniforms = {} if self._extruders_model.rowCount() > 0: # Get color to render this mesh in from ExtrudersModel extruder_index = 0 extruder_id = node.callDecoration("getActiveExtruder") if extruder_id: extruder_index = max(0, self._extruders_model.find("id", extruder_id)) extruder_color = self._extruders_model.getItem(extruder_index)["colour"] try: # Colors are passed as rgb hex strings (eg "#ffffff"), and the shader needs # an rgba list of floats (eg [1.0, 1.0, 1.0, 1.0]) uniforms["diffuse_color"] = [ int(extruder_color[1:3], 16) / 255, int(extruder_color[3:5], 16) / 255, int(extruder_color[5:7], 16) / 255, 1.0 ] except ValueError: pass if hasattr(node, "_outside_buildarea"): if node._outside_buildarea: renderer.queueNode(node, shader = self._disabled_shader) else: renderer.queueNode(node, shader = self._enabled_shader, uniforms = uniforms) else: renderer.queueNode(node, material = self._enabled_shader, uniforms = uniforms) if node.callDecoration("isGroup"): renderer.queueNode(scene.getRoot(), mesh = node.getBoundingBoxMesh(), mode = Renderer.RenderLines)
def _onInstanceNameChanged(self, instance, old_name): file_name = urllib.parse.quote_plus(old_name) try: path = Resources.getStoragePath(Resources.MachineInstances, file_name + ".cfg") os.remove(path) path = Resources.getStoragePath(Resources.MachineInstanceProfiles, file_name + ".curaprofile") os.remove(path) except FileNotFoundError: pass #Update machine instance name for all profiles attached to this machine instance for profile in self._profiles: if profile.isReadOnly() or profile.getMachineInstanceName() != old_name: continue file_name = urllib.parse.quote_plus(profile.getName()) + ".cfg" try: path = Resources.getStoragePath(Resources.Profiles, file_name) os.remove(path) except FileNotFoundError: pass profile.setMachineInstanceName(instance.getName()) self.machineInstanceNameChanged.emit(instance)
def restore(self) -> bool: if not self.zip_file or not self.meta_data or not self.meta_data.get("cura_release", None): # We can restore without the minimum required information. Logger.log("w", "Tried to restore a Cura backup without having proper data or meta data.") self._showMessage( self.catalog.i18nc("@info:backup_failed", "Tried to restore a Cura backup without having proper data or meta data.")) return False current_version = self._application.getVersion() version_to_restore = self.meta_data.get("cura_release", "master") if current_version < version_to_restore: # Cannot restore version newer than current because settings might have changed. Logger.log("d", "Tried to restore a Cura backup of version {version_to_restore} with cura version {current_version}".format(version_to_restore = version_to_restore, current_version = current_version)) self._showMessage( self.catalog.i18nc("@info:backup_failed", "Tried to restore a Cura backup that is higher than the current version.")) return False version_data_dir = Resources.getDataStoragePath() archive = ZipFile(io.BytesIO(self.zip_file), "r") extracted = self._extractArchive(archive, version_data_dir) # Under Linux, preferences are stored elsewhere, so we copy the file to there. if Platform.isLinux(): preferences_file_name = self._application.getApplicationName() preferences_file = Resources.getPath(Resources.Preferences, "{}.cfg".format(preferences_file_name)) backup_preferences_file = os.path.join(version_data_dir, "{}.cfg".format(preferences_file_name)) Logger.log("d", "Moving preferences file from %s to %s", backup_preferences_file, preferences_file) shutil.move(backup_preferences_file, preferences_file) return extracted
def _getUpgradeTasks(self) -> Iterator[UpgradeTask]: storage_path_prefixes = set() storage_path_prefixes.add(Resources.getConfigStoragePath()) storage_path_prefixes.add(Resources.getDataStoragePath()) # Make sure the types and paths are ordered so we always get the same results. self._storage_paths = collections.OrderedDict(sorted(self._storage_paths.items())) for key in self._storage_paths: self._storage_paths[key] = collections.OrderedDict(sorted(self._storage_paths[key].items())) # Use pattern: /^(pattern_a|pattern_b|pattern_c|...)$/ combined_regex_ignored_files = "^(" + "|".join(self._ignored_files) + ")" for old_configuration_type, version_storage_paths_dict in self._storage_paths.items(): for src_version, storage_paths in version_storage_paths_dict.items(): for prefix in storage_path_prefixes: for storage_path in storage_paths: path = os.path.join(prefix, storage_path) for configuration_file in self._getFilesInDirectory(path): # Get file version. Only add this upgrade task if the current file version matches with # the defined version that scans through this folder. if re.match(combined_regex_ignored_files, configuration_file): continue try: with open(os.path.join(path, configuration_file), "r", encoding = "utf-8") as f: file_version = self._get_version_functions[old_configuration_type](f.read()) if file_version != src_version: continue except: Logger.log("w", "Failed to get file version: %s, skip it", configuration_file) continue Logger.log("i", "Create upgrade task for configuration file [%s] with type [%s] and source version [%s]", configuration_file, old_configuration_type, file_version) yield UpgradeTask(storage_path = path, file_name = configuration_file, configuration_type = old_configuration_type)
def _updateTimeQualitySettings(self): if not self._current_settings or not self._enabled: return if not self._low_quality_settings: self._low_quality_settings = MachineSettings() self._low_quality_settings.loadSettingsFromFile(Resources.getPath(Resources.SettingsLocation, self._current_settings.getTypeID() + ".json")) self._low_quality_settings.loadValuesFromFile(Resources.getPath(Resources.SettingsLocation, "profiles", "low_quality.conf")) if not self._high_quality_settings: self._high_quality_settings = MachineSettings() self._high_quality_settings.loadSettingsFromFile(Resources.getPath(Resources.SettingsLocation, self._current_settings.getTypeID() + ".json")) self._high_quality_settings.loadValuesFromFile(Resources.getPath(Resources.SettingsLocation, "profiles", "high_quality.conf")) for key, options in self._interpolation_settings.items(): minimum_value = None if options["minimum"] == "low": minimum_value = self._low_quality_settings.getSettingValueByKey(key) elif options["minimum"] == "high": minimum_value = self._high_quality_settings.getSettingValueByKey(key) else: continue maximum_value = None if options["maximum"] == "low": maximum_value = self._low_quality_settings.getSettingValueByKey(key) elif options["maximum"] == "high": maximum_value = self._high_quality_settings.getSettingValueByKey(key) else: continue setting_value = round(minimum_value + (maximum_value - minimum_value) * (self._time_quality_value / 100), options["precision"]) self._current_settings.setSettingValueByKey(key, setting_value)
def loadProfiles(self): storage_path = Resources.getStoragePathForType(Resources.Profiles) dirs = Resources.getAllPathsForType(Resources.Profiles) for dir in dirs: if not os.path.isdir(dir): continue read_only = dir != storage_path for file_name in os.listdir(dir): path = os.path.join(dir, file_name) if os.path.isdir(path): continue profile = Profile(self, read_only) try: profile.loadFromFile(path) except Exception as e: Logger.log("e", "An exception occurred loading Profile %s: %s", path, str(e)) continue if not self.findProfile(profile.getName()): self._profiles.append(profile) profile.nameChanged.connect(self._onProfileNameChanged) profile = self.findProfile(Preferences.getInstance().getValue("machines/active_profile")) if profile: self.setActiveProfile(profile) self.profilesChanged.emit()
def registerObjects(self, engine): engine.rootContext().setContextProperty("Printer", self) engine.rootContext().setContextProperty("CuraApplication", self) self._print_information = PrintInformation.PrintInformation() engine.rootContext().setContextProperty("PrintInformation", self._print_information) self._cura_actions = CuraActions.CuraActions(self) engine.rootContext().setContextProperty("CuraActions", self._cura_actions) qmlRegisterUncreatableType(CuraApplication, "Cura", 1, 0, "ResourceTypes", "Just an Enum type") qmlRegisterType(cura.Settings.ExtrudersModel, "Cura", 1, 0, "ExtrudersModel") qmlRegisterType(cura.Settings.ContainerSettingsModel, "Cura", 1, 0, "ContainerSettingsModel") qmlRegisterSingletonType(cura.Settings.ProfilesModel, "Cura", 1, 0, "ProfilesModel", cura.Settings.ProfilesModel.createProfilesModel) qmlRegisterType(cura.Settings.QualityAndUserProfilesModel, "Cura", 1, 0, "QualityAndUserProfilesModel") qmlRegisterType(cura.Settings.UserProfilesModel, "Cura", 1, 0, "UserProfilesModel") qmlRegisterType(cura.Settings.MaterialSettingsVisibilityHandler, "Cura", 1, 0, "MaterialSettingsVisibilityHandler") qmlRegisterType(cura.Settings.QualitySettingsModel, "Cura", 1, 0, "QualitySettingsModel") qmlRegisterType(cura.Settings.MachineNameValidator, "Cura", 1, 0, "MachineNameValidator") qmlRegisterSingletonType(cura.Settings.ContainerManager, "Cura", 1, 0, "ContainerManager", cura.Settings.ContainerManager.createContainerManager) # 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"))) qmlRegisterSingletonType(actions_url, "Cura", 1, 0, "Actions") engine.rootContext().setContextProperty("ExtruderManager", cura.Settings.ExtruderManager.getInstance()) for path in Resources.getAllResourcesOfType(CuraApplication.ResourceTypes.QmlFiles): type_name = os.path.splitext(os.path.basename(path))[0] if type_name in ("Cura", "Actions"): continue qmlRegisterType(QUrl.fromLocalFile(path), "Cura", 1, 0, type_name)
def container_registry(application): MimeTypeDatabase.addMimeType( MimeType( name = "application/x-uranium-definitioncontainer", comment = "Uranium Definition Container", suffixes = ["def.json"] ) ) MimeTypeDatabase.addMimeType( MimeType( name = "application/x-uranium-instancecontainer", comment = "Uranium Instance Container", suffixes = [ "inst.cfg" ] ) ) MimeTypeDatabase.addMimeType( MimeType( name = "application/x-uranium-containerstack", comment = "Uranium Container Stack", suffixes = [ "stack.cfg" ] ) ) Resources.addSearchPath(os.path.dirname(os.path.abspath(__file__))) ContainerRegistry._ContainerRegistry__instance = None # Reset the private instance variable every time ContainerRegistry.setApplication(application) UM.Settings.ContainerStack.setContainerRegistry(ContainerRegistry.getInstance()) UM.Settings.InstanceContainer.setContainerRegistry(ContainerRegistry.getInstance()) return ContainerRegistry.getInstance()
def loadQtTranslation(self, file, language = "default"): #TODO Add support for specifying a language from preferences path = None if language == "default": # If we have a language set in the environment, try and use that. lang = os.getenv("LANGUAGE") if lang: try: path = Resources.getPath(Resources.i18nLocation, lang, "LC_MESSAGES", file + ".qm") except FileNotFoundError: path = None # If looking up the language from the enviroment fails, try and use Qt's system locale instead. if not path: locale = QLocale.system() # First, try and find a directory for any of the provided languages for lang in locale.uiLanguages(): try: path = Resources.getPath(Resources.i18nLocation, lang, "LC_MESSAGES", file + ".qm") language = lang except FileNotFoundError: pass else: break # If that fails, see if we can extract a language "class" from the # preferred language. This will turn "en-GB" into "en" for example. if not path: lang = locale.uiLanguages()[0] lang = lang[0:lang.find("-")] try: path = Resources.getPath(Resources.i18nLocation, lang, "LC_MESSAGES", file + ".qm") language = lang except FileNotFoundError: pass else: path = Resources.getPath(Resources.i18nLocation, language, "LC_MESSAGES", file + ".qm") # If all else fails, fall back to english. if not path: Logger.log("w", "Could not find any translations matching {0} for file {1}, falling back to english".format(language, file)) try: path = Resources.getPath(Resources.i18nLocation, "en", "LC_MESSAGES", file + ".qm") except FileNotFoundError: Logger.log("w", "Could not find English translations for file {0}. Switching to developer english.".format(file)) return translator = QTranslator() if not translator.load(path): Logger.log("e", "Unable to load translations %s", file) return # Store a reference to the translator. # This prevents the translator from being destroyed before Qt has a chance to use it. self._translators[file] = translator # Finally, install the translator so Qt can use it. self.installTranslator(translator)
def beginRendering(self): scene = self.getController().getScene() renderer = self.getRenderer() renderer.setRenderSelection(False) if not self._material: self._material = renderer.createMaterial(Resources.getPath(Resources.Shaders, "basic.vert"), Resources.getPath(Resources.Shaders, "vertexcolor.frag")) self._material.setUniformValue("u_color", [1.0, 0.0, 0.0, 1.0]) self._selection_material = renderer.createMaterial(Resources.getPath(Resources.Shaders, "basic.vert"), Resources.getPath(Resources.Shaders, "color.frag")) self._selection_material.setUniformValue("u_color", Color(35, 35, 35, 128)) for node in DepthFirstIterator(scene.getRoot()): # We do not want to render ConvexHullNode as it conflicts with the bottom layers. # However, it is somewhat relevant when the node is selected, so do render it then. if type(node) is ConvexHullNode and not Selection.isSelected(node.getWatchedNode()): continue if not node.render(renderer): if node.getMeshData() and node.isVisible(): if Selection.isSelected(node): renderer.queueNode(node, material = self._selection_material, transparent = True) layer_data = node.callDecoration("getLayerData") if not layer_data: continue # Render all layers below a certain number as line mesh instead of vertices. if self._current_layer_num - self._solid_layers > -1: start = 0 end = 0 element_counts = layer_data.getElementCounts() for layer, counts in element_counts.items(): if layer + self._solid_layers > self._current_layer_num: break end += counts # This uses glDrawRangeElements internally to only draw a certain range of lines. renderer.queueNode(node, mesh = layer_data, material = self._material, mode = Renderer.RenderLines, start = start, end = end) # We currently recreate the current "solid" layers every time a if not self._current_layer_mesh: self._current_layer_mesh = MeshData() for i in range(self._solid_layers): layer = self._current_layer_num - i if layer < 0: continue layer_mesh = layer_data.getLayer(layer).createMesh() if not layer_mesh or layer_mesh.getVertices() is None: continue self._current_layer_mesh.addVertices(layer_mesh.getVertices()) # Scale layer color by a brightness factor based on the current layer number # This will result in a range of 0.5 - 1.0 to multiply colors by. brightness = (2.0 - (i / self._solid_layers)) / 2.0 self._current_layer_mesh.addColors(layer_mesh.getColors() * brightness) renderer.queueNode(node, mesh = self._current_layer_mesh, material = self._material)
def load(self): files = [] for resource_type in self._resource_types: resources = Resources.getAllResourcesOfType(resource_type) try: resource_storage_path = Resources.getStoragePathForType(resource_type) except UnsupportedStorageTypeError: resource_storage_path = "" # Pre-process the list of files to insert relevant data # Most importantly, we need to ensure the loading order is DefinitionContainer, InstanceContainer, ContainerStack for path in resources: mime = MimeTypeDatabase.getMimeTypeForFile(path) container_type = self.__mime_type_map.get(mime.name) if not container_type: Logger.log("w", "Could not determine container type for file %s, ignoring", path) continue type_priority = 2 if issubclass(container_type, DefinitionContainer.DefinitionContainer): type_priority = 0 if issubclass(container_type, InstanceContainer.InstanceContainer): type_priority = 1 # Since we have the mime type and resource type here, process these two properties so we do not # need to look up mime types etc. again. container_id = urllib.parse.unquote_plus(mime.stripExtension(os.path.basename(path))) read_only = os.path.dirname(path) != resource_storage_path files.append((type_priority, container_id, path, read_only, container_type)) # Sort the list of files by type_priority so we can ensure correct loading order. files = sorted(files, key = lambda i: i[0]) for _, container_id, file_path, read_only, container_type in files: if container_id in self._id_container_cache: continue try: if issubclass(container_type, DefinitionContainer.DefinitionContainer): definition = self._loadCachedDefinition(container_id, file_path) if definition: self.addContainer(definition) continue new_container = container_type(container_id) with open(file_path, encoding = "utf-8") as f: new_container.deserialize(f.read()) new_container.setReadOnly(read_only) if issubclass(container_type, DefinitionContainer.DefinitionContainer): self._saveCachedDefinition(new_container) self.addContainer(new_container) except Exception as e: Logger.logException("e", "Could not deserialize container %s", container_id)
def _actionTriggered(self, _, action_id): if action_id == "reset": result = QMessageBox.question(None, i18n_catalog.i18nc("@title:window", "Reset to factory"), i18n_catalog.i18nc("@label", "Reset will remove all your current printers and profiles! Are you sure you want to reset?")) if result == QMessageBox.Yes: Resources.factoryReset() sys.exit(1)
def run(self): self.showSplashMessage(self._i18n_catalog.i18nc("@info:progress", "Setting up scene...")) controller = self.getController() controller.setActiveView("SolidView") controller.setCameraTool("CameraTool") controller.setSelectionTool("SelectionTool") t = controller.getTool("TranslateTool") if t: t.setEnabledAxis([ToolHandle.XAxis, ToolHandle.YAxis,ToolHandle.ZAxis]) Selection.selectionChanged.connect(self.onSelectionChanged) root = controller.getScene().getRoot() self._platform = Scene_Platform(root) self._volume = BuildVolume.BuildVolume(root) self.getRenderer().setBackgroundColor(QColor(245, 245, 245)) self._physics = PlatformPhysics.PlatformPhysics(controller, self._volume) camera = Camera("3d", root) camera.setPosition(Vector(-80, 250, 700)) camera.setPerspective(True) camera.lookAt(Vector(0, 0, 0)) controller.getScene().setActiveCamera("3d") self.getController().getTool("CameraTool").setOrigin(Vector(0, 100, 0)) self._camera_animation = CameraAnimation.CameraAnimation() self._camera_animation.setCameraTool(self.getController().getTool("CameraTool")) self.showSplashMessage(self._i18n_catalog.i18nc("@info:progress", "Loading interface...")) # Initialise extruder so as to listen to global container stack changes before the first global container stack is set. cura.Settings.ExtruderManager.getInstance() qmlRegisterSingletonType(cura.Settings.MachineManager, "Cura", 1, 0, "MachineManager", cura.Settings.MachineManager.createMachineManager) qmlRegisterSingletonType(MachineActionManager.MachineActionManager, "Cura", 1, 0, "MachineActionManager", self.getMachineActionManager) self.setMainQml(Resources.getPath(self.ResourceTypes.QmlFiles, "Cura.qml")) self._qml_import_paths.append(Resources.getPath(self.ResourceTypes.QmlFiles)) self.initializeEngine() if self._engine.rootObjects: self.closeSplash() for file in self.getCommandLineOption("file", []): self._openFile(file) for file_name in self._open_file_queue: #Open all the files that were queued up while plug-ins were loading. self._openFile(file_name) self._started = True self.exec_()
def saveAll(self) -> None: for instance in self.findInstanceContainers(): if not instance.isDirty(): continue try: data = instance.serialize() except NotImplementedError: # Serializing is not supported so skip this container continue except Exception: Logger.logException("e", "An exception occurred trying to serialize container %s", instance.getId()) continue mime_type = self.getMimeTypeForContainer(type(instance)) if mime_type is not None: file_name = urllib.parse.quote_plus(instance.getId()) + "." + mime_type.preferredSuffix path = Resources.getStoragePath(Resources.InstanceContainers, file_name) with SaveFile(path, "wt") as f: f.write(data) for stack in self.findContainerStacks(): if not stack.isDirty(): continue try: data = stack.serialize() except NotImplementedError: # Serializing is not supported so skip this container continue except Exception: Logger.logException("e", "An exception occurred trying to serialize container %s", stack.getId()) continue mime_type = self.getMimeTypeForContainer(type(stack)) if mime_type is not None: file_name = urllib.parse.quote_plus(stack.getId()) + "." + mime_type.preferredSuffix path = Resources.getStoragePath(Resources.ContainerStacks, file_name) with SaveFile(path, "wt") as f: f.write(data) for definition in self.findDefinitionContainers(): try: data = definition.serialize() except NotImplementedError: # Serializing is not supported so skip this container continue except Exception: Logger.logException("e", "An exception occurred trying to serialize container %s", definition.getId()) continue mime_type = self.getMimeTypeForContainer(type(definition)) if mime_type is not None: file_name = urllib.parse.quote_plus(definition.getId()) + "." + mime_type.preferredSuffix path = Resources.getStoragePath(Resources.DefinitionContainers, file_name) with SaveFile(path, "wt") as f: f.write(data)
def saveMachineInstances(self): if self._active_machine: Preferences.getInstance().setValue("machines/active_instance", self._active_machine.getName()) for instance in self._machine_instances: file_name = urllib.parse.quote_plus(instance.getName()) + ".cfg" instance.saveToFile(Resources.getStoragePath(Resources.MachineInstances, file_name)) file_name = urllib.parse.quote_plus(instance.getName()) + ".curaprofile" instance.getWorkingProfile().saveToFile(Resources.getStoragePath(Resources.MachineInstanceProfiles, file_name))
def _createCustomFdmPrinterExtruderStack(self, machine_id: str, position: int, quality_id: str, material_id: str): stack_id = "custom_extruder_%s" % (position + 1) if self._current_fdm_printer_count > 1: stack_id += " #%s" % self._current_fdm_printer_count definition_id = "custom_extruder_%s" % (position + 1) # create a definition changes container for this stack definition_changes_parser = self._getCustomFdmPrinterDefinitionChanges(stack_id) definition_changes_id = definition_changes_parser["general"]["name"] # create a user settings container user_settings_parser = self._getCustomFdmPrinterUserSettings(stack_id) user_settings_id = user_settings_parser["general"]["name"] parser = configparser.ConfigParser() parser.add_section("general") parser["general"]["version"] = str(2) parser["general"]["name"] = "Extruder %s" % (position + 1) parser["general"]["id"] = stack_id parser.add_section("metadata") parser["metadata"]["type"] = "extruder_train" parser["metadata"]["machine"] = machine_id parser["metadata"]["position"] = str(position) parser.add_section("containers") parser["containers"]["0"] = user_settings_id parser["containers"]["1"] = "empty_quality_changes" parser["containers"]["2"] = quality_id parser["containers"]["3"] = material_id parser["containers"]["4"] = "empty_variant" parser["containers"]["5"] = definition_changes_id parser["containers"]["6"] = definition_id definition_changes_output = io.StringIO() definition_changes_parser.write(definition_changes_output) definition_changes_filename = quote_plus(definition_changes_id) + ".inst.cfg" user_settings_output = io.StringIO() user_settings_parser.write(user_settings_output) user_settings_filename = quote_plus(user_settings_id) + ".inst.cfg" extruder_output = io.StringIO() parser.write(extruder_output) extruder_filename = quote_plus(stack_id) + ".extruder.cfg" extruder_stack_dir = Resources.getPath(CuraApplication.ResourceTypes.ExtruderStack) definition_changes_dir = Resources.getPath(CuraApplication.ResourceTypes.DefinitionChangesContainer) user_settings_dir = Resources.getPath(CuraApplication.ResourceTypes.UserInstanceContainer) with open(os.path.join(definition_changes_dir, definition_changes_filename), "w", encoding = "utf-8") as f: f.write(definition_changes_output.getvalue()) with open(os.path.join(user_settings_dir, user_settings_filename), "w", encoding = "utf-8") as f: f.write(user_settings_output.getvalue()) with open(os.path.join(extruder_stack_dir, extruder_filename), "w", encoding = "utf-8") as f: f.write(extruder_output.getvalue())
def __init__(self, **kwargs): plugin_path = "" if sys.platform == "win32": plugin_path = os.path.join(os.path.dirname(os.path.abspath(sys.executable)), "PyQt5", "plugins") Logger.log("i", "Adding QT5 plugin path: %s" % (plugin_path)) QCoreApplication.addLibraryPath(plugin_path) elif sys.platform == "darwin": plugin_path = os.path.join(Application.getInstallPrefix(), "Resources", "plugins") if plugin_path: Logger.log("i", "Adding QT5 plugin path: %s" % (plugin_path)) QCoreApplication.addLibraryPath(plugin_path) os.environ["QSG_RENDER_LOOP"] = "basic" super().__init__(sys.argv, **kwargs) self._main_qml = "main.qml" self._engine = None self._renderer = None self.setAttribute(Qt.AA_UseDesktopOpenGL) try: self._splash = QSplashScreen(QPixmap(Resources.getPath(Resources.ImagesLocation, self.getApplicationName() + ".png"))) except FileNotFoundError: self._splash = None else: self._splash.show() self.processEvents() signal.signal(signal.SIGINT, signal.SIG_DFL) # This is done here as a lot of plugins require a correct gl context. If you want to change the framework, # these checks need to be done in your <framework>Application.py class __init__(). i18n_catalog = i18nCatalog("uranium") self.showSplashMessage(i18n_catalog.i18nc("Splash screen message", "Loading plugins...")) self._loadPlugins() self._plugin_registry.checkRequiredPlugins(self.getRequiredPlugins()) self.showSplashMessage(i18n_catalog.i18nc("Splash screen message", "Loading machines...")) self.loadMachines() self.showSplashMessage(i18n_catalog.i18nc("Splash screen message", "Loading preferences...")) try: file = Resources.getPath(Resources.PreferencesLocation, self.getApplicationName() + ".cfg") Preferences.getInstance().readFromFile(file) except FileNotFoundError: pass self._translators = {} self.showSplashMessage(i18n_catalog.i18nc("Splash screen message", "Loading translations...")) self.loadQtTranslation("uranium_qt") self.loadQtTranslation(self.getApplicationName() + "_qt")
def _extractArchive(archive: "ZipFile", target_path: str) -> bool: Logger.log("d", "Removing current data in location: %s", target_path) Resources.factoryReset() Logger.log("d", "Extracting backup to location: %s", target_path) try: archive.extractall(target_path) except PermissionError: Logger.logException("e", "Unable to extract the backup due to permission errors") return False return True
def _getUpgradeTasks(self): storage_path_prefixes = set() storage_path_prefixes.add(Resources.getConfigStoragePath()) storage_path_prefixes.add(Resources.getDataStoragePath()) for old_configuration_type, storage_paths in self._storage_paths.items(): for prefix in storage_path_prefixes: for storage_path in storage_paths: path = os.path.join(prefix, storage_path) for configuration_file in self._getFilesInDirectory(path): yield UpgradeTask(storage_path = path, file_name = configuration_file, configuration_type = old_configuration_type)
def __init__(self): Resources.addSearchPath(os.path.join(QtApplication.getInstallPrefix(), "share", "cura", "resources")) if not hasattr(sys, "frozen"): Resources.addSearchPath(os.path.join(os.path.abspath(os.path.dirname(__file__)), "..", "resources")) self._open_file_queue = [] # Files to open when plug-ins are loaded. super().__init__(name = "cura", version = CuraVersion) self.setWindowIcon(QIcon(Resources.getPath(Resources.Images, "cura-icon.png"))) self.setRequiredPlugins([ "CuraEngineBackend", "MeshView", "LayerView", "STLReader", "SelectionTool", "CameraTool", "GCodeWriter", "LocalFileOutputDevice" ]) self._physics = None self._volume = None self._platform = None self._output_devices = {} self._print_information = None self._i18n_catalog = None self._previous_active_tool = None self._platform_activity = False self._scene_boundingbox = AxisAlignedBox() self._job_name = None self._center_after_select = False self._camera_animation = None self._cura_actions = None self.getMachineManager().activeMachineInstanceChanged.connect(self._onActiveMachineChanged) self.getMachineManager().addMachineRequested.connect(self._onAddMachineRequested) self.getController().getScene().sceneChanged.connect(self.updatePlatformActivity) self.getController().toolOperationStopped.connect(self._onToolOperationStopped) Resources.addType(self.ResourceTypes.QmlFiles, "qml") Resources.addType(self.ResourceTypes.Firmware, "firmware") Preferences.getInstance().addPreference("cura/active_machine", "") Preferences.getInstance().addPreference("cura/active_mode", "simple") Preferences.getInstance().addPreference("cura/recent_files", "") Preferences.getInstance().addPreference("cura/categories_expanded", "") Preferences.getInstance().addPreference("view/center_on_select", True) Preferences.getInstance().addPreference("mesh/scale_to_fit", True) Preferences.getInstance().setDefault("local_file/last_used_type", "text/x-gcode") JobQueue.getInstance().jobFinished.connect(self._onJobFinished) self._recent_files = [] files = Preferences.getInstance().getValue("cura/recent_files").split(";") for f in files: if not os.path.isfile(f): continue self._recent_files.append(QUrl.fromLocalFile(f))
def __init__(self, width, height): super().__init__("selection", width, height, -999) self._shader = OpenGL.getInstance().createShaderProgram(Resources.getPath(Resources.Shaders, "selection.shader")) self._tool_handle_shader = OpenGL.getInstance().createShaderProgram(Resources.getPath(Resources.Shaders, "default.shader")) self._gl = OpenGL.getInstance().getBindingsObject() self._scene = Application.getInstance().getController().getScene() self._renderer = Application.getInstance().getRenderer() self._selection_map = {} self._output = None
def loadProfiles(self): storage_path = Resources.getStoragePathForType(Resources.Profiles) dirs = Resources.getAllPathsForType(Resources.Profiles) for dir in dirs: if not os.path.isdir(dir): continue read_only = dir != storage_path for root, dirs, files in os.walk(dir): for file_name in files: path = os.path.join(root, file_name) if os.path.isdir(path): continue profile = Profile(self, read_only) try: profile.loadFromFile(path) except Exception as e: Logger.log("e", "An exception occurred loading Profile %s: %s", path, str(e)) continue if not self.findProfile(profile.getName(), variant_name = profile.getMachineVariantName(), material_name = profile.getMaterialName(), instance = self._active_machine): self._profiles.append(profile) profile.nameChanged.connect(self._onProfileNameChanged) for instance in self._machine_instances: try: file_name = urllib.parse.quote_plus(instance.getName()) + ".curaprofile" instance.getWorkingProfile().loadFromFile(Resources.getStoragePath(Resources.MachineInstanceProfiles, file_name)) except Exception as e: Logger.log("w", "Could not load working profile: %s: %s", file_name, str(e)) self._setDefaultVariantMaterialProfile(instance) self._protect_working_profile = True if self._active_machine: profile_name = self._active_machine.getActiveProfileName() if profile_name == "": profile_name = "Normal Quality" profile = self.findProfile(self._active_machine.getActiveProfileName(), instance = self._active_machine) if profile: self.setActiveProfile(profile) else: profiles = self.getProfiles(instance = self._active_machine) if len(profiles) > 0: self.setActiveProfile(profiles[0]) self.profilesChanged.emit() self._protect_working_profile = False
def render(self, renderer): if not self._material: self._material = renderer.createMaterial( Resources.getPath(Resources.ShadersLocation, "basic.vert"), Resources.getPath(Resources.ShadersLocation, "color.frag"), ) self._material.setUniformValue("u_color", Color(35, 35, 35, 128)) if self.getParent(): renderer.queueNode(self, material=self._material, transparent=True) return True
def saveAll(self): for instance in self.findInstanceContainers(): if not instance.isDirty(): continue try: data = instance.serialize() except NotImplementedError: # Serializing is not supported so skip this container continue except Exception: Logger.logException("e", "An exception occurred trying to serialize container %s", instance.getId()) continue file_name = urllib.parse.quote_plus(instance.getId()) + ".inst.cfg" path = Resources.getStoragePath(Resources.InstanceContainers, file_name) with SaveFile(path, "wt", -1, "utf-8") as f: f.write(data) for stack in self.findContainerStacks(): if not stack.isDirty(): continue try: data = stack.serialize() except NotImplementedError: # Serializing is not supported so skip this container continue except Exception: Logger.logException("e", "An exception occurred trying to serialize container %s", stack.getId()) continue file_name = urllib.parse.quote_plus(stack.getId()) + ".stack.cfg" path = Resources.getStoragePath(Resources.ContainerStacks, file_name) with SaveFile(path, "wt", -1, "utf-8") as f: f.write(data) for definition in self.findDefinitionContainers(): try: data = definition.serialize() except NotImplementedError: # Serializing is not supported so skip this container continue except Exception: Logger.logException("e", "An exception occurred trying to serialize container %s", instance.getId()) continue file_name = urllib.parse.quote_plus(definition.getId()) + ".def.cfg" path = Resources.getStoragePath(Resources.DefinitionContainers, file_name) with SaveFile(path, "wt", -1, "utf-8") as f: f.write(data)
def _onActiveMachineChanged(self): if self._settings: self.setMeshData(None) app = Application.getInstance() self._settings = app.getActiveMachine() if self._settings: mesh = self._settings.getPlatformMesh() self.setMeshData(app.getMeshFileHandler().read(Resources.getPath(Resources.MeshesLocation, mesh), app.getStorageDevice("LocalFileStorage"), center = False)) self._texture = self._settings.getPlatformTexture() if self._material and self._texture: self._material.setUniformTexture("u_texture", Resources.getPath(Resources.ImagesLocation, self._texture))
def _upgradeFile(self, storage_path_absolute, configuration_file, old_configuration_type, paths): configuration_file_absolute = os.path.join(storage_path_absolute, configuration_file) #Read the old file. try: with open(configuration_file_absolute, encoding="utf-8", errors="ignore") as file_handle: files_data = [file_handle.read()] except IOError: Logger.log("w", "Can't open configuration file %s for reading.", configuration_file_absolute) return False #Get the version number of the old file. try: old_version = self._get_version_functions[old_configuration_type]( files_data[0]) except: #Version getter gives an exception. Not a valid file. Can't upgrade it then. return False version = old_version configuration_type = old_configuration_type filenames_without_extension = [os.path.splitext(configuration_file)[0]] #Keep converting the file until it's at one of the current versions. while (configuration_type, version) not in self._current_versions: if (configuration_type, version) not in paths: #No version upgrade plug-in claims to be able to upgrade this file. return False new_type, new_version, upgrade = paths[(configuration_type, version)] new_filenames_without_extension = [] new_files_data = [] for file_idx, file_data in enumerate(files_data): try: this_filenames_without_extension, this_files_data = upgrade( file_data, filenames_without_extension[file_idx]) except Exception as e: #Upgrade failed due to a coding error in the plug-in. Logger.logException("w", "Exception in %s upgrade with %s: %s", old_configuration_type, upgrade.__module__, str(e)) return False if not this_files_data: #Upgrade failed. return False new_filenames_without_extension += this_filenames_without_extension new_files_data += this_files_data filenames_without_extension = new_filenames_without_extension files_data = new_files_data version = new_version configuration_type = new_type #If the version changed, save the new files. if version != old_version or configuration_type != old_configuration_type: self._storeOldFile(storage_path_absolute, configuration_file, old_version) #Finding out where to store these files. resource_type, mime_type = self._current_versions[( configuration_type, version)] storage_path = Resources.getStoragePathForType(resource_type) mime_type = UM.MimeTypeDatabase.getMimeType( mime_type) #Get the actual MIME type object, from the name. if mime_type.preferredSuffix: extension = "." + mime_type.preferredSuffix elif mime_type.suffixes: extension = "." + mime_type.suffixes[0] else: extension = "" #No known suffix. Put no extension behind it. new_filenames = [ filename + extension for filename in filenames_without_extension ] configuration_files_absolute = [ os.path.join(storage_path, filename) for filename in new_filenames ] for file_idx, configuration_file_absolute in enumerate( configuration_files_absolute): try: with open(os.path.join(configuration_file_absolute), "w", encoding="utf-8") as file_handle: file_handle.write( files_data[file_idx]) #Save the new file. except IOError: Logger.log("w", "Couldn't write new configuration file to %s.", configuration_file_absolute) return False Logger.log("i", "Upgraded %s to version %s.", configuration_file, str(version)) return True return False #Version didn't change. Was already current.
def getCacheLockFilename(self) -> str: """Get the cache lock filename including full path.""" return Resources.getStoragePath( Resources.Cache, self._application.getApplicationLockFilename())
def __init__(self): Resources.addSearchPath( os.path.join(QtApplication.getInstallPrefix(), "share", "cura", "resources")) if not hasattr(sys, "frozen"): Resources.addSearchPath( os.path.join(os.path.abspath(os.path.dirname(__file__)), "..", "resources")) self._open_file_queue = [] # Files to open when plug-ins are loaded. super().__init__(name="cura", version=CuraVersion) self.setWindowIcon( QIcon(Resources.getPath(Resources.Images, "cura-icon.png"))) self.setRequiredPlugins([ "CuraEngineBackend", "MeshView", "LayerView", "STLReader", "SelectionTool", "CameraTool", "GCodeWriter", "LocalFileOutputDevice" ]) self._physics = None self._volume = None self._platform = None self._output_devices = {} self._print_information = None self._i18n_catalog = None self._previous_active_tool = None self._platform_activity = False self._scene_boundingbox = AxisAlignedBox() self._job_name = None self._center_after_select = False self._camera_animation = None self._cura_actions = None self.getMachineManager().activeMachineInstanceChanged.connect( self._onActiveMachineChanged) self.getMachineManager().addMachineRequested.connect( self._onAddMachineRequested) self.getController().getScene().sceneChanged.connect( self.updatePlatformActivity) self.getController().toolOperationStopped.connect( self._onToolOperationStopped) Resources.addType(self.ResourceTypes.QmlFiles, "qml") Resources.addType(self.ResourceTypes.Firmware, "firmware") Preferences.getInstance().addPreference("cura/active_machine", "") Preferences.getInstance().addPreference("cura/active_mode", "simple") Preferences.getInstance().addPreference("cura/recent_files", "") Preferences.getInstance().addPreference("cura/categories_expanded", "") Preferences.getInstance().addPreference("view/center_on_select", True) Preferences.getInstance().addPreference("mesh/scale_to_fit", True) Preferences.getInstance().setDefault("local_file/last_used_type", "text/x-gcode") JobQueue.getInstance().jobFinished.connect(self._onJobFinished) self._recent_files = [] files = Preferences.getInstance().getValue("cura/recent_files").split( ";") for f in files: if not os.path.isfile(f): continue self._recent_files.append(QUrl.fromLocalFile(f))
def getEngineCommand(self): json_path = Resources.getPath(Resources.DefinitionContainers, "fdmprinter.def.json") return [Preferences.getInstance().getValue("backend/location"), "connect", "127.0.0.1:{0}".format(self._port), "-j", json_path, ""]
def load(self, path: str, is_first_call: bool = True) -> None: if path == self._path: return theme_full_path = os.path.join(path, "theme.json") Logger.log( "d", "Loading theme file: {theme_full_path}".format( theme_full_path=theme_full_path)) try: with open(theme_full_path, encoding="utf-8") as f: data = json.load(f) except EnvironmentError as e: Logger.error( "Unable to load theme file at {theme_full_path}: {err}".format( theme_full_path=theme_full_path, err=e)) return except UnicodeDecodeError: Logger.error( "Theme file at {theme_full_path} is corrupt (invalid UTF-8 bytes)." .format(theme_full_path=theme_full_path)) return except json.JSONDecodeError: Logger.error( "Theme file at {theme_full_path} is corrupt (invalid JSON syntax)." .format(theme_full_path=theme_full_path)) return # Iteratively load inherited themes try: theme_id = data["metadata"]["inherits"] self.load(Resources.getPath(Resources.Themes, theme_id), is_first_call=False) except FileNotFoundError: Logger.log("e", "Could not find inherited theme %s", theme_id) except KeyError: pass # No metadata or no inherits keyword in the theme.json file if "colors" in data: for name, color in data["colors"].items(): try: c = QColor(color[0], color[1], color[2], color[3]) except IndexError: # Color doesn't have enough components. Logger.log( "w", "Colour {name} doesn't have enough components. Need to have 4, but had {num_components}." .format(name=name, num_components=len(color))) continue # Skip this one then. self._colors[name] = c fonts_dir = os.path.join(path, "fonts") if os.path.isdir(fonts_dir): for root, dirnames, filenames in os.walk(fonts_dir): for filename in filenames: if filename.lower().endswith(".ttf"): QFontDatabase.addApplicationFont( os.path.join(root, filename)) if "fonts" in data: system_font_size = QCoreApplication.instance().font().pointSize() for name, font in data["fonts"].items(): q_font = QFont() q_font.setFamily( font.get("family", QCoreApplication.instance().font().family())) if font.get("bold"): q_font.setBold(font.get("bold", False)) else: q_font.setWeight(font.get("weight", 50)) q_font.setLetterSpacing(QFont.AbsoluteSpacing, font.get("letterSpacing", 0)) q_font.setItalic(font.get("italic", False)) q_font.setPointSize(int( font.get("size", 1) * system_font_size)) q_font.setCapitalization(QFont.AllUppercase if font.get( "capitalize", False) else QFont.MixedCase) self._fonts[name] = q_font if "sizes" in data: for name, size in data["sizes"].items(): s = QSizeF() s.setWidth(round(size[0] * self._em_width)) s.setHeight(round(size[1] * self._em_height)) self._sizes[name] = s iconsdir = os.path.join(path, "icons") if os.path.isdir(iconsdir): for icon in os.listdir(iconsdir): name = os.path.splitext(icon)[0] self._icons[name] = QUrl.fromLocalFile( os.path.join(iconsdir, icon)) imagesdir = os.path.join(path, "images") if os.path.isdir(imagesdir): for image in os.listdir(imagesdir): name = os.path.splitext(image)[0] self._images[name] = QUrl.fromLocalFile( os.path.join(imagesdir, image)) styles = os.path.join(path, "styles.qml") if os.path.isfile(styles): c = QQmlComponent(self._engine, styles) context = QQmlContext(self._engine, self._engine) context.setContextProperty("Theme", self) self._styles = c.create(context) if c.isError(): for error in c.errors(): Logger.log("e", error.toString()) Logger.log("d", "Loaded theme %s", path) self._path = path # only emit the theme loaded signal once after all the themes in the inheritance chain have been loaded if is_first_call: self.themeLoaded.emit()
def load(self) -> None: files = [] for resource_type in self._resource_types: resources = Resources.getAllResourcesOfType(resource_type) try: resource_storage_path = Resources.getStoragePathForType( resource_type) except UnsupportedStorageTypeError: resource_storage_path = "" # Pre-process the list of files to insert relevant data # Most importantly, we need to ensure the loading order is DefinitionContainer, InstanceContainer, ContainerStack for path in resources: mime = MimeTypeDatabase.getMimeTypeForFile(path) container_type = self.__mime_type_map.get(mime.name) if not container_type: Logger.log( "w", "Could not determine container type for file %s, ignoring", path) continue type_priority = container_type.getLoadingPriority() # Since we have the mime type and resource type here, process these two properties so we do not # need to look up mime types etc. again. container_id = urllib.parse.unquote_plus( mime.stripExtension(os.path.basename(path))) read_only = os.path.realpath(os.path.dirname( path)) != os.path.realpath(resource_storage_path) files.append((type_priority, container_id, path, read_only, container_type)) # Sort the list of files by type_priority so we can ensure correct loading order. files = sorted(files, key=lambda i: i[0]) resource_start_time = time.time() for _, container_id, file_path, read_only, container_type in files: if container_id in self._id_container_cache: Logger.log("c", "Found a container with a duplicate ID: %s", container_id) Logger.log( "c", "Existing container is %s, trying to load %s from %s", self._id_container_cache[container_id], container_type, file_path) continue try: if issubclass(container_type, DefinitionContainer): definition = self._loadCachedDefinition( container_id, file_path) if definition: self.addContainer(definition) continue new_container = container_type(container_id) with open(file_path, encoding="utf-8") as f: new_container.deserialize(f.read()) new_container.setReadOnly(read_only) new_container.setPath(file_path) if issubclass(container_type, DefinitionContainer): self._saveCachedDefinition(new_container) self.addContainer(new_container) except Exception as e: Logger.logException("e", "Could not deserialize container %s", container_id) Logger.log("d", "Loading data into container registry took %s seconds", time.time() - resource_start_time)
def run(self): self.showSplashMessage( self._i18n_catalog.i18nc("@info:progress", "Setting up scene...")) controller = self.getController() controller.setActiveView("SolidView") controller.setCameraTool("CameraTool") controller.setSelectionTool("SelectionTool") t = controller.getTool("TranslateTool") if t: t.setEnabledAxis( [ToolHandle.XAxis, ToolHandle.YAxis, ToolHandle.ZAxis]) Selection.selectionChanged.connect(self.onSelectionChanged) root = controller.getScene().getRoot() # The platform is a child of BuildVolume self._volume = BuildVolume.BuildVolume(root) self.getRenderer().setBackgroundColor(QColor(245, 245, 245)) self._physics = PlatformPhysics.PlatformPhysics( controller, self._volume) camera = Camera("3d", root) camera.setPosition(Vector(-80, 250, 700)) camera.setPerspective(True) camera.lookAt(Vector(0, 0, 0)) controller.getScene().setActiveCamera("3d") self.getController().getTool("CameraTool").setOrigin(Vector(0, 100, 0)) self._camera_animation = CameraAnimation.CameraAnimation() self._camera_animation.setCameraTool( self.getController().getTool("CameraTool")) self.showSplashMessage( self._i18n_catalog.i18nc("@info:progress", "Loading interface...")) # Initialise extruder so as to listen to global container stack changes before the first global container stack is set. cura.Settings.ExtruderManager.getInstance() qmlRegisterSingletonType(cura.Settings.MachineManager, "Cura", 1, 0, "MachineManager", self.getMachineManager) qmlRegisterSingletonType(cura.Settings.SettingInheritanceManager, "Cura", 1, 0, "SettingInheritanceManager", self.getSettingInheritanceManager) qmlRegisterSingletonType(MachineActionManager.MachineActionManager, "Cura", 1, 0, "MachineActionManager", self.getMachineActionManager) self.setMainQml( Resources.getPath(self.ResourceTypes.QmlFiles, "Cura.qml")) self._qml_import_paths.append( Resources.getPath(self.ResourceTypes.QmlFiles)) self.initializeEngine() if self._engine.rootObjects: self.closeSplash() for file in self.getCommandLineOption("file", []): self._openFile(file) for file_name in self._open_file_queue: #Open all the files that were queued up while plug-ins were loading. self._openFile(file_name) self._started = True self.exec_()
def getLockFilename(self): return Resources.getStoragePath(Resources.Resources, CONFIG_LOCK_FILENAME)
def installPackage(self, filename: str) -> Optional[str]: """Schedules the given package file to be installed upon the next start. :return: The to-be-installed package_id or None if something went wrong """ has_changes = False package_id = "" try: # Get package information package_info = self.getPackageInfo(filename) if not package_info: return None package_id = package_info["package_id"] # If the package is being installed but it is in the list on to remove, then it is deleted from that list. if package_id in self._to_remove_package_set: self._to_remove_package_set.remove(package_id) # We do not check if the same package has been installed already here because, for example, in Cura, # it may need to install a package with the same package-version but with a higher SDK version. So, # the package-version is not the only version that can be in play here. # Need to use the lock file to prevent concurrent I/O issues. with self._container_registry.lockFile(): Logger.log( "i", "Package [%s] version [%s] is scheduled to be installed.", package_id, package_info["package_version"]) # Copy the file to cache dir so we don't need to rely on the original file to be present package_cache_dir = os.path.join( os.path.abspath(Resources.getCacheStoragePath()), "cura_packages") if not os.path.exists(package_cache_dir): os.makedirs(package_cache_dir, exist_ok=True) target_file_path = os.path.join(package_cache_dir, package_id + ".curapackage") shutil.copy2(filename, target_file_path) self._to_install_package_dict[package_id] = { "package_info": package_info, "filename": target_file_path } has_changes = True except: Logger.logException("c", "Failed to install package file '%s'", filename) finally: self._saveManagementData() if has_changes: self.installedPackagesChanged.emit() if package_id in self._packages_with_update_available: # After installing the update, the check will return that not other updates are available. # In that case we remove it from the list. This is actually a safe check (could be removed) if not self.checkIfPackageCanUpdate(package_id): # The install ensured that the package no longer has a valid update option. self._packages_with_update_available.remove(package_id) self.packagesWithUpdateChanged.emit() if has_changes: self.packageInstalled.emit(package_id) return package_id else: return None
def __init__(self): Resources.addSearchPath( os.path.join(QtApplication.getInstallPrefix(), "share", "cura", "resources")) if not hasattr(sys, "frozen"): Resources.addSearchPath( os.path.join(os.path.abspath(os.path.dirname(__file__)), "..", "resources")) self._open_file_queue = [] # Files to open when plug-ins are loaded. # 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) # this setting can be changed for each group in one-at-a-time mode SettingDefinition.addSupportedProperty("settable_per_meshgroup", DefinitionPropertyType.Any, default=True, read_only=True) SettingDefinition.addSupportedProperty("settable_globally", DefinitionPropertyType.Any, default=True, read_only=True) # From which stack the setting would inherit if not defined per object (handled in the engine) # AND for settings which are not settable_per_mesh: # which extruder is the only extruder this setting is obtained from SettingDefinition.addSupportedProperty("limit_to_extruder", DefinitionPropertyType.Function, default="-1") # For settings which are not settable_per_mesh and not settable_per_extruder: # A function which determines the glabel/meshgroup value by looking at the values of the setting in all (used) extruders SettingDefinition.addSupportedProperty("resolve", DefinitionPropertyType.Function, default=None, depends_on="value") SettingDefinition.addSettingType("extruder", None, str, Validator) SettingFunction.registerOperator( "extruderValues", cura.Settings.ExtruderManager.getExtruderValues) SettingFunction.registerOperator( "extruderValue", cura.Settings.ExtruderManager.getExtruderValue) SettingFunction.registerOperator( "resolveOrValue", cura.Settings.ExtruderManager.getResolveOrValue) ## Add the 4 types of profiles to storage. Resources.addStorageType(self.ResourceTypes.QualityInstanceContainer, "quality") Resources.addStorageType(self.ResourceTypes.VariantInstanceContainer, "variants") Resources.addStorageType(self.ResourceTypes.MaterialInstanceContainer, "materials") Resources.addStorageType(self.ResourceTypes.UserInstanceContainer, "user") Resources.addStorageType(self.ResourceTypes.ExtruderStack, "extruders") Resources.addStorageType(self.ResourceTypes.MachineStack, "machine_instances") ContainerRegistry.getInstance().addResourceType( self.ResourceTypes.QualityInstanceContainer) ContainerRegistry.getInstance().addResourceType( self.ResourceTypes.VariantInstanceContainer) ContainerRegistry.getInstance().addResourceType( self.ResourceTypes.MaterialInstanceContainer) ContainerRegistry.getInstance().addResourceType( self.ResourceTypes.UserInstanceContainer) ContainerRegistry.getInstance().addResourceType( self.ResourceTypes.ExtruderStack) ContainerRegistry.getInstance().addResourceType( self.ResourceTypes.MachineStack) ## Initialise the version upgrade manager with Cura's storage paths. import UM.VersionUpgradeManager #Needs to be here to prevent circular dependencies. UM.VersionUpgradeManager.VersionUpgradeManager.getInstance( ).setCurrentVersions({ ("quality", UM.Settings.InstanceContainer.Version): (self.ResourceTypes.QualityInstanceContainer, "application/x-uranium-instancecontainer"), ("machine_stack", UM.Settings.ContainerStack.Version): (self.ResourceTypes.MachineStack, "application/x-uranium-containerstack"), ("preferences", UM.Preferences.Version): (Resources.Preferences, "application/x-uranium-preferences"), ("user", UM.Settings.InstanceContainer.Version): (self.ResourceTypes.UserInstanceContainer, "application/x-uranium-instancecontainer") }) self._machine_action_manager = MachineActionManager.MachineActionManager( ) self._machine_manager = None # This is initialized on demand. self._setting_inheritance_manager = None self._additional_components = { } # Components to add to certain areas in the interface super().__init__(name="cura", version=CuraVersion, buildtype=CuraBuildType) self.setWindowIcon( QIcon(Resources.getPath(Resources.Images, "cura-icon.png"))) self.setRequiredPlugins([ "CuraEngineBackend", "MeshView", "LayerView", "STLReader", "SelectionTool", "CameraTool", "GCodeWriter", "LocalFileOutputDevice" ]) 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._i18n_catalog = i18nCatalog("cura") self.getController().getScene().sceneChanged.connect( self.updatePlatformActivity) self.getController().toolOperationStopped.connect( self._onToolOperationStopped) 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() empty_variant_container = copy.deepcopy(empty_container) empty_variant_container._id = "empty_variant" empty_variant_container.addMetaDataEntry("type", "variant") ContainerRegistry.getInstance().addContainer(empty_variant_container) empty_material_container = copy.deepcopy(empty_container) empty_material_container._id = "empty_material" empty_material_container.addMetaDataEntry("type", "material") ContainerRegistry.getInstance().addContainer(empty_material_container) empty_quality_container = copy.deepcopy(empty_container) empty_quality_container._id = "empty_quality" empty_quality_container.setName("Not supported") empty_quality_container.addMetaDataEntry("quality_type", "normal") empty_quality_container.addMetaDataEntry("type", "quality") ContainerRegistry.getInstance().addContainer(empty_quality_container) empty_quality_changes_container = copy.deepcopy(empty_container) empty_quality_changes_container._id = "empty_quality_changes" empty_quality_changes_container.addMetaDataEntry( "type", "quality_changes") ContainerRegistry.getInstance().addContainer( empty_quality_changes_container) # Set the filename to create if cura is writing in the config dir. self._config_lock_filename = os.path.join( Resources.getConfigStoragePath(), CONFIG_LOCK_FILENAME) self.waitConfigLockFile() ContainerRegistry.getInstance().load() Preferences.getInstance().addPreference("cura/active_mode", "simple") Preferences.getInstance().addPreference("cura/recent_files", "") Preferences.getInstance().addPreference("cura/categories_expanded", "") Preferences.getInstance().addPreference("cura/jobname_prefix", True) Preferences.getInstance().addPreference("view/center_on_select", True) Preferences.getInstance().addPreference("mesh/scale_to_fit", True) Preferences.getInstance().addPreference("mesh/scale_tiny_meshes", True) for key in [ "dialog_load_path", # dialog_save_path is in LocalFileOutputDevicePlugin "dialog_profile_path", "dialog_material_path" ]: Preferences.getInstance().addPreference("local_file/%s" % key, os.path.expanduser("~/")) Preferences.getInstance().setDefault("local_file/last_used_type", "text/x-gcode") Preferences.getInstance().setDefault( "general/visible_settings", """ machine_settings resolution layer_height shell wall_thickness top_bottom_thickness infill infill_sparse_density material material_print_temperature material_bed_temperature material_diameter material_flow retraction_enable speed speed_print speed_travel acceleration_print acceleration_travel jerk_print jerk_travel travel cooling cool_fan_enabled support support_enable support_extruder_nr support_type support_interface_density platform_adhesion adhesion_type adhesion_extruder_nr brim_width raft_airgap layer_0_z_overlap raft_surface_layers dual prime_tower_enable prime_tower_size prime_tower_position_x prime_tower_position_y meshfix blackmagic print_sequence infill_mesh experimental """.replace("\n", ";").replace(" ", "")) JobQueue.getInstance().jobFinished.connect(self._onJobFinished) self.applicationShuttingDown.connect(self.saveSettings) self.engineCreatedSignal.connect(self._onEngineCreated) self._recent_files = [] files = Preferences.getInstance().getValue("cura/recent_files").split( ";") for f in files: if not os.path.isfile(f): continue self._recent_files.append(QUrl.fromLocalFile(f))
def __init__(self, application: "QtApplication", parent: Optional[QObject] = None) -> None: super().__init__(parent) self._application = application self._container_registry = self._application.getContainerRegistry() self._plugin_registry = self._application.getPluginRegistry() # JSON files that keep track of all installed packages. self._user_package_management_file_path = None # type: Optional[str] self._bundled_package_management_file_paths = [] # type: List[str] for search_path in Resources.getAllPathsForType( Resources.BundledPackages): if not os.path.isdir(search_path): continue # Load all JSON files that are located in the bundled_packages directory. try: for file_name in os.listdir(search_path): if not file_name.endswith(".json"): continue file_path = os.path.join(search_path, file_name) if not os.path.isfile(file_path): continue self._bundled_package_management_file_paths.append( file_path) Logger.log( "i", "Found bundled packages JSON file: {location}".format( location=file_path)) except EnvironmentError as e: # Unable to read directory. Could be corrupt disk or insufficient access to list the directory. Logger.log( "e", f"Unable to read package directory to search for packages JSON files: {str(e)}" ) pass for search_path in (Resources.getDataStoragePath(), Resources.getConfigStoragePath()): candidate_user_path = os.path.join(search_path, "packages.json") if os.path.exists(candidate_user_path): self._user_package_management_file_path = candidate_user_path if self._user_package_management_file_path is None: # Doesn't exist yet. self._user_package_management_file_path = os.path.join( Resources.getDataStoragePath(), "packages.json") self._installation_dirs_dict = { "plugins": os.path.abspath(Resources.getStoragePath(Resources.Plugins)) } # type: Dict[str, str] self._bundled_package_dict = { } # type: Dict[str, Dict[str, Any]] # A dict of all bundled packages self._installed_package_dict = { } # type: Dict[str, Dict[str, Any]] # A dict of all installed packages self._to_remove_package_set = set( ) # type: Set[str] # A set of packages that need to be removed at the next start self._to_install_package_dict = { } # type: Dict[str, Dict[str, Any]] # A dict of packages that need to be installed at the next start self._dismissed_packages = set( ) # type: Set[str] # A set of packages that are dismissed by the user # There can be plugins that provide remote packages (and thus, newer / different versions for a package). self._available_package_versions = { } # type: Dict[str, Set[UMVersion]] self._packages_with_update_available = set() # type: Set[str]
def _checkSetup(self): if not self._extruders_model: self._extruders_model = Application.getInstance( ).getExtrudersModel() if not self._theme: self._theme = Application.getInstance().getTheme() if not self._enabled_shader: self._enabled_shader = OpenGL.getInstance().createShaderProgram( Resources.getPath(Resources.Shaders, "overhang.shader")) self._enabled_shader.setUniformValue( "u_overhangColor", Color(*self._theme.getColor("model_overhang").getRgb())) self._enabled_shader.setUniformValue("u_renderError", 0.0) if not self._disabled_shader: self._disabled_shader = OpenGL.getInstance().createShaderProgram( Resources.getPath(Resources.Shaders, "striped.shader")) self._disabled_shader.setUniformValue( "u_diffuseColor1", Color(*self._theme.getColor("model_unslicable").getRgb())) self._disabled_shader.setUniformValue( "u_diffuseColor2", Color(*self._theme.getColor("model_unslicable_alt").getRgb())) self._disabled_shader.setUniformValue("u_width", 50.0) if not self._non_printing_shader: self._non_printing_shader = OpenGL.getInstance( ).createShaderProgram( Resources.getPath(Resources.Shaders, "transparent_object.shader")) self._non_printing_shader.setUniformValue( "u_diffuseColor", Color(*self._theme.getColor("model_non_printing").getRgb())) self._non_printing_shader.setUniformValue("u_opacity", 0.6) if not self._support_mesh_shader: self._support_mesh_shader = OpenGL.getInstance( ).createShaderProgram( Resources.getPath(Resources.Shaders, "striped.shader")) self._support_mesh_shader.setUniformValue("u_vertical_stripes", True) self._support_mesh_shader.setUniformValue("u_width", 5.0) if not Application.getInstance().getPreferences().getValue( self._show_xray_warning_preference): self._xray_shader = None self._xray_composite_shader = None if self._composite_pass and 'xray' in self._composite_pass.getLayerBindings( ): self._composite_pass.setLayerBindings(self._old_layer_bindings) self._composite_pass.setCompositeShader( self._old_composite_shader) self._old_layer_bindings = None self._old_composite_shader = None self._enabled_shader.setUniformValue( "u_renderError", 0.0) # We don't want any error markers!. self._xray_warning_message.hide() else: if not self._xray_shader: self._xray_shader = OpenGL.getInstance().createShaderProgram( Resources.getPath(Resources.Shaders, "xray.shader")) if not self._xray_composite_shader: self._xray_composite_shader = OpenGL.getInstance( ).createShaderProgram( Resources.getPath(Resources.Shaders, "xray_composite.shader")) theme = Application.getInstance().getTheme() self._xray_composite_shader.setUniformValue( "u_background_color", Color(*theme.getColor("viewport_background").getRgb())) self._xray_composite_shader.setUniformValue( "u_outline_color", Color(*theme.getColor("model_selection_outline").getRgb())) self._xray_composite_shader.setUniformValue( "u_flat_error_color_mix", 0.) # Don't show flat error color in solid-view. renderer = self.getRenderer() if not self._composite_pass or not 'xray' in self._composite_pass.getLayerBindings( ): # Currently the RenderPass constructor requires a size > 0 # This should be fixed in RenderPass's constructor. self._xray_pass = XRayPass.XRayPass(1, 1) self._enabled_shader.setUniformValue( "u_renderError", 1.0) # We don't want any error markers!. renderer.addRenderPass(self._xray_pass) if not self._composite_pass: self._composite_pass = self.getRenderer().getRenderPass( "composite") self._old_layer_bindings = self._composite_pass.getLayerBindings( ) self._composite_pass.setLayerBindings( ["default", "selection", "xray"]) self._old_composite_shader = self._composite_pass.getCompositeShader( ) self._composite_pass.setCompositeShader( self._xray_composite_shader)
def render(self): if not self._layer_shader: if self._compatibility_mode: shader_filename = "layers.shader" shadow_shader_filename = "layers_shadow.shader" else: shader_filename = "layers3d.shader" shadow_shader_filename = "layers3d_shadow.shader" self._layer_shader = OpenGL.getInstance().createShaderProgram(os.path.join(PluginRegistry.getInstance().getPluginPath("SimulationView"), shader_filename)) self._layer_shadow_shader = OpenGL.getInstance().createShaderProgram(os.path.join(PluginRegistry.getInstance().getPluginPath("SimulationView"), shadow_shader_filename)) self._current_shader = self._layer_shader # Use extruder 0 if the extruder manager reports extruder index -1 (for single extrusion printers) self._layer_shader.setUniformValue("u_active_extruder", float(max(0, self._extruder_manager.activeExtruderIndex))) if not self._compatibility_mode: self._layer_shader.setUniformValue("u_starts_color", Color(*Application.getInstance().getTheme().getColor("layerview_starts").getRgb())) if self._layer_view: self._layer_shader.setUniformValue("u_max_feedrate", self._layer_view.getMaxFeedrate()) self._layer_shader.setUniformValue("u_min_feedrate", self._layer_view.getMinFeedrate()) self._layer_shader.setUniformValue("u_max_thickness", self._layer_view.getMaxThickness()) self._layer_shader.setUniformValue("u_min_thickness", self._layer_view.getMinThickness()) self._layer_shader.setUniformValue("u_max_line_width", self._layer_view.getMaxLineWidth()) self._layer_shader.setUniformValue("u_min_line_width", self._layer_view.getMinLineWidth()) self._layer_shader.setUniformValue("u_layer_view_type", self._layer_view.getSimulationViewType()) self._layer_shader.setUniformValue("u_extruder_opacity", self._layer_view.getExtruderOpacities()) self._layer_shader.setUniformValue("u_show_travel_moves", self._layer_view.getShowTravelMoves()) self._layer_shader.setUniformValue("u_show_helpers", self._layer_view.getShowHelpers()) self._layer_shader.setUniformValue("u_show_skin", self._layer_view.getShowSkin()) self._layer_shader.setUniformValue("u_show_infill", self._layer_view.getShowInfill()) self._layer_shader.setUniformValue("u_show_starts", self._layer_view.getShowStarts()) else: #defaults self._layer_shader.setUniformValue("u_max_feedrate", 1) self._layer_shader.setUniformValue("u_min_feedrate", 0) self._layer_shader.setUniformValue("u_max_thickness", 1) self._layer_shader.setUniformValue("u_min_thickness", 0) self._layer_shader.setUniformValue("u_max_line_width", 1) self._layer_shader.setUniformValue("u_min_line_width", 0) self._layer_shader.setUniformValue("u_layer_view_type", 1) self._layer_shader.setUniformValue("u_extruder_opacity", [[1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]]) self._layer_shader.setUniformValue("u_show_travel_moves", 0) self._layer_shader.setUniformValue("u_show_helpers", 1) self._layer_shader.setUniformValue("u_show_skin", 1) self._layer_shader.setUniformValue("u_show_infill", 1) self._layer_shader.setUniformValue("u_show_starts", 1) if not self._tool_handle_shader: self._tool_handle_shader = OpenGL.getInstance().createShaderProgram(Resources.getPath(Resources.Shaders, "toolhandle.shader")) if not self._nozzle_shader: self._nozzle_shader = OpenGL.getInstance().createShaderProgram(Resources.getPath(Resources.Shaders, "color.shader")) self._nozzle_shader.setUniformValue("u_color", Color(*Application.getInstance().getTheme().getColor("layerview_nozzle").getRgb())) if not self._disabled_shader: self._disabled_shader = OpenGL.getInstance().createShaderProgram(Resources.getPath(Resources.Shaders, "striped.shader")) self._disabled_shader.setUniformValue("u_diffuseColor1", Color(*Application.getInstance().getTheme().getColor("model_unslicable").getRgb())) self._disabled_shader.setUniformValue("u_diffuseColor2", Color(*Application.getInstance().getTheme().getColor("model_unslicable_alt").getRgb())) self._disabled_shader.setUniformValue("u_width", 50.0) self._disabled_shader.setUniformValue("u_opacity", 0.6) self.bind() tool_handle_batch = RenderBatch(self._tool_handle_shader, type = RenderBatch.RenderType.Overlay, backface_cull = True) disabled_batch = RenderBatch(self._disabled_shader) head_position = None # Indicates the current position of the print head nozzle_node = None for node in DepthFirstIterator(self._scene.getRoot()): if isinstance(node, ToolHandle): tool_handle_batch.addItem(node.getWorldTransformation(), mesh = node.getSolidMesh()) elif isinstance(node, NozzleNode): nozzle_node = node nozzle_node.setVisible(False) # Don't set to true, we render it separately! elif getattr(node, "_outside_buildarea", False) and isinstance(node, SceneNode) and node.getMeshData() and node.isVisible() and not node.callDecoration("isNonPrintingMesh"): disabled_batch.addItem(node.getWorldTransformation(copy=False), node.getMeshData()) elif isinstance(node, SceneNode) and (node.getMeshData() or node.callDecoration("isBlockSlicing")) and node.isVisible(): layer_data = node.callDecoration("getLayerData") if not layer_data: continue # Render all layers below a certain number as line mesh instead of vertices. if self._layer_view._current_layer_num > -1 and ((not self._layer_view._only_show_top_layers) or (not self._layer_view.getCompatibilityMode())): start = 0 end = 0 element_counts = layer_data.getElementCounts() for layer in sorted(element_counts.keys()): # In the current layer, we show just the indicated paths if layer == self._layer_view._current_layer_num: # We look for the position of the head, searching the point of the current path index = self._layer_view._current_path_num offset = 0 for polygon in layer_data.getLayer(layer).polygons: # The size indicates all values in the two-dimension array, and the second dimension is # always size 3 because we have 3D points. if index >= polygon.data.size // 3 - offset: index -= polygon.data.size // 3 - offset offset = 1 # This is to avoid the first point when there is more than one polygon, since has the same value as the last point in the previous polygon continue # The head position is calculated and translated head_position = Vector(polygon.data[index+offset][0], polygon.data[index+offset][1], polygon.data[index+offset][2]) + node.getWorldPosition() break break if self._layer_view._minimum_layer_num > layer: start += element_counts[layer] end += element_counts[layer] # Calculate the range of paths in the last layer current_layer_start = end current_layer_end = end + self._layer_view._current_path_num * 2 # Because each point is used twice # This uses glDrawRangeElements internally to only draw a certain range of lines. # All the layers but the current selected layer are rendered first if self._old_current_path != self._layer_view._current_path_num: self._current_shader = self._layer_shadow_shader self._switching_layers = False if not self._layer_view.isSimulationRunning() and self._old_current_layer != self._layer_view._current_layer_num: self._current_shader = self._layer_shader self._switching_layers = True # The first line does not have a previous line: add a MoveCombingType in front for start detection # this way the first start of the layer can also be drawn prev_line_types = numpy.concatenate([numpy.asarray([LayerPolygon.MoveCombingType], dtype = numpy.float32), layer_data._attributes["line_types"]["value"]]) # Remove the last element prev_line_types = prev_line_types[0:layer_data._attributes["line_types"]["value"].size] layer_data._attributes["prev_line_types"] = {'opengl_type': 'float', 'value': prev_line_types, 'opengl_name': 'a_prev_line_type'} layers_batch = RenderBatch(self._current_shader, type = RenderBatch.RenderType.Solid, mode = RenderBatch.RenderMode.Lines, range = (start, end), backface_cull = True) layers_batch.addItem(node.getWorldTransformation(), layer_data) layers_batch.render(self._scene.getActiveCamera()) # Current selected layer is rendered current_layer_batch = RenderBatch(self._layer_shader, type = RenderBatch.RenderType.Solid, mode = RenderBatch.RenderMode.Lines, range = (current_layer_start, current_layer_end)) current_layer_batch.addItem(node.getWorldTransformation(), layer_data) current_layer_batch.render(self._scene.getActiveCamera()) self._old_current_layer = self._layer_view._current_layer_num self._old_current_path = self._layer_view._current_path_num # Create a new batch that is not range-limited batch = RenderBatch(self._layer_shader, type = RenderBatch.RenderType.Solid) if self._layer_view.getCurrentLayerMesh(): batch.addItem(node.getWorldTransformation(), self._layer_view.getCurrentLayerMesh()) if self._layer_view.getCurrentLayerJumps(): batch.addItem(node.getWorldTransformation(), self._layer_view.getCurrentLayerJumps()) if len(batch.items) > 0: batch.render(self._scene.getActiveCamera()) # The nozzle is drawn when once we know the correct position of the head, # but the user is not using the layer slider, and the compatibility mode is not enabled if not self._switching_layers and not self._compatibility_mode and self._layer_view.getActivity() and nozzle_node is not None: if head_position is not None: nozzle_node.setPosition(head_position) nozzle_batch = RenderBatch(self._nozzle_shader, type = RenderBatch.RenderType.Transparent) nozzle_batch.addItem(nozzle_node.getWorldTransformation(), mesh = nozzle_node.getMeshData()) nozzle_batch.render(self._scene.getActiveCamera()) if len(disabled_batch.items) > 0: disabled_batch.render(self._scene.getActiveCamera()) # Render toolhandles on top of the layerview if len(tool_handle_batch.items) > 0: tool_handle_batch.render(self._scene.getActiveCamera()) self.release()
def beginRendering(self): # Convenience setup scene = self.getController().getScene() renderer = self.getRenderer() if not self._shader: self._shader = OpenGL.getInstance().createShaderProgram(Resources.getPath(Resources.Shaders, "color.shader")) self._shader.setUniformValue("u_color", Color(32, 32, 32, 170)) for node in DepthFirstIterator(scene.getRoot()): if not node.render(renderer): # For now we only render nodes that indicate that they need rendering. if node.getMeshData(): # Render origin of this node. renderer.queueNode(scene.getRoot(), mesh = self._getAxisMesh(node), transparent = True) # Render transparent MeshData renderer.queueNode(node, shader = self._shader, transparent = True) billboard_node = self._ensureNodeHasBillboard(node) # Update the displayed data on the billboard. data = self._matrixToHtml(node.getLocalTransformation()) billboard_node.setDisplayData({"name": node.getName(), "matrix": data, "depth": node.getDepth(), "parent_name": node.getParent().getName(), "has_mesh": "True"}) # Handle group nodes if node.callDecoration("isGroup"): # Render origin of this node. renderer.queueNode(scene.getRoot(), mesh=self._getAxisMesh(node), transparent = True) # Render bounding box of this node renderer.queueNode(scene.getRoot(), mesh=node.getBoundingBoxMesh(), mode=Renderer.RenderLines) billboard_node = self._ensureNodeHasBillboard(node) # Update the displayed data on the billboard. data = self._matrixToHtml(node.getLocalTransformation()) billboard_node.setDisplayData({"name": node.getName(), "matrix": data, "depth": node.getDepth(), "parent_name": node.getParent().getName(), "has_mesh": node.getMeshData() is not None}) # We sometimes have nodes that are not groups, but have children. Also draw them elif not node.getMeshData() and len(node.getChildren()) != 0: # Render origin of this node. renderer.queueNode(scene.getRoot(), mesh=self._getAxisMesh(node), transparent = True) billboard_node = self._ensureNodeHasBillboard(node) # Update the displayed data on the billboard. data = self._matrixToHtml(node.getLocalTransformation()) parent_name = node.getParent().getName() if node.getParent() else "" billboard_node.setDisplayData({"name": node.getName(), "matrix": data, "depth": node.getDepth(), "parent_name": parent_name, "has_mesh": "False"}) bounding_box = node.getBoundingBox() if bounding_box: mesh_builder = MeshBuilder() mesh_builder.addCube( width=bounding_box.width, height=bounding_box.height, depth=bounding_box.depth, center=bounding_box.center, color=Color(0.0, 0.0, 1.0, 1.0) ) mesh = mesh_builder.build() renderer.queueNode(scene.getRoot(), mesh=mesh, mode=Renderer.RenderLines)
def _createSplashScreen(self): return QSplashScreen( QPixmap( Resources.getPath(Resources.Images, self.getApplicationName() + ".png")))
def beginRendering(self): scene = self.getController().getScene() renderer = self.getRenderer() if not self._enabled_shader: self._enabled_shader = OpenGL.getInstance().createShaderProgram(Resources.getPath(Resources.Shaders, "overhang.shader")) theme = Application.getInstance().getTheme() self._enabled_shader.setUniformValue("u_overhangColor", Color(*theme.getColor("model_overhang").getRgb())) if not self._disabled_shader: self._disabled_shader = OpenGL.getInstance().createShaderProgram(Resources.getPath(Resources.Shaders, "striped.shader")) theme = Application.getInstance().getTheme() self._disabled_shader.setUniformValue("u_diffuseColor1", Color(*theme.getColor("model_unslicable").getRgb())) self._disabled_shader.setUniformValue("u_diffuseColor2", Color(*theme.getColor("model_unslicable_alt").getRgb())) self._disabled_shader.setUniformValue("u_width", 50.0) multi_extrusion = False global_container_stack = Application.getInstance().getGlobalContainerStack() if global_container_stack: multi_extrusion = global_container_stack.getProperty("machine_extruder_count", "value") > 1 if multi_extrusion: support_extruder_nr = global_container_stack.getProperty("support_extruder_nr", "value") support_angle_stack = ExtruderManager.getInstance().getExtruderStack(support_extruder_nr) if not support_angle_stack: support_angle_stack = global_container_stack else: support_angle_stack = global_container_stack if Preferences.getInstance().getValue("view/show_overhang"): angle = support_angle_stack.getProperty("support_angle", "value") # Make sure the overhang angle is valid before passing it to the shader # Note: if the overhang angle is set to its default value, it does not need to get validated (validationState = None) if angle is not None and global_container_stack.getProperty("support_angle", "validationState") in [None, ValidatorState.Valid]: self._enabled_shader.setUniformValue("u_overhangAngle", math.cos(math.radians(90 - angle))) else: self._enabled_shader.setUniformValue("u_overhangAngle", math.cos(math.radians(0))) #Overhang angle of 0 causes no area at all to be marked as overhang. else: self._enabled_shader.setUniformValue("u_overhangAngle", math.cos(math.radians(0))) for node in DepthFirstIterator(scene.getRoot()): if not node.render(renderer): if node.getMeshData() and node.isVisible(): uniforms = {} shade_factor = 1.0 if not multi_extrusion: if global_container_stack: material = global_container_stack.findContainer({ "type": "material" }) material_color = material.getMetaDataEntry("color_code", default = self._extruders_model.defaultColors[0]) if material else self._extruders_model.defaultColors[0] else: material_color = self._extruders_model.defaultColors[0] else: # Get color to render this mesh in from ExtrudersModel extruder_index = 0 extruder_id = node.callDecoration("getActiveExtruder") if extruder_id: extruder_index = max(0, self._extruders_model.find("id", extruder_id)) try: material_color = self._extruders_model.getItem(extruder_index)["color"] except KeyError: material_color = self._extruders_model.defaultColors[0] if extruder_index != ExtruderManager.getInstance().activeExtruderIndex: # Shade objects that are printed with the non-active extruder 25% darker shade_factor = 0.6 try: # Colors are passed as rgb hex strings (eg "#ffffff"), and the shader needs # an rgba list of floats (eg [1.0, 1.0, 1.0, 1.0]) uniforms["diffuse_color"] = [ shade_factor * int(material_color[1:3], 16) / 255, shade_factor * int(material_color[3:5], 16) / 255, shade_factor * int(material_color[5:7], 16) / 255, 1.0 ] except ValueError: pass if hasattr(node, "_outside_buildarea"): if node._outside_buildarea: renderer.queueNode(node, shader = self._disabled_shader) else: renderer.queueNode(node, shader = self._enabled_shader, uniforms = uniforms) else: renderer.queueNode(node, material = self._enabled_shader, uniforms = uniforms) if node.callDecoration("isGroup") and Selection.isSelected(node): renderer.queueNode(scene.getRoot(), mesh = node.getBoundingBoxMesh(), mode = RenderBatch.RenderMode.LineLoop)
def __init__(self, name, version, buildtype="", **kwargs): if Application._instance != None: raise ValueError("Duplicate singleton creation") # If the constructor is called and there is no instance, set the instance to self. # This is done because we can't make constructor private Application._instance = self self._application_name = name self._version = version self._buildtype = buildtype os.putenv( "UBUNTU_MENUPROXY", "0" ) # For Ubuntu Unity this makes Qt use its own menu bar rather than pass it on to Unity. Signal._app = self Signal._signalQueue = self Resources.ApplicationIdentifier = name Resources.addSearchPath( os.path.join(os.path.dirname(sys.executable), "resources")) Resources.addSearchPath( os.path.join(Application.getInstallPrefix(), "share", "uranium", "resources")) Resources.addSearchPath( os.path.join(Application.getInstallPrefix(), "Resources", "uranium", "resources")) Resources.addSearchPath( os.path.join(Application.getInstallPrefix(), "Resources", self.getApplicationName(), "resources")) if not hasattr(sys, "frozen"): Resources.addSearchPath( os.path.join(os.path.abspath(os.path.dirname(__file__)), "..", "resources")) self._main_thread = threading.current_thread() super().__init__() # Call super to make multiple inheritance work. i18nCatalog.setApplication(self) self._renderer = None PluginRegistry.addType("backend", self.setBackend) PluginRegistry.addType("logger", Logger.addLogger) PluginRegistry.addType("extension", self.addExtension) preferences = Preferences.getInstance() env_lang = locale.getdefaultlocale()[0] preferences.addPreference("general/language", env_lang) preferences.addPreference("general/visible_settings", "") try: preferences.readFromFile( Resources.getPath(Resources.Preferences, self._application_name + ".cfg")) except FileNotFoundError: pass self._controller = Controller(self) self._mesh_file_handler = MeshFileHandler.getInstance() self._mesh_file_handler.setApplication(self) self._workspace_file_handler = WorkspaceFileHandler.getInstance() self._workspace_file_handler.setApplication(self) self._extensions = [] self._backend = None self._output_device_manager = OutputDeviceManager() self._required_plugins = [] self._operation_stack = OperationStack(self.getController()) self._plugin_registry = PluginRegistry.getInstance() self._plugin_registry.addPluginLocation( os.path.join(Application.getInstallPrefix(), "lib", "uranium")) self._plugin_registry.addPluginLocation( os.path.join(os.path.dirname(sys.executable), "plugins")) self._plugin_registry.addPluginLocation( os.path.join(Application.getInstallPrefix(), "Resources", "uranium", "plugins")) self._plugin_registry.addPluginLocation( os.path.join(Application.getInstallPrefix(), "Resources", self.getApplicationName(), "plugins")) # Locally installed plugins local_path = os.path.join( Resources.getStoragePath(Resources.Resources), "plugins") # Ensure the local plugins directory exists try: os.makedirs(local_path) except OSError: pass self._plugin_registry.addPluginLocation(local_path) if not hasattr(sys, "frozen"): self._plugin_registry.addPluginLocation( os.path.join(os.path.abspath(os.path.dirname(__file__)), "..", "plugins")) self._plugin_registry.setApplication(self) ContainerRegistry.setApplication(self) UM.Settings.InstanceContainer.setContainerRegistry( self.getContainerRegistry()) UM.Settings.ContainerStack.setContainerRegistry( self.getContainerRegistry()) self._parsed_command_line = None self.parseCommandLine() self._visible_messages = [] self._message_lock = threading.Lock() self.showMessageSignal.connect(self.showMessage) self.hideMessageSignal.connect(self.hideMessage) self._global_container_stack = None
def installPlugin(self, plugin_path: str): plugin_path = QUrl(plugin_path).toLocalFile() Logger.log("d", "Attempting to install a new plugin %s", plugin_path) local_plugin_path = os.path.join( Resources.getStoragePath(Resources.Resources), "plugins") plugin_folder = "" try: with zipfile.ZipFile(plugin_path, "r") as zip_ref: plugin_id = None for file in zip_ref.infolist(): if file.filename.endswith("/"): plugin_id = file.filename.strip("/") break if plugin_id is None: return { "status": "error", "message": i18n_catalog.i18nc( "@info:status", "Failed to install plugin from <filename>{0}</filename>:\n<message>{1}</message>", plugin_path, "Invalid plugin file") } plugin_folder = os.path.join(local_plugin_path, plugin_id) if os.path.isdir( plugin_folder ): # Plugin is already installed by user (so not a bundled plugin) metadata = {} with zip_ref.open(plugin_id + "/plugin.json") as metadata_file: metadata = json.loads( metadata_file.read().decode("utf-8")) if "version" in metadata: new_version = Version(metadata["version"]) old_version = Version( self.getMetaData(plugin_id)["plugin"]["version"]) if new_version > old_version: zip_ref.extractall(plugin_folder) return { "status": "ok", "message": i18n_catalog.i18nc( "@info:status", "The plugin has been installed.\n Please re-start the application to activate the plugin." ) } Logger.log( "w", "The plugin was already installed. Unable to install it again!" ) return { "status": "duplicate", "message": i18n_catalog.i18nc( "@info:status", "Failed to install the plugin; \n<message>{0}</message>", "Plugin was already installed") } elif plugin_id in self._plugins: # Plugin is already installed, but not by the user (eg; this is a bundled plugin) # TODO: Right now we don't support upgrading bundled plugins at all, but we might do so in the future. return { "status": "duplicate", "message": i18n_catalog.i18nc( "@info:status", "Failed to install the plugin; \n<message>{0}</message>", "Unable to upgrade or instal bundled plugins.") } zip_ref.extractall(plugin_folder) except: # Installing a new plugin should never crash the application. Logger.logException( "d", "An exception occurred while installing plugin ") return { "status": "error", "message": i18n_catalog.i18nc( "@info:status", "Failed to install plugin from <filename>{0}</filename>:\n<message>{1}</message>", plugin_folder, "Invalid plugin file") } return { "status": "ok", "message": i18n_catalog.i18nc( "@info:status", "The plugin has been installed.\n Please re-start the application to activate the plugin." ) }
def beginRendering(self): scene = self.getController().getScene() renderer = self.getRenderer() if not self._extruders_model: self._extruders_model = Application.getInstance( ).getExtrudersModel() if not self._theme: self._theme = Application.getInstance().getTheme() if not self._enabled_shader: self._enabled_shader = OpenGL.getInstance().createShaderProgram( Resources.getPath(Resources.Shaders, "overhang.shader")) self._enabled_shader.setUniformValue( "u_overhangColor", Color(*self._theme.getColor("model_overhang").getRgb())) if not self._disabled_shader: self._disabled_shader = OpenGL.getInstance().createShaderProgram( Resources.getPath(Resources.Shaders, "striped.shader")) self._disabled_shader.setUniformValue( "u_diffuseColor1", Color(*self._theme.getColor("model_unslicable").getRgb())) self._disabled_shader.setUniformValue( "u_diffuseColor2", Color(*self._theme.getColor("model_unslicable_alt").getRgb())) self._disabled_shader.setUniformValue("u_width", 50.0) if not self._non_printing_shader: self._non_printing_shader = OpenGL.getInstance( ).createShaderProgram( Resources.getPath(Resources.Shaders, "transparent_object.shader")) self._non_printing_shader.setUniformValue( "u_diffuseColor", Color(*self._theme.getColor("model_non_printing").getRgb())) self._non_printing_shader.setUniformValue("u_opacity", 0.6) if not self._support_mesh_shader: self._support_mesh_shader = OpenGL.getInstance( ).createShaderProgram( Resources.getPath(Resources.Shaders, "striped.shader")) self._support_mesh_shader.setUniformValue("u_vertical_stripes", True) self._support_mesh_shader.setUniformValue("u_width", 5.0) global_container_stack = Application.getInstance( ).getGlobalContainerStack() if global_container_stack: support_extruder_nr = global_container_stack.getExtruderPositionValueWithDefault( "support_extruder_nr") support_angle_stack = Application.getInstance().getExtruderManager( ).getExtruderStack(support_extruder_nr) if support_angle_stack is not None and Application.getInstance( ).getPreferences().getValue("view/show_overhang"): angle = support_angle_stack.getProperty( "support_angle", "value") # Make sure the overhang angle is valid before passing it to the shader # Note: if the overhang angle is set to its default value, it does not need to get validated (validationState = None) if angle is not None and global_container_stack.getProperty( "support_angle", "validationState") in [None, ValidatorState.Valid]: self._enabled_shader.setUniformValue( "u_overhangAngle", math.cos(math.radians(90 - angle))) else: self._enabled_shader.setUniformValue( "u_overhangAngle", math.cos(math.radians(0)) ) #Overhang angle of 0 causes no area at all to be marked as overhang. else: self._enabled_shader.setUniformValue("u_overhangAngle", math.cos(math.radians(0))) for node in DepthFirstIterator(scene.getRoot()): if not node.render(renderer): if node.getMeshData() and node.isVisible( ) and not node.callDecoration("getLayerData"): uniforms = {} shade_factor = 1.0 per_mesh_stack = node.callDecoration("getStack") extruder_index = node.callDecoration( "getActiveExtruderPosition") if extruder_index is None: extruder_index = "0" extruder_index = int(extruder_index) # Use the support extruder instead of the active extruder if this is a support_mesh if per_mesh_stack: if per_mesh_stack.getProperty("support_mesh", "value"): extruder_index = int( global_container_stack. getExtruderPositionValueWithDefault( "support_extruder_nr")) try: material_color = self._extruders_model.getItem( extruder_index)["color"] except KeyError: material_color = self._extruders_model.defaultColors[0] if extruder_index != ExtruderManager.getInstance( ).activeExtruderIndex: # Shade objects that are printed with the non-active extruder 25% darker shade_factor = 0.6 try: # Colors are passed as rgb hex strings (eg "#ffffff"), and the shader needs # an rgba list of floats (eg [1.0, 1.0, 1.0, 1.0]) uniforms["diffuse_color"] = [ shade_factor * int(material_color[1:3], 16) / 255, shade_factor * int(material_color[3:5], 16) / 255, shade_factor * int(material_color[5:7], 16) / 255, 1.0 ] except ValueError: pass if node.callDecoration("isNonPrintingMesh"): if per_mesh_stack and (per_mesh_stack.getProperty( "infill_mesh", "value") or per_mesh_stack.getProperty( "cutting_mesh", "value")): renderer.queueNode( node, shader=self._non_printing_shader, uniforms=uniforms, transparent=True) else: renderer.queueNode( node, shader=self._non_printing_shader, transparent=True) elif getattr(node, "_outside_buildarea", False): renderer.queueNode(node, shader=self._disabled_shader) elif per_mesh_stack and per_mesh_stack.getProperty( "support_mesh", "value"): # Render support meshes with a vertical stripe that is darker shade_factor = 0.6 uniforms["diffuse_color_2"] = [ uniforms["diffuse_color"][0] * shade_factor, uniforms["diffuse_color"][1] * shade_factor, uniforms["diffuse_color"][2] * shade_factor, 1.0 ] renderer.queueNode(node, shader=self._support_mesh_shader, uniforms=uniforms) else: renderer.queueNode(node, shader=self._enabled_shader, uniforms=uniforms) if node.callDecoration("isGroup") and Selection.isSelected( node): renderer.queueNode(scene.getRoot(), mesh=node.getBoundingBoxMesh(), mode=RenderBatch.RenderMode.LineLoop)
def saveAll(self) -> None: for instance in self.findInstanceContainers(): if not instance.isDirty(): continue try: data = instance.serialize() except NotImplementedError: # Serializing is not supported so skip this container continue except Exception: Logger.logException( "e", "An exception occurred trying to serialize container %s", instance.getId()) continue mime_type = self.getMimeTypeForContainer(type(instance)) if mime_type is not None: file_name = urllib.parse.quote_plus( instance.getId()) + "." + mime_type.preferredSuffix path = Resources.getStoragePath(Resources.InstanceContainers, file_name) with SaveFile(path, "wt") as f: f.write(data) for stack in self.findContainerStacks(): if not stack.isDirty(): continue try: data = stack.serialize() except NotImplementedError: # Serializing is not supported so skip this container continue except Exception: Logger.logException( "e", "An exception occurred trying to serialize container %s", stack.getId()) continue mime_type = self.getMimeTypeForContainer(type(stack)) if mime_type is not None: file_name = urllib.parse.quote_plus( stack.getId()) + "." + mime_type.preferredSuffix path = Resources.getStoragePath(Resources.ContainerStacks, file_name) with SaveFile(path, "wt") as f: f.write(data) for definition in self.findDefinitionContainers(): try: data = definition.serialize() except NotImplementedError: # Serializing is not supported so skip this container continue except Exception: Logger.logException( "e", "An exception occurred trying to serialize container %s", definition.getId()) continue mime_type = self.getMimeTypeForContainer(type(definition)) if mime_type is not None: file_name = urllib.parse.quote_plus( definition.getId()) + "." + mime_type.preferredSuffix path = Resources.getStoragePath(Resources.DefinitionContainers, file_name) with SaveFile(path, "wt") as f: f.write(data)
def initializeBeforePluginsAreLoaded(self) -> None: config_path = Resources.getConfigStoragePath() # File to store plugin info, such as which ones to install/remove and which ones are disabled. # At this point we can load this here because we already know the actual Application name, so the directory name self._plugin_config_filename = os.path.join( os.path.abspath(config_path), "plugins.json") # type: str from UM.Settings.ContainerRegistry import ContainerRegistry container_registry = ContainerRegistry.getInstance() try: with container_registry.lockFile(): # Load the plugin info if exists if os.path.exists(self._plugin_config_filename): Logger.log("i", "Loading plugin configuration file '%s'", self._plugin_config_filename) with open(self._plugin_config_filename, "r", encoding="utf-8") as f: data = json.load(f) self._disabled_plugins = data["disabled"] self._plugins_to_install = data["to_install"] self._plugins_to_remove = data["to_remove"] except: Logger.logException( "e", "Failed to load plugin configuration file '%s'", self._plugin_config_filename) # Also load data from preferences, where the plugin info used to be saved preferences = self._application.getPreferences() disabled_plugins = preferences.getValue("general/disabled_plugins") disabled_plugins = disabled_plugins.split( ",") if disabled_plugins else [] disabled_plugins = [ plugin for plugin in disabled_plugins if len(plugin.strip()) > 0 ] for plugin_id in disabled_plugins: if plugin_id not in self._disabled_plugins: self._disabled_plugins.append(plugin_id) plugins_to_remove = preferences.getValue("general/plugins_to_remove") plugins_to_remove = plugins_to_remove.split( ",") if plugins_to_remove else [] for plugin_id in plugins_to_remove: if plugin_id not in self._plugins_to_remove: self._plugins_to_remove.append(plugin_id) # Remove plugins that need to be removed for plugin_id in self._plugins_to_remove: self._removePlugin(plugin_id) self._plugins_to_remove = [] if plugins_to_remove is not None: preferences.setValue("general/plugins_to_remove", "") self._savePluginData() # Install the plugins that need to be installed (overwrite existing) for plugin_id, plugin_info in self._plugins_to_install.items(): self._installPlugin(plugin_id, plugin_info["filename"]) self._plugins_to_install = dict() self._savePluginData()
def __init__(self, tray_icon_name=None, **kwargs): plugin_path = "" if sys.platform == "win32": if hasattr(sys, "frozen"): plugin_path = os.path.join( os.path.dirname(os.path.abspath(sys.executable)), "PyQt5", "plugins") Logger.log("i", "Adding QT5 plugin path: %s" % (plugin_path)) QCoreApplication.addLibraryPath(plugin_path) else: import site for sitepackage_dir in site.getsitepackages(): QCoreApplication.addLibraryPath( os.path.join(sitepackage_dir, "PyQt5", "plugins")) elif sys.platform == "darwin": plugin_path = os.path.join(Application.getInstallPrefix(), "Resources", "plugins") if plugin_path: Logger.log("i", "Adding QT5 plugin path: %s" % (plugin_path)) QCoreApplication.addLibraryPath(plugin_path) os.environ["QSG_RENDER_LOOP"] = "basic" super().__init__(sys.argv, **kwargs) self.setAttribute(Qt.AA_UseDesktopOpenGL) major_version, minor_version, profile = OpenGLContext.detectBestOpenGLVersion( ) if major_version is None and minor_version is None and profile is None: Logger.log( "e", "Startup failed because OpenGL version probing has failed: tried to create a 2.0 and 4.1 context. Exiting" ) QMessageBox.critical( None, "Failed to probe OpenGL", "Could not probe OpenGL. This program requires OpenGL 2.0 or higher. Please check your video card drivers." ) sys.exit(1) else: Logger.log( "d", "Detected most suitable OpenGL context version: %s" % (OpenGLContext.versionAsText(major_version, minor_version, profile))) OpenGLContext.setDefaultFormat(major_version, minor_version, profile=profile) self._plugins_loaded = False # Used to determine when it's safe to use the plug-ins. self._main_qml = "main.qml" self._engine = None self._renderer = None self._main_window = None self._theme = None self._shutting_down = False self._qml_import_paths = [] self._qml_import_paths.append( os.path.join(os.path.dirname(sys.executable), "qml")) self._qml_import_paths.append( os.path.join(Application.getInstallPrefix(), "Resources", "qml")) self.parseCommandLine() Logger.log("i", "Command line arguments: %s", self._parsed_command_line) signal.signal(signal.SIGINT, signal.SIG_DFL) # This is done here as a lot of plugins require a correct gl context. If you want to change the framework, # these checks need to be done in your <framework>Application.py class __init__(). i18n_catalog = i18nCatalog("uranium") self.showSplashMessage( i18n_catalog.i18nc("@info:progress", "Loading plugins...")) # Remove and install the plugins that have been scheduled self._plugin_registry.initializeBeforePluginsAreLoaded() self._loadPlugins() self._plugin_registry.initializeAfterPlguinsAreLoaded() self._plugin_registry.checkRequiredPlugins(self.getRequiredPlugins()) self.pluginsLoaded.emit() self.showSplashMessage( i18n_catalog.i18nc("@info:progress", "Updating configuration...")) UM.VersionUpgradeManager.VersionUpgradeManager.getInstance().upgrade() # Preferences might have changed. Load them again. # Note that the language can't be updated, so that will always revert to English. preferences = Preferences.getInstance() try: file_name = Resources.getPath(Resources.Preferences, self._application_name + ".cfg") with open(file_name, "r", encoding="utf-8") as f: serialized = f.read() preferences.deserialize(serialized) except FileNotFoundError: pass # Force the configuration file to be written again since the list of plugins to remove maybe changed Preferences.getInstance().setValue("general/plugins_to_remove", "") Preferences.getInstance().writeToFile( Resources.getStoragePath(Resources.Preferences, self.getApplicationName() + ".cfg")) self.showSplashMessage( i18n_catalog.i18nc("@info:progress", "Loading preferences...")) try: file_name = Resources.getPath(Resources.Preferences, self.getApplicationName() + ".cfg") Preferences.getInstance().readFromFile(file_name) except FileNotFoundError: pass self.getApplicationName() Preferences.getInstance().addPreference( "%s/recent_files" % self.getApplicationName(), "") self._recent_files = [] file_names = Preferences.getInstance().getValue( "%s/recent_files" % self.getApplicationName()).split(";") for file_name in file_names: if not os.path.isfile(file_name): continue self._recent_files.append(QUrl.fromLocalFile(file_name)) JobQueue.getInstance().jobFinished.connect(self._onJobFinished) # Initialize System tray icon and make it invisible because it is used only to show pop up messages self._tray_icon = None self._tray_icon_widget = None if tray_icon_name: self._tray_icon = QIcon( Resources.getPath(Resources.Images, tray_icon_name)) self._tray_icon_widget = QSystemTrayIcon(self._tray_icon) self._tray_icon_widget.setVisible(False)
def saveSettingValues(self): self._machine_settings.saveValuesToFile( Resources.getStoragePath(Resources.SettingsLocation, "settings.cfg"))
def _engineCreated(self): sidebar_component_path = os.path.join( Resources.getPath( Application.getInstance().ResourceTypes.QmlFiles), "PrepareSidebar.qml") self.addDisplayComponent("sidebar", sidebar_component_path)
def run(self): self._i18n_catalog = i18nCatalog("cura") i18nCatalog.setTagReplacements({ "filename": "font color=\"black\"", "message": "font color=UM.Theme.colors.message_text;", }) self.showSplashMessage( self._i18n_catalog.i18nc("@info:progress", "Setting up scene...")) controller = self.getController() controller.setActiveView("SolidView") controller.setCameraTool("CameraTool") controller.setSelectionTool("SelectionTool") t = controller.getTool("TranslateTool") if t: t.setEnabledAxis( [ToolHandle.XAxis, ToolHandle.YAxis, ToolHandle.ZAxis]) Selection.selectionChanged.connect(self.onSelectionChanged) root = controller.getScene().getRoot() self._platform = Platform(root) self._volume = BuildVolume.BuildVolume(root) self.getRenderer().setBackgroundColor(QColor(245, 245, 245)) self._physics = PlatformPhysics.PlatformPhysics( controller, self._volume) camera = Camera("3d", root) camera.setPosition(Vector(-80, 250, 700)) camera.setPerspective(True) camera.lookAt(Vector(0, 0, 0)) controller.getScene().setActiveCamera("3d") self.getController().getTool("CameraTool").setOrigin(Vector(0, 100, 0)) self._camera_animation = CameraAnimation.CameraAnimation() self._camera_animation.setCameraTool( self.getController().getTool("CameraTool")) self.showSplashMessage( self._i18n_catalog.i18nc("@info:progress", "Loading interface...")) self.setMainQml( Resources.getPath(self.ResourceTypes.QmlFiles, "Cura.qml")) self.initializeEngine() if self._engine.rootObjects: self.closeSplash() for file in self.getCommandLineOption("file", []): self._openFile(file) for file_name in self._open_file_queue: #Open all the files that were queued up while plug-ins were loading. self._openFile(file_name) self.exec_()
def __init__(self, **kwargs): plugin_path = "" if sys.platform == "win32": if hasattr(sys, "frozen"): plugin_path = os.path.join( os.path.dirname(os.path.abspath(sys.executable)), "PyQt5", "plugins") Logger.log("i", "Adding QT5 plugin path: %s" % (plugin_path)) QCoreApplication.addLibraryPath(plugin_path) else: import site for dir in site.getsitepackages(): QCoreApplication.addLibraryPath( os.path.join(dir, "PyQt5", "plugins")) elif sys.platform == "darwin": plugin_path = os.path.join(Application.getInstallPrefix(), "Resources", "plugins") if plugin_path: Logger.log("i", "Adding QT5 plugin path: %s" % (plugin_path)) QCoreApplication.addLibraryPath(plugin_path) os.environ["QSG_RENDER_LOOP"] = "basic" super().__init__(sys.argv, **kwargs) self.setAttribute(Qt.AA_UseDesktopOpenGL) major_version, minor_version, profile = OpenGLContext.detectBestOpenGLVersion( ) if major_version is None and minor_version is None and profile is None: Logger.log( "e", "Startup failed because OpenGL version probing has failed: tried to create a 2.0 and 4.1 context. Exiting" ) QMessageBox.critical( None, "Failed to probe OpenGL", "Could not probe OpenGL. This program requires OpenGL 2.0 or higher. Please check your video card drivers." ) sys.exit(1) else: Logger.log( "d", "Detected most suitable OpenGL context version: %s" % (OpenGLContext.versionAsText(major_version, minor_version, profile))) OpenGLContext.setDefaultFormat(major_version, minor_version, profile=profile) self._plugins_loaded = False # Used to determine when it's safe to use the plug-ins. self._main_qml = "main.qml" self._engine = None self._renderer = None self._main_window = None self._theme = None self._shutting_down = False self._qml_import_paths = [] self._qml_import_paths.append( os.path.join(os.path.dirname(sys.executable), "qml")) self._qml_import_paths.append( os.path.join(Application.getInstallPrefix(), "Resources", "qml")) try: self._splash = self._createSplashScreen() except FileNotFoundError: self._splash = None else: self._splash.show() self.processEvents() signal.signal(signal.SIGINT, signal.SIG_DFL) # This is done here as a lot of plugins require a correct gl context. If you want to change the framework, # these checks need to be done in your <framework>Application.py class __init__(). i18n_catalog = i18nCatalog("uranium") self.showSplashMessage( i18n_catalog.i18nc("@info:progress", "Loading plugins...")) self._loadPlugins() self.parseCommandLine() Logger.log("i", "Command line arguments: %s", self._parsed_command_line) self._plugin_registry.checkRequiredPlugins(self.getRequiredPlugins()) self.showSplashMessage( i18n_catalog.i18nc("@info:progress", "Updating configuration...")) upgraded = UM.VersionUpgradeManager.VersionUpgradeManager.getInstance( ).upgrade() if upgraded: preferences = Preferences.getInstance( ) #Preferences might have changed. Load them again. #Note that the language can't be updated, so that will always revert to English. try: preferences.readFromFile( Resources.getPath(Resources.Preferences, self._application_name + ".cfg")) except FileNotFoundError: pass self.showSplashMessage( i18n_catalog.i18nc("@info:progress", "Loading preferences...")) try: file = Resources.getPath(Resources.Preferences, self.getApplicationName() + ".cfg") Preferences.getInstance().readFromFile(file) except FileNotFoundError: pass
def _getSingleExtrusionMachineExtruders(self, definition_name): machine_instances_dir = Resources.getPath( CuraApplication.ResourceTypes.MachineStack) machine_instance_id = None # Find machine instances for item in os.listdir(machine_instances_dir): file_path = os.path.join(machine_instances_dir, item) if not os.path.isfile(file_path): continue parser = configparser.ConfigParser(interpolation=None) try: parser.read([file_path]) except: # skip, it is not a valid stack file continue if not parser.has_option("metadata", "type"): continue if "machine" != parser["metadata"]["type"]: continue if not parser.has_option("general", "id"): continue id = parser["general"]["id"] if id + "_settings" != definition_name: continue else: machine_instance_id = id break if machine_instance_id is not None: extruders_instances_dir = Resources.getPath( CuraApplication.ResourceTypes.ExtruderStack) #"machine",[extruders] extruder_instances = [] # Find all custom extruders for found machines for item in os.listdir(extruders_instances_dir): file_path = os.path.join(extruders_instances_dir, item) if not os.path.isfile(file_path): continue parser = configparser.ConfigParser(interpolation=None) try: parser.read([file_path]) except: # skip, it is not a valid stack file continue if not parser.has_option("metadata", "type"): continue if "extruder_train" != parser["metadata"]["type"]: continue if not parser.has_option("metadata", "machine"): continue if not parser.has_option("metadata", "position"): continue if machine_instance_id != parser["metadata"]["machine"]: continue extruder_instances.append(parser) return extruder_instances
def startSplashWindowPhase(self) -> None: super().startSplashWindowPhase() self._package_manager.initialize() # Read preferences here (upgrade won't work) to get the language in use, so the splash window can be shown in # the correct language. try: preferences_filename = Resources.getPath(Resources.Preferences, self._app_name + ".cfg") self._preferences.readFromFile(preferences_filename) except FileNotFoundError: Logger.log( "i", "Preferences file not found, ignore and use default language '%s'", self._default_language) signal.signal(signal.SIGINT, signal.SIG_DFL) # This is done here as a lot of plugins require a correct gl context. If you want to change the framework, # these checks need to be done in your <framework>Application.py class __init__(). i18n_catalog = i18nCatalog("uranium") self._configuration_error_message = ConfigurationErrorMessage( self, i18n_catalog.i18nc("@info:status", "Your configuration seems to be corrupt."), lifetime=0, title=i18n_catalog.i18nc("@info:title", "Configuration errors")) # Remove, install, and then loading plugins self.showSplashMessage( i18n_catalog.i18nc("@info:progress", "Loading plugins...")) # Remove and install the plugins that have been scheduled self._plugin_registry.initializeBeforePluginsAreLoaded() self._loadPlugins() self._plugin_registry.checkRequiredPlugins(self.getRequiredPlugins()) self.pluginsLoaded.emit() self.showSplashMessage( i18n_catalog.i18nc("@info:progress", "Updating configuration...")) with self._container_registry.lockFile(): VersionUpgradeManager.getInstance().upgrade() # Load preferences again because before we have loaded the plugins, we don't have the upgrade routine for # the preferences file. Now that we have, load the preferences file again so it can be upgraded and loaded. try: preferences_filename = Resources.getPath(Resources.Preferences, self._app_name + ".cfg") with open(preferences_filename, "r", encoding="utf-8") as f: serialized = f.read() # This performs the upgrade for Preferences self._preferences.deserialize(serialized) self._preferences.setValue("general/plugins_to_remove", "") self._preferences.writeToFile(preferences_filename) except FileNotFoundError: Logger.log( "i", "The preferences file cannot be found, will use default values" ) # Force the configuration file to be written again since the list of plugins to remove maybe changed self.showSplashMessage( i18n_catalog.i18nc("@info:progress", "Loading preferences...")) try: self._preferences_filename = Resources.getPath( Resources.Preferences, self._app_name + ".cfg") self._preferences.readFromFile(self._preferences_filename) except FileNotFoundError: Logger.log( "i", "The preferences file '%s' cannot be found, will use default values", self._preferences_filename) self._preferences_filename = Resources.getStoragePath( Resources.Preferences, self._app_name + ".cfg") # FIXME: This is done here because we now use "plugins.json" to manage plugins instead of the Preferences file, # but the PluginRegistry will still import data from the Preferences files if present, such as disabled plugins, # so we need to reset those values AFTER the Preferences file is loaded. self._plugin_registry.initializeAfterPluginsAreLoaded() # Preferences: recent files self._preferences.addPreference("%s/recent_files" % self._app_name, "") file_names = self._preferences.getValue("%s/recent_files" % self._app_name).split(";") for file_name in file_names: if not os.path.isfile(file_name): continue self._recent_files.append(QUrl.fromLocalFile(file_name)) # Initialize System tray icon and make it invisible because it is used only to show pop up messages self._tray_icon = None if self._tray_icon_name: self._tray_icon = QIcon( Resources.getPath(Resources.Images, self._tray_icon_name)) self._tray_icon_widget = QSystemTrayIcon(self._tray_icon) self._tray_icon_widget.setVisible(False)
def getCacheLockFilename(self) -> str: return Resources.getStoragePath( Resources.Cache, self._application.getApplicationLockFilename())
# Copyright (c) 2016 Ultimaker B.V. # Uranium is released under the terms of the AGPLv3 or higher. import pytest import os import UM.Settings.InstanceContainer # import UM.Settings.SettingDefinition from UM.Resources import Resources Resources.addSearchPath(os.path.dirname(os.path.abspath(__file__))) def test_create(): container = UM.Settings.InstanceContainer.InstanceContainer("test") assert container.getId() == "test" ## Test whether setting a property on an instance correctly updates dependencies. # # This test primarily tests the SettingInstance but requires some functionality # from InstanceContainer that is not easily captured in a Mock object. Therefore # it is included here. def test_instance_setProperty(): instance_container = UM.Settings.InstanceContainer.InstanceContainer( "test") definition1 = UM.Settings.SettingDefinition.SettingDefinition( "test_0", None) definition1.deserialize({ "label": "Test 0", "type": "float",
def loadQtTranslation(self, file, language = "default"): #TODO Add support for specifying a language from preferences path = None if language == "default": path = self._getDefaultLanguage(file) else: path = Resources.getPath(Resources.i18n, language, "LC_MESSAGES", file + ".qm") # If all else fails, fall back to english. if not path: Logger.log("w", "Could not find any translations matching {0} for file {1}, falling back to english".format(language, file)) try: path = Resources.getPath(Resources.i18n, "en", "LC_MESSAGES", file + ".qm") except FileNotFoundError: Logger.log("w", "Could not find English translations for file {0}. Switching to developer english.".format(file)) return translator = QTranslator() if not translator.load(path): Logger.log("e", "Unable to load translations %s", file) return # Store a reference to the translator. # This prevents the translator from being destroyed before Qt has a chance to use it. self._translators[file] = translator # Finally, install the translator so Qt can use it. self.installTranslator(translator)