How to add a menuitem in Nautilus context menu.

博客介绍了在文件管理器中添加命令和菜单项的操作,包括在nautilus - directory - view - ui.xml中添加命令和菜单项,在fm - directory - view.c的函数里添加相关项,还说明了如何在回调函数中启动对应程序,以及获取实际文件名的方法。
部署运行你感兴趣的模型镜像

1. In src/file-manager/ directory, add command section and menuitem section in nautilus-directory-view-ui.xml.

<commands>
    ...
    <cmd name=”Name Convert”
        _label=”Name _Convert”
        _tip=”Convert the file name”/>
    ...
</commands>

<popup name=“selection“ tearoff=“0“>
    ....
    <placeholder name=“File Actions“ delimit=“top“>
        ...
       <menuitem name=”Name Convert” verb=”Name Convert”/>
        ...
    </placeholder>
    ...
</popup> 

2. In fm-directory-view.c:

    #define FM_DIRECTORY_VIEW_COMMAND_NAME_CONVERT    “/commands/Name Convert“

    In real_merge_menus () function, BonoboUIVerb verbs [] array, add the following item:
    BONOBO_UI_VERB (“Name Convert“, name_convert_callback),

    You could use nautilus_bonobo_set_sensitive () or nautilus_bonobo_hidden () to show or hide this menuitem.

3. How to launch the corresponding program in callback function:

    GnomeVFSMimeApplication *test;
    
    test = g_new0 (GnomeVFSMimeApplication, 1);
    test->id = g_strdup (“test“);
    test->name = g_strdup (“this is a test“);
    test->command = g_strdup (“test“);
    test->expects_uris = GNOME_VFS_MIME_APPLICATION_ARGUMENT_TYPE_PATHS;
    
    file = NAUTILUS_FILE (selection->data);
    nautilus_launch_application (test, file, NULL);

    g_free (test->id);
    g_free (test->name);
    g_free (test->name);
    g_free (test);

    You could use gnome_vfs-get_local_path_from_uri (nautilus_file_get_uri (file)) to get the actuall file name.

    

您可能感兴趣的与本文相关的镜像

Dify

Dify

AI应用
Agent编排

Dify 是一款开源的大语言模型(LLM)应用开发平台,它结合了 后端即服务(Backend as a Service) 和LLMOps 的理念,让开发者能快速、高效地构建和部署生产级的生成式AI应用。 它提供了包含模型兼容支持、Prompt 编排界面、RAG 引擎、Agent 框架、工作流编排等核心技术栈,并且提供了易用的界面和API,让技术和非技术人员都能参与到AI应用的开发过程中

package com.oplus.engineermode.aftersale; import android.os.Bundle; import android.view.KeyEvent; import android.view.Menu; import android.view.MenuItem; import androidx.annotation.Nullable; import com.oplus.engineermode.R; import com.oplus.engineermode.entrance.EngineerFragmentContainer; public class DeviceCalibrationContainer extends EngineerFragmentContainer { private static final int MENU_ITEM_SAVE = Menu.FIRST; private static final int MENU_ITEM_CANCEL = Menu.FIRST + 1; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); } @Override public boolean onCreateOptionsMenu(Menu menu) { if (getFragmentContent().contains("DeviceCalibrationActivity")) { menu.add(0, 1, Menu.NONE, "Batch Test Mode"); menu.add(0, 2, Menu.NONE, "Reset All"); return true; } else if (getFragmentContent().contains("AdvancedSettings")) { menu.add(0, MENU_ITEM_SAVE, 0, R.string.wifi_ip_settings_menu_save).setIcon(android.R.drawable.ic_menu_save); menu.add(0, MENU_ITEM_CANCEL, 0, R.string.wifi_ip_settings_menu_cancel).setIcon(android.R.drawable.ic_menu_close_clear_cancel); } return super.onCreateOptionsMenu(menu); } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { return super.onKeyDown(keyCode, event); } @Override public boolean onOptionsItemSelected(MenuItem menuItem) { if (getFragmentContent().contains("DeviceCalibrationActivity")) { return ((DeviceCalibrationActivity) getFragment()).onOptionsItemSelected(menuItem); } return super.onOptionsItemSelected(menuItem); } }
最新发布
10-23
你提供的代码是一个 Android 工程师模式(Engineer Mode)中用于设备校准功能的容器 Activity —— `DeviceCalibrationContainer`,它继承自 `EngineerFragmentContainer`。这个类主要用于承载与设备校准相关的 Fragment,并根据当前显示的内容动态地添加菜单项,处理用户操作。 下面我将 **逐段分析代码**,解释其作用,并指出可能的优化或潜在问题。 --- ### ✅ 完整代码解析 ```java package com.oplus.engineermode.aftersale; import android.os.Bundle; import android.view.KeyEvent; import android.view.Menu; import android.view.MenuItem; import androidx.annotation.Nullable; import com.oplus.engineermode.R; import com.oplus.engineermode.entrance.EngineerFragmentContainer; public class DeviceCalibrationContainer extends EngineerFragmentContainer { // 菜单项 ID 常量定义 private static final int MENU_ITEM_SAVE = Menu.FIRST; private static final int MENU_ITEM_CANCEL = Menu.FIRST + 1; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); // 当前未设置布局或其他初始化操作,依赖父类实现 } @Override public boolean onCreateOptionsMenu(Menu menu) { // 根据 Fragment 内容动态添加菜单项 if (getFragmentContent().contains("DeviceCalibrationActivity")) { menu.add(0, 1, Menu.NONE, "Batch Test Mode"); menu.add(0, 2, Menu.NONE, "Reset All"); return true; } else if (getFragmentContent().contains("AdvancedSettings")) { menu.add(0, MENU_ITEM_SAVE, 0, R.string.wifi_ip_settings_menu_save) .setIcon(android.R.drawable.ic_menu_save); menu.add(0, MENU_ITEM_CANCEL, 0, R.string.wifi_ip_settings_menu_cancel) .setIcon(android.R.drawable.ic_menu_close_clear_cancel); } return super.onCreateOptionsMenu(menu); } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { return super.onKeyDown(keyCode, event); } @Override public boolean onOptionsItemSelected(MenuItem menuItem) { if (getFragmentContent().contains("DeviceCalibrationActivity")) { return ((DeviceCalibrationActivity) getFragment()).onOptionsItemSelected(menuItem); } return super.onOptionsItemSelected(menuItem); } } ``` --- ### 🔍 分析与解释 #### 1. 类结构和继承关系 ```java public class DeviceCalibrationContainer extends EngineerFragmentContainer ``` - 这个 Activity 继承自 `EngineerFragmentContainer`,说明它是 Oplus 工程师模式中的一个通用 Fragment 容器。 - 通常这种设计是为了复用 Fragment 管理逻辑(如加载、切换、回退栈等),并集中处理 UI 控制。 #### 2. 菜单项常量定义 ```java private static final int MENU_ITEM_SAVE = Menu.FIRST; private static final int MENU_ITEM_CANCEL = Menu.FIRST + 1; ``` - 使用 `Menu.FIRST` 是一种传统方式来避免菜单 ID 冲突。 - `Menu.FIRST` 的值通常是 `1`,所以: - `MENU_ITEM_SAVE = 1` - `MENU_ITEM_CANCEL = 2` > ⚠️ 注意:硬编码菜单 ID 可能导致冲突,建议使用资源 ID 或枚举替代。 #### 3. `onCreate()` ```java @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); } ``` - 没有调用 `setContentView()`,说明界面由父类 `EngineerFragmentContainer` 处理。 - 推测父类已经设置了默认布局(比如一个 `FrameLayout` 作为 fragment 容器)。 #### 4. `onCreateOptionsMenu(Menu menu)` 这是重点部分: ##### 功能逻辑: - 判断当前 Fragment 的内容是否包含 `"DeviceCalibrationActivity"` 或 `"AdvancedSettings"` 字符串。 - 若是设备校准页,则添加两个文本菜单项:“Batch Test Mode” 和 “Reset All”。 - 若是高级设置页,则添加带图标的“保存”和“取消”按钮。 ##### 存在的问题: - ❌ 使用 `String.contains()` 来判断当前 Fragment 类型非常脆弱! - 如果类名变更、拼写错误、或存在相似名称(如 `AdvancedSettingsFragment` vs `AdvancedSettingsActivity`),就会出错。 - 更安全的方式是使用 `instanceof` 或通过接口/标记判断。 ✅ **推荐改法示例**: ```java Fragment fragment = getFragment(); if (fragment instanceof DeviceCalibrationActivity) { ... } else if (fragment instanceof AdvancedSettingsFragment) { ... } ``` ##### 图标使用: - `.setIcon(android.R.drawable.ic_menu_save)` 使用系统图标,兼容性好但样式较旧(Holo 风格)。 - 现代应用更推荐使用 Material Design 图标(通过 `androidx.appcompat:appcompat` 或 `MaterialComponents` 主题支持矢量图标)。 #### 5. `onKeyDown(...)` ```java @Override public boolean onKeyDown(int keyCode, KeyEvent event) { return super.onKeyDown(keyCode, event); } ``` - 当前只是透传事件给父类。 - 可在此处拦截特定按键(例如音量键触发调试),但现在没有扩展逻辑。 #### 6. `onOptionsItemSelected(...)` ```java if (getFragmentContent().contains("DeviceCalibrationActivity")) { return ((DeviceCalibrationActivity) getFragment()).onOptionsItemSelected(menuItem); } return super.onOptionsItemSelected(menuItem); ``` - 将菜单点击事件转发给内部的 `DeviceCalibrationActivity` Fragment。 - ❌ 强转风险高!如果 `getFragment()` 返回的不是该类型,会抛出 `ClassCastException`。 - ✅ 应先判断类型再转换。 ✅ 改进建议: ```java Fragment fragment = getFragment(); if (fragment instanceof DeviceCalibrationActivity) { return ((DeviceCalibrationActivity) fragment).onOptionsItemSelected(menuItem); } return super.onOptionsItemSelected(menuItem); ``` --- ### 🛠️ 改进建议总结 | 问题 | 建议 | |------|------| | 使用 `String.contains()` 判断 Fragment 类型 | 改为 `instanceof` 判断 | | 硬编码菜单 ID (`1`, `2`) | 使用常量或资源 ID | | 直接强转 Fragment | 加 `instanceof` 判断防止崩溃 | | 使用过时的系统图标 | 替换为 VectorDrawable 图标 | | 无 `onDestroy` / 生命周期管理 | 视需求补充资源释放 | --- ### ✅ 示例改进后的代码(优化版) ```java @Override public boolean onCreateOptionsMenu(Menu menu) { Fragment fragment = getFragment(); if (fragment instanceof DeviceCalibrationActivity) { menu.add(0, R.id.menu_batch_test, Menu.NONE, "Batch Test Mode"); menu.add(0, R.id.menu_reset_all, Menu.NONE, "Reset All"); return true; } else if (fragment instanceof AdvancedSettingsFragment) { menu.add(0, MENU_ITEM_SAVE, 0, R.string.wifi_ip_settings_menu_save) .setIcon(R.drawable.ic_save) // 自定义 vector drawable .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); menu.add(0, MENU_ITEM_CANCEL, 0, R.string.wifi_ip_settings_menu_cancel) .setIcon(R.drawable.ic_cancel) .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); return true; } return super.onCreateOptionsMenu(menu); } @Override public boolean onOptionsItemSelected(MenuItem menuItem) { Fragment fragment = getFragment(); if (fragment instanceof DeviceCalibrationActivity) { return ((DeviceCalibrationActivity) fragment).onOptionsItemSelected(menuItem); } return super.onOptionsItemSelected(menuItem); } ``` 同时,在 `res/values/ids.xml` 中定义: ```xml <resources> <item name="menu_batch_test" type="id" /> <item name="menu_reset_all" type="id" /> </resources> ``` --- ###
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值