New Features of Remote
Forms
By David Swain
Polymath Business Systems
It has been quite a while since
Remote Forms were last addressed within the Omnis Tech News. There
have been some significant improvements to them in that time. In
this article we will examine some of the new features added since
Omnis Studio version 4.0 was released. This is only a survey of
those new features that do not require lengthy explanations, either
because they are straightforward or because they work essentially
the same as Window features we have already covered extensively.
We will return to this topic in future articles to look at individual
new features that require more individual attention.
New Features of Old Components
A number of basic Remote Form field types have been given additional
properties and other facilities in Omnis Studio 4.x. These enhancements
have been developed to give our browser-based applications more
of the look and feel of our desktop applications. It appears that,
whenever possible, efforts have been made to unify the programming
techniques we use between Window Classes and Remote Forms.
For example, Studio 4.2 provides tooltip functionality
to most basic Remote Form field types. Edit fields (both
single and multiline), pushbuttons (but not button areas),
checkboxes, radio groups, list, heading
list and picture fields all now contain a $tooltip
property. A couple of new field types have this ability as well,
but we will get to them later in this article. The $tooltip
property takes a string value. Unlike Window object tooltips, though,
Remote Form tooltips do not support square bracket notation.
So only static text can be displayed as a tooltip. However, if we
need tooltips to report the current state of some variable or other
application element, we can always update the necessary tooltip
properties with a calculation whenever that value changes. Just
be sure that the code used to make this change modifies the value
of the $tooltip property for an item in the current instance
and not in the current class. This will not be practical for constantly
changing information, such as the current time, but is easily done
with values changed as part of an action under our control.
The observant reader will notice that the illustration above was
captured on a Windows machine rather than on Mac OS X as is my usual
habit. This is because I have so far failed to get the Remote Form
tooltip feature to work in Safari on Mac OS X. I am not yet ready
to call this a bug, but I cannot think of any more options to twiddle
that should have any effect on this. On Windows XP with Internet
Explorer, this feature worked flawlessly on the first attempt.
Also notice the futile attempt to use square bracket notation,
which is simply carried as part of the text and not evaluated. Even
using instance variables will not help as the resources for evaluating
square bracket notation are not available on the client.
A feature that has long been on the wish list for Remote Forms
is the ability to detect the use of modifier keys during
event processing. These are the Shift, Command/Control
and Option/Alt keys. Since Omnis Studio 4.1, we
can use #SHIFT, #COMMAND, #CONTROL, #OPTION
and #ALT in our event handling methods in Remote Forms.
They are properly populated for both server- and client-side methods
during the event cycle. If part of the event is processed on the
server, the necessary event-related variables are passed to the
server. I do not know whether these are thread-safe on the server,
however. This will require more testing (or asking) than I was able
to do before publication here. Certainly these variables are specific
to the Remote Form instance when accessed on the client side.
In addition, Edit fields (single and multiline) have a $isshift()
method that reports kTrue if the Shift key is
held down when it is invoked. This method was given to us in Omnis
Studio 4.0. I must emphasize that this is a method of the
field and not a property. It differs from the message variables
listed above in another important way as well. The value returned
by $isshift() is an instantaneous value at
the time of execution. #SHIFT is part of an event
message, so it reports the state of the Shift key at
the time the current event occurred - even though that key
may no longer actually be depressed. This distinction is subtle,
but it may be important to understand at some point.
One of the more exciting new abilities we have been given in Omnis
Studio 4.2 is drag-and-drop functionality among Remote
Form fields. This is a great enhancement of the user experience
with browser-based applications! As with many other Remote Form
operations, a little more preparation is required than with the
same operation on Window Classes, but the basic programming is the
same.
Many Remote Form field types now offer us the choice of selecting
evDrop, evDrag, evCanDrop, evWillDrop
and evDragFinished events for detection. As with other
event types, this must be specified or the event will not
be generated. These fields must also be set to allow either dragging
or dropping (or both) by setting their $dragmode and $dropmode
properties to the appropriate value. This is simpler than it is
for window fields because there are fewer choices. In fact, it is
literally an "all or nothing" proposition. $dragmode
only lets us choose between kNoDragging and kDragData
and $dropmode only offers a choice between kAcceptAll
and kAcceptNone. At least that part of the operation
is simpler! (We can also specify a $dragiconid if we wish.)
An interesting side note is that many more Remote Form field types
contain $dragmode and $dropmode properties than
offer drag-and-drop events for selection. Perhaps this is a sign
of future expansion?
Once we have set these properties for our source and/or target
fields, we must then build the method segments that are to handle
the drag-and-drop operations. These must be handled on the client
side, so the $event methods of the fields involved must
be set to "Execute on client". This is true even for
a field used only for basic dragging where we do not need any event
handling. Of course, I didn't have to tell you this because
the first time you test your handiwork Omnis Studio itself (actually,
the webclient plugin) will tell you if your $event method
for either the source or target field is not properly designated.
Otherwise, the programming is exactly the same as for drag-and-drop
among Window Class fields.
Here is what the result looks like in operation. Notice that the
dragged value follows the mouse pointer and that the target field
highlights to indicate that dropping is allowed. Also, the default
mouse pointer icon when dropping is not allowed is the
international "circle-slash" symbol.
Improved Components
There are other components beyond the basic ones that have received
improvements in Omnis Studio 4.x. One which was barely mentioned
in any of the documentation, but which I know about because of requests
I made, is the QuickTime or MoviePlayer component.
This component now properly supports streaming video and audio as
well as downloaded files. To clarify what the manual says: This
component plays streaming video that is set to stream from its server.
The component downloads QuickTime movies that are not specifically
set up for streaming, but will begin playing them before the download
is complete if the movie is properly configured. All media type
supported by QuickTime 6 are supported.
The player component also supports additional QuickTime plugins,
such as the Flip4Mac extension that allows Windows Media files (.wmv)
to be played using the QuickTime Player. If it's set up in your
QuickTime installation (and doesn't require features added in QuickTime
7), the QuickTime component can take advantage of it!
The FormFile component has a new $splitpathname() method
that was introduced in Omnis Studio 4.2. This allows us to parse
pathnames out on the client (in client-side methods) whenever the
need arises. This method uses exactly the same parameters and operates
in exactly the same way as the $splitpathname() method
of the FileOps extension. But to use FileOps, we have to come back
to the server for processing.
This is not so much of a problem, though, and there is another
new feature that was given to us in Studio 4.1 that makes this more
viable. A number of external components, FileOps among them, were
rewritten to make them multi-threaded when used with the
Omnis Web Server. This helps the server function more efficiently
and keeps one user's operations from stepping on those of another.
Another efficiency enhancement is one given to the FormPri component
in Omnis Studio 4.1. This component was rebuilt to offer print
compression so that large reports can be sent more quickly
to the client. This process takes advantage of the compress()
and uncompress() functions of Omnis Studio to reduce the
size of the binary report data for transport to the client browser.
Here is a brief description of the process:
First the report, which is generated on the server, is written
to a binary variable by setting the report destination
to the Memory device. This was always the way we would
generate a report for a Remote Form. But now we can also compress
that binary value before transmitting it back to the client. this
is done using the compress() function, which takes the
binary variable containing our report as its one parameter. Since
the Printing Control field on our Remote Form must use the uncompress()
function (which it does internally as needed, so we don't have to
worry about it), we need to gather some other information before
we compress the report value, though. The uncompress()
method requires two parameters: the name of the variable that contains
the compressed binary value and the original binary length of the
uncompressed report. These two pieces of information are transmitted
in the $reportdata and $reportdatalen properties of the Printing
Control field (which exists on both the server and the client instances
of the form), but we have to populate those properties first. We
can do so like this:
; print report into binary variable reportBinary
Calculate $cinst.$objs.printField.$reportdatalen as binlength(reportBinary)
Calculate $cinst.$objs.printField.$reportdata as compress(reportBinary)
Calculate $cinst.$objs.printField.$action as kFPriSendToScreen
; complete process and let Omnis Studio send changed values back
to client
As long as we are not putting the compressed version of the report
data back into our binary variable, it doesn't matter in which order
we deal with the report binary data. We just want to be sure that
we supply the uncompressed binary length so that the Printing
Control object has the necessary information to uncompress the report.
Compressing the report data gives us increasing benefits the larger
our reports become. If we happen to not compress the report
data, no problem! The Printing Control component can deal with that
situation seamlessly.
New Components
Omnis Studio 4.x has seen the advent of two new Remote Form field
types: the Masked Edit field and the Hyperlink component. These
both work in essentially the same way as their Window Class counterparts
- with the usual additional limitations imposed by the Remote Form
environment.
Masked Edit fields work basically like Masked Entry fields.
This is a great new field type - and one I've requested for quite
some time. We can now gather and present formatted data elements
without having to store the formatting using either Window
or Remote Form classes. In Omnis Studio 4.2, this field type was
also given the $tooltip property as were the other edit
fields. It was also given the $dragmode, $dragiconid
and $dropmode properties, although it was not
given any of the drag-and-drop event types for us to select in its
$events property. Nevertheless, drag and drop operations
work with it just fine as long as all other preparations are made.
This is an intriguing exception to the rule that events
must always be specified for a field to be able to use
them!
The Hyperlink component was added to Window Classes in
Omnis Studio 4.0
. In Omnis Studio 4.1, this component was also added for use on
Remote Forms. In fact, many developers have expressed to me that
they felt a Remote Form is a more appropriate place for the use
of such a control, since it mimics the kinds of link controls we
use on web pages. I slightly disagree, feeling that this interface
element is a very familiar one since so many people have become
accustomed to using a web browser. Its use on a thick client window
should not be a shock or surprise to such a user. But opinions are
just that...
An interesting note is that the Remote Form version of this component
retained its $tooltipcolumn property in Studio 4.1, which
could be viewed as a precursor to the tooltips feature we now have
for other Remote Form field types. To use this property, the list
variable named in the $dataname property value must have
a column to hold the "link tips". So each link can have
its own separate tooltip value in addition to its text label. Here
is an example of what that tooltip might look like:
New Operations
A couple of operational items have become easier to deal with -
and simply less confusing to some - as we move through the generations
of Studio 4.x. In Studio 4.1, we were given the $enablesenddata
property for a Remote Task. The default value for this property
for new Remote Tasks is kFalse, although existing Remote
Tasks created before this property existed will have a value of
kTrue to maintain their original operating style. The purpose
of this property is to switch off the execution of (and, generally,
the need for) the $senddata() method of Remote Form instances
opened within the Remote Task. Omnis Studio is now able to determine
for itself which variables on the server require synchronization
to the client. We used to have to either manage this ourselves or
accept that Omnis Studio would update all instance variables
on the client from the server with each trip back from a server
method. And there were rules we could follow to keep the variables
in the return collection from accumulating. But the rules for using
$senddata() were difficult for many developers to understand,
so this new "automatic mode" should be a welcome change.
The value of $enablesenddata must be set in design mode.
It cannot be modified at runtime. Simply setting it to kFalse
will disable any existing $senddata() methods in our code,
so it is not necessary to traverse the code and strip out or comment
out those lines containing that method. Once this is done, Omnis
Studio will pass back to the client only those variable values that
have changed as the result of actions on the server. If a developer
feels the need to continue managing this process using $senddata(),
that developer must set $enablesenddata to kTrue
for each new Remote Task that is created.
The $startfield property for a Remote Form is becoming
more viable in Omnis Studio 4.2. There still appear to be issues
with its use on the Mac Os X platform, but it now properly sets
the field that will originally receive the focus when a form is
opened. We give the $startfield property the $order
value of that field. The field so specified must be enterable and
enabled for this to work properly. This is how it works given a
positive numeric value. if we give it a negative value and then
use the form within a subform field, the absolute value of the $startfield
value is the number of the field within the subform that will initially
receive the focus when the subform receives the focus. Of course,
if a zero value is given for this property, the focus will go to
the first enterable field in $order order that can accept
it.
New Operating Environment
Finally, we have a new way of using Remote Forms. Omnis Studio
4.1 first allowed us to open a Remote Form within a window directly
within the thick client for the first time. This is an historic
event, but time will tell how frequently this feature gets used.
Possible uses might be to maintain a consistent interface on both
thick and thin client uses of a form to reduce library size and
to minimize end user training problems. Perhaps you will begin to
develop some ideas as we briefly review how this new environment
works.
We cause a Remote Form to open in a window on either a development
or runtime copy of Omnis Studio by first setting the $openinwindow
property of the Remote Form class to kTrue. We have not
been given any new 4GL commands for opening a form and the Open
window instance command will not accept the name of a Remote
Form on execution, but we can use the $open() method of
the class. This launches a window instance containing our
Remote Form instance. So far, so good - but there are some limitations
of which we must remain mindful.
First, we no longer can use features and methods that relate to
being deployed in a browser. This means that methods like $showurl()
will not function in this environment because there is nowhere to
direct the display of the url - and no browser software to which
to pass the url in the first place.
But we can invoke items that are specific to Remote Tasks,
because the appropriate Remote Task is also instantiated along with
the Remote Form! Some methods that we might think would be included
in the limitation mentioned in the previous paragraph have been
reworked to sense within which environment the instance resides.
So the $showmessage() method for either the Remote Form
or the Remote Task will display an Omnis Studio dialog rather than
the dialog of a browser. Since we have both a Remote Form instance
and a Window instance co-existing (well, the window is
a shell for the form), we also have a Remote Task and a "normal"
Task instance co-existing as well! This leads to some interesting
results.
Even such methods as $openform() and $changeform()
of a Remote Task can be used effectively in this environment. If
we issue $ctask.$changeform() and specify a different Remote
Form (and one which also has its $openinwindow property
set to kTrue), Omnis Studio will swap the forms within
the shell of the same window instance, just as if that window were
a web browser. If the new form is a different size than the original,
Omnis Studio will even resize the window instance to accommodate
the new form. If we use the $ctask.$openform() method to
open another form, the window retains its original size (although
it can be manually resized), but both forms now reside
within the same window instance!
So this window shell acts as a substitute browser, maintaining
an interface that is as consistent as possible between our thick
and thin client deployments. The only things it can't do are those
reserved for a real browser. It has no frames, so we cannot
direct output to a different frame. And it cannot open a new browser
window or display HTML content from web sites on the internet.
And we have been given all the tools we need to find our way around
within this environment. Remote Form instances now have a $windowinst()
method that returns a reference to the containing window instance
- or a null if the form is deployed within a browser. And
window instances have been given a $rforminst() method,
which returns a reference to the Remote Form instance it contains
- or a null if this is a "normal" window instance.
We can use these methods to reach out and influence this new environment
if we need that kind of control.
Just imagine the possibilities!
Another Time
There are many more new features of Omnis Studio Remote Forms and
Remote Tasks, but most of the rest require more extensive explanations
than we can deal with this month - not to mention that we also have
a complete new suite of Web Services tools available! But all of
this will have to wait for another time. I hope you have found this
brief tour useful - or, at least, intriguing! |