Get default settings view to work as sidebar component

This commit is contained in:
ChrisTerBeke 2017-12-04 16:28:35 +01:00
parent 5eeb98bbcf
commit 3c863fc388
8 changed files with 138 additions and 49 deletions

View file

@ -32,13 +32,11 @@ from UM.Operations.AddSceneNodeOperation import AddSceneNodeOperation
from UM.Operations.RemoveSceneNodeOperation import RemoveSceneNodeOperation from UM.Operations.RemoveSceneNodeOperation import RemoveSceneNodeOperation
from UM.Operations.GroupedOperation import GroupedOperation from UM.Operations.GroupedOperation import GroupedOperation
from UM.Operations.SetTransformOperation import SetTransformOperation from UM.Operations.SetTransformOperation import SetTransformOperation
from cura.Arrange import Arrange from cura.Arrange import Arrange
from cura.Settings.SettingsSidebarView import SettingsSidebarView
from cura.ShapeArray import ShapeArray from cura.ShapeArray import ShapeArray
from cura.ConvexHullDecorator import ConvexHullDecorator from cura.ConvexHullDecorator import ConvexHullDecorator
from cura.SetParentOperation import SetParentOperation from cura.SetParentOperation import SetParentOperation
from cura.Sidebar.SidebarController import SidebarController
from cura.Sidebar.SidebarViewModel import SidebarViewModel
from cura.SliceableObjectDecorator import SliceableObjectDecorator from cura.SliceableObjectDecorator import SliceableObjectDecorator
from cura.BlockSlicingDecorator import BlockSlicingDecorator from cura.BlockSlicingDecorator import BlockSlicingDecorator
@ -78,6 +76,11 @@ from cura.Settings.ContainerManager import ContainerManager
from cura.Settings.GlobalStack import GlobalStack from cura.Settings.GlobalStack import GlobalStack
from cura.Settings.ExtruderStack import ExtruderStack from cura.Settings.ExtruderStack import ExtruderStack
from cura.Sidebar.SidebarController import SidebarController
from cura.Sidebar.SidebarControllerProxy import SidebarControllerProxy
from cura.Sidebar.SidebarViewModel import SidebarViewModel
from cura.Settings.SettingsSidebarView import SettingsSidebarView
from PyQt5.QtCore import QUrl, pyqtSignal, pyqtProperty, QEvent, Q_ENUMS from PyQt5.QtCore import QUrl, pyqtSignal, pyqtProperty, QEvent, Q_ENUMS
from UM.FlameProfiler import pyqtSlot from UM.FlameProfiler import pyqtSlot
from PyQt5.QtGui import QColor, QIcon from PyQt5.QtGui import QColor, QIcon
@ -131,6 +134,7 @@ class CuraApplication(QtApplication):
stacksValidationFinished = pyqtSignal() # Emitted whenever a validation is finished stacksValidationFinished = pyqtSignal() # Emitted whenever a validation is finished
def __init__(self): def __init__(self):
# this list of dir names will be used by UM to detect an old cura directory # this list of dir names will be used by UM to detect an old cura directory
for dir_name in ["extruders", "machine_instances", "materials", "plugins", "quality", "user", "variants"]: for dir_name in ["extruders", "machine_instances", "materials", "plugins", "quality", "user", "variants"]:
Resources.addExpectedDirNameInData(dir_name) Resources.addExpectedDirNameInData(dir_name)
@ -159,7 +163,6 @@ class CuraApplication(QtApplication):
SettingDefinition.addSettingType("extruder", None, str, Validator) SettingDefinition.addSettingType("extruder", None, str, Validator)
SettingDefinition.addSettingType("optional_extruder", None, str, None) SettingDefinition.addSettingType("optional_extruder", None, str, None)
SettingDefinition.addSettingType("[int]", None, str, None) SettingDefinition.addSettingType("[int]", None, str, None)
SettingFunction.registerOperator("extruderValues", ExtruderManager.getExtruderValues) SettingFunction.registerOperator("extruderValues", ExtruderManager.getExtruderValues)
@ -184,7 +187,8 @@ class CuraApplication(QtApplication):
ContainerRegistry.getInstance().addResourceType(self.ResourceTypes.DefinitionChangesContainer) ContainerRegistry.getInstance().addResourceType(self.ResourceTypes.DefinitionChangesContainer)
## Initialise the version upgrade manager with Cura's storage paths. ## Initialise the version upgrade manager with Cura's storage paths.
import UM.VersionUpgradeManager #Needs to be here to prevent circular dependencies. # Needs to be here to prevent circular dependencies.
import UM.VersionUpgradeManager
UM.VersionUpgradeManager.VersionUpgradeManager.getInstance().setCurrentVersions( UM.VersionUpgradeManager.VersionUpgradeManager.getInstance().setCurrentVersions(
{ {
@ -323,6 +327,11 @@ class CuraApplication(QtApplication):
self._need_to_show_user_agreement = not Preferences.getInstance().getValue("general/accepted_user_agreement") self._need_to_show_user_agreement = not Preferences.getInstance().getValue("general/accepted_user_agreement")
# Set the active sidebar view based on user preferences
preferences.addPreference("cura/active_sidebar_view", "default")
active_sidebar_view = preferences.getValue("cura/active_sidebar_view")
self._sidebar_controller.setActiveSidebarView(active_sidebar_view)
for key in [ for key in [
"dialog_load_path", # dialog_save_path is in LocalFileOutputDevicePlugin "dialog_load_path", # dialog_save_path is in LocalFileOutputDevicePlugin
"dialog_profile_path", "dialog_profile_path",
@ -678,7 +687,6 @@ class CuraApplication(QtApplication):
controller = self.getController() controller = self.getController()
controller.setActiveView("SolidView") controller.setActiveView("SolidView")
controller.setCameraTool("CameraTool") controller.setCameraTool("CameraTool")
controller.setSelectionTool("SelectionTool") controller.setSelectionTool("SelectionTool")
@ -741,6 +749,11 @@ class CuraApplication(QtApplication):
self.exec_() self.exec_()
## Get the SidebarController of this application.
# \returns SidebarControllers \type{SidebarController}
def getSidebarController(self) -> SidebarController:
return self._sidebar_controller
def getMachineManager(self, *args): def getMachineManager(self, *args):
if self._machine_manager is None: if self._machine_manager is None:
self._machine_manager = MachineManager.createMachineManager() self._machine_manager = MachineManager.createMachineManager()
@ -786,14 +799,6 @@ class CuraApplication(QtApplication):
def getPrintInformation(self): def getPrintInformation(self):
return self._print_information return self._print_information
## Get the SidebarController of this application.
# A sidebar controller is created if it wasn't yet.
# \returns SidebarControllers \type{SidebarController}
def getSidebarController(self) -> SidebarController:
if self._sidebar_controller is None:
self._sidebar_controller = SidebarController(self)
return self._sidebar_controller
## Registers objects for the QML engine to use. ## Registers objects for the QML engine to use.
# #
# \param engine The QML engine. # \param engine The QML engine.
@ -808,6 +813,7 @@ class CuraApplication(QtApplication):
qmlRegisterUncreatableType(CuraApplication, "Cura", 1, 0, "ResourceTypes", "Just an Enum type") qmlRegisterUncreatableType(CuraApplication, "Cura", 1, 0, "ResourceTypes", "Just an Enum type")
qmlRegisterType(SidebarViewModel, "Cura", 1, 0, "SidebarViewModel")
qmlRegisterType(ExtrudersModel, "Cura", 1, 0, "ExtrudersModel") qmlRegisterType(ExtrudersModel, "Cura", 1, 0, "ExtrudersModel")
qmlRegisterType(ContainerSettingsModel, "Cura", 1, 0, "ContainerSettingsModel") qmlRegisterType(ContainerSettingsModel, "Cura", 1, 0, "ContainerSettingsModel")
qmlRegisterSingletonType(ProfilesModel, "Cura", 1, 0, "ProfilesModel", ProfilesModel.createProfilesModel) qmlRegisterSingletonType(ProfilesModel, "Cura", 1, 0, "ProfilesModel", ProfilesModel.createProfilesModel)
@ -819,8 +825,7 @@ class CuraApplication(QtApplication):
qmlRegisterType(MachineNameValidator, "Cura", 1, 0, "MachineNameValidator") qmlRegisterType(MachineNameValidator, "Cura", 1, 0, "MachineNameValidator")
qmlRegisterType(UserChangesModel, "Cura", 1, 1, "UserChangesModel") qmlRegisterType(UserChangesModel, "Cura", 1, 1, "UserChangesModel")
qmlRegisterSingletonType(ContainerManager, "Cura", 1, 0, "ContainerManager", ContainerManager.createContainerManager) qmlRegisterSingletonType(ContainerManager, "Cura", 1, 0, "ContainerManager", ContainerManager.createContainerManager)
qmlRegisterSingletonType(SidebarController, "Cura", 1, 0, "SidebarController", self.getSidebarController) qmlRegisterSingletonType(SidebarControllerProxy, "Cura", 1, 0, "SidebarController", SidebarControllerProxy.createSidebarControllerProxy)
qmlRegisterType(SidebarViewModel, "Cura", 1, 0, "SidebarViewModel")
# As of Qt5.7, it is necessary to get rid of any ".." in the path for the singleton to work. # As of Qt5.7, it is necessary to get rid of any ".." in the path for the singleton to work.
actions_url = QUrl.fromLocalFile(os.path.abspath(Resources.getPath(CuraApplication.ResourceTypes.QmlFiles, "Actions.qml"))) actions_url = QUrl.fromLocalFile(os.path.abspath(Resources.getPath(CuraApplication.ResourceTypes.QmlFiles, "Actions.qml")))

View file

@ -1,23 +1,29 @@
# Copyright (c) 2017 Ultimaker B.V. # Copyright (c) 2017 Ultimaker B.V.
from PyQt5.QtCore import QObject import os.path
from PyQt5.QtCore import QObject, QUrl
from UM.i18n import i18nCatalog from UM.i18n import i18nCatalog
from cura.Sidebar.SidebarView import SidebarView from cura.Sidebar.SidebarView import SidebarView
i18n_catalog = i18nCatalog("cura") i18n_catalog = i18nCatalog("cura")
class SettingsSidebarView(QObject, SidebarView): class SettingsSidebarView(QObject, SidebarView):
def __init__(self): def __init__(self, parent = None):
super().__init__() super().__init__(parent)
## As the default sidebar is not a plugin, we have a get plugin ID method to allow the sidebar view model to get the needed data. ## As the default sidebar is not a plugin, we have a get plugin ID method to allow the sidebar view model to get the needed data.
def getPluginId(self): def getPluginId(self):
return "default" return "default"
## As the default sidebar is not a plugin, we have a get meta data method here to allow the sidebar view model to get the needed data. ## As the default sidebar is not a plugin, we have a add meta data method here to allow the sidebar view model to get the needed data.
def getMetaData(self): def getMetaData(self):
return { return {
"sidebar_view": { "sidebar_view": {
"name": i18n_catalog.i18nc("", "Print settings"), "name": i18n_catalog.i18nc("", "Print settings"),
"weight": 1 "weight": 0
} }
} }
## As the default sidebar is not a plugin, we have a get component path method here to allow the sidebar controller to get the needed data.
def getComponentPath(self):
return QUrl("SidebarSettings.qml")

View file

@ -1,9 +1,7 @@
# Copyright (c) 2017 Ultimaker B.V. # Copyright (c) 2017 Ultimaker B.V.
from UM.Logger import Logger from UM.Logger import Logger
from UM.PluginRegistry import PluginRegistry
from UM.Signal import Signal from UM.Signal import Signal
from .SidebarView import SidebarView from UM.PluginRegistry import PluginRegistry
from typing import Optional, Dict
# The sidebar controller manages available sidebar components and decides which one to display. # The sidebar controller manages available sidebar components and decides which one to display.
# The cura.qml file uses this controller to repeat over the sidebars and show the active index. # The cura.qml file uses this controller to repeat over the sidebars and show the active index.
@ -14,6 +12,7 @@ class SidebarController:
self._sidebar_views = {} self._sidebar_views = {}
self._active_sidebar_view = None self._active_sidebar_view = None
# Register the sidebar_view plugin type so plugins can expose custom sidebar views.
PluginRegistry.addType("sidebar_view", self.addSidebarView) PluginRegistry.addType("sidebar_view", self.addSidebarView)
## Emitted when the list of views changes. ## Emitted when the list of views changes.
@ -26,28 +25,32 @@ class SidebarController:
def getApplication(self): def getApplication(self):
return self._application return self._application
## Get all sidebar views registered in this controller.
def getAllSidebarViews(self):
return self._sidebar_views
## Add a sidebar view to the registry. ## Add a sidebar view to the registry.
# It get's a unique name based on the plugin ID. # It get's a unique name based on the plugin ID.
def addSidebarView(self, sidebar_view: SidebarView): def addSidebarView(self, sidebar_view):
name = sidebar_view.getPluginId() sidebar_view_id = sidebar_view.getPluginId()
if name not in self._sidebar_views: if sidebar_view_id not in self._sidebar_views:
self._sidebar_views[name] = sidebar_view self._sidebar_views[sidebar_view_id] = sidebar_view
self.sidebarViewsChanged.emit() self.sidebarViewsChanged.emit()
## Get a registered sidebar view by name. ## Get a registered sidebar view by name.
# The name is the ID of the plugin that registered the view. # The name is the ID of the plugin that registered the view.
def getSidebarView(self, name: str) -> Optional[SidebarView]: def getSidebarView(self, name: str):
try: try:
return self._sidebar_views[name] return self._sidebar_views[name]
except KeyError: except KeyError:
Logger.log("e", "Unable to find %s in sidebar view list", name) Logger.log("e", "Unable to find %s in sidebar view list", name)
return None return None
## Change the active sidebar view to one of the registered views. ## Get the active sidebar view.
def setActiveSidebarView(self, name: str): def getActiveSidebarView(self):
print("setting active sidebar view") return self._active_sidebar_view
self.activeSidebarViewChanged.emit()
## Get all sidebar views registered in this controller. ## Change the active sidebar view to one of the registered views.
def getAllSidebarViews(self) -> Dict[SidebarView]: def setActiveSidebarView(self, sidebar_view_id: str):
return self._sidebar_views self._active_sidebar_view = self._sidebar_views[sidebar_view_id]
self.activeSidebarViewChanged.emit()

View file

@ -0,0 +1,36 @@
# Copyright (c) 2017 Ultimaker B.V.
from PyQt5.QtCore import QObject, pyqtSlot, QUrl, pyqtProperty, pyqtSignal
from UM.Application import Application
## The sidebar controller proxy acts a proxy between the sidebar controller and the QMl context of the controller.
class SidebarControllerProxy(QObject):
def __init__(self, parent = None):
super().__init__(parent)
self._controller = Application.getInstance().getSidebarController()
self._controller.activeSidebarViewChanged.connect(self._onActiveSidebarComponentChanged)
## Emitted when the active view changes.
activeSidebarViewChanged = pyqtSignal()
@classmethod
def createSidebarControllerProxy(self, engine, script_engine):
return SidebarControllerProxy()
@pyqtSlot()
def setActiveView(self, sidebar_view):
self._controller.setActiveSidebarView(sidebar_view)
@pyqtProperty(QUrl, notify = activeSidebarViewChanged)
def activeComponentPath(self):
if not self._controller.getActiveSidebarView():
return QUrl()
return self._controller.getActiveSidebarView().getComponentPath()
@pyqtSlot(QUrl)
def getSidebarComponentPath(self, sidebar_id):
self._controller.getSidebarView(sidebar_id).getComponentPath()
def _onActiveSidebarComponentChanged(self):
self.activeSidebarViewChanged.emit()

View file

@ -1,7 +1,9 @@
# Copyright (c) 2017 Ultimaker B.V. # Copyright (c) 2017 Ultimaker B.V.
from PyQt5.QtCore import QUrl
from UM.Logger import Logger
from UM.PluginObject import PluginObject from UM.PluginObject import PluginObject
from UM.PluginRegistry import PluginRegistry
# Abstract class for sidebar view objects. # Abstract class for sidebar view objects.
# By default the sidebar is Cura's settings, slicing and printing overview. # By default the sidebar is Cura's settings, slicing and printing overview.
@ -10,4 +12,13 @@ class SidebarView(PluginObject):
def __init__(self): def __init__(self):
super().__init__() super().__init__()
print("sidebar view hello") self._view = None
## Get the path to the component QML file as QUrl
def getComponentPath(self):
try:
sidebar_component_file_path = PluginRegistry.getInstance().getMetaData(self.getPluginId())["sidebar_view"]["sidebar_component"]
return QUrl.fromLocalFile(sidebar_component_file_path)
except KeyError:
Logger.log("w", "Could not find sidebar component QML file for %s", self.getPluginId())
return QUrl()

View file

@ -22,7 +22,8 @@ if Platform.isLinux(): # Needed for platform.linux_distribution, which is not av
if Platform.isWindows() and hasattr(sys, "frozen"): if Platform.isWindows() and hasattr(sys, "frozen"):
try: try:
del os.environ["PYTHONPATH"] del os.environ["PYTHONPATH"]
except KeyError: pass except KeyError:
pass
# WORKAROUND: GITHUB-704 GITHUB-708 # WORKAROUND: GITHUB-704 GITHUB-708
# It looks like setuptools creates a .pth file in # It looks like setuptools creates a .pth file in
@ -45,6 +46,7 @@ def exceptHook(hook_type, value, traceback):
_crash_handler = CrashHandler(hook_type, value, traceback) _crash_handler = CrashHandler(hook_type, value, traceback)
_crash_handler.show() _crash_handler.show()
sys.excepthook = exceptHook sys.excepthook = exceptHook
# Workaround for a race condition on certain systems where there # Workaround for a race condition on certain systems where there
@ -75,7 +77,7 @@ faulthandler.enable()
# Force an instance of CuraContainerRegistry to be created and reused later. # Force an instance of CuraContainerRegistry to be created and reused later.
cura.Settings.CuraContainerRegistry.CuraContainerRegistry.getInstance() cura.Settings.CuraContainerRegistry.CuraContainerRegistry.getInstance()
# This prestart up check is needed to determine if we should start the application at all. # This pre-start up check is needed to determine if we should start the application at all.
if not cura.CuraApplication.CuraApplication.preStartUp(): if not cura.CuraApplication.CuraApplication.preStartUp():
sys.exit(0) sys.exit(0)

View file

@ -366,19 +366,24 @@ UM.MainWindow
onStopMonitoringPrint: base.showPrintMonitor = false onStopMonitoringPrint: base.showPrintMonitor = false
} }
Sidebar Loader
{ {
id: sidebar; id: sidebar
anchors anchors
{ {
top: topbar.bottom; top: topbar.bottom
bottom: parent.bottom; bottom: parent.bottom
right: parent.right; right: parent.right
} }
z: 1
width: UM.Theme.getSize("sidebar").width; width: UM.Theme.getSize("sidebar").width
monitoringPrint: base.showPrintMonitor
// all sidebar components will have access to the show print monitor flag
property bool showPrintMonitor: base.showPrintMonitor
// dynamically get the component from the sidebar controller
source: Cura.SidebarController.activeComponentPath
} }
Rectangle Rectangle

View file

@ -0,0 +1,21 @@
// Copyright (c) 2017 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.2
Sidebar
{
id: sidebarSettings
property bool showPrintMonitor: false
anchors {
top: parent.top
bottom: parent.bottom
left: parent.left
right: parent.right
}
width: parent.width
monitoringPrint: showPrintMonitor
}