See: Description
Interface | Description |
---|---|
BrowseImpl.ColumnRenderer |
Interface for renderers of horizontally scrollable rows.
|
Class | Description |
---|---|
AbstractTerminalBuffer |
This class is a base with most possible common code for implementations
which hold internal screen buffer for drawing operations.
|
AlertBoxImpl |
This class is an specific implementation of the AlertBox for CHUI.
|
BasePrimitives |
Base class for all other
OutputPrimitives implementations used by
CHUI. |
BrowseImpl |
CHUI-specific portion of implementation of Progress BROWSE widget.
|
ButtonImpl |
Specific implementation of a "push button" with a text label for CHUI.
|
ChuiWidgetFactory |
CHUI-specific widget factory implementation.
|
ColumnLayout<O extends OutputManager<?>> |
This is the LayoutManager which places the widgets into specified number
of the columns and put the container into SIDE-LABELS mode.
|
ComboBoxImpl |
Specific ComboBox implementation for CHUI.
|
ContentResolver |
Worker class which resolves the content for TEXT/FILL-IN/LITERAL widgets in ChUI.
|
DirectPrimitives |
Direct output primitives which implement shadow buffer semantic.
|
DoubleBufferedTerminal |
Provides a plugin as a compatible back-end for interactive terminal, which
uses a double buffering technique to output only the absolute minimum
of information to the terminal, which is calculated as the difference
between the current and the previous buffers.
|
DropDownImpl |
Implements the drop-down window for a combo-box.
|
EditorImpl |
CHUI-specific portion of EDITOR component.
|
FillInImpl |
Implementation of Progress FILL-IN component for CHUI.
|
FramePlacementManager |
The class handles proper placement of frames at the screen.
|
FramePlacementManager.FrameComparator |
Local comparator for two Frame instances.
|
LabelImpl |
CHUI-specific portion of Label.
|
MessageLine |
Message line implementation.
|
RadioButtonImpl |
CHUI-specific portion of RadioButton.
|
RectangleImpl |
Specific implementation of RECTANGLE widget.
|
RedirectedTerminal |
Provides an implementation which with a compatible back-end for formatted
output acts like a terminal but for which the transformed data is written to
a stream.
|
ScrollableListImpl |
CHUI-specific portion of ScrollableList.
|
ScrollPaneImpl |
CHUI-specific implementation of
ScrollPane . |
SelectionListBodyImpl |
CHUI-specific part of the SelectionListBody.
|
SelectionListImpl |
CHUI-specific implementation of SelectionList
|
SeparatorImpl |
CHUI-specific implementation of Separator.
|
SkipImpl |
CHUI-specific version of Skip.
|
StatusLineImpl |
CHUI-specific version of StatusLine
|
TerminalBuffer |
Minimal possible driver which implements all output primitives using
memory buffer as destination.
|
TextImpl |
CHUI-specific static text widget (
Text ) implementation. |
ThinClient |
Thin Client generic CHUI driver.
|
ThinClient.TriggerResult |
Container for the flags related to trigger processing.
|
ThinClient.WaitForOp |
Container for data related to wait-for loops.
|
ToggleBoxImpl |
Specific implementation of a "toggle box" with a text label for CHUI.
|
TraceableTerminal |
This implementation can be used to trace all output calls for testing and/or
debugging purposes.
|
Author |
Eric Faulhaber Sergiy Yevtushenko Rohithaksha Kalluraya Stanislav Lomany Constantin Asofiei Nick Saxon |
Date |
Sep 15, 2011 |
Access Control |
CONFIDENTIAL |
Widget data value and SCREEN-VALUE handling
Unknown date value displayProgress Frame Hiding Behavior
Progress Frame Hiding
and PUT SCREEN output
Progress Frame Initial
Display and PUT SCREEN output
Known issues with the current design
Values returned by widget when F1 is pressed right after start of the UPDATE operation.
Widget |
Variable value |
SCREEN-VALUE |
Comments |
COMBO-BOX with default variable
value |
(default value) | (value of first choice) |
|
COMBO-BOX with initialized
variable |
(initial value) |
(initial value) | |
COMBO-BOX with variable
initialized to incorrect value |
(initial value) | (value of first choice) | |
EDITOR with default variable
value |
(default value) | (default value) | |
EDITOR with initialized variable |
(initial value) | (initial value) | |
FILL-IN with default variable value | (default value) | (default value) | |
FILL-IN with initialized variable | (initial value) | (initial value) | |
RADIO-SET with default variable value | (value of first choice) |
(value of first choice) |
|
RADIO-SET with initialized variable | (initial value) | (initial value) | |
RADIO-SET with variable initialized to incorrect value | (value of first choice) | (value of first choice) | Warning message: **Attribute SCREEN-VALUE for the RADIO-SET txt1 has an invalid value of x (4058) |
SELECTION-LIST with default variable value | (default value) | UNKNOWN |
|
SELECTION-LIST with initialized variable | (initial value) | (initial value) | |
SELECTION-LIST with variable initialized to incorrect value | (UNKNOWN value) | UNKNOWN | Warning message **Attribute SCREEN-VALUE for the SELECTION-LIST txt1 has an invalid value of x. (4058) |
Progress 4GL adjusts leading space of the label of the widget depending on the terminal width (so the frame width). Following test cases demonstrate its behaviors.
If a frame has a "COLON" phrase defined as a part of its side-label, it will try to adjust the leading space of that side-label when the terminal width is less than the total width of the frame. In this scenario, progress throws an error but continues to show the frame with an adjustment in the leading space of the side-labels. This adjustment is possible ONLY until there is some leading space in the longest among the side-labels (in the below case its "Program Name").
For all the test cases keep the terminal width (number of columns) as 80.
"frame_width_adjustment_1a.p" is a working program to demonstrate how a frame looks like without any adjustment. This fits the terminal having the width as mentioned above. To prove that Progress tries to adjust the side-label's leading space, in "frame_width_adjustment_1b.p", "name" widget's width has been increased to 64. This program shows an error message while running but on click of OK button it shows the frame with leading space being truncated. However as demonstrated in "frame_width_adjustment_1c.p", it does not truncate the text from the side-label. In that, "name" widget's length has been increased further to 65. Also note that this adjustment happens until the longest of the side-labels has a leading space. To justify this behavior, same scenario has been repeated in "frame_width_adjustment_1d.p" and "frame_width_adjustment_1e.p" with different text for "name" widget.
COLON: "frame_width_adjustment_2a.p" proves its the COLON phrase which shows adjustment behavior. This program shows an error message and exits.
NO-BOX: "frame_width_adjustment_3a.p" and "frame_width_adjustment_3b.p" proves that NO-BOX option does not affect the adjustment behavior. However, since NO-BOX phrase removes the frame border, two characters can be used for widgets.
ATTR-SPACE and NO-ATTR-SPACE: "frame_width_adjustment_4a.p" and "frame_width_adjustment_4b.p" proves that ATTR-SPACE phrase does not affect the adjustment behavior.
Leading space within the label: "frame_width_adjustment_5a.p" proves providing leading space within the label does not get adjusted when the frame width exceeds terminal width.
No side-labels: "frame_width_adjustment_6a.p", "frame_width_adjustment_6b.p" and "frame_width_adjustment_6c.p" proves that side-labels does not affect the adjustment behavior.
Multiple widgets of same type: "frame_width_adjustment_7a.p", "frame_width_adjustment_7b.p" and "frame_width_adjustment_7c.p" proves that longest of the side-labels are considered for adjustment. "frame_width_adjustment_7d.p", "frame_width_adjustment_7e.p" and "frame_width_adjustment_7f.p" are the similar test cases with three widgets.
FILL-IN: "frame_width_adjustment_8a.p" and "frame_width_adjustment_8b.p" proves that FILL-IN phrase does not show any adjustment behavior.
DOWN: "frame_width_adjustment_9a.p" and "frame_width_adjustment_9b.p" proves that DOWN phrase does not show any adjustment behavior.
RETAIN x: "frame_width_adjustment_10a.p" and "frame_width_adjustment_10b.p" proves that RETAIN x phrase does not show any adjustment behavior.
TO: This phrase has a different behavior than COLON behavior.
"frame_width_adjustment_11a.p": Total frame width is same as terminal width. So this example runs without any error.
"frame_width_adjustment_11b.p": This test case has both display and update statements separated by a pause. It shows a horizontal scroll-bar since the total frame width is more than terminal width. Notice a shift in the content when moving from display to update. Total widget width is 81 (= 65 + 12 (side-label) + 2 (frame border) + 2 (colon and space)).
"frame_width_adjustment_11c.p": This program shows an error message and exits. In this case total widget width is 82 (= 66 + 12 (side-label) + 2 (frame border) + 2 (colon and space)).
"frame_width_adjustment_11d.p": TO position exceeds frame width. So progress adjusts side-label by removing leading space.
"frame_width_adjustment_11e.p": This program shows an error message and exits because side-label does not have enough leading space to adjust.
ROW x COLUMN y:
"frame_width_adjustment_12a.p" and "frame_width_adjustment_12b.p" proves that ROX x COLUMN y does not show any adjustment behavior.
"frame_width_adjustment_12c.p" and "frame_width_adjustment_12d.p" proves that data part gets truncated for all the columns but last column's label does not get truncated. All other column labels get truncated if its length exceeds the width.
"frame_width_adjustment_12e.p" and "frame_width_adjustment_12f.p"proves that ROX x COLUMN y with COLON-ALIGNED option does not show any adjustment behavior.
"frame_width_adjustment_12g.p", "frame_width_adjustment_12h.p" and "frame_width_adjustment_12i.p" proves that ROX x COLUMN y with LEFT-ALIGNED option shows adjustment behavior ONLY if it exceeds frame width by one character.
"frame_width_adjustment_12j.p" and "frame_width_adjustment_12k.p" proves that ROX x COLUMN y with RIGHT-ALIGNED option does not show any adjustment behavior.
SPACE(x): "frame_width_adjustment_13a.p", "frame_width_adjustment_13b.p" and "frame_width_adjustment_13c.p": If the space value is between 1 and 73, text appears right justified (as expected). If the value is between 74 and 78, it appears left justified and for values beyond 79 and 0, it ignores the space.
The following table specifies how the insert mode behaves when the focus moves between two widgets into one frame of the given types using the given transition method.
The "/" separates movements that were done due to: (TAB or ENTER or F1 to complete update) / (arrows or DISABLE current widget or WAIT-FOR FOCUS). If indicator states are the same in both cases, then "/" is omitted.
Focus Moving From |
to FILLIN or BROWSE cell |
to EDITOR with INSERT previously ON |
to EDITOR with INSERT previously OFF |
to NON-INSERT-MODE WIDGET (all others?) |
FILLIN with INSERT ON |
OFF / ON |
ON |
OFF |
ON |
FILLIN with INSERT OFF |
OFF |
ON |
OFF |
OFF |
EDITOR with INSERT ON |
OFF |
ON |
OFF |
OFF |
EDITOR with INSERT OFF |
OFF |
ON |
OFF |
OFF |
NON-INSERT-MODE WIDGET (all others?) |
OFF / ON|OFF * |
ON |
OFF |
ON|OFF * |
* - Depends on the state of the insert indicator when the non-insert-mode widget we are moving from is focused.
Additional rules:
Transition of any kind between two browse cells makes the insert indicator OFF.
If transition was initiated by a prompting statement (UPDATE/SET/PROMPT-FOR/MESSAGE UPDATE/MESSAGE SET including EDITING modifications) or a trigger call then the fill-in which will receive the focus after initial focus adjustment into this statement, will have the insert mode that was just before execution of this statement (no matter what key triggered execution of this statement). After leaving of a prompting statement/block or a trigger the insert mode is restored to the one that was just before its execution (except the case when trigger has returned NO-APPLY), and if a fill-in will receive the focus in the following focus adjustment, it will have the recently restored insert mode (no matter what key triggered leaving of this statement). When we have some nested editing blocks or triggers, the insert mode is saved before each nested call and restored after we have returned from this call. When an insert mode is restored, the insert indicator is forcedly redrawn after prompting statements, but not after triggers.
Transition of any kind between any widgets (except editors), which are situated into different frames, keeps the current insert indicator state. When we leave an editor, insert indicator becomes OFF. When we enter an editor, the insert indicator is set according to the saved state of the editor.
If there is no focused widget, newly displayed fillin accepts the current insert mode.
On focus restoration after a WAIT-FOR cycle, if a fillin receives the focus, we should use the current insert mode for it rather the one that is stored into this fillin.
The insert indicator is not cleared by HIDE ALL statement if there are not visible frames and no output has been performed using PUT SCREEN since the previous call of HIDE ALL.
Rules for the insert indicator state for read-only editors:
Insert indicator is always OFF when a read-only editor gains the focus. But the actual insert state is the one that was previously saved for this editor, and it will be displayed if the editor will become available for writing.
Pressing INSERT key for an editor in a read-only mode will switch the displayed state to the opposite one. The saved state for this editor also will change according to the displayed state.
After an APPLY "ENTRY" statement, insert state should be OFF for the ENTRY target (fill-in), or for the currently focused fill-in if ENTRY has returned NO-APPLY.
The following table specifies what will be the auto-zap state when the focus moves between two widgets of the given types using the given transition method.
The "/" separates movements that were done due to: (TAB or ENTER or F1 to complete update or WAIT-FOR FOCUS) / arrows / DISABLE current widget.
Focus Moving From |
to FILLIN |
to BROWSE cell |
FILLIN with AUTO-ZAP ON |
ON / OFF / ON |
ON / ON / ON |
FILLIN with AUTO-ZAP OFF |
ON / OFF / OFF |
ON / ON / ON |
OTHER WIDGETS |
ON / OFF / ON |
ON / ON|OFF* / ON |
* - The value is ON if down or up arrow was pressed and OFF if right or left arrow was pressed.
Additional rules:
Transition of any kind between two browse cells makes the auto-zap state ON.
Auto-zap state becomes ON after we have tried to leave a fill-in using TAB, BACK-TAB, GO or RETURN keys, but failed because no widgets have applied ENTRY event.
If we have a WAIT-FOR PAUSE cycle and a fillin receives the focus upon initial focus adjustment, then auto-zap state becomes OFF for this fillin.
When the focus is restored after a trigger call (if event is not consumed, event is not VALUE-CHANGED and widget is fill-in), auto-zap state should be ON for the focused fill-in.
After an APPLY "ENTRY" statement, auto-zap state should be ON for the ENTRY target (fill-in), or for the currently focused fill-in if ENTRY has returned NO-APPLY.
The following rules specify how the unknown ("?") date value is displayed - with separators (e.g. " / / ") or without them (as empty string). These rules only apply to the editing mode. When a widget is disabled (or SENSITIVE is set to false), the unknown value is displayed as empty string.
An unknown date (or if any value hasn't been copied to screen buffer) is displayed with separators after ENABLE / UPDATE / SET / PROMPT-FOR calls and set SENSITIVE = true, if the fill-in was in disabled state before.
The following actions makes unknown date to be displayed without separators:
"?" key pressing;
CLEAR key pressing;
RECALL key pressing, if initial value was unknown;
displaying of the unknown value with enabled widget, e.g.:
WAIT-FOR frame events without FOCUS
clause (frame events is an important part) For UPDATE operation, Y represents the first widget in list and FY represents the frame targeted by UPDATE (Y belongs to this frame). |
||||
Testcase | Focus before WAIT-FOR | ENTRY trigger | Initial focus in WAIT-FOR | Focus after WAIT-FOR |
wait-for_restore_focus1.p | enabled widget X | - | same widget X | same widget X (can get disabled by 'a trigger on 'x') |
wait-for_restore_focus1e.p wait-for_restore_focus1ef.p |
enabled widget X | X:NO-APPLY there are enabled widgets
|
same widget X - ignores NO-APPLY |
same widget X (can get disabled by 'a trigger on 'x') |
update_focus_valid0b.p update_focus_valid2b.p update_focus_valid4b.p | enabled widget X | Y:NO-APPLY there are other enabled widgets |
use ST5, starting from Y. | enabled widget X |
wait-for_restore_focus1m.p | enabled widget X |
X:NO-APPLY
there are only disabled widgets
|
same widget X - ignores NO-APPLY |
same widget X |
wait-for_restore_focus1s.p | enabled widget X |
X:NO-APPLY
there are no other widgets
|
same widget X - ignores NO-APPLY |
same widget X |
update_focus_valid0.p update_focus_valid1.p update_focus_valid2.p update_focus_valid3b.p |
enabled widget X | Y gets ENTRY, Y gets disabled | widget X is set FOCUS without ENTRY. | enabled widget X |
update_focus_valid3.p update_focus_valid3c.p |
enabled widget X | Y gets ENTRY, all widgets get disabled | if no other enabled widget on screen, focus is unknown. Else, search using ST6. | enabled widget X |
update_focus_valid4.p | enabled widget X | Y:NO-APPLY there are other enabled widgets in frame FY; all widgets in frame FY reject ENTRY. |
use ST5 starting from Y; immediate exit | enabled widget X |
waitfor_request_valid0.p waitfor_request_valid3b.p | enabled widget X | Y is first enabled widget on screen. Y gets ENTRY, Y gets disabled. | use ST4, starting from Y | enabled widget X |
waitfor_request_valid0B.p waitfor_request_valid3cB.p | enabled widget X | Y is NOT the first enabled widget on screen. Y gets ENTRY, Y gets disabled. | first enabled widget Z in frame FY is focused, without ENTRY sent | enabled widget X |
waitfor_request_valid3.p | enabled widget X | Y gets disabled, no other enabled widgets on screen. | focus is undefined | enabled widget X |
waitfor_request_valid3c.p | enabled widget X | Y gets disabled, no other enabled widgets in FY. | use ST6 | enabled widget X |
w_valid_hidden/*A[1|2]?_[a|b]a*.p |
enabled and hidden widget X | - | send entry to next widget in X frame | same widget X |
w_valid_hidden/*A[1|2]?_[a|b]b1.p w_valid_hidden/*A[1|2]?_[a|b]b2.p |
enabled widget X in hidden frame | - | use ST6; focus is still X before W entry | same widget X |
w_valid_hidden/*A[1|2]?_[a|b]c[a|b]*.p w_valid_hidden/*A[1|2]?_[a|b]cc1.p w_valid_hidden/*A[1|2]?_[a|b]cc2.p |
enabled widget X | hides widget X or parent frame | use ST6; focus is still X before W entry | same widget X |
wait-for_restore_focus3.p | undefined | - | first enabled widget X | last focused widget * |
wait-for_restore_focus3e.p | undefined | X:NO-APPLY there are enabled widgets |
first enabled widget X is attempted; second enabled widget Y gets focus |
last focused widget * |
update_focus_undefined0b.p update_focus_undefined2b.p update_focus_undefined4b.p | undefined | Y:NO-APPLY there are other enabled widgets |
use ST5. | undefined |
waitfor_request_undefined0.p waitfor_request_undefined3.p waitfor_request_undefined3b.p waitfor_request_undefined3c.p | undefined | Y receives ENTRY and gets disabled | focus is undefined, regardless if there are other enabled widgets or not. | undefined |
wait-for_restore_focus3t.p wait-for_restore_focus3tf.p |
undefined |
all enabled widgets return
NO-APPLY
there are no other enabled
widgets
|
use ST5; immediate exit | undefined |
wait-for_restore_focus3m.p | undefined |
-
there are only disabled widgets |
immediate exit | undefined |
wait-for_restore_focus3s.p | undefined |
-
there are no other widgets |
immediate exit | undefined |
update_focus_undefined0.p update_focus_undefined1.p update_focus_undefined2.p update_focus_undefined3b.p | undefined | Y gets ENTRY and disabled | use ST4, starting from Y. | undefined |
update_focus_undefined3.p update_focus_undefined3c.p | undefined | Y gets ENTRY, all widgets get disabled | if no other enabled widget on screen, focus is unknown. Else, use ST4, starting from Y. | undefined |
update_focus_undefined4.p | undefined | Y:NO-APPLY there are other enabled widgets in frame FY; all enabled widgets in frame FY reject ENTRY; |
use ST5, from Y; immediate exit | undefined |
wait-for_restore_focus4.p wait-for_restore_focus4f.p wait-for_restore_focus4ff.p |
disabled widget X | - | use ST2 | same widget X, which remains disabled, unless enabled by a
trigger |
wait-for_restore_focus4e.p wait-for_restore_focus4mf.p wait-for_restore_focus4ef.p update_focus_invalid0b.p update_focus_invalid2b.p update_focus_invalid4b.p |
disabled widget X | Y:NO-APPLY there are enabled widgets |
for UPDATE operation, next enabled widget in frame FY; else, use ST2 |
same widget X, which remains disabled, unless enabled by a trigger |
wait-for_restore_focus4m.p | disabled widget X |
-
there are only disabled widgets |
undefined | same widget X, which remains disabled, unless enabled by a trigger |
wait-for_restore_focus4s.p | disabled widget X |
-
there are no other widgets |
undefined | same widget X, which remains disabled, unless enabled by a trigger |
update_focus_invalid0.p update_focus_invalid1.p update_focus_invalid2.p update_focus_invalid3b.p | disabled widget X | Y gets ENTRY, Y is disabled | use ST4, from Y; | disabled widget X |
update_focus_invalid3.p update_focus_invalid3c.p | disabled widget X | Y gets entry, all widgets get disabled | if no other enabled widget on screen, focus is unknown. Else, use ST4, from Y. | disabled widget X |
update_focus_invalid4.p | disabled widget X | Y:NO-APPLY there are other enabled widgets in frame FY; all enabled widgets in frame FY reject ENTRY; |
use ST5; immediate exit | disabled widget X |
WAIT-FOR frame events FOCUS Y | ||||
wait-for_restore_focus2.p | enabled widget X | - | Y was enabled - focus set on Y | same widget X (can get disabled by 'a trigger on 'x') |
wait-for_restore_focus2d.p wait-for_restore_focus2df.p |
enabled widget X | - there are other enabled widgets |
Y was disabled - focus set on X - no ENTRY event sent |
same widget X (can get disabled by a trigger on 'x') |
wait-for_restore_focus2g.p | enabled widget X | - there are no other enabled widgets but X |
Y was disabled - focus set on X - no ENTRY event sent |
same widget X (can get disabled by a trigger on 'x') |
wait-for_restore_focus2e.p | enabled widget X | Y:NO-APPLY there are enabled widgets |
Y is attempted; next enabled widget Z receives ENTRY event and gets focus |
same widget X (can get disabled by a trigger on 'x') |
wait-for_restore_focus2t.p wait-for_restore_focus2tf.p |
enabled widget X |
all enabled widgets return
NO-APPLY
there are no other enabled
widgets
|
Y is attempted; next enabled widgets in the tab order are
attempted; search does not wrap nor does it extend to other frames; ;
immediate exit |
same widget X |
wait-for_restore_focus2f.p wait-for_restore_focus2ff.p |
enabled widget X | Y:NO-APPLY there are no other enabled widget but X |
Y is attempted; widget X receives LEAVE event; immediate exit |
same widget X |
wait-for_restore_focus2m.p (same as 2g) |
enabled widget X |
X:NO-APPLY
there are only disabled widgets |
focus set on X - no ENTRY event sent | same widget X (can get disabled by a trigger on 'x') |
waitfor_focus_request_invalid0.p waitfor_focus_request_invalid3b.p |
enabled widget X | Y gets ENTRY, Y is disabled. Y = X | use ST2 | same widget X |
waitfor_focus_request_invalid0B.p |
enabled widget X | Y gets ENTRY, Y is disabled. Y != X | focus is set on X, without ENTRY sent | same widget X |
waitfor_focus_request_invalid3c.p waitfor_focus_request_invalid3cB.p |
enabled widget X | Y gets ENTRY, all widgets in FY get disabled, X gets disabled | use ST6 | same widget X |
waitfor_focus_request_invalid3.p |
enabled widget X | Y gets ENTRY, all widgets get disabled | focus is undefined | same widget X |
wf_valid_A1/*A1?_[a|b]a*.p wf_valid_A2/*A2?_[a|b]a*.p wf_valid_A3/*A3?_[a|b]a*.p wf_valid_A4/*A4?_[a|b]a*.p wf_valid_A5/*A5?_[a|b]a*.p |
enabled widget X | Y is disabled before ENTRY | no ENTRY is sent to Y. X receives focus without ENTRY | same widget X |
wf_valid_A1/*A1?_[a|b]b[a|c]*.p wf_valid_A4/*A4?_[a|b]b[a|c]*.p wf_valid_A1/*A1?_[a|b]bb*.p wf_valid_A4/*A4?_[a|b]bb*.p |
enabled widget X | ENTRY disables Y | X and Y in same frame. if X is still enabled, X is focused without ENTRY. else, use ST6. | same widget X |
wf_valid_A2/*A2?_[a|b][a|c]*.p wf_valid_A3/*A3?_[a|b][a|c]*.p wf_valid_A5/*A5?_[a|b][a|c]*.p |
enabled widget X | ENTRY disables Y | X and Y in different frames. X is still enabled, focus is set to undefined. | same widget X |
wf_valid_A2/*A2?_[a|b]bb*.p wf_valid_A3/*A3?_[a|b]bb*.p wf_valid_A5/*A5?_[a|b]bb*.p |
enabled widget X | ENTRY disables Y | X and Y in different frames. X is disabled, use ST6. | same widget X |
wf_valid_A1/*A1a_c[a|b][a|b].p wf_valid_A2/*A2a_c[a|b][a|b]*.p wf_valid_A3/*A3a_c[a|b][a|b]*.p wf_valid_A4/*A4a_c[a|b][a|b]*.p wf_valid_A5/*A5a_c[a|b][a|b]*.p |
enabled widget X | ENTRY for Y returns NO-APPLY | use ST5. | same widget X |
wf_valid_A1/*A1a_c[a|b]c*.p wf_valid_A4/*A4a_c[a|b]c*.p |
enabled widget X | all widgets return NO-APPLY | X and Y in same frame. if X is not reached, wait-for ends. if X is reached, it ignores no-apply. | same widget X |
wf_valid_A2/*A2a_c[a|b]c*.p wf_valid_A3/*A3a_c[a|b]c*.p wf_valid_A5/*A5a_c[a|b]c*.p |
enabled widget X | all widgets return NO-APPLY | X and Y in different frames. X is focused without ENTRY. | same widget X |
wait-for_restore_focus5.p | undefined | - | Y was enabled - focus set on Y If Y is not the first enabled widget X, X gets ENTRY event before Y without LEAVE event. |
last focused widget * |
wait-for_restore_focus5d.p wait-for_restore_focus5t.p |
undefined | - | Y was disabled - use ST6 | last focused widget * |
wait-for_restore_focus5g.p | undefined |
-
there are only disabled widgets
|
Y was disabled - focus is undefined | last focused widget * |
wait-for_restore_focus5e.p | undefined |
Y:NO-APPLY
there are enabled widgets
|
If Y is not the first enabled widget X in the first displayed
frame, X gets ENTRY event. Then Y gets ENTRY and the next enabled widget X finally gets ENTRY and remains focused |
last focused widget * |
wait-for_restore_focus5ee.p | undefined |
all enabled widgets return
NO-APPLY
there are no other enabled
widgets
|
If Y is not the first enabled widget X in the first displayed
frame, X gets ENTRY event. Then Y gets ENTRY and all next enabled widgets in the tab order (no wrap). X receives LEAVE event; immediate exit |
X |
wait-for_restore_focus5m.p | undefined | Y:NO-APPLY there are only disabled widgets |
Y - ignores NO-APPLY
|
last focused widget * |
wait-for_restore_focus5s.p | undefined | Y:NO-APPLY there are no other widgets |
Y - ignores NO-APPLY | Y |
waitfor_focus_request_undefined0.p waitfor_focus_request_undefined3b.p | undefined | Y is the first enabled widget on screen; Y gets disabled | use ST4, starting from Y. | last focused widget |
waitfor_focus_request_undefined3.p waitfor_focus_request_undefined3c.p | undefined | Y is the first enabled widget on screen; Y gets disabled; no other enabled widgets | focus is undefined | undefined |
waitfor_focus_request_undefined0B.p waitfor_focus_request_undefined3cB.p | undefined | Y is NOT the first enabled widget on screen; Y gets disabled | focus is undefined, regardless if there are other enabled widgets on screen. | undefined |
wf_undefined_A1/*A1?_[a|b]a.p wf_undefined_A2/*A2?_[a|b]a.p | undefined | - | focus is set on first enabled widget on screen W if Y is disabled before ENTRY or Y = W. ENTRY is not sent to W | last focused widget |
wf_undefined_A1/*A1?_[a|b][a|b]*.p | undefined | Y gets disabled | Y frame is the first enabled frame on screen; use ST6 | last focused widget |
wf_undefined_A2/*A2?_[a|b]c[a|c]*.p | undefined | Y gets disabled | Y frame is not the first enabled frame on screen; W is still enabled; focus is undefined | last focused widget |
wf_undefined_A2/*A2?_[a|b]cb*.p | undefined | Y gets disabled | Y frame is not the first enabled frame on screen; W is disabled or hidden; use ST6 | last focused widget |
wait-for_restore_focus6.p | disabled widget X | - | Y was enabled - focus set on Y |
same widget X |
wait-for_restore_focus6d.p wait-for_restore_focus6f.p wait-for_restore_focus6f2.p wait-for_restore_focus6f3.p wait-for_restore_focus6f4.p wait-for_restore_focus6f5.p waitfor_focus_request0.p waitfor_focus_request3.p waitfor_focus_request3b.p waitfor_focus_request3c.p |
disabled widget X | - | Y was disabled - use ST4 starting from Y |
same widget X (can get enabled by a trigger on 'x') |
wait-for_restore_focus6g.p | disabled widget X |
-
there are only disabled widgets
|
Y was disabled - focus is undefined |
same widget X |
wait-for_restore_focus6e.p | disabled widget X |
Y:NO-APPLY
there are enabled widgets
|
Y is attempted; next enabled widget in tab order gets focus | same widget X |
wait-for_restore_focus6e2.p | disabled widget X |
Y:NO-APPLY
next enabled
widgets NO-APPLY
|
Y is attempted; next enabled widget in tab order are attempted; immediate exit | same widget X |
wait-for_restore_focus6m.p | disabled widget X | - there are only disabled widgets |
undefined | same widget X |
wait-for_restore_focus6s.p | disabled widget X |
-
there are no other widgets
|
undefined | same widget X |
waitfor_focus_request0B.p waitfor_focus_request03cB.p | disabled widget X | Y receives ENTRY; Y gets disabled | use ST4 starting from Y | same widget X |
wf_invalid_A1/*A1?_[a|b]a*.p wf_invalid_A2/*A2?_[a|b]a*.p wf_invalid_A3/*A3?_[a|b]a*.p wf_invalid_A4/*A4?_[a|b]a*.p wf_invalid_A5/*A5?_[a|b]a*.p | disabled widget X | - | use ST6. | same widget X |
wf_invalid_A1/*A1?_[a|b]b*.p wf_invalid_A4/*A4?_[a|b]b*.p | disabled widget X | Y gets disabled | Y and X in same frame. use ST6. | same widget X |
wf_invalid_A2/*A2?_[a|b]b*.p wf_invalid_A3/*A3?_[a|b]b*.p wf_invalid_A5/*A5?_[a|b]b*.p | disabled widget X | Y gets disabled | Y and X in different frames. focus is undefined. | same widget X |
WAIT-FOR window events without FOCUS
clause |
||||
Testcase | Focus before WAIT-FOR | ENTRY trigger | Initial focus in WAIT-FOR | Focus after WAIT-FOR |
wait-for_restore_focus7.p | enabled widget X | - | same widget X | same widget X (can get disabled by 'a trigger on 'x') |
wait-for_restore_focus7e.p wait-for_restore_focus7ef.p |
enabled widget X |
X:NO-APPLY
there are enabled widgets
|
same widget X - ignores NO-APPLY |
same widget X (can get disabled by 'a trigger on 'x') |
wait-for_restore_focus7m.p | enabled widget X |
X:NO-APPLY
there are only disabled widgets
|
same widget X - ignores NO-APPLY |
same widget X |
wait-for_restore_focus7s.p | enabled widget X |
X:NO-APPLY
there are no other widgets
|
same widget X - ignores NO-APPLY |
same widget X |
wait-for_restore_focus8.p | undefined | - | first enabled widget X | last focused widget * |
wait-for_restore_focus8e.p | undefined | X:NO-APPLY there are enabled widgets |
first enabled widget X is attempted; second enabled widget Y gets focus |
last focused widget * |
wait-for_restore_focus8t.p wait-for_restore_focus8tf.p |
undefined | all enabled widgets return
NO-APPLY there are no other enabled widgets |
all enabled widgets are attempted in the tab order; search does not extend to the next frame; focus undefined | undefined |
wait-for_restore_focus8m.p | undefined | - there are only disabled widgets |
undefined | undefined |
wait-for_restore_focus8s.p | undefined | - there are no other widgets |
undefined | undefined |
wait-for_restore_focus9.p wait-for_restore_focus9f.p wait-for_restore_focus9ff.p |
disabled widget X | - | next enabled widget Y in the tab order of the frame containing X; the search does wrap; continues on the first displayed frame - no ENTRY event sent | same widget X, which remains disabled, unless enabled by a trigger |
wait-for_restore_focus9e.p wait-for_restore_focus9mf.p wait-for_restore_focus9ef.p |
disabled widget X | Y:NO-APPLY there are enabled widgets |
next enabled widget Y in the tab order of the frame containing X; the search does wrap; continues on the first displayed frame; continues through all displayed frames - no ENTRY event sent | same widget X, which remains disabled, unless enabled by a trigger |
wait-for_restore_focus9m.p | disabled widget X |
-
there are only disabled widgets
|
undefined | same widget X |
wait-for_restore_focus9s.p | disabled widget X |
-
there are no other widgets
|
undefined | same widget X |
WAIT-FOR window events FOCUS Y | ||||
wait-for_restore_focus10.p | enabled widget X | - | Y was enabled - focus set on Y | same widget X (can get disabled by 'a trigger on 'x') |
wait-for_restore_focus10d.p | enabled widget X | - | Y was disabled - focus set on next enabled widget Z - no ENTRY event sent |
same widget X (can get disabled by a trigger on 'x') |
wait-for_restore_focus10g.p | enabled widget X |
-
there are no other enabled
widgets but X
|
Y was disabled - focus set on X - no ENTRY event sent |
same widget X (can get disabled by a trigger on 'x') |
wait-for_restore_focus10e.p | enabled widget X |
Y:NO-APPLY
there are enabled widgets
|
Y is attempted; next enabled widget Z receives ENTRY event and gets focus |
same widget X (can get disabled by a trigger on 'x') |
wait-for_restore_focus10f.p wait-for_restore_focus10ff.p |
enabled widget X |
Y:NO-APPLY
there are no other enabled
widget but X
|
Y is attempted; focus set on X - no ENTRY event sent |
same widget X (can get disabled by a trigger on 'x') |
wait-for_restore_focus10m.p (same as 10g) |
enabled widget X |
X:NO-APPLY
there are only disabled widgets
|
focus set on X - no ENTRY event sent | same widget X (can get disabled by a trigger on 'x') |
wait-for_restore_focus11.p | undefined | - | Y was enabled - focus set on Y If Y is not the first enabled widget X, X gets ENTRY event before Y without LEAVE event. |
last focused widget * |
wait-for_restore_focus11d.p | undefined | - | Y was disabled - focus set on first enabled widget Z among all displayed frames | last focused widget * |
wait-for_restore_focus11g.p | undefined |
-
there are only disabled widgets
|
Y was disabled - focus is undefined | last focused widget * |
wait-for_restore_focus11e.p | undefined |
Y:NO-APPLY
there are enabled widgets
|
If Y is not the first enabled widget X, X gets ENTRY event
before Y without LEAVE event. Then Y gets ENTRY and the next enabled widget X finally gets ENTRY and remains focused |
last focused widget * |
wait-for_restore_focus11ee.p | undefined |
Y:NO-APPLY
next enabled
widgets NO-APPLY
|
last focused widget * | |
wait-for_restore_focus11ea.p wait-for_restore_focus11eb.p wait-for_restore_focus11ec.p |
undefined |
Y:NO-APPLY
next enabled
widgets NO-APPLY
|
last focused widget * | |
wait-for_restore_focus11m.p | undefined | Y:NO-APPLY there are only disabled widgets |
Y - ignores NO-APPLY | last focused widget * |
wait-for_restore_focus11s.p | undefined | Y:NO-APPLY there are no other widgets |
Y - ignores NO-APPLY | Y |
wait-for_restore_focus12.p | disabled widget X | - | Y was enabled - focus set on Y | same widget X |
wait-for_restore_focus12d.p wait-for_restore_focus12f.p wait-for_restore_focus12f2.p wait-for_restore_focus12f3.p wait-for_restore_focus12f4.p wait-for_restore_focus12f5.p |
disabled widget X | - | Y was disabled - focus set on next enabled widget Z - no ENTRY event sent |
same widget X (can get enabled by a trigger on 'x') |
wait-for_restore_focus12g.p | disabled widget X |
-
there are only disabled widgets
|
Y was disabled - focus is undefined | same widget X |
wait-for_restore_focus12e.p | disabled widget X | Y:NO-APPLY there are enabled widgets |
Y is attempted; next enabled widget in tab order gets focus | same widget X |
wait-for_restore_focus12e2.p | disabled widget X |
Y:NO-APPLY
next enabled
widgets NO-APPLY
|
Y is attempted; next enabled widget in tab order are attempted; Y gets focus - ignores NO-APPLY | same widget X |
wait-for_restore_focus12m.p | disabled widget X | - there are only disabled widgets |
undefined | same widget X |
wait-for_restore_focus12s.p | disabled widget X |
-
there are no other widgets
|
undefined | same widget X (can get enabled by a trigger on 'x') |
X - current focus, triggers are applied to this widgetFrame ENTRY/LEAVE rules
X2 - first enabled widget in FX after X, in tab-order
Y - first widget in UPDATE or the explicit widget in WAIT-FOR ... FOCUS Y
FX - parent frame for X, X2, Y
FZ - the next frame on screen which has an enabled widget Z
T - trigger on a key (i.e. not a ENTRY/LEAVE trigger)
The set of testcases apply_entry*.p shows some other details of ENTRY behavior; assume X receives ENTRY via APPLY "ENTRY" and there is an ON ENTRY trigger for it:
The MESSAGE ... UPDATE statement adjusts focus after it has been executed this way (see msg_entry*.p)
The set of testcases focus_apply*.p uncovers some details of the APPLY statement regarding the focus management:
Before reading the focus adjustment prior to trigger invocation rules, the following info must be noted:
Frame hiding in Progress 4GL can be split into three large classes depending on the basic cause:
Explicit application requests are triggered by HIDE or HIDE ALL statements in 4GL code.
Implicit frame hiding triggered by frame placement takes place in two situations:
The general rule for marking frame for hiding is that frames are marked for hiding when block to which frame is scoped or some outer block is retried or iterated. When iterated or retried block to which frame is scoped, frame is marked for hiding immediately ("immediately" here means that frame will be marked during next client call). Iteration of outer block means exit from block to which frame is scoped. During block exit frames registered at current scope are moved to outer scope for further processing. In outer scope frames moved from inner scope are marked for hiding during next iteration/retry processing. Note that frames moved from inner scope are marked only once. Note that for some types of blocks abnormal exit from the block caused by ENDKEY or ERROR condition causes also resetting of marking for hiding.
General rule for triggering of the frame hiding is that it happens on first explicit or implicit VIEW call for the frame which belongs to current scope on second or subsequent iterations of this or outer looping block. But this rule has several exceptions so actual rules will be simpler to describe in terms of implementation. The general rule in this case can be described so:
As mentioned above general rule has exceptions:
Existing design was initially based on CHARVA library and inherited event queue/listener model (which, in turn, resembles AWT/Swing event model). Event based approach is not directly applicable to 4GL event model which is synchronous while CHARVA/AWT/Swing event model is asynchronous. In order to overcome these differences P2J uses mixed approach - events are still placed in event queue, but processing of these events is performed in synchronous way. Also, in order to implement 4GL-specific behavior stacked event queues were introduced. In each moment of time only one queue is active, but runtime may create new empty event queue, perform some tasks, process messages and then drop it and restore active event queue. In regard to event which was processed at the moment of switching queue all this processing is performed as single atomic operation similar to regular function call. This feature closely resembles 4GL behavior when some event may invoke trigger which in turn may perform some event processing (start event processing loop, invoke APPLY, etc.), but from point of view of event which caused trigger invocation all these operations are performed synchronously.
Nevertheless, despite its flexibility resulting UI package design is complex and interaction of different components of the package is far from obvious despite the fact that wast majority of required functionality does not require such a complex design. Also, this complexity complicates support, maintenance and further development of the UI package.
During discussion about possible refactoring of the existing code and approaches which may simplify design, following issues were found: