Files

257 lines
9.0 KiB
QML

import QtQuick
import qs.Common
import qs.Services
import qs.Widgets
import "ControllerUtils.js" as Utils
DContextMenu {
id: root
property var item: null
property var controller: null
property var searchField: null
property var parentHandler: null
property string pinDockId: ""
readonly property bool isCoreApp: item?.type === "app" && !!item?.isCore
readonly property var coreAppData: isCoreApp ? item?.data ?? null : null
readonly property var desktopEntry: !isCoreApp ? (item?.data ?? null) : null
readonly property string appId: {
if (isCoreApp)
return item?.id || coreAppData?.builtInPluginId || "";
return desktopEntry?.id || desktopEntry?.execString || "";
}
readonly property bool isPinned: !!appId && SessionData.getDockPins(pinDockId).includes(appId)
readonly property bool isRegularApp: item?.type === "app" && !item.isCore && desktopEntry
readonly property bool isFlatpakApp: isRegularApp && (item?.source === "flatpak" || !!item?.flatpakId || Utils.classifyAppSource(desktopEntry) === "flatpak")
readonly property string flatpakAppId: item?.flatpakId || (isFlatpakApp ? Utils.extractFlatpakAppId(desktopEntry) : "")
readonly property bool isPluginItem: item?.type === "plugin"
signal editAppRequested(var app)
layerNamespace: "dms:launcher-context-menu"
keyboardNavigable: true
menuItems: {
if (isPluginItem)
return getPluginContextMenuActions().map(act => ({
type: "item",
icon: act.icon || "play_arrow",
text: act.text || act.name || "",
action: () => executePluginAction(act)
}));
if (item?.type !== "app" && item?.actions?.length > 0)
return item.actions.map(act => ({
type: "item",
icon: act.icon || "play_arrow",
text: act.name || "",
action: () => executeLauncherAction(act)
}));
const items = [];
if (item?.type === "app" && pinDockId)
items.push({
type: "item",
icon: isPinned ? "keep_off" : "push_pin",
text: isPinned ? I18n.tr("Unpin from Dock") : I18n.tr("Pin to Dock"),
action: togglePin
});
if (isRegularApp) {
items.push({
type: "item",
icon: "visibility_off",
text: I18n.tr("Hide App"),
action: hideCurrentApp
});
items.push({
type: "item",
icon: "edit",
text: I18n.tr("Edit App"),
action: editCurrentApp
});
}
if (item?.actions?.length > 0) {
items.push({
type: "separator"
});
for (const act of item.actions)
items.push({
type: "item",
icon: act.icon || "play_arrow",
text: act.name || "",
action: () => executeDesktopAction(act)
});
}
items.push({
type: "separator"
});
if (isRegularApp && SessionService.nvidiaCommand)
items.push({
type: "item",
icon: "memory",
text: I18n.tr("Launch on dGPU"),
action: launchWithNvidia
});
items.push({
type: "item",
icon: "launch",
text: I18n.tr("Launch", "verb, start an application"),
action: launchApp
});
if (isFlatpakApp && flatpakAppId)
items.push({
type: "separator"
}, {
type: "item",
icon: "delete",
text: I18n.tr("Uninstall", "context menu action to uninstall app") + "…",
isDestructive: true,
action: uninstallCurrentApp
});
return items;
}
onRenderActiveChanged: {
if (renderActive)
return;
if (parentHandler)
parentHandler.enabled = true;
if (searchField?.visible)
Qt.callLater(() => searchField.forceActiveFocus());
}
function hasContextMenuActions(spotlightItem) {
if (!spotlightItem)
return false;
if (spotlightItem.type === "app")
return true;
if (spotlightItem.type === "plugin" && spotlightItem.pluginId) {
const instance = PluginService.pluginInstances[spotlightItem.pluginId];
if (typeof instance?.getContextMenuActions !== "function")
return false;
const actions = instance.getContextMenuActions(spotlightItem.data);
return Array.isArray(actions) && actions.length > 0;
}
return spotlightItem.actions?.length > 0;
}
function getPluginContextMenuActions() {
if (!isPluginItem || !item?.pluginId)
return [];
const instance = PluginService.pluginInstances[item.pluginId];
if (typeof instance?.getContextMenuActions !== "function")
return [];
const actions = instance.getContextMenuActions(item.data);
return Array.isArray(actions) ? actions : [];
}
function show(x, y, spotlightItem, fromKeyboard) {
if (!spotlightItem?.data)
return;
item = spotlightItem;
const modal = parentHandler?.parentModal ?? null;
const screenRef = modal?.effectiveScreen ?? parentHandler?.Window?.window?.screen ?? searchField?.Window?.window?.screen ?? null;
const screenX = screenRef?.x || 0;
const screenY = screenRef?.y || 0;
const screenRelativeX = modal ? ((modal.alignedX ?? 0) + x) : ((parentHandler ? parentHandler.mapToGlobal(x, y).x : x) - screenX);
const screenRelativeY = modal ? ((modal.alignedY ?? 0) + y) : ((parentHandler ? parentHandler.mapToGlobal(x, y).y : y) - screenY);
pinDockId = SettingsData.dockConfigForAction(screenRef)?.id ?? "";
if (parentHandler)
parentHandler.enabled = false;
open(screenRef, screenRelativeX + Theme.spacingXS, screenRelativeY + Theme.spacingXS, fromKeyboard);
}
function executePluginAction(actionOrObj) {
const actionFunc = typeof actionOrObj === "function" ? actionOrObj : actionOrObj?.action;
const closeLauncher = typeof actionOrObj === "object" && actionOrObj?.closeLauncher;
if (typeof actionFunc === "function")
actionFunc();
if (closeLauncher)
controller?.itemExecuted();
else
controller?.performSearch();
hide();
}
function executeLauncherAction(actionData) {
if (!controller || !item || !actionData)
return;
controller.executeAction(item, actionData);
hide();
}
function togglePin() {
if (!appId || !SettingsData.getDockConfig(pinDockId))
return;
const pins = SessionData.getDockPins(pinDockId);
if (!isPinned)
SettingsData.ensureDockApps(pinDockId);
SessionData.setDockPins(pinDockId, isPinned ? pins.filter(id => id !== appId) : pins.concat([appId]));
hide();
}
function hideCurrentApp() {
if (!appId)
return;
SessionData.hideApp(appId);
controller?.performSearch();
hide();
}
function editCurrentApp() {
if (!desktopEntry)
return;
editAppRequested(desktopEntry);
hide();
}
function uninstallCurrentApp() {
if (!isFlatpakApp || !flatpakAppId)
return;
const targetFlatpakId = flatpakAppId;
const appName = item?.name || desktopEntry?.name || flatpakAppId;
const currentAppId = appId;
hide();
controller?.itemExecuted();
AppSearchService.requestUninstallFlatpak(currentAppId, appName, targetFlatpakId);
}
function launchApp() {
if (isCoreApp) {
if (!coreAppData)
return;
AppSearchService.executeCoreApp(coreAppData);
controller?.itemExecuted();
hide();
return;
}
if (!desktopEntry)
return;
SessionService.launchDesktopEntry(desktopEntry);
AppUsageHistoryData.addAppUsage(desktopEntry);
controller?.itemExecuted();
hide();
}
function launchWithNvidia() {
if (!desktopEntry)
return;
SessionService.launchDesktopEntry(desktopEntry, true);
AppUsageHistoryData.addAppUsage(desktopEntry);
controller?.itemExecuted();
hide();
}
function executeDesktopAction(actionData) {
if (!desktopEntry || !actionData)
return;
SessionService.launchDesktopAction(desktopEntry, actionData.actionData || actionData);
AppUsageHistoryData.addAppUsage(desktopEntry);
controller?.itemExecuted();
hide();
}
}