Merge pull request #5604 from Ultimaker/CURA-6447_fix_start_onboarding

CURA-6447 Fix start onboarding
This commit is contained in:
Jaime van Kessel 2019-04-17 10:59:23 +02:00 committed by GitHub
commit f2044998ae
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
25 changed files with 473 additions and 685 deletions

View file

@ -112,7 +112,9 @@ from cura.UI import CuraSplashScreen, MachineActionManager, PrintInformation
from cura.UI.MachineSettingsManager import MachineSettingsManager
from cura.UI.ObjectsModel import ObjectsModel
from cura.UI.TextManager import TextManager
from cura.UI.AddPrinterPagesModel import AddPrinterPagesModel
from cura.UI.WelcomePagesModel import WelcomePagesModel
from cura.UI.WhatsNewPagesModel import WhatsNewPagesModel
from .SingleInstance import SingleInstance
from .AutoSave import AutoSave
@ -217,6 +219,8 @@ class CuraApplication(QtApplication):
self._discovered_printer_model = DiscoveredPrintersModel(self)
self._first_start_machine_actions_model = FirstStartMachineActionsModel(self)
self._welcome_pages_model = WelcomePagesModel(self)
self._add_printer_pages_model = AddPrinterPagesModel(self)
self._whats_new_pages_model = WhatsNewPagesModel(self)
self._text_manager = TextManager(self)
self._quality_profile_drop_down_menu_model = None
@ -762,6 +766,8 @@ class CuraApplication(QtApplication):
self._output_device_manager.start()
self._welcome_pages_model.initialize()
self._add_printer_pages_model.initialize()
self._whats_new_pages_model.initialize()
# Detect in which mode to run and execute that mode
if self._is_headless:
@ -873,6 +879,14 @@ class CuraApplication(QtApplication):
def getWelcomePagesModel(self, *args) -> "WelcomePagesModel":
return self._welcome_pages_model
@pyqtSlot(result = QObject)
def getAddPrinterPagesModel(self, *args) -> "AddPrinterPagesModel":
return self._add_printer_pages_model
@pyqtSlot(result = QObject)
def getWhatsNewPagesModel(self, *args) -> "WhatsNewPagesModel":
return self._whats_new_pages_model
@pyqtSlot(result = QObject)
def getMachineSettingsManager(self, *args) -> "MachineSettingsManager":
return self._machine_settings_manager
@ -1014,6 +1028,8 @@ class CuraApplication(QtApplication):
qmlRegisterSingletonType(MachineActionManager.MachineActionManager, "Cura", 1, 0, "MachineActionManager", self.getMachineActionManager)
qmlRegisterType(WelcomePagesModel, "Cura", 1, 0, "WelcomePagesModel")
qmlRegisterType(WhatsNewPagesModel, "Cura", 1, 0, "WhatsNewPagesModel")
qmlRegisterType(AddPrinterPagesModel, "Cura", 1, 0, "AddPrinterPagesModel")
qmlRegisterType(TextManager, "Cura", 1, 0, "TextManager")
qmlRegisterType(NetworkMJPGImage, "Cura", 1, 0, "NetworkMJPGImage")
@ -1098,7 +1114,6 @@ class CuraApplication(QtApplication):
self._camera_animation.setTarget(Selection.getSelectedObject(0).getWorldPosition())
self._camera_animation.start()
requestAddPrinter = pyqtSignal()
activityChanged = pyqtSignal()
sceneBoundingBoxChanged = pyqtSignal()
@ -1758,3 +1773,16 @@ class CuraApplication(QtApplication):
def getSidebarCustomMenuItems(self) -> list:
return self._sidebar_custom_menu_items
@pyqtSlot(result = bool)
def shouldShowWelcomeDialog(self) -> bool:
# Only show the complete flow if there is no printer yet.
return self._machine_manager.activeMachine is None
@pyqtSlot(result = bool)
def shouldShowWhatsNewDialog(self) -> bool:
has_active_machine = self._machine_manager.activeMachine is not None
has_app_just_upgraded = self.hasJustUpdatedFromOldVersion()
# Only show the what's new dialog if there's no machine and we have just upgraded
show_whatsnew_only = has_active_machine and has_app_just_upgraded
return show_whatsnew_only

View file

@ -0,0 +1,30 @@
# Copyright (c) 2019 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher.
from .WelcomePagesModel import WelcomePagesModel
#
# This Qt ListModel is more or less the same the WelcomePagesModel, except that this model is only for adding a printer,
# so only the steps for adding a printer is included.
#
class AddPrinterPagesModel(WelcomePagesModel):
def initialize(self) -> None:
self._pages.append({"id": "add_network_or_local_printer",
"page_url": self._getBuiltinWelcomePagePath("AddNetworkOrLocalPrinterContent.qml"),
"next_page_id": "machine_actions",
"next_page_button_text": self._catalog.i18nc("@action:button", "Add"),
})
self._pages.append({"id": "add_printer_by_ip",
"page_url": self._getBuiltinWelcomePagePath("AddPrinterByIpContent.qml"),
"next_page_id": "machine_actions",
})
self._pages.append({"id": "machine_actions",
"page_url": self._getBuiltinWelcomePagePath("FirstStartMachineActionsContent.qml"),
"should_show_function": self.shouldShowMachineActions,
})
self.setItems(self._pages)
__all__ = ["AddPrinterPagesModel"]

View file

@ -6,6 +6,7 @@ from typing import TYPE_CHECKING, Optional, List, Dict, Any
from PyQt5.QtCore import QUrl, Qt, pyqtSlot, pyqtProperty, pyqtSignal
from UM.i18n import i18nCatalog
from UM.Logger import Logger
from UM.Qt.ListModel import ListModel
from UM.Resources import Resources
@ -23,6 +24,9 @@ if TYPE_CHECKING:
# - page_url : The QUrl to the QML file that contains the content of this page
# - next_page_id : (OPTIONAL) The next page ID to go to when this page finished. This is optional. If this is not
# provided, it will go to the page with the current index + 1
# - next_page_button_text: (OPTIONAL) The text to show for the "next" button, by default it's the translated text of
# "Next". Note that each step QML can decide whether to use this text or not, so it's not
# mandatory.
# - should_show_function : (OPTIONAL) An optional function that returns True/False indicating if this page should be
# shown. By default all pages should be shown. If a function returns False, that page will
# be skipped and its next page will be shown.
@ -34,6 +38,7 @@ class WelcomePagesModel(ListModel):
IdRole = Qt.UserRole + 1 # Page ID
PageUrlRole = Qt.UserRole + 2 # URL to the page's QML file
NextPageIdRole = Qt.UserRole + 3 # The next page ID it should go to
NextPageButtonTextRole = Qt.UserRole + 4 # The text for the next page button
def __init__(self, application: "CuraApplication", parent: Optional["QObject"] = None) -> None:
super().__init__(parent)
@ -41,8 +46,12 @@ class WelcomePagesModel(ListModel):
self.addRoleName(self.IdRole, "id")
self.addRoleName(self.PageUrlRole, "page_url")
self.addRoleName(self.NextPageIdRole, "next_page_id")
self.addRoleName(self.NextPageButtonTextRole, "next_page_button_text")
self._application = application
self._catalog = i18nCatalog("cura")
self._default_next_button_text = self._catalog.i18nc("@action:button", "Next")
self._pages = [] # type: List[Dict[str, Any]]
@ -137,7 +146,8 @@ class WelcomePagesModel(ListModel):
page_index = self.getPageIndexById(page_id)
if page_index is None:
# FIXME: If we cannot find the next page, we cannot do anything here.
Logger.log("e", "Cannot find page with ID [%s]", page_index)
Logger.log("e", "Cannot find page with ID [%s], go to the next page by default", page_index)
self.goToNextPage()
return
if self._shouldPageBeShown(page_index):
@ -180,38 +190,48 @@ class WelcomePagesModel(ListModel):
os.path.join("WelcomePages", page_filename)))
def initialize(self) -> None:
# Add default welcome pages
self._pages.append({"id": "welcome",
# All pages
all_pages_list = [{"id": "welcome",
"page_url": self._getBuiltinWelcomePagePath("WelcomeContent.qml"),
})
self._pages.append({"id": "user_agreement",
},
{"id": "user_agreement",
"page_url": self._getBuiltinWelcomePagePath("UserAgreementContent.qml"),
})
self._pages.append({"id": "whats_new",
},
{"id": "whats_new",
"page_url": self._getBuiltinWelcomePagePath("WhatsNewContent.qml"),
})
self._pages.append({"id": "data_collections",
},
{"id": "data_collections",
"page_url": self._getBuiltinWelcomePagePath("DataCollectionsContent.qml"),
})
self._pages.append({"id": "add_network_or_local_printer",
},
{"id": "add_network_or_local_printer",
"page_url": self._getBuiltinWelcomePagePath("AddNetworkOrLocalPrinterContent.qml"),
"next_page_id": "machine_actions",
})
self._pages.append({"id": "add_printer_by_ip",
},
{"id": "add_printer_by_ip",
"page_url": self._getBuiltinWelcomePagePath("AddPrinterByIpContent.qml"),
"next_page_id": "machine_actions",
})
self._pages.append({"id": "machine_actions",
},
{"id": "machine_actions",
"page_url": self._getBuiltinWelcomePagePath("FirstStartMachineActionsContent.qml"),
"next_page_id": "cloud",
"should_show_function": self.shouldShowMachineActions,
})
self._pages.append({"id": "cloud",
},
{"id": "cloud",
"page_url": self._getBuiltinWelcomePagePath("CloudContent.qml"),
})
},
]
self._pages = all_pages_list
self.setItems(self._pages)
# For convenience, inject the default "next" button text to each item if it's not present.
def setItems(self, items: List[Dict[str, Any]]) -> None:
for item in items:
if "next_page_button_text" not in item:
item["next_page_button_text"] = self._default_next_button_text
super().setItems(items)
# Indicates if the machine action panel should be shown by checking if there's any first start machine actions
# available.
def shouldShowMachineActions(self) -> bool:

View file

@ -0,0 +1,22 @@
# Copyright (c) 2019 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher.
from .WelcomePagesModel import WelcomePagesModel
#
# This Qt ListModel is more or less the same the WelcomePagesModel, except that this model is only for showing the
# "what's new" page. This is also used in the "Help" menu to show the changes log.
#
class WhatsNewPagesModel(WelcomePagesModel):
def initialize(self) -> None:
self._pages = []
self._pages.append({"id": "whats_new",
"page_url": self._getBuiltinWelcomePagePath("WhatsNewContent.qml"),
"next_page_button_text": self._catalog.i18nc("@action:button", "Close"),
})
self.setItems(self._pages)
__all__ = ["WhatsNewPagesModel"]

View file

@ -1,65 +0,0 @@
# Copyright (c) 2019 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher.
import os.path
from PyQt5.QtCore import QObject
from UM.i18n import i18nCatalog
from UM.Extension import Extension
from UM.Application import Application
from UM.PluginRegistry import PluginRegistry
from UM.Version import Version
catalog = i18nCatalog("cura")
class ChangeLog(Extension, QObject):
def __init__(self, parent = None):
QObject.__init__(self, parent)
Extension.__init__(self)
self._changelog_window = None
self._changelog_context = None
version_string = Application.getInstance().getVersion()
if version_string is not "master":
self._current_app_version = Version(version_string)
else:
self._current_app_version = None
Application.getInstance().engineCreatedSignal.connect(self._onEngineCreated)
Application.getInstance().getPreferences().addPreference("general/latest_version_changelog_shown", "2.0.0") #First version of CURA with uranium
self.setMenuName(catalog.i18nc("@item:inmenu", "Changelog"))
self.addMenuItem(catalog.i18nc("@item:inmenu", "Show Changelog"), self.showChangelog)
def _onEngineCreated(self):
if not self._current_app_version:
return #We're on dev branch.
if Application.getInstance().getPreferences().getValue("general/latest_version_changelog_shown") == "master":
latest_version_shown = Version("0.0.0")
else:
latest_version_shown = Version(Application.getInstance().getPreferences().getValue("general/latest_version_changelog_shown"))
Application.getInstance().getPreferences().setValue("general/latest_version_changelog_shown", Application.getInstance().getVersion())
# Do not show the changelog when there is no global container stack
# This implies we are running Cura for the first time.
if not Application.getInstance().getGlobalContainerStack():
return
if self._current_app_version > latest_version_shown:
self.showChangelog()
def showChangelog(self):
if not self._changelog_window:
self.createChangelogWindow()
self._changelog_window.show()
def hideChangelog(self):
if self._changelog_window:
self._changelog_window.hide()
def createChangelogWindow(self):
path = os.path.join(PluginRegistry.getInstance().getPluginPath(self.getPluginId()), "ChangeLog.qml")
self._changelog_window = Application.getInstance().createQmlComponent(path, {"manager": self})

View file

@ -1,43 +0,0 @@
// Copyright (c) 2015 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.1
import QtQuick.Controls 1.3
import QtQuick.Layouts 1.1
import QtQuick.Window 2.1
import UM 1.3 as UM
import Cura 1.0 as Cura
UM.Dialog
{
id: base
minimumWidth: (UM.Theme.getSize("modal_window_minimum").width * 0.75) | 0
minimumHeight: (UM.Theme.getSize("modal_window_minimum").height * 0.75) | 0
width: minimumWidth
height: minimumHeight
title: catalog.i18nc("@label", "Changelog")
TextArea
{
anchors.fill: parent
text: CuraApplication.getTextManager().getChangeLogText()
readOnly: true;
textFormat: TextEdit.RichText
}
rightButtons: [
Button
{
UM.I18nCatalog
{
id: catalog
name: "cura"
}
text: catalog.i18nc("@action:button", "Close")
onClicked: base.hide()
}
]
}

View file

@ -1,11 +0,0 @@
# Copyright (c) 2015 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher.
from . import ChangeLog
def getMetaData():
return {}
def register(app):
return {"extension": ChangeLog.ChangeLog()}

View file

@ -1,8 +0,0 @@
{
"name": "Changelog",
"author": "Ultimaker B.V.",
"version": "1.0.1",
"description": "Shows changes since latest checked version.",
"api": "6.0",
"i18n-catalog": "cura"
}

View file

@ -23,11 +23,11 @@ Cura.MachineAction
Label
{
id: pageDescription
anchors.top: pageTitle.bottom
anchors.top: parent.top
anchors.topMargin: UM.Theme.getSize("default_margin").height
width: parent.width
wrapMode: Text.WordWrap
text: catalog.i18nc("@label","Please select any upgrades made to this Ultimaker 2.")
text: catalog.i18nc("@label", "Please select any upgrades made to this Ultimaker 2.")
font: UM.Theme.getFont("medium")
renderType: Text.NativeRendering
}

View file

@ -71,6 +71,11 @@ class VersionUpgrade40to41(VersionUpgrade):
parser["general"]["version"] = "6"
if "metadata" not in parser:
parser["metadata"] = {}
# Remove changelog plugin
if "latest_version_changelog_shown" in parser["general"]:
del parser["general"]["latest_version_changelog_shown"]
parser["metadata"]["setting_version"] = "7"
result = io.StringIO()

View file

@ -33,23 +33,6 @@
}
}
},
"ChangeLogPlugin": {
"package_info": {
"package_id": "ChangeLogPlugin",
"package_type": "plugin",
"display_name": "Change Log",
"description": "Shows changes since latest checked version.",
"package_version": "1.0.1",
"sdk_version": "6.0.0",
"website": "https://ultimaker.com",
"author": {
"author_id": "UltimakerPackages",
"display_name": "Ultimaker B.V.",
"email": "plugins@ultimaker.com",
"website": "https://ultimaker.com"
}
}
},
"CuraDrive": {
"package_info": {
"package_id": "CuraDrive",

View file

@ -61,6 +61,7 @@ Item
property alias documentation: documentationAction;
property alias showTroubleshooting: showTroubleShootingAction
property alias reportBug: reportBugAction;
property alias whatsNew: whatsNewAction
property alias about: aboutAction;
property alias toggleFullScreen: toggleFullScreenAction;
@ -229,6 +230,12 @@ Item
onTriggered: CuraActions.openBugReportPage();
}
Action
{
id: whatsNewAction;
text: catalog.i18nc("@action:inmenu menubar:help", "What's New");
}
Action
{
id: aboutAction;

View file

@ -46,7 +46,7 @@ UM.MainWindow
{
id: greyOutBackground
anchors.fill: parent
visible: welcomeDialog.visible
visible: welcomeDialogItem.visible
color: UM.Theme.getColor("window_disabled_background")
opacity: 0.7
z: stageMenu.z + 1
@ -61,9 +61,9 @@ UM.MainWindow
}
}
WelcomeDialog
WelcomeDialogItem
{
id: welcomeDialog
id: welcomeDialogItem
visible: true // True, so if somehow no preferences are found/loaded, it's shown anyway.
z: greyOutBackground.z + 1
}
@ -71,6 +71,14 @@ UM.MainWindow
Component.onCompleted:
{
CuraApplication.setMinimumWindowSize(UM.Theme.getSize("window_minimum_size"))
CuraApplication.purgeWindows()
}
Connections
{
target: CuraApplication
onInitializationFinished:
{
// Workaround silly issues with QML Action's shortcut property.
//
// Currently, there is no way to define shortcuts as "Application Shortcut".
@ -82,18 +90,24 @@ UM.MainWindow
//
// This has been fixed for QtQuick Controls 2 since the Shortcut item has a context property.
Cura.Actions.parent = backgroundItem
CuraApplication.purgeWindows()
if (CuraApplication.needToShowUserAgreement)
if (CuraApplication.shouldShowWelcomeDialog())
{
welcomeDialog.visible = true
welcomeDialogItem.visible = true
}
else
{
welcomeDialog.visible = false
welcomeDialogItem.visible = false
}
// Reuse the welcome dialog item to show "What's New" only.
if (CuraApplication.shouldShowWhatsNewDialog())
{
welcomeDialogItem.model = CuraApplication.getWhatsNewPagesModel()
welcomeDialogItem.progressBarVisible = false
welcomeDialogItem.visible = true
}
}
// TODO: While the new onboarding process contains the user-agreement,
// it should probably not entirely rely on 'needToShowUserAgreement' for show/hide.
}
Item
@ -731,44 +745,6 @@ UM.MainWindow
}
}
AddMachineDialog
{
id: addMachineDialog
onMachineAdded:
{
machineActionsWizard.firstRun = addMachineDialog.firstRun
machineActionsWizard.start(id)
}
}
// Dialog to handle first run machine actions
UM.Wizard
{
id: machineActionsWizard;
title: catalog.i18nc("@title:window", "Add Printer")
property var machine;
function start(id)
{
var actions = Cura.MachineActionManager.getFirstStartActions(id)
resetPages() // Remove previous pages
for (var i = 0; i < actions.length; i++)
{
actions[i].displayItem.reset()
machineActionsWizard.appendPage(actions[i].displayItem, catalog.i18nc("@title", actions[i].label));
}
//Only start if there are actions to perform.
if (actions.length > 0)
{
machineActionsWizard.currentPage = 0;
show()
}
}
}
MessageDialog
{
id: messageDialog
@ -812,10 +788,32 @@ UM.MainWindow
}
}
Cura.WizardDialog
{
id: addMachineDialog
title: catalog.i18nc("@title:window", "Add Printer")
model: CuraApplication.getAddPrinterPagesModel()
progressBarVisible: false
}
Cura.WizardDialog
{
id: whatsNewDialog
title: catalog.i18nc("@title:window", "What's New")
model: CuraApplication.getWhatsNewPagesModel()
progressBarVisible: false
}
Connections
{
target: Cura.Actions.whatsNew
onTriggered: whatsNewDialog.show()
}
Connections
{
target: Cura.Actions.addMachine
onTriggered: addMachineDialog.visible = true;
onTriggered: addMachineDialog.show()
}
AboutDialog
@ -829,31 +827,17 @@ UM.MainWindow
onTriggered: aboutDialog.visible = true;
}
Connections
{
target: CuraApplication
onRequestAddPrinter:
{
addMachineDialog.visible = true
addMachineDialog.firstRun = false
}
}
Timer
{
id: startupTimer;
interval: 100;
repeat: false;
running: true;
id: startupTimer
interval: 100
repeat: false
running: true
onTriggered:
{
if(!base.visible)
if (!base.visible)
{
base.visible = true;
}
if(!CuraApplication.needToShowUserAgreement && Cura.MachineManager.activeMachine == null)
{
addMachineDialog.open();
base.visible = true
}
}
}

View file

@ -1,321 +0,0 @@
// Copyright (c) 2019 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.2
import QtQuick.Controls 1.1
import QtQuick.Layouts 1.1
import QtQuick.Window 2.1
import QtQuick.Controls.Styles 1.1
import UM 1.2 as UM
import Cura 1.0 as Cura
UM.Dialog
{
id: base
title: catalog.i18nc("@title:window", "Add Printer")
property bool firstRun: false
property string preferredCategory: "Ultimaker"
property string activeCategory: preferredCategory
minimumWidth: UM.Theme.getSize("modal_window_minimum").width
minimumHeight: UM.Theme.getSize("modal_window_minimum").height
width: minimumWidth
height: minimumHeight
flags:
{
var window_flags = Qt.Dialog | Qt.CustomizeWindowHint | Qt.WindowTitleHint;
if (Cura.MachineManager.activeDefinitionId !== "") //Disallow closing the window if we have no active printer yet. You MUST add a printer.
{
window_flags |= Qt.WindowCloseButtonHint;
}
return window_flags;
}
onVisibilityChanged:
{
// Reset selection and machine name
if (visible)
{
activeCategory = preferredCategory;
machineList.currentIndex = 0;
machineName.text = getMachineName();
}
}
signal machineAdded(string id)
function getMachineName()
{
if (machineList.model.getItem(machineList.currentIndex) != undefined)
{
return machineList.model.getItem(machineList.currentIndex).name;
}
return "";
}
function getMachineMetaDataEntry(key)
{
if (machineList.model.getItem(machineList.currentIndex) != undefined)
{
return machineList.model.getItem(machineList.currentIndex).metadata[key];
}
return "";
}
Label
{
id: titleLabel
anchors
{
top: parent.top
left: parent.left
topMargin: UM.Theme.getSize("default_margin").height
}
text: catalog.i18nc("@title:tab", "Add a printer to Cura")
font.pointSize: 18
}
Label
{
id: captionLabel
anchors
{
left: parent.left
top: titleLabel.bottom
topMargin: UM.Theme.getSize("default_margin").height
}
text: catalog.i18nc("@title:tab", "Select the printer you want to use from the list below.\n\nIf your printer is not in the list, use the \"Custom FFF Printer\" from the \"Custom\" category and adjust the settings to match your printer in the next dialog.")
width: parent.width
wrapMode: Text.WordWrap
}
ScrollView
{
id: machinesHolder
anchors
{
top: captionLabel.visible ? captionLabel.bottom : parent.top;
topMargin: captionLabel.visible ? UM.Theme.getSize("default_margin").height : 0;
bottom: addPrinterButton.top;
bottomMargin: UM.Theme.getSize("default_margin").height
}
width: Math.round(parent.width * 0.45)
frameVisible: true;
Rectangle
{
parent: viewport
anchors.fill: parent
color: palette.light
}
ListView
{
id: machineList
model: UM.DefinitionContainersModel
{
id: machineDefinitionsModel
filter: { "visible": true }
sectionProperty: "category"
preferredSectionValue: preferredCategory
}
section.property: "section"
section.delegate: Button
{
id: machineSectionButton
text: section
width: machineList.width
style: ButtonStyle
{
background: Item
{
height: UM.Theme.getSize("standard_list_lineheight").height
width: machineList.width
}
label: Label
{
anchors.left: parent.left
anchors.leftMargin: UM.Theme.getSize("standard_arrow").width + UM.Theme.getSize("default_margin").width
text: control.text
color: palette.windowText
font.bold: true
UM.RecolorImage
{
id: downArrow
anchors.verticalCenter: parent.verticalCenter
anchors.right: parent.left
anchors.rightMargin: UM.Theme.getSize("default_margin").width
width: UM.Theme.getSize("standard_arrow").width
height: UM.Theme.getSize("standard_arrow").height
sourceSize.height: width
color: palette.windowText
source: base.activeCategory == section ? UM.Theme.getIcon("arrow_bottom") : UM.Theme.getIcon("arrow_right")
}
}
}
onClicked:
{
base.activeCategory = section;
if (machineList.model.getItem(machineList.currentIndex).section != section)
{
// Find the first machine from this section
for(var i = 0; i < machineList.model.count; i++)
{
var item = machineList.model.getItem(i);
if (item.section == section)
{
machineList.currentIndex = i;
break;
}
}
}
machineName.text = getMachineName();
}
}
delegate: RadioButton
{
id: machineButton
anchors.left: parent.left
anchors.leftMargin: UM.Theme.getSize("standard_list_lineheight").width
opacity: 1;
height: UM.Theme.getSize("standard_list_lineheight").height;
checked: ListView.isCurrentItem;
exclusiveGroup: printerGroup;
text: model.name
onClicked:
{
ListView.view.currentIndex = index;
machineName.text = getMachineName()
}
states: State
{
name: "collapsed";
when: base.activeCategory != model.section;
PropertyChanges { target: machineButton; opacity: 0; height: 0; }
}
}
}
}
Column
{
anchors
{
top: machinesHolder.top
left: machinesHolder.right
right: parent.right
leftMargin: UM.Theme.getSize("default_margin").width
}
spacing: UM.Theme.getSize("default_margin").height
Label
{
width: parent.width
wrapMode: Text.WordWrap
text: getMachineName()
font.pointSize: 16
elide: Text.ElideRight
}
Grid
{
width: parent.width
columns: 2
rowSpacing: UM.Theme.getSize("default_lining").height
columnSpacing: UM.Theme.getSize("default_margin").width
verticalItemAlignment: Grid.AlignVCenter
Label
{
wrapMode: Text.WordWrap
text: catalog.i18nc("@label", "Manufacturer")
}
Label
{
width: Math.floor(parent.width * 0.65)
wrapMode: Text.WordWrap
text: getMachineMetaDataEntry("manufacturer")
}
Label
{
wrapMode: Text.WordWrap
text: catalog.i18nc("@label", "Author")
}
Label
{
width: Math.floor(parent.width * 0.75)
wrapMode: Text.WordWrap
text: getMachineMetaDataEntry("author")
}
Label
{
wrapMode: Text.WordWrap
text: catalog.i18nc("@label", "Printer Name")
}
TextField
{
id: machineName
text: getMachineName()
width: Math.floor(parent.width * 0.75)
maximumLength: 40
//validator: Cura.MachineNameValidator { } //TODO: Gives a segfault in PyQt5.6. For now, we must use a signal on text changed.
validator: RegExpValidator
{
regExp: {
machineName.machine_name_validator.machineNameRegex
}
}
property var machine_name_validator: Cura.MachineNameValidator { }
}
}
}
Button
{
id: addPrinterButton
text: catalog.i18nc("@action:button", "Add Printer")
anchors.bottom: parent.bottom
anchors.right: parent.right
onClicked: addMachine()
}
onAccepted: addMachine()
function addMachine()
{
base.visible = false
var item = machineList.model.getItem(machineList.currentIndex);
Cura.MachineManager.addMachine(item.id, machineName.text)
base.machineAdded(item.id) // Emit signal that the user added a machine.
}
Item
{
UM.I18nCatalog
{
id: catalog;
name: "cura";
}
SystemPalette { id: palette }
ExclusiveGroup { id: printerGroup; }
}
}

View file

@ -101,6 +101,7 @@ Item
MenuItem { action: Cura.Actions.documentation }
MenuItem { action: Cura.Actions.reportBug }
MenuSeparator { }
MenuItem { action: Cura.Actions.whatsNew }
MenuItem { action: Cura.Actions.about }
}
}

View file

@ -45,7 +45,7 @@ UM.ManagementPage
{
text: catalog.i18nc("@action:button", "Add");
iconName: "list-add";
onClicked: CuraApplication.requestAddPrinter()
onClicked: Cura.Actions.addMachine.trigger()
},
Button
{

View file

@ -12,9 +12,12 @@ import Cura 1.0 as Cura
// This is the scroll view widget for adding a (local) printer. This scroll view shows a list view with printers
// categorized into 3 categories: "Ultimaker", "Custom", and "Other".
//
ScrollView
Item
{
UM.I18nCatalog { id: catalog; name: "cura" }
id: base
height: childrenRect.height
// The currently selected machine item in the local machine list.
property var currentItem: (machineList.currentIndex >= 0)
@ -25,12 +28,16 @@ ScrollView
// By default (when this list shows up) we always expand the "Ultimaker" section.
property string preferredCategory: "Ultimaker"
ScrollBar.horizontal.policy: ScrollBar.AlwaysOff
ScrollBar.vertical.policy: ScrollBar.AsNeeded
property int maxItemCountAtOnce: 10 // show at max 10 items at once, otherwise you need to scroll.
height: maxItemCountAtOnce * UM.Theme.getSize("action_button").height
clip: true
// User-editable printer name
property alias printerName: printerNameTextField.text
property alias isPrinterNameValid: printerNameTextField.acceptableInput
onCurrentItemChanged:
{
printerName = currentItem == null ? "" : currentItem.name
}
function updateCurrentItemUponSectionChange()
{
@ -51,6 +58,29 @@ ScrollView
updateCurrentItemUponSectionChange()
}
Item
{
id: localPrinterSelectionItem
anchors.left: parent.left
anchors.right: parent.right
anchors.top: parent.top
height: childrenRect.height
// ScrollView + ListView for selecting a local printer to add
ScrollView
{
id: scrollView
anchors.left: parent.left
anchors.right: parent.right
anchors.top: parent.top
height: maxItemCountAtOnce * UM.Theme.getSize("action_button").height
ScrollBar.horizontal.policy: ScrollBar.AlwaysOff
ScrollBar.vertical.policy: ScrollBar.AsNeeded
clip: true
ListView
{
id: machineList
@ -111,7 +141,7 @@ ScrollView
anchors.leftMargin: UM.Theme.getSize("default_margin").width
verticalAlignment: Text.AlignVCenter
text: button.text
font.bold: true
font: UM.Theme.getFont("default_bold")
renderType: Text.NativeRendering
}
}
@ -138,16 +168,54 @@ ScrollView
height: visible ? UM.Theme.getSize("standard_list_lineheight").height : 0
checked: ListView.view.currentIndex == index
onCheckedChanged:
{
if(checked)
{
machineList.currentIndex = index
}
}
text: name
visible: base.currentSection == section
onClicked: ListView.view.currentIndex = index
}
}
}
}
// Horizontal line
Rectangle
{
id: horizontalLine
anchors.top: localPrinterSelectionItem.bottom
anchors.left: parent.left
anchors.right: parent.right
height: UM.Theme.getSize("default_lining").height
color: UM.Theme.getColor("lining")
}
// User-editable printer name row
Row
{
anchors.top: horizontalLine.bottom
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: UM.Theme.getSize("default_lining").height
anchors.leftMargin: UM.Theme.getSize("default_margin").width
spacing: UM.Theme.getSize("default_margin").width
Label
{
text: catalog.i18nc("@label", "Printer Name")
anchors.verticalCenter: parent.verticalCenter
font: UM.Theme.getFont("medium")
verticalAlignment: Text.AlignVCenter
renderType: Text.NativeRendering
}
Cura.TextField
{
id: printerNameTextField
anchors.verticalCenter: parent.verticalCenter
width: (parent.width / 2) | 0
placeholderText: catalog.i18nc("@text", "Please give your printer a name")
// Make sure that the fill is not empty
validator: RegExpValidator { regExp: /.+/ }
}
}
}

View file

@ -118,11 +118,14 @@ Item
}
else
{
return addLocalPrinterDropDown.contentItem.currentItem != null
// Printer name cannot be empty
const localPrinterItem = addLocalPrinterDropDown.contentItem.currentItem
const isPrinterNameValid = addLocalPrinterDropDown.contentItem.isPrinterNameValid
return localPrinterItem != null && isPrinterNameValid
}
}
text: catalog.i18nc("@button", "Next")
text: base.currentItem.next_page_button_text
onClicked:
{
// Create a network printer or a local printer according to the selection
@ -139,7 +142,8 @@ Item
{
// Create a local printer
const localPrinterItem = addLocalPrinterDropDown.contentItem.currentItem
Cura.MachineManager.addMachine(localPrinterItem.id)
const printerName = addLocalPrinterDropDown.contentItem.printerName
Cura.MachineManager.addMachine(localPrinterItem.id, printerName)
base.showNextPage()
}

View file

@ -60,7 +60,7 @@ Item
anchors.left: header.left
anchors.right: header.right
// Add 2x lining, because it needs a bit of space on the top and the bottom.
height: contentLoader.height + 2 * UM.Theme.getSize("thick_lining").height
height: contentLoader.item.height + 2 * UM.Theme.getSize("thick_lining").height
border.width: UM.Theme.getSize("default_lining").width
border.color: UM.Theme.getColor("lining")

View file

@ -11,7 +11,7 @@ import Cura 1.1 as Cura
//
// This is a no-frame dialog that shows the welcome process.
// This is an Item that tries to mimic a dialog for showing the welcome process.
//
Item
{
@ -26,6 +26,7 @@ Item
property int shadowOffset: 1 * screenScaleFactor
property alias progressBarVisible: wizardPanel.progressBarVisible
property var model: CuraApplication.getWelcomePagesModel()
onVisibleChanged:
@ -38,7 +39,7 @@ Item
WizardPanel
{
id: stepPanel
id: wizardPanel
anchors.fill: parent
model: dialog.model
}
@ -48,8 +49,8 @@ Item
{
id: shadow
radius: UM.Theme.getSize("first_run_shadow_radius").width
anchors.fill: stepPanel
source: stepPanel
anchors.fill: wizardPanel
source: wizardPanel
horizontalOffset: shadowOffset
verticalOffset: shadowOffset
color: UM.Theme.getColor("first_run_shadow")

View file

@ -51,7 +51,7 @@ Item
id: getStartedButton
anchors.right: parent.right
anchors.bottom: parent.bottom
text: catalog.i18nc("@button", "Next")
text: base.currentItem.next_page_button_text
onClicked: base.showNextPage()
}
}

View file

@ -0,0 +1,54 @@
// Copyright (c) 2019 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.10
import QtQuick.Controls 2.3
import QtQuick.Window 2.2
import UM 1.3 as UM
import Cura 1.1 as Cura
//
// This is a dialog for showing a set of processes that's defined in a WelcomePagesModel or some other Qt ListModel with
// a compatible interface.
//
Window
{
UM.I18nCatalog { id: catalog; name: "cura" }
id: dialog
flags: Qt.Dialog
modality: Qt.ApplicationModal
minimumWidth: 580 * screenScaleFactor
minimumHeight: 600 * screenScaleFactor
color: UM.Theme.getColor("main_background")
property var model: null // Needs to be set by whoever is using this dialog.
property alias progressBarVisible: wizardPanel.progressBarVisible
onVisibilityChanged:
{
if (visible)
{
model.resetState()
}
}
WizardPanel
{
id: wizardPanel
anchors.fill: parent
model: dialog.model
}
// Close this dialog when there's no more page to show
Connections
{
target: model
onAllFinished: dialog.hide()
}
}

View file

@ -25,6 +25,7 @@ Item
property var progressValue: model == null ? 0 : model.currentProgress
property string pageUrl: currentItem == null ? "" : currentItem.page_url
property alias progressBarVisible: progressBar.visible
property alias backgroundColor: panelBackground.color
signal showNextPage()
@ -44,6 +45,7 @@ Item
anchors.fill: parent
radius: UM.Theme.getSize("default_radius").width
color: UM.Theme.getColor("main_background")
UM.ProgressBar
{
id: progressBar

View file

@ -17,17 +17,38 @@ TextField
UM.I18nCatalog { id: catalog; name: "cura" }
property int controlWidth: UM.Theme.getSize("setting_control").width
property int controlHeight: UM.Theme.getSize("setting_control").height
hoverEnabled: true
selectByMouse: true
font: UM.Theme.getFont("default")
renderType: Text.NativeRendering
states: [
State
{
name: "disabled"
when: !textField.enabled
PropertyChanges { target: backgroundRectangle.border; color: UM.Theme.getColor("setting_control_disabled_border")}
PropertyChanges { target: backgroundRectangle; color: UM.Theme.getColor("setting_control_disabled")}
},
State
{
name: "invalid"
when: !textField.acceptableInput
PropertyChanges { target: backgroundRectangle.border; color: UM.Theme.getColor("setting_validation_error")}
PropertyChanges { target: backgroundRectangle; color: UM.Theme.getColor("setting_validation_error_background")}
},
State
{
name: "hovered"
when: textField.hovered || textField.activeFocus
PropertyChanges { target: backgroundRectangle.border; color: UM.Theme.getColor("setting_control_border_highlight") }
}
]
background: Rectangle
{
anchors.fill: parent
id: backgroundRectangle
anchors.margins: Math.round(UM.Theme.getSize("default_lining").width)
radius: UM.Theme.getSize("setting_control_radius").width

View file

@ -20,6 +20,12 @@ CheckBoxWithTooltip 1.0 CheckBoxWithTooltip.qml
ToolTip 1.0 ToolTip.qml
# Cura/WelcomePages
WizardPanel 1.0 WizardPanel.qml
WizardDialog 1.0 WizardDialog.qml
# Cura/Widgets
CheckBox 1.0 CheckBox.qml