Warning, /plasma/plasma-desktop/applets/taskmanager/package/contents/ui/ContextMenu.qml is written in an unsupported language. File is not indexed.

0001 /*
0002     SPDX-FileCopyrightText: 2012-2016 Eike Hein <hein@kde.org>
0003     SPDX-FileCopyrightText: 2016 Kai Uwe Broulik <kde@privat.broulik.de>
0004 
0005     SPDX-License-Identifier: GPL-2.0-or-later
0006 */
0007 
0008 import QtQuick 2.15
0009 
0010 import org.kde.plasma.plasmoid 2.0
0011 
0012 import org.kde.plasma.core as PlasmaCore
0013 import org.kde.plasma.extras 2.0 as PlasmaExtras
0014 
0015 import org.kde.taskmanager 0.1 as TaskManager
0016 import org.kde.plasma.private.mpris as Mpris
0017 
0018 import "code/layout.js" as LayoutManager
0019 
0020 PlasmaExtras.Menu {
0021     id: menu
0022 
0023     property QtObject backend
0024     property QtObject mpris2Source
0025     property var modelIndex
0026     readonly property var atm: TaskManager.AbstractTasksModel
0027 
0028     property bool showAllPlaces: false
0029 
0030     placement: {
0031         if (Plasmoid.location === PlasmaCore.Types.LeftEdge) {
0032             return PlasmaExtras.Menu.RightPosedTopAlignedPopup;
0033         } else if (Plasmoid.location === PlasmaCore.Types.TopEdge) {
0034             return PlasmaExtras.Menu.BottomPosedLeftAlignedPopup;
0035         } else if (Plasmoid.location === PlasmaCore.Types.RightEdge) {
0036             return PlasmaExtras.Menu.LeftPosedTopAlignedPopup;
0037         } else {
0038             return PlasmaExtras.Menu.TopPosedLeftAlignedPopup;
0039         }
0040     }
0041 
0042     minimumWidth: visualParent.width
0043 
0044     onStatusChanged: {
0045         if (visualParent && get(atm.LauncherUrlWithoutIcon) != "" && status == PlasmaExtras.Menu.Open) {
0046             activitiesDesktopsMenu.refresh();
0047 
0048         } else if (status == PlasmaExtras.Menu.Closed) {
0049             menu.destroy();
0050         }
0051     }
0052 
0053     Component.onCompleted: {
0054         // Cannot have "Connections" as child of PlasmaExtras.Menu.
0055         backend.showAllPlaces.connect(showContextMenuWithAllPlaces);
0056     }
0057 
0058     Component.onDestruction: {
0059         backend.showAllPlaces.disconnect(showContextMenuWithAllPlaces);
0060     }
0061 
0062     function showContextMenuWithAllPlaces() {
0063         visualParent.showContextMenu({showAllPlaces: true});
0064     }
0065 
0066     function get(modelProp) {
0067         return tasksModel.data(modelIndex, modelProp)
0068     }
0069 
0070     function show() {
0071         Plasmoid.contextualActionsAboutToShow();
0072 
0073         loadDynamicLaunchActions(get(atm.LauncherUrlWithoutIcon));
0074         openRelative();
0075     }
0076 
0077     function newMenuItem(parent) {
0078         return Qt.createQmlObject(`
0079             import org.kde.plasma.extras 2.0 as PlasmaExtras
0080 
0081             PlasmaExtras.MenuItem {}
0082         `, parent);
0083     }
0084 
0085     function newSeparator(parent) {
0086         return Qt.createQmlObject(`
0087             import org.kde.plasma.extras 2.0 as PlasmaExtras
0088 
0089             PlasmaExtras.MenuItem { separator: true }
0090             `, parent);
0091     }
0092 
0093     function loadDynamicLaunchActions(launcherUrl) {
0094         let sections = [];
0095 
0096         const placesActions = backend.placesActions(launcherUrl, showAllPlaces, menu);
0097 
0098         if (placesActions.length > 0) {
0099             sections.push({
0100                 title: i18n("Places"),
0101                 group: "places",
0102                 actions: placesActions
0103             });
0104         } else {
0105             sections.push({
0106                 title:   i18n("Recent Files"),
0107                 group:   "recents",
0108                 actions: backend.recentDocumentActions(launcherUrl, menu)
0109             });
0110         }
0111 
0112         sections.push({
0113             title: i18n("Actions"),
0114             group: "actions",
0115             actions: backend.jumpListActions(launcherUrl, menu)
0116         });
0117 
0118         // C++ can override section heading by returning a QString as first action
0119         sections.forEach((section) => {
0120             if (typeof section.actions[0] === "string") {
0121                 section.title = section.actions.shift(); // take first
0122             }
0123         });
0124 
0125         // QMenu does not limit its width automatically. Even if we set a maximumWidth
0126         // it would just cut off text rather than eliding. So we do this manually.
0127         var textMetrics = Qt.createQmlObject("import QtQuick 2.4; TextMetrics {}", menu);
0128         var maximumWidth = LayoutManager.maximumContextMenuTextWidth();
0129 
0130         sections.forEach(function (section) {
0131             if (section["actions"].length > 0 || section["group"] == "actions") {
0132                 // Don't add the "Actions" header if the menu has nothing but actions
0133                 // in it, because then it's redundant (all menus have actions)
0134                 if (
0135                     (section["group"] != "actions") ||
0136                     (section["group"] == "actions" && (sections[0]["actions"].length > 0 || sections[1]["actions"].length > 0))
0137                 ) {
0138                     var sectionHeader = newMenuItem(menu);
0139                     sectionHeader.text = section["title"];
0140                     sectionHeader.section = true;
0141                     menu.addMenuItem(sectionHeader, startNewInstanceItem);
0142                 }
0143             }
0144 
0145             for (var i = 0; i < section["actions"].length; ++i) {
0146                 var item = newMenuItem(menu);
0147                 item.action = section["actions"][i];
0148 
0149                 // Crude way of manually eliding...
0150                 var elided = false;
0151                 textMetrics.text = Qt.binding(function() {
0152                     return item.action.text;
0153                 });
0154 
0155                 while (textMetrics.width > maximumWidth) {
0156                     item.action.text = item.action.text.slice(0, -1);
0157                     elided = true;
0158                 }
0159 
0160                 if (elided) {
0161                     item.action.text += "…";
0162                 }
0163 
0164                 menu.addMenuItem(item, startNewInstanceItem);
0165             }
0166         });
0167 
0168         // Add Media Player control actions
0169         const playerData = mpris2Source.playerForLauncherUrl(launcherUrl, get(atm.AppPid));
0170 
0171         if (playerData && playerData.canControl && !(get(atm.WinIdList) !== undefined && get(atm.WinIdList).length > 1)) {
0172             const playing = playerData.playbackStatus === Mpris.PlaybackStatus.Playing;
0173             var menuItem = menu.newMenuItem(menu);
0174             menuItem.text = i18nc("Play previous track", "Previous Track");
0175             menuItem.icon = "media-skip-backward";
0176             menuItem.enabled = Qt.binding(function() {
0177                 return playerData.canGoPrevious;
0178             });
0179             menuItem.clicked.connect(function() {
0180                 playerData.Previous();
0181             });
0182             menu.addMenuItem(menuItem, startNewInstanceItem);
0183 
0184             menuItem = menu.newMenuItem(menu);
0185             // PlasmaCore Menu doesn't actually handle icons or labels changing at runtime...
0186             menuItem.text = Qt.binding(function() {
0187                 // if CanPause, toggle the menu entry between Play & Pause, otherwise always use Play
0188                 return playing && playerData.canPause ? i18nc("Pause playback", "Pause") : i18nc("Start playback", "Play");
0189             });
0190             menuItem.icon = Qt.binding(function() {
0191                 return playing && playerData.canPause ? "media-playback-pause" : "media-playback-start";
0192             });
0193             menuItem.enabled = Qt.binding(function() {
0194                 return playing ? playerData.canPause : playerData.canPlay;
0195             });
0196             menuItem.clicked.connect(function() {
0197                 if (playing) {
0198                     playerData.Pause();
0199                 } else {
0200                     playerData.Play();
0201                 }
0202             });
0203             menu.addMenuItem(menuItem, startNewInstanceItem);
0204 
0205             menuItem = menu.newMenuItem(menu);
0206             menuItem.text = i18nc("Play next track", "Next Track");
0207             menuItem.icon = "media-skip-forward";
0208             menuItem.enabled = Qt.binding(function() {
0209                 return playerData.canGoNext;
0210             });
0211             menuItem.clicked.connect(function() {
0212                 playerData.Next();
0213             });
0214             menu.addMenuItem(menuItem, startNewInstanceItem);
0215 
0216             menuItem = menu.newMenuItem(menu);
0217             menuItem.text = i18nc("Stop playback", "Stop");
0218             menuItem.icon = "media-playback-stop";
0219             menuItem.enabled = Qt.binding(function() {
0220                 return playerData.canStop;
0221             });
0222             menuItem.clicked.connect(function() {
0223                 playerData.Stop();
0224             });
0225             menu.addMenuItem(menuItem, startNewInstanceItem);
0226 
0227             // Technically media controls and audio streams are separate but for the user they're
0228             // semantically related, don't add a separator inbetween.
0229             if (!menu.visualParent.hasAudioStream) {
0230                 menu.addMenuItem(newSeparator(menu), startNewInstanceItem);
0231             }
0232 
0233             // If we don't have a window associated with the player but we can quit
0234             // it through MPRIS we'll offer a "Quit" option instead of "Close"
0235             if (!closeWindowItem.visible && playerData.canQuit) {
0236                 menuItem = menu.newMenuItem(menu);
0237                 menuItem.text = i18nc("Quit media player app", "Quit");
0238                 menuItem.icon = "application-exit";
0239                 menuItem.visible = Qt.binding(function() {
0240                     return !closeWindowItem.visible;
0241                 });
0242                 menuItem.clicked.connect(function() {
0243                     playerData.Quit();
0244                 });
0245                 menu.addMenuItem(menuItem);
0246             }
0247 
0248             // If we don't have a window associated with the player but we can raise
0249             // it through MPRIS we'll offer a "Restore" option
0250             if (get(atm.IsLauncher) && !startNewInstanceItem.visible && playerData.canRaise) {
0251                 menuItem = menu.newMenuItem(menu);
0252                 menuItem.text = i18nc("Open or bring to the front window of media player app", "Restore");
0253                 menuItem.icon = playerData.iconName;
0254                 menuItem.visible = Qt.binding(function() {
0255                     return !startNewInstanceItem.visible;
0256                 });
0257                 menuItem.clicked.connect(function() {
0258                     playerData.Raise();
0259                 });
0260                 menu.addMenuItem(menuItem, startNewInstanceItem);
0261             }
0262         }
0263 
0264         // We allow mute/unmute whenever an application has a stream, regardless of whether it
0265         // is actually playing sound.
0266         // This way you can unmute, e.g. a telephony app, even after the conversation has ended,
0267         // so you still have it ringing later on.
0268         if (menu.visualParent.hasAudioStream) {
0269             var muteItem = menu.newMenuItem(menu);
0270             muteItem.checkable = true;
0271             muteItem.checked = Qt.binding(function() {
0272                 return menu.visualParent && menu.visualParent.muted;
0273             });
0274             muteItem.clicked.connect(function() {
0275                 menu.visualParent.toggleMuted();
0276             });
0277             muteItem.text = i18n("Mute");
0278             muteItem.icon = "audio-volume-muted";
0279             menu.addMenuItem(muteItem, startNewInstanceItem);
0280 
0281             menu.addMenuItem(newSeparator(menu), startNewInstanceItem);
0282         }
0283     }
0284 
0285     PlasmaExtras.MenuItem {
0286         id: startNewInstanceItem
0287         visible: get(atm.CanLaunchNewInstance)
0288         text: i18n("Open New Window")
0289         icon: "window-new"
0290 
0291         onClicked: tasksModel.requestNewInstance(modelIndex)
0292     }
0293 
0294     PlasmaExtras.MenuItem {
0295         id: virtualDesktopsMenuItem
0296 
0297         visible: virtualDesktopInfo.numberOfDesktops > 1
0298             && (visualParent && !get(atm.IsLauncher)
0299             && !get(atm.IsStartup)
0300             && get(atm.IsVirtualDesktopsChangeable))
0301 
0302         enabled: visible
0303 
0304         text: i18n("Move to &Desktop")
0305         icon: "virtual-desktops"
0306 
0307         property Connections virtualDesktopsMenuConnections: Connections {
0308             target: virtualDesktopInfo
0309 
0310             function onNumberOfDesktopsChanged() {Qt.callLater(virtualDesktopsMenu.refresh)}
0311             function onDesktopIdsChanged() {Qt.callLater(virtualDesktopsMenu.refresh)}
0312             function onDesktopNamesChanged() {Qt.callLater(virtualDesktopsMenu.refresh)}
0313         }
0314 
0315         property PlasmaExtras.Menu _virtualDesktopsMenu: PlasmaExtras.Menu {
0316             id: virtualDesktopsMenu
0317 
0318             visualParent: virtualDesktopsMenuItem.action
0319 
0320             function refresh() {
0321                 clearMenuItems();
0322 
0323                 if (virtualDesktopInfo.numberOfDesktops <= 1 || !virtualDesktopsMenuItem.enabled) {
0324                     return;
0325                 }
0326 
0327                 var menuItem = menu.newMenuItem(virtualDesktopsMenu);
0328                 menuItem.text = i18n("Move &To Current Desktop");
0329                 menuItem.enabled = Qt.binding(function() {
0330                     return menu.visualParent && menu.get(atm.VirtualDesktops).indexOf(virtualDesktopInfo.currentDesktop) === -1;
0331                 });
0332                 menuItem.clicked.connect(function() {
0333                     tasksModel.requestVirtualDesktops(menu.modelIndex, [virtualDesktopInfo.currentDesktop]);
0334                 });
0335 
0336                 menuItem = menu.newMenuItem(virtualDesktopsMenu);
0337                 menuItem.text = i18n("&All Desktops");
0338                 menuItem.checkable = true;
0339                 menuItem.checked = Qt.binding(function() {
0340                     return menu.visualParent && menu.get(atm.IsOnAllVirtualDesktops);
0341                 });
0342                 menuItem.clicked.connect(function() {
0343                     tasksModel.requestVirtualDesktops(menu.modelIndex, []);
0344                 });
0345                 backend.setActionGroup(menuItem.action);
0346 
0347                 menu.newSeparator(virtualDesktopsMenu);
0348 
0349                 for (var i = 0; i < virtualDesktopInfo.desktopNames.length; ++i) {
0350                     menuItem = menu.newMenuItem(virtualDesktopsMenu);
0351                     menuItem.text = i18nc("1 = number of desktop, 2 = desktop name", "&%1 %2", i + 1, virtualDesktopInfo.desktopNames[i]);
0352                     menuItem.checkable = true;
0353                     menuItem.checked = Qt.binding((function(i) {
0354                         return function() { return menu.visualParent && menu.get(atm.VirtualDesktops).indexOf(virtualDesktopInfo.desktopIds[i]) > -1 };
0355                     })(i));
0356                     menuItem.clicked.connect((function(i) {
0357                         return function() { return tasksModel.requestVirtualDesktops(menu.modelIndex, [virtualDesktopInfo.desktopIds[i]]); };
0358                     })(i));
0359                     backend.setActionGroup(menuItem.action);
0360                 }
0361 
0362                 menu.newSeparator(virtualDesktopsMenu);
0363 
0364                 menuItem = menu.newMenuItem(virtualDesktopsMenu);
0365                 menuItem.text = i18n("&New Desktop");
0366                 menuItem.icon = "list-add";
0367                 menuItem.clicked.connect(function() {
0368                     tasksModel.requestNewVirtualDesktop(menu.modelIndex);
0369                 });
0370             }
0371 
0372             Component.onCompleted: refresh()
0373         }
0374     }
0375 
0376      PlasmaExtras.MenuItem {
0377         id: activitiesDesktopsMenuItem
0378 
0379         visible: activityInfo.numberOfRunningActivities > 1
0380             && (visualParent && !get(atm.IsLauncher)
0381             && !get(atm.IsStartup))
0382 
0383         enabled: visible
0384 
0385         text: i18n("Show in &Activities")
0386         icon: "activities"
0387 
0388         property Connections activityInfoConnections : Connections {
0389             target: activityInfo
0390 
0391             function onNumberOfRunningActivitiesChanged() {
0392                 activitiesDesktopsMenu.refresh()
0393             }
0394         }
0395 
0396         property PlasmaExtras.Menu _activitiesDesktopsMenu: PlasmaExtras.Menu {
0397             id: activitiesDesktopsMenu
0398 
0399             visualParent: activitiesDesktopsMenuItem.action
0400 
0401             function refresh() {
0402                 clearMenuItems();
0403 
0404                 if (activityInfo.numberOfRunningActivities <= 1) {
0405                     return;
0406                 }
0407 
0408                 var menuItem = menu.newMenuItem(activitiesDesktopsMenu);
0409                 menuItem.text = i18n("Add To Current Activity");
0410                 menuItem.enabled = Qt.binding(function() {
0411                     return menu.visualParent && menu.get(atm.Activities).length > 0 &&
0412                            menu.get(atm.Activities).indexOf(activityInfo.currentActivity) < 0;
0413                 });
0414                 menuItem.clicked.connect(function() {
0415                     tasksModel.requestActivities(menu.modelIndex, menu.get(atm.Activities).concat(activityInfo.currentActivity));
0416                 });
0417 
0418                 menuItem = menu.newMenuItem(activitiesDesktopsMenu);
0419                 menuItem.text = i18n("All Activities");
0420                 menuItem.checkable = true;
0421                 menuItem.checked = Qt.binding(function() {
0422                     return menu.visualParent && menu.get(atm.Activities).length === 0;
0423                 });
0424                 menuItem.toggled.connect(function(checked) {
0425                     let newActivities = []; // will cast to an empty QStringList i.e all activities
0426                     if (!checked) {
0427                         newActivities = new Array(activityInfo.currentActivity);
0428                     }
0429                     tasksModel.requestActivities(menu.modelIndex, newActivities);
0430                 });
0431 
0432                 menu.newSeparator(activitiesDesktopsMenu);
0433 
0434                 var runningActivities = activityInfo.runningActivities();
0435                 for (var i = 0; i < runningActivities.length; ++i) {
0436                     var activityId = runningActivities[i];
0437 
0438                     menuItem = menu.newMenuItem(activitiesDesktopsMenu);
0439                     menuItem.text = activityInfo.activityName(runningActivities[i]);
0440                     menuItem.icon = activityInfo.activityIcon(runningActivities[i]);
0441                     menuItem.checkable = true;
0442                     menuItem.checked = Qt.binding( (function(activityId) {
0443                         return function() {
0444                             return menu.visualParent && menu.get(atm.Activities).indexOf(activityId) >= 0;
0445                         };
0446                     })(activityId));
0447                     menuItem.toggled.connect((function(activityId) {
0448                         return function (checked) {
0449                             var newActivities = menu.get(atm.Activities);
0450                             if (checked) {
0451                                 newActivities = newActivities.concat(activityId);
0452                             } else {
0453                                 var index = newActivities.indexOf(activityId)
0454                                 if (index < 0) {
0455                                     return;
0456                                 }
0457 
0458                                 newActivities.splice(index, 1);
0459                             }
0460                             return tasksModel.requestActivities(menu.modelIndex, newActivities);
0461                         };
0462                     })(activityId));
0463                 }
0464 
0465                 menu.newSeparator(activitiesDesktopsMenu);
0466 
0467                 for (var i = 0; i < runningActivities.length; ++i) {
0468                     var activityId = runningActivities[i];
0469                     var onActivities = menu.get(atm.Activities);
0470 
0471                     // if the task is on a single activity, don't insert a "move to" item for that activity
0472                     if(onActivities.length == 1 && onActivities[0] == activityId) {
0473                         continue;
0474                     }
0475 
0476                     menuItem = menu.newMenuItem(activitiesDesktopsMenu);
0477                     menuItem.text = i18n("Move to %1", activityInfo.activityName(activityId))
0478                     menuItem.icon = activityInfo.activityIcon(activityId)
0479                     menuItem.clicked.connect((function(activityId) {
0480                         return function () {
0481                             return tasksModel.requestActivities(menu.modelIndex, [activityId]);
0482                         };
0483                     })(activityId));
0484                 }
0485 
0486                 menu.newSeparator(activitiesDesktopsMenu);
0487             }
0488 
0489             Component.onCompleted: refresh()
0490         }
0491     }
0492 
0493     PlasmaExtras.MenuItem {
0494         id: launcherToggleAction
0495 
0496         visible: visualParent
0497                      && !get(atm.IsLauncher)
0498                      && !get(atm.IsStartup)
0499                      && Plasmoid.immutability !== PlasmaCore.Types.SystemImmutable
0500                      && (activityInfo.numberOfRunningActivities < 2)
0501                      && !doesBelongToCurrentActivity()
0502 
0503         enabled: visualParent && get(atm.LauncherUrlWithoutIcon) != ""
0504 
0505         text: i18n("&Pin to Task Manager")
0506         icon: "window-pin"
0507 
0508         function doesBelongToCurrentActivity() {
0509             return tasksModel.launcherActivities(get(atm.LauncherUrlWithoutIcon)).some(function(activity) {
0510                 return activity === activityInfo.currentActivity || activity === activityInfo.nullUuid;
0511             });
0512         }
0513 
0514         onClicked: {
0515             tasksModel.requestAddLauncher(get(atm.LauncherUrl));
0516         }
0517     }
0518 
0519     PlasmaExtras.MenuItem {
0520         id: showLauncherInActivitiesItem
0521 
0522         text: i18n("&Pin to Task Manager")
0523         icon: "window-pin"
0524 
0525         visible: visualParent
0526                      && !get(atm.IsStartup)
0527                      && Plasmoid.immutability !== PlasmaCore.Types.SystemImmutable
0528                      && (activityInfo.numberOfRunningActivities >= 2)
0529 
0530         property Connections activitiesLaunchersMenuConnections: Connections {
0531             target: activityInfo
0532             function onNumberOfRunningActivitiesChanged() {
0533                 activitiesDesktopsMenu.refresh()
0534             }
0535         }
0536 
0537         property PlasmaExtras.Menu _activitiesLaunchersMenu: PlasmaExtras.Menu {
0538             id: activitiesLaunchersMenu
0539             visualParent: showLauncherInActivitiesItem.action
0540 
0541             function refresh() {
0542                 clearMenuItems();
0543 
0544                 if (menu.visualParent === null) return;
0545 
0546                 var createNewItem = function(id, title, iconName, url, activities) {
0547                     var result = menu.newMenuItem(activitiesLaunchersMenu);
0548                     result.text = title;
0549                     result.icon = iconName;
0550 
0551                     result.visible = true;
0552                     result.checkable = true;
0553 
0554                     result.checked = activities.some(function(activity) { return activity === id });
0555 
0556                     result.clicked.connect(
0557                         function() {
0558                             if (result.checked) {
0559                                 tasksModel.requestAddLauncherToActivity(url, id);
0560                             } else {
0561                                 tasksModel.requestRemoveLauncherFromActivity(url, id);
0562                             }
0563                         }
0564                     );
0565 
0566                     return result;
0567                 }
0568 
0569                 if (menu.visualParent === null) return;
0570 
0571                 var url = menu.get(atm.LauncherUrlWithoutIcon);
0572 
0573                 var activities = tasksModel.launcherActivities(url);
0574 
0575                 createNewItem(activityInfo.nullUuid, i18n("On All Activities"), "", url, activities);
0576 
0577                 if (activityInfo.numberOfRunningActivities <= 1) {
0578                     return;
0579                 }
0580 
0581                 createNewItem(activityInfo.currentActivity, i18n("On The Current Activity"), activityInfo.activityIcon(activityInfo.currentActivity), url, activities);
0582 
0583                 menu.newSeparator(activitiesLaunchersMenu);
0584 
0585                 var runningActivities = activityInfo.runningActivities();
0586 
0587                 runningActivities.forEach(function(id) {
0588                     createNewItem(id, activityInfo.activityName(id), activityInfo.activityIcon(id), url, activities);
0589                 });
0590             }
0591 
0592             Component.onCompleted: {
0593                 menu.onVisualParentChanged.connect(refresh);
0594                 refresh();
0595             }
0596         }
0597     }
0598 
0599     PlasmaExtras.MenuItem {
0600         visible: (visualParent
0601                 && get(atm.IsStartup) !== true
0602                 && Plasmoid.immutability !== PlasmaCore.Types.SystemImmutable
0603                 && !launcherToggleAction.visible
0604                 && activityInfo.numberOfRunningActivities < 2)
0605 
0606         text: i18n("Unpin from Task Manager")
0607         icon: "window-unpin"
0608 
0609         onClicked: {
0610             tasksModel.requestRemoveLauncher(get(atm.LauncherUrlWithoutIcon));
0611         }
0612     }
0613 
0614     PlasmaExtras.MenuItem {
0615         id: moreActionsMenuItem
0616 
0617         visible: (visualParent && !get(atm.IsLauncher) && !get(atm.IsStartup))
0618 
0619         enabled: visible
0620 
0621         text: i18n("More")
0622         icon: "view-more-symbolic"
0623 
0624         property PlasmaExtras.Menu moreMenu: PlasmaExtras.Menu {
0625             visualParent: moreActionsMenuItem.action
0626 
0627             PlasmaExtras.MenuItem {
0628                 enabled: menu.visualParent && menu.get(atm.IsMovable)
0629 
0630                 text: i18n("&Move")
0631                 icon: "transform-move"
0632 
0633                 onClicked: tasksModel.requestMove(menu.modelIndex)
0634             }
0635 
0636             PlasmaExtras.MenuItem {
0637                 enabled: menu.visualParent && menu.get(atm.IsResizable)
0638 
0639                 text: i18n("Re&size")
0640                 icon: "transform-scale"
0641 
0642                 onClicked: tasksModel.requestResize(menu.modelIndex)
0643             }
0644 
0645             PlasmaExtras.MenuItem {
0646                 visible: (menu.visualParent && !get(atm.IsLauncher) && !get(atm.IsStartup))
0647 
0648                 enabled: menu.visualParent && get(atm.IsMaximizable)
0649 
0650                 checkable: true
0651                 checked: menu.visualParent && get(atm.IsMaximized)
0652 
0653                 text: i18n("Ma&ximize")
0654                 icon: "window-maximize"
0655 
0656                 onClicked: tasksModel.requestToggleMaximized(modelIndex)
0657             }
0658 
0659             PlasmaExtras.MenuItem {
0660                 visible: (menu.visualParent && !get(atm.IsLauncher) && !get(atm.IsStartup))
0661 
0662                 enabled: menu.visualParent && get(atm.IsMinimizable)
0663 
0664                 checkable: true
0665                 checked: menu.visualParent && get(atm.IsMinimized)
0666 
0667                 text: i18n("Mi&nimize")
0668                 icon: "window-minimize"
0669 
0670                 onClicked: tasksModel.requestToggleMinimized(modelIndex)
0671             }
0672 
0673             PlasmaExtras.MenuItem {
0674                 checkable: true
0675                 checked: menu.visualParent && menu.get(atm.IsKeepAbove)
0676 
0677                 text: i18n("Keep &Above Others")
0678                 icon: "window-keep-above"
0679 
0680                 onClicked: tasksModel.requestToggleKeepAbove(menu.modelIndex)
0681             }
0682 
0683             PlasmaExtras.MenuItem {
0684                 checkable: true
0685                 checked: menu.visualParent && menu.get(atm.IsKeepBelow)
0686 
0687                 text: i18n("Keep &Below Others")
0688                 icon: "window-keep-below"
0689 
0690                 onClicked: tasksModel.requestToggleKeepBelow(menu.modelIndex)
0691             }
0692 
0693             PlasmaExtras.MenuItem {
0694                 enabled: menu.visualParent && menu.get(atm.IsFullScreenable)
0695 
0696                 checkable: true
0697                 checked: menu.visualParent && menu.get(atm.IsFullScreen)
0698 
0699                 text: i18n("&Fullscreen")
0700                 icon: "view-fullscreen"
0701 
0702                 onClicked: tasksModel.requestToggleFullScreen(menu.modelIndex)
0703             }
0704 
0705             PlasmaExtras.MenuItem {
0706                 enabled: menu.visualParent && menu.get(atm.IsShadeable)
0707 
0708                 checkable: true
0709                 checked: menu.visualParent && menu.get(atm.IsShaded)
0710 
0711                 text: i18n("&Shade")
0712                 icon: "window-shade"
0713 
0714                 onClicked: tasksModel.requestToggleShaded(menu.modelIndex)
0715             }
0716 
0717             PlasmaExtras.MenuItem {
0718                 separator: true
0719             }
0720 
0721             PlasmaExtras.MenuItem {
0722                 visible: (Plasmoid.configuration.groupingStrategy !== 0) && menu.get(atm.IsWindow)
0723 
0724                 checkable: true
0725                 checked: menu.visualParent && menu.get(atm.IsGroupable)
0726 
0727                 text: i18n("Allow this program to be grouped")
0728                 icon: "view-group"
0729 
0730                 onClicked: tasksModel.requestToggleGrouping(menu.modelIndex)
0731             }
0732         }
0733     }
0734 
0735     PlasmaExtras.MenuItem { separator: true }
0736 
0737     PlasmaExtras.MenuItem {
0738         property QtObject configureAction: null
0739 
0740         enabled: configureAction && configureAction.enabled
0741         visible: configureAction && configureAction.visible
0742 
0743         text: configureAction ? configureAction.text : ""
0744         icon: configureAction ? configureAction.icon : ""
0745 
0746         onClicked: configureAction.trigger()
0747 
0748         Component.onCompleted: configureAction = Plasmoid.internalAction("configure")
0749     }
0750 
0751     PlasmaExtras.MenuItem {
0752         property QtObject editModeAction: null
0753 
0754         enabled: editModeAction && editModeAction.enabled
0755         visible: editModeAction && editModeAction.visible
0756 
0757         text: editModeAction ? editModeAction.text : ""
0758         icon: editModeAction ? editModeAction.icon : ""
0759 
0760         onClicked: editModeAction.trigger()
0761 
0762         Component.onCompleted: editModeAction = Plasmoid.containment.internalAction("configure")
0763     }
0764 
0765     PlasmaExtras.MenuItem { separator: true }
0766 
0767     PlasmaExtras.MenuItem {
0768         id: closeWindowItem
0769         visible: (visualParent && !get(atm.IsLauncher) && !get(atm.IsStartup))
0770 
0771         enabled: visualParent && get(atm.IsClosable)
0772 
0773         text: get(atm.IsGroupParent) ? i18nc("@item:inmenu", "&Close All") : i18n("&Close")
0774         icon: "window-close"
0775 
0776         onClicked: {
0777             if (tasks.groupDialog !== null && tasks.groupDialog.visualParent === visualParent) {
0778                 tasks.groupDialog.visible = false;
0779             }
0780 
0781             tasksModel.requestClose(modelIndex);
0782         }
0783     }
0784 }