Introduction
There are many reasons you might want to write a program whose inputs (and
sometimes, outputs) are Notes design elements. This article presents the
basic techniques for doing this, and discusses the limitations. The examples
all use LotusScript, but the same techniques can be done using Notes' Java
API, if you prefer.
Example applications for these techniques
might be:
- Update view selection formula to change
over time (to avoid use of @Today in a view).
- Perform automated quality checks on
Notes/Domino designs, e.g.:
- find all editable fields that
have no field help.
- determine which forms, subforms and
pages contain a particular word in their static text (see Resources)
- automatically find formulas that could
be optimized (because they use the same @DbLookup twice, for instance).
- Change the look of an application by
automatically updating a stylesheet based on selections in a setup form.
- Change the look of an application by
scanning forms, subforms and pages for text with certain formatting, and
changing them to different formatting.
- Increase productivity by automatically
creating design elements -- e.g.:
- Create a custom view based on user selection
input in a dialog, copying predefined columns from a model view.
- Create a view that includes all the
fields on a form, so that you just have to delete the ones you didn't want
(see Resources)
- Create an "email survey" form
based on user input of questions and answer lists (see Resources).
- Rescue design elements that have somehow
become corrupted.
- ...
This
article doesn't go into these specific tasks in detail -- some have been
discussed elsewhere. Here we cover the basic techniques to get you to the
point where you can do the simple things, and have a shot at figuring out
more complex tasks.
Anything that you can't do with LotusScript,
you can do with the Notes C++ API or C API. However, LotusScript
does a lot of the work for you in many cases, and it's easy to integrate
into an application so that it can be invoked from the Notes client as
needed.
General Considerations
Here are a few things you need to be aware of when working with design
elements.
Caching Issues
The Notes client maintains a cache of design elements; the first time you
access a design note, it's added to the cache, and as long as the application
remains open, when you make use of that design element the cached copy
will be used. When you edit a design element using Domino Designer, Designer
sends a signal to the Notes client to dump its cache of that design element,
so that you can see the changes immediately. However, when the changes
are made by an automated process, in general there is no way to notify
the client of the change, so the cached copy will continue to be used.
This is an obstacle to certain things we would like to be able to automate,
and it is to be hoped that at some point in the future a method will be
available to refresh the cache programmatically.
Meanwhile, you can deal with this in
the following ways:
- If you modify an Outline design element
(in verion 8.0 or later), the method NotesUIWorkspace.OutlineReload
can be used to update the cache and re-paint the outline if it is displayed
on screen at that time.
- Design notes with file attachments are
not cached. This is kind of a kludge, but if you attach a hidden file attachment
to your design element, you should be able to update it and have users
see the changes immediately. This works with forms, subforms, and pages,
since they have a rich-text body where you can attach something. As it
happens, though, every design element is a note, and any note can contain
any items, so it's possible in theory to add a file attachment to anything.
I don't know whether this would work to prevent caching of other design
element types; if you try it, please add a comment!
- Rename the design element also, and
refer to it by its new name or alias. This may require some refinement
to allow reference by an invariant alias while changing some other alias
that would force reloading. For instance, if it's a form, you might call
it "User Survey|Surveyxxx|Survey" (it has two aliases,
and in the first alias you replace xxx with a sequential number).
Then you compose the form using the Surveyxxx alias (which
is not in the cache, so the user sees the latest version), but when they
save the form, the value of the Form item is "Survey".
- Tell the user to close and reopen the
application. Note: The application is considered open if any window
to it is still open, including in Domino Designer or Administrator. In
Designer 8.5, you might have to close the Designer client entirely to make
it release the database (it might be sufficient to close the tabs into
the application and collapse it in the navigator).
- If you have other ingenious methods
of dealing with this limitation, please add a comment! Thanks.
Signatures
For security, when you edit a design element in Domino Designer, an electronic
signature is stored so that unauthorized changes to the design element
can be detected. The signature uses public-key encryption and involves
a checksum of the contents of the "signed items" in the note.
If you update a design element by the built-in classes (NotesView, NotesForm,
etc), or by editing in Designer, the electronic signature will automatically
be recalculated using the ID in use at that time. If you update the design
element in any other way, it's up to you to re-sign the note when you're
done (use the NotesDocument.Sign method).
Certain design elements -- image resources
for instance -- it doesn't matter whether they're signed because they can
contain no executable code. There's no security risk if someone modifies
them, so confirming their signatures would be a waste of time. In general,
though, you should make sure any signatures in design elements are up to
date whenever you modify them.
This is covered in more detail in sections
below.
Private Design Elements
There are two types of private design elements. "Server Private"
design elements are stored in the application NSF, just like any other
design element, and you can access their designs the same way you can a
regular, shared design element -- provided you have access to them. What
distinguishes a server private design element from shared, is covered in
more detail later.
"Desktop private" design elements
are stored in the user's desktop file. These are difficult to automate,
and in fact are outside the scope of this document. Someone might write
a separate article about how to access design elements in the desktop file.
In theory, any design element type can
be private, but generally, only views, folders and agents can easily be
created as private by users.
Similar Design Elements Types
A subform is really nothing but a form that can't be used on its own. Anything
we say about forms, can generally be applied to subforms also, with the
exception of features that are different between them (window title formula,
for instance). Likewise, a Page design element (not XPage) is nothing but
a form that can't have fields and can't be used to edit a document.
Views and folders are likewise similar,
and we'll often talk about views as shorthand for "views and folders."
There are several design elements that
are essentially just containers for a file. Whatever we might say about
File Resources, generally applies to Images, Stylesheets, Wiring Properties,
Composite Applications, XPages and Themes. Some of these types only store
XML files, but the format of the design element is not different.
The Design Element Classes
Because these classes are covered in the Domino Designer help files, we
won't describe them in detail here -- just draw your attention to the ones
that will be useful and add any caveats that you might not find in the
help.
Generally speaking, there's not a lot
you can do here that you can't do with DXL or in other ways; these classes
are just a lot easier to use, if whatever you want to do is supported.
So if we say you can't do something in one of the sections below, read
that as, you can't do it with this class, not that it's necessarily
impossible.
NotesDatabase
The database is not a design element, but it's the class you use as a starting
point to access the different design elements. The members of the NotesDatabase
class that are relevant to design programming:
- Forms property
- GetForm method: One drawback
to this method is that a design will often contain multiple forms with
the same name -- one for the Notes client and one for the web, for instance
-- and there's no way to control which one you will get. You would have
to iterate through the array returned by the Forms property to find the
right one.
- Views property
- GetView method: As with GetForm,
if there are duplicate names you can't predict which will be returned.
However, iterating through the Views property is generally not a
good idea, as will be explained in the section on NotesView, below.
- Agents property
- GetAgent method: See notes about
GetForm, above. Duplicate agent names are rarer, since there's no real
reason to have them.
- TemplateName and DesignTemplateName:
These are unfortunately read-only.
NotesView
and NotesViewColumn
The NotesView class represents information about a view or folder design
note, and also gives you access to the view index -- you can read data
from the rows, or get the documents.
One problem with NotesView is that when
you create the object -- or maybe when you first try to access any of its
properties or methods -- its index is automatically updated. For some views
in some databases, this can take a long time. Sometimes you just want information
about the view -- it's title, say, to see whether it's the view you're
searching for in the NotesDatabase.Views array. In that case, building
the index is a total waste of time. Not only is it slow, but if the view
is seldom used, its index could well have expired, so the view indexing
task on the server is not keeping it up to date. If you access the view
and build its index, you're using up a chunk of storage on the server and
adding work for the view indexer, which must now keep this view up to date
for the next 45 days (assuming the view has the default indexing settings),
even though nobody ever uses it.
That's why it's often better to use other
techniques, described in later sections, to access design information about
views. Unless you want to read view entries and documents from it, avoid
causing the index to build.
The main contents of a view design are:
- Options: some are available through
this class. The most useful is the SelectionFormula property, which lets
you programmatically adjust the view selection. This is useful for automatically
creating private views with customized selection formula, and for creating
date-based views that don't use @Today -- instead, the date can be hardcoded
into the selection formula and updated periodically by a scheduled agent,
for better performance.
- Columns: There's a Columns property
of NotesView that returns an array of NotesViewColumn objects. One useful
thing you can do with these, is copy them to a different view using NotesView.CopyColumn
method. This lets you put together customized views based on selections
from among a list of pre-programmed columns.
- Actions: Not available through this
class.
- Event code: Not available through this
class.
If you read data from a
view and try to match the elements of the Columns array with the ColumnValues
property of a NotesViewEntry or NotesDocument, you may find that there
are often fewer ColumnValues than there are columns. That's because columns
that return a constant value aren't stored in the view index and aren't
retrieved with ColumnValues. The Designer help also mentions "UI-only"
functions, listing @DocNumber as one example, but these values are also
constants. You might not think of some of these functions as returning
a constant, but what happens behind the scenes is that the functions actually
return a string containing special characters that the view display code
replaces with the correct value at runtime. It's done this way because
these values can change without the document changing. For instance, @DocNumber
might be 7 for a particular document in a give view, but two documents
are added above it, and now @DocNumber is 9 for the same document. Or,
the number might be different for two users at the same time because they
don't have read access to the same set of documents. So the actual number
can't be stored in the view index -- the formula just generates a placeholder
that says, in effect "insert number here".
There's no easy way to figure out which
columns contribute to the ColumnValues array and which do not. You would
have to parse the formula yourself to determine whether it returned a constant
value.
NotesForm
The NotesForm class represents a form or subform. You can get an object
of this class either using the GetForm method of NotesDatabase, or the
Forms property.
Probably the most useful property is
Fields, which returns you an array of the names of fields on the form.
This class doesn't provide any way to get more information about the fields,
however, such as their datatype or whether they're editable.
There doesn't appear to be any way to
use a NotesForm to get access to a Page design element (though, as mentioned
above, they are otherwise similar).
NotesAgent
You can automatically enable profiling for an agent, and you can retrieve
the document with the profiling results after it runs. It would be nice
to have a way to adjust the agent's schedule and selection criteria from
here, but that's not supported.
NotesOutline and NotesOutlineEntry
The NotesOutline class represents an Outline design element. By using this
and the NotesOutlineEntry class, it's possible to create or manipulate
outlines.
Besides their use for navigation in applications,
outlines are also used internally to represent toolbars and bookmarks.
The outline entries in these special outlines use a special format, so
you can't use some of the properties that you might think would be useful
in these cases. For instance, you can't use NotesOutlineEntry.Formula to
access the formula of a toolbar icon. However, you can copy outline entries,
even these special ones, from one outline to another using the CreateEntryFrom
method of NotesOutline.
Once you have updated an outline, if
it's visible on the user's screen, you can force it to update using the
method NotesUIDatabase.OutlineRefresh. This is the only design element
for which we have the ability to update the client's design element cache.
Internals of Design Elements
To do more with design elements than
the above classes will allow, you must understand how design elements are
stored in a Notes application.
Every design element and every document
in an NSF or NTF file is stored in the same way, as a "note."
A note is a collection of "items" with some header information
(e.g. when was it last modified). Each item has a name, datatype, value,
and potentially some flags (for instance, one of the flags says whether
the item is a Readers list).
With the exception of file attachments
and OLE objects, all information about a design element is stored in the
items of the design note and in the note header.
It's instructive to highlight a design
element in the design list in Domino Designer and examine its properties,
where you can see the values of the items. Figure 1 shows an example, where
we can see the $Title item contains a two-element list whose values are
"Response" and "Response". Prior to version 8.5, this
information would be displayed in the "fields" tab of the design
element infobox (Figure 2).
Figure 1: Properties of a design
element, showing item values (from Designer version 8.5)

Figure 2: Properties of a design element, showing item values (pre-8.5)

Note Class
The "note class" is part of the note header. There are several
different note classes, e.g. "document" (a regular document,
profile document, or other special document), "form" (a Form
design element or related design element), "filter" (an agent
or similar), "view", and several
others. The note class distinguishes
a design element from a data note, and some types of design elements from
others. Some types of design elements have the same note class (form and
subform are both "form" class, for instance) and are told apart
by their $Flags item (more about this later).
Unfortunately, the note class is not
available through the NotesDocument properties.
Common Design Element Data Items
Each design element type stores information in items with specific names.
Some item names are only used for specific types of design elements, but
some apply to all design element types. Here's a list of some common items
that apply to all or many design elements.
| $TITLE
| The name and alias(es) of
the design element. Normally this is a multivalue item with the name as
the first item and each alias in a subsequent item. However, in some cases
the value will be a string where the name and alias are separated by a
vertical bar, usually with spaces around it, e.g. "Submit Grades |
GrSubmit"
|
| $Flags
| A string where each character has a
meaning as regards a property of the design element. See separate section
below about this item.
|
| $LANGUAGE
| In a multilingual application, a string
giving the language of this design element, e.g. "en" for English.
|
| $Body
| In form-based design elements, this
is the content of the form; fields, buttons, static text and so on.
|
| $DesignerVersion
| The version of Domino Designer used
to edit the design element. In case it has been edited with multiple versions,
this will retain the number of the highest version that has ever saved
the design element.
|
| $$ScriptName
| For design elements that have design
element level event code (e.g. Querysave on a Form) this string is used
by the LotusScript engine to locate the right object module. This item
is set when the event scripts are compiled, either by editing the design
element or by "recompile all". Generally its value is the name
or last alias of the design element, but it may be different if the design
element has been renamed from the design list or in some other way besides
editing the design element.
|
| $FileData
| For "resource type" design
elements, this is the contents of the file. This is used for file resources,
image resources, stylesheets, composite applications -- basically anything
where the main purpose of the design element is to store a file or some
XML data. The file data is stored in a binary record format that breaks
it into chunks each with a header, so you shouldn't expect to just be able
to plop the bytes into a file and get the original file data. It has to
be interpreted by the NSF subroutines.
|
| $Class
| If the design element inherits its design
from a template (individually), this is the name of the template.
|
| $xxx_O
| LotusScript object code for the script
source stored in item $xxx. The data in this item is binary, and
not very intelligible for humans.
|
| $Readers
| If the design element is restricted
to certain users (such as a view with a Readers list), this is the Readers
item that contains the list of who has access to it. This has the "Readers"
item flag set (Field Flags include "READ-ACCESS").
|
| $Authors
| This item is created in "server
private" design elements. It serves a dual purpose -- to identify
who is the owner of the design element, and to let them edit it even though
they might not be Designers in the application's ACL. This item has
the Authors item flag set (Field Flags include "READ/WRITE-ACCESS").
So an Authors item in a design element works just like an Authors item
in a document -- the user can make changes to it with just Author access
to the application.
|
$UpdatedBy
$Revisions
$Signature
| Same as for regular documents. |
There are many other item names which
are specific to one or a few types of design element. If you're unsure,
it helps to manually edit the design element and see what effect this has
on the item values, to find out where and how certain design information
is stored.
In cases where it's not clear how a certain
property is represented, you can always copy down information from the
items, change that property, and then compare the items before and after.
The file "stdnames.h" contains definitions of these names and
sometimes comments about how they're used (see Resources)
The $Flags Item
Many properties of design elements are encoded in the $Flags item. For
instance, a design element that's hidden from web users contains the character
"w" in $Flags. This item is also used to distinguish between
design elements of the same note class but different types. For instance,
"U" means the design element is a subform (assuming its note
class is "Form").
To find out the meanings of the different
characters, refer to the file "stdnames.h" (see Resources)
A few of the more important characters
that apply to all types of design elements:
| "P"
| Protect this element from
design refresh/replace.
|
| "V"
| A "server private" design
element.
|
| "w"
| Hide from web browsers.
|
| "n"
| Hide from Notes clients.
|
| "d"
| The default design note for its class
(default form, default view)
|
| "Y"
| Hide from menus.
|
| "3" - "9"
| Hide from version 3 and earlier, 4 and
earlier, etc. |
Binary-Formatted Items
Much of the most useful information in design elements is stored in binary
form within items. Generally speaking, you're not going to be able to make
much sense of this data without the Notes APIs or client to help you. These
items are generally formatted as "Composite Data Records," (CD
for short). Each record begins with a few bytes that identify the code
for the record type and a length. These are formatted so that even if you
don't recognize the record type, there's a standard way to determine the
length. This lets the client code skip over records of a type it doesn't
support. This is helpful in providing backwards compatibility, allowing
earlier versions of Notes to make use of design elements edited by later
versions, while skipping over information having to do with new features.
However, there are some cases where you
can do something useful with the binary-formatted data, without having
to parse it. Sometimes it makes sense to delete an item from the design
note. For instance, there's a tool to remove compiled LotusScript code
from forms and views, which unnecessarily duplicates the code in shared
actions. This is done by determining which actions are shared (by examining
the DXL, about which more later) and removing the corresponding $$ScriptObj_x
items from the note.
Sometimes, you may also want to copy
items from one design note to another. If you can figure out which items
represent the data on an action bar, for instance, you can copy an action
bar and all the actions from one view to another automatically, together
with all the action bar formatting options such as background color and
button height.
The Form Body
The $Body item contains the body of a form design element. One useful fact
about this item, is that it's a rich text item, just like the body of a
document, and you can use the Notes rich text classes (NotesRichTextItem,
NotesRichTextRange, etcetera) to read and update it. There are no entities
in the rich text classes corresponding to fields, buttons, URL links, and
many other things you can find on forms, but you can manipulate static
text and text styles, which is often useful, and you can work with tables
to a limited extent.
Like other binary-formatted items, rich
text consists of CD records. Unlike those other binary formats, though,
some interpretation of the contents is possible with the built-in classes.
LotusScript - Source and Object
LotusScript source code is stored as "straight text" in items
of the design note. There may be several separate items of source code.
For instance, on a form, there's an item that represents the source code
for the (Globals) section, another for the form event, and for each field
that has LotusScript event code (such as an Entering event).
For buttons and other action hotspots
embedded in the rich text, there is no separate item for source code storage.
The LotusScript code in this case is embedded in the CD records of the
rich text.
The source code for actions is stored
in the binary records $ACTIONS and $V5ACTIONS.
When you save a design element in Designer,
the LotusScript source is compiled (not necessarily all of it, however
-- modules you haven't edited won't be). The compiled "object"
code is stored in items whose names end with "_O" (letter O).
The exception is actions, whose object code is stored in items named $SCRIPTOBJ_#
(with # replaced by a number corresponding to the numerical position of
the action in the list of actions).
Signatures
If you modify a design element by accessing its items directly, and any
of the items you change are included in the electronic signature, you've
invalidated the signature. In that case, generally, you need to update
the signature or the design element will be unusable. You can only sign
design elements (or any note for that matter) using the ID that's running
the code.
Pay attention to which items in a note
are signed. You can see this in the design note properties (Figures 1 and
2). Certain items are not signed because we need to be able to modify them
without invalidating the signature -- whether an agent is enabled to run,
for instance. If you are only modifying unsigned items, it's probably better
to not update the signature, unless you're using an ID you know
is privileged in your end users' ECLs.
The Icon Note
Each application contains one special design note which is used to store
the database icon and also many of the database-level properties. The $Flags
item in this note encodes many of these properties; others are stored in
their own items.
You can quickly locate the icon note
by its special noteID ( db.GetDocumentByID("FFFF0010") ). This
ID isn't officially documented by IBM that I know of, and I don't guarantee
that it'll never change, but it seems unlikely at this point that it would,
as some of IBM's own code depends on this. If you want to be extra safe,
use the NotesNoteCollection.SelectIcon property to build a collection containing
just that note; however, this is not as efficient. See Resources for documentation
of special note IDs.
Private Design Elements
As noted above, a "server private" design element has a $Authors
item that both designates the owner and gives them access to edit it. Additionally,
the $Flags item contains the character "V".
I'm not sure whether, if you just remove
the Authors flag from the $Authors item, you can produce a design element
that's private but can't be edited by the owner. If you know the answer,
please post a comment.
Stored Forms
There is very seldom a good reason to use stored forms.
Several of the items from the Form design
note are copied into the document, including but not limited to $Body,
$ACTIONS and $V5ACTIONS, and everything containing LotusScript object code.
In effect., everything that makes up the form design, plus everything
in the document.
If you want to convert a stored form
document to a regular document, there's code to do this in the Domino Designer
help document titled "Examples: RemoveItem method". This code
is sufficient to make the document behave like a normal document; however,
it might be leaving behind some $Items that you could delete to save storage.
Check the document properties to see whether you missed anything.
Shared Actions
Shared actions are unlike other shared design elements in that they are
all stored in a single design note. You only see multiple Shared Action
design notes in multilingual applications, in which case they should contain
the same set of actions in different languages.
Each shared action has a numeric ID which
is assigned at the time the action is created. When you include the action
in the action bar of form or view, the form or view contains a reference
to the shared action, and also a copy of the action. At runtime,
the client will first try to locate the action information in the shared
action note using the reference number; if not found, the copy may be used.
When you copy a design element from one
application to another, if that design element contains references to shared
actions, the shared actions are not copied automatically along with the
referencing design element. This can cause problems if the application
into which the design element is pasted also contains shared actions. Since
the reference IDs of these actions may duplicate those of the shared actions
in the original application, the pasted design element will now be referencing
different actions than those that it originally referenced.
Shared View Columns
Shared view columns aren't shared in the same sense as shared fields and
actions. They aren't referenced at runtime as you're using the view; they
are simply flagged with a shared column ID which is used during editing.
When you save a shared column, Domino Designer finds the views that contain
that column and update them.
One problem you might run into: views'
copies of shared columns can only be updated if the person editing the
shared column has access to those views. Since view access control lists
apply to all users, even Managers, it's possible they may not be able to
update all views.
Also, the function to update views with
the new column design, is part of the Domino Designer user interface. If
you modify a Shared Column in some other way, for instance by importing
DXL or accessing its items directly through a NotesDocument, the referencing
views will not be automatically updated. There's no easy way to automate
this.
Accessing Design Elements Using NotesDocument
With the information in the above section, you should be able to use the
properties and methods of NotesDocument, NotesItem, and NotesRichTextItem,
to do some useful things with design elements. The basis of this technique
is the fact that any note, including a design note, can be manipulated
by accessing it with the NotesDocument class. To do this, you start with
the note ID or UNID of the design note, and use NotesDatabase.GetDocumentByID
or GetDocumentByUNID. To get the note ID or UNID, the following techniques
may be useful:
- NotesNoteCollection class lets you build
collections of note IDs of design elements. The SelectXxx properties
of the class let you narrow down the type of design element you want to
retrieve, and the SelectionFormula property is useful for homing in further
on design elements of that type with specific properties, by testing the
values of the items in the design note. For instance, to find design elements
with a name or alias of "Report", you might use the selection
formula $TITLE = "Report". Testing the $Flags item
in the selection is also occasionally useful (use @Contains here).
- If the design element is a view or folder,
the NotesView.UniversalID property lets you retrieve the UNID.
- Using a technique described in the Resources
section, it's possible to programmatically modify a Notes view to display
design elements instead of (or in addition to) documents. This lets you
access the design elements directly from the view using GetNextDocument,
or via the NotesViewEntry object.
The
NotesNoteCollection technique is the most generally useful. That class
hasn't kept pace with the several design element types added in versions
8 and 8.5, but you can retrieve every type of design element using a combination
of selection criteria, including tests of the $Flags. The
SetSelection
function in Listing 2, shows how to set a NotesNoteCollection to retrieve
all the design elements of a specified type, for all the design elements
that exist as of this writing.
If a future version updates NotesNoteCollection
class to include specific logic to select some of these new design element
types, some of the options in the SetSelection function may quit working.
That's because many of them rely on the "SelectMisc..." properties,
which return lists of design elements of a given note class, whose $Flags
values don't correspond to a type that NotesNoteCollection recognizes.
If the class is updated to recognize additional design element types,
those might be removed from the subset of elements returned by "misc"
collections.
Once you have the NotesDocument, you
can access the items using the NotesItem and NotesRichTextItem classes
(the latter for the $Body item of a form). You can retrieve items for other
binary types besides rich text, and they may be returned either as a NotesItem
or a NotesRichTextItem, but in either case, you aren't going to be able
to get any useful information about the contents from that. Even with such
items, though, it's sometimes useful to be able to:
- tell that they exist and how large they
are.
- delete them (using NotesItem.Remove
method, for example).
- copy them from one design note to another
(using NotesItem.CopyItemToDocument method), after deleting any item with
the same name that you want to replace.
As
mentioned elsewhere in this document, if you make any change to signed
items in the design note, you must explicitly call the NotesDocument.Sign
method to update the electronic signature; otherwise, users will receive
ECL warnings and may be unable to use the design element. Take care to
activate the SIGN flag on any items you create, that are generally signed
in design notes of that type. The signature checker in the client tests
to make sure the right items are signed, so if you replace a signed value
with a new unsigned value, the client may throw an error at runtime even
if the signature is technically valid.
Accessing Design Elements with DXL
The third major method of accessing design elements, is by way of DXL (Domino
XML). Every design element (with some exceptions which IBM is treating
as bugs) can be exported into an XML description, which you can then manipulate
and re-import.
This technique is often useful in combination
with other techniques described here. For instance, IBM has a tool used
internally that uses DXL to export design elements to get information about
their action bars, and then uses the NotesDocument technique of the previous
section to remove $SCRIPTOBJ objects that are unneeded (there used to be
a bug that failed to delete them when the actions were moved or deleted).
The output of the DXL exporter (NotesDXLExporter
class) can be directed into an XML parser object, such as the NotesDOMParser,
where it can be examined or translated into another format. The NotesDXLImporter
can be connected to a source of XML data (such as the output of a NotesDOMParser)
and used to create or update design elements.
"Note Format" versus "Descriptive
Format"
Some design elements offer you a choice of how they are rendered into DXL.
The descriptive format, which is the default, is relatively easy to interpret;
when you look at the DXL description of an agent, for instance, you might
see:
A person can look at this and stand a
fair chance of figuring out what they would see in the properties infobox
if they opened the design element in Domino Designer.
The "note format", on the other
hand, just lists the items in the note and their contents. If the item
is binary, it's included verbatim using base64 encoding. Someone reading
this XML output doesn't get any assistance in figuring out when the agent
runs -- that's part of a binary item and you can't even pick out the strings
from it to see the server name. The contents of $Flags are just reported
-- not explained. In the note format, only rich text CD records are interpreted
into a readable form; everything else is "raw."
Some design elements don't support a
descriptive format (mostly resource elements at this point). In some cases,
though, it make make sense to use the note format deliberately by setting
the property NotesDXLExporter.ForceNoteFormat. The problem with the descriptive
format is that it doesn't necessarily report every option (at all, or correctly),
so if you export and import it you may be losing information.
The note format, on the other hand, is
round-trippable without loss of information (with the possible exception
of some of the more esoteric/newer options of rich text entities). It's
a better choice if you want to archive a checkpoint copy of the design
element. If you want to manipulate the DXL and re-import it, however, the
descriptive format is far easier to work with in most cases.
Signatures
Design elements created via DXL import are unsigned. This is deliberately
done as a security measure. Your code must explicitly sign them using NotesDocument.Sign.
Listing 1 shows how to import DXL, then find all the imported design elements
and update their signatures.
Resources
The file stdnames.h, part of the Notes C API toolkit, contains symbolic
names for all the $Flags characters and many other special values used
in design elements. You can download this toolkit from the Lotus
Downloads page of IBM developerWorks.
"Make
a Notes view list design elements"
wiki article.
Lotusphere
2008 - AD307 Session examples
from Rocky Oliver, includes an application to patch together Form design
elements containing surveys with questions created by end-users. It's an
example of creating complex design elements, without any use of Domino
Designer.
This sample database from The View contains
a
LotusScript agent to automatically create a view with all the fields from
any form.
Here's a tool to search
a database (or all databases) for design elements
that meet specified search criteria, including strings in source code and
static text on forms.
For a glimpse of the future of design
element programming, the Secret
Agent project on openntf shows
how to access design information from a sidebar plugin.
Special
note IDs to find the icon
note and other design documents.
See comments for additional resources
suggested by our readers!
Sample Code
Listing 1: Importing DXL and Signing the
Imported Design Elements
...
Set dxli = session.CreateDXLImporter(stream, db)
dxli.DesignImportOption = ...
...
dxli.Process
' if import succeeded, sign new/updated design notes.
If dxli.ImportedNoteCount Then
Dim strID$
strID = dxli.GetFirstImportedNoteId()
Do Until strID = ""
Dim docDesign As
NotesDocument
Set docDesign =
db.GetDocumentByID(strID)
Call docDesign.Sign()
Call docDesign.Save(True,
False, True)
strID = dxli.GetNextImportedNoteId(strID)
Loop
End If
Listing 2: Setting a NotesNoteCollection to Locate Specific Design
Element Types
Sub SetSelection(ncoll As NotesNoteCollection, Byval strDesignType
As String)
' Given the name of a design element type,
e.g. "Form", and a note collection,
' sets the note collection to select design
elements of that type.
' Note: detecting certain design elements requires
testing $Flags. This means
' it doesn't always work to call SetSelection
twice with the same collection but different
' design element names. For instance, if you
say you want forms and file resources,
' you will only find no forms because their
$Flag items never contain the character 'g'.
' Written by Andre Guirard, IBM -- last updated
June 2007.
Select Case Lcase(strDesignType)
Case {action}
ncoll.SelectActions
= True
Case {agent}
ncoll.SelectAgents
= True
Case {applet}
ncoll.SelectAllDesignElements
True
ncoll.SelectionFormula
= {@Contains($Flags; "@")}
' not very efficient,
but seems to be the only thing that works. Sorry.
Case {databasescript},
{database script}
ncoll.SelectDatabaseScript
= True
Case {column}
ncoll.SelectMiscIndexElements
= True
ncoll.SelectionFormula
= {@Contains($Flags; "^")}
Case {data
connection}
ncoll.SelectDataConnections
= True
Case {file},
{file resource}
ncoll.SelectMiscFormatElements
= True
ncoll.SelectionFormula
= |@Contains($Flags; "g") & !@Matches($Flags; "*{~K[];`}*")|
Case {hidden
file} ' extra file-resource type elements
created when XPages are built.
ncoll.SelectMiscFormatElements
= True
ncoll.SelectionFormula
= |@Contains($Flags; "g") & @Contains($Flags; "~")
& !@Matches($Flags; "*{~K[];`}*")|
Case {custom
control}
ncoll.SelectMiscFormatElements
= True
ncoll.SelectionFormula
= {@Contains($Flags; "g") & @Contains($Flags; ";")}
Case {theme}
ncoll.SelectMiscFormatElements
= True
ncoll.SelectionFormula
= {@Contains($Flags; "g") & @Contains($Flags; "`")}
Case {xpage}
ncoll.SelectMiscFormatElements
= True
ncoll.SelectionFormula
= {@Contains($Flags; "g") & @Contains($Flags; "K")}
Case {folder}
ncoll.SelectFolders
= True
Case {form}
ncoll.SelectForms
= True
Case {frameset}
ncoll.SelectFrameSets
= True
Case {navigator}
ncoll.SelectNavigators
= True
Case {outline}
ncoll.SelectOutlines
= True
Case {page}
ncoll.SelectPages
= True
Case {profile}
ncoll.SelectProfiles
= True
Case {script
library}, {library} ' including web service
consumers
ncoll.SelectScriptLibraries
= True
Case {libraryonly}
' not including web service consumers
ncoll.SelectScriptLibraries
= True
ncoll.SelectionFormula
= {!@Contains($FlagsExt; "W")}
Case {web
service consumer}
ncoll.SelectScriptLibraries
= True
ncoll.SelectionFormula
= {@Contains($FlagsExt; "W")}
Case {web
service}, {web
service provider}
ncoll.SelectMiscCodeElements
= True
ncoll.SelectionFormula
= |@Contains($Flags; "{")|
Case {sharedfield},
{shared field}
ncoll.SelectSharedFields
= True
Case {subform}
ncoll.SelectSubforms
= True
Case {view}
ncoll.SelectViews
= True
Case {wiring},
{wiring properties}
ncoll.SelectMiscFormatElements
= True
ncoll.SelectionFormula
= {@Contains($Flags; ":")}
Case {composite
application}, {ca xml}
ncoll.SelectMiscFormatElements
= True
ncoll.SelectionFormula
= {@Contains($Flags; "|")}
Case {image}
ncoll.SelectImageResources
= True
Case {stylesheet}
ncoll.SelectStyleSheetResources
= True
Case {db2
access view}
ncoll.SelectMiscFormatElements
= True
ncoll.SelectionFormula
= {@Contains($Flags; "z")}
Case {icon}
ncoll.SelectIcon
= True
End Select
End Sub