diff --git a/applets/kickoff/package/contents/ui/ApplicationsView.qml b/applets/kickoff/package/contents/ui/ApplicationsView.qml index fdf8ab245..57900f3df 100644 --- a/applets/kickoff/package/contents/ui/ApplicationsView.qml +++ b/applets/kickoff/package/contents/ui/ApplicationsView.qml @@ -1,306 +1,286 @@ /* Copyright (C) 2011 Martin Gräßlin Copyright (C) 2012 Gregor Taetzner Copyright 2014 Sebastian Kügler Copyright (C) 2015 Eike Hein 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 02110-1301 USA. */ import QtQuick 2.0 import org.kde.plasma.core 2.0 as PlasmaCore import org.kde.plasma.extras 2.0 as PlasmaExtras import org.kde.plasma.components 2.0 as PlasmaComponents Item { id: appViewContainer anchors.fill: parent objectName: "ApplicationsView" property ListView listView: applicationsView function decrementCurrentIndex() { applicationsView.decrementCurrentIndex(); } function incrementCurrentIndex() { applicationsView.incrementCurrentIndex(); } function activateCurrentIndex(start) { if (!applicationsView.currentItem.modelChildren) { if (!start) { return; } } appViewScrollArea.state = "OutgoingLeft"; } function openContextMenu() { applicationsView.currentItem.openActionMenu(); } function deactivateCurrentIndex() { if (crumbModel.count > 0) { // this is not the case when switching from the "Applications" to the "Favorites" tab using the "Left" key breadcrumbsElement.children[crumbModel.count-1].clickCrumb(); appViewScrollArea.state = "OutgoingRight"; return true; } return false; } function reset() { applicationsView.model = rootModel; applicationsView.positionViewAtBeginning(); applicationsView.clearBreadcrumbs(); } function refreshed() { reset(); updatedLabelTimer.running = true; } Connections { target: plasmoid onExpandedChanged: { if (!expanded) { reset(); } } } Item { id: crumbContainer anchors { top: parent.top left: parent.left right: parent.right } height: childrenRect.height Behavior on opacity { NumberAnimation { duration: units.longDuration } } Flickable { id: breadcrumbFlickable anchors { top: parent.top left: parent.left right: parent.right } height: breadcrumbsElement.height boundsBehavior: Flickable.StopAtBounds contentWidth: breadcrumbsElement.width pixelAligned: true //contentX: contentWidth - width PlasmaComponents.ButtonRow { id: breadcrumbsElement exclusive: false Breadcrumb { id: rootBreadcrumb root: true text: i18n("All Applications") depth: 0 } Repeater { model: ListModel { id: crumbModel // Array of the models property var models: [] } Breadcrumb { root: false text: model.text } } onWidthChanged: { breadcrumbFlickable.contentX = Math.max(0, breadcrumbsElement.width - breadcrumbFlickable.width) } } } // Flickable } // crumbContainer PlasmaExtras.ScrollArea { id: appViewScrollArea property Item activatedItem: null anchors { top: crumbContainer.bottom bottom: parent.bottom rightMargin: -units.largeSpacing leftMargin: -units.largeSpacing } Behavior on opacity { NumberAnimation { duration: units.longDuration } } width: parent.width function moveRight() { state = ""; activatedItem.activate() applicationsView.positionViewAtBeginning() } function moveLeft() { state = ""; // newModelIndex set by clicked breadcrumb var oldModel = applicationsView.model; applicationsView.model = applicationsView.newModel; applicationsView.positionViewAtIndex(applicationsView.model.rowForModel(oldModel), ListView.Center) } ListView { id: applicationsView property variant newModel focus: true keyNavigationWraps: true boundsBehavior: Flickable.StopAtBounds highlight: KickoffHighlight {} highlightMoveDuration : 0 highlightResizeDuration: 0 model: rootModel delegate: KickoffItem { id: kickoffItem appView: true - - PlasmaCore.SvgItem { - anchors { - right: parent.right - verticalCenter: parent.verticalCenter - rightMargin: y - } - height: units.iconSizes.small - width: height - - svg: arrowSvg - elementId: "go-next" - visible: model.hasChildren - } } function addBreadcrumb(model, title) { crumbModel.append({"text": title, "depth": crumbModel.count+1}) crumbModel.models.push(model); } function clearBreadcrumbs() { crumbModel.clear(); crumbModel.models = []; } - - PlasmaCore.Svg { - id: arrowSvg - - imagePath: "toolbar-icons/go" - } } // applicationsView states: [ State { name: "OutgoingLeft" PropertyChanges { target: appViewScrollArea x: -parent.width opacity: 0.0 } }, State { name: "OutgoingRight" PropertyChanges { target: appViewScrollArea x: parent.width opacity: 0.0 } } ] transitions: [ Transition { to: "OutgoingLeft" SequentialAnimation { // We need to cache the currentItem since the selection can move during animation, // and we want the item that has been clicked on, not the one that is under the // mouse once the animation is done ScriptAction { script: appViewScrollArea.activatedItem = applicationsView.currentItem } NumberAnimation { properties: "x,opacity"; easing.type: Easing.InQuad; duration: units.longDuration } ScriptAction { script: appViewScrollArea.moveRight() } } }, Transition { to: "OutgoingRight" SequentialAnimation { NumberAnimation { properties: "x,opacity"; easing.type: Easing.InQuad; duration: units.longDuration } ScriptAction { script: appViewScrollArea.moveLeft() } } } ] } // appViewScrollArea MouseArea { anchors.fill: appViewScrollArea acceptedButtons: Qt.BackButton onClicked: { deactivateCurrentIndex() } } Timer { id: updatedLabelTimer interval: 1500 running: false repeat: true onRunningChanged: { if (running) { updatedLabel.opacity = 1; crumbContainer.opacity = 0.3; appViewScrollArea.opacity = 0.3; } } onTriggered: { updatedLabel.opacity = 0; crumbContainer.opacity = 1; appViewScrollArea.opacity = 1; running = false; } } PlasmaComponents.Label { id: updatedLabel text: i18n("Applications updated.") opacity: 0 visible: opacity != 0 anchors.centerIn: parent Behavior on opacity { NumberAnimation { duration: units.shortDuration } } } Component.onCompleted: { rootModel.cleared.connect(refreshed); } } // appViewContainer diff --git a/applets/kickoff/package/contents/ui/KickoffItem.qml b/applets/kickoff/package/contents/ui/KickoffItem.qml index e7c57d401..f64a52040 100644 --- a/applets/kickoff/package/contents/ui/KickoffItem.qml +++ b/applets/kickoff/package/contents/ui/KickoffItem.qml @@ -1,252 +1,252 @@ /* Copyright (C) 2011 Martin Gräßlin Copyright (C) 2012 Gregor Taetzner Copyright 2014 Sebastian Kügler Copyright (C) 2015 Eike Hein 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 02110-1301 USA. */ import QtQuick 2.0 import org.kde.plasma.core 2.0 as PlasmaCore import org.kde.plasma.components 2.0 as PlasmaComponents import org.kde.draganddrop 2.0 import "../code/tools.js" as Tools Item { id: listItem width: ListView.view.width // height: listItemDelegate.height // + listItemDelegate.anchors.margins*2 height: (units.smallSpacing * 2) + Math.max(elementIcon.height, titleElement.height + subTitleElement.height) signal actionTriggered(string actionId, variant actionArgument) signal aboutToShowActionMenu(variant actionMenu) property bool dropEnabled: false property bool appView: false property bool modelChildren: model.hasChildren property bool isCurrent: listItem.ListView.view.currentIndex === index; - property string url: model.url + property string url: model.url || "" property bool showAppsByName: plasmoid.configuration.showAppsByName property bool hasActionList: ((model.favoriteId != null) || (("hasActionList" in model) && (model.hasActionList == true))) property Item menu: actionMenu onAboutToShowActionMenu: { var actionList = hasActionList ? model.actionList : []; Tools.fillActionMenu(actionMenu, actionList, ListView.view.model.favoritesModel, model.favoriteId); } onActionTriggered: { Tools.triggerAction(ListView.view.model, model.index, actionId, actionArgument); if (actionId.indexOf("_kicker_favorite_") === 0) { switchToFavorites(); } } function activate() { var view = listItem.ListView.view; if (model.hasChildren) { var childModel = view.model.modelForRow(index); view.addBreadcrumb(childModel, display); view.model = childModel; } else { view.model.trigger(index, "", null); plasmoid.expanded = false; if (view.reset) { view.reset(); } } } function openActionMenu(visualParent, x, y) { aboutToShowActionMenu(actionMenu); actionMenu.visualParent = visualParent != undefined ? visualParent : mouseArea; actionMenu.open(x, y); } ActionMenu { id: actionMenu onActionClicked: { actionTriggered(actionId, actionArgument); } } Item { id: listItemDelegate anchors { left: parent.left right: parent.right top: parent.top bottom: parent.bottom //margins: units.smallSpacing } MouseArea { id: mouseArea anchors.fill: parent //anchors.margins: -8 property bool pressed: false property int pressX: -1 property int pressY: -1 hoverEnabled: true acceptedButtons: Qt.LeftButton | Qt.RightButton onEntered: { listItem.ListView.view.currentIndex = index; } onExited: { listItem.ListView.view.currentIndex = -1; } onPressed: { if (mouse.buttons & Qt.RightButton) { if (hasActionList) { openActionMenu(mouseArea, mouse.x, mouse.y); } } else { pressed = true; pressX = mouse.x; pressY = mouse.y; } } onReleased: { if (pressed) { if (appView) { appViewScrollArea.state = "OutgoingLeft"; } else { listItem.activate(); } listItem.ListView.view.currentIndex = -1; } pressed = false; pressX = -1; pressY = -1; } onPositionChanged: { if (pressX != -1 && model.url && dragHelper.isDrag(pressX, pressY, mouse.x, mouse.y)) { dragHelper.startDrag(root, model.url, model.decoration); pressed = false; pressX = -1; pressY = -1; } } onContainsMouseChanged: { if (!containsMouse) { pressed = false; pressX = -1; pressY = -1; } } } PlasmaCore.IconItem { id: elementIcon anchors { left: parent.left leftMargin: (units.gridUnit * 4) - units.iconSizes.medium verticalCenter: parent.verticalCenter } width: units.iconSizes.medium height: width animated: false usesPlasmaTheme: false source: decoration } PlasmaComponents.Label { id: titleElement y: Math.round((parent.height - titleElement.height - ( (subTitleElement.text != "") ? subTitleElement.paintedHeight : 0) ) / 2) anchors { //bottom: elementIcon.verticalCenter left: elementIcon.right right: arrow.left leftMargin: units.gridUnit rightMargin: units.gridUnit * 2 } height: paintedHeight // TODO: games should always show the by name! text: model.display elide: Text.ElideRight } PlasmaComponents.Label { id: subTitleElement anchors { left: titleElement.left right: arrow.left rightMargin: units.gridUnit * 2 top: titleElement.bottom } height: paintedHeight text: model.description opacity: isCurrent ? 0.6 : 0.3 font.pointSize: theme.smallestFont.pointSize elide: Text.ElideMiddle } PlasmaCore.SvgItem { id: arrow anchors { right: parent.right rightMargin: units.gridUnit * 2 verticalCenter: parent.verticalCenter } width: visible ? units.iconSizes.small : 0 height: width visible: (model.hasChildren == true) opacity: (listItem.ListView.view.currentIndex == index) ? 1.0 : 0.4 svg: arrowsSvg elementId: (Qt.application.layoutDirection == Qt.RightToLeft) ? "left-arrow" : "right-arrow" } } // listItemDelegate Keys.onPressed: { if (event.key == Qt.Key_Menu && hasActionList) { event.accepted = true; openActionMenu(mouseArea); } else if ((event.key == Qt.Key_Enter || event.key == Qt.Key_Return) && !modelChildren) { if (!modelChildren) { event.accepted = true; listItem.activate(); } } } } // listItem diff --git a/applets/taskmanager/package/contents/ui/Task.qml b/applets/taskmanager/package/contents/ui/Task.qml index fd4e60893..9a28a354b 100644 --- a/applets/taskmanager/package/contents/ui/Task.qml +++ b/applets/taskmanager/package/contents/ui/Task.qml @@ -1,442 +1,443 @@ /*************************************************************************** * Copyright (C) 2012-2013 by Eike Hein * * * * 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 02110-1301 USA . * ***************************************************************************/ import QtQuick 2.0 import org.kde.plasma.core 2.0 as PlasmaCore import org.kde.plasma.components 2.0 as PlasmaComponents import org.kde.draganddrop 2.0 import org.kde.plasma.private.taskmanager 0.1 as TaskManager import "../code/layout.js" as LayoutManager import "../code/tools.js" as TaskTools MouseArea { id: task width: groupDialog.mainItem.width height: units.iconSizes.small + LayoutManager.verticalMargins() visible: false LayoutMirroring.enabled: (Qt.application.layoutDirection == Qt.RightToLeft) LayoutMirroring.childrenInherit: (Qt.application.layoutDirection == Qt.RightToLeft) property int itemIndex: index property int itemId: model.Id property bool inPopup: false property bool isGroupParent: model.hasModelChildren property bool isLauncher: model.IsLauncher property bool isStartup: model.IsStartup property bool demandsAttention: model.DemandsAttention property bool showingContextMenu: false property int textWidth: label.implicitWidth property bool pressed: false property int pressX: -1 property int pressY: -1 property Item busyIndicator property int wheelDelta: 0 readonly property bool smartLauncherEnabled: plasmoid.configuration.smartLaunchersEnabled && !inPopup && !isStartup property QtObject smartLauncherItem: null acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MidButton hoverEnabled: true onItemIndexChanged: { if (!inPopup && !tasks.vertical && LayoutManager.calculateStripes() > 1) { var newWidth = LayoutManager.taskWidth(); if (index == backend.tasksModel.launcherCount) { newWidth += LayoutManager.launcherLayoutWidthDiff(); } width = newWidth; } } onIsStartupChanged: { if (!isStartup) { tasks.itemGeometryChanged(task, itemId); busyIndicator.visible = false; busyIndicator.running = false; icon.visible = true; } } onDemandsAttentionChanged: { tasks.updateStatus(demandsAttention); } onContainsMouseChanged: { if (!containsMouse) { pressed = false; } tasks.itemHovered(model.Id, containsMouse); } onPressed: { if (mouse.button == Qt.LeftButton || mouse.button == Qt.MidButton) { pressed = true; pressX = mouse.x; pressY = mouse.y; } else if (mouse.button == Qt.RightButton) { if (plasmoid.configuration.showToolTips) { toolTip.hideToolTip(); } showingContextMenu = true; tasks.itemContextMenu(task, plasmoid.action("configure")); } } onReleased: { if (pressed) { if (mouse.button == Qt.MidButton) { if (plasmoid.configuration.middleClickAction == TaskManager.Backend.NewInstance) { tasks.launchNewInstance(model.Id); } else if (plasmoid.configuration.middleClickAction == TaskManager.Backend.Close) { tasks.closeByItemId(model.Id); } } else if (mouse.button == Qt.LeftButton) { if (mouse.modifiers & Qt.ShiftModifier) { tasks.launchNewInstance(model.Id); } else if (isGroupParent) { if ((iconsOnly || mouse.modifiers == Qt.ControlModifier) && backend.canPresentWindows()) { tasks.presentWindows(model.Id); } else if (groupDialog.visible) { groupDialog.visible = false; } else { groupDialog.visualParent = task; groupDialog.visible = true; } } else { tasks.activateItem(model.Id, true); } } } pressed = false; pressX = -1; pressY = -1; } onPositionChanged: { if (pressX != -1 && dragHelper.isDrag(pressX, pressY, mouse.x, mouse.y)) { tasks.dragSource = task; dragHelper.startDrag(task, model.MimeType, model.MimeData, model.LauncherUrl, model.DecorationRole); pressX = -1; pressY = -1; return; } } onWheel: { if (plasmoid.configuration.wheelEnabled) { wheelDelta = TaskTools.wheelActivateNextPrevTask(task, wheelDelta, wheel.angleDelta.y); } } onSmartLauncherEnabledChanged: { if (smartLauncherEnabled && !smartLauncherItem) { var smartLauncher = Qt.createQmlObject(" import org.kde.plasma.private.taskmanager 0.1 as TaskManager; TaskManager.SmartLauncherItem { }", task); smartLauncher.launcherUrl = Qt.binding(function() { return model.LauncherUrl; }); smartLauncherItem = smartLauncher; } } Connections { target: backend onShowingContextMenuChanged: { if (task.showingContextMenu && !backend.showingContextMenu) { task.showingContextMenu = false; } } } PlasmaCore.FrameSvgItem { id: frame anchors { fill: parent topMargin: (!tasks.vertical && taskList.rows > 1) ? units.smallSpacing / 4 : 0 bottomMargin: (!tasks.vertical && taskList.rows > 1) ? units.smallSpacing / 4 : 0 leftMargin: ((inPopup || tasks.vertical) && taskList.columns > 1) ? units.smallSpacing / 4 : 0 rightMargin: ((inPopup || tasks.vertical) && taskList.columns > 1) ? units.smallSpacing / 4 : 0 } imagePath: "widgets/tasks" property string basePrefix: "normal" prefix: TaskTools.taskPrefix("normal") onRepaintNeeded: prefix = TaskTools.taskPrefix(basePrefix); onBasePrefixChanged: prefix = TaskTools.taskPrefix(basePrefix); PlasmaCore.ToolTipArea { id: toolTip anchors.fill: parent active: !inPopup && !groupDialog.visible && plasmoid.configuration.showToolTips interactive: true location: plasmoid.location mainItem: toolTipDelegate //FIXME TODO: highlightWindows: plasmoid.configuration.highlightWindows onContainsMouseChanged: { if (containsMouse) { - toolTipDelegate.windows = model.WindowList; - toolTipDelegate.mainText = model.DisplayRole; - toolTipDelegate.icon = model.DecorationRole; - toolTipDelegate.subText = model.IsLauncher ? model.GenericName - : toolTip.generateSubText(model); - toolTipDelegate.launcherUrl = model.LauncherUrl; + toolTipDelegate.windows = Qt.binding(function() { + return model.WindowList; + }); + toolTipDelegate.mainText = Qt.binding(function() { + return model.DisplayRole; + }); + toolTipDelegate.icon = Qt.binding(function() { + return model.DecorationRole; + }); + toolTipDelegate.subText = Qt.binding(function() { + return model.IsLauncher ? model.GenericName : toolTip.generateSubText(model); + }); + toolTipDelegate.launcherUrl = Qt.binding(function() { + return model.LauncherUrl; + }); } } function generateSubText(task) { var subTextEntries = new Array(); if (!plasmoid.configuration.showOnlyCurrentDesktop && backend.numberOfDesktops() > 1) { subTextEntries.push(i18n("On %1", task.DesktopName)); } if (task.OnAllActivities && backend.numberOfActivities() > 1) { subTextEntries.push(i18nc("Which virtual desktop a window is currently on", "Available on all activities")); } else if (plasmoid.configuration.showOnlyCurrentActivity) { if (task.OtherActivityNames.length > 0) { subTextEntries.push(i18nc("Activities a window is currently on (apart from the current one)", "Also available on %1", task.OtherActivityNames.join(", "))); } } else if (task.ActivityNames.length > 0) { subTextEntries.push(i18nc("Which activities a window is currently on", "Available on %1", task.ActivityNames.join(", "))); } return subTextEntries.join("\n"); } - - Connections { - target: toolTip.containsMouse ? label : null - - onTextChanged: { - toolTipDelegate.mainText = label.text; - } - } } } Loader { anchors.fill: frame asynchronous: true source: "TaskProgressOverlay.qml" active: plasmoid.configuration.smartLaunchersEnabled && task.smartLauncherItem && task.smartLauncherItem.progressVisible } Item { id: iconBox anchors { left: parent.left leftMargin: tasks.vertical && !label.visible ? adjustMargin(true, parent.width, taskFrame.margins.left) : taskFrame.margins.left top: parent.top topMargin: adjustMargin(false, parent.height, taskFrame.margins.top); bottom: parent.bottom bottomMargin: adjustMargin(false, parent.height, taskFrame.margins.bottom); right: (tasks.vertical && !label.visible && !inPopup) ? parent.right : undefined rightMargin: tasks.vertical && !label.visible ? adjustMargin(true, parent.width, taskFrame.margins.right) : undefined } function adjustMargin(vert, size, margin) { if (!size) { return margin; } var margins = vert ? LayoutManager.horizontalMargins() : LayoutManager.verticalMargins(); if ((size - margins) < units.iconSizes.small) { return Math.ceil((margin * (units.iconSizes.small / size)) / 2); } return margin; } width: inPopup ? units.iconSizes.small : Math.min(height, parent.width - LayoutManager.horizontalMargins()) PlasmaCore.IconItem { id: icon anchors.fill: parent visible: false active: task.containsMouse || task.showingContextMenu enabled: true usesPlasmaTheme: false source: model.DecorationRole onVisibleChanged: { if (visible && busyIndicator) { busyIndicator.destroy(); } } } Loader { anchors.fill: icon asynchronous: true source: "TaskBadgeOverlay.qml" active: plasmoid.configuration.smartLaunchersEnabled && height >= units.iconSizes.small && icon.visible && task.smartLauncherItem && task.smartLauncherItem.countVisible } PlasmaComponents.BusyIndicator { id: busyIndicator anchors.fill: parent visible: false running: false } states: [ // Using a state transition avoids a binding loop between label.visible and // the text label margin, which derives from the icon width. State { name: "standalone" when: !label.visible AnchorChanges { target: iconBox anchors.left: undefined anchors.horizontalCenter: parent.horizontalCenter } PropertyChanges { target: iconBox anchors.leftMargin: 0 } } ] } TaskManager.TextLabel { id: label anchors { fill: parent leftMargin: taskFrame.margins.left + iconBox.width + units.smallSpacing topMargin: taskFrame.margins.top rightMargin: taskFrame.margins.right bottomMargin: taskFrame.margins.bottom } visible: (inPopup || !iconsOnly && !model.IsLauncher && (parent.width - LayoutManager.horizontalMargins()) >= (theme.mSize(theme.defaultFont).width * 7)) enabled: true text: (!inPopup && iconsOnly) ? "" : model.DisplayRole color: theme.textColor elide: !inPopup } states: [ State { name: "launcher" when: model.IsLauncher PropertyChanges { target: frame basePrefix: "" } }, State { name: "hovered" when: containsMouse || showingContextMenu PropertyChanges { target: frame basePrefix: "hover" } }, State { name: "attention" when: model.DemandsAttention || (task.smartLauncherItem && task.smartLauncherItem.urgent) PropertyChanges { target: frame basePrefix: "attention" } }, State { name: "minimized" when: model.Minimized && !(groupDialog.visible && groupDialog.target == task) PropertyChanges { target: frame basePrefix: "minimized" } }, State { name: "active" when: model.Active || groupDialog.visible && groupDialog.target == task PropertyChanges { target: frame basePrefix: "focus" } } ] Component.onCompleted: { if (model.IsStartup) { busyIndicator.running = true; busyIndicator.visible = true; } else { icon.visible = true; } if (model.hasModelChildren) { var component = Qt.createComponent("GroupExpanderOverlay.qml"); component.createObject(task); } } /* Component.onDestruction: { if (groupDialog.visible && groupDialog.groupItemId == model.Id) { groupDialog.visible = false; } } */ } diff --git a/applets/taskmanager/package/contents/ui/ToolTipDelegate.qml b/applets/taskmanager/package/contents/ui/ToolTipDelegate.qml index 1af0c27fe..383c4a4be 100644 --- a/applets/taskmanager/package/contents/ui/ToolTipDelegate.qml +++ b/applets/taskmanager/package/contents/ui/ToolTipDelegate.qml @@ -1,375 +1,377 @@ /* * Copyright 2013 by Sebastian Kügler * Copyright 2014 by Martin Gräßlin * Copyright 2016 by Kai Uwe Broulik * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2, 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 Library General Public License for more details * * You should have received a copy of the GNU Library 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.Layouts 1.1 import QtGraphicalEffects 1.0 import org.kde.plasma.core 2.0 as PlasmaCore import org.kde.plasma.components 2.0 as PlasmaComponents import org.kde.plasma.extras 2.0 as PlasmaExtras import org.kde.kquickcontrolsaddons 2.0 as KQuickControlsAddons Column { id: tooltipContentItem property Item toolTip property var windows property string mainText property string subText property variant icon property url launcherUrl readonly property int thumbnailWidth: units.gridUnit * 15 readonly property int thumbnailHeight: units.gridUnit * 10 property int preferredTextWidth: theme.mSize(theme.defaultFont).width * 30 property int _s: units.largeSpacing / 2 Layout.minimumWidth: Math.max(thumbnailWidth, windowRow.width, appLabelRow.width) + _s Layout.minimumHeight: childrenRect.height Layout.maximumWidth: Layout.minimumWidth Layout.maximumHeight: Layout.minimumHeight spacing: _s states: State { when: mpris2Source.hasPlayer PropertyChanges { target: thumbnailSourceItem opacity: 0 // cannot set visible to false or else WindowThumbnail won't provide thumbnail } PropertyChanges { target: playerControlsOpacityMask visible: true source: thumbnailSourceItem maskSource: playerControlsShadowMask } PropertyChanges { target: playerControlsRow visible: mpris2Source.hasPlayer } } PlasmaCore.DataSource { id: mpris2Source readonly property string current: { var split = launcherUrl.toString().split('/') var appName = split[split.length - 1].replace(".desktop", "") return appName } readonly property bool hasPlayer: sources.indexOf(current) > -1 readonly property bool playing: hasPlayer && data[current].PlaybackStatus === "Playing" readonly property bool canControl: hasPlayer && data[current].CanControl readonly property bool canGoBack: hasPlayer && data[current].CanGoPrevious readonly property bool canGoNext: hasPlayer && data[current].CanGoNext readonly property bool canRaise: hasPlayer && data[current].CanRaise readonly property var currentMetadata: hasPlayer ? data[current].Metadata : ({}) readonly property string track: { var xesamTitle = currentMetadata["xesam:title"] if (xesamTitle) { return xesamTitle } // if no track title is given, print out the file name var xesamUrl = currentMetadata["xesam:url"] ? currentMetadata["xesam:url"].toString() : "" if (!xesamUrl) { return "" } var lastSlashPos = xesamUrl.lastIndexOf('/') if (lastSlashPos < 0) { return "" } var lastUrlPart = xesamUrl.substring(lastSlashPos + 1) return decodeURIComponent(lastUrlPart) } readonly property string artist: currentMetadata["xesam:artist"] || "" readonly property string albumArt: currentMetadata["mpris:artUrl"] || "" function goPrevious() { startOperation("Previous") } function goNext() { startOperation("Next") } function playPause() { startOperation("PlayPause") } function raise() { startOperation("Raise") } function startOperation(op) { var service = mpris2Source.serviceForSource(current) var operation = service.operationDescription(op) return service.startOperationCall(operation) } engine: "mpris2" connectedSources: current } Item { id: thumbnailContainer width: Math.max(parent.width, windowRow.width) height: albumArtImage.available ? albumArtImage.height : raisePlayerArea.visible ? raisePlayerArea.height : windowRow.height Item { id: thumbnailSourceItem anchors.fill: parent PlasmaExtras.ScrollArea { id: scrollArea anchors.horizontalCenter: parent.horizontalCenter width: Math.max(windowRow.width, thumbnailWidth) height: parent.height visible: !albumArtImage.available verticalScrollBarPolicy: Qt.ScrollBarAlwaysOff horizontalScrollBarPolicy: Qt.ScrollBarAlwaysOff Component.onCompleted: { flickableItem.interactive = Qt.binding(function() { return contentItem.width > viewport.width; }); } Row { id: windowRow width: childrenRect.width height: childrenRect.height spacing: units.largeSpacing Repeater { model: plasmoid.configuration.showToolTips && !albumArtImage.available ? windows : null PlasmaCore.WindowThumbnail { id: windowThumbnail y: -s width: thumbnailWidth height: thumbnailHeight winId: modelData ToolTipWindowMouseArea { anchors.fill: parent winId: parent.winId thumbnailItem: parent } } } } } Image { id: albumArtImage // also Image.Loading to prevent loading thumbnails just because the album art takes a split second to load readonly property bool available: status === Image.Ready || status === Image.Loading anchors.centerIn: parent width: parent.width height: thumbnailHeight sourceSize: Qt.size(thumbnailWidth, thumbnailHeight) asynchronous: true source: mpris2Source.albumArt fillMode: Image.PreserveAspectCrop visible: available ToolTipWindowMouseArea { anchors.fill: parent winId: windows[0] || 0 } } MouseArea { id: raisePlayerArea anchors.centerIn: parent width: thumbnailWidth height: thumbnailHeight // if there's no window associated with this task, we might still be able to raise the player visible: !windows[0] && mpris2Source.canRaise onClicked: mpris2Source.raise() PlasmaCore.IconItem { anchors.fill: parent source: icon + animated: false + usesPlasmaTheme: false visible: !albumArtImage.available } } } Item { id: playerControlsShadowMask anchors.fill: thumbnailSourceItem visible: false // OpacityMask would render it Rectangle { width: parent.width height: parent.height - playerControlsRow.height } Rectangle { anchors.bottom: parent.bottom width: parent.width height: playerControlsRow.height opacity: 0.2 } } OpacityMask { id: playerControlsOpacityMask anchors.fill: thumbnailSourceItem visible: false } // prevent accidental click-through when a control is disabled MouseArea { anchors.fill: playerControlsRow enabled: playerControlsRow.visible } RowLayout { id: playerControlsRow anchors { horizontalCenter: parent.horizontalCenter bottom: thumbnailSourceItem.bottom } width: thumbnailWidth spacing: 0 enabled: mpris2Source.canControl visible: false ColumnLayout { Layout.fillWidth: true spacing: 0 PlasmaExtras.Heading { Layout.fillWidth: true level: 4 wrapMode: Text.NoWrap elide: Text.ElideRight text: mpris2Source.track || "" } PlasmaExtras.Heading { Layout.fillWidth: true level: 5 wrapMode: Text.NoWrap elide: Text.ElideRight text: mpris2Source.artist || "" } } PlasmaComponents.ToolButton { enabled: mpris2Source.canGoBack iconName: "media-skip-backward" tooltip: i18nc("Go to previous song", "Previous") Accessible.name: tooltip onClicked: mpris2Source.goPrevious() } PlasmaComponents.ToolButton { Layout.fillHeight: true Layout.preferredWidth: height // make this button bigger iconName: mpris2Source.playing ? "media-playback-pause" : "media-playback-start" tooltip: mpris2Source.playing ? i18nc("Pause player", "Pause") : i18nc("Start player", "Play") Accessible.name: tooltip onClicked: mpris2Source.playPause() } PlasmaComponents.ToolButton { enabled: mpris2Source.canGoNext iconName: "media-skip-forward" tooltip: i18nc("Go to next song", "Next") Accessible.name: tooltip onClicked: mpris2Source.goNext() } } } Row { id: appLabelRow width: childrenRect.width + _s height: childrenRect.height + units.largeSpacing spacing: units.largeSpacing Item { id: imageContainer width: tooltipIcon.width height: tooltipIcon.height y: _s PlasmaCore.IconItem { id: tooltipIcon x: _s width: units.iconSizes.desktop height: width animated: false usesPlasmaTheme: false source: icon } } Column { id: mainColumn y: _s //This instance is purely for metrics PlasmaExtras.Heading { id: tooltipMaintextPlaceholder visible: false level: 3 text: mainText textFormat: Text.PlainText } PlasmaExtras.Heading { id: tooltipMaintext level: 3 width: Math.min(tooltipMaintextPlaceholder.width, preferredTextWidth) //width: 400 elide: Text.ElideRight text: mainText textFormat: Text.PlainText } PlasmaComponents.Label { id: tooltipSubtext width: tooltipContentItem.preferredTextWidth wrapMode: Text.WordWrap text: subText textFormat: Text.PlainText opacity: 0.5 visible: text !== "" } } } } diff --git a/applets/trash/package/contents/ui/main.qml b/applets/trash/package/contents/ui/main.qml index 0d1aad3ab..d81b0d6f7 100644 --- a/applets/trash/package/contents/ui/main.qml +++ b/applets/trash/package/contents/ui/main.qml @@ -1,135 +1,156 @@ /* * Copyright 2013 Heena Mahour - * Copyright 2015 Kai Uwe Broulik + * Copyright 2015, 2016 Kai Uwe Broulik * * 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, see . */ import QtQuick 2.0 import QtQuick.Layouts 1.1 +import QtGraphicalEffects 1.0 + import org.kde.plasma.plasmoid 2.0 import org.kde.plasma.core 2.0 as PlasmaCore import org.kde.plasma.components 2.0 as Components import org.kde.kcoreaddons 1.0 as KCoreAddons import org.kde.kquickcontrolsaddons 2.0 import org.kde.draganddrop 2.0 as DragDrop import org.kde.plasma.private.trash 1.0 as TrashPrivate DragDrop.DropArea { id: root property bool containsAcceptableDrag: false Layout.minimumWidth: { if (constrained) { return formFactor === PlasmaCore.Types.Horizontal ? height : 1 } return text.width } Layout.minimumHeight: { if (constrained) { formFactor === PlasmaCore.Types.Vertical ? width : 1 } return units.iconSizes.small + text.height } readonly property int formFactor: plasmoid.formFactor readonly property bool constrained: formFactor === PlasmaCore.Types.Vertical || formFactor === PlasmaCore.Types.Horizontal Plasmoid.preferredRepresentation: Plasmoid.fullRepresentation - - Plasmoid.backgroundHints: PlasmaCore.Types.TranslucentBackground + Plasmoid.backgroundHints: PlasmaCore.Types.NoBackground + Plasmoid.icon: (dirModel.count > 0) ? "user-trash-full": "user-trash" preventStealing: true onDragEnter: containsAcceptableDrag = TrashPrivate.Trash.trashableUrls(event.mimeData.urls).length > 0 onDragLeave: containsAcceptableDrag = false onDrop: { containsAcceptableDrag = false var trashableUrls = TrashPrivate.Trash.trashableUrls(event.mimeData.urls) if (trashableUrls.length > 0) { TrashPrivate.Trash.trashUrls(trashableUrls) event.accept(Qt.MoveAction) } else { event.accept(Qt.IgnoreAction) // prevent Plasma from spawning an applet } } TrashPrivate.DirModel { id: dirModel url: "trash:/" onCountChanged: { plasmoid.action("empty").enabled = count > 0; } } function action_open() { Qt.openUrlExternally("trash:/"); } function action_empty() { TrashPrivate.Trash.emptyTrash() } function action_openkcm() { KCMShell.open(["trash"]); } Component.onCompleted: { plasmoid.removeAction("configure"); plasmoid.setAction("open", i18nc("a verb", "Open"),"document-open"); plasmoid.setAction("empty",i18nc("a verb", "Empty"),"trash-empty"); plasmoid.setAction("openkcm", i18n("Trash Settings"), "configure"); - plasmoid.popupIcon = "user-trash"; - plasmoid.action("empty").enabled = count > 0; + plasmoid.action("empty").enabled = dirModel.count > 0; } MouseArea { id: mouseArea anchors.fill: parent onClicked: Qt.openUrlExternally("trash:/"); } PlasmaCore.IconItem { id: icon - source: (dirModel.count > 0) ? "user-trash-full": "user-trash" + source: plasmoid.icon anchors { left: parent.left right: parent.right top: parent.top bottom: constrained ? parent.bottom: text.top } active: toolTip.containsMouse || root.containsAcceptableDrag } + DropShadow { + id: textShadow + + anchors.fill: text + + visible: !constrained + + horizontalOffset: units.devicePixelRatio * 2 + verticalOffset: horizontalOffset + + radius: 9.0 + samples: 18 + spread: 0.15 + + color: "black" + + source: constrained ? null : text + } + Components.Label { id: text anchors { horizontalCenter: parent.horizontalCenter bottom: parent.bottom } text: (dirModel.count === 0) ? i18n("Trash\nEmpty") : i18np("Trash\nOne item", "Trash\n %1 items", dirModel.count) + color: "white" horizontalAlignment: Text.AlignHCenter - visible: !constrained + visible: false // rendered by DropShadow } PlasmaCore.ToolTipArea { id: toolTip anchors.fill: parent mainText: i18n("Trash") subText: (dirModel.count === 0) ? i18n("Empty") : i18np("One item", "%1 items", dirModel.count) icon: (dirModel.count > 0) ? "user-trash-full" : "user-trash" } } diff --git a/containments/desktop/package/contents/ui/AppletAppearance.qml b/containments/desktop/package/contents/ui/AppletAppearance.qml index 523da06d4..b85d5fca7 100644 --- a/containments/desktop/package/contents/ui/AppletAppearance.qml +++ b/containments/desktop/package/contents/ui/AppletAppearance.qml @@ -1,449 +1,449 @@ /* * Copyright 2011-2013 Sebastian Kügler * Copyright 2011 Marco Martin * Copyright 2014 David Edmundson * Copyright 2015 Eike Hein * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2 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 Library General Public License for more details * * You should have received a copy of the GNU Library General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import QtQuick 2.0 import QtQuick.Layouts 1.1 import org.kde.plasma.core 2.0 as PlasmaCore import org.kde.plasma.components 2.0 as PlasmaComponents import org.kde.plasma.extras 2.0 as PlasmaExtras import org.kde.kquickcontrolsaddons 2.0 as KQuickControlsAddons import org.kde.plasma.plasmoid 2.0 Item { id: appletItem property int handleWidth: iconSize - property int minimumHandleHeight: 6 * (root.iconSize + 6) + margins.top + margins.bottom + property int minimumHandleHeight: 7 * (root.iconSize + 7) + margins.top + margins.bottom property int handleHeight: (height < minimumHandleHeight) ? minimumHandleHeight : height property string category property bool showAppletHandle: false property real controlsOpacity: (plasmoid.immutable || !showAppletHandle) ? 0 : 1 property string backgroundHints: "NoBackground" property bool hasBackground: false property bool handleMerged: (height > minimumHandleHeight && !appletHandle.forceFloating) property bool animationsEnabled: false property int minimumWidth: Math.max(root.layoutManager.cellSize.width, appletContainer.minimumWidth + appletItem.contents.anchors.leftMargin + appletItem.contents.anchors.rightMargin) property int minimumHeight: Math.max(root.layoutManager.cellSize.height, appletContainer.minimumHeight + appletItem.contents.anchors.topMargin + appletItem.contents.anchors.bottomMargin) property alias applet: appletContainer.applet property Item contents: appletContainer property alias margins: plasmoidBackground.margins property alias imagePath: plasmoidBackground.imagePath visible: false onMinimumWidthChanged: appletItem.width = Math.max(minimumWidth, width); onMinimumHeightChanged: appletItem.height = Math.max(minimumHeight, height); function updateBackgroundHints() { hasBackground = (applet.backgroundHints != "NoBackground"); if (applet.backgroundHints == 1) { appletItem.imagePath = "widgets/background"; backgroundHints = "StandardBackground"; } else if (applet.backgroundHints == 2) { appletItem.imagePath = "widgets/translucentbackground" backgroundHints = "TranslucentBackground"; } else if (applet.backgroundHints == 0) { appletItem.imagePath = "" backgroundHints = "NoBackground"; } else { backgroundHints = "DefaultBackground"; appletItem.imagePath = "widgets/background"; } //print("Backgroundhints changed: " + appletItem.imagePath); } Rectangle { color: Qt.rgba(0,0,0,0); border.width: 3; border.color: "white"; opacity: 0.5; visible: debug; anchors.fill: parent; } KQuickControlsAddons.MouseEventListener { id: mouseListener anchors { fill: parent } z: 10 hoverEnabled: true property int pressX: -1 property int pressY: -1 onPressed: { pressX = mouse.x; pressY = mouse.y; } onPressAndHold: { if (!plasmoid.immutable && plasmoid.configuration.pressToMove) { if (!dragMouseArea.dragging && !systemSettings.isDrag(pressX, pressY, mouse.x, mouse.y)) { showAppletHandle = true; dragMouseArea.dragging = true; eventGenerator.sendGrabEventRecursive(appletItem, KQuickControlsAddons.EventGenerator.UngrabMouse); eventGenerator.sendGrabEvent(dragMouseArea, KQuickControlsAddons.EventGenerator.GrabMouse); eventGenerator.sendMouseEvent(dragMouseArea, KQuickControlsAddons.EventGenerator.MouseButtonPress, mouse.x, mouse.y, Qt.LeftButton, Qt.LeftButton, 0); } } pressX = -1; pressY = -1; } onContainsMouseChanged: { animationsEnabled = true; if (!plasmoid.immutable && (!plasmoid.configuration.pressToMove || !containsMouse)) { hoverTracker.restart(); } } Timer { id: hoverTracker repeat: false interval: root.handleDelay onTriggered: { if (mouseListener.containsMouse || (appletHandle.item && (appletHandle.item.containsMouse || appletHandle.item.pressed))) { if (!plasmoid.configuration.pressToMove) { showAppletHandle = true; } } else if (!dragMouseArea.dragging) { showAppletHandle = false; } } } Item { anchors { left: parent.left; top: parent.top; bottom: parent.bottom; } width: parent.width+handleWidth; z: mouseListener.z + 4 PlasmaCore.FrameSvgItem { id: plasmoidBackground visible: backgroundHints != PlasmaCore.Types.NoBackground imagePath: "widgets/background" anchors { left: parent.left; top: parent.top; bottom: parent.bottom; } width: (showAppletHandle && handleMerged) ? parent.width : parent.width-handleWidth; smooth: true Behavior on width { enabled: animationsEnabled NumberAnimation { duration: units.longDuration easing.type: Easing.InOutQuad } } } Connections { target: plasmoid onImmutableChanged: { // print(" TB dragMouseArea.visible: " + plasmoid.immutable) dragMouseArea.visible = !plasmoid.immutable; showAppletHandle = false; } onAppletRemoved: { // print("Applet removed Applet-" + applet.id) if (applet.id == appletItem.applet.id) { // print("Destroying Applet-" + applet.id) root.layoutManager.setSpaceAvailable(appletItem.x, appletItem.y, appletItem.width, appletItem.height, true) //applet.action("remove").trigger(); //appletItem.destroy() appletItem.destroy(); } } } Connections { target: applet onBusyChanged: { if (applet.busy) { busyLoader.source = "BusyOverlay.qml" } else if (busyLoader.item && typeof(busyLoader.item) != "undefined") { busyLoader.item.disappear(); } } onBackgroundHintsChanged: { // print("plasmoid.backgroundHintsChanged"); updateBackgroundHints(); } } MouseArea { id: dragMouseArea anchors.fill: parent z: appletContainer.z - 2 visible: !plasmoid.immutable property int zoffset: 1000 drag.target: appletItem property bool dragging: false // Set by mouseListener.onPressAndHold -- drag.active only becomes true on movement. function endDrag() { appletItem.z = appletItem.z - zoffset; repositionTimer.running = false; placeHolderPaint.opacity = 0; animationsEnabled = true; root.layoutManager.positionItem(appletItem); root.layoutManager.save(); dragging = false; } onDraggingChanged: { cursorShape = dragging ? Qt.DragMoveCursor : Qt.ArrowCursor; } onPressed: { appletItem.z = appletItem.z + zoffset; animationsEnabled = plasmoid.configuration.pressToMove ? true : false; mouse.accepted = true; var x = Math.round(appletItem.x / root.layoutManager.cellSize.width) * root.layoutManager.cellSize.width; var y = Math.round(appletItem.y / root.layoutManager.cellSize.height) * root.layoutManager.cellSize.height; root.layoutManager.setSpaceAvailable(x, y, appletItem.width, appletItem.height, true); placeHolder.syncWithItem(appletItem); placeHolderPaint.opacity = root.haloOpacity; } onPositionChanged: { var pos = mapToItem(root.parent, mouse.x, mouse.y); var newCont = plasmoid.containmentAt(pos.x, pos.y); if (newCont && newCont != plasmoid) { var newPos = newCont.mapFromApplet(plasmoid, pos.x, pos.y); newCont.addApplet(appletItem.applet, newPos.x, newPos.y); placeHolderPaint.opacity = 0; } else { placeHolder.syncWithItem(appletItem); } } onCanceled: { endDrag(); appletHandle.positionHandle(); } onReleased: { endDrag(); appletHandle.positionHandle(); } } Item { id: appletContainer anchors { fill: parent leftMargin: plasmoidBackground.margins.left rightMargin: plasmoidBackground.margins.right + handleWidth topMargin: plasmoidBackground.margins.top bottomMargin: plasmoidBackground.margins.bottom } z: mouseListener.z+1 property QtObject applet property var minimumSize: { var size; if (applet && applet.Layout) { var layout = applet.Layout size = { 'width': layout.minimumWidth, 'height': layout.minimumHeight }; } else { size = { 'width': 0, 'height': 0 }; } return size; } property int minimumWidth: minimumSize.width; property int minimumHeight: minimumSize.height; function appletDestroyed() { // print("Applet DESTROYED."); root.layoutManager.setSpaceAvailable(appletItem.x, appletItem.y, appletItem.width, appletItem.height, true) applet.action("remove").trigger(); appletItem.destroy() } onAppletChanged: { if (!applet) { return; } applet.parent = appletContainer; applet.anchors.fill = appletContainer; updateBackgroundHints(); } Connections { target: appletHandle.item onRemoveApplet: { killAnim.running = true; } } Behavior on opacity { NumberAnimation { duration: units.longDuration easing.type: Easing.InOutQuad } } SequentialAnimation { id: killAnim PlasmaExtras.DisappearAnimation { targetItem: appletItem } ScriptAction { script: { appletItem.scale = 1; appletContainer.appletDestroyed(); } } } Loader { id: busyLoader anchors.centerIn: parent z: appletContainer.z + 1 } // Rectangle { color: "green"; opacity: 0.3; visible: debug; anchors.fill: parent; } Component.onCompleted: PlasmaExtras.AppearAnimation { targetItem: appletItem } } Loader { id: appletHandle z: appletContainer.z + 1 property bool forceFloating : false anchors { verticalCenter: parent.verticalCenter right: plasmoidBackground.right } Connections { target: appletItem onShowAppletHandleChanged: { if (appletItem.showAppletHandle) { appletItem.z += dragMouseArea.zoffset; appletHandle.positionHandle(); if (appletHandle.source == "") { appletHandle.source = "AppletHandle.qml"; } } else { appletItem.z -= dragMouseArea.zoffset; } } onHandleMergedChanged: { if (appletItem.handleMerged) { appletHandle.anchors.verticalCenterOffset = 0; } else { appletHandle.positionHandle(); } } } Connections { target: appletHandle.item onMoveFinished: { appletHandle.positionHandle(); } } function positionHandle() { // Don't show handle outside of desktop var available = plasmoid.availableScreenRect; var x = Math.min(Math.max(0, appletItem.x), available.width - appletItem.width); var y = Math.min(Math.max(0, appletItem.y), available.height - appletItem.height); var verticalCenter = (y + appletItem.height / 2); var topOutside = (verticalCenter - minimumHandleHeight / 2); var bottomOutside = verticalCenter + minimumHandleHeight / 2 - available.height; if (bottomOutside > 0) { anchors.verticalCenterOffset = -bottomOutside; } else if (topOutside < 0) { anchors.verticalCenterOffset = -topOutside; } else { anchors.verticalCenterOffset = 0; } var rightOutside = x + appletItem.width + handleWidth - available.width; appletHandle.anchors.rightMargin = appletItem.margins.right + Math.max(0, rightOutside); appletHandle.forceFloating = rightOutside > 0; } } // Rectangle { color: "orange"; opacity: 0.1; visible: debug; anchors.fill: parent; } } } Behavior on controlsOpacity { NumberAnimation { duration: units.longDuration easing.type: Easing.InOutQuad } } Behavior on x { enabled: animationsEnabled NumberAnimation { duration: units.longDuration easing.type: Easing.InOutQuad } } Behavior on y { enabled: animationsEnabled NumberAnimation { duration: units.longDuration easing.type: Easing.InOutQuad } } Behavior on width { enabled: animationsEnabled NumberAnimation { id: widthAnimation duration: units.longDuration easing.type: Easing.InOutQuad } } Behavior on height { enabled: animationsEnabled NumberAnimation { id: heightAnimation duration: units.longDuration easing.type: Easing.InOutQuad } } Component.onCompleted: { layoutTimer.running = true layoutTimer.restart() visible = false // restore rotation } } diff --git a/containments/desktop/package/contents/ui/main.qml b/containments/desktop/package/contents/ui/main.qml index 1abba15fa..12b7bad73 100644 --- a/containments/desktop/package/contents/ui/main.qml +++ b/containments/desktop/package/contents/ui/main.qml @@ -1,562 +1,563 @@ /*************************************************************************** * Copyright (C) 2011-2013 Sebastian Kügler * * Copyright (C) 2011 Marco Martin * * Copyright (C) 2014-2015 by Eike Hein * * * * 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 02110-1301 USA . * ***************************************************************************/ import QtQuick 2.0 import QtQuick.Layouts 1.1 import org.kde.plasma.plasmoid 2.0 import org.kde.plasma.core 2.0 as PlasmaCore import org.kde.plasma.components 2.0 as PlasmaComponents import org.kde.draganddrop 2.0 as DragDrop import org.kde.kquickcontrolsaddons 2.0 as KQuickControlsAddons import org.kde.private.desktopcontainment.desktop 0.1 as Desktop import "LayoutManager.js" as LayoutManager DragDrop.DropArea { id: root objectName: isFolder ? "folder" : "desktop" width: isPopup ? undefined : preferredWidth() // for the initial size when placed on the desktop Layout.preferredWidth: isPopup ? preferredWidth() : 0 // for the popup size to change at runtime when view mode changes height: isPopup ? undefined : preferredHeight() Layout.preferredHeight: isPopup ? preferredHeight() : 0 property bool isFolder: (plasmoid.pluginName == "org.kde.plasma.folder") property bool isContainment: ("containmentType" in plasmoid) property bool isPopup: (plasmoid.location != PlasmaCore.Types.Floating) property bool useListViewMode: isPopup && plasmoid.configuration.viewMode === 0 property Item toolBox property var layoutManager: LayoutManager property bool debug: false property int handleDelay: 800 property real haloOpacity: 0.5 property int iconSize: units.iconSizes.small property int iconWidth: iconSize property int iconHeight: iconWidth preventStealing: true // Plasmoid.title is set by a Binding {} in FolderViewLayer Plasmoid.toolTipSubText: "" Plasmoid.icon: (!plasmoid.configuration.useCustomIcon && folderViewLayer.ready) ? folderViewLayer.view.model.iconName : plasmoid.configuration.icon Plasmoid.compactRepresentation: (isFolder && !isContainment) ? compactRepresentation : null Plasmoid.associatedApplicationUrls: folderViewLayer.ready ? folderViewLayer.model.resolvedUrl : null onIconHeightChanged: updateGridSize() anchors { leftMargin: plasmoid.availableScreenRect ? plasmoid.availableScreenRect.x : 0 topMargin: plasmoid.availableScreenRect ? plasmoid.availableScreenRect.y : 0 // Don't apply the right margin if the folderView is in column mode and not overflowing. // In this way, the last column remains droppable even if a small part of the icon is behind a panel. rightMargin: folderViewLayer.ready && (folderViewLayer.view.overflowing || folderViewLayer.view.flow == GridView.FlowLeftToRight) && plasmoid.availableScreenRect && parent ? parent.width - (plasmoid.availableScreenRect.x + plasmoid.availableScreenRect.width) : 0 // Same mechanism as the right margin but applied here to the bottom when the folderView is in row mode. bottomMargin: folderViewLayer.ready && (folderViewLayer.view.overflowing || folderViewLayer.view.flow == GridView.FlowTopToBottom) && plasmoid.availableScreenRect && parent ? parent.height - (plasmoid.availableScreenRect.y + plasmoid.availableScreenRect.height) : 0 } function updateGridSize() { LayoutManager.cellSize.width = root.iconWidth + toolBoxSvg.elementSize("left").width + toolBoxSvg.elementSize("right").width LayoutManager.cellSize.height = root.iconHeight + toolBoxSvg.elementSize("top").height + toolBoxSvg.elementSize("bottom").height; LayoutManager.defaultAppletSize.width = LayoutManager.cellSize.width * 6; LayoutManager.defaultAppletSize.height = LayoutManager.cellSize.height * 6; layoutTimer.restart(); } function addLauncher(desktopUrl) { if (!isFolder) { return; } folderViewLayer.view.linkHere(desktopUrl); } function addApplet(applet, x, y) { var component = Qt.createComponent("AppletAppearance.qml"); var e = component.errorString(); if (e != "") { print("Error loading AppletAppearance.qml: " + component.errorString()); } var container = component.createObject(resultsFlow) applet.parent = container applet.visible = true; container.category = "Applet-" + applet.id; var config = LayoutManager.itemsConfig[container.category]; // We have it in the config. if (config !== undefined && config.width !== undefined && config.height !== undefined && config.width > 0 && config.height > 0) { container.width = config.width; container.height = config.height; // We have a default. } else if (applet.width > 0 && applet.height > 0) { container.width = applet.width; container.height = applet.height; // The container needs to be bigger than applet of margins factor. if (applet.backgroundHints != PlasmaCore.Types.NoBackground) { container.width += container.margins.left + container.margins.right; container.height += container.margins.top + container.margins.bottom; } // Give up, assign the global default. } else { container.width = LayoutManager.defaultAppletSize.width; container.height = LayoutManager.defaultAppletSize.height; } container.applet = applet; // Coordinated passed by param? if ( x >= 0 && y >= 0) { if (x + container.width > root.width) { x = root.width - container.width - 10; } if (y + container.height > root.height) { x = root.height - container.height; } // On applet undo or via scripting, the applet position will be saved // in applet's scene coordinates so remap it to resultsflow's coordinates. var pos = root.parent.mapToItem(resultsFlow, x, y); container.x = pos.x; container.y = pos.y; // To be sure it's restored at the same position, take margins into account // if there is a background. if (applet.backgroundHints != PlasmaCore.Types.NoBackground) { container.x -= container.margins.left; container.y -= container.margins.top; } // Coordinates stored? } else if (config !== undefined && config.x !== undefined && config.y !== undefined && config.x >= 0 && config.y >= 0) { container.x = config.x; container.y = config.y; } // Rotation stored and significant? if (config !== undefined && config.rotation !== undefined && (config.rotation > 5 || config.rotation < -5)) { container.rotation = config.rotation; } LayoutManager.itemGroups[container.category] = container; if (container.x >= 0 && container.y >= 0) { LayoutManager.positionItem(container); } } function preferredWidth() { if (isContainment || !folderViewLayer.ready) { return undefined; } else if (useListViewMode) { return units.gridUnit * 16; } return (folderViewLayer.view.cellWidth * 3) + (units.largeSpacing * 2); } function preferredHeight() { if (isContainment || !folderViewLayer.ready) { return undefined; } else if (useListViewMode) { var height = (folderViewLayer.view.cellHeight * 15) + units.smallSpacing; } else { var height = (folderViewLayer.view.cellHeight * 2) + units.largeSpacing } if (plasmoid.configuration.labelMode != 0) { height += folderViewLayer.item.labelHeight; } return height } onDragEnter: { if (isContainment && plasmoid.immutable) { event.ignore(); } } onDragMove: { // TODO: We should reject drag moves onto file items that don't accept drops // (cf. QAbstractItemModel::flags() here, but DeclarativeDropArea currently // is currently incapable of rejecting drag events. var arkService = event.mimeData.formats.indexOf("application/x-kde-ark-dndextract-service") != -1; var arkPath = event.mimeData.formats.indexOf("application/x-kde-ark-dndextract-path") != -1; // Trigger autoscroll. if (isFolder && (event.mimeData.hasUrls || (arkService && arkPath))) { folderViewLayer.view.scrollLeft = (event.x < (units.largeSpacing * 3)); folderViewLayer.view.scrollRight = (event.x > width - (units.largeSpacing * 3)); folderViewLayer.view.scrollUp = (event.y < (units.largeSpacing * 3)); folderViewLayer.view.scrollDown = (event.y > height - (units.largeSpacing * 3)); } else if (isContainment) { placeHolder.width = LayoutManager.defaultAppletSize.width; placeHolder.height = LayoutManager.defaultAppletSize.height; placeHolder.minimumWidth = placeHolder.minimumHeight = 0; placeHolder.x = event.x - placeHolder.width / 2; placeHolder.y = event.y - placeHolder.width / 2; LayoutManager.positionItem(placeHolder); LayoutManager.setSpaceAvailable(placeHolder.x, placeHolder.y, placeHolder.width, placeHolder.height, true); placeHolderPaint.opacity = root.haloOpacity; } } onDragLeave: { // Cancel autoscroll. if (isFolder) { folderViewLayer.view.scrollLeft = false; folderViewLayer.view.scrollRight = false; folderViewLayer.view.scrollUp = false; folderViewLayer.view.scrollDown = false; } if (isContainment) { placeHolderPaint.opacity = 0; } } onDrop: { var arkService = event.mimeData.formats.indexOf("application/x-kde-ark-dndextract-service") != -1; var arkPath = event.mimeData.formats.indexOf("application/x-kde-ark-dndextract-path") != -1; if (isFolder && (event.mimeData.hasUrls || (arkService && arkPath))) { // Cancel autoscroll. folderViewLayer.view.scrollLeft = false; folderViewLayer.view.scrollRight = false; folderViewLayer.view.scrollUp = false; folderViewLayer.view.scrollDown = false; folderViewLayer.view.drop(root, event, mapToItem(folderViewLayer.view, event.x, event.y)); } else if (isContainment) { placeHolderPaint.opacity = 0; - plasmoid.processMimeData(event.mimeData, event.x - placeHolder.width / 2, event.y - placeHolder.height / 2); + var pos = root.parent.mapFromItem(resultsFlow, event.x - placeHolder.width / 2, event.y - placeHolder.height / 2); + plasmoid.processMimeData(event.mimeData, pos.x, pos.y); event.accept(event.proposedAction); } } Component { id: compactRepresentation CompactRepresentation { folderView: folderViewLayer.view } } Connections { target: plasmoid ignoreUnknownSignals: true onAppletAdded: { addApplet(applet, x, y); // Clean any eventual invalid chunks in the config. LayoutManager.save(); } onAppletRemoved: { // Clean any eventual invalid chunks in the config. LayoutManager.removeApplet(applet); LayoutManager.save(); } onImmutableChanged: { if (!plasmoid.immutable) { pressToMoveHelp.show(); } } onAvailableScreenRegionChanged: layoutTimer.restart(); } Connections { target: plasmoid.configuration onPressToMoveChanged: { if (plasmoid.configuration.pressToMove && plasmoid.configuration.pressToMoveHelp && !plasmoid.immutable) { pressToMoveHelp.show(); } } } Binding { target: toolBox property: "visible" value: plasmoid.configuration.showToolbox } Desktop.InfoNotification { id: pressToMoveHelp enabled: plasmoid.configuration.pressToMove && plasmoid.configuration.pressToMoveHelp iconName: "plasma" titleText: i18n("Widgets unlocked") text: i18n("You can press and hold widgets to move them and reveal their handles.") acknowledgeActionText: i18n("Got it") onAcknowledged: { plasmoid.configuration.pressToMoveHelp = false; } } PlasmaCore.FrameSvgItem { id : highlightItemSvg visible: false imagePath: isPopup ? "widgets/viewitem" : "" prefix: "hover" } PlasmaCore.FrameSvgItem { id : listItemSvg visible: false imagePath: isPopup ? "widgets/viewitem" : "" prefix: "normal" } PlasmaCore.Svg { id: toolBoxSvg imagePath: "widgets/toolbox" property int rightBorder: elementSize("right").width property int topBorder: elementSize("top").height property int bottomBorder: elementSize("bottom").height property int leftBorder: elementSize("left").width } PlasmaCore.Svg { id: configIconsSvg imagePath: "widgets/configuration-icons" } Desktop.SystemSettings { id: systemSettings } KQuickControlsAddons.EventGenerator { id: eventGenerator } MouseArea { // unfocus any plasmoid when clicking empty desktop area anchors.fill: parent onPressed: { root.forceActiveFocus() mouse.accepted = false // Bug 351277 } } Loader { id: folderViewLayer anchors.fill: parent property bool ready: status == Loader.Ready property Item view: item ? item.view : null property QtObject model: item ? item.model : null focus: true active: isFolder asynchronous: false source: "FolderViewLayer.qml" onFocusChanged: { if (!focus && model) { model.clearSelection(); } } Connections { target: folderViewLayer.view onPressed: { folderViewLayer.focus = true; } } } Item { id: resultsFlow anchors.fill: parent anchors { top: parent.top topMargin: 5 horizontalCenter: parent.horizontalCenter } visible: isContainment enabled: isContainment // This is just for event compression when a lot of boxes are created one after the other. Timer { id: layoutTimer repeat: false running: false interval: 100 onTriggered: { LayoutManager.resetPositions() for (var i=0; i * * 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.Layouts 1.0 import org.kde.plasma.components 2.0 as PlasmaComponents import org.kde.plasma.core 2.0 as PlasmaCore import org.kde.plasma.configuration 2.0 Item { id: root state: parent.state implicitWidth: Math.max(buttonsLayout.width, row.width) + units.smallSpacing * 2 implicitHeight: row.height + 20 readonly property string addWidgetsButtonText: i18nd("plasma_shell_org.kde.plasma.desktop", "Add Widgets...") readonly property string addSpacerButtonText: i18nd("plasma_shell_org.kde.plasma.desktop", "Add Spacer") readonly property string settingsButtonText: i18nd("plasma_shell_org.kde.plasma.desktop", "More Settings...") GridLayout { id: row columns: dialogRoot.vertical ? 1 : 2 rows: dialogRoot.vertical ? 2 : 1 anchors.centerIn: parent rowSpacing: units.smallSpacing columnSpacing: units.smallSpacing EdgeHandle { Layout.alignment: Qt.AlignHCenter } SizeHandle { Layout.alignment: Qt.AlignHCenter } } PlasmaComponents.Label { id: placeHolder visible: false text: addWidgetsButtonText + addSpacerButtonText + settingsButtonText } Connections { target: configDialog onVisibleChanged: { if (!configDialog.visible) { settingsButton.checked = false } } } GridLayout { id: buttonsLayout rows: 1 columns: 1 flow: plasmoid.formFactor == PlasmaCore.Types.Horizontal ? GridLayout.TopToBottom : GridLayout.LeftToRight anchors.margins: rowSpacing property bool showText: plasmoid.formFactor == PlasmaCore.Types.Vertical || (row.x + row.width < root.width - placeHolder.width - units.iconSizes.small*4 - units.largeSpacing*5) rowSpacing: units.smallSpacing columnSpacing: units.smallSpacing PlasmaComponents.Button { text: buttonsLayout.showText ? root.addWidgetsButtonText : "" tooltip: buttonsLayout.showText ? "" : root.addWidgetsButtonText iconSource: "list-add" Layout.fillWidth: true onClicked: { configDialog.close(); configDialog.showAddWidgetDialog(); } } PlasmaComponents.Button { iconSource: "distribute-horizontal-x" text: buttonsLayout.showText ? root.addSpacerButtonText : "" tooltip: buttonsLayout.showText ? "" : root.addSpacerButtonText Layout.fillWidth: true onClicked: { configDialog.addPanelSpacer(); } } PlasmaComponents.Button { id: settingsButton iconSource: "configure" text: buttonsLayout.showText ? root.settingsButtonText : "" tooltip: buttonsLayout.showText ? "" : root.settingsButtonText Layout.fillWidth: true checkable: true onCheckedChanged: { if (checked) { contextMenuLoader.open() } else { contextMenuLoader.close() } } } PlasmaComponents.ToolButton { parent: plasmoid.formFactor == PlasmaCore.Types.Horizontal ? buttonsLayout : root anchors.right: plasmoid.formFactor == PlasmaCore.Types.Horizontal ? undefined : parent.right iconSource: "window-close" tooltip: i18nd("plasma_shell_org.kde.plasma.desktop", "Close") onClicked: { configDialog.close() } } Loader { id: contextMenuLoader property bool opened: item && item.visible + onOpenedChanged: settingsButton.checked = opened source: "MoreSettingsMenu.qml" active: false function open() { active = true item.visible = true } function close() { if (item) { item.visible = false } } } } //BEGIN States states: [ State { name: "TopEdge" PropertyChanges { target: root height: root.implicitHeight } AnchorChanges { target: root anchors { top: undefined bottom: root.parent.bottom left: root.parent.left right: root.parent.right } } AnchorChanges { target: buttonsLayout anchors { verticalCenter: root.verticalCenter top: undefined bottom: undefined left: undefined right: root.right } } PropertyChanges { target: buttonsLayout width: buttonsLayout.implicitWidth } }, State { name: "BottomEdge" PropertyChanges { target: root height: root.implicitHeight } AnchorChanges { target: root anchors { top: root.parent.top bottom: undefined left: root.parent.left right: root.parent.right } } AnchorChanges { target: buttonsLayout anchors { verticalCenter: root.verticalCenter top: undefined bottom: undefined left: undefined right: root.right } } PropertyChanges { target: buttonsLayout width: buttonsLayout.implicitWidth } }, State { name: "LeftEdge" PropertyChanges { target: root width: root.implicitWidth } AnchorChanges { target: root anchors { top: root.parent.top bottom: root.parent.bottom left: undefined right: root.parent.right } } AnchorChanges { target: buttonsLayout anchors { verticalCenter: undefined top: undefined bottom: root.bottom left: root.left right: root.right } } }, State { name: "RightEdge" PropertyChanges { target: root width: root.implicitWidth } AnchorChanges { target: root anchors { top: root.parent.top bottom: root.parent.bottom left: root.parent.left right: undefined } } AnchorChanges { target: buttonsLayout anchors { verticalCenter: undefined top: undefined bottom: root.bottom left: root.left right: root.right } } } ] //END States } diff --git a/kcms/lookandfeel/autotests/lookandfeel/metadata.desktop b/kcms/lookandfeel/autotests/lookandfeel/metadata.desktop index d7f6a4af4..4975ff02d 100644 --- a/kcms/lookandfeel/autotests/lookandfeel/metadata.desktop +++ b/kcms/lookandfeel/autotests/lookandfeel/metadata.desktop @@ -1,77 +1,94 @@ [Desktop Entry] Comment=Test Look and Feel package Comment[ast]=Paquete d'aspeutu y sentir de prueba Comment[bs]=Test paketa Pogledaj i Osjeti Comment[ca]=Prova el paquet d'aspecte i comportament Comment[ca@valencia]=Prova el paquet d'aspecte i comportament +Comment[cs]=Otestovat balíček vzhledu a chování Comment[da]=Test pakke med udseende og fremtoning Comment[de]=Testpaket für das Erscheinungsbild Comment[el]=Δοκιμή του πακέτου εμφάνισης και αίσθησης Comment[en_GB]=Test Look and Feel package Comment[es]=Probar paquete de aspecto visual Comment[et]=Välimuse testimine +Comment[fr]=Tester le paquet d'apparence Comment[gl]=Paquete de aparencia e comportamento de probas Comment[hu]=A megjelenés csomag tesztelése Comment[id]=Paket Tes Lihat dan Rasakan Comment[it]=Prova il pacchetto dell'aspetto Comment[ja]=外観パッケージをテスト Comment[ko]=모습과 느낌 테스트 패키지 +Comment[nb]=Test pakka Utseende og oppførsel Comment[nds]=Test-Utsehn- un Bedenen-Paket Comment[nl]=Pakket voor uiterlijk en gedrag testen +Comment[nn]=Testpakke for utsjånad og åtferd Comment[pl]=Wypróbuj pakiet wrażeń wzrokowych i dotykowych Comment[pt]=Pacote de teste da Aparência e Comportamento Comment[pt_BR]=Pacote de teste de Aparência Comment[ru]=Тестовое оформление рабочей среды Comment[sk]=Balík pre vzhľad a nastavenie Comment[sl]=Preizkusni paket za Videz in občutek +Comment[sr]=Пробни пакет изгледа и осећаја +Comment[sr@ijekavian]=Пробни пакет изгледа и осећаја +Comment[sr@ijekavianlatin]=Probni paket izgleda i osećaja +Comment[sr@latin]=Probni paket izgleda i osećaja Comment[sv]=Prova paket för utseende och känsla Comment[tr]=Görünüm ve Duyum paketini dene Comment[uk]=Перевірка пакунка вигляду і поведінки Comment[x-test]=xxTest Look and Feel packagexx Comment[zh_CN]=测试观感包 Comment[zh_TW]=測試外觀與感覺套件 Encoding=UTF-8 Name=Test Name[bs]=Test Name[ca]=Prova Name[ca@valencia]=Prova +Name[cs]=Test Name[da]=Test Name[de]=Test Name[el]=Δοκιμή Name[en_GB]=Test Name[es]=Probar Name[et]=Test +Name[fr]=Tester Name[gl]=Proba Name[hu]=Teszt Name[id]=Tes Name[it]=Prova Name[ja]=テスト Name[ko]=시험 +Name[nb]=Test Name[nds]=Test Name[nl]=Test +Name[nn]=Test Name[pa]=ਟੈਸਟ Name[pl]=Próba Name[pt]=Teste Name[pt_BR]=Teste Name[ru]=Тест +Name[se]=Geahččaleapmi Name[sk]=Test Name[sl]=Preizkus +Name[sr]=Проба +Name[sr@ijekavian]=Проба +Name[sr@ijekavianlatin]=Proba +Name[sr@latin]=Proba Name[sv]=Prova Name[tr]=Test Name[uk]=Тест Name[x-test]=xxTestxx Name[zh_CN]=测试 Name[zh_TW]=測試 Type=Service X-KDE-ServiceTypes=Plasma/LookAndFeel X-KDE-ParentApp= X-KDE-PluginInfo-Author=KDE Visual Design Group X-KDE-PluginInfo-Category= X-KDE-PluginInfo-Email=plasma-devel@kde.org X-KDE-PluginInfo-License=GPLv2+ X-KDE-PluginInfo-Name=org.kde.test X-KDE-PluginInfo-Version=2.0 X-KDE-PluginInfo-Website=http://www.kde.org X-Plasma-MainScript=defaults diff --git a/toolboxes/desktoptoolbox/contents/ui/ToolBoxItem.qml b/toolboxes/desktoptoolbox/contents/ui/ToolBoxItem.qml index 1c3c03c61..baf7c6efa 100644 --- a/toolboxes/desktoptoolbox/contents/ui/ToolBoxItem.qml +++ b/toolboxes/desktoptoolbox/contents/ui/ToolBoxItem.qml @@ -1,154 +1,155 @@ /*************************************************************************** * Copyright 2012 by Sebastian Kügler * * Copyright 2015 by Kai Uwe Broulik * * * * 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 02110-1301 USA . * ***************************************************************************/ import QtQuick 2.0 import QtQuick.Layouts 1.1 import org.kde.plasma.core 2.0 as PlasmaCore import org.kde.plasma.components 2.0 as PlasmaComponents ListView { id: menu width: units.gridUnit * 14 height: contentHeight currentIndex: -1 focus: true keyNavigationWraps: true onVisibleChanged: currentIndex = -1 // needs to be on released, otherwise Dashboard hides because it already gained focus // because of the dialog closing right on the key *press* event Keys.onReleased: { if (event.key === Qt.Key_Escape) { toolBoxLoader.item.visible = false event.accepted = true } } Keys.onPressed: { if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) { if (currentIndex >= 0) { if (model[currentIndex].operation) { performOperation(model[currentIndex].operation) } else { model[currentIndex].trigger() } } toolBoxLoader.item.visible = false event.accepted = true } } function performOperation(what) { var service = dataEngine.serviceForSource("PowerDevil"); var operation = service.operationDescription(what); return service.startOperationCall(operation); } highlightMoveDuration: 0 highlightResizeDuration: 0 highlight: PlasmaComponents.Highlight { } PlasmaCore.DataSource { id: dataEngine engine: "powermanagement" connectedSources: ["PowerDevil", "Sleep States"] } model: { var model = [] var actions = plasmoid.actions for (var i = 0, j = actions.length; i < j; ++i) { var action = actions[i] if (action && action.visible && action.text !== "") { model.push(action) } } if (dataEngine.data["Sleep States"].LockScreen) { model.push({ text: i18nd("plasma_toolbox_org.kde.desktoptoolbox", "Lock Screen"), icon: "system-lock-screen", visible: true, enabled: true, operation: "lockScreen" }) } model.push({ text: i18nd("plasma_toolbox_org.kde.desktoptoolbox", "Leave"), icon: "system-log-out", visible: true, enabled: true, operation: "requestShutDown" // cannot put function() into a model :( }) return model } delegate: MouseArea { width: menu.width height: labelRow.implicitHeight + units.smallSpacing * 2 hoverEnabled: true enabled: modelData.enabled opacity: modelData.enabled ? 1 : 0.5 onEntered: menu.currentIndex = index onExited: menu.currentIndex = -1 onClicked: { if (modelData.operation) { performOperation(modelData.operation) } else { modelData.trigger() } toolBoxLoader.item.visible = false } Accessible.role: Accessible.MenuItem Accessible.name: textLabel.text RowLayout { id: labelRow anchors { left: parent.left right: parent.right margins: units.smallSpacing verticalCenter: parent.verticalCenter } spacing: units.smallSpacing PlasmaCore.IconItem { width: units.iconSizes.medium height: width source: modelData.icon Accessible.ignored: true } PlasmaComponents.Label { id: textLabel Layout.fillWidth: true text: modelData.text.replace("&", "") // hack to get rid of keyboard accelerator hints + elide: Text.ElideRight Accessible.ignored: true } } } }