[Omnis-Newsletter] Omnis Tech Newsletter
omnis-news-admin@omnis.net
omnis-news-admin@omnis.net
Wed, 30 May 2001 15:38:24 +0100
Omnis Tech Newsletter May 30th, 2001
========================================
UNSUBSCRIBE OPTIONS: You have been sent this email because you have directly
signed up for, or expressed an interest in receiving a technical newsletter
when you downloaded an evaluation of Omnis Studio, or registered the Lite
version of Omnis Studio. If, however you feel you have received this email
in error you can unsubscribe as well as change your subscription options at
www.omnis.net/newsletter.
N.B. If you subscribed by checking a box on one of our forms, you will not
have received a password. You will need to submit your email address at
www.omnis.net/newsletter and select the 'email me my password' option on the
next page in order to receive this.
========================================
WELCOME!
Welcome and thank you for subscribing to the Omnis Technical Newsletter.
Published fortnightly, it is intended for Omnis developers of all levels and
experience, for those people evaluating Omnis Studio, or for developers
moving from a similar tool. We think you'll find the content both
interesting and useful for your Omnis development needs and hopefully it
will help you become more productive in Omnis application design.
In the first article in this newsletter David Swain describes the many uses
of the Headed list box, a very flexible window control for displaying
multiple columns of list data. The second article is the next part of our
basic Omnis tutorial in which Geir shows you how to create the SQL database
structures in your Omnis application. You may find it easier to work through
the exercises and examples in this newsletter by printing it out before you
begin.
CONTENTS:
-About the Authors
-Headed List Boxes, by David Swain
-Raining Data Worldwide User Conference Photos
-Building Your First Omnis Application: Part 5, Creating schemas and
database tables
-About Omduit
-Copyright and Unsubscribe details
========================================
About the Authors
The Omnis Technical Newsletter contains high quality content from two
leading and well respected Omnis developers, Geir Fjaerli and David Swain.
Geir Fjaerli is based in Norway and has been an Omnis professional developer
for many years as well as a Regional Sales Manager for Omnis. He is
currently working freelance again developing a range of products (in Omnis
of course) including his Prophet5 sales and customer relationship management
solution, soon to be released for Mac OS X.
David Swain is the founder and president of Polymath Business Systems, for
many years a leading provider of Omnis training. His expertise in Omnis
programming and his ability to make complex concepts understandable are
recognized throughout the worldwide Omnis community.
========================================
Headed List Boxes
By David Swain, Polymath Business Systems Inc
Email: dataguru@polymath-bus-sys.com
Web: www.polymath-bus-sys.com
----------------------------------------------------------------------
One of the most versatile window components for use in displaying list
variables is the Headed List Box. It allows us to simply display the raw
contents of a list variable or to format it as we see fit. It provides a
multi-column view of these contents that allows us to use any font,
proportional or not, while maintaining nice even columns. These columns can
be individually left, right or center justified and can be labeled with
column headers. We can even allow the user to resize the columns by dragging
the right edge of the column header. These headers are what truly
distinguish this list field type as they are actually sub-components that
can respond to being clicked.
If you haven't yet used a Headed List Box, perhaps this article will help
you on your way.
Basics
All a Headed List Box needs to display the contents of a list variable are
two property values: a value for its "dataname" property that specifies the
name of the list variable to display and a value for its "designcols"
property that gives the number of columns to display. For simple list
displays where no special formatting is required, Omnis Studio will use this
information to display the first n columns ("n" being the value of
"designcols" for the field) in the list variables definition. Each column
value is given the default display formatting for its datatype.
If the display order of the columns must differ from their defined order, or
if more complex or specific formatting is required, a Headed List Box field
also has a "calculation" property for this purpose. This property treats the
entire contents of a list line as a string value with "tab" characters used
to delimit columns. The most appropriate form for this calculation is as a
long concatenation expression.
Consider this example: We have first name, last name, city and state columns
somewhere in the definition of our list variable. We wish to display one
column with both last and first name values (comma-separated) and city and
state (again comma-separated) in the second column. Our calculation property
value could look like this:
con(lastName,', ',firstName,kTab,cityName,', ',stateCode)
Notice that we do not have to nest concatenation functions for our separate
columns in this example. We just include the "tab" character (kTab) at the
appropriate place in the expression. More complex expressions may require
jst(), mid() or other string manipulation functions nested within the
overall con(), and these may require additional con() functions nested
within them, but for simple examples as given here the con() function is
only required once.
Header Text
If column headings are desired, a minimum of two additional properties come
into play: First, the "hideheader" property must be set to kFalse so that
the headers can be seen. Then the "columnnames" property must be supplied
with a comma-delimited set of header text values. These column labels should
remain simple as there are limitations to what this property can contain.
The property value is taken literally, so quotes are not required around
literal values unless they are intended for display. The property does not
support square bracket notation, so expressions are not allowed. This being
the case, commas cannot be included in a column heading since a comma is
interpreted as the delimiter for the next column heading. We can include
fewer column headings than the number of design columns for the field, but
Omnis Studio will truncate the columnnames value to a maximum of designcols
headings.
Header Click Events
In addition to the basic "Click" and "Double-click" events that a normal
List Box field detects, a Headed List Box can also respond to a "Header
Click" event. The event message variable for this is "evHeaderClick". This
can only be detected, however, if the fields "enableheader" property is set
to kTrue. If we enable the header, we need to decide what such an event
means in our application. In any case, the $event() method of the Headed
List Box field must have a block of code under an "On evHeaderClick" line to
respond to such an event.
The most common use for detecting a header click is to sort the list
variable contents based upon the order implied by the display column whose
header was clicked. There are two basic things to consider when programming
for this option: The first is how to set the sort fields appropriately, so
we will begin there. Some display columns may imply many levels of sorting.
We may also choose a descending sort for certain columns, for example to
show the largest sales on top.
To test our remaining examples, let's establish a window with a Headed List
Box field and a list to display in it. Perform the following steps:
1. Create a new window class named "listTester".
2. Give this window the following instance variables: "list" of type List,
"column1" of type Character, "column2" of type Short number 2dp, and "idno"
of type Long integer.
3. Put the following lines of code in the $construct() method of the window:
Do list.$define(column1,column2,idno)
Do list.$add('First',12.95,1)
Do list.$add('Second',14.95,2)
Do list.$add('Third',21.95,3)
Do list.$add('Fourth',29.95,4)
Do list.$add('Fifth',8.95,5)
4. Place a Headed List Box field on the window with the following property
values:
dataname: list
calculation: con(column1,kTab,jst(column2,'N4'))
designcols: 3
columnnames: Label,Amount
hideheader: kFalse
enableheader: kTrue
5. Instantiate the window once to verify that the list is created and
displayed in the field.
To inform us of which column received the header click, the evHeaderClick
message contains an event parameter named "pColumnNumber". We can use this
in a Switch/Case statement to set our sort fields. Put the following lines
of code in the $event() method of the field:
On evHeaderClick
Begin reversible block
Set current list list
Clear sort fields
Switch pColumnNumber
Case 1 ;; Label
Set sort field column1 (Upper case)
Case 2 ;; Amount
Set sort field column2 (Descending)
Case 3 ;; idno
Set sort field idno
End Switch
End reversible block
Sort list
Redraw
Notice that the list sorted just fine, but there is a slight problem. The
second thing (as mentioned above) to consider in this sort process is how to
re-establish the proper current line if one was set. When the lines of a
list are sorted, the current line remains the same -- however it may very
well have different contents as a result of the sort operation. Good user
interface design requires that the line now containing the content
originally on the current line must be set as the current line. In other
words, if line three was the current line before the sort operation and
those contents end up on line five after the sort, line five must be set as
the current line to present a consistent interface to the user. Omnis Studio
will not automatically do this, so we must expend some programming effort to
make it so.
To do this, we can add a method to the Headed List Box field named
"$setcurrent". The advantage of having a separate method to do this is that
there may be other times when this method needs to be invoked. This method
will have one parameter to track the unique identifier for the list line in
question. We will name this parameter "currIdno" and give it a Long integer
datatype. The code for our $setcurrent() method is:
Begin reversible block
Set current list list
Set search as calculation {idno=currIdNo}
End reversible block
Search list (From start,Do Not Load Line)
Of course, we'll need a few more lines of code in the $event() method and a
local variable (named "currID") to track the original idno value before the
sort and to invoke the $setcurrent() method. The updated $event() method is
then:
On evHeaderClick
Begin reversible block
Set current list list
Calculate currID as list.idno
Clear sort fields
Switch pColumnNumber
Case 1 ;; Label
Set sort field column1 (Upper case)
Case 2 ;; Amount
Set sort field column2 (Descending)
Case 3 ;; idno
Set sort field idno
End Switch
End reversible block
Sort list
Do $cobj.$setcurrent(currID)
Redraw
Note that we could have just as well used
Do $cfield.$setcurrent(currID)
To invoke the $setcurrent() method. $cobj is a notational shortcut to "the
object the received the current event" while $cfield is a notational
shortcut for "the field that contains the currently executing method".
Either is appropriate in this case.
Our method now works as a user might expect it to.
Column Alignment
By default, the columns of a Headed List Box field will have the alignment
given the field in its "align" property. We can override this alignment on a
column-by-column basis, but only at runtime. The $setcolumnalign() method,
one of the many built-in methods of a Headed List Box, is used for this
purpose. It has the following syntax:
ListFieldNotation.$setcolumnalign(column number,justification)
Both parameters are required. The first is the column number of the display
column we wish to align, so it should be given an integer value. The second
is the alignment we wish to impose on that column, and we should use one of
the alignment constants (kLeftJst, kRightJst or kCenterJst) or their numeric
equivalents (0, 1 or 2) for this value. (The constants are generally more
readable.)
So that this field is properly encapsulated, the most appropriate place to
invoke the $setcolumnalign() method is in the $construct() method of the
field. To do this, we must add a method named "$construct" to the list of
methods for the Headed List Box field. (We can have up to 501 methods for
any field object on a window, so we are not in any jeopardy of having too
many.) This method will automatically run whenever the window on which the
field is placed is instantiated. If we wish to right-align the second
display column of the list field, our $construct() method would contain this
code:
Do $cfield.$setcolumnalign(2,kRightJst)
Note that we had to use $cfield here and not $cobj to generically specify
our Headed List Box field. In this case, we needed to use the "field
containing this method" shortcut rather than the "object that received the
current event" shortcut since there is no event involved.
Final Notes
This article is by no means a comprehensive treatise on the properties and
uses of Headed List Box fields. The examples given here were selected to
illustrate some common uses of such fields of which the Omnis Studio
beginner might not be aware.
You might also consider the Headed List Box field created above as a prime
candidate for inclusion in the Component Store, either as a custom component
or as a replacement for the basic Headed List Box field component.
========================================
Raining Data Worldwide User Conference Photos
Raining Data just held their Worldwide User Conference at the Hyatt Regency
in Long Beach, California, followed closely by the annual US Geek Week
conference for Omnis developers. See the pics for the Worldwide User
Conference at:
http://www.rainingdata.com/news/events/wwuc/news.html
========================================
Building Your First Omnis Application: Part 5, Creating schemas and database
tables
By Geir Fjaerli, Sunshine Data
Email: geir@sunshinedata.net
Web: www.sunshinedata.net
----------------------------------------------------------------------
Welcome to a new chapter of our Basic Omnis tutorial. After building our
first basic application in the first issue of this newsletter, we started
looking at the details of an Omnis application. They included:
Part 2: The Studio Classes. The classes are the building blocks of an
application, and include windows, reports, menus etc.
Part 3: The Omnis Integrated Development Environment. Here we looked at the
Component store, the Property Manager and the Catalog.
Part 4: The Data Structure. Including basic terminology.
I strongly suggest that you refer to these chapters if you haven't already,
or if you feel uncertain about the details. (For back issues, please go to
www.omnis.net/newsletter and click on the Newsletter Archive link.)
Last time we looked at the data structure of our application, and the Omnis
Studio SQL classes that implement the database layout and functionality in
our libraries. Today we are going to look at the basic work involved in
implementing this functionality.
Our first step is setting up the data structure. You can do this in two
ways: Either create it in the database itself or in your library. If you
want to create it in the database, you may use the tools that come with the
database itself, or you can use the SQL Browser in Omnis Studio. We shall
briefly look at the SQL Browser a bit later in this issue.
In this tutorial we shall build the data structure using schema classes in
Studio. The application we are building is a simple "To do" system, linking
employees to tasks. The brief description is like this: We have a number of
employees, and a number of jobs or tasks to be performed. In the beginning
we will assume that there is only one employee per task, later we shall see
how we can use a link file to link multiple employees to the same task.
In the beginning we will assume that only one employee is linked to a task.
One employee however can have many tasks. We call this a one-to-many
relationship. This is often referred to as a hierarchical or "parent-child"
relationship. You may illustrate it this way: A mother may have many
children, a child has only one mother. Or to use the example we made in the
previous chapter, one customer may have placed many orders, but an order is
placed by that one customer only. As we learned in the previous chapter, we
implement this using a foreign key in the "child" table which equals the
primary key in the "parent".
The following assumes that you have read the previous chapters, refer to
those if you find expressions that you are not familiar with.
To start our application open Omnis Studio. In the Welcome screen (or from
the File menu if the welcome screen is closed) select New library. Name the
library "Tasks" (without the quotes) and click OK. In the browser
double-click the Tasks library.
Now locate the "New schema" icon in the Component Store and drag it into
your library (in the browser). Call the schema "sEmployee" (without the
quotes) and hit Return. Now your library will have two classes: the Startup
Task and the sEmployee schema. Double-click sEmployee to open the schema
editor.
The editor has two parts. On the top is a field titled "Server table or
view". Below is a list of columns for the schema, currently displaying a
single empty line.
Start by naming the server table, type "Employee" (without the quotes) into
the top field.
Then press TAB to go to the list. The list has 6 columns:
Column name: The name of the database column, e.g. FirstName, BirthDate etc.
Data type: The main data type, e.g. character, number, date etc.
Data subtype: Depends on the main type. If character this holds the max
length of the string to store, if number it holds various integer or decimal
number types, if date it holds date subtypes.
Description: A free text description of the column which helps you remember
its purpose.
Primary key: Set this to true for the column that holds the primary key, and
false for the others. (A primary key may span more than one column, but for
our tutorial we will stick to one.)
No nulls: If true the column has to have a value (zero and empty are values,
but it cannot be unassigned). For our basic tutorial we will leave this
false, as setting it may cause our SQL to fail.
Note that as we have mentioned earlier the data types in the schema are
Omnis variable types, and not the same as the ones in the database. Omnis
will convert the data types for us when we create the database tables, as
well as when we run the application.
Now we are ready to enter the columns for our sEmployee schema. This
introduces us to another problem: While we want to have descriptive names
for our columns, we will find that not all names are usable. This is because
some words are "reserved" by the database for its own use, or is part of the
SQL syntax. To avoid confusion, the databases simply says "don't use them",
and generate errors if we try. Unfortunately we don't get those errors
before we create the database tables, Omnis will quite happily let us use
them in the schema. To make things worse, the list of restricted words is
different from database to database, so just because it works on Oracle
doesn't mean it works with SQL Server.
So, how do we solve this issue? Apart from learning all restricted words and
not using them, we have two solutions: Either enclose column names in
quotes, or prefix them. The quoted solution is supported by most databases
that follow the current SQL standard. (Note: Just because a database vendor
says they do, doesn't mean they are 100% compliant.) I prefer using a
prefix, "c" for column. We will stick to that for this tutorial.
So our first column will be named cID (ID is the primary key), the type is
Number and the subtype is Long integer. Follow this and set the columns of
sEmployee as follows:
No. Column name Data type subtype Description Primary key No nulls
1 cID Number Long integer kTrue kFalse
2 cFirstName Character 32 kFalse kFalse
3 cLastName Character 32 kFalse kFalse
4 cPhone Character 16 kFalse kFalse
If you need to delete one of the rows, use the context menu. (Right/Option
click on the row.)
Now close the schema to save it. (Omnis automatically saves a class when the
editor is closed.)
Repeat this operation for the second schema. name it "sTasks", and the
server table name is "Task" (both without the quotes). The columns for this
schema are:
No. Column name Data type subtype Description Primary key No nulls
1 cID Number Long integer kTrue kFalse
2 cTask Character 64 kFalse kFalse
3 cDatePlanned Short date 2000..2099 kFalse kFalse
4 cDateDone Short date 2000..2099 kFalse kFalse
5 cType Number Short integer(0 to 255) kFalse kFalse
6 cEmployeeID Number Long integer kFalse kFalse
There is a couple of things to note here:
* The primary key is named cID in both schemas. Column names do not need to
be unique across tables.
* cEmployeeID is our foreign key, which will hold the primary key of the
linked employee.
* cType will be used to identify the type of task, e.g. meeting, phone call
etc. The type then will be hardcoded in our library. A more flexible
approach would be to make a separate "Type" table and link to that.
Now that we have created our schemas in the library, it is time to create
them in our database. To do that we use the SQL Browser, which is the second
selection in the Tools menu in Studio. Select this to open the SQL Object
Browser. It comes up empty, since we have not created any database objects
yet.
The SQL Object Browser has three menus:
Session: Lets us open and close sessions, modify their attributes, print
them.
Tools: Gives you access to Interactive SQL, a window that lets you write SQL
statements and execute them directly, User Admin for the database, and
options for the SQL Object Browser itself.
View: Like other windows in the Studio development environment you can
change and save the display options of the browser window.
Most of the items on these menus are currently greyed out, which means they
are not accessible. This is because we have yet not opened a database
session. A session is a connection to a database. In Studio we can have
multiple sessions to different databases, and more than one can be open at
the same time.
For our tutorial we shall be using an OmnisSQL session, that is a session
using SQL with the native Omnis database. As mentioned earlier the Omnis
database is not a full fledged SQL database, but for our tutorial it will do
the job. If you have a relational database like Oracle or FrontBase or DB2
with the appropriate Omnis DAM (Data Access Module), you may want to try
that as well, but the setup of this is outside the scope of this tutorial.
Once setup and connected, though, the steps we follow here should work with
any supported SQL database.
On the Sessions menu select Modify Session Templates. This opens the Session
Template Manager window. This has a number of predefined templates that we
can duplicate and modify for our purposes. Click on the one labelled
OMNISSQL and select Duplicate from the Sessions menu. This created a copy of
the template and names it OMNISSQL_1. (Or _2 etc. if you already have a
duplicate.)
Double-click the OMNISSQL_1 template to open the editor. This has a number
of predefined attributes, plus some that are empty for us to complete. We
shall set up our OMNIS SQL session details as follows:
1. Change the Session name from OMNISSQL_1 to TASK.
2. DBMS vendor is OMNIS, and Data Access Module is DOMNIS. For OMNISSQL we
leave the DB version empty.
3. Host name will point to our database. For database servers that will be a
network name (e.g. @TNS:DBNAME), but for OMNISSQL it will instead hold the
path to the Omnis data file. Next to the host name field is a New Data File
button. Click this to open a standard file dialog which lets you set the
name and location of your datafile. For now, store the datafile in the same
directory as your library. Click OK to return to the session editor.
4. OMNIS SQL does not use Username or Password, so we can leave those empty,
the rest of the attributes we can leave at the default setting. We shall
return to their purpose later. Finally click OK to close the editor and save
the session template. As you can see the Manager window now holds a session
template called TASK.
Now close the Manager window and return to the SQL Object Browser. From the
Session menu select Open and then the TASK sub menu item. This opens a
session to our Tasks database as defined in our TASK session template. The
Browser displays an entry for our session.
Double-click the entry to see the object types of that session. There is
only one type there, and that is Tables. An Omnis datafile only holds
tables. Other databases may display triggers, store procedures and more.
Double-click again to display the tables of the TASK session. It is
currently empty, as we haven't added any tables yet. This is our next step.
The SQL browser contains tools to let us add and edit tables. But we have
already created the definition when we created the schemas. Omnis offers us
an easy way to avoid having to duplicate our effort. We can simply drag a
schema into the SQL browser to create the table. Here is how we do it:
First drag the TASK_Tables window to the side, so that we can get back to
the library browser. You can close the other SQL Browser windows if you want
to avoid the clutter. Now open the library browser and our TASKS library.
This will display our two schema classes. Select the schemas and drag them
into the TASK_Tables window (one by one or both at once). If the library and
SQL browsers overlap, you may want to move them first so that you can drag
from one to the other.
Once you drop the schemas on TASK_Tables, Omnis will create the database
tables for you, and display them in the window. Double-click them to see how
they look. You can see that the columns are the same, but the types have a
different name. As mentioned before, Omnis will convert for us, so don't
worry about this now. (There may problems with certain datatypes in some
databases, once you change to another database, but mostly it works OK.)
Congratulations! You have just created your first database. Very simplistic,
but still a database. It is actually ready to use, we can start adding data
right away by using the built in Insert Data window or the Interactive SQL
tool.
In coming chapters we shall move ahead and explain how we can use our
schemas in the application, by adding table classes and defining our window
variables from them. We shall also look closer on some of the issues we have
skipped this time around, including indexes.
========================================
About Omduit
The Omduit plug-in for Omnis Studio allows you to transfer data from your
Omnis application, whether stored on a server or Omnis database, to your
Palm OS compatible handheld device via the HotSync(r) function. This allows
you to take your data wherever you go, change your data while you are on the
move, and then merge and update your data with that contained on your shared
server. For more details, go to:
http://www.omnis.net/omduit/index.html
========================================
I hope you've found this issue of the Omnis Tech Newsletter both interesting
and informative. Please send me your comments and feedback, and include
suggestions for future articles if you like. We would like to hear from
you...
Regards,
--Andrew Smith.
Omnis Tech Newsletter Editor
Email: editor@omnis.net
========================================
No part of this newsletter may be reproduced, transmitted, stored in a
retrieval system or translated into any language in any form by any means
without the written permission of Raining Data.
(c) Copyright Raining Data, Inc., and its licensors 2001. All rights
reserved.
Omnis(r) is a registered trademark and Omnis 7(tm), and Omnis Studio are
trademarks of Raining Data UK Ltd. Other products mentioned are trademarks
or registered trademarks of their corporations.
========================================
To unsubscribe from this newsletter or change your subscription options,
please go to:
www.omnis.net/newsletter