Exemplo n.º 1
0
    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")
Exemplo n.º 2
0
    def _onActiveMachineChanged(self):
        machine = self.getActiveMachine()
        if machine:
            Preferences.getInstance().setValue("cura/active_machine", machine.getName())

            self._volume.setWidth(machine.getSettingValueByKey("machine_width"))
            self._volume.setHeight(machine.getSettingValueByKey("machine_height"))
            self._volume.setDepth(machine.getSettingValueByKey("machine_depth"))

            disallowed_areas = machine.getSettingValueByKey("machine_disallowed_areas")
            areas = []
            if disallowed_areas:

                for area in disallowed_areas:
                    polygon = []
                    polygon.append(Vector(area[0][0], 0.2, area[0][1]))
                    polygon.append(Vector(area[1][0], 0.2, area[1][1]))
                    polygon.append(Vector(area[2][0], 0.2, area[2][1]))
                    polygon.append(Vector(area[3][0], 0.2, area[3][1]))
                    areas.append(polygon)
            self._volume.setDisallowedAreas(areas)

            self._volume.rebuild()

            if self.getController().getTool("ScaleTool"):
                self.getController().getTool("ScaleTool").setMaximumBounds(self._volume.getBoundingBox())

            offset = machine.getSettingValueByKey("machine_platform_offset")
            if offset:
                self._platform.setPosition(Vector(offset[0], offset[1], offset[2]))
            else:
                self._platform.setPosition(Vector(0.0, 0.0, 0.0))
Exemplo n.º 3
0
    def __init__(self):
        super().__init__()
        self._scene = Application.getInstance().getController().getScene()

        self._yaw = 0
        self._pitch = 0
        self._origin = Vector(0, 0, 0)
        self._min_zoom = 1
        self._max_zoom = 2000.0
        self._manual_zoom = 200

        self._rotate = False
        self._move = False
        self._dragged = False

        self._shift_is_active = None
        self._ctrl_is_active = None
        self._space_is_active = None

        self._start_drag = None
        self._start_y = None

        self._drag_distance = 0.05

        Preferences.getInstance().addPreference("view/invert_zoom", False)
        self._invert_zoom = Preferences.getInstance().getValue("view/invert_zoom")
        Preferences.getInstance().preferenceChanged.connect(self._onPreferencesChanged)
Exemplo n.º 4
0
    def __init__(self):
        super().__init__()
        self.addMenuItem(i18n_catalog.i18nc("@item:inmenu", "Check for Updates"), self.checkNewVersion)

        Preferences.getInstance().addPreference("info/automatic_update_check", True)
        if Preferences.getInstance().getValue("info/automatic_update_check"):
            self.checkNewVersion(True)
Exemplo n.º 5
0
    def __init__(self, parent = None):
        super().__init__(parent)

        self._current_print_time = Duration(None, self)

        self._material_lengths = []
        self._material_weights = []
        self._material_costs = []

        self._pre_sliced = False

        self._backend = Application.getInstance().getBackend()
        if self._backend:
            self._backend.printDurationMessage.connect(self._onPrintDurationMessage)

        self._job_name = ""
        self._abbr_machine = ""

        Application.getInstance().globalContainerStackChanged.connect(self._setAbbreviatedMachineName)
        Application.getInstance().fileLoaded.connect(self.setJobName)

        Preferences.getInstance().preferenceChanged.connect(self._onPreferencesChanged)

        self._active_material_container = None
        Application.getInstance().getMachineManager().activeMaterialChanged.connect(self._onActiveMaterialChanged)
        self._onActiveMaterialChanged()

        self._material_amounts = []
Exemplo n.º 6
0
    def __init__(self):
        super().__init__()

        Preferences.getInstance().addPreference("view/show_overhang", True)

        self._enabled_shader = None
        self._disabled_shader = None
Exemplo n.º 7
0
    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))
Exemplo n.º 8
0
    def _onGlobalContainerChanged(self):
        if self._global_container_stack:
            self._global_container_stack.nameChanged.disconnect(self._onMachineNameChanged)
            self._global_container_stack.containersChanged.disconnect(self._onInstanceContainersChanged)
            self._global_container_stack.propertyChanged.disconnect(self._onPropertyChanged)

            material = self._global_container_stack.findContainer({"type": "material"})
            material.nameChanged.disconnect(self._onMaterialNameChanged)

            quality = self._global_container_stack.findContainer({"type": "quality"})
            quality.nameChanged.disconnect(self._onQualityNameChanged)

        self._global_container_stack = Application.getInstance().getGlobalContainerStack()
        self._active_container_stack = self._global_container_stack

        self.globalContainerChanged.emit()

        if self._global_container_stack:
            Preferences.getInstance().setValue("cura/active_machine", self._global_container_stack.getId())
            self._global_container_stack.nameChanged.connect(self._onMachineNameChanged)
            self._global_container_stack.containersChanged.connect(self._onInstanceContainersChanged)
            self._global_container_stack.propertyChanged.connect(self._onPropertyChanged)
            material = self._global_container_stack.findContainer({"type": "material"})
            material.nameChanged.connect(self._onMaterialNameChanged)

            quality = self._global_container_stack.findContainer({"type": "quality"})
            quality.nameChanged.connect(self._onQualityNameChanged)
Exemplo n.º 9
0
    def __init__(self):
        super().__init__()
        self._shader = None
        self._selection_shader = None
        self._num_layers = 0
        self._layer_percentage = 0 # what percentage of layers need to be shown (SLider gives value between 0 - 100)
        self._proxy = LayerViewProxy.LayerViewProxy()
        self._controller.getScene().getRoot().childrenChanged.connect(self._onSceneChanged)
        self._max_layers = 0
        self._current_layer_num = 0
        self._current_layer_mesh = None
        self._current_layer_jumps = None
        self._top_layers_job = None
        self._activity = False

        Preferences.getInstance().addPreference("view/top_layer_count", 1)
        Preferences.getInstance().preferenceChanged.connect(self._onPreferencesChanged)

        self._solid_layers = int(Preferences.getInstance().getValue("view/top_layer_count"))

        self._top_layer_timer = QTimer()
        self._top_layer_timer.setInterval(50)
        self._top_layer_timer.setSingleShot(True)
        self._top_layer_timer.timeout.connect(self._startUpdateTopLayers)

        self._busy = False
    def __init__(self, parent = None, *args, **kwargs):
        super().__init__(parent = parent, *args, **kwargs)

        Preferences.getInstance().preferenceChanged.connect(self._onPreferencesChanged)
        self._onPreferencesChanged("general/visible_settings")

        self.visibilityChanged.connect(self._onVisibilityChanged)
Exemplo n.º 11
0
    def __init__(self, engine, parent = None):
        super().__init__(parent)

        self._engine = engine
        self._styles = None
        self._path = ""
        self._icons = {}
        self._images = {}

        # Workaround for incorrect default font on Windows
        if sys.platform == "win32":
            default_font = QFont()
            default_font.setPointSize(9)
            QCoreApplication.instance().setFont(default_font)

        self._em_height = int(QFontMetrics(QCoreApplication.instance().font()).ascent())
        self._em_width = self._em_height;

        self._initializeDefaults()

        Preferences.getInstance().addPreference("general/theme", Application.getInstance().getApplicationName())
        try:
            theme_path = Resources.getPath(Resources.Themes, Preferences.getInstance().getValue("general/theme"))
            self.load(theme_path)
        except FileNotFoundError:
            Logger.log("e", "Could not find theme file.")
Exemplo n.º 12
0
def test_loginAndLogout() -> None:
    preferences = Preferences()
    authorization_service = AuthorizationService(OAUTH_SETTINGS, preferences)
    authorization_service.onAuthenticationError.emit = MagicMock()
    authorization_service.onAuthStateChanged.emit = MagicMock()
    authorization_service.initialize()

    # Let the service think there was a successful response
    with patch.object(AuthorizationHelpers, "parseJWT", return_value=UserProfile()):
        authorization_service._onAuthStateChanged(SUCCESSFUL_AUTH_RESPONSE)

    # Ensure that the error signal was not triggered
    assert authorization_service.onAuthenticationError.emit.call_count == 0

    # Since we said that it went right this time, validate that we got a signal.
    assert authorization_service.onAuthStateChanged.emit.call_count == 1
    assert authorization_service.getUserProfile() is not None
    assert authorization_service.getAccessToken() == "beep"

    # Check that we stored the authentication data, so next time the user won't have to log in again.
    assert preferences.getValue("test/auth_data") is not None

    # We're logged in now, also check if logging out works
    authorization_service.deleteAuthData()
    assert authorization_service.onAuthStateChanged.emit.call_count == 2
    assert authorization_service.getUserProfile() is None

    # Ensure the data is gone after we logged out.
    assert preferences.getValue("test/auth_data") == "{}"
Exemplo n.º 13
0
    def __init__(self, parent = None):
        super().__init__(parent)

        self._global_container_stack = None
        Application.getInstance().globalContainerStackChanged.connect(self._onGlobalContainerChanged)
        self._global_stack_valid = None
        self._onGlobalContainerChanged()

        ##  When the global container is changed, active material probably needs to be updated.
        self.globalContainerChanged.connect(self.activeMaterialChanged)
        self.globalContainerChanged.connect(self.activeVariantChanged)
        self.globalContainerChanged.connect(self.activeQualityChanged)

        self._empty_variant_container = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = "empty_variant")[0]
        self._empty_material_container = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = "empty_material")[0]
        self._empty_quality_container = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = "empty_quality")[0]

        Preferences.getInstance().addPreference("cura/active_machine", "")

        active_machine_id = Preferences.getInstance().getValue("cura/active_machine")

        if active_machine_id != "":
            # An active machine was saved, so restore it.
            self.setActiveMachine(active_machine_id)
            pass
Exemplo n.º 14
0
    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._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._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.setAttribute(Qt.AA_UseDesktopOpenGL)

        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", "Loading preferences..."))
        try:
            file = Resources.getPath(Resources.Preferences, self.getApplicationName() + ".cfg")
            Preferences.getInstance().readFromFile(file)
        except FileNotFoundError:
            pass
Exemplo n.º 15
0
 def setExpandedCategories(self, categories):
     categories = list(set(categories))
     categories.sort()
     joined = ";".join(categories)
     if joined != Preferences.getInstance().getValue("cura/categories_expanded"):
         Preferences.getInstance().setValue("cura/categories_expanded", joined)
         self.expandedCategoriesChanged.emit()
Exemplo n.º 16
0
    def __init__(self):
        super().__init__()
        self._model = None

        self.setExposedProperties("Model", "SelectedIndex")

        Preferences.getInstance().preferenceChanged.connect(self._onPreferenceChanged)
        self._onPreferenceChanged("cura/active_mode")
Exemplo n.º 17
0
def test_deserialize():
    preferences = Preferences()
    path = Resources.getPath(Resources.Preferences, "preferences_test.cfg")

    with open(path, "r", encoding="utf-8") as f:
        preferences.deserialize(f.read())
    assert preferences.getValue("general/foo") == "omgzomg"
    assert preferences.getValue("general/derp") == True
Exemplo n.º 18
0
    def _onPreferencesChanged(self, preference):
        if preference != "view/top_layer_count" and preference != "view/only_show_top_layers":
            return

        self._solid_layers = int(Preferences.getInstance().getValue("view/top_layer_count"))
        self._only_show_top_layers = bool(Preferences.getInstance().getValue("view/only_show_top_layers"))

        self._startUpdateTopLayers()
Exemplo n.º 19
0
    def __init__(self):
        super().__init__()

        Preferences.getInstance().addPreference("view/show_overhang", False)
        Preferences.getInstance().preferenceChanged.connect(self._onPreferenceChanged)

        self._enabled_material = None
        self._disabled_material = None
Exemplo n.º 20
0
    def __init__(self):
        super().__init__()

        # Find out where the engine is located, and how it is called. This depends on how Cura is packaged and which OS we are running on.
        default_engine_location = os.path.join(Application.getInstallPrefix(), "bin", "CuraEngine")
        if hasattr(sys, "frozen"):
            default_engine_location = os.path.join(os.path.dirname(os.path.abspath(sys.executable)), "CuraEngine")
        if sys.platform == "win32":
            default_engine_location += ".exe"
        default_engine_location = os.path.abspath(default_engine_location)
        Preferences.getInstance().addPreference("backend/location", default_engine_location)

        self._scene = Application.getInstance().getController().getScene()
        self._scene.sceneChanged.connect(self._onSceneChanged)

        # Workaround to disable layer view processing if layer view is not active.
        self._layer_view_active = False
        Application.getInstance().getController().activeViewChanged.connect(self._onActiveViewChanged)
        self._onActiveViewChanged()
        self._stored_layer_data = []

        #Triggers for when to (re)start slicing:
        self._global_container_stack = None
        Application.getInstance().globalContainerStackChanged.connect(self._onGlobalStackChanged)
        self._onGlobalStackChanged()

        #When you update a setting and other settings get changed through inheritance, many propertyChanged signals are fired.
        #This timer will group them up, and only slice for the last setting changed signal.
        #TODO: Properly group propertyChanged signals by whether they are triggered by the same user interaction.
        self._change_timer = QTimer()
        self._change_timer.setInterval(500)
        self._change_timer.setSingleShot(True)
        self._change_timer.timeout.connect(self.slice)

        #Listeners for receiving messages from the back-end.
        self._message_handlers["cura.proto.Layer"] = self._onLayerMessage
        self._message_handlers["cura.proto.Progress"] = self._onProgressMessage
        self._message_handlers["cura.proto.GCodeLayer"] = self._onGCodeLayerMessage
        self._message_handlers["cura.proto.GCodePrefix"] = self._onGCodePrefixMessage
        self._message_handlers["cura.proto.ObjectPrintTime"] = self._onObjectPrintTimeMessage
        self._message_handlers["cura.proto.SlicingFinished"] = self._onSlicingFinishedMessage

        self._start_slice_job = None
        self._slicing = False #Are we currently slicing?
        self._restart = False #Back-end is currently restarting?
        self._enabled = True #Should we be slicing? Slicing might be paused when, for instance, the user is dragging the mesh around.
        self._always_restart = True #Always restart the engine when starting a new slice. Don't keep the process running. TODO: Fix engine statelessness.
        self._process_layers_job = None #The currently active job to process layers, or None if it is not processing layers.

        self._error_message = None #Pop-up message that shows errors.

        self.backendQuit.connect(self._onBackendQuit)
        self.backendConnected.connect(self._onBackendConnected)

        #When a tool operation is in progress, don't slice. So we need to listen for tool operations.
        Application.getInstance().getController().toolOperationStarted.connect(self._onToolOperationStarted)
        Application.getInstance().getController().toolOperationStopped.connect(self._onToolOperationStopped)
Exemplo n.º 21
0
    def __init__(self):
        super().__init__()

        # Find out where the engine is located, and how it is called. This depends on how Cura is packaged and which OS we are running on.
        default_engine_location = os.path.join(Application.getInstallPrefix(), "bin", "CuraEngine")
        if hasattr(sys, "frozen"):
            default_engine_location = os.path.join(os.path.dirname(os.path.abspath(sys.executable)), "CuraEngine")
        if sys.platform == "win32":
            default_engine_location += ".exe"
        default_engine_location = os.path.abspath(default_engine_location)
        Preferences.getInstance().addPreference("backend/location", default_engine_location)

        self._scene = Application.getInstance().getController().getScene()
        self._scene.sceneChanged.connect(self._onSceneChanged)

        # Workaround to disable layer view processing if layer view is not active.
        self._layer_view_active = False
        Application.getInstance().getController().activeViewChanged.connect(self._onActiveViewChanged)
        self._onActiveViewChanged()
        self._stored_layer_data = []

        # When there are current settings and machine instance is changed, there is no profile changed event. We should
        # pretend there is though.
        Application.getInstance().getMachineManager().activeMachineInstanceChanged.connect(self._onActiveProfileChanged)

        self._profile = None
        Application.getInstance().getMachineManager().activeProfileChanged.connect(self._onActiveProfileChanged)
        self._onActiveProfileChanged()

        self._change_timer = QTimer()
        self._change_timer.setInterval(500)
        self._change_timer.setSingleShot(True)
        self._change_timer.timeout.connect(self.slice)

        self._message_handlers["cura.proto.Layer"] = self._onLayerMessage
        self._message_handlers["cura.proto.Progress"] = self._onProgressMessage
        self._message_handlers["cura.proto.GCodeLayer"] = self._onGCodeLayerMessage
        self._message_handlers["cura.proto.GCodePrefix"] = self._onGCodePrefixMessage
        self._message_handlers["cura.proto.ObjectPrintTime"] = self._onObjectPrintTimeMessage
        self._message_handlers["cura.proto.SlicingFinished"] = self._onSlicingFinishedMessage

        self._slicing = False
        self._start_slice_job = None
        self._restart = False
        self._enabled = True
        self._always_restart = True
        self._process_layers_job = None #The currently active job to process layers, or None if it is not processing layers.

        self._message = None

        self.backendQuit.connect(self._onBackendQuit)

        self.backendConnected.connect(self._onBackendConnected)
        Application.getInstance().getController().toolOperationStarted.connect(self._onToolOperationStarted)
        Application.getInstance().getController().toolOperationStopped.connect(self._onToolOperationStopped)

        Application.getInstance().getMachineManager().activeMachineInstanceChanged.connect(self._onInstanceChanged)
Exemplo n.º 22
0
    def __init__(self):
        super().__init__()
        self._model = None

        self.setExposedProperties("SelectedObjectId","ContainerID")

        Preferences.getInstance().preferenceChanged.connect(self._onPreferenceChanged)
        Selection.selectionChanged.connect(self.propertyChanged)
        self._onPreferenceChanged("cura/active_mode")
Exemplo n.º 23
0
    def _onTimeout(self):
        self._saving = True # To prevent the save process from triggering another autosave.
        Logger.log("d", "Autosaving preferences, instances and profiles")

        Application.getInstance().saveSettings()

        Preferences.getInstance().writeToFile(Resources.getStoragePath(Resources.Preferences, Application.getInstance().getApplicationName() + ".cfg"))

        self._saving = False
Exemplo n.º 24
0
    def __init__(self):
        super().__init__()

        Preferences.getInstance().addPreference("view/show_overhang", True)

        self._enabled_shader = None
        self._disabled_shader = None

        self._extruders_model = cura.Settings.ExtrudersModel()
Exemplo n.º 25
0
    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")
Exemplo n.º 26
0
    def __init__(self):
        super().__init__()
        self.addMenuItem(i18n_catalog.i18nc("@item:inmenu", "Check for Updates"), self.checkNewVersion)
        self._url = None

        Preferences.getInstance().addPreference("info/automatic_update_check", True)
        if Preferences.getInstance().getValue("info/automatic_update_check"):
            thread = Thread(target = self.checkNewVersion, args = (True,))
            thread.daemon = True
            thread.start()
Exemplo n.º 27
0
    def _onGlobalContainerChanged(self):
        if self._global_container_stack:
            self._global_container_stack.containersChanged.disconnect(self._onInstanceContainersChanged)

        self._global_container_stack = Application.getInstance().getGlobalContainerStack()
        self.globalContainerChanged.emit()

        if self._global_container_stack:
            Preferences.getInstance().setValue("cura/active_machine", self._global_container_stack.getId())
            self._global_container_stack.containersChanged.connect(self._onInstanceContainersChanged)
Exemplo n.º 28
0
    def saveVisibility(self):
        if not self._active_machine:
            Logger.log("w", "No active machine found when trying to save setting visibility")
            return

        visible_settings = self._active_machine.getMachineDefinition().getAllSettings(visible_only = True)
        visible_settings = map(lambda s: s.getKey(), visible_settings)

        preference = ",".join(visible_settings)
        Preferences.getInstance().setValue("machines/setting_visibility", preference)
Exemplo n.º 29
0
 def didAgree(self, user_choice):
     if user_choice:
         Logger.log("i", "User agreed to the user agreement")
         Preferences.getInstance().setValue("general/accepted_user_agreement", True)
         self._user_agreement_window.hide()
     else:
         Logger.log("i", "User did NOT agree to the user agreement")
         Preferences.getInstance().setValue("general/accepted_user_agreement", False)
         CuraApplication.getInstance().quit()
     CuraApplication.getInstance().setNeedToShowUserAgreement(False)
Exemplo n.º 30
0
    def __init__(self):
        super().__init__()
        Application.getInstance().getOutputDeviceManager().writeStarted.connect(self._onWriteStarted)
        Preferences.getInstance().addPreference("info/send_slice_info", True)
        Preferences.getInstance().addPreference("info/asked_send_slice_info", False)

        if not Preferences.getInstance().getValue("info/asked_send_slice_info"):
            self.send_slice_info_message = Message(catalog.i18nc("@info", "Cura automatically sends slice info. You can disable this in preferences"), lifetime = 0, dismissable = False)
            self.send_slice_info_message.addAction("Dismiss", catalog.i18nc("@action:button", "Dismiss"), None, "")
            self.send_slice_info_message.actionTriggered.connect(self.messageActionTriggered)
            self.send_slice_info_message.show()
Exemplo n.º 31
0
    def _updateJobName(self):
        if self._base_name == "":
            self._job_name = ""
            self.jobNameChanged.emit()
            return

        base_name = self._stripAccents(self._base_name)
        self._setAbbreviatedMachineName()
        if self._pre_sliced:
            self._job_name = catalog.i18nc("@label", "Pre-sliced file {0}",
                                           base_name)
        elif Preferences.getInstance().getValue("cura/jobname_prefix"):
            # Don't add abbreviation if it already has the exact same abbreviation.
            if base_name.startswith(self._abbr_machine + "_"):
                self._job_name = base_name
            else:
                self._job_name = self._abbr_machine + "_" + base_name
        else:
            self._job_name = base_name

        self.jobNameChanged.emit()
Exemplo n.º 32
0
def test_setActivePreset():
    preferences = Preferences()
    visibility_model = SettingVisibilityPresetsModel(preferences)
    visibility_model.activePresetChanged = MagicMock()
    # Ensure that we start off with basic (since we didn't change anyting just yet!)
    assert visibility_model.activePreset == "basic"

    # Everything should be the same.
    visibility_model.setActivePreset("basic")
    assert visibility_model.activePreset == "basic"
    assert visibility_model.activePresetChanged.emit.call_count == 0  # No events should be sent.

    # Change it to existing type (should work...)
    visibility_model.setActivePreset("advanced")
    assert visibility_model.activePreset == "advanced"
    assert visibility_model.activePresetChanged.emit.call_count == 1

    # Change to unknown preset. Shouldn't do anything.
    visibility_model.setActivePreset("OMGZOMGNOPE")
    assert visibility_model.activePreset == "advanced"
    assert visibility_model.activePresetChanged.emit.call_count == 1
Exemplo n.º 33
0
    def _update(self, *args):
        nodes = []
        filter_current_build_plate = Preferences.getInstance().getValue("view/filter_current_build_plate")
        active_build_plate_number = self._build_plate_number
        group_nr = 1
        for node in DepthFirstIterator(Application.getInstance().getController().getScene().getRoot()):
            if not isinstance(node, SceneNode):
                continue
            if (not node.getMeshData() and not node.callDecoration("getLayerData")) and not node.callDecoration("isGroup"):
                continue
            if node.getParent() and node.getParent().callDecoration("isGroup"):
                continue  # Grouped nodes don't need resetting as their parent (the group) is resetted)
            if not node.callDecoration("isSliceable") and not node.callDecoration("isGroup"):
                continue
            node_build_plate_number = node.callDecoration("getBuildPlateNumber")
            if filter_current_build_plate and node_build_plate_number != active_build_plate_number:
                continue

            if not node.callDecoration("isGroup"):
                name = node.getName()
            else:
                name = catalog.i18nc("@label", "Group #{group_nr}").format(group_nr = str(group_nr))
                group_nr += 1

            if hasattr(node, "isOutsideBuildArea"):
                is_outside_build_area = node.isOutsideBuildArea()
            else:
                is_outside_build_area = False

            nodes.append({
                "name": name,
                "isSelected": Selection.isSelected(node),
                "isOutsideBuildArea": is_outside_build_area,
                "buildPlateNumber": node_build_plate_number,
                "node": node
            })
        nodes = sorted(nodes, key=lambda n: n["name"])
        self.setItems(nodes)

        self.itemsChanged.emit()
Exemplo n.º 34
0
    def initializeBeforePluginsAreLoaded(self):
        config_path = Resources.getConfigStoragePath()
        self._plugin_config_filename = os.path.join(os.path.abspath(config_path), "plugins.json")

        # 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"]

        # Also load data from preferences, where the plugin info used to be saved
        preferences = Preferences.getInstance()
        disabled_plugins = preferences.getValue("general/disabled_plugins")
        disabled_plugins = disabled_plugins.split(",") if disabled_plugins else []
        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()
Exemplo n.º 35
0
 def onSelectionChanged(self):
     if Selection.hasSelection():
         if not self.getController().getActiveTool():
             if self._previous_active_tool:
                 self.getController().setActiveTool(
                     self._previous_active_tool)
                 self._previous_active_tool = None
             else:
                 self.getController().setActiveTool("TranslateTool")
         if Preferences.getInstance().getValue("view/center_on_select"):
             self._camera_animation.setStart(
                 self.getController().getTool("CameraTool").getOrigin())
             self._camera_animation.setTarget(
                 Selection.getSelectedObject(0).getWorldPosition())
             self._camera_animation.start()
     else:
         if self.getController().getActiveTool():
             self._previous_active_tool = self.getController(
             ).getActiveTool().getPluginId()
             self.getController().setActiveTool(None)
         else:
             self._previous_active_tool = None
Exemplo n.º 36
0
 def onSelectionChanged(self):
     if Selection.hasSelection():
         if self.getController().getActiveTool():
             # If the tool has been disabled by the new selection
             if not self.getController().getActiveTool().getEnabled():
                 # Default
                 self.getController().setActiveTool("TranslateTool")
         else:
             if self._previous_active_tool:
                 self.getController().setActiveTool(self._previous_active_tool)
                 if not self.getController().getActiveTool().getEnabled():
                     self.getController().setActiveTool("TranslateTool")
                 self._previous_active_tool = None
             else:
                 # Default
                 self.getController().setActiveTool("TranslateTool")
         if Preferences.getInstance().getValue("view/center_on_select"):
             self._center_after_select = True
     else:
         if self.getController().getActiveTool():
             self._previous_active_tool = self.getController().getActiveTool().getPluginId()
             self.getController().setActiveTool(None)
Exemplo n.º 37
0
    def determineAutoSlicing(self):
        enable_timer = True

        if not Preferences.getInstance().getValue("general/auto_slice"):
            enable_timer = False
        for node in DepthFirstIterator(self._scene.getRoot()):
            if node.callDecoration("isBlockSlicing"):
                enable_timer = False
                self.backendStateChange.emit(BackendState.Disabled)
            gcode_list = node.callDecoration("getGCodeList")
            if gcode_list is not None:
                self._scene.gcode_dict[node.callDecoration("getBuildPlateNumber")] = gcode_list

        if self._use_timer == enable_timer:
            return self._use_timer
        if enable_timer:
            self.backendStateChange.emit(BackendState.NotStarted)
            self.enableTimer()
            return True
        else:
            self.disableTimer()
            return False
Exemplo n.º 38
0
    def reload(self):
        self._styles = None
        self._path = ""
        self._icons = {}
        self._images = {}
        Preferences.getInstance().addPreference("general/theme", Application.getInstance().default_theme)

        try:
            theme_path = Resources.getPath(Resources.Themes, Preferences.getInstance().getValue("general/theme"))
            self.load(theme_path)
        except FileNotFoundError:
            Logger.log("e", "Could not find theme file, resetting to the default theme.")

            # cannot the current theme, so go back to the default
            Preferences.getInstance().setValue("general/theme", Application.getInstance().default_theme)
            theme_path = Resources.getPath(Resources.Themes, Preferences.getInstance().getValue("general/theme"))
            self.load(theme_path)
Exemplo n.º 39
0
    def __init__(self, app_name):
        super().__init__()

        self._application_name = app_name

        self._machine_definitions = []
        self._machine_instances = []
        self._profiles = []

        self._active_machine = None
        self._active_profile = None

        Preferences.getInstance().addPreference("machines/setting_visibility",
                                                "")
        Preferences.getInstance().addPreference("machines/active_instance", "")
        Preferences.getInstance().addPreference("machines/active_profile",
                                                "Normal Quality")
Exemplo n.º 40
0
    def __init__(self):
        super().__init__()
        if PrintModeManager._instance is not None:
            raise ValueError("Duplicate singleton creation")

        PrintModeManager._instance = self

        self._duplicated_nodes = []
        self._scene = Application.getInstance().getController().getScene()

        #Settings which value needs to be handled when changing print_mode
        self._conflict_settings = {
            'wall_extruder_nr', 'wall_0_extruder_nr', 'wall_x_extruder_nr',
            'roofing_extruder_nr', 'top_bottom_extruder_nr',
            'infill_extruder_nr', 'support_extruder_nr',
            'support_infill_extruder_nr', 'support_extruder_nr_layer_0',
            'support_interface_extruder_nr', 'support_roof_extruder_nr',
            'support_bottom_extruder_nr', 'adhesion_extruder_nr',
            'prime_tower_enable', 'ooze_shield_enabled',
            'carve_multiple_volumes', 'retraction_max_count'
        }

        old_material_id = Preferences.getInstance().getValue(
            "cura/old_material")
        if Application.getInstance().getContainerRegistry().findContainers(
                id=old_material_id):
            self._old_material = Application.getInstance(
            ).getContainerRegistry().findContainers(id=old_material_id)[0]
        else:
            self._old_material = ""

        self._global_stack = None
        Application.getInstance().globalContainerStackChanged.connect(
            self._onGlobalStackChanged)
        self._onGlobalStackChanged()

        self.printModeChanged.connect(self._onPrintModeChanged)
        self._onPrintModeChanged()
Exemplo n.º 41
0
    def __init__(self):
        super().__init__()
        self._zero_conf = None
        self._zero_conf_browser = None

        # Because the model needs to be created in the same thread as the QMLEngine, we use a signal.
        self.addDeviceSignal.connect(self._onAddDevice)
        self.removeDeviceSignal.connect(self._onRemoveDevice)

        Application.getInstance().globalContainerStackChanged.connect(self.reCheckConnections)

        self._discovered_devices = {}
        
        self._network_manager = QNetworkAccessManager()
        self._network_manager.finished.connect(self._onNetworkRequestFinished)

        self._min_cluster_version = Version("4.0.0")

        self._api_version = "1"
        self._api_prefix = "/api/v" + self._api_version + "/"
        self._cluster_api_version = "1"
        self._cluster_api_prefix = "/cluster-api/v" + self._cluster_api_version + "/"

        # Get list of manual instances from preferences
        self._preferences = Preferences.getInstance()
        self._preferences.addPreference("um3networkprinting/manual_instances",
                                        "")  # A comma-separated list of ip adresses or hostnames

        self._manual_instances = self._preferences.getValue("um3networkprinting/manual_instances").split(",")

        # The zero-conf service changed requests are handled in a separate thread, so we can re-schedule the requests
        # which fail to get detailed service info.
        # Any new or re-scheduled requests will be appended to the request queue, and the handling thread will pick
        # them up and process them.
        self._service_changed_request_queue = Queue()
        self._service_changed_request_event = Event()
        self._service_changed_request_thread = Thread(target=self._handleOnServiceChangedRequests, daemon=True)
        self._service_changed_request_thread.start()
Exemplo n.º 42
0
    def requestWrite(self, node, file_name=None, filter_by_machine=False):
        if self._writing:
            raise OutputDeviceError.DeviceBusyError()

        self.writeStarted.emit(self)
        mesh_writer = Application.getInstance().getMeshFileHandler(
        ).getWriterByMimeType("text/x-gcode")

        job = OctoprintUploadJob(mesh_writer, node)
        job.setFileName(file_name + ".gcode")
        job.progress.connect(self._onJobProgress)
        job.finished.connect(self._onWriteJobFinished)

        message = Message("Uploading {0} to {1}".format(
            job.getFileName(),
            Preferences.getInstance().getValue("octoprint/base_url")),
                          0,
                          progress=-1)
        message.show()

        job._message = message
        self._writing = True
        job.start()
Exemplo n.º 43
0
    def _configurationNeedsUpdates(self):
        preferences = Preferences.getInstance()
        preferences.addPreference("blackbelt/setting_version", "0.0.0")

        # Get version information from plugin.json
        plugin_file_path = os.path.join(
            os.path.dirname(os.path.abspath(__file__)), "plugin.json")
        try:
            with open(plugin_file_path) as plugin_file:
                plugin_info = json.load(plugin_file)
                plugin_version = plugin_info["version"]
        except:
            Logger.log("w", "Could not determine BlackBelt plugin version")
            return False

        if Version(preferences.getValue(
                "blackbelt/setting_version")) < Version(plugin_version):
            Logger.log("d",
                       "Setting BlackBelt version nr to %s" % plugin_version)
            preferences.setValue("blackbelt/setting_version", plugin_version)
            return True

        return False
    def __init__(self):
        super().__init__()
        self._zero_conf = None
        self._browser = None
        self._instances = {}

        # Because the model needs to be created in the same thread as the QMLEngine, we use a signal.
        self.addInstanceSignal.connect(self.addInstance)
        self.removeInstanceSignal.connect(self.removeInstance)
        Application.getInstance().globalContainerStackChanged.connect(self.reCheckConnections)

        # Load custom instances from preferences
        self._preferences = Preferences.getInstance()
        self._preferences.addPreference("Repetier/manual_instances", "{}")

        try:
            self._manual_instances = json.loads(self._preferences.getValue("Repetier/manual_instances"))
        except ValueError:
            self._manual_instances = {}
        if not isinstance(self._manual_instances, dict):
            self._manual_instances = {}

        self._name_regex = re.compile("Repetier instance (\".*\"\.|on )(.*)\.")
Exemplo n.º 45
0
def test_refreshAccessTokenFailed():
    """
    Test if the authentication is reset once the refresh token fails to refresh access.
    """
    authorization_service = AuthorizationService(OAUTH_SETTINGS, Preferences())
    authorization_service.initialize()

    def mock_refresh(self, refresh_token,
                     callback):  # Refreshing gives a valid token.
        callback(FAILED_AUTH_RESPONSE)

    mock_reply = Mock(
    )  # The response that the request should give, containing an error about it failing to authenticate.
    mock_reply.error = Mock(
        return_value=QNetworkReply.NetworkError.AuthenticationRequiredError
    )  # The reply is 403: Authentication required, meaning the server responded with a "Can't do that, Dave".
    http_mock = Mock()
    http_mock.get = lambda url, headers_dict, callback, error_callback: callback(
        mock_reply)
    http_mock.post = lambda url, data, headers_dict, callback, error_callback: callback(
        mock_reply)

    with patch(
            "UM.TaskManagement.HttpRequestManager.HttpRequestManager.readJSON",
            Mock(
                return_value={"error_description": "Mock a failed request!"})):
        with patch(
                "UM.TaskManagement.HttpRequestManager.HttpRequestManager.getInstance",
                MagicMock(return_value=http_mock)):
            authorization_service._storeAuthData(SUCCESSFUL_AUTH_RESPONSE)
            authorization_service.onAuthStateChanged.emit = MagicMock()
            with patch(
                    "cura.OAuth2.AuthorizationHelpers.AuthorizationHelpers.getAccessTokenUsingRefreshToken",
                    mock_refresh):
                authorization_service.refreshAccessToken()
                assert authorization_service.onAuthStateChanged.emit.called_with(
                    False)
Exemplo n.º 46
0
    def __init__(self):
        super().__init__()
        self._zero_conf = None
        self._browser = None
        self._printers = {}
        self._cluster_printers_seen = {
        }  # do not forget a cluster printer when we have seen one, to not 'downgrade' from Connect to legacy printer

        self._api_version = "1"
        self._api_prefix = "/api/v" + self._api_version + "/"
        self._cluster_api_version = "1"
        self._cluster_api_prefix = "/cluster-api/v" + self._cluster_api_version + "/"

        self._network_manager = QNetworkAccessManager()
        self._network_manager.finished.connect(self._onNetworkRequestFinished)

        # List of old printer names. This is used to ensure that a refresh of zeroconf does not needlessly forces
        # authentication requests.
        self._old_printers = []

        # Because the model needs to be created in the same thread as the QMLEngine, we use a signal.
        self.addPrinterSignal.connect(self.addPrinter)
        self.removePrinterSignal.connect(self.removePrinter)
        Application.getInstance().globalContainerStackChanged.connect(
            self.reCheckConnections)

        # Get list of manual printers from preferences
        self._preferences = Preferences.getInstance()
        self._preferences.addPreference(
            "um3networkprinting/manual_instances",
            "")  #  A comma-separated list of ip adresses or hostnames
        self._manual_instances = self._preferences.getValue(
            "um3networkprinting/manual_instances").split(",")

        self._network_requests_buffer = {
        }  # store api responses until data is complete
Exemplo n.º 47
0
def test_preferenceChanged():
    preferences = Preferences()
    # Set the visible_settings to something silly
    preferences.addPreference("general/visible_settings", "omgzomg")
    visibility_model = SettingVisibilityPresetsModel(preferences)
    visibility_model.activePresetChanged = MagicMock()

    assert visibility_model.activePreset == "custom"  # This should make the model start at "custom
    assert visibility_model.activePresetChanged.emit.call_count == 0

    basic_visibility = visibility_model.getVisibilityPresetById("basic")
    new_visibility_string = ";".join(basic_visibility.settings)
    preferences.setValue("general/visible_settings", new_visibility_string)

    # Fake a signal emit (since we didn't create the application, our own signals are not fired)
    visibility_model._onPreferencesChanged("general/visible_settings")
    # Set the visibility settings to basic
    assert visibility_model.activePreset == "basic"
    assert visibility_model.activePresetChanged.emit.call_count == 1
Exemplo n.º 48
0
    def __init__(self, engine, parent=None):
        super().__init__(parent)

        self._engine = engine
        self._styles = None
        self._path = ""
        self._icons = {}
        self._images = {}

        # Workaround for incorrect default font on Windows
        if sys.platform == "win32":
            default_font = QFont()
            default_font.setPointSize(9)
            QCoreApplication.instance().setFont(default_font)

        self._em_height = int(
            QFontMetrics(QCoreApplication.instance().font()).ascent())
        self._em_width = self._em_height

        self._initializeDefaults()

        Preferences.getInstance().addPreference(
            "general/theme",
            Application.getInstance().default_theme)
        try:
            theme_path = Resources.getPath(
                Resources.Themes,
                Preferences.getInstance().getValue("general/theme"))
            self.load(theme_path)
        except FileNotFoundError:
            Logger.log(
                "e",
                "Could not find theme file, resetting to the default theme.")

            # cannot the current theme, so go back to the default
            Preferences.getInstance().setValue(
                "general/theme",
                Application.getInstance().default_theme)
            theme_path = Resources.getPath(
                Resources.Themes,
                Preferences.getInstance().getValue("general/theme"))
            self.load(theme_path)
Exemplo n.º 49
0
    def __init__(self, app_name):
        super().__init__()

        self._application_name = app_name

        self._machine_definitions = []
        self._machine_instances = []
        self._profiles = []

        self._active_machine = None
        self._active_profile = None

        self._profile_readers = {}  #Plugins that read profiles from file.
        self._profile_writers = {}  #Plugins that write profiles to file.
        PluginRegistry.addType("profile_reader", self.addProfileReader)
        PluginRegistry.addType("profile_writer", self.addProfileWriter)

        Preferences.getInstance().addPreference("machines/setting_visibility",
                                                "")
        Preferences.getInstance().addPreference("machines/active_instance", "")
        Preferences.getInstance().addPreference("machines/active_profile",
                                                "Normal Quality")
Exemplo n.º 50
0
    def _onChangeTimerFinished(self):
        if not self._enabled:
            return

        root = self._controller.getScene().getRoot()

        # Keep a list of nodes that are moving. We use this so that we don't move two intersecting objects in the
        # same direction.
        transformed_nodes = []

        # We try to shuffle all the nodes to prevent "locked" situations, where iteration B inverts iteration A.
        # By shuffling the order of the nodes, this might happen a few times, but at some point it will resolve.
        nodes = list(BreadthFirstIterator(root))

        # Only check nodes inside build area.
        nodes = [
            node for node in nodes if (hasattr(node, "_outside_buildarea")
                                       and not node._outside_buildarea)
        ]

        random.shuffle(nodes)
        for node in nodes:
            if node is root or not isinstance(node, SceneNode) or isinstance(
                    node, DuplicatedNode) or node.getBoundingBox() is None:
                continue

            bbox = node.getBoundingBox()

            # Move it downwards if bottom is above platform
            move_vector = Vector()

            if Preferences.getInstance().getValue(
                    "physics/automatic_drop_down") and not (
                        node.getParent() and node.getParent().callDecoration(
                            "isGroup")) and node.isEnabled(
                            ):  #If an object is grouped, don't move it down
                z_offset = node.callDecoration(
                    "getZOffset") if node.getDecorator(
                        ZOffsetDecorator.ZOffsetDecorator) else 0
                move_vector = move_vector.set(y=-bbox.bottom + z_offset)

            # If there is no convex hull for the node, start calculating it and continue.
            if not node.getDecorator(ConvexHullDecorator):
                node.addDecorator(ConvexHullDecorator())

            # only push away objects if this node is a printing mesh
            if not node.callDecoration(
                    "isNonPrintingMesh") and Preferences.getInstance(
                    ).getValue("physics/automatic_push_free"
                               ) and type(node) != DuplicatedNode:
                # Check for collisions between convex hulls
                for other_node in BreadthFirstIterator(root):
                    # Ignore root, ourselves and anything that is not a normal SceneNode.
                    if other_node is root or not issubclass(
                            type(other_node), SceneNode
                    ) or other_node is node or other_node.callDecoration(
                            "getBuildPlateNumber") != node.callDecoration(
                                "getBuildPlateNumber"):
                        continue

                    # Ignore collisions of a group with it's own children
                    if other_node in node.getAllChildren(
                    ) or node in other_node.getAllChildren():
                        continue

                    # Ignore collisions within a group
                    if other_node.getParent() and node.getParent() and (
                            other_node.getParent().callDecoration("isGroup")
                            is not None
                            or node.getParent().callDecoration("isGroup")
                            is not None):
                        continue

                    # Ignore nodes that do not have the right properties set.
                    if not other_node.callDecoration(
                            "getConvexHull") or not other_node.getBoundingBox(
                            ):
                        continue

                    if other_node in transformed_nodes:
                        continue  # Other node is already moving, wait for next pass.

                    if other_node.callDecoration("isNonPrintingMesh"):
                        continue

                    overlap = (0, 0)  # Start loop with no overlap
                    current_overlap_checks = 0
                    # Continue to check the overlap until we no longer find one.
                    while overlap and current_overlap_checks < self._max_overlap_checks:
                        current_overlap_checks += 1
                        head_hull = node.callDecoration("getConvexHullHead")
                        if head_hull:  # One at a time intersection.
                            overlap = head_hull.translate(
                                move_vector.x,
                                move_vector.z).intersectsPolygon(
                                    other_node.callDecoration("getConvexHull"))
                            if not overlap:
                                other_head_hull = other_node.callDecoration(
                                    "getConvexHullHead")
                                if other_head_hull:
                                    overlap = node.callDecoration(
                                        "getConvexHull").translate(
                                            move_vector.x,
                                            move_vector.z).intersectsPolygon(
                                                other_head_hull)
                                    if overlap:
                                        # Moving ensured that overlap was still there. Try anew!
                                        move_vector = move_vector.set(
                                            x=move_vector.x +
                                            overlap[0] * self._move_factor,
                                            z=move_vector.z +
                                            overlap[1] * self._move_factor)
                            else:
                                # Moving ensured that overlap was still there. Try anew!
                                move_vector = move_vector.set(
                                    x=move_vector.x +
                                    overlap[0] * self._move_factor,
                                    z=move_vector.z +
                                    overlap[1] * self._move_factor)
                        else:
                            own_convex_hull = node.callDecoration(
                                "getConvexHull")
                            other_convex_hull = other_node.callDecoration(
                                "getConvexHull")
                            if own_convex_hull and other_convex_hull:
                                overlap = own_convex_hull.translate(
                                    move_vector.x,
                                    move_vector.z).intersectsPolygon(
                                        other_convex_hull)
                                if overlap:  # Moving ensured that overlap was still there. Try anew!
                                    temp_move_vector = move_vector.set(
                                        x=move_vector.x +
                                        overlap[0] * self._move_factor,
                                        z=move_vector.z +
                                        overlap[1] * self._move_factor)

                                    # if the distance between two models less than 2mm then try to find a new factor
                                    if abs(temp_move_vector.x - overlap[0]
                                           ) < self._minimum_gap and abs(
                                               temp_move_vector.y -
                                               overlap[1]) < self._minimum_gap:
                                        temp_x_factor = (
                                            abs(overlap[0]) + self._minimum_gap
                                        ) / overlap[0] if overlap[
                                            0] != 0 else 0  # find x move_factor, like (3.4 + 2) / 3.4 = 1.58
                                        temp_y_factor = (
                                            abs(overlap[1]) + self._minimum_gap
                                        ) / overlap[1] if overlap[
                                            1] != 0 else 0  # find y move_factor

                                        temp_scale_factor = temp_x_factor if abs(
                                            temp_x_factor) > abs(
                                                temp_y_factor
                                            ) else temp_y_factor

                                        move_vector = move_vector.set(
                                            x=move_vector.x +
                                            overlap[0] * temp_scale_factor,
                                            z=move_vector.z +
                                            overlap[1] * temp_scale_factor)
                                    else:
                                        move_vector = temp_move_vector
                            else:
                                # This can happen in some cases if the object is not yet done with being loaded.
                                # Simply waiting for the next tick seems to resolve this correctly.
                                overlap = None

            if not Vector.Null.equals(move_vector, epsilon=1e-5):
                transformed_nodes.append(node)
                op = PlatformPhysicsOperation.PlatformPhysicsOperation(
                    node, move_vector)
                op.push()

        # After moving, we have to evaluate the boundary checks for nodes
        build_volume = Application.getInstance().getBuildVolume()
        build_volume.updateNodeBoundaryCheck()
Exemplo n.º 51
0
    def __init__(self):
        super().__init__()

        self._max_layers = 0
        self._current_layer_num = 0
        self._minimum_layer_num = 0
        self._current_layer_mesh = None
        self._current_layer_jumps = None
        self._top_layers_job = None
        self._activity = False
        self._old_max_layers = 0

        self._max_paths = 0
        self._current_path_num = 0
        self._minimum_path_num = 0
        self.currentLayerNumChanged.connect(self._onCurrentLayerNumChanged)

        self._busy = False
        self._simulation_running = False

        self._ghost_shader = None
        self._layer_pass = None
        self._composite_pass = None
        self._old_layer_bindings = None
        self._simulationview_composite_shader = None
        self._old_composite_shader = None

        self._global_container_stack = None
        self._proxy = SimulationViewProxy()
        self._controller.getScene().getRoot().childrenChanged.connect(self._onSceneChanged)

        self._resetSettings()
        self._legend_items = None
        self._show_travel_moves = False
        self._nozzle_node = None

        Preferences.getInstance().addPreference("view/top_layer_count", 5)
        Preferences.getInstance().addPreference("view/only_show_top_layers", False)
        Preferences.getInstance().addPreference("view/force_layer_view_compatibility_mode", False)

        Preferences.getInstance().addPreference("layerview/layer_view_type", 0)
        Preferences.getInstance().addPreference("layerview/extruder_opacities", "")

        Preferences.getInstance().addPreference("layerview/show_travel_moves", False)
        Preferences.getInstance().addPreference("layerview/show_helpers", True)
        Preferences.getInstance().addPreference("layerview/show_skin", True)
        Preferences.getInstance().addPreference("layerview/show_infill", True)

        Preferences.getInstance().preferenceChanged.connect(self._onPreferencesChanged)
        self._updateWithPreferences()

        self._solid_layers = int(Preferences.getInstance().getValue("view/top_layer_count"))
        self._only_show_top_layers = bool(Preferences.getInstance().getValue("view/only_show_top_layers"))
        self._compatibility_mode = True  # for safety

        self._wireprint_warning_message = Message(catalog.i18nc("@info:status", "Cura does not accurately display layers when Wire Printing is enabled"),
                                                  title = catalog.i18nc("@info:title", "Simulation View"))
    def requestWrite(self,
                     nodes,
                     file_name=None,
                     limit_mimetypes=None,
                     file_handler=None):
        if self._writing:
            raise OutputDeviceError.DeviceBusyError()

        dialog = QFileDialog()

        dialog.setWindowTitle(catalog.i18nc("@title:window", "Save to File"))
        dialog.setFileMode(QFileDialog.AnyFile)
        dialog.setAcceptMode(QFileDialog.AcceptSave)

        # Ensure platform never ask for overwrite confirmation since we do this ourselves
        dialog.setOption(QFileDialog.DontConfirmOverwrite)

        if sys.platform == "linux" and "KDE_FULL_SESSION" in os.environ:
            dialog.setOption(QFileDialog.DontUseNativeDialog)

        filters = []
        mime_types = []
        selected_filter = None
        last_used_type = Preferences.getInstance().getValue(
            "local_file/last_used_type")

        if not file_handler:
            file_handler = Application.getInstance().getMeshFileHandler()

        file_types = file_handler.getSupportedFileTypesWrite()

        file_types.sort(key=lambda k: k["description"])
        if limit_mimetypes:
            file_types = list(
                filter(lambda i: i["mime_type"] in limit_mimetypes,
                       file_types))

        if len(file_types) == 0:
            Logger.log("e", "There are no file types available to write with!")
            raise OutputDeviceError.WriteRequestFailedError()

        for item in file_types:
            type_filter = "{0} (*.{1})".format(item["description"],
                                               item["extension"])
            filters.append(type_filter)
            mime_types.append(item["mime_type"])
            if last_used_type == item["mime_type"]:
                selected_filter = type_filter
                if file_name:
                    file_name += "." + item["extension"]

        dialog.setNameFilters(filters)
        if selected_filter is not None:
            dialog.selectNameFilter(selected_filter)

        if file_name is not None:
            dialog.selectFile(file_name)

        stored_directory = Preferences.getInstance().getValue(
            "local_file/dialog_save_path")
        dialog.setDirectory(stored_directory)

        if not dialog.exec_():
            raise OutputDeviceError.UserCanceledError()

        save_path = dialog.directory().absolutePath()
        Preferences.getInstance().setValue("local_file/dialog_save_path",
                                           save_path)

        selected_type = file_types[filters.index(dialog.selectedNameFilter())]
        Preferences.getInstance().setValue("local_file/last_used_type",
                                           selected_type["mime_type"])

        file_name = dialog.selectedFiles()[0]

        if os.path.exists(file_name):
            result = QMessageBox.question(
                None, catalog.i18nc("@title:window", "File Already Exists"),
                catalog.i18nc(
                    "@label",
                    "The file <filename>{0}</filename> already exists. Are you sure you want to overwrite it?"
                ).format(file_name))
            if result == QMessageBox.No:
                raise OutputDeviceError.UserCanceledError()

        self.writeStarted.emit(self)

        if file_handler:
            file_writer = file_handler.getWriter(selected_type["id"])
        else:
            file_writer = Application.getInstance().getMeshFileHandler(
            ).getWriter(selected_type["id"])

        try:
            mode = selected_type["mode"]
            if mode == MeshWriter.OutputMode.TextMode:
                Logger.log("d", "Writing to Local File %s in text mode",
                           file_name)
                stream = open(file_name, "wt", encoding="utf-8")
            elif mode == MeshWriter.OutputMode.BinaryMode:
                Logger.log("d", "Writing to Local File %s in binary mode",
                           file_name)
                stream = open(file_name, "wb")

            job = WriteFileJob(file_writer, stream, nodes, mode)
            job.setFileName(file_name)
            job.progress.connect(self._onJobProgress)
            job.finished.connect(self._onWriteJobFinished)

            message = Message(
                catalog.i18nc(
                    "@info:progress",
                    "Saving to <filename>{0}</filename>").format(file_name), 0,
                False, -1)
            message.show()

            job._message = message
            self._writing = True
            job.start()
        except PermissionError as e:
            Logger.log("e", "Permission denied when trying to write to %s: %s",
                       file_name, str(e))
            raise OutputDeviceError.PermissionDeniedError(
                catalog.i18nc(
                    "@info:status",
                    "Permission denied when trying to save <filename>{0}</filename>"
                ).format(file_name)) from e
        except OSError as e:
            Logger.log("e",
                       "Operating system would not let us write to %s: %s",
                       file_name, str(e))
            raise OutputDeviceError.WriteRequestFailedError(
                catalog.i18nc(
                    "@info:status",
                    "Could not save to <filename>{0}</filename>: <message>{1}</message>"
                ).format()) from e
Exemplo n.º 53
0
class Application:
    ##  Init method
    #
    #   \param name \type{string} The name of the application.
    #   \param version \type{string} Version, formatted as major.minor.rev
    #   \param build_type Additional version info on the type of build this is, such as "master".
    #   \param is_debug_mode Whether to run in debug mode.
    def __init__(self,
                 name: str,
                 version: str,
                 api_version: str,
                 app_display_name: str = "",
                 build_type: str = "",
                 is_debug_mode: bool = False,
                 **kwargs) -> None:
        if Application.__instance is not None:
            raise RuntimeError("Try to create singleton '%s' more than once" %
                               self.__class__.__name__)
        Application.__instance = self

        super().__init__()  # Call super to make multiple inheritance work.

        self._api_version = Version(api_version)  # type: Version

        self._app_name = name  #type: str
        self._app_display_name = app_display_name if app_display_name else name  # type: str
        self._version = version  #type: str
        self._build_type = build_type  #type: str
        self._is_debug_mode = is_debug_mode  #type: bool
        self._is_headless = False  #type: bool
        self._use_external_backend = False  #type: bool

        self._config_lock_filename = "{name}.lock".format(
            name=self._app_name)  # type: str

        self._cli_args = None  #type: argparse.Namespace
        self._cli_parser = argparse.ArgumentParser(
            prog=self._app_name,
            add_help=False)  #type: argparse.ArgumentParser

        self._main_thread = threading.current_thread()  #type: threading.Thread

        self.default_theme = self._app_name  #type: str # Default theme is the application name
        self._default_language = "en_US"  #type: str

        self.change_log_url = "https://github.com/Ultimaker/Uranium"  # Where to find a more detailed description of the recent updates.

        self._preferences_filename = None  #type: str
        self._preferences = None  #type: Preferences

        self._extensions = []  #type: List[Extension]
        self._required_plugins = []  #type: List[str]

        self._package_manager_class = PackageManager  # type: type
        self._package_manager = None  # type: PackageManager

        self._plugin_registry = None  #type: PluginRegistry
        self._container_registry_class = ContainerRegistry  #type: type
        self._container_registry = None  #type: ContainerRegistry
        self._global_container_stack = None  #type: ContainerStack

        self._controller = None  #type: Controller
        self._backend = None  #type: Backend
        self._output_device_manager = None  #type: OutputDeviceManager
        self._operation_stack = None  #type: OperationStack

        self._visible_messages = []  #type: List[Message]
        self._message_lock = threading.Lock()  #type: threading.Lock

        self._app_install_dir = self.getInstallPrefix()  #type: str

    def getAPIVersion(self) -> "Version":
        return self._api_version

    # Adds the command line options that can be parsed by the command line parser.
    # Can be overridden to add additional command line options to the parser.
    def addCommandLineOptions(self) -> None:
        self._cli_parser.add_argument("--version",
                                      action="version",
                                      version="%(prog)s version: {0}".format(
                                          self._version))
        self._cli_parser.add_argument(
            "--external-backend",
            action="store_true",
            default=False,
            help=
            "Use an externally started backend instead of starting it automatically. This is a debug feature to make it possible to run the engine with debug options enabled."
        )
        self._cli_parser.add_argument('--headless',
                                      action='store_true',
                                      default=False,
                                      help="Hides all GUI elements.")
        self._cli_parser.add_argument(
            "--debug",
            action="store_true",
            default=False,
            help="Turn on the debug mode by setting this option.")

    def parseCliOptions(self) -> None:
        self._cli_args = self._cli_parser.parse_args()

        self._is_headless = self._cli_args.headless
        self._is_debug_mode = self._cli_args.debug or self._is_debug_mode
        self._use_external_backend = self._cli_args.external_backend

    # Performs initialization that must be done before start.
    def initialize(self) -> None:
        # For Ubuntu Unity this makes Qt use its own menu bar rather than pass it on to Unity.
        os.putenv("UBUNTU_MENUPROXY", "0")

        # Custom signal handling
        Signal._app = self
        Signal._signalQueue = self

        # Initialize Resources. Set the application name and version here because we can only know the actual info
        # after the __init__() has been called.
        Resources.ApplicationIdentifier = self._app_name
        Resources.ApplicationVersion = self._version

        Resources.addSearchPath(
            os.path.join(os.path.dirname(sys.executable), "resources"))
        Resources.addSearchPath(
            os.path.join(self._app_install_dir, "share", "uranium",
                         "resources"))
        Resources.addSearchPath(
            os.path.join(self._app_install_dir, "Resources", "uranium",
                         "resources"))
        Resources.addSearchPath(
            os.path.join(self._app_install_dir, "Resources", self._app_name,
                         "resources"))

        if not hasattr(sys, "frozen"):
            Resources.addSearchPath(
                os.path.join(os.path.abspath(os.path.dirname(__file__)), "..",
                             "resources"))

        i18nCatalog.setApplication(self)

        PluginRegistry.addType("backend", self.setBackend)
        PluginRegistry.addType("logger", Logger.addLogger)
        PluginRegistry.addType("extension", self.addExtension)

        self._preferences = Preferences()
        self._preferences.addPreference("general/language",
                                        self._default_language)
        self._preferences.addPreference("general/visible_settings", "")
        self._preferences.addPreference("general/plugins_to_remove", "")
        self._preferences.addPreference("general/disabled_plugins", "")

        self._controller = Controller(self)
        self._output_device_manager = OutputDeviceManager()

        self._operation_stack = OperationStack(
            self._controller)  # type: OperationStack

        self._plugin_registry = PluginRegistry(self)  #type: PluginRegistry

        self._plugin_registry.addPluginLocation(
            os.path.join(self._app_install_dir, "lib", "uranium"))
        self._plugin_registry.addPluginLocation(
            os.path.join(self._app_install_dir, "lib64", "uranium"))
        self._plugin_registry.addPluginLocation(
            os.path.join(self._app_install_dir, "lib32", "uranium"))
        self._plugin_registry.addPluginLocation(
            os.path.join(os.path.dirname(sys.executable), "plugins"))
        self._plugin_registry.addPluginLocation(
            os.path.join(self._app_install_dir, "Resources", "uranium",
                         "plugins"))
        self._plugin_registry.addPluginLocation(
            os.path.join(self._app_install_dir, "Resources", self._app_name,
                         "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._container_registry = self._container_registry_class(self)

        UM.Settings.InstanceContainer.setContainerRegistry(
            self._container_registry)
        UM.Settings.ContainerStack.setContainerRegistry(
            self._container_registry)

        # Initialize the package manager to remove and install scheduled packages.
        self._package_manager = self._package_manager_class(self)

        self.showMessageSignal.connect(self.showMessage)
        self.hideMessageSignal.connect(self.hideMessage)

    def startSplashWindowPhase(self) -> None:
        pass

    def startPostSplashWindowPhase(self) -> None:
        pass

    ##  Run the main event loop.
    #   This method should be re-implemented by subclasses to start the main event loop.
    #   \exception NotImplementedError
    def run(self):
        self.addCommandLineOptions()
        self.parseCliOptions()
        self.initialize()

        self.startSplashWindowPhase()
        self.startPostSplashWindowPhase()

    def getContainerRegistry(self):
        return self._container_registry

    ##  Get the lock filename
    def getApplicationLockFilename(self) -> str:
        return self._config_lock_filename

    ##  Emitted when the application window was closed and we need to shut down the application
    applicationShuttingDown = Signal()

    showMessageSignal = Signal()

    hideMessageSignal = Signal()

    globalContainerStackChanged = Signal()

    workspaceLoaded = Signal()

    def setGlobalContainerStack(self, stack: "ContainerStack") -> None:
        if self._global_container_stack != stack:
            self._global_container_stack = stack
            self.globalContainerStackChanged.emit()

    def getGlobalContainerStack(self) -> Optional["ContainerStack"]:
        return self._global_container_stack

    def hideMessage(self, message: Message) -> None:
        raise NotImplementedError

    def showMessage(self, message: Message) -> None:
        raise NotImplementedError

    def showToastMessage(self, title: str, message: str) -> None:
        raise NotImplementedError

    ##  Get the version of the application
    def getVersion(self) -> str:
        return self._version

    ##  Get the build type of the application
    def getBuildType(self) -> str:
        return self._build_type

    def getIsDebugMode(self) -> bool:
        return self._is_debug_mode

    def getIsHeadLess(self) -> bool:
        return self._is_headless

    def getUseExternalBackend(self) -> bool:
        return self._use_external_backend

    visibleMessageAdded = Signal()

    ##  Hide message by ID (as provided by built-in id function)
    def hideMessageById(self, message_id: int) -> None:
        # If a user and the application tries to close same message dialog simultaneously, message_id could become an empty
        # string, and then the application will raise an error when trying to do "int(message_id)".
        # So we check the message_id here.
        if not message_id:
            return

        found_message = None
        with self._message_lock:
            for message in self._visible_messages:
                if id(message) == int(message_id):
                    found_message = message
        if found_message is not None:
            self.hideMessageSignal.emit(found_message)

    visibleMessageRemoved = Signal()

    ##  Get list of all visible messages
    def getVisibleMessages(self) -> List[Message]:
        with self._message_lock:
            return self._visible_messages

    ##  Function that needs to be overridden by child classes with a list of plugins it needs.
    def _loadPlugins(self) -> None:
        pass

    ##  Get name of the application.
    #   \returns app_name \type{string}
    def getApplicationName(self) -> str:
        return self._app_name

    def getApplicationDisplayName(self) -> str:
        return self._app_display_name

    ##  Get the preferences.
    #   \return preferences \type{Preferences}
    def getPreferences(self) -> Preferences:
        return self._preferences

    def savePreferences(self) -> None:
        if self._preferences_filename:
            self._preferences.writeToFile(self._preferences_filename)
        else:
            Logger.log("i",
                       "Preferences filename not set. Unable to save file.")

    ##  Get the currently used IETF language tag.
    #   The returned tag is during runtime used to translate strings.
    #   \returns Language tag.
    def getApplicationLanguage(self) -> str:
        language = os.getenv("URANIUM_LANGUAGE")
        if not language:
            language = self._preferences.getValue("general/language")
        if not language:
            language = os.getenv("LANGUAGE")
        if not language:
            language = self._default_language

        return language

    ##  Application has a list of plugins that it *must* have. If it does not have these, it cannot function.
    #   These plugins can not be disabled in any way.
    def getRequiredPlugins(self) -> List[str]:
        return self._required_plugins

    ##  Set the plugins that the application *must* have in order to function.
    #   \param plugin_names \type{list} List of strings with the names of the required plugins
    def setRequiredPlugins(self, plugin_names: List[str]) -> None:
        self._required_plugins = plugin_names

    ##  Set the backend of the application (the program that does the heavy lifting).
    def setBackend(self, backend: "Backend") -> None:
        self._backend = backend

    ##  Get the backend of the application (the program that does the heavy lifting).
    #   \returns Backend \type{Backend}
    def getBackend(self) -> "Backend":
        return self._backend

    ##  Get the PluginRegistry of this application.
    #   \returns PluginRegistry \type{PluginRegistry}
    def getPluginRegistry(self) -> PluginRegistry:
        return self._plugin_registry

    ##  Get the Controller of this application.
    #   \returns Controller \type{Controller}
    def getController(self) -> Controller:
        return self._controller

    def getOperationStack(self) -> OperationStack:
        return self._operation_stack

    def getOutputDeviceManager(self) -> OutputDeviceManager:
        return self._output_device_manager

    ##  Return an application-specific Renderer object.
    #   \exception NotImplementedError
    def getRenderer(self) -> Renderer:
        raise NotImplementedError(
            "getRenderer must be implemented by subclasses.")

    ##  Post a function event onto the event loop.
    #
    #   This takes a CallFunctionEvent object and puts it into the actual event loop.
    #   \exception NotImplementedError
    def functionEvent(self, event: CallFunctionEvent) -> None:
        raise NotImplementedError(
            "functionEvent must be implemented by subclasses.")

    ##  Call a function the next time the event loop runs.
    #
    #   You can't get the result of this function directly. It won't block.
    #   \param function The function to call.
    #   \param args The positional arguments to pass to the function.
    #   \param kwargs The keyword arguments to pass to the function.
    def callLater(self, func: Callable[..., Any], *args, **kwargs) -> None:
        event = CallFunctionEvent(func, args, kwargs)
        self.functionEvent(event)

    ##  Get the application's main thread.
    def getMainThread(self) -> threading.Thread:
        return self._main_thread

    def addExtension(self, extension: "Extension") -> None:
        self._extensions.append(extension)

    def getExtensions(self) -> List["Extension"]:
        return self._extensions

    @staticmethod
    def getInstallPrefix() -> str:
        if "python" in os.path.basename(sys.executable):
            return os.path.abspath(
                os.path.join(os.path.dirname(sys.argv[0]), ".."))
        else:
            return os.path.abspath(
                os.path.join(os.path.dirname(sys.executable), ".."))

    __instance = None  # type: Application

    @classmethod
    def getInstance(cls, *args, **kwargs) -> "Application":
        return cls.__instance
Exemplo n.º 54
0
    def initialize(self) -> None:
        # For Ubuntu Unity this makes Qt use its own menu bar rather than pass it on to Unity.
        os.putenv("UBUNTU_MENUPROXY", "0")

        # Custom signal handling
        Signal._app = self
        Signal._signalQueue = self

        # Initialize Resources. Set the application name and version here because we can only know the actual info
        # after the __init__() has been called.
        Resources.ApplicationIdentifier = self._app_name
        Resources.ApplicationVersion = self._version

        Resources.addSearchPath(
            os.path.join(os.path.dirname(sys.executable), "resources"))
        Resources.addSearchPath(
            os.path.join(self._app_install_dir, "share", "uranium",
                         "resources"))
        Resources.addSearchPath(
            os.path.join(self._app_install_dir, "Resources", "uranium",
                         "resources"))
        Resources.addSearchPath(
            os.path.join(self._app_install_dir, "Resources", self._app_name,
                         "resources"))

        if not hasattr(sys, "frozen"):
            Resources.addSearchPath(
                os.path.join(os.path.abspath(os.path.dirname(__file__)), "..",
                             "resources"))

        i18nCatalog.setApplication(self)

        PluginRegistry.addType("backend", self.setBackend)
        PluginRegistry.addType("logger", Logger.addLogger)
        PluginRegistry.addType("extension", self.addExtension)

        self._preferences = Preferences()
        self._preferences.addPreference("general/language",
                                        self._default_language)
        self._preferences.addPreference("general/visible_settings", "")
        self._preferences.addPreference("general/plugins_to_remove", "")
        self._preferences.addPreference("general/disabled_plugins", "")

        self._controller = Controller(self)
        self._output_device_manager = OutputDeviceManager()

        self._operation_stack = OperationStack(
            self._controller)  # type: OperationStack

        self._plugin_registry = PluginRegistry(self)  #type: PluginRegistry

        self._plugin_registry.addPluginLocation(
            os.path.join(self._app_install_dir, "lib", "uranium"))
        self._plugin_registry.addPluginLocation(
            os.path.join(self._app_install_dir, "lib64", "uranium"))
        self._plugin_registry.addPluginLocation(
            os.path.join(self._app_install_dir, "lib32", "uranium"))
        self._plugin_registry.addPluginLocation(
            os.path.join(os.path.dirname(sys.executable), "plugins"))
        self._plugin_registry.addPluginLocation(
            os.path.join(self._app_install_dir, "Resources", "uranium",
                         "plugins"))
        self._plugin_registry.addPluginLocation(
            os.path.join(self._app_install_dir, "Resources", self._app_name,
                         "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._container_registry = self._container_registry_class(self)

        UM.Settings.InstanceContainer.setContainerRegistry(
            self._container_registry)
        UM.Settings.ContainerStack.setContainerRegistry(
            self._container_registry)

        # Initialize the package manager to remove and install scheduled packages.
        self._package_manager = self._package_manager_class(self)

        self.showMessageSignal.connect(self.showMessage)
        self.hideMessageSignal.connect(self.hideMessage)
    def _onChangeTimerFinished(self):
        if not self._enabled:
            return

        root = self._controller.getScene().getRoot()
        for node in BreadthFirstIterator(root):
            if node is root or type(node) is not SceneNode:
                continue

            bbox = node.getBoundingBox()
            if not bbox or not bbox.isValid():
                self._change_timer.start()
                continue

            build_volume_bounding_box = copy.deepcopy(
                self._build_volume.getBoundingBox())
            build_volume_bounding_box.setBottom(
                -9001)  # Ignore intersections with the bottom
            node._outside_buildarea = False

            # Mark the node as outside the build volume if the bounding box test fails.
            if build_volume_bounding_box.intersectsBox(
                    bbox
            ) != AxisAlignedBox.IntersectionResult.FullIntersection:
                node._outside_buildarea = True

            # Move it downwards if bottom is above platform
            move_vector = Vector()
            if not (node.getParent()
                    and node.getParent().callDecoration("isGroup")
                    ):  #If an object is grouped, don't move it down
                z_offset = node.callDecoration(
                    "getZOffset") if node.getDecorator(
                        ZOffsetDecorator.ZOffsetDecorator) else 0
                if bbox.bottom > 0:
                    move_vector.setY(-bbox.bottom + z_offset)
                elif bbox.bottom < z_offset:
                    move_vector.setY((-bbox.bottom) - z_offset)

            #if not Float.fuzzyCompare(bbox.bottom, 0.0):
            #   pass#move_vector.setY(-bbox.bottom)

            # If there is no convex hull for the node, start calculating it and continue.
            if not node.getDecorator(ConvexHullDecorator):
                node.addDecorator(ConvexHullDecorator())

            if not node.callDecoration("getConvexHull"):
                if not node.callDecoration("getConvexHullJob"):
                    job = ConvexHullJob.ConvexHullJob(node)
                    job.start()
                    node.callDecoration("setConvexHullJob", job)

            elif Preferences.getInstance().getValue(
                    "physics/automatic_push_free"):
                # Check for collisions between convex hulls
                for other_node in BreadthFirstIterator(root):
                    # Ignore root, ourselves and anything that is not a normal SceneNode.
                    if other_node is root or type(
                            other_node) is not SceneNode or other_node is node:
                        continue

                    # Ignore colissions of a group with it's own children
                    if other_node in node.getAllChildren(
                    ) or node in other_node.getAllChildren():
                        continue

                    # Ignore colissions within a group
                    if other_node.getParent().callDecoration(
                            "isGroup") is not None or node.getParent(
                            ).callDecoration("isGroup") is not None:
                        continue
                        #if node.getParent().callDecoration("isGroup") is other_node.getParent().callDecoration("isGroup"):
                        #    continue

                    # Ignore nodes that do not have the right properties set.
                    if not other_node.callDecoration(
                            "getConvexHull") or not other_node.getBoundingBox(
                            ):
                        continue

                    # Check to see if the bounding boxes intersect. If not, we can ignore the node as there is no way the hull intersects.
                    #if node.getBoundingBox().intersectsBox(other_node.getBoundingBox()) == AxisAlignedBox.IntersectionResult.NoIntersection:
                    #    continue

                    # Get the overlap distance for both convex hulls. If this returns None, there is no intersection.
                    try:
                        head_hull = node.callDecoration("getConvexHullHead")
                        if head_hull:
                            overlap = head_hull.intersectsPolygon(
                                other_node.callDecoration("getConvexHullHead"))
                            if not overlap:
                                other_head_hull = other_node.callDecoration(
                                    "getConvexHullHead")
                                if other_head_hull:
                                    overlap = node.callDecoration(
                                        "getConvexHullHead").intersectsPolygon(
                                            other_head_hull)
                        else:
                            overlap = node.callDecoration(
                                "getConvexHull").intersectsPolygon(
                                    other_node.callDecoration("getConvexHull"))
                    except:
                        overlap = None  #It can sometimes occur that the caclulated convex hull has no size, in which case there is no overlap.

                    if overlap is None:
                        continue
                    move_vector.setX(overlap[0] * 1.1)
                    move_vector.setZ(overlap[1] * 1.1)
            convex_hull = node.callDecoration("getConvexHull")
            if convex_hull:
                if not convex_hull.isValid():
                    return
                # Check for collisions between disallowed areas and the object
                for area in self._build_volume.getDisallowedAreas():
                    overlap = convex_hull.intersectsPolygon(area)
                    if overlap is None:
                        continue

                    node._outside_buildarea = True

            if move_vector != Vector():
                op = PlatformPhysicsOperation.PlatformPhysicsOperation(
                    node, move_vector)
                op.push()
Exemplo n.º 56
0
    def write(self, stream, nodes, mode=WorkspaceWriter.OutputMode.BinaryMode):
        application = Application.getInstance()
        machine_manager = application.getMachineManager()

        mesh_writer = application.getMeshFileHandler().getWriter("3MFWriter")

        if not mesh_writer:  # We need to have the 3mf mesh writer, otherwise we can't save the entire workspace
            return False

        # Indicate that the 3mf mesh writer should not close the archive just yet (we still need to add stuff to it).
        mesh_writer.setStoreArchive(True)
        mesh_writer.write(stream, nodes, mode)

        archive = mesh_writer.getArchive()
        if archive is None:  # This happens if there was no mesh data to write.
            archive = zipfile.ZipFile(stream,
                                      "w",
                                      compression=zipfile.ZIP_DEFLATED)

        global_stack = machine_manager.activeMachine

        # Add global container stack data to the archive.
        self._writeContainerToArchive(global_stack, archive)

        # Also write all containers in the stack to the file
        for container in global_stack.getContainers():
            self._writeContainerToArchive(container, archive)

        # Check if the machine has extruders and save all that data as well.
        for extruder_stack in global_stack.extruders.values():
            self._writeContainerToArchive(extruder_stack, archive)
            for container in extruder_stack.getContainers():
                self._writeContainerToArchive(container, archive)

        # Write preferences to archive
        original_preferences = Application.getInstance().getPreferences(
        )  #Copy only the preferences that we use to the workspace.
        temp_preferences = Preferences()
        for preference in {
                "general/visible_settings", "steslicer/active_mode",
                "steslicer/categories_expanded"
        }:
            temp_preferences.addPreference(preference, None)
            temp_preferences.setValue(
                preference, original_preferences.getValue(preference))
        preferences_string = StringIO()
        temp_preferences.writeToFile(preferences_string)
        preferences_file = zipfile.ZipInfo("SteSlicer/preferences.cfg")
        archive.writestr(preferences_file, preferences_string.getvalue())

        # Save STE Slicer version
        version_file = zipfile.ZipInfo("SteSlicer/version.ini")
        version_config_parser = configparser.ConfigParser(interpolation=None)
        version_config_parser.add_section("versions")
        version_config_parser.set("versions", "steslicer_version",
                                  application.getVersion())
        version_config_parser.set("versions", "build_type",
                                  application.getBuildType())
        version_config_parser.set("versions", "is_debug_mode",
                                  str(application.getIsDebugMode()))

        version_file_string = StringIO()
        version_config_parser.write(version_file_string)
        archive.writestr(version_file, version_file_string.getvalue())

        # Close the archive & reset states.
        archive.close()
        mesh_writer.setStoreArchive(False)
        return True
Exemplo n.º 57
0
    def __init__(self, name, version, **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

        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
        Resources.ApplicationIdentifier = name
        i18nCatalog.setApplication(self)

        Resources.addSearchPath(os.path.dirname(sys.executable))
        Resources.addSearchPath(
            os.path.join(Application.getInstallPrefix(), "share", "uranium"))
        Resources.addSearchPath(
            os.path.join(Application.getInstallPrefix(), "Resources",
                         "uranium"))
        Resources.addSearchPath(
            os.path.join(Application.getInstallPrefix(), "Resources",
                         self.getApplicationName()))
        if not hasattr(sys, "frozen"):
            Resources.addSearchPath(
                os.path.join(os.path.abspath(os.path.dirname(__file__)), ".."))

        self._main_thread = threading.current_thread()

        super().__init__(
            **kwargs)  # Call super to make multiple inheritence work.

        self._renderer = None

        PluginRegistry.addType("backend", self.setBackend)
        PluginRegistry.addType("logger", Logger.addLogger)
        PluginRegistry.addType("extension", self.addExtension)

        preferences = Preferences.getInstance()
        preferences.addPreference("general/language", "en")
        try:
            preferences.readFromFile(
                Resources.getPath(Resources.Preferences,
                                  self._application_name + ".cfg"))
        except FileNotFoundError:
            pass

        self._controller = Controller(self)
        self._mesh_file_handler = MeshFileHandler()
        self._extensions = []
        self._backend = None
        self._output_device_manager = OutputDeviceManager()
        self._machine_manager = MachineManager(self._application_name)

        self._required_plugins = []

        self._operation_stack = OperationStack()

        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
        self._plugin_registry.addPluginLocation(
            os.path.join(Resources.getStoragePath(Resources.Resources),
                         "plugins"))
        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)

        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)
Exemplo n.º 58
0
 def _onPreferenceChanged(self, preference):
     if preference == "cura/active_mode":
         self._advanced_mode = Preferences.getInstance().getValue(preference) == 1
         self._updateEnabled()
Exemplo n.º 59
0
    def _onChangeTimerFinished(self):
        if not self._enabled:
            return

        root = self._controller.getScene().getRoot()

        # Keep a list of nodes that are moving. We use this so that we don't move two intersecting objects in the
        # same direction.
        transformed_nodes = []

        group_nodes = []
        # We try to shuffle all the nodes to prevent "locked" situations, where iteration B inverts iteration A.
        # By shuffling the order of the nodes, this might happen a few times, but at some point it will resolve.
        nodes = list(BreadthFirstIterator(root))
        random.shuffle(nodes)
        for node in nodes:
            if node is root or type(
                    node) is not SceneNode or node.getBoundingBox() is None:
                continue

            bbox = node.getBoundingBox()

            # Ignore intersections with the bottom
            build_volume_bounding_box = self._build_volume.getBoundingBox()
            if build_volume_bounding_box:
                # It's over 9000!
                build_volume_bounding_box = build_volume_bounding_box.set(
                    bottom=-9001)
            else:
                # No bounding box. This is triggered when running Cura from command line with a model for the first time
                # In that situation there is a model, but no machine (and therefore no build volume.
                return
            node._outside_buildarea = False

            # Mark the node as outside the build volume if the bounding box test fails.
            if build_volume_bounding_box.intersectsBox(
                    bbox
            ) != AxisAlignedBox.IntersectionResult.FullIntersection:
                node._outside_buildarea = True

            if node.callDecoration("isGroup"):
                group_nodes.append(node)  # Keep list of affected group_nodes

            # Move it downwards if bottom is above platform
            move_vector = Vector()
            if Preferences.getInstance().getValue(
                    "physics/automatic_drop_down") and not (
                        node.getParent() and node.getParent().callDecoration(
                            "isGroup")) and node.isEnabled(
                            ):  #If an object is grouped, don't move it down
                z_offset = node.callDecoration(
                    "getZOffset") if node.getDecorator(
                        ZOffsetDecorator.ZOffsetDecorator) else 0
                move_vector = move_vector.set(y=-bbox.bottom + z_offset)

            # If there is no convex hull for the node, start calculating it and continue.
            if not node.getDecorator(ConvexHullDecorator):
                node.addDecorator(ConvexHullDecorator())

            if Preferences.getInstance().getValue(
                    "physics/automatic_push_free"):
                # Check for collisions between convex hulls
                for other_node in BreadthFirstIterator(root):
                    # Ignore root, ourselves and anything that is not a normal SceneNode.
                    if other_node is root or type(
                            other_node) is not SceneNode or other_node is node:
                        continue

                    # Ignore collisions of a group with it's own children
                    if other_node in node.getAllChildren(
                    ) or node in other_node.getAllChildren():
                        continue

                    # Ignore collisions within a group
                    if other_node.getParent() and node.getParent() and (
                            other_node.getParent().callDecoration("isGroup")
                            is not None
                            or node.getParent().callDecoration("isGroup")
                            is not None):
                        continue

                    # Ignore nodes that do not have the right properties set.
                    if not other_node.callDecoration(
                            "getConvexHull") or not other_node.getBoundingBox(
                            ):
                        continue

                    if other_node in transformed_nodes:
                        continue  # Other node is already moving, wait for next pass.

                    overlap = (0, 0)  # Start loop with no overlap
                    current_overlap_checks = 0
                    # Continue to check the overlap until we no longer find one.
                    while overlap and current_overlap_checks < self._max_overlap_checks:
                        current_overlap_checks += 1
                        head_hull = node.callDecoration("getConvexHullHead")
                        if head_hull:  # One at a time intersection.
                            overlap = head_hull.translate(
                                move_vector.x,
                                move_vector.z).intersectsPolygon(
                                    other_node.callDecoration("getConvexHull"))
                            if not overlap:
                                other_head_hull = other_node.callDecoration(
                                    "getConvexHullHead")
                                if other_head_hull:
                                    overlap = node.callDecoration(
                                        "getConvexHull").translate(
                                            move_vector.x,
                                            move_vector.z).intersectsPolygon(
                                                other_head_hull)
                                    if overlap:
                                        # Moving ensured that overlap was still there. Try anew!
                                        move_vector = move_vector.set(
                                            x=move_vector.x +
                                            overlap[0] * self._move_factor,
                                            z=move_vector.z +
                                            overlap[1] * self._move_factor)
                            else:
                                # Moving ensured that overlap was still there. Try anew!
                                move_vector = move_vector.set(
                                    x=move_vector.x +
                                    overlap[0] * self._move_factor,
                                    z=move_vector.z +
                                    overlap[1] * self._move_factor)
                        else:
                            own_convex_hull = node.callDecoration(
                                "getConvexHull")
                            other_convex_hull = other_node.callDecoration(
                                "getConvexHull")
                            if own_convex_hull and other_convex_hull:
                                overlap = own_convex_hull.translate(
                                    move_vector.x,
                                    move_vector.z).intersectsPolygon(
                                        other_convex_hull)
                                if overlap:  # Moving ensured that overlap was still there. Try anew!
                                    move_vector = move_vector.set(
                                        x=move_vector.x +
                                        overlap[0] * self._move_factor,
                                        z=move_vector.z +
                                        overlap[1] * self._move_factor)
                            else:
                                # This can happen in some cases if the object is not yet done with being loaded.
                                #  Simply waiting for the next tick seems to resolve this correctly.
                                overlap = None

            convex_hull = node.callDecoration("getConvexHull")
            if convex_hull:
                if not convex_hull.isValid():
                    return
                # Check for collisions between disallowed areas and the object
                for area in self._build_volume.getDisallowedAreas():
                    overlap = convex_hull.intersectsPolygon(area)
                    if overlap is None:
                        continue
                    node._outside_buildarea = True

            if not Vector.Null.equals(move_vector, epsilon=1e-5):
                transformed_nodes.append(node)
                op = PlatformPhysicsOperation.PlatformPhysicsOperation(
                    node, move_vector)
                op.push()

        # Group nodes should override the _outside_buildarea property of their children.
        for group_node in group_nodes:
            for child_node in group_node.getAllChildren():
                child_node._outside_buildarea = group_node._outside_buildarea
Exemplo n.º 60
0
    def run(self):
        super().run()

        if not self._result:
            self._result = []

        # Scale down to maximum bounds size if that is available
        if hasattr(Application.getInstance().getController().getScene(),
                   "_maximum_bounds"):
            for node in self._result:
                max_bounds = Application.getInstance().getController(
                ).getScene()._maximum_bounds
                node._resetAABB()
                build_bounds = node.getBoundingBox()

                if Preferences.getInstance().getValue(
                        "mesh/scale_to_fit"
                ) == True or Preferences.getInstance().getValue(
                        "mesh/scale_tiny_meshes") == True:
                    scale_factor_width = max_bounds.width / build_bounds.width
                    scale_factor_height = max_bounds.height / build_bounds.height
                    scale_factor_depth = max_bounds.depth / build_bounds.depth
                    scale_factor = min(scale_factor_width, scale_factor_depth,
                                       scale_factor_height)
                    if Preferences.getInstance(
                    ).getValue("mesh/scale_to_fit") == True and (
                            scale_factor_width < 1 or scale_factor_height < 1
                            or scale_factor_depth < 1
                    ):  # Use scale factor to scale large object down
                        # Ignore scaling on models which are less than 1.25 times bigger than the build volume
                        ignore_factor = 1.25
                        if 1 / scale_factor < ignore_factor:
                            Logger.log(
                                "i",
                                "Ignoring auto-scaling, because %.3d < %.3d" %
                                (1 / scale_factor, ignore_factor))
                            scale_factor = 1
                        pass
                    elif Preferences.getInstance().getValue(
                            "mesh/scale_tiny_meshes") == True and (
                                scale_factor_width > 100
                                and scale_factor_height > 100
                                and scale_factor_depth > 100):
                        # Round scale factor to lower factor of 10 to scale tiny object up (eg convert m to mm units)
                        scale_factor = math.pow(
                            10,
                            math.floor(math.log(scale_factor) / math.log(10)))
                    else:
                        scale_factor = 1

                    if scale_factor != 1:
                        scale_vector = Vector(scale_factor, scale_factor,
                                              scale_factor)
                        display_scale_factor = scale_factor * 100

                        scale_message = Message(
                            i18n_catalog.i18nc(
                                "@info:status",
                                "Auto scaled object to {0}% of original size",
                                ("%i" % display_scale_factor)))

                        try:
                            node.scale(scale_vector)
                            scale_message.show()
                        except Exception:
                            Logger.logException(
                                "e",
                                "While auto-scaling an exception has been raised"
                            )