diff --git a/applets/kicker/package/contents/code/tools.js b/applets/kicker/package/contents/code/tools.js index 9a26eef62..da2cf5866 100644 --- a/applets/kicker/package/contents/code/tools.js +++ b/applets/kicker/package/contents/code/tools.js @@ -1,202 +1,204 @@ /*************************************************************************** * Copyright (C) 2013 by Aurélien Gâteau * * Copyright (C) 2013-2015 by Eike Hein * * Copyright (C) 2017 by Ivan Cukic * * * * 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 . * ***************************************************************************/ -function fillActionMenu(actionMenu, actionList, favoriteModel, favoriteId) { +.pragma library + +function fillActionMenu(i18n, actionMenu, actionList, favoriteModel, favoriteId) { // Accessing actionList can be a costly operation, so we don't // access it until we need the menu. - var actions = createFavoriteActions(favoriteModel, favoriteId); + var actions = createFavoriteActions(i18n, favoriteModel, favoriteId); if (actions) { if (actionList && actionList.length > 0) { var separator = { "type": "separator" }; actionList.push(separator); // actionList = actions.concat(actionList); // this crashes Qt O.o actionList.push.apply(actionList, actions); } else { actionList = actions; } } actionMenu.actionList = actionList; } -function createFavoriteActions(favoriteModel, favoriteId) { +function createFavoriteActions(i18n, favoriteModel, favoriteId) { if (favoriteModel === null || !favoriteModel.enabled || favoriteId == null) { return null; } if (favoriteModel.activities === undefined || favoriteModel.activities.runningActivities.length <= 1) { var action = {}; if (favoriteModel.isFavorite(favoriteId)) { action.text = i18n("Remove from Favorites"); action.icon = "list-remove"; action.actionId = "_kicker_favorite_remove"; } else if (favoriteModel.maxFavorites == -1 || favoriteModel.count < favoriteModel.maxFavorites) { action.text = i18n("Add to Favorites"); action.icon = "bookmark-new"; action.actionId = "_kicker_favorite_add"; } else { return null; } action.actionArgument = { favoriteModel: favoriteModel, favoriteId: favoriteId }; return [action]; } else { var actions = []; var linkedActivities = favoriteModel.linkedActivitiesFor(favoriteId); var activities = favoriteModel.activities.runningActivities; // Adding the item to link/unlink to all activities var linkedToAllActivities = !(linkedActivities.indexOf(":global") === -1); actions.push({ text : i18n("On All Activities"), checkable : true, actionId : linkedToAllActivities ? "_kicker_favorite_remove_from_activity" : "_kicker_favorite_set_to_activity", checked : linkedToAllActivities, actionArgument : { favoriteModel: favoriteModel, favoriteId: favoriteId, favoriteActivity: "" } }); // Adding items for each activity separately var addActivityItem = function(activityId, activityName) { var linkedToThisActivity = !(linkedActivities.indexOf(activityId) === -1); actions.push({ text : activityName, checkable : true, checked : linkedToThisActivity && !linkedToAllActivities, actionId : // If we are on all activities, and the user clicks just one // specific activity, unlink from everything else linkedToAllActivities ? "_kicker_favorite_set_to_activity" : // If we are linked to the current activity, just unlink from // that single one linkedToThisActivity ? "_kicker_favorite_remove_from_activity" : // Otherwise, link to this activity, but do not unlink from // other ones "_kicker_favorite_add_to_activity", actionArgument : { favoriteModel : favoriteModel, favoriteId : favoriteId, favoriteActivity : activityId } }); }; // Adding the item to link/unlink to the current activity addActivityItem(favoriteModel.activities.currentActivity, i18n("On The Current Activity")); actions.push({ type: "separator", actionId: "_kicker_favorite_separator" }); // Adding the items for each activity activities.forEach(function(activityId) { addActivityItem(activityId, favoriteModel.activityNameForId(activityId)); }); return [{ text : i18n("Show In Favorites"), icon : "favorite", subActions : actions }]; } } function triggerAction(model, index, actionId, actionArgument) { function startsWith(txt, needle) { return txt.substr(0, needle.length) === needle; } if (startsWith(actionId, "_kicker_favorite_")) { handleFavoriteAction(actionId, actionArgument); return; } var closeRequested = model.trigger(index, actionId, actionArgument); if (closeRequested) { plasmoid.expanded = false; return true; } return false; } function handleFavoriteAction(actionId, actionArgument) { var favoriteId = actionArgument.favoriteId; var favoriteModel = actionArgument.favoriteModel; console.log(actionId); if (favoriteModel === null || favoriteId == null) { return null; } if (actionId == "_kicker_favorite_remove") { console.log("Removing from all activities"); favoriteModel.removeFavorite(favoriteId); } else if (actionId == "_kicker_favorite_add") { console.log("Adding to global activity"); favoriteModel.addFavorite(favoriteId); } else if (actionId == "_kicker_favorite_remove_from_activity") { console.log("Removing from a specific activity"); favoriteModel.removeFavoriteFrom(favoriteId, actionArgument.favoriteActivity); } else if (actionId == "_kicker_favorite_add_to_activity") { console.log("Adding to another activity"); favoriteModel.addFavoriteTo(favoriteId, actionArgument.favoriteActivity); } else if (actionId == "_kicker_favorite_set_to_activity") { console.log("Removing the item from the favourites, and re-adding it just to be on a specific activity"); favoriteModel.setFavoriteOn(favoriteId, actionArgument.favoriteActivity); } } diff --git a/applets/kicker/package/contents/ui/DashboardRepresentation.qml b/applets/kicker/package/contents/ui/DashboardRepresentation.qml index 1132c4836..8a9775281 100644 --- a/applets/kicker/package/contents/ui/DashboardRepresentation.qml +++ b/applets/kicker/package/contents/ui/DashboardRepresentation.qml @@ -1,1068 +1,1068 @@ /*************************************************************************** * Copyright (C) 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.4 import QtGraphicalEffects 1.0 import org.kde.plasma.core 2.1 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 import org.kde.kwindowsystem 1.0 import org.kde.plasma.private.shell 2.0 import org.kde.plasma.private.kicker 0.1 as Kicker import "../code/tools.js" as Tools /* TODO * Reverse middleRow layout + keyboard nav + filter list text alignment in rtl locales. * Keep cursor column when arrow'ing down past non-full trailing rows into a lower grid. * Make DND transitions cleaner by performing an item swap instead of index reinsertion. */ Kicker.DashboardWindow { id: root property bool smallScreen: ((Math.floor(width / units.iconSizes.huge) <= 22) || (Math.floor(height / units.iconSizes.huge) <= 14)) property int iconSize: smallScreen ? units.iconSizes.large : units.iconSizes.huge property int cellSize: iconSize + theme.mSize(theme.defaultFont).height + (2 * units.smallSpacing) + (2 * Math.max(highlightItemSvg.margins.top + highlightItemSvg.margins.bottom, highlightItemSvg.margins.left + highlightItemSvg.margins.right)) property int columns: Math.floor(((smallScreen ? 85 : 80)/100) * Math.ceil(width / cellSize)) property bool searching: (searchField.text != "") property var widgetExplorer: null keyEventProxy: searchField backgroundColor: Qt.rgba(0, 0, 0, 0.737) onKeyEscapePressed: { if (searching) { searchField.clear(); } else { root.toggle(); } } onVisibleChanged: { tabBar.activeTab = 0; reset(); if (visible) { preloadAllAppsTimer.restart(); } } onSearchingChanged: { if (!searching) { reset(); } else { filterList.currentIndex = -1; if (tabBar.activeTab == 1) { widgetExplorer.widgetsModel.filterQuery = ""; widgetExplorer.widgetsModel.filterType = ""; } } } function reset() { searchField.clear(); globalFavoritesGrid.currentIndex = -1; systemFavoritesGrid.currentIndex = -1; filterList.currentIndex = 0; funnelModel.sourceModel = rootModel.modelForRow(0); mainGrid.model = (tabBar.activeTab == 0) ? funnelModel : root.widgetExplorer.widgetsModel; mainGrid.currentIndex = -1; filterListScrollArea.focus = true; filterList.model = (tabBar.activeTab == 0) ? rootModel : root.widgetExplorer.filterModel; } function updateWidgetExplorer() { if (tabBar.activeTab == 1 /* Widgets */ || tabBar.hoveredTab == 1) { if (!root.widgetExplorer) { root.widgetExplorer = widgetExplorerComponent.createObject(root, { containment: containmentInterface.screenContainment(plasmoid) }); } } else if (root.widgetExplorer) { root.widgetExplorer.destroy(); root.widgetExplorer = null; } } mainItem: MouseArea { id: rootItem anchors.fill: parent acceptedButtons: Qt.LeftButton | Qt.RightButton LayoutMirroring.enabled: Qt.application.layoutDirection == Qt.RightToLeft LayoutMirroring.childrenInherit: true Connections { target: kicker onReset: { if (!searching) { filterList.applyFilter(); if (tabBar.activeTab == 0) { funnelModel.reset(); } } } onDragSourceChanged: { if (!dragSource) { // FIXME TODO HACK: Reset all views post-DND to work around // mouse grab bug despite QQuickWindow::mouseGrabberItem==0x0. // Needs a more involved hunt through Qt Quick sources later since // it's not happening with near-identical code in the menu repr. rootModel.refresh(); } else if (tabBar.activeTab == 1) { root.toggle(); containmentInterface.ensureMutable(containmentInterface.screenContainment(plasmoid)); kwindowsystem.showingDesktop = true; } } } KWindowSystem { id: kwindowsystem } Component { id: widgetExplorerComponent WidgetExplorer { showSpecialFilters: false } } Connections { target: plasmoid onUserConfiguringChanged: { if (plasmoid.userConfiguring) { root.hide() } } } PlasmaComponents.Menu { id: contextMenu PlasmaComponents.MenuItem { action: plasmoid.action("configure") } } PlasmaExtras.Heading { id: dummyHeading visible: false width: 0 level: 1 } TextMetrics { id: headingMetrics font: dummyHeading.font } Kicker.FunnelModel { id: funnelModel onSourceModelChanged: { if (mainColumn.visible) { mainGrid.currentIndex = -1; mainGrid.forceLayout(); } } } Timer { id: preloadAllAppsTimer property bool done: false interval: 1000 repeat: false onTriggered: { if (done || searching) { return; } for (var i = 0; i < rootModel.count; ++i) { var model = rootModel.modelForRow(i); if (model.description == "KICKER_ALL_MODEL") { allAppsGrid.model = model; done = true; break; } } } function defer() { if (running && !done) { restart(); } } } Kicker.ContainmentInterface { id: containmentInterface } DashboardTabBar { id: tabBar y: 0 anchors.horizontalCenter: parent.horizontalCenter visible: (plasmoid.immutability !== PlasmaCore.Types.SystemImmutable) onActiveTabChanged: { updateWidgetExplorer(); reset(); } onHoveredTabChanged: updateWidgetExplorer() Keys.onDownPressed: { mainColumn.tryActivate(0, 0); } } PlasmaComponents.TextField { id: searchField width: 0 height: 0 visible: false onTextChanged: { if (tabBar.activeTab == 0) { runnerModel.query = searchField.text; } else { widgetExplorer.widgetsModel.searchTerm = searchField.text; } } function clear() { text = ""; } } PlasmaExtras.Heading { id: searchHeading anchors { horizontalCenter: parent.horizontalCenter } y: (middleRow.anchors.topMargin / 2) - (smallScreen ? (height/10) : 0) font.pointSize: dummyHeading.font.pointSize * 1.5 elide: Text.ElideRight wrapMode: Text.NoWrap opacity: 1.0 color: "white" level: 1 text: searching ? i18n("Searching for '%1'", searchField.text) : i18n("Type to search.") } PlasmaComponents.ToolButton { id: cancelSearchButton anchors { left: searchHeading.right leftMargin: units.largeSpacing verticalCenter: searchHeading.verticalCenter } width: units.iconSizes.large height: width visible: (searchField.text != "") iconName: "dialog-close" flat: false onClicked: searchField.clear(); Keys.onPressed: { if (event.key == Qt.Key_Tab) { event.accepted = true; if (runnerModel.count) { mainColumn.tryActivate(0, 0); } else { systemFavoritesGrid.tryActivate(0, 0); } } else if (event.key == Qt.Key_Backtab) { event.accepted = true; if (tabBar.visible) { tabBar.focus = true; } else if (globalFavoritesGrid.enabled) { globalFavoritesGrid.tryActivate(0, 0); } else { systemFavoritesGrid.tryActivate(0, 0); } } } } Row { id: middleRow anchors { top: parent.top topMargin: units.gridUnit * (smallScreen ? 8 : 10) bottom: parent.bottom bottomMargin: (units.gridUnit * 2) horizontalCenter: parent.horizontalCenter } width: (root.columns * cellSize) + (2 * spacing) spacing: units.gridUnit * 2 Item { id: favoritesColumn anchors { top: parent.top bottom: parent.bottom } width: (columns * cellSize) + units.gridUnit property int columns: 3 PlasmaExtras.Heading { id: favoritesColumnLabel enabled: (tabBar.activeTab == 0) anchors { top: parent.top } x: units.smallSpacing width: parent.width - x elide: Text.ElideRight wrapMode: Text.NoWrap color: "white" level: 1 text: i18n("Favorites") opacity: (enabled ? 1.0 : 0.3) Behavior on opacity { SmoothedAnimation { duration: units.longDuration; velocity: 0.01 } } } PlasmaCore.SvgItem { id: favoritesColumnLabelUnderline enabled: (tabBar.activeTab == 0) anchors { top: favoritesColumnLabel.bottom } width: parent.width - units.gridUnit height: lineSvg.horLineHeight svg: lineSvg elementId: "horizontal-line" opacity: (enabled ? 1.0 : 0.3) Behavior on opacity { SmoothedAnimation { duration: units.longDuration; velocity: 0.01 } } } ItemGridView { id: globalFavoritesGrid enabled: (tabBar.activeTab == 0) anchors { top: favoritesColumnLabelUnderline.bottom topMargin: units.largeSpacing } property int rows: (Math.floor((parent.height - favoritesColumnLabel.height - favoritesColumnLabelUnderline.height - units.largeSpacing) / cellSize) - systemFavoritesGrid.rows) width: parent.width height: rows * cellSize cellWidth: cellSize cellHeight: cellSize iconSize: root.iconSize model: globalFavorites dropEnabled: true usesPlasmaTheme: false opacity: (enabled ? 1.0 : 0.3) Behavior on opacity { SmoothedAnimation { duration: units.longDuration; velocity: 0.01 } } onCurrentIndexChanged: { preloadAllAppsTimer.defer(); } onKeyNavRight: { mainColumn.tryActivate(currentRow(), 0); } onKeyNavDown: { systemFavoritesGrid.tryActivate(0, currentCol()); } Keys.onPressed: { if (event.key == Qt.Key_Tab) { event.accepted = true; if (tabBar.visible) { tabBar.focus = true; } else if (searching) { cancelSearchButton.focus = true; } else { mainColumn.tryActivate(0, 0); } } else if (event.key == Qt.Key_Backtab) { event.accepted = true; systemFavoritesGrid.tryActivate(0, 0); } } Binding { target: globalFavorites property: "iconSize" value: root.iconSize } } ItemGridView { id: systemFavoritesGrid anchors { top: globalFavoritesGrid.bottom } property int rows: Math.ceil(count / Math.floor(width / cellSize)) width: parent.width height: rows * cellSize cellWidth: cellSize cellHeight: cellSize iconSize: root.iconSize model: systemFavorites dropEnabled: true usesPlasmaTheme: true onCurrentIndexChanged: { preloadAllAppsTimer.defer(); } onKeyNavRight: { mainColumn.tryActivate(globalFavoritesGrid.rows + currentRow(), 0); } onKeyNavUp: { globalFavoritesGrid.tryActivate(globalFavoritesGrid.rows - 1, currentCol()); } Keys.onPressed: { if (event.key == Qt.Key_Tab) { event.accepted = true; if (globalFavoritesGrid.enabled) { globalFavoritesGrid.tryActivate(0, 0); } else if (tabBar.visible) { tabBar.focus = true; } else if (searching && !runnerModel.count) { cancelSearchButton.focus = true; } else { mainColumn.tryActivate(0, 0); } } else if (event.key == Qt.Key_Backtab) { event.accepted = true; if (filterList.enabled) { filterList.forceActiveFocus(); } else if (searching && !runnerModel.count) { cancelSearchButton.focus = true; } else { mainColumn.tryActivate(0, 0); } } } } } Item { id: mainColumn anchors.top: parent.top width: (columns * cellSize) + units.gridUnit height: Math.floor(parent.height / cellSize) * cellSize + mainGridContainer.headerHeight property int columns: root.columns - favoritesColumn.columns - filterListColumn.columns property Item visibleGrid: mainGrid function tryActivate(row, col) { if (visibleGrid) { visibleGrid.tryActivate(row, col); } } Item { id: mainGridContainer anchors.fill: parent z: (opacity == 1.0) ? 1 : 0 enabled: (opacity == 1.0) ? 1 : 0 property int headerHeight: mainColumnLabel.height + mainColumnLabelUnderline.height + units.largeSpacing opacity: { if (tabBar.activeTab == 0 && searching) { return 0.0; } if (filterList.allApps) { return 0.0; } return 1.0; } onOpacityChanged: { if (opacity == 1.0) { mainColumn.visibleGrid = mainGrid; } } PlasmaExtras.Heading { id: mainColumnLabel anchors { top: parent.top } x: units.smallSpacing width: parent.width - x elide: Text.ElideRight wrapMode: Text.NoWrap opacity: 1.0 color: "white" level: 1 text: (tabBar.activeTab == 0) ? funnelModel.description : i18n("Widgets") } PlasmaCore.SvgItem { id: mainColumnLabelUnderline visible: mainGrid.count anchors { top: mainColumnLabel.bottom } width: parent.width - units.gridUnit height: lineSvg.horLineHeight svg: lineSvg elementId: "horizontal-line" } ItemGridView { id: mainGrid anchors { top: mainColumnLabelUnderline.bottom topMargin: units.largeSpacing } width: parent.width height: systemFavoritesGrid.y + systemFavoritesGrid.height - mainGridContainer.headerHeight cellWidth: (tabBar.activeTab == 0 ? cellSize : cellSize * 2) cellHeight: cellWidth iconSize: (tabBar.activeTab == 0 ? root.iconSize : cellWidth - (units.largeSpacing * 2)) model: funnelModel onCurrentIndexChanged: { preloadAllAppsTimer.defer(); } onKeyNavLeft: { if (tabBar.activeTab == 0) { var row = currentRow(); var target = row + 1 > globalFavoritesGrid.rows ? systemFavoritesGrid : globalFavoritesGrid; var targetRow = row + 1 > globalFavoritesGrid.rows ? row - globalFavoritesGrid.rows : row; target.tryActivate(targetRow, favoritesColumn.columns - 1); } } onKeyNavRight: { filterListScrollArea.focus = true; } onKeyNavUp: { if (tabBar.visible) { tabBar.focus = true; } } onItemActivated: { if (tabBar.activeTab == 1) { containmentInterface.ensureMutable(containmentInterface.screenContainment(plasmoid)); root.widgetExplorer.addApplet(currentItem.m.pluginName); root.toggle(); kwindowsystem.showingDesktop = true; } } } } ItemMultiGridView { id: allAppsGrid anchors { top: parent.top } z: (opacity == 1.0) ? 1 : 0 width: parent.width height: systemFavoritesGrid.y + systemFavoritesGrid.height enabled: (opacity == 1.0) ? 1 : 0 opacity: filterList.allApps ? 1.0 : 0.0 onOpacityChanged: { if (opacity == 1.0) { allAppsGrid.flickableItem.contentY = 0; mainColumn.visibleGrid = allAppsGrid; } } onKeyNavLeft: { var row = 0; for (var i = 0; i < subGridIndex; i++) { row += subGridAt(i).lastRow() + 2; // Header counts as one. } row += subGridAt(subGridIndex).currentRow(); var target = row + 1 > globalFavoritesGrid.rows ? systemFavoritesGrid : globalFavoritesGrid; var targetRow = row + 1 > globalFavoritesGrid.rows ? row - globalFavoritesGrid.rows : row; target.tryActivate(targetRow, favoritesColumn.columns - 1); } onKeyNavRight: { filterListScrollArea.focus = true; } } ItemMultiGridView { id: runnerGrid anchors { top: parent.top } z: (opacity == 1.0) ? 1 : 0 width: parent.width height: systemFavoritesGrid.y + systemFavoritesGrid.height enabled: (opacity == 1.0) ? 1 : 0 model: runnerModel grabFocus: true opacity: (tabBar.activeTab == 0 && searching) ? 1.0 : 0.0 onOpacityChanged: { if (opacity == 1.0) { mainColumn.visibleGrid = runnerGrid; } } onKeyNavLeft: { var row = 0; for (var i = 0; i < subGridIndex; i++) { row += subGridAt(i).lastRow() + 2; // Header counts as one. } row += subGridAt(subGridIndex).currentRow(); var target = row + 1 > globalFavoritesGrid.rows ? systemFavoritesGrid : globalFavoritesGrid; var targetRow = row + 1 > globalFavoritesGrid.rows ? row - globalFavoritesGrid.rows : row; target.tryActivate(targetRow, favoritesColumn.columns - 1); } } Keys.onPressed: { if (event.key == Qt.Key_Tab) { event.accepted = true; if (filterList.enabled) { filterList.forceActiveFocus(); } else { systemFavoritesGrid.tryActivate(0, 0); } } else if (event.key == Qt.Key_Backtab) { event.accepted = true; if (searching) { cancelSearchButton.focus = true; } else if (tabBar.visible) { tabBar.focus = true; } else if (globalFavoritesGrid.enabled) { globalFavoritesGrid.tryActivate(0, 0); } else { systemFavoritesGrid.tryActivate(0, 0); } } } } Item { id: filterListColumn anchors { top: parent.top topMargin: mainColumnLabelUnderline.y + mainColumnLabelUnderline.height + units.largeSpacing bottom: parent.bottom } width: columns * cellSize property int columns: 3 PlasmaExtras.ScrollArea { id: filterListScrollArea x: root.visible ? 0 : units.gridUnit Behavior on x { SmoothedAnimation { duration: units.longDuration; velocity: 0.01 } } width: parent.width height: mainGrid.height enabled: !searching property alias currentIndex: filterList.currentIndex opacity: root.visible ? (searching ? 0.30 : 1.0) : 0.3 Behavior on opacity { SmoothedAnimation { duration: units.longDuration; velocity: 0.01 } } verticalScrollBarPolicy: (opacity == 1.0) ? Qt.ScrollBarAsNeeded : Qt.ScrollBarAlwaysOff onEnabledChanged: { if (!enabled) { filterList.currentIndex = -1; } } onCurrentIndexChanged: { focus = (currentIndex != -1); } ListView { id: filterList focus: true property bool allApps: false property int eligibleWidth: width property int hItemMargins: Math.max(highlightItemSvg.margins.left + highlightItemSvg.margins.right, listItemSvg.margins.left + listItemSvg.margins.right) model: rootModel boundsBehavior: Flickable.StopAtBounds snapMode: ListView.SnapToItem spacing: 0 keyNavigationWraps: true delegate: MouseArea { id: item signal actionTriggered(string actionId, variant actionArgument) signal aboutToShowActionMenu(variant actionMenu) property var m: model property int textWidth: label.contentWidth property int mouseCol property bool hasActionList: ((model.favoriteId != null) || (("hasActionList" in model) && (model.hasActionList == true))) property Item menu: actionMenu width: parent.width height: Math.ceil((label.paintedHeight + Math.max(highlightItemSvg.margins.top + highlightItemSvg.margins.bottom, listItemSvg.margins.top + listItemSvg.margins.bottom)) / 2) * 2 Accessible.role: Accessible.MenuItem Accessible.name: model.display acceptedButtons: Qt.LeftButton | Qt.RightButton hoverEnabled: true onContainsMouseChanged: { if (!containsMouse) { updateCurrentItemTimer.stop(); } } onPositionChanged: { // Lazy menu implementation. mouseCol = mouse.x; if (justOpenedTimer.running || ListView.view.currentIndex == 0 || index == ListView.view.currentIndex) { updateCurrentItem(); } else if ((index == ListView.view.currentIndex - 1) && mouse.y < (height - 6) || (index == ListView.view.currentIndex + 1) && mouse.y > 5) { if (mouse.x > ListView.view.eligibleWidth - 5) { updateCurrentItem(); } } else if (mouse.x > ListView.view.eligibleWidth) { updateCurrentItem(); } updateCurrentItemTimer.restart(); } onPressed: { if (mouse.buttons & Qt.RightButton) { if (hasActionList) { openActionMenu(item, mouse.x, mouse.y); } } } onClicked: { if (mouse.button == Qt.LeftButton) { updateCurrentItem(); } } onAboutToShowActionMenu: { var actionList = hasActionList ? model.actionList : []; - Tools.fillActionMenu(actionMenu, actionList, ListView.view.model.favoritesModel, model.favoriteId); + Tools.fillActionMenu(i18n, actionMenu, actionList, ListView.view.model.favoritesModel, model.favoriteId); } onActionTriggered: { Tools.triggerAction(ListView.view.model, model.index, actionId, actionArgument); } function openActionMenu(visualParent, x, y) { aboutToShowActionMenu(actionMenu); actionMenu.visualParent = visualParent; actionMenu.open(x, y); } function updateCurrentItem() { ListView.view.currentIndex = index; ListView.view.eligibleWidth = Math.min(width, mouseCol); } ActionMenu { id: actionMenu onActionClicked: { actionTriggered(actionId, actionArgument); } } Timer { id: updateCurrentItemTimer interval: 50 repeat: false onTriggered: parent.updateCurrentItem() } PlasmaExtras.Heading { id: label anchors { fill: parent leftMargin: highlightItemSvg.margins.left rightMargin: highlightItemSvg.margins.right } elide: Text.ElideRight wrapMode: Text.NoWrap opacity: 1.0 color: "white" level: 1 text: model.display } } highlight: PlasmaComponents.Highlight { anchors { top: filterList.currentItem ? filterList.currentItem.top : undefined left: filterList.currentItem ? filterList.currentItem.left : undefined bottom: filterList.currentItem ? filterList.currentItem.bottom : undefined } opacity: filterListScrollArea.focus ? 1.0 : 0.7 width: (highlightItemSvg.margins.left + filterList.currentItem.textWidth + highlightItemSvg.margins.right + units.smallSpacing) visible: filterList.currentItem } highlightFollowsCurrentItem: false highlightMoveDuration: 0 highlightResizeDuration: 0 onCurrentIndexChanged: applyFilter() onCountChanged: { var width = 0; for (var i = 0; i < rootModel.count; ++i) { headingMetrics.text = rootModel.labelForRow(i); if (headingMetrics.width > width) { width = headingMetrics.width; } } filterListColumn.columns = Math.ceil(width / cellSize); filterListScrollArea.width = width + hItemMargins + (units.gridUnit * 2); } function applyFilter() { if (!searching && currentIndex >= 0) { if (tabBar.activeTab == 1) { root.widgetExplorer.widgetsModel.filterQuery = currentItem.m.filterData; root.widgetExplorer.widgetsModel.filterType = currentItem.m.filterType; allApps = false; funnelModel.sourceModel = model; return; } if (preloadAllAppsTimer.running) { preloadAllAppsTimer.stop(); } var model = rootModel.modelForRow(currentIndex); if (model.description == "KICKER_ALL_MODEL") { allAppsGrid.model = model; allApps = true; funnelModel.sourceModel = null; preloadAllAppsTimer.done = true; } else { funnelModel.sourceModel = model; allApps = false; } } else { funnelModel.sourceModel = null; allApps = false; } } Keys.onPressed: { if (event.key == Qt.Key_Left) { event.accepted = true; var currentRow = Math.max(0, Math.ceil(currentItem.y / mainGrid.cellHeight) - 1); mainColumn.tryActivate(currentRow, mainColumn.columns - 1); } else if (event.key == Qt.Key_Tab) { event.accepted = true; systemFavoritesGrid.tryActivate(0, 0); } else if (event.key == Qt.Key_Backtab) { event.accepted = true; mainColumn.tryActivate(0, 0); } } } } } } onPressed: { if (mouse.button == Qt.RightButton) { contextMenu.open(mouse.x, mouse.y); } } onClicked: { if (mouse.button == Qt.LeftButton) { root.toggle(); } } } } diff --git a/applets/kicker/package/contents/ui/ItemGridDelegate.qml b/applets/kicker/package/contents/ui/ItemGridDelegate.qml index 0a258762a..5b5b69df1 100644 --- a/applets/kicker/package/contents/ui/ItemGridDelegate.qml +++ b/applets/kicker/package/contents/ui/ItemGridDelegate.qml @@ -1,129 +1,129 @@ /*************************************************************************** * Copyright (C) 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 org.kde.plasma.core 2.0 as PlasmaCore import org.kde.plasma.components 2.0 as PlasmaComponents import "../code/tools.js" as Tools Item { id: item width: GridView.view.cellWidth height: width property bool showLabel: true property int itemIndex: model.index property string favoriteId: model.favoriteId != undefined ? model.favoriteId : "" property url url: model.url != undefined ? model.url : "" property variant icon: model.decoration != undefined ? model.decoration : "" property var m: model property bool hasActionList: ((model.favoriteId != null) || (("hasActionList" in model) && (model.hasActionList == true))) Accessible.role: Accessible.MenuItem Accessible.name: model.display function openActionMenu(x, y) { var actionList = hasActionList ? model.actionList : []; - Tools.fillActionMenu(actionMenu, actionList, GridView.view.model.favoritesModel, model.favoriteId); + Tools.fillActionMenu(i18n, actionMenu, actionList, GridView.view.model.favoritesModel, model.favoriteId); actionMenu.visualParent = item; actionMenu.open(x, y); } function actionTriggered(actionId, actionArgument) { var close = Tools.triggerAction(GridView.view.model, model.index, actionId, actionArgument); if (close) { root.toggle(); } } PlasmaCore.IconItem { id: icon y: showLabel ? (2 * highlightItemSvg.margins.top) : undefined anchors.horizontalCenter: parent.horizontalCenter anchors.verticalCenter: showLabel ? undefined : parent.verticalCenter width: iconSize height: width colorGroup: PlasmaCore.Theme.ComplementaryColorGroup animated: false usesPlasmaTheme: GridView.view.usesPlasmaTheme source: model.decoration } PlasmaComponents.Label { id: label visible: showLabel anchors { top: icon.bottom topMargin: units.smallSpacing left: parent.left leftMargin: highlightItemSvg.margins.left right: parent.right rightMargin: highlightItemSvg.margins.right } horizontalAlignment: Text.AlignHCenter elide: Text.ElideRight wrapMode: Text.NoWrap color: "white" // FIXME TODO: Respect theming? text: ("name" in model ? model.name : model.display) } PlasmaCore.ToolTipArea { id: toolTip property string text: model.display anchors.fill: parent active: root.visible && label.truncated mainItem: toolTipDelegate } Keys.onPressed: { if (event.key == Qt.Key_Menu && hasActionList) { event.accepted = true; openActionMenu(item); } else if ((event.key == Qt.Key_Enter || event.key == Qt.Key_Return)) { event.accepted = true; if ("trigger" in GridView.view.model) { GridView.view.model.trigger(index, "", null); root.toggle(); } itemGrid.itemActivated(index, "", null); } } } diff --git a/applets/kicker/package/contents/ui/ItemListDelegate.qml b/applets/kicker/package/contents/ui/ItemListDelegate.qml index 261c14aa9..ce74967ad 100644 --- a/applets/kicker/package/contents/ui/ItemListDelegate.qml +++ b/applets/kicker/package/contents/ui/ItemListDelegate.qml @@ -1,279 +1,279 @@ /*************************************************************************** * Copyright (C) 2013-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 org.kde.plasma.core 2.0 as PlasmaCore import org.kde.plasma.components 2.0 as PlasmaComponents import "../code/tools.js" as Tools Item { id: item height: isSeparator ? separatorHeight : itemHeight width: ListView.view.width enabled: !isSeparator signal actionTriggered(string actionId, variant actionArgument) signal aboutToShowActionMenu(variant actionMenu) property bool isSeparator: (model.isSeparator == true) property bool hasChildren: (model.hasChildren == true) property bool hasActionList: ((model.favoriteId != null) || (("hasActionList" in model) && (model.hasActionList == true))) property QtObject childDialog: null property Item menu: actionMenu Accessible.role: isSeparator ? Accessible.Separator: Accessible.MenuItem Accessible.name: label.text onHasChildrenChanged: { if (!hasChildren && ListView.view.currentItem == item) { ListView.view.currentIndex = -1; } } onAboutToShowActionMenu: { var actionList = hasActionList ? model.actionList : []; - Tools.fillActionMenu(actionMenu, actionList, ListView.view.model.favoritesModel, model.favoriteId); + Tools.fillActionMenu(i18n, actionMenu, actionList, ListView.view.model.favoritesModel, model.favoriteId); } onActionTriggered: { Tools.triggerAction(ListView.view.model, model.index, actionId, actionArgument); } function openActionMenu(visualParent, x, y) { aboutToShowActionMenu(actionMenu); actionMenu.visualParent = visualParent; actionMenu.open(x, y); } ActionMenu { id: actionMenu onActionClicked: { actionTriggered(actionId, actionArgument); } } MouseArea { id: mouseArea anchors { left: parent.left right: parent.right verticalCenter: parent.verticalCenter } height: parent.height property int mouseCol property bool pressed: false property int pressX: -1 property int pressY: -1 hoverEnabled: true acceptedButtons: Qt.LeftButton | Qt.RightButton 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 && !hasChildren) { item.ListView.view.model.trigger(index, "", null); plasmoid.expanded = false; } pressed = false; pressX = -1; pressY = -1; } onPositionChanged: { if (pressX != -1 && model.url && dragHelper.isDrag(pressX, pressY, mouse.x, mouse.y)) { dragHelper.startDrag(kicker, model.url, model.decoration); pressed = false; pressX = -1; pressY = -1; return; } // FIXME: Correct escape angle calc for right screen edge. if (justOpenedTimer.running || !hasChildren) { item.ListView.view.currentIndex = index; } else { mouseCol = mouse.x; if (index == item.ListView.view.currentIndex) { updateCurrentItem(); } else if ((index == item.ListView.view.currentIndex - 1) && mouse.y < (itemHeight - 6) || (index == item.ListView.view.currentIndex + 1) && mouse.y > 5) { if ((childDialog != null && childDialog.facingLeft) ? mouse.x > item.ListView.view.eligibleWidth - 5 : mouse.x < item.ListView.view.eligibleWidth + 5) { updateCurrentItem(); } } else if ((childDialog != null && childDialog.facingLeft) ? mouse.x > item.ListView.view.eligibleWidth : mouse.x < item.ListView.view.eligibleWidth) { updateCurrentItem(); } updateCurrentItemTimer.start(); } } onContainsMouseChanged: { if (!containsMouse) { pressed = false; pressX = -1; pressY = -1; updateCurrentItemTimer.stop(); } } function updateCurrentItem() { item.ListView.view.currentIndex = index; item.ListView.view.eligibleWidth = Math.min(width, mouseCol); } Timer { id: updateCurrentItemTimer interval: 50 repeat: false onTriggered: parent.updateCurrentItem() } } Row { anchors.left: parent.left anchors.leftMargin: highlightItemSvg.margins.left anchors.right: parent.right anchors.rightMargin: highlightItemSvg.margins.right height: parent.height spacing: units.smallSpacing * 2 LayoutMirroring.enabled: (Qt.application.layoutDirection == Qt.RightToLeft) PlasmaCore.IconItem { id: icon anchors.verticalCenter: parent.verticalCenter width: visible ? units.iconSizes.small : 0 height: width visible: iconsEnabled animated: false usesPlasmaTheme: false source: model.decoration } PlasmaComponents.Label { id: label enabled: !isParent || (isParent && hasChildren) anchors.verticalCenter: parent.verticalCenter width: (parent.width - icon.width - arrow.width - ((icon.visible ? 1 : 0) * parent.spacing) - ((arrow.visible ? 1 : 0) * parent.spacing)) verticalAlignment: Text.AlignVCenter textFormat: Text.PlainText wrapMode: Text.NoWrap elide: Text.ElideRight text: model.display } PlasmaCore.SvgItem { id: arrow anchors.verticalCenter: parent.verticalCenter width: visible ? units.iconSizes.small : 0 height: width visible: hasChildren opacity: (item.ListView.view.currentIndex == index) ? 1.0 : 0.4 svg: arrows elementId: (Qt.application.layoutDirection == Qt.RightToLeft) ? "left-arrow" : "right-arrow" } } Component { id: separatorComponent PlasmaCore.SvgItem { width: parent.width height: lineSvg.horLineHeight svg: lineSvg elementId: "horizontal-line" } } Loader { id: separatorLoader anchors.left: parent.left anchors.leftMargin: highlightItemSvg.margins.left anchors.right: parent.right anchors.rightMargin: highlightItemSvg.margins.right anchors.verticalCenter: parent.verticalCenter active: isSeparator asynchronous: false sourceComponent: separatorComponent } 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) && !hasChildren) { if (!hasChildren) { event.accepted = true; item.ListView.view.model.trigger(index, "", null); plasmoid.expanded = false; } } } } diff --git a/applets/kicker/package/contents/ui/SideBarItem.qml b/applets/kicker/package/contents/ui/SideBarItem.qml index e25921ffe..83e9800dd 100644 --- a/applets/kicker/package/contents/ui/SideBarItem.qml +++ b/applets/kicker/package/contents/ui/SideBarItem.qml @@ -1,154 +1,154 @@ /*************************************************************************** * Copyright (C) 2013-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 org.kde.plasma.core 2.0 as PlasmaCore import org.kde.kquickcontrolsaddons 2.0 import "../code/tools.js" as Tools Item { id: item width: root.width height: root.width signal actionTriggered(string actionId, variant actionArgument) signal aboutToShowActionMenu(variant actionMenu) property bool hasActionList: ((model.favoriteId != null) || (("hasActionList" in model) && (model.hasActionList != null))) property int itemIndex: model.index onAboutToShowActionMenu: { var actionList = (model.hasActionList != null) ? model.actionList : []; - Tools.fillActionMenu(actionMenu, actionList, repeater.model, model.favoriteId); + Tools.fillActionMenu(i18n, actionMenu, actionList, repeater.model, model.favoriteId); } onActionTriggered: { Tools.triggerAction(repeater.model, model.index, actionId, actionArgument); } function openActionMenu(visualParent, x, y) { aboutToShowActionMenu(actionMenu); actionMenu.visualParent = visualParent; actionMenu.open(x, y); } ActionMenu { id: actionMenu onActionClicked: { actionTriggered(actionId, actionArgument); } } PlasmaCore.IconItem { anchors.fill: parent active: toolTip.containsMouse source: model.decoration usesPlasmaTheme: repeater.usesPlasmaTheme } MouseEventListener { id: listener anchors { fill: parent leftMargin: - sideBar.margins.left rightMargin: - sideBar.margins.right } enabled: (item.parent && !item.parent.animating) property bool pressed: false property int pressX: -1 property int pressY: -1 hoverEnabled: true acceptedButtons: Qt.LeftButton | Qt.RightButton onPressed: { if (mouse.buttons & Qt.RightButton) { if (item.hasActionList) { item.openActionMenu(item, mouse.x, mouse.y); } } else { pressed = true; pressX = mouse.x; pressY = mouse.y; } } onReleased: { if (pressed) { repeater.model.trigger(index, "", null); plasmoid.expanded = false; } pressed = false; pressX = -1; pressY = -1; } onContainsMouseChanged: { if (!containsMouse) { pressed = false; pressX = -1; pressY = -1; } } onPositionChanged: { if (pressX != -1 && dragHelper.isDrag(pressX, pressY, mouse.x, mouse.y)) { kicker.dragSource = item; dragHelper.startDrag(kicker, model.url, model.icon); pressed = false; pressX = -1; pressY = -1; return; } } } PlasmaCore.ToolTipArea { id: toolTip property string text: model.display anchors { fill: parent leftMargin: - sideBar.margins.left rightMargin: - sideBar.margins.right } interactive: false location: (((plasmoid.location == PlasmaCore.Types.RightEdge) || (Qt.application.layoutDirection == Qt.RightToLeft)) ? PlasmaCore.Types.RightEdge : PlasmaCore.Types.LeftEdge) mainItem: toolTipDelegate } } diff --git a/applets/kickoff/package/contents/code/tools.js b/applets/kickoff/package/contents/code/tools.js index 9a26eef62..da2cf5866 100644 --- a/applets/kickoff/package/contents/code/tools.js +++ b/applets/kickoff/package/contents/code/tools.js @@ -1,202 +1,204 @@ /*************************************************************************** * Copyright (C) 2013 by Aurélien Gâteau * * Copyright (C) 2013-2015 by Eike Hein * * Copyright (C) 2017 by Ivan Cukic * * * * 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 . * ***************************************************************************/ -function fillActionMenu(actionMenu, actionList, favoriteModel, favoriteId) { +.pragma library + +function fillActionMenu(i18n, actionMenu, actionList, favoriteModel, favoriteId) { // Accessing actionList can be a costly operation, so we don't // access it until we need the menu. - var actions = createFavoriteActions(favoriteModel, favoriteId); + var actions = createFavoriteActions(i18n, favoriteModel, favoriteId); if (actions) { if (actionList && actionList.length > 0) { var separator = { "type": "separator" }; actionList.push(separator); // actionList = actions.concat(actionList); // this crashes Qt O.o actionList.push.apply(actionList, actions); } else { actionList = actions; } } actionMenu.actionList = actionList; } -function createFavoriteActions(favoriteModel, favoriteId) { +function createFavoriteActions(i18n, favoriteModel, favoriteId) { if (favoriteModel === null || !favoriteModel.enabled || favoriteId == null) { return null; } if (favoriteModel.activities === undefined || favoriteModel.activities.runningActivities.length <= 1) { var action = {}; if (favoriteModel.isFavorite(favoriteId)) { action.text = i18n("Remove from Favorites"); action.icon = "list-remove"; action.actionId = "_kicker_favorite_remove"; } else if (favoriteModel.maxFavorites == -1 || favoriteModel.count < favoriteModel.maxFavorites) { action.text = i18n("Add to Favorites"); action.icon = "bookmark-new"; action.actionId = "_kicker_favorite_add"; } else { return null; } action.actionArgument = { favoriteModel: favoriteModel, favoriteId: favoriteId }; return [action]; } else { var actions = []; var linkedActivities = favoriteModel.linkedActivitiesFor(favoriteId); var activities = favoriteModel.activities.runningActivities; // Adding the item to link/unlink to all activities var linkedToAllActivities = !(linkedActivities.indexOf(":global") === -1); actions.push({ text : i18n("On All Activities"), checkable : true, actionId : linkedToAllActivities ? "_kicker_favorite_remove_from_activity" : "_kicker_favorite_set_to_activity", checked : linkedToAllActivities, actionArgument : { favoriteModel: favoriteModel, favoriteId: favoriteId, favoriteActivity: "" } }); // Adding items for each activity separately var addActivityItem = function(activityId, activityName) { var linkedToThisActivity = !(linkedActivities.indexOf(activityId) === -1); actions.push({ text : activityName, checkable : true, checked : linkedToThisActivity && !linkedToAllActivities, actionId : // If we are on all activities, and the user clicks just one // specific activity, unlink from everything else linkedToAllActivities ? "_kicker_favorite_set_to_activity" : // If we are linked to the current activity, just unlink from // that single one linkedToThisActivity ? "_kicker_favorite_remove_from_activity" : // Otherwise, link to this activity, but do not unlink from // other ones "_kicker_favorite_add_to_activity", actionArgument : { favoriteModel : favoriteModel, favoriteId : favoriteId, favoriteActivity : activityId } }); }; // Adding the item to link/unlink to the current activity addActivityItem(favoriteModel.activities.currentActivity, i18n("On The Current Activity")); actions.push({ type: "separator", actionId: "_kicker_favorite_separator" }); // Adding the items for each activity activities.forEach(function(activityId) { addActivityItem(activityId, favoriteModel.activityNameForId(activityId)); }); return [{ text : i18n("Show In Favorites"), icon : "favorite", subActions : actions }]; } } function triggerAction(model, index, actionId, actionArgument) { function startsWith(txt, needle) { return txt.substr(0, needle.length) === needle; } if (startsWith(actionId, "_kicker_favorite_")) { handleFavoriteAction(actionId, actionArgument); return; } var closeRequested = model.trigger(index, actionId, actionArgument); if (closeRequested) { plasmoid.expanded = false; return true; } return false; } function handleFavoriteAction(actionId, actionArgument) { var favoriteId = actionArgument.favoriteId; var favoriteModel = actionArgument.favoriteModel; console.log(actionId); if (favoriteModel === null || favoriteId == null) { return null; } if (actionId == "_kicker_favorite_remove") { console.log("Removing from all activities"); favoriteModel.removeFavorite(favoriteId); } else if (actionId == "_kicker_favorite_add") { console.log("Adding to global activity"); favoriteModel.addFavorite(favoriteId); } else if (actionId == "_kicker_favorite_remove_from_activity") { console.log("Removing from a specific activity"); favoriteModel.removeFavoriteFrom(favoriteId, actionArgument.favoriteActivity); } else if (actionId == "_kicker_favorite_add_to_activity") { console.log("Adding to another activity"); favoriteModel.addFavoriteTo(favoriteId, actionArgument.favoriteActivity); } else if (actionId == "_kicker_favorite_set_to_activity") { console.log("Removing the item from the favourites, and re-adding it just to be on a specific activity"); favoriteModel.setFavoriteOn(favoriteId, actionArgument.favoriteActivity); } } diff --git a/applets/kickoff/package/contents/ui/KickoffItem.qml b/applets/kickoff/package/contents/ui/KickoffItem.qml index 33bf0bdb8..b81c463ea 100644 --- a/applets/kickoff/package/contents/ui/KickoffItem.qml +++ b/applets/kickoff/package/contents/ui/KickoffItem.qml @@ -1,257 +1,257 @@ /* 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) readonly property int itemIndex: model.index property bool dropEnabled: false property bool appView: false property bool modelChildren: model.hasChildren || false property bool isCurrent: listItem.ListView.view.currentIndex === index; 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); + Tools.fillActionMenu(i18n, actionMenu, actionList, ListView.view.model.favoritesModel, model.favoriteId); } onActionTriggered: { Tools.triggerAction(ListView.view.model, model.index, actionId, actionArgument); if (actionId.indexOf("_kicker_favorite_") === 0) { switchToInitial(); } } 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)) { kickoff.dragSource = listItem; 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: model.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 horizontalAlignment: Text.AlignLeft } 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.8 : 0.6 font.pointSize: theme.smallestFont.pointSize elide: Text.ElideMiddle horizontalAlignment: Text.AlignLeft } 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