《EclipseSWT/JFACE核心应用》清华大学出版社 23 RCP开发
23.3 扩展编辑器
编辑器与视图一样,是工作台页面内的可视组件。通常用来编辑文件(例如查源代码)或查看输入对象(例如打开的plugin.xml文件时的页面)。用于创建视图的扩展点为org.eclipse.ui.editors。
1. 编辑器扩展点
在扩展编辑器中新增扩展点,配置好的plugin.xml文件如下:
<extension
point="org.eclipse.ui.editors">
<editor
class="com.testrcp.myrcp.editors.JsEditor"
contributorClass="com.testrcp.myrcp.editors.JsEditorContributor"
default="false"
icon="icons/alt_about.gif"
id="com.testrcp.myrcp.editors.JsEditor"
name="JsEditor">
</editor>
</extension>
编辑器扩展点的各元素的说明如下:
◇ 编辑器的扩展点类型是 org.eclipse.ui.editors 。
◇ 与视图一样,一个编辑器对应一个 class 类,该类必须是实现了 org.eclipse.ui.IEditorPart 的类。
◇ id 是该编辑器对象的唯一标识, name 为编辑器显示的名称。
◇ default :表示是否使用默认的编辑器。
◇ contributorClass 是实现了 org.eclipse.ui.IEditorActionBarContributor 接口的类, Eclipse 中 EditorActionBarContributor 类已经实现了该接口,通常的做法是继承该类,然后覆盖父类中的方法实现的。
◇ 其他需要注意的元素如下:
⊙ extensions :打开该编辑器的所对应的文件的扩展名,例如 “htm , html” 。
⊙ command 和 launcher : command 为要运行以启动外部编辑器的命令。 launcher 为实现了 org.eclipse.ui.IEditorLauncher 的类。这样启动程序将打开外部编辑器。其中 class 、 command 和 launcher 都是打开编辑器的方式,属性是互斥的。
⊙ filenames :编辑器打开文件时可选的文件名。
⊙ symbolicFontName :编辑器字体的名称。
⊙ matchingStrategy :实现 org.eclipse.ui.IEditorMatchingStrategy 的类。这运行编辑器扩展提供一个策略,是编辑器的输入与指定的编辑器输入相匹配。
一般开发编辑器时通常会用到这些属性,但在RCP开发中,如果不是开发的RCP编辑器程序,一般是用不到这些属性的。
2. 编辑器类
本例中的编辑器类是JsEditor,代码如下:
package com.testrcp.myrcp.editors;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IEditorSite;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.part.EditorPart;
public class JsEditor extends EditorPart {
//对应plugin.xml指定的id
public static final String ID = "com.testrcp.myrcp.editors.JsEditor";
private Text text;
//编辑器中的内容是否被修改的标志
private boolean bDirty = false;
public JsEditor() {
super();
}
//初始化编辑器
public void init(IEditorSite site, IEditorInput input)
throws PartInitException {
this.setSite(site);//设置site
this.setInput(input);//设置输入的IEditorInput对象
this.setPartName(input.getName());//设置编辑器上方显示的名称
}
//创建编辑器中的控件
public void createPartControl(Composite parent) {
text = new Text(parent, SWT.NONE);
//当文本框修改时,设定内容被修改过
text.addModifyListener(new ModifyListener() {
public void modifyText(ModifyEvent e) {
if (!isDirty()) {//如果未修改
setDirty(true);//设置修改
//更改编辑器的状态
firePropertyChange(IEditorPart.PROP_DIRTY);
}
}
});
}
//编辑器关闭时,保存编辑器内容时所调用的方法
public void doSave(IProgressMonitor monitor) {
//将保存状态显示在状态栏中
try {
monitor.beginTask("保存文件...", 100);
for (int i = 0; i < 10 &&!monitor.isCanceled(); i++) {
Thread.sleep(500);
monitor.worked(10);
double d = (i + 1) / 10d;
monitor.subTask("已完成" + d * 100 +"%");// 显示任务状态
}
monitor.done();
if (monitor.isCanceled())
throw new InterruptedException("取消保存");
} catch (InterruptedException e) {
;
}
}
//另存为调用的方法
public void doSaveAs() {
}
//判断是否被修改过
public boolean isDirty() {
return bDirty;
}
//是否允许保存
public boolean isSaveAsAllowed() {
return true;
}
//设置焦点
public void setFocus() {
text.setFocus();
}
//设置编辑器内容被修改过
public void setDirty(boolean b) {
bDirty = b;
}
}
创建编辑器时应注意以下问题:
◇ 编辑器所对应的类为实现了 IEditorPart 接口的类。本例中使用的是继承了 EditorPart 类,例如下文中讲述的多页编辑器则要继承自 MultiPageEditorPart 类,表单编辑器则要继承 FormEditor 类。
◇ 编辑器中显示的控件通过 createPartControl 方法创建。
◇ isDirty() :编辑器内容是否被修改过,如果被修改过,标签上会显示一个 “*” 号。当状态改变时要及时的更新界面效果,使用下面的方法:
firePropertyChange(IEditorPart.PROP_DIRTY);
⊙ isSaveAsAllowed() :是否允许全部保存。
⊙ doSaveAs() :另存时调用的方法。
⊙ doSave() :保存时调用的方法。
⊙ setFocus() :设置编辑器激活时焦点所在的控件。
3. 打开编辑器
与视图不同,编辑器不能直接显示到透视图的某一个区域,而是由一项操作所打开的,通常使用 IWorkbenchPage 的以下两个方法:
◇ openEditor(IEditorInput input, String editorId) : input 对象为打开文件器时所指定输入到编辑器的内容,为了实现 IEditorInput 接口, editorId 为编辑器的唯一标识。
◇ openEditor(IEditorId input, String editorId, boolean activate) : activate 表示是否打开后并激活该编辑器。
本例中所创建的实现了接口的类为 JsEditorInput 类,代码如下:
package com.testrcp.myrcp.editors;
import myrcp.Activator;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IPersistableElement;
public class JsEditorInput implements IEditorInput {
//输入的字符
private String input ;
public JsEditorInput ( String input ){
this.input = input ;
}
//是否将编辑器保存在最近访问记录中
public boolean exists() {
return true;
}
//输入内容的图标
public ImageDescriptor getImageDescriptor() {
returnActivator.getImageDescriptor("icons/samples.gif");
}
//输入信息的名称
public String getName() {
return input;
}
//是否可以持久化该编辑器
public IPersistableElement getPersistable() {
return null;
}
//设置编辑器标签中显示提示信息
public String getToolTipText() {
return input;
}
//返回与该输入相关的类的对象
public Object getAdapter(Class adapter) {
return null;
}
}
这些方法都是 IEditorInput 接口中的方法。另外除了可以自己实现该接口的类外, Eclipse 中已经有一些实现了该接口的类,可以直接使用或者通过继承的方法。实现 IEditorInput 接口的类如下:
CommonSourceNotFoundEditorInput, CompareEditorInput,FileEditorInput, FileInPlaceEditorInput, FileStoreEditorInput,HistoryPageCompareEditorInput, MultiEditorInput, PageCompareEditorInput, ParticipantPageCompareEditorInput,SaveableCompareEditorInput, SyncInfoCompareInput
创建了打开编辑器输入内容的类,也有了对应的编辑器,就可以打开编辑器了。要想打开编辑器,还需要创建一个视图,视图中放置了一个列表List,然后单击列表中的一项来打开编辑器。plugin.xml中的配置代码如下:
<view
class="com.testrcp.myrcp.views.OpenEditorView"
icon="icons/alt_launcher.ico"
id="com.testrcp.myrcp.views.OpenEditorView"
name="打开编辑器">
</view>
后面的代码需要在项目中增加一个 jar 包: org.eclipse.ui.forms_3.5.0.v20100427.jar ,在 Eclipse 的安装目录下的 plugins 目录中可以找到。
对应的视图类如下:
package com.testrcp.myrcp.views;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.List;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.internal.part.NullEditorInput;
import org.eclipse.ui.part.ViewPart;
import com.testrcp.myrcp.editors.JsEditor;
import com.testrcp.myrcp.editors.JsEditorInput;
import com.testrcp.myrcp.editors.MutiEditorSample;
import com.testrcp.myrcp.forms.MyMutiForm;
public class OpenEditorView extends ViewPart {
public static final String ID ="com.testrcp.myrcp.views.OpenEditorView";
public List list;
public OpenEditorView() {
super();
}
public void createPartControl(Composite parent) {
list = new List(parent, SWT.NONE);
list.add("Editor");
list.add("MutiPage Editor");
list.add("Form Editor");
list.add("Master/Detail Page");
list.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
String select = list.getSelection()[0];
// 获得当前激活的IWorkbenchPage对象
IWorkbenchPage page =getViewSite().getWorkbenchWindow().getActivePage();
try {
if (select.equals("Editor")) {// 如果选中的"Editor"一项
// 创建输入的内容对象
JsEditorInput editor = newJsEditorInput(select);
// 打开该编辑器
page.openEditor(editor, JsEditor.ID);
} else if(select.equals("MutiPage Editor")) {// 如果选中的"Editor"一项
page.openEditor(new NullEditorInput(),MutiEditorSample.ID);
}else if(select.equals("Form Editor")) {// 如果选中的"Editor"一项
page.openEditor(newNullEditorInput(), MyMutiForm.ID);
}
} catch (PartInitException ee) {
ee.printStackTrace();
}
}
});
}
public void setFocus() {
list.setFocus();
}
}
4. 添加编辑器的菜单和工具栏
对于编辑器,也可以设置编辑器所对应的菜单、工具栏和上下文菜单。实现这些功能需要实现 IEditorActionBarContributor 接口, EditorActionBarContributor 类实现了该接口。代码如下:
package com.testrcp.myrcp.editors;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.ui.ISharedImages;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.part.EditorActionBarContributor;
public class JsEditorContributor extendsEditorActionBarContributor {
private Action action1 ;
private Action action2 ;
public JsEditorContributor() {
super();
makeActions();
}
public void makeActions() {
action1 = new Action() {
public void run() {
}
};
action1.setText("Action 1");
action1.setToolTipText("Action 1 tooltip");
action1.setImageDescriptor(PlatformUI.getWorkbench().getSharedImages().
getImageDescriptor(ISharedImages.IMG_DEF_VIEW));
action2 = new Action() {
public void run() {
}
};
action2.setText("Action 2");
action2.setToolTipText("Action 2 tooltip");
action2.setImageDescriptor(PlatformUI.getWorkbench().getSharedImages().
getImageDescriptor(ISharedImages.IMG_OBJS_WARN_TSK));
}
//覆盖父类中的方法,创建菜单
public void contributeToMenu(IMenuManager menuManager) {
MenuManager editMenu = new MenuManager("编辑器菜单");
editMenu.add( action1 );
editMenu.add( action2 );
menuManager.add( editMenu );
}
//覆盖父类的方法,创建工具栏
public void contributeToToolBar(IToolBarManager toolBarManager) {
toolBarManager.add( action1 );
toolBarManager.add( action2 );
}
}
其中,创建菜单栏和工具栏的方法分别是覆盖父类中的 contributeToMenu 和 contributeToToolBar 方法。
在Perspective类的createInitialLayout方法中只留下下面两行代码:
String editorArea = layout.getEditorArea();
layout.addStandaloneView(OpenEditorView.ID,true,IPageLayout.RIGHT,.3f,editorArea);
运行后的显示效果如下:
点击“Editor”行,显示效果如下:
多点击几次Editor,出现多个Editor,如下图:
菜单如下图:
点击除“Editor”外的项时,菜单效果如下图:
5. 多页编辑器
多页编辑器可以同时打开多个页面,每个页面可以是一个编辑器IEditorPart,也可以是普通控件Control。
在plugin.xml配置一个新的编辑器。内容如下:
<extension
point="org.eclipse.ui.editors">
<editor
class="com.testrcp.myrcp.editors.MutiEditorSample"
default="false"
icon="icons/alt_window_16.gif"
id="com.testrcp.myrcp.editors.MutiEditorSample"
name="多页编辑器">
</editor>
</extension>
该编辑器对应的类为 MutiEditorSample ,该类要继承自 MultiPageEditorPart 类才可以实现多页显示效果。代码如下:
package com.testrcp.myrcp.editors;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Label;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.part.MultiPageEditorPart;
public class MutiEditorSample extends MultiPageEditorPart {
//该编辑器的标识
public static final String ID ="com.testrcp.myrcp.editors.MutiEditorSample";
private JsEditor page1 ;//编辑器对象
private JsEditor page2 ;//编辑器对象
private Label control1 ;//标签对象
//父类中抽象方法
protected void createPages() {
//创建页面和标签对象
page1 = new JsEditor();
page2 = new JsEditor();
control1 = new Label ( getContainer(), SWT.NONE);
control1.setText("这是一个标签");
try {
//添加第一页
addPage( page1 , new JsEditorInput("One"));
//设置选项卡的名称
setPageText(0,"One");
//添加第二页
addPage( page2 , new JsEditorInput("Two"));
setPageText(1,"Two");
//添加第三页,为一个标签
addPage(control1);
setPageText(2,"Three");
} catch (PartInitException e) {
e.printStackTrace();
}
}
public void doSave(IProgressMonitor monitor) {
}
public void doSaveAs() {
}
public boolean isSaveAsAllowed() {
return false;
}
}
创建多页编辑器时应注意以下几个问题:
◇ 该类必须继承自 MultiPageEditorPart 类。
◇ 创建页面的代码是在 createPages 方法中。
◇ 每个页面可以是 IEditorPart 对象,也可以是 Control 对象。
◇ 创建完页面后要调用 addPage 方法,将该页添加。如果不使用该方法,将不会显示页面。
◇ addPage 方法如下所示:
◇ addPage(Control control) :添加一个控件,其中 control 为选项卡中的控件对象。
◇ addPage(IEditorPart editor, IEditorInputinput) :添加一个编辑页面。
◇ addPage(int index, Control control) :在指定索引的选项卡中,添加一个控件。
◇ addPage(int index, IEditorPart editor,IEditorInput input) :在指定索引的选项卡中,添加一个编辑页面。
◇ 可以使用父类的 setPageText(int pageIndex, String text) 方法设定显示选项卡的名称。
注意:MutiEditorSample对应的扩展点是 org.eclipse.ui.editors,而不是 org.eclipse.ui.views,不小心搞错了,在点击“MutiPage Editor”时,总是出现下面的异常:
org.eclipse.ui.PartInitException: Unable to open editor, unknown editor ID:com.testrcp.myrcp.editors.MutiEditorSample
多页编辑器的显示效果如下: