Commit 0334b5a4 authored by Nate Graham's avatar Nate Graham
Browse files

Collapse GridBrowserView into DataGridView

GridBrowserView is used only once, in one other component: DataGridView.
Most of its properties are passed right on as aliases. This adds an
unnecessary layer of abstraction that causes fragility due to the
opportunity for the two to drift out of sync or communicate in
imperative rather than declarative ways.

This situation can be simplified by simply moving the content of
GridBrowserView into DataGridView and then deleting it.
parent b0b997cd
......@@ -424,7 +424,6 @@ if (Qt5Quick_FOUND AND Qt5Widgets_FOUND)
qml/MediaTrackMetadataForm.qml
qml/TracksDiscHeader.qml
qml/MediaTrackMetadataView.qml
qml/GridBrowserView.qml
qml/GridBrowserDelegate.qml
qml/ListBrowserView.qml
qml/ListBrowserDelegate.qml
......
/*
SPDX-FileCopyrightText: 2018 (c) Matthieu Gallien <matthieu_gallien@yahoo.fr>
SPDX-FileCopyrightText: 2022 (c) Nate Graham <kate@kde.org>
SPDX-License-Identifier: LGPL-3.0-or-later
*/
import QtQuick 2.10
import QtQuick.Controls 2.3
import org.kde.kirigami 2.5 as Kirigami
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQml.Models 2.1
import QtQuick.Layouts 1.2
import org.kde.kirigami 2.12 as Kirigami
import org.kde.elisa 1.0
FocusScope {
id: viewHeader
id: gridView
property var filterType
property alias mainTitle: gridView.mainTitle
property alias secondaryTitle: gridView.secondaryTitle
property alias image: gridView.image
property var modelType
property AbstractItemModel realModel
property AbstractProxyModel contentModel
property AbstractProxyModel proxyModel
property alias defaultIcon: gridView.defaultIcon
property alias showRating: gridView.showRating
property alias delegateDisplaySecondaryText: gridView.delegateDisplaySecondaryText
property alias isSubPage: gridView.isSubPage
property alias expandedFilterView: gridView.expandedFilterView
property alias haveTreeModel: gridView.haveTreeModel
property var filter
property alias sortRole: gridView.sortRole
property alias sortRoles: gridView.sortRoles
property alias sortRoleNames: gridView.sortRoleNames
property alias sortOrderNames: gridView.sortOrderNames
property alias sortOrder: gridView.sortOrder
property string mainTitle
property string secondaryTitle
property url image
property url defaultIcon
property int depth: 1
property bool isSubPage: false
property bool delegateDisplaySecondaryText: true
property bool haveTreeModel: false
property bool modelIsInitialized: false
property alias viewManager: gridView.viewManager
property var filterType
property var modelType
property var filter
property alias expandedFilterView: navigationBar.expandedFilterView
property alias showRating: navigationBar.showRating
property alias sortRole: navigationBar.sortRole
property alias sortRoles: navigationBar.sortRoles
property alias sortRoleNames: navigationBar.sortRoleNames
property alias sortOrderNames: navigationBar.sortOrderNames
property alias sortOrder: navigationBar.sortOrder
property alias viewManager: navigationBar.viewManager
signal enqueue(var fullData, string name)
signal replaceAndPlay(var fullData, string name)
signal open(var fullData)
onEnqueue: proxyModel.enqueue(fullData, name,
ElisaUtils.AppendPlayList,
ElisaUtils.DoNotTriggerPlay)
onReplaceAndPlay: proxyModel.enqueue(fullData, name,
ElisaUtils.ReplacePlayList,
ElisaUtils.TriggerPlay)
onOpen: viewManager.openChildView(fullData)
focus: true
......@@ -71,47 +96,206 @@ FocusScope {
}
function goToBack() {
gridView.goToBack()
if (haveTreeModel) {
delegateModel.rootIndex = delegateModel.parentModelIndex()
--depth
} else {
viewManager.goBack()
}
}
GridBrowserView {
id: gridView
focus: true
// Model
DelegateModel {
id: delegateModel
model: gridView.contentModel
delegate: GridBrowserDelegate {
width: Kirigami.Settings.isMobile ? contentDirectoryView.cellWidth : elisaTheme.gridDelegateSize
height: contentDirectoryView.cellHeight
focus: true
isSelected: contentDirectoryView.currentIndex === index
isPartial: false
mainText: model.display
fileUrl: model.url ? model.url : ""
secondaryText: gridView.delegateDisplaySecondaryText && model.secondaryText ? model.secondaryText : ""
imageUrl: model.imageUrl ? model.imageUrl : ''
imageFallbackUrl: defaultIcon
databaseId: model.databaseId
delegateDisplaySecondaryText: gridView.delegateDisplaySecondaryText
entryType: model.dataType
hasChildren: model.hasChildren
onEnqueue: gridView.enqueue(model.fullData, model.display)
onReplaceAndPlay: gridView.replaceAndPlay(model.fullData, model.display)
onOpen: {
if (haveTreeModel && !model.hasModelChildren) {
return
}
if (haveTreeModel) {
delegateModel.rootIndex = delegateModel.modelIndex(model.index)
++depth
} else {
gridView.open(model.fullData)
}
}
onSelected: {
forceActiveFocus()
contentDirectoryView.currentIndex = model.index
}
onActiveFocusChanged: {
if (activeFocus && contentDirectoryView.currentIndex !== model.index) {
contentDirectoryView.currentIndex = model.index
}
}
}
}
// Main view components
ColumnLayout {
anchors.fill: parent
spacing: 0
onEnqueue: proxyModel.enqueue(fullData, name,
ElisaUtils.AppendPlayList,
ElisaUtils.DoNotTriggerPlay)
NavigationActionBar {
id: navigationBar
onReplaceAndPlay: proxyModel.enqueue(fullData, name,
ElisaUtils.ReplacePlayList,
ElisaUtils.TriggerPlay)
z: 1 // on top of track list
onOpen: viewManager.openChildView(fullData)
mainTitle: gridView.mainTitle
secondaryTitle: gridView.secondaryTitle
image: gridView.image
enableGoBack: gridView.isSubPage || depth > 1
suppressNoDataPlaceholderMessage: busyIndicatorLoader.active
Layout.fillWidth: true
onGoBackRequested: {
viewManager.goBack()
Loader {
active: gridView.contentModel
sourceComponent: Binding {
target: gridView.contentModel
property: 'filterText'
when: gridView.contentModel
value: navigationBar.filterText
}
}
Loader {
active: gridView.contentModel
sourceComponent: Binding {
target: gridView.contentModel
property: 'filterRating'
when: gridView.contentModel
value: navigationBar.filterRating
}
}
Loader {
active: gridView.contentModel && navigationBar.enableSorting
sourceComponent: Binding {
target: gridView.contentModel
property: 'sortRole'
when: gridView.contentModel && navigationBar.enableSorting
value: navigationBar.sortRole
}
}
onEnqueue: contentModel.enqueueToPlayList(delegateModel.rootIndex)
onReplaceAndPlay:contentModel.replaceAndPlayOfPlayList(delegateModel.rootIndex)
onGoBack: {
gridView.goToBack()
}
onSortOrderChanged: {
if (!contentModel || !navigationBar.enableSorting) {
return
}
if ((contentModel.sortedAscending && sortOrder !== Qt.AscendingOrder) ||
(!contentModel.sortedAscending && sortOrder !== Qt.DescendingOrder)) {
contentModel.sortModel(sortOrder)
}
}
}
Loader {
id: busyIndicatorLoader
anchors.centerIn: parent
height: Kirigami.Units.gridUnit * 5
width: height
ScrollView {
id: scrollView
readonly property int scrollBarWidth: ScrollBar.vertical.visible ? ScrollBar.vertical.width : 0
readonly property int availableSpace: scrollView.width - scrollView.scrollBarWidth
visible: realModel ? realModel.isBusy : true
active: realModel ? realModel.isBusy : true
Layout.fillHeight: true
Layout.fillWidth: true
Layout.leftMargin: Kirigami.Units.smallSpacing
sourceComponent: BusyIndicator {
anchors.centerIn: parent
// HACK: workaround for https://bugreports.qt.io/browse/QTBUG-83890
ScrollBar.horizontal.policy: ScrollBar.AlwaysOff
contentItem: GridView {
id: contentDirectoryView
activeFocusOnTab: true
keyNavigationEnabled: true
reuseItems: true
model: delegateModel
// HACK: setting currentIndex to -1 in mobile for some reason causes segfaults, no idea why
currentIndex: Kirigami.Settings.isMobile ? 0 : -1
Accessible.role: Accessible.List
Accessible.name: mainTitle
Kirigami.PlaceholderMessage {
anchors.centerIn: parent
width: parent.width - (Kirigami.Units.largeSpacing * 4)
visible: contentDirectoryView.count === 0 && !busyIndicatorLoader.active
text: i18n("Nothing to display")
}
cellWidth: {
let columns = Math.max(Math.floor(scrollView.availableSpace / elisaTheme.gridDelegateSize), 2);
return Math.floor(scrollView.availableSpace / columns);
}
cellHeight: {
if (Kirigami.Settings.isMobile) {
return cellWidth + Kirigami.Units.gridUnit * 2 + Kirigami.Units.largeSpacing;
} else {
return elisaTheme.gridDelegateSize + Kirigami.Units.gridUnit * 2 + Kirigami.Units.largeSpacing;
}
}
}
}
}
// Placeholder spinner while loading
Loader {
id: busyIndicatorLoader
anchors.centerIn: parent
height: Kirigami.Units.gridUnit * 5
width: height
visible: realModel ? realModel.isBusy : true
active: realModel ? realModel.isBusy : true
sourceComponent: BusyIndicator {
anchors.centerIn: parent
}
}
Connections {
target: ElisaApplication
......
/*
SPDX-FileCopyrightText: 2016 (c) Matthieu Gallien <matthieu_gallien@yahoo.fr>
SPDX-License-Identifier: LGPL-3.0-or-later
*/
import QtQuick 2.15
import QtQuick.Controls 2.2
import QtQuick.Window 2.2
import QtQml.Models 2.1
import QtQuick.Layouts 1.2
import QtGraphicalEffects 1.0
import org.kde.kirigami 2.12 as Kirigami
import org.kde.elisa 1.0
import "mobile"
FocusScope {
id: gridView
property bool isSubPage: false
property string mainTitle
property string secondaryTitle
property url image
property AbstractProxyModel contentModel
property alias showRating: navigationBar.showRating
property bool delegateDisplaySecondaryText: true
property alias expandedFilterView: navigationBar.expandedFilterView
property bool haveTreeModel: false
property alias sortRole: navigationBar.sortRole
property alias sortRoles: navigationBar.sortRoles
property alias sortRoleNames: navigationBar.sortRoleNames
property alias sortOrderNames: navigationBar.sortOrderNames
property alias sortOrder: navigationBar.sortOrder
property var stackView
property url defaultIcon
property int depth: 1
property alias viewManager: navigationBar.viewManager
property bool suppressNoDataPlaceholderMessage: false
signal enqueue(var fullData, string name)
signal replaceAndPlay(var fullData, string name)
signal open(var fullData)
signal goBackRequested()
function goToBack() {
if (haveTreeModel) {
delegateModel.rootIndex = delegateModel.parentModelIndex()
--depth
} else {
gridView.goBackRequested()
}
}
ColumnLayout {
anchors.fill: parent
spacing: 0
NavigationActionBar {
id: navigationBar
z: 1 // on top of track list
mainTitle: gridView.mainTitle
secondaryTitle: gridView.secondaryTitle
image: gridView.image
enableGoBack: gridView.isSubPage || depth > 1
Layout.fillWidth: true
Loader {
active: gridView.contentModel
sourceComponent: Binding {
target: gridView.contentModel
property: 'filterText'
when: gridView.contentModel
value: navigationBar.filterText
}
}
Loader {
active: gridView.contentModel
sourceComponent: Binding {
target: gridView.contentModel
property: 'filterRating'
when: gridView.contentModel
value: navigationBar.filterRating
}
}
Loader {
active: gridView.contentModel && navigationBar.enableSorting
sourceComponent: Binding {
target: gridView.contentModel
property: 'sortRole'
when: gridView.contentModel && navigationBar.enableSorting
value: navigationBar.sortRole
}
}
onEnqueue: contentModel.enqueueToPlayList(delegateModel.rootIndex)
onReplaceAndPlay:contentModel.replaceAndPlayOfPlayList(delegateModel.rootIndex)
onGoBack: {
gridView.goToBack()
}
onSortOrderChanged: {
if (!contentModel || !navigationBar.enableSorting) {
return
}
if ((contentModel.sortedAscending && sortOrder !== Qt.AscendingOrder) ||
(!contentModel.sortedAscending && sortOrder !== Qt.DescendingOrder)) {
contentModel.sortModel(sortOrder)
}
}
}
DelegateModel {
id: delegateModel
model: gridView.contentModel
delegate: GridBrowserDelegate {
width: Kirigami.Settings.isMobile ? contentDirectoryView.cellWidth : elisaTheme.gridDelegateSize
height: contentDirectoryView.cellHeight
focus: true
isSelected: contentDirectoryView.currentIndex === index
isPartial: false
mainText: model.display
fileUrl: model.url ? model.url : ""
secondaryText: gridView.delegateDisplaySecondaryText && model.secondaryText ? model.secondaryText : ""
imageUrl: model.imageUrl ? model.imageUrl : ''
imageFallbackUrl: defaultIcon
databaseId: model.databaseId
delegateDisplaySecondaryText: gridView.delegateDisplaySecondaryText
entryType: model.dataType
hasChildren: model.hasChildren
onEnqueue: gridView.enqueue(model.fullData, model.display)
onReplaceAndPlay: gridView.replaceAndPlay(model.fullData, model.display)
onOpen: {
if (haveTreeModel && !model.hasModelChildren) {
return
}
if (haveTreeModel) {
delegateModel.rootIndex = delegateModel.modelIndex(model.index)
++depth
} else {
gridView.open(model.fullData)
}
}
onSelected: {
forceActiveFocus()
contentDirectoryView.currentIndex = model.index
}
onActiveFocusChanged: {
if (activeFocus && contentDirectoryView.currentIndex !== model.index) {
contentDirectoryView.currentIndex = model.index
}
}
}
}
ScrollView {
id: scrollView
readonly property int scrollBarWidth: ScrollBar.vertical.visible ? ScrollBar.vertical.width : 0
readonly property int availableSpace: scrollView.width - scrollView.scrollBarWidth
Layout.fillHeight: true
Layout.fillWidth: true
Layout.leftMargin: Kirigami.Units.smallSpacing
// HACK: workaround for https://bugreports.qt.io/browse/QTBUG-83890
ScrollBar.horizontal.policy: ScrollBar.AlwaysOff
contentItem: GridView {
id: contentDirectoryView
activeFocusOnTab: true
keyNavigationEnabled: true
reuseItems: true
model: delegateModel
// HACK: setting currentIndex to -1 in mobile for some reason causes segfaults, no idea why
currentIndex: Kirigami.Settings.isMobile ? 0 : -1
Accessible.role: Accessible.List
Accessible.name: mainTitle
Kirigami.PlaceholderMessage {
anchors.centerIn: parent
width: parent.width - (Kirigami.Units.largeSpacing * 4)
visible: contentDirectoryView.count === 0 && !suppressNoDataPlaceholderMessage
text: i18n("Nothing to display")
}
cellWidth: {
let columns = Math.max(Math.floor(scrollView.availableSpace / elisaTheme.gridDelegateSize), 2);
return Math.floor(scrollView.availableSpace / columns);
}
cellHeight: {
if (Kirigami.Settings.isMobile) {
return cellWidth + Kirigami.Units.gridUnit * 2 + Kirigami.Units.largeSpacing;
} else {
return elisaTheme.gridDelegateSize + Kirigami.Units.gridUnit * 2 + Kirigami.Units.largeSpacing;
}
}
}
}
}
}
......@@ -15,7 +15,6 @@
<file>qml/LabelWithToolTip.qml</file>
<file>qml/TrackImportNotification.qml</file>
<file>qml/MediaTrackMetadataView.qml</file>
<file>qml/GridBrowserView.qml</file>
<file>qml/GridBrowserDelegate.qml</file>
<file>qml/ListBrowserView.qml</file>
<file>qml/ListBrowserDelegate.qml</file>
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment