Tech News Back Issues Issue: 020906

New Features in Omnis Studio Version 4.1

By David Swain
Polymath Business Systems

After much anticipation, Omnis Studio version 4.1 shipped in December, 2005. There were quite a few new or expanded features, as well as fixes to problems in earlier versions. While the "What's New" document that accompanies this release gives us some detail of most of the new and improved items, there are a few that entirely missed being mentioned there. There are also a number of others that could use some additional clarification - or at least some additional time in the spotlight. We will begin to fill in some of those holes with this article.

Also, some of the items mentioned in the "What's New" document as new in this version actually appeared in Omnis Studio version 4.0 - although they may not have appeared in the "What's New" document for that version. A few of them simply appear in more places now. For example, the Hyperlink control was detailed in Omnis Tech News on April 13, 2004, although it did not appear in the "What's New" document at that time. In version 4.1, it now also appears on Remote Forms in addition to Window Classes. It also now has a new event and a couple of new properties (which are not explained in any detail in the current documentation). This paragraph is not intended to fault the official documentation, which has some improvements of its own (see below), but to point out the enormity and celerity of the changes made in this release. It is difficult for a documentor to keep up with them all!

This article is not intended as a comprehensive listing of all the new things in Omnis Studio 4.1. Rather, it is a mention of some of my favorite new items in this version along with some additional information that is not included in the documentation that accompanied the release. Many features that might be significant to some readers are left out of this one article - either because there is not time or space enough to do the feature justice in a survey article (the Unicode version, for example) or because there is nothing more that needs to be said about the feature (new serial numbering scheme). There will certainly be future articles on items that appeared for the first time or were expanded upon in the Studio 4.1 product. In fact, next month we will take a close look at the new Graph2 component.

Since my most recent computers operate on Mac OS X and I do not have a contemporary Windows machine at this time, I may cover some Mac-specific improvements while not covering Windows- or Linux-specific improvements. This is not done to slight the Windows- and Linux-using developer community. I simply need some new equipment so that I might test those features before writing about them. I hope to have this situation rectified within the next few months.

New Documentation

The very first thing I want to do is to congratulate the Raining Data staff for expanding the documentation for Omnis Studio. Specifically, I applaud their breaking up the old Omnis Reference Manual and reorganizing that material into three separate documents: the Omnis Command Reference, the Omnis Function Reference and the Omnis Notation Reference. If you haven't looked at these pdf files yet, do so as soon as you can.

One notable improvement is the expansion of the header information for commands and functions. For example, the reference manual header information for a method command now states unequivocably which platforms support the command instead of showing symbols only for commands that are platform-specific. It also indicates whether the command is available for the Unicode version, both versions or only the Unicode version of Omnis Studio:

New Command Header Information

The function header information is presented in much the same way:

New Function Reference header Information

The Omnis Notation Reference is organized by class type, with both class and instance groupings within the same section. Properties, methods and events are all listed together for each item that can contain them. Notation for all external components are listed alongside notation for built-in components - for example, all window components that ship with Omnis Studio are listed together. This makes it more convenient for us to find the information we need without remembering whether a specific item is external or built in. While these may seem like minor improvements to some, I find them to be both worthwhile and significant.

Now on to the new features of the product...

New format() Function

Here is an example of an important (at least to me) new feature that did not make it to the "What's New" document - and that barely got a mention in the new "Function Reference" document. We have been given a new string function named format(). It allows us to impose a display mask on a string value as part of a calculation.

So why would we want to do this? My favorite example of the utility of this function is in displaying a formatted telephone number in a list display field where that number had been entered using an input mask to capture and store only the numerals. I will use a North American 10-digit number for this example. In order to do this in the past, we had to deconstruct the telephone number using the mid() function and then reconstruct it using con():

con('(',mid(phone,1,3),') ',mid(phone,4,3),'-',mid(phone,7,4))

Now we only need to apply a display format:

format("'('@@@')' @@@'-'@@@@",phone)

Or if we know the index of the format (1 in this case) within the appropriate system table ($textformats here), we can use notation to access it:


Notice that the format is the first parameter of the function and the value to be formatted is the second parameter. The value can also be derived from a calculation and does not have to be supplied as a variable (in spite of the description given in the manual):


There is much more potential to this function, but we will have to cover that some other time.

New rpos() Function

This function did get mentioned in the "What's New" document, but it could easily escape notice. It returns to us the position of last occurance of a specified character string (the rightmost starting position of the substring) within a given string value. Why would we need such a thing? Well, one use might be in determining the domain type extension from a url (or a file name extension, etc.):


Here we located the position of the last '.' character (there could be many such characters in that string) within url and extracted all the characters that followed it. If no such character exists in url, we get the entire value of url as a result (and can make further decisions comparing what we extracted with the original value, etc.).

I once created a custom function that required a number of lines of code to perform this operation as a demonstration of implicit method execution. Guess I'll have to think up another useful example to use at conferences now!

Really Redraw

We can now force the redrawing of background objects on our windows while also redrawing foreground objects. (Sure, we can use $redraw() directly on a background object, but this new feature has broader application.) The $redraw() method for Window Instances and the foreground objects on them can now accept a third parameter. When set to kTrue, this parameter causes background objects within the scope of the item to which the $redraw() method is applied, such as text objects containing calculated content on the current window instance, to be redrawn. This is only a feature of Window Instances, not of Remote Forms.

QuickTime MoviePlayer Improvements

I am very pleased to report that the MoviePlayer component in Omnis Studio has been updated so that we can take advantage of more recent features of QuickTime than the version 3 level originally supported (and for which the component library that contains this component is still named). Specifically, we can now view streaming QuickTime content using either the Window or the Remote Form MoviePlayer component. While there are no new properties or methods for this component (which is probably why the "What's New" document is silent on this subject), this improvement is still very much worth mentioning! Because the component now supports all current QuickTime plugins, it can play avi and swf movies as well. In fact, with a new (free!) QuickTime plugin from Telestream, we can even play wmv movies using QuickTime on Mac OS X! (For webclient playing of wmv files in the MoviePlayer component, the client must have this plugin installed on their local machine.) With a little more work, we'll be able to edit QuickTime movies right in our applications. (There are currently some redraw issues, but it is possible to drag a second movie from the desktop on Mac OS X to the current MoviePlayer in a window instance and that movie will be inserted at the playhead position in the current movie. More on all this some other time...)

Complex Grid Header Properties

The Complex Grid window component has a new property and some new options for an existing property. First those new options...

We can now determine whether the height of the horizontal header (the header with the same width as the rows in the illustration below, which scrolls horizontally with the rows so that column headings placed there continue to match the column content) can be resized by the user. In the past, the horizontal header could be resized if the rows could be resized, although its height is independent of the height of the rows. This ability is determined by the value of the $canresizerows property. While this ability is still determined by this one property, it is no longer a kTrue and kFalse proposition. There are now four possible values for the $canresizerows property - as opposed to the two possible values from the past. These values (the constants and their numeric equivalents) are now kResizeNone (0), kResizeHeaderAndRows (1), kResizeHeaderOnly (2) and kResizeRowsOnly (3). Notice that an existing complex grid will retain its current behavior because it has either a value of 0 or 1 for this property (from the old kFalse or kTrue value).

The setting of the $canresizerows property now determines not only whether the resize mouse icon (shown in the illustration below) appears, but to what it applies when positioned over the dividing line just below the horizontal header (as shown). If the value is 0, it does not appear. If the value is 1 or 2, dragging this line resizes the horizontal header. But if the value is 3, dragging this line resizes the rows and not the horizontal header. The rows can still be resized by dragging the dividing line below any row - as long as the $canresizerows property value is not 0 or 3.

There are no events triggered as a result of such a user action however, so we cannot react to this change. Then again, what would we want to do if such a change occurred? Omnis Studio already manages whether the thumb and scroll arrows appear in the vertical scrollbar region - as long as we have the $vertscroll property already set to kTrue.

Complex Grid Header Resize

The ability for the user to resize the height of the main header is determined by the value of the $canresizeheader property. This still takes only kTrue and kFalse as possible values and its behavior has not changed.

There is, however, a new property named $canclickverticalheader. This determines whether the user can select (highlight) a row by clicking in the vertical header region of the complex grid field. (This can only be done if the $enterable property value is set to kFalse.) This was not possible in the past. Existing complex grids will continue to exhibit their previous behavior since this property will have a value of kFalse automatically on conversion to Studio 4.1. But we can now allow the user to select a line by clicking in this region in addition to clicking on the display portion of the line. Again, there is no event triggered by this action - and there is no additional event parameter to the evClick event that indicates the user clicked on the vertical header rather than the line.

Headed List Header Resize

We now have an event that reports that the user resized a column of a Headed List Box. The event is named evHeadedListHeadResize and it returns a parameter named pColumnNumber. This allows us (among other things) to dynamically determine whether a horizontal scrollbar is needed for the field if the user changes a column width too severely:

On evHeadedListHeadResize
   Calculate totalWidth as eval(replaceall($cfield.$columnwidths,',','+'))
   Calculate $cfield.$horzscroll as totalWidth>$cfield.$width

Oh yeah, you might find an interesting and useful technique tucked into the code shown above...

Space - The Latest Constant

We have a new Special character constant in Omnis Studio version 4.1. It is kSp - the space character (ASCII character number 32). We can use this inside the con() function (and elsewhere) instead of a space between quote characters - or chr(32). This is especially helpful in constructing long and complex strings, like SQL statements, where we have already used up our two levels of quotes (or our six levels of parentheses). While it doesn't save us any keystrokes on entry (three keystrokes for either this or a space and two quotes - but seven for chr(32)), it does save space once the calculation is tokenized, since the constant only requires one byte of storage where a space and two quote characters requires three bytes (and chr(32) is a function token, two numeral characters and a closed parenthesis - four bytes in all). As part of a large concatenation expression, this new constant could prove to be very useful!

New Hyperlink Features

There are two new properties of the Hyperlink component. These are the $keymodifiers (runtime only) and $tooltipcolumn properties. Neither are explained in any detail in the Omnis Notation Reference - and neither were mentioned in the "What's new" document.

The $tooltipcolumn property allows us to specify a column number of the list that is used to drive the hyperlink control that contains line-by-line tooltips for the items displayed in the hyperlink. All we need to do is create and populate an extra column in that list and point this property at it! If we do not designate a tooltip column, or if we leave the cell in that column empty for a given line, and if the hyperlink control is too narrow to display the entire text for a given line, the text itself becomes the tooltip. Very clever!

The $keymodifiers property is only available at runtime. It keeps track of the key modifiers that were last in force when the mouse pointer was over the area covered by the hyperlink control. It begins its life containing a value of 0, meaning that no modifiers had so far been used while the mouse was over that field. (In fact, the mouse would not have been over that field yet at this point.) This property holds a Long integer value which is derived from the sum of the key modifier constants that are in force. These constants are kCommand or kControl (65536 - or 216), kShift (131072 - or 217) and kOption or kAlt (262144 - or 218). We can then test the value of this property during an evLinkClicked event to determine whether special action should be taken. If more than one modifier key is held down, the values of the corresponding constants are added to yield the $keymodifiers value.

The $keymodifiers property "remembers" the value it had when the mouse last left the boundaries of the field. It is reset when the mouse again enters the field. If a different set of modifier keys is held down while the mouse is over the field, the new value is immediately generated. We have also been given a new event that lets us track when changes occur to the $keymodifiers property value. This is the evLinkKeyModifiersChanged event. We could use this event to change the text displayed for a given link (or all the links), for example. If the Shift key was held down when the mouse left the field and the Shift key is again held down when the mouse re-enters the field, this event is not triggered because the current value of the modifier key constants equals the value of $keymodifiers. But it some other combination of key modifiers is in force when the mouse re-enters the field, the evLinkKeymodifiersChanged event is triggered - even if there are no key modifiers in force now, but there had been earlier. We can use the following code to further explore how this event operates:

On evLinkKeyModifiersChanged
   OK message {pKeyModifiers = [pKeyModifiers]//$cfield.$keymodifiers = [$cfield.$keymodifiers]}

This combination of properties and events greatly expands the flexibility of this field type.

Remote Form Improvements

There are a number of new features for Remote Forms - too many to really detail thoroughly here. So I will again mention a few of my favorites.

One that is not so much a favorite of mine, but that has generated a lot of discussion over the years (because we did not have it) is the ability to open remote forms on the thick client as windows. (I suspect what the most vocal people in this discussion may have wanted is Window instances to show up as Remote Forms - but that just can't happen.) All the particulars on using Remote Forms in this way are given in the "What's New" document and in the newly revised manuals. Now on to some of the new features and components for Remote Forms.

We now have Masked Entry fields on Remote Forms that work just like those for Window Instances! (I was tempted to use a couple more exclamation marks for that sentence...) This allows us to both display and capture formatted strings without having to store the extra punctuation marks for such common values as telephone numbers, part numbers and other such structured strings. It also allows us greater flexibility in displaying date and time values, numbers with formatting and Boolean values with alternate labels. In my own work, this makes Remote Forms ever so much more useful!

The Hyperlink component is now also available on Remote Forms. This is the environment where this component would seem most at home, since hyperlinks are used much more frequently on web pages than on thick client windows. This component has exactly the same properties and events as its Window Class counterpart - including the new ones detailed above!

We can now detect that the user of a Remote Form is holding down modifier keys when they perform such actions as clicking a pushbutton on the form. We do this by testing the value of the keyboard event hash variables (#SHIFT, etc. - not to be confused with the modifier key constants mentioned above). These variables are populated for and detectable by both server-side and client-side methods. I have not tested these for threading issues yet, but I am most likely to use them in client-side methods to avoid any possible threading complications.

The final new "feature" of the Omnis Studio web client technology that comes with version 4.1 that I want to mention today has been requested by a number of developers for some time. We have now been given prepackaged "complete" web client installers that contain all the external components that ship with this version of Omnis Studio. Even with all components included, the installer file is only 1.2 megabytes, so it shouldn't deter anyone whose only concern is the size of the download. More details on this are given in the "What's New" document.

There are other new features in the Omnis Studio web technology, but we will have to devote a separate article to them to deal with them effectively.

Debugger Improvements

Some of the best new features, from the programmer's perspective, were put into the Debugger. For example, we can now view and set NULL values appropriately in the Debugger. Such values appear in red type in Variable Value windows - and there is a new button on these windows that allows us to set a variable value to NULL (with an appropriate warning dialog).

Null Value in the Debugger

There is a context menu option for the Watch Variables pane now that switches on Auto Variable Mode in the Debugger. (Actually, it is switched on by default!) In this mode, the variables used in the current, next and previous method lines are automatically included in the Watch Variables list, saving us a lot of effort to make sure that variables of interest to us are included. So any variable used as the target of a calculation or as a source value appears there, allowing us to see those variables before and after a calculation. This is incredibly convenient!

We can now drill down into embedded list variables and individual cells in the Variable Value window for a list or row variable. There is a context menu available for each cell in the list variable. If that cell contains an embedded list value, the context menu only has one item, which is used to open a value window for that list value as shown here:

Context Menu for List Cell

Selecting this menu item opens a new value window for the embedded list. Notice that the title of the Variable Value window indicates the parent list, row number and column name where that value resides:

Editing Embedded List

We can now manipulate this list value as we would any other list in a Variable Value window. We can even drill down further! The cell context menu for a non-list cell is shown here:

Context menu for Non-List Cell

Selecting this menu item opens a normal Variable Value window for that cell - again, named appropriately with the notation for that cell. Notice that we also have a button that can be used to set the current cells value to NULL in the list Variable Value window.

Also notice that there is an additional icon on the toolbar for the Variable Value window for a list value that allows us to print the contents of that list to the current report destination. This can be another great debugging aid!

And speaking of great debugging aids, we can now view and edit the contents of a binary variable directly in the Debugger! The Variable Value window for a binary variable presents us with a standard hexadecimal and ASCII display and allows us to modify the hexadecimal values:

Binary Variable Value Window

There are a number of additional options that I have yet to explore, but here is the menu of viewing and editing options offered in this window:

Binary Editing Options

So much for runtime programmer aids for now. Let's look at a few IDE enhancements...

Design Time Improvements

One of my favorite new design time items is our newfound ability to display property values other than $name and $order in the fields on a Window, Report or Remote Form Class. How do we do this? It takes some preparation...

First, we must open the class we want to affect and select a field that contains the property that interests us. In the example here, we want to view the value of the $visible property in all the fields. So we select a field on the window (even the background objects contain this property) and then context-click on that property in the Property Manager. The context menu contains a new item labeled Show Property Using Editor Context Menu, as shown here:

Set Alternate Property

We select this menu line (it will be checked if we open that menu again) and then return to the window class. When we open the context menu for that class, or for any field on that class, we see that the line that used to say "Show Field Numbers" in earlier versions of Omnis Studio, now says "Show $visible". (For backwards compatibility, it says "Show $order" by default.)

Show Property in Window Context Menu

If we select that menu item, the window then displays the value of the specified property for each field rather than displaying the name, label or whatever information would normally be displayed:

Window Showing Alternate Property

If we wish to see the normal information again, we simply deselect (uncheck) that item from the context menu. If we wish to see the values of a different property, we simply repeat the process outlined above.

One final item from my "favorites" list: we can now specify a subtype for an Object reference variable. This allows us to use the Interface Manager to more easily specify properties and methods in our code that will eventually be used with that variable. The variable must still be instantiated or populated at runtime as before. We can specify any Object Class, External Object or Java Class. For the DAMs, we can specify either the DAM itself (which makes it a session object) or a statement object for a session with that DAM:

Object Reference Subtype

Again, this is only a design-time convenience. We must still instantiate the object reference as usual at runtime.

Big Issues Not Covered Here

There are many more new and improved features in Omnis Studio version 4.1. Major topics that we should cover at some other time include: the new Unicode version of Omnis Studio, use of Java objects within Omnis Studio, advanced uses of icon libraries, more details on new and improved web thin and ultra-thin client features, enhanced drag and drop operations and enhanced FileOps methods. But these will have to wait for other Omnis Tech News issues.

Next Time

In the next issue of Omnis Tech News, we will take a look at the new Graph2 component. It offers some features the old Graph component did not, but it is also less configurable and lacking in many ways when compared with the older component. Fortunately, we continue to have both available to us, so we should learn how to take the best advantage of them both.

I hope you have found this information to be useful.

© 2006 Copyright of the text and images herein remains with the respective author. 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 the author or Raining Data.
Omnis® and Omnis Studio® are registered trademarks, and Omnis 7™ is a trademark of Raining Data UK Ltd. Other products mentioned are trademarks or registered trademarks of their corporations. All rights reserved.