1/* 2 SPDX-FileCopyrightText: 2012-2016 Eike Hein <hein@kde.org> 3 SPDX-FileCopyrightText: 2016 Kai Uwe Broulik <kde@privat.broulik.de> 4 5 SPDX-License-Identifier: GPL-2.0-or-later 6*/ 7 8import QtQuick 2.0 9 10import org.kde.plasma.plasmoid 2.0 11 12import org.kde.plasma.core 2.0 as PlasmaCore 13import org.kde.plasma.components 2.0 as PlasmaComponents 14 15import org.kde.taskmanager 0.1 as TaskManager 16 17import "code/layout.js" as LayoutManager 18 19PlasmaComponents.ContextMenu { 20 id: menu 21 22 property QtObject backend 23 property QtObject mpris2Source 24 property var modelIndex 25 readonly property var atm: TaskManager.AbstractTasksModel 26 27 property bool showAllPlaces: false 28 29 placement: { 30 if (plasmoid.location === PlasmaCore.Types.LeftEdge) { 31 return PlasmaCore.Types.RightPosedTopAlignedPopup; 32 } else if (plasmoid.location === PlasmaCore.Types.TopEdge) { 33 return PlasmaCore.Types.BottomPosedLeftAlignedPopup; 34 } else if (plasmoid.location === PlasmaCore.Types.RightEdge) { 35 return PlasmaCore.Types.LeftPosedTopAlignedPopup; 36 } else { 37 return PlasmaCore.Types.TopPosedLeftAlignedPopup; 38 } 39 } 40 41 minimumWidth: visualParent.width 42 43 onStatusChanged: { 44 if (visualParent && get(atm.LauncherUrlWithoutIcon) != "" && status == PlasmaComponents.DialogStatus.Open) { 45 activitiesDesktopsMenu.refresh(); 46 47 } else if (status == PlasmaComponents.DialogStatus.Closed) { 48 menu.destroy(); 49 backend.ungrabMouse(visualParent); 50 } 51 } 52 53 Component.onCompleted: { 54 // Cannot have "Connections" as child of PlasmaCoponents.ContextMenu. 55 backend.showAllPlaces.connect(showContextMenuWithAllPlaces); 56 } 57 58 Component.onDestruction: { 59 backend.showAllPlaces.disconnect(showContextMenuWithAllPlaces); 60 } 61 62 function showContextMenuWithAllPlaces() { 63 visualParent.showContextMenu({showAllPlaces: true}); 64 } 65 66 function get(modelProp) { 67 return tasksModel.data(modelIndex, modelProp) 68 } 69 70 function show() { 71 loadDynamicLaunchActions(get(atm.LauncherUrlWithoutIcon)); 72 openRelative(); 73 } 74 75 function newMenuItem(parent) { 76 return Qt.createQmlObject( 77 "import org.kde.plasma.components 2.0 as PlasmaComponents;" + 78 "PlasmaComponents.MenuItem {}", 79 parent); 80 } 81 82 function newSeparator(parent) { 83 return Qt.createQmlObject( 84 "import org.kde.plasma.components 2.0 as PlasmaComponents;" + 85 "PlasmaComponents.MenuItem { separator: true }", 86 parent); 87 } 88 89 function loadDynamicLaunchActions(launcherUrl) { 90 var sections = [ 91 { 92 title: i18n("Places"), 93 group: "places", 94 actions: backend.placesActions(launcherUrl, showAllPlaces, menu) 95 }, 96 { 97 title: i18n("Recent Files"), 98 group: "recents", 99 actions: backend.recentDocumentActions(launcherUrl, menu) 100 }, 101 { 102 title: i18n("Actions"), 103 group: "actions", 104 actions: backend.jumpListActions(launcherUrl, menu) 105 } 106 ] 107 108 // QMenu does not limit its width automatically. Even if we set a maximumWidth 109 // it would just cut off text rather than eliding. So we do this manually. 110 var textMetrics = Qt.createQmlObject("import QtQuick 2.4; TextMetrics {}", menu); 111 var maximumWidth = LayoutManager.maximumContextMenuTextWidth(); 112 113 sections.forEach(function (section) { 114 if (section["actions"].length > 0 || section["group"] == "actions") { 115 // Don't add the "Actions" header if the menu has nothing but actions 116 // in it, because then it's redundant (all menus have actions) 117 if ( 118 (section["group"] != "actions") || 119 (section["group"] == "actions" && (sections[0]["actions"].length > 0 || sections[1]["actions"].length > 0)) 120 ) { 121 var sectionHeader = newMenuItem(menu); 122 sectionHeader.text = section["title"]; 123 sectionHeader.section = true; 124 menu.addMenuItem(sectionHeader, startNewInstanceItem); 125 } 126 } 127 128 for (var i = 0; i < section["actions"].length; ++i) { 129 var item = newMenuItem(menu); 130 item.action = section["actions"][i]; 131 132 // Crude way of manually eliding... 133 var elided = false; 134 textMetrics.text = Qt.binding(function() { 135 return item.action.text; 136 }); 137 138 while (textMetrics.width > maximumWidth) { 139 item.action.text = item.action.text.slice(0, -1); 140 elided = true; 141 } 142 143 if (elided) { 144 item.action.text += "…"; 145 } 146 147 menu.addMenuItem(item, startNewInstanceItem); 148 } 149 }); 150 151 // Add Media Player control actions 152 var sourceName = mpris2Source.sourceNameForLauncherUrl(launcherUrl, get(atm.AppPid)); 153 154 if (sourceName && !(get(atm.WinIdList) !== undefined && get(atm.WinIdList).length > 1)) { 155 var playerData = mpris2Source.data[sourceName] 156 157 if (playerData.CanControl) { 158 var playing = (playerData.PlaybackStatus === "Playing"); 159 var menuItem = menu.newMenuItem(menu); 160 menuItem.text = i18nc("Play previous track", "Previous Track"); 161 menuItem.icon = "media-skip-backward"; 162 menuItem.enabled = Qt.binding(function() { 163 return playerData.CanGoPrevious; 164 }); 165 menuItem.clicked.connect(function() { 166 mpris2Source.goPrevious(sourceName); 167 }); 168 menu.addMenuItem(menuItem, startNewInstanceItem); 169 170 menuItem = menu.newMenuItem(menu); 171 // PlasmaCore Menu doesn't actually handle icons or labels changing at runtime... 172 menuItem.text = Qt.binding(function() { 173 // if CanPause, toggle the menu entry between Play & Pause, otherwise always use Play 174 return playing && playerData.CanPause ? i18nc("Pause playback", "Pause") : i18nc("Start playback", "Play"); 175 }); 176 menuItem.icon = Qt.binding(function() { 177 return playing && playerData.CanPause ? "media-playback-pause" : "media-playback-start"; 178 }); 179 menuItem.enabled = Qt.binding(function() { 180 return playing ? playerData.CanPause : playerData.CanPlay; 181 }); 182 menuItem.clicked.connect(function() { 183 if (playing) { 184 mpris2Source.pause(sourceName); 185 } else { 186 mpris2Source.play(sourceName); 187 } 188 }); 189 menu.addMenuItem(menuItem, startNewInstanceItem); 190 191 menuItem = menu.newMenuItem(menu); 192 menuItem.text = i18nc("Play next track", "Next Track"); 193 menuItem.icon = "media-skip-forward"; 194 menuItem.enabled = Qt.binding(function() { 195 return playerData.CanGoNext; 196 }); 197 menuItem.clicked.connect(function() { 198 mpris2Source.goNext(sourceName); 199 }); 200 menu.addMenuItem(menuItem, startNewInstanceItem); 201 202 menuItem = menu.newMenuItem(menu); 203 menuItem.text = i18nc("Stop playback", "Stop"); 204 menuItem.icon = "media-playback-stop"; 205 menuItem.enabled = Qt.binding(function() { 206 return playerData.PlaybackStatus !== "Stopped"; 207 }); 208 menuItem.clicked.connect(function() { 209 mpris2Source.stop(sourceName); 210 }); 211 menu.addMenuItem(menuItem, startNewInstanceItem); 212 213 // Technically media controls and audio streams are separate but for the user they're 214 // semantically related, don't add a separator inbetween. 215 if (!menu.visualParent.hasAudioStream) { 216 menu.addMenuItem(newSeparator(menu), startNewInstanceItem); 217 } 218 219 // If we don't have a window associated with the player but we can quit 220 // it through MPRIS we'll offer a "Quit" option instead of "Close" 221 if (!closeWindowItem.visible && playerData.CanQuit) { 222 menuItem = menu.newMenuItem(menu); 223 menuItem.text = i18nc("Quit media player app", "Quit"); 224 menuItem.icon = "application-exit"; 225 menuItem.visible = Qt.binding(function() { 226 return !closeWindowItem.visible; 227 }); 228 menuItem.clicked.connect(function() { 229 mpris2Source.quit(sourceName); 230 }); 231 menu.addMenuItem(menuItem); 232 } 233 234 // If we don't have a window associated with the player but we can raise 235 // it through MPRIS we'll offer a "Restore" option 236 if (!startNewInstanceItem.visible && playerData.CanRaise) { 237 menuItem = menu.newMenuItem(menu); 238 menuItem.text = i18nc("Open or bring to the front window of media player app", "Restore"); 239 menuItem.icon = playerData["Desktop Icon Name"]; 240 menuItem.visible = Qt.binding(function() { 241 return !startNewInstanceItem.visible; 242 }); 243 menuItem.clicked.connect(function() { 244 mpris2Source.raise(sourceName); 245 }); 246 menu.addMenuItem(menuItem, startNewInstanceItem); 247 } 248 } 249 } 250 251 // We allow mute/unmute whenever an application has a stream, regardless of whether it 252 // is actually playing sound. 253 // This way you can unmute, e.g. a telephony app, even after the conversation has ended, 254 // so you still have it ringing later on. 255 if (menu.visualParent.hasAudioStream) { 256 var muteItem = menu.newMenuItem(menu); 257 muteItem.checkable = true; 258 muteItem.checked = Qt.binding(function() { 259 return menu.visualParent && menu.visualParent.muted; 260 }); 261 muteItem.clicked.connect(function() { 262 menu.visualParent.toggleMuted(); 263 }); 264 muteItem.text = i18n("Mute"); 265 muteItem.icon = "audio-volume-muted"; 266 menu.addMenuItem(muteItem, startNewInstanceItem); 267 268 menu.addMenuItem(newSeparator(menu), startNewInstanceItem); 269 } 270 } 271 272 PlasmaComponents.MenuItem { 273 id: startNewInstanceItem 274 visible: (visualParent && get(atm.IsLauncher) !== true && get(atm.IsStartup) !== true) 275 276 enabled: visualParent && get(atm.LauncherUrlWithoutIcon) != "" 277 278 text: i18n("Start New Instance") 279 icon: "list-add-symbolic" 280 281 onClicked: tasksModel.requestNewInstance(modelIndex) 282 } 283 284 PlasmaComponents.MenuItem { 285 id: virtualDesktopsMenuItem 286 287 visible: virtualDesktopInfo.numberOfDesktops > 1 288 && (visualParent && get(atm.IsLauncher) !== true 289 && get(atm.IsStartup) !== true 290 && get(atm.IsVirtualDesktopsChangeable) === true) 291 292 enabled: visible 293 294 text: i18n("Move to &Desktop") 295 icon: "virtual-desktops" 296 297 Connections { 298 target: virtualDesktopInfo 299 300 function onNumberOfDesktopsChanged() {Qt.callLater(virtualDesktopsMenu.refresh)} 301 function onDesktopIdsChanged() {Qt.callLater(virtualDesktopsMenu.refresh)} 302 function onDesktopNamesChanged() {Qt.callLater(virtualDesktopsMenu.refresh)} 303 } 304 305 PlasmaComponents.ContextMenu { 306 id: virtualDesktopsMenu 307 308 visualParent: virtualDesktopsMenuItem.action 309 310 function refresh() { 311 clearMenuItems(); 312 313 if (virtualDesktopInfo.numberOfDesktops <= 1) { 314 return; 315 } 316 317 var menuItem = menu.newMenuItem(virtualDesktopsMenu); 318 menuItem.text = i18n("Move &To Current Desktop"); 319 menuItem.enabled = Qt.binding(function() { 320 return menu.visualParent && menu.get(atm.VirtualDesktops).indexOf(virtualDesktopInfo.currentDesktop) === -1; 321 }); 322 menuItem.clicked.connect(function() { 323 tasksModel.requestVirtualDesktops(menu.modelIndex, [virtualDesktopInfo.currentDesktop]); 324 }); 325 326 menuItem = menu.newMenuItem(virtualDesktopsMenu); 327 menuItem.text = i18n("&All Desktops"); 328 menuItem.checkable = true; 329 menuItem.checked = Qt.binding(function() { 330 return menu.visualParent && menu.get(atm.IsOnAllVirtualDesktops) === true; 331 }); 332 menuItem.clicked.connect(function() { 333 tasksModel.requestVirtualDesktops(menu.modelIndex, []); 334 }); 335 backend.setActionGroup(menuItem.action); 336 337 menu.newSeparator(virtualDesktopsMenu); 338 339 for (var i = 0; i < virtualDesktopInfo.desktopNames.length; ++i) { 340 menuItem = menu.newMenuItem(virtualDesktopsMenu); 341 menuItem.text = i18nc("1 = number of desktop, 2 = desktop name", "&%1 %2", i + 1, virtualDesktopInfo.desktopNames[i]); 342 menuItem.checkable = true; 343 menuItem.checked = Qt.binding((function(i) { 344 return function() { return menu.visualParent && menu.get(atm.VirtualDesktops).indexOf(virtualDesktopInfo.desktopIds[i]) > -1 }; 345 })(i)); 346 menuItem.clicked.connect((function(i) { 347 return function() { return tasksModel.requestVirtualDesktops(menu.modelIndex, [virtualDesktopInfo.desktopIds[i]]); }; 348 })(i)); 349 backend.setActionGroup(menuItem.action); 350 } 351 352 menu.newSeparator(virtualDesktopsMenu); 353 354 menuItem = menu.newMenuItem(virtualDesktopsMenu); 355 menuItem.text = i18n("&New Desktop"); 356 menuItem.clicked.connect(function() { 357 tasksModel.requestNewVirtualDesktop(menu.modelIndex); 358 }); 359 } 360 361 Component.onCompleted: refresh() 362 } 363 } 364 365 PlasmaComponents.MenuItem { 366 id: activitiesDesktopsMenuItem 367 368 visible: activityInfo.numberOfRunningActivities > 1 369 && (visualParent && !get(atm.IsLauncher) 370 && !get(atm.IsStartup)) 371 372 enabled: visible 373 374 text: i18n("Show in &Activities") 375 icon: "activities" 376 377 Connections { 378 target: activityInfo 379 380 function onNumberOfRunningActivitiesChanged() { 381 activitiesDesktopsMenu.refresh() 382 } 383 } 384 385 PlasmaComponents.ContextMenu { 386 id: activitiesDesktopsMenu 387 388 visualParent: activitiesDesktopsMenuItem.action 389 390 function refresh() { 391 clearMenuItems(); 392 393 if (activityInfo.numberOfRunningActivities <= 1) { 394 return; 395 } 396 397 var menuItem = menu.newMenuItem(activitiesDesktopsMenu); 398 menuItem.text = i18n("Add To Current Activity"); 399 menuItem.enabled = Qt.binding(function() { 400 return menu.visualParent && menu.get(atm.Activities).length > 0 && 401 menu.get(atm.Activities).indexOf(activityInfo.currentActivity) < 0; 402 }); 403 menuItem.clicked.connect(function() { 404 tasksModel.requestActivities(menu.modelIndex, menu.get(atm.Activities).concat(activityInfo.currentActivity)); 405 }); 406 407 menuItem = menu.newMenuItem(activitiesDesktopsMenu); 408 menuItem.text = i18n("All Activities"); 409 menuItem.checkable = true; 410 menuItem.checked = Qt.binding(function() { 411 return menu.visualParent && menu.get(atm.Activities).length === 0; 412 }); 413 menuItem.toggled.connect(function(checked) { 414 var newActivities = undefined; // will cast to an empty QStringList i.e all activities 415 if (!checked) { 416 newActivities = new Array(activityInfo.currentActivity); 417 } 418 tasksModel.requestActivities(menu.modelIndex, newActivities); 419 }); 420 421 menu.newSeparator(activitiesDesktopsMenu); 422 423 var runningActivities = activityInfo.runningActivities(); 424 for (var i = 0; i < runningActivities.length; ++i) { 425 var activityId = runningActivities[i]; 426 427 menuItem = menu.newMenuItem(activitiesDesktopsMenu); 428 menuItem.text = activityInfo.activityName(runningActivities[i]); 429 menuItem.checkable = true; 430 menuItem.checked = Qt.binding( (function(activityId) { 431 return function() { 432 return menu.visualParent && menu.get(atm.Activities).indexOf(activityId) >= 0; 433 }; 434 })(activityId)); 435 menuItem.toggled.connect((function(activityId) { 436 return function (checked) { 437 var newActivities = menu.get(atm.Activities); 438 if (checked) { 439 newActivities = newActivities.concat(activityId); 440 } else { 441 var index = newActivities.indexOf(activityId) 442 if (index < 0) { 443 return; 444 } 445 446 newActivities.splice(index, 1); 447 } 448 return tasksModel.requestActivities(menu.modelIndex, newActivities); 449 }; 450 })(activityId)); 451 } 452 453 menu.newSeparator(activitiesDesktopsMenu); 454 } 455 456 Component.onCompleted: refresh() 457 } 458 } 459 460 PlasmaComponents.MenuItem { 461 id: moreActionsMenuItem 462 463 visible: (visualParent && get(atm.IsLauncher) !== true && get(atm.IsStartup) !== true) 464 465 enabled: visible 466 467 text: i18n("More Actions") 468 icon: "view-more-symbolic" 469 470 PlasmaComponents.ContextMenu { 471 visualParent: moreActionsMenuItem.action 472 473 PlasmaComponents.MenuItem { 474 enabled: menu.visualParent && menu.get(atm.IsMovable) === true 475 476 text: i18n("&Move") 477 icon: "transform-move" 478 479 onClicked: tasksModel.requestMove(menu.modelIndex) 480 } 481 482 PlasmaComponents.MenuItem { 483 enabled: menu.visualParent && menu.get(atm.IsResizable) === true 484 485 text: i18n("Re&size") 486 icon: "transform-scale" 487 488 onClicked: tasksModel.requestResize(menu.modelIndex) 489 } 490 491 PlasmaComponents.MenuItem { 492 visible: (menu.visualParent && get(atm.IsLauncher) !== true && get(atm.IsStartup) !== true) 493 494 enabled: menu.visualParent && get(atm.IsMaximizable) === true 495 496 checkable: true 497 checked: menu.visualParent && get(atm.IsMaximized) === true 498 499 text: i18n("Ma&ximize") 500 icon: "window-maximize" 501 502 onClicked: tasksModel.requestToggleMaximized(modelIndex) 503 } 504 505 PlasmaComponents.MenuItem { 506 visible: (menu.visualParent && get(atm.IsLauncher) !== true && get(atm.IsStartup) !== true) 507 508 enabled: menu.visualParent && get(atm.IsMinimizable) === true 509 510 checkable: true 511 checked: menu.visualParent && get(atm.IsMinimized) === true 512 513 text: i18n("Mi&nimize") 514 icon: "window-minimize" 515 516 onClicked: tasksModel.requestToggleMinimized(modelIndex) 517 } 518 519 PlasmaComponents.MenuItem { 520 checkable: true 521 checked: menu.visualParent && menu.get(atm.IsKeepAbove) === true 522 523 text: i18n("Keep &Above Others") 524 icon: "window-keep-above" 525 526 onClicked: tasksModel.requestToggleKeepAbove(menu.modelIndex) 527 } 528 529 PlasmaComponents.MenuItem { 530 checkable: true 531 checked: menu.visualParent && menu.get(atm.IsKeepBelow) === true 532 533 text: i18n("Keep &Below Others") 534 icon: "window-keep-below" 535 536 onClicked: tasksModel.requestToggleKeepBelow(menu.modelIndex) 537 } 538 539 PlasmaComponents.MenuItem { 540 enabled: menu.visualParent && menu.get(atm.IsFullScreenable) === true 541 542 checkable: true 543 checked: menu.visualParent && menu.get(atm.IsFullScreen) === true 544 545 text: i18n("&Fullscreen") 546 icon: "view-fullscreen" 547 548 onClicked: tasksModel.requestToggleFullScreen(menu.modelIndex) 549 } 550 551 PlasmaComponents.MenuItem { 552 enabled: menu.visualParent && menu.get(atm.IsShadeable) === true 553 554 checkable: true 555 checked: menu.visualParent && menu.get(atm.IsShaded) === true 556 557 text: i18n("&Shade") 558 icon: "window-shade" 559 560 onClicked: tasksModel.requestToggleShaded(menu.modelIndex) 561 } 562 563 PlasmaComponents.MenuItem { 564 separator: true 565 } 566 567 PlasmaComponents.MenuItem { 568 visible: (plasmoid.configuration.groupingStrategy !== 0) && menu.get(atm.IsWindow) === true 569 570 checkable: true 571 checked: menu.visualParent && menu.get(atm.IsGroupable) === true 572 573 text: i18n("Allow this program to be grouped") 574 icon: "view-group" 575 576 onClicked: tasksModel.requestToggleGrouping(menu.modelIndex) 577 } 578 579 PlasmaComponents.MenuItem { 580 separator: true 581 } 582 583 PlasmaComponents.MenuItem { 584 property QtObject configureAction: null 585 586 enabled: configureAction && configureAction.enabled 587 visible: configureAction && configureAction.visible 588 589 text: configureAction ? configureAction.text : "" 590 icon: configureAction ? configureAction.icon : "" 591 592 onClicked: configureAction.trigger() 593 594 Component.onCompleted: configureAction = plasmoid.action("configure") 595 } 596 597 PlasmaComponents.MenuItem { 598 property QtObject alternativesAction: null 599 600 enabled: alternativesAction && alternativesAction.enabled 601 visible: alternativesAction && alternativesAction.visible 602 603 text: alternativesAction ? alternativesAction.text : "" 604 icon: alternativesAction ? alternativesAction.icon : "" 605 606 onClicked: alternativesAction.trigger() 607 608 Component.onCompleted: alternativesAction = plasmoid.action("alternatives") 609 } 610 } 611 } 612 613 PlasmaComponents.MenuItem { 614 id: launcherToggleAction 615 616 visible: visualParent 617 && get(atm.IsLauncher) !== true 618 && get(atm.IsStartup) !== true 619 && plasmoid.immutability !== PlasmaCore.Types.SystemImmutable 620 && (activityInfo.numberOfRunningActivities < 2) 621 && tasksModel.launcherPosition(get(atm.LauncherUrlWithoutIcon)) == -1 622 623 enabled: visualParent && get(atm.LauncherUrlWithoutIcon) != "" 624 625 text: i18n("&Pin to Task Manager") 626 icon: "window-pin" 627 628 onClicked: { 629 if (tasksModel.launcherPosition(get(atm.LauncherUrlWithoutIcon)) !== -1) { 630 tasksModel.requestRemoveLauncher(get(atm.LauncherUrlWithoutIcon)); 631 } else { 632 tasksModel.requestAddLauncher(get(atm.LauncherUrl)); 633 } 634 } 635 } 636 637 PlasmaComponents.MenuItem { 638 id: showLauncherInActivitiesItem 639 640 text: i18n("&Pin to Task Manager") 641 icon: "window-pin" 642 643 visible: visualParent 644 && get(atm.IsLauncher) !== true 645 && get(atm.IsStartup) !== true 646 && plasmoid.immutability !== PlasmaCore.Types.SystemImmutable 647 && (activityInfo.numberOfRunningActivities >= 2) 648 649 Connections { 650 target: activityInfo 651 function onNumberOfRunningActivitiesChanged() { 652 activitiesDesktopsMenu.refresh() 653 } 654 } 655 656 PlasmaComponents.ContextMenu { 657 id: activitiesLaunchersMenu 658 visualParent: showLauncherInActivitiesItem.action 659 660 function refresh() { 661 clearMenuItems(); 662 663 if (menu.visualParent === null) return; 664 665 var createNewItem = function(id, title, url, activities) { 666 var result = menu.newMenuItem(activitiesLaunchersMenu); 667 result.text = title; 668 669 result.visible = true; 670 result.checkable = true; 671 672 result.checked = activities.some(function(activity) { return activity === id }); 673 674 result.clicked.connect( 675 function() { 676 if (result.checked) { 677 tasksModel.requestAddLauncherToActivity(url, id); 678 } else { 679 tasksModel.requestRemoveLauncherFromActivity(url, id); 680 } 681 } 682 ); 683 684 return result; 685 } 686 687 if (menu.visualParent === null) return; 688 689 var url = menu.get(atm.LauncherUrlWithoutIcon); 690 691 var activities = tasksModel.launcherActivities(url); 692 693 var NULL_UUID = "00000000-0000-0000-0000-000000000000"; 694 695 createNewItem(NULL_UUID, i18n("On All Activities"), url, activities); 696 697 if (activityInfo.numberOfRunningActivities <= 1) { 698 return; 699 } 700 701 createNewItem(activityInfo.currentActivity, i18n("On The Current Activity"), url, activities); 702 703 menu.newSeparator(activitiesLaunchersMenu); 704 705 var runningActivities = activityInfo.runningActivities(); 706 707 runningActivities.forEach(function(id) { 708 createNewItem(id, activityInfo.activityName(id), url, activities); 709 }); 710 } 711 712 Component.onCompleted: { 713 menu.onVisualParentChanged.connect(refresh); 714 refresh(); 715 } 716 } 717 } 718 719 PlasmaComponents.MenuItem { 720 visible: (visualParent 721 && plasmoid.immutability !== PlasmaCore.Types.SystemImmutable 722 && !launcherToggleAction.visible 723 && !showLauncherInActivitiesItem.visible) 724 725 text: i18n("Unpin from Task Manager") 726 icon: "window-unpin" 727 728 onClicked: { 729 tasksModel.requestRemoveLauncher(get(atm.LauncherUrlWithoutIcon)); 730 } 731 } 732 733 PlasmaComponents.MenuItem { separator: true } 734 735 PlasmaComponents.MenuItem { 736 id: closeWindowItem 737 visible: (visualParent && get(atm.IsLauncher) !== true && get(atm.IsStartup) !== true) 738 739 enabled: visualParent && get(atm.IsClosable) === true 740 741 text: i18n("&Close") 742 icon: "window-close" 743 744 onClicked: tasksModel.requestClose(modelIndex) 745 } 746} 747