[Omnis-Newsletter] Omnis technical newsletter

omnis-news-admin@omnis.net omnis-news-admin@omnis.net
Mon, 15 Oct 2001 17:45:25 +0100


Omnis Technical Newsletter October 15th, 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, Geir Fjaerli continues his tutorial
in which he describes how to build a basic task window, adding objects from
the Component Store. In the second article, David Swain describes the
internal workings of the Omnis Component Store and describes how you can
change or add to the Store to help your development efforts. 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
-Building part 10: The task window continued.
-The Omnis Web Client
-Modifying the Component Store by David Swain
-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, now available 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.


========================================

Building part 10: The task window continued.
By Geir Fjaerli, Sunshine Data
Email: geir@sunshinedata.net
Web: www.sunshinedata.net

----------------------------------------------------------------------

Hi, and welcome back to our Omnis Studio tutorial.

After taking a break in the last issue for some urgent project work, it is
time to pick up where we left in mid September.

Here is our work so far:
Part 1: Hello World, our first little Studio application
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.
Part 5: Creating schemas and database tables.
Part 6: Adding table classes and using our schemas in application windows.
Part 7: What did the wizard build, and a tour of the method editor.
Part 8: The logon window and object class.
Part 9: The task window.

You should have those handy, and your "tasks.lbs" library file.

As usual, I strongly suggest that you refer to these parts if you haven't
already, or if you feel uncertain about the details. From part 5 onwards,
each new part will be based on programming done in previous parts, so you
have to follow them all. (For back issues, please go to
www.omnis.net/newsletter and click on the Newsletter Archive link.)

THE FORGOTTEN TASK DESCRIPTION:
In the previous chapter of our tutorial, we started building the task
window, wTask. (We renamed the logon window which was originally called
wTask.) So far we have added 3 entry fields and 4 radio buttons to the
window, and given them data names to link to the appropriate row vars and
columns. Some of you may have noticed that we actually forgot to set up one
entry field, that is the task description itself. So let us start with
correcting that little mistake.

Open your wTask window in design mode. You should have fields and labels for
ID, Date planned and Date done. The Task field should logically be placed
below the ID field, but before the dates. So we need to make room for it.
Assuming you have all your fields and radio buttons set up beneath each
other vertically, you will want to move everything except the ID field and
label down. To do so click in the window above and to the left of the label
for the first date field and while holding the mouse button down drag a
selection rectangle down to the right until all the objects are surrounded
by it, then release the button. All fields should now show small selection
"handles". Note that Omnis will select any field that is touched by the
selection rectangle, even if parts of it is outside the rectangle. You can
also hold down the Shift key and click on each individual object to select
them.

Once you have selected the objects move them down enough to make room for an
extra field between the ID and the date field. You can either use the mouse
and hold the mouse button down on one of the objects, then drag them to
where you want them, or you can use the arrow keys on the keyboard to move
them one pixel at a time. If the fields you were moving all shared the same
top or left property, you could also set the position using the Property
manager, but this is not the case here.

Note: To make sure you move them in one direction only, press and hold the
Shift key after starting to drag the fields, this will constrain the drag to
vertical or horizontal movement only. Omnis offers a number of such
key+mouse combinations:
* Shift + Click: Add the object to the selection, or unselect it if already
selected.
* Drag + Shift: Constrain the drag operation to vertical or horizontal.
* Ctrl + Click: Use this to select on or more fields inside a container.
This is good for two situations:
a. If you want to select more than one object inside a container, by holding
down the Ctrl key you can drag a selection rectangle inside the container
without selecting the container.
b. If the container is already selected, hold down the Ctrl key to select an
object inside it and deselect the container.
* Ctrl + Drag: This will copy the selected objects.

So by dragging the fields down, we have made room for the Task description
field. Use the Ctrl+Drag technique to create a copy of the ID field in the
space created. In the property manager, rename the data name for the copy to
iTaskRow.cTask. Double-click the label and rename it "Task:". These
operations were described in the previous chapter.

We need to do one more thing. We have earlier discussed the "order" property
of the window controls. This determines the tab order of the fields, that is
which field you will go to when you tab out of another. Since our task
description field was the last one added, it is also the last in the tab
order. Usually you will want the tab order to follow the physical order on
screen, either horizontally or vertically. Our new field should therefore be
number two. So click the field, open the Property manager and set the
"order" property to 2. This will renumber all the following fields,
including the date planned field which was number 2 before. You can put the
fields in any order you like, but remember that the radio buttons must be in
consecutive order to be recognised as a group, and that their internal order
determines the value assigned to each.

Now we are ready for the next bit, adding an employee selection list.

THE EMPLOYEE LIST:
As we discussed in the previous chapter, we will use drop down lists on
Windows and pop up lists on Mac for our employee list. This is because those
are the two controls that behave the most like each other, while still being
"proper" Mac and Windows controls respectively. You can use the appropriate
one for the platform you are developing on. Note that the real issue us not
which platform you develop on, but which platform the application will be
used on. Fortunately the development version of Studio contains both
controls on all platforms. If you know that you will deploy the application
on both platforms, then you could even put both controls there in the same
position, and then hide and show each of them according to the platform.
Omnis lets you test which platform you are running on, so this may be done
dynamically at runtime.

The first thing we want to do is to add the control to the window. In design
mode, open the Component store and drag either a drop down or pop up menu
control into the window. Place it beneath the radio buttons. If you want to
see the difference between the drop down and pop up, you can add them both.
The pop up list will appear as an embossed grey rectangle, the drop down as
an inset rectangle with a little drop down arrow at the right end. Looking
at the Property manager we find a few other differences: * The drop down can
have hardcoded "default" lines (as opposed to using a dynamic list variable,
like we will do.) * The drop down has a property to set the number of
visible lines, and uses a scroll bar to move up and down the list. The pop
up always shows all lines up to the maximum supported by the control.
Neither of them is suited for long lists, they are intended for quick
selection among a limited number of alternatives. * The pop up list supports
multiple selections, the drop down not. I would not recommend using this
with the pop up list anyway, since it will only be able to display one of
the selections at a time without clicking to open it.

In the following I will refer to it as the list control, meaning drop down
or pop up according to you choice.

HOW DO WE MAKE THE LIST WORK:
Anyway, for our purpose (that is main properties and methods) they behave
the same. So let us look at what is need to create a working list: 1. The
control needs to know which variable holds the data. This variable will be a
list, and its name goes into the dataname field, just as with our entry
fields. There is one difference, though. Since the entry field is linked to
a single column, we include the column name in the dataname property, as
"RowName.ColumnName". A list control can show multiple columns, and so the
dataname just holds the list name without any columns.

2. The columns to display are a separate issue. We usually does not want a
list on screen display all the columns of the underlying list variable. Some
of them may be primary or foreign keys, and only interesting to our internal
code, not to the user. Sometimes we just want to show the name, like in this
case, not any other info. So we need a way to tell which of the list columns
to display. In the drop down and pop up lists, we use the calculation
property for this.

Note that the various list and grid controls in Studio behave differently.
The old list boxes takes a jst() function with name and length, separated
with commas, the new takes a con(), using column names and tabs, some even
simply uses the columns in the list var. This is confusing in the beginning,
eventually you will learn the purpose of each control. But for our purpose
both the pop up and drop down can be handled the same way. Unlike grids,
they are really best suited to display a single column only. We want to
display two columns from our list variable, the employees first and last
name, but we will concatenate them into a single column in the list
calculation.

3. We need to "populate" the list, that is build the list to hold all the
employees. We have already done something similar (or rather the wizard did
it for us): In our employee window we selected all employees, then we
fetched one at the time into our row var as we hit the Next button. This
time the code will be quite similar, but instead of fetching one row at the
time, we will fetch them all in one go into our list var.

This needs some consideration. Where/when do we want to do this? When the
application starts, when the window opens, every time we need the list? This
of course depends on the nature of the list data. If the list is static,
lets build it at startup, and hold it in a  global var for later use. If it
may change, but usually doesn't, lets build it when the window opens. If the
contents of the list depends on the contents of other fields, we need to
build whenever they change. In our case alternative two is fine, we will
build the list when the window opens. We usually don't change employees that
often, and if we do, we just have to reopen the task window, rather than
having to restart the whole application.

There are other ways to handle this. In a more complex application we may
implement a "message" system, that is when we add an employee in the
employee window, we could send a message to the other open windows saying
"Hey, I just added an employee, please update your employee lists." This
kind of behaviour is part of an object oriented paradigm, which Studio
supports very well.

4. When a line (employee) is selected, we need to detect which employee that
is, and put his ID into the foreign key of the task.

5. And finally, when a task record is selected, we need to fond the
corresponding line in the list and select it, so that the list displays the
correct one.

Let's begin:
SETTING DATANAME AND CALCULATION:
1. First click you list control and open the Property manager. In the
Dataname property enter iEmployeeList. If you look back on last chapters
work, you will remember that we already have created and defined our list
variable with that name.

2. Then move to the Calculation property and enter the following:
"con(iEmployeeList.cFirstname,' ',iEmployeeList.cLastname)" (as usual
without the quotes). That is: Concatenate the values inside the brackets,
which are first name, a space and last name.

BUILDING THE LIST:
3. Now let's populate the list:
As mentioned, the list is already created and defined from the SQL class.
This happens in $construct. We will add the rest of list building code to
the same method, so that the list is built when the window opens. So go to
the class methods of wTask and select $construct. it will already have the
following two lines:
Do iTaskRow.$definefromsqlclass('tTask')
Do iEmployeeList.$definefromsqlclass('tEmployee')

Now click on the first empty line below these, and add the following method
lines:
Do iEmployeeList.$select()
Do iEmployeeList.$fetch(kFetchAll)
Do $cinst.$redraw()

Please refer to the previous chapter for a discussion of the methods editor
and how to add method lines. Also refer to part 4 for a basic discussion on
the SQL used above. In short, the $select asks the database server to find
and prepare the data for us, the $fetch the retrieves those rows to our
application. The select can take a so called where clause inside the
brackets, to tell the server the criteria we want it to use for selecting
the data (e.g.: where cLastName like 'Smith' will select all rows where last
name = Smith.) In our case we want all the rows (employees) so we leave the
where clause empty.

This is all the code needed to list the employees, so we now have both
defined the list, in memory and screen, and built it. Assuming that you have
entered some employees in you employee table, you should be able to open the
window now and click the list to se the employees listed. (Note: It is
fairly easy to "loose" your database session during design. If things
doesn't work, then try shutting down Omnis and restarting. You can also
close the session using the SQL Browser and the log on again. As we
currently have no advanced session handling, you may end up with multiple
session open if you simply try to logon again. We shall look at session
management later.)

The final line does $cinst.$redraw. This redraws the whole window. $cinst
means "current instance", in this case the open window. (For an in depth
discussion on instances and classes refer to object oriented literature, or
for instance my "Triple-O" session, next one coming at the EurOmnis
conference in Holland in November.)

NAMING WINDOW CONTROLS:
We don't really have to redraw the whole window, as the only object we have
dine anything with is the employee list. In our simple window it does not
really matter, but in large windows with lots of object a redraw may cause a
noticeable flicker. So it is often advisable to be aware if this and only
redraw where needed. If so, we can redraw using the $name property of the
object like this:
Do $cinst.$objs.ObjectName.$redraw()

To find $name of a field, look in the Property manager. (Note, as discussed
earlier all properties have a $ prefix. However, in design mode the Property
manager does not show the $-sign, so the property will simply be labelled
"name".

However, when you do that for the fields in wTask, you will notice they are
all given rather meaningless names like "wTask_1016". This is because we
haven't named those controls, so they still hold the names assigned by
Studio when they were created. We want to replace them with names that
illustrates their purpose in the code. As usual, the standard is up to the
programmer to decide. Some simply copies the column part of the dataname up
there, some adds a prefix like "ef" for entry field, some like upper case,
some prefer lower case.

On thing that is strongly recommended is to avoid spaces or special
characters, a s these may confuse the notation in your methods. For
instance, the period (.) is used a notation separator, and comma as a
function separator, so if you used one in you $name Omnis would not know if
this was one or two arguments.

Some objects don't have a dataname, for these you just have to come up with
a descriptive name. Labels don't even have a $name, these you will have to
refer to using $ident, which is the unique numeric identifier of the control
within the class/instance.

I will leave it to you to some up with a scheme that suits you best, in the
tutorial I will use the column part of the dataname for entry fields,
without the "c" prefix, and same case as the column name. The column name
doesn't have any spaces or other special characters, so we can use them as
is.

Now this will work for the entry fields, but what about the radio buttons
and the list? $name should be unique for each control, but the radio buttons
share the same dataname. And the list doesn't have a simple column name. So
here we have to be creative. I will use the $text (the "label" of the radio
button) instead, with underscore (_) replacing any spaces. So for the "Not
selected" radio button $name will be Not_selected. And for the list simply
use the variable name without the prefix, so since the dataname is
iEmployeeList we name the control EmployeeList.

So select each control in the window and name them using the first property
in the Property manager.

Once you have named them, go back to the $construct method and change the
last method line to read:
Do $cinst.$objs.EmployeeList.$redraw()
Assuming of course that you are using my suggested naming convention. If
not, substitute your own.

LIST METHODS:
Now after this little detour into object naming, let us continue
implementing the list methods and properties. So far we have completed the
three first steps: We have set the data name and calculation for the list,
and we have built the list of all employees when the window opens. Next is
the method for selecting an employee and linking to the task, so go back to
design mode on wTask.

WHEN THE USER SELECTS AN EMPLOYEE:
4. We have briefly discussed the concept of events earlier, in part 3 and
during our look at the wEmployee window in part 7. Events are triggered by
user actions (or system events), in this case the user will be selecting a
line in the list, which triggers an unclick event in the list control. The
event handler method in Studio is called $event. Double-click the list
control to open its methods, and you will find that Omnis has already added
one called $event for us. This is where we will add our event handler, which
will simply look like this:
On evClick
  Calculate iTaskRow.cEmployeeID as iEmployeeList.cID

The first line tells us which event to react upon. Some controls react to
more than one event, so we need to filter out the appropriate event for each
action. You can have more than one event in a single "On" statement,
separated with a comma.

The second line says "take the ID of the employee in the list and calculate
the EmployeeID foreign key in the task row to be the same". Note: You may
notice that iEmployeeList.cID seems to be ambiguous. There are more than one
employee in the list, so how do we know which ID to use? Shouldn't we
include the line number in the notation? We could do that, the full notation
for accessing a list column would be: Listname.LineNumber.ColumnName.

But the way it is implemented in Studio, if you leave the line number out of
the notation, it will assume that you mean the "current line", which is
exactly what we want in this case. If we wanted another line, we would have
to include it. Btw: The current line of a list is Listname.$line, so if we
wanted to, the full notation for the above statement would be
iEmployeeList.[iEmployeeList.$line].cID Note the square brackets, [], which
tells Omnis to substitute the value of the enclosed property (or variable)
in this position.

To try the event method out, open the window in runtime mode again, and
select one of the employees in the list. Now open the Catalog, go to
instance vars and right-click on iTaskRow, and then select the first option
in the context menu to look at its values. The cEmployeeID column should now
hold the ID of the selected employee.

Since the list displays the employee name, we don't have to do anything more
to display the employee when selected. But the list is independent of the
task row, and will not automatically display the correct line when we go to
another task. So we need to add code to handle this as well.

DISPLAY THE EMPLOYEE FOR A TASK:
5. When we find a given task (by a find, next or whatever means) we want the
list to display the employee for that task. Since our employees are shown as
a list, that means we have to search the list for the correct line, and set
that to be current. The column we use for that is the ID, which is stored in
both tables: cEmployeeID in the Task table and cad in the Employee table.
(Refer to part 4 and 5 for discussions on foreign keys and our data
structure.)

So assuming we have found a task record, we need a method that performs the
list search. Since we may want to use this method with more than one list
control (both the pop up and drop down in a multi-platform application) we
make this a class method. So go to the class methods for wTask, right click
on Class methods and select Insert New Method. Name the new method
DisplayEmployee. Since this is an internal subroutine for the window, we do
not need to give it a $prefix. (I promised in an earlier chapter to discuss
public versus private methods in more details later, But I thin we need to
wrap it up for today. And another side track may distract you from the main
issues. Since this tutorial comes in plain text format, it is not easy to
follow the main thread with too many inserted comments like this.)

Our DisplayEmployee method will be called from the methods that find a task.
It will use the ID of that task to locate the employee in the list. The best
way to tell our subroutine what the ID is, is to pass it to the subroutine
as a parameter. A parameter is a local variable in a method that gets its
value from the calling method. To create one select the Parameter tab in the
variables pane of the method editor. Name the parameter pID, type Number,
and subtype Long Integer to match the data type of the ID columns in our
schemas.

Now type the following method lines:
Do iEmployeeList.$search(iEmployeeList.cID=pID,kTrue,kFalse,kFalse,kFalse)
Do $cinst.$objs.EmployeeList.$redraw()

The first line does the actual search, and takes 5 parameters:
a. The search criteria, in this case we want to search for lines where the
employee cID equals the pID passed. There should only be one, as cID is set
to be a unique key. (However, since we still type in the ID manually, we may
have managed to use the same twice. We shall use methods to generate keys
later.)
b. The second parameter tells Omnis to search the list from start, which is
what we want. (In other cases you may want to continue a search from where
it last stopped.)
c. The third says selected lines only, which we set to false, because we
want to search all the lines.
d. The fourth will select all matching lines, if more than one
e. The fifth will deselect all lines that does not match.
We leave the two last arguments false, because Omnis will then set the
current line, which is what we want.

The redraw is probably not needed, because the method will be called from a
method that finds a task, and this will most likely do a redraw on the whole
window. So we may end up taking this one away.

So, now we have a working employee list, which displays the first and last
names of the employee, lets us select the employee for a task, and which
will display the correct employee for a task when we fetch it. What remains
is the controls and methods to find, save, delete a task. We will implement
these next time.

Until then, take care!


========================================

The Omnis Web Client

The Omnis Web ClientT is a revolutionary new technology that lets you create
any type of application and deploy it to the Internet or your Intranet. It
lets you design and implement genuine thin client, multi-tier, and web-based
solutions for different business sectors and fits the ASP/dedicated web
application scenario very well. The Web Client lets you deploy the GUI
aspects of an application to web browsers, while the business logic and
database management is handled on the Omnis Server, via your web server. The
Omnis Web Client is an ActiveX or Netscape plug-in that embeds the Omnis
driven GUI in a web page, and at under 500K allows for reasonable download
times to clients.

For more details about the Omnis Web Client, to download the client (it's
free), and to view our gallery of sample applications, please go to:
www.omnis.net/products/webclient


========================================


Modifying the Component Store
By David Swain, Polymath Business Systems Inc
Email: dataguru@polymath-bus-sys.com
Web: www.polymath-bus-sys.com

------------------------------------------------------------------

One of the most frequently used tools in the Omnis Studio Integrated
Development Environment (IDE) is the Component Store. While we all use its
contents every time we sit down to work with Omnis Studio, many people still
don't understand that it is meant to be modified to suit our individual
tastes and work styles.

In many previous articles I have suggested that certain modified components
would make good candidates for adding to the Component Store, but I
neglected to tell you how that might be accomplished. This next series of
articles will explore the different types of Component Store features and
many ways we can take advantage of them.

Opening the Component Library

The Component Store is simply a special library that is installed with our
development copy of Omnis Studio. Its name is "comps.lbs" and it is found in
the "Studio" directory/folder inside the main directory/folder of our Omnis
Studio installation. While this is interesting information, it is not
necessary to know where the Component Library resides to work with it
(unless we need to completely replace it). Omnis Studio knows where to find
it and gives us access to its contents in a special way.

PLEASE NOTE: You should make a backup copy of the Component Library before
you start modifying it.

The first thing we must do to examine and perhaps modify the contents of the
Component Library is to open it. If you didn't already know, we do this by
using a command found in the context menu of the Component Store window. We
access this menu by performing a "context click" (right mouse button on
Windows and Linux, control-click on MacOS) somewhere on the window (except
on its title bar, border or scrollbar). This menu is actually the View menu
for the Component Store window, which can be installed by toggling on the
"Menu Bar" option. (I don't want to go further astray explaining all the
features of this menu, but its basic purpose is to let us customize the look
and placement of the window to better fit our working style.)

The menu option used to open the Component Store library is labeled "Show
Component Library In Browser". If we toggle this on, the Component Store
window is emptied of its contents and the "Component Library" appears in the
Library Browser. While the Component Library is open in this way, we cannot
drag classes from the Component Store, but we can still drag classes from
one library's Class Browser to another and we can still drag components
between windows, reports, etc. We also still have access to "built-in" field
level and background components, but not to external components or
collections of custom components (which I will explain later in this
article).

The main reason for opening the Component Library is to modify its contents.
We have the same access to the classes of the Component Library as we do to
those of any other library. If we double-click on the library icon in the
Library Browser, we open the Class Browser for the Component Library. This
Class Browser is the same as for any other library with one exception: the
Class menu has an additional option at the bottom labeled "Component Store
Type...". This applies to a selected class in the browser.

Component Store Types

A class of the Component Library can be one of five types: "New class
default", "Template", "Design objects", "Wizard", or "Hidden". Any new class
introduced to the Component Library begins its existence as "Hidden". To
examine or change the Component Store type of a class in the Component
Library, we select the "Component Store Type..." item from the Class menu
and use the radio buttons on the dialog window that appears. In this
article, we will limit our exploration to the "Design objects" category.

Only certain types of class can be legitimately set as the "Design objects"
type: those that have "built-in" internal components that are normally
selected from the Component Store. These are Window, Report and Toolbar
classes. (Remote Form classes only contain external components and these are
treated a bit differently, as are external window and report components.)
Earlier generations of Omnis Studio used a naming convention to distinguish
design object collections from other Component Library classes. The name of
each such a class begins with an underscore ("_") character. (This is still
expected by the tooltips facility, so we'll follow this convention when
naming new classes of this type.)

Customizing Design Components

Go ahead and open the Component Library class named "_Field Components".
Here is where the Omnis Studio window field components reside. When we drag
a window field component from the Component Store, we are really dragging it
from this class in the Component Library. If we modify the properties or
methods of a component in this class, those modifications will forever be
included with that component when it is dragged from the Component Store
(using the associated development copy of Omnis Studio) in the future.
Obviously, this will not affect development copies on other machines or in
other directories, but we can always replace the "comps.lbs" libraries of
our other copies (or those of our co-workers) with our customized one if we
choose.

We can go wild setting up customized field components to work the way we
want them to here. Think of all the changes you commonly make to fields
dragged from the Component Store, then make those changes here as a
preemptive strike against future hassle and busy-work. Here are some of my
favorites:

Masked Entry Field: set the "formatmode" property to "kFormatCharacter"
(since I most frequently used masked fields for character data) and the
"allowempty" property to "kTrue" (since most of my masked fields contain
optional data).

Headed List Field: set the "horzscroll property to "kFalse" (since I rarely
use a horizontal scrollbar on this field type), "boldheader" to "kTrue"
(since I like the look), and "enableheader" to "kTrue" (since I usually want
to sort the list contents based on a header click).

Tab Pane Field: set the "tabstyle" property to "kTrianglePanes" (my personal
preference) and the "tabcolor" and "selectedtabcolor" properties to colors
that show a distinct difference and work with my preferred window background
color.

You get the idea. I also modify or add methods to many of these field
components:

All appropriate list display fields: add methods for printing the list
contents to a special report that uses a Report Data Grid and for setting
the column properties to be transferred to that report component (see
previous articles on list display field types).

Headed List Field: add methods for sorting the list based on which column
header is clicked and then re-locating the current line after the sort.

Tab Pane Field: add skeletal method for putting the focus into the first
enterable field on the selected pane (a Switch-Case block based on
pTabNumber).

Tree List Field: expand methods for expanding and collapsing nodes of the
tree with skeletal code.

All container fields: add a $control() method.

There are many others that I use and you will find even more that match your
individual preferences. The point is, we can truly personalize our
development copy of Omnis Studio and save ourselves hours of time.

System Tables in the Component Library

I also set appropriate fieldstyles for Component Store field components. We
have to remember, though, that each library, including the Component
Library, contains its own version of #STYLES and the other System Tables.
This can be a very convenient feature as well. These System Tables are
***not*** used as the defaults for new libraries and the Component Store
does not offer us a direct means of transferring them into other libraries,
but the Class Browser does.

Suppose we have created the ultimate set of Text, Date, Numeric and Boolean
formats and input masks in one of our libraries. We can open that library's
Class Browser, open the Component Library, and drag these special System
Tables (#TFORMS, #DFORMS, #NFORMS, #BFORMS and #MASKS respectively) to the
Component Library to replace the basic ones. Then we can reverse this
process for every new library we create. (If you don't remember, we can make
these classes visible by using the "Browser Options..." item from the View
menu of the Class Browser.)

We can also do this for #STYLES, but we might want to first examine what
we're replacing. Beginning with Studio 3.0.2 for MacOSX (I haven't received
version 3.1 as of this writing, but I assume this will hold true there), the
Component Library contains a very extensive set of fieldstyles right down to
having a separate style for each component type. This reflects the new
"themes" and other features introduced by OSX. While this #STYLES System
Table is not automatically put into new libraries, we can easily open the
Component Library and drag it to our new libraries as outlined above. We can
also add our own touches for each supported platform to the #STYLES in the
Component Library itself.

In this way, we can specify fieldstyles in our Component Library that will
already be in force when we subsequently drag fields from the Component
Store. Since fieldstyles are now (beginning with version 3.0.2) more like
interface rules than simply text properties, our work has become that much
simpler!

Adding Sets of Specialized Components

I don't know about you, but I have a number of specialized field components
of many field types that I use repeatedly, not just one per field type.
After a while it becomes a bit of a hassle to drag them from some earlier
window or report, especially if I'm creating a new library and have to dig
through my old ones to find the right one for my needs. Wouldn't it be great
if we could have multiple versions of various field components in the
Component Store set up for special purposes and then labeled appropriately?

Well, we can! We can create a new window (or report or toolbar) in our
Component Library, name it appropriately, set its Component Store Type as
"Design objects", and then add any components we like with whatever names
make sense to us. This window will appear in the Component Store as an
additional icon along the Component Store toolbar and its tooltip will
contain the name of the Component Library window class (minus the leading
underscore character).

If we only have a few such specialized components, we only need one
additional window. But why not emulate the Class Wizards and Templates
selection in the Component Store and create a separate "Design objects"
window (or report) for each field type for which we desire pre-configured
specialized components.

For example, I have a number of commonly used masked entry fields. Among
them are: US Telephone, Social Security Number, Full Date, Dollar Amount,
etc. I have similar sets of Entry Fields, List Boxes, Headed Lists,
Pushbuttons, and other field types. We can make separate Component Library
"Design objects" classes for each of these and they will all appear in the
Component Store toolbar appropriately labeled.

But how will we distinguish them visually? By default, they will all display
a window icon in the Component Store toolbar. But we can change the
"componenticon" property of the Component Library class to better reflect
its contents. For example, I selected the masked Entry Field icon (icon
number 1834 in the "k32x32" size, found on the "Window Components 2" page of
the "OmniPic" icon file) to represent my set of specialized masked entry
fields. I also named the Component Library class "_Masked Fields". This
makes the set very easy to identify while I'm working - and the rest of my
work goes much faster as my specialized component sets mature.

External Component Collections

The external component design objects collections for window, report and
remote form classes are actually "Hidden" classes in the Component Library.
Their names all begin with a question mark ("?") character like the Wizards
and their auxiliary classes. We can still open these and make adjustments as
we see fit. My most pressing need was to open the "?Remote Form Components"
class and turn on evClick event detection for the Pushbutton and Button Area
components (since I couldn't imagine using a pushbutton that doesn't at
least respond to clicks!). This prevents me from having to remember to set
this for each such button I place on a remote form in the future. As with
field components, we can also add methods to external components that will
be part of their default state. You may well find many such adjustments to
perform that will make your life easier.

I hope this has proven useful to you. In the next issue we will examine "New
class default" and "Template" Component Store types.


========================================

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 Technical 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.
© Copyright Raining Data, Inc., and its licensors 2001. All rights reserved.
Omnis® is a registered trademark and Omnis 7T, 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