Eclipse 中 IMemento 接口定义了对象持久化方式,通过 IMemento 接口的实现类,用户能把对象持久化到文件系统中, IMemento 接口定义如例程 24-7 所示。
例程 24-7 IMemento.java
package org.eclipse.ui;
public interface IMemento {
public static final String TAG_ID = "IMemento.internal.id"; //$NON-NLS-1$
public IMemento createChild(String type);
public IMemento createChild(String type, String id);
public IMemento getChild(String type);
public IMemento[] getChildren(String type);
public Float getFloat(String key);
public String getID();
public Integer getInteger(String key);
public String getString(String key);
public String getTextData();
public void putFloat(String key, float value);
public void putInteger(String key, int value);
public void putMemento(IMemento memento);
public void putString(String key, String value);
public void putTextData(String data);
}
Eclipse 中 XMLMemento 实现了 IMemento 接口,通过 XMLMemento 对象, Eclipse 能把当前 UI 的状态持久化到文件系统中,其中 createChild 方法为创建下一级 IMemento 节点, getChild 方法返回下一级 IMemento 节点。
24.4.2 UI 持久化与恢复的实现
Eclipse UI 的设计目标之一,就是在多次会话之间保持用户体验的连贯性。当一次会话结束时,工作台会保存当前的配置和工作台窗口的内容;用户开始新的一次会话时,工作台将这些状态恢复到上一次会话结束之前的样子。
Eclipse UI 持久化的过程比较复杂,因 UI 要持久化的内容比较多,包括编辑器、视图、视角、 page 和 window 的状态,但持久化的方式一样,持久化的步骤如下:
( 1 )创建 XMLMemento 对象,并保存,实现类为 Workbench ,如下代码片段所示。
XMLMemento memento = XMLMemento
.createWriteRoot(IWorkbenchConstants.TAG_WORKBENCH);
IStatus status = saveState(memento);o);
( 2 )得到所有的工作台窗口( WorkbenchWindow ),保存所有窗口的状态,实现类为 Workbench ,如下代码片段所示。
IWorkbenchWindow[] windows = getWorkbenchWindows();
for (int nX = 0; nX < windows.length; nX++) {
WorkbenchWindow window = (WorkbenchWindow) windows[nX];
IMemento childMem = memento
.createChild(IWorkbenchConstants.TAG_WINDOW);
result.merge(window.saveState(childMem));
}
( 3 )得到工作台窗口包括的 Page ( WorkbenchPage )页,并保存 Page 页的状态,实现类为 WorkbenchWindow ,如下代码片段所示。
Iterator itr = pageList.iterator();
while (itr.hasNext()) {
WorkbenchPage page = (WorkbenchPage) itr.next();
IMemento pageMem = memento
.createChild(IWorkbenchConstants.TAG_PAGE);
pageMem.putString(IWorkbenchConstants.TAG_LABEL, page.getLabel());
result.add(page.saveState(pageMem));
if (page == getActiveWorkbenchPage()) {
pageMem.putString(IWorkbenchConstants.TAG_FOCUS, "true"); //$NON-NLS-1$
}
IAdaptable input = page.getInput();
if (input != null) {
IPersistableElement persistable = (IPersistableElement) input
.getAdapter(IPersistableElement.class);
if (persistable == null) {
WorkbenchPlugin
.log("Unable to save page input: " //$NON-NLS-1$
+ input
+ ", because it does not adapt to IPersistableElement");
} else {
IMemento inputMem = pageMem
.createChild(IWorkbenchConstants.TAG_INPUT);
inputMem.putString(IWorkbenchConstants.TAG_FACTORY_ID,
persistable.getFactoryId());
persistable.saveState(inputMem);
}
}
}
( 4 )保存 Page 页中所有的编辑器、视图、视角的状态,通过 EditorManager 、 ViewFactory 和 Perspective 保存编辑器、视图、视角的状态,实现类为 WorkbenchPage ,如下代码片段所示。
IMemento childMem = memento
.createChild(IWorkbenchConstants.TAG_EDITORS);
result.merge(editorMgr.saveState(childMem));
childMem = memento.createChild(IWorkbenchConstants.TAG_VIEWS);
result.merge(getViewFactory().saveState(childMem));
…
Iterator itr = perspList.iterator();
while (itr.hasNext()) {
Perspective persp = (Perspective) itr.next();
IMemento gChildMem = childMem
.createChild(IWorkbenchConstants.TAG_PERSPECTIVE);
result.merge(persp.saveState(gChildMem));
}
( 5 )把最底层的 XMLMemento 保存到文件,实现类为 Workbench ,如下代码片段所示。
private boolean saveMementoToFile(XMLMemento memento) {
File stateFile = getWorkbenchStateFile();
if (stateFile == null)
return false;
try {
FileOutputStream stream = new FileOutputStream(stateFile);
OutputStreamWriter writer = new OutputStreamWriter(stream, "utf-8");
memento.save(writer);
writer.close();
} catch (IOException e) {
stateFile.delete();
MessageDialog.openError((Shell) null,
WorkbenchMessages.SavingProblem,
WorkbenchMessages.ProblemSavingState);
return false;
}
return true;
}
如上的步骤只是列出了持久化的过程,并没有完全列出持久化的所有代码,读者可以通过实现类找到具体代码的实现。
当 Eclipse 重新启动时, Eclipse 将通过从文件中读取相应的 XMLMemento 信息 ,恢复上一次退出 Eclipse 时的状态,具体步骤如下:
( 1 )从文件中读取 XMLMemento 信息,实现类为 Workbench ,如下代码片段如示。
final File stateFile = getWorkbenchStateFile();
if (stateFile == null || !stateFile.exists()) {
String msg = WorkbenchMessages.Workbench_noStateToRestore;
return new Status(IStatus.WARNING, WorkbenchPlugin.PI_WORKBENCH,
IWorkbenchConfigurer.RESTORE_CODE_RESET, msg, null);
}
…
FileInputStream input = new FileInputStream(stateFile);
BufferedReader reader = new BufferedReader(
new InputStreamReader(input, "utf-8"));
IMemento memento = XMLMemento.createReadRoot(reader);
….
IStatus restoreResult = restoreState(memento);
( 2 )从 XMLMemento 读取所有窗口信息,并恢复窗口,实现类为 Workbench ,如下代码片段所示。
IMemento[] children = memento
.getChildren(IWorkbenchConstants.TAG_WINDOW);
createdWindows = new WorkbenchWindow[children.length];
for (int i = 0; i < children.length; i++) {
childMem = children[i];
WorkbenchWindow newWindow = newWorkbenchWindow();
createdWindows[i] = newWindow;
newWindow.create();
windowManager.add(newWindow);
boolean restored = false;
try {
status.merge(newWindow.restoreState(childMem, null));
try {
newWindow.fireWindowRestored();
} catch (WorkbenchException e) {
status.add(e.getStatus());
}
restored = true;
} finally {
if (!restored) {
createdWindows[i] = null;
newWindow.close();
}
}
}
( 3 )恢复所有 Page 的状态,实现类为 WorkbenchWindow ,如下代码片段所示。
WorkbenchPage newPage = null;
try {
newPage = new WorkbenchPage(this, input);
result.add(newPage.restoreState(pageMem, activeDescriptor));
pageList.add(newPage);
firePageOpened(newPage);
} catch (WorkbenchException e) {
WorkbenchPlugin
.log("Unable to restore perspective - constructor failed.", e);
result.add(e.getStatus());
continue;
}
( 4 )恢复所有编辑器、视图和视角的状态,通过 EditorManager 、 ViewFactory 和 Perspective 恢复编辑器、视图、视角的状态,实现类为 WorkbenchPage ,如下代码片段所示。
IMemento childMem = memento
.getChild(IWorkbenchConstants.TAG_EDITORS);
result.merge(getEditorManager().restoreState(childMem));
childMem = memento.getChild(IWorkbenchConstants.TAG_VIEWS);
if (childMem != null)
result.merge(getViewFactory().restoreState(childMem));
…
IMemento perspMems[] = childMem
.getChildren(IWorkbenchConstants.TAG_PERSPECTIVE);
Perspective activePerspective = null;
for (int i = 0; i < perspMems.length; i++) {
try {
Perspective persp = new Perspective(null, this);
result.merge(persp.restoreState(perspMems[i]));
IPerspectiveDescriptor desc = persp.getDesc();
if (desc.equals(activeDescriptor))
activePerspective = persp;
else if ((activePerspective == null)
&& desc.getId().equals(activePerspectiveID))
activePerspective = persp;
perspList.add(persp);
window.firePerspectiveOpened(this, desc);
} catch (WorkbenchException e) {
}
}