Project

General

Profile

Displaying Data Using Frames

Introduction

This chapter provides details on the primary method of outputting data on the screen for a user. In the converted application, as in the original 4GL, everything happens inside one or more frames. In Java, the GenericFrame class is the container to lay out the data represented by different widget types. The related language statements can be categorized by statements that display data, statements that change the default behavior of how to display data and statements which combine display and ability to change the data.

Although there are low-level methods to output data to the screen (see the Terminal Management chapter), the primary mechanism to output data to the screen uses frames. Frames are collections of widgets that are laid out in a specified pattern with labels, headers and other formatting to control the appearance. Data is output by causing all or part of a frame to be visible on the screen.

The following statements all have a role in displaying data on the screen:

Statement Type Description Java Supported
COLOR Display-like Specifies the color attributes used to display data on screen or during editing of data entry fields. GenericFrame.setColors() Yes
DISPLAY Displaying Moves data to the screen buffer and them on the screen or other output destination. GenericFrame.display() Yes
DOWN Cursor Iteration Positions the cursor on a new line inside the down or multi-line frame. When combined with a loop in the business logic which generates or accesses new data with each iteration, this usually has the result of displaying an additional row of data in a multi-line (“down”) frame. GenericFrame.down() Yes
ENABLE Displaying Enables input for one or more field level widgets in a frame. GenericFrame.enable() Yes
HIDE Display-like Makes the widget invisible or clears the message area or hides widget in a window and clears the message area. GenericFrame.hide() Yes
INSERT Displaying Not supported at this time. - No
PROMPT-FOR Displaying Waits for input to be done and places the result into screen buffer. GenericFrame.promptFor() Yes
SET Displaying Waits for input to be done and places the result into record buffer of the variable. GenericFrame.set() Yes
UNDERLINE Display-like Underlines the field or variable using the next line of the display for underlining characters. GenericWidget.underline() Yes
UPDATE Displaying Displays the variable, waits for the data entry and stores the result into the record buffer of the variable. GenericFrame.update() Yes
VIEW Displaying Displays a widget. GenericFrame.view() Yes

From the table above we can see two types of the statements - one related to real work visible on the screen and others - so-called display-like - related to how information is presented on the screen. The display statements are DISPLAY, ENABLE, PROMPT-FOR, SET, UPDATE, VIEW. The display-like are COLOR, HIDE, UNDERLINE. The display-like statements looks like the display related but these statements do not display the associated frame if it was not visible already and during conversion these statements do not affect frame scoping. This difference should be taken into account when planning the business logic of the application. The results of the display-like statements will be visible when running next real display statement.

The frame is the central container where everything is happening in the 4GL user interface (UI). The FWD project preserves this approach offering GenericFrame as the Java counterpart of a 4GL frame. All converted frames are descended from this base class adding more special functionality according to the particular purpose. The GenericFrame in turn is an implementation of the CommonFrame interface. All methods from this interface are implemented in final application frame instance either coming from GenericFrame class or implemented in the custom application frame class itself.

Some displaying language statements mentioned in a table above are comprised of multiple implicit “primitives” on for the display of the current state of the widget listed as a subject of the statement. Each statement is different in the implicit primitives used. Some statements use the VIEW embedded statement while some of them use DISPLAY. For example, the ENABLE statement has an embedded VIEW, while the PROMPT-FOR, SET and UPDATE have an implicit DISPLAY. The difference between DISPLAY and VIEW is that DISPLAY moves the current data from the business logic into the screen buffer before making the screen buffer contents visible. VIEW only renders the current content of the screen buffer which may not be the same as the current values as seen in the business logic (in the backing record buffers or variables).

The concept of the frame management is one of the central point of the 4GL and therefore FWD applications. There are the two types of the frames. Down frames (which have multiple rows, each row containing the same widgets) and one-down (or non-down) frames. The difference between the two is the ability to display and work with multiple iterations of data. The one-down frame is able to display only the single data iterations while down frames are able to display more than one. To handle down frames the special DOWN statement is used to move the cursor to the next iteration of the data. Also it is possible to have the implicit DOWN calls inside the iteration loop based on the type of block being used (see the Blocks chapter of part 4). Down frames are useful to fetch and display many similar data rows from a database table presenting them on the screen in a tabular organization. The term “cursor” here has a special meaning indicating the currently displayed row. Do not confuse it with the cursor used within field-level widgets that indicates the current typing position during an editing operation. Later in this chapter down frames and the DOWN statement itself will be discussed in detail.

Most statements in this chapter can be used to output formatted data to both the screen as well as to a stream. For more details, please see the Streams chapter and the Redirected Terminal chapter.

Frame Elements

As mentioned in Frames chapter, during conversion any static widget definitions are created from variables, fields, literals and expressions which are included in certain language statements. In Progress 4GL, although a widget may be created by a reference to a variable/database field and that widget will share a name with that variable/field, the widget remains disconnected from its backing data source. In order to display data and during interactive I/O it is necessary to establish connection between each widget and its backing data source. This is accomplished by the creation of FrameElement instances. Each instance establishes a temporary link between widget and backing data source. By passing an array of FrameElement instances to the appropriate runtime code that implements a 4GL statement, that statement will have access to the data sources and can read and write data from them and into/out of the associated widget.

A simple 4GL example which illustrates this approach:

define variable i as integer label "Integer variable" init 123.
define variable s as char    label "String"           init "text".

display i s.

The converted business logic (excerpt):

...
public void execute()
{
   externalProcedure(new Block()
   {
      integer i = new integer(123);

      character s = new character("text");

      public void init()
      {
         TransactionManager.register(i, s);
      }

      public void body()
      {
         frame0.openScope();

         FrameElement[] elementList0 = new FrameElement[]
         {
            new Element(i, frame0.widgeti()),
            new Element(s, frame0.widgets())
         };

         frame0.display(elementList0);
      }
   });
...

The display of the actual content of the data source (variables in this case) is performed by passing an array of FrameElement instances to the display() method, where each instance binds a widget to a particular variable.

FrameElement Type Purpose
AggregatorElement Associates a widget with an accumulator expression.
BypassElement Use to specify that a specific widget is to be ignored.
Element Establishes an association between a data source/sink (e.g. variable or field) and a widget in the frame.
EmbeddedAssignment The specified widget will not be edited by the user, instead a specific expression will be evaluated and assigned to the widget after any interactive editing operation has occurred.
HeaderElement Specifies an expression to be placed in the header of a frame.
WidgetElement Represents control widgets (that have no data association) such as buttons.
WordWrapElement Associates widgets with a TEXT group.

The following sections provide more detail.

AggregatorElement

This class is used to add the 4GL accumulator expressions as a widget in the frame. This is an artificial widget which accumulates one of a set of possible statistics for the given variable, field or expression. For example consider the following 4GL code:

define var decvar as decimal.
PROC:
repeat on endkey undo, leave:
   assign decvar = decvar + 2.
   display decvar (total) column-label "Aggregator Label" 
      with down frame fr0.
   pause.
end.

will be implemented in Java as:

...
public void body()
{
   decvar.assign(plus(decvar, 2));

   FrameElement[] elementList0 = new FrameElement[]
   {
      new AggregatorElement(decvar, fr0Frame.widgetDecvar(), accumDisp0)
   };

   fr0Frame.display(elementList0);

   pause();
}
...

When application starts press spacebar two times. The variable value increases by 2 with each iteration. Then press F4 to leave the procedure. The screen becomes:

You see the new data representing the total value of the varable. This is the result of the accumulation. The possible statistics types are: AVERAGE, COUNT, MAXIMUM, MINIMUM, TOTAL, SUB-AVERAGE, SUB-COUNT, SUB-MAXIMUM, SUB-MINIMUM, SUB-TOTAL.

See the Accumulator chapter of Part 5 for more details.

BypassElement

The elements of this type are used when it is required to ignore some fields if they are currently disabled. The instance of this class has the setter and getter methods but they just do nothing generating the exception UnsupportedOperationException.

Consider the following 4GL example code:

input stream mystr from "display_training8.txt".
set stream mystr ^ ch1 ^ ch2 with frame fr0.
message "Variable values:" ch1+" "+ch2.

Will be converted in Java as:

mystrStream.assign(StreamFactory.openFileStream("display_training8.txt", false, false));
FrameElement[] elementList0 = new FrameElement[]
{
   new BypassElement(),
   new Element(ch1, fr0Frame.widgetCh1=()),
   new BypassElement(),
   new Element(ch2, fr0Frame.widgetCh2())
};

fr0Frame.set(mystrStream, elementList0);

message(new Object[]
{
   "Variable values:", concat(ch1, " ", ch2)
});

The data file we use for this sample contains the following line:

This input file is

After application starts the screen will be:

The CARET symbol in 4GL code converting into the BypassElement class of the elements array tells the system to skip over the next data entry from the input file. In the example above we skip over the 1-st and 3-rd words. The BypassElement receives no data generating the exception. If the input file is:

the sample

The screen becomes:

The variable ch2 is not setting at all in this case because in the data line we have nothing after two skips and one reading. That's why the ch2 is empty in this case.

Element

This class provides a simple association between a widget and the source and/or sink for the data to be displayed/edited in that widget. In the 4GL, this relationship is implicit and is hidden inside the runtime. In Java,. this relationship is made explicit. This is the most common type of FrameElement seen in converted code.

Consider the following 4GL code:

define var ch1 as char.
define var ch2 as char.
define var ch3 as char.
define var ch4 as char.
display ch1 ch2 ch3 ch4.

will be implemented in Java as (this is only a fragment):

character ch1 = new character("");
character ch2 = new character("");
character ch3 = new character("");
character ch4 = new character("");
...
   FrameElement[] elementList0 = new FrameElement[]
   {
      new Element(ch1, frame0.widgetCh1()),
      new Element(ch2, frame0.widgetCh2()),
      new Element(ch3, frame0.widgetCh3()),
      new Element(ch4, frame0.widgetCh4())
   };

In this example we see the array of the elements each one presents the binding between the real variable ch1 - ch4 and the appropriate widgets displaying on the screen.

EmbeddedAssignment

The elements of this type is used to implement an arbitrary assignment operation after an interactive editing operation is complete. It is implemented differently than other display related statements and does not produce any visible output. For more details please see the Embedded Assignments section of the Frames chapter of this book.

HeaderElement

This class is used to represent a header expression for display related statements. This implements the 4GL HEADER clause of the FORM statement. This facility allows 4GL code to custom design a frame's header instead of using the standard facilities such as column labels. For example, this 4GL code:

form header
      "This " 
      "is " at 33
      today format "99/99/9999"             to 79
      "the current " 
      "date"     at  58
      with page-top width 80 no-labels no-box no-attr-space
        frame f-head.

will be converted to Java as (this is only a fragment):

FrameElement[] elementList0 = new FrameElement[]
{
   new HeaderElement("This ", fHeadFrame.widgetExpr1()),
   new HeaderElement("is ", fHeadFrame.widgetExpr2()),
   new HeaderElement(new HeaderExpr0(), fHeadFrame.widgetExpr3()),
   new HeaderElement("the current ", fHeadFrame.widgetExpr4()),
   new HeaderElement("date", fHeadFrame.widgetExpr5())
};
fHeadFrame.registerHeader(elementList0);

When application starts the screen is this:

WidgetElement

This class is used to represent control type widgets. Such widgets do not represent data, but rather they provide a way for the user to interact with the application. A good example is a button.

Consider the following 4GL code:

define button btn1 label "One".
define button btn2 label "Two".
form btn1 btn2 with frame buuton-frame.

This will be converted to Java as (this is the frame element array only):

FrameElement[] elementList0 = new FrameElement[]
{
   new WidgetElement(buutonFrameFrame.widgetBtn1()),
   new WidgetElement(buutonFrameFrame.widgetBtn2())
};

WordWrapElement

This form is used to pack the widget allowing the automatic word wrap for the current editing operation. Each such element has a group index (by default this is 0). All elements with the same group index are part of the same word wrapping group. Consider the following 4GL example:

define var chx as char extent 4.
update text(chx).

will be implemented in Java as:

character[] chx = new character[4];
...
   FrameElement[] elementList0 = new FrameElement[]
   {
      new WordWrapElement(subscript(chx, 1), frame0.widgetChxArray0()),
      new WordWrapElement(subscript(chx, 2), frame0.widgetChxArray1()),
      new WordWrapElement(subscript(chx, 3), frame0.widgetChxArray2()),
      new WordWrapElement(subscript(chx, 4), frame0.widgetChxArray3())
   };

Screen Buffers

Each frame has a ScreenBuffer instance. The screen buffer is used to maintain the transient state of all the widget-specific data for that frame. It does not store configuration (e.g. format strings or labels). But when a widget holds a data value, the value (or lack thereof) and the editing state of that value are stored in the screen buffer. Each frame instance has a unique instance of the screen buffer, such that multiple instances of the same frame will each have their own screen buffer instance.

During interactive I/O (editing) operations it can be safely assumed that the screen buffer holds the current edits for each widget, which will contain changes that have not yet been written back out to any associated variable or database field associated with each widget. It is possible to access these “intermediate” values during trigger execution.

Converted code does not directly access instances of this class. It is hidden in the runtime and only accessed indirectly through the Java replacement 4GL functionality. For example, the current value of a widget can be assigned (set) and read using the SCREEN-VALUE attribute. See below for details on this attribute.

From the programmer's perspective, the screen buffer is an abstract construct, however, it is important to understand. The reason for this is that knowing how it works allows proper understanding of how displaying and editing statements work. For example, a DISPLAY statement takes an array of frame elements as a parameter. The backing code in the runtime iterates that array and copies data values from the backing variables/database fields into the screen buffer (where the value is assigned to a specific widget). Then the equivalent of a VIEW statement occurs, which takes the (now updated) data in the screen buffer and outputs that data to the screen, in the format, location... that is defined by the frame. When a VIEW statement is called directly (as opposed to being implicitly called from within DISPLAY), it does not copy new values from the business logic to the screen buffer, it only operates on the state of the screen buffer as it already exists.

Generally, the displaying statements have implicit VIEW or DISPLAY statements inside them.

Likewise the editing statements (see the Editing chapter) usually have implicit VIEW or DISPLAY statements inside them. Just as important, the editing statements may have an implicit ASSIGN statement that (when present) executes after the editing operation successfully completes. The ASSIGN statement is a mechanism to copy data back from the screen buffer into each associated variable or database field (for those widgets which were being edited in that editing statement). For example, the UPDATE statement has an implicit ASSIGN, but the SET, PROMPT-FOR and ENABLE do not. For those cases, the program must explicitly execute an ASSIGN statement or use the SCREEN-VALUE to copy the edited data out of the screen buffer and back into storage that is accessible to the business logic.

For more details on the ASSIGN statement, see the Expressions chapter and the Editing chapter.

SCREEN-VALUE Attribute

The attribute SCREEN-VALUE is the data value of a frame widget as it is stored in the screen buffer. This attribute can be read or set. The data type for the SCREEN-VALUE attribute is CHARACTER. To clearly understand the meaning of the SCREEN-VALUE attribute and the relationship with the variable value consider the following 4GL example:

def var num as int init 14.
display num with frame f0.
message "Variable value:"+string(num).
message "Screen attribute value:"+string(num:screen-value).
pause.
num = 2.
message "Variable value:"+string(num).
message "Screen attribute value:"+string(num:screen-value).
pause.
num:screen-value = "30".
message "Variable value:"+string(num).
message "Screen attribute value:"+string(num:screen-value).
pause.
assign num.
message "Variable value:"+string(num).
message "Screen attribute value:"+string(num:screen-value).

This converts to Java as:

integer num = new integer(14);
...
   f0Frame.display(elementList0);
   message(concat(new character("Variable value:"), valueOf(num)));
   message(concat(new character("Screen attribute value:"),
                  valueOf(f0Frame.getScreenValue(f0Frame.widgetNum()))));   pause();
   num.assign(2);
   message(concat(new character("Variable value:"), valueOf(num)));
   message(concat(new character("Screen attribute value:"),
                  valueOf(f0Frame.getScreenValue(f0Frame.widgetNum()))));
   pause();
   f0Frame.setScreenValue(f0Frame.widgetNum(), new character("30"));
   message(concat(new character("Variable value:"), valueOf(num)));
   message(concat(new character("Screen attribute value:"),
                  valueOf(f0Frame.getScreenValue(f0Frame.widgetNum()))));
   pause();
   f0Frame.assignScreenValue(new Element(num, f0Frame.widgetNum()));
   message(concat(new character("Variable value:"), valueOf(num)));
   message(concat(new character("Screen attribute value:"),
                  valueOf(f0Frame.getScreenValue(f0Frame.widgetNum()))));

The methods getScreenValue() and setScreenValue() of the class GenericFrame is used to operate with the SCREEN-VALUE attribute. When the application starts the screen is:

Initially the SCREEN-VALUE attribute has the same value as the variable itself. Now we change only variable value leaving SCREEN-VALUE attribute unchanged. Press the spacebar to continue. The screen becomes:

Note the difference between real variable value and the attribute of the widget. Now we change the SCREENVALUE attribute keeping the variable untouched. Press spacebar to continue. The screen becomes:

Here we see the changed screen attribute value and the visible representation of the widget is also changed. This can be the illustration of the difference between the variable and the it's display representation. To synchronize these two entities the statement ASSIGN should be used. Press spacebar to continue to see what is happening after synchronization. The screen becomes:

As we can see the both values are the same. Some statements like SET or UPDATE have built in assignment.

INPUT Built-In Function

The built-in function INPUT allows code to read the current value of from the screen buffer used to display the widget on the screen. Technically this is the area of the user data input. Any changes performed by the user on the screen remain in this special area until the next ASSIGN statement is used to commit the changed transferring them to the variable or record value.

Initially the screen buffer value is empty. It is not initialized based on the current variable value. These are 2 different things that can be synchronized in value when a DISPLAY statement is used (which copies from the variable/field to the screen buffer) or an ASSIGN statement is used (which copies from the screen buffer to the variable/field).

Consider the following 4GL example:

DEF VAR ix AS INTEGER INITIAL 3.
MESSAGE "Variable value:" ix.
MESSAGE "Screen buffer value:" INPUT ix.
PROMPT-FOR ix.

This converts to Java as:

integer ix = new integer(3);
...
   message(new Object[]
   {
      "Variable value:", ix
   });
   message(new Object[]
   {
      "Screen buffer value:", frame0.getIx()
   });

   FrameElement[] elementList0 = new FrameElement[]
   {
      new Element(ix, frame0.widgetIx())
   };

   frame0.promptFor(elementList0);

When the application starts the screen will be:

Note the difference between the real variable value and contents of the screen buffer. Also in this example we see the difference between accessing the variable itself and it's screen buffer contents. The PROMPT-FOR statements takes the current screen buffer value to display the variable.

To write the changes to the variable the ASSIGN statement should be performed explicitly or implicitly. The SET statement has embedded assignment. So when we modify the data inside this statement and execute GO the changes will be transferred from the screen buffer to the variable value. Consider the following 4GL example:

DEF VAR ix AS INTEGER INITIAL 3.
MESSAGE "Variable value:" ix.
MESSAGE "Screen buffer value:" INPUT ix.
SET ix.
MESSAGE "Variable value:" ix.
MESSAGE "Screen buffer value:" INPUT ix.

This converts to Java as:

...
message(new Object[]
{
   "Variable value:", ix
});
message(new Object[]
{
   "Screen buffer value:", frame0.getIx()
});

FrameElement[] elementList0 = new FrameElement[]
{
   new Element(ix, frame0.widgetIx())
};
frame0.set(elementList0);
message(new Object[]
{
   "Variable value:", ix
});
message(new Object[]
{
   "Screen buffer value:", frame0.getIx()
});
...

The screen after the application starts:

Type the new value and press ENTER:

The screen buffer value and the variable value now have equivalent values. This is because the SET statement has the embedded assignment at the end of the execution.

Displaying Statements Conversion Overview

Conversion of the all frame displaying statements (complete list provided below) has many similarities. In particular, most of them may contain Frame Phrase which is converted into the frame properties. Also, some of them may contain Format Phrase after each widget reference. The Format Phrase is converted into widget properties. These conversion details are described in the Frames chapter. But beside widget and frame properties each displaying statement is converted into part of business logic class. There are three groups of displaying statements. First group consist of real displaying statements which make frame appear on the screen if it was not visible yet. Second group consist of displaying-like statements. Their syntax diagrams look very similar to displaying statements and they are converted almost exactly like displaying statements. But these statements do not display frame if it was not visible already and during conversion these statements do not affect frame scoping. Finally third group consist of frame properties which affect frame visibility (may frame appear or disappear on the screen) and therefore behave like real displaying statements, but during conversion they are handled like regular frame properties. Conversion details of each statement/property are described below.

Displaying Statements

List of displaying statements is provided below:

DISPLAY
ENABLE
INSERT
PROMPT-FOR
SET
UPDATE
VIEW

Statements listed above trigger displaying of the frame if it was not visible before. The conversion of each statement will be described in detail below.

Some of these statements are the combination of the set of the other ones or have the other statements embedded inside. For such a cases this will be noted additionally in a summary of the statement.

DISPLAY Statement

The statement moves the data to the screen buffer and displays them on the screen by the implicit VIEW call. Conversion of DISPLAY statement completely involves Frame Elements approach described above.

Syntax of DISPLAY statement provided below:

DISPLAY
   [ STREAM stream ]
   [ UNLESS-HIDDEN ]
   {
        expression  [ ( aggregate-phrase ) ] [ format-phrase ] [ WHEN expression ] [ @ base-field ]
      | [ SPACE [ ( n ) ] ]
      | [ SKIP [ ( n ) ] ]
   } ...
   [ IN WINDOW window ]
   [ frame-phrase ]
   [ NO-ERROR ]

During conversion format-phrase, SKIP and SPACE are converted in constructors and methods calls in the static frame definition class. Refer to the Frames chapter for more details. The IN WINDOW clause is not supported.

Following example illustrates conversion of a simple DISPLAY statement without STREAM, UNLESS-HIDDEN and NO-ERROR options:

def var i as int.
def var j as char.

display i j with frame f0.

Unlike the ENABLE statement, the full version of Frame Elements approach is used:

...
public void body()
{
   f0Frame.openScope();

   FrameElement[] elementList0 = new FrameElement[]
   {
      new Element(i, f0Frame.widgeti()),
      new Element(j, f0Frame.widgetj())
   };

   f0Frame.display(elementList0);
}
...
Expression/Widget Support

The option expression in the description of the DISPLAY statement has several different meanings we consider in this section.

First it can be a single (scalar) variable, a single (scalar) database field, an element of an array variable or an element of a database array field. In this case the expressions are considered as widgets and can be used in an editing sessions to modify and assign a new value. Specific array element references must have the [index] subscripting included, where index is an expression that evaluates to a valid offset into the array.

As a special case, if an unsubscripted array variable or unsubscripted array database field reference is used, this is equivalent to explicitly specifying all elements of the array (in ascending index order). This expansion is described in more detail in the section entitled Unsubscripted Array Reference Expansion in the Data Types chapter.

All of the above cases are “lvalues”. An lvalue is some kind of named storage that can be assigned. In other words it can appear on the left side of an assignment operator, so it is a left value or lvalue. All lvalues are normal editable widgets.

Second, non-lvalues can be used as the expression. In this case it is possible to use a literal or complex expressions like *z. In this case, the value displayed is constant when defined as a literal or can vary at runtime (it changes each time the DISPLAY statement is executed) when specified as a complex expression. In both the literal and complex expression cases, the result is a display-only value and the resulting widget is not editable.

Consider the following simple 4GL example of using simple variable in DISPLAY statement:

define var chVar as char initial "Hi".
define var intVar as integer initial 2012.

display chVar intVar.

Will be converted in Java as:

character chVar = new character("Hi");
integer intVar = new integer(2012);
...
FrameElement[] elementList0 = new FrameElement[]
{
   new Element(chVar, frame0.widgetChVar()),
   new Element(intVar, frame0.widgetIntVar())
};

frame0.display(elementList0);

After application starts the screen is:

Note the look of the variables. We see the horizontal line indicating the widget can potentially be edited. The next example will demonstrate the usage of the array elements. The 4GL code is:

define var chArr as char extent 3.
define var intArr as integer extent 3.

display chArr intArr.

Will be converted to Java as:

character[] chArr = new character[3];
integer[] intArr = new integer[3];
...
FrameElement[] elementList0 = new FrameElement[]
{
   new Element(subscript(chArr, 1), frame0.widgetChArrArray0()),
   new Element(subscript(chArr, 2), frame0.widgetChArrArray1()),
   new Element(subscript(chArr, 3), frame0.widgetChArrArray2()),
   new Element(subscript(intArr, 1), frame0.widgetIntArrArray0()),
   new Element(subscript(intArr, 2), frame0.widgetIntArrArray1()),
   new Element(subscript(intArr, 3), frame0.widgetIntArrArray2())
};

frame0.display(elementList0);

After application starts the screen is:

Note the widgets are seen as potentially editable as in previous example. Also in this example the array elements are considered as single variable by static method com.goldencode.p2j.util.ArrayAssigner.subscript() extracting the element via the array index value.

The next example demonstrates the using of the simple database field with DISPLAY statement. The 4GL code is:

define temp-table tt field num as integer.

display tt.num.

will be converted to Java as:

TempRecord1 tt = TemporaryBuffer.define(TempRecord1.class, "tt", false);
...
FrameElement[] elementList0 = new FrameElement[]
{
   new Element(new FieldReference(tt, "num"), frame0.widgetNum())
};

frame0.display(elementList0);

Now the widget is extracted by the FieldReference class to provided delegated access to the database field. The screen after application start is:

Note the widget is also opened for edit and change the value. Now consider the second way of using the DISPLAY statement with literals. The first simple example will use the character constant. The 4GL code is:

display "This is a display-only literal, not an lvalue".

Will be converted to Java as:

FrameElement[] elementList0 = new FrameElement[]
{
   new Element("This is a display-only literal, not an lvalue", frame0.widgetExpr1())
};

frame0.display(elementList0);

After starting the application the screen become:

Note the result is just a text without ability to edit. The more complex example demonstrates using functions and operands within the literal like expressions. Consider the following 4GL code:

define var chVar as char initial "Today 2x2+1=".
define var chLVal as char initial "lvalue".
define var intVar as integer initial 2.

display chLVal chVar+(intVar * 2 + 1)+" As the date of: "+today.

This will be converted to Java as:

character chVar = new character("Today 2x2+1=");
character chLval = new character("lvalue");
integer intVar = new integer(2);

...
FrameElement[] elementList0 = new FrameElement[]
{
   new Element(chLval, frame0.widgetChLval()),
   new Element(concat(chVar, plus(multiply(intVar, 2), 1),
                      " As the date of: ", new date()), frame0.widgetExpr2())
};

frame0.display(elementList0);

After application starts the screen is:

A widget based on an lvalue has a column header, but widgets based on complex expressions will have no column header. And now let's consider what will be if we change the code to the following:

define var chVar as char initial "Today".
define var intVar as integer initial 2.

display chVar " 2x2+1=" (intVar * 2 + 1) " As the date of: " today.

This converts to Java as:

character chVar = new character("Today");
integer intVar = new integer(2);
...
FrameElement[] elementList0 = new FrameElement[]
{
   new Element(chVar, frame0.widgetChVar()),
   new Element(" 2x2+1=", frame0.widgetExpr2()),
   new Element(plus(multiply(intVar, 2), 1), frame0.widgetExpr3()),
   new Element(" As the date of: ", frame0.widgetExpr4()),
   new Element(new date(), frame0.widgetExpr5())
};

frame0.display(elementList0);

The screen after the application starts:

Note what is changed. The first character variable is an editable lvalue. The complex expression is not. The inclusion of operands, constants, function calls or other complex expression elements changes the widget from an lvalue reference (editable) to a display-only output widget.

Aggregate Phrase

Syntax of aggregate-phrase provided below:

{
     AVERAGE
   | COUNT
   | MAXIMUM
   | MINIMUM
   | TOTAL
   | SUB-AVERAGE
   | SUB-COUNT
   | SUB-MAXIMUM
   | SUB-MINIMUM
   | SUB-TOTAL
} ...
[ LABEL aggr-label ] [ BY break-group ] ...

Conversion details for aggregate-phrase can be found in the Accumulator chapter.

STREAM Support

Following example illustrates conversion of DISPLAY statement with STREAM option:

def var i as int.
def var j as char.
def stream str.

display stream str i j with frame f0.

Code looks very similar to converted code provided above except that other form of display() method is used:

...
public void body()
{
   f0Frame.openScope();
   TransactionManager.registerTopLevelFinalizable(strStream, true);

   FrameElement[] elementList0 = new FrameElement[]
   {
      new Element(i, f0Frame.widgeti()),
      new Element(j, f0Frame.widgetj())
   };

   f0Frame.display(strStream, elementList0);
}
...

The result writes the frame's formatted contents (including any border) to the stream instead of to the terminal. For full details please see the Redirected Terminal chapter.

UNLESS-HIDDEN Option

The next example illustrates conversion of DISPLAY statement with UNLESS-HIDDEN option:

def var i as int.
def var j as char.

display unless-hidden i j with frame f0.

Now, instead of display() method, displayUnlessHidden() method is used. Remaining part of the converted code is identical to code from previous examples:

...
public void body()
{
   f0Frame.openScope();

   FrameElement[] elementList0 = new FrameElement[]
   {
      new Element(i, f0Frame.widgeti()),
      new Element(j, f0Frame.widgetj())
   };

   f0Frame.displayUnlessHidden(elementList0);
}
...
NO-ERROR Option

Conversion of DISPLAY statement with NO-ERROR option illustrated with following example:

def var i as int.
def var j as char.

display i j with frame f0 no-error.

Note calls to ErrorManager in converted business logic code:

...
public void body()
{
   f0Frame.openScope();
   ErrorManager.silentErrorEnable();

   FrameElement[] elementList0 = new FrameElement[]
   {
      new Element(i, f0Frame.widgeti()),
      new Element(j, f0Frame.widgetj())
   };

   f0Frame.display(elementList0);

   ErrorManager.silentErrorDisable();
}
...
@ Base-Field Clause

Conversion of base-field syntax is illustrated by following code:

def var i as int.
def var j as char.

form j with frame f0.
display i @ j with frame f0.

Any expression listed in a DISPLAY statement which is followed by an symbol and then an already existing widget name is called an@base-field@ reference. The idea is that the preceding expression does not specify a new widget. Instead it temporarily overrides the formatted value drawn in the space on the screen that was reserved for the named widget (that follows the symbol).

Using the example above, the j widget is created by the FORM statement. The i expression in the DISPLAY statement would normally create a second widget, but since it is followed by the symbol and the name of a valid widget, this is an@base-field@ usage. The value of the expression (in this case, the value of the variable i) will be evaluated at runtime when the DISPLAY statement is executed, it will be formated as an integer with the proper format string (the default for integers in this case). The resulting formatted value will be displayed on the screen in the space reserved for widget j (which happens to be of type character, but it could be any type). This is essentially a temporary visual override of a named location in the frame.

Interestingly, the usage is easily accommodated by the Java frame element syntax. Because of this, the result looks very close to any other usage. The major difference is that a format string is passed explicitly to the frame element since the value is of an arbitrary data type and the format of the widget being used is ignored.

...
public void body()
{
   f0Frame.openScope();

   FrameElement[] elementList0 = new FrameElement[]
   {
      new Element(i, "->,>>>,>>9", f0Frame.widgetj())
   };

   f0Frame.display(elementList0);
}
...
WHEN Clause

It is possible to conditionally show widgets in a DISPLAY statement. Sometimes it is useful to have the ability for application to decide whether to display widgets or not depending on some conditions. The syntax for this case is:

DISPLAY ... WHEN expression ...

The expression is the field name, variable name, constant or expression to be computed with the logical result type. If the expression is TRUE the widgets defined in the DISPLAY statement will be displayed. Otherwise - not. Consider the following 4GL example:

def var chVar as char initial "Hello".
def var bval as logical initial true.

form chVar with frame f0.
display chVar when bval with frame f0.
bval = false.
pause.
clear frame f0 all.
display chVar when bval with frame f0.

Will be implemented in Java as:

boolean whenCondition0 = bval.booleanValue();

FrameElement[] elementList0 = new FrameElement[]
{
   whenCondition0 ? new Element(chVar, f0Frame.widgetChVar()) : null
};

f0Frame.display(elementList0);

bval.assign(false);
pause();
f0Frame.clearAll(false);
boolean whenCondition1 = bval.booleanValue();

FrameElement[] elementList1 = new FrameElement[]
{
   whenCondition1 ? new Element(chVar, f0Frame.widgetChVar()) : null
};

f0Frame.display(elementList1);

Before pressing the key on the pause the screen is:

Now press the space bar to see the result of the second DISPLAY statement:

Consider the widget label is presented but the value is not due to the WHEN condition is FALSE is this case.

Record Convenience Syntax

Another form of the DISPLAY statement is designed as a convenience syntax when displaying most or all of a database record (and nothing else):

DISPLAY
   [ STREAM stream ]
   [ UNLESS-HIDDEN ]
  record [ EXCEPT field ... ]
  [ IN WINDOW window ]
  [ frame-phrase ]
  [ NO-ERROR ]

The only difference is in syntax. In this case, all fields of the database record (excluding any fields listed in the optional EXCEPT clause) will be created as widgets in the frame, in the order in which they appear in the database schema. The Java conversion simple expands these database fields out as if they were explicitly specified. Then all the rest of the conversion and runtime processing is the same.

Consider the following 4GL code sample:

create book.
display book with frame f0.

This will be implemented in Java as:

RecordBuffer.create(book);

FrameElement[] elementList0 = new FrameElement[]
{
   new Element(new FieldReference(book, "bookId"), f0Frame.widgetBookId()),
   new Element(new FieldReference(book, "bookTitle"), f0Frame.widgetBookTitle()),
   new Element(new FieldReference(book, "publisher"), f0Frame.widgetPublisher()),
   new Element(new FieldReference(book, "isbn"), f0Frame.widgetIsbn()),
   new Element(new FieldReference(book, "onHandQty"), f0Frame.widgetOnHandQty()),
   new Element(new FieldReference(book, "cost"), f0Frame.widgetCost()),
   new Element(new FieldReference(book, "pubDate"), f0Frame.widgetPubDate()),
   new Element(new FieldReference(book, "authorId"), f0Frame.widgetAuthorId()),
   new Element(new FieldReference(book, "soldQty"), f0Frame.widgetSoldQty()),
   new Element(new FieldReference(book, "price"), f0Frame.widgetPrice())
};

f0Frame.display(elementList0);

The table record is expanded into a set of the widget elements comprising all fields of the table.

WITH BROWSE Form

Another form of the DISPLAY statement displays the specified database record and/or the value of the specified expressions into the current row of a specific BROWSE widget.

The 4GL syntax for this case is:

DISPLAY
{
    expression ...
  | record [ ESCEPT field ... ]

WITH BROWSE browse [ NO-ERROR ]

The following example uses this form of the statement to display content of the book record. The 4GL source will be:

def browse brws query q no-lock no-wait display book with no-box separators 7 down.
enable brws with frame f0.
display book with browse brws.

This converts to Java as:

RecordBuffer.create(book);

FrameElement[] elementList0 = new FrameElement[]
{
   new Element(new FieldReference(book, "bookId"), f0Frame.widgetBrwsBookIdColumn()),
   new Element(new FieldReference(book, "bookTitle"), f0Frame.widgetBrwsBookTitleColumn()),
   new Element(new FieldReference(book, "publisher"), f0Frame.widgetBrwsPublisherColumn()),
   new Element(new FieldReference(book, "isbn"), f0Frame.widgetBrwsIsbnColumn()),
   new Element(new FieldReference(book, "onHandQty"), f0Frame.widgetBrwsOnHandQtyColumn()),
   new Element(new FieldReference(book, "cost"), f0Frame.widgetBrwsCostColumn()),
   new Element(new FieldReference(book, "pubDate"), f0Frame.widgetBrwsPubDateColumn()),
   new Element(new FieldReference(book, "authorId"), f0Frame.widgetBrwsAuthorIdColumn()),
   new Element(new FieldReference(book, "soldQty"), f0Frame.widgetBrwsSoldQtyColumn()),
   new Element(new FieldReference(book, "price"), f0Frame.widgetBrwsPriceColumn())
};
f0Frame.widgetBrws().registerQuery(query0, elementList0);

FrameElement[] elementList1 = new FrameElement[]
{
   new WidgetElement(f0Frame.widgetBrws())
};

f0Frame.enable(elementList1);

f0Frame.display(f0Frame.widgetBrws());

Note the data is encapsulated in the BROWSE widget instead of the FRAME as in previous example.

ENABLE Statement

Enables input for one or more field-level and child frame widgets within a frame. There is a hidden VIEW statement inside the enable processing. This section addresses the visual behavior of ENABLE which is provided by this embedded VIEW.

Complete syntax of the ENABLE statement provided below:

ENABLE [ UNLESS-HIDDEN ]
{
     ALL [ EXCEPT field ... ]
   | {   widget-phrase [ WHEN expression ]
       | TEXT ( { widget-phrase [ WHEN expression ] } ... )
       | constant [ AT n | TO n ] [ presentation-element ] [ VIEW-AS TEXT ]
       | SPACE [ ( n ) ]
       | SKIP [ ( n ) ]
     } ...
}
[ IN WINDOW window ] [ frame-phrase ]

The syntax of widget-phrase:

widget [format-phrase]

During conversion format-phrase, constants, AT n, TO n, VIEW-AS TEXT, SKIP and SPACE are converted in the static frame definition class. Refer to Frames chapter for more details. The IN WINDOW clause is not supported. Remaining elements of statement are converted into business logic code into calls to different frame methods depending on the actual expression syntax. Following example illustrates conversion of ENABLE ALL, ENABLE ALL EXCEPT and ENABLE UNLESS-HIDDEN ALL:

def temp-table test no-undo
    field tot-hrs as int
    field proj-mgr  as int.

form test with frame f0.
enable all with frame f0.
enable all except proj-mgr with frame f0.
enable unless-hidden all with frame f0.

Resulting business logic code provided below (excerpt):

...
public void execute()

   externalProcedure(new Block()
   {
      public void body()
      {
         f0Frame.openScope();
         RecordBuffer.openScope(test);
         f0Frame.enable();
         f0Frame.enableExcept(f0Frame.widgetProjMgr());
         f0Frame.enableUnlessHidden();
      }
   });
}
...

Note calls to frame methods which correspond to appropriate versions of the statement syntax.

Example above enables does not refer particular widgets which need to be enabled. Following example illustrates conversion of the case when particular widgets are enabled:

def var i as int.
def var j as char.

form i j with frame f0.
enable i j with frame f0.

Converted business logic code uses simplified version of Frame Elements approach described above:

...
   f0Frame.openScope();

   FrameElement[] elementList0 = new FrameElement[]
   {
      new WidgetElement(f0Frame.widgeti()),
      new WidgetElement(f0Frame.widgetj())
   };

   f0Frame.enable(elementList0);
}
...

The next example illustrates the conversion of a WHEN clause:

def var i as int.
def var j as char.

form i j with frame f0.
enable j when i > 1 with frame f0.

The resulting converted business logic:

...
public void body()
{
   f0Frame.openScope();
   boolean whenCondition0 = _isGreaterThan(i, 1);

   FrameElement[] elementList0 = new FrameElement[]
   {
      whenCondition0 ? new WidgetElement(f0Frame.widgetj()) : null
   };

   f0Frame.enable(elementList0);
}
...

The TEXT option allows to define a group of the character fields or variable to use automatic text-wrap. The including fields can be the elements of the array. When inserting data into the middle of the TEXT field, the system wraps data that follows into the next TEXT field if necessary. When the chars are deleted in a middle of the TEXT field, system wraps data that follows into the empty area.

The following 4GL code:

enable text( chVar format "x(20)" ).

will be implemented in Java as:

FrameElement[] elementList0 = new FrameElement[]
{
   new WidgetElement(frame0.widgetChVarArray0()),
   new WidgetElement(frame0.widgetChVarArray1()),
   new WidgetElement(frame0.widgetChVarArray2()),
   new WidgetElement(frame0.widgetChVarArray3()),
   new WidgetElement(frame0.widgetChVarArray4()),
   new WidgetElement(frame0.widgetChVarArray5())
};

frame0.enable(elementList0);

This option usually is used when the ENABLE statement is embedded into one of the more complicated statement. For example type any long data into the character FILL-IN with limited format. The text will be automatically wrapped to the next FILL-IN as in the example below.

The constant option allows to display the literal in a frame as constant value. If the VIEW-AS TEXT is used in constant option the constant is displaying as text widget rather than the fill-in. Consider the following 4GL example:

def var chVar as char initial "The text constant" format "x(20)".
enable chVar at 10.
display chVar.

Will be implemented in Java as:

...
FillInWidget chVar = new FillInWidget();
...
FrameElement[] elementList0 = new FrameElement[]
{
   new WidgetElement(frame0.widgetChVar())
};

frame0.enable(elementList0);
...

The screen will show the FILL-IN widget constant style:

Another 4GL example:

def var chVar as char initial "The text constant" format "x(20)".
enable chVar to 35 view-as text.
display chVar.

Implementing in Java as:

...
ControlTextWidget chVar = new ControlTextWidget();
...
FrameElement[] elementList0 = new FrameElement[]
{
   new WidgetElement(frame0.widgetChVar())
};

frame0.enable(elementList0);
...

will have the following screen:

Note the difference in displaying the constant. The second example uses the TEXT widget style rather than FILL-IN.

INSERT Statement

The INSERT statement is not supported at this time.

PROMPT-FOR Statement

Requests input and places that input in the screen buffer. Consist of the following simple statements: ENABLE to enable the widget modification, WAIT-FOR blocks to wait for the input and DISABLE to disable the modification after the changes are committed. There is no copying of data to the screen buffer nor is there any assignment back after the edits occur.

The PROMPT-FOR statement has following syntax:

PROMPT-FOR [ STREAM stream ] [ UNLESS-HIDDEN ]
{ { widget-phrase [ WHEN expression ]}
 | { TEXT ( { widget-phrase [ WHEN expression ] } ...)}
 | { constant [ { AT | TO } n ] [ VIEW-AS TEXT ] [ presentation-element ]}
 | SPACE [ ( n ) ] | SKIP [ ( n ) ] | ^ } ...
[ GO-ON ( key-label ... ) ]
[ IN WINDOW window ] [ frame-phrase ] [ editing-phrase ]

During conversion format-phrase, constants, AT n, TO n, VIEW-AS TEXT, presentation-element, SKIP and SPACE are converted in the static frame definition class. Refer to Frames chapter for more details. The IN WINDOW clause, UNLESS-HIDDEN clause and caret (^) are not supported.

The PROMPT-FOR statement has many similarities in syntax with ENABLE and DISPLAY statements, so converted code also looks very similar to code generated for these statements. First example illustrates conversion of simple PROMPT-FOR statement without STREAM clause:

def var i as int.
def var j as char.

prompt-for i j with frame f0.

Converted code uses Frame Elements approach just like DISPLAY statement:

...
public void body()
{
   f0Frame.openScope();

   FrameElement[] elementList0 = new FrameElement[]
   {
      new Element(i, f0Frame.widgeti()),
      new Element(j, f0Frame.widgetj())
   };

   f0Frame.promptFor(elementList0);
}
...

With STREAM clause converted code also very similar to code produced for DISPLAY statement:

def var i as int.
def var j as char.
def stream str.

prompt-for stream str i j with frame f0.

The stream reference is passed as a first parameter:

...
public void body()
{
   f0Frame.openScope();
   TransactionManager.registerTopLevelFinalizable(strStream, true);

   FrameElement[] elementList0 = new FrameElement[]
   {
      new Element(i, f0Frame.widgeti()),
      new Element(j, f0Frame.widgetj())
   };

   f0Frame.promptFor(strStream, elementList0);
}
...

Next example illustrates use of GO-ON clause which has no counterpart in DISPLAY statement:

def var i as int.
def var j as char.

prompt-for i j go-on ( "F11" ) with frame f0.

List of events from GO-ON clause is passed as a second parameter:

...
public void body()
{
   f0Frame.openScope();

   FrameElement[] elementList0 = new FrameElement[]
   {
      new Element(i, f0Frame.widgeti()),
      new Element(j, f0Frame.widgetj())
   };
   EventList list0 = new EventList();
   list0.addGoOn("F11");

   f0Frame.promptFor(elementList0, list0);
}
...

The complete detail set is described in respective PROMPT-FOR section of the Editing chapter.

There is another form of this statement to use with the particular DB record:

PROMPT-FOR
   [ STREAM stream ]
   [ UNLESS-HIDDEN ]
   record [ ESCEPT field ... ]
   [ IN WINDOW window ] { [ frame-phrase ] }

In this case the record reference is expanded into a list of all fields in the record and then the statement is converted normally. Consider the following 4GL code sample:

prompt-for book with frame f0.

Will be implemented in Java as:

FrameElement[] elementList0 = new FrameElement[]
{
   new Element(new FieldReference(book, "bookId"), f0Frame.widgetBookId()),
   new Element(new FieldReference(book, "bookTitle"), f0Frame.widgetBookTitle()),
   new Element(new FieldReference(book, "publisher"), f0Frame.widgetPublisher()),
   new Element(new FieldReference(book, "isbn"), f0Frame.widgetIsbn()),
   new Element(new FieldReference(book, "onHandQty"), f0Frame.widgetOnHandQty()),
   new Element(new FieldReference(book, "cost"), f0Frame.widgetCost()),
   new Element(new FieldReference(book, "pubDate"), f0Frame.widgetPubDate()),
   new Element(new FieldReference(book, "authorId"), f0Frame.widgetAuthorId()),
   new Element(new FieldReference(book, "soldQty"), f0Frame.widgetSoldQty()),
   new Element(new FieldReference(book, "price"), f0Frame.widgetPrice())
};

f0Frame.promptFor(elementList0);

Note the single record is converted to the set of the elements. Then the statement PROMPT-FOR is used as in previous examples for the single widgets.

SET Statement

Request input, puts data into the screen buffer of the frame and in the variable itself. Internally, this statement consists of a PROMPT-FOR statement to take the input to the screen buffer and ASSIGN to move the screen buffer to the variable or the record buffer. There is no copying of data from the business logic into the screen buffer.

The syntax of SET statement is:

SET [ STREAM stream ] [ UNLESS-HIDDEN ]
[{ widget-phrase } [ WHEN expression ]
 | TEXT ( widget-phrase ... )
 | embedded-assignment
 | constant [ AT n | TO n ]
 | ^
 | SPACE [ ( n ) ]
 | SKIP [ ( n ) ]
] ...
[ GO-ON (key-label ... ) ]
[ frame-phrase ] [ editing-phrase ] [ NO-ERROR ]

During conversion format-phrase, constants, AT n, TO n, SKIP and SPACE are converted in the static frame definition class. Refer to Frames chapter for more details. The UNLESS-HIDDEN clause and caret (^) are not supported.

The embedded-assignment has following syntax:

field = expression

The editing-phrase syntax is described in more details in SET EDITING section of the appropriate Editing statements chapter.

As one might note, SET statement is very similar to PROMPT-FOR statement, except embedded-assignment and editing-phrase. The embedded-assignment is converted into regular variable declaration, while editing-phrase is converted into editing block. See the respective editing block implementation section of the Editing chapter.

Following example illustrates conversion of the SET statement without STREAM clause:

def var i as int.
def var j as char.

set i j with frame f0.

Converted code is very similar to code for PROMPT-FOR code, except set() method is invoked:

...
public void body()
{
   f0Frame.openScope();

   FrameElement[] elementList0 = new FrameElement[]
   {
      new Element(i, f0Frame.widgeti()),
      new Element(j, f0Frame.widgetj())
   };

   f0Frame.set(elementList0);
}
...

Next example demonstrates use of STREAM clause and default frame:

def var i as int.
def var j as char.
def stream str.

set stream str i j.

Again, converted code is very similar to PROMPT-FOR:

...
public void body()
{
   frame0.openScope();
   TransactionManager.registerTopLevelFinalizable(strStream, true);

   FrameElement[] elementList0 = new FrameElement[]
   {
      new Element(i, frame0.widgeti()),
      new Element(j, frame0.widgetj())
   };

   frame0.set(strStream, elementList0);
}
...

Last example uses event list and GO-ON clause:

def var i as int.
def var j as char.

set i j go-on ( "F11" ) with frame f0.

Event list is passed as second parameter:

...
public void body()
{
   f0Frame.openScope();

   FrameElement[] elementList0 = new FrameElement[]
   {
      new Element(i, f0Frame.widgeti()),
      new Element(j, f0Frame.widgetj())
   };
   EventList list0 = new EventList();
   list0.addGoOn("F11");

   f0Frame.set(elementList0, list0);
}
...

The GO-ON option of the set statement has also been described in Editing chapter, SET GO-ON subsection.

There is another form of this statement to use with the particular DB record:

SET [ STREAM stream ] [ UNLESS-HIDDEN ]
   record [ ESCEPT field ... ] [ frame-phrase ] [ NO-ERROR ]

In this case the record reference is expanded into a list of all fields in the record and then the statement is converted normally. Consider the following 4GL code sample:

set book with frame f0.

Will be implemented in Java as:

FrameElement[] elementList0 = new FrameElement[]
{
   new Element(new FieldReference(book, "bookId"), f0Frame.widgetBookId()),
   new Element(new FieldReference(book, "bookTitle"), f0Frame.widgetBookTitle()),
   new Element(new FieldReference(book, "publisher"), f0Frame.widgetPublisher()),
   new Element(new FieldReference(book, "isbn"), f0Frame.widgetIsbn()),
   new Element(new FieldReference(book, "onHandQty"), f0Frame.widgetOnHandQty()),
   new Element(new FieldReference(book, "cost"), f0Frame.widgetCost()),
   new Element(new FieldReference(book, "pubDate"), f0Frame.widgetPubDate()),
   new Element(new FieldReference(book, "authorId"), f0Frame.widgetAuthorId()),
   new Element(new FieldReference(book, "soldQty"), f0Frame.widgetSoldQty()),
   new Element(new FieldReference(book, "price"), f0Frame.widgetPrice())
};

f0Frame.set(elementList0);

Note the single record is converted to the set of the elements. Then the statement SET is used as in previous examples for the single widgets.

UPDATE Statement

The statement displays the fields or variable, requests modification inputs and puts the new data to the screen buffer and underlying variable or record buffer.

This is the composition of the following simple statements: DISPLAY to moves the data to the screen buffer and displays it, PROMPT-FOR for requesting data modification and store it in the screen buffer and ASSIGN to move the screen buffer to the variable or record buffer.

UPDATE [ STREAM stream ] [ UNLESS-HIDDEN ]
[{ widget-phrase } [ WHEN expression ]
 | TEXT ( widget-phrase ... )
 | embedded-assignment
 | constant [ AT n | TO n ]
 | ^
 | SPACE [ ( n ) ]
 | SKIP [ ( n ) ]
] ...
[ GO-ON (key-label ... ) ]
[ frame-phrase ] [ editing-phrase ] [ NO-ERROR ]

The UPDATE statement is exact copy of the SET statement by the means of syntax, conversion and limitations. The only difference is that instead of set() method, update() method is called:

def var i as int.
def var j as char.

update i j go-on ( "F11" ) with frame f0.

Converted code looks so:

...
public void body()
{
   f0Frame.openScope();

   FrameElement[] elementList0 = new FrameElement[]
   {
      new Element(i, f0Frame.widgeti()),
      new Element(j, f0Frame.widgetj())
   };
   EventList list0 = new EventList();
   list0.addGoOn("F11");

   f0Frame.update(elementList0, list0);
}
...

Fore details of using the UPDATE statement can be found in appropriate section of the Editing chapter.

There is another form of this statement to use with the particular DB record:

UPDATE record
   [ ESCEPT field ... ]
   [ frame-phrase ]
   [ NO-ERROR ]

In this case the record reference is expanded into a list of all fields in the record and then the statement is converted normally.

Consider the following 4GL code sample:

update book with frame f0.

Will be implemented in Java as:

FrameElement[] elementList0 = new FrameElement[]
{
   new Element(new FieldReference(book, "bookId"), f0Frame.widgetBookId()),
   new Element(new FieldReference(book, "bookTitle"), f0Frame.widgetBookTitle()),
   new Element(new FieldReference(book, "publisher"), f0Frame.widgetPublisher()),
   new Element(new FieldReference(book, "isbn"), f0Frame.widgetIsbn()),
   new Element(new FieldReference(book, "onHandQty"), f0Frame.widgetOnHandQty()),
   new Element(new FieldReference(book, "cost"), f0Frame.widgetCost()),
   new Element(new FieldReference(book, "pubDate"), f0Frame.widgetPubDate()),
   new Element(new FieldReference(book, "authorId"), f0Frame.widgetAuthorId()),
   new Element(new FieldReference(book, "soldQty"), f0Frame.widgetSoldQty()),
   new Element(new FieldReference(book, "price"), f0Frame.widgetPrice())
};

f0Frame.update(elementList0);

Note the single record is converted to the set of the elements. Then the statement UPDATE is used as in previous examples for the single widgets.

VIEW Statement

The statement displays a widget(sets its VISIBLE attribute to TRUE). This causes the values in the screen buffer to appear on the screen. It does not copy any new values into the screen buffer.

Complete syntax of the VIEW statement is provided below:

VIEW [ STREAM stream ] [ frame-reference | widget-reference | handle-reference ]
   [ IN WINDOW window ]

The IN WINDOW clause is not supported. If no frame nor widget is specified then current default frame is displayed.

The frame-reference has following syntax:

FRAME frame

The widget-reference has following syntax:

[FIELD] widget [IN FRAME frame]
 | column [IN BROWSE browse]
 | {MENU | SUB-MENU menu}
 | MENU-ITEM item [IN MENU menu]

MENU, SUB-MENU and MENU-ITEM clauses are not supported.

The handle-reference has following syntax:

handle | system-handle

The handle-reference clause is not supported. If no frame nor widget is specified then current default frame is displayed.

Following example illustrates conversion of some variants of VIEW statement syntax:

def var i as int.
def var j as char.

form i j with frame f0.
view frame f0.
view i in frame f0.

Converted business logic code looks so (excerpt):

...
public void body()
{
   f0Frame.openScope();

   f0Frame.view();

   f0Frame.widgeti().view();
}
...

Next example illustrates conversion of the VIEW statement with STREAM clause:

def var i as int.
def var j as char.
def stream str.

form i j with frame f0.
view stream str frame f0.

Converted code looks very similar to previous example, except additional parameter - stream - passed to view() method:

...
public void body()
{
   f0Frame.openScope();
   TransactionManager.registerTopLevelFinalizable(strStream, true);

   f0Frame.view(strStream);
}
...

Consideration to take into account when using the VIEW statement is the following. The statement does not display the widget itself. Only attribute of the widget is changing. The VIEW statement set the VISIBLE attribute to TRUE and the HIDDEN attribute to FALSE.

Display-like Statements

This group of statements contains following statements:

COLOR
HIDE
UNDERLINE

As mentioned above, during conversion these statements don't affect frame scoping. This does mean that frame referred in these statements scoped as if there were no such statements in code at all. Conversion of each statement described in details below.

COLOR Statement

The COLOR statement has following syntax:

COLOR [DISPLAY | {PROMPT | PROMPT-FOR}]  color-phrase
      [{PROMPT | PROMPT-FOR} color-phrase]
      widget {, widget... }
      [frame-phrase]

Where widget is the name of the variable for which widget was created.

The color-phrase has following syntax:

NORMAL | INPUT | MESSAGES | color-attribute | VALUE(expression)

The color-attribute has following syntax:

unix-attribute | dos-attribute | [BLINK-] [BRIGHT-] [RVV-] [UNDERLINE-] [color-name] [color-name]

The first color-name represents the foreground color, the second (if present) is the background color.

The color-phrase converts as an instance of the com.goldencode.p2j.ui.ColorSpec class, which has public constants to specify the well known colors of NORMAL, INPUT and MESSAGES. See below for examples.

The use of the color-attribute is not supported at this time.

The following example illustrates conversion of the COLOR statement:

def var i as int.
form i with 10 down frame f1.

color display message i with frame f1.

Relevant code in business logic:

...
public void execute()
{
   externalProcedure(new Block()
   {
...
      public void body()
      {
...
         f1Frame.setColors(new ColorSpec(ColorSpec.COLOR_MESSAGES), null, f1Frame.widgeti());
      }
   });
}
...

The option PROMPT (which has as synonym PROMPT-FOR) is used to redefine the color attribute displaying in different data updating statements like PROMPT-FOR, SET or UPDATE. Consider the following 4GL example:

def var iVar as integer.
color prompt messages iVar.
update iVar.

This converts to Java as:

frame0.setColors(null, new ColorSpec(ColorSpec.COLOR_MESSAGES), frame0.widgetIVar());

FrameElement[] elementList0 = new FrameElement[]
{
   new Element(iVar, frame0.widgetIVar())
};

frame0.update(elementList0);

After the application starts the update color attribute is changing and the screen become:

Note the color change in data update area.

Another option can be used to redefine the color attribute is VALUE. The expression here is a character variable with the possible values of “NORMAL”, “INPUT” or “MESSAGES”. The 4GL example of usage is:

def var iVar as integer.
def var chColor as character initial "MESSAGES".

color prompt value(chColor) iVar.
update iVar.

This will be converted to Java as:

...
character chColor = new character("MESSAGE");

...
  frame0.setColors(null, new ColorSpec((chColor).toStringMessage()), frame0.widgetIVar());

FrameElement[] elementList0 = new FrameElement[]
{
   new Element(iVar, frame0.widgetIVar())
};

frame0.update(elementList0);
...

Again after starting application the screen will be:

The screen is the same as in previous example and this is expected.

HIDE Statement

The syntax of HIDE statement provided below:

HIDE [STREAM stream] [ALL | MESSAGE | widget-phrase] [NO-PAUSE] [IN WINDOW window]

Syntax of widget-phrase is provided above. The ALL clause hides all visible frames. The MESSAGE clause does not affect frames but hides messages present in message area instead. This version of the HIDE statement syntax is not related to frames and provided here only for completeness. The NO-PAUSE clause suppresses (possible) pause which may be triggered by HIDE statement. The IN WINDOW clause is not supported.

Conversion of HIDE statement is identical to display statements as can be seen from the following example:

display "Hello" with frame f0.
hide frame f0.

Business logic class contains following code:

...
public void execute()
{
   externalProcedure(new Block()
   {
      public void body()
      {
         f0Frame.openScope();
...
         f0Frame.hide();
      }
   });
}
...

When using option HIDE ALL every widget in a frame will be hidden. Consider the following example:

def var chVar as character initial "World".
display "Hello" chVar with frame f0.
pause.
hide all.

The converted code will be:

character chVar = new character("World");
...
   FrameElement[] elementList0 = new FrameElement[]
   {
      new Element("Hello", f0Frame.widgetExpr1()),
      new Element(chVar, f0Frame.widgetChVar())
   };

   f0Frame.display(elementList0);
   pause();
   hideAll(false);

After application starts the screen is:

Press a key to hide everything:

The option NO-PAUSE disables emitting the key press waiting to continue on some conditions.

The statement option HIDE MESSAGE is completely described in appropriate section of the Terminal chapter.

UNDERLINE Statement

The UNDERLINE statement also has syntax similar to displaying statements:

UNDERLINE [STREAM stream] widget {, widget ...} [frame-phrase]

Following example illustrates conversion of UNDERLINE statement:

def var ch1 as character format "x(40)".

assign ch1 = "Hello underlined world.".
display ch1 with 2 down no-labels no-box.
underline ch1.

Business logic part of the converted code looks so:

...
public void body()
{
   frame0.openScope();
   ch1.assign("Hello underlined world.");

   FrameElement[] elementList0 = new FrameElement[]
   {
      new Element(ch1, frame0.widgetCh1())
   };

   frame0.display(elementList0);

   frame0.widgetCh1().underline();
...
}
...

When the application starts the screen will be:

The widget has no labels as defined in the DISPLAY statement. The statement works for down frames only (when down is more than 1). When using side labels, the label portion is not underlined:

For 1 DOWN frames the UNDERLINE statement does not work. The underlined widget is cleared in this case instead.

Frame/Widget Attributes Which Affect Visibility

This group consist of following attributes:

VISIBLE
HIDDEN

For details on the conversion of attributes, see the Expressions chapter. The following simple example illustrates conversion of both attributes:

def var i as int init 10.
display i with frame f1.
frame f1:visible = false.
frame f1:hidden = false.

Business logic class contains the following code after conversion:

...
public void execute()
{
   externalProcedure(new Block()
   {
      integer i = new integer(10);

      public void init()
      {
         TransactionManager.registerUndo(i);
      }

      public void body()
      {
         f1Frame.openScope();

         FrameElement[] elementList0 = new FrameElement[]
         {
            new Element(i, f1Frame.widgeti())
         };

         f1Frame.display(elementList0);

         f1Frame.setVisible(new logical(false));
         f1Frame.setHidden(new logical(false));
      }
   });
}
...

There are the considerations to take into account using this attribute depending on the widget type the attribute used with. This is related to the FWD implementation details.

If the widget is a frame and we set the VISIBLE attribute to TRUE:

  • attribute VISIBLE is accepting TRUE value
  • attribute HIDDEN for the frame becomes FALSE
  • the frame becomes visible.

If the widget is a frame and we set the VISIBLE attribute to FALSE:

  • attribute VISIBLE of the frame becomes FALSE
  • attribute HIDDEN of the frame becomes TRUE
  • the frame becomes hidden.

If the widget is a frame and we set the HIDDEN attribute to TRUE:

  • attribute VISIBLE is accepting FALSE value
  • the frame becomes hidden.
  • attribute HIDDEN for the frame becomes TRUE.

If the widget is a frame and we set the HIDDEN attribute to FALSE:

  • attribute VISIBLE of the frame becomes TRUE
  • the frame becomes visible
  • attribute HIDDEN of the frame becomes FALSE.

If the widget is not a frame and we set the VISIBLE attribute:

  • attribute VISIBLE accepts the new value
  • attribute HIDDEN accepts the opposite value
  • the widget is forced to be redrawn

If the widget is not a frame and we set the HIDDEN attribute:

  • attribute HIDDEN accepts the new value
  • attribute VISIBLE accepts the opposite value
  • the widget is forced to be redrawn

The attributes are mutually exclusive. Both attributes cannot have the same value, TRUE or FALSE.


© 2004-2017 Golden Code Development Corporation. ALL RIGHTS RESERVED.