构建 Lotus Notes/Domino 日程表应用程序

很多人对 Lotus Notes 日程表都是“即购即用”。但是您知道吗,您也可以将日程表特性融入到自己定制的应用程序中来。本文将解释如何做到这一点。
                                                                                                                                                                                                                                                                                                                        Lotus Notes 日程表是 Lotus Notes 的一个最流行且易于使用的组件。日程表可以有很多不同的用途,其中常见的用途有:
· 会议室预定
· 设备预定
· 共用业务或部门日程表
· 资源或事件计划
· 假期计划

除了其终端用户特性外,Notes 日程表对于应用程序开发人员也非常有用。在本文中,我们提供了构建一个示例日程表应用程序的逐步说明。我们假设您是一名有经验的 Lotus Notes/Domino 开发人员,并且熟悉基本的 Notes 日程表特性。
应用程序架构
一个日程表应用程序由两大部分组成:一个表单和一个视图。表单用于捕捉约会日期、时间和主题之类的信息。视图则根据表单中提供的指定日期和时间显示主题。信不信由您,用这两部分就足以构建一个可以管理重复事件的日程表应用程序。
在开始编程之前,我们首先需要理解构建日程表应用程序的一些规则,并弄清管理重复事件的过程。
规则:
· 约会表单必须有一个起始日期字段。该字段决定了在日程表的什么地方显示事件。起始日期是日程表应用程序的锚。
· 约会表单必须包含一个持续时间(duration)。这个字段必须是一个数字,表示时间持续的天数。(约会表单还可以包含一个起始时间和一个终止时间。不过,这是一个可选值,当实际在日程表上显示事件时这不是必需的。)
· 日程表视图的第一列必须包含一个日期/时间值,并且按升序排序。这一列对用户应该是隐藏的。(为了正确地显示,必须将第一列按升序排序。)
· 日程表视图的第二列必须包含日程表事件的持续时间。这个值决定了应该连续多少天显示这个约会。持续时间值可以是正数,也可以是负数。如果是正数,则将日程表事件显示到起始日期的右边(或将来)。如果是负数,则将日程表事件显示到起始日期的左边(或之前)。
· 视图的风格必须设置为 Calendar。这种设置将视图的外观从传统外观变成实际的日程表。

现在让我们更深入地研究用于管理重复日程表事件的架构和实现选择。应用程序的复杂性是围绕着管理重复事件的过程而形成的。同任何软件语言一样,设计、开发和实现一个解决方案的方法有很多种。接下来的几个小节将讨论两种可能的架构。
使用单个文档管理重复事件
我们已经讨论了日程表应用程序的主要组成部分,即一个表单和一个视图。接下来要谈到的是管理重复事件的不同选择。第一种方法是管理连续日程表事件的一种简单而有效的方法。
连续事件是指从起始日期起往后延续的约会。换句话说,您可以创建一个约会,这个约会将在多个日程表日期上显示。然而,所有日程表日期必须是连续的,例如从4 月 4 日到 4 月 7 日。“单文档”方法只创建一个文档,并在日程表日期范围内显示约会(见图1)。这种方法实现起来比较简单。如果您想快速地构建一个日程表应用程序,或者将一个日程表添加到一个已有的应用程序中,那么这种方法可以作为很好的起点。
图 1. 单文档重复事件

这种方法的主要优点是易于实现。您可以很轻松地生成一个新的应用程序(或者通过添加两个字段并创建一个日程表视图来增强一个已有的应用程序)。而且,由于所有日程表日期都引用相同的(单个)文档,用户只需更新一个文档。文档的更新可以反映到每一个日程表日期。例如,假设作者想在约会的主体中包括一个会议电话号码。那么作者只需进行一次更新,更改就会立即在所有日程表日期上生效。其他小组成员可以右键单击任何一个文档,然后看到一致的信息。
这种方法的缺点是不能管理复杂的重复事件。如果您需要将事件安排在每个月的第二个星期五或每个月的 3 号,那么单文档方法就要求用户手动地在每个日期上创建条目。
下面这一节将讨论一种更健壮的、全面的用于重复事件的架构。
使用多个文档管理重复事件
“多文档”方法根据在初次约会中指定的重复事件参数创建一个单独的文档。例如,您可以创建一个约会,这个约会为每个日程表日期生成一个单独的文档(见图 2)。这种架构在排日程表时可以提供更大的灵活性,但是实现起来也要复杂许多。
图 2. 多文档重复事件

为了实现第二种方法,需要在初次约会表单中捕捉附加的信息。这是通过一个单独的对话框窗口管理的,该窗口提示用户指定重复事件参数: weekly(每周)、daily(每天)、day of the week(星期几)、skip weekends(跳过周末)、monthly(每月)、custom dates(定制日期),等等。当保存初次约会时,该方法计算出所有重复事件日期,并为每个日程表日期生成一个单独的文档。
通过使用第二种方法可以获得更大的灵活性,并且有更多的选择来管理重复事件。实现这种架构时可以创建各种不同的事件:
事件类型 例子
By Date 4 月 4 日(单天事件)
Daily by date 4 月 4 日到 4 月 7 日(连续)
Weekly by day 星期一、星期三和星期五
Monthly by date 每个月的第一天
Monthly by day 每个月的第三个星期五
Custom dates 定制的一组不连续的日期
Skip Weekends 如果事件落在星期六或星期天上,则不创建
Next Business Day 如果碰到周末,则将事件移到星期一
另一个优点是可以移动和删除事件。由于每个事件都是作为惟一的文档存放的,因此用户可以在不影响其他相关事件的情况下移动、删除或更新一个日程表事件。
这种方法的缺点是计算事件日期时需要复杂的算法。而且,这种方法要为每个事件创建一个单独的文档。如果作者想要更新所有相关事件的主题或主体,那么需要独立地更新每个文档。
在删除或移除一个已经安排好的约会时也会遇到挑战。为了删除所有相关的约会,作者需要逐个地删除每个约会,或者添加一个子例程来自动删除相关的事件。
构建一个简单的事件日程表
现在让我们将注意力转移到构建一个简单的单文档日程表应用程序上来。首先要启动 Lotus Domino Designer 客户机,并创建一个空白数据库(见图 3)。为此,打开 Domino Designer 客户机,并选择 File - Database - New。指定一个应用程序标题和文件名。确保选择了 "-Blank-" 作为模板类型。
图 3. New Database 屏幕

删除“File name”字段中的所有空格是有益的。在使用 Web 应用程序时,空格可能导致一些问题。例如,将“Meeting Calendar.nsf”替换为“MeetingCalendar.nsf”。
创建 Appointment 表单
约会表单捕捉事件起始日期和终止日期、持续时间、作者、主题和一些细节。持续时间是自动计算的。大多数与日程表应用程序相关的工作都处在约会表单中,包括重复事件的管理。
为创建一个表单,单击 New Form 按钮,或者选择 Create - Design - Form 菜单选项。
定义字段
接下来,添加下面表中指定的字段。为创建一个字段,选择 Create - Field 菜单选项。确保为表单上每个字段设置了数据类型、公式和其他属性。
字段名称 类型 公式 备注
StartDate Date/Time, Editable DEFAULT StartDate:= @If(@IsNewDoc;@Today; @Return(StartDateTime)); StartDate 在字段属性对话框中将风格设置为Calendar/Time Control
EndDate Date/Time, Editable n/a 在字段属性对话框中将风格设置为 Calendar/Time Control
Duration Number, Computed @If(StartDate = ""; 0; EndDate = ""; 0; @BusinessDays(StartDate; EndDate)) 该公式将根据起始日期和终止日期自动计算持续时间
Person Text, Computed when Composed @Name([CN]; @UserName) 该公式将自动得出作者的名称
Subject Text, Editable n/a n/a
Body Rich Text, Editable n/a n/a
字段名称、类型和风格将在属性对话框中定义。字段公式被放在 Programmer’s Pane 窗格的 Value or DefaultValue 部分,这个窗格位于 Designer 客户机较下面的一个区域。如果没有看到这个窗格,那么可以选择 View -Programmer’s Pane。(请参阅 Domino Designer product documentation 以了解关于如何使用 Domino Designer 客户机的细节。)
定义全局对象
接下来的步骤是定义与“(Globals)”部分中的表单相关的全局对象。您可以只定义一次对象,然后在整个表单中引用这个对象。这样便简化了代码,并使得应用程序的代码更高效。
在“(Global)”标题下的“Declarations”部分中作如下设置:
Dim doc As NotesDocument '' Refers to the current calendar document           Dim ws As NotesUIWorkspace '' Refers to the current applicationworkspace            Dim s As NotesSession '' Refers to the currentnotes session            Dim db As NotesDatabase '' Refers to thecurrent Notes database            Dim sDate As NotesDateTime ''Temporary variable for Start Date calculations            Dim eDate AsNotesDateTime '' Temporary variable for End Date calculations           
我们建议在“(Options)”部分添加“Option Explicit”。这样将迫使您声明(例如 DIM)所有变量,从而有助于调试。如果变量没有定义,则语句被标为有语法错误。这样就可以更容易地发现代码中的问题(例如输错的变量名)。
现在您的日程表约会表单看上去应该如图 4 所示:
图 4. 日程表约会表单

将窗口标题设置为 Appointment。每当在 Lotus Notes客户机中打开这个表单时,该标题都将显示在窗口的顶端。这个标题有助于使应用程序更加用户友好。应用程序的其他地方不会用到窗口标题,您可以将窗口标题改为自己喜欢的任何值(例如 Appointment、Meeting 或“Meeting by” + 人名)。
打开文档后,在约会表单中设置一个默认的起始日期:
Sub Queryopen(Source As Notesuidocument, Mode As Integer, Isnewdoc AsVariant, Continue As Variant)            Set ws = New NotesUIWorkspace           Set s = New NotesSession            ApptDate =ws.CurrentCalendarDateTime            End Sub            
显示了约会之后,获得文档的一个句柄。doc 对象将在多个 LotusScript 事件中用于设置和获取约会记录中的信息:
Sub Postopen(Source As Notesuidocument)            Set doc = source.Document            End Sub            
计算日程表视图中要用到的两个变量:StartDateTime 和 CalendarDateTime。这两个变量将包括连续日程表日期数组。下面这段代码格式化数据,并设置约会表单上的值。
Sub Postrecalc(Source As Notesuidocument)            Dim mydate AsNotesItem            Set doc = source.Document            Set mydate =doc.GetFirstItem("StartDate")            Set sDate = NewNotesDateTime(mydate.DateTimeValue.DateOnly)            Setdoc.StartDateTime = sDate            Set eDate = New NotesDateTime("")           Set eDate = sDate            eDate.AdjustDay(doc.Duration(0)- 1)            Set doc.EndDateTime = eDate           doc.CalendarDateTime = doc.StartDateTime            End Sub            
每当保存文档时刷新当前文档。这样可以确保每当保存表单时(例如,当用户选择 File - Save 时),将最近的数据显示给用户。
Sub Querysave(Source As Notesuidocument, Continue As Variant)            Source.Refresh            End Sub            
设置表单属性
最后,在表单属性对话框中,选中第一个选项卡中 Options 部分的“Automatically refresh fields”选项(见图 5)。该选项在您更改约会表单上的数据时将刷新计算字段。例如,当起始日期和终止日期被更改时,持续时间值将自动更新。
图 5. Form 属性

为完成这个表单,在 Properties 对话框中指定 Appointment | Appt作为表单名。其中的竖线表明后面是该表单的别名。然后,保存并关闭该表单。(总是提供一个表单名和一个别名是一种很好的作法,这使得后面所有代码都可以引用别名。这样一来,便可以在不影响已有代码和/或视图公式的情况下更改表单名,从而拥有更大的灵活性。)
创建 Calendar 视图
至此,应用程序的大部分都已经完成了。剩下的惟一一步是用于显示约会事件的日程表视图。每当创建一个数据库时,都会自动生成一个名为“(Untitled)”的默认视图。双击这个视图,从而以 Edit 模式打开它。将 Properties 对话框从 Column 转换为View。将名称设置为 Calendar,别名设置为 Cal。
定义列
接下来的步骤是定义列。通过单击一个已有的列标题,并选择 Create - Insert New Column 菜单选项,就可以添加一个列。接下来添加以下几列。
Column1 是一个隐藏列,它必须包含按升序排序的起始日期/时间值。对于本项目,需要选择“show multiple values asseparate entries”选项。这个选项用于在多个日程表日期之间显示一个文档(见图 1)。在 programmer’s pane上,将显示类型更改为 Formula,并将列公式设置为:
REM "Column1 contains the list of start dates as defined in theappointment form";            StartTime := @Time(CalendarDateTime);           DateList := @Explode(@TextToTime(@Text(CalendarDateTime) + "-" +@Text(EndDateTime)));            @TextToTime(@Text(DateList) + " " +@Text(StartTime))            
为设置排序类型,选择 Column properties 对话框的第二个选项卡,并单击 Ascending 单选按钮选项。同时也选择“Showmultiple values as separate entries”。为隐藏该列,选择 Column properties对话框中的最后一个选项卡。双击 column1 标题弹出 Properties 对话框。然后选择最后一个选项卡上的 Hide Column复选框:
图 6. Column properties


Column2 是一个隐藏列,它必须包含事件持续时间,以使日程表视图能够正确显示事件。如果第二列没有包含一个有效的数值,那么您将收到一条错误消息。将列公式设置为:
REM "Column2 contains the duration for each appointment form";
Duration;  
使用与设置 column1 时一样的步骤隐藏 column2。
Column3 只是显示日程表事件的文本值。这个值将被显示在实际的日程表视图上。将列公式设置为:
REM
"Column3 represents the value displayed on the calendar";
Person;  
或者,这个列也可以包含人名和主题,或其他某种数据元素和文本的组合。您可能还想设置这个列的背景颜色,以增强应用程序的易用性。这样可以突出条目,帮助用户在视图中找到日程表事件。为设置背景颜色,选择 View properties 对话框中的第三个选项卡。Background 设置位于Entry 部分。
注意: 列标题在日程表视图中是不显示的。然而,通过提供一个列标题名称可以帮助您和其他开发人员理解视图的设计和列中的内容。
设置视图对象和属性
RegionDoubleClick事件允许用户双击一个日程表日期,自动打开新的约会表单。表单显示之后,起始日期上显示日程表上选择的日期。该事件还包含一个数据合法性检查,以判断所选日期是否在当前日期之前。如果所选日期处在过去,那么用户会收到提示:"Date in past… Do you want tocontinue?" 如果用户选择 Yes,那么变量“answer”被设置为 6(这是由 Lotus Notes 应用程序自动设置的默认值)。
如果所选日期处在将来,或者用户对上述问题回答 Yes以创建处在过去的记录,那么将出现一个新的约会表单。下面的例程只有在用户双击一个日程表日期时才会执行。(或者,用户可以选择本节后面描述的 NewAppointment 按钮,或选择 Create - Appointment 菜单选项。)
Sub Regiondoubleclick(Source As Notesuiview)            Dim doc AsNotesDocument            Dim workspace As New NotesUIWorkspace           Dim uidoc As NotesUIDocument            Dim view As NotesView           Dim dateTime As New NotesDateTime( "" )            CalldateTime.SetNow            ''Display warning if selected date is in thepast.            If Source.CalendarDateTime < Cdat(dateTime.DateOnly) Then            answer% = Messagebox("Date inpast... Do you want to continue?", 292, "Continue?")            End If           ''Create the appointment if date is in the past and userclicked YES, or            ''create the appointment if date is in thefuture.            If (answer% = 6) Or (Source.CalendarDateTime >=Cdat (dateTime.DateOnly)) Then            Set view = Source.View           Set uidoc = workspace.ComposeDocument ( "", "", "Appt" )           Set doc = uidoc.Document            doc.StartDate =Source.CalendarDateTime            End If            End Sub            
您可能想考虑将这段代码添加到任何包含一个日程表视图的应用程序中。为此只需将 Appt 改为适当的表单名。这样可以使应用程序更具用户友好性,并增加易用性。
为视图创建动作按钮
为创建允许用户建立新约会的按钮,选择 Create - Action - Actions。将按钮标题设为 New Appointment,并在 programmer’s pane 中输入以下公式:
REM "Create new calendar events";
@PostedCommand([Compose];"":"Appt")

为创建允许用户跳到当前日程表日期的按钮,选择 Create - Action - Actions。将按钮标题设为 Today,并在 programmer’s pane 中输入以下公式:
REM "Jump to today’s calendar
date";
@Command([CalendarGoTo];@Date(@Now));

保存并关闭视图。
恭喜,您已经完成了这个日程表应用程序!
结束语
在本文中,我们讨论了一个简单的单文档日程表的组成部分,以及重复事件的组成部分。我们还提供了关于如何创建一个简单的日程表应用程序的说明。希望本文对您有所帮助。请告诉我们您的想法,并为将来关于 Lotus Notes 和 Domino 的文章建议其他的话题。

posted @ 2008-12-04 22:23  hannover  阅读(1241)  评论(0编辑  收藏  举报