GNUe Forms: A Developer's Introduction
A Guide to Programming with GNUe Forms
Version 0.5.1
Written by Jason Cater, your tour guide
Copyright © 2000-2003 Free Software Foundation.
Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in the section entitled GNU Free Documentation License.
Table of Contents
Introduction 4
Structuring the Database 4
Designing the Form 4
Planning for Security 4
Basic Concepts 5
Datasources 5
Blocks and Fields 5
Pages and Visual Elements 5
Triggers 5
Designing for Multiple Interfaces 5
Designing for Multiple Databases 5
Creating your First Form 6
Preliminary Steps 6
Creating the Empty Form 7
Creating the Datasources 7
Creating the Logic Structure 8
Creating the Layout 9
Running the Form 11
Where To Go Next 11
Understanding Datasources 12
Table-Bound Datasources 12
Static Datasources 12
Defining Conditions 13
Linking Datasources via Master/Detail 13
Advanced Relationships 13
Understanding Events and Triggers 14
Form's Event Model 14
Named Triggers verses Embedded Triggers 14
Form-level Triggers 14
Block-level Triggers 15
Field-level Triggers 18
Page-level Triggers 19
Entry-level Triggers 19
Button-Level Triggers 19
Working with Fields 21
Typecasting Fields 21
Default Values 21
Formatting Fields with Masks 21
Dropdown Fields 24
Check boxes 24
A Brief Introduction to Python 25
The Basics 25
Variables and Expressions 25
Control Structures 25
Tuples, Lists, and Dictionaries... oh, my! 26
Exploring Trigger Namespaces 27
Introduction 27
Object Heirarchy 28
Fields and Entries 28
Blocks 28
Datasources 28
Form 29
Creating and Using Libraries 30
Overview 30
Integration with GNUe Tools 31
Running Reports from Forms 31
Running Forms from Navigator 31
Advanced Topics 32
Runtime Parameters 32
External Python Modules 33
Designing for Multiple Interfaces 33
Trigger Recipes 35
Timestamping a Record prior to a Commit 35
Stamping a Record with User's Login prior to a Commit 35
Auto-Populating an Entry from a Sequence 36
Appendix A: Trigger Hierarchy 37
Appendix B: Form Elements 38
Form Tags 38
Connection Tags 38
Datasource Tags 39
Dialog Tags 43
Layout Tags 43
Logic Tags 46
Menu Tags 48
Options Tags 49
Parameter Tags 50
Trigger Tags 50
Import Tags 51
Appendix C: Form Objects 56
Form 56
Datasource 59
Block 60
Entry 62
Appendix D: Data Objects 65
Result Set 65
Record Set 65
Appendix E: Sample Librarian Schema 66
Appendix F: Glossary 67
Appendix G: GNU Free Documentation License 68
Introduction
This section briefly introduces the process of designing an application using GNUe Forms. blah, blah, blah...
Before designing an application for Forms, the developer should be somewhat familiar with a few key concepts:
Database Design - This guide does not delve into database design. It is assumed the developer can either create his own tables, or has an existing set of tables to work with.
Python Scripting - GNUe uses Python for scripting/event support. Any level of serious applications programming will likely require some level of Python. There is a short section entitled "A Brief Introduction to Python" in this guide that can serve as a starting point. The average programmer can likely learn enough simply by trying out the examples in this guide.
XML - GNUe extensively uses XML for its internal storage format. While it is possible to create GNUe applications via Designer without interacting with the XML formats, a good, solid understanding of XML basics would definitely be useful.
Structuring the Database
TODO
Designing the Form
TODO
Planning for Security
TODO
Basic Concepts
TODO
Datasources
Since GNUe Forms was designed from the ground up to manipulate database data, it must have some way to tie the graphical elements to database tables. This is where a datasource comes into play.
A datasource provides a link to a database table or some similar data store.
[TODO: Expand]
Datasources are portable from one GNUe tool to another. A datasource that is usable in forms should also be usable in a report.
Blocks and Fields
A datasource provides a link to a table, but Forms needs more information than a simple reference to meaningfully interface with an end user. A block is the first step to making datasources suitable for such user interaction. At its most basic level, a block contains instructions on how Forms should interact with a datasource.
Any datasources that are to interact with a user must have a single corresponding block. Datasources that are only used internally and not for displaying data will not normally have an associated block, although the developer may choose to do so.
A field is ....
Pages and Visual Elements
TODO
Layout Management
TODO
Triggers
TODO
Designing for Multiple Interfaces
TODO
Designing for Multiple Databases
TODO
Creating your First Form
In this chapter, we will create our first full-featured form -- a postal code lookup table. [TODO: Expand]
[TODO: Replace the postal code example with librarian]
We are going to create a form that looks something like:
01234567890123456789012345678901234567890
|---------+---------+---------+---------|
Zip Code: [___]
City Name: [_______________________]
State: [__]
The ruler is simply for our layout reference. We will come back to it later.
[TODO: expand]
Preliminary Steps
[TODO: Intro]
The following two steps may need to be performed by your database or systems administrator.
First, we need to create a test table. Using your database of choice, create a table named zipcodes, with three appropriately sized fields, zipcode, city, and state. In PostgreSQL, SAP-DB, and others, the following statement will work:
create table zipcodes (
zipcode varchar(5),
city varchar(30),
state varchar(2) );
For other databases, create a similarly structured table.
Next, if you have not done so yet, setup your connections.conf file to point to your database. Our examples will use a connection called tutorial. An example entry:
[tutorial]
comment = Tutorial Database
provider = psycopg
host = localhost
dbname = mydb
Of course, your entry will probably look different. This example is using the PostgreSQL psycopg driver, connecting to a database named mydb running on the local machine. See the Forms Installation Guide for information on the location and syntax of this file.
If you already have a connection for the database you will be using, simply add an alias = tutorial line to the appropriate section. Example:
[dev]
comment = Foobar Development
provider = psycopg
host = dbserver
dbname = mydb
alias = tutorial
Creating the Empty Form
By default, GNUe Designer will start up with an empty form. You may also create a new form by selecting File | New | Form.
[TODO: change the title of the form]
Creating the Datasource
Our sample form will use a single table - zipcodes. To access this table in Forms, we need to associate it with a datasource. We will call this datasource MyDS.
From the menu, select Edit | Insert | Datasource... to run the datasource wizard. The first step of the datasource wizard asks for your connection. Select tutorial. This is the connection we setup in the first part of this section. Click Next... You may be asked to log in. Provide a valid database username and password.
It will need three attributes: name, connection, and table.
name: All referencable objects in GNUe need a unique name. We will name our datasource MyDS.
connection: This is the name of the connection we set up in the first part of this section. If you used our example entry, then this is called tutorial.
table: This should be the name of the table we will be referencing. Once again, if you used our example table create script, this will be zipcodes.
Creating the Logic Structure
[TODO: Explain the logic section and tag]
Blocks are the display equivalent of datasources. Since we are working with a single datasource, we will have a corresponding single block. Since this is tied to the zipcodes table, we will call this block ZipBlock.
Block-specific attributes:
name: Set this to a unique name that we will later refer back to.
datasource: The name of the datasource that this block is tied back to. If no datasource is specified, then the block will be considered an unbound block.
Field-specific attributes:
name: Set this to a unique name that we will later refer back to.
field: Set this to the name of the corresponding field in the database.
case: This can be set to any one of mixed, upper, or lower to force case convention. For example, if set to upper, then all lower case input characters will be converted to uppercase. Note that this only applies to data input from the user. Setting this field will not convert existing data that is queried. The default value is mixed.
.....
Creating the Layout
Forms contains its layout logic in units called pages. Only a single page is normally seen any given time by the end user. Our simple form will need one page. We will call it MyPage.
Given the layout grid we created earlier, we see that our form will be 40 characters wide and 7 lines high. For simplicity's sake, we are using a simple character based layout, identified as GNUe:Layout:Char. In the future, forms will support other layout styles.
Again, looking back at our earlier layout grid, we have three labels and three entries. Each label starts in column two and each entry starts in column 13. Each pair of label/entry skips a row, with the first pair being on row 1.
This gives us enough information to create our display layout.
Via GNUe Designer:
An empty form created by GNUe Designer automatically has a single, empty page. If we were to add more pages, this could be accomplished by selecting Edit | Insert | Page. However, this example uses a single page, so we do not need to do anything for this step.
[TODO]
Running the Form
TODO
[TODO: Insert pic of Win32 form]
[TODO: Insert pic of HTML form]
Where To Go Next
[TODO: Well, home *is* where the heart's at]
Understanding Datasources
A Datasource links data to our form. Usually, a datasource points to a table if using a relational database, or a data object if using an object database. A form can have several datasources if pulling data from multiple locations, or no datasources at all if the form does not reference outside data.
If a form does not have a datasource, a virtual datasource is created. The commit, rollback, and query functions do not serve a purpose against virtual datasources. This is particularly useful for action forms that simply cause actions to occur, but do not directly manipulate data.
Datasources can be linked to each other in a master/detail fashion via a foreign key. In essence, each time the master datasource changes, the detail datasource is automatically requeried to bring up records related to the master. See the section on master/detail relationships for more information.
Table-Bound Datasources
The most common datasource is one that is bound to an individual table or view.
Static Datasources
TODO
TODO
Defining Conditions
Form's datasources support conditions. Conditions place restrictions on the records returned by a datasource. For those familiar with SQL, a condition translates directly into a WHERE clause.
In this example, we are basically only allowing records from the reps table where the representative is either active (active = 'Y') or had sales this year.
Linking Datasources via Master/Detail
Quite often, you will want a second datasource's behavior to be tied to a primary datasource. If a new record is queried in the first datasource, all corresponding records in the second datasource should automatically appear. Likewise, creating a new record in the first datasource should clear out the second datasource and any subsequent new records in this second datasource will be automatically associated with the new primary record.
In GNUe, we call this relationship a Master/Detail relationship. It closely mirrors the concept of primary/foreign keys in relational databases.
Master/detail relationships have the following properties:
When a new record is created in the master datasource, the detail datasource will have no records.
When the master source is queried, a new set of records is queried in the child datasource for each record in the master source. This happens on an as-needed basis so as not to waste resources.
A master record cannot be deleted while detail records exist.
On posting, or saving, a detail record, its "foreign key" is automatically populated with the "primary key" of the master record.
Defining Master/Detail Datasources
There are no special attributes for a master datasource to indicate its role as master.
The detail datasource, on the other hand, has three special attributes that must be provided: master, masterlink, and detaillink.
master: This should be the name of the master datasource.
masterlink: This is the name of the field or fields in the master datasource that links it to the child datasource. If there are multiple fields, i.e., the master primary key is "composite", then masterlink should be a comma-separated list of field names.
detaillink: This is the name of the field or fields in the detail datasource that links it to the child datasource. If there are multiple fields, i.e., the master primary key is "composite", then detaillink should be a comma-separated list of field names with the order of the fields corresponding to the order provided in masterlink.
Master/Detail Considerations
TODO
Advanced Relationships
TODO
Master/Detail/Detail
TODO
Reverse Master/Detail
TODO
Understanding Events and Triggers
TODO
Form's Event Model
TODO
Named Triggers verses Embedded Triggers
TODO
Form-level Triggers
A Form-level trigger is defined as an object that is activated at the form-level and is defined as a child of the form object.
The following form level triggers are defined.
On-Startup
The On-Startup trigger is executed once during the lifetime of a Form's instance. This happens after all the objects have been initialized and initially populated.
Suggested uses for On-Startup:
Setting initial flags.
Marking variables or common functions/modules as:
On-Activate
The On-Activate trigger is executed each time a form or dialog is activated. For a normal form, the difference between On-Activate and On-Startup is very nominal. However, for dialog-style forms, the difference is more pronounced. On-Startup will only be executed once in the form's life, whereas On-Activate is called every time the dialog is instantiated and displayed.
For non-dialog forms, we recommend you use On-Startup.
Suggested used for On-Activate:
Useful for adjusting dialogs based upon parameters passed in by the calling form.
On-Exit
The On-Exit trigger is executed when either the user or a trigger requests that a form closes.
Suggested uses for On-Exit:
Wishing the user best of luck?
Pre-Commit
The Pre-Commit trigger is executed before a form-level commit occurs.
Suggested uses for Pre-Commit:
Perform form-level validation of data (??)
[ TODO: ??? ]
Post-Commit
The Post-Commit trigger is executed after a form-level commit occurs.
Suggested uses for Post-Commit:
[ TODO: ??? ]
Block-level Triggers
All block-level triggers are executed on a per-record basis. That is, a trigger would get executed once for every applicable record, not just once for the entire block.
Pre-Query
The Pre-Query trigger is executed before a query against the database occurs. This trigger is unique from all other triggers in that it is called while the form is in query mode -- ie., the same mode as selecting Data | Enter Query from the menu. This means that any field changes made by this trigger don't actually modify a record, but instead are used as query conditionals.
Suggested uses for a block-level Pre-Query trigger:
Adding custom conditions to a query that are more complex than can be represented by a field's queryDefault property.
Post-Query
The Post-Query trigger is executed after a query occurs on a record. A block-level Post-Query is executed once for each record that was loaded from a database. Post-Query is the counter-part to On-NewRecord in that one or the other should be executed for every displayed record.
NOTE: Post-Query is only fired as a record is loaded from the database. This implies that, with GNUe's caching system, if only 10 records are displayed on screen at a time out of a table of 100 records, then only the first 10 or so records will have Post-Query fired. It is guaranteed, however, that by the time a the user can see a loaded record or before another trigger can be fired against a loaded record, Post-Query has already been called. It is possible to get around this by, at some point [TODO: where?], calling block.lastRecord() and (optionally, if needed) block.firstRecord().
Suggested uses for a block-level Post-Query trigger:
Populating non-database (automaticall calculated) fields.
Resetting user-defined flags
Pre-Change
The Pre-Change trigger is executed before a record is initially modified -- i.e., when the first field of a record is set to a new value. At the time the Pre-Change record is called, the modified field will still contain the old value.
Suggested uses for a block-level Pre-Change trigger:
[TODO: a good example?]
Pre-Insert
The Pre-Insert trigger is executed before a commit occurs on a record that is pending an insertion. A block-level Pre-Insert is executed once for each inserted record and is fired prior to the Pre-Commit trigger.
Suggested uses for a block-level Pre-Insert trigger:
Stamping records with a creation date or created-by value
Setting a primary key's value
Setting other hidden, but pertinent, fields with default or pre-calculated values
Storing historical information in transaction tables
Pre-Update
The Pre-Update trigger is executed before a commit occurs on a record that is pending an update. A new or deleted record is not considered "updated" for the purpose of this trigger. A block-level Pre-Commit is executed once for each changed record and is fired prior to the Pre-Commit trigger.
Suggested uses for a block-level Pre-Update trigger:
Stamping records with a modification date or modified-by value
Setting hidden, but pertinent, fields with default or pre-calculated values
Storing historical information in transaction tables
Pre-Delete
The Pre-Delete trigger is executed before a commit occurs on a record that is pending a deletion. A block-level Pre-Commit is executed once for each record that has pending deletion. A block-level Pre-Delete fires prior to a Pre-Commit trigger.
Suggested uses for a block-level Pre-Delete trigger:
[TODO: a good example?]
Storing historical information in transaction tables
Pre-Commit
The Pre-Commit trigger is executed before a commit occurs on a record. A block-level Pre-Commit is executed once for each record that has pending changes, including new and deleted records. A block-level Pre-Commit fires prior to a Field's Pre-Commit trigger, but after the Pre-Insert, Pre-Update, and Pre-Delete triggers.
Suggested uses for a block-level Pre-Commit trigger:
Stamping modified records with a date or modified-by value
Setting hidden, but pertinent, fields with default or pre-calculated values
Storing historical information in transaction tables
Post-Commit
The Post-Commit trigger is executed after a commit occurs on a record. A block-level Post-Commit is executed once for each record that had pending changes, including new and deleted records. A block-level Post-Commit fires after a Field's Post-Commit trigger.
If a Post-Commit trigger modifies the values in a record, then the record will be, once again, pending changes. Typically a Post-Commit trigger would not modify any values and you could create an unsavable form.
Suggested uses for a block-level Post-Commit trigger:
Resetting user-defined flags or non-database fields.
On-NewRecord
The On-NewRecord trigger is executed when a record is initially created. This trigger is executed once for each new record at the time of creation in the form.
Suggested uses for a block-level On-NewRecord trigger:
Setting default values
Pre-FocusIn
The Pre-FocusIn trigger is executed as a new record is focused in a block. It is recommended that unless you have a specified understanding of the intention of forms, use Post-FocusIn instead of Pre-FocusIn as the latter trigger's behavior may change at some point to better reflect record focus.
Suggested uses for a block-level Pre-FocusIn trigger:
[ TODO: ??? ]
Post-FocusIn
The Post-FocusIn trigger is executed as a new record is focused in a block. This may be triggered by a user navigating to a different record or by creating a new record. The actual record change has occurred when this trigger is fired.
Suggested uses for a block-level Post-FocusIn trigger:
[ TODO: ??? ]
Pre-FocusOut
The Pre-FocusOut trigger is executed as a different record is about to be focused in a block. This may be triggered by a user navigating to a different record or by creating a new record. The actual record change has not occurred when this trigger is fired.
Suggested uses for a block-level Pre-FocusOut trigger:
[ TODO: ??? ]
Post-FocusOut
The Post-FocusOut trigger is executed as a new record is focused in a block. It is recommended that unless you have a specified understanding of the internals of forms, use Pre-FocusOut instead of Post-FocusOut as the latter trigger's behavior may change at some point to better reflect record focus.
Suggested uses for a block-level Post-FocusOut trigger:
[ TODO: ??? ]
Field-level Triggers
TODO
Pre-FocusIn
TODO
Post-FocusIn
TODO
Pre-FocusOut
TODOglimpse
Post-FocusOut
TODO
Post-Query
TODO
Pre-Modify
TODO
Pre-Insert
TODO
Pre-Update
TODO
Pre-Delete
TODO
Pre-Commit
TODO
Post-Commit
TODO
Pre-Change
TODO
Post-Change
TODO
Page-level Triggers
TODO
Pre-FocusIn
TODO
Post-FocusIn
TODO
Pre-FocusOut
TODO
Post-FocusOut
TODO
Entry-level Triggers
TODO
Pre-FocusIn
TODO
Post-FocusIn
TODO
Pre-FocusOut
TODO
Post-FocusOut
TODO
Button-Level Triggers
Buttons have a special relationship with triggers.
On-Action
This trigger is run when the user activates (e.g., clicks) a button.
Suggested uses for an On-Action trigger:
Perform a calculation
Navigate to another section of the form
Open another form
Pre-FocusIn
TODO
Post-FocusIn
TODO
Pre-FocusOut
TODO
Post-FocusOut
TODO
Post-Change
TODO
Working with Fields
TODO
Typecasting Fields
TODO
Default Values
TODO
Formatting Fields with Masks
[ NOTE: Format Masks are not yet completely functional! This section reflects the intended support ]
Forms supports two types of format masks: display masks and input masks. A display mask defines how the field data will be formatted for display. An input mask defines how the user will edit a field's value. Input mask elements are a subset of display mask elements -- in other words, all input masks can also be used as display masks, but not all display masks can be used as input masks.
Note: if first character of a format is '&', then rest of date defines a preset format (settable by developer? in gnue.conf or geas?).
e.g., in gnue.conf:
FormatDate_longdate = "A, b d, Y"
Then, in the client, the format string could be: &longdate
This allows reuse of common format masks throughout the application.
Formatting Numeric Fields
TODO
Formatting Date/Time Fields
Element
Input?
Description
\
Yes
Next character is a literal
a
Yes
Abbreviated weekday name (Sun..Sat)
A
Full weekday name (Sunday..Saturday)
b
Yes
Abbreviated month name (Jan..Dec)
B
Full month name (January..December)
c
Century (20,21)
d
Yes
Day of month, left padded with zeros (01..31)
D
Day of month, non-padded (1..31)
h
Yes
Hour (24-hour format), left padded with zeros (00..23)
H
Hour (24-hour format), non-padded (0..23)
g
Yes
Hour (12-hour format), left padded with zeros (01..12)
G
Hour (12-hour format), non-padded (1..12)
j
Yes
Day of year, left padded with zeros (001..366)
J
Day of year, non-padded (1..366)
m
Yes
Month, left padded with zeros (01..12)
M
Month, non-padded (1..12)
i
Yes
Minute, left padded with zeros (01..59)
I
Minute, non-padded (1..59)
p
Yes
am/pm designation (lowercase)
P
AM/PM designation (uppercase)
s
Yes
Seconds, left padded with zeros (00..59)
S
Seconds, non-padded (0..59)
u
Yes
Week number of year with Sunday as first day of week, left padded with zeros (01..52)
U
Week number of year with Sunday as first day of week, non-padded (1..52)
v
Yes
Week number of year with Monday as first day of week, left padded with zeros (01..52)
V
Week number of year with Monday as first day of week, non-padded (1..52)
w
Yes
Day of week with Sunday as first day of week (0=Sunday) (0..6)
W
Yes
Day of week with Monday as first day of week (0=Monday) (0..6)
y
Yes
Year (1900..2100)
Y
Yes
Year, using 2-digit notation (00..99) When used as an input mask, forms tries to reasonably guess the century. (TODO: Elaborate)
Predefined literals: "/-.:, "
Examples: 01/01/2001: "m/d/y" Friday, June 1, 2001: "A, b d, Y"
Formatting Text Fields
TODO
Dropdown Fields
TODO
Check boxes
TODO
A Brief Introduction to Python
While GNUe Forms will eventually support a plethora of scripting languages, the default, and best-supported, language will always be Python. Python is a ...........
If you do not know Python, don't worry! Python is one of the simplest languages to pick up. .............
Once multi-language support is added, the developer will be able to write triggers in Python, Perl, Ruby, Scheme, or possibly even Basic. .............
While Python is easy to learn, this section assumes that you know at least one programming language. It is beyond the scope of this guide to cover basic programming concepts. There are several excellent Python tutorials for those beginning programming available on the Web. Go to http://www.python.org/doc/ for a listing of available tutorials. They have docs for every stage of python programming, from new-to-programming to seasoned veteran.
The Basics
The first thing most people notice about Python is its reliance on whitespace for grouping.
Variables and Expressions
x = 1
Control Structures
if x == 1:
print "Yip"
for f in (1,2,3):
print f
for f in range(4):
print f
n = 1
while n < 10:
n += 1
Tuples, Lists, and Dictionaries... oh, my!
TODO
Exploring Trigger Namespaces
Introduction
TODO
Global Names
GNUe Forms supports the Python global construct, which can be used by the developer to define global variables and methods, or import modules globally. For example, assume the following code chunk is a form's On-Startup trigger:
##
## On-Startup [Form]
##
# We want to give our other triggers
# access to these three objects.
global math, myfunc, DEBUG
# We will use the math module a lot
# in our other triggers
import math
# A handy function
def myfunc(n1,n2):
return n1+n2
# Are we in DEBUG mode?
# Enquiring triggers want to know...
DEBUG = 1
# This is an example of a non-global name.
# Only our On-Startup trigger sees this.
test = 2
Because Forms executes On-Startup before any other triggers, all other triggers within this form can now see math, myfunc, and DEBUG.
For example, an On-Change trigger could now do:
##
## On-Change (MyEntry)
##
if DEBUG:
print "Starting value: %s" % self.get()
computed = myfunc(self.get(), 12)
AnotherEntry.set(math.floor(computed))
Note that if another trigger wanted to globally change the values of math, myfunc, or DEBUG, they would also have to use the global construct. The following section of code would only change DEBUG for this single execution of On-Change:
##
## On-Change (MyEntry)
##
DEBUG = 0
# ... other code ...
The other code in this example would see DEBUG as being 0, but once the trigger was completed, DEBUG would return to being 1 for all future triggers. Now, suppose the trigger had instead looked like:
##
## On-Change (MyEntry)
##
global DEBUG
DEBUG = 0
# ... other code ...
Now, this trigger and all future triggers will see DEBUG as 0.
Object Heirarchy
TODO
Fields and Entries
TODO
Blocks
TODO
Datasources
Datasource objects
The datasource objects, in addition to providing sensible methods for data access and manipulation, also act as python container objects whenever possible. For example, a recordset can behave as a python dictionary, and resultsets behave as tuples. Any container-related behavior will be discussed after the supported methods are detailed.
Datasource
ResultSet
RecordSet
Examples
TODO
resultset = MyDataSource.createResultSet({'id':1})
recordset = resultset.nextRecord()
if recordset:
DescrField.set(recordset['description'])
TODO
resultset = MyDataSource.createResultSet()
recordset = resultset.createRecord()
recordset['id'] = 1
recordset['description'] = 'Test Record'
recordset['amount'] = 10.00
TODO
resultset = MyDataSource.createResultSet({'id':1})
recordset = resultset.nextRecord()
# Delete the last record
recordset.deleteRecord()
TODO
# Query all records where amount is 5.00
resultset = MyDataSource.createResultSet({'amount':5})
for recordset in resultset:
recordset['queue'] = 'Y'
TODO
Form
Creating and Using Libraries
Overview
TODO
Integration with GNUe Tools
Running Reports from Forms
TODO
Running Forms from Navigator
TODO
Advanced Topics
This section describes advanced forms concepts. [TODO: expand]
Runtime Parameters
Forms supports runtime parameters that can be passed to a form instance at startup. Parameters are mainly useful for specifying conditions in datasources, but can also be accessed via triggers. This allows the perceived behavior of a form to be altered only by passing a parameter.
A good example is a form designed to service two divisions of a company. While you could offer an opening dialog that asks the user which division he wants to work on, an alternative is to modify his startup script to tell the form which division he works with. This especially works well when the worker only belongs in one division and will never need access to any others.
Note that in the above example, though, parameters are not a good substitute for access security. This example would strictly be for convenience, not security.
Parameters must be defined, with a default value, using the tag:
Once defined, parameters can be passed to forms in one of two ways. The first is via the command line. Parameters can be passed in the format parameter=value on the command line appearing after the name of the form. For example:
gnue-forms myform.gfd division=101
Alternately, if the form is being called from another form, the trigger would look like:
## Run "myform.gfd"
form.runForm( 'myform.gfd', { 'division' : 101 } )
That is, the parameters would be passed to runForm as a Python dictionary. Once passed to the form, parameters can be used in one of two ways: via trigger code or as a parameter to a datasource condition.
First, triggers can access parameters using the form.getParameter() method. This method takes one argument, the case-insensitive parameter name. It returns the requsested parameter, or the default value if no parameter was passed on startup.
## Get the "company" parameter
division = form.getParameter('division')
Conditions are also a good place for parameters. Take the following fragment:
With this in place, whenever the table sales is queried, the only records returned are the ones where the field division matches the parameter division. Note that if this datasource will also be used for inserting new rows, a Pre-Insert trigger is needed to set the division field:
##
## Pre-Insert [SalesBlock]
DivisionEntry.set(form.getParameter('division'))
External Python Modules
Python triggers have full access to your installed Python modules. For example, if your project needs the twofish cryptographic module, you can install it normally and do an import twofish in your triggers.
Alternately, GNUe's gnue.conf file supports an ImportPath directive. You can have this point to a directory containing your custom python modules.
Designing for Multiple Interfaces
A form definition, when designed within reasonable guidelines, can be run on a plethora of system architectures and a wide variety of user interfaces. By using the approach taken in this guide, most of your forms will, by default, run on a graphical workstation (X11, Windows, Mac), in a text-based session (telnet or ssh), or via a web browser (HTML). This section highlights a few key compatibility issues.
This list, while not exhaustive, should give you a good idea of common portability pitfalls. As with all things in GNUe, you will always have a choice on how to implement your application. GNUe is not about forcing rules on developers, but about providing viable options. There will be instances where the following suggestions simply are not feasible or practical. In any event, these are simply suggestions on getting the most out of Forms.
Images
Do not make your application dependent on displayed images. It would be acceptable, and appropriate, to display pictures for informational purposes. For example, when doing parts lookups, it would be appropriate to display a picture of the part for reference use. However, it would be normally be inappropriate to prevent the form from working if this image could not be displayed. (TODO: Better example?)
OS-specific trigger code
Python, the default trigger language, provides an extensive library of cross-platform functions. For example, it provides a library of file-access routines that work on all its supported platforms. This is really a broad category as trigger code has all the power of Python behind it.
Custom widgets
It is often tempting to use a new whiz-bang widget available on a certain platform/widget set. This will surely make your application hard to migrate to other platforms/interfaces, as well as restrict your ability to upgrade to a newer Forms version. Form's widget-set was carefully selected to be as multi-platform-friendly as possible, while still providing all the functionality most forms will need. If your application widgets are not supported by forms, there's a good chance that your form could be more functional with a slight rethinking of its design. Remember: a goal of Forms is to be usable on as many platforms as possible, not to exploit all the features of a particular platform.
Trigger Recipes
Over the coarse of writing a complex application, you will encounter a few situations where you will need a trigger to perform a common task. This section lists several
Timestamping a Record prior to a Commit
To automatically fill an entry with a timestamp retrieved from the database, you can use the datasource extension getTimestamp(). create a Pre-Commit trigger on that block. For example,
##
## Pre-Commit [MyBlock]
##
self.MyTimeField.set(MyDS.extensions.getTimestamp())
This example assumes your entry is named MyTimeField and your datasource is called MyDS.
As noted elsewhere in this guide, Pre-Commit is run prior to saving changes to the database regardless of whether the record in question is being inserted, updated, or deleted. If you want to timestamp only new records, you can use the same code listed above, only inside a Pre-Insert trigger. Similarly, if you only want to timestamp modifications, you can use a Pre-Update trigger.
At this point, you may be asking why did we go through MyDS to get to a database timestamp. After all, MyDS corresponds to a table, not to a database. [TODO: Provide an explanation]
By using a timestamp retrieved from the database server, you do not have to worry about differences in the client machines' times. If you would prefer to have the client's time, you can use python's time module.
Stamping a Record with User's Login prior to a Commit
To automatically fill an entry with a the user's login name, you can use form.getAuthenticatedUser() and creating a Pre-Insert trigger on that block. For example,
##
## Pre-Insert [MyBlock]
##
self.CreatedBy.set(form.getAuthenticatedUser())
This example assumes your entry is named CreatedBy. As noted elsewhere in this guide, Pre-Insert is run prior to saving a new record to the database.
This method is commonly called alongside the timestamping recipe above. Together, a Pre-Insert trigger to stamp a new record might look like:
##
## Pre-Insert [MyBlock]
##
self.CreatedBy.set(form.getAuthenticatedUser())
self.CreatedOn.set(MyDS.extensions.getTimestamp())
See the recipe for timestamping for more information on usage of getTimestamp().
Auto-Populating an Entry from a Sequence
To automatically fill an entry with a value from a sequence, you can create a Pre-Insert trigger on that entry. For example,
##
## Pre-Insert [MyEntry]
##
self.set(MyDS.extensions.getSequence("MySequence"))
This example assumes your entry is named MyEntry, your datasource is called MyDS, and the sequence name as stored in the database is MySequence. Note that MyEntry and MyDS are both names originating in your form, whereas MySequence is a name originating in your database.
At this point, you may be asking why did we go through MyDS to get to a database sequence. After all, MyDS corresponds to a table, not to a database. [TODO: Provide an explanation]
Appendix A: Trigger Hierarchy
Forms supports
Appendix B: Form Elements
[TODO: Introduction]
Form Tags
form
No description provided
Attributes
Attribute
Values
Default
Description
name
text
A unique ID for the form.
readonly
Y, N
N
If set to Y, then no modifications to data by the end user will be allowed. The form will become a query-only form.
style
dialog
No description provided
title
text
Untitled Form
The title of the form.
Child Nodes
connection, datasource, dialog, import-datasource, import-dialog, import-layout, import-logic, import-trigger, layout, logic, menu, options, parameter, trigger
Connection Tags
connection
No description provided
Attributes
Attribute
Values
Default
Description
name
text
No description provided
provider
text
No description provided
comment
text
No description provided
dbname
text
No description provided
host
text
No description provided
service
text
No description provided
Datasource Tags
datasource
No description provided
Attributes
Attribute
Values
Default
Description
name
text
No description provided
cache
number
5
No description provided
connection
text
No description provided
detaillink
text
No description provided
distinct
Y, N
N
No description provided
explicitfields
text
No description provided
master
text
No description provided
masterlink
text
No description provided
order_by
text
No description provided
prequery
Y, N
N
No description provided
primarykey
text
No description provided
table
text
No description provided
type
text
object
No description provided
Child Nodes
condition, staticset
add
No description provided
Child Nodes
add, cconst, cfield, cparam, div, mul, sub
and
No description provided
Child Nodes
and, between, conditions, eq, ge, gt, le, like, lt, ne, negate, not, notbetween, notlike, notnull, null, or
between
No description provided
Child Nodes
add, cconst, cfield, cparam, div, mul, sub
cconst
No description provided
Attributes
Attribute
Values
Default
Description
value
text
No description provided
cfield
No description provided
Attributes
Attribute
Values
Default
Description
name
text
No description provided
condition
No description provided
Child Nodes
and, between, eq, ge, gt, le, like, lt, ne, negate, not, notbetween, notlike, notnull, null, or
cparam
No description provided
Attributes
Attribute
Values
Default
Description
name
text
No description provided
div
No description provided
Child Nodes
add, cconst, cfield, cparam, div, mul, sub
eq
No description provided
Child Nodes
add, cconst, cfield, cparam, div, mul, sub
ge
No description provided
Child Nodes
add, cconst, cfield, cparam, div, mul, sub
gt
No description provided
Child Nodes
add, cconst, cfield, cparam, div, mul, sub
le
No description provided
Child Nodes
add, cconst, cfield, cparam, div, mul, sub
like
No description provided
Child Nodes
add, cconst, cfield, cparam, div, mul, sub
lt
No description provided
Child Nodes
add, cconst, cfield, cparam, div, mul, sub
mul
No description provided
Child Nodes
add, cconst, cfield, cparam, div, mul, sub
ne
No description provided
Child Nodes
add, cconst, cfield, cparam, div, mul, sub
negate
No description provided
Child Nodes
and, between, conditions, eq, ge, gt, le, like, lt, ne, negate, not, notbetween, notlike, or
not
No description provided
Child Nodes
and, between, conditions, eq, ge, gt, le, like, lt, ne, negate, not, notbetween, notlike, notnull, null, or
notbetween
No description provided
Child Nodes
add, cconst, cfield, cparam, div, mul, sub
notlike
No description provided
Child Nodes
add, cconst, cfield, cparam, div, mul, sub
notnull
No description provided
null
No description provided
or
No description provided
Child Nodes
and, between, conditions, eq, ge, gt, le, like, lt, ne, negate, not, notbetween, notlike, notnull, null, or
staticset
No description provided
Attributes
Attribute
Values
Default
Description
fields
text
No description provided
Child Nodes
staticsetrow
staticsetfield
No description provided
Attributes
Attribute
Values
Default
Description
name
text
No description provided
value
text
No description provided
staticsetrow
No description provided
Child Nodes
staticsetfield
sub
No description provided
Child Nodes
add, cconst, cfield, cparam, div, mul, sub
Dialog Tags
dialog
No description provided
Attributes
Attribute
Values
Default
Description
name
text
A unique ID for the form.
readonly
Y, N
N
If set to Y, then no modifications to data by the end user will be allowed. The form will become a query-only form.
style
dialog
dialog
No description provided
title
text
Untitled Form
The title of the form.
Layout Tags
layout
No description provided
Attributes
Attribute
Values
Default
Description
tabbed
bottom, left, right, top
Allows a form to convert it's pages as notebook tabs. Allowed values are left, right, bottom, top.
Child Nodes
import-page, page
box
No description provided
Attributes
Attribute
Values
Default
Description
focusorder
number
No description provided
label
text
An optional text label that will be displayed on the border.
name
text
No description provided
button
No description provided
Attributes
Attribute
Values
Default
Description
focusorder
number
No description provided
label
text
The text that should appear on the button
name
text
A unique ID for the widget. Useful for importable buttons.
entry
An entry is the visual counterpart to a field.
Attributes
Attribute
Values
Default
Description
block
text
The name of the block that this ties to.
field
text
The name of the field that this ties to.
focusorder
number
No description provided
hidden
Y, N
N
If defined the entry widget will not be displayed on the form. This is usefull for fields the user doesn't need to know about that you wish to update via triggers.
name
text
The unique ID of the entry.
navigable
Y, N
Y
It false, the user will be unable to navigate to this entry. Triggers can still alter the value.
rowSpacer
number
No description provided
rows
number
No description provided
style
checkbox, default, dropdown, label, password
default
The style of entry widget requested. Currently either text, label, checkbox, or dropdown. To use dropdown you are required to use both the fk_source, fk_key, and fk_description attributes. The label style implies the readonly attribute.
image
No description provided
Attributes
Attribute
Values
Default
Description
block
text
The name of the block that this ties to.
field
text
The name of the field that this ties to.
focusorder
number
No description provided
name
text
No description provided
type
BINARY, URL
URL
No description provided
label
No description provided
Attributes
Attribute
Values
Default
Description
text
text
The text to be displayed.
alignment
center, left, right
left
The justification of the label. Can be one of the following: left, right, or center. Requires that the width attribute be set.
name
text
The unique ID of the label.
rowSpacer
number
Overriders the rowSpace setting defined at the block level.
rows
number
Overrides the rows setting defined at the block level.
page
No description provided
Attributes
Attribute
Values
Default
Description
caption
text
For tabbed or popup pages, this contains the caption to use for the page.
name
text
A unique ID for the widget. This is only useful when importing pages from a library.
style
normal
normal
The type of page when importing pages from a library.
transparent
Y, N
N
If set, then you can tab out of the page via next- or previous-field events. Makes navigation in mutlipage forms easier. If false, focus stays within a page until user explicitly moves to another page
Child Nodes
box, button, entry, image, import-button, label, scrollbar
scrollbar
No description provided
Attributes
Attribute
Values
Default
Description
block
text
The block to which this scrollbar scrolls.
Logic Tags
logic
No description provided
Child Nodes
block, import-block
block
No description provided
Attributes
Attribute
Values
Default
Description
name
text
A unique ID for the widget.The name of the widget. No blocks can share the same name without causing namespace collisions in user triggers.
datasource
text
The name of a datasource (defined in by a tag.) that provides this block with it's data.
restrictDelete
Y, N
N
If set then the user will be unable to request that a record be deleted via the user interface.
restrictInsert
Y, N
N
If set then the user will be unable to request that new records be inserted into the block.
rowSpacer
number
Adjusts the vertical gap of this number of rows between duplicated widgets. Serves the same purpose as some of the gap attributes on individual widgets.
rows
number
Any widgets inside the block will display this number of copies in a verticle column. Simulates a grid entry system.
transparent
Y, N
Y
If set, then you can tab out of the block via next- or previous-field events. Makes navigation in mutliblock forms easier. If false, focus stays within a block until user explicitly moves to another block
Child Nodes
field, import-field
field
No description provided
Attributes
Attribute
Values
Default
Description
name
text
The unique ID of the entry. Referenced in master/detail setups as well as triggers.
case
lower, mixed, upper
mixed
No description provided
default
text
The default value for any new records created. If the field is visible the user can override the value.
displaymask
text
No description provided
editOnNull
Y, N
N
No description provided
field
text
The name of the field in the datasource to which this widget is tied.
fk_description
text
No description provided
fk_key
text
No description provided
fk_refresh
change, commit, startup
startup
No description provided
fk_source
text
No description provided
formatmask
text
No description provided
ignoreCaseOnQuery
Y, N
N
If defined the entry widget ignores the case of the information entered into the query mask.
inputmask
text
No description provided
ltrim
Y, N
N
Trim extraneous space at beginning of user input.
max_length
number
The maximum number of characters the user is allowed to enter into the entry.
min_length
number
0
The minimum number of characters the user must enter into the entry.
queryDefault
text
The form will be populated with this value automatically when a query is requested. If the field is visible the user can still override the value.
readonly
Y, N
N
It defined the user will be unable to alter the contents of this entry. Triggers can still alter the value.
required
Y, N
N
This object cannot have an empty value prior to a commit.
rtrim
Y, N
Y
Trim extraneous space at end of user input.
sloppyQuery
text
When set, whatever value the user enters for the query mask is rewritten with % between each character. Thus example would be queried as %e%x%a%m%p%l%e%
typecast
date, number, text
text
The type of data the entry widget will accept. Possible values are text, number, date.
value
text
No description provided
Menu Tags
menu
No description provided
Attributes
Attribute
Values
Default
Description
name
text
No description provided
enabled
Y, N
N
No description provided
event
text
No description provided
label
text
No description provided
leader
text
No description provided
location
text
No description provided
trigger
text
No description provided
type
text
No description provided
Options Tags
options
No description provided
Child Nodes
author, description, name, option, tip, title, version
author
No description provided
Attributes
Attribute
Values
Default
Description
name
author
author
No description provided
value
text
No description provided
description
No description provided
Attributes
Attribute
Values
Default
Description
name
description
description
No description provided
value
text
No description provided
name
No description provided
Attributes
Attribute
Values
Default
Description
name
name
name
No description provided
value
text
No description provided
option
No description provided
Attributes
Attribute
Values
Default
Description
name
text
No description provided
value
text
No description provided
tip
No description provided
Attributes
Attribute
Values
Default
Description
name
tip
tip
No description provided
value
text
No description provided
version
No description provided
Attributes
Attribute
Values
Default
Description
name
version
version
No description provided
value
text
No description provided
Parameter Tags
parameter
No description provided
Attributes
Attribute
Values
Default
Description
name
text
No description provided
default
text
No description provided
description
text
No description provided
required
Y, N
N
No description provided
type
text
char
No description provided
Trigger Tags
trigger
No description provided
Attributes
Attribute
Values
Default
Description
language
python
python
No description provided
name
text
No description provided
src
text
No description provided
type
text
No description provided
Import Tags
import-block
No description provided
Attributes
Attribute
Values
Default
Description
library
text
No description provided
name
text
A unique ID for the widget.The name of the widget. No blocks can share the same name without causing namespace collisions in user triggers.
datasource
text
The name of a datasource (defined in by a tag.) that provides this block with it's data.
restrictDelete
Y, N
N
If set then the user will be unable to request that a record be deleted via the user interface.
restrictInsert
Y, N
N
If set then the user will be unable to request that new records be inserted into the block.
rowSpacer
number
Adjusts the vertical gap of this number of rows between duplicated widgets. Serves the same purpose as some of the gap attributes on individual widgets.
rows
number
Any widgets inside the block will display this number of copies in a verticle column. Simulates a grid entry system.
transparent
Y, N
Y
If set, then you can tab out of the block via next- or previous-field events. Makes navigation in mutliblock forms easier. If false, focus stays within a block until user explicitly moves to another block
import-button
No description provided
Attributes
Attribute
Values
Default
Description
library
text
No description provided
focusorder
number
No description provided
label
text
The text that should appear on the button
name
text
A unique ID for the widget. Useful for importable buttons.
import-datasource
No description provided
Attributes
Attribute
Values
Default
Description
library
text
No description provided
name
text
No description provided
cache
number
5
No description provided
connection
text
No description provided
detaillink
text
No description provided
distinct
Y, N
N
No description provided
explicitfields
text
No description provided
master
text
No description provided
masterlink
text
No description provided
order_by
text
No description provided
prequery
Y, N
N
No description provided
primarykey
text
No description provided
table
text
No description provided
type
text
object
No description provided
import-dialog
No description provided
Attributes
Attribute
Values
Default
Description
library
text
No description provided
name
text
A unique ID for the form.
readonly
Y, N
N
If set to Y, then no modifications to data by the end user will be allowed. The form will become a query-only form.
style
dialog
dialog
No description provided
title
text
Untitled Form
The title of the form.
import-field
No description provided
Attributes
Attribute
Values
Default
Description
library
text
No description provided
name
text
The unique ID of the entry. Referenced in master/detail setups as well as triggers.
case
lower, mixed, upper
mixed
No description provided
default
text
The default value for any new records created. If the field is visible the user can override the value.
displaymask
text
No description provided
editOnNull
Y, N
N
No description provided
field
text
The name of the field in the datasource to which this widget is tied.
fk_description
text
No description provided
fk_key
text
No description provided
fk_refresh
change, commit, startup
startup
No description provided
fk_source
text
No description provided
formatmask
text
No description provided
ignoreCaseOnQuery
Y, N
N
If defined the entry widget ignores the case of the information entered into the query mask.
inputmask
text
No description provided
ltrim
Y, N
N
Trim extraneous space at beginning of user input.
max_length
number
The maximum number of characters the user is allowed to enter into the entry.
min_length
number
0
The minimum number of characters the user must enter into the entry.
queryDefault
text
The form will be populated with this value automatically when a query is requested. If the field is visible the user can still override the value.
readonly
Y, N
N
It defined the user will be unable to alter the contents of this entry. Triggers can still alter the value.
required
Y, N
N
This object cannot have an empty value prior to a commit.
rtrim
Y, N
Y
Trim extraneous space at end of user input.
sloppyQuery
text
When set, whatever value the user enters for the query mask is rewritten with % between each character. Thus example would be queried as %e%x%a%m%p%l%e%
typecast
date, number, text
text
The type of data the entry widget will accept. Possible values are text, number, date.
value
text
No description provided
import-layout
No description provided
Attributes
Attribute
Values
Default
Description
library
text
No description provided
tabbed
bottom, left, right, top
Allows a form to convert it's pages as notebook tabs. Allowed values are left, right, bottom, top.
import-logic
No description provided
Attributes
Attribute
Values
Default
Description
library
text
No description provided
import-page
No description provided
Attributes
Attribute
Values
Default
Description
library
text
No description provided
caption
text
For tabbed or popup pages, this contains the caption to use for the page.
name
text
A unique ID for the widget. This is only useful when importing pages from a library.
style
normal
normal
The type of page when importing pages from a library.
transparent
Y, N
N
If set, then you can tab out of the page via next- or previous-field events. Makes navigation in mutlipage forms easier. If false, focus stays within a page until user explicitly moves to another page
import-trigger
No description provided
Attributes
Attribute
Values
Default
Description
library
text
No description provided
language
python
python
No description provided
name
text
No description provided
src
text
No description provided
type
text
No description provided
Appendix C: Form Objects
TODO
Form
getParameter()
Syntax:
getParameter(parameter)
Description:
Returns a runtime parameter, or the default value of such if the user did not pass the requested runtime parameter. See Runtime Parameters on page 31 for more information.
Example:
# Get the runtime parameter "company"
company = form.getParameter("company")
setParameter()
Syntax:
setParameter(parameter,value)
Description:
Changes the value of a runtime parameter. See Runtime Parameters on page 31 for more information.
Example:
# Set the runtime parameter "company" to "101"
form.setParameter("company","101")
getFocus()
Syntax:
getFocus(object)
Description:
Request that the current focus be given to object. If object is a block or a page, then focus will be given to the first navigable entry on that page or block. All appropriate Pre-FocusOut, Pre-FocusIn, Post-FocusOut, and Post-FocusIn triggers will be executed. If setFocus is called on a non-navigable item (such as a label), the call is ignored and focus does not change.
Example:
# Request that MyEntry gets the current focus
form.setFocus(MyEntry)
setFocus()
Syntax:
setFocus(object)
Description:
Request that the current focus be given to object. If object is a block or a page, then focus will be given to the first navigable entry on that page or block. All appropriate Pre-FocusOut, Pre-FocusIn, Post-FocusOut, and Post-FocusIn triggers will be executed. If setFocus is called on a non-navigable item (such as a label), the call is ignored and focus does not change.
Example:
# Request that MyEntry gets the current focus
form.setFocus(MyEntry)
setStatusText()
Syntax:
setStatusText(text)
Description:
For user interfaces that support a status bar, or some textual equivalent, set the displayed text. For interfaces without a status bar equivalent, this function is meaningless.
Example:
# Tell the user how great they are
form.setStatusText("Dude, you are the best user ever!")
showMessage()
Syntax:
showMessage(text)
Description:
Description goes here.
Example:
# Code Sample
commit()
Syntax:
commit()
Description:
Description goes here.
Example:
# Code Sample
close()
Syntax:
close()
Description:
Description goes here.
Example:
# Exit the current form
form.close()
getAuthenticatedUser()
Syntax:
getAuthenticatedUser([connection])
Description:
Description goes here.
Example:
# Set "modified_by" to the current user's login
modified_by.set(form.getAuthenticatedUser())
Datasource
createResultSet()
Syntax:
createResultSet([conditions], [readOnly] )
Description:
Description goes here.
Example:
# Code Sample
simpleQuery()
Syntax:
simpleQuery(dictionary)
Description:
Description goes here.
Example:
# Code Sample
delete()
Syntax:
delete()
Description:
Description goes here.
Example:
# Code Sample
Block
clear()
Syntax:
clear()
Description:
Clears the current block with an empty result set.
Example:
# Clear out MyBlock
MyBlock.clear()
gotoRecord()
Syntax:
gotoRecord(index)
Description:
Move to the record indicated by index. If index is negative, then move relative to the last record. Records are numbered beginning with 0.
Example:
# Go to the second record in this block
MyBlock.gotoRecord(1)
# Go to the last record in this block
MyBlock.gotoRecord(-1)
newRecord()
Syntax:
newRecord()
Description:
Inserts a new record immediately following the current record. This new record will then become the current record. The On-NewRecord trigger is executed for the newly created record and any default values are recorded.
Example:
# Code Sample
MyBlock.newRecord()
nextRecord()
Syntax:
nextRecord()
Description:
Navigate to the next record. If the block is currently on the last record, then this method returns 0 (false). Otherwise it returns 1 (true).
Example:
# Move to the next record
MyBlock.nextRecord()
prevRecord()
Syntax:
prevRecord()
Description:
Navigate to the previous record. If the block is currently on the first record, then this method returns 0 (false). Otherwise it returns 1 (true).
Example:
# Move to the previous record
MyBlock.prevRecord()
deleteRecord()
Syntax:
deleteRecord()
Description:
Mark the current record as deleted. On the next save, this record will be permanently removed.
Example:
# Code Sample
MyBlock.deleteRecord()
parent
Description:
This read-only property contains the parent container of this block. The parent container is usually a page.
Example:
# Get MyBlock's parent page
page = MyBlock.parent
Entry
allowedValues()
Syntax:
allowedValues()
Description:
Returns a tuple containing valid values for this entry. This call will only return a set when a fk_source has been specified for the entry.
Example:
# Code Sample
if 'Test' not in MyEntry.allowedValues():
MyEntry.set(None)
autofillBySequence()
Syntax:
autofillBySequence(sequence)
Description:
Description goes here.
Example:
# Code Sample
isEmpty()
Syntax:
isEmpty()
Description:
Returns true if the current entry is considered empty. Empty is usually associated with a blank, or null, value.
Example:
# Set MyEntry to 0 if it has no other value.
if MyEntry.isEmpty():
MyEntry.set(0)
set()
Syntax:
set(value)
Description:
Description goes here.
Example:
# Code Sample
get()
Syntax:
get()
Description:
Description goes here.
Example:
# Code Sample
resetForeignKey()
Syntax:
resetForeignKey()
Description:
Description goes here.
Example:
# Code Sample
parent
Description:
This read-only property contains the parent container of this entry. The parent container will typically be a block, unless container boxes are used.
Example:
# Get this entry's parent block
block = self.parent
readonly
Description:
Description goes here.
Example:
# Set MyEntry to be readonly if not already
if not MyEntry.readonly:
MyEntry.readonly = 1
Appendix D: Data Objects
TODO
Result Set
xxxx()
Syntax:
getParameter(parameter)
Description:
Description....
Example:
# Get the runtime parameter "company"
company = form.getParameter("company")
Record Set
xxxx()
Syntax:
getParameter(parameter)
Description:
Description....
Example:
# Get the runtime parameter "company"
company = form.getParameter("company")
Appendix E: Sample Librarian Schema
[TODO: Add example schema explanations]
Appendix F: Glossary
database
datasource
entry
field
python
Appendix G: GNU Free Documentation License
GNU Free Documentation License
Version 1.2, November 2002
Copyright (C) 2000, 2001, 2002 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.
0. PREAMBLE
The purpose of this License is to make a manual, textbook, or other functional and useful document "free" in the sense of freedom: to assure everyone the effective freedom to copy and redistribute it, with or without modifying it, either commercially or noncommercially. Secondarily, this License preserves for the author and publisher a way to get credit for their work, while not being considered responsible for modifications made by others.
This License is a kind of "copyleft", which means that derivative works of the document must themselves be free in the same sense. It complements the GNU General Public License, which is a copyleft license designed for free software.
We have designed this License in order to use it for manuals for free software, because free software needs free documentation: a free program should come with manuals providing the same freedoms that the software does. But this License is not limited to software manuals; it can be used for any textual work, regardless of subject matter or whether it is published as a printed book. We recommend this License principally for works whose purpose is instruction or reference.
1. APPLICABILITY AND DEFINITIONS
This License applies to any manual or other work, in any medium, that contains a notice placed by the copyright holder saying it can be distributed under the terms of this License. Such a notice grants a world-wide, royalty-free license, unlimited in duration, to use that work under the conditions stated herein. The "Document", below, refers to any such manual or work. Any member of the public is a licensee, and is addressed as "you". You accept the license if you copy, modify or distribute the work in a way requiring permission under copyright law.
A "Modified Version" of the Document means any work containing the Document or a portion of it, either copied verbatim, or with modifications and/or translated into another language.
A "Secondary Section" is a named appendix or a front-matter section of the Document that deals exclusively with the relationship of the publishers or authors of the Document to the Document's overall subject (or to related matters) and contains nothing that could fall directly within that overall subject. (Thus, if the Document is in part a textbook of mathematics, a Secondary Section may not explain any mathematics.) The relationship could be a matter of historical connection with the subject or with related matters, or of legal, commercial, philosophical, ethical or political position regarding them.
The "Invariant Sections" are certain Secondary Sections whose titles are designated, as being those of Invariant Sections, in the notice that says that the Document is released under this License. If a section does not fit the above definition of Secondary then it is not allowed to be designated as Invariant. The Document may contain zero Invariant Sections. If the Document does not identify any Invariant Sections then there are none.
The "Cover Texts" are certain short passages of text that are listed, as Front-Cover Texts or Back-Cover Texts, in the notice that says that the Document is released under this License. A Front-Cover Text may be at most 5 words, and a Back-Cover Text may be at most 25 words.
A "Transparent" copy of the Document means a machine-readable copy, represented in a format whose specification is available to the general public, that is suitable for revising the document straightforwardly with generic text editors or (for images composed of pixels) generic paint programs or (for drawings) some widely available drawing editor, and that is suitable for input to text formatters or for automatic translation to a variety of formats suitable for input to text formatters. A copy made in an otherwise Transparent file format whose markup, or absence of markup, has been arranged to thwart or discourage subsequent modification by readers is not Transparent. An image format is not Transparent if used for any substantial amount of text. A copy that is not "Transparent" is called "Opaque".
Examples of suitable formats for Transparent copies include plain ASCII without markup, Texinfo input format, LaTeX input format, SGML or XML using a publicly available DTD, and standard-conforming simple HTML, PostScript or PDF designed for human modification. Examples of transparent image formats include PNG, XCF and JPG. Opaque formats include proprietary formats that can be read and edited only by proprietary word processors, SGML or XML for which the DTD and/or processing tools are not generally available, and the machine-generated HTML, PostScript or PDF produced by some wordprocessors for output purposes only.
The "Title Page" means, for a printed book, the title page itself, plus such following pages as are needed to hold, legibly, the material this License requires to appear in the title page. For works in formats which do not have any title page as such, "Title Page" means the text near the most prominent appearance of the work's title, preceding the beginning of the body of the text.
A section "Entitled XYZ" means a named subunit of the Document whose title either is precisely XYZ or contains XYZ in parentheses following text that translates XYZ in another language. (Here XYZ stands for a specific section name mentioned below, such as "Acknowledgements", "Dedications", "Endorsements", or "History".) To "Preserve the Title" of such a section when you modify the Document means that it remains a section "Entitled XYZ" according to this definition.
The Document may include Warranty Disclaimers next to the notice which states that this License applies to the Document. These Warranty Disclaimers are considered to be included by reference in this License, but only as regards disclaiming warranties: any other implication that these Warranty Disclaimers may have is void and has no effect on the meaning of this License.
2. VERBATIM COPYING
You may copy and distribute the Document in any medium, either commercially or noncommercially, provided that this License, the copyright notices, and the license notice saying this License applies to the Document are reproduced in all copies, and that you add no other conditions whatsoever to those of this License. You may not use technical measures to obstruct or control the reading or further copying of the copies you make or distribute. However, you may accept compensation in exchange for copies. If you distribute a large enough number of copies you must also follow the conditions in section 3.
You may also lend copies, under the same conditions stated above, and you may publicly display copies.
3. COPYING IN QUANTITY
If you publish printed copies (or copies in media that commonly have printed covers) of the Document, numbering more than 100, and the Document's license notice requires Cover Texts, you must enclose the copies in covers that carry, clearly and legibly, all these Cover Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on the back cover. Both covers must also clearly and legibly identify you as the publisher of these copies. The front cover must present the full title with all words of the title equally prominent and visible. You may add other material on the covers in addition. Copying with changes limited to the covers, as long as they preserve the title of the Document and satisfy these conditions, can be treated as verbatim copying in other respects.
If the required texts for either cover are too voluminous to fit legibly, you should put the first ones listed (as many as fit reasonably) on the actual cover, and continue the rest onto adjacent pages.
If you publish or distribute Opaque copies of the Document numbering more than 100, you must either include a machine-readable Transparent copy along with each Opaque copy, or state in or with each Opaque copy a computer-network location from which the general network-using public has access to download using public-standard network protocols a complete Transparent copy of the Document, free of added material. If you use the latter option, you must take reasonably prudent steps, when you begin distribution of Opaque copies in quantity, to ensure that this Transparent copy will remain thus accessible at the stated location until at least one year after the last time you distribute an Opaque copy (directly or through your agents or retailers) of that edition to the public.
It is requested, but not required, that you contact the authors of the Document well before redistributing any large number of copies, to give them a chance to provide you with an updated version of the Document.
4. MODIFICATIONS
You may copy and distribute a Modified Version of the Document under the conditions of sections 2 and 3 above, provided that you release the Modified Version under precisely this License, with the Modified Version filling the role of the Document, thus licensing distribution and modification of the Modified Version to whoever possesses a copy of it. In addition, you must do these things in the Modified Version:
a)Use in the Title Page (and on the covers, if any) a title distinct from that of the Document, and from those of previous versions (which should, if there were any, be listed in the History section of the Document). You may use the same title as a previous version if the original publisher of that version gives permission.
b)List on the Title Page, as authors, one or more persons or entities responsible for authorship of the modifications in the Modified Version, together with at least five of the principal authors of the Document (all of its principal authors, if it has fewer than five), unless they release you from this requirement.
c)State on the Title page the name of the publisher of the Modified Version, as the publisher.
d)Preserve all the copyright notices of the Document.
e)Add an appropriate copyright notice for your modifications adjacent to the other copyright notices.
f)Include, immediately after the copyright notices, a license notice giving the public permission to use the Modified Version under the terms of this License, in the form shown in the Addendum below.
g)Preserve in that license notice the full lists of Invariant Sections and required Cover Texts given in the Document's license notice.
h)Include an unaltered copy of this License.
i)Preserve the section Entitled "History", Preserve its Title, and add to it an item stating at least the title, year, new authors, and publisher of the Modified Version as given on the Title Page. If there is no section Entitled "History" in the Document, create one stating the title, year, authors, and publisher of the Document as given on its Title Page, then add an item describing the Modified Version as stated in the previous sentence.
j)Preserve the network location, if any, given in the Document for public access to a Transparent copy of the Document, and likewise the network locations given in the Document for previous versions it was based on. These may be placed in the "History" section. You may omit a network location for a work that was published at least four years before the Document itself, or if the original publisher of the version it refers to gives permission.
k)For any section Entitled "Acknowledgements" or "Dedications", Preserve the Title of the section, and preserve in the section all the substance and tone of each of the contributor acknowledgements and/or dedications given therein.
l)Preserve all the Invariant Sections of the Document, unaltered in their text and in their titles. Section numbers or the equivalent are not considered part of the section titles.
m)Delete any section Entitled "Endorsements". Such a section may not be included in the Modified Version.
n)Do not retitle any existing section to be Entitled "Endorsements" or to conflict in title with any Invariant Section.
o)Preserve any Warranty Disclaimers.
If the Modified Version includes new front-matter sections or appendices that qualify as Secondary Sections and contain no material copied from the Document, you may at your option designate some or all of these sections as invariant. To do this, add their titles to the list of Invariant Sections in the Modified Version's license notice. These titles must be distinct from any other section titles.
You may add a section Entitled "Endorsements", provided it contains nothing but endorsements of your Modified Version by various parties--for example, statements of peer review or that the text has been approved by an organization as the authoritative definition of a standard.
You may add a passage of up to five words as a Front-Cover Text, and a passage of up to 25 words as a Back-Cover Text, to the end of the list of Cover Texts in the Modified Version. Only one passage of Front-Cover Text and one of Back-Cover Text may be added by (or through arrangements made by) any one entity. If the Document already includes a cover text for the same cover, previously added by you or by arrangement made by the same entity you are acting on behalf of, you may not add another; but you may replace the old one, on explicit permission from the previous publisher that added the old one.
The author(s) and publisher(s) of the Document do not by this License give permission to use their names for publicity for or to assert or imply endorsement of any Modified Version.
5. COMBINING DOCUMENTS
You may combine the Document with other documents released under this License, under the terms defined in section 4 above for modified versions, provided that you include in the combination all of the Invariant Sections of all of the original documents, unmodified, and list them all as Invariant Sections of your combined work in its license notice, and that you preserve all their Warranty Disclaimers.
The combined work need only contain one copy of this License, and multiple identical Invariant Sections may be replaced with a single copy. If there are multiple Invariant Sections with the same name but different contents, make the title of each such section unique by adding at the end of it, in parentheses, the name of the original author or publisher of that section if known, or else a unique number. Make the same adjustment to the section titles in the list of Invariant Sections in the license notice of the combined work.
In the combination, you must combine any sections Entitled "History" in the various original documents, forming one section Entitled "History"; likewise combine any sections Entitled "Acknowledgements", and any sections Entitled "Dedications". You must delete all sections Entitled "Endorsements".
6. COLLECTIONS OF DOCUMENTS
You may make a collection consisting of the Document and other documents released under this License, and replace the individual copies of this License in the various documents with a single copy that is included in the collection, provided that you follow the rules of this License for verbatim copying of each of the documents in all other respects.
You may extract a single document from such a collection, and distribute it individually under this License, provided you insert a copy of this License into the extracted document, and follow this License in all other respects regarding verbatim copying of that document.
7. AGGREGATION WITH INDEPENDENT WORKS
A compilation of the Document or its derivatives with other separate and independent documents or works, in or on a volume of a storage or distribution medium, is called an "aggregate" if the copyright resulting from the compilation is not used to limit the legal rights of the compilation's users beyond what the individual works permit. When the Document is included an aggregate, this License does not apply to the other works in the aggregate which are not themselves derivative works of the Document.
If the Cover Text requirement of section 3 is applicable to these copies of the Document, then if the Document is less than one half of the entire aggregate, the Document's Cover Texts may be placed on covers that bracket the Document within the aggregate, or the electronic equivalent of covers if the Document is in electronic form. Otherwise they must appear on printed covers that bracket the whole aggregate.
8. TRANSLATION
Translation is considered a kind of modification, so you may distribute translations of the Document under the terms of section 4. Replacing Invariant Sections with translations requires special permission from their copyright holders, but you may include translations of some or all Invariant Sections in addition to the original versions of these Invariant Sections. You may include a translation of this License, and all the license notices in the Document, and any Warrany Disclaimers, provided that you also include the original English version of this License and the original versions of those notices and disclaimers. In case of a disagreement between the translation and the original version of this License or a notice or disclaimer, the original version will prevail.
If a section in the Document is Entitled "Acknowledgements", "Dedications", or "History", the requirement (section 4) to Preserve its Title (section 1) will typically require changing the actual title.
9. TERMINATION
You may not copy, modify, sublicense, or distribute the Document except as expressly provided for under this License. Any other attempt to copy, modify, sublicense or distribute the Document is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance.
10. FUTURE REVISIONS OF THIS LICENSE
The Free Software Foundation may publish new, revised versions of the GNU Free Documentation License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. See http://www.gnu.org/copyleft/.
Each version of the License is given a distinguishing version number. If the Document specifies that a particular numbered version of this License "or any later version" applies to it, you have the option of following the terms and conditions either of that specified version or of any later version that has been published (not as a draft) by the Free Software Foundation. If the Document does not specify a version number of this License, you may choose any version ever published (not as a draft) by the Free Software Foundation.
Alphabetical Index
C
CUSTOM WIDGETSustom widgets 33
D
DATASOURCEatasource 10-13, 35, 36
DESIGNEResigner 7, 10-12
G
GETSEQUENCEetSequence 36
GETTIMESTAMPetTimestamp 35
P
PRE-COMMITre-Commit 35
PRE-INSERTre-Insert 35, 36
PYTHONython 7, 32-34
S
SEQUENCEequence 36
T
TIMESTAMPimestamp 35
X
XMLml 12, 13