如前所述,Notes数据库的核心就是其中保存各种数据的通用结构note。Notes提供的很多功能都是建立在这种结构上,我们开发的应用程序也是围绕着它的应用,同时受益于和受制于它的特点。之后的几篇文章,我都会介绍一些关于这位幕后主角的信息。
在Notes数据库中,我们会接触到各种不同形式的数据。在workspace(工作台)上,可以看到数据库的图标;在视图里,可以看到文档列表;打开其中一个,可以看到文档的内容;通过相应的菜单命令,可以在对话框中看到存取控制列表和复制公式等等;在designer(设计器)里可以看到表单、代理和脚本库。所有这些数据在形式上和功能上是如此不同,但是在数据库中都是以同样的结构note保存。文档(document)作为用户note、数据note的同义词,是我们很熟悉的。对于开发和管理人员,有趣和值得注意的是,设计元素与文档从技术上说没有多少差别。或者说在Notes程序的眼中,它们只是同一种东西的不同子类,在读取、修改、保存和删除等操作上没有差别。我们在desinger中已经可以看到这一点的表现,各种设计元素的列表和显示文档的视图就十分相似,在每个设计元素的属性中,还可以看到和文档一样的域列表。我们甚至可以创建一个视图,显示设计元素。在给出这样一个例子前,我们先看看Notes是怎样区分各种note的。
Notes程序将note分成下面这些类型。
类型 | 说明 | NOTE_CLASS | 单复数 |
ACL | 设定数据库的存取权限。 | 0x0040 | 单个 |
Document | 用户文档。 | 0x0001 | 多个 |
Design | 设计note集合,即NotesNoteCollection。 | 0x0020 | |
Field | 共享域(字段) | 0x0400 | 多个 |
Filter | 代理、代理数据、大纲、脚本库、数据库脚本都归在此类型下。 | 0x0200 | |
Agent | 多个 | ||
Agent Data | 多个 | ||
Outline | 多个 | ||
Script Library | 多个 | ||
Database Script | 单个 | ||
Form | 表单、子表单、页面、帧结构集、图片资源、Java资源、共享操作、XPage都归在此类型下。 | 0x0004 | |
Form | 多个 | ||
Subform | 多个 | ||
Page | 多个 | ||
Frameset | 多个 | ||
Image Resource | 多个 | ||
Java Resource | 多个 | ||
Shared Action | 所有共享操作保存在唯一的note里。 | 单个 | |
Xpage | 多个 | ||
Icon | 设定数据库的图标、标题和分类。 | 0x0010 | 单个 |
Info | 设定“关于数据库”的帮助。 | 0x0002 | 单个 |
Help | 设定“使用数据库”的帮助。 | 0x0100 | 单个 |
Help Index | 设定Notes产品帮助信息的索引。 | 0x0080 | 单个 |
ReplFormula | 设定复制公式。 | 0x0800 | 单个 |
View | 视图、文件夹、导航器都归在此类型下。 | 0x0008 | |
View | 多个 | ||
Folder | 多个 | ||
Navigator | 多个 |
“NOTE_CLASS”是Notes程序中代表不同note类型的代码,这里用16进制表示。
“单复数”列指的是该类型的note在数据库中只能有一个还是可以有多个。
可以看出程序中Notes对note的分类,特别是设计元素,与我们在开发中认识的分类有很大的不同。表单、子表单、页面、XPage这些都是Form类型的note在应用上的分类。实际上从功能的角度我们也能体会到它们中的一些除了某些特性,确实是相同的。比如子表单除了不能单独,显示与表单完全一样;页面除了不能插入域用于保存和显示文档,与表单的功能也一致。视图和文件夹的情况也类似。
另外还可以看出,NOTE_CLASS是被设计成可以参与“或”运算的标志位。这样既可以用单个NOTE_CLASS确定某个类型的note,也可以用任意多个NOTE_CLASS的“或”组合代表多种note。比如将所有设计元素的NOTE_CLASS组合起来,就成为代表数据库中所有设计note的标志位0x7ffe,再与0x0001做“或”运算,就成为表示所有note的0x7fff。NOTE_CLASS还被用来表示其他一些含义,比如0x8000表示某类note中的默认个体,0x1000表示私有设计note。
下一个问题是,Notes程序如何区分具有相同NOTE_CLASS的不同设计元素。答案是借助于另一个文本型的标志—— Flags条目(item)。每个设计元素中都有一个 Flags条目,它被用于保存很多重要的行为信息,其中一个字符表示一个特性,有些特性只适用于一种NOTE_CLASS,有些则对所有note都适用。通过查看设计元素的属性,可以在它们的域列表中找到$Flags。下面举几个例子:
‘A’ – FORM,说明一个子表单在增加子表单的列表中。
‘a’ – VIEW,说明一个视图不包含任何文件夹中的文档。
‘w’ – 所有,说明这个设计note对Web客户端隐藏。
‘#’ – FORM,说明这是一个帧结构集。
可以看出,确定某种设计元素的类型与描述其他特性被混合在一起,而字符的数量是有限的,所以当新特性和新类型不断被增加时,这种编码方式的资源很快会被耗尽。于是Notes开始采用“模式”,也即具有特殊功能的字符与普通字符的组合,来表示某种信息。比如用”+sh.”表示脚本库。
以上这些描述可能会显得距离太遥远,下面就来看一个实际应用的例子。
我们建一个视图来显示设计元素。不妨把视图命名为( DesignElements),别名为 DesignElements。视图选择公式(View Selection)需要由我们想包含的元素种类来决定。下表列出了每种设计元素对应的NOTE_CLASS和所需的选择公式(引自Make a Notes view list design elements)。
设计元素种类
|
NOTE_CLASS( 16进制 )
|
选择公式(R8.5)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
因为每个设计元素的名称都保留在一个$Title条目中,所以可以建一个名称列,公式为:
$Title
根据需要和喜好,还可以添加“最近修改人”,“最近修改时间”等列。
针对含有代码的设计元素(代理、脚本库等)我们还可以显示它们使用的编程语言,公式为:
f:=$Flags;
@If(@Contains(f; “s”);
@If(@Contains(f; “j”);
“Java“;
@IsAvailable(“$ScriptLib”);
“LotusScript”;”“);
@Contains(f; “j”); “Java”;
@Contains(f; “L”); “LotusScript”;
@Contains(f; “f”); “Formula”;
“”)
现在在Notes中显示这个视图,什么都没有!因为在视图中还有一个开关—— FormulaClass条目,这是一个文本条目,保存的是视图中包含的note的NOTECLASS值,用来显示文档的普通视图的这个条目的值为”1”,而要成为显示设计元素的特殊视图,这个条目的值需要被改成相应的NOTECLASS值。比如要显示FORM类型的note,就要改成”4”;而要显示所有设计note,则要改成”32766”。怎样修改一个设计元素中的条目呢?答案是与修改一个文档一样,只要我们获得了指向这个视图的NotesDocument,就可以用我们熟悉的修改文档条目的方法。那么怎样获得这个NotesDocument呢?我们可以用GetView方法获得这个视图,但它是一个NotesView对象,无法获得底层的note中的条目。作为用户文档的NotesDocument往往是从一个视图中取得,而现在用于包含设计元素的视图还没有完成。我们只能使用在数据库中获取某个note的更基本的方法GetDocumentByUNID。幸运的是,NotesView有一个UniversalID属性,正是底层的note的UniversalID。这样,我们就可以写出下面的代码,修改DesignElements视图的 FormulaClass条目。考虑到今后可能会对这个视图做修改,而在某些版本(例如6.5)的设计器中,每次视图在被保存时,$FormulaClass条目都会被自动恢复成”1”,所以我们将这段代码放在视图的一个按钮中,每次修改视图之后,都在Notes客户端运行一次。
Option Public
Option Declare
Sub Initialize
Dim s As New NotesSession
Dim db As NotesDatabase
Set db=s.CurrentDatabase
Dim view As NotesView
Set view=db.GetView("$DesignElements")
If view Is Nothing Then
Exit Sub
End If
Dim viewDoc As NotesDocument
Set viewDoc=db.GetDocumentByUNID(view.UniversalID)
'将$FormulaClass改成任何希望包含的设计元素对应的值。
Call viewDoc.ReplaceItemValue("$FormulaClass","4")
Call viewDoc.Sign()
Call viewDoc.Save(True,False)
Dim ws As New NotesUIWorkspace
Call ws.ViewRebuild()
End Sub
最后需要指出的是,因为需要同时使用NOTE_CLASS和选择公式才能确定某些设计元素的类型,所以如果将上述视图的 FormulaClass改成对应所有设计note的”32766”,将无法使用一个公式列准确地显示哪些是表单、视图和代理等类型,这些类型的选择公式使用了!@Match(),在没有限定NOTECLASS的情况下,会互相冲突。如果将表单的判定公式放在列的计算公式的前面,则视图等其它元素会被归类成表单;将视图或代理的判定公式放在前面也会出现类似的情况。所以要使这个视图显示的内容最准确有效,还是应该限定 FormulaClass为某个具体的NOTE_CLASS值。