[Omnis-Newsletter] Omnis Tech Newsletter

omnis-news-admin@omnis.net omnis-news-admin@omnis.net
Wed, 18 Apr 2001 16:30:17 +0100


Omnis Tech Newsletter April 18th, 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 to this the third issue of our Omnis Technical Newsletter. Published
fortnightly, it is intended for Omnis developers of all levels and
experience and for those people evaluating Omnis Studio. 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.

The first article in this newsletter illustrates very nicely the distinction
between variables and fields, which is something you need to consider when
setting values in memory and displaying the results of calculations on
screen. The second article will interest anyone wishing to make their Omnis
applications truly portable for world-wide markets, in that it discusses the
use of String tables to display language-specific text and field labels in
your 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
-Variables and Fields, by David Swain
-Openday: Enterprise Development for Mac OS X Made Easy
-About the Omnis News
-String Tables, by Geir Fjaerli
-About the Omnis Studio Editions
-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.


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

Variables and Fields
By David Swain, Polymath Business Systems Inc
Email: dataguru@polymath-bus-sys.com
Web: www.polymath-bus-sys.com

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

Many newcomers to Omnis Studio confuse the terms "field" and "variable" or
use them synonymously where they have separate and distinct meanings. For
the purposes of discussing and using Omnis Studio programming, precise and
rigorous definitions will serve us well in the long run, so let's establish
some rules on terminology to help future explanations be clearer.

Variables

A "variable" is a "virtual value container" in RAM. A variable has a name
and a datatype and is used to hold a value. We cannot "see" a variable (it
is only a memory location after all), but we use it by reference to its
name. A variable exists in only one place (its memory location in RAM), but
we can display its value in many places using fields. (Yes, I realize that a
data-bound variable in a File Class is referred to as a "field" in the File
Class Editor, but this is an archaic Omnis term that I prefer not to use for
clarity's sake.)

Variables can be either "scoped" or "data-bound". A "scoped" variable is
generally defined in the Variables Pane of the Method Editor and may only be
referenced when it is "in scope". For example, a "local" variable can only
be referenced from within the method for which it is defined. Omnis Studio
also comes with a set of variables that are "global" in scope (i.e., they
can be referenced from anywhere within Omnis Studio) called the "hash"
variables (their names begin with a "hash" symbol -- #).

"Data-bound" variables are those defined in a File Class. The name implies
that they relate to a retrievable storage location on disk as well as to a
location in RAM (a slot in a construct known as the Current Record Buffer or
CRB). They are also "global" within the context of an Omnis Studio library.
The names of "columns" from a Schema or Query Class would technically be
data-bound variables as well, although they are most often used to define
the columns of a (scoped) list or row variable and don't have an independent
existence or RAM allocation of their own. Still, they serve as a bridge to a
value stored in a database.

Fields

A "field" is a foreground component object on a window, remote form or
report. The term "field" indicates an "area", and fields all exist as a
rectangular area on the visual aspect of their respective Classes. Many
types of field can be used to display and manipulate the value of a
variable. Other fields are of a special type we call "controls", which are
used to either manipulate data in a special way (e.g., radio buttons) or to
simply allow the user to invoke methods (e.g., pushbuttons). Fields used to
display or manipulate the value of a variable have both a name and a
dataname (the name of the associated variable). The name and the dataname do
not have to be the same, although this is not disallowed and may be more
comfortable for new Omnis Studio users migrating from certain other
products.

Although variables and fields (as defined here) are separate and distinct
entities, there are a number of interesting and useful ways in which they
interrelate. The remainder of this article contains exercises that
demonstrate some revealing techniques and tidbits.

Field Placement Using Variables

Because of the way we normally introduce newcomers to Omnis Studio
programming, nearly everyone soon learns that we can add new field
components to Window, Report and Remote Form Classes by dragging them from
the Component Store and dropping them onto the Class Editor. Such components
have no dataname property value automatically assigned, but we teach that
variable names can be assigned to that property using the Property Manager
and the Catalog.

For the most basic field-variable type combinations, there is a shortcut
that can save a step for each placed field. We can drag a variable name
directly from the Catalog (Variables and Hash panes only) onto a class
editor (window, report, remote form) and a basic field with that variable
name already assigned to the dataname property appears. Try the following
exercise to explore the possibilities and limitations of this technique:

Exercise 1: Placing Fields from the Catalog

1. Create a new Window Class and name it "winFldTester".
2. Open the Method Editor for this class (by double-clicking anywhere on the
window) and create the following instance variables using the Variables
Pane, making sure to select the appropriate data types:
Variable Name  Datatype
string1   Character
number1   Number - long integer
date1   Short date 2000-2099
boolean1   Boolean
list1   List
picture1   Picture
3. Close the Method Editor. The Class Editor for our window should now be
open and on top. If it isn't, click on it to bring it to the top.
4. Open the Catalog by either selecting View>Catalog from the main menu bar
or by using the F9 or Ctrl/Cmnd-9 keys. Then click on the Variables pane and
select "Instance" from the list on the left. The list on the right should
display the names of the variables you created in step 2. Arrange the Window
Class Editor and the Catalog so that both can be viewed.
5. Drag the variable named "string1" from the Catalog window and drop it
onto the Window Class Editor. Notice that as soon as the drag operation
begins, the variable name and an icon representing an entry field attach
themselves to the mouse cursor. The mouse cursor itself displays its "no
drop" image until it is over an appropriate place to drop the field (i.e.,
over the Window Class Editor). Drop the field onto the window.
6. Examine the properties of the new field using the Property Manager (press
F6/Cmnd-6 to open). Notice that the variable name has already been assigned
to the dataname property. All other properties are the same as they would be
if the field had been dragged directly from the Component Store.
7. Now drag the variables "number1" and "date1" to the Window Class Editor
in the same way. Notice that the only difference between these and the first
field created is the dataname assigned (and the top and left coordinates
where the fields were placed). The point here is that variables of most
datatypes dragged from the Catalog in this way will create Entry fields.
There are a few exceptions, though.
8. Now drag the variable named "boolean1" from the Catalog to the Window
Class Editor. Notice that this creates a Checkbox field instead of an Entry
field. Again, the dataname property is set to the name of the variable used
as the source of the field, but all other properties are as they would be if
the checkbox had been dragged directly from the Component Store. It is up to
you to supply an appropriate name and label text for the field.
9. Now drag the variable named "list1" from the Catalog to the Window Class
Editor. Notice that this creates a List field instead of an Entry field.
10. Now drag the variable named "picture1" from the Catalog to the Window
Class Editor. Notice that this creates a Picture field instead of an Entry
field.
11. For extra points, repeat this exercise for a Remote Form Class and for a
Report Class. Here is what you should notice for each of these:
Remote Form -- works basically the same as the Window Class. Some of the
component names are slightly different (Single Line Edit and Check Box
instead of Entry and Checkbox), but otherwise you should see no differences.
(By the way, you should ONLY use instance variables on a Remote Form.)
Report -- Boolean variables also create Entry fields since there is no
checkbox-type component for a report. List variables dragged to the Report
Class Editor vaporize on contact. That is, they cannot be dropped onto a
report. Yes, there are now list-type fields for reports, but they are
external components, not built-in ones, so this technique doesn't work for
list variables.

Current Values and Screen Buffers

The dual nature of a Remote Form Instance (visible aspect in the client's
web browser and invisible aspect on the server) is well established in the
basic Web Client course I teach. Our ability to manipulate the contents of a
report field that is about to be printed while not affecting the value of
the variable from which it is spawned is explored in the Reporting
Techniques course. I have not explicitly demonstrated the related aspects of
window fields until this article.

There are two places where the value of a window field exists. Omnis Studio
does a great job of keeping them in synch, but we can still separate them if
we are (or are not) careful. First there is an area in RAM I will call the
Current Values Buffer (CVB) where the variables "live". Calculations and
other operations performed on variables happen here. (We can only change the
values of variables that are currently "in scope" for most operations, but
there are notational techniques that bypass OO rules and can be used to
manipulate "out of scope" variables. This is not a recommended practice, but
it can be done.)

There is also a separate area I will call the Screen Buffer. This area is
used both to display the value of a variable and to accept data entry that
will be passed to the CVB for a variable. At certain times the Screen Buffer
can hold a different value from that in the corresponding variable in the
CVB, but Omnis Studio automatically synchronizes these two memory locations
for many operations. Occasionally, though, it is our responsibility to do
this.

Consider what happens during data entry. The user types a new value into a
field. If the user then moves the cursor to another field, the new value is
copied into the corresponding variable in the CVB. This is an attribute of
the field, so it happens even before the fields $event() method can react to
an evAfter event.

If a calculation in some method affects the value of a variable, it is our
responsibility to transfer that value into the Screen Buffer for display. We
do this by using either the Redraw command or by issuing a $redraw() message
of appropriate scope. Sure, Omnis Studio could have been made to do this
automatically, but resulting applications would look really bad with changed
values popping all over the screen while some lengthy background method
executes. We were therefore given the ability to determine at what time and
to what collection of objects this operation will be done -- but with this
comes the responsibility to make sure that it does take place.

Let's examine how this all works with some examples:

Exercise 2: Fun with Fields

1. Open the Library Browser and select the current library. Then use the
View menu of the browser to open the Properties for this library. Click on
the Prefs tab and set the canfocusbuttons property to kFalse. (We need this
setting to make some of the final examples of this exercise work as
described on all platforms.)
2. Now open the Class Browser, create a new Window Class and name it
"varFldTests". Double-click the window to open its method editor.
3. In the variable pane at the top, create two instance variables of
Character type named "variable1" and "variable2" for this window class.
4. While in the Method Editor, put the following code in the $construct()
method for the window:
Calculate variable1 as 'old value'
Calculate variable2 as 'anything else'
This will reestablish a known base state that we can return to by closing
and reopening our test instance of this window.
5. After closing the Method Editor, drag a field for each variable from the
Catalog to the Window Class Editor. (You can drag them from the Component
Store instead and then assign the datanames if you wish.) Name the field for
variable 1 "field1" and the field for variable2 "field2" (you name fields by
entering text in the name property of the field using the Property Manager).
The order property for field1 should be 1 and for field2 should be 2 (again
using the Property Manager). Align these fields with the one for variable1
above the one for variable2 and set their enabled property to kFalse. (We'll
do an even more interesting exercise with these fields being enterable
before we're finished.)
Remember that we can select multiple fields by dragging a rectangle with the
mouse cursor that touches or encloses those fields. We can then work with
them as a group, using the alignment options of the windows context menu or
modifying any property the selected fields have in common using the Property
Manager.
6. Drag a pushbutton field from the Component Store to this window. It will
be "user defined" by default (unless you have modified this in your
Component Library), but check to make sure that the buttonmode property is
set to kBMuser. Then set the text property to "test".
7. Having established the tools for this exercise, let's put some code
behind the pushbutton. All of the following steps involving this code assume
that the first line of the $event() method is "On evClick".
Double-click the pushbutton field to open the Method Editor directly to its
$event() method and enter the following line of code after the "On evClick"
line that is (or should be) already there:
Calculate variable1 as 'new value'
8. Now close the Method Editor and open a test instance of the window using
the Ctrl/Cmnd-T key combination. Then click the pushbutton. Nothing appears
to have happened.
9. Open the Catalog and make sure the Variables pane is selected, then click
in the Instance variables group in the left column. Move the mouse over the
name "variable1" in the right column (or Right/Ctrl-click and hold to
display the context menu). Notice that the variables value is 'new value',
but we haven't transferred it to the Screen Buffer yet.
10. Close the test instance, go back to the $event() method for the
pushbutton and add the following line of code to what is already there:
Redraw {field1}
(The line "Do $cinst.$objs.field1.$redraw()" will do the same job.)
Now perform step 7 again and notice that the new value appears in the field.
11. Close the instance and go back to the $event() method for the
pushbutton. We will now demonstrate that notational changes to properties of
window fields take place immediately and do not require a redraw as do
changes to the variables they represent.
Change the "redraw" line to the following:
Calculate $cinst.$objs.field2.$dataname as 'variable1'
Since this is performed after the calculation affecting the value of
variable1, we will see whether the new value appears in field2 without
benefit of a redraw. Now open the test instance and see.
12. Close the instance again. This time we will leave the code as it is, but
change the context slightly. Select both entry fields and change their
enterable property to kTrue. Now open the test instance. Notice that the
value in field1 is highlighted (selected). Don't do this, but if we were to
type on our keyboard the value displayed would immediately be replaced by
what we typed. Instead, click the pushbutton. Notice that the same thing
happened as in the previous step. Now tab to field2.
Wow! Both fields now display "old value". If we bring up the Catalog and
examine the value of variable1, we see that it has changed too. But we had
just calculated the value to be "new value" -- what happened? Well, the
Screen Buffer still had the value "old value" in an active data entry field.
When we tabbed out of that field, Omnis automatically replaced the value in
the CVB with the one from the active entry field. Furthermore, Omnis also
automatically redrew the next field we entered (field2) to make sure the
value we were about to modify matched the one in the CVB. Got that? OK, one
more demonstration.
13. Close the instance again, reopen it and click the pushbutton. Now bring
the Catalog window to the front (press F9/cmnd-9), then bring the test
instance back to the front. Both fields should now read "new value". Omnis
did an automatic redraw of the window instance when it was brought back to
the front, so the value from the CVB is established everywhere it is needed.
This will only work for windows in Instance Space (like the Catalog), but
windows in Design Space (like the Property Manager or the Class Browser)
appear to be treated like palettes in this regard.

While this exercise doesn't show you how to write better or faster
applications, it does help explain effects you may (and probably will)
encounter in your work with Omnis Studio. Remember these examples if you
ever find your variables and fields don't correspond.

Future articles will assume that "variable" means the place where a value is
held and may be manipulated by method commands and "field" means an area on
a visible class or instance where a value may be displayed or manipulated by
the user.


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

Openday: Enterprise Development for Mac OS X Made Easy
Stockley Park, Uxbridge, UK
24th April, 2001

For those of you in the south of England, you may be interested to know that
Raining Data, along with FrontBase and Apple, will be running an open-day at
Apple's UK headquarters on Tuesday 24th April, 2001.  Whether you are
currently developing software on Mac OS X, Mac OS 9, Windows or Linux, this
open day will give you an excellent opportunity to learn more about Omnis
Studio, FrontBase plus other Raining Data products including Omduit and
mvDesigner.  The day will also be a great chance to meet the Omnis team and
other Omnis developers and evaluators from around the UK.  As an added
bonus, Apple will be offering a 20% hardware discount to attendees on the
day.  For more information and to register, visit:

www.omnis.net/openday


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

About the Omnis News

Published weekly, the Omnis News contains all the latest company and product
news and is a must-read for all dedicated Omnis developers and for those
evaluating Omnis. Each issue contains an Omnis-related 'Site of the Week',
an Omnis Studio tech tip, as well as all the news items concerning trade
fairs, conferences, training dates, seminars, latest product releases, and
more besides. The Omnis News is published every Friday, so why not grab a
coffee now, and take a few moments to read the latest issue at:

www.omnis.net/news

And while you're there, don't miss the back issues:

www.omnis.net/news/backissue.html


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

String Tables
By Geir Fjaerli, Sunshine Data
Email: geir@sunshinedata.net
Web: www.sunshinedata.net

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

With the latest version of Omnis Studio (version 3.x), new functionality has
been added to allow for multi-language applications. The process of porting
or developing applications for multi-lingual support is referred to as
"localization".

What are the issues with localization? Say you want to ship your application
in an international market. There are many problems connected to this. E.g.
if you are making accounting software, the German and French laws are
different from the US ones. But in addition to such application specific
issues, there is one common to most of them: The user will expect a
localized interface. The key elements to consider are:
* The labels in windows and reports should be in the local language.
* The text on buttons and other controls.
* Any messages to the user or help texts.

While there are other issues, like units of measure (inches vs. centimeter)
and currencies, etc, I am going to focus on the labels and text issues.
There are several ways to approach this problem:
(a) You can keep multiple language specific versions of your application.
(b) You can use a utility that lets you translate all the texts of a master
library.
(c) You can store all texts in the database, and use normal display fields
instead of labels in your windows.
(d) You can store the text in separate files on the hard disk, and read them
in at runtime.

Solution (a) requires you to maintain and update several versions of your
app. Most of us have more than enough to do with one copy, so this is
clearly something to avoid. Solution (b) requires you to apply the
translation for every language every time you have a new release. Obviously
it would be better if the translation was just done along with the
development.

Omnis offers an elegant way to handle the last two solutions (c and d
above), called String tables. A string table is a list of strings with one
row for each label/text, and a column for each language, plus a column for a
unique Id used to locate the string. You can use a string table column
anywhere there is text in the application. Also you can store your string
tables in the database if you prefer. How do you use them:

* First, create your stringtable. This can be done in Omnis using the String
Table Editor, available in the Add-ons submenu on the Tools menu. You can
also export the strings into a file and use another program if you prefer.
Or make your own editor, using Studio and the String table functions (see
next issue for more detail). Set up columns for each of the languages (you
may add columns to existing string tables later.) You can have one string
table file holding all your strings, or multiple string tables, say one for
each module in your application.

* Now start adding the strings, one row for each. Any string may be used as
many times as you like throughout the application, so you may plan a bit so
that you do not end up duplicating them, if for example several windows have
a cancel button, you only need to have Cancel once in your string table.
Each row needs a unique ID in the first column. This is used by Omnis to
locate the correct row at runtime. Note that the string table will be sorted
according to this ID when you save it. This is done to facilitate faster
retrieval of a given row, since Omnis can then do a binary search for it.
But the side effect is you cannot organize your strings in logical order
within the file. The ID can be any alphanumeric character, when you create a
new stringtable Omnis suggests an 'A' as the ID of the first row. However,
since you need to reference these in your windows, reports and code, I
advise that you use descriptive IDs. Say for the Cancel button text, use the
id 'cancelbutton' (without the quotes).

* Before you start using the string tables, please note: The Stringtable
functionality is implemented as a 'non visual component' in Studio. Some of
these components will support dynamic instantiation, and you add an object
variable of suitable scope to instantiate them. (E.g.
myObjectVar.$functionname). Stringtables however are static. You do not
create object vars to hold them, instead you just prefix the stringtable
functions with the built in identifier 'Stringtable', e.g.
StringTable.$gettext(myrow).

* Now you are ready to start using the strings in your library. Before the
strings are available in your app, you need to tell Omnis where they can be
found, since they are stored in external files. This is done with
StringTable.$loadstringtable(tablename,path). The tablename is whatever you
want to refer to when you use the table later, if you have multiple
stringtables in your application you will need to prefix the rowid with the
table name. (This is a good practice anyway, this way it will still work if
you decide to add more tables later.) The pathname is the path to the
stringtable file on disk. Do not use hardcoded paths, remember the
application may be installed in a different place on your users machines
than on your development machine. A good practice is to have the
stringtables in a given location relative to the application, say in a
subfolder within the application folder. This way you can use sys(10) to
find the path to the application, and use the splitpathname function to
build the path to the stringtable.

* Next you need to select the column to use. This you do with the
StringTable.$setcolumn(columnname) function. Since the user is likely to
want the same language every time he opens the application, you should store
the current column somewhere, e.g. in your user prefs table in the database
or in a prefs file on disk. Also you will need to have some mechanism for
selecting language, maybe a menu choice or a drop down list in your options
dialog window. You can change the language at any time, but you will need to
redraw to update open windows. The normal redraw command doesn't work here,
instead use the StringTable.$redraw(Hwnd) function. Personally I prefer to
allow change of language only at startup, one less thing to confuse the user
at runtime.

* The easiest way to use stringtables is to use them in window and report
labels. Omnis has an external background component called 'String label'. It
looks and behaves much like the standard label, except it doesn't take a
hardcoded text. Instead you type the row ID of the string you want to appear
into the rowid property on the Custom tab of the Property manager. Remember
to prefix with the stringtable name as discussed above (tablename.rowid).

* Anywhere else you want to use stringtable text, use the
StringTable.$gettext(tablename.rowid) function. Remember that since this is
a function that needs to evaluated, you will have to use square brackets in
text attributes. E.g. [StringTable.$gettext(myOKtext)] in an OK message. You
can use the $gettext function inline, e.g. "Calculate myVar as
con(StringTable.$gettext(myrow),somenumber)". Again, remember the table name
prefix.

This is all there is to it. There are a number of other stringtable
functions that, for example, allow you to store stringtables in lists (and
consequently in a database table), more on that in the next issue.

One last issue: Using multiple languages adds a new variable to all your
application issues: Strings will invariably be of different length in
different languages. So you need to make sure you have room for the longer
ones in your labels, for example.


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

About the Omnis Studio Editions

Omnis Studio Version 3 is optimized for multi-tier and web-based application
development. Omnis Studio is packaged in three easy and fully scalable
editions to exactly meet your development needs.

*Standard Edition:-
The Omnis Studio Standard Edition provides a cost-effective rapid
application development tool for the small to medium size business and
entry-level developer.

*Enterprise Edition:-
The Omnis Studio Enterprise Edition provides a value-for-money RAD
environment that lets you build literally any type of business solution for
companies of all sizes.

*Web Edition:-
The Omnis Studio Web Edition is the premium cross-platform, multi-tier
application development tool for the serious developer, solution provider,
VAR, ISP, and ASP markets.

For further information about the Omnis Studio editions, please go to:
www.omnis.net/products/studio/editions.html


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

I hope you've found this third 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