diff --git a/applets/systemtray/package/contents/config/main.xml b/applets/systemtray/package/contents/config/main.xml
--- a/applets/systemtray/package/contents/config/main.xml
+++ b/applets/systemtray/package/contents/config/main.xml
@@ -39,6 +39,10 @@
+
+
+ org.kde.plasma.notifications
+
false
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
@@ -34,8 +34,18 @@
property var cfg_shownItems: []
property var cfg_hiddenItems: []
+ property var cfg_itemOrder: []
property alias cfg_showAllItems: showAllCheckBox.checked
+ property var itemInfo
+
+ onConfigurationChanged: {
+ // trigger updates of dependent properties
+ tableView.modelChanged()
+ cfg_shownItems = cfg_shownItems
+ cfg_hiddenItems = cfg_hiddenItems
+ }
+
columns: 2 // so we can indent the entries below...
function saveConfig () {
@@ -65,183 +75,257 @@
visible: false
}
- function retrieveAllItems() {
- print(plasmoid)
- print(plasmoid.rootItem.statusNotifierModel)
- var list = [];
- for (var i = 0; i < plasmoid.rootItem.statusNotifierModel.count; ++i) {
+ function arrayTryRemove(arr, item) {
+ var i = arr.indexOf(item)
+ if (i !== -1) {
+ arr.splice(i, 1)
+ }
+ }
+
+ function arrayTryAdd(arr, item) {
+ var i = arr.indexOf(item)
+ if (i === -1) {
+ arr.push(item)
+ }
+ }
+
+ function moveItem(from, to) {
+ var tmp = cfg_itemOrder.splice(from, 1)
+ cfg_itemOrder.splice(to, 0, tmp[0])
+ }
+
+ function retrieveItemInfo() {
+ // print(plasmoid)
+ // print(plasmoid.rootItem.statusNotifierModel)
+ print(cfg_itemOrder)
+
+ var itemInfo = {}
+
+ for (var i = 0; i < cfg_itemOrder.length; ++i) {
+ var itemId = cfg_itemOrder[i]
+ itemInfo[itemId] = {
+ "taskId": itemId,
+ "name": itemId,
+ "inactive": true
+ }
+ }
+
+ /*for (var i = 0; i < plasmoid.rootItem.statusNotifierModel.count; ++i) {
var item = plasmoid.rootItem.statusNotifierModel.get(i);
- list.push({
- "index": i,
+ itemInfo[item.Id] = {
"taskId": item.Id,
"name": item.Title,
"iconName": item.IconName,
- "icon": item.Icon
- });
- }
- var lastIndex = list.length;
+ "icon": item.Icon,
+ "inactive": false
+ }
+ }*/
+
for (var i = 0; i < plasmoid.applets.length; ++i) {
var item = plasmoid.applets[i]
- list.push({
- "index": (i + lastIndex),
+ itemInfo[item.pluginName] = {
+ "index": i,
"applet": item,
"taskId": item.pluginName,
"name": item.title,
"iconName": item.icon,
- "shortcut": item.globalShortcut
- });
+ "shortcut": item.globalShortcut,
+ "inactive": false
+ }
}
- list.sort(function(a, b) {
- return a.name.localeCompare(b.name);
- });
- return list;
+
+ iconsPage.itemInfo = itemInfo
+ }
+
+ Component.onCompleted: {
+ retrieveItemInfo()
+ configurationChanged()
}
- QtControls.TableView {
- id: tableView
+ Item {
+ id: dragArea
+ property var dragAxis: Drag.XandYAxis
+ property bool dragActive: false
+
QtLayouts.Layout.fillWidth: true
QtLayouts.Layout.fillHeight: true
- QtLayouts.Layout.row: 2
- QtLayouts.Layout.column: 1
+ QtLayouts.Layout.columnSpan: iconsPage.columns
- model: retrieveAllItems()
- horizontalScrollBarPolicy: Qt.ScrollBarAlwaysOff
- flickableItem.boundsBehavior: Flickable.StopAtBounds
+ QtControls.TableView {
+ id: tableView
+ anchors.fill: parent
- Component.onCompleted: {
- visibilityColumn.resizeToContents()
- shortcutColumn.resizeToContents()
- }
+ model: cfg_itemOrder
+ horizontalScrollBarPolicy: Qt.ScrollBarAlwaysOff
+ flickableItem.boundsBehavior: Flickable.StopAtBounds
- // 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
- }
+ Component.onCompleted: {
+ visibilityColumn.resizeToContents()
+ shortcutColumn.resizeToContents()
+ }
- QtControls.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: QtLayouts.RowLayout {
- Item { // spacer
- QtLayouts.Layout.preferredWidth: 1
- QtLayouts.Layout.fillHeight: true
- }
+ // 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
+ }
- QIconItem {
- width: units.iconSizes.small
- height: width
- icon: modelData.iconName || modelData.icon || ""
- }
+ QtControls.TableViewColumn {
+ id: entryColumn
+ width: tableView.viewport.width - visibilityColumn.width - shortcutColumn.width
+ title: i18nc("Name of the system tray entry", "Entry")
+ movable: false
+ resizable: false
- QtControls.Label {
+ delegate: OrderableItem {
+ dragParent: dragArea
+ onMoveItemRequested: {
+ if (to == -1) { // delete item
+ arrayTryRemove(cfg_itemOrder, modelData)
+ arrayTryRemove(cfg_shownItems, modelData)
+ arrayTryRemove(cfg_hiddenItems, modelData)
+ } else {
+ moveItem(from, to)
+ }
+ iconsPage.configurationChanged();
+ }
+ property var item: iconsPage.itemInfo[modelData]
QtLayouts.Layout.fillWidth: true
- text: modelData.name
- elide: Text.ElideRight
- wrapMode: Text.NoWrap
+
+ QtLayouts.RowLayout {
+ Item { // spacer
+ QtLayouts.Layout.preferredWidth: 1
+ QtLayouts.Layout.fillHeight: true
+ }
+
+ QIconItem {
+ width: units.iconSizes.small
+ height: width
+ icon: item.iconName || item.icon || ""
+ }
+
+ QtControls.Label {
+ text: item.name
+ elide: Text.ElideRight
+ wrapMode: Text.NoWrap
+ font.italic: !!item.inactive
+ }
+ }
}
}
- }
- QtControls.TableViewColumn {
- id: visibilityColumn
- title: i18n("Visibility")
- movable: false
- resizable: false
-
- delegate: QtControls.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;
+ QtControls.TableViewColumn {
+ id: visibilityColumn
+ title: i18n("Visibility")
+ movable: false
+ resizable: false
+
+ delegate: QtControls.ComboBox {
+ QtLayouts.Layout.leftMargin: 30
+ QtControls.Label {
+ text: (cfg_shownItems.indexOf(modelData) != -1 ? "S" : "") +
+ (cfg_hiddenItems.indexOf(modelData) != -1 ? "H" : "")
+ wrapMode: Text.NoWrap
}
- }
- // 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);
+ implicitWidth: Math.round(units.gridUnit * 6.5) // ComboBox sizing is broken
- switch (index) {
- case 0: {
- if (shownIndex > -1) {
- cfg_shownItems.splice(shownIndex, 1);
- }
- if (hiddenIndex > -1) {
- cfg_hiddenItems.splice(hiddenIndex, 1);
+ enabled: !showAllCheckBox.checked
+
+ currentIndex: {
+ if (cfg_shownItems.indexOf(modelData) != -1) {
+ return 1
+ } else if (cfg_hiddenItems.indexOf(modelData) != -1) {
+ return 2
+ } else {
+ return 0
}
- break;
}
- case 1: {
- if (shownIndex == -1) {
- cfg_shownItems.push(modelData.taskId);
+
+ // activated, in contrast to currentIndexChanged, only fires if the user himself changed the value
+ onActivated: {
+ if (index == 1) {
+ arrayTryAdd(cfg_shownItems, modelData)
+ } else {
+ arrayTryRemove(cfg_shownItems, modelData);
}
- if (hiddenIndex > -1) {
- cfg_hiddenItems.splice(hiddenIndex, 1);
+
+ if (index == 2) {
+ arrayTryAdd(cfg_hiddenItems, modelData)
+ } else {
+ arrayTryRemove(cfg_hiddenItems, modelData);
}
- break;
+
+ iconsPage.configurationChanged();
}
- case 2: {
- if (shownIndex > -1) {
- cfg_shownItems.splice(shownIndex, 1);
- }
- if (hiddenIndex == -1) {
- cfg_hiddenItems.push(modelData.taskId);
+ model: [i18n("Auto"), i18n("Shown"), i18n("Hidden")]
+ }
+ }
+
+ QtControls.TableViewColumn {
+ id: shortcutColumn
+ title: i18n("Keyboard Shortcut") // FIXME doesn't fit
+ movable: false
+ resizable: false
+
+ // this Item wrapper prevents TableView from ripping apart the two KeySequenceItem buttons
+ delegate: Item {
+ property var item: iconsPage.itemInfo[modelData]
+
+ implicitWidth: Math.max(shortcutColumnMeasureLabel.width, keySequenceItem.width) + 10
+ height: keySequenceItem.height
+
+ KQC.KeySequenceItem {
+ id: keySequenceItem
+ anchors.right: parent.right
+
+ keySequence: item.shortcut
+ // only Plasmoids have that
+ visible: item.hasOwnProperty("shortcut")
+ onKeySequenceChanged: {
+ if (keySequence && keySequence != item.shortcut) {
+ // both SNIs and plasmoids are listed in the same TableView
+ // but they come from two separate models, so we need to subtract
+ // the SNI model count to get the actual plasmoid index
+ var index = item.index
+ plasmoid.applets[index].globalShortcut = keySequence
+
+ iconsPage.configurationChanged()
+ }
+
+ shortcutColumn.resizeToContents()
}
- break;
- }
}
- iconsPage.configurationChanged();
}
- model: [i18n("Auto"), i18n("Shown"), i18n("Hidden")]
}
}
- QtControls.TableViewColumn {
- id: shortcutColumn
- title: i18n("Keyboard Shortcut") // FIXME doesn't fit
- movable: false
- resizable: false
-
- // 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
-
- KQC.KeySequenceItem {
- id: keySequenceItem
- anchors.right: parent.right
-
- keySequence: modelData.shortcut
- // only Plasmoids have that
- visible: modelData.hasOwnProperty("shortcut")
- onKeySequenceChanged: {
- if (keySequence != modelData.shortcut) {
- // both SNIs and plasmoids are listed in the same TableView
- // but they come from two separate models, so we need to subtract
- // the SNI model count to get the actual plasmoid index
- var index = modelData.index - plasmoid.rootItem.statusNotifierModel.count
- plasmoid.applets[index].globalShortcut = keySequence
-
- iconsPage.configurationChanged()
- }
+ OrderableItem {
+ id: discardTarget
+ dropIndex: -1
+ draggable: false
+ visible: dragArea.dragActive
- shortcutColumn.resizeToContents()
- }
- }
+ anchors.bottom: parent.bottom
+ anchors.left: parent.left
+ anchors.bottomMargin: Math.round(units.gridUnit * 0.5)
+ anchors.leftMargin: Math.round(units.gridUnit * 0.5)
+ width: Math.round(units.gridUnit * 2.5)
+ height: width
+
+ Rectangle {
+ color: "black"
+ opacity: 0.7
+ anchors.fill: parent
+ }
+
+ QIconItem {
+ anchors.fill: parent
+ anchors.margins: Math.round(units.gridUnit * 0.2)
+ icon: "trash-empty"
}
}
}
diff --git a/applets/systemtray/package/contents/ui/OrderableItem.qml b/applets/systemtray/package/contents/ui/OrderableItem.qml
new file mode 100644
--- /dev/null
+++ b/applets/systemtray/package/contents/ui/OrderableItem.qml
@@ -0,0 +1,106 @@
+import QtQuick 2.0
+import QtQuick.Layouts 1.1
+
+Item {
+ id: root
+
+ default property Item contentItem
+
+ property int dropIndex: model.index
+ property bool draggable: true
+
+ // This item will become the parent of the dragged item during the drag operation
+ property Item dragParent
+
+ signal moveItemRequested(int from, int to)
+
+ Layout.preferredWidth: contentItem.width
+ Layout.preferredHeight: contentItem.height
+
+ // Make contentItem a child of contentItemWrapper
+ onContentItemChanged: {
+ contentItem.parent = contentItemWrapper;
+ }
+
+ Item {
+ id: contentItemWrapper
+ anchors.fill: parent
+ Drag.active: dragArea.drag.active
+ Drag.hotSpot {
+ x: dragArea.mouseX
+ y: dragArea.mouseY
+ }
+
+ MouseArea {
+ id: dragArea
+ visible: root.draggable
+ anchors.fill: parent
+ drag.target: parent
+ // Keep the dragged item at the same X position. Nice for lists, but not mandatory
+ drag.axis: dragParent.dragAxis
+ // Disable smoothed so that the Item pixel from where we started the drag remains
+ // under the mouse cursor
+ drag.smoothed: false
+
+ cursorShape: Qt.OpenHandCursor
+
+ onReleased: {
+ if (drag.active) {
+ emitMoveItemRequested();
+ }
+ }
+ }
+ }
+
+ states: [
+ State {
+ when: dragArea.drag.active
+ name: 'dragging'
+
+ ParentChange {
+ target: contentItemWrapper
+ parent: dragParent
+ }
+ PropertyChanges {
+ target: contentItemWrapper
+ opacity: 0.9
+ anchors.fill: undefined
+ width: contentItem.width
+ height: contentItem.height
+ }
+ PropertyChanges {
+ target: dragParent
+ dragActive: true
+ }
+ }
+ ]
+
+ DropArea {
+ id: itemDropArea
+ anchors.fill: parent
+
+ property alias dropIndex: root.dropIndex
+
+ Rectangle {
+ id: dropIndicator
+ anchors.fill: parent
+ border.width: 1
+ border.color: theme.highlightColor
+ color: 'transparent'
+ opacity: itemDropArea.containsDrag ? 1 : 0
+ }
+ }
+
+ function emitMoveItemRequested() {
+ var dropArea = contentItemWrapper.Drag.target;
+ if (!dropArea) {
+ return;
+ }
+ var dropIndex = dropArea.dropIndex;
+
+ if (model.index === dropIndex) {
+ return;
+ }
+ root.moveItemRequested(model.index, dropIndex);
+ }
+}
diff --git a/applets/systemtray/package/contents/ui/items/AbstractItem.qml b/applets/systemtray/package/contents/ui/items/AbstractItem.qml
--- a/applets/systemtray/package/contents/ui/items/AbstractItem.qml
+++ b/applets/systemtray/package/contents/ui/items/AbstractItem.qml
@@ -57,6 +57,18 @@
}
}
+ property int position: {
+ var pos = plasmoid.configuration.itemOrder.indexOf(itemId)
+ if (pos === -1 && !!itemId) {
+ // yes we must use temp variable otherwise push() does nothing
+ var tmp = plasmoid.configuration.itemOrder
+ tmp.push(itemId)
+ plasmoid.configuration.itemOrder = tmp
+ pos = plasmoid.configuration.itemOrder.indexOf(itemId)
+ }
+ return pos
+ }
+
/* subclasses need to assign to this tiiltip properties
mainText:
subText:
@@ -77,18 +89,22 @@
//BEGIN CONNECTIONS
- onEffectiveStatusChanged: updateItemVisibility(abstractItem);
+ function updateVisibility() {
+ updateItemVisibility(abstractItem)
+ }
+
+ onEffectiveStatusChanged: Qt.callLater(updateVisibility)
+
+ onPositionChanged: Qt.callLater(updateVisibility)
onContainsMouseChanged: {
if (hidden && containsMouse) {
root.hiddenLayout.hoveredItem = abstractItem
}
}
- Component.onCompleted: updateItemVisibility(abstractItem);
-
//dangerous but needed due how repeater reparents
- onParentChanged: updateItemVisibility(abstractItem);
+ onParentChanged: Qt.callLater(updateVisibility)
//END CONNECTIONS
diff --git a/applets/systemtray/package/contents/ui/main.qml b/applets/systemtray/package/contents/ui/main.qml
--- a/applets/systemtray/package/contents/ui/main.qml
+++ b/applets/systemtray/package/contents/ui/main.qml
@@ -58,39 +58,48 @@
}
}
+ function getFixedItemId(itemId, context) {
+ return itemId;
+ }
+
+ function reorderItem(item, container) {
+ if (container.children.length == 0) {
+ item.parent = container;
+ } else {
+ var i = 0;
+ while (i < container.children.length &&
+ container.children[i].position < item.position) {
+ i++
+ }
+
+ if (i == container.children.length) {
+ var other = container.children[i - 1]
+ if (item != other) {
+ plasmoid.nativeInterface.reorderItemAfter(item, other)
+ }
+ } else {
+ var other = container.children[i]
+ if (item != other) {
+ plasmoid.nativeInterface.reorderItemBefore(item, other)
+ }
+ }
+ }
+ }
+
function updateItemVisibility(item) {
switch (item.effectiveStatus) {
case PlasmaCore.Types.HiddenStatus:
- if (item.parent == invisibleEntriesContainer) {
- return;
+ if (item.parent != invisibleEntriesContainer) {
+ item.parent = invisibleEntriesContainer;
}
-
- item.parent = invisibleEntriesContainer;
break;
case PlasmaCore.Types.ActiveStatus:
- if (visibleLayout.children.length == 0) {
- item.parent = visibleLayout;
- //notifications is always the first
- } else if (visibleLayout.children[0].itemId == "org.kde.plasma.notifications" &&
- item.itemId != "org.kde.plasma.notifications") {
- plasmoid.nativeInterface.reorderItemAfter(item, visibleLayout.children[0]);
- } else if (visibleLayout.children[0] != item) {
- plasmoid.nativeInterface.reorderItemBefore(item, visibleLayout.children[0]);
- }
+ reorderItem(item, visibleLayout)
break;
case PlasmaCore.Types.PassiveStatus:
-
- if (hiddenLayout.children.length == 0) {
- item.parent = hiddenLayout;
- //notifications is always the first
- } else if (hiddenLayout.children[0].itemId == "org.kde.plasma.notifications" &&
- item.itemId != "org.kde.plasma.notifications") {
- plasmoid.nativeInterface.reorderItemAfter(item, hiddenLayout.children[0]);
- } else if (hiddenLayout.children[0] != item) {
- plasmoid.nativeInterface.reorderItemBefore(item, hiddenLayout.children[0]);
- }
+ reorderItem(item, hiddenLayout)
item.x = 0;
break;
}