9import QtQuick.Templates as QT
10import QtQuick.Controls as QQC2
11import org.kde.kirigami as Kirigami
12import "private/globaltoolbar" as GlobalToolBar
13import "templates" as KT
33 readonly
property alias depth: columnView.count
39 readonly
property Item lastItem: columnView.contentChildren.length > 0 ? columnView.contentChildren[columnView.contentChildren.length - 1] : null
48 readonly
property alias currentItem: columnView.currentItem
55 property alias currentIndex: columnView.currentIndex
61 property var initialPage
67 contentItem: columnView
77 property alias columnView: columnView
84 readonly
property alias items: columnView.contentChildren
92 readonly
property alias visibleItems: columnView.visibleItems
101 readonly
property alias leadingVisibleItem: columnView.leadingVisibleItem
110 readonly
property alias trailingVisibleItem: columnView.trailingVisibleItem
119 property int defaultColumnWidth: Kirigami.Units.gridUnit * 20
129 property alias interactive: columnView.interactive
135 readonly
property bool wideMode: width >= defaultColumnWidth * 2 && depth >= 2
145 property alias separatorVisible: columnView.separatorVisible
169 readonly
property alias globalToolBar: globalToolBar
180 property OverlayDrawer leftSidebar
191 property alias layers: layersStack
201 property bool popHiddenPages:
false
220 function push(page, properties): QT.Page {
221 if (!pagesLogic.verifyPages(page, properties)) {
222 console.warn(
"Pushed pages do not conform to the rules. Please check the documentation.");
227 const item = pagesLogic.insertPage_unchecked(currentIndex + 1, page, properties)
228 currentIndex = depth - 1
245 function pushDialogLayer(page, properties = {}, windowProperties = {}): QT.
Page {
246 if (!pagesLogic.verifyPages(page, properties)) {
247 console.warn(
"Page pushed as a dialog or layer does not conform to the rules. Please check the documentation.");
252 if (Kirigami.Settings.isMobile) {
253 if (QQC2.ApplicationWindow.window.width > Kirigami.Units.gridUnit * 40) {
255 const component = pagesLogic.getMobileDialogLayerComponent();
256 const dialog = component.createObject(QQC2.Overlay.overlay, {
257 width: Qt.binding(() => QQC2.ApplicationWindow.window.width - Kirigami.Units.gridUnit * 5),
258 height: Qt.binding(() => QQC2.ApplicationWindow.window.height - Kirigami.Units.gridUnit * 5),
259 x: Kirigami.Units.gridUnit * 2.5,
260 y: Kirigami.Units.gridUnit * 2.5,
263 if (typeof page ===
"string") {
265 const component = Qt.createComponent(Qt.resolvedUrl(page));
266 item = component.createObject(dialog.contentItem, properties);
268 dialog.contentItem.contentItem = item
269 } else if (page instanceof Component) {
270 item = page.createObject(dialog.contentItem, properties);
271 dialog.contentItem.contentItem = item
272 } else if (page instanceof Item) {
274 page.parent = dialog.contentItem;
275 } else if (typeof page ===
'object' && typeof page.toString() ===
'string') {
276 const component = Qt.createComponent(page);
277 item = component.createObject(dialog.contentItem, properties);
279 dialog.contentItem.contentItem = item
281 dialog.title = Qt.binding(() => item.title);
284 if (item.globalToolBar && item.globalToolBar.style) {
285 item.globalToolBar.style = Kirigami.ApplicationHeaderStyle.None
287 Object.defineProperty(item,
'closeDialog', {
295 item = layers.push(page, properties);
296 Object.defineProperty(item,
'closeDialog', {
304 if (!(
"modality" in windowProperties)) {
305 windowProperties.modality =
Qt.WindowModal;
307 if (!(
"height" in windowProperties)) {
308 windowProperties.height = Kirigami.Units.gridUnit * 30;
310 if (!(
"width" in windowProperties)) {
311 windowProperties.width = Kirigami.Units.gridUnit * 50;
313 if (!(
"minimumWidth" in windowProperties)) {
314 windowProperties.minimumWidth = Kirigami.Units.gridUnit * 20;
316 if (!(
"minimumHeight" in windowProperties)) {
317 windowProperties.minimumHeight = Kirigami.Units.gridUnit * 15;
319 if (!(
"flags" in windowProperties)) {
320 windowProperties.flags =
Qt.Dialog |
Qt.CustomizeWindowHint |
Qt.WindowTitleHint |
Qt.WindowCloseButtonHint;
322 const windowComponent =
Qt.createComponent(
Qt.resolvedUrl(
"./ApplicationWindow.qml"));
323 const window = windowComponent.createObject(root, windowProperties);
325 item = window.pageStack.push(page, properties);
326 Object.defineProperty(item,
'closeDialog', {
332 item.Keys.escapePressed.connect(event => item.closeDialog());
352 function insertPage(position, page, properties): QT.
Page {
353 if (!pagesLogic.verifyPages(page,
properties)) {
354 console.warn(
"Inserted pages do not conform to the rules. Please check the documentation.");
359 if (position < 0 || position > depth) {
360 console.warn(
"You are trying to insert a page to an out-of-bounds position. Position will be adjusted accordingly.");
362 position = Math.max(0, Math.min(depth, position));
364 return pagesLogic.insertPage_unchecked(position, page, properties)
373 function movePage(fromPos, toPos): void {
374 columnView.moveItem(fromPos, toPos);
383 function removePage(page): QT.
Page {
385 return columnView.removeItem(page);
396 function pop(page): QT.
Page {
397 return columnView.pop(page);
417 if (!pagesLogic.verifyPages(page,
properties)) {
418 console.warn(
"Specified pages do not conform to the rules. Please check the documentation.");
424 if (currentIndex >= 0) {
425 columnView.pop(currentIndex);
427 console.warn(
"There's no page to replace");
433 if (page instanceof Array) {
435 page = pages.shift();
437 if (properties instanceof Array) {
445 let pageItem = pagesLogic.initPage(page, properties);
447 columnView.replaceItem(depth - 1, pageItem);
449 console.log(
"Calling replace on empty PageRow", pageItem)
450 columnView.addItem(pageItem)
452 pagePushed(pageItem);
456 for (
const i in pages) {
457 const tPage = pages[i];
458 const tProps = propsArray[i];
460 pageItem = pagesLogic.initPage(tPage, tProps);
461 columnView.addItem(pageItem);
462 pagePushed(pageItem);
466 currentIndex = depth - 1;
475 function
clear(): void {
490 function flickBack(): void {
492 currentIndex = Math.max(0, currentIndex - 1);
504 function goBack(event = null): void {
505 const backEvent = {accepted:
false}
507 if (layersStack.depth >= 1) {
509 layersStack.currentItem.backRequested(backEvent)
512 if (!backEvent.accepted) {
513 if (layersStack.depth > 1) {
516 event.accepted =
true
523 if (currentIndex >= 1) {
525 currentItem.backRequested(backEvent)
528 if (!backEvent.accepted) {
530 currentIndex = Math.max(0, currentIndex - 1)
532 event.accepted =
true
545 function goForward(): void {
546 currentIndex = Math.min(depth - 1, currentIndex + 1)
557 signal pageInserted(int position,
Item page)
564 signal pagePushed(
Item page)
572 signal pageRemoved(
Item page)
574 onLeftSidebarChanged: {
575 if (leftSidebar && !leftSidebar.modal) {
576 modalConnection.onModalChanged();
580 Keys.onReleased:
event => {
581 if (
event.key ===
Qt.Key_Back) {
586 onInitialPageChanged: {
589 push(initialPage, null)
608 function onModalChanged(): void {
609 if (leftSidebar.modal) {
610 const sidebar = sidebarControl.contentItem;
611 const background = sidebarControl.background;
612 sidebarControl.contentItem = null;
613 leftSidebar.contentItem = sidebar;
614 sidebarControl.background = null;
615 leftSidebar.background = background;
617 sidebar.visible =
true;
618 background.visible =
true;
620 const sidebar = leftSidebar.contentItem
621 const background = leftSidebar.background
622 leftSidebar.contentItem=null
623 sidebarControl.contentItem = sidebar
624 leftSidebar.background=null
625 sidebarControl.background = background
627 sidebar.visible =
true;
628 background.visible =
true;
633 implicitWidth: contentItem.implicitWidth + leftPadding + rightPadding
634 implicitHeight: contentItem.implicitHeight + topPadding + bottomPadding
637 sequences: [ StandardKey.Back ]
638 onActivated: goBack()
641 sequences: [ StandardKey.Forward ]
642 onActivated: goForward()
645 Keys.forwardTo: [currentItem]
647 GlobalToolBar.PageRowGlobalToolBarStyleGroup {
649 readonly
property int leftReservedSpace: globalToolBarUI.item ? globalToolBarUI.item.leftReservedSpace : 0
650 readonly
property int rightReservedSpace: globalToolBarUI.item ? globalToolBarUI.item.rightReservedSpace : 0
651 readonly
property int height: globalToolBarUI.height
652 readonly
property Item leftHandleAnchor: globalToolBarUI.item ? globalToolBarUI.item.leftHandleAnchor : null
653 readonly
property Item rightHandleAnchor: globalToolBarUI.item ? globalToolBarUI.item.rightHandleAnchor : null
657 id: layerToolbarStack
664 height: currentItem?.implicitHeight ?? 0
665 initialItem:
Item {implicitHeight: 0}
673 popEnter: Transition {
677 duration: Kirigami.Units.longDuration
678 easing.type: Easing.InOutCubic
681 popExit: Transition {
685 duration: Kirigami.Units.longDuration
686 easing.type: Easing.InOutCubic
689 pushEnter: Transition {
693 duration: Kirigami.Units.longDuration
694 easing.type: Easing.InOutCubic
697 pushExit: Transition {
701 duration: Kirigami.Units.longDuration
702 easing.type: Easing.InOutCubic
705 replaceEnter: Transition {
709 duration: Kirigami.Units.longDuration
710 easing.type: Easing.InOutCubic
713 replaceExit: Transition {
717 duration: Kirigami.Units.longDuration
718 easing.type: Easing.InOutCubic
727 bottom: parent.bottom
731 height: currentItem?.implicitHeight ?? 0
732 initialItem:
Item {implicitHeight: 0}
734 popEnter: Transition {
738 duration: Kirigami.Units.longDuration
739 easing.type: Easing.InOutCubic
742 popExit: Transition {
746 duration: Kirigami.Units.longDuration
747 easing.type: Easing.InOutCubic
750 pushEnter: Transition {
754 duration: Kirigami.Units.longDuration
755 easing.type: Easing.InOutCubic
758 pushExit: Transition {
762 duration: Kirigami.Units.longDuration
763 easing.type: Easing.InOutCubic
766 replaceEnter: Transition {
770 duration: Kirigami.Units.longDuration
771 easing.type: Easing.InOutCubic
774 replaceExit: Transition {
778 duration: Kirigami.Units.longDuration
779 easing.type: Easing.InOutCubic
789 top: layerToolbarStack.bottom
791 bottom: layerFooterStack.top
794 initialItem: columnViewLayout
797 let item = layersStack.get(depth - 1)
799 if (layerToolbarStack.depth > depth) {
800 while (layerToolbarStack.depth > depth) {
801 layerToolbarStack.pop();
803 }
else if (layerToolbarStack.depth < depth) {
804 for (let i = layerToolbarStack.depth; i < depth; ++i) {
805 const toolBar = layersStack.get(i).Kirigami.ColumnView.globalHeader;
806 layerToolbarStack.push(toolBar || emptyToolbar);
809 let toolBarItem = layerToolbarStack.get(layerToolbarStack.depth - 1)
810 if (item.Kirigami.ColumnView.globalHeader != toolBarItem) {
811 const toolBar = item.Kirigami.ColumnView.globalHeader;
812 layerToolbarStack.replace(toolBar ?? emptyToolbar);
815 toolBarItem = layerToolbarStack.get(layerToolbarStack.depth - 1)
816 toolBarItem.opacity = 1;
818 if (layerFooterStack.depth > depth) {
819 while (layerFooterStack.depth > depth) {
820 layerFooterStack.pop();
822 }
else if (layerFooterStack.depth < depth) {
823 for (let i = layerFooterStack.depth; i < depth; ++i) {
824 const footer = layersStack.get(i).Kirigami.ColumnView.globalFooter;
825 layerFooterStack.push(footer ?? emptyToolbar);
828 let footerItem = layerFooterStack.get(layerFooterStack.depth - 1)
829 if (item.Kirigami.ColumnView.globalHeader != footerItem) {
830 const footer = item.Kirigami.ColumnView.globalFooter;
831 layerFooterStack.replace(footer ?? emptyToolbar);
833 footerItem = layerFooterStack.get(layerFooterStack.depth - 1)
834 footerItem.opacity = 1;
837 function
clear(): void {
839 const d = layersStack.depth;
840 for (let i = 1; i < d; ++i) {
845 popEnter: Transition {
849 duration: Kirigami.Units.longDuration
850 easing.type: Easing.InOutCubic
853 popExit: Transition {
858 duration: Kirigami.Units.longDuration
859 easing.type: Easing.InOutCubic
864 duration: Kirigami.Units.longDuration
865 easing.type: Easing.InCubic
870 pushEnter: Transition {
877 duration: Kirigami.Units.longDuration
878 easing.type: Easing.InOutCubic
883 duration: Kirigami.Units.longDuration
884 easing.type: Easing.OutCubic
890 pushExit: Transition {
894 duration: Kirigami.Units.longDuration
895 easing.type: Easing.InOutCubic
899 replaceEnter: Transition {
904 duration: Kirigami.Units.longDuration
905 easing.type: Easing.InOutCubic
910 duration: Kirigami.Units.longDuration
911 easing.type: Easing.OutCubic
916 replaceExit: Transition {
921 duration: Kirigami.Units.longDuration
922 easing.type: Easing.InCubic
927 duration: Kirigami.Units.longDuration
928 easing.type: Easing.InOutCubic
942 property QT.Control pageRow: root
943 active: (!leadingVisibleItem || leadingVisibleItem.globalToolBarStyle !== Kirigami.ApplicationHeaderStyle.None) &&
944 (globalToolBar.actualStyle !== Kirigami.ApplicationHeaderStyle.None || (leadingVisibleItem && leadingVisibleItem.globalToolBarStyle === Kirigami.ApplicationHeaderStyle.ToolBar))
946 height: active ? implicitHeight : 0
950 source:
Qt.resolvedUrl(
"private/globaltoolbar/PageRowGlobalToolBarUI.qml");
955 readonly
property var componentCache:
new Array()
957 property Component __mobileDialogLayerComponent
959 function getMobileDialogLayerComponent() {
960 if (!__mobileDialogLayerComponent) {
961 __mobileDialogLayerComponent =
Qt.createComponent(
Qt.resolvedUrl(
"private/MobileDialogLayer.qml"));
963 return __mobileDialogLayerComponent;
966 function verifyPages(pages, properties): bool {
967 function validPage(page) {
969 if (page instanceof QT.Page && columnView.containsItem(page)) {
970 console.log(`Page ${page} is already in the
PageRow`)
973 return page instanceof QT.Page || page instanceof Component || typeof page ===
'string'
974 || (typeof page ===
'object' && typeof page.toString() ===
'string')
978 const pagesIsArr = Array.isArray(pages) && pages.length > 0
979 let isValidArrOfPages = pagesIsArr;
982 for (
const page of pages) {
983 if (!validPage(page)) {
984 isValidArrOfPages =
false;
991 const isProp = typeof
properties ===
'object';
992 const propsIsArr = Array.isArray(properties) &&
properties.length > 0
993 let isValidPropArr = propsIsArr;
996 for (
const prop of properties) {
997 if (typeof prop !==
'object') {
998 isValidPropArr =
false;
1002 isValidPropArr = isValidPropArr && pages.length ===
properties.length
1005 return (validPage(pages) || isValidArrOfPages)
1006 && (!
properties || (isProp || isValidPropArr))
1009 function insertPage_unchecked(position, page, properties) {
1010 columnView.pop(position - 1);
1014 let propsArray = [];
1015 if (page instanceof Array) {
1019 if (properties instanceof Array) {
1028 for (
const i in pages) {
1029 let tPage = pages[i];
1030 let tProps = propsArray[i];
1032 pagesLogic.initAndInsertPage(position, tPage, tProps);
1038 const pageItem = pagesLogic.initAndInsertPage(position, page, properties);
1040 pagePushed(pageItem);
1045 function getPageComponent(page): Component {
1048 if (page.createObject) {
1051 }
else if (typeof page ===
"string") {
1053 pageComp = pagesLogic.componentCache[page];
1055 pageComp = pagesLogic.componentCache[page] =
Qt.createComponent(page);
1057 }
else if (typeof page ===
"object" && !(page instanceof
Item) && page.toString !== undefined) {
1059 pageComp = pagesLogic.componentCache[page.toString()];
1061 pageComp = pagesLogic.componentCache[page.toString()] =
Qt.createComponent(page.toString());
1068 function initPage(page, properties): QT.
Page {
1069 const pageComp = getPageComponent(page,
properties);
1075 page = pageComp.createObject(pagesLogic, properties || {});
1077 if (pageComp.status === Component.Error) {
1078 throw new Error(
"Error while loading page: " + pageComp.errorString());
1082 for (
const prop in properties) {
1091 function initAndInsertPage(position, page, properties): QT.
Page {
1093 columnView.insertItem(position, page);
1099 id: columnViewLayout
1101 readonly
property alias columnView: columnView
1104 topMargin: -layersStack.y
1108 Layout.fillHeight:
true
1109 visible: contentItem !== null
1110 leftPadding: root.leftSidebar ? root.leftSidebar.leftPadding : 0
1111 topPadding: root.leftSidebar ? root.leftSidebar.topPadding : 0
1112 rightPadding: root.leftSidebar ? root.leftSidebar.rightPadding : 0
1113 bottomPadding: root.leftSidebar ? root.leftSidebar.bottomPadding : 0
1115 Kirigami.ColumnView {
1117 Layout.fillWidth:
true
1118 Layout.fillHeight:
true
1120 topPadding: globalToolBarUI.item && globalToolBarUI.item.breadcrumbVisible
1121 ? globalToolBarUI.height : 0
1124 readonly
property Item __pageRow: root
1125 acceptsMouse: Kirigami.Settings.isMobile
1126 columnResizeMode: root.wideMode ? Kirigami.ColumnView.FixedColumns : Kirigami.ColumnView.SingleColumn
1127 columnWidth: root.defaultColumnWidth
1128 interactive:
Qt.platform.os !==
'android'
1130 onItemInserted: (position, item) => root.pageInserted(position, item);
1131 onItemRemoved: item => root.pageRemoved(item);
1133 onVisibleItemsChanged: {
1135 if (root.popHiddenPages) {
1137 let lastItem = columnView.contentChildren[columnView.contentChildren.length - 1];
1138 let trailingVisibleItem = columnView.trailingVisibleItem;
1141 while (lastItem && columnView.trailingVisibleItem &&
1142 lastItem !== columnView.trailingVisibleItem && columnView.containsItem(lastItem)) {
1151 anchors.bottom: parent.bottom
1152 height: Kirigami.Units.smallSpacing
1153 x: (columnView.width - width) * (columnView.contentX / (columnView.contentWidth - columnView.width))
1154 width: columnView.width * (columnView.width/columnView.contentWidth)
1155 color: Kirigami.Theme.textColor
1159 scrollIndicatorTimer.restart();
1161 Behavior on opacity {
1163 duration: Kirigami.Units.longDuration
1164 easing.type: Easing.InOutQuad
1168 id: scrollIndicatorTimer
1169 interval: Kirigami.Units.longDuration * 4
1170 onTriggered: parent.opacity = 0;
Page is a container for all the app pages: everything pushed to the ApplicationWindow's pageStack sho...
AKONADI_CALENDAR_EXPORT KCalendarCore::Event::Ptr event(const Akonadi::Item &item)
KIOCORE_EXPORT TransferJob * get(const QUrl &url, LoadType reload=NoReload, JobFlags flags=DefaultFlags)
KGUIADDONS_EXPORT QWindow * window(QObject *job)
const QList< QKeySequence > & replace()
QTextStream & left(QTextStream &stream)
QTextStream & right(QTextStream &stream)