插件开发遇到的问题
如下图所示,在一个编辑器中,配置右键菜单,提供了icons/cut.png图标。 由于剪切操作为通用的操作,每一个编辑器都需要支持剪切操作,通过点击Browse…按钮,却只能选择本插件内的图片资源。如果每一个编辑器都需要支持这些通用操作,难道每一个插件项目中都必须有一套cut.png吗?
本篇文章就是为了解决这个问题。
问题的研究
在Eclipse中,平台本身对于图片资源有很多处理机制。对于跨插件方式,可以通过org.eclipse.ui.ISharedImages共享图片,这些图片创建后可以直到程序关闭才释放,一般用于通用的部分。在这个接口中,定义的一些图标,例如IMG_TOOL_CUT。这些图标,已经在类WorkbenchImages中,将这些图标声明。所以上图中,icon位置可以配置IMG_TOOL_CUT,在对应右键菜单处采用Eclipse平台的剪切图标。
除了Eclipse平台图标以外,我们可以自己定制吗?
于是尝试,通过在插件启动的时候,调用WorkbenchImages的public static void declareImage(String symbolicName,ImageDescriptor descriptor, boolean shared)方法,传入自定义字符串,例如_CUT,以及图标descriptor,在加载后,平台报出无法找到/_CUT图片路径。
所以这里就涉及到,扩展点之中配置的资源路径,是通过什么方式查找的?
该处扩展点中,图片资源的查找是通过AbstractUIPlugin类的public static ImageDescriptor imageDescriptorFromPlugin(String pluginId, String imageFilePath)方法查找的。当调用的时候,pluginId就是扩展点所处的插件的ID,
通过源码,可以看到图片加载顺序,首先是平台共享的图片资源,但是我们在对应的插件激活后调用declareImage,在图片查找之后,所以无法找到。
文件是通过FileLocator.find(url)查找,最后定位到图标。 所以,我们需要知道Eclipse平台的URL机制,该机制是在Eclipse平台启动后,内置的分析机制。
Eclipse平台的URL机制
转载自:https://blog.csdn.net/zhoujianboy/article/details/84129480
除常见的Http、FTP、FILE等协议之外,eclipse平台还支持多种扩展协议,甚至可以支持用户自定义协议。
Eclipse平台支持的协议,包括Plugin、Fragment、Meta、Config等,会在Eclipse runtime启动时候注册,可参见:
- org.eclipse.core.internal.runtime.Activator
- org.eclipse.core.internal.boot.PlatformURLHandler
- PlatformURLConnection
- URLConnection
从上述3)的继承实现上,可以看到,Eclipse对platform协议url的定位的支持情况如下:
platform:base/xxx, 相对于rcp根目录下的资源
platform:config/xxx, 相对于rcp的configuration目录下的资源
platform:fragment/foo.bar/xxx, 相对于foo.bar这个fragment下的资源
platform:meta/foo.bar/xxx, 相对于workspace/.metadata/.plugins/foo.bar目录下的资源
platform:plugin/foo.bar/xxx, 相对于foo.bar这个plugin下的资源
platform:resource/foo/xxx, 相对于workspace里foo工程下的资源, foo工程有可能在workspace目录之外.
也可以通过继承PlatformURLConnection类,定义自己的基于Platform的URL。
从根本上来说,这种便利性是由Java URLConnection 乃至关于URL的标准的可扩展性带来的,Eclipse平台只是有效地利用了这种可扩展性。类似的情况还有OSGI的Bundle协议和Java的Jar协议等。
在实际的插件开发中,常用以下方法给文件定位
1 在插件内定位:
Bundle bundle = MapEditorPlugin.getDefault().getBundle();
URL url = bundle.getEntry(“temp/xxx”);
这种方式表示 xxx 这个文件在本插件的temp目录下
2 在RCP的配置路径下:
URL url = new URL(“platform:config/xxx”);
Properties prop = new Properties() ;
prop.load(url.openStream());
这种方式表示xxx这个文件在你的rcp的工作目录下的configuration目录下
另外,应该善加利用Platform里的方法,如调用Platform.getConfigurationLocation()也可获得配置目录的Location,通过location可以getURL()。
以下变量也可用作提供的URL路径中的段:
• n l nl nl-用于语言特定信息
• o s os os-用于操作系统特定信息
• w s ws ws-用于打开系统特定信息的窗口
例如,默认语言环境为en_CA的环境中的“platform:/plugin/org.eclipse.core.runtime/ n l nl nl/about.properties”的URL将返回与第一个位置about.properties对应的URL,其顺序如下:
plugin root/nl/en/CA/about.properties
fragment1 root/nl/en/CA/about.properties
fragment2 root/nl/en/CA/about.properties
…
plugin root/nl/en/about.properties
fragment1 root/nl/en/about.properties
fragment2 root/nl/en/about.properties
…
plugin root/about.properties
fragment1 root/about.properties
fragment2 root/about.properties
…
问题的解决
所以,上图中碰到的问题,可以通过下面方式解决。在icon中配置:
platform:plugin/图标所在其他插件ID/图标在其他插件中的位置
如果是在插件内的图标,则前面的” platform:plugin/图标所在其他插件ID/”可以省略掉。
测试后,问题解决了,右键菜单中对应项图标确实为配置的目标图片。
更多的思考
通过这种问题的解决,我们可以考虑到对于某一款基于Eclipse插件开发的程序,可以定义一个公共的资源插件。例如XXX.XXX.resource.ui项目。该项目中放置某一个整体模块或者整个软件系统的公共图标。其他插件扩展点中,可以采用上述配置方式。
当新扩展某一个子功能模块时,子功能可以引用核心系统的图片等资源,同时子功能模块维护自身特殊的图标。当某个插件未加载时,提供某个默认图标替代。而且URL字符串不会造成对某个插件的依赖。通过这种方式,既保证了资源文件的统一管理,也不会耦合。
如果在程序中,可以先通过org.eclipse.core.runtime.FileLocator.find(new java.net.URL(urlString)); 其中urlString可以采用”问题的解决”中的字符串。然后,通过ImageDescriptor.createFromURL(url)获取图标描述(其他资源获取方式也可以通过URL构建),进而获取图标。