级别: 中级 Brian Leonard, Lotus Notes 客户机开发人员, IBM
2008 年 7 月 14 日 IBM Lotus Notes V8 的新架构可以让用户在给定时间的操作可见。本文描述了如何访问信息并给出了如何使用它来提高用户生产率的方法。
在上一篇文章 “扩展 IBM Lotus Notes V8 侧栏和工具栏” 中,介绍了如何为 IBM Lotus Notes V8 用户体验贡献自己的组件。在 “在 Lotus Notes V8 侧栏和工具栏中集成 IBM Lotus Notes 数据” 中,您又了解了该如何让侧栏和工具栏能够访问 Lotus Notes 数据以使它们更加有用。
您创建的 Journal 工具栏和 SideNote 对于快速保存和访问即刻写下的一些不经意的想法十分有用。如果曾经使用过这些工具,就会注意到通常想法并不总是不经意间产生的。这些快速 note 通常都是您一直关注的事情,甚至是您当前正在屏幕上查看的东西。如果能将这些想法链接至其源头又该如何呢?
在之前的文章 “在 Lotus Notes V8 侧栏和工具栏中集成 IBM Lotus Notes 数据” 中,曾经使用过 notes.jar 向 journal 保存信息以便可以在桌面创建另一个数据存储库。如果能轻松地将这些文档的源链接到文档本身,就可以减少信息进一步分散的问题。
Lotus Notes 新的基于 Eclipse 的架构让这种链接变得可能。该平台让您可以对用户在给定的任何时间的操作都有可见性。可以利用此信息创建更有效的工具和应用程序。本文解释了如何访问用户当前的上下文,而且还进一步扩展了前面两篇文章中创建的应用程序以使用此新信息。
设置
首先,需要安装 Lotus Notes V8 测试软件。安装 Eclipse,Eclipse 可免费下载。之后,需要设置 Eclipse 使之能与 Lotus Notes 环境相协作。以下步骤假设已经将 Notes 安装在了默认位置 C:\Program Files\IBM\Lotus\Notes,而且也已经有了数据目录 C:\Program Files\IBM\Lotus\Notes\Data。如果您的具体环境与之稍有区别,那么就请使用您具体的目录和位置。
打开 Eclipse,设置目标平台,方法是:
- 选择 Window - Preferences。
- 展开 Plug-in Development。
- 选择 Target Platform。
- 在 Location 编辑控件,键入或浏览到 C:\Program Files\IBM\Lotus\notes\framework\eclipse。
- 单击 Reload 按钮并单击 OK。
接下来,添加另一个已安装的 JRE:
- 选择 Window - Preferences。
- 展开 Java。
- 选择 Installed JREs。
- 单击 Add。
- 将 JRE 名称指定为 Notes JRE。
- 输入或浏览到 C:\Program Files\IBM\Lotus\notes\framework\rcp\eclipse\plugins\com.ibm.rcp.j2se.win32.<version number> 作为 JRE Home Directory。
对于 Lotus Notes Beta 3,该值是:com.ibm.rcp.j2se.win32.x86_1.5.0.SR4-200705170110
(注意:这会将 JAR 文件填充到弹出框的底端。)
接下来,创建新的运行时配置,方法是:
- 选择 Run - Run,然后选择 Eclipse Application。
- 右键单击,然后选择 New。
- 输入名称(比如 Notes)。
- 在 Program to Run 下,选择 Run a product,然后选择 select com.ibm.notes.branding.notes。
- 在 Runtime JRE 内,选择 Notes JRE。
- 在 Arguments 附签的 Program 文本框输入如下内容:
-personality com.ibm.rcp.platform.personality
-product com.ibm.notes.branding.notes
-debug
-console
将如下参数输入到 VM arguments 文本框:
-Drcp.home=${notes.install}\framework
-Drcp.data=notes.data\workspace
-Drcp.install.config=user
-Dosgi.install.area=${notes.install}\framework\eclipse
-Dcom.ibm.pvc.osgiagent.core.logfileloc=${notes.install}\framework\rcp
-Dcom.ibm.pvc.webcontainer.port=0
-Declipse.pluginCustomization=${notes.install}\framework\rcp\plugin_customization.ini
-Declipse.registry.nulltoken=true
-Djava.protocol.handler.pkgs=com.ibm.net.ssl.www.protocol
-Djava.util.logging.config.class=com.ibm.rcp.core.internal.logger.boot.LoggerConfig
-Dosgi.hook.configurators.exclude=org.eclipse.core.runtime.internal.adaptor.EclipseLogHook
-Dosgi.framework.extensions=com.ibm.rcp.core.logger.frameworkhook
-Xbootclasspath/a:${notes.install}\framework\rcp\eclipse\plugins\${rcp.base}\rcpbootcp.jar;
接下来,按如下步骤完成运行时配置:
- 单击 Variables。
- 单击 Ededitariables。
- 单击 New。
- 输入 notes.install 作为名称。
- 输入 Lotus Notes 的安装路径作为值,然后单击 OK。此路径不应有任何空格。比如,如果安装路径为 C:\Program Files\Lotus\Notes,那么 notes.install 值就应该是 C:\PROGRA~1\IBM\Lotus\Notes。
- 重复步骤 1 到 3。
- 输入 notes.data 作为名称。
- 输入数据目录所在位置作为值,然后单击 OK。例如,使用默认值:
C:\PROGRA~1\IBM\Lotus\Notes\Data。
- 重复步骤 1 到 3。
- 输入 rcp.base 作为名称。
- 针对为此值安装的 com.ibm.rcp.base 插件输入文件夹名的版本,然后单击 OK。要实现此目的,请转到如下位置:<notes 安装位置>\framework\rcp\eclipse\plugins。另外还有一个文件夹看上去很像 com.ibm.rcp.base_6.1.1.<date>。
例如,在 Lotus Notes Beta 3 中,该值就是 com.ibm.rcp.base_6.1.1.200705170110。
- 单击 OK,然后单击 Select Variable 对话框的 Cancel(如果单击 OK 选择变量,它将在插入点添加此变量)。
要从 Eclipse 启用 Notes 安全性,需要反注释两行代码。在 <notes install location>\framework\shared\eclipse\plugins\com.ibm.notes.branding_3.0.0.<version number>\notes_plugin_customization.ini,通过删除开头的 # 字符反注释如下的两行代码:
com.ibm.rcp.security.auth/loginEnabled=true
com.ibm.rcp.security.auth/loginConfigName=NOTES
现在,选择 Run/Debug 以启动 Lotus Notes。
最后,下载本文所提供的代码并将其解压缩到新的文件夹。要将它导入到 Eclipse,需要导入现有的项目。
- 选择 File - Import。
- 选择 General - Existing Projects into Workplace,然后单击 Next。
- 浏览并选择代码解压缩后所在的文件夹,然后单击 OK。
- 单击 Finish,完成导入的过程。
Eclipse 选择
Eclipse 平台是由几层构成的,而且为每个插件提供了侦听其中每一层所发生的事情的能力。通过侦听程序,可以获知用户当前的上下文的变化。
此外,com.ibm.lotuslabs.context.service 插件的创建在 Eclipse 所提供的层上又多加了一层。具体说来,DocumentContextService 允许其他插件进行订阅并在用户更改 Lotus Notes 客户机内的文档时被告知。
在任何给定时间,此上下文都被描述为当前 IWorkbenchPart 中的当前选择(selection)。Eclipse 平台要求当前部分应该发布其选择,可采用的方法是:定义 ISelectionProvider 并通过它的站点 part.getSite().setSelectionProvider() 对它进行设置。
IWorkbenchWindow 包含透视图以及各个部分,若在各个部分中,选择正在改变,IWorkbenchWindow 就可以获得 ISelectionService,而后者则可告知更改何时发生。此服务允许添加两类选择侦听程序。如果使用 addSelectionListener() 方法,只要选择有所更改,就会通知您。如果使用 addPostSelectionListener() 方法,它会简短暂停键盘导航以确保用户在此处停留。DocumentContextService 使用 addPostSelectionListener 最小化多余通知。
DocumentContextService 也以类似的方式使用两类侦听程序。如果客户使用 addSelectionListener() 方法,每次选择更改,它就会获得通知。如果使用的是 addListener() 方法,用户就只想知道何时新文档被选中。此服务定义了当新的选择具有与当前 URI 不同的 URI 时,选中新文档。
要使之对客户而言更为简便,此服务首先要作为 IWindowListener 注册自身以便当新窗口打开时被通知到。对该新窗口,它向其选择服务添加选择侦听程序。通过这种机制,DocumentContextService 类中的 selectionChanged() 方法在每次用户更改此选择时都会被调用。此方法决定了这是不是一个新文档并通知具备当前 DocumentSelection 的合适用户。
DocumentSelection 是面向此服务的类,该服务用来代表一个文档集。每个文档都通过 IDocumentContext 对象提供关于自身的信息。与此插件有关的一个有趣逻辑是如何转变由 Eclipse 平台提供的选择。
除非针对特定对象重写,否则这种转变应在内部 DocumentContext 类的构造函数中发生。提取相关信息的关键是 IAdaptable 的 Eclipse 特征。
这一灵活框架让任何对象都可被转换到另一类型。这种转换可以直接或间接发生。可以通过成为该类对象或通过实现 IAdaptable 完成直接转换。而间接转换则可通过此平台和 org.eclipse.core.runtime.adapters 扩展点实现。因此,要想从一个对象转换成另一个对象,可以使用清单 1 所示的代码。
清单 1. 从给定对象提取适配器
public static Object getAdapterObject(Object o, Class clazz) {
Object item = null;
if(clazz.isInstance(o))
item = o;
else if(o instanceof IAdaptable) {
item = ((IAdaptable)o).getAdapter(clazz);
}
if(item==null) {
IAdapterManager man = Platform.getAdapterManager();
if(man!=null)
item = man.getAdapter(o, clazz);
}
return item;
}
|
DocumentContext 采用 getAdapterObject() 方法确定选中对象的标题、URI、图标和属性。首先,试图使用 Lotus Notes 所使用的 IURIProvider 来决定要添加的书签。它提供了所有这些项目。如果不能找到标题或图标,它就使用 IWorkbenchAdapter 接口,其中可能含有这些细节。如果没有 URI,它就试图使对象直接与 URI 类相适应。最后,它试图使用 IPropertySource 接口发现其他各属性。如果这种技巧不奏效,DocumentContext 就使用来自当前 IViewPart 的信息。
所提供的 com.ibm.lotuslabs.context.ui.test 插件贡献一个侧栏面板,其中显示了 DocumentContextService 作为当前文档正在报告的内容。参见图 1。
图 1. 上下文侧栏
Todo 工具栏
com.ibm.lotuslabs.todo.ui 插件贡献一个工具栏,此工具栏是 SideNote 概念的另一个扩展,此外还有上篇文章中提到的 Journal 工具栏。Todo 工具栏可以启动 Todo 应用程序、显示新的任务表单或快速创建任务,如图 2 所示。不同之处是此工具栏使用 DocumentContextService 创建引用当前文档的任务。
图 2. 创建快捷任务
这种从当前文档或围绕当前文档创建任务的方式应该能够提高生产率,因为它能增进应用程序间的耦合。而所创建的新任务则能拥有所键入的文本和一个到原始文档的链接。参见图 3。
图 3. 带链接的新任务
除了添加链接的能力之外,此工具栏所能做的贡献与在前一篇文章 “在 Lotus Notes V8 侧栏和工具栏中集成 IBM Lotus Notes 数据” 中介绍的 Journal 工具栏几乎无异。作为一个实例变量,此 TodoContribution 类保存了当前的 DocumentSelection。当创建此工具栏时,它会向此服务添加侦听程序,如清单 2 所示。
清单 2. 添加 DocumentContextService 侦听程序
final IDocumentContextListener listener = new IDocumentContextListener() {
public void selectionChanged(IWorkbenchPart part, DocumentSelection selection) {
current = selection;
}
};
final DocumentContextService service = DocumentContextService.getDefault();
service.addListener(listener);
|
现在,当对话框出现时,它能使用选择对象生成一个链接项。当用户选择 Quick 时,它会从此选择中提取标题和 URI。SideNote 对象具有为复选标记设置文本并查看当用户关闭它时此选项是否还被选中的能力。
不管用户是否选中此选项,代码都会使用 com.ibm.lotuslabs.notes.pim 插件创建任务。具体说来,它会调用 TodoTask.createTask() 方法。作为输入,这会接受新任务的文本和标题。此外,它还能接受链接的数组以将其包含到文本之上。
createTask() 方法使用的是 “在 Lotus Notes V8 侧栏和工具栏中集成 IBM Lotus Notes 数据” 中所讨论的 NotesJob 框架。正如在创建 journal 条目时所做的,您必须创建具有正确项目的新文档。需要具体地设置标题和主体、完成 Task 表单所需的其他字段,比如重要性、到期日等等。
在创建主体时,还可以添加传入的链接。清单 3 中所示的代码显示了这是如何实现的。
清单 3. 创建主体
RichTextItem body = doc.createRichTextItem("Body");
// if links
if(links!=null) {
for(int i=0;i<links.length;i++) {
addLink(session,body,links[i]);
}
body.addNewLine();
}
body.appendText(val);
|
addLink() 方法允许将任一 String 用作链接。此方法具体执行对 notes:// URL 的检查。如果找到,它就会创建一个定制 Lotus Notes 链接;否则,它只向文本添加链接本身。
Journal It
SideNote 是侧栏中的一个应用程序,它提供单一地点以写下文本。但它并不是真的要保存这些文本。Journal It 使用相同的位置,但方式不同。Journal It 为每个文档都提供一个保存 note,而非单个 note。参见图 4。
图 4. Journal It 应用程序
在 Journal It 接受 note 会将条目链接到当前文档。用户可以在侧栏记下关于电子邮件的 note。之后,电子邮件显示时,这些 note 也会出现。
com.ibm.lotuslabs.journal.ui.context 插件为 Lotus Notes 侧栏贡献了 JournalCurrentViewPart 部分。此 ViewPart 订阅 DocumentContextService 以了解用户何时交换文档。文档的 URI 影射到 ID。此 ID 用来在 journal 数据库中的视图中查找一个文档。如果该文档不存在,Journal It 使用服务的标题。如果用户更改了任何内容,数据就使用该 ID 保存。
journal 条目的实际显示使用 com.ibm.lotuslabs.notes.pim 插件中的 JournalNote Composite。具有像这样的一个受 Lotus Notes 数据支持的 UI 组件的挑战在于如何处理线程方面的问题。即,不能从 UI 线程连接到 journal 数据库。
JournalNotes 通过名为 createValueMap() 的静态方法处理线程问题,此方法能接受文档对象并能用初始化 UI 所需的内容填充 Map。而这个 Map 在 NotesJob 中创建,因此所有的工作都在这另一个线程中完成。之后,此 Map 可以传递到 UI 线程以创建控件。
在创建此 Map 之前,文档必须要能在视图中找到。当 JournalSidebarUtil 类中的 createSidebarView() 方法需要 JournalIt 视图时,此视图才首次创建。此视图显示具有 JournalIt ID 字段的数据库中的所有文档。而且,当创建此视图时,数据库中的其他视图就会被更新以便不显示这些文档。此动作使 By Category 视图能对用户保持不变。而查找使用的 view.getDocumentByKey() 方法借助了上述提到的 ID 值。
当文档服务向应用程序告知新文档出现时,此应用程序就会检查用户是否做了任何更改。如果有更改,就会创建新的 journal 条目或由主题和文本修改后的之前的条目。
限制
IBM Lotus Notes V8 有几个限制;最主要的限制是若文档在非 PIM 视图中选中,则所选文档的标题是不正确的。具体说来,DocumentContextService 会报告此文档的标题就是视图的标题。
另一个问题是服务当前并不报告嵌入浏览器正在浏览的网站的 URL。使用 Eclipse 界面的一个主要好处是所有类型的组件都可以加入。嵌入的浏览器只需通过 IViewPart 报告其选择。这之后,诸如 Journal It 这样的应用程序就可以跨 Lotus Notes 文档和 Web 页面以及任何能报告应用程序选择的工具工作。
结束语
在这三篇文章中,我们着重介绍了如何将组件插入 Lotus Notes 用户界面、如何访问和修改 Lotus Notes 数据以及如何充分利用用户上下文。通过结合这三种功能,就可以创建着实让人兴奋的应用程序。
特别指出的是,根据用户的当前操作量身定做应用程序的这种方法异常有效。本文所提供的服务和示例应该能帮助您入门。
参考资料 学习
获得产品和技术
讨论
关于作者  | |  | Brian Leonard 是一名 Lotus Notes 客户机开发人员。在 IBM Lotus Notes V8 中,他从事搜索、电子邮件显示、显示图片的装载、拼写检查和可扩展性等方面的工作。他想长高一点,但是没法找到合适的 “扩展点”。 |
对本文的评价
|