diff --git a/applets/systemtray/package/contents/config/config.qml b/applets/systemtray/package/contents/config/config.qml --- a/applets/systemtray/package/contents/config/config.qml +++ b/applets/systemtray/package/contents/config/config.qml @@ -22,11 +22,6 @@ import org.kde.plasma.configuration 2.0 ConfigModel { - ConfigCategory { - name: i18n("General") - icon: "preferences-system-windows" - source: "ConfigGeneral.qml" - } ConfigCategory { name: i18n("Entries") icon: "preferences-desktop-notification" diff --git a/applets/systemtray/package/contents/ui/ConfigEntries.qml b/applets/systemtray/package/contents/ui/ConfigEntries.qml --- a/applets/systemtray/package/contents/ui/ConfigEntries.qml +++ b/applets/systemtray/package/contents/ui/ConfigEntries.qml @@ -1,6 +1,7 @@ /* * Copyright 2013 Sebastian Kügler * Copyright 2014 Marco Martin + * Copyright 2019 Konrad Materka * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -16,211 +17,319 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 2.010-1301, USA. */ - import QtQuick 2.5 -import QtQuick.Controls 1.4 as QQC1 import QtQuick.Controls 2.5 as QQC2 import QtQuick.Layouts 1.3 -import org.kde.plasma.core 2.0 as PlasmaCore +import org.kde.plasma.core 2.1 as PlasmaCore +import org.kde.plasma.components 3.0 as PlasmaComponents3 import org.kde.kquickcontrolsaddons 2.0 import org.kde.kquickcontrols 2.0 as KQC -import org.kde.kirigami 2.5 as Kirigami +import org.kde.kirigami 2.10 as Kirigami ColumnLayout { id: iconsPage signal configurationChanged + property bool cfg_applicationStatusShown + property bool cfg_communicationsShown + property bool cfg_systemServicesShown + property bool cfg_hardwareControlShown + property bool cfg_miscellaneousShown property var cfg_shownItems: [] property var cfg_hiddenItems: [] + property var cfg_extraItems: [] property alias cfg_showAllItems: showAllCheckBox.checked - PlasmaCore.SortFilterModel { - id: systemTrayModel - sourceModel: plasmoid.nativeInterface.systemTrayModel + QQC2.ComboBox { + id: comboboxMeasure + visible: false + implicitWidth: Math.round(units.gridUnit * 6.5) // ComboBox sizing is broken + } + KQC.KeySequenceItem { + id: keyMeasure + visible: false } - Kirigami.FormLayout { - - QQC2.CheckBox { - id: showAllCheckBox - text: i18n("Always show all entries") - } - - QQC2.Button { // just for measurement - id: measureButton - text: "measureButton" - visible: false - } + QQC2.CheckBox { + id: showAllCheckBox + text: i18n("Always show all entries") + } - // resizeToContents does not take into account the heading - QQC2.Label { - id: shortcutColumnMeasureLabel - text: shortcutColumn.title - visible: false + function categoryName(category) { + switch (category) { + case "ApplicationStatus": + return i18n("Application Status") + case "Communications": + return i18n("Communications") + case "SystemServices": + return i18n("System Services") + case "Hardware": + return i18n("Hardware Control") + case "UnknownCategory": + default: + return i18n("Miscellaneous") } } - // convert to QtObjects compatible with TableView - function retrieveAllItems() { - var list = []; - for (var i = 0; i < systemTrayModel.count; i++) { - var item = systemTrayModel.get(i); - if (item.itemType === "Plasmoid" && !item.hasApplet) { - continue; - } - list.push({ - "taskId": item.itemId, - "name": item.display, - "icon": item.decoration, - "applet": item.applet - }); + function categoryShown(category) { + switch (category) { + case "ApplicationStatus": + return cfg_applicationStatusShown + case "Communications": + return cfg_communicationsShown + case "SystemServices": + return cfg_systemServicesShown + case "Hardware": + return cfg_hardwareControlShown + case "UnknownCategory": + return cfg_miscellaneousShown + default: + return false } - list.sort(function(a, b) { - return a.name.localeCompare(b.name); - }); - return list; } - // There is no QQC2 version of TableView yet - QQC1.TableView { - id: tableView + QQC2.ScrollView { + id: scrollView + Layout.fillWidth: true Layout.fillHeight: true + contentHeight: itemsList.implicitHeight - model: retrieveAllItems() - horizontalScrollBarPolicy: Qt.ScrollBarAlwaysOff - flickableItem.boundsBehavior: Flickable.StopAtBounds - - Component.onCompleted: { - visibilityColumn.resizeToContents() - shortcutColumn.resizeToContents() - } - - // Taken from QtQuickControls BasicTableViewStyle, just to make its height sensible... - rowDelegate: BorderImage { - visible: styleData.selected || styleData.alternate - source: "image://__tablerow/" + (styleData.alternate ? "alternate_" : "") - + (tableView.activeFocus ? "active" : "") - height: measureButton.height - border.left: 4 ; border.right: 4 - } + ListView { + id: itemsList + Layout.fillWidth: true + Layout.fillHeight: true - QQC1.TableViewColumn { - id: entryColumn - width: tableView.viewport.width - visibilityColumn.width - shortcutColumn.width - title: i18nc("Name of the system tray entry", "Entry") - movable: false - resizable: false - - delegate: RowLayout { - Item { // spacer - Layout.preferredWidth: 1 - Layout.fillHeight: true - } + model: PlasmaCore.SortFilterModel { + sourceModel: PlasmaCore.SortFilterModel { + sourceModel: plasmoid.nativeInterface.systemTrayModel - QIconItem { - width: units.iconSizes.small - height: width - icon: modelData.icon + sortRole: "display" + sortColumn: 0 + isSortLocaleAware: true } - QQC2.Label { - Layout.fillWidth: true - text: modelData.name - elide: Text.ElideRight - wrapMode: Text.NoWrap - } + sortRole: "category" + sortColumn: 0 + isSortLocaleAware: true } - } - QQC1.TableViewColumn { - id: visibilityColumn - title: i18n("Visibility") - movable: false - resizable: false - - delegate: QQC2.ComboBox { - implicitWidth: Math.round(units.gridUnit * 6.5) // ComboBox sizing is broken - - enabled: !showAllCheckBox.checked - currentIndex: { - if (cfg_shownItems.indexOf(modelData.taskId) != -1) { - return 1; - } else if (cfg_hiddenItems.indexOf(modelData.taskId) != -1) { - return 2; - } else { - return 0; + header: Kirigami.AbstractListItem { + + leftPadding: LayoutMirroring.enabled && scrollView.QQC2.ScrollBar.vertical && scrollView.QQC2.ScrollBar.vertical.visible ? scrollView.QQC2.ScrollBar.vertical.width : padding*2 + rightPadding: !LayoutMirroring.enabled && scrollView.QQC2.ScrollBar.vertical && scrollView.QQC2.ScrollBar.vertical.visible ? scrollView.QQC2.ScrollBar.vertical.width : padding*2 + + hoverEnabled: false + + RowLayout { + Kirigami.Heading { + text: i18nc("Name of the system tray entry", "Entry") + level: 2 + Layout.fillWidth: true + } + Kirigami.Heading { + text: i18n("Visibility") + level: 2 + Layout.preferredWidth: comboboxMeasure.implicitWidth + } + Kirigami.Heading { + text: i18n("Keyboard Shortcut") + level: 2 + Layout.preferredWidth: keyMeasure.width } } + } - // activated, in contrast to currentIndexChanged, only fires if the user himself changed the value - onActivated: { - var shownIndex = cfg_shownItems.indexOf(modelData.taskId); - var hiddenIndex = cfg_hiddenItems.indexOf(modelData.taskId); + section { + property: "category" + delegate: Kirigami.ListSectionHeader { + label: categoryName(section) - switch (index) { - case 0: { - if (shownIndex > -1) { - cfg_shownItems.splice(shownIndex, 1); - } - if (hiddenIndex > -1) { - cfg_hiddenItems.splice(hiddenIndex, 1); - } - break; - } - case 1: { - if (shownIndex === -1) { - cfg_shownItems.push(modelData.taskId); - } - if (hiddenIndex > -1) { - cfg_hiddenItems.splice(hiddenIndex, 1); + leftPadding: LayoutMirroring.enabled && scrollView.QQC2.ScrollBar.vertical && scrollView.QQC2.ScrollBar.vertical.visible ? scrollView.QQC2.ScrollBar.vertical.width : padding*2 + rightPadding: !LayoutMirroring.enabled && scrollView.QQC2.ScrollBar.vertical && scrollView.QQC2.ScrollBar.vertical.visible ? scrollView.QQC2.ScrollBar.vertical.width : padding*2 + + PlasmaComponents3.ToolButton { + Layout.alignment: LayoutMirroring.enabled ? Qt.AlignLeft : Qt.AlignRight + + text: i18n("Shown") + icon.name: categoryShown(section) ? "starred-symbolic" : "non-starred-symbolic" + checkable: true + checked: categoryShown(section) + onClicked: function() { + switch (section) { + case "ApplicationStatus": + cfg_applicationStatusShown = checked + break + case "Communications": + cfg_communicationsShown = checked + break + case "SystemServices": + cfg_systemServicesShown = checked + break + case "Hardware": + cfg_hardwareControlShown = checked + break + case "UnknownCategory": + default: + cfg_miscellaneousShown = checked + break + } } - break; } - case 2: { - if (shownIndex > -1) { - cfg_shownItems.splice(shownIndex, 1); + } + } + + delegate: Kirigami.AbstractListItem { + leftPadding: LayoutMirroring.enabled && scrollView.QQC2.ScrollBar.vertical && scrollView.QQC2.ScrollBar.vertical.visible ? scrollView.QQC2.ScrollBar.vertical.width : padding*2 + rightPadding: !LayoutMirroring.enabled && scrollView.QQC2.ScrollBar.vertical && scrollView.QQC2.ScrollBar.vertical.visible ? scrollView.QQC2.ScrollBar.vertical.width : padding*2 + highlighted: false + hoverEnabled: false + backgroundColor: Kirigami.Theme.backgroundColor + + property bool isPlasmoid: itemType === "Plasmoid" + + contentItem: RowLayout { + RowLayout { + Layout.fillWidth: true + + QIconItem { + width: units.iconSizes.small + height: width + icon: model.decoration } - if (hiddenIndex === -1) { - cfg_hiddenItems.push(modelData.taskId); + QQC2.Label { + Layout.fillWidth: true + + text: display + elide: Text.ElideRight + wrapMode: Text.NoWrap } - break; - } } - iconsPage.configurationChanged(); - } - model: [i18n("Auto"), i18n("Shown"), i18n("Hidden")] - } - } - QQC1.TableViewColumn { - id: shortcutColumn - title: i18n("Keyboard Shortcut") // FIXME doesn't fit - movable: false - resizable: false + QQC2.ComboBox { + implicitWidth: comboboxMeasure.implicitWidth + enabled: (!showAllCheckBox.checked || isPlasmoid) && itemId && categoryShown(category) - // this Item wrapper prevents TableView from ripping apart the two KeySequenceItem buttons - delegate: Item { - implicitWidth: Math.max(shortcutColumnMeasureLabel.width, keySequenceItem.width) + 10 - height: keySequenceItem.height + textRole: "text" + model: comboBoxModel(category) - KQC.KeySequenceItem { - id: keySequenceItem - anchors.right: parent.right + currentIndex: { + var value - keySequence: modelData.applet ? modelData.applet.globalShortcut : "" - // only Plasmoids have that - visible: modelData.hasOwnProperty("applet") - onKeySequenceChanged: { - if (modelData.applet && keySequence !== modelData.applet.globalShortcut) { - modelData.applet.globalShortcut = keySequence + if (!categoryShown(category)) { + value = "disabled" + } else if (cfg_shownItems.indexOf(itemId) !== -1) { + value = "shown" + } else if (cfg_hiddenItems.indexOf(itemId) !== -1) { + value = "hidden" + } else if (isPlasmoid && cfg_extraItems.indexOf(itemId) === -1) { + value = "disabled" + } else { + value = "auto" + } + for (var i = 0; i < model.length; i++) { + if (model[i].value === value) { + return i + } + } + + return 0; + } + + onActivated: { + var shownIndex = cfg_shownItems.indexOf(itemId) + var hiddenIndex = cfg_hiddenItems.indexOf(itemId) + var extraIndex = cfg_extraItems.indexOf(itemId) + + var currentValue = model[index].value + + switch (currentValue) { + case "auto": + if (shownIndex > -1) { + cfg_shownItems.splice(shownIndex, 1) + } + if (hiddenIndex > -1) { + cfg_hiddenItems.splice(hiddenIndex, 1) + } + if (extraIndex === -1) { + cfg_extraItems.push(itemId) + } + break + case "shown": + if (shownIndex === -1) { + cfg_shownItems.push(itemId) + } + if (hiddenIndex > -1) { + cfg_hiddenItems.splice(hiddenIndex, 1) + } + if (extraIndex === -1) { + cfg_extraItems.push(itemId) + } + break + case "hidden": + if (shownIndex > -1) { + cfg_shownItems.splice(shownIndex, 1) + } + if (hiddenIndex === -1) { + cfg_hiddenItems.push(itemId) + } + if (extraIndex === -1) { + cfg_extraItems.push(itemId) + } + break + case "disabled": + if (extraIndex > -1) { + cfg_extraItems.splice(extraIndex, 1) + } + break + } iconsPage.configurationChanged() } - shortcutColumn.resizeToContents() + function comboBoxModel(category) { + var autoElement = {value: "auto", text: i18n("Auto")} + var shownElement = {value: "shown", text: i18n("Shown")} + var hiddenElement = {value: "hidden", text: i18n("Hidden")} + var disabledElement = {value: "disabled", text: i18n("Disabled")} + + if (!categoryShown(category)) { + return [disabledElement] + } + + if (showAllCheckBox.checked) { + if (isPlasmoid) { + return [autoElement, disabledElement] + } else { + return [shownElement] + } + } else { + if (isPlasmoid) { + return [autoElement, shownElement, hiddenElement, disabledElement] + } else { + return [autoElement, shownElement, hiddenElement] + } + } + } + } + KQC.KeySequenceItem { + id: keySequenceItem + visible: isPlasmoid + keySequence: model.applet ? model.applet.globalShortcut : "" + onKeySequenceChanged: { + if (model.applet && keySequence !== model.applet.globalShortcut) { + model.applet.globalShortcut = keySequence + + iconsPage.configurationChanged() + } + } + } + // Placeholder for when KeySequenceItem is not visible + Item { + Layout.preferredWidth: keyMeasure.width + visible: !keySequenceItem.visible } } } diff --git a/applets/systemtray/package/contents/ui/ConfigGeneral.qml b/applets/systemtray/package/contents/ui/ConfigGeneral.qml deleted file mode 100644 --- a/applets/systemtray/package/contents/ui/ConfigGeneral.qml +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright 2013 Sebastian Kügler - * Copyright 2014 Marco Martin - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 2.010-1301, USA. - */ - -import QtQuick 2.0 -import QtQuick.Controls 2.3 as QtControls -import QtQuick.Layouts 1.0 as QtLayouts - -import org.kde.kquickcontrolsaddons 2.0 -import org.kde.kirigami 2.5 as Kirigami - -Item { - id: iconsPage - - signal configurationChanged - - width: childrenRect.width - height: childrenRect.height - implicitWidth: mainColumn.implicitWidth - implicitHeight: pageColumn.implicitHeight - - property alias cfg_applicationStatusShown: applicationStatus.checked - property alias cfg_communicationsShown: communications.checked - property alias cfg_systemServicesShown: systemServices.checked - property alias cfg_hardwareControlShown: hardwareControl.checked - property alias cfg_miscellaneousShown: miscellaneous.checked - property var cfg_extraItems: [] - - QtControls.CheckBox { - id: dummyCheckbox - visible: false - } - - Kirigami.FormLayout { - id: pageColumn - anchors { - left: parent.left - right: parent.right - } - - Item { - Kirigami.FormData.isSection: true - Kirigami.FormData.label: i18n("Categories") - } - - QtControls.CheckBox { - id: applicationStatus - text: i18n("Application Status") - } - QtControls.CheckBox { - id: communications - text: i18n("Communications") - } - QtControls.CheckBox { - id: systemServices - text: i18n("System Services") - } - QtControls.CheckBox { - id: hardwareControl - text: i18n("Hardware Control") - } - QtControls.CheckBox { - id: miscellaneous - text: i18n("Miscellaneous") - } - - - Item { - Kirigami.FormData.isSection: true - Kirigami.FormData.label: i18n("Extra Items") - } - - Repeater { - model: plasmoid.nativeInterface.availablePlasmoids - delegate: QtControls.CheckBox { - QtLayouts.Layout.minimumWidth: childrenRect.width - checked: cfg_extraItems.indexOf(itemId) != -1 - implicitWidth: itemLayout.width + itemLayout.x - onCheckedChanged: { - var index = cfg_extraItems.indexOf(itemId); - if (checked) { - if (index === -1) { - cfg_extraItems.push(itemId); - } - } else { - if (index > -1) { - cfg_extraItems.splice(index, 1); - } - } - configurationChanged() // qml cannot detect changes inside an Array - } - QtLayouts.RowLayout { - id: itemLayout - anchors.verticalCenter: parent.verticalCenter - x: dummyCheckbox.width - QIconItem { - icon: model.decoration - width: Kirigami.Units.iconSizes.small - height: width - } - QtControls.Label { - text: model.display - } - } - } - } - } -} diff --git a/applets/systemtray/systemtray.cpp b/applets/systemtray/systemtray.cpp --- a/applets/systemtray/systemtray.cpp +++ b/applets/systemtray/systemtray.cpp @@ -21,18 +21,15 @@ #include "systemtraymodel.h" #include "debug.h" -#include -#include - #include #include #include #include #include +#include #include #include -#include -#include +#include #include #include diff --git a/applets/systemtray/systemtraymodel.h b/applets/systemtray/systemtraymodel.h --- a/applets/systemtray/systemtraymodel.h +++ b/applets/systemtray/systemtraymodel.h @@ -34,6 +34,7 @@ ItemType = Qt::UserRole + 1, ItemId, CanRender, + Category, LastBaseRole }; diff --git a/applets/systemtray/systemtraymodel.cpp b/applets/systemtray/systemtraymodel.cpp --- a/applets/systemtray/systemtraymodel.cpp +++ b/applets/systemtray/systemtraymodel.cpp @@ -45,8 +45,9 @@ } QStandardItem *item = new QStandardItem(QIcon::fromTheme(info.iconName()), name); item->setData(info.pluginId(), static_cast(BaseRole::ItemId)); - item->setData("Plasmoid", static_cast(BaseRole::ItemType)); + item->setData(QStringLiteral("Plasmoid"), static_cast(BaseRole::ItemType)); item->setData(false, static_cast(BaseRole::CanRender)); + item->setData(QStringLiteral("UnknownCategory"), static_cast(BaseRole::Category)); item->setData(false, static_cast(Role::HasApplet)); appendRow(item); } @@ -60,6 +61,7 @@ roles.insert(static_cast(BaseRole::ItemType), QByteArrayLiteral("itemType")); roles.insert(static_cast(BaseRole::ItemId), QByteArrayLiteral("itemId")); roles.insert(static_cast(BaseRole::CanRender), QByteArrayLiteral("canRender")); + roles.insert(static_cast(BaseRole::Category), QByteArrayLiteral("category")); roles.insert(static_cast(Role::Applet), QByteArrayLiteral("applet")); roles.insert(static_cast(Role::HasApplet), QByteArrayLiteral("hasApplet")); @@ -88,6 +90,17 @@ dataItem->setData(applet->property("_plasma_graphicObject"), static_cast(Role::Applet)); dataItem->setData(true, static_cast(Role::HasApplet)); dataItem->setData(true, static_cast(BaseRole::CanRender)); + + if (applet->pluginMetaData().isValid()) { + const QString category = applet->pluginMetaData().value(QStringLiteral("X-Plasma-NotificationAreaCategory")); + if (category.isEmpty()) { + dataItem->setData(QStringLiteral("UnknownCategory"), static_cast(BaseRole::Category)); + } else { + dataItem->setData(category, static_cast(BaseRole::Category)); + } + } else { + dataItem->setData(QStringLiteral("UnknownCategory"), static_cast(BaseRole::Category)); + } } void PlasmoidModel::removeApplet(Plasma::Applet *applet) @@ -122,6 +135,7 @@ roles.insert(static_cast(BaseRole::ItemType), QByteArrayLiteral("itemType")); roles.insert(static_cast(BaseRole::ItemId), QByteArrayLiteral("itemId")); roles.insert(static_cast(BaseRole::CanRender), QByteArrayLiteral("canRender")); + roles.insert(static_cast(BaseRole::Category), QByteArrayLiteral("category")); roles.insert(static_cast(Role::DataEngineSource), QByteArrayLiteral("DataEngineSource")); roles.insert(static_cast(Role::AttentionIcon), QByteArrayLiteral("AttentionIcon")); @@ -189,7 +203,7 @@ dataItem = item(m_sources.indexOf(sourceName)); } else { dataItem = new QStandardItem(); - dataItem->setData("StatusNotifier", static_cast(BaseRole::ItemType)); + dataItem->setData(QStringLiteral("StatusNotifier"), static_cast(BaseRole::ItemType)); dataItem->setData(true, static_cast(BaseRole::CanRender)); } @@ -202,6 +216,7 @@ } dataItem->setData(data.value("Id"), static_cast(BaseRole::ItemId)); + dataItem->setData(data.value("Category"), static_cast(BaseRole::Category)); dataItem->setData(sourceName, static_cast(Role::DataEngineSource)); updateItemData(dataItem, data, Role::AttentionIcon);