Context Menu Extension (zh)

知识库 - 编写上下文菜单扩展

上下文菜单

在大多应用软件程序中,在特定位置按下上下文菜单按键(通常是鼠标右键)即可触发对应语义的上下文菜单。 在深度文件管理器中,在文件浏览视图位置的不同情况下,如在文件上、在文件夹上、或者是在空白位置 按下上下文菜单键都会触发不同内容的上下文菜单。

通常情况,空白位置的上下文菜单会呈现创建文件或是对当前路径进行的其他常见操作,而在文件上触发上下文菜单 则会呈现可对文件进行的若干处理选项,如打开方式、剪切等内容。

尽管默认的呈现内容应当涵盖了大部分的使用场景,用户或应用程序可能依然希望呈现额外的上下文菜单以便辅助使用。 本文即覆盖了编写自己的上下文菜单扩展的须知内容。

深度文件管理器的上下文菜单扩展支持

深度文件管理器目前提供多种形式的上下文菜单扩展支持,为 desktop 格式的上下文菜单扩展支持、 json 格式的扩展支持和 C++ 插件形式的上下文菜单扩展插件。

在 v20 以上版本的文件管理器(版本号高于 5.0.0)中,我们提供了 desktop 格式形式的上下文菜单扩展支持和 C++ 插件形式的上下文菜单支持, 在 v15 版本中,文件管理器提供了 json 文件形式的扩展支持和 C++ 插件形式的上下文菜单支持,为了方便用户和开发者,我们还 提供了适用于 v15 版本文件管理器的 desktop 格式形式的扩展支持插件。请根据您的实际需求选择对应的方案,配置方法参见下方的详细描述。

需要注意的是,如果您希望为您的应用程序能够出现在 “打开方式” 的应用列表中,您应当考虑为您的应用程序编写适当的 .desktop 文件并指定对应的 MimeType 文件(请参见 desktop-entry-spec)。 如果您希望您的自定义文件类型能够出现在 “新建文档” 的列表中,您应当参阅 新建文件模板 。 对于上述的这两种需求情况,使用上下文菜单扩展都不是恰当的选择。

desktop 格式形式的上下文菜单扩展

适用版本:适用于 v20 版本(即版本 > 5.0.0 )的深度文件管理器,或安装了 desktop 格式形式的上下文菜单扩展插件(在 Deepin 中包名为 dde-file-manager-menu-oem)的 v15 版本文件管理器。

文件管理器会识别指定目录( `/usr/share/deepin/dde-file-manager/oem-menuextensions` )下的 `.desktop` 文件,并将其视为扩展菜单项,加入到文件管理器的上下文菜单中。 开发者或用户仅需按照正确的格式编写 desktop 文件并放置于对应目录即可使用。

每个有效的 desktop 格式形式的上下文菜单扩展均为一个独立的 Application 类型的 `.desktop` 文件。对于每个文件,在其 `[Desktop Entry]` 下至少需要包含 `Name` 和 `Exec` 字段, `Name` 的内容为添加到上下文菜单中时将会显示的名称,`Exec` 的内容为当单击此新增的菜单项时将会执行的行为(遵循 desktop 文件规范标准,可以使用 `%u` 等参数)。

定制菜单支持使用 `Actions` 字段增加指定的子菜单,子菜单需至少包含 `Name` 和 `Exec` 字段,可以通过 `Icon` 指定图标。 若指定子菜单,则入口项(原本 `[Desktop Entry]` 下)的 `Exec` 字段将不再有效。

对于文件管理器菜单项定制,支持额外的字段可供定制,可以使用 `X-DFM-MenuTypes` 字段来指定菜单项在何种情况会显示,此字段可包含一个或多个类型, 其中包括 `SingleFile`, `SingleDir`, `MultiFileDirs` 和 `EmptyArea` 四种。

对于此种类型的配置详细规则,请参阅:项目源码仓库中所附带的 PLUGIN-README.md

示例扩展

可以将下面的示例存储为 `test.desktop` 并放置到 `/usr/share/deepin/dde-file-manager/oem-menuextensions/` 中,关闭现有的所有文件管理器窗口并打开新的文件管理器窗口,定制的菜单将会出现在单独目录或多选文件的情况的上下文菜单中。

[Desktop Entry]
Type=Application
Exec=/home/wzc/Temp/test.sh %U
Icon=utilities-terminal
Name=示例菜单项名称
X-DFM-MenuTypes=SingleDir;MultiFileDirs;

Json 形式的上下文菜单扩展

适用版本:仅适用于 v15 版本,即版本 <= 5.0.0 的深度文件管理器。

注意:如果您计划在将来升级到 v20 版本的文件管理器,请考虑安装由我们提供的适用于 v15 版本的 desktop 格式形式的扩展支持插件,并使用 desktop 格式形式的扩展支持。

默认情况下文件管理器会在开启时试图加载 `~/.config/deepin/dde-file-manager/menuextensions/` 目录 (如需要编写此类扩展但发现此路径不存在时,手动创建完整路径即可)中的 json 文件作为上下文菜单扩展, 对于一个上下文菜单扩展,应当包含有如下的通用字段。

通用字段

支持扩展的右键菜单各个字段说明:

  • MenuType 菜单类型(必须指定)
    • SingleFile 选中单个文件
    • MultiFiles 选中多个文件
    • SingleDir 选中单个目录
    • MultiDirs 选中多个目录
    • MultiFileDirs 选中多个文件和目录
    • EmptyArea 空白区域
  • Icon 菜单项的指定图标(可选)
    • Icon: /home/djf/Music/usb_normal_16px.svg
  • Text[local] 根据不同的语言环境给出不同的菜单文本(必须指定)
    • Text[zh_CN]: 示例文本
    • Text[en]: Sample Text
    • ...
  • Exec 点击菜单项执行的命令(必须指定)
    • Exec: xterm 启动 XTerm 。注意此项只能跟一个名称,不能包含参数。
  • Args 执行命令的额外参数列表
    • "Args": ["."] 为执行 Exec 内容指定额外的一个参数(".")。
  • NotShowIn 在什么情况下不显示
    • "NotShowIn": ["Desktop"] 在桌面上不显示此菜单。
  • SubMenu 子菜单列表,子菜单列表不需要再次指定 MenuType 字段,其他字段参数一样,支持 SubMenu 中嵌套无限

如果 MenuType 为 SingleFile 或者 MultiFiles ,可以增加下面两个字段来细化菜单控制。

  • MimeType 文件的MimeType类型,如果指定了这个参数,表示只拓展这个类型的文件右键菜单;以;隔开
    • MimeType:text/plain;image/jpeg
  • Suffix 文件的后缀,如果指定了这个参数,表示只拓展后缀名为指定后缀的文件的右键菜单;以;隔开
    • Suffix: md;txt
  • 如果MimeType和Suffix两个参数同时指定,表示文件类型为MimeType且后缀名为Suffix的文件才支持扩展右键菜单

示例扩展

下面的示例为 在文件管理器的空白区域触发上下文菜单,增加 “在 VSCode 中打开” 选项 的示例。

[
    {
        "MenuType": "EmptyArea",
        "Icon": "Files",
        "Text[zh_CN]": "在 VSCode 中打开",
        "Text[en_US]": "Open with VSCode",
        "Exec": "code",
        "Args": ["."],
        "NotShowIn": ["Desktop"],
    }
]

下面为旧文档中所附带的示例。

[
    {
        "MenuType": "SingleFile",
        "Icon": "/home/djf/Music/usb_normal_16px.svg",
        "Text[zh_CN]": "文件SingleFile",
        "Text[zh_HK]": "文件SingleFile",
        "Text[zh_TW]": "文件SingleFile",
        "MimeType": "",
        "Suffix": "md;",
        "Exec": "",
        "SubMenu": [
             {
                "Icon": "111111111",
                "Text[zh_CN]": "sub文件SingleFile",
                "Text[zh_HK]": "sub文件SingleFile",
                "Text[zh_TW]": "sub文件SingleFile",
                "Exec": "dde-file-manager",
                "SubMenu": [
                    {
                        "Icon": "dssd",
                        "Text[zh_CN]": "sub文件SingleFile",
                        "Text[zh_HK]": "sub文件SingleFile",
                        "Text[zh_TW]": "sub文件SingleFile",
                        "Exec": "dde-file-manager"
                    },
                    {
                        "Icon": "dssd",
                        "Text[zh_CN]": "sub文件SingleFile",
                        "Text[zh_HK]": "sub文件SingleFile",
                        "Text[zh_TW]": "sub文件SingleFile",
                        "Exec": "dde-file-manager"
                    }
                ]
             },
             {
                "Icon": "2222222",
                "Text[zh_CN]": "sub文件SingleFile",
                "Text[zh_HK]": "sub文件SingleFile",
                "Text[zh_TW]": "sub文件SingleFile",
                "Exec": "dde-file-manager"
             }
        ]
    },
    {
        "MenuType": "SingleFile",
        "Icon": "Files",
        "Text[zh_CN]": "文件SingleFile2",
        "Text[zh_HK]": "文件SingleFile2",
        "Text[zh_TW]": "文件SingleFile2",
        "MimeType": "",
        "Exec": "dde-file-manager"
    },
    {
        "MenuType": "MultiFiles",
        "Icon": "Files",
        "Text[zh_CN]": "文件MultiFiles",
        "Text[zh_HK]": "文件MultiFiles",
        "Text[zh_TW]": "文件MultiFiles",
        "MimeType": "text/plain;image/jpeg",
        "Exec": "dde-file-manager"
    },
    {
        "MenuType": "MultiFiles",
        "Icon": "Files",
        "Text[zh_CN]": "文件MultiFiles2",
        "Text[zh_HK]": "文件MultiFiles2",
        "Text[zh_TW]": "文件MultiFiles2",
        "MimeType": "",
        "Exec": "dde-file-manager"
    },
    {
        "MenuType": "SingleDir",
        "Icon": "Files",
        "Text[zh_CN]": "文件SingleDir",
        "Text[zh_HK]": "文件SingleDir",
        "Text[zh_TW]": "文件SingleDir",
        "Exec": "dde-file-manager"
    },
    {
        "MenuType": "MultiDirs",
        "Icon": "Files",
        "Text[zh_CN]": "文件MultiDir",
        "Text[zh_HK]": "文件MultiDir",
        "Text[zh_TW]": "文件MultiDir",
        "Exec": "dde-file-manager"
    },
    {
        "MenuType": "MultiFileDirs",
        "Icon": "Files",
        "Text[zh_CN]": "文件MultiFileDirs",
        "Text[zh_HK]": "文件MultiFileDirs",
        "Text[zh_TW]": "文件MultiFileDirs",
        "Exec": "dde-file-manager"
    },
    {
        "MenuType": "EmptyArea",
        "Icon": "Files",
        "Text[zh_CN]": "EmptyArea",
        "Text[zh_HK]": "EmptyArea",
        "Text[zh_TW]": "EmptyArea",
        "Exec": "dde-file-manager"
    }
]

遵守 Qt 插件规范的 C++ 上下文菜单插件

注意:接口可能在将来废弃或调整,尽管适用于 v15 和 v20 版本,但仍不推荐使用。

文件管理器支持加载 Qt 规范的 C++ 插件,实现需继承 MenuInterface ,遵守 Qt 的插件规范实现你的菜单插件接口。

插件头文件

在安装好 libdde-file-manager-dev (文件管理器开发包)后即可得到对应的插件头文件 menuinterface.h ,使用时需在对应的代码中包含此文件。

#include "dde-file-manager-plugins/menuinterface.h"

接口说明

  • virtual QList<QAction*> additionalMenu(const QStringList &files, const QString& currentDir) 实现这个接口可以扩展选中文件的右键菜单
    • const QStringList &files 表示选中的文件的完整路径列表
    • const QString& currentDir 表示选中的文件所在的目录
    • QList<QAction*> 返回一组QAction指针列表
  • virtual QList<QAction*> additionalEmptyMenu(const QString &currentDir, bool onDesktop = false) 实现这个接口可以扩展空白处的右键菜单
    • const QString& currentDir 表示空白处所在的文件目录
    • const QString& currentDir 表示空白处所在的文件目录
    • QList<QAction*> 返回一组QAction指针列表

插件安装目录

在 Deepin 上,安装位置为 `/usr/lib/<target_arch>/dde-file-manager/plugins/menu/` ,其中 <target_arch> 表示对应架构名,可以通过 `gcc -dumpmachine` 得到。下表供参考:

  • x86 架构
    • /usr/lib/x86_64-linux-gnu/dde-file-manager/plugins/menu/ 64位
    • /usr/lib/x86_32-linux-gnu/dde-file-manager/plugins/menu/ 32位
  • 龙芯架构
    • /usr/lib/mipsel-linux-gnu/dde-file-manager/plugins/menu/
  • 神威架构
    • /usr/lib/sw_64-linux-gnu/dde-file-manager/plugins/menu/

源码

对于接口头文件的源码,可以直接参阅开发包所附带的头文件。以下为可供参考的简单右键菜单扩展插件实例源码。

context-menu-ext/content-menu-ext.pro:

# Still need the widgets module since MenuInterface need it.
QT       += widgets

CONFIG   += link_pkgconfig
PKGCONFIG += dde-file-manager

TARGET = dde-file-manager-mounter-plugin
TEMPLATE = lib

DEFINES += DFMMOUNTERPLUGIN_LIBRARY

# The following define makes your compiler emit warnings if you use
# any feature of Qt which has been marked as deprecated.
DEFINES += QT_DEPRECATED_WARNINGS

SOURCES += \
        dfmctxmenuplugin.cpp

HEADERS += \
        dfmctxmenuplugin.h

unix {
    target.path = $$[QT_INSTALL_LIBS]/dde-file-manager/plugins/menu/
    INSTALLS += target
}

context-menu-ext/dfmctxmenuplugin.h:

#ifndef DFMCTXMENUPLUGIN_H
#define DFMCTXMENUPLUGIN_H

#include "dde-file-manager-plugins/menuinterface.h"

class DFMCtxMenuPlugin : public MenuInterface
{
    Q_OBJECT
    Q_INTERFACES(MenuInterface)
    Q_PLUGIN_METADATA(IID MenuInterface_iid)
public:
    DFMCtxMenuPlugin();

    QList<QAction*> additionalMenu(const QStringList &files, const QString& currentDir) override;
};

#endif // DFMCTXMENUPLUGIN_H

context-menu-ext/dfmctxmenuplugin.cpp:

#include "dfmctxmenuplugin.h"

DFMCtxMenuPlugin::DFMCtxMenuPlugin()
{
}

QList<QAction *> DFMCtxMenuPlugin::additionalMenu(const QStringList &files, const QString &currentDir)
{
    QList<QAction *> actionPtrList;
    actionPtrList.append(new QAction("Sample Text"));
    return actionPtrList;
}

参考链接