Project

General

Profile

Feature #2252

implement GUI client support

Added by Greg Shah about 10 years ago. Updated about 7 years ago.

Status:
Closed
Priority:
Normal
Assignee:
-
Start date:
03/24/2014
Due date:
% Done:

100%

Estimated time:
(Total: 660.00 h)
billable:
No
vendor_id:
GCD

how_to_calculate_the_character_width_across_fonts_and_points_blog_by_stephen_20080219.pdf - Archived version of the blog post that was listed in note 11. (41.4 KB) Greg Shah, 03/27/2014 11:00 AM

window_attributes.txt Magnifier (7.37 KB) Marius Gligor, 05/08/2014 11:18 AM

window-1.zip (1.14 KB) Marius Gligor, 05/09/2014 11:26 AM

mag_upd20140513a.zip (255 KB) Marius Gligor, 05/13/2014 10:35 AM

mag_upd20140514a.zip (262 KB) Marius Gligor, 05/14/2014 09:36 AM

mag_upd20140515a.zip (325 KB) Marius Gligor, 05/15/2014 11:08 AM

mag_upd20140516a.zip (331 KB) Marius Gligor, 05/16/2014 10:04 AM

mag_upd20140516b.zip (331 KB) Marius Gligor, 05/16/2014 02:23 PM

window.png (13.5 KB) Marius Gligor, 05/21/2014 11:55 AM

mag_upd20140521a.zip (344 KB) Marius Gligor, 05/21/2014 11:55 AM

mag_upd20140522a.zip (350 KB) Marius Gligor, 05/22/2014 03:55 AM

mag_upd20140522b.zip (351 KB) Marius Gligor, 05/22/2014 09:59 AM

mag_upd20140523a.zip (352 KB) Marius Gligor, 05/23/2014 07:34 AM

window_float2.png (338 KB) Marius Gligor, 05/23/2014 07:34 AM

mag_upd20140602a.zip (348 KB) Marius Gligor, 06/02/2014 03:20 AM

font stats - v2.ods (57.2 KB) Constantin Asofiei, 06/09/2014 12:01 PM

ges_upd20140627a.zip (687 KB) Greg Shah, 06/27/2014 03:03 PM

ges_upd20140627b.zip (5.47 KB) Greg Shah, 06/27/2014 03:03 PM

ca_upd20140729a.zip (8.48 KB) Greg Shah, 07/29/2014 11:13 AM

ca_upd20140731a.zip (8.64 KB) Constantin Asofiei, 07/31/2014 09:27 AM

thin_client_err.log Magnifier (9.99 KB) Vadim Gindin, 08/05/2014 03:13 PM

vig_upd20140806a.zip (54 KB) Vadim Gindin, 08/06/2014 05:28 AM

ca_upd20140806d.zip (731 KB) Constantin Asofiei, 08/06/2014 04:19 PM

ca_upd20140807b.zip (731 KB) Constantin Asofiei, 08/07/2014 02:21 PM

ca_upd20140808b.zip (741 KB) Constantin Asofiei, 08/08/2014 06:32 AM

ca_upd20140808c.zip (733 KB) Constantin Asofiei, 08/08/2014 03:56 PM

vig_upd20140810a.zip (256 KB) Vadim Gindin, 08/10/2014 12:53 PM

vig_upd20140815a.zip (251 KB) Vadim Gindin, 08/15/2014 01:58 PM

vig_upd20140820a.zip (250 KB) Vadim Gindin, 08/20/2014 02:27 AM

vig_upd20140821a.zip (260 KB) Vadim Gindin, 08/21/2014 04:35 AM

vig_upd20140820b.zip (250 KB) Vadim Gindin, 08/21/2014 01:16 PM

ca_upd20140826a.zip (743 KB) Constantin Asofiei, 08/26/2014 05:46 AM

2252.txt Magnifier - error logs (6 KB) Vadim Gindin, 08/28/2014 04:17 PM

vig_upd20140827a.zip (216 KB) Vadim Gindin, 08/28/2014 04:17 PM

hc_upd20140831a.zip (720 KB) Hynek Cihlar, 08/31/2014 06:06 PM

vig_upd20140901a.zip (204 KB) Vadim Gindin, 09/01/2014 02:10 PM

0901.log Magnifier (6.05 KB) Vadim Gindin, 09/01/2014 02:10 PM

hc_upd20140907a.zip (733 KB) Hynek Cihlar, 09/07/2014 04:31 PM

vig_upd20140905a.zip (205 KB) Vadim Gindin, 09/10/2014 05:01 PM

client_vig_26776.log Magnifier (2.79 KB) Vadim Gindin, 09/10/2014 05:01 PM

hc_upd20140911a.zip (740 KB) Hynek Cihlar, 09/12/2014 12:45 PM

vig_upd20140912a.zip (214 KB) Vadim Gindin, 09/12/2014 04:34 PM

vig_upd20140919a.zip (214 KB) Vadim Gindin, 09/18/2014 02:34 PM

vig_upd20140919b.zip (225 KB) Vadim Gindin, 09/18/2014 04:50 PM

vig_upd20140919c.zip (229 KB) Vadim Gindin, 09/19/2014 05:32 AM

vig_upd20140920a.zip (230 KB) Vadim Gindin, 09/19/2014 04:18 PM

vig_upd20140924a.zip (236 KB) Vadim Gindin, 09/24/2014 04:43 AM

hc_upd20140924a.zip (745 KB) Hynek Cihlar, 09/24/2014 10:19 AM

ca_upd20140926c.zip (838 KB) Constantin Asofiei, 09/26/2014 05:25 AM

ca_upd20140926g.zip (190 KB) Constantin Asofiei, 09/26/2014 12:51 PM

server_gso_370.log Magnifier - syman log, containing quit error (17.9 KB) Vadim Gindin, 09/29/2014 01:29 PM

vig_upd20141001a.zip (237 KB) Vadim Gindin, 10/01/2014 12:43 PM

ca_upd20141001d.zip (536 KB) Constantin Asofiei, 10/01/2014 01:20 PM

ca_upd20141002h.zip (945 KB) Constantin Asofiei, 10/02/2014 12:11 PM

vig_upd20141002a.zip - merged status* and message* methods update (256 KB) Vadim Gindin, 10/02/2014 03:18 PM

vig_upd20141002b.zip - combined history entries (256 KB) Vadim Gindin, 10/02/2014 03:52 PM

hc_upd20141004a.zip (64.1 KB) Hynek Cihlar, 10/04/2014 05:32 PM

hc_upd20141005a.zip (64.9 KB) Hynek Cihlar, 10/05/2014 04:49 PM

vig_upd20141006a.zip - multi-window support of DISPLAY/VIEW/HIDE statements (342 KB) Vadim Gindin, 10/05/2014 05:31 PM

ca_upd20141003a.zip (946 KB) Constantin Asofiei, 10/06/2014 09:40 AM

vig_upd20141007a.zip (347 KB) Vadim Gindin, 10/07/2014 10:49 AM

oe-2.png (34.9 KB) Marius Gligor, 10/08/2014 12:37 PM

server_gso_0_1008.log Magnifier - regression testing log of vig_upd20141007a.zip (31.9 KB) Vadim Gindin, 10/08/2014 01:01 PM

vig_upd20141008a.zip (347 KB) Vadim Gindin, 10/08/2014 01:52 PM

mag_upd20141009a.zip (30.7 KB) Marius Gligor, 10/09/2014 09:11 AM

vig_upd20141009a.zip - corrections of messageBox methods and other remarks of previous update (347 KB) Vadim Gindin, 10/10/2014 06:32 AM

1009logs.zip - logs of regression testing (285 KB) Vadim Gindin, 10/10/2014 06:32 AM

mag_upd20141010a.zip (30.8 KB) Marius Gligor, 10/10/2014 12:02 PM

mag_upd20141013a.zip (49.8 KB) Marius Gligor, 10/13/2014 10:14 AM

vig_upd20141013a.zip (347 KB) Vadim Gindin, 10/14/2014 06:16 AM

mag_upd20141014a.zip (114 KB) Marius Gligor, 10/14/2014 09:45 AM

mag_upd20141014b.zip (115 KB) Marius Gligor, 10/14/2014 11:10 AM

mag_upd20141016a.zip (142 KB) Marius Gligor, 10/16/2014 11:17 AM

vig_upd20141017a.zip (629 KB) Vadim Gindin, 10/16/2014 08:02 PM

frame-1.png (6.24 KB) Marius Gligor, 10/17/2014 04:05 AM

frame-2.png (5.26 KB) Marius Gligor, 10/17/2014 04:05 AM

frame-3.png (7.38 KB) Marius Gligor, 10/17/2014 04:05 AM

frame-4.png (7.24 KB) Marius Gligor, 10/17/2014 04:05 AM

frame-5.png (5.55 KB) Marius Gligor, 10/17/2014 04:05 AM

mag_upd20141017a.zip (188 KB) Marius Gligor, 10/17/2014 10:07 AM

vig_upd20141017b.zip (629 KB) Vadim Gindin, 10/17/2014 02:15 PM

vig_upd20141020a.zip (671 KB) Vadim Gindin, 10/20/2014 12:04 PM

ca_upd20141021b.zip (302 KB) Constantin Asofiei, 10/21/2014 09:49 AM

mag_upd20141021a.zip (216 KB) Marius Gligor, 10/21/2014 11:27 AM

frame-1.png (6.15 KB) Marius Gligor, 10/21/2014 11:27 AM

frame-2.png (5.83 KB) Marius Gligor, 10/21/2014 11:27 AM

frame-3.png (5.99 KB) Marius Gligor, 10/21/2014 11:27 AM

ca_upd20141021c.zip (301 KB) Constantin Asofiei, 10/21/2014 04:50 PM

hc_upd20141021b.zip (318 KB) Hynek Cihlar, 10/21/2014 06:44 PM

vig_upd20141022a.zip (675 KB) Vadim Gindin, 10/22/2014 12:58 PM

ca_upd20141023a.zip (306 KB) Constantin Asofiei, 10/23/2014 07:28 AM

mouseevts.p Magnifier (5.07 KB) Constantin Asofiei, 10/23/2014 07:28 AM

mag_upd20141023a.zip (227 KB) Marius Gligor, 10/23/2014 09:11 AM

vig_upd20141024a.zip (687 KB) Vadim Gindin, 10/23/2014 02:22 PM

hc_upd20141023b.zip (332 KB) Hynek Cihlar, 10/23/2014 05:56 PM

mag_upd20141024a.zip (234 KB) Marius Gligor, 10/24/2014 08:04 AM

hc_upd20141024a.zip (330 KB) Hynek Cihlar, 10/24/2014 11:06 AM

vig_upd20141025a.zip (691 KB) Vadim Gindin, 10/24/2014 06:25 PM

vig_upd20141027a.zip (691 KB) Vadim Gindin, 10/27/2014 08:25 AM

ca_upd20141027a.zip (694 KB) Constantin Asofiei, 10/27/2014 09:50 AM

mag_upd20141027a.zip (226 KB) Marius Gligor, 10/27/2014 02:13 PM

mag_upd20141028a.zip (226 KB) Marius Gligor, 10/28/2014 10:45 AM

ca_upd20141029a.zip (694 KB) Constantin Asofiei, 10/29/2014 10:08 AM

mag_upd20141029a.zip (244 KB) Marius Gligor, 10/29/2014 12:33 PM

mag_upd20141029b.zip (243 KB) Marius Gligor, 10/29/2014 02:19 PM

mag_upd20141030a.zip (245 KB) Marius Gligor, 10/30/2014 03:47 AM

mag_upd20141030b.zip (245 KB) Marius Gligor, 10/30/2014 07:25 AM

mag_upd20141031a.zip (247 KB) Marius Gligor, 10/31/2014 08:00 AM

mag_upd20141031b.zip (245 KB) Marius Gligor, 10/31/2014 09:39 AM

mag_upd20141028a.zip (2.04 KB) Greg Shah, 10/31/2014 10:16 AM

hc_upd20141104a.zip (617 KB) Hynek Cihlar, 11/04/2014 04:58 PM

evl_upd20141104a.zip - Conversion support for rectangle attributes (59.4 KB) Eugenie Lyzenko, 11/04/2014 09:38 PM

ca_upd20141105a.zip (291 KB) Constantin Asofiei, 11/05/2014 09:16 AM

testcases_evl_20141105a.zip - Retcangle tests as of 11/05 (2.4 KB) Eugenie Lyzenko, 11/05/2014 09:28 AM

ca_upd20141105d.zip (288 KB) Constantin Asofiei, 11/05/2014 02:59 PM

ca_upd20141106c.zip (310 KB) Constantin Asofiei, 11/06/2014 08:01 AM

evl_upd20141106a.zip - Conversion support (115 KB) Eugenie Lyzenko, 11/06/2014 11:02 AM

testcases_evl_20141106a.zip - The testcases for rectangle as of 2014/11/06 (2.78 KB) Eugenie Lyzenko, 11/06/2014 11:02 AM

evl_upd20141106b.zip - Notes resolution for rectangle widget (123 KB) Eugenie Lyzenko, 11/06/2014 03:06 PM

evl_upd20141106c.zip - Fix for EDGE_CHARS storage (117 KB) Eugenie Lyzenko, 11/06/2014 04:06 PM

evl_upd20141106d.zip - Rectangle widget conversion support to test (117 KB) Eugenie Lyzenko, 11/06/2014 04:18 PM

hc_upd20141106b.zip (635 KB) Hynek Cihlar, 11/06/2014 04:31 PM

hc_upd20141106c.zip (635 KB) Hynek Cihlar, 11/06/2014 04:55 PM

ca_upd20141107c.zip (309 KB) Constantin Asofiei, 11/07/2014 01:03 PM

evl_upd20141109a.zip - Rectangle changes merged with the recent code base (117 KB) Eugenie Lyzenko, 11/09/2014 07:57 AM

evl_upd20141111a.zip - Code merged with 10651 (118 KB) Eugenie Lyzenko, 11/11/2014 11:36 AM

evl_upd20141111b.zip - Small color fix/additions (124 KB) Eugenie Lyzenko, 11/11/2014 12:30 PM

ca_upd20141113c.zip (490 KB) Constantin Asofiei, 11/13/2014 09:00 AM

evl_upd20141116a.zip - GUI rectangle first step (4.51 KB) Eugenie Lyzenko, 11/16/2014 11:21 AM

evl_upd20141117a.zip - ROUNDED attribute implementation (29.8 KB) Eugenie Lyzenko, 11/17/2014 02:06 PM

rect_test6_1_4gl_gui.jpg - 4GL output (43.7 KB) Eugenie Lyzenko, 11/17/2014 08:53 PM

rect_test6_p2j_gui_char.jpg - P2J character based coords (24.1 KB) Eugenie Lyzenko, 11/17/2014 08:53 PM

rect_test6_p2j_gui_phys.jpg - P2J physical based coords (24.8 KB) Eugenie Lyzenko, 11/17/2014 08:53 PM

evl_upd20141118a.zip - GUI rectangle release candidate (77.3 KB) Eugenie Lyzenko, 11/18/2014 01:59 PM

ca_upd20141118c.zip (9.8 KB) Constantin Asofiei, 11/18/2014 03:01 PM

ca_upd20141119d.zip (499 KB) Constantin Asofiei, 11/19/2014 10:03 AM

evl_upd20141119a.zip - GROUP-BOXfull support (79.2 KB) Eugenie Lyzenko, 11/19/2014 12:14 PM

rect_test3_1_p2j_gui.jpg - Buggy screen fot coord issue (29.5 KB) Eugenie Lyzenko, 11/19/2014 12:14 PM

evl_upd20141119b.zip - No more hardcoded colors (79.3 KB) Eugenie Lyzenko, 11/19/2014 04:34 PM

ca_upd20141120c.zip (499 KB) Constantin Asofiei, 11/20/2014 09:31 AM

evl_upd20141120a.zip - Rectangle merged with 10660 (79.9 KB) Eugenie Lyzenko, 11/20/2014 04:30 PM

ca_upd20141123c.zip (320 KB) Constantin Asofiei, 11/23/2014 02:32 PM

ca_upd20141124c.zip (324 KB) Constantin Asofiei, 11/24/2014 04:11 PM

blogs-msdn-com.pdf - algorithm for default win32 window placement (110 KB) Constantin Asofiei, 11/24/2014 04:25 PM

ca_upd20141125d.zip (238 KB) Constantin Asofiei, 11/25/2014 03:35 PM

ges_upd20141125a.zip (798 KB) Greg Shah, 11/26/2014 08:47 AM

evl_upd20141126a.zip - Preliminary step (69.5 KB) Eugenie Lyzenko, 11/26/2014 12:20 PM

button1_p2j_0_gui.jpg - Buggy GUI drawing (48.1 KB) Eugenie Lyzenko, 11/26/2014 12:20 PM

evl_upd20141126b.zip - Fixed update integrity (70.8 KB) Eugenie Lyzenko, 11/26/2014 01:12 PM

rect_test3_bug_p2j_gui.jpg - Drawing issue (32.4 KB) Eugenie Lyzenko, 11/27/2014 10:12 AM

evl_upd20141127a.zip - Full keyboard support and button states (71.4 KB) Eugenie Lyzenko, 11/27/2014 02:03 PM

ges_upd20141127b.zip (848 KB) Greg Shah, 11/27/2014 02:18 PM

evl_upd20141128a.zip - Mouse support added (79 KB) Eugenie Lyzenko, 11/28/2014 03:21 PM

hc_diff20141129a.diff Magnifier (2.35 KB) Hynek Cihlar, 11/29/2014 10:48 AM

ges_upd20141130a.zip (871 KB) Greg Shah, 11/30/2014 05:55 AM

hc_diff20141130a.diff Magnifier (4.58 KB) Hynek Cihlar, 11/30/2014 06:24 PM

hc_diff20141130b.diff Magnifier (890 Bytes) Hynek Cihlar, 11/30/2014 06:54 PM

ges_upd20141130b.zip (898 KB) Greg Shah, 11/30/2014 08:00 PM

hc_upd20141201b.zip (9.03 KB) Hynek Cihlar, 12/01/2014 06:26 AM

evl_upd20141201a.zip - Tooltip feature implementation (7.77 KB) Eugenie Lyzenko, 12/01/2014 01:41 PM

button2_p2j_0_gui.jpg - P2J tootip screen 0 (38.9 KB) Eugenie Lyzenko, 12/01/2014 01:41 PM

button2_p2j_1_gui.jpg - P2J tootip screen 1 (36.8 KB) Eugenie Lyzenko, 12/01/2014 01:41 PM

ges_upd20141201a.zip (934 KB) Greg Shah, 12/01/2014 07:10 PM

ges_upd20141203a.zip (949 KB) Greg Shah, 12/03/2014 03:30 PM

image-4bpp-ico.jpg - Icon sample usage for 4bpp ico (27.1 KB) Eugenie Lyzenko, 12/03/2014 04:21 PM

ca_upd20141204d.zip (143 KB) Constantin Asofiei, 12/04/2014 05:04 PM

evl_upd20141204a.zip - Runtime icons loading for window widget (29.4 KB) Eugenie Lyzenko, 12/04/2014 08:15 PM

evl_upd20141205a.zip - Window icon complete implementation (456 KB) Eugenie Lyzenko, 12/05/2014 11:01 AM

evl_image_testcases_20141205a.zip - Tests to verify window icon solution (1.95 KB) Eugenie Lyzenko, 12/05/2014 11:01 AM

ca_upd20141205d.zip (159 KB) Constantin Asofiei, 12/05/2014 03:09 PM

evl_upd20141205b.zip - Image processing for window title update fix (456 KB) Eugenie Lyzenko, 12/05/2014 03:13 PM

ca_upd20141205e.zip (108 KB) Constantin Asofiei, 12/05/2014 07:47 PM

evl_upd20141206a.zip - Default colors and toolbar regression fixes (10.5 KB) Eugenie Lyzenko, 12/06/2014 08:30 AM

ca_upd20141206b.zip (52.6 KB) Constantin Asofiei, 12/06/2014 12:51 PM

ges_upd20141206a.zip (950 KB) Greg Shah, 12/06/2014 02:17 PM

hc_upd20141207d.zip (529 KB) Hynek Cihlar, 12/07/2014 03:07 PM

hc_upd20141207e.zip (529 KB) Hynek Cihlar, 12/07/2014 06:07 PM

hc_upd20141207f.zip (529 KB) Hynek Cihlar, 12/07/2014 06:10 PM

hc_upd20141208a.zip (534 KB) Hynek Cihlar, 12/08/2014 07:09 AM

hc_upd20141208b.zip (534 KB) Hynek Cihlar, 12/08/2014 07:59 AM

ca_upd20141208d.zip (188 KB) Constantin Asofiei, 12/08/2014 11:19 AM

evl_upd20141208a.zip - Image widget first steps (304 KB) Eugenie Lyzenko, 12/08/2014 08:37 PM

image4-p2j.jpg - Demo 4 screenshot (63.2 KB) Eugenie Lyzenko, 12/08/2014 08:37 PM

evl_upd20141209a.zip - Merged with Label and FillIn code (304 KB) Eugenie Lyzenko, 12/09/2014 06:49 AM

evl_upd20141212a.zip - New tooltip approach implementation (20.2 KB) Eugenie Lyzenko, 12/12/2014 10:46 AM

evl_upd20141215a.zip - Fix for review notes (304 KB) Eugenie Lyzenko, 12/15/2014 04:14 PM

evl_upd20141215b.zip - Added missing file (305 KB) Eugenie Lyzenko, 12/15/2014 06:41 PM

evl_upd20141217a.zip - SESSION:TOOLTIPS attribute conversion and runtime (280 KB) Eugenie Lyzenko, 12/17/2014 11:57 AM

evl_upd20141218a.zip - Tooltip feature candidate (287 KB) Eugenie Lyzenko, 12/18/2014 03:17 PM

hc_upd20141218c.zip (535 KB) Hynek Cihlar, 12/18/2014 07:17 PM

evl_upd20141218b.zip - Bug fixing for tooltip feature (287 KB) Eugenie Lyzenko, 12/18/2014 08:15 PM

ca_upd20141220b.zip (366 KB) Constantin Asofiei, 12/20/2014 11:29 AM

ca_upd20141221a.zip (367 KB) Constantin Asofiei, 12/21/2014 06:06 AM

hc_upd20141221c.zip (540 KB) Hynek Cihlar, 12/22/2014 11:39 AM

evl_upd20141222a.zip - Notes resolution for tooltip implementation (299 KB) Eugenie Lyzenko, 12/22/2014 09:32 PM

ges_upd20141222a.zip - Apply this 1st. (955 KB) Greg Shah, 12/28/2014 09:46 AM

ecf_upd20141217a.zip - 2nd (63.7 KB) Greg Shah, 12/28/2014 09:46 AM

ecf_upd20141218b.zip - 3rd (14.1 KB) Greg Shah, 12/28/2014 09:46 AM

ecf_upd20141222a.zip - 4th (30.6 KB) Greg Shah, 12/28/2014 09:46 AM

evl_upd20150103a.zip - Tooltip feature with recent code base merge (301 KB) Eugenie Lyzenko, 01/03/2015 06:50 AM

hc_upd20150103a.zip (6.68 KB) Hynek Cihlar, 01/05/2015 11:04 AM

ca_upd20150105c.zip (270 KB) Constantin Asofiei, 01/05/2015 04:00 PM

evl_upd20150106a.zip - Using images to draw the button (29.9 KB) Eugenie Lyzenko, 01/06/2015 05:42 PM

evl_upd20150106b.zip - Notes resolution for button image loading (29.9 KB) Eugenie Lyzenko, 01/06/2015 09:14 PM

evl_upd20150106c.zip - LOAD-SMALL-ICON restore (29.9 KB) Eugenie Lyzenko, 01/06/2015 09:50 PM

evl_upd20150107a.zip - Fix for conversion regression. (29.9 KB) Eugenie Lyzenko, 01/07/2015 08:57 AM

ca_upd20150108a.zip (279 KB) Constantin Asofiei, 01/08/2015 01:57 AM

hc_upd20150112a.zip (264 KB) Hynek Cihlar, 01/12/2015 06:30 PM

ca_upd20150114b.zip (221 KB) Constantin Asofiei, 01/14/2015 06:51 AM

ca_upd20150115a.zip (221 KB) Constantin Asofiei, 01/15/2015 04:46 AM

ca_upd20150115b.zip (179 KB) Constantin Asofiei, 01/15/2015 01:51 PM

ca_upd20150123a.zip (95 KB) Constantin Asofiei, 01/23/2015 07:48 AM

hc_upd20150129a.zip (336 KB) Hynek Cihlar, 01/28/2015 08:51 PM

ca_upd20150127b.zip (99.7 KB) Constantin Asofiei, 01/29/2015 02:44 AM

hc_upd20150129b.zip (336 KB) Hynek Cihlar, 01/29/2015 05:06 AM

hc_upd20150318a.zip (485 KB) Hynek Cihlar, 03/18/2015 08:03 PM

ca_upd20150323b.zip (512 KB) Constantin Asofiei, 03/23/2015 05:59 PM

hc_upd20150323a.zip (850 KB) Hynek Cihlar, 03/23/2015 09:09 PM

ca_upd20150324a.zip (512 KB) Constantin Asofiei, 03/24/2015 01:48 PM

ca_upd20150406c.zip (323 KB) Constantin Asofiei, 04/06/2015 11:19 AM

hc_upd20150407b.zip (877 KB) Hynek Cihlar, 04/07/2015 06:08 PM

hc_upd20150408b.zip (877 KB) Hynek Cihlar, 04/08/2015 03:02 PM

ca_upd201504315c.zip (280 KB) Constantin Asofiei, 04/15/2015 03:42 PM

hc_upd20150417c.zip (952 KB) Hynek Cihlar, 04/17/2015 03:15 PM

hc_upd20150420g.zip (972 KB) Hynek Cihlar, 04/20/2015 09:16 PM

hc_upd20150421c.zip (974 KB) Hynek Cihlar, 04/21/2015 03:08 PM

hc_upd20140424f.zip (969 KB) Hynek Cihlar, 04/24/2015 08:34 PM

hc_upd20150424f.zip (969 KB) Hynek Cihlar, 04/24/2015 08:36 PM

hc_upd20150424g.zip (969 KB) Hynek Cihlar, 04/24/2015 09:01 PM

hc_upd20150424h.zip (969 KB) Hynek Cihlar, 04/24/2015 09:09 PM

hc_upd20150427b.zip (969 KB) Hynek Cihlar, 04/27/2015 06:28 PM

hc_upd20150428a.zip (969 KB) Hynek Cihlar, 04/28/2015 06:02 AM

hc_upd20150428b.zip (969 KB) Hynek Cihlar, 04/28/2015 06:51 PM

hc_upd20150429a.zip (10.4 KB) Hynek Cihlar, 04/29/2015 10:48 AM

hc_upd20150429b.zip (10.4 KB) Hynek Cihlar, 04/29/2015 11:35 AM

ca_upd20150429a.zip (511 KB) Constantin Asofiei, 04/29/2015 02:34 PM

ca_upd20150430c.zip (513 KB) Constantin Asofiei, 05/01/2015 04:04 AM

ca_upd20150507a.zip (282 KB) Constantin Asofiei, 05/07/2015 03:57 PM

ca_upd20150508a.zip (284 KB) Constantin Asofiei, 05/08/2015 03:44 AM

ca_upd20150508b.zip (14.2 KB) Constantin Asofiei, 05/08/2015 10:21 AM

hc_upd20150508a.zip (327 KB) Hynek Cihlar, 05/08/2015 11:43 AM

hc_upd20150508b.zip (327 KB) Hynek Cihlar, 05/08/2015 12:02 PM

hc_upd20150509a.zip (332 KB) Hynek Cihlar, 05/09/2015 04:17 AM

hc_upd20150509b.zip (11.1 KB) Hynek Cihlar, 05/10/2015 02:41 AM

hc_upd20150510a.zip (10.2 KB) Hynek Cihlar, 05/10/2015 02:46 AM

hc_upd20150510b.zip (10.3 KB) Hynek Cihlar, 05/10/2015 08:13 AM

hc_upd20150510d.zip (44.9 KB) Hynek Cihlar, 05/10/2015 04:09 PM

hc_upd20150513b.zip (47.7 KB) Hynek Cihlar, 05/14/2015 07:12 AM

hc_upd20150612b.zip (424 KB) Hynek Cihlar, 06/12/2015 04:32 PM

cbb_p2j_drop_down_0620_0_gui.jpg - Sample 0 mouse inside the opened drop-down (73.4 KB) Eugenie Lyzenko, 06/20/2015 10:29 AM

cbb_p2j_drop_down_0620_1_gui.jpg - Sample 1 mouse left the opened drop-down (41.2 KB) Eugenie Lyzenko, 06/20/2015 10:29 AM

Max coordinate.png (3.84 KB) Hynek Cihlar, 07/14/2015 02:45 PM

cbb_test10_p2j_layout_regression_gui.jpg - Wrong layout picture (56.5 KB) Eugenie Lyzenko, 07/24/2015 12:35 PM

frame_items_offset.png (1.05 KB) Hynek Cihlar, 09/07/2015 09:02 AM


Subtasks

Feature #2264: analyze how the GUI interface is implemented in 4GLClosedConstantin Asofiei

Feature #2286: design and implement basic GUI window widget supportClosedMarius Gligor

Feature #2229: implement CURRENT-WINDOW, ACTIVE-WINDOW and DEFAULT-WINDOW system handles for GUIClosedVadim Gindin

Feature #2323: refactor coordinate system and implement GUI coordinate supportClosedHynek Cihlar

Feature #1794: implement font supportClosedConstantin Asofiei

Feature #2333: implement the GUI status line widgetClosedMarius Gligor

Feature #2334: implement the GUI message line widgetClosedMarius Gligor

Feature #2340: implement the window title barClosedConstantin Asofiei

Feature #2369: add configuration for window details inherited from the OS (title, border, color, etc)Rejected

Feature #2370: finish window popup menu implClosedVadim Gindin

Feature #2254: eliminate the logic in the Config* classes and make them simple containers with public membersClosedConstantin Asofiei

Feature #2388: finish GUI window move/position supportClosedHynek Cihlar

Feature #2415: insert indicator support for GUI windowClosedMarius Gligor

Feature #2416: implement frame widget support for GUIClosedMarius Gligor

Feature #2424: GUI window sizing and scrollbar/viewport handlingClosedHynek Cihlar

Feature #2425: implement GUI rectangle widgetClosedMarius Gligor

Feature #2446: implement BUTTON and IMAGE GUI widgets (runtime and conversion support)ClosedEugenie Lyzenko

Bug #2477: button remains pressed when it should notClosedEugenie Lyzenko

Bug #2452: Button label resize fails with error 4054ClosedEugenie Lyzenko

Feature #2478: button image supportClosedEugenie Lyzenko

Feature #2479: DEFINE IMAGE and image phrase support for both button and imageClosedEugenie Lyzenko

Feature #2480: add support for button and image attributes and optionsClosedEugenie Lyzenko

Feature #2481: enable, test and fix clipping for both rectangle and button GUI widgetsClosedEugenie Lyzenko

Feature #2545: add support for specially named button imagesClosedEugenie Lyzenko

Feature #1832: implement image supportClosedEugenie Lyzenko

Feature #2476: window icon support improvementsClosedEugenie Lyzenko

Feature #2486: enhance editor functionalityClosed

Feature #2487: implement READ-FILE() and SAVE-FILE() methods in the editor widgetClosedEvgeny Kiselev

Feature #2534: methods/attrs support for EDITOR, SELECTION-LIST and COMBO-BOXClosedIgor Skornyakov

Feature #2521: enhance/implement radio-set for GUIClosed

Feature #2522: add attribute/method support for radio-setClosedIgor Skornyakov

Feature #2523: implement GUI radio-set widgetClosed

Feature #2559: implement ALERT-BOX supportClosedHynek Cihlar

Feature #2560: implement GUI DIALOG-BOX supportClosedHynek Cihlar

Feature #2563: implement GUI EDITOR widgetClosedConstantin Asofiei

Feature #2564: implement GUI BROWSE widgetClosedStanislav Lomany

Feature #2565: implement runtime support for the SET-WAIT-STATE methodClosedIgor Skornyakov

Feature #2566: implement LOAD-MOUSE-POINTER methodClosedIgor Skornyakov

Feature #1796: implement full GUI layout supportClosedConstantin Asofiei

Feature #2567: add misc widget support part 2: more options, attributes and methodsClosedIgor Skornyakov

Feature #2606: implement GUI runtime support for SELECTION-LISTClosedEugenie Lyzenko

Feature #2612: implement GUI conversion and runtime support for the SLIDER widgetClosedEugenie Lyzenko

Feature #2614: implement GUI runtime support for RADIO-SET widgetClosedEugenie Lyzenko


Related issues

Related to User Interface - Feature #2016: implement CURRENT-WINDOW, ACTIVE-WINDOW and DEFAULT-WINDOW system handles Closed 02/20/2013 08/13/2013
Related to User Interface - Feature #2372: implement support for PUT SCREEN in GUI New
Related to User Interface - Feature #2373: implemented output to redirected, paged terminal via (un)named streams in GUI mode New
Related to User Interface - Feature #2374: implement WINDOW events in GUI mode Closed
Related to User Interface - Feature #2490: fix movement of widgets part of a down frame's body New
Related to User Interface - Bug #2677: fix drawing and functional differences between P2J GUI and 4GL GUI New 09/11/2015
Related to User Interface - Feature #2676: implement the equivalent to configurable support for a windows theme Closed

History

#1 Updated by Greg Shah about 10 years ago

This task is meant to be the parent task for the GUI implementation. Please place task history here instead of in the child tasks.

#2 Updated by Greg Shah about 10 years ago

The client will need significant changes to implement GUI support.

One important change that is necessary is to enhance the driver model. The current model only supports CHUI and its interface is not sufficient to support GUI. This means we need to abstract/split the client into a 3 layer model (common core, chui or gui specific middle and low level driver that implements a gui-specific or chui-specific rendering/event model).

The code we have today in "common" is still very CHUI-specific. I would also see major package changes and classes being added/removed/moved to allow the chui/gui specific stuff to be kept in cleanly separated packages, while only the common core would be in the more generic packages. We have started the work to this end, but it is not complete.

It seems to me that there should be 3 UI layers separated by 2 APIs which abstract at different levels:

       |------------------------------------------------|
       |       common UI implementation                 |
       |------------------------------------------------|  <-- high level "component API" 
       |   GUI-specific   |   CHUI-specific             |
       |------------------------------------------------|  <-- low level "driver API" 
       | GUI     | GUI    | CHUI    | CHUI    |  CHUI   |
       | Swing + | AJAX   | Swing + | NCURSES |  AJAX   |
       | Java2D  | Driver | Java2D  | Driver  | Driver  |
       | Driver  |        | Driver  |         |         |
       |------------------------------------------------|

All of the above code is envisioned as P2J code.

There is only a single component API. It is meant to be completely generic so that all code above it is completely independent of the UI type.

Below the component API is code that implements the Progress behavior that is specific to GUI or CHUI. The idea here is that each UI type (GUI or CHUI) has certain features like how it renders each widget type (i.e. component), layout... and other things that cannot be common between GUI and CHUI. In a perfect world, the same GUI code at the middle layer can drive different low-level destinations.

I suspect that there will be 2 driver APIs, one that is specific to GUI and one that is specific to CHUI. This is not required, but it is perfectly acceptable so that CHUI drivers can be simplified to just the minimum they need (and sizes etc... can be in the units that are natural for CHUI). It is possible to make a single driver API, but it would need to be more complicated and I don't know that there is much value in doing so. I prefer to have a super-interface for the common portions of the 2 driver models. Optimally, the GUI driver API would be a superset of the CHUI API.

Please note that we have no intention of implementing GUI support using pre-existing widgets in Swing or in Javascript. The Progress behavior needs to be duplicated exactly and the look/feel and behavior cannot be duplicated with existing components. Instead, we will use a JComponent in Swing and a HTML5 Canvas in Javascript and we will draw/manage our entire UI ourselves.

For details on the current AJAX client approach (at this time it is CHUI only, see #1811). While we have been able to implement the AJAX CHUI driver with no changes in the CHUI driver API, I am unsure if this same approach can/would be taken for the AJAX GUI driver. In particular, I am concerned about reducing the number of trips down to the browser via websockets. In other words, for the AJAX drivers, there is an inherent 3rd API that splits the final portion of the rendering/input event capture and delegates that to the javascript implementation in the browser. In a GUI environment, we have buttons, browses and other widgets that are visually complex and graphically intense. It is expected that we will need to be smart about how we tell the JS side to draw. There are different high level approaches we might take:

  1. implement a set of drawing primitives for graphical environments similar to (but more sophisticated than) how the CHUI driver interface does it; then send a list of primitive operations down to the client as a batch and let it "replay" the sequence there; for example to draw a button we might have to draw a rectangle of a certain size, position and fill color, then we might have to draw shadow rectangles, border, label text... each of these items might correspond to a graphics primitive
  2. implement a smarter widget-specific drawing layer in the driver; instead of primitives, the driver would know how to draw a button (given a small list of input parameters)

The second approach is likely to be significantly faster than the first, BUT the "cost" is that we must maintain parallel drawing implementations for each GUI driver. In other words, the GUI drivers could share much less code.

#3 Updated by Constantin Asofiei about 10 years ago

Some initial findings about how 4GL implements the GUI interfaces:
  1. the MESSAGE ... VIEW-AS ALERT-BOX statements use the Windows system information/question/error dialogs.
  2. the color scheme used to draw the frame widgets and the window is the same as the current Windows color scheme. When the Windows color scheme is changed (even while the GUI application is running), the application is redrawn using the new color scheme, immediately. My assumption at this time is that 4GL maps the 4GL widgets to Windows controls. See this test in GUI mode:
    def button btn label "button".
    display btn with frame f1.
    
    message frame f1:hwnd btn:hwnd.
    

    which shows that the two hwnd values are different. This, some findings about how the Progress 8 used to work, found here: http://www.oehive.org/win32api?page=10 , and this example http://www.oehive.org/node/410 which shows how is possible to change the shape of a widget, I think are a very good indicator that almost (if not all?) GUI widgets are mapped to Win32 controls.
    Note that the current documentation for the HWND attributes states that it is An integer value for a Windows handle to the window that contains the widget., but if we change the test above to this:
    PROCEDURE SetWindowRgn EXTERNAL "user32.dll" :
      DEFINE INPUT  PARAMETER HWND        AS LONG.
      DEFINE INPUT  PARAMETER hRgn        AS LONG.
      DEFINE INPUT  PARAMETER bRedraw     AS LONG.
      DEFINE RETURN PARAMETER ReturnValue AS LONG.
    END PROCEDURE.
    
    PROCEDURE CreateEllipticRgn EXTERNAL "gdi32.dll" :
      DEFINE INPUT  PARAMETER StartX AS LONG.
      DEFINE INPUT  PARAMETER StartY AS LONG.
      DEFINE INPUT  PARAMETER HEIGHT AS LONG.
      DEFINE INPUT  PARAMETER WIDTH  AS LONG.
      DEFINE RETURN PARAMETER hrgn   AS LONG.
    END PROCEDURE.  
    def button btn label "button".
    
    display btn with frame f1.
    
    message frame f1:hwnd btn:hwnd.
    
    ON '1':U ANYWHERE
    DO:
       DEFINE VARIABLE hrgn        AS INTEGER NO-UNDO.
       DEFINE VARIABLE ReturnValue AS INTEGER NO-UNDO.
       DEF VAR hwidget AS HANDLE.
       hwidget = btn:HANDLE IN FRAME f1.
       RUN CreateEllipticRgn (1, /* Start Xpos */
                              1, /* Start Ypos */
                              hWidget:WIDTH-PIXELS,
                              hWidget:HEIGHT-PIXELS, 
                              OUTPUT hrgn).
    
       RUN SetWindowRgn(hWidget:HWND, 
                        hrgn, 
                        1, /* 1 = Redraw */
                        OUTPUT ReturnValue).
    
       RETURN.
    END.
    
    WAIT-FOR CLOSE OF CURRENT-WINDOW.
    

    and press "1" you will notice how the button's appearance changes - so the documentation is incorrect.
  3. the message area looks like it can record a maximum of 50 messages. Didn't find yet a way to change this.
  4. the message area and status area can be made optional for new windows.
  5. I couldn't find a way to make the created windows modal. So, this allows multiple windows to be active, with all the enable/visible widgets in a window at a "click-distance", to gain focus.

#4 Updated by Greg Shah about 10 years ago

It is my understanding that all Progress GUI widgets have a backing native Windows control as the implementation. There may be exceptions to this rule. For example, the FIELD-GROUP is probably only an internal 4GL construct. My reasons for believing this are primarily because I have seen too much code that directly manipulates 4GL widgets using the HWND and WIN32 APIs. I have seen this in real customer source code, but the example you provided is pretty definitive too.

Because each 4GL widget has its own native control, there is a unique HWND for each 4GL widget. In other words, there is a full hierarchy of native controls and each can be manipulated using the WIN32 APIs.

By the way, this is very similar to the Java AWT implementation, which has native controls mapped to each AWT widget. These are called "peer" controls and the resulting implementation is tricky to get right because:

1. The state must be kept synchronized between Java and the native control.
2. The functionality must be carefully split between the two separate pieces of code.
3. The native implementation may not support all features well and/or may need severe measures to make it work.

Of course, Swing avoided the native peering mess and results in a significantly better implementation.

We will NOT be implementing using a native control approach. This means we will not support the direct usage of HWND in WIN32 APIs and any such code will need to be replaced/removed before conversion.

#5 Updated by Greg Shah about 10 years ago

I couldn't find a way to make the created windows modal. So, this allows multiple windows to be active, with all the enable/visible widgets in a window at a "click-distance", to gain focus.

Yes, the design is based on the Windows "MDI" (Multiple Document Interface) approach. Multiple windows, z-order, tab-order/focus will all be areas needing attention.

#6 Updated by Constantin Asofiei about 10 years ago

Greg Shah wrote:

We will NOT be implementing using a native control approach. This means we will not support the direct usage of HWND in WIN32 APIs and any such code will need to be replaced/removed before conversion.

This is what I was hoping to hear. On a side-note, I think the Server/GUI project might have HWND depedencies, as I recall at least a case where HWND was used.

My next steps will be to take each widget type and determine differences in the GUI/ChUI implementations. Considering the fact that the GUI widgets are directly linked with Win32 widgets, which color scheme (and skin?) will we use as standard?

#7 Updated by Greg Shah about 10 years ago

We will be implementing configurable control over all fonts, colors and other standard GUI configuration via our directory. We won't necessarily be running on Windows, so we cannot and will not be dependent upon any native APIs for our GUI implementation. That way it can run in Swing and as a browser-based AJAX implementation.

We will also be allowing "skinning" of the AJAX version of the client, through CSS (the default styles applied will come from the directory and then we will allow the customer to override those using CSS values). This CSS stuff is not a top priority right now. I just want to mention it for future reference.

#8 Updated by Greg Shah about 10 years ago

Upon additional consideration of our implementation approaches in note 2, I think it makes the most sense to implement option 2:

implement a smarter widget-specific drawing layer in the driver; instead of primitives, the driver would know how to draw a button (given a small list of input parameters)

The reasoning:

1. This is certainly the approach which will perform the best.

2. This approach allows us to limit the number of round trips between the browser and the Java client. For example, the button implementation can handle the animation (being pressed and released) without a trip to the Java client. The event will still be fired and will cause the Java client to process. But the user won't have to wait for the Java client in order to see the UI respond. This kind of responsiveness is critical to going into production.

This approach has the least risk and the only cost is some additional code that must be implemented (and maintained) in parallel. I think the costs are far outweighed by the benefits.

#9 Updated by Greg Shah about 10 years ago

The following is some early planning that was done (at my request) by Sergey Yevtushenko in 2011:

-------- Original Message --------
Subject: plan for getting simplest GUI testcase running
Date: Thu, 13 Oct 2011 23:36:55 +0300
From: Sergiy Yevtushenko <>
Organization: ES@Home
To: Greg Shah <>
CC: Eric Faulhaber <>

Gregory,

Please, find below the plan. It is based on assumption that we're going
to reuse existing code where this makes sense.

Prerequisites

As an absolute minimum we need ThinClient, Frame, FillIn and Skip/Space
widgets. Since Frame is based on BorderedPanel which, in turn, based on
AbstractContainer, we need these two as well. Also, internally Frame
uses ScrollContainer and ScrollPane classes. ScrollContainer has same base
as Frame, so this does not create new dependencies, but the class itself
heavily uses coordinate calculations, so porting it will not be simple.
Almost the same is true for ScrollPane, although it looks slightly simpler
from this point of view.

Beside that we will need few utility classes .
Some of which are independent from UI type (WidgetRegistry and FrameData,
for example), but some are UI-dependent (ZeroColumnLayout, for example).

Stage 1

0. Check dependencies between classes and determine which classes are
UI-type specific. Classes which are UI-type independent should be moved into
shared package.

1. Carefully review and clean up *Config classes from any coordinate
calculations. Necessary code should be shifted into locations where these
calculations are necessary. Also, FONT attribute should be added to all these
classes.

2. Check ThinClient.java for coordinates calculations. If there are any, they
should be refactored into separate class shielded by the interface and injected
at run-time (probably taken from driver) into ThinClient. Probably this
class may use ScreenDriver to calculate offsets from font.

3. Carefully review and fix coordinates calculation in the ZeroColumnLayout.
Ideally it should not depend on the UI type at all (perhaps direction of the
coordinates is the only alowed dependency).

Stage 2

1. New implementation of the screen driver with required primitives.

2. Implement minimal set of required widgets (see prerequisites).

Thanks.
*-------------------------------------------
Software Products Team
Golden Code Development
http://www.goldencode.com

Please note that in subsequent development work, the "Stage 1" items 0 and 1 were both completed. The results are long since checked into bzr. Items 2 and 3 remain to be done, as does Stage 2 and beyond.

#10 Updated by Greg Shah about 10 years ago

Some initial thoughts based on reviewing basic 4GL GUI examples:

1. Fonts

  • By default the GUI uses the Windows "default system font" which is NOT a fixed width font.
  • ChUI uses a fixed width font.
  • I think that activities in a GUI app that would be "report processing" activities, will act like ChUI.
  • Font metrics are critical for sizing everything in the 4GL GUI (see below).
  • Matching the font used in the original GUI code will be very important. This matching will have to work in both Swing and in the browser.
  • Each font that can be used by the 4GL is mapped to an ordinal number. The 4GL programmer uses this number to reference the font. This means that the code is very dependent upon the installation environment being extremely rigid/consistent.

Some questions:

  • How does the 4GL determine the list of fonts that are available?
  • How does the 4GL map these into ordinals?
  • What limits are there in terms of what fonts are allowed to be used? (e.g. anything reported by a WIN32 API call, or only TrueType or only Postscript Level 2...)
  • How does the default system font get determined?
  • How are fonts configured in the 4GL? (INI files, registry, INI + registry, command line, no config at all)
  • Is there any way to dynamically change (at runtime) the default font?

2. Coordinate/Sizing System

  • Although the natural WIN32 GUI coordinate system is pixel-based, the 4GL seems very biased towards sizing that is a multiple of the character size. This means that there are many character-oriented options like WIDTH-CHARS (synonym for WIDTH), HEIGHT-CHARS (synonym for HEIGHT), SIZE-CHARS (synonym for SIZE), ROW and COL.
  • Each of the above character-oriented options has a pixel form: WIDTH-PIXELS, HEIGHT-PIXELS, SIZE-PIXELS, X and Y.
  • There is some level of translation/intermixing between these two ways of specifying values.

Some questions:

  • Does the default approach calculate values in character units and then translate them into decimal values that are the equivalent to the pixel forms?
  • How does the character approach calculate the font metrics? In other words, how does it determine the number of pixels that 1 WIDTH-CHAR and 1 HEIGHT-CHAR will occupy?
  • Can the two types of specification be intermixed fully or are there limits?

3. By default, code that has a "good" layout in ChUI code will generally look bad in GUI. I believe the primary reason for this is that some controls (notably the FILL-IN) take up more vertical space in GUI than they did in ChUI. This is because of the border drawn for the text entry field Windows control (there is a "3D" effect which makes the entry field itself seem recessed into the "form" or background. This difference in sizing will be a big cause of layout differences.

#11 Updated by Constantin Asofiei about 10 years ago

Greg Shah wrote:

  • How does the 4GL determine the list of fonts that are available?

Do you mean font names or ordinals? If ordinals, see below.

  • How are fonts configured in the 4GL? (INI files, registry, INI + registry, command line, no config at all)

From the Getting Started: Installation and Configuration book, chapter Progress.ini file and the Windows registry, the fonts can be read either from registry or progress.ini files. The diagram which shows how the settings are read from the registry or ini files can be seen in Figure 4–1: Windows environment information search path in the Managinb ABL Applications book. If we will rely on registry configurations for the fonts and other environment settings, we will need to follow the diagram, to properly determine when to read from the registry and when to read from directory settings.

  • How does the 4GL map these into ordinals?

The non-default fonts are specified via a property with font# syntax, where # is a numeric value greater than 0. Fonts from 0 to 7 are reserved (although they can be changed) and from font8 forward (until font255) custom fonts can be set. It shows an error if a missing font ordinal is assigned to the FONT attribute. The Managing ABL Applications book contains more informations about what options can be set at the fonts.

  • What limits are there in terms of what fonts are allowed to be used? (e.g. anything reported by a WIN32 API call, or only TrueType or only Postscript Level 2...)

Considering that 4GL backs all widgets with Win32 controls, I think any installed font available via a WIN32 API call can be used. And it looks like if a fond name can't be found, it defaults to the system font, not the default font from ini/registry.

  • How does the default system font get determined?

The default font is determined from the defaultFont configuration, if set, or from the system font, otherwise. This font will be used to compute the size in pixels of a widget. If the font for a widget is changed, then the widget will not be resized. The interesting fact is that, for some widgets (like togglebox), unless the height is explicitly set to 1 char, the default height reported by height-chars is not 1, is a value depending on the size of the used default font. For fill-in, it computes a 1-char size.
There is also the defaultFixedFont property, which is used this way, accordingly to this comment in dvref.pdf view-as phrase notes:

In Windows, if no font is specified for a fill-in field, ABL uses two default fonts:
– A fixed font for date fields, numeric fields, and character fields that contain fill
characters (such as the parentheses surrounding the area code of a telephone
number).
– A proportional font for character fields that do not contain fill characters.
The AVM looks for these fonts in the current environment, which may be the registry
(Windows only) or an initialization file. If the current environment does not define these
fonts, the AVM uses the system default fixed and proportional fonts. For more information

  • Is there any way to dynamically change (at runtime) the default font?

I didn't find a way to change at runtime the defaultFont and defaultFixedFont - only the font# fonts can be changed via system-dialog font statement.

The SESSION:PIXELS-PER-ROW and PIXELS-PER-COLUMN attributes contain metrics based on the default font. My findings show that these will be used as default when sizing the widgets in pixels (from character metrics) and back, sizing the widgets in characters (from pixel-based metrics).

The position of a widget can be set via both character-based and pixel-based coordinates (COLUMN and ROW attributes or X and Y attributes). From these, only the X and Y coordinates are static: once set, they do not change with the font; COLUMN and ROW attributes are converted to pixels, based on the default font.

I've found something interesting about how we can compute the font metrics here: http://stephensite.net/WordPressSS/2008/02/19/how-to-calculate-the-character-width-accross-fonts-and-points/ The interesting part is the gdi32.dll GetTextMetrics function, as is possible that 4GL relies on it for computing the height/width of a 1 character, in a given font.

#12 Updated by Greg Shah about 10 years ago

Do you mean font names or ordinals? If ordinals, see below.

I mean both, really.

I understand that the configuration (progress.ini and/or the registry) can specify a mapping of a font number font<num> to a font family name, point size and optionally a qualifier (e.g. bold).

I understand that the 4GL code can only ever specify an ordinal and map that to the font property of a widget, label, column-label, frame or window. This mapping is stored in a resource that can be referenced via the FONT-TABLE system handle.

But when we actually have to implement code that works with fonts, we must know the font name. Getting the mapping working exactly as in the 4GL is thus important.

Some questions:

  • If the mappings in the FONT-TABLE change, when do the changes become visible to the user? (Immediately, the next time the affected controls are redrawn, never...?)
  • Do different controls handle dynamic font changes differently?
  • The SYSTEM-DIALOG FONT allows the user to change a specified entry in the FONT-TABLE. The 4GL docs suggest this is the only way to edit this table, but it also seems like the "environment" (as dynamically set by LOAD/USE) can be used to dynamically load/save the FONT-TABLE (using PUT-KEY-VALUE and GET-KEY-VALUE). This suggests that the 4GL programmer can dynamically load the entire table at any time. Is that right?
  • Does changing the environment cause the font table to be reloaded implicitly or does one have to use GET-KEY-VALUE to read it in?
  • Does the loading of the font table really end at the first font<num> that is not configured?
  • To what extent can ChUI code use the FONT table? The Progress docs state that there are 128 fonts available to ChUI code. I wonder if that is just on Windows. LE: I misread the docs, they only reference 128 colors, not fonts.
  • Is SYSTEM-DIALOG FONT using the WIN32 ChooseFont (http://msdn.microsoft.com/en-us/library/windows/desktop/ms646958%28v=vs.85%29.aspx) for its implementation?
  • Does the 4GL support fonts in different colors?
  • Can the DefaultFont, DefaultFixedFont, PrinterFont, PrinterFont1, PrinterFont2 and PrinterFont3 be changed by LOAD/USE...?

Implementation guidelines:

  • We won't always be running on a Windows system. In such cases, we cannot read the registry or progress.ini files at startup or dynamically. In general we would not want to do this even if we were running on Windows. So we must create a directory-based configuration that provides us with all the same font mapping information that is read by Progress at startup/runtime.
  • If the font-table can truly by changed by using the LOAD/USE/GET-KEY-VALUE/PUT-KEY-VALUE, then we will have to consider how we support this. Perhaps we will have to change code that does this. We do support these features on Windows already, because they are there for general purpose usage (just like shared library calls).
  • Each GUI driver will need to provide primitives for font metrics. These will be part of the low-level driver API.
  • Each GUI driver will need to provide a list of fonts to back the SYSTEM-DIALOG FONT implementation.
  • We will have to test the SYSTEM-DIALOG FONT implementation to see if we can reuse our other dialog and widget support to duplicate its features. This one is probably a Windows dialog and it may have behaviors that cannot be duplicated with the 4GL widgets alone. For example, the WIN32 ChooseFont dialog shows a sample of the font currently chosen (before it is loaded into the font table).

#13 Updated by Greg Shah about 10 years ago

This is an interesting comment in the Colors and Fonts chapter of the Programming Interfaces book:

In Windows, to assign colors to buttons, menus, and window titles, you must use the Display Properties dialog box in the Control Panel. You cannot change these colors in your OpenEdge application.

This suggests that they have a pretty limited mapping of these widgets to the Windows counterparts. In other words, they probably rely heavily on the native control and don't play many tricks to customize them.

#14 Updated by Greg Shah almost 10 years ago

The first step in creating GUI support is to implement #2286, which is support for the creation and display of a GUI window widget.

In GUI, the most common code is the CREATE WINDOW (it is really just a CREATE WIDGET statement where the widget type is WINDOW). But if a CREATE WINDOW is not used as the container for a frame, then the 4GL will create a DEFAULT-WINDOW and the frames will be placed inside that. This #2286 task is meant to implement the support for both CREATE WINDOW and for implicit use of the DEFAULT-WINDOW. Support only should be implemented for a Swing GUI driver. Do NOT implement the AJAX driver yet (that will be the next step in a different task). However, your design should anticipate that the same GUI driver API will need to support both the Swing driver and an AJAX driver.

This is the first code that will be written for GUI and as such, there will be some initial infrastructure to put in place:

  • The beginnings of the GUI driver interface. As noted above, if possible we want it to be a superset of the ChUI driver API, so that common code can deal with a super-interface that is common.
  • The Swing GUI driver.
  • Changes to the ClientDriver to start up the Swing GUI driver.

Please carefully review the options that can be controlled for a window:

  • borders
  • decorations (e.g. min/max/restore buttons)
  • position
  • sizing
  • visibility
  • status area
  • message area

You don't need to implement the status or message area yet, but the space they utilize must be considered.

In all of the above, determine what the 4GL does by default and also when there is explicit input. To the degree that this is dependent upon Constantin's font work (positioning and sizing are going to be dependent on character units and font metrics), just stub out what you need from an API and mock it. Document the API here so we can understand what the driver will have to provide to allow your code to work.

We won't have any widgets to put in the Window initially. But you still can write runtime support to allow it to be displayed, moved, hidden, sized and so forth. Hopefully you can find ways to write test code to drive this.

#15 Updated by Marius Gligor almost 10 years ago

Before starting to implements the GUI model we have to describe and understand the ChUI model implementation.
Here is what I found looking inside the ChUI implementation.

A - On server side:
- StandardServer exports ServerExports services implemented in class LogicalTerminal

B - On client side:

- The core is the ThinClient which exports ClientExports services.

- ChUI widgets are pushed down from server to client and stored inside a WidgetRegistry structure which is a member of the ThinClient instance.

- The WidgetRegistry structure has a map collection of widgets. An entry in the map is of type <Integer, Widget>
Each entry in the map represent a widget. Each widget has an unique Integer ID (map entry key) and it is stored as an instance of Widget interface (map entry value).

- An OutputManager instance is used as an interface to low level UI primitives via an ScreenDriver interface.

- ScreenDriver instances drive an OutputPrimitives interface which provide primitive drawing services.

Example for ChUI:
ChuiScreenDriver implements ScreenDriver
SwingChuiDriver extends ChuiScreenDriver

ChuiWebDriver extends ChuiScreenDriver implements WebScreenDriver

- OutputPrimitives define the low level UI primitives methods.

Example for ChUI:
BasePrimitives implements OutputPrimitives
DriverPrimitives extends BasePrimitives
ChuiPrimitives extends DriverPrimitives

Each widget implements the Widget interface. The Widget interface define a draw() method which is called to draw the widget.
The draw method use an OutputManager instance to draw to the screen.
The current implementation for ChUI widgets provides simple drawing primitives character oriented.
The draw method for a widget is called whenever the widget has to be draw.

#16 Updated by Marius Gligor almost 10 years ago

I have some questions related to this issue:

1. Should we follow the same model for GUI like the ChUI model (see note #15) and define specific draw methods using GUI primitives on each widgets?

2. For WINDOW widget the size is always calculated based on character size (font metrics)?

#17 Updated by Greg Shah almost 10 years ago

Here is what I found looking inside the ChUI implementation.

A - On server side:
- StandardServer exports ServerExports services implemented in class LogicalTerminal

B - On client side:

- The core is the ThinClient which exports ClientExports services.

These aspects of the solution are not ChUI-specific. These should be completely generic to any UI (ChUI or GUI). We always strive to make the server side code and as much of the client-side code to be generic. Of course, the driver interfaces are supposed to hide the implementation differences of ChUI/GUI as much as possible. There will also be specific widget differences (e.g. drawing) and possibly some differences in layout etc... but all of these things are client-side. It is possible that there are some ChUI-only or GUI-only features that may be exposed even through to the server. That is OK, so long as the Progress 4GL also makes these features specific to ChUI or GUI. For example, PFCOLOR (ChUI) vs BGCOLOR (GUI). Both must be there but they are not generic even in the 4GL, so it is OK.

ChUI widgets are pushed down from server to client and stored inside a WidgetRegistry structure which is a member of the ThinClient instance.

Some thoughts:

First, there should be very little that is ChUI specific in our server-side implementation. I wouldn't say that those widgets are ChUI widgets. The server-side widgets (BrowseWidget, FillInWidget...) have little to do with ChUI. They are just the abstract representation of the widget for the business logic.

Second, on the client-side, I do know that the ThinClient implementation needs to be cleaned up and made less ChUI-specific. It is not supposed to be ChUI-specific code, even though it does currently reside in the ui/chui/ directory. I expect we will move the ChUI specific code in ThinClient, ZeroColumnLayout and so forth into separate classes, abstracted behind the driver interfaces. Then the majority of the code will remain in classes like ThinClient and ZeroColumnLayout, which will be moved out of ui/chui/ and into ui/client/.

Third, what we push down to the client is 2 things:

  • frame definitions (each frame has a Java class which has the instances of each widget and some setup/configuration code), these are turned into a data which is sent to the client to tell the client how to create and configure that frame
  • a screen buffer with the data and runtime state of each widget

Other than for the special authentication logic, we don't ever send classes down to the client. We just send data.

An OutputManager instance is used as an interface to low level UI primitives via an ScreenDriver interface.

Yes. It hides the use of the specific drivers (and OutputPrimitives instances) behind appropriate interfaces.

OutputPrimitives define the low level UI primitives methods.

Yes. These are not just used to hide the interactive UI differences. A big reason for this separate "pluggable" low level primitives interface is to cleanly accommodate the redirected terminal cases. The output from the UI can be redirected to files or child processes when you write code to explicitly use UI statements (like DISPLAY) with a stream (DISPLAY STREAM my-stream my-var1 my-var2 WITH FRAME f0.) or implicitly by redirecting the unnamed stream first (OUTPUT TO some-report-file.txt. DISPLAY my-var1 my-var2 WITH FRAME f0.). This works for GUI apps too and it is a very common case for creating reports and printer output. Interestingly, I think the same redirected terminal output primitives should work for GUI with little or no change.

1. Should we follow the same model for GUI like the ChUI model (see note #15) and define specific draw methods using GUI primitives on each widgets?

Yes, we will create GUI versions of the "Impl" classes (e.g. ui/chui/FillInImpl, ui/chui/ButtonImpl...) that provide the same interface, but handle the differences between GUI and ChUI.

2. For WINDOW widget the size is always calculated based on character size (font metrics)?

I don't know. You must write 4GL testcases and explore/document this.

#18 Updated by Marius Gligor almost 10 years ago

I attached a list with all WINDOW widget attributes more than 70!
I started to do tests using some WINDOW attributes on the customer's windev01 server.
Most attributes cannot be used on DEFAULT-WINDOW.

#19 Updated by Marius Gligor almost 10 years ago

Regarding HTML 5 Canvas please read this document: [[http://www.w3.org/TR/2dcontext/#best-practices]]

#20 Updated by Greg Shah almost 10 years ago

For now, only implement the Window attributes that are already "stubbed out" in our classes. To the degree that they are already implemented, if you find problems, do fix them. You don't need to add new features unless they are important for your test cases to work.

#21 Updated by Greg Shah almost 10 years ago

The points about the HTML5 canvas use are valid. However, in our case we have these mitigating circumstances:

  1. Many of these features do not exist in the 4GL. For example, spell checking, text search... are not done.
  2. Those features that exist must work exactly like they work in the 4GL which is likely to be very different than how browsers deal with these same features.
  3. We already have implemented many of these features (cursor management, focus management, low level text processing, word wrapping...) in our runtime.

#22 Updated by Marius Gligor almost 10 years ago

I designed a small test for WINDOW widget using the current defined attributes.
By adding some rules finally I managed to fully convert the script in P2J.
Than I fixed the Java code errors for generated code providing empty methods.
Now I'm working to write Java code for WINDOW widget attributes.

#23 Updated by Marius Gligor almost 10 years ago

1. Here are the changes that I made so far to implements the CREATE WINDOW on server side.
On each option assigned to WINDOW widget a WindowConfig structure is pushed down to the client via exported ThinClient.pushWindow(final WindowConfig config) exported service.
On ChUI interfaces only one WINDOW exists which is static created and is the parent of all other widgets.
For GUI interfaces it is possible to create one or more dynamic windows and family of windows (child / parent relation).
On the next step we have to implements multiple windows support on client side. (ThinClient)

2. The package contains also a skeleton for a GUI screen driver based on the existing ChUI screen driver.
This screen driver shall evolve into a full GUI implementation when we will implements the draw operations for GUI widgets.

#24 Updated by Greg Shah almost 10 years ago

Code Review 0513a

This is really good. Some feedback:

1. Some of the changes in BaseConfig are only shared between DIALOG, FRAME and WINDOW (and sometimes SESSION). For example, THREE-D, VIRTUAL-*...

These should not be placed in BaseConfig because almost everything inherits from that. And the ContainerConfig is only there for DIALOG/FRAME but not WINDOW.

I think we need a new Config class (PaneConfig?) that would inherit from BaseConfig and be the parent class to ContainerConfig. This would be the place for anything shared between DIALOG, FRAME and WINDOW.

This would need a matching PaneEntity that has the implementation code and is likewise situated in the class hierarchy.

2. Constantin: is there any issue with the changing of the setParent(Object) signature to setParent(GenericWidget)?

3. Instead of putting the GUI driver code in com/goldencode/p2j/ui/gui/, please put it in com/goldencode/p2j/ui/client/gui/. The com/goldencode/p2j/ui/chui/ directory is there on an historical basis and we will be eliminating it over time as the code get properly refactored into common code (in com/goldencode/p2j/ui/client/ and related subdirectories) and chui-specific code which will be in com/goldencode/p2j/ui/client/chui/.

#25 Updated by Constantin Asofiei almost 10 years ago

Greg Shah wrote:

2. Constantin: is there any issue with the changing of the setParent(Object) signature to setParent(GenericWidget)?

I think it should be OK.

Marius: note that the GenericWidget.setParent(Object) needs to be removed and GenericWidget.setParentHandle updated to use setParent(GenericWidget) - i.e. check if the object is a GenericWidget before calling, else throw exception.

#26 Updated by Marius Gligor almost 10 years ago

I added a new layer of inheritance PaneEntity and PaneConfig which holds shared options for DIALOG, FRAME and WINDOW widgets.
The GUI driver classes were moved on com/goldencode/p2j/ui/client/gui/ package.

Some observations:

1. setParent and getParent are implemented in BaseEntity class but setParentHandle and getParentHandle are implemented in the super class GenericWidget.
Should We move the implementation for setParentHandle and getParentHandle to BaseEntity?

2. I found inside rules different method names for the same option. For example I found setFgColor and setFgcolor definitions which basically are for the same attribute.
Should we change the definitions inside the rules in order to have the same method name?

3. In P4G options calculated in CHARS units are of type DECIMAL. This kind of options should be kept as double value inside the configuration files.
On character interfaces this values are rounded to integers but in graphical interfaces I think this should be transformed in pixels at one moment that's why we have to keep the original values which are decimals.
I found integer values for such kind of options inside the existing configuration files.
Even more I saw in the source code statements like: (int) double as a round substitute.
This is not OK because (int) double does not round the returned integer value it returns just the integer part.
Example for a value of 0.75 it returns 0 instead 1.

#27 Updated by Greg Shah almost 10 years ago

Code Review 0514a

Everything looks good.

#28 Updated by Greg Shah almost 10 years ago

Should We move the implementation for setParentHandle and getParentHandle to BaseEntity?

I will let Constantin respond to this one (he may not respond until early next week).

2. I found inside rules different method names for the same option. For example I found setFgColor and setFgcolor definitions > which basically are for the same attribute.
Should we change the definitions inside the rules in order to have the same method name?

Yes.

3. In P4G options calculated in CHARS units are of type DECIMAL. This kind of options should be kept as double value inside the configuration files.

Yes, that is probably correct. Although it is slightly complicated by the changes we are introducing in #1600. But for the purposes of the UI processing, our internal representation is probably fine using double since the precision needed will mostly likely never cause a loss of accuracy.

On character interfaces this values are rounded to integers but in graphical interfaces I think this should be transformed in pixels at one moment that's why we have to keep the original values which are decimals.

Yes.

I found integer values for such kind of options inside the existing configuration files.
Even more I saw in the source code statements like: (int) double as a round substitute.

Yes, please fix this. All "PIXEL" attributes are really integers. But all "CHAR" attributes are decimals. We must get this right for GUI, now.

#29 Updated by Constantin Asofiei almost 10 years ago

Marius Gligor wrote:

Should We move the implementation for setParentHandle and getParentHandle to BaseEntity?

From dvref.pdf, the PARENT attribute applies to browse column too; but BrowseColumnWidget does not inherit BaseEntity, so we need these to remain at GenericWidget.

#30 Updated by Marius Gligor almost 10 years ago

I designed a flow the assign unique ID's to a window dynamic created and register the new created window on server side and client side.
A static window is always created when a new session is started. This is the DEFAULT_WINDOW and is created on both server side and client side.
For character interface this is the only window that an application have.
For graphical interface (GUI) the static windows is also created but it is possible to create dynamic windows via CREATE WINDOW statement.
Each new created window should have an unique id inside the session an should be registered (stored) on both server and client side for further processing.
Here is a description of the designed flaw to assign ID's and registry dynamic windows:

1. On the server side a LogicalTerminal instance is assigned for each session. I used this instance to assign ID's to created windows by incrementing an integer value which was previous initialized with the ID of the default static window WindowConfig.SESSION_WINDOW_ID.
Also a list of WindowWidget instances is used to registry each new create window.
Whenever a new window widget is created on the server side a new ID is assigned to the created window and the instance is registered (see WindowWidget constructor)

2. On the client side a WindowConfig structure is used to keep the state of each window. This structure is pushed down whenever a new dynamic window is created or window attributes are changes.
For windows registry I designed a separate class WindowRegistry which at this stage contains only a map collection. WindowRegistry became the superclass of Window class.
Whenever the Window.pushConfig is called from ThinClient.pushWindow as a result of a server push (LogicalTerminal.pushWindow) the window is register using the assigned ID.
If the window is already registered an update is performed by replacing the old value with the new value in registry using the assigned ID as a key.

On the next steps we have to change and add code to effective manage the dynamic windows on both server side and client side.

#31 Updated by Greg Shah almost 10 years ago

Code Review 0515a

My only concern is in regard to the ID processing (and the new WindowRegistry class). Today, all widgets (including for the special DEFAULT-WINDOW) have widget IDs in the same "address space". The current approach:

  • DEFAULT-WINDOW is 999
  • each frame is modulo 1000 starting at 1000 (1000 as 1st frame, 2000 as 2nd frame, 3000 as 3rd frame...)
  • each contained control is a unique value incremented from its containing frame's ID (1st contained widget of a frame is frameid + 1, 2nd is frameid + 2...)
  • we assume that -1 (and maybe 0 too?) are invalid widget IDs and I think we have logic that depends on this

Although we don't have a single registry on the server side, we do keep a single registry on the client. This WidgetRegistry instance lives in the ThinClient and it contains everything. We have a very large amount of logic that is dependent upon that registry.

As far as I understand it, a Window is just a widget in the 4GL and shares many behaviors in common. Of course, windows are special widgets (like frames). They contain frames and they have parent/child relationships with other windows. But in the end, they are just widgets.

For these reasons, I prefer to allocate window IDs from the same address space instead of keeping a separate address space. of course, we may need to have a window-specific registry too. But on the client side, we keep everything together and when we want a frame to go with a widget, we rely upon the convention frameid == (widgetid / 1000) * 1000.

Unless you have important reasons to exclude windows from this address space, please do come up with an approach that is compatible. The simple approach: window IDs could start at 999 for the DEFAULT-WINDOW and then decrease by one from there; we would probably need to re-use IDs that are no longer in use but there would only ever be 999 valid windows at any time; in practice this is probably fine.

In regard to WindowRegistry, why not just keep a static member in Window.java? It could be private and access could be controlled. It is likely the Window class will be the primary consumer of it anyway.

#32 Updated by Marius Gligor almost 10 years ago

Indeed windows are like other widgets and on the client side we could use the WidgetRegistry to register dynamic windows.
I have to do some changes on Window and WindowImpl classes to allow constructors having a ComponentConfig parameter following the same model as for other widgets.
The actual implementation of Window and WindowImpl is specific to character interface and does not provide a way to create windows based on a WindowConfig structure.
Whenever a WindowConfig is pushed from server we have to construct/reconstruct the widget inside WidgetRegistry.

#33 Updated by Marius Gligor almost 10 years ago

Here are my latest changes:

1. On server side I used ID's from the same address space like frames. This offer a wide range of ID's.
Basically the frame address space is shared between frames and windows.

2. On client side I changed the Window class to allow the creation of windows based on a configuration structure.
In respect to other widgets windows are special widgets containing frames and dialogs.
We could keep the windows in the same registry together to other widgets but my feeling at this stage is that is better to keep them on a separate registry.
So I created a static registry inside the Window class. Later we could add static methods to Window class in order to manage the window registry.

#34 Updated by Constantin Asofiei almost 10 years ago

Greg, I keep forgetting to mention something about font metrics, so here it is: in Windows, is there a way to intercept gdi32.dll API calls? Because in Windows GUI code, the font is used only when drawing something, it's not saved as an attribute for the button/input/whatever; so we can't find a font from i.e. a button. If we intercept the gdi32.dll API calls, we can find the parameter values sent by 4GL when drawing text on screen for various widgets.

#35 Updated by Greg Shah almost 10 years ago

in Windows, is there a way to intercept gdi32.dll API calls?

Yes, there are some tools out there. For example:

http://billauer.co.il/blog/2010/07/strace-ltrace-win32-api-dll/ (good summary, includes some open source options)
http://gopalakrishna.palem.in/TracerApp.html (open source)
http://www.apimonitor.com/index.html (limited version available in a 3-day trial, author referenced above didn't like this one)

Try to stay with the open source options if they will work. If you must go with a non-open source/binary-only version, be very careful as this is exactly the kind of program that may masquerade as a tool when it is really malware.

The most common approach with these tools is that they operate as a debugger. That means they start a child process or attach to an existing process and use a WIN32 API to get privileged access to the address space, control the execution of the debuggee and so forth. An intro article is here:

http://msdn.microsoft.com/en-us/library/ms809754.aspx

To trace an API, there are multiple approaches. One could use a form of breakpoints to do it, but the best approach would normally be to fixup the imported function pointer table. The idea is that when the Windows loader loads a program, it fills in a table of function pointers for all imported APIs. This table is empty until the loader puts the real (runtime) addresses into it (after each dependent DLL is loaded). The compiled code deliberately calls the APIs indirectly. So when CreateProcess is called, there is a function pointer in the imported entry point table and all calls to CreateProcess actually use the pointer in that table. The reason for this is that otherwise, the Windows loader would have to edit the code in every location that uses CreateProcess (and all other imported APIs) every time a process was loaded. This would be very inefficient. So the calling is made indirect through this fixup or "relocation table". The target API's function pointer in this table would be modified to point to an alternate location (where your logging code exists). The original target API function pointer is saved off in your own copy of the table so that your code can still call there. Any code in that process that calls a modified pointer, would jump to your code where the parameters can be copied off and then the original call is made like before. On return, the return value (and any output parms that are passed by pointer) are copied off, and a log entry is written. Finally, this "API stub" returns back to the original call site.

Anyway, it is not super hard to do, but there are enough details and trickiness that it is best to use a tool that already exists. One of the great things you get with such a tool is that they often have good decodes for each API (the constants and so forth are all displayed in a symbolic form instead of as a number or bitfield).

#36 Updated by Marius Gligor almost 10 years ago

When a WindowWidget option is changed the window configuration file should be send down to the client via LogicalTerminal.pushWindow
However when a WindowWidget option is set in super class like Title for example no pushWindow is performed.
For other widgets a pushScreenDefinition() is used to send down the changes to client.
I fixed this issue by changing the GenericWidget.pushScreenDefinition() method to force a LogicalTerminal.pushWindow in case of a WindowWidget.

#37 Updated by Greg Shah almost 10 years ago

Code Review 0516b

The changes look good. I only have one question: why were the local.set(null); and config = null; removed from reset() in Window.java? There are important use cases that depend on this behavior. For example, when CTRL-C "restarts" the client, the reset is critical.

#38 Updated by Marius Gligor almost 10 years ago

Initially Window class had only the default constructor. The init() method was initially the body of the default constructor.
Default constructor is used to build the DEFAULT_WINDOW which is always first constructed before any other dynamic window.
I added another constructor having a ComponentConfig as parameter to create dynamic windows.

local.set(null); and config = null; should be called only when the DEFAULT_WINDOW is constructed.

If these are called when we create dynamic windows the created DEFAULT_WINDOW is set to null and it does not work properly.
I think that a best idea is to clear also the windowRegistry whenever the DEFAULT_WINDOW is create (default constructor) because the creation of the static window is basically an application initialization.

#39 Updated by Greg Shah almost 10 years ago

I think that a best idea is to clear also the windowRegistry whenever the DEFAULT_WINDOW is create (default constructor) because the creation of the static window is basically an application initialization.

Yes, this is probably correct. Certainly, the idea of Window.reset() is to allow application re-initialization without exiting the JVM client process.

Please confirm that the entire set of Windows are cleared in GUI when the user uses CTRL-C to generate a STOP condition. If so, then this is the right approach.

#40 Updated by Marius Gligor almost 10 years ago

On CTRL-C the entire set of Windows are cleared in GUI.

#41 Updated by Marius Gligor almost 10 years ago

I've implemented a first skeleton version for drawing WINDOW widgets in GUI interfaces.
I attached a picture with the DEFAULT_WINDOW which has been draw on the GUI interface. The entire draw is done using Java 2D drawing primitives.

I have a question here:
As you can see on the attached picture the WINDOW is draw on the content pane of the application which in fact is a JComponent.
Should other windows dynamic created to be draw on the same canvas?
In other words should we consider the content pane as the screen of the application?

#42 Updated by Greg Shah almost 10 years ago

Code Review 0521a

Wow! Very cool. I like it.

Some thoughts:

1. I would like the GUI screen driver to be designed as a superset of the ChUI screen driver. In my mind, this means that the GuiScreenDriver interface would extend ScreenDriver. Perhaps I am linking the two when I should not. I really like the drawing primitives approach you are taking, except I am worried that the drawing primitives approach may be incompatible with a performant AJAX GUI client (my concerns are documented in the notes above).

2. If we take the drawing primitives approach, then it would be best to implement the WindowGuiImpl in terms of these primitives instead of direct drawing. This is especially important in order to have common code for both the Swing and AJAX GUI clients.

3. With your WindowImpl changes, we see the first time that we must design a "fork in the road" for drawing GUI vs ChUI. I would like to take a different approach. Making WindowImpl inherit from WindowGuiImpl is not optimal. It brings in dependencies that don't need to be there for the ChUI case. One would expect that WindowGuiImpl is only for GUI code and later on, if someone edits it and makes GUI-only changes, that may break or change how the ChUI client works. Instead, I prefer one of the following approach:

We create an abstract base class that implements the common drawing code (for both GUI and ChUI). Some classes may have a great deal of common code and others may have very little. This code would have some number of abstract methods upon which it relies for the non-common drawing features. There would be GUI-only and ChUI-only widget drawing classes that are concrete classes that extend that abstract base. For the Window widget, there would be an abstract base class of ui/client/WindowImpl and then the concrete classes would be ui/client/gui/WindowGuiImpl and ui/client/chui/WindowChuiImpl. These concrete drawing classes are sibling classes with no dependencies upon one another. Each widget can be easily implemented in this approach, tailoring the common code/abstract methods as needed. The ScreenDriver would provide a way to instantiate the proper concrete drawing implementation for each widget. This can be hard coded into the ScreenDriver implementations since it would always be the same class.

4. Other comments and answers to your questions:

As you can see on the attached picture the WINDOW is draw on the content pane of the application which in fact is a JComponent.

For the AJAX client, each WINDOW will be a separate canvas. Multiple WINDOW widgets will share the same document, so the document is the "workspace" or "desktop". However, please do consider that we will need to eventually provide support for an alternate mode where each WINDOW can be displayed in its own IFrame/document. This will be needed for integration with other web applications.

For Swing, it is different. We don't want the WINDOW to be drawn on a JComponent inside of a JFrame. There must be no Java frame border, titlebar or decorations.

Should other windows dynamic created to be draw on the same canvas?
In other words should we consider the content pane as the screen of the application?

Not in Swing. Each WINDOW widget must be drawn on its own such that it is a fully independent entity on the graphical desktop. The same trick of eliminating the Java "chrome" of the containing frame must be done for each WINDOW and each one would be an independent JComponent.

#43 Updated by Marius Gligor almost 10 years ago

1. The GuiScreen interface extends ScreenDriver interface.

2. Could you please offer more details? What means "implement the WindowGuiImpl in terms of these primitives instead of direct drawing"?

3. I created distinct factories for widgets ChuiWidgetFactory and GuiWidgetFactory to create widgets.
The widgets factory is a member of screen driver so a ChUI screen driver will use a ChuiWidgetFactory and a GUI screen driver a GuiWidgetFactory.
Window class still contains a lot of ChUI specific code and I'm thinking to fix that.

4. Regarding to draw WINDOW widgets in separate JComponent objects. JComponent is not a top-level container like a JFrame and cannot be moved
outside of it container. For a JFrame it is easily to remove decorations so I think that a possible solution might be to use the JComponent
as a content pane on a JFrame and remove the JFrame decorations. All operations on window like move, resize, etc. should be reimplemented.

#44 Updated by Marius Gligor almost 10 years ago

For ChUI interface the status and message area are implemented as widgets (StatusLine instances)
To keep the compatibility I created GUI widgets for status and message area similar to ChUI version.
Since they are widgets I used the draw method to draw status and message area on the GUI window so the drawing code was moved from GuiWindowImpl
to StatusLineGuiImpl respective MessageLineGui

#45 Updated by Greg Shah almost 10 years ago

Code Review 0522b

It looks good.

2. Could you please offer more details? What means "implement the WindowGuiImpl in terms of these primitives instead of direct drawing"?

This is my mistake. Your WindowGuiImpl is already implemented with the primitives.

Window class still contains a lot of ChUI specific code and I'm thinking to fix that.

Perfect.

JComponent is not a top-level container like a JFrame and cannot be moved

outside of it container. For a JFrame it is easily to remove decorations so I think that a possible solution might be to use the JComponent as a content pane on a JFrame and remove the JFrame decorations. All operations on window like move, resize, etc. should be reimplemented.

Yes, exactly right.

#46 Updated by Marius Gligor almost 10 years ago

The package contains the changes and new classes used to implements CREATE WINDOW statement. So far the following issues were implemented:

A. On the server side:

1. The conversion of CREATE WINDOW statement based on the existing options already defined in P2J project.

2. A new WindowWidget is registered in LogicalTerminal windowRegistry map whenever a new dynamic window is created. Before register an ID is assigned to the new created widget. The ID space for window widgets are shared with the ID for frames widgets.

3. The WindowConfig structure which contains the widget options is pushed down toward the client.

4. No business code was written or changed on the server side.

On the next steps new WINDOW options should be implemented and some business code has to be write.

B. On the client side:

1. The pushed window from the server are registered inside the Window class on the windowRegistry map. An object of type WindowGuiImpl is created and registered for each new window dynamic created. For more details see ThinClient.pushWindow and Window.pushConfig. The DEFAULT_WINDOW which is always created is processed separate of dynamic windows on both server side and client side.

2. I created a GUI screen driver skeleton identified as "swing_gui_frame"

3. On the GUI screen driver I designed and implemented a drawing engine based on Java 2D graphical primitives. The goal of the engine is to allow the drawing of GUI widgets based on graphical primitives (lines, rectangles, texts, font, colors).

4. So far only the WINDOW widget is started to be implemented. For WINDOW widgets a simple draw method is implemented which allow the drawing of the window having a title bar a status bar and a message area. On the title bar the three window buttons are draw an icon and the title text as a string.

5. The status and the messages area are implemented as widgets on ChUI interface. I designed and implemented GUI versions for these widgets having their own drawing methods.

6. The window is drawing on a JComponent which is the content pane of a JFrame. The JFrame is an undecorated and the window will looks like on the attached picture. The screen driver provide services to resize and change the location of window. Because in GUI multiple window exists I started to implements a window selection mechanism inside the screen driver.
Inside SwingGuiPrimitives a Map (renderers) is used to register the window canvases of each window based on the window ID. Before any drawing operation on a window a selectWindow with window ID as parameter must be called in order to select the appropriate canvas.

7. No business code was written or changed on the client side.

The current implementation is far from end and on the next steps at least the following issues should be implemented:

- Multiple windows management on the business code and on the drawing part.
- Integrate window widgets inside the existing business code.
- Improve the window drawing when new options will be added.
- Implements mouse and keyboards events handling for windows.
- Layout other widgets inside the window which depends on the GUI implementation for widgets.

#47 Updated by Marius Gligor almost 10 years ago

Merged with the latest P2J updates (rules files).

#48 Updated by Greg Shah almost 10 years ago

Code Review 0602a

The code looks good. There are a few files that are missing the standard headers and so forth, but that is not a big deal. I will take this update and enhance it from that starting point.

#49 Updated by Constantin Asofiei almost 10 years ago

Related to fonts: I've managed to find the formula used by 4GL to compute the pixels-per-row and pixels-per-column. It relies on the height and averageWidth of a font (supplied by the gdi32 getTextMetrics function) this way (formula's are excel-like):
  1. if Use-3D-Size=No, then the formula is PIXELS-PER-ROW = font-height + int(font-height/2.0) and PIXELS-PER-COLUMN=font-avg-width.
  2. if Use-3D-Size=Yes, then the formula is PIXELS-PER-ROW = font-height + int(font-height/2.0) + 2 and PIXELS-PER-COLUMN=font-avg-width.

where font-height and font-avg-width are the TEXTMETRIC.tmHeight and TEXTMETRIC.tmAveCharWidth, from the structure returned by getTextMetrics. The attached document shows that the formula is correct: it checks font size from 1 to 100, for MS Sans Serif, Courier New and Segoe UI. Use-3D-Size is a setting in the progress.ini file.

These formulas can be used to make sure all the layout/positioning is proportional to how 4GL does it. Unfortunately, there is a problem: I can't find a way for the Java AWT's FontMetrics (built from a Graphics object or other ways) to return at least the same font height, as the gdi32's getTextMetrics. I think this is because AWT/Swing doesn't allow scaling on the system's DPI; while the OS's DPI is usually 96dpi for 100%, the Java's DPI is internally hard-coded to 72dpi; scaling the font size to the system's DPI might work, but I'm not finished investigating/testing this.

#50 Updated by Constantin Asofiei almost 10 years ago

About fond rendering: no useful info found in Java FX or a way to switch the font rasterizer. More, the metrics are not even the same across JRE implementations: OpenJDK and Oracle show complete different results.

Only for the Courier New and Segoe UI scaling from Java metrics to sys metrics looks stable across characters/texts, but MS Sans Serif is a PITA, for the avg text width... can't find an appropriate scale which would survive the I and M tests. And something else weird about MS Sans Serif: in 4GL, anti-aliasing is not enabled for this font.

The major problem here are sizes or coordinates given in pixels, in the legacy code: we will need to hard-code in the directory the metrics for each font configuration, from the legacy machine on which the code was ran. If we have this, then:
  1. all legacy fonts are automatically scaled, using a legacy metric/java metric scale. I think we can go one step further here, for width: when drawing text, scale using the text as reference, by scaling the font width using legacy width/real width of this text.
  2. pixel coordinates/sizes are transformed to character units using the legacy metrics, and back to real pixels, using the java metrics.

Unfortunately, this will mean that font choosing via the font dialog will be restricted only to fonts for which their legacy metrics is known...

#51 Updated by Greg Shah almost 10 years ago

The results are unfortunate but understandable.

the metrics are not even the same across JRE implementations: OpenJDK and Oracle show complete different results.

The two distributions have diverged in regard to the font rasterizer. The Oracle JVM always used a proprietary font rasterizer and I think they replaced it with an open source version (Freetype?) in OpenJDK. Likewise, there can be embedded fonts that are included with a JDK. These fonts might differ from system fonts of the same name.

we will need to hard-code in the directory the metrics for each font configuration, from the legacy machine on which the code was ran

Please write a program that can inspect and dump these values from a legacy system. Is it sufficient to write a 4GL program that uses FONT-TABLE:GET-TEXT-WIDTH-PIXELS and FONT-TABLE:GET-TEXT-HEIGHT-PIXELS?

Unfortunately, this will mean that font choosing via the font dialog will be restricted only to fonts for which their legacy metrics is known..

Understood.

#52 Updated by Constantin Asofiei almost 10 years ago

Greg Shah wrote:

Please write a program that can inspect and dump these values from a legacy system. Is it sufficient to write a 4GL program that uses FONT-TABLE:GET-TEXT-WIDTH-PIXELS and FONT-TABLE:GET-TEXT-HEIGHT-PIXELS?

No, these will not help, one reasone being that GET-TEXT-WIDTH-PIXELS works with a string; the other is that we need the actual metrics used to compute the PIXELS-PER-COLUMN/ROW values. Invoking the getTextMetrics API from 4GL works fine, produces same results as my previous tests (documented in font stats - v2.ods).

I'm thinking to build an XML file with the nodes like this:

<font name="MS Sans Serif" size="10" bold="true/false" italic="true/false" underline="true/false" avgwidth="x" height="y"/>

where size can vary from 1 to 1638 (max font size). I will let the list of font names to be read from an external file, one-per-line, as in:
MS Sans Serif
Courier New
Segoe UI

#53 Updated by Greg Shah almost 10 years ago

OK. Automate the generation as much as is reasonable. Include any information needed for the FONT-TABLE to be configured as well (e.g. font to font number mappings). At runtime, we can read the font configuration XML file out of the application jar, instead of putting the information into the directory. If it doesn't exist, we can include a default configuration that matches Progress' default on a common Windows platform.

#54 Updated by Constantin Asofiei almost 10 years ago

I've added these files to the testcases repo:
  1. uast/fonts/system-metrics/font-list.txt - list of fonts standard fonts; currently, it includes the 4GL standard fonts - MS Sans Serif and Courier New, plus Segoe UI, the standard font for Windows 7. I can't find easily the standard font for other windows versions, or a way to pragmatically determine the OS's dfefault fonts.
  2. uast/fonts/system-metrics/font-metrics.xml - the metrics obtained from windev01, as described in note 52.
  3. uast/fonts/system-metrics/get-font-metrics.p - the program used to obtain the metrics (uses font-list.txt as input and font-metrics.xml as output).

Greg Shah wrote:

Include any information needed for the FONT-TABLE to be configured as well (e.g. font to font number mappings).

About the FONT-TABLE: my feeling is that 4GL doesn't allow access to the font details (name, size, etc). The only way I found to obtain some details is to use the SYSTEM-DIALOG FONT statement: this will automatically select the font settings for the specified ordinal, and show them to the user. But passing them back to the program or allowing the program to know them - I don't think is possible.

Something else I have a feeling it will be a PITA: as I noted before, MS Sans Serif is somehow special, scaling the font's width using legacy avgwidth/java avgwidth will not produce correct results always, when real text is drawn. And my idea to scale the font using legacy txt width/java txt width is not feasible: legacy txt width is not the same as legacy-avg-width * text-length, and we will not be able to compute the legacy txt width using native APIs, to obtain the txt length as on the legacy system.

#55 Updated by Constantin Asofiei almost 10 years ago

Greg Shah wrote:

Include any information needed for the FONT-TABLE to be configured as well (e.g. font to font number mappings).

About the FONT-TABLE: my feeling is that 4GL doesn't allow access to the font details (name, size, etc). The only way I found to obtain some details is to use the SYSTEM-DIALOG FONT statement: this will automatically select the font settings for the specified ordinal, and show them to the user. But passing them back to the program or allowing the program to know them - I don't think is possible.

Nevermind, my bad, I missed the get-key-value and setput-key-value statements which affect the environment.

#56 Updated by Greg Shah almost 10 years ago

To be clear, I don't plan to provide any support that the 4GL doesn't already provide. For compatibility purposes, we must know the exact list of the font ordinals and how they map to the original system's fonts. That is what I mean by the "FONT-TABLE to be configured".

Something else I have a feeling it will be a PITA: as I noted before, MS Sans Serif is somehow special, scaling the font's width using legacy avgwidth/java avgwidth will not produce correct results always, when real text is drawn.

Could Windows (or the 4GL) be mapping this as a "generic" sans-serif font that is actually different fonts depending on size and attributes?

#57 Updated by Constantin Asofiei almost 10 years ago

Greg Shah wrote:

Could Windows (or the 4GL) be mapping this as a "generic" sans-serif font that is actually different fonts depending on size and attributes?

The problem with MS Sans Serif is that this is a bitmap font, and Java2D does not support bitmap fonts. If the font can't be found, Java defaults to the Dialog font - that's why the text metrics weren't matching. Don't know how we can get past this - we might need to implement our own font renderer, for bitmap fonts...

#58 Updated by Constantin Asofiei almost 10 years ago

To be clear, I don't plan to provide any support that the 4GL doesn't already provide. For compatibility purposes, we must know the exact list of the font ordinals and how they map to the original system's fonts. That is what I mean by the "FONT-TABLE to be configured".

There is a catch here: we need to keep in mind that the font table may vary with the system where the application is deployed... If we know for sure that all used fonts are defined explicitly via a progress.ini/registry keys (i.e. 4GL-specific settings), and these are setup properly when the application is installed, then things are easy: we have only one place were to look. I have an app which reads the font table from the default environment and from default registry keys, but in the end this depends on how LOAD is used throughout the application... and considering that new fonts can be added dynamically via PUT-KEY-VALUE and there is another unknown related to the default OS fonts, I don't think there is a way to determine 100% "these are the fonts used", unless we dig into the application code + configuration files, and check how the fonts are managed.

Some answers for the questions at note 12:

If the mappings in the FONT-TABLE change, when do the changes become visible to the user? (Immediately, the next time the affected controls are redrawn, never...?)

This depends how the environment is changed: if it is via SYSTEM-DIALOG FONT, then the affected widgets using the target environment are updated immediately. Same, if the font attribute is changed, the widget is redrawn immediately. PUT-KEY-VALUE will not affect the font-table.

Do different controls handle dynamic font changes differently?

They all look to behave the same: when their explicitly-set font entry is changed (via system-dialog font), the widgets are redrawn. But they will not be resized until their font attribute is changed.

The SYSTEM-DIALOG FONT allows the user to change a specified entry in the FONT-TABLE. The 4GL docs suggest this is the only way to edit this table, but it also seems like the "environment" (as dynamically set by LOAD/USE) can be used to dynamically load/save the FONT-TABLE (using PUT-KEY-VALUE and GET-KEY-VALUE). This suggests that the 4GL programmer can dynamically load the entire table at any time. Is that right?

Each window has its own environment, the default one or an explicit one, via LOAD/USE. The font-table in that environment can be changed only via SYSTEM-DIALOG FONT. PUT-KEY-VALUE will not be able to change existing fonts in the environment, only add new ones - and even the new ones are not visible by the window's font-table until the environment is reloaded... PUT-KEY-VALUE behaviour is pretty strange, when fonts are involved. I think when talking about fonts, things are split in at least two parts:
- an environment related to the window, with which PUT-/GET-KEY-VALUE works.
- a font-table (associated with one or more windows), which is maintained by SYSTEM-DIALOG FONT and is not affected by PUT-/GET-KEY-VALUE, but updates the environment, when it gets changed. This font-table includes the default fonts, too, but these will not be updated if a window is created with another environment.

Does changing the environment cause the font table to be reloaded implicitly or does one have to use GET-KEY-VALUE to read it in?

LOAD/USE do not affect the current window, only future windows. Also:
  1. once the environment is updated, it will need a PUT-KEY-VALUE FONT[#|ALL] to persist the environment.
  2. when a new window is created, its configuration is used computed from the latest activated environment (via USE).

Does the loading of the font table really end at the first font<num> that is not configured?

There is a catch here, again: the environment will see all the font# keys, but the font-table will keep reading from 0 to 255 and stop on the first missing font# key.

Is SYSTEM-DIALOG FONT using the WIN32 ChooseFont (http://msdn.microsoft.com/en-us/library/windows/desktop/ms646958%28v=vs.85%29.aspx) for its implementation?

Yes

Does the 4GL support fonts in different colors?

Yes

Can the DefaultFont, DefaultFixedFont, PrinterFont, PrinterFont1, PrinterFont2 and PrinterFont3 be changed by LOAD/USE...?

Per docs (and testing for DefaultFont/DefaultFixedFont), LOAD/USE work only with colors and fonts sections, but:
- PUT-KEY-VALUE can change them and the changes can be persisted.
- the changes will not end up in the font-table until the client is restarted.

Some other notes:
  1. system-dialog font
    - changes the font immediately, for the font-table associated with the default window or the explicitly targeted window (affects all windows using that font-table).
    - does not update the value reported by get-key-value. only when put-key-value font [#|all] is called, the value will be updated.
  2. put-key-value
    - put-key-value will not change the runtime font-table - only system-dialog font does it.
    - new fonts can be added, but they will not be seen in the font-table until the environment is refreshed.
    - put-key-value font [#|all]. will actually save the font-table; changes to existing fonts via put-key-value will be discarded (I think this is because the FONT-TABLE is actually persisted to the environment).
  3. get-key-value
    - this will report the last value set by put-key-value, even if this is not the same as the one set by system-dialog font.
    - when the values are refreshed via put-key-value font, then the it will start reporting the correct value (the value will not be persisted by put-key-value).
    - I think this means that system-dialog font pushes the font to the font-table, too, while put-key-value will push it only in the current environment.
  4. load/use
    - work only with font or color sections.
    - default fonts can't be changed.
    - current window(s) are not affected by load/use - only the next created window will be affected.
  5. font attribute:
    - when changed, the widgets are redrawn immediately

#59 Updated by Greg Shah almost 10 years ago

For #2229, I have started a set of testcases to explore the behavior and features of the GUI multi-window environment. The basic idea is to explore how the target window is chosen implicitly or explicitly for various 4GL language features.

I will note my current results below. All of these results have been found with the testcases that I have checked in to testcases/uast/window_parenting/. You must run these on windev01. Open a command prompt and run this: prowin32 -p .\window_parenting\test_runner.p. It is required that you put all of those testcases in that sub-directory of your windev01 home dir. You will be able to read the log in the window_parents.log of your home directory.

As much as possible, I tried to make these tests non-interactive. Unfortunately, for some of the tests (e.g. msg_and_status_targeting_*.p) there is no way other than to make some interactive parts. Please read the source carefully and ask any questions as needed. I tried to put comments there to explain the behavior I found.

I left off in the status_targeting_with_no_status_line.p program. I just started that test and it is just some copied template code. So that is the place to pick this up and continue.

Findings

1. When the 4GL starts, the initial system handle window values (CURRENT-WINDOW, DEFAULT-WINDOW and ACTIVE-WINDOW) are all the same.
2. The initial value of THIS-PROCEDURE:CURRENT-WINDOW is unknown value.
3. CREATE WINDOW my-window-handle does not change CURRENT-WINDOW, THIS-PROCEDURE:CURRENT-WINDOW, DEFAULT-WINDOW or ACTIVE-WINDOW.
4. VIEW my-window-handle does not change CURRENT-WINDOW, THIS-PROCEDURE:CURRENT-WINDOW, DEFAULT-WINDOW or ACTIVE-WINDOW.
5. DELETE WIDGET my-window-handle does not change CURRENT-WINDOW, THIS-PROCEDURE:CURRENT-WINDOW, DEFAULT-WINDOW or ACTIVE-WINDOW.
6. Before realization (the first VIEW) of a frame, the FRAME my-frame:PARENT is unknown value.
7. After realization (the first VIEW) of a frame, the FRAME my-frame:PARENT is assigned either implicitly or explicitly.
8. Any attempt to assign the FRAME:PARENT attribute after realization will generate a message **Unable to set attribute PARENT for FRAME f0. (4078), but an ERROR condition is not raised.
9. Even after using HIDE on a frame or frame:VISIBLE = false or frame:HIDDEN = true, you still cannot assign FRAME:PARENT. The result is the same message (but not error) as in 8 above.
10. If you don't change CURRENT-WINDOW, THIS-PROCEDURE:CURRENT-WINDOW or otherwise explicitly assign the parent of a frame (using FRAME:PARENT or IN WINDOW), then the targeted window will really be the DEFAULT-WINDOW.

I need to pause for a bit. More findings and the list of open questions will be posted next.

#60 Updated by Greg Shah almost 10 years ago

The Progress documentation suggests the following precedence order for window targeting (please note that I have already found this is not entirely accurate, see 11 and 12 below):

1. Use of an explicit window parenting specification should take highest precedence. There are 2 possible ways to do this: the IN WINDOW clause and the use of the FRAME:PARENT attribute.

2. If not explicitly specified, but the THIS-PROCEDURE:CURRENT-WINDOW attribute is set at the time of frame/widget realization, then that will be the implicit window targeted. (This has been found to not always be true.)

3. If THIS-PROCEDURE:CURRENT-WINDOW is not set, the value for CURRENT-WINDOW at the time of frame/widget realization is used. If CURRENT-WINDOW has not been assigned for this session, then it will have the same value of DEFAULT-WINDOW.

The FRAME:PARENT can only be used with frames but IN WINDOW can be used with the following language statements:

CHOOSE
COLOR
DEFINE FRAME
DISPLAY
DO
DOWN
ENABLE
FOR
FORM
HIDE
INSERT
MESSAGE
NEXT-PROMPT
PAUSE
PROMPT-FOR
SCROLL
SET
STATUS
SYSTEM-DIALOG-*
UNDERLINE
UP
UPDATE
VIEW

Most of these are from the inclusion of a FRAME_PHRASE in their syntax. Please note that one UI statement which is documented as NOT supporting IN WINDOW is the DISABLE statement.

#61 Updated by Greg Shah almost 10 years ago

More Findings

11. MESSAGE statement window targeting:

For both a regular MESSAGE statement and the MESSAGE VIEW-AS ALERT-BOX, when the targeted window is already realized, the documented precedence order is honored. To summarize from most to least precedence: IN WINDOW, THIS-PROCEDURE:CURRENT-WINDOW, CURRENT-WINDOW, DEFAULT-WINDOW.

When the targeted window is NOT already realized, the behavior changes. The DEFAULT-WINDOW is always implicitly realized when needed, so behavior that depends on that will work fine. But when CURRENT-WINDOW is assigned a handle to a window that is not realized OR an IN WINDOW clause targets such an unrealized window, the regular MESSAGE statement output is lost (does not appear anywhere, including the DEFAULT-WINDOW). The MESSAGE VIEW-AS ALERT-BOX does appear in these same cases, however the user must "click in" to the message box first before then actually pressing the button on the dialog. Some additonal testing needs to be done with THIS-PROCEDURE:CURRENT-WINDOW (see below) in this unrealized case.

12. PAUSE and STATUS statement window targeting:

When targeting a realized window, the documented precedence order is honored EXCEPT that THIS-PROCEDURE:CURRENT-WINDOW is ignored.

When the targeted window is NOT already realized, the behavior changes. The DEFAULT-WINDOW is always implicitly realized when needed, so behavior that depends on that will work fine. But when CURRENT-WINDOW is assigned a handle to a window that is not realized OR an IN WINDOW clause targets such an unrealized window, the STATUS and PAUSE statement output is lost (does not appear anywhere, including the DEFAULT-WINDOW). Some additonal testing needs to be done with THIS-PROCEDURE:CURRENT-WINDOW (see below) in this unrealized case.

13. HELP output for a widget targets the window in which the containing frame is targeted. There is still an open question about this below.

Open Questions

  • The current msg_and_status_targeting.p needs changes to better test the behavior of STATUS and PAUSE when THIS-PROCEDURE:CURRENT-WINDOW is assigned but CURRENT-WINDOW is NOT assigned.
  • The current msg_and_status_targeting_non_realized_window.p needs changes to better test the behavior of STATUS, PAUSE, MESSAGE and MESSAGE VIEW-AS ALERT-BOX when the CURRENT-WINDOW is assigned to an unrealized window when THIS-PROCEDURE:CURRENT-WINDOW is also assigned to an unrealized window. It also needs to be tested with CURRENT-WINDOW is assigned to the DEFAULT-WINDOW when THIS-PROCEDURE:CURRENT-WINDOW is assigned to an unrealized window.
  • What happens to MESSAGE statement output when there is no message line in the targeted window?
  • what happens to MESSAGE statement output when the terminal is redirected but the specific MESSAGE statement is targeted at a window using something like IN WINDOW?
  • What happens to STATUS statement output when there is no status line in the targeted window?
  • What happens to PAUSE statement output when there is no status line in the targeted window?
  • What happens to HELP output when there is no status line in the targeted window?
  • The documented precedence order needs to be proved/tested using statically created frames (DEF FRAME, FORM, DISPLAY), dynamically created frames (CREATE FRAME). This should be tested for both dialog (VIEW-AS DIALOG-BOX in frame phrase) and non-dialog frames.
  • Test these same static/dynamic frame cases with unrealized windows.
  • Test these same static/dynamic frame cases with an invalid window (e.g. CURRENT-WINDOW assigned to a Window that was already DELETEd).
  • Can you reparent a realized FRAME to a different window using IN WINDOW?
  • If you use both FRAME:PARENT and IN WINDOW and these conflict, what happens? This is similar to the last question, except this should test what happens before the frame is realized.
  • If you have multiple IN WINDOW clauses and they conflict, what happens?
  • If you have multiple FRAME:PARENT assignments and they conflict, what happens?
  • Is IN WINDOW really not allowed in DISABLE?
  • Is there any kind of scoping or stacking of the CURRENT-WINDOW system handle? For example, if you assign CURRENT-WINDOW in an internal procedure/external procedure/trigger/function and then exit scope, does anything change?
  • Is THIS-PROCEDURE:CURRENT-WINDOW really specific to the current procedure (and has no effect on the calling procedure)?
  • Does THIS-PROCEDURE:CURRENT-WINDOW have any effect on procedures that are called once it is set?
  • The Progress docs suggest that there is some way to implicitly set CURRENT-WINDOW. I haven't yet found any way to do this.
  • Can you apply ENTRY to a specific window to force a different ACTIVE-WINDOW?

#62 Updated by Constantin Asofiei almost 10 years ago

I have some bad news... width for TEXT/FILL-IN widgets is computed via the avg-font-width, but for BUTTON, is computed via the real text width, using the specified font... I think we are out of luck with this one, we will need to use native APIs to compute the font metrics.

#63 Updated by Greg Shah almost 10 years ago

I had not planned to require P2J to be running on a Windows OS in order to run the converted system. It would be a really bad limitation. For example, we would not even be able to test/develop outside of Windows.

Please consider alternatives. For example, most buttons will only ever have a small number of possible labels (often only 1). We can determine this size statically and store it as part of conversion. Such a solution is not great, but it is far better than requiring the P2J client for any GUI code to always run on Windows.

#64 Updated by Constantin Asofiei almost 10 years ago

Greg Shah wrote:

For example, most buttons will only ever have a small number of possible labels (often only 1). We can determine this size statically and store it as part of conversion. Such a solution is not great, but it is far better than requiring the P2J client for any GUI code to always run on Windows.

Yes, a solution would be to collect all strings from the application and compute/save their size in an external file; but dynamic strings will need to be manually specified. I will continue my analysis to finish the size formulas for all widgets.

#65 Updated by Greg Shah almost 10 years ago

#2323 is a task to implement support for GUI coordinate processing. Currently the implementation is hard coded to ChUI mode which is character (row/column) coordinates.

Interestingly, (as noted above and in #2322) the 4GL actually still uses character units in GUI. Of course, the character units are not necessarily whole numbers (ChUI always uses whole numbers), but instead decimal units are used. These units are based on the font metrics and ultimately must be translated to pixels to be used in the native coordinate system. I'm simplifying greatly here, but this is just meant to be a summary.

The following is a list of known places that have coordinate system processing (it is not necessarily an exhaustive list):

ScrollContainer (heavy usage)
ScrollPane (uses coordinates but is a bit simpler)
Frame
*Config (any coordinate usage should probably be moved out)
ThinClient
ZeroColumnLayout

The basic idea is to find places where there is coordinate processing, and refactor the usage into separate classes shielded by an abstraction layer (an interface). This may possibly be implemented at run-time in the ChUI/GUI drivers or in utility classes. The bottom line is our objective is to implement a common interface abstracting the separate ChUI and GUI implementations. If possible, let's implement this processing in common for all ChUI drivers and a separate implementation in common for all GUI drivers. In GUI, the low level driver implementations will probably have to provide some amount of implementation-specific support (e.g. font metrics).

#66 Updated by Constantin Asofiei almost 10 years ago

The uast/fonts/font_details.odt contains details about how the widget metrics are computed; the main notes are:
  • we will need to determine which font is best to set for the frame title case, as this is dependent on Windows OS: Windows Color Scheme, the Active Window settings.
  • we will need a custom renderer for bitmap fonts (Java does not support them)
  • P2J will need to know the original metrics for all fonts and for all string literals used in a frame (as widget labels, static text, button's label, etc).
  • FILL-IN/TEXT widgets are a PITA when no explicit font is used: the width is greater than the normal case (when an explicit font is set, even if the explicit font is the same as the default font); we need to determine how this is computed, and at this time I'm out of ideas; the collected metrics just don't make sense (they are in the .ods files, in uast/fonts/widget.metrics/implicit.withdefault.* if someone wants to take a crack at it). This formula might be the same as the formula used to compute the width needed for the frame's title... which is an unknown at this time, too. Note that the metrics for the TEXT widget are from a <var> VIEW-AS TEXT definition, not with static text.
  • when testing the metrics for a certain widget (by hand), use the BGCOLOR to hightlight that specific widget; else, it's background is the same as the frame's and it can get confusing.

Some notes about how the metrics were collected. As 4GL does not allow updating the font-table automatically, while the client is running (I couldn't find a way, regardless what the official docs state: PUT-KEY-VALUE does not set the font in the FONT-TABLE), I chose a different approach: I've used a template progress.ini file and an associated batch program; this batch program will go through some metrics (i.e. font size, rows, columns) and for each case, will read the template, replace the appropriate strings, and generate a progress.ini file, valid for that metrics. After this, the 4GL program (which collects the metrics and writes them to a file) is ran. Metrics were collected for the abcdefg, iiiiiii and mmmmmmm strings, for each tested widget font, in 3D and no-3D cases.

Also, the uast/fonts/system.metrics/get-text-metrics.p and uast/fonts/system.metrics/get-font-metrics.p programs can be used to collect the metrics for specified fonts or strings. It uses native win32 API calls to determine them.

#67 Updated by Greg Shah almost 10 years ago

I read the uast/fonts/font_details.odt. Clearly there are still some tricky parts to figure out.

If I understand things correctly, a dependency we will have will be that the fonts on which an application depends will have to be installed on the client system that is being used. Correct?

I'm still trying to figure out how we would handle this for the web client case. We may need "assistance" from the Java code (which should be common code for implementing GUI anyway).

In regard to Java bitmap font rendering, there is this (uses the Apache 2.0 license):

https://github.com/libgdx/libgdx

FYI, the example images did not make it into the .ods document (there was text referencing the images but I didn't see any corresponding pictures).

#68 Updated by Constantin Asofiei almost 10 years ago

Greg Shah wrote:

If I understand things correctly, a dependency we will have will be that the fonts on which an application depends will have to be installed on the client system that is being used. Correct?

Not necessarily. Java allows loading fonts at runtime, which are not necessarily known to the OS; if we do this, we have more control over which fonts are used by the application.

I'm still trying to figure out how we would handle this for the web client case. We may need "assistance" from the Java code (which should be common code for implementing GUI anyway).

If P2J has access to the font files, then it's just a matter of importing the fonts via CSS (and exposing the fonts via the web browser). There is the font-face rule in CSS3.

In regard to Java bitmap font rendering, there is this (uses the Apache 2.0 license):

https://github.com/libgdx/libgdx

Thanks, my search terms were way off from the keywords used to describe this library.

FYI, the example images did not make it into the .ods document (there was text referencing the images but I didn't see any corresponding pictures).

Do you have rev 1159? I know rev 1158 of this file was missing the images, rev 1159 looks OK on my side.

#69 Updated by Greg Shah almost 10 years ago

Do you have rev 1159? I know rev 1158 of this file was missing the images, rev 1159 looks OK on my side.

Yes, I was looking at the wrong version.

#70 Updated by Greg Shah over 9 years ago

This is a cleaned up/enhanced version of the mag_upd20140602a.zip. It includes the following:

1. Everything has history entries and some cleaned up formatting and minor fixes.

2. I have eliminated the ui/ContainerConfig and ui/ContainerEntity classes that were in between PaneConfig/PaneEntity and FrameConfig/FrameWidget. There was no other class inheriting or using those classes so the code is now merged.

3. I rationalized all the color attribute names to match our naming standards.

[gs]etDcolor            -> [gs]etDColor
[gs]etPfcolor           -> [gs]etPfColor
[gs]etColumnDcolor      -> [gs]etColumnDColor
[gs]etColumnPfcolor     -> [gs]etColumnPfColor
[gs]etLabelDcolor       -> [gs]etLabelDColor
[gs]etTitleDcolor       -> [gs]etTitleDColor
[gs]etFgcolor           -> [gs]etFgColor
[gs]etBgcolor           -> [gs]etBgColor

This caused one MAJIC change (the 0627b update) for LoginClient.java.

I'm going to conversion regression test this.

Constantin: If that works properly, then I'll need a code review.

#71 Updated by Greg Shah over 9 years ago

Conversion regression testing for MAJIC has passed. There are some expected modifications (a copyright notice and the setDcolor() change to setDColor()), but everything looks good.

Constantin: please do a code review. I will make any final changes based on your feedback and then go into full testing.

#72 Updated by Greg Shah over 9 years ago

Also please note that the 0627a is up to date with bzr revision 10560 (the p2j tips as of this writing).

#73 Updated by Constantin Asofiei over 9 years ago

Greg Shah wrote:

Constantin: please do a code review. I will make any final changes based on your feedback and then go into full testing.

The changes look good. Note that some of the font-related code (FontSize class, SwingGuiPrimitives.getFontSize, and others) will need some refactoring, considering the font-related changes I'm doing now. The idea is: current code is using real Java font metrics when computing window dimensions; this needs to be adjusted, to use the same metrics as 4GL, plus eventually the rows and columns settings from the current environment.

#74 Updated by Constantin Asofiei over 9 years ago

Greg, I'm confused by the window_float2.png and window.png cases; in the end, what is the window policy with the GUI client, to emulate 4GL's MDI approach: will the legacy windows have as parent a Java canvas (from which they can not escape), or each window will be a Swing frame?

#75 Updated by Greg Shah over 9 years ago

will the legacy windows have as parent a Java canvas (from which they can not escape), or each window will be a Swing frame?

The window.png was just an early screenshot that was not the needed approach.

The window_float2.png is a newer example that is in line with the correct approach:

  • each window is a separate JFrame that has no decorations
  • each JFrame will have a canvas child that covers the entire JFrame parent
  • the canvas will have the window elements and decorations rendered and managed by our code to duplicate the look and feel of the 4GL windows

#76 Updated by Greg Shah over 9 years ago

All the changes have passed both conversion and runtime regression testing.

The P2J changes are checked into bzr as revision 10563. Refs #2286 and #2252.

The MAJIC change is checked into the staging branch of /opt/secure/code/majic_repo/majic.git on devsrv01.

LE: Some files were found to be missing (com.goldencode.p2j.ui.client.gui.*), they have been added in revision 10564.

#77 Updated by Greg Shah over 9 years ago

Here are some initial findings and open questions for #2333:

  • I have not found any way to make a 4GL window have the status area be larger than 1 line.
  • The window widget has a STATUS-AREA logical attribute that is read/write. Supposedly, if this is set FALSE before the window is realized, then there will be no STATUS-AREA present in the window.
  • The window widget has a STATUS-AREA-FONT integer attribute that is read/write. This allows programmable control over the font used, based on an integer index in the current FONT-TABLE for that window. Changes to this attribute are supposedly dynamically honored.
  • The status line is documented to be limited to 63 characters in the 4GL. In ChUI, we have found this limit to be correct. Our implementation truncates status line output in the Window class itself (it should probably be in the status line widget).
  • By default, the bottom right corner of the status area will have a kind of "grippy" set of diagonal lines that seems to indicate that the window can be resized. This grippy thing can disappear when the window has wide content that is positioned on the last row.

Questions:

  • Does setting STATUS-AREA to false before window realization really cause the status area to be missing for that window?
  • Is there any way to make the window "unrealized" once it has been VIEWed (for the purposes of removing the status area)?
  • Is there an error or other behavior that occurs when STATUS-AREA is set while the window has already been realized?
  • How does the STATUS-AREA attribute behave on ChUI?
  • How does the 4GL choose the default font used when the STATUS-AREA-FONT is not assigned? (inherited from containing window, system default, 4GL default...)
  • What does the 4GL report for STATUS-AREA-FONT by default? Is it unknown value or does it actually reflect the default value being used?
  • Are changes to the STATUS-AREA-FONT honored dynamically/immediately?
  • Does GUI implement the same 63 character limit for the status area?
  • How does the status area handle text that is less than 64 characters but which is too long to display (based on the font being used)?
  • Investigate the "grippy" purpose, behavior and the cases when it can go away.

#78 Updated by Greg Shah over 9 years ago

#2333 and #2334 do not need to address how the proper status/message lines are targeted in a GUI (multi-window) environment. That issue will be addressed as part of #2229.

#79 Updated by Greg Shah over 9 years ago

Here are some initial findings and open questions for #2334:

  • I have not found any way to make a 4GL window have a height that not 2 lines.
  • The MESSAGE-LINES built-in function (which does not take parenthesis, so it looks like a global variable) always reports 2 even when more than 2 lines of output have been made in GUI (see below about the "spinner" behavior and the buffering that occurs).
  • MESSAGE-LINES can be "assigned" a different value (e.g. MESSAGE-LINES = 5.) but it has no effect. The actual height of the message lines does not change. There is no 4GL error or other indication of a problem. The MESSAGE-LINES "function" continues to report 2.
  • The window widget has a MESSAGE-AREA logical attribute that is read/write. Supposedly, if this is set FALSE before the window is realized, then there will be no message area present in the window.
  • The window widget has a MESSAGE-AREA-FONT integer attribute that is read/write. This allows programmable control over the font used, based on an integer index in the current FONT-TABLE for that window. Changes to this attribute are supposedly dynamically honored.
  • Although only 2 message lines of output are visible at a time in GUI, when more than 2 lines of message output have been shown, the message area will have a set of "spinner buttons" on the far right side. Use of those buttons allows the display of previously shown messages. When 2 or fewer message lines have been output, the spinner buttons are not present.

Questions:

  • Does setting MESSAGE-AREA to false before window realization really cause the message area to be missing for that window?
  • Is there any way to make the window "unrealized" once it has been VIEWed (for the purposes of removing the message area)?
  • Is there an error or other behavior that occurs when MESSAGE-AREA is set while the window has already been realized?
  • How does the MESSAGE-AREA attribute behave on ChUI?
  • How does the 4GL choose the default font used when the MESSAGE-AREA-FONT is not assigned? (inherited from containing window, system default, 4GL default...)
  • What does the 4GL report for MESSAGE-AREA-FONT by default? Is it unknown value or does it actually reflect the default value being used?
  • Are changes to the MESSAGE-AREA-FONT honored dynamically/immediately?
  • Does GUI implement the same word wrapping/line break beahvior for the message area as seen in ChUI?
  • Does any word wrapping behavior in GUI detect its wrapping based on sizing from the font being used?
  • Is there a limit to the buffer size for previously shown messages?
  • If there is such a buffer limit, do the oldest messages just "scroll" out of the buffer when it is full?
  • Is there any difference in message area behavior in GUI when the "terminal" is redirected? Remember that the message area in ChUI can be made to output to both the screen and to a redirected file (it is a strange behavior). Make sure that this is checked using both the DEFAULT-WINDOW and CURRENT-WINDOW to ensure that the multi-window behavior of GUI doesn't confuse this testing.

#80 Updated by Vadim Gindin over 9 years ago

I've made some additional tests for STATUS, PAUSE, MESSAGE, MESSAGE VIEW-AS ALERT-BOX statements. Here are what I found.
1) STATUS and PAUSE MESSAGE and HELP statements using status line of the window itself and MESSAGE statements used the area at the bottom of the window.
2) PAUSE MESSAGE uses CURRENT-WINDOW not THIS-PROCEDURE:CURRENT-WINDOW. FOCUS management operates CURRENT-WINDOW.
3) You wrote that I should test the situation when CURRENT-WINDOW is not set, but THIS-PROCEDURE:CURRENT-WINDOW is set. I didn't find a way to do so, because CURRENT-WINDOW always has a value.
4) The case with question 2 about DEFAULT-WINDOW and THIS-PROCEDURE:CURRENT-WINDOW pointing to unrealized window behaves predictable. There are no window displayed at all and only alert box was appeared.
Did I miss something?
Going further with the next open questions.

#81 Updated by Greg Shah over 9 years ago

3) You wrote that I should test the situation when CURRENT-WINDOW is not set, but THIS-PROCEDURE:CURRENT-WINDOW is set. I didn't find a way to do so, because CURRENT-WINDOW always has a value.

What I meant was to test this case:

CURRENT-WINDOW DEFAULT-WINDOW and THIS-PROCEDURE:CURRENT-WINDOW some_other_real_window

#82 Updated by Vadim Gindin over 9 years ago

I've added some tests for the questions about MESSAGE, STATUS, PAUSE statements without status line, message line or for redirected output. Here are results.
4. When in the target window there is not message line. MESSAGE outputs its text to the dialog-box with title "Message" as it would executed with VIEW-AS ALERT-BOX.
5. When output is redirected message text is displayed in the message line and gets into output file independent of IN WINDOW clause. The only when VIEW-AS ALERT-BOX clause is used - the message does not get into file also independent of IN WINDOW.
6. When there is no status line STATUS statement message does not appear anywhere in the window or alert-box.
7. When there is no status line PAUSE statement message does not appear anywhere in the window or alert-box. Procedure does not stopped by the PAUSE.
8. When there is no status line HELP statement message does not appear anywhere in the window or alert-box.

#83 Updated by Constantin Asofiei over 9 years ago

Greg, some other key points for the GUI clients:
  • the output can switch from GUI to ChUI, when i.e. output is sent to a file. This means that OutputManager should be able to switch primitives, depending on where the output is redirected.
  • the major problem is that OutputManager is highly ChUI specific, is very character-oriented. I think this needs to be dependent on the driver (GUI or ChUI), and the ChUI specific stuff (ScreenBitmap and various OutputManager APIs) should be moved in a sub-class.

Where this conclusions came from: when posting i.e. a PaintEvent in a GUI client, currently all computations are ChUI-specific. This makes impossible to redraw the screen, as the metrics (dimension, location) are dependent on the used driver - and when ScreenBitmap is reached, this fails (as expected). In addition, as 4GL uses windows APIs for the GUI client, I don't think this drawing algorithm is similar with the ChUI drawing. More likely, the algorithm is windows specific; if this is the case, as the ScreenBitmap class and current OutputManager implementation is something ChUI specific, we need to refactor their usage to take into consideration the driver type (GUI or ChUI).

#84 Updated by Greg Shah over 9 years ago

I just looked at those files again, with your comments in mind. Yes, you are right. 60%-75% of OutputManager and OutputPrimitives are probably ChUI-specific.

In addition, as 4GL uses windows APIs for the GUI client, I don't think this drawing algorithm is similar with the ChUI drawing.

From a drawing perspective, I think you are right. I do suspect that most of the 4GL's underlying implementation is in common between ChUI and GUI. They expose very little of the Windows API at the 4GL level. The one obvious thing that is exposed is the HWND for each widget, without which it would be impossible to use WIN32 APIs to operate on the 4GL UI. But generally, one does not see the influence of the WIN32 GUI message queuing approach at the 4GL level. That is a blessing.

Ultimately, they create "peer" Windows controls that map to each 4GL widget and then let Windows do the drawing of these as needed. Our implementation will need to be much closer to what we do for the ChUI approach (where we draw everything ourselves).

I think this needs to be dependent on the driver (GUI or ChUI), and the ChUI specific stuff (ScreenBitmap and various OutputManager APIs) should be moved in a sub-class.

Yes.

#85 Updated by Constantin Asofiei over 9 years ago

Currently I'm abstracting ScreenBitmap and OutputManager; a conclusion is that each implementation hierarchy (GUI and ChUI) needs to provide the type of OutputManager returned by AbstractWidget.screen(). This allows a more strict control over which OutputManager APIs are used by the generic widget classes (the ones from the p2j.ui.client package) and will also allow easy access to the OutputManager/ScreenBitmap APIs which are implementation-specific.

Also, making the AbstractWidget.screen() strong-typed exposes ChUI-specific APIs used in (supposedly) generic widget classes.

#86 Updated by Greg Shah over 9 years ago

Do you mean that AbstractWidget.screen() will return a generic like <T extends OutputManager> T screen(T type)?

#87 Updated by Constantin Asofiei over 9 years ago

Greg Shah wrote:

Do you mean that AbstractWidget.screen() will return a generic like <T extends OutputManager> T screen(T type)?

No, I want to go further than that. I want to:
  • change Widget class to this:
    public interface Widget<O extends OutputManager<?>>
    {
       /**
        * Get access to {@link OutputManager} instance.
        * 
        * @return  reference to {@link OutputManager}.
        */
       public O screen();
       ...
    }
    
  • widget impl classes to i.e.:
    public class FillInImpl
    extends FillIn<ChuiOutputManager>
    ...
    public abstract class FillIn<O extends OutputManager<?>>
    extends LabeledDataContainer<O>
    
    ... and so on up the hierarchy
    
  • OutputManager to this:
    public abstract class OutputManager<T extends ScreenBitmap>
    {
       public T getBitmapCopy()
       {
         ...
       }
    }
    
  • plus OutputPrimitives:
    public interface OutputPrimitives<T extends ScreenBitmap>
    {
       public T getScreenBitmap();
    }
    
  • plus some other classes.

The idea behind this is that the widget implementations are not interchangeable - i.e. a FillIn from a redirected stream (which needs to be a ChUI impl) can't be attached to a GUI window. Another result from this is that the widget registry is dependent on the output manager, too. Until know, I thought that ChUI and GUI are completely exclusive - but it looks like they are not, as the streams still works in GUI mode, thus these two drivers can co-exist. And I think we can go deeper than that: as the standard output is treated as a stream, too, I think the output manager looks better if it belongs to the stream currently being used. And as the streams switch, the output manager switches, too (plus the widget registry and maybe other stuff).

My main reason why I'm digging so deep into the UI code: without having a separation betwheen ChUI and GUI early on, GUI widget events will be a PITA to be added blindly, as testing will not be possible.

#88 Updated by Greg Shah over 9 years ago

Good, I really like the approach. It leaves as much common as possible, while making it easy to access the more specific APIs in specific implementation sub-classes.

My main reason why I'm digging so deep into the UI code: without having a separation betwheen ChUI and GUI early on, GUI widget events will be a PITA to be added blindly, as testing will not be possible.

You are absolutely right to dig deep into this and get it right from the start. Doing it later will be more work.

#89 Updated by Vadim Gindin over 9 years ago

I've added precedence* tests. They confirm documented precedence order: IN WINDOW, THIS-PROCEDURE:CURRENT-WINDOW, CURRENT-WINDOW, DEFAULT-WINDOW.
1) non-dialog frames. The order is confirmed.
2) Dialog frames. It's hard to classify this case because dialogs are not visually related to it's parent window.
3) Dynamic frames. The order is confirmed
4) Unrealized windows case. There are created default window for the external procedure that owns all frames.
5) Failed windows case. There are errors happened during the tries to assign invalid values for THIS-PROCEDURE:CURRENT-WINDOW or CURRENT-WINDOW:
**Unable to assign widget to CURRENT-WINDOW. (3130) or ** Unable to set attribute CURRENT-WINDOW of procedure widget. (4078)

#90 Updated by Vadim Gindin over 9 years ago

More tests for conflicting statements. Here are results.
1) Can you re parent a realized FRAME to a different window using IN WINDOW
Yes, we can. The frame is successfully moved to other window.
2) conflicting PARENT and IN WINDOW
IN WINDOW wins
3) multiple IN WINDOW clauses and they conflict
I tried 2 variants: before realizing and after realizing.
I tried to use DISPLAY .. IN WINDOW and ENABLE .. IN WINDOW both conflicting statements.
I didn't find the way to use one statement with conflicting options.
In the case of 2 conflicting statements the Progress executes both statements in order
of execution independently of the place: before realizing or after it.

#91 Updated by Vadim Gindin over 9 years ago

1. Conflicting frame:parent.
I tried to found two conflicting statements with frame:parent set, but I didn't find any except just sequenced sets of one frame. It works using the last statement. But I tried to create completely conflicting situation and faced with Progress crash. I created 2 frames f1 and f2 and set f2:frame=f1. After that I tried to set different parents for these frames f1:parent=h1 and f2:parent=h2. Every try of running this procedure conflict_some_parent_fail.p ends with crash. Here is the details:

Problem signature:
  Problem Event Name:     APPCRASH
  Application Name:     prowin32.exe
  Application Version:     10.2.6.1613
  Application Timestamp: 4f67bf4a
  Fault Module Name:     prow32.dll
  Fault Module Version:     10.2.6.1613
  Fault Module Timestamp:4f67bf43
  Exception Code:     c0000005
  Exception Offset:     00266411
  OS Version:    6.1.7601.2.1.0.144.8
  Locale ID:    2057
  Additional Information 1:    0a9e
  Additional Information 2:    0a9e372d3b4ad19135b953a78882e789
  Additional Information 3:    0a9e
  Additional Information 4:    0a9e372d3b4ad19135b953a78882e789

Read our privacy statement online:
  http://go.microsoft.com/fwlink/?linkid=104288&clcid=0x0409

If the online privacy statement is not available, please read our privacy statement offline:
  C:\Windows\system32\en-US\erofflps.txt

It looks like Progress bug, but how we will reproduce this in Java?

2. IN WINDOW clause is really restricted in DISABLE statement. The procedure won't run with error message:
IN WINDOW phrase not allowed in this statement. (3460)

#92 Updated by Vadim Gindin over 9 years ago

I also prepared tests this*.p to investigate an impact of THIS-PROCEDURE:CURRENT-WINDOW setting on called procedure and calling procedure. I've found that THIS-PROCEDURE:CURRENT-WINDOW is only affects current procedure and remains uninitialized until it will be initialized in the current procedure manually. This behavior corresponds to documented.

#93 Updated by Greg Shah over 9 years ago

2) Dialog frames. It's hard to classify this case because dialogs are not visually related to it's parent window.

Yes, you are right. I should not have included these.

4) Unrealized windows case. There are created default window for the external procedure that owns all frames.

What I meant by these cases is how the precedence order works when the CURRENT-WINDOW, THIS-PROCEDURE:CURRENT-WINDOW and IN WINDOW... are set to an unrealized window. Do your tests show that the unrealized window is ignored and the DEFAULT-WINDOW is used instead?

In the case of 2 conflicting statements the Progress executes both statements in order of execution independently of the place: before realizing or after it.

I don't understand what you mean by this. Please be more specific.

But I tried to create completely conflicting situation and faced with Progress crash. I created 2 frames f1 and f2 and set f2:frame=f1. After that I tried to set different parents for these frames f1:parent=h1 and f2:parent=h2. Every try of running this procedure conflict_some_parent_fail.p ends with crash.
...
It looks like Progress bug, but how we will reproduce this in Java?

It is a Progress bug, but since it is a crash, there is no way to have a working 4GL application "use" this feature. Because any application that "uses" this "feature" would crash, which means it is NOT working.

We will NOT try to duplicate this crash.

What testing remains? Please check in your latest testcases.

#94 Updated by Hynek Cihlar over 9 years ago

Here are some first thoughts regarding the refactoring of coordinate system - #2323..

From what I have seen in the code and from my (most likely not yet 100% accurate) interpretation of Progress coordinate processing I think most of the coordinate processing logic can either stay as is or can be improved to work generically for both ChUI and GUI. The key premises for this seem to be (1) a proper type system and (2) one source of truth.

Ad (1)
The proper type system is not surprisingly one of the key ingredients. Nothing new here, the units of measure for representing dimensions are either characters (row/columns) or pixels. Characters can be fractional whereas pixels are always whole numbers. The APIs should strictly follow this scheme, all character attributes/parameters must be declared as double, pixel attributes/parameters must be declared as integer.

Btw, double probably holds enough precision to achieve pixel-perfect precision. But at this point it is hard to say what surprises has Progress to offer in this regard.

Ad (2)
All coordinate values should be stored only in the pixel units. Character units should be mapped to pixels and backwards pixels should be mapped to characters with pixels being the only source of truth. The mapping function for ChUI will be a simple 1 Character = 1 Pixel, for GUI the mapping logic will include some font metrics (this seems to be already implemented, at least to some extent).

Here's some interesting point on this I found in the Progress Programming Handbook:

Note that character units are decimal values and pixels are integer values in Progress. If you set
a pixel attribute to a decimal value, it is rounded to the nearest whole integer. This also means
that if you set a character unit attribute (such as HEIGHT–CHARS) and then read it back,
Progress can return a different value than the one you set based on the actual corresponding
pixel value. This is a necessary rounding error because all graphic dimensions are ultimately
stored as pixels, and the nearest whole pixel dimension might not exactly match the character
units you specify.
For example, depending on the resolution and default system font of your interface, if you set
the HEIGHT–CHARS attribute to 2.5, Progress might store and return its value as 2.51. This is
because 2.51 most closely matches the number of pixels corresponding to 2.5 character units.
Thus, if your application uses character units to track widget size and location, be sure to reset
your initial values to the values that Progress actually stores and returns.

Depending on the complexity, there seem to be several kinds of coordinates logic. From the simplest of solely storing the dimension values to some trivial calculations like widget centering up to complex ones involving multiple widgets and keeping temporal states (Frame.rearrangeEditors for example). I think most of the code can be generalized to work for ChUI as well as for GUI where the widget layout is the same. For cases where the layout differs between ChUI and GUI different implementations (governing by an abstraction API) will be required.

#95 Updated by Constantin Asofiei over 9 years ago

Hynek Cihlar wrote:

Ad (1)
The proper type system is not surprisingly one of the key ingredients. Nothing new here, the units of measure for representing dimensions are either characters (row/columns) or pixels. Characters can be fractional whereas pixels are always whole numbers.

I think character units can always have at most 2 decimals - lease confirm this.

The APIs should strictly follow this scheme, all character attributes/parameters must be declared as double, pixel attributes/parameters must be declared as integer.

I agree.

Btw, double probably holds enough precision to achieve pixel-perfect precision. But at this point it is hard to say what surprises has Progress to offer in this regard.

Ad (2)
All coordinate values should be stored only in the pixel units.

I don't agree with this one. The abstraction widget layer (which does the layout, determines which widgets need to be drawn/hidden, etc) needs to work with character units. Consider this case: you are sending data to a stream. This stream can be linked with either the terminal or a file. How do you determine the pixel dimensions of the widget, when you don't know where the widget will be displayed? More, the widget's pixel dimensions can change, if it is moved from a window to another window, which has a different font-table.

Note that character units are decimal values and pixels are integer values in Progress. If you set
a pixel attribute to a decimal value, it is rounded to the nearest whole integer. This also means
that if you set a character unit attribute (such as HEIGHT–CHARS) and then read it back,
Progress can return a different value than the one you set based on the actual corresponding
pixel value. This is a necessary rounding error because all graphic dimensions are ultimately
stored as pixels, and the nearest whole pixel dimension might not exactly match the character
units you specify.
For example, depending on the resolution and default system font of your interface, if you set
the HEIGHT–CHARS attribute to 2.5, Progress might store and return its value as 2.51. This is
because 2.51 most closely matches the number of pixels corresponding to 2.5 character units.
Thus, if your application uses character units to track widget size and location, be sure to reset
your initial values to the values that Progress actually stores and returns.

Please try to duplicate this with a test. Once you have this, see what happens if the widget is moved to a window with a different font-table: are the character units re-adjusted? More, we need to make sure that:
  • if the pixel units are set for a widget, then the character unit metrics are re-adjusted, depending on which font-table is in use.
  • if the character units are set (or no explicit units are set by the business logic), then the pixel units will always be recomputed, based on the character units in use.
  • check what happens if a coordinate is in pixel units and the other in character units.
  • the implementation needs to allow reporting of the pixel and character units properly, for both these cases.

Depending on the complexity, there seem to be several kinds of coordinates logic. From the simplest of solely storing the dimension values to some trivial calculations like widget centering up to complex ones involving multiple widgets and keeping temporal states (Frame.rearrangeEditors for example). I think most of the code can be generalized to work for ChUI as well as for GUI where the widget layout is the same. For cases where the layout differs between ChUI and GUI different implementations (governing by an abstraction API) will be required.

Until proven otherwise, my assumption is that the layout should be the same in both GUI and ChUI.

#96 Updated by Vadim Gindin over 9 years ago

Greg Shah wrote:

4) Unrealized windows case. There are created default window for the external procedure that owns all frames.

What I meant by these cases is how the precedence order works when the CURRENT-WINDOW, THIS-PROCEDURE:CURRENT-WINDOW and IN WINDOW... are set to an unrealized window. Do your tests show that the unrealized window is ignored and the DEFAULT-WINDOW is used instead?

Yes, that is exactly what I meant.

In the case of 2 conflicting statements the Progress executes both statements in order of execution independently of the place: before realizing or after it.

I don't understand what you mean by this. Please be more specific.

I made a mistake in my description: "order of execution" should be read as "order of appearing". I meant the following. Lets assume that we have 2 conflicting statements. There are possible 2 different interesting cases there: when statements are before realizing windows, or when statements are after realizing corresponding windows.
1. Before. We will see effect of the latest of conflicting statements only.
2. After. If we add PAUSE between conflicting statements, then we will see behavior of both conflicting statements one after another in order of appearing in the source procedure.

Take a look at conflict_some_in_window_p for details about case №2. (There are 2 windows and one frame. I'm trying to display this frame in every of these windows using DISPLAY .. IN WINDOW statement. After execution of the first statement I see the frame in the first window. Then PAUSE. After execution of the second statement I see the frame in the second window.)

What testing remains? Please check in your latest testcases.

At this moment I've checked in all testcases I have finished. Remained testing is about: stacking of CURRENT-WINDOW and the latest question about an impact of ENTRY event. I also tried to find the way to set CURRENT-WINDOW implicitly but without success at this moment.

#97 Updated by Hynek Cihlar over 9 years ago

Constantin Asofiei wrote:

Ad (2)
All coordinate values should be stored only in the pixel units.

I don't agree with this one. The abstraction widget layer (which does the layout, determines which widgets need to be drawn/hidden, etc) needs to work with character units. Consider this case: you are sending data to a stream. This stream can be linked with either the terminal or a file. How do you determine the pixel dimensions of the widget, when you don't know where the widget will be displayed? More, the widget's pixel dimensions can change, if it is moved from a window to another window, which has a different font-table.

Are you saying that we may not know the type/resolution of the UI for a particular session or that there can be multiple different UIs per session? Also I had the impression that the font-table is allocated per session.

  • check what happens if a coordinate is in pixel units and the other in character units.

For example, do you mean to set COLUMN and Y on the same widget?

#98 Updated by Constantin Asofiei over 9 years ago

Hynek Cihlar wrote:

Are you saying that we may not know the type/resolution of the UI for a particular session or that there can be multiple different UIs per session? Also I had the impression that the font-table is allocated per session.

Yes. Consider if the unnamed stream is redirected to file: in this case, there are no pixel units. More, if the stream is paged and directed to the terminal, there is a different way of displaying the widgets.

  • check what happens if a coordinate is in pixel units and the other in character units.

For example, do you mean to set COLUMN and Y on the same widget?

Yes, this is what I mean.

#99 Updated by Constantin Asofiei over 9 years ago

Hynek Cihlar wrote:

Also I had the impression that the font-table is allocated per session.

The font-table is associated with a window's environment. If the font-table gets changed, then the UI changes for all the windows using that environment.

#100 Updated by Greg Shah over 9 years ago

The mapping function for ChUI will be a simple 1 Character = 1 Pixel, for GUI the mapping logic will include some font metrics (this seems to be already implemented, at least to some extent).

To make this part work, we must have all logic that depends on the width of the character driven by the driver currently in use for the output destination.

Until proven otherwise, my assumption is that the layout should be the same in both GUI and ChUI.

It is my understanding that layout differences will be caused by slightly different sizing of widgets. For example, the FILLIN is more than 1 row high in GUI because of its border, but in ChUI it only takes up one row.

As far as I can tell, the flow/rules of the layout are the same for GUI and ChUI, but because of sizing differences the results will look different.

#101 Updated by Greg Shah over 9 years ago

I'm trying to display this frame in every of these windows using DISPLAY .. IN WINDOW statement. After execution of the first statement I see the frame in the first window. Then PAUSE. After execution of the second statement I see the frame in the second window.)

Interesting results. In other words, a frame can be output to multiple destination windows without a problem. Questions:

  1. Can the user switch back and forth between those windows and use that same frame each time?
  2. When in editing mode (ENABLE) do changes to the frame in one window get displayed in the same frame of the other window (switching focus to the other window may be needed to refresh that frame)?
  3. When a DISPLAY occurs to a frame in one window, does the change appear in the same frame of the other window (switching focus to the other window may be needed to refresh that frame)?

LE: One other point: I wonder if the "stream switching" behavior we see today (when a frame is used on multiple streams) will define the same behavior here. Typically, when the "stream" (output destination) being used is changed, the current changes that have been accumulating (cached) are "flushed" to (made visible on) the output destination.

#102 Updated by Constantin Asofiei over 9 years ago

Greg Shah wrote:

As far as I can tell, the flow/rules of the layout are the same for GUI and ChUI, but because of sizing differences the results will look different.

Yes, because in my understanding the sizing is driven by the device on which the widgets are displayed.

In other words, a frame can be output to multiple destination windows without a problem.

Keep in mind that the frame can be attached to only a single window, at a certain time.

#103 Updated by Greg Shah over 9 years ago

Copied from #2340, posted by Constantin:

This version switches from a matrix bitmap to a list of activated rectangles. This allows a more dynamic approach of the screen's dimensions (considering that the window can be resized). Plus, it will simplify introduction of decimal coordinates.

Is going through runtime testing now.

#104 Updated by Greg Shah over 9 years ago

Code Review ca_upd20140729a

1. In Rectangle.difference(), is this code correct?

      if (rect.left - baseUnit >= left)
...
      if (rect.right + baseUnit <= right)

Shouldn't it be rect.left - baseUnit <= left and rect.right + baseUnit >= right? It may just be a cut/paste error if I am interpreting it correctly.

2. Would Rectangle.size() be better described as Rectangle.area()?

#105 Updated by Constantin Asofiei over 9 years ago

Greg Shah wrote:

Code Review ca_upd20140729a

Shouldn't it be rect.left - baseUnit <= left and rect.right + baseUnit >= right? It may just be a cut/paste error if I am interpreting it correctly.

The code is correct, unless I got the coordinate system wrong. My assumption is that origin is on (top, left) corner, with the positive X axis going left and positive Y axis going down. The case can look like this, when T1.difference(T2) is called:

      T1
+-----------+
|           |
|     T2    |
|   +---+   |
|   |   |   |
|L1 |L2 |R2 |R1
|   +---+   |
|           |
+-----------+

The point here is if L2 is on the right-side of L1, then there is a rectangle portion which must remain after rectangle T2 is cut off. Same for right-side of T2: if is on left-side of R1, then there is something to be cut off.

2. Would Rectangle.size() be better described as Rectangle.area()?

I agree, I'll rename it.

#106 Updated by Greg Shah over 9 years ago

The code is correct, unless I got the coordinate system wrong. My assumption is that origin is on (top, left) corner

You are right.

I had in my mind (incorrectly) that the origin was (bottom, left). This is a sad leftover default mindset from my days of programming GUI on OS/2 which (strangely) had its origin on bottom, left. The incorrect mindset led me to interpret that the T2 was the outer rectangle and thus come to the wrong conclusion on the left/right calc. My bad.

#107 Updated by Constantin Asofiei over 9 years ago

replacement for 0729a.zip: fixed the ScreenBitmap problems related to using lists of activated rectangles instead of a matrix bitmap. This version passed testing.

#108 Updated by Greg Shah over 9 years ago

Code Review 0731a

It looks good. You can check-in and distribute, if you are comfortable with the level of testing.

#109 Updated by Constantin Asofiei over 9 years ago

Greg/Hynek, something about the character and pixel units. I think these metrics can originate from two directions:
  • from the 4GL side: when it computes dynamic layout, the business logic which sets a certain character metric, etc. In this case, 4GL should work with character units.
  • from the device on which the window is displayed - when the window (or a generic widget) is resized/moved, then the resize/movement is done at the device in pixels, and the 4GL side is informed about the pixel metric change (to recompute the character units).

What this translates into: we need to be very careful in differentiating between a config change incoming from the server-side and one incoming from the client-side... more, I think the client-side should collect these changes (via ClientState fields) and inform the server-side (on the first request back to the server). We need to keep these values in sync, else when the frame state is pushed to the client-side, its metrics might be obsolete.

Also, if the server-side sends pixel units, it needs to "freeze" this metric in pixels, and let the character units vary. The opposite: if the server-side sends character units (or lets them be computed dynamically), then the pixels are always re-computed from the character units.

#110 Updated by Constantin Asofiei over 9 years ago

Greg, my goal would be to provide full bi-directional support of these coordinate/size attributes; but if the client sources work only in one direction (i.e. the server-side pushes to client-side the configuration, and it does not rely on reading them back - a "write-only" mode), I think we can get away without doing too many changes in the code. But if this is not the case and the business logic relies on reading these runtime values, then our problem is that the WidgetConfig implementations are used as data containers on both client-side and server-side. And when the server-side pushes a config to the client, the client can't know which config is explicitly set by the server-side and which is not. A case I can refer to is pushing the window config: currently, if i.e. the window's title is set, then the entire window config is pushed to the client-side. We need to decide what is the policy of pushing a certain widget config to the client:
  1. create APIs to push only that config to the client (i.e. only the window title, not the full config)
  2. always sync the client-side config with the server-side config (via ClientState messages) - so when the server-side pushes the config, it will always have the latest values
  3. something else.

#111 Updated by Greg Shah over 9 years ago

create APIs to push only that config to the client (i.e. only the window title, not the full config)

We don't want to explode our APIs, so this could only be done using some kind of mapping approach. For example, we send down the diffs as an explicit list of changed values and some identifier of the attribute they are associated with.

However, this doesn't solve the reverse direction issue (changes known only on the client side, which are used on the server).

always sync the client-side config with the server-side config (via ClientState messages) - so when the server-side pushes the config, it will always have the latest values

I think this is long overdue. We have tried various "band-aids" to try to get around this issue in the past, but I think it is not advisable to implement the GUI using this approach. With GUI comes 2 common things:

  1. The code is much more aggressive in its use of attributes (and methods).
  2. The code is much more aggressive in its use dynamic UI (windows, frames and widgets).

This is due to the more complex nature of the UI. But it means that the code is much more dependent upon this state to work properly. Now is the time to fix this issue.

We still will want to implement this as a diffs approach, to minimize the amount of data to be synchronized. I wonder if this is also the time when we pursue #2254. If we implement this on a bidirectional basis and use dynamic proxies to implement the logic in a common way, perhaps we can do this on a more clean basis.

#112 Updated by Constantin Asofiei over 9 years ago

Greg Shah wrote:

I wonder if this is also the time when we pursue #2254.

Yes, I think we need to do this. Better yet, I think we should do it before or at the same time with the #2323, but after my first iteration at #2340. For #2340, the only issue I want to finish is abstracting the support for widget move/resize via mouse.

#113 Updated by Hynek Cihlar over 9 years ago

Greg Shah wrote:

I wonder if this is also the time when we pursue #2254.

Yes, I think we need to do this.

Greg, do you want me to take care of that?

#114 Updated by Hynek Cihlar over 9 years ago

Constantin Asofiei wrote:

Greg/Hynek, something about the character and pixel units. I think these metrics can originate from two directions:
  • from the 4GL side: when it computes dynamic layout, the business logic which sets a certain character metric, etc. In this case, 4GL should work with character units.
  • from the device on which the window is displayed - when the window (or a generic widget) is resized/moved, then the resize/movement is done at the device in pixels, and the 4GL side is informed about the pixel metric change (to recompute the character units).

Would it make sense then to also send the transformation parameters (font metrics for example) in the requests?

#115 Updated by Hynek Cihlar over 9 years ago

Constantin Asofiei wrote:

Note that character units are decimal values and pixels are integer values in Progress. If you set
a pixel attribute to a decimal value, it is rounded to the nearest whole integer. This also means
that if you set a character unit attribute (such as HEIGHT–CHARS) and then read it back,
Progress can return a different value than the one you set based on the actual corresponding
pixel value. This is a necessary rounding error because all graphic dimensions are ultimately
stored as pixels, and the nearest whole pixel dimension might not exactly match the character
units you specify.
For example, depending on the resolution and default system font of your interface, if you set
the HEIGHT–CHARS attribute to 2.5, Progress might store and return its value as 2.51. This is
because 2.51 most closely matches the number of pixels corresponding to 2.5 character units.
Thus, if your application uses character units to track widget size and location, be sure to reset
your initial values to the values that Progress actually stores and returns.

Please try to duplicate this with a test.

So far I can confirm the rounding error behavior. When a value is set to a widget's character dimension attribute in one statement a different value might be read back in the next one.

#116 Updated by Greg Shah over 9 years ago

Constantin wrote:

I think we should do it before or at the same time with the #2323, but after my first iteration at #2340. For #2340, the only issue I want to finish is abstracting the support for widget move/resize via mouse.

Yes.

Hynek wrote:

Greg, do you want me to take care of that?

I will let you and Constantin split the work on this one, as you find makes the most sense. Your #2323 work is non-trivial already, but there are definitely pieces of this that may be better done as part of your work. I'd like Constantin to take on whatever portion of this work is not too close to #2323.

#117 Updated by Hynek Cihlar over 9 years ago

Greg Shah wrote:

I will let you and Constantin split the work on this one, as you find makes the most sense. Your #2323 work is non-trivial already, but there are definitely pieces of this that may be better done as part of your work. I'd like Constantin to take on whatever portion of this work is not too close to #2323.

No problem, I'll wait for Constantin to choose his part.

#118 Updated by Constantin Asofiei over 9 years ago

ca_upd20140731a.zip was released as bzr rev 10589.

#119 Updated by Vadim Gindin over 9 years ago

Greg Shah wrote:

I'm trying to display this frame in every of these windows using DISPLAY .. IN WINDOW statement. After execution of the first statement I see the frame in the first window. Then PAUSE. After execution of the second statement I see the frame in the second window.)

Interesting results. In other words, a frame can be output to multiple destination windows without a problem. ...

No. That is not right. Frame just moved from one window to another during execution. Sorry, my description was not clear.

I added additional tests for the last test cases.
1. I didn't find stacking behavior for CURRENT-WINDOW in different blocks. Doing additional testing.
2. ENTRY event. We can't make some window active by applying ENTRY event to it. During execution of event trigger ACTIVE-WINDOW points to this window but at the same time it remains visually inactive.

#120 Updated by Vadim Gindin over 9 years ago

I tried to run change_parent_frame.p with gui swing driver. I added some UI components stubs for that, but I faced with the error (see thin_client_err.log). The test contains simple frame with one widget. Is it possible to run that testcase with some corrections? Why ThinClient (from chui package) is used here. Is it correct?

I successfully runned errlist/err.p testcase for gui swing driver. But that test does not contain widgets. I need to execute ENABLE command to run my tests. What do you think?

#121 Updated by Constantin Asofiei over 9 years ago

Vadim Gindin wrote:

I tried to run change_parent_frame.p with gui swing driver.

The swing gui driver is very-very limited; only status/message work (very limited), frame is not supported at all.

Have you extracted the rules describing the default-/current-/active- window, from the testcases you wrote? If so, please compile them in a single post and add them here.

#122 Updated by Vadim Gindin over 9 years ago

If you meant conversion rules, they already formulated for the corresponding task for CHUI case. I'm trying to add just new implementation for GUI.

I also understand that current swing gui driver implementation is limited, but how to implement and test window handles?

#123 Updated by Constantin Asofiei over 9 years ago

Vadim Gindin wrote:

If you meant conversion rules, they already formulated for the corresponding task for CHUI case. I'm trying to add just new implementation for GUI.

No, not the conversion rules. I refer to the behaviour of these handles in GUI case, observed on windev01.

I also understand that current swing gui driver implementation is limited, but how to implement and test window handles?

You can't, momentarily. We don't even have multiple window support yet.

I'm working on a first iteration of a more complex UI redesign, and after this I think it will be possible to work on multi-window support (in GUI). But again, this is somehow dependent on the dynamic widget support Eugenie is working on.

#124 Updated by Vadim Gindin over 9 years ago

I just added new fields to LogicalTerminal class. To add some real behavior (for ENABLE, MESSAGE and other statements) I need to know the future GUI client class. Will it be different from ThinClient?

#125 Updated by Greg Shah over 9 years ago

To add some real behavior (for ENABLE, MESSAGE and other statements) I need to know the future GUI client class. Will it be different from ThinClient?

The code in ThinClient will still be the core for the future UI (both ChUI and GUI). As highlighted in the first history entries in this task, we will be doing a significant amount of refactoring:

  1. Code like ThinClient will become independent of UI type. Any code in there that is currently dependent upon UI type will be moved into classes that implement an abstraction layer. That interface will be relied upon the "common code".
  2. All code will move out of the ui/chui/ package and it will be properly integrated into the ui/client/ hierarchy.

But ThinClient will remain, so changes can be made there.

As Constantin requested, please write up a single, comprehensive list of the behavioral rules that must be implemented. Do this as your top priority. I will review your code changes shortly and provide some feedback.

#126 Updated by Greg Shah over 9 years ago

Code Review vig_upd20140806a.zip

1. Can ACTIVE-WINDOW really be assigned from business logic? Your code allows it.

2. It seems like you can remove the TODO in LT.defaultWindow() and LT.activeWindow().

3. You are missing a history entry in the file.

More importantly, I think you must look at the final set of behavioral rules and make sure that all of the error handling and limitations are properly implemented (to the degree these can be implemented on the server-side, i.e. in LogicalTerminal).

Once you have the full set of rules documented (in the history here) and you have an update with the changes noted above, the next step seems like we need to finish the server-side multiple window support. Such support will not be working until the client-side is done, but you can definitely get most of the server-side done independently.

Here is the approach I have been thinking about:

  • For every Progress feature which must be "window-aware" (see notes 59, 60 and 61; note 60 has a nice list of features) we will change the backing method in ClientExports to add the widget ID of the targeted window. This will require changes in both LogicalTerminal and ThinClient. We will NOT add APIs, instead the core API itself will always pass a window widget ID.
  • Where the external business logic API (e.g. usually in GenericFrame for frame-level functionality like UPDATE/SET/PROMPT-FOR or LogicalTerminal for features like MESSAGE/STATUS) does not yet provide support for IN WINDOW, it must be added.
  • The server-side code must implement the full behavior of the precedence hierarchy of window targeting behavior, including all of the strange quirks and error handling. The only exceptions are features which can only be implemented on the client, if any. It seems to me that this hierarchy can be kept purely on the server-side (e.g. the client doesn't need to know about concepts like CURRENT-WINDOW, THIS-PROCEDURE:CURRENT-WINDOW, DEFAULT-WINDOW or ACTIVE-WINDOW). I prefer if this code could be done in a very small number of methods, optimally with a main worker method that can be called from code in GenericFrame/LogicalTerminal to determine the window target before calling down to the client. This code should be able to handle both ChUI and GUI, such that it can be always used. Of course, on ChUI the results will return very quickly with the same CURRENT-WINDOW handle that is the only window that can ever be targeted.
  • Where events on the client cause server state to change (e.g. ACTIVE-WINDOW changes when focus shifts between windows), we can use the server state sync mechanism to notify the server of the change. As far as I understand it, this is the only way that ACTIVE-WINDOW can ever change.

This can all be implemented, tested and checked in without any additional GUI support.

After that, the changes on the client-side will be next.

#127 Updated by Constantin Asofiei over 9 years ago

Greg, attached is a massive update which touches more than the window title. The GUI window is a little ugly at this time, but this is mainly due to the fact that we don't have decimal char units yet. Window min/max/resize/move should work properly. Title can be displayed, i.e. a DEFAULT-WINDOW:TITLE = "bla" will work. Status line works (as it used to), message area only shows a hard-coded bogus text (for testing purposes). I think the status area can be worked easy (as it's just look&feel stuff to address), the message area is a little more complex; we should add least proper scrollable container support, if not full support which requires at least:
  • basic fill-in/tiny-frame input (for MESSAGE ... UPDATE cases
  • MESSAGE ... VIEW-AS, for which I think 4GL is using Windows dialog boxes.
Following is a list of touched areas:
  1. split OutputManager into two subclasses, for GUI and ChUI. This also means that all widgets now need to specify which OutputManager will be using. This helps in having access to the corresponding impl APIs right away, and also limiting the abstract widget classes to access only generic APIs.
  2. adds mouse support. This includes capturing the events and posting them to the event queue (there is a catch here, 4GL doesn't capture mouse if not in a event processing loop) and some generic widget actions (widget move/resize/popup).
  3. for all classes outside of ChUI related classes, all imports targeting ChUI classes are now explicitly used (do not import entire package). This allows an easy way to identify dependencies of ChUI classes, outside of the ChUI packages.
  4. basic IMAGE widget support, on client-side - not tested/completed yet
  5. added widget state listener support: mainly this was to notify misc listeners that a widget was destroyed, but this can be extended to some other cases.
  6. removed the com.goldencode.p2j.ui.chui.WindowImpl class, and created specific ChUI and GUI classes, from the base Window class.
  7. moved com.goldencode.p2j.ui.client.driver.ChuiScreenDriver to ui.client.chui.driver.package
  8. refactored misc driver/mgr related classes (ScreenDriver, swing simulators, primitives), so that common APIs are in base classes.
  9. removed the AbstractContainer.size() API, and replaced its usage with the dimension API.
  10. removed the hasColors API from misc classes (as it was never used, and ChUI specific code was already using something else to determine if the terminal has colors or not).
  11. the widget registry now resides at the output manager - this is needed because ChUI output mgr can be used in GUI mode too, when writing to streams.
  12. similar for ScreenBitmap - this is something window-specific (as each window can have its own dimension, and the dimension can vary). For now, this is set at the GuiSimulator, which is already linked with one and only one window.
  13. all window OS-related components must be widgets. This allows usage of the abstract draw/repaint mechanism.
  14. many more misc changes to split ChUI code into ChUI specific classes
Some TODOs are (some of which I think can be in separate tasks):
  1. add multiple driver support at runtime, to allow writing to streams. This is somehow tricky, as same widget can be referenced both in GUI and ChUI modes... the widget registry might need to be maintained for all available drivers.
  2. we need to make the window configuration details (like border width, insets, window title color, etc - all OS-related stuff which can't be set via the WINDOW handle) configurable.
  3. 4GL mouse events - not sure if we need this or not
  4. finish window popup menu impl (i.e. drawing/actions/etc)
  5. disable the window native popup via the menu key - I'll try to fix this one before releasing the update for this iteration.
  6. there is still a CTRL-C bug which I need to fix (the state is not reinitialized properly in GUI mode).
Misc findigs:
  1. even if PUT SCREEN is documented as being ChUI specific, it still works in GUI.
  2. when redirecting the unnamed output stream to a paged terminal (i.e. OUTPUT TO TERMINAL PAGED), then the GUI is switching in a "pseudo-terminal" mode: it is using a dedicated canvas which overlays all existing widgets, to output data. If the GUI client code does not rely on it, we can postpone/avoid it.
  3. 4GL does not allow window closing via the OS window close button. Not sure about dialogs.

Please review.

#128 Updated by Hynek Cihlar over 9 years ago

Constantin Asofiei wrote:

Once you have this, see what happens if the widget is moved to a window with a different font-table: are the character units re-adjusted?

It seems that character positioning and sizing is always performed with the default font. As there is no way to change the default font during runtime (I tried even in a LOADed environment) the layout is stable when moving a widget from one window to another with different font table (?).

I created a test case for moving an EDITOR widget from one window to another which confirms the above but I am not sure it is correct as it exhibits some weird behavior. Here are the steps of pseudo code how I do it:
  • CREATE WINDOW w1
  • VIEW w1
  • THIS-PROCEDURE:CURRENT-WINDOW = w1.
  • CURRENT-WINDOW = w1.
  • DEFINE FRAME f1
  • CREATE EDITOR e ASSIGN FRAME = FRAME f1:HANDLE
  • CREATE WINDOW w2
  • VIEW w2
  • THIS-PROCEDURE:CURRENT-WINDOW = w2
  • CURRENT-WINDOW = w2
  • VIEW FRAME f1 IN WINDOW w2

After the steps above the EDITOR widget moves to window w2, but setting its attribute SCREEN-VALUE has no effect.

What is the correct way to move a widget from one window to another?

#129 Updated by Greg Shah over 9 years ago

What is the correct way to move a widget from one window to another?

The f1 frame is never realized before the VIEW FRAME f1 IN WINDOW w2. That means that it is always in window w2 and never was in window w1, so it did not move.

#130 Updated by Hynek Cihlar over 9 years ago

Greg Shah wrote:

What is the correct way to move a widget from one window to another?

The f1 frame is never realized before the VIEW FRAME f1 IN WINDOW w2. That means that it is always in window w2 and never was in window w1, so it did not move.

It was realized by assigning VISIBLE and SENSITIVE to TRUE in the CREATE EDITOR statement. It seems to work ok - the widget is first shown in w1 and then moves to w2.

#131 Updated by Hynek Cihlar over 9 years ago

Hynek Cihlar wrote:

Greg Shah wrote:

What is the correct way to move a widget from one window to another?

The f1 frame is never realized before the VIEW FRAME f1 IN WINDOW w2. That means that it is always in window w2 and never was in window w1, so it did not move.

It was realized by assigning VISIBLE and SENSITIVE to TRUE in the CREATE EDITOR statement. It seems to work ok - the widget is first shown in w1 and then moves to w2.

Please disregard, the problem was in my code.

#132 Updated by Constantin Asofiei over 9 years ago

Hynek Cihlar wrote:

Constantin Asofiei wrote:

Once you have this, see what happens if the widget is moved to a window with a different font-table: are the character units re-adjusted?

It seems that character positioning and sizing is always performed with the default font. As there is no way to change the default font during runtime (I tried even in a LOADed environment) the layout is stable when moving a widget from one window to another with different font table (?).

I think EDITOR widget is an unfortunate choice, as it's formula is dependent on PIXELS-PER-ROW/COLUMN values (thus the font is not used). Try using a BUTTON with a text and an explicit font used. Make sure the windows are not using the same environment (as the FONT-TABLE is not private per window, all windows using a certain environment use the same FONT-TABLE). Also, when creating a WINDOW, it will always use the currently active/loaded environment, and that will be the "parent" for the FONT-TABLE. When moving the widget from a window to another, if the font entry referenced by the BUTTON is different in these two font-tables, the widget should draw different. Once you have this, check the widget's metrics (pixels and chars) while in the two windows; after this, you can check more complex cases - like layout, etc.

#133 Updated by Hynek Cihlar over 9 years ago

Constantin Asofiei wrote:

It seems that character positioning and sizing is always performed with the default font. As there is no way to change the default font during runtime (I tried even in a LOADed environment) the layout is stable when moving a widget from one window to another with different font table (?).

I think EDITOR widget is an unfortunate choice, as it's formula is dependent on PIXELS-PER-ROW/COLUMN values (thus the font is not used). Try using a BUTTON with a text and an explicit font used. Make sure the windows are not using the same environment (as the FONT-TABLE is not private per window, all windows using a certain environment use the same FONT-TABLE). Also, when creating a WINDOW, it will always use the currently active/loaded environment, and that will be the "parent" for the FONT-TABLE. When moving the widget from a window to another, if the font entry referenced by the BUTTON is different in these two font-tables, the widget should draw different. Once you have this, check the widget's metrics (pixels and chars) while in the two windows; after this, you can check more complex cases - like layout, etc.

Constantin, thank you for valuable info.

I actually tried moving behavior of an EDITOR, a TEXT and a BUTTON. All of them show stable positioning and all of them show stable sizing when the size set explicitly. When not set explicitly BUTTON adjusts its size according to its current LABEL font metrics, both the EDITOR and the TEXT stay put and the content is clipped. Also there are differences in the timing when is the content text resized according to new font metrics in the new environment, it either happens right away after the move or after FONT attribute is set (even with the same font ordinal). I didn't yet dig deeper into all the different semantics though. In all cases the char-pixel mapping doesn't change with the varying font metrics of the font set to the widgets.

#134 Updated by Constantin Asofiei over 9 years ago

Replacement for ca_upd20140806d.zip. It fixes a bug exposed by regression testing (related to 0806d.zip) plus:
  • currently, the SigintWaiter thread is leaked on CTRL-C (in both GUI/ChUI) - the fix is to stop the TypeAhead and SigintWaiter threads, and restart them as necessary
  • fix for CTRL-C in GUI mode: the changes allow only one GuiSimulator instance per window, and when selecting a window, its simulator + bitmap are selected into the primitives/driver

Hopefully only one more harness run is needed. Tomorrow I'll start looking into the bi-directional support for the widget attributes.

#135 Updated by Greg Shah over 9 years ago

Code Review 0806d

This is a really great step forward for the client! I was already deep into this review before you posted 0807b. I'll do that review tomorrow. Some feedback:

1. The ProcessStream history entry is not accurate. You are removing the unnecessary TC import.

2. OutputManager.newInstance() is aware of its sub-classes, which is not optimal.

3. WidgetFactoryAdapter should have class-level javadoc.

4. Why are the ChuiWidgetFactory and GuiWidgetFactory classes modifying the return value signature to be the impl class (LabelImpl instead of Label) when the WidgetFactory interface defines the abstract class as the return type. These are listed as overrides but they really are something a bit different (even if Java does let you get away with this).

5. Why doesn't GenericScreenDriver.getPrimitives() return type P?

6. In regard to the mouse processing architecture, my only question is whether it makes sense to fire the widget-specific behavior before the event is posted for general processing to ThinClient. But otherwise, I really like the design.

7. How compatible is the image widget with the 4GL requirements? For example, does the javax.imageio support properly handle the necessary image formats that the 4GL supports? Does the blank box drawn when the image is null correspond to behavior in the 4GL?

8. Where did the need for SelectionListBody.requestFocus()/ComboBoxImpl.requestFocus()/ScrollableListImpl.requestFocus() come from? Is this moved from DefaultList?

9. How comfortable are you with the changes in AbstractContainer.draw()?

10. I'm still thinking on the type ahead/TC.waitForEvent() changes, but it seems best to consider those more carefully in your next update.

#136 Updated by Constantin Asofiei over 9 years ago

Greg Shah wrote:

1. The ProcessStream history entry is not accurate. You are removing the unnecessary TC import.

Done.

2. OutputManager.newInstance() is aware of its sub-classes, which is not optimal.

I've added a ScreenDriver.createOutputManager API, to hide the OutputManager impl class.

3. WidgetFactoryAdapter should have class-level javadoc.

Done.

4. Why are the ChuiWidgetFactory and GuiWidgetFactory classes modifying the return value signature to be the impl class (LabelImpl instead of Label) when the WidgetFactory interface defines the abstract class as the return type. These are listed as overrides but they really are something a bit different (even if Java does let you get away with this).

There were two reasons I've changed them this way:
  1. if impl classes are not used, the approach would be to add the OutputManager type at the method's result, as in Label<ChuiOutputManager> createLabel(String text).
  2. an additional protection against incorrect usage of the WidgetFactory impl classes: if the WidgetFactory impl class is used explicitly, it prevents accidental mixing of ChUI and GUI usage (i.e. if used from incorrect location).

Let me know if you still consider I should remove these.

5. Why doesn't GenericScreenDriver.getPrimitives() return type P?

I've missed that, fixed.

6. In regard to the mouse processing architecture, my only question is whether it makes sense to fire the widget-specific behavior before the event is posted for general processing to ThinClient. But otherwise, I really like the design.

Mouse events are not processed by 4GL, if the business logic is not in a event-processing loop/readkey/pause. This can be tested by creating a very-long loop: in this case, the window is in a "busy" state (with the mouse icon set to the hourglass).

7. How compatible is the image widget with the 4GL requirements? For example, does the javax.imageio support properly handle the necessary image formats that the 4GL supports? Does the blank box drawn when the image is null correspond to behavior in the 4GL?

I haven't dig that deeper for this widget. The goal of the added support was to have a widget in place, which can receive events on its own.

8. Where did the need for SelectionListBody.requestFocus()/ComboBoxImpl.requestFocus()/ScrollableListImpl.requestFocus() come from? Is this moved from DefaultList?

Yes. This code:

screen().at(screenLocation().translate(0, currentRow));

is ChUI specific and can't be used from the base class.
Same for ComboBoxImpl: the screen().at(screenLocation()); code is ChUI specific, so it was moved from ComboBox.requestFocus to the impl class.

9. How comfortable are you with the changes in AbstractContainer.draw()?

This was the cause of a regression, 0807b.zip fixes it now - somehow instead of reading parent instanceof I read this instanceof, and that's why I moved the widget resolving code up to TitledWindow.

10. I'm still thinking on the type ahead/TC.waitForEvent() changes, but it seems best to consider those more carefully in your next update.

This is a little tricky, as 4GL listens for more than key events. The idea here is that if a server or mouse event is generated, then key waiting is interrupted, to allow for that event to be processed. I agree this doesn't look very well structured, but it should do the work in the short term. In the long term, we should refactor the event waiting loops to not rely on TypeAhead, but more on a generic event manager, which listens to more than one kind of events.

Attached update fixes some other issue (in advance of multi-window support):
  1. when multiple windows are used, there must be only one key reader instance. Previously, each GuiSimulator had its own SwingKeyboardReader class
  2. window selection triggers the ThinClient.screenDimension update, too
  3. the GuiDriver is responsible of creating the window simulators

Also, it fixes javadoc related problems (you will see some more explicit imports of ChUI classes).

Something else I don't like: on Linux, there is no compatibility for the EnvironmentDaemon impl. As P2J clients will be able to run on any platform (web included), I think we should at least allow LOAD/UNLOAD/GET-KEY-VALUE/PUT-KEY-VALUE/SYSTEM-DIALOG to work - registry access outside Windows OS can be restricted.

#137 Updated by Greg Shah over 9 years ago

4. Why are the ChuiWidgetFactory and GuiWidgetFactory classes modifying the return value signature to be the impl class (LabelImpl instead of Label) when the WidgetFactory interface defines the abstract class as the return type. These are listed as overrides but they really are something a bit different (even if Java does let you get away with this).

There were two reasons I've changed them this way:
  1. if impl classes are not used, the approach would be to add the OutputManager type at the method's result, as in Label<ChuiOutputManager> createLabel(String text).
  2. an additional protection against incorrect usage of the WidgetFactory impl classes: if the WidgetFactory impl class is used explicitly, it prevents accidental mixing of ChUI and GUI usage (i.e. if used from incorrect location).

Let me know if you still consider I should remove these.

No, your reasons make sense. Please put your 2 points into the file as comments.

6. In regard to the mouse processing architecture, my only question is whether it makes sense to fire the widget-specific behavior before the event is posted for general processing to ThinClient. But otherwise, I really like the design.

Mouse events are not processed by 4GL, if the business logic is not in a event-processing loop/readkey/pause. This can be tested by creating a very-long loop: in this case, the window is in a "busy" state (with the mouse icon set to the hourglass).

My concern is more in regards to how this will work with other widgets, most of which are mouse aware in some form. For example, does a MOUSE-SELECT-DOWN event occur before a button widget displays as "pushed down"?

From the 4GL docs:

The priority of events is an important concept. For any mouse or keyboard action on a
widget, ABL generates a single event. Thus, certain events take priority over others
that are generated by the same keyboard or mouse action for the same widget. Without
direct manipulation, the priority (first to last) of keyboard events is key label, key
function, and then high-level widget events such as CHOOSE. The priority of mouse
events is three-button, portable, and then high-level widget events. Within three-button
and portable mouse events, low-level mouse events (up, down) take priority over
high-level mouse events (click, double-click).

The default behavior for widgets is often after all of the Progress event processing occurs, so that NO-APPLY triggers can bypass the default. If I recall, there may be some exceptions to this.

In the long term, we should refactor the event waiting loops to not rely on TypeAhead, but more on a generic event manager, which listens to more than one kind of events.

Yes, this is a good idea.

Something else I don't like: on Linux, there is no compatibility for the EnvironmentDaemon impl. As P2J clients will be able to run on any platform (web included), I think we should at least allow LOAD/UNLOAD/GET-KEY-VALUE/PUT-KEY-VALUE/SYSTEM-DIALOG to work - registry access outside Windows OS can be restricted.

You're right.

#138 Updated by Greg Shah over 9 years ago

add multiple driver support at runtime, to allow writing to streams. This is somehow tricky, as same widget can be referenced both in GUI and ChUI modes... the widget registry might need to be maintained for all available drivers.
we need to make the window configuration details (like border width, insets, window title color, etc - all OS-related stuff which can't be set via the WINDOW handle) configurable.
finish window popup menu impl (i.e. drawing/actions/etc)

Please create tasks for these.

4GL mouse events - not sure if we need this or not

Yes, these are needed. Both 3-button and portable mouse events are used in this application.

even if PUT SCREEN is documented as being ChUI specific, it still works in GUI.

Do you have a testcase that shows this. I tried to make it work. It did not display anything (but it did not cause an error either).

when redirecting the unnamed output stream to a paged terminal (i.e. OUTPUT TO TERMINAL PAGED), then the GUI is switching in a "pseudo-terminal" mode: it is using a dedicated canvas which overlays all existing widgets, to output data. If the GUI client code does not rely on it, we can postpone/avoid it.

You are describing a 4GL feature here? Do you have a testcase that I can look at?

4GL does not allow window closing via the OS window close button. Not sure about dialogs.

Doesn't it still generate the WINDOW-CLOSE 4GL event? It is very common to have code like ON WINDOW-CLOSE OF FRAME my-frame and this app does it thousands of times.

The other caption buttons (and OS actions that cause the same result) will also generate these:

WINDOW-MAXIMIZED
WINDOW-MINIMIZED
WINDOW-RESIZED
WINDOW-RESTORED

#139 Updated by Greg Shah over 9 years ago

Code Review 0808b

My only concern is with the previous ThinClient.waitForEvent() change:

1. Why isn't honorServerEvent used at the bottom to protect the evt = EventManager.getServerEvent(); code as in the current TC version?

2. Can evt != null && !(evt instanceof KeyInput) in the else block on line 11275? If so, then that changes the behavior of this method.

3. This code seems unsafe/incorrect:

            else if (EventManager.hasMouseEvents())
            {
               evt = EventManager.getMouseEvent();
            }

Shouldn't this code look like this:

            else if (EventManager.hasMouseEvents())
            {
               applyWorker(EventManager.getMouseEvent());
            }

or

            else if (EventManager.hasMouseEvents())
            {
               continue;
            }

Otherwise the applyWorker() won't be called. Actually, I don't understand the idea of having this code here in general, since it can only execute on one more mouse event unless the continue is used.

#140 Updated by Greg Shah over 9 years ago

Two other thoughts:

1. When the ui/chui/ code reaches a state where:

  • It only has ChUI-specific code left in it.
  • It only have common-code left in it.

then we should move that code out of ui/chui/ and into the new/proper client hierarchy.

2. When we remove a file and create a new one based substantially on that original, this should be done with the bzr rename command. This will ensure that the version history is maintained.

#141 Updated by Constantin Asofiei over 9 years ago

Greg Shah wrote:

There were two reasons I've changed them this way:

No, your reasons make sense. Please put your 2 points into the file as comments.

Done.

My concern is more in regards to how this will work with other widgets, most of which are mouse aware in some form. For example, does a MOUSE-SELECT-DOWN event occur before a button widget displays as "pushed down"?
...
The default behavior for widgets is often after all of the Progress event processing occurs, so that NO-APPLY triggers can bypass the default. If I recall, there may be some exceptions to this.

I think mouse events is a beast of its own, and it's worth its own task. I should have been more explicit, the mouse support I added was related only to driver integration. The legacy support of mouse events was not touched at all... this will require testing and maybe some redesign (if i.e. the Swing-style events provided by the mouse event interfaces do not map on the 4GL behavior).

Please create tasks for these.

Done - see #2368, #2369, #2370

Even if PUT SCREEN is documented as being ChUI specific, it still works in GUI.

Do you have a testcase that shows this. I tried to make it work. It did not display anything (but it did not cause an error either).

See this:

DEF VAR i AS INT.

DISPLAY "abcdef" AT ROW 5 COL 1 WITH FRAME f1 SIZE 10 BY 10.

PUT SCREEN ROW 1 COL 1 "1".

The idea was that this proves that GUI still handles the PUT SCREEN. But we need to make sure that the client code relies on this, before digging into this... as this looks like more of a "bug" feature than a recommended/official one.

when redirecting the unnamed output stream to a paged terminal (i.e. OUTPUT TO TERMINAL PAGED), then the GUI is switching in a "pseudo-terminal" mode: it is using a dedicated canvas which overlays all existing widgets, to output data. If the GUI client code does not rely on it, we can postpone/avoid it.

You are describing a 4GL feature here? Do you have a testcase that I can look at?

See this:

DEF VAR i AS INT.

DISPLAY i WITH FRAME f1.
PAUSE.

DEF STREAM rpt.
OUTPUT STREAM rpt TO TERMINAL PAGED.
DO i = 1 TO 2:
   DISPLAY STREAM rpt i.
   DOWN STREAM rpt 1.
END.
DISPLAY i WITH FRAME f1. /* this shows warning that terminal output can't be mixed with paged/non-paged*/
OUTPUT STREAM rpt CLOSE.

MESSAGE string(FRAME f1:VISIBLE).

See how the terminal switches to a white background instead of gray. More, the underlying frame is hidden and it looks like it doesn't allow direct access to the terminal.

Doesn't it still generate the WINDOW-CLOSE 4GL event? It is very common to have code like ON WINDOW-CLOSE OF FRAME my-frame and this app does it thousands of times.

I didn't digg into the legacy window events, but a quick test like this:

def var ch as char.
enable ch with frame f1.
wait-for window-close of frame f1.

shows that the window close button does trigger this event.

The other caption buttons (and OS actions that cause the same result) will also generate these:

OK, I think is worth of adding a dedicated task for this, as the behavior is isolated enough to not interfere with other parts.

My only concern is with the previous ThinClient.waitForEvent() change:

All your points are valid. The code in ThinClient.waitForEvent() evolved quite a lot during testing/impl, and I forgot to recheck it.

I'm putting this update into a final harness run, to make sure it doesn't break anything else. A previous version did pass, so I expect this one to be OK.

#142 Updated by Vadim Gindin over 9 years ago

I would summarize behavior rules of *-WINDOW system handles as follows.

Handles itself.

1. When the 4GL starts, the initial system handle window values (CURRENT-WINDOW, DEFAULT-WINDOW and ACTIVE-WINDOW) are all the same.
2. DEFAULT-WINDOW cannot be assigned/changed
3. ACTIVE-WINDOW is being changed when user makes some window active manually at a time of execution ENTRY trigger.
After trigger is executed it ACTIVE-WINDOW takes CURRENT-WINDOW value.
4. After manual setting CURRENT-WINDOW, ACTIVE-WINDOW is changed also.
5. Failed window handles as the values of ^-WINDOW handles. There are errors happened during the tries to assign invalid values for THIS-PROCEDURE:CURRENT-WINDOW or CURRENT-WINDOW:
!**Unable to assign widget to CURRENT-WINDOW. (3130) or ** Unable to set attribute CURRENT-WINDOW of procedure widget. (4078)
6. THIS-PROCEDURE:CURRENT-WINDOW remains uninitialized until it will be initialized manually and holds it value till the end of external procedure.
7. If CURRENT-WINDOW, THIS-PROCEDURE:CURRENT-WINDOW and IN WINDOW... are set to an unrealized window then these unrealized windows are ignored and the DEFAULT-WINDOW is used instead.

Behavior of different statements

Common precedence order is IN WINDOW, THIS-PROCEDURE:CURRENT-WINDOW, CURRENT-WINDOW, DEFAULT-WINDOW.

1. PAUSE and MESSAGE uses CURRENT-WINDOW and when it points to unrealized window there are no output even in DEFAULT-WINDOW
2. When target window does not contain message line MESSAGE shows alert-box with title "Message" as it does with VIEW-AS ALERT-BOX
3. When the output is redirected message got into output file independent of IN WINDOW clause only if VIEW-AS ALERT-BOX is not specified
4. When there are no status line in the target window STATUS, PAUSE and HELP does not output anything.
5. In most statements CURRENT-WINDOW is used. If THIS-PROCEDURE:CURRENT-WINDOW is specified it used instead.
Exception: PAUSE and STATUS statements, that ignore THIS-PROCEDURE:CURRENT-WINDOW

#143 Updated by Hynek Cihlar over 9 years ago

Constantin Asofiei wrote:

The position of a widget can be set via both character-based and pixel-based coordinates (COLUMN and ROW attributes or X and Y attributes). From these, only the X and Y coordinates are static: once set, they do not change with the font; COLUMN and ROW attributes are converted to pixels, based on the default font.

Constantin, what would be the use case for a widget to change character values while retaining pixel values with a font change?

#144 Updated by Vadim Gindin over 9 years ago

Here is the first skeleton of implementation system handles ^-WINDOW. Could you look at it. I've added window Id parameter only for pause method at this moment. It also contains stub method LogicalTerminal.isWindowRealized and does not include usage of window Id in ThinClient.pause() method

Questions.

1) Is conception right?
2) I need to define if some window is realized or not on server side (see LogicalTerminal.isWindowRealized())
3) How to define target window in client-side? See ThinClient.pauseBeforeHide() or others methods. I need to set a value of new pause(...) parameter. Should I ask server-side (LogicalTerminal) for that?

#145 Updated by Greg Shah over 9 years ago

The idea was that this proves that GUI still handles the PUT SCREEN. But we need to make sure that the client code relies on this, before digging into this... as this looks like more of a "bug" feature than a recommended/official one.

Agreed. We won't work this right now. The task created is #2372.

See how the terminal switches to a white background instead of gray. More, the underlying frame is hidden and it looks like it doesn't allow direct access to the terminal.

Interesting. This is all caused by the PAGED option when the "terminal" is opened as a stream. I suspect this feature is used heavily for reporting purposes. Please add a task for this one in milestone 12.

The other caption buttons (and OS actions that cause the same result) will also generate these:

OK, I think is worth of adding a dedicated task for this, as the behavior is isolated enough to not interfere with other parts.

Agreed, please add a task.

#146 Updated by Greg Shah over 9 years ago

Code Review ca_upd20140808c.zip

The changes are OK.

#147 Updated by Greg Shah over 9 years ago

Code Review vig_upd20140810a.zip

The approach is moving in the right direction.

1. I would prefer to use an int instead of Integer for the window ID, as it is more efficient in each call to/from the client. We have done some analysis on what possible values can be for the "widget ID address space". Please see #1791 for some details. The idea right now is to have 1 be used as the default window and all other widgets (including other created windows) would be allocated a positive value starting at 2. A -1 can be used to denote an unknown or null value.

2. The LogicalTerminal.targetWindowWorker() is a good start. I wonder if you need to also pass any IN WINDOW value, so that it can be checked for realization, thus using a "fallback" when needed. The fallback behavior of this case is not obvious from your previous findings, so you may need some more testcases here:

7. If CURRENT-WINDOW, THIS-PROCEDURE:CURRENT-WINDOW and IN WINDOW... are set to an unrealized window then these unrealized windows are ignored and the DEFAULT-WINDOW is used instead.

It isn't clear what happens if only the IN WINDOW reference is unrealized while the others (e.g. CURRENT-WINDOW) are realized.

3. isWindowRealized() seems like it would be best implemented inside the Window widget itself, since it is state about the window.

4. The external LogicalTerminal.pause*() methods need support added for IN WINDOW. This will flow through the APIs to the worker too.

5. Frame.java needs a history entry.

6. UiUtils.locateParentWidget() is missing javadoc for the 2nd parameter.

In regard to your questions:

1) Is conception right?

Yes.

2) I need to define if some window is realized or not on server side (see LogicalTerminal.isWindowRealized())

Yes.

Generally, realization is caused by some server-side invocation that then is pushed down to the client. If there are cases where there is some implicit behavior on the client that causes realization indirectly, then we may need some state synching to make this work.

Constantin: can you think of any such case?

3) How to define target window in client-side? See ThinClient.pauseBeforeHide() or others methods. I need to set a value of new pause(...) parameter. Should I ask server-side (LogicalTerminal) for that?

In the ThinClient cases that pass null to pause(), you will need to write test cases that show how such "implicit pause" cases behave in a multi-window environment.

#148 Updated by Constantin Asofiei over 9 years ago

Hynek Cihlar wrote:

Constantin Asofiei wrote:

The position of a widget can be set via both character-based and pixel-based coordinates (COLUMN and ROW attributes or X and Y attributes). From these, only the X and Y coordinates are static: once set, they do not change with the font; COLUMN and ROW attributes are converted to pixels, based on the default font.

Constantin, what would be the use case for a widget to change character values while retaining pixel values with a font change?

That is an old assumption, which is no longer valid: the widget location can't change with the font, as the default fonts can't be changed (even if the new window uses another environment).

#149 Updated by Hynek Cihlar over 9 years ago

Constantin Asofiei wrote:

That is an old assumption, which is no longer valid: the widget location can't change with the font, as the default fonts can't be changed (even if the new window uses another environment).

Good, this is in-line with my findings.

#150 Updated by Constantin Asofiei over 9 years ago

Greg Shah wrote:

Interesting. This is all caused by the PAGED option when the "terminal" is opened as a stream. I suspect this feature is used heavily for reporting purposes. Please add a task for this one in milestone 12.

See #2373 for the paged terminal.

The other caption buttons (and OS actions that cause the same result) will also generate these:

OK, I think is worth of adding a dedicated task for this, as the behavior is isolated enough to not interfere with other parts.

Agreed, please add a task.

See #2374 for the window events.

#151 Updated by Constantin Asofiei over 9 years ago

Greg Shah wrote:

Code Review vig_upd20140810a.zip

Some thoughts about this update:
  1. instead of UiUtils.locateParentWidget, why not use AbstractWidget.ancestor? This always returns the window in which a widget resides...
  2. ACTIVE-WINDOW (and maybe CURRENT-WINDOW too) can be driven from the client-side; check this test:
    DEF VAR ch1 AS CHAR.
    DEF VAR ch2 AS CHAR.
    
    DEF VAR h AS HANDLE.
    CREATE WINDOW h.
    
    ENABLE ch1 WITH FRAME f1 IN WINDOW h.
    ENABLE ch2 WITH FRAME f2 IN WINDOW DEFAULT-WINDOW.
    
    ON '1':U ANYWHERE
    DO:
       MESSAGE ACTIVE-WINDOW CURRENT-WINDOW DEFAULT-WINDOW.
       RETURN.
    END.
    
    WAIT-FOR CLOSE OF CURRENT-WINDOW.
    

    We have two enabled frames, each one in its own window. If 1 is pressed in frame f1 then frame f2, it will report different ACTIVE-WINDOW handles. This means that this handle either needs to interrogate the client-side OR the client-side needs to update the server-side each time the focus changes in another window.

Generally, realization is caused by some server-side invocation that then is pushed down to the client. If there are cases where there is some implicit behavior on the client that causes realization indirectly, then we may need some state synching to make this work.

Constantin: can you think of any such case?

No, I don't think so. If a window is not yet realized, then I don't think it can even contain widgets (AFAIK the WINDOW attribute is not settable for frames). More, if the DEFAULT-WINDOW is unrealized, then it will become realized only when some statement explicitly targets it; and I think implicit usage of this window (by i.e. the final Procedure complete. Press space-bar to continue. message/pause shown at end of program) will not make the window realized:

DEF VAR ch1 AS CHAR.
DEF VAR ch2 AS CHAR.

FORM ch1 WITH FRAME f1.

DEF VAR h AS HANDLE.
DEF VAR h2 AS HANDLE.

CREATE WINDOW h.
CREATE WINDOW h2.

ENABLE ch1 WITH FRAME f1 IN WINDOW h.
ENABLE ch2 WITH FRAME f2 IN WINDOW h2.

ON '1':U ANYWHERE
DO:
   MESSAGE ACTIVE-WINDOW CURRENT-WINDOW DEFAULT-WINDOW.
   RETURN.
END.

UPDATE ch2 WITH FRAME f2 IN WINDOW h2. 

until "1" is pressed to realize the default-window, the default-window will not be visible. But this doesn't mean the window does not exist: is there, the default-window handle has a valid value.

#152 Updated by Constantin Asofiei over 9 years ago

Constantin Asofiei wrote:

  1. ACTIVE-WINDOW (and maybe CURRENT-WINDOW too) can be driven from the client-side; check this test:

This was already stated in previous notes, disregard.

#153 Updated by Vadim Gindin over 9 years ago

Greg Shah wrote:
..

3. isWindowRealized() seems like it would be best implemented inside the Window widget itself, since it is state about the window.

Window is a client-side class, but I need to call it on server-side. Do you mean WindowWidget or exactly Window?

4. The external LogicalTerminal.pause*() methods need support added for IN WINDOW. This will flow through the APIs to the worker too.

I just started to add corresponding window Id to pause* methods - only tried to add to one of them. Is it right?

#154 Updated by Greg Shah over 9 years ago

Do you mean WindowWidget or exactly Window?

I mean WindowWidget.

4. The external LogicalTerminal.pause*() methods need support added for IN WINDOW. This will flow through the APIs to the worker too.

I just started to add corresponding window Id to pause* methods - only tried to add to one of them. Is it right?

What I mean is that we must add new method signatures for the optional cases where the PAUSE language statement has an IN WINDOW specified. We don't need to change the current signatures, but we must add new signatures to allow the following:

PAUSE IN WINDOW h.
PAUSE 5 IN WINDOW h.
PAUSE MESSAGE "my message" IN WINDOW h.
PAUSE NO-MESSAGE IN WINDOW h.
PAUSE 10 MESSAGE "my message" IN WINDOW h.
PAUSE 10 NO-MESSAGE IN WINDOW h.
PAUSE BEFORE-HIDE IN WINDOW h.
PAUSE 5 BEFORE-HIDE IN WINDOW h.
PAUSE BEFORE-HIDE MESSAGE "my message" IN WINDOW h.
PAUSE BEFORE-HIDE NO-MESSAGE IN WINDOW h.
PAUSE 10 BEFORE-HIDE MESSAGE "my message" IN WINDOW h.
PAUSE 10 BEFORE-HIDE NO-MESSAGE IN WINDOW h.

This means that we need a pause(handle) and a pause(character, handle) and a pause(String, handle) and ...

It also means that pauseWorker() will need changing.

#155 Updated by Vadim Gindin over 9 years ago

About my question 4 in the note 144. I will need to know not only default window from the client (static method Window.getDefaultWindow()), but also active and current window or I will need to call server-side method to know target window from the client-side. It will be needed for these pause methods like pauseBeforeHide and pauseBeforeEnd (they are defined in ClientExports) and for methods pauseAfterPage and stopNoAvailableWidgets. Testing target statements are not clear for me at this moment. Except that I wanted to ask in my question 4 what method is preferable?

#156 Updated by Greg Shah over 9 years ago

I will need to know not only default window from the client (static method Window.getDefaultWindow()), but also active and current window or I will need to call server-side method to know target window from the client-side.

The default window is always known on the client. I think the active window is also always already known on the client, right?

The question is: do we need to know the current window for the implicit PAUSE cases? I think we can only know this with some testcases. Once you know that, we can decide on an approach. If possible, it is best to not have this information on the client (especially because it may also require that we honor the precedence hierarchy on the client side, which adds complexity).

But if we do need it there, then there are multiple ways to get it there. But first let's know if we need it or not.

#157 Updated by Hynek Cihlar over 9 years ago

Constantin Asofiei wrote:

We need to decide what is the policy of pushing a certain widget config to the client:
  1. create APIs to push only that config to the client (i.e. only the window title, not the full config)
  2. always sync the client-side config with the server-side config (via ClientState messages) - so when the server-side pushes the config, it will always have the latest values
  3. something else.

A three-way merge? Keeping a read-only copy of the last config state locally. When new config is pushed from the other side the state is compared to the saved config state. This would allow to determine what has changed remotely and locally and act accordingly.

#158 Updated by Greg Shah over 9 years ago

Hynek Cihlar wrote:

Constantin Asofiei wrote:

We need to decide what is the policy of pushing a certain widget config to the client:
  1. create APIs to push only that config to the client (i.e. only the window title, not the full config)
  2. always sync the client-side config with the server-side config (via ClientState messages) - so when the server-side pushes the config, it will always have the latest values
  3. something else.

A three-way merge? Keeping a read-only copy of the last config state locally. When new config is pushed from the other side the state is compared to the saved config state. This would allow to determine what has changed remotely and locally and act accordingly.

It is an interesting idea.

Any state sync/merge approach should be implemented generically. In other words, we don't want to duplicate the core sync/merge logic in every class that has data needing sync/merge. We could potentially use reflection but that is slow, so I would rather have hard coded worker methods. It would be OK to have such classes potentially extend a base class that provides services and only have to implement a small number of abstract and simple worker methods. The config classes already implement the Externalizable interface for serialization. That could be enhanced to only send the diffs. A space-efficient and performant approach might be to encode a bit field that specifies which fields are being sent. That bit field would always be sent as the first data serialized. There would be 1 bit for each member of the config class. If the member's corresponding bit is set in that field, then the other side knows that it is present in the serialized stream. We would have to work out the snapshot process as well, I guess that can be driven from the Externalizable methods too (that is the best time to capture/replace a snapshot).

Another approach is to use Java's dynamic proxy facilities. The cost of this is that we need a bean-like interface for each config class. This would have getters and setters for each member. The implementation of this interface is not needed as that can be done with a generic invocation handler and a map. I don't like this approach since it "gives up" one of the things we are looking for in #2254, which is moving to a simple container approach for the config classes. This would require every member to be accessed only as getter/setter methods. If only Java had a way to dynamically proxy data members, we would be able to do this very cleanly.

Starting in Java 7, the new java.lang.invoke package (and its MethodHandle facility) has some very nice features. In particular, you can use it to obtain a kind of variable reference that is faster than using reflection, but which is still "linked" at runtime instead of by the compiler. But it doesn't give us the facility be need to detect arbitrary direct assignments to those members. On the other hand, it might give us some ability to have common worker code for the snapshot and snapshot comparison/bitfield calculation.

Constantin is working on this problem right now, including the rework of the config classes in #2254.

#159 Updated by Hynek Cihlar over 9 years ago

I would like to do some real work (read code changes) on the GUI coordinate support (#2323). The following are the steps I want to start with. Somebody please validate this also in respect to the other ongoing related tasks.

  • Change the int data type to double for all existing data structures and attributes holding character coordinate values.
  • Introduce new data types to hold pixel coordinate value (Point, Dimension, etc.), if needed and implement missing pixel attributes if any.
  • Abstract server coordinate logic if needed. But hopefully all or most of the server logic will stay in character coordinates.
  • TBD (client-server coordinate state synchronization, character-pixel conversion on the server)

I want to avoid boxing/unboxing so whenever possible I want to use the Java primitive types for representing the character and pixel coordinate values even if this will mean some amount of code duplication (unable to use generics, etc.).

#160 Updated by Vadim Gindin over 9 years ago

About PAUSE statements list. Only following statements with BEFORE-HIDE are correct from the Progress point of view:

PAUSE BEFORE-HIDE IN WINDOW h.
PAUSE 5 BEFORE-HIDE IN WINDOW h.
PAUSE BEFORE-HIDE MESSAGE "my message".
PAUSE BEFORE-HIDE NO-MESSAGE.
PAUSE 5 BEFORE-HIDE NO-MESSAGE.

Others lead to CPE.

About implementation. ClientExports contains 1 pause() method and 1 pauseBeforeHide() method. Am I understand correctly that new methods with window handle in those signatures should be added to LogicalTerminal like I did in my update? Take a look at it please.

About special pause cases. Methods pauseBeforeEnd and pauseAfterPage and other internal pause calls.
1) Frame.moveCursor() calls ThinClient.pause method in it's internal class
2) ErrorWriterInteractive.pause() calls ThinClient.pause method.
3) LogicalTerminal.scopeStart calls ThinClient.pauseBeforeEnd method.
4) TerminalStream.teletype calls ThinClient.pauseAfterPage method

How to test behavior of such internal pause usages?

P.S.
It seems NO-ERROR is not applicable to PAUSE. Simple statement PAUSE NO-ERROR. raises CPE error. How to find out if it sets ERROR-STATUS-ERROR flag or not?

#161 Updated by Greg Shah over 9 years ago

Change the int data type to double for all existing data structures and attributes holding character coordinate values.

Yes.

Introduce new data types to hold pixel coordinate value (Point, Dimension, etc.), if needed

Yes.

and implement missing pixel attributes if any.

I was going to be implementing some of these in the window widget, but I have been consumed with other things. You should go ahead with these changes as needed. Just let me know about any changes you make in window so I don't duplicate work.

Abstract server coordinate logic if needed.

Yes.

But hopefully all or most of the server logic will stay in character coordinates.

Very much YES.

TBD (client-server coordinate state synchronization, character-pixel conversion on the server)

Constantin is definitely working on the client-server state sync issue.

As you say, the character-pixel conversion on the server is TBD. Constantin will need to be involved with any discussions in that area, but he is out until next Thursday.

I want to avoid boxing/unboxing so whenever possible I want to use the Java primitive types for representing the character and pixel coordinate values even if this will mean some amount of code duplication (unable to use generics, etc.).

Agreed.

I would like to do some real work (read code changes) on the GUI coordinate support (#2323).

Yes, please do so.

Also, do check in your testcases.

#162 Updated by Hynek Cihlar over 9 years ago

Greg Shah wrote:

Also, do check in your testcases.

Due to the customer server outage I have committed the test cases just now. Please see uast/gui_coordinates dir.

#163 Updated by Greg Shah over 9 years ago

I will handle the code review for vig_upd20140815a.zip shortly.

Only following statements with BEFORE-HIDE are correct from the Progress point of view:

I don't understand what you mean here. For example, this version without BEFORE-HIDE is valid:

pause message "what" in window current-window.

Others lead to CPE.

What is "CPE"?

About special pause cases. Methods pauseBeforeEnd and pauseAfterPage and other internal pause calls.
1) Frame.moveCursor() calls ThinClient.pause method in it's internal class

DOWN processing causes this when the down frame is full and it is about to "scroll" and clear the iterations.

2) ErrorWriterInteractive.pause() calls ThinClient.pause method.

Error display processing

3) LogicalTerminal.scopeStart calls ThinClient.pauseBeforeEnd method.

This occurs when the global scope is exiting. In other words, when the entire application is exiting.

4) TerminalStream.teletype calls ThinClient.pauseAfterPage method

This is used for "redirected output" to the terminal, which is a weird case that is not exactly a stream and it is not exactly the terminal. When the page gets full, there will be an implicit pause (similar to DOWN processing).

It seems NO-ERROR is not applicable to PAUSE. Simple statement PAUSE NO-ERROR. raises CPE error. How to find out if it sets ERROR-STATUS-ERROR flag or not?

Some statements don't allow NO-ERROR. As far as we know, if you can't use NO-ERROR then there won't be any changes to ERROR-STATUS:ERROR.

#164 Updated by Vadim Gindin over 9 years ago

Greg Shah wrote:

I will handle the code review for vig_upd20140815a.zip shortly.

Only following statements with BEFORE-HIDE are correct from the Progress point of view:

I don't understand what you mean here. For example, this version without BEFORE-HIDE is valid:

[...]

I only wanted to say that some forms of PAUSE statement with clause BEFORE-HIDE from the list in the note №154 are not valid and will not be executed by Progress. For example, that one:

PAUSE BEFORE-HIDE MESSAGE "my message" IN WINDOW h.

Others lead to CPE.

What is "CPE"?

CPE - Compile Error.

#165 Updated by Greg Shah over 9 years ago

Code Review vig_upd20140815a.zip

The only thing I would like to see changed is to move the common hWin processing code from pauseBeforeHide(double, String, handle) and pauseWorker() and to put that common code into targetWindowWorker().

Am I understand correctly that new methods with window handle in those signatures should be added to LogicalTerminal like I did in my update? Take a look at it please.

Yes, this is exactly what I was looking for.

#166 Updated by Vadim Gindin over 9 years ago

I've tested implicit pause cases, listed in the note №160. Implicit Pause behaves exactly as explicit: uses CURRENT-WINDOW. In such situations ACTIVE-WINDOW always equal CURRENT-WINDOW. I'll commit tests little later.

I've also updated LogicalTerminal and moved common code to targetWindowWorker. I can't remember method to find resource type for example "BUTTON". Could you recall me?

Also, should I add some client implementation for PAUSE statement at this step or I should go forward with some other statement?

#167 Updated by Greg Shah over 9 years ago

Code Review 0820a

The changes look fine.

Implicit Pause behaves exactly as explicit: uses CURRENT-WINDOW.

That means we will need to keep track of (or sync) CURRENT-WINDOW on the client.

What happens if CURRENT-WINDOW is unrealized?

I can't remember method to find resource type for example "BUTTON". Could you recall me?

Please see CommonHandle.getResourceType() and the LegacyResource.java. These implement the TYPE annotation, which is probably what you are looking for.

Also, should I add some client implementation for PAUSE statement at this step or I should go forward with some other statement?

Yes, get the client implementation done next. That will allow us to put the needed infrastructure in there and the "entire picture" will be pretty clear. From there, adding more statements is pretty easy.

But I think it makes sense to get the current update tested and checked in on its own.

#168 Updated by Vadim Gindin over 9 years ago

What happens if CURRENT-WINDOW is unrealized?

DEFAULT-WINDOW is used

I've added some client implementation for pause. It also affects status methods because it uses status line as these methods. Please take a look.

#169 Updated by Greg Shah over 9 years ago

Code Review 0821a

I like the way this is going. Moving the Window functionality from static to non-static is clean and makes sense.

1. The history entry for ThinClient should say something like: "Added multi-window support for pause implementation.".

2. I think you can remove the TODO in LT.targetWindowWorker() now that you have added the type lookup.

What happens if CURRENT-WINDOW is unrealized?

DEFAULT-WINDOW is used

Does this also honor THIS-PROCEDURE:CURRENT-WINDOW? In other words, can the precedence hierarchy have to be fully processed on the client side?

#170 Updated by Vadim Gindin over 9 years ago

Previous update passed regression testing. Can I commit it?

#171 Updated by Greg Shah over 9 years ago

Previous update passed regression testing. Can I commit it?

Yes, please do.

#172 Updated by Vadim Gindin over 9 years ago

Committed to bzr with rev 10600.

#173 Updated by Constantin Asofiei over 9 years ago

About note 157/158, the work for #2254 and sync'ing the server and client-side widget states. Unfortunately, there is no way of hooking up a listener and notify if a class field has been set/changed, via Java APIs, without relying on dynamic proxies or complicating things by using property listeners. I think there is a way around it, and as Hynek mentioned, use a "three-way merge". An important goal is to no duplicate the widget attributes, so that we end up with a set of attributes maintained (via explicit instance fields) on server-side classes and a different set maintained on the client-side classes. My goal is to centralize the storage of these attributes and use them for everything: transport, client-side logic, server-side logic. I think this can be done this way:
  1. all widget attributes are kept in dumb classes with only public members. But a class hierarchy will still exist: common attributes will be in base class, and specific attributes will be in widget-specific classes.
  2. there is a central repository of these classes where, for each widget, two copies are kept: one is for the last state received from the remote side (the "backup" config) and one for the current state on the local side (the "active" config).
  3. when control is switched from one side to another, two actions are performed:
    - on the side which loses control, the active and backup configs are compared and only the differences are sent to the other side. We will need to find a way to handle the unknown 4GL state (which can be allowed for some attributes, or in cases when they are not yet initialized).
    - on the side which receives control, the changes are applied to the active config and the backup config is replaced with a copy of the active config
  4. any widget resource requiring access to these attributes (from either server or client side) will interrogate the central repository which will always return the active config.
  5. the server-side and client-side specific logic from the WidgetConfig classes can be moved to the specific widget impl

In this scenario, we are eliminating redundancy between server and client-side widget classes (in terms of maintaining the code for these attributes) and we can get rid of the WidgetConfig classes, too.

About transferring the differences to the other side (note that a bit-field is limited to max 64 entries, and at least WINDOW widget has 75 attrs): we have two choices to avoid sending the attribute name to the other side, each with its own downside(s):
  1. automatically associate each field in each class with a pre-determined index, and sync this with the client-side. We can't rely on the order given by the Class.getFields API, as this is not deterministic. The down-side here is that we will need to apply the differences to the active config via reflection, as we will not know at compile time the index of each field.
  2. manually associate each field in each class with a pre-determined index. As we will have a class hierarchy, changes in a parent class might trigger renumbering of fields in a sub-class. But this can be avoided by using prefixes, as in each sub-class has its own base index from which it starts numbering (i.e. in a similar way with ID-ing widgets from frames in the current P2J code, 1000 + widget ID). When applying changes, there will be a method similar to what WidgetConfig.applyConfig does now, but instead of receiving another WidgetConfig instance, it will receive an attr index plus a new value for that attr, and the attribute will be set explicitly (by a big switch block) or the parent applyConfig will be called, if the base index is not for this class.

If we can live with the small overhead of using reflection when updating the differences, then I think case 1 is best in terms of code maintenance.

#174 Updated by Constantin Asofiei over 9 years ago

About ca_upd20140808c.zip: as code touched by this update seems to be affected by other tasks, I think I should release this one.

#175 Updated by Greg Shah over 9 years ago

About ca_upd20140808c.zip: as code touched by this update seems to be affected by other tasks, I think I should release this one.

OK, release it.

#176 Updated by Greg Shah over 9 years ago

any widget resource requiring access to these attributes (from either server or client side) will interrogate the central repository which will always return the active config.

I assume that users of these instances only need to query the central repository once and then that reference will be good for the lifetime of the widget? In other words, the active reference will not change over time, only the state inside that object.

About transferring the differences to the other side (note that a bit-field is limited to max 64 entries, and at least WINDOW widget has 75 attrs): we have two choices to avoid sending the attribute name to the other side, each with its own downside(s):

We can always use 2 bit fields or an array of bytes of a size that is appropriate for the class being processed.

If we can live with the small overhead of using reflection when updating the differences, then I think case 1 is best in terms of code maintenance.

Normally, I would be willing to start with this approach. But this code will be very performance sensitive, since it will be called constantly. Perhaps the MethodHandle approach may be a good middle ground. It requires one time setup code to create the instances but using them is faster than the fully dynamic reflection APIs.

You can go ahead with the implementation.

#177 Updated by Constantin Asofiei over 9 years ago

Greg Shah wrote:

About ca_upd20140808c.zip: as code touched by this update seems to be affected by other tasks, I think I should release this one.

OK, release it.

Attached is replacement for ca_upd20140808c.zip (merged with rev 10601) and released as rev 10602.

#178 Updated by Vadim Gindin over 9 years ago

I faced with the following problems.

1) We probably do not need to use contsant session window ID everywhere or we should just try to avoid that and use:
Window defw = Window.getDefaultWindow();
int defwId = UiUtils.getWidgetId(defw);

After some moment I update to the last version of p2j and faced with the problem during execution. See attached error log. One of them is the usage of constant WindowConfig.SESSION_WINDOW_ID. The second one is in some cases there are not registered window in the registry. I added processDefaultWindow call in such case.

2) The problem is during execution there new windows are created for every pause method call. It because of window IDs problem. If I remember correctly window ID is not the same in the client side or server side.

ThinClient.pushWindow => Window.pushConfig => ...

In this method we are firstly search window by ID from the config. It is not found and we are creating new window for each pause call.

How to get correct window Id or how to get correct window on the client side in this case.

3) Is current window added correctly to the client-side.

I've added current window handle to Window but I'm nut sure if it is correct and where to set it when it being changed (in the code).

4) Window ID on the server side is long. I changed our methods correspondingly. But on the client-side widget id is int. I also cant trim long to trim without data lost.

5) I added getWidget method to WindowRegistry but WindowManager.findWindow also seemed as doing similar thing. But once again it uses int and I got long value from the server-side that cannot be converted to int without data lost.

#179 Updated by Vadim Gindin over 9 years ago

6) StatusLineGuiImpl.draw is not called at all and message string is not displayed in the status line of any open windows. Don't understand why.

#180 Updated by Greg Shah over 9 years ago

Code Review 0827a

1. In GuiOutputManager you ask // TODO added to try. Fix this later. Was WindowConfig.SESSION_WINDOW_ID. Why only this ID?.

The simple answer is that we currently only support a single window that is the default window. Since the old code only supported ChUI, and ChUI only has that one window, everything worked. Now we are implementing GUI and things must change. Your job with #2229 is to enable multiple window support. In other words, you must fix this design limitation.

2. You ask:

1) We probably do not need to use contsant session window ID everywhere or we should just try to avoid that and use:
Window defw = Window.getDefaultWindow();
int defwId = UiUtils.getWidgetId(defw);

We can go ahead and use the session window ID where the functionality actually does need it. But I think this should generally be only used in:

  • a worker method that processes the precedence hierarchy on the client-side (if needed)
  • client functionality that always uses the session window and doesn't ever honor current-window

You never answered my previous question:

What happens if CURRENT-WINDOW is unrealized?

DEFAULT-WINDOW is used

Does this also honor THIS-PROCEDURE:CURRENT-WINDOW? In other words, can the precedence hierarchy have to be fully processed on the client side?

This is important to know how much state needs to be duplicated to the client. Without this we also really don't know how Window.resolveWindow() needs to work.

3. We have task #1791 which is designed to enable dynamic widget support. I think some of the problems you are having are caused by the fact that our dynamic widget support is not complete yet. It works only for conversion/compilation but the runtime is known to be incomplete.

The problem is during execution there new windows are created for every pause method call. It because of window IDs problem.

I think this is probably a consequence of the broken dynamic widget support.

If I remember correctly window ID is not the same in the client side or server side.

No, this is incorrect. The window IDs should be assigned on the server and should be visible as the same IDs on the client.

In addition, Eugenie is reworking the widget ID processing right now. He is making changes to code that you are also changing. Please look at his work and at the discussions in that task to understand how this affects things.

4. In regard to client-side current-window support:

I've added current window handle to Window but I'm nut sure if it is correct and where to set it when it being changed (in the code).

Well, it is OK to maintain this in the Window class like you do. However, it needs to be synchronized with the state on the server. To understand how we synchronize state, please see:

ui/ClientState
ui/ServerState
ui/LogicalTerminal (both getChanges() and applyChanges())
ui/chui/ThinClient (both getChanges() and applyChanges())
net/StateSynchronizer
net/Protocol (see registerSynchronizer(), attachChanges() and applyChanges())

The basic idea is to "piggyback" the transfer of state changes on the next message sent to the other side. By timing the apply process on the target side such that it is before any possible use of that state, it appears to the code like the state is always synchronized with the version on the other side.

5. Window IDs don't need to be a long on the server side. These should just be an int. This will eliminate other changes like the ClientExports changes.

6. For WidgetRegistry can't getComponent() be used instead of your new getWidget()?

I added getWidget method to WindowRegistry but WindowManager.findWindow also seemed as doing similar thing.

Do you mean WidgetRegistry instead of WindowRegistry?

I want us to keep the window instances in the WidgetRegistry just like we keep the frames and other widgets. If we need a separate WindowRegistry, we can also maintain that separately. That should solve this issue.

7. In regard to the status line issue, our status line is not fully working in GUI yet.

#181 Updated by Vadim Gindin over 9 years ago

I retested implicit pause cases and PAUSE BEFORE HIDE statement to research behavior of THIS-PROCEDURE:CURRENT-WINDOW. I missed some cases before. Here are actual results:

1. Pausing during error output.
test_pause_in_error.p
DEFAULT_WINDOW is unrealized. Only 3 dynamically created windows are shown. DEFAULT-WINDOW is hidden.
THIS-PROCEDURE:CURRENT-WINDOW is ignored
CURRENT-WINDOW is used
When CURRENT-WINDOW points to unrealized window - messagebox is used to display the error. I.e. all candidates are unrealized - message-box is shown. I.e. works as expected except the message-box is shown if all windows are unrealized.

2. Frame.moveCursor, impicit pause during clearing frame.
test_pause_in_clear_stat.p
It seems there are clearing logic interferes to test this case and therefore it's difficult to make conclusion. But it seems that it works as expected.

3. LogicalTerminal.scopeStart calls ThinClient.pauseBeforeEnd method. Implicit pause during before end of execution. Works as expected.

4. TerminalStream testing
OUTPUT TO TERMINAL and implicit pause in it works with CURRENT-WINDOW and THIS-PROCEDURE:CURRENT-WINDOW is ignored. DEFAULT-WINDOW is used if CURRENT-WINDOW is unrealized. Works as expected

--

Interesting founding.
DEFAULT-WINDOW can be visible only if taking part in clause IN WINDOW or contains widgets (static frames for exapmle). In other cases it is invisible.

ENABLE .. IN WINDOW makes hidden window visible. (any window).

5. Pause before hide
current-window
if unrealized - nothing outputed (in contrast with case №1)
this-procedure:current-window is ignored
default window is unrealized.
Works as expected.

Common conclusion. Implicit pause cases works as explicit pause cases. The difference is when all windows are unrealized including DEFAULT-WINDOW. THIS-PROCEDURE:CURRENT-WINDOW is ignored.

#182 Updated by Hynek Cihlar over 9 years ago

Attached are changes related to #2323 - refactor coordinate system and implement GUI coordinate support.

What's included:
  • refactoring of coordinate data types
  • 1st iteration of Chui and Gui coordinates conversion logic implementation
  • runtime resolution of coordinates conversion logic implementation (see the class hierarchy of CoordinatesConversion and OutputManagerProvider)
  • the necessary coordinates logic changes related to the refactoring of data types

Coordinates are split into character units and so-called native units. Native units are meaningful to each UI subsystem and either map to terminal character cells, characters in streams or pixels. The character data types are Point, Dimension, Rectangle and the Java primitive double. The native types are NativePoint, NativeDimension, NativeRectangle and the Java primitive int. I chose primitive types over classes for performance reasons, the downside is a limited type safety when dealing with ints and doubles.

There are TODO's embedded. If you can answer any of them please do, if not I'll hunt for the answer myself. The added classes are missing javadocs. Also file headers are not added yet.

Please review.

#183 Updated by Vadim Gindin over 9 years ago

I'm trying to test the following update with the last remarks and got strange behavior. It shows window button on the task bar but does not show the window itself. Testcase window_parenting/pause.p. Body method does not executed. Logs does not contain interesting notes (see also attached 0901.log). Could you help me - how to debug it?

P.S.
Update contains the last behavior with several TODOs. Changed Window.resolveWindow() methods, added synchronization, and some other changes are also there. Previous version ran many windows: 2 for every pause statement call. Btw pausing was working as far as I could test it with current level of implementation. Pause messages have to be shown in a status line and was not showed because status line is not fully implemented yet for GUI.

#184 Updated by Greg Shah over 9 years ago

Code Review hc_upd20140831a

Wow, that is a lot of work! It took me many hours to review that update. Generally, I am fine with the changes. I have this feedback:

1. I am worried that we need to use epsilon testing instead of using Double.compare() or directly comparing double values using operators (!=) or Double.doubleToLongBits() return values. Neither approach uses a safe comparison approach. We need to simulate a maximum of 2 digits of precision to the right of the decimal point, right? Without epsilon testing, the smallest difference will be treated as a difference in P2J when in the 4GL it would not. Of course, we will want to centralize that logic and then just be cafeful to use it everywhere comparisons of doubles will occur.

I think this is the only more serious problem in the approach. The following items are more minor in nature.

2. EditorImpl.draw() is now re-assigning the reference to start where it was not previously. Is this planned?

3. I think the TypeAhead.init() should not be in the ThinClient constructor. It was recently moved out of there and into the initializePrep() code.

4. In ColumnLayout.calcLayout(), you are merging the behavior of step and dstep into a single step var with a different calculated value and rounding. How confident are you that the new version is correct?

5. I think that DoubleBufferedTerminal.conditionalRefresh() needs the result of the nrect = nrect.intersection() call to be checked for null before using it. This same problem affects @conditionalLineRefresh() too.

6. In ChuiOutputManager.hLine(), do we need to call widthToNative() before checking the cursorInvalid?

#185 Updated by Hynek Cihlar over 9 years ago

Greg Shah wrote:

Code Review hc_upd20140831a

Wow, that is a lot of work! It took me many hours to review that update. Generally, I am fine with the changes. I have this feedback:

1. I am worried that we need to use epsilon testing instead of using Double.compare() or directly comparing double values using operators (!=) or Double.doubleToLongBits() return values. Neither approach uses a safe comparison approach. We need to simulate a maximum of 2 digits of precision to the right of the decimal point, right? Without epsilon testing, the smallest difference will be treated as a difference in P2J when in the 4GL it would not. Of course, we will want to centralize that logic and then just be cafeful to use it everywhere comparisons of doubles will occur.

Yes, you are right 0.1 + 0.2 is not equal to 0.3. The reason I didn't implement the centralized comparison logic is that it would probably not yield the correct results anyway.
(1) In the ChUI mode, the character values are rounded and the computations are performed on whole numbers. I tried to identify the places where double imprecision could give wrong results and provide the correct rounding logic (cast, round, floor, ceiling) simulate the ChUI whole number arithmetic (I admit I could miss some in the amount of changed code). This should yield the same behavior as before the change.
(2) The GUI mode is whole different story though. It all depends how 4GL calculates the floating values internally. Does it honour the two decimal places, or the default of ten decimal places, or something else? Does it use higher precision for intermediate results? Does it use consistent approach across all components? Does it even use the character coordinate values? I think this will require more detailed GUI functional testing to figure out how they do it.

2. EditorImpl.draw() is now re-assigning the reference to start where it was not previously. Is this planned?

No, this slipped through my fingers. All the changes must yield the same functional results.
Fixed.

3. I think the TypeAhead.init() should not be in the ThinClient constructor. It was recently moved out of there and into the initializePrep() code.

Right! Fixed.

4. In ColumnLayout.calcLayout(), you are merging the behavior of step and dstep into a single step var with a different calculated value and rounding. How confident are you that the new version is correct?

I probably got too creative here. I will revert it back to the original version and provide correct rounding.

5. I think that DoubleBufferedTerminal.conditionalRefresh() needs the result of the nrect = nrect.intersection() call to be checked for null before using it. This same problem affects @conditionalLineRefresh() too.

You are right. I misunderstood the meaning of the reference check and moved it up as the first statement in the function body.
Fixed.

6. In ChuiOutputManager.hLine(), do we need to call widthToNative() before checking the cursorInvalid?

No we don't, I fixed this by moving it below the conditional.

#186 Updated by Greg Shah over 9 years ago

Code Review vig_upd20140901a.zip

I am generally fine with this as an interim update.

1. Can we make the window calculation code in ThinClient.pause() into a generic worker method like we do on the server? We are going to need the same/similar logic in many places.

2. Does current-window ever change do to client-side activity (e.g. something the user can do)? If not, then we don't need to push the current-window state back to the server in ThinClient.getChanges().

3. In regard to your comment in Window: // TODO not sure how to process THIS-PROCEDURE:CURRENT-WINDOW here: I thought that THIS-PROCEDURE:CURRENT-WINDOW was not honored on the client? If it is honored, then we need to sync it from server to client (like CURRENT-WINDOW). We do NOT want to call back up to the server to get it.

#187 Updated by Greg Shah over 9 years ago

It shows window button on the task bar but does not show the window itself. Testcase window_parenting/pause.p. Body method does not executed. Logs does not contain interesting notes (see also attached 0901.log). Could you help me - how to debug it?

In such a case you generally connect the debugger to the P2J server and just set a breakpoint in the top of the execute() method for Pause.java. Step through the code until you find the difference in behavior from how the 4GL is working.

But the pause.p code is relying upon dynamic widget support to work. I don't know if our current support is sufficient to run that code. In particular, does the create window work enough to get a functional window on the client.

By the way, in the 4GL does the PAUSE statement make the newly created window visible?

#188 Updated by Greg Shah over 9 years ago

Hynek Cihlar wrote:

Greg Shah wrote:

Code Review hc_upd20140831a

Wow, that is a lot of work! It took me many hours to review that update. Generally, I am fine with the changes. I have this feedback:

1. I am worried that we need to use epsilon testing instead of using Double.compare() or directly comparing double values using operators (!=) or Double.doubleToLongBits() return values. Neither approach uses a safe comparison approach. We need to simulate a maximum of 2 digits of precision to the right of the decimal point, right? Without epsilon testing, the smallest difference will be treated as a difference in P2J when in the 4GL it would not. Of course, we will want to centralize that logic and then just be cafeful to use it everywhere comparisons of doubles will occur.

Yes, you are right 0.1 + 0.2 is not equal to 0.3. The reason I didn't implement the centralized comparison logic is that it would probably not yield the correct results anyway.
(1) In the ChUI mode, the character values are rounded and the computations are performed on whole numbers. I tried to identify the places where double imprecision could give wrong results and provide the correct rounding logic (cast, round, floor, ceiling) simulate the ChUI whole number arithmetic (I admit I could miss some in the amount of changed code). This should yield the same behavior as before the change.
(2) The GUI mode is whole different story though. It all depends how 4GL calculates the floating values internally. Does it honour the two decimal places, or the default of ten decimal places, or something else? Does it use higher precision for intermediate results? Does it use consistent approach across all components? Does it even use the character coordinate values? I think this will require more detailed GUI functional testing to figure out how they do it.

Since this is a planned approach and it is believed to be OK, it is important to mark all of these locations with 2 things:

1. Place a standardized marker in a comment, which can be searched on to find all these places again. Something like // WARNING: DOUBLE COORDINATE ROUNDING LOCATION.

2. Also add a comment that explains how the implemented code has been made safe.

Another advantage to this approach is that if someone finds a location that has rounding implications but which is not marked, they will know that the location needs some attention.

#189 Updated by Hynek Cihlar over 9 years ago

1. Place a standardized marker in a comment, which can be searched on to find all these places again. Something like // WARNING: DOUBLE COORDINATE ROUNDING LOCATION.

2. Also add a comment that explains how the implemented code has been made safe.

Another advantage to this approach is that if someone finds a location that has rounding implications but which is not marked, they will know that the location needs some attention.

Good idea, will do.

#190 Updated by Vadim Gindin over 9 years ago

Greg Shah wrote:

Code Review vig_upd20140901a.zip

I am generally fine with this as an interim update.

1. Can we make the window calculation code in ThinClient.pause() into a generic worker method like we do on the server? We are going to need the same/similar logic in many places.

This logic is placed in Window.resolveWindow().

2. Does current-window ever change do to client-side activity (e.g. something the user can do)? If not, then we don't need to push the current-window state back to the server in ThinClient.getChanges().

Ok, I'll correct it.

3. In regard to your comment in Window: // TODO not sure how to process THIS-PROCEDURE:CURRENT-WINDOW here: I thought that THIS-PROCEDURE:CURRENT-WINDOW was not honored on the client? If it is honored, then we need to sync it from server to client (like CURRENT-WINDOW). We do NOT want to call back up to the server to get it.

PAUSE ingores THIS-PROCEDURE:CURRENT-WINDOW, but other statements can honor it.

#191 Updated by Hynek Cihlar over 9 years ago

Attached is the update of hc_upd20140831a. It resolves the issues from review at notes 184 and 188.

The most important change is the explicit handling of potential loss of double significance in hc_upd20140831a. Character coordinate values are always rounded when being stored in widget/config instances. Also calculations are performed only on the rounded double values to get predictable results.

In addition to the above the change set also contains missed int->double refactorings and other related changes.

Please review.

#192 Updated by Greg Shah over 9 years ago

Code Review hc_upd20140907a.zip

I like the new Coordinate helper class. Use of it makes clear to the reader that a very specific rounding operation is intentionally being applied.

1. In many places in this update, you are moving back to int from double. A good example is src/com/goldencode/p2j/ui/chui/BrowseImpl.java. This approach means that the code is specifically being left ChUI based. We will be moving BrowseImpl and all of the rest of the current widgets into common code and abstracting the ChUI/GUI aspects into specific subclasses as needed. We have much code in these ui/chui/ classes that we intend to be common code. One of the objectives of #2323 is to abstract the coordinate system such that the current implementation is less ChUI-specific. Is it best to do those changes in a later update? What are your thoughts?

2. In DoubleBufferedTerminal line 441, rect should be nrect.

3. We already have OutputManager.isChui() and ScreenDriver.isChui(). Do we also need UiUtils.isChui() and Coordinate.isChui()?

4. I think some of the UiUtils code is now moved to Coordinate so it can be deleted.

#193 Updated by Hynek Cihlar over 9 years ago

1. In many places in this update, you are moving back to int from double. A good example is src/com/goldencode/p2j/ui/chui/BrowseImpl.java. This approach means that the code is specifically being left ChUI based. We will be moving BrowseImpl and all of the rest of the current widgets into common code and abstracting the ChUI/GUI aspects into specific subclasses as needed. We have much code in these ui/chui/ classes that we intend to be common code. One of the objectives of #2323 is to abstract the coordinate system such that the current implementation is less ChUI-specific. Is it best to do those changes in a later update? What are your thoughts?

The chance is that some of this chui specific code will not be portable to the common package and should internally work on ints. I think this will make it better maintainable. Also abstracting the code in many cases will likely require more than simply rounding the doubles. I would rather keep this for the future updates and solve it in more complex way.

2. In DoubleBufferedTerminal line 441, rect should be nrect.

Well done. Fixed.

3. We already have OutputManager.isChui() and ScreenDriver.isChui(). Do we also need UiUtils.isChui() and Coordinate.isChui()?

Good point. This is one of the open questions. The private Coordinate.isChui servers as a placeholder for a real solution.

The problem is that we will need rounding on the server side as well. So I was thinking to store the flag in the session context. I am not sure how this fits to the plans though.

4. I think some of the UiUtils code is now moved to Coordinate so it can be deleted.

Yes, I left the methods in UiUtils by mistake. Fixed.

#194 Updated by Greg Shah over 9 years ago

In regard to task #2333 (finish status area support), the following needs to be done:

  • proper font/color usage
  • proper look and feel (including resizing the status area if the window gets resized)
  • formatting (i.e. max line length, how does it work if the window is resized, etc)

#195 Updated by Vadim Gindin over 9 years ago

I was running regression testing several times. Made some fix. Here is the latest update. It passes regression testing. But there was an exception. See error log (client_vig_26776.log). I'm trying to figure out does it relates to my update or not.

#196 Updated by Greg Shah over 9 years ago

Code Review 0905a

I am fine with the changes.

But there was an exception. See error log (client_vig_26776.log). I'm trying to figure out does it relates to my update or not.

This is an already existing issue. You don't need to fix it.

I think you can check this in and distribute it.

#197 Updated by Vadim Gindin over 9 years ago

Committed to revision 10606.

#198 Updated by Vadim Gindin over 9 years ago

I'm working on status methods implementation. I'm going to move some fields from ThinClient to Window (or TitledWindow?), for exapmle "defaultMessage", "inputMessage", "statusType", "statusStack". I'm sure about all of them except "statusStack". Could you please describe its function and may be some real example.

#199 Updated by Constantin Asofiei over 9 years ago

Vadim Gindin wrote:

I'm sure about all of them except "statusStack". Could you please describe its function and may be some real example.

See this test:

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

on 1 anywhere do:
   update j help "status pushed to stack".
end.

update i help "status for i needs to be restored".

The question here is: what happens if i and j are updated in different windows?

#200 Updated by Hynek Cihlar over 9 years ago

I am attaching update to the work in progress of #2323. The change set resolves comments from review, resolves resolvable TODOs and properly documents at-the-moment unresolvable TODOs. It also contains proper Javadocs and standard file headers. I am still looking for a bug I found during regression testing - some reports have broken layouts. I expect posting an update shortly so please wait with the full review for that. I want to plan the next steps so I have enough work that would keep me busy during the weekend.

Here are the possible areas I think I could continue on without much interference with other ongoing efforts:

(1) In the change set in the file Coordinate.java - // TODO: #2323 implement GUI coordinate rounding.
GUI rounding involves conversion to pixel units and back. I have a feeling though this may depend on the client-server state synchronization.

(2) In the change set in the file Coordinate.java -// TODO: #2323 implement chui detection
Taken from the file:
// At the moment it is unknown to me whether the coordinate conversion and
// rounding services on the server-side will be implemented (a) directly or
// (b) by pushing the state change to the client where the conversion will be
// performed and the converted state feedbacked to the server.
//
// At the moment I am assuming (a) and therefore the class is designed to be
// called by both the server-side and the client-side code.
//
// The question is how to detect the ischui flag on the server?
//
// On the client we already have the method OutputManager.isChui.
// The method however requires the OutputManager instance which is resolved by
// calling the static method OutputManager.instance. instance() is a heavy-weight
// operation performing thread-synchronization. Should the flag be then somehow
// cached? The most logical place should probably be the widget instance itself.
// The API would have to be extended so that the ischui flag would be passed
// to the Coordinate methods.

(3) Start abstracting the coordinate logic for individual client components (widgets)
For this I will need to know who is working on what so we don't interfere. Also this pretty much means to fully implement the GUI widgets. I don't think it is quite doable to abstract well without knowing the implementation details of both the GUI and ChUI parts.

(4) Anything else?

#201 Updated by Greg Shah over 9 years ago

Code Review 0911a

The changes look good.

#202 Updated by Greg Shah over 9 years ago

(1) In the change set in the file Coordinate.java - // TODO: #2323 implement GUI coordinate rounding.
GUI rounding involves conversion to pixel units and back. I have a feeling though this may depend on the client-server state synchronization.

I don't see the harm in waiting for the state sync work to be completed first.

The other thing to note here is that I'm still working on a set of testcases for Window moving and sizing. I'm pretty far along with the moving part, but still not done. One thing that I can point out is the 4GL logic that I wrote for conversion between x/column and y/row:

/* the following functions encode the algorithm for translating what a given change in */
/* row/col will be when read back from the x/y and vice versa */ 

> 
function row-to-y returns int (input row-val as dec):
   return integer((row-val - (if row-val < 0 then -1 else 1)) * pixels-per-row).
end.

function y-to-row returns dec (input y-val as int):
   def var result as dec decimals 2.
   /* force rounding using assignment */
   result = (y-val / pixels-per-row) + (if y-val < 0 then -1 else 1).
   return result.
end.

function col-to-x returns int (input col-val as dec):
   return integer((col-val - (if col-val < 0 then -1 else 1)) * pixels-per-col).
end.

function x-to-col returns dec (input x-val as int):
   def var result as dec decimals 2.
   /* force rounding using assignment */
   result = (x-val / pixels-per-col) + (if x-val < 0 then -1 else 1).
   return result.
end.

I use these to check that the changes my code is making are honored. So far, this logic has been exactly correct but as I say, I'm not done yet. Note that it does properly handle negative values too.

// At the moment I am assuming (a) and therefore the class is designed to be
// called by both the server-side and the client-side code.

I think it is best to design this for use on both sides.

// The question is how to detect the ischui flag on the server?

See LogicalTerminal.icChui().

The only issue with this is that every call takes a trip down to the client to call OutputManager.isChui().

Should the flag be then somehow cached? The most logical place should probably be the widget instance itself.

Please propose a better approach (which includes caching).

The caching should occur on both client and server. I think there are cases where the same user's session may act as ChUI for the redirected output while GUI for interactive stuff, right?

(3) Start abstracting the coordinate logic for individual client components (widgets)
For this I will need to know who is working on what so we don't interfere. Also this pretty much means to fully implement the GUI widgets. I don't think it is quite doable to abstract well without knowing the implementation details of both the GUI and ChUI parts.

Don't work on this right now. We will handle this as part of each widget implementation in GUI.

(4) Anything else?

Not for #2323.

#203 Updated by Constantin Asofiei over 9 years ago

Greg Shah wrote:

The only issue with this is that every call takes a trip down to the client to call OutputManager.isChui().

Should the flag be then somehow cached? The most logical place should probably be the widget instance itself.

Please propose a better approach (which includes caching).

The caching should occur on both client and server. I think there are cases where the same user's session may act as ChUI for the redirected output while GUI for interactive stuff, right?

Greg/Hynek: please keep in mind that in GUI mode, the ChUI mode is still possible to be accessed (when the default unnamed streams are redirected). So the server-side needs to be aware of the fact if the OutputManager has been switched. I think we need to cache it on server-side and use the ClientState class to pass it to the server side.

#204 Updated by Hynek Cihlar over 9 years ago

Greg Shah wrote:

Should the flag be then somehow cached? The most logical place should probably be the widget instance itself.

Please propose a better approach (which includes caching).

Ok.

The caching should occur on both client and server. I think there are cases where the same user's session may act as ChUI for the redirected output while GUI for interactive stuff, right?

Yes, I think this is right.

#205 Updated by Constantin Asofiei over 9 years ago

Hynek Cihlar wrote:

// At the moment it is unknown to me whether the coordinate conversion and
// rounding services on the server-side will be implemented (a) directly or
// (b) by pushing the state change to the client where the conversion will be
// performed and the converted state feedbacked to the server.
//
// At the moment I am assuming (a) and therefore the class is designed to be
// called by both the server-side and the client-side code.

Considering that if i.e. char metrics are set, the pixel metrics automatically change, I'm inclined to let the client-side make the transformation and this will be pushed automatically to the server side; because even if you set a certain char metric, the real value might be something else. Also, the metrics are GUI-specific even if the output is redirected (i.e. a ChUI driver is in use). See this:

DEF VAR ch AS CHAR INIT "test".
DEF VAR wc AS DEC.
DEF VAR hc AS DEC.

FORM ch WITH FRAME f1.
ch:WIDTH-CHARS = 4.4.
ch:HEIGHT-CHARS = 2.7.
MESSAGE ch:WIDTH-CHARS ch:HEIGHT-CHARS.

OUTPUT TO a.txt.
DISPLAY ch WITH FRAME f1 SIZE 20 BY 20 NO-LABELS.
wc = ch:WIDTH-CHARS.
hc = ch:HEIGHT-CHARS.
OUTPUT CLOSE.

MESSAGE wc hc.

which produces decimal metrics even if the unnamed output stream is redirect. Running this test in a real ChUI terminal, the char metrics are integer.

This is also a symptom of a larger problem in P2J, which I'm trying to solve: when GUI mode is used, a widget's state is common regardless where the widget is output. This contradicts the P2J, where the widget drawing implementation is mixed with the widget's state. Part of #2254, I've made the config instances global (so a widget with the same ID will share the config instance, regardless the output manager where this is registered), but there is still some state (especially in Frame.java) which needs to be common, regardless of concrete widget implementation. I think at some point we will need to either:
  1. refresh widget state from i.e. GUI to ChUI implementations, when the output manager (and the widget registry) switch
  2. completely separate the runtime state of a widget (on client side) from its ChUI/GUI implementations and make it shared. This is a little tricky, as in cases where Widget instances are part of this runtime state (i.e. the components of a frame), these need to be replaced with widget IDs, not concrete widget references.

At this time, I'm inclined on the second part, as to me it looks like it will be less prone to problems in the long term.

#206 Updated by Vadim Gindin over 9 years ago

Constantin Asofiei wrote:

Vadim Gindin wrote:

I'm sure about all of them except "statusStack". Could you please describe its function and may be some real example.

See this test:
[...]
The question here is: what happens if i and j are updated in different windows?

Help string will be displayed in corresponding window as documented. Thank you. I understood the goal of Stack<StatusData>. Here is the next update draft. It contains status methods refinement. Take a look please.

#207 Updated by Greg Shah over 9 years ago

Considering that if i.e. char metrics are set, the pixel metrics automatically change, I'm inclined to let the client-side make the transformation and this will be pushed automatically to the server side; because even if you set a certain char metric, the real value might be something else.

Unfortunately, setting ROW/COLUMN not only changes the Y/X values but can then re-assign a slightly different value to ROW/COLUMN because of a double conversion that can cause unexpected rounding. I will be documenting this more thoroughly later today. The key point: setting Y/X also assigns ROW/COLUMN. When you set ROW/COLUMN, it's internal assignment of Y/X causes a re-assignment of ROW/COLUMN that is usually (but not always) the same value that you just assigned.

Because of this, I do worry that a "lazy" (state sync) approach combined with client-side calculation of the "dependent attribute" re-assignments could lead to some code that does not work. In other words, code that sets ROW and then reads ROW or Y without any intervening trip down to the client, would find the wrong state.

On the other hand, all we need to know on the server side is ChUI vs GUI and the PIXELS-PER-* values. The rest of the translations can be calculated on the server side from those (at least for ROW/COLUMN and Y/X).

Also, the metrics are GUI-specific even if the output is redirected (i.e. a ChUI driver is in use).

This is interesting. It may make our implementation simpler since we won't have to do different transformations depending on the OutputManager.

#208 Updated by Greg Shah over 9 years ago

Code Review vig_upd20140912a.zip

In general, the changes are really good. I do want to make some slight changes to clean up some messiness that was part of our original implementation.

1. I like that you have moved much of the status "machinery" out of ThinClient. However, I think it is best to go even further in this approach. Why provide getter/setter access to all of the data structures you have moved to Window, when we can just move the worker methods into Window. For example, drawStatusLine(), pushStatus(), popStatus() and even the core logic in the statusInput(), statusDefault() methods should be placed in the Window class. The ThinClient code only needs to determine the correct window instance and call the worker method. This will better separate the functionality and simultaneously reduce the code in ThinClient, both of which are good things.

2. Let's eliminate the ThinClient/ClientExports.statusDefault(String) method. On the server, we just call ThinClient.statusDefault(String, boolean, int) with false and -1, so it is unnecessary.

3. Window.java needs a history entry.

4. Some of your new methods in Window are missing javadoc or have incorrectly formatted javadoc. Of course, these may no longer be needed so in that case it isn't an issue.

Is there anything else that remains to be done to finish multi-window status support?

#209 Updated by Vadim Gindin over 9 years ago

Greg Shah wrote:

..
Is there anything else that remains to be done to finish multi-window status support?

I'm just recalling that the client-side implementation is not finished yet. Status line does not display a value. That probably will be enough to finish status support.

By the way, little question: ThinClient.inputActive - what is the purpose of it? I tried to move it to Window with other fields but It used in many places.

#210 Updated by Greg Shah over 9 years ago

I'm just recalling that the client-side implementation is not finished yet. Status line does not display a value.

Marius is working on the GUI status line support (see #2333). You only need to enable the multi-window support for status.

By the way, little question: ThinClient.inputActive - what is the purpose of it? I tried to move it to Window with other fields but It used in many places.

It is a flag that allows our client code to detect if we are editing or not. In editing mode (e.g. a WAIT-FOR), we are processing focus, events, user input (keys), validation and triggers. Even the drawing is different for the currently focused widget.

That flag should not be treated as part of the status line.

#211 Updated by Greg Shah over 9 years ago

In regard to task #2334 (finish message area support), the following needs to be done:

  • create a proper scrollable container in GUI, with horizontal/vertical scrollbars (please make this generic which will allow us to use it for frames or other cases which require scrollable support)
  • proper font/color
  • proper look and feel (including resizing the status area if the window gets resized)
  • formatting (i.e. max line length, how does it work if the window is resized, etc)
  • maximum number of messages saved, how are they removed, can you set or clear this list

Do NOT handle the following as part of #2334:

  • VIEW-AS MESSAGE-BOX support
  • message statement support when there is no message area in the window (which implicitly causes the output to be rendered as VIEW-AS MESSAGE-BOX)

Both of these items must wait for our dialog box support.

#212 Updated by Vadim Gindin over 9 years ago

I have the following question about methods pushStatus and popStatus (ThinClient). They are called from applyChanges method (synchronizing client state with the server state). Recalling, I'm going to move these methods (pop and push) to Window. What window to apply these methods for? May be we should transfer id of that window in ServerState?

#213 Updated by Greg Shah over 9 years ago

Recalling, I'm going to move these methods (pop and push) to Window. What window to apply these methods for? May be we should transfer id of that window in ServerState?

nesting is shared for all windows, since it is tracking the current number of external procedures on the call stack. Such a value is not kept per-window instance.

Perhaps it should be kept in a context-local static var so it is shared between all Window instances for this client.

#214 Updated by Vadim Gindin over 9 years ago

I asked more about popStatus and pushStatus, rather then nesting. Do you mean I should stay these methods in ThinClient?

#215 Updated by Greg Shah over 9 years ago

I asked more about popStatus and pushStatus, rather then nesting. Do you mean I should stay these methods in ThinClient?

No, they definitely don't belong there. Likewise, the StatusData class shouldn't be there.

I think the more important question is how does the statusStack need to be implemented in a multi-window environment? Is there a stack that is per-window OR is it shared across all windows?

You should write testcases to figure that out. Some questions:

  • When you implement a WAIT-FOR and enter editing mode (inputActive is true), are all window instances affected?
  • Can different window instances have a different statusType at the same time?

Based on the answers to these, you can design a StatusData implementation that will properly store the state needed. Since there is only 1 shared level of nesting for all window instances, it seems to me that there can be a single statusStack instance that is also shared. The key thing here is figure out what to store about multi-window status line state in the StatusData instances that are stacked.

#216 Updated by Hynek Cihlar over 9 years ago

Regarding #2323 please advice with runtime regression results. Several test cases fail with an alert box missing buttons, see below.

09/17/2014              OPERATION MATERIAL TRANSACTIONS                 13:14:50
          ┌────────────────── SERVICE ORDER ISSUE ───────────────────┐

confidential information redacted

          │      Site: GSO           Fac:                            │
          │  Turn Num:          Location:                            │
          │      Item:                                               │
          │ Mfg's P/N:                                               │
          ┌───────────────────────── Error ─────────────────────────┐│
          │ Turn-num not found! Check the number entered and retry. ││
          │ ─────────────────────────────────────────────────────── ││
          │                                                     ││
          └─────────────────────────────────────────────────────────┘│
          │----------------------------------------------------      │
          │   On Hand:                                               │
          │  Required:                                               │
          │Qty Issued:                                               │
          │----------------------------------------------------      │
          │ Plan Cost:                                               │
          │Total Cost:                                               │
          └──────────────────────────────────────────────────────────┘

Enter Turn-num or ? for MOR browser                                      Insert

This happens when p2j is built with my changes, bzr trunk displays the "OK" button correctly. Now interesting thing is that when the test case is executed with my changes interactively in an xterm terminal, the button is also displayed correctly. I am wondering how is the test runner interacting with the application and whether it may cause a different path of execution?

#217 Updated by Greg Shah over 9 years ago

I am wondering how is the test runner interacting with the application and whether it may cause a different path of execution?

The harness uses an embedded java-based terminal emulation client that has been modified to be driven by the harness itself instead of by an interactive UI. The software is "JTA". That terminal software is most likely one difference.

You are using xterm, but the harness is running as a vt320 terminal and uses ISO-8859-1 for translation of bytes to characters (see src/com/goldencode/harness/terminal/Terminal.java in the harness project).

The terminal type definitely will cause some minor differences in the P2J code paths as a result, though there is not that much that is different.

#218 Updated by Vadim Gindin over 9 years ago

Greg Shah wrote:

I think the more important question is how does the statusStack need to be implemented in a multi-window environment? Is there a stack that is per-window OR is it shared across all windows?

You should write testcases to figure that out. Some questions:

  • When you implement a WAIT-FOR and enter editing mode (inputActive is true), are all window instances affected?

Actually I didn't understand this question.. WAIT-FOR always has widget specification. This widget uniquely identify the window it belongs. Assuming we have 2 windows with 2 enabled widgets. WAIT-FOR construct will be applied only for one of them and will be waiting for event in it only. I understood that I should find out is stack shared or not but the question...

  • Can different window instances have a different statusType at the same time?

Yes, statusType is different for different windows.

#219 Updated by Greg Shah over 9 years ago

WAIT-FOR always has widget specification. This widget uniquely identify the window it belongs. Assuming we have 2 windows with 2 enabled widgets. WAIT-FOR construct will be applied only for one of them and will be waiting for event in it only.

No, this is not correct.

WAIT-FOR starts the event processing loop for the client. While this loop is processing, the UI will respond to user input like keystrokes and mouse events. The widget specification only specifies the condition or conditions that cause the event processing loop to exit. It is perfectly valid to have more than 1 window in editing mode at the same time and for more than one widget (even in different windows) to be specified in the same WAIT-FOR.

Consider this:

def var hwin1 as handle.
def var hwin2 as handle.

create window hwin1.
create window hwin2.

def var i1 as int init 14.
def var i2 as int init 30.

enable i1 with frame f1 in window hwin1.
enable i2 with frame f2 in window hwin2.

wait-for "6" of i1 or "8" of i2.

delete widget hwin1.
delete widget hwin2.

This works just fine. You can use the mouse to switch back and forth, editing as you like. It is my understanding that there is only a single event processing loop for the entire client.

When you implement a WAIT-FOR and enter editing mode (inputActive is true), are all window instances affected?

Based on this result, I believe the answer is YES.

#220 Updated by Greg Shah over 9 years ago

Details for #2388:

I have created a test suite that explores the behavior of window move/positioning. #2388 is intended to extend P2J support to fully handle all of these tests.

The tests are in testcases/uast/window_sizing/. See the readme.txt in that directory for how to run them in the 4GL.

The following are my findings from the tests. Let me know if you have questions. Feel free to enhance/extend the tests if they are not sufficient.

Window Position/Moves

ChUI

  • ROW/COLUMN are read/write DECIMAL attributes, values are 1-based
  • X/Y are readable INTEGER attributes, values are 0-based

The default-window row/column can be edited, it is saved into the attributes but has
no practical effect. Edits can happen either before or after realization. Valid changes
are saved either way but they make no difference.

Values between 1 and 131072 (inclusive) can be successfully assigned to ROW/COLUMN.
131072 is 2 to the 17th power, which is evidently the maximum allowable character
unit.

Although X/Y cannot be assigned directly (see below), they do change when the ROW/COLUMN
changes (X changes with COLUMN, Y changes with ROW). For details on how these "linked
assignments" occur, please see the Rounding and Linked Assignment section below. The
primary difference in this linked assignment behavior is that the X/Y values are NOT
constrained by the 32767/-32768 values (which ARE constraints in GUI).

When the value assigned to ROW/COLUMN is <= 0 or ?, it causes the following messages
to be displayed (this does not raise an error, see below):

**Attribute ROW must be greater than or equal to 1 on WINDOW widget. (4081)
**Attribute COL must be greater than or equal to 1 on WINDOW widget. (4081)

Any non-unknown value (positive, negative, zero) assigned to X/Y does NOT change the
value and causes the following messages to be displayed (this does not raise an error,
see below):

**Unable to set attribute X on WINDOW widget in the current environment. (4079)
**Unable to set attribute Y on WINDOW widget in the current environment. (4079)

Trying to set unknown-value for X/Y displays (this does not raise an error, see below):

**Unable to assign UNKNOWN value to attribute X on WINDOW widget. (4083)
**Unable to assign UNKNOWN value to attribute Y on WINDOW widget. (4083)

Assigning any value over 131072, will be changed into 131072 with a message (this does
not raise an error, see below). For example, when assigned 900000, this causes (this
works the same way for both ROW and COLUMN):

** Invalid character unit value 900000 changed to 131072. (13734)

In all of the above failing cases, an ERROR condition is NOT raised. Without NO-ERROR
a message is displayed. With NO-ERROR, the ERROR-STATUS:ERROR is NO but the error number
and message are stored. The abbreviated keyword (if any) is used in the message
(depending on the attribute name) instead of the full keyword. None of these failing
cases changes behavior with UNREALIZED windows.

GUI

  • ROW/COLUMN are read/write DECIMAL attributes, values are 1-based
  • X/Y are read/write INTEGER attributes, values are 0-based

For any window, the row/column and/or the x/y can be edited and those changes actually
move the window. Edits can happen either before or after realization. Valid changes
are saved either way.

As with ChUI, in GUI the changes to ROW/COLUMN cause "linked assignment" to X/Y. Unlike
ChUI, in GUI the X/Y can be modified independently. When X/Y is modified, the ROW/COLUMN
will be changed via linked assignment. There is some strange rounding behavior that can
occur here due to round tripping of ROW/COLUMN assignments. For more details, please see
the Rounding and Linked Assignment section below.

The maximum and minimum valid values for X/Y in a REALIZED window are 32767 and -32768
respectively. You may assign any non-unknown X or Y value and the result is saved (and
used) with the exception that any values smaller than -32768 are converted to -32768 and
values larger than 32767 are converted to 32767. These conversions are done silently
and occur for both X and Y attributes.

This silent truncation behavior changes for UNREALIZED windows. For UNREALIZED windows
the X/Y values are unconstrained, which means that the linked assignment and round tripping
of values to ROW/COLUMN are only constrained by the ROW/COLUMN min/max values (see below).

Values between -131072 and -1 (inclusive) AND between 1 and 131072 (inclusive) can be
successfully assigned to ROW/COLUMN. 131072 is 2 to the 17th power, which is evidently
the maximum allowable character unit. However, because of linked assignments and
round-tripping of ROW/COLUMN changes, the actual values set for REALIZED windows will
silently be changed based on the maximum X/Y attribute values. UNREALIZED windows will
not have the X/Y contraints, but still have the 131072/-131072 constraints. Strangely,
the value -1 has a special behavior, where it is silently changed to 1 when assigned to
ROW/COLUMN.

Although the above noted values for ROW/COLUMN can be assigned WITHOUT any "non-error"
message being displayed, the actual maximum/minimum ROW/COLUMN values are NOT 131072
and -131072 for REALIZED windows. This is due to the linked assignments behavior. Since these
values are assigned to the X/Y attributes which are limited to 32767 and -32768, when the assigned
value is round-tripped assigned back to the ROW/COLUMN, it will have been silently "cut down"
to a different maximum/minimum value. No error or message is reported in this case.
The actual value assigned will depend upon the ROW/Y and COLUMN/X conversion algorithm
which is documented below in the section entitled Rounding and Linked Assignment. As
an example, assuming that the SESSION:PIXELS-PER-ROW = 21 and
SESSION:PIXELS-PER-COLUMN = 5, then for a REALIZED window:

  • ROW maximum is 1561.33 (which is the maximum Y at 32767)
  • ROW minimum is -1561.38 (which is the minimum Y at -32768)
  • COLUMN maximum is 6554.4 (which is the maximum X at 32767)
  • COLUMN minimum is -6554.6 (which is the minimum X at -32768)

Within the valid boundaries noted above, the actual max/min values will be silently changed
and assigned back to ROW/COLUMN. This means that values between 1561.33/6554.4 and 131072
are accepted and are silently converted to these maximum values. The same happens for
values between -1561.38/-6554.6 and -131072. This behavior is bypassed for UNREALIZED
windows and REDIRECTED TERMINAL usage since the X/Y trunction does not occur.

When the value assigned to ROW/COLUMN is 0 or ?, it causes the following messages
to be displayed (this does not raise an error, see below):

**Attribute ROW must be greater than or equal to 1 on WINDOW widget. (4081)
**Attribute COL must be greater than or equal to 1 on WINDOW widget. (4081)

Trying to set unknown-value for X/Y displays (this does not raise an error, see below):

**Unable to assign UNKNOWN value to attribute X on WINDOW widget. (4083)
**Unable to assign UNKNOWN value to attribute Y on WINDOW widget. (4083)

Assigning any value to ROW/COLUMN over 131072 or less than -131072, will be changed
into the actual max/min value (see above) with a message (this does not raise an error,
see below). For example, when 900000 is assigned to ROW (assumes the above example
max/min values) this causes this message (this does not raise an error, see below):

** Invalid character unit value 900000 changed to 1561.33. (13734)

A strange quirk of these 13734 messages is that they do not display any negative sign
when the value being changed to is negative. The actual value assigned is kept as a
negative, so this is only a problem in the message text.

In all of the above failing cases, an ERROR condition is NOT raised. Without NO-ERROR
a message is displayed. With NO-ERROR, the ERROR-STATUS:ERROR is NO but the error number
and message are stored. The abbreviated keyword (if any) is used in the message
(depending on the attribute name) instead of the full keyword. None of these failing
cases changes behavior with UNREALIZED windows.

Rounding and Linked Assignment

ROW and Y are linked attributes.
COLUMN and X are linked attributes.

A linked attribute is a pair of attributes such that when one is assigned, the other will
be re-assigned a related value.

In ChUI, only ROW/COLUMN can be assigned, so one only sees re-assignments of Y/X based on
the changes to ROW/COLUMN.

In GUI, the re-assignments can occur in either direction since Y/X can be assigned as well.

The tricky part is that the value to be re-assigned to the "target side" of the linked
attribute must be calculated based on particular algorithms.

These translations depend upon the number of pixels per row or per column, such that row/column
values (decimal character coordinates) can be converted to y/x values (integer pixels).

For GUI, the algorithm uses the reported SESSION:PIXELS-PER-ROW and SESSION:PIXELS-PER-COLUMN
values. In the test system used, these values were reported as 21 and 5 respectively.

For ChUI, both SESSION:PIXELS-PER-ROW and SESSION:PIXELS-PER-COLUMN report as 1 BUT that is
NOT the value used. For some reason, the ChUI implements a fixed value of 8 pixels per
row and 8 pixels per column.

There are 4 possible attributes that can be assigned. Each of those is linked to another
attribute. You would think that would mean there would be 4 possible transformations:

Assigned     Reassigned
--------     ----------
ROW       -> Y
Y         -> ROW
COLUMN    -> X
X         -> COLUMN

While changes to Y/X exactly follow the above transformations, changes to ROW/COLUMN will
actually re-assign the ROW/COLUMN attribute based on changes that may occur during the
re-assignment of the linked Y/X value! In other words, changes to ROW/COLUMN will have a
"round trip" that assigns itself twice:

                                            Round Trip
Assigned             Reassigned             Assignment
--------             ----------             ----------
ROW      -row-to-y-> Y          -y-to-row-> ROW
Y        -y-to-row-> ROW
COLUMN   -col-to-x-> X          -x-to-col-> COLUMN
X        -x-to-col-> COLUMN

The following 4GL code was found to describe each of the possible transformations:

pixels-per-row = (if SESSION:DISPLAY-TYPE = "GUI" then SESSION:PIXELS-PER-ROW    else 8).
pixels-per-col = (if SESSION:DISPLAY-TYPE = "GUI" then SESSION:PIXELS-PER-COLUMN else 8).

/* the following functions encode the algorithm for translating what a given change in */
/* row/col will be when read back from the x/y and vice versa */ 
function row-to-y returns int (input row-val as dec):
   def var row-rnd as dec decimals 0.

   /* in ChUI, use assignment to remove digits to the right of the decimal point */
   if SESSION:DISPLAY-TYPE = "TTY" then
   do:
      row-rnd = row-val.
      row-val = row-rnd.
   end.

   return integer((row-val - (if row-val < 0 then -1 else 1)) * pixels-per-row).
end.

function y-to-row returns dec (input y-val as int):
   def var result as dec decimals 3.
   /* 2 levels of rounding here, force rounding to 3 digits first using assignment */
   result = (y-val / pixels-per-row) + (if y-val < 0 then -1 else 1).
   /* now round to the final 2 digits level */
   return round(result, 2).
end.

function col-to-x returns int (input col-val as dec):
   def var col-rnd as dec decimals 0.

   /* in ChUI, use assignment to remove digits to the right of the decimal point */
   if SESSION:DISPLAY-TYPE = "TTY" then
   do:
      col-rnd = col-val.
      col-val = col-rnd.
   end.

   return integer((col-val - (if col-val < 0 then -1 else 1)) * pixels-per-col).
end.

function x-to-col returns dec (input x-val as int):
   def var result as dec decimals 3.
   /* 2 levels of rounding here, force rounding to 3 digits first using assignment */
   result = (x-val / pixels-per-col) + (if x-val < 0 then -1 else 1).
   /* now round to the final 2 digits level */
   return round(result, 2).
end.

function round-trip-row returns dec (input row-val as dec):
   return y-to-row(row-to-y(row-val)).
end.

function round-trip-col returns dec (input col-val as dec):
   return x-to-col(col-to-x(col-val)).
end.

As part of using these transformations of the linked attributes (our so called
"linked assignments", the transformations naturally cause rounding to occur. For
some reason, the x-to-col and y-to-row transformations have internal calculations
done with 3 digits of precision while returning a final result in 2 digits of
precision. This causes some very slight differences in rare cases compared to
doing everything with 2 digits of precision.

In ChUI, the row-to-y and col-to-x transformations have an internal rounding step
to remove all digits of precision before the calculation occurs. Otherwise the
calculations are the same between GUI/ChUI (of course they may use different
pixels per row/col values, so the results can differ that way too).

The round tripping that occurs with assignments to ROW/COLUMN will potentially magnify
the rounding errors twice, leading to a resulting ROW/COLUMN value that is different
than the value that was initially assigned. Progress alludes to this in its documentation
without really explaining it.

The following shows some example output from our testcases which triggered round-trip
differences (both cases are for REALIZED windows):

ChUI:

ROUNDING/TRUNCATION during MOVE: set ROW = 40.1; reassigned to 40
ROUNDING/TRUNCATION during MOVE: set ROW = 40.11; reassigned to 40
ROUNDING/TRUNCATION during MOVE: set ROW = 40.12; reassigned to 40
ROUNDING/TRUNCATION during MOVE: set ROW = 40.13; reassigned to 40
ROUNDING/TRUNCATION during MOVE: set ROW = 40.14; reassigned to 40
ROUNDING/TRUNCATION during MOVE: set ROW = 40.15; reassigned to 40
ROUNDING/TRUNCATION during MOVE: set ROW = 40.16; reassigned to 40
ROUNDING/TRUNCATION during MOVE: set ROW = 40.17; reassigned to 40
ROUNDING/TRUNCATION during MOVE: set ROW = 40.18; reassigned to 40
ROUNDING/TRUNCATION during MOVE: set ROW = 40.19; reassigned to 40
ROUNDING/TRUNCATION during MOVE: set ROW = 40.4; reassigned to 40
ROUNDING/TRUNCATION during MOVE: set ROW = 40.5; reassigned to 41
ROUNDING/TRUNCATION during MOVE: set ROW = 40.6; reassigned to 41
ROUNDING/TRUNCATION during MOVE: set ROW = 40.9; reassigned to 41
ROUNDING/TRUNCATION during MOVE: set COL = 40.1; reassigned to 40
ROUNDING/TRUNCATION during MOVE: set COL = 40.11; reassigned to 40
ROUNDING/TRUNCATION during MOVE: set COL = 40.12; reassigned to 40
ROUNDING/TRUNCATION during MOVE: set COL = 40.13; reassigned to 40
ROUNDING/TRUNCATION during MOVE: set COL = 40.14; reassigned to 40
ROUNDING/TRUNCATION during MOVE: set COL = 40.15; reassigned to 40
ROUNDING/TRUNCATION during MOVE: set COL = 40.16; reassigned to 40
ROUNDING/TRUNCATION during MOVE: set COL = 40.17; reassigned to 40
ROUNDING/TRUNCATION during MOVE: set COL = 40.18; reassigned to 40
ROUNDING/TRUNCATION during MOVE: set COL = 40.19; reassigned to 40
ROUNDING/TRUNCATION during MOVE: set COL = 40.4; reassigned to 40
ROUNDING/TRUNCATION during MOVE: set COL = 40.5; reassigned to 41
ROUNDING/TRUNCATION during MOVE: set COL = 40.6; reassigned to 41
ROUNDING/TRUNCATION during MOVE: set COL = 40.9; reassigned to 41

GUI:

ROUNDING/TRUNCATION during MOVE: set ROW = -1; reassigned to 1
ROUNDING/TRUNCATION during MOVE: set ROW = -11.11; reassigned to -11.1
ROUNDING/TRUNCATION during MOVE: set ROW = -11.12; reassigned to -11.14
ROUNDING/TRUNCATION during MOVE: set ROW = -11.13; reassigned to -11.14
ROUNDING/TRUNCATION during MOVE: set ROW = -11.15; reassigned to -11.14
ROUNDING/TRUNCATION during MOVE: set ROW = -11.16; reassigned to -11.14
ROUNDING/TRUNCATION during MOVE: set ROW = -11.17; reassigned to -11.19
ROUNDING/TRUNCATION during MOVE: set ROW = -11.18; reassigned to -11.19
ROUNDING/TRUNCATION during MOVE: set ROW = -11.4; reassigned to -11.38
ROUNDING/TRUNCATION during MOVE: set ROW = -11.5; reassigned to -11.52
ROUNDING/TRUNCATION during MOVE: set ROW = -11.6; reassigned to -11.62
ROUNDING/TRUNCATION during MOVE: set ROW = -11.9; reassigned to -11.91
ROUNDING/TRUNCATION during MOVE: set ROW = -4000; reassigned to -1561.38
ROUNDING/TRUNCATION during MOVE: set ROW = -131072; reassigned to -1561.38
ROUNDING/TRUNCATION during MOVE: set ROW = 40.11; reassigned to 40.1
ROUNDING/TRUNCATION during MOVE: set ROW = 40.12; reassigned to 40.14
ROUNDING/TRUNCATION during MOVE: set ROW = 40.13; reassigned to 40.14
ROUNDING/TRUNCATION during MOVE: set ROW = 40.15; reassigned to 40.14
ROUNDING/TRUNCATION during MOVE: set ROW = 40.16; reassigned to 40.14
ROUNDING/TRUNCATION during MOVE: set ROW = 40.17; reassigned to 40.19
ROUNDING/TRUNCATION during MOVE: set ROW = 40.18; reassigned to 40.19
ROUNDING/TRUNCATION during MOVE: set ROW = 40.4; reassigned to 40.38
ROUNDING/TRUNCATION during MOVE: set ROW = 40.5; reassigned to 40.52
ROUNDING/TRUNCATION during MOVE: set ROW = 40.6; reassigned to 40.62
ROUNDING/TRUNCATION during MOVE: set ROW = 40.9; reassigned to 40.91
ROUNDING/TRUNCATION during MOVE: set ROW = 4000; reassigned to 1561.33
ROUNDING/TRUNCATION during MOVE: set ROW = 131072; reassigned to 1561.33
ROUNDING/TRUNCATION during MOVE: set COL = -1; reassigned to 1
ROUNDING/TRUNCATION during MOVE: set COL = -11.1; reassigned to -11.2
ROUNDING/TRUNCATION during MOVE: set COL = -11.11; reassigned to -11.2
ROUNDING/TRUNCATION during MOVE: set COL = -11.12; reassigned to -11.2
ROUNDING/TRUNCATION during MOVE: set COL = -11.13; reassigned to -11.2
ROUNDING/TRUNCATION during MOVE: set COL = -11.14; reassigned to -11.2
ROUNDING/TRUNCATION during MOVE: set COL = -11.15; reassigned to -11.2
ROUNDING/TRUNCATION during MOVE: set COL = -11.16; reassigned to -11.2
ROUNDING/TRUNCATION during MOVE: set COL = -11.17; reassigned to -11.2
ROUNDING/TRUNCATION during MOVE: set COL = -11.18; reassigned to -11.2
ROUNDING/TRUNCATION during MOVE: set COL = -11.19; reassigned to -11.2
ROUNDING/TRUNCATION during MOVE: set COL = -11.5; reassigned to -11.6
ROUNDING/TRUNCATION during MOVE: set COL = -11.9; reassigned to -12
ROUNDING/TRUNCATION during MOVE: set COL = -8000; reassigned to -6554.6
ROUNDING/TRUNCATION during MOVE: set COL = -131072; reassigned to -6554.6
ROUNDING/TRUNCATION during MOVE: set COL = 40.1; reassigned to 40.2
ROUNDING/TRUNCATION during MOVE: set COL = 40.11; reassigned to 40.2
ROUNDING/TRUNCATION during MOVE: set COL = 40.12; reassigned to 40.2
ROUNDING/TRUNCATION during MOVE: set COL = 40.13; reassigned to 40.2
ROUNDING/TRUNCATION during MOVE: set COL = 40.14; reassigned to 40.2
ROUNDING/TRUNCATION during MOVE: set COL = 40.15; reassigned to 40.2
ROUNDING/TRUNCATION during MOVE: set COL = 40.16; reassigned to 40.2
ROUNDING/TRUNCATION during MOVE: set COL = 40.17; reassigned to 40.2
ROUNDING/TRUNCATION during MOVE: set COL = 40.18; reassigned to 40.2
ROUNDING/TRUNCATION during MOVE: set COL = 40.19; reassigned to 40.2
ROUNDING/TRUNCATION during MOVE: set COL = 40.5; reassigned to 40.6
ROUNDING/TRUNCATION during MOVE: set COL = 40.9; reassigned to 41
ROUNDING/TRUNCATION during MOVE: set COL = 8000; reassigned to 6554.4
ROUNDING/TRUNCATION during MOVE: set COL = 131072; reassigned to 6554.4
ROUNDING/TRUNCATION during MOVE: set X = -400000; reassigned to -32768
ROUNDING/TRUNCATION during MOVE: set X = -32769; reassigned to -32768
ROUNDING/TRUNCATION during MOVE: set X = 32768; reassigned to 32767
ROUNDING/TRUNCATION during MOVE: set X = 400000; reassigned to 32767
ROUNDING/TRUNCATION during MOVE: set Y = -400000; reassigned to -32768
ROUNDING/TRUNCATION during MOVE: set Y = -32769; reassigned to -32768
ROUNDING/TRUNCATION during MOVE: set Y = 32768; reassigned to 32767
ROUNDING/TRUNCATION during MOVE: set Y = 400000; reassigned to 32767                                                                                                 

Some of the changes are due to the rounding behavior of the transformations and other
differences are due to the limits imposed by the minimum/maximum values of the
4 attributes. To the degree that those min/max values are imposed by the mix/max
X/Y values, those truncations only occur for REALIZED GUI windows.

These truncations can also happen in failure mode, but such truncations do NOT occur
when in ChUI, when using UNREALIZED GUI windows OR when using REDIRECTED TERMINAL
GUI window usage.

Initial Window Position

In ChUI, only the default window ever exists. It will always start at:

ROW = 1
COLUMN = 1
X = 0
Y = 0

In GUI, the initial window position (of the default window and any subsequently created
windows) is set by the operating system (Windows OS) except in the scenario where the
CREATE WINDOW statement has ROW/COLUMN/X/Y values specified in an embedded ASSIGN clause.
Although we don't know for sure, one can theorize that the 4GL creates windows using
something like the WIN32 API CreateWindowEx() with X/Y values set to the CW_USEDEFAULT
constant. That would cause this kind of OS-assigned initial window position which the
4GL exhibits. This is not something that we will duplicate. It probably is not a
compatibility issue at this time. Duplicating it would be tricky because we would have
to figure out how Windows calculates that value AND it may be dependent upon other
random programs started independently on the client system (something that is not in
our control and is inherently unpredictable).

Batch Assignment Ordering Considerations

Because of the linked assignment behavior, there is the possibility that two (or more)
assignments in the same ASSIGN statement can conflict. Since such statements have been
shown to have batching qualities such that additional behavior can be introduced, this
behavior was explored here.

It turns out that the assignment order is as expected, the last one listed is what will be
saved when there is a conflict (i.e. LAST ONE WINS).

ROW assignments can conflict with Y:

  • ROW first then Y leaves results consistent with Y only
  • Y first then ROW leaves results consistent with ROW only

COLUMN assignments can conflict with X:

  • COL first then X leaves results consistent with X only
  • X first then COL leaves results consistent with COL only

Other Possible Dependencies

The above documented behavior does not depend on the following:

  • previous values of ROW/COLUMN/X/Y
  • default window vs dynamically created window
  • empty window vs a window with content
  • windows of different sizes and starting positions
  • windows used on the redirected terminal

#221 Updated by Vadim Gindin over 9 years ago

I've made corrections with status stack, but I have some doubts.

1. Why it is necessary to hold the stack of statuses even for one-window UI?
2. Why it is necessary to hold integer counter inputActive - not boolean. What it counts?

Some thoughts.

1. May be we should stay statusType also in the ThinClient. It will be mean current status type and we will change it when active window is changed.
2. May be we should add windowId field to StatusData in spite of calling Window.resolveWindow() in popStatus and pushStatus methods.

What do you think?

#222 Updated by Vadim Gindin over 9 years ago

Fixed 2 files (compile errors)

#223 Updated by Greg Shah over 9 years ago

1. Why it is necessary to hold the stack of statuses even for one-window UI?

Because you can have nested WAIT-FOR statements. For example, you can have a WAIT-FOR active and an event causes a trigger to fire that then executes code that runs another WAIT-FOR statement. In such a case, without a stack approach, the exit of the nested WAIT-FOR would restore the status line improperly.

2. Why it is necessary to hold integer counter inputActive - not boolean. What it counts?

This is needed for the same nested WAIT-FOR reason. It counts the number of times that we have entered editing mode. It will be more than 1 when there is a nested WAIT-FOR.

1. May be we should stay statusType also in the ThinClient. It will be mean current status type and we will change it when active window is changed.

Based on your tests, each Window can have its own independent statusType. How can we keep a single instance of it in the StatusData? I think we must restore all the statusType for all Windows in popStatus() and save it off in pushStatus().

2. May be we should add windowId field to StatusData in spite of calling Window.resolveWindow() in popStatus and pushStatus methods.

There must be only 1 StatusData instance for each level of the stack. There is a level of the stack for each external procedure in the call stack. The StatusData is not specific to one Window, it is specific to 1 external procedure. The contents of the StatusData needs to be aware of the state of all Windows. Previously it was setup for ChUI and only needs to handle a single window ever.

#224 Updated by Greg Shah over 9 years ago

Code Review vig_upd20140919b.zip

This mostly is moving in the right direction.

1. The statusStack, StatusData, pushStatus() and popStatus() still need to be moved out of the TC and made suitable for multi-window support.

2. I think it is likely that the helpText also needs to move out.

3. Don't we still need to honor the THIS-PROCEDURE:CURRENT-WINDOW? It isn't passed via state sync yet.

#225 Updated by Vadim Gindin over 9 years ago

Next update with the latest corrections except StatusStack move from ThinClient. See below.

Greg Shah wrote (note 213):
..

Perhaps it should be kept in a context-local static var so it is shared between all Window instances for this client.

1. ThinClient already context local (see ThinClient.local field). You want me to get it to some new class or may be to Window context local var?
2. See Window.setHelp. The target window there is defined through the current widget, having focus. This is an alternate way than just call Window.resolveWindow(). I suspect that result target window will be the same. May be I should simplify this method replacing it?
3. In the ThinClient.popStatus method should I throw an exception or just ignore the status info where correspondent window does not exists in widget registry?

#226 Updated by Greg Shah over 9 years ago

Perhaps it should be kept in a context-local static var so it is shared between all Window instances for this client.

1. ThinClient already context local (see ThinClient.local field). You want me to get it to some new class or may be to Window context local var?

Yes, please use a context-local var in Window.

2. See Window.setHelp. The target window there is defined through the current widget, having focus. This is an alternate way than just call Window.resolveWindow(). I suspect that result target window will be the same. May be I should simplify this method replacing it?

Not right now. It may need changes later. But it is only called from 2 places: ThinClient.checkHelpText() which is only called from ThinClient.invokeTriggers() AND ThinClient.prepareChooseWidgetList() during ROW MODE processing. In both cases, there is a very specific focused widget or CHOOSE operation occurring. The focus-based approach is possibly OK.

3. In the ThinClient.popStatus method should I throw an exception or just ignore the status info where correspondent window does not exists in widget registry?

I think you should restore by iterating the key set of the StatusData.types map. Then the window should always exist.

#227 Updated by Greg Shah over 9 years ago

Code Review vig_upd20140919c.zip

This is moving in the right direction.

#228 Updated by Vadim Gindin over 9 years ago

I made corrections. Have a look please.

#229 Updated by Hynek Cihlar over 9 years ago

The mystery resolved! Harness reporting doesn't HTML-escape the HTML outputs, that is the reason the button is not visible on the HTML page. The real cause for the failed step was the button was shifted to the right by one character.

Hynek Cihlar wrote:

Regarding #2323 please advice with runtime regression results. Several test cases fail with an alert box missing buttons, see below.
[...]

This happens when p2j is built with my changes, bzr trunk displays the "OK" button correctly. Now interesting thing is that when the test case is executed with my changes interactively in an xterm terminal, the button is also displayed correctly. I am wondering how is the test runner interacting with the application and whether it may cause a different path of execution?

#230 Updated by Greg Shah over 9 years ago

Code Review vig_upd20140920a.zip

1. THIS-PROCEDURE:CURRENT-WINDOW is not handled via state sync but you previously said the client needed to support that feature. If you want to fix this in the next set of updates, that is fine. I just don't want to forget this.

2. The Window.wa member is missing javadoc.

Add the javadoc and you can go into testing. Keep working on the next set of IN WINDOW/multi-window features.

#231 Updated by Greg Shah over 9 years ago

The mystery resolved! Harness reporting doesn't HTML-escape the HTML outputs, that is the reason the button is not visible on the HTML page.

Ouch! Sorry for that. Would you please add a task documenting the problem? It should be added to the "Harness" project.

#232 Updated by Hynek Cihlar over 9 years ago

Greg Shah wrote:

Would you please add a task documenting the problem? It should be added to the "Harness" project.

See the issue #2397.

#233 Updated by Vadim Gindin over 9 years ago

Tried to run regression testing and faced with the problem: majic is not builded because of compile errors:

compile_jasper:
      [jrc] Compiling 5 report design files.
      [jrc] File : /home/vig/testing/majic/srcnew/jrxml/line_text_subreport.jrxml ... OK.
      [jrc] File : /home/vig/testing/majic/srcnew/jrxml/cmu_function_list.jrxml ... OK.
      [jrc] File : /home/vig/testing/majic/srcnew/jrxml/SA-M122P_20110126_20110126.jrxml ... OK.
      [jrc] File : /home/vig/testing/majic/srcnew/jrxml/po_hardcopy.jrxml ... OK.
      [jrc] File : /home/vig/testing/majic/srcnew/jrxml/line_text_subreport_paragraphs.jrxml ... OK.

compile:
    [javac] Compiling 14677 source files to /home/vig/testing/majic/build/classes
    [javac] /home/vig/testing/majic/src/aero/timco/majic/security/LoginClient.java:309: error: method statusInput in class ThinClient cannot be applied to given types;
    [javac]          client.statusInput(STD_MSG);
    [javac]                ^
    [javac]   required: String,int
    [javac]   found: String
    [javac]   reason: actual and formal argument lists differ in length
    [javac] /home/vig/testing/majic/src/aero/timco/majic/security/LoginClient.java:431: error: cannot find symbol
    [javac]       client.statusInputRevert();
    [javac]             ^
    [javac]   symbol:   method statusInputRevert()
    [javac]   location: variable client of type ThinClient
    [javac] Note: Some input files use unchecked or unsafe operations.
    [javac] Note: Recompile with -Xlint:unchecked for details.
    [javac] 2 errors

Should I fix them? If yes - how to do it correctly?

#234 Updated by Greg Shah over 9 years ago

Eugenie (EVL) sent a recent update email that notified that there were MAJIC changes to match his recent check-in:

Passed the regression testing and committed in bzr as 10615 and pushed into git staging.

0829b - majic source code update
0919a - P2J source code update

You will have to rebuild majic*.jar files too for changes to take effect.

On devsrv01, that means you must pull the recent MAJIC changes from git. The easiest way is to just delete everything and re-run the configure target.

#235 Updated by Vadim Gindin over 9 years ago

These errors correlate with my update not with Eugenys.

#236 Updated by Constantin Asofiei over 9 years ago

Vadim Gindin wrote:

These errors correlate with my update not with Eugenys.

I guess your changes affect MAJIC code - you need to fix the LoginClient.java (in the MAJIC sources) to be compatible with your update.

#237 Updated by Greg Shah over 9 years ago

Please see the "Source Management" section of the timco.html document for details on how to deal with check-out/check-in on the devsrv01 git repositories. You don't need to worry about the lightning system or about synchronizing git between devsrv01 and lightning. Your changes can only be for devsrv01. Once you have them prepared, you wouldn't commit them to git until the p2j changes are also committed (they get committed at the same time).

#238 Updated by Greg Shah over 9 years ago

This is the priority order for implementation of multi-window support (please edit this entry over time to mark off when something is complete):

PAUSE
STATUS
MESSAGE
DEFINE FRAME/FORM
DOWN/UP/SCROLL
DISPLAY/VIEW/HIDE
ENABLE/PROMPT-FOR/SET/UPDATE/INSERT/NEXT-PROMPT
COLOR/UNDERLINE
CHOOSE
DO/FOR
SYSTEM-DIALOG-*

It is important to get this done ASAP as it is inhibiting many other tasks.

#239 Updated by Vadim Gindin over 9 years ago

Here is the update with multi-window support for message methods. Following methods was moved from ThinClient to Window:

message*
hideMessage
clearPutScreenInMessageArea
displayMessage
splitMessage
messageClearWorker

I also added getters and setters for the following flags in ThinClient:
clearMessage
autoCleared
afterChoose
messageNeedPause

I'm not sure about them. Should I also move them to Window?
Please have a look to update.

#240 Updated by Hynek Cihlar over 9 years ago

For the #2323 please review the attached file.

- fixed initialization of GUI mode
- fixed AlertBox positioning in ChUI
- fixed rounding in native to character conversion
- added rounding to Rectangle, Dimension, Point and Insets classes
- added a workaround for Rectangle hardcoded base coordinate value
- other small fixes

This update passes conversion and runtime regression test.

Note that there are still some shortcomings for the GUI mode with this update:
(1) Some of the code I have tested was using the old native-char coordinates conversion which was casting to ints. There are places where this rounding down is assumed, for example in WindowLayout and WindowGuiImpl. The result is that with this update the window doesn't layout properly.

(2) Several places hard code the coordinate base values of the ChUI mode. I have provided a workaround in this update but hardly all cases are covered.

(3) GUI clipping in ScreenBitmap seems to be broken. I think this is either problem in rounding of the double values or it is another case of (1). I have attempted to fix this but the problem seems to be spread to multiple components.

I would resolve (1), (2) and (3) as part of #2388 as they are more related.

#241 Updated by Greg Shah over 9 years ago

Code Review vig_upd20140924a.zip

The overall approach is correct. Eventually, some of this logic may be moved to the message area widget itself, but for now this is a good start.

I also added getters and setters for the following flags in ThinClient:
...
I'm not sure about them. Should I also move them to Window?

You need to review the use of each with the following questions in mind:

1. Is this a global client flag or does this need to be tracked per-window?
2. Is the primary use of this from Window or from ThinClient?

clearMessage, autoCleared and messageNeedPause all seem to meet both criteria. That means they should be in Window.

The afterChoose is currently best in Window, but when CHOOSE is multi-window enabled, that will probably change.

#242 Updated by Greg Shah over 9 years ago

Code Review hc_upd20140924a.zip

Wow! Great work. That is a huge amount of change. Please go ahead and check it in and distribute it.

I would resolve (1), (2) and (3) as part of #2388 as they are more related.

I agree. I will close #2323 unless you believe there is something else to do (outside of the additional tasks for #2388).

#243 Updated by Hynek Cihlar over 9 years ago

Greg Shah wrote:

I agree. I will close #2323 unless you believe there is something else to do (outside of the additional tasks for #2388).

I have committed hc_upd20140924a.zip to bzr revision 10616. Yes, please close #2323.

#244 Updated by Constantin Asofiei over 9 years ago

This entry contains details for #2254

New configuration manager
------------------------------------
The new ConfigManager class is responsible of storing and updating the widget state. On both server and client-side, concrete implementation of widgets need to hold as little state as possible. All state needs to be kept in the *Config classes, especially state which needs to be accessed from both client and server sides.

Currently, the *Config classes have public fields which can be safely set or get directly, with some exceptions: in cases when an explicit setter exists, that setter might need to be called (this is on a case-by-case basis). To the extent possible, all logic which resided in the previous getters/setters was moved in the widget classes, on server or client-side, or in the new "WidgetConfig.syncWithWidget" method.

The WidgetConfig class has some setDynamic<attr> APIs, which can be called in cases when the concrete impl class of the Config is unknown: these will dynamically set the attribute, without raising an exception.

The widget's ID is always determined from the associated Config instance, the WidgetConfig.id field. On server side, all widgets are identified via WidgetId instances. On client-side, widgets can be identified via WidgetId or WidgetDownId instances. The new WidgetDownId class can uniquely identify widgets part of a down frame, on client-side. As these widgets have no correspondent on the server-side, state is shared via the widgets which are on the first row in the down body (as they are linked with the server-side widgets). This problem (the fact that server-side can only access the widgets on the current iteration) is a limitation which will need to be addressed in the future.

There is still some logic left some of the *Config classes (explicit setter or syncWithWidget): this logic can't be easily eliminated, as it requires that the associated widget be immediately updated (i.e. repainted or some other state changed).

All changes in widget state is transferred from the client side to the server side immediately; the server side will transfer the full configuration only when required, via pushScreenDefinition API calls.

The definitions of the widget configuration classes are resolved on client-side, and stored in WidgetConfigDef instances. These definitions are pushed to the server-side, so that the fields can be identified by an unique integer ID.

The client-side will start pushing widget config updates only when the server-side will inform it, via the ClientExports.activateConfigUpdates API. Also, with these changes, the previous code which was pushing widget visibility state to the server-side was removed.

Client-side changes
--------------------------
- Widget.initialize - container for logic which is dependent on the widget being already added to the client-side registry.
- the ComponentConfig constants (related to layout and widget type) have been removed. Always identify the widget via its associated WidgetConfig implementation. No collisions should exist: for widget creation on client-side, there should be a 1-on-1 mapping of widget config classes to widget type.
- AbstractWidget.visible/hidden/enabled need to be on their own, because concrete impl of this class can exist without a config!
- no widget can be constructed without setting its ID at construction time.
- there are widgets implementations which do not require a config. For these cases, some state (visible, hidden, enabled) is kept in the AbstractWidget class.
- virtual widgets (like short-lived Label instances during frame layout, OS widgets and any other case where there is no server-side counterpart) all have negative IDs. These IDs are generated via WidgetId.nextId() API.
- when creating widgets, the widget's ID needs to be specified to the c'tor or factory API.
- ThinClient.setFrameValue/getValue APIs - these are never called either from server or client-side
- the previous BaseConfig APIs related to X,Y coordinates were removed. They usage was replaced with their implementation (which for now is the COLUMN/ROW). These need to be properly implemented as distinct config fields and managed accordingly by the runtime.

Server-side changes
---------------------------
- all widget classes now specify the type of Config impl class associated with them.
- place widget state only in the config classes, to the extent possible (i.e especially widget attributes)

Misc changes
------------------
- Coordinate.round: is the caller's responsibility to ensure the value that ends up assigned to a widget config field is properly rounded
- ScreenBuffer: all APIs which were taking an Integer or Object as parameter instead of int were removed: the compiler takes care of boxing/unboxing, they are no longer needed. More, no such API had NPE protection, so another reason they are not needed.
- com.goldencode.p2j.ui.ComponentConfig and com.goldencode.p2j.ui.client.widget.WidgetConfig files have been removed.
- shared frames: currently, P2J creates a distinct widget instance no server-side (although with the same Widget ID), thus a different resource. This contradicts 4GL (as they should be the same resource), and at some point needs to be fixed. P2J was changed to allow all these shared instances (being frame or widget) to share the WidgetConfig instance. Some state (like LABEL or HELP, which can change in the shared frame) is restored on a per-widget level, when the shared frame goes out of scope.

Next steps
--------------
- fix any more problems related to this update
- there is a performance issue related to collecting the widget configuration changes. At this time, client-side processes all live widgets to determine the differences. This needs to be fixed. The solution is to add AspectJ support to intercept widget configuration field changes, so that the client-side will process only the widget configurations which had at least on if its field changed. To allow debugging directly into a IDE, the client-side should be able to check only the "dirty" configs only when the AspectJ rules are in place.
- test the GUI client to make sure is still working

#245 Updated by Constantin Asofiei over 9 years ago

Vadim, there is this code in OutputManager.setInvalidate which breaks the GUI window creation:

         TitledWindow<?> win = WindowManager.topWindow();
         if (win instanceof Window)
         {
            processDefaultWindow((Window<?>) win);
         }

each time it's executed, a new simulator (and JFrame) is created.

Vadim: can you elaborate why this is needed?

Marius: have you encountered this problem? Did you fix it with the status area work?

#246 Updated by Marius Gligor over 9 years ago

I found the same problem.
I fixed this problem in my current task by creating a method SwingGuiPrimitives#hasWindowRenderer in order to avoid to create multiple simulator instances.

   /**
    * Check if window has renderer.
    * 
    * @param   windowId
    *          Window ID.
    * 
    * @return  true if window has renderer true</false> otherwise.
    */
   public boolean hasWindowRenderer(int windowId)
   {
      return renderers.get(windowId) != null;
   }

And in SwingGuiDriver#hasWindowRenderer I added

   /**
    * Check if window has renderer.
    * 
    * @param   windowId
    *          Window ID.
    * 
    * @return  <code>true</code> if window has renderer <code>true</false> otherwise.
    */
   public boolean hasWindowRenderer(int windowId)
   {
      return direct.hasWindowRenderer(windowId);
   }
</pre>

Then I changed @GuiOutputManager#processDefaultWindow@ as follow

<pre>
   /**
    * Process the default window, depending on the output manager type.
    * 
    * @param    window
    *           The default window.
    */
   @Override
   public void processDefaultWindow(Window<?> window)
   {
      int windowId = UiUtils.lookupWidgetId(window);

      GuiDriver driver = (GuiDriver) this.driver;

      if (!driver.hasWindowRenderer(windowId))
      {
         GuiOptions options = SwingGuiDriver.convertToOptions(cfg);

         GuiSimulator sim = driver.newSimulator(options);

         // TODO added to try. Fix this later. Was WindowConfig.SESSION_WINDOW_ID. Why only this ID?            
         driver.registerWindow(windowId, sim);
      }

      driver.selectWindow(windowId);
   }
</pre>

With this patch in place it works fine and I executed a first GUI application "Hello World!".
If you have other idea please let me know.

#247 Updated by Vadim Gindin over 9 years ago

Constantin Asofiei wrote:

Vadim, there is this code in OutputManager.setInvalidate which breaks the GUI window creation:
[...]
each time it's executed, a new simulator (and JFrame) is created.

Vadim: can you elaborate why this is needed?

I added such peace of code somewhere because of NullPointerException appeared there. I also faced, that multiple windows are created during execution and I'm glad it is fixed. Thank you.

#248 Updated by Constantin Asofiei over 9 years ago

This update contains some fixes and the AspectJ changes related to optimizing the computation of widget config updates, on client-side. Is built on top of ca_upd20140926c.zip (is not a replacement) and both are currently under regression testing.

About AspectJ. This link http://www.eclipse.org/aspectj/downloads.php contains a download for an "install AspectJ 1.8.2" jar which gives you (beside the two jars we need) some other stuff which we don't need. The jars we need are:
  1. aspectjrt.jar - this is a small one, and P2J runtime is dependent on it. It is copied to build/lib by ant.
  2. aspectjtools.jar - this is a ~10MB jar which contains (beside other tools) the ant task to automatically run the aspectj compiler during build. P2J runtime is not dependent on it, so it is not added to p2j.mf and is not copied to build/lib. This file (being large) is not included in this update, but will be committed to bzr when releasing.

During build, the aspectj task takes as input the classes in the build/classes folder and writes the result to build/classes.aop folder. build/classes.aop folder will be used as input for the jar task.

I didn't make any changes yet to allow P2J to run without the AspectJ Point Cuts (and I will make these changes only if I find a way to not impact the performance when AspectJ is in use). If you want to run the P2J client and server from your IDE (without using the P2J jars), these are the steps to use to setup your Eclipse project:
  1. install AspectJ Development Tools for your Eclipse
  2. edit your .project file:
    - replace the buildSpec/buildCommand/name node from org.eclipse.jdt.core.javabuilder
    to:
    <buildSpec>
       ...
       <buildCommand>
          <name>org.eclipse.ajdt.core.ajbuilder</name>
       </buildCommand>
    </buildSpec>
    

    - add this line to the natures node:
    <natures>
       ...
       <nature>org.eclipse.ajdt.ui.ajnature</nature>
    </natures>
    
  3. add to your project's classpath the lib/aspectjrt.jar file
  4. run your project as AspectJ/Java Application

Using this steps, it will inform eclipse to automatically apply the AspectJ rules during compilation; without the AspectJ rules applied to your classes, the P2J Client most likely will not behave correct. I'm not that familiar with NetBeans or IntelliJ, but I think there should be similar plugins for them.

#249 Updated by Greg Shah over 9 years ago

Code Review ca_upd20140926c.zip - Part 1

I'm half-way through the review of your previous update. I haven't looked at the new one at all. Here are some initial thoughts and questions.

1. Why not sync the server state on the next trip down to the client, instead of waiting for a pushScreenDefinition()? It seems simpler and future additions/changes wouldn't need to worry about inserting the push at just the right places.

2. Can we use AspectJ and a notification/listener approach to eliminate the need for the remaining setters in the config classes? The client and server could register different listeners for such events, allowing a clean separation of the code into inner classes of the client/server widgets as makes sense. Listeners could be chained and the same listener could potentially be reused in many places. For example, the use of Coordinate.round() before assigning the value is used for multiple attributes on both the client and server.

3. In using AspectJ for the dirty checking, we might as well track the exact widgets that are changing instead of just tracking the config object that is changing. The specific field ID can be stored to track the changed fields. You may have already done it this way, I was just going by your previous comments.

4. In AbstractWidget, why don't we keep a reference to our WidgetConfig and use the enabled, hidden, visible state from there instead of storing separate state?

5. Widget subclasses are using their parent's config() method to access the private config instance. I would prefer making the config instance protected, renaming it cfg and directly accessing it from the child classes instead of calling config(). A simple example is client/Frame and chui/FrameImpl. In a perfect world we wouldn't need the config() method, but at least today it is used directly elsewhere.

6. It would be better to have a separation of the client-specific and server-specific code in ConfigManager. Common code/abstract methods can remain in the ConfigManager. Perhaps we can implement sub-classes that can reside in separate packages and inject the right one at runtime.

7. It looks like you may have eliminated the memory leak of shared frames in LT. Correct?

#250 Updated by Constantin Asofiei over 9 years ago

Greg Shah wrote:

1. Why not sync the server state on the next trip down to the client, instead of waiting for a pushScreenDefinition()? It seems simpler and future additions/changes wouldn't need to worry about inserting the push at just the right places.

This is mainly because the client-side effect must be immediate (just consider hiding a frame by changing its VISIBLE attribute). We can't wait for another trip to the client, as there might be some other business logic between that which will delay this... This was my first instinct too, but I was proven wrong immediately.

2. Can we use AspectJ and a notification/listener approach to eliminate the need for the remaining setters in the config classes? The client and server could register different listeners for such events, allowing a clean separation of the code into inner classes of the client/server widgets as makes sense. Listeners could be chained and the same listener could potentially be reused in many places. For example, the use of Coordinate.round() before assigning the value is used for multiple attributes on both the client and server.

This is a good idea, but is tricky. At least on client-side, there are cases when the explicit setter needs to be invoked, and other cases when it does not. Anyway, as we have the AspectJ in place, there is nothing stopping us from adding new rules, if we can improve something.

3. ... The specific field ID can be stored to track the changed fields.

I've tried this, but it doesn't work, as the rule currently intercepts assignments during object creation (in the default c'tor), when there is no ID available. Also, there are cases (like code WidgetConfig.init) which is executed by the c'tor, thus ID might not be available yet (consider the case when it gets deserialized). My current solution is to track WidgetConfig instances and ensure only the active ones are processed. I've profiled the client-side a little using the scenarios which showed the ConfigManager.getConfigUpdates in the top 3 CPU consumers, and it was gone after the AspectJ changes.

4. In AbstractWidget, why don't we keep a reference to our WidgetConfig and use the enabled, hidden, visible state from there instead of storing separate state?

Because there are cases where no WidgetConfig is available (like TempContainer, ScrollContainer).

5. Widget subclasses are using their parent's config() method to access the private config instance. I would prefer making the config instance protected, renaming it cfg and directly accessing it from the child classes instead of calling config(). A simple example is client/Frame and chui/FrameImpl. In a perfect world we wouldn't need the config() method, but at least today it is used directly elsewhere.

Because of the fact that not all client-side widgets have a config, I chose to keep the config() method for now. A next step is to add a T extends WidgetConfig type to all Widget implementations on client-side and ensure each concrete widget impl has its own WidgetConfig type - so that all client-side state can be moved to it. I prefer doing this in stages, when each widget is worked (eventually the basic infrastructure can be done early).

6. It would be better to have a separation of the client-specific and server-specific code in ConfigManager. Common code/abstract methods can remain in the ConfigManager. Perhaps we can implement sub-classes that can reside in separate packages and inject the right one at runtime.

Yes, this will be cleaner. This will not take much, I will change it once I have all regressions/performance issues fixed.

7. It looks like you may have eliminated the memory leak of shared frames in LT. Correct?

Can't tell, didn't check specifically for it. But it would be nice if I did <g>.

#251 Updated by Hynek Cihlar over 9 years ago

In the context of #2388 I checked the current state of output redirection logic and it seems to be far away from the workable state for the GUI mode. Should I then skip it and leave it for later?

#252 Updated by Greg Shah over 9 years ago

In the context of #2388 I checked the current state of output redirection logic and it seems to be far away from the workable state for the GUI mode. Should I then skip it and leave it for later?

Yes. Please create a task for that work and make sure that it is assigned to milestone 12 and that I am a watcher.

#253 Updated by Greg Shah over 9 years ago

Code Review ca_upd20140926c.zip - Part 2

I still haven't reviewed your latest update. That is next. My apologies if any of these comments are redundant.

1. Could we drive association of common listeners (e.g. pushScreenDefinition() or rounding) by AspectJ using annotations to mark the attributes? It might make the "registration" of listeners simpler/cleaner.

2. Minor header issue in ClientState. Probably due to gen_headers.py being surprised by the -T- column.

3. The server-side WidgetId.allocateId() could be abstracted to be common code with the client-side WidgetId.nextId(). The actual implementations and their context-local data could be stored in server-specific and client-specific subclasses.

4. I think the use of LogicalTerminal from StandardServer.invoke() is a problem. This is our official "Progress-Compatible Top-Level Session Wrapper" which can be called from server-side code that has no client.

#254 Updated by Greg Shah over 9 years ago

Code Review ca_upd20140926g.zip

Generally, it all looks fine. The only thing I don't understand is why ConfigManager.notifyWidgetDestroyed() removes the backup config from the dirtyConfigs set. Can the same wid be in the dirtyConfigs set as both its active and backup instance?

#255 Updated by Constantin Asofiei over 9 years ago

1. Could we drive association of common listeners (e.g. pushScreenDefinition() or rounding) by AspectJ using annotations to mark the attributes? It might make the "registration" of listeners simpler/cleaner.

Yes, AspectJ allows this.

3. The server-side WidgetId.allocateId() could be abstracted to be common code with the client-side WidgetId.nextId(). The actual implementations and their context-local data could be stored in server-specific and client-specific subclasses.

OK.

4. I think the use of LogicalTerminal from StandardServer.invoke() is a problem. This is our official "Progress-Compatible Top-Level Session Wrapper" which can be called from server-side code that has no client.

I need server-side to inform the client when to start pushing updates... I'll look for a better place/way.

The only thing I don't understand is why ConfigManager.notifyWidgetDestroyed() removes the backup config from the dirtyConfigs set. Can the same wid be in the dirtyConfigs set as both its active and backup instance?

This is because the AspectJ Point Cuts (intercepted field setters) are called always (including during instance field initialization, when default/no-param c'tor is executed), and I can't distinguish between a not-fully-initialized active Config instance (with no ID yet, but which needs to be tracked) from a backup config instance... I can temporarily disable ConfigManager.addDirtyConfig while the backup config is being constructed/initialized, but I don't know if this will fully work. And as both active and backup can end up as being "dirty", I need to remove them both from the dirtyConfigs set.

#256 Updated by Greg Shah over 9 years ago

This is because the AspectJ Point Cuts (intercepted field setters) are called always (including during instance field initialization, when default/no-param c'tor is executed), and I can't distinguish between a not-fully-initialized active Config instance (with no ID yet, but which needs to be tracked) from a backup config instance...

Please document this in the javadoc somewhere.

I can temporarily disable ConfigManager.addDirtyConfig while the backup config is being constructed/initialized, but I don't know if this will fully work. And as both active and backup can end up as being "dirty", I need to remove them both from the dirtyConfigs set.

Understood.

#257 Updated by Constantin Asofiei over 9 years ago

About the MethodHandle performance issues: disabling the field setter listener code during duplicate plus the AspectJ listeners help, but not enough. I still get a lot of time spent in duplicate and setWidgetConfig. The MethodHandle is fast, but considering the amount of times is executed, it hurts us; there are tens of million of setWidgetConfig calls for a report, and this is explained if we multiply the 0.6 million ComponentConfig.applyConfig calls with 50, the average number of attributes serialized by it and its sub-classes.

I think we need to take a step back and add back the applyConfig logic to WidgetConfig; this will reduce the footprint of the ConfigManager.duplicate calls (and other cases where the state needs to be copied from one instances to another).

#258 Updated by Greg Shah over 9 years ago

Wouldn't moving to tracking changes at the field-level solve this issue?

#259 Updated by Constantin Asofiei over 9 years ago

Greg Shah wrote:

Wouldn't moving to tracking changes at the field-level solve this issue?

We are not in the tracking changes part here... this is the "make an exact duplicate of this configuration" part, which is currently using MethodHandle.

And there is another case which doesn't require listening for field changes: when de-serializing a WidgetConfig instance by the Reader thread.

#260 Updated by Greg Shah over 9 years ago

Constantin Asofiei wrote:

Greg Shah wrote:

Wouldn't moving to tracking changes at the field-level solve this issue?

We are not in the tracking changes part here... this is the "make an exact duplicate of this configuration" part, which is currently using MethodHandle.

My idea is that there is no need for a backup copy if you maintain a specific list of the fields that have changed. It seems that we should be able to store exactly the list of the changed values and which fields they map to. There is no need to duplicate entire instances.

#261 Updated by Constantin Asofiei over 9 years ago

Greg Shah wrote:

Constantin Asofiei wrote:

Greg Shah wrote:

Wouldn't moving to tracking changes at the field-level solve this issue?

We are not in the tracking changes part here... this is the "make an exact duplicate of this configuration" part, which is currently using MethodHandle.

My idea is that there is no need for a backup copy if you maintain a specific list of the fields that have changed. It seems that we should be able to store exactly the list of the changed values and which fields they map to. There is no need to duplicate entire instances.

Correct. If I manage to remove the dependency of the config's prior state in ControlConfig.syncWithWidget() and FillInConfig.syncWithWidget(), then I think this should work.

#262 Updated by Vadim Gindin over 9 years ago

I looked into testing results for my update and tried to reproduce failed tests locally. I found that most of them failed at the moment of quit. I'm pressing 'r' in syman menu, got the confirmation message "Are you sure you want to quit?..", pressing 'y' and application is closing.

See tests gso_370, gso_364, gso_217, tc_inquiry_inventory_001, tc_item_master_001, tc_item_stock_room_001 and many others. I tested some of them and found the error (see server_gso_370.log) in the log, when application is closing. As far as I can see in that log there are some multi-threading problem, some deadlock. Could you advice me how to find out real reason?

#263 Updated by Eric Faulhaber over 9 years ago

Vadim, from the server_gso_370.log file you attached, it looks like the P2J server cannot connect to the database. Make sure your JDBC URL for the majic database in gso-directory.xml specifies an existing, running, accessible database. Make sure you can connect with that database manually (i.e., with the psql client) with the same host, port, user, and password information as is specified in that section of the directory.

#264 Updated by Vadim Gindin over 9 years ago

Eric, If it would be a database connectivity problem the application would not work. The error happen at the quit processing. I.e. I ran the application, do something and choosing "Quit". The error happen during this quit processing.

#265 Updated by Eric Faulhaber over 9 years ago

Yes, good point -- it makes sense that the application would not work at all if the fundamental things I told you to check were wrong. However, it IS still a database connectivity problem.

The c3p0 connection pool is using 3 helper threads. From the stack traces in the log, they all appear to be testing the validity of existing, pooled connections by making requests to the database server. All 3 are waiting for a response from the database server at the time the traces were captured. The threads are unable to obtain a usable connection (either new or existing) within a reasonable amount of time, BUT the database is not reporting an error either, so the pool reports an apparent deadlock. This suggests a very heavy load or a long latency with the database. Given your description of what you are doing at the time, I guess it's the latter.

How is your environment configured? Are you using a remote database (i.e., on devsrv01) or a local one? If remote, is your connection to GCD slow or unstable?

#266 Updated by Vadim Gindin over 9 years ago

Understood. I ran local server with remote (devsrv01) database. An Internet connection to GCD is good and stable. Connection to GCD was good..

#267 Updated by Greg Shah over 9 years ago

Are these same "apparent deadlock" issues occurring when you run testing on devsrv01?

#268 Updated by Vadim Gindin over 9 years ago

No, server logs (server.log, server_gso_0.log) does not contain such error.

#269 Updated by Greg Shah over 9 years ago

OK, then please ignore this issue and try to debug and/or solve your problems a different way. One important question: in your regression testing runs, can you recreate the failures by manually executing the scenario on devsrv01?

#270 Updated by Vadim Gindin over 9 years ago

I tried to manually recreate the failures in tests I noted earlier in devsrv01. But there were no such error. Moreover, most of tests marked as failed at the quit step. But I don't see any errors in the logs and when I manually executing some of the test it works correctly.

Intermediate conclusion.
1. My db error could be caused by connection to GCD. That could be unstable at some time. For example yesterday there were such moment: www.goldencode.com wasn't available at all.
2. I don't understand why failed tests I noted earlier are marked as failed.

#271 Updated by Greg Shah over 9 years ago

Please focus on running testing on devsrv01. What failures are you seeing consistently on that system? How many times have you run testing?

#272 Updated by Vadim Gindin over 9 years ago

I ran regression testing on devsrv01 2 or 3 times. That is the point. I didn't see failures in the tests, that are marked as failed. Logs did not contain errors. By the way, should I ran majic from the folder ~/testing/majic, created by run_regression.sh configure or from staging git branch ~/testing/git/majic. In one of previous letters Constantin wrote the instruction to run majic on the client machine. This instruction contained the point about where to get majic sources - from git staging branch - checkout, zip and downloaded to local machine. Yesterday I setup and used that folder (~/testing/git/majic). Is it correct?

Could you look at some of failed tests, for example gso_370 or gso_364. As I can see the failures are happen there when user choose "quit" and print "y" in confirmation step. Do I correctly interpret them?

#273 Updated by Vadim Gindin over 9 years ago

I merged my update (message multi-window support) with the last updates, moved 3 flags from ThinClient to Window and added pause method with Window parameter and so forth.

#274 Updated by Constantin Asofiei over 9 years ago

Attached update is built on top of 0926c and 0296g.zip. Not yet merged with latest version. Issues from review notes 249, 253 and 254 are addressed. Still need to check the shared frame mem leak in LT.

The performance issues are fixed with only a ~20% downgrade in a report which creates lots of widgets; from ~90s usual time, now it takes ~110s (from initial 500s with 0926c/g). The conclusions are:
  1. avoid reflection at all cost. This includes:
    - no reflection for creating WidgetConfig instances
    - no reflection for copying a state from a config to another (this logic is now in WidgetConfig.applyConfig and sub-classes)
    - caching of Constructor objects in WidgetFactoryAdapter.create(Class<T>, WidgetId, WidgetConfig)
    - on a side note: a rule of thumb should be that Constructor, Field or Method objects are cached, at least in heavy-duty methods, to avoid resolving them on each call.
  2. MethodHandle.invokeWithArguments isslower than Field.set, Field.get and Method.invoke, one of the reasons being that it needs to check the parameters. I think they improved this in Java 8, but I didn't dig further.
  3. avoid unnecessary method calls executed by the AspectJ field set listener.
  4. use AspectJ to disable field set listener for applyConfig, constructor and readExternal and writeExternal.
  5. although collected dirty configs helps us in determining which fields were touched, the backup config is needed to avoid sending unchanged state to the server-side.
  6. removed the ServerExports.frameHidden call - this is not needed, as the server-side will take notice of this, on the next trip, in LT.applyChanges.

#275 Updated by Greg Shah over 9 years ago

By the way, should I ran majic from the folder ~/testing/majic, created by run_regression.sh configure or from staging git branch ~/testing/git/majic.

Are you talking about running majic servers and clients manually?

If you are using run_regression.sh, you ALWAYS run it from the ~/testing/ directory.

In one of previous letters Constantin wrote the instruction to run majic on the client machine. This instruction contained the point about where to get majic sources - from git staging branch - checkout, zip and downloaded to local machine. Yesterday I setup and used that folder (~/testing/git/majic). Is it correct?

I don't think you need to do that.

Focus right now on devsrv01. Please clear out your home dir and delete the ~/testing/ directory. Then use our timco.html documentation to recreate a fresh regression testing environment. DO NOT put your update there. I want you to run a fresh conversion using the current trunk of p2j and then execute runtime testing as documented in timco.html. Again, I want you to run regression testing WITHOUT your updates. Make sure you are running in screen and following the other suggestions in timco.html.

This will prove that you have a working testing environment or not. Once the basic environment is working OK, then you can repeat the testing process using your update.

Could you look at some of failed tests, for example gso_370 or gso_364. As I can see the failures are happen there when user choose "quit" and print "y" in confirmation step. Do I correctly interpret them?

Yes, it seems so. But I think you have something essentially wrong with your environment.

#276 Updated by Greg Shah over 9 years ago

Code Review vig_upd20141001a.zip

Everything looks fine. Please merge your STATUS and MESSAGE updates into a single update. There is no reason to keep these separate since you have to restart testing anyway.

#277 Updated by Greg Shah over 9 years ago

Code Review ca_upd20141001d.zip

1. The StandardServer.invoke() issue still exists.

2. The merge of the history entries for DynamicWidgetFactory is incorrect.

The performance issues are fixed with only a ~20% downgrade in a report which creates lots of widgets; from ~90s usual time, now it takes ~110s (from initial 500s with 0926c/g).

Is this just the overhead for the new approach in sending the widget configurations down to the client in a loop? Or is there this process actually copying state back to the server? If there is significant state sync back to the server, please help me understand what that would be.

One place that I see as being costly is widgetConfigUpdates.[read|write]External() which is writing most of its data as Object[]. This may be significantly less efficient than how we handle data in the normal Externalizable implementation in the *Config classes which is tuned to write out primitives. For example, serializing an Integer versus an int is very different. Why not leverage the Externalizable implementation in the *Config classes itself? Those methods could be turned into worker methods that get the bitset passed in. Then they would include the bitset in the stream but make each individual field's serialization conditional upon the associated bit being set. This also seems as if it might avoid the list processing work in the ConfigManager.getConfigUpdates().

although collected dirty configs helps us in determining which fields were touched, the backup config is needed to avoid sending unchanged state to the server-side.

Is the issue here that it is too costly to check the current state of the field being changed in the cfg instance during ConfigFieldSetterAspect.beforeSetField()? Because otherwise it seems that we could compare the new value with the current value right there and avoid calling addDirectConfig() unless there is a change.

#278 Updated by Constantin Asofiei over 9 years ago

Greg Shah wrote:

1. The StandardServer.invoke() issue still exists.

Thanks, forgot about it, is fixed now.

2. The merge of the history entries for DynamicWidgetFactory is incorrect.

Fixed.

You are correct, there was overhead too, when sending the config updates back to the server. Changing the WidgetConfig.[read/write]External is too hard to maintain and it adds additional overhead (there will always be fieldCount IF's to check if a field is marked as "dirty" or not, plus the field's ID must either be hard-coded or determined/checked by its name - in any case, messy). My solution was to add a NativeTypeSerializer class, which is associated with each WidgetConfig field (in the WidgetConfigDef class). When (de)serializing the WidgetConfigDef.updates array, the APIs provided by NativeTypeSerializer ensure that the native value is serialized as is, with only 1 byte transport overhead for each update, to let the receiving side now the data type (conformed to NativeTypeSerializer) of the next value to be read.

although collected dirty configs helps us in determining which fields were touched, the backup config is needed to avoid sending unchanged state to the server-side.

Is the issue here that it is too costly to check the current state of the field being changed in the cfg instance during ConfigFieldSetterAspect.beforeSetField()? Because otherwise it seems that we could compare the new value with the current value right there and avoid calling addDirectConfig() unless there is a change.

Yes, adding reflection there is costly (as AspectJ doesn't give us the old value via a parameter). But there was another way of improving this: I've changed the AspectJ rule to intercept only fields which are outside of c'tors, read/writeExternal, applyConfig, server-side classes. This (and the WidgetConfigUpdate changes) moved the report time back to ~95 seconds.

Attached update is replacement for my previous 0926c, 0926g, 1001d updates (again, lib/aspecttools.jar is not included). This is going through regression testing now.

#279 Updated by Greg Shah over 9 years ago

Code Review ca_upd20141002h.zip

It looks good. We should remember the "wishlist" somewhere for later development:

  • Delegate all custom setter logic that remains to widgets or helper classes, eliminating the remaining "code" from the config classes.
  • Implement a listener/notification framework and a clean way to associate listeners with their target changes. This would simplify things like the server-side pushScreenDefinition() or the rounding that we do.
  • Eliminate the config() method and any reliance on direct access to widget configs from outside of widgets. Move all widget-internal access to direct field references on the local properly-typed config instance.

You may have a better way to describe these ideas. Perhaps these can be added into the code somewhere as TODOs, so that we don't lose track?

#280 Updated by Vadim Gindin over 9 years ago

I merged status* update and message* update. Here is the merged common update. Can I stay 2 history entries in corresponding files like Window or ThinClient?

#281 Updated by Greg Shah over 9 years ago

Code Review vig_upd20141002a.zip

The changes are fine. Please do combine the history entries into a single entry (in those files where you have double entries). The reason is that we should always match 1 history entry to 1 bzr check in.

#282 Updated by Vadim Gindin over 9 years ago

I thought so. I've combined history entries.

#283 Updated by Greg Shah over 9 years ago

Code Review vig_upd20141002b.zip

It looks good.

#284 Updated by Greg Shah over 9 years ago

Is there anything left to do for STATUS or MESSAGE in #2229? If not, then please work on DEFINE FRAME/FORM next (see note 238). My guess is that may only need server side changes because DEFINE FRAME/FORM don't translate into a direct call to the client side.

Please build an additional changes in versions of the code that are from vig_upd20141002b.zip. In other words, I want your new code to be "pre-merged" with your current work.

What is the status of your testing environment reset?

#285 Updated by Vadim Gindin over 9 years ago

Greg Shah wrote:

Is there anything left to do for STATUS or MESSAGE in #2229?

Nothing.

..
What is the status of your testing environment reset?

Regression testing without my update is running.

#286 Updated by Hynek Cihlar over 9 years ago

Greg Shah wrote:

  • Implement a listener/notification framework and a clean way to associate listeners with their target changes. This would simplify things like the server-side pushScreenDefinition() or the rounding that we do.

This is very actual for me. My current approach is simple and relies on manual coded logic. For example when setting the pixel position of a window the update of the character dimensions is performed in the respective setter. Of course, the downside is that if the field is assigned directly the logic is not executed.

#287 Updated by Vadim Gindin over 9 years ago

Regression testing of p2j trunk without my update succeed. Only 2 tests have failed: tc_job_002 and tc_misc_reports_015. It happens as we know, so I think I can run regression with my update now. What do you think?

IN WINDOW clause is not supported for statements DEFINE FRAME/FORM. I didn't find a way to use IN WINDOW in these statements. The error "IN WINDOW phrase is not supported in this statement (3460)." always happen. I've started working on DOWN/SCROLL statements.

#288 Updated by Greg Shah over 9 years ago

Hynek Cihlar wrote:

Greg Shah wrote:

  • Implement a listener/notification framework and a clean way to associate listeners with their target changes. This would simplify things like the server-side pushScreenDefinition() or the rounding that we do.

This is very actual for me. My current approach is simple and relies on manual coded logic. For example when setting the pixel position of a window the update of the character dimensions is performed in the respective setter. Of course, the downside is that if the field is assigned directly the logic is not executed.

I understand. Constantin's approach retains any such code for now. My "wish" is that we handle this without the setters being located in the config classes. In addition, this approach may allow this extra logic to be common code where it makes sense.

#289 Updated by Greg Shah over 9 years ago

Regression testing of p2j trunk without my update succeed. Only 2 tests have failed: tc_job_002 and tc_misc_reports_015. It happens as we know, so I think I can run regression with my update now. What do you think?

Agreed.

Now please run testing with your 1002b update.

IN WINDOW clause is not supported for statements DEFINE FRAME/FORM. I didn't find a way to use IN WINDOW in these statements. The error "IN WINDOW phrase is not supported in this statement (3460)." always happen. I've started working on DOWN/SCROLL statements.

Good. These statements are "compile-time" things but since they support the "frame phase", I wasn't sure the impact of an IN WINDOW clause which would have a runtime implication. Don't forget to edit note 238 to mark off DEFINE FRAME/FORM from the list.

#290 Updated by Constantin Asofiei over 9 years ago

Greg Shah wrote:

It looks good. We should remember the "wishlist" somewhere for later development:

  • Delegate all custom setter logic that remains to widgets or helper classes, eliminating the remaining "code" from the config classes.
  • Implement a listener/notification framework and a clean way to associate listeners with their target changes. This would simplify things like the server-side pushScreenDefinition() or the rounding that we do.
  • Eliminate the config() method and any reliance on direct access to widget configs from outside of widgets. Move all widget-internal access to direct field references on the local properly-typed config instance.

You may have a better way to describe these ideas. Perhaps these can be added into the code somewhere as TODOs, so that we don't lose track?

I've added these details (plus the part that we need to separate the client-side state from the concrete widget impl) to the WidgetConfig class javadoc. There was a regression (and only one) in the last testing, is fixed now and I'm testing it again. Will upload/release the final update once I have a clean pass.

#291 Updated by Vadim Gindin over 9 years ago

DOWN/UP/SCROLL statements also do not support IN WINDOW clause. Compile error is IN WINDOW invalid with UP, DOWN, and SCROLL statements. (3052).

Greg, I can't edit note 238 probably because I'm not it's author. I'm posting this list here again to be able to edit it.

PAUSE
STATUS
MESSAGE
DEFINE FRAME/FORM (unsupported)
DOWN/UP/SCROLL (unsupported)
DISPLAY/VIEW/HIDE
ENABLE/PROMPT-FOR/SET/UPDATE/INSERT
NEXT-PROMPT (unsupported)
COLOR/UNDERLINE (unsupported)
CHOOSE (unsupported)
DO/FOR (unsupported)
SYSTEM-DIALOG-*

#292 Updated by Hynek Cihlar over 9 years ago

@Constantin, I found a little problem with the initialization of LogicalTerminal in ca_upd20141002h.zip.

LogicalTerminal is instantiated twice during the setup of new client-server conversation. The first call to the LogicalTerminal constructor invokes ClientExports.activateConfigUpdates() which causes another entry from the client to the server and ultimately enters LogicalTerminal.locate() for the second time. This results in the second instantiation of LogicalTerminal because the first call to the LogicalTerminal constructor has not finished and the instance has not been saved into the session context.

LogicalTerminal as part of its initialization creates the default window widget and thanks to the multiple instances the client window widget does not properly synchronize with the server counterpart.

I have fixed my working copy by splitting LogicalTerminal instantiation and initialization into two operations. First LogicalTerminal instance is created as before in ContextLocal.get, the instance is set into the context and only after that is the initialization performed. Please see the attached change set, implemented on top of ca_upd20141002h.zip.

A similar problem exists in the bzr trunk, but due to different execution dependencies.

#293 Updated by Greg Shah over 9 years ago

Code Review hc_upd20141004a.zip

I like the approach. It changes nothing for current context local instances, but provides a mechanism to cleanly separate construction from initialization. Please javadoc it, add headers and finish the TODO.

#294 Updated by Hynek Cihlar over 9 years ago

I am attaching the change set with added javadocs and the TODO implemented.

Greg Shah wrote:

Code Review hc_upd20141004a.zip

I like the approach. It changes nothing for current context local instances, but provides a mechanism to cleanly separate construction from initialization. Please javadoc it, add headers and finish the TODO.

#295 Updated by Vadim Gindin over 9 years ago

Here is an update for multi-window support of DISPLAY/VIEW/HIDE statements. Have a look please. I'm not sure about VIEW/DISPLAY methods in GenericFrame.

#296 Updated by Hynek Cihlar over 9 years ago

The change set is already up to date with ca_upd20141003a.zip and ca_upd20140929c.zip and is currently regression-tested.

Hynek Cihlar wrote:

I am attaching the change set with added javadocs and the TODO implemented.

Greg Shah wrote:

Code Review hc_upd20141004a.zip

I like the approach. It changes nothing for current context local instances, but provides a mechanism to cleanly separate construction from initialization. Please javadoc it, add headers and finish the TODO.

#297 Updated by Constantin Asofiei over 9 years ago

Final update for #2254, replacement for 1002h.zip - passed testing, released to bzr rev 10620. The lib/aspectjtools.jar file is not included, but is committed to bzr.

#298 Updated by Greg Shah over 9 years ago

Code Review vig_upd20141006a.zip

This looks really good. Did you fix the NPE from regression testing yet?

1. This code needs to be merged with the bzr revision 10620.

2. FramePlacementManager, UiUtils each need a history entry.

3. When we are adding optional parameters to methods like LogicalTerminal.hideAll(), we should do it with the optional parameters last. Instead of hideAll(handle hWin, boolean noPause) it should be hideAll(boolean noPause, handle hWin). This should make it easier to emit at conversion time and it is more consistent with the rest of our APIs.

4. It seems like there should be a LogicalTerminal.view(int widgetId, handle hWin), a LogicalTerminal.view(GenericFrame frame, ScreenBuffer frameBuf, int[] widgetId, handle hWin) and a LogicalTerminal.hide(int widgetId, boolean noPause, handle hWin).

5. In GenericFrame.display()/viewWorker(), is your use of LogicalTerminal.currentWindow() correct? It seems like there should be a precedence hierarchy lookup lok we do with other features.

#299 Updated by Greg Shah over 9 years ago

Code Review hc_upd20141005a.zip

If it passes testing, you can check it in.

Please note that since this affects context local initialization, any oversight or problem has the potential to impact the low level session processing severely. For this reason, the CTRL-C testing will be especially important to get a passing grade. I know that the 3-way CTRL-C tests almost always fail. I just want you to look carefully at those failures and make sure they are the same as previous failures. Otherwise, everything else needs to pass.

#300 Updated by Greg Shah over 9 years ago

Details of work for #2415:

I have not yet seen an insert indicator be displayed/maintained in GUI windows. This is just based on my testing so far, and I haven't really done much with the editing statements. I tried to connect to windev01 today to look into this, but right now I cannot access that system. I can find no feature listed in the documentation of the 4GL to turn such an indicator on (in GUI or ChUI). The #2415 task is to try various forms of editing statements (PROMPT-FOR, SET, UPDATE, INSERT, CHOOSE, ENABLE + WAIT-FOR) to see if any of these does cause the insert indicator to display in GUI. In ChUI, any of these editing statements will cause the client to enter "input mode" and allow the user to enter data. While in this mode, if the user presses the "Insert" key, then the text entry (fill-ins, editor...) fields will shift from replace mode into insert mode AND the "Insert" indicator will be displayed on the far right side of the status line. Please test to see if this same behavior exists in GUI. If so, please implement that behavior. Be careful with any such implementation, there are some strange behaviors that are implemented. In particular, there are 3 modes (insert mode, override mode and no mode, see Window.setInsertMode()) and an ambiguous flag (see Window.setInsertInAmbiguousState()). If the insert indicator is not present in GUI, then the ChUI-specific code will have to be safely moved out into ChUI code and the GUI version would be empty.

#301 Updated by Greg Shah over 9 years ago

Details of work for #2416:

This task is about implementing GUI frame support. At this time we will only implement an empty frame since we have no widget support yet, but that should still be very useful. Having that in place, we can both add more widget support and implement the scrollbar functionality in Window.

4GL code like this is simple enough and I think it needs no other widget support:

define frame f with width 30 title "Empty Frame".
frame f:height = 3.
view frame f.

Other variants with NO-BOX, different sizes, different positions and so forth can all be implemented. Part of the work is to make sure there is a clean abstraction of the ChUI and GUI code into specific subclasses, with the ui/client/Frame.java being completely common code.

The part that may be tricky here is if there are GUI-specific layout or sizing behaviors. Constantin notes this:

We should know which size is used as a base when determining the frame's size: virtual, current, max window size? IMO is the virtual size. Also, I hope that the window's scrollable support is just a scroll for the client-area's virtual size, it doesn't touch the layout of the existing/future frames.

Try implementing the frame in a straightforward manner but then you should test some different 4GL samples to confirm if our default behavior (for positioning/layout/sizing of frames when explicit values are not provided) is correct.

#302 Updated by Vadim Gindin over 9 years ago

Merged update with Constantin's fix of ProcedureManager.currentWindow bug.

#303 Updated by Marius Gligor over 9 years ago

1. I tested INSERT indicator for GUI using the following simple tests:

DEFINE VARIABLE myvar AS CHARACTER NO-UNDO FORMAT "x(60)".
MESSAGE "Enter value:" SET myvar.

DEFINE VARIABLE myvar AS CHARACTER NO-UNDO FORMAT "x(60)".
MESSAGE "Enter value:" UPDATE myvar.

DEFINE VARIABLE ix AS INTEGER NO-UNDO INITIAL 3.
PROMPT-FOR ix.
MESSAGE "Record buffer" ix SKIP(0) "Screen buffer" INPUT ix.

I tested also ask.p and primes.p procedures.
On all cases no INSERT state occur on the window in GUI mode. Only on ChUI mode occur.
Seems that INSERT indicator is not implemented on GUI. Only on ChUI is implemented.

2. On OE Procedure Editor the state of insert is show by changing the cursor (caret) style as follow:
- A line cursor means INSERT mode, the typed character is inserted at cursor position. The remaining line is shifted to the right one position.
- A block cursor means OVERRIDE mode, the typed character override the existing character at cursor position.

However when running tests and press the INSERT key on an edit widget the cursor (caret) is not changed.
The behaviour is always like an INSERT mode. So far I could not put the cursor in OVERRIDE mode!

#304 Updated by Greg Shah over 9 years ago

Before you consider your work with #2415 closed, please test SET, INSERT, CHOOSE, ENABLE + WAIT-FOR. I'm not referring to the MESSAGE SET or MESSAGE UPDATE, which are "special" editing modes. You do have a PROMPT-FOR case in your tests and an UPDATE case (primes.p), but the others are not yet tested. I just want to be thorough in our testing.

However when running tests and press the INSERT key on an edit widget the cursor (caret) is not changed. The behaviour is always like an INSERT mode. So far I could not put the cursor in OVERRIDE mode!

How strange! Please do make sure you are running each testcase using -p like: prowin32.exe -p primes.p. This ensures that the procedure editor is not causing strange results (which it can sometimes cause).

Try adding this to the beginning of each testcase:

ON F7 INSERT-MODE.

This should remap the insert-mode toggling button to the F7 key. On ChUI, this code shows the behavior:

on f7 insert-mode.

def var txt as char.
update txt.

#305 Updated by Marius Gligor over 9 years ago

Today I managed to connect OE to sports2000 database on the customer's server. Having a database connection I did many tests using examples from OE manual.
One of the tests using UPDATE statement have many edit fields (see the attached picture).

After doing many tests my conclusions are:
1. No INSERT indicator is displayed in GUI.
2. ON F7 INSERT-MODE. works on ChUI but not on GUI. On Windows the ChUI version looks strange, has more than 24 rows!
3. The edit caret is not changed when INSERT key is pressed and the insert mode was always insert-mode.

#306 Updated by Vadim Gindin over 9 years ago

After regression testing of vig_upd20141007a.zip I faced with the error (see attached log):
java.io.NotSerializableException: com.goldencode.p2j.ui.SkipEntity

Does somebody know how SkipEntity could get into Message?

There are also other strange error:
org.hibernate.service.UnknownServiceException: Unknown service requested [org.hibernate.stat.spi.StatisticsImplementor]

Need advice.

#307 Updated by Greg Shah over 9 years ago

VIG: While I look at the log, please merge your vig_upd20141007a.zip with the latest bzr level 10623.

#308 Updated by Vadim Gindin over 9 years ago

Merged update.

#309 Updated by Eric Faulhaber over 9 years ago

Vadim Gindin wrote:

There are also other strange error:
org.hibernate.service.UnknownServiceException: Unknown service requested [org.hibernate.stat.spi.StatisticsImplementor]

I have not seen this before, and until now, no one has reported it, so I'm at a bit of a loss to explain it. For some reason, Hibernate thinks statistics should be enabled for your environment, and it is failing to access the org.hibernate.stat.spi.StatisticsImplementor service. I don't know whether the error is that it is incorrectly determining that statistics collection should be enabled, or whether that is correct and the error is in Hibernate's effort to provide the service.

The org.hibernate.stat.spi.StatisticsImplementor interface is in the Hibernate jar file, as are a number of classes that implement it. Honestly, I don't know the details of how the service registry in Hibernate works, so I don't know why it is failing to load the service.

In any case, this is happening when the client connection is terminating. The current user context is being cleaned up and is about to end, so I don't think it is affecting the outcome of any test.

#310 Updated by Greg Shah over 9 years ago

Code Review vig_upd20141008a.zip

1. Please add this TODO just above the call to view() on line 4471 of GenericFrame.

// TODO: This call probably will need to be targeted at a specific window, but for now
//       we don't have redirected mode working for GUI, so it is unclear what to do.

2. The code at line 2799 of ThinClient was merged incorrectly. It should be moved to Window.message(String, Color, boolean).

3. Why are you needing to import com.goldencode.p2j.ui.chui.*; in LogicalTerminal?

4. In regard to the SkipEntity problem:

I don't see the place where the problem is caused. But I can give you some ideas:

  • SkipEntity is a server-side class. It is never expected to be sent to the client. We only should be sending the SkipConfig down when a SKIP is part of a frame definition.
  • The failure occurs in the writer thread, so that means that the server is trying to send an instance of the SkipEntity to the client. For this reason, you should look at your server-side code changes.
  • You have made changes to the code in LogicalTerminal.message() and LogicalTerminal.messageBox(). The workers for those methods happen to both be places that directly attempt to convert instances of SkipEntity into something "safe" to send down to the client. For example, for messageBox() we convert SkipEntity instances into an Integer and replace it in the Object[] named list before calling the client API. For message() we process the list to create a string and then send that to the client API. Either way, something with your changes to these methods is most likely the problem.
  • I didn't find the problem itself, but I do wonder if all the added method signatures isn't causing the problem. Perhaps there is some place where the use of Object[] in messageBox() is being passed to a version that just has Object because some null values aren't being cast to a more explicit type. In such a case, I wonder if it is possible to completely bypass the type fixup loop on line 3303. Since we then pass the resulting instance of list to the client API, that might be a place where there would be an attempt to serialize SkipEntity instances. My recommendation is to focus first on the messageBox() signatures to ensure that they all resolve down to the expected variants.

#311 Updated by Greg Shah over 9 years ago

About #2415 and #2334:

Now we know that there is no insert indicator for GUI. That is good information. Before we close #2415, I want to remove the use of InsertIndicator. This class isn't needed for GUI, right? But it actually does have behavior via its superclass. This can only cause problems.

In looking at that code, I looked closer at AbstractMessageArea. As far as I can see, that is ChUI-specific code and it is only used in ChUI. Did you have specific plans to make this into common code with GUI? Please help me understand the idea.

One reason I ask is that WidgetFactory.createMessageLine() is only used in these places:

  • It is used in Window.reset() to assign the insertModeLabel which we now know is something that only ChUI should do.
  • It is used in the AbstractMessageArea constructor to populate the messageLines list. If I am reading everything right, this is something that is also only done in ChUI.

Because WidgetFactory.createMessageLine() is only needed for ChUI, it should be removed from WidgetFactory and any dependent code can be implemented directly in ChUI-specific classes. The factory is only needed for creation of resources that have a UI-independent interface/usage.

Please get these cleanups done as part of #2415.

#312 Updated by Marius Gligor over 9 years ago

1. The idea behind AbstractMessageArea was to find an OOP solution (abstraction) rather than a trivial test like if ( isChui() ) for message area widget implementation.
Finally the resulted AbstractMessageArea class contains indeed only ChUI specific code so I moved the code to MessageAreaImpl which is the ChUI implementation for message area widget.
The class AbstractMessageArea has been deleted from project.

2. Insert indicator is ChUI specific only. I did some code refactoring in order to move the code related to insert indicator from Window to WindowChuiImpl class.
Since the widget is not used on GUI InsertIndicator class has been also deleted from project.

3. I observed that we cannot manage deleted files from project when we run regression tests. When one or more classes are deleted from project because the classes are still
on the remote repository compile errors could occur and build of P2J on tests fails. As a solution I uploaded also dummy classes for deleted files
which are compiled without errors in order to replace existing old files which are compile errors prone.
Finally after regression tests passed I deleted the dummy files from my project and I committed the changes to remote repository.As a result the deleted files was also deleted from remote repository.
The distributed archive does not contains deleted files is just mentioned in the body of the message that files was deleted.
The question is: Should we put also the deleted files on archive when we upload the changes on Redmine for a code review?
I think that you just override an existing project with the changes from archive before doing a code review.
If deleted files are missing from archive you have to delete these files by hand from your project on case of compile errors.

#313 Updated by Constantin Asofiei over 9 years ago

Marius Gligor wrote:

3. I observed that we cannot manage deleted files from project when we run regression tests. When one or more classes are deleted from project because the classes are still

Yes, this is problematic. What you can do for now is manually apply the update to P2J and build it (also removing the files), then adding the -Dp2j-built=yes to the run_regression.sh script, so that P2J will not be rebuilt. Our current approach doesn't allow automatic deletion of files during automatic testing.

Greg, an idea: we can add a .sh script with the same name as the archive, and execute that script in the i.e. ~/testing/majic or ~/testing/majic/p2j folder - this will allow a way of including the files which need to be removed in the automatic testing steps.

The question is: Should we put also the deleted files on archive when we upload the changes on Redmine for a code review?

No, this is not needed. Just mention which files need to be removed, when the update is uploaded to Redmine.

#314 Updated by Hynek Cihlar over 9 years ago

Constantin Asofiei wrote:

Greg, an idea: we can add a .sh script with the same name as the archive, and execute that script in the i.e. ~/testing/majic or ~/testing/majic/p2j folder - this will allow a way of including the files which need to be removed in the automatic testing steps.

Or simple list of files to be removed - one entry per line in a file in the root of the archive? Simple to read and less opportunities for an error.

#315 Updated by Constantin Asofiei over 9 years ago

Hynek, if the common UI logic is using native coordinates (you have bitmaps of NativeRectangle), then am I correct to assume that ScreenBuffer.rows and ScreenBuffer.cols should be in pixels, for GUI? Because currently I think the ScreenBuffer usage is still mixed between character coordinates and native (pixel) coordinates, in GUI case.

#316 Updated by Hynek Cihlar over 9 years ago

Constantin Asofiei wrote:

Hynek, if the common UI logic is using native coordinates (you have bitmaps of NativeRectangle), then am I correct to assume that ScreenBuffer.rows and ScreenBuffer.cols should be in pixels, for GUI? Because currently I think the ScreenBuffer usage is still mixed between character coordinates and native (pixel) coordinates, in GUI case.

IMHO ScreenBuffer.row and ScreenBuffer.column should be in character units (thus type double instead of current int) as these attributes seem to have bindings to the converted code dealing with characters. I didn't spent much time on searching all the use cases, but was not able to find any which would use pixels. Do you have any actual GUI case on mind?

ScreenBitmap I think should work on native units (discrete characters for chui and pixels for gui) as this is the nature of any bitmap and the code in the class doesn't seem to be of an exception.

#317 Updated by Vadim Gindin over 9 years ago

The next update, that failed regression testing. I've also attached logs. They looks strange. The log "testing_*" contain 2 rows about the same error about SkipEntity, but other logs do not contain its stack. By the way "audit_*" logs contain a lot of rows. How to interpret them?

#318 Updated by Constantin Asofiei over 9 years ago

Hynek Cihlar wrote:

Constantin Asofiei wrote:

Hynek, if the common UI logic is using native coordinates (you have bitmaps of NativeRectangle), then am I correct to assume that ScreenBuffer.rows and ScreenBuffer.cols should be in pixels, for GUI? Because currently I think the ScreenBuffer usage is still mixed between character coordinates and native (pixel) coordinates, in GUI case.

ScreenBitmap I think should work on native units (discrete characters for chui and pixels for gui) as this is the nature of any bitmap and the code in the class doesn't seem to be of an exception.

Sorry, in note 315 I meant ScreenBitmap.rows/cols - this is still set to character units in some places (like SwingGuiDriver.newSimulator and GuiSimulator.resizeWindow); I'll fix this.

I'm still a little confused as to when to use NativeRectangle/NativePoint and when to use Rectangle/Point: at this time, the UI layer looks like is still using character units, correct? And the OutputManager is responsible of transforming this into native units?

#319 Updated by Greg Shah over 9 years ago

Code Review mag_upd20141009a.zip

It looks good.

1. The explicit use of import com.goldencode.p2j.ui.chui.ThinClient; in Window.java is an exception to our normal rule about using wildcards for imports. The reason: we are temporarily importing the TC until we can move all the chui code out of it and move it to the ui/client/ package. For now, please revert that import back to the explicit version and place a comment on that line // TODO: remove this when TC is UI independent.

2. The insert mode processing is going to need to be reworked in all the editing/formatting classes. We will wait to do that work until later. For now, please put a TODO in the Window class to explain that "A substantial amount of the insert mode processing may eventually move to the ChUI-specific classes, but remains there until the editing widgets and formatting classes have been reworked.".

Please make these minor changes and get the result tested.

#320 Updated by Greg Shah over 9 years ago

we can add a .sh script with the same name as the archive, and execute that script in the i.e. ~/testing/majic or ~/testing/majic/p2j folder - this will allow a way of including the files which need to be removed in the automatic testing steps.

Or simple list of files to be removed - one entry per line in a file in the root of the archive? Simple to read and less opportunities for an error.

These are both good ideas. I am OK with either one. The script approach does allow for additional "processing" besides just the file removals, so that does provide a use in exchange for the cost of complexity.

Constantin: you can make the call and the change to the regression testing environment.

All: I do plan to move us to a development process that uses bzr branching instead of our current update zip process. We've done a pilot of the approach and it works, but I haven't lined up the final changes and docs to push it out. Such an approach more naturally handles these issues.

#321 Updated by Greg Shah over 9 years ago

Code Review vig_upd20141009a.zip

I'm fine with the changes. It looks like the messageBox() signatures look much better now.

The log "testing_*" contain 2 rows about the same error about SkipEntity, but other logs do not contain its stack.

Are you sure that testing_20141008_014734.log really matches the same server.log and server_gso_0.log that you sent? The SkipEntity issue is gone from those logs, so I think your changes resolved the issue. I don't see anything really concerning in the server.log and server_gso_0.log that you sent.

It also seems you have made additional runs. What are the results?

By the way "audit_*" logs contain a lot of rows. How to interpret them?

These are generated by our SecurityManager, but I'm surprised they are being created. The purpose is to allow security sensitive APIs to be traced separately from our logging framework.

Constantin: did we intentionally enable this at some point? It seems like we should clean that up since they are not needed.

#322 Updated by Marius Gligor over 9 years ago

Fixed Code Review mag_upd20141009a.zip issues.

#323 Updated by Marius Gligor over 9 years ago

I've started to work on task #2416. First of all I converted your sample

define frame f with width 30 title "Empty Frame".
frame f:height = 3.
view frame f.

but I found two problems: a conversion error and a runtime error.

1. Conversion error. The sample is converted in Java as follow:

public class F1
{
   F1F fFrame = GenericFrame.createFrame(F1F.class, "f");

   /**
    * External procedure (converted to Java from the 4GL source code
    * in f-1.p).
    */
   public void execute()
   {
      externalProcedure(new Block()
      {
         public void body()
         {
            fFrame.setHeightChars(new integer(3));

            fFrame.view();
         }
      });
   }
}

The problem is that generated code is not compiled due to an error in statement. fFrame.setHeightChars(new integer(3)); because GenericFrame doesn't have a setHeightChars method only a setHeight method is available which in turn set the height in caracters field in frame configuration. config.setHeightChars(height); (see GenericFrame.setHeightChars line 5077. The simple way to fix this issue is to add missing methods to GenericFrame class instead to change the conversion rules.
The same problem occur if we add a statement like frame f:width = 23. converted as fFrame.setWidthChars(new integer(23)); because setWidthChars is method is also missing.

2. Runtime error. The first executed statement is fFrame.setHeightChars(new integer(3)); which id delegated to GenericFrame.setHeight. In line 5076
execution of getHeight().doubleValue() throw an exception "Invalid frame ID 4" on client side. getHeight() make a call on client side to get the actual frame height but at the moment of call the frame definition wasn't yet send down to client. Usually an Frame.openScope() is generated at the beginning of body() on other samples like ask.p The first action in openScope is to push down any pending screen definitions LogicalTerminal.processDeferredPush(); and no more errors occur executing other statements on body() method.

public void body()
{
   fFrame.openScope();
   fFrame.setHeightChars(new integer(3));           
   fFrame.view();
}

Should we force an openScope always or we have to create another method wich contains only LogicalTerminal.processDeferredPush(); and force the execution of this new method always at the beginning of body() method?

3. I saw a frame ID with a value of 4 which means that the old rule for assign id's to frames is no longer used, isn't it?

4. I've created a dummy FrameGuiImpl class and I registered the class with widget factory. When a widget is created using WidgetFactoryAdaptor.create which invoke a constructor having two paramaetes WidgetId.class, WidgetConfig.class
This force widgets to have a constructor having exactly same parameters types.
For example: a constructor like:

   public FrameGuiImpl(WidgetId id, FrameConfig cfg)
   {
      super(id, cfg);
      gd = (GuiDriver) OutputManager.getDriver();
   }

does not work even thought the FrameConfig is a subclass of WidgetConfig
The constructor should be as follow:
   public FrameGuiImpl(WidgetId id, WidgetConfig cfg)
   {
      super(id, (FrameConfig) cfg);
      gd = (GuiDriver) OutputManager.getDriver();
   }

which force a cast from WidgetConfig to FrameConfig

We could change a little bit WidgetFactoryAdaptor.create method to works with constructors having subclasses as parameters and eliminate the casting. The solution is to search on all constructors for a constructor having 2 parameters and check if types are OK (Class.isAsignableFrom)
What do you think about this?

#324 Updated by Greg Shah over 9 years ago

Code Review mag_upd20141010a.zip

It looks good. Please test it.

#325 Updated by Constantin Asofiei over 9 years ago

Greg Shah wrote:

Constantin: did we intentionally enable this at some point? It seems like we should clean that up since they are not needed.

The audit logs have always been there... I think audit might have been enabled sometime before devsrv01 was in place, and the setting ended up in the directory templates we use for testing.

#326 Updated by Constantin Asofiei over 9 years ago

Marius Gligor wrote:

We could change a little bit WidgetFactoryAdaptor.create method to works with constructors having subclasses as parameters and eliminate the casting. The solution is to search on all constructors for a constructor having 2 parameters and check if types are OK (Class.isAsignableFrom)
What do you think about this?

I prefer to leave it as is. WidgetFactoryAdaptor.create is already a highly-invoked method, and is best to keep the code there simpler.

#327 Updated by Greg Shah over 9 years ago

The problem is that generated code is not compiled due to an error in statement. fFrame.setHeightChars(new integer(3)); because GenericFrame doesn't have a setHeightChars method only a setHeight method is available which in turn set the height in caracters field in frame configuration. config.setHeightChars(height); (see GenericFrame.setHeightChars line 5077.

In the 4GL, HEIGHT-CHARS and HEIGHT are considered the same keyword. They are synonyms. WIDTH-CHARS and WIDTH are the same way.

I don't want to duplicate code here by adding extra setters to GenericFrame. Let's just change the conversion to always emit setHeight() and setWidth() for HEIGHT-CHARS and WIDTH-CHARS respectively.

Should we force an openScope always or we have to create another method wich contains only LogicalTerminal.processDeferredPush(); and force the execution of this new method always at the beginning of body() method?

This seems like a bug in our frame scoping detection. Please see rules/annotations/frame_scoping.rules. I think the references (both VIEW and the attribute assignment) to the frame should have caused the frame scope to open.

I saw a frame ID with a value of 4 which means that the old rule for assign id's to frames is no longer used, isn't it?

Yes. Please see #1791 and bzr rev 10615. This was the email:

-------- Original Message --------
Subject: Updates [evl_upd20140829, evl_upd20140919a]
Date: Fri, 19 Sep 2014 20:10:35 +0400
From: Eugenie V. Lyzenko <>
To: ...

These updates introduce new widget ID allocation approach.

From now if you need to have ID for widget please use WidgetId.allocateId() method. No
more manual ID calculation or predefined frame ID like X000. Frame ID now is not embedded
into widget ID. All IDs are independent from each other.

...

#328 Updated by Greg Shah over 9 years ago

The audit logs have always been there... I think audit might have been enabled sometime before devsrv01 was in place, and the setting ended up in the directory templates we use for testing.

Interesting. I think someone might have put that in there for debugging. It definitely is not useful for our devsrv01 environment. Next time you make changes to the regression testing env, please disable all of that auditing.

#329 Updated by Vadim Gindin over 9 years ago

Greg Shah wrote:

Code Review vig_upd20141009a.zip

I'm fine with the changes. It looks like the messageBox() signatures look much better now.

The log "testing_*" contain 2 rows about the same error about SkipEntity, but other logs do not contain its stack.

Are you sure that testing_20141008_014734.log really matches the same server.log and server_gso_0.log that you sent? The SkipEntity issue is gone from those logs, so I think your changes resolved the issue. I don't see anything really concerning in the server.log and server_gso_0.log that you sent.

It also seems you have made additional runs. What are the results?

Oh, sorry. My mistake. Sure the corresponding testing_* log file (also the last) is the other (testing_20141009_090937.log) and it does not contain SkipEntity errors. It contains only 2 warnings except audit records:

    [exec] ======================= Exceptions in file: server_gso_0.log =======================
     [exec] [10/09/2014 11:20:17 EDT] (org.hibernate.engine.jdbc.spi.SqlExceptionHelper:WARN) SQL Error: 0, SQLState: null [10/09/2014 11:20:17 EDT] (org.hibernate.engine.jdbc.spi.SqlExceptionHelper:ERROR) An SQLException was provoked by the following failure: java.lang.InterruptedException
     [exec] ======================= Exceptions in file: server.log =======================
     [exec] [10/09/2014 11:20:17 EDT] (org.hibernate.engine.jdbc.spi.SqlExceptionHelper:WARN) SQL Error: 0, SQLState: null [10/09/2014 11:20:17 EDT] (org.hibernate.engine.jdbc.spi.SqlExceptionHelper:ERROR) An SQLException was provoked by the following failure: java.lang.InterruptedException

But in spite of errors absence in logs. There are a lot of failing tests. I'm working on them. For example gso_200 failed on step of buyer number input:
Main screen -> F Syman Master File Maintenance -> H Stock Buyers Master.
Then alertbox with input is displayed and the message "Enter buyer number" is displayed in the message area. Could you look at the screen gso_200/buyer_search1.txt:


                        ┌─────────────────────────────┐
                        │                             │
                        │   Buyer: 10                 │
                        │                             │
                        │   Enter your buyer number   │
                        │                             │
                        └─────────────────────────────┘

Enter buyer number

And I got when ran gso_200 manually on devsrv01:

┌────────────────────── TIMCO - Greensboro GSO TIPR833K ───────────────────────┐
│ C  Customers                           1  Service Order Status Maintenance   │
│ V  Vendors                             2  Service Order Status Alias Maint   │
│ E  Employees                           3  Operation Status Maintenance       │
│ U  Syman Users Maintenance             4  Operation Status Alias Maintenance │
│ K  Aircraft                            5  Service Type Master File           │
│ T  Contract Terms Master               6  ┌─────────────────────────────┐    │
│ L  Service Order Check List Master     7  │                             │    │
│ I  Inventory                           8  │   Buyer:                    │    │
│ W  Work Center Capacity & Dispatching  9  │                             │    │
│ S  Serial Number Master                J  │   Enter your buyer number   │    │
│ P  Printer Report Defaults             N  │                             │    │
│ Q  Department E-Mail Master            G  └─────────────────────────────┘    │
│ A  Chart of Accounts                   F  Buyer Master File                  │
│ B  Salesman Master File                H  Stock Buyers Master                │
│ D  Discrepancy Reason Master           Y  Hold For Codes Maintenance         │
│ M  Contact Master                      R  Return                             │
└──────────────────────────────────────────────────────────────────────────────┘

Enter buyer number

Is the error in absence of main screen? Did I correctly interpret the failing place? If yes - what the reason of this behavior can be?

#330 Updated by Hynek Cihlar over 9 years ago

Constantin Asofiei wrote:

Sorry, in note 315 I meant ScreenBitmap.rows/cols - this is still set to character units in some places (like SwingGuiDriver.newSimulator and GuiSimulator.resizeWindow); I'll fix this.

Yes, correct, both the cases should deal with native/pixel units not characters. The conversion to characters in GuiSimulator.resizeWindow is even mine fault.

I'm still a little confused as to when to use NativeRectangle/NativePoint and when to use Rectangle/Point: at this time, the UI layer looks like is still using character units, correct? And the OutputManager is responsible of transforming this into native units?

Native* data types should be used when representing the discrete units of the physical device - pixels of a GUI interface or the discrete character units of a terminal output (whether character based or Swing simulator). For example ScreenBitmap uses native units because it better maps to the output devices. ScreenBitmap is also a good example of the abstract nature of the "native" units, one code for two different kinds of output subsystems. Obviously GUI-specific or Chui-specific are also good candidates for the usage of the Native* data types.

With some exceptions the OutputManager indeed does the translation, however this is not a requirement but more a matter of convenience.

I should also note that the coordinates conversion logic is still being shaped as new requirements or limitations are being revealed. For example as part of #2388 I had to move the conversion logic to both server and client due to a few weird 4GL behaviours when validating the limits of the coordinate attributes.

#331 Updated by Greg Shah over 9 years ago

The gso_200/buyer_search1.txt is only referenced in 1 test (majic_baseline/tests/gso/gso_200/gso_200.xml):

   <send-text value="10" />
   <check-screen-buffer filename="gso_200/buyer_search1.txt" named-rectangle="screen" />

The first line inputs the text "10" and then second line waits the default amount of time (180000 seconds) for the named-rectangle "screen" to match the contents of gso_200/buyer_search1.txt.

In majic_baseline/majic.xml, "screen" is defined like this:

   <named-rectangles>
      <rectangle name="screen" row="0" column="0" width="80" height="24" />

This code compares the entire screen. And there are no "exclusion regions" specified, so the entire screen should match exactly.

The background of the screen is different which will cause this to fail. In the captured version it is expected that the background is blank, so my guess is that there is a problem with the HIDE or HIDE ALL. Also: the positioning of the dialog box seems different, so check that. But that positioning issue might be caused by the other frames on the screen, so fix the hide issue first and then try it to see.

#332 Updated by Hynek Cihlar over 9 years ago

I have a question to the widget experts out there. What does it mean for a window (in GUI) to be realized? I found the private method LogicalTerminal.isWindowRealized which only contains "TODO implement".

#333 Updated by Greg Shah over 9 years ago

For a widget to be realized, it means that the widget has been viewed (made visible on the screen) at least once. In the window move cases I didn't find any scenario where hiding the window could make it "unrealized" once it had already been realized. However, I think that for other unrelated widget cases and functionality, we may have found some cases where hiding something reset its "realized" flag.

#334 Updated by Hynek Cihlar over 9 years ago

Greg Shah wrote:

For a widget to be realized, it means that the widget has been viewed (made visible on the screen) at least once. In the window move cases I didn't find any scenario where hiding the window could make it "unrealized" once it had already been realized. However, I think that for other unrelated widget cases and functionality, we may have found some cases where hiding something reset its "realized" flag.

I see. Do you have anything against if I add the flag to the config and getters/setters to the widgets? The flag will be set from the setVisible(true) call.

#335 Updated by Constantin Asofiei over 9 years ago

Hynek Cihlar wrote:

I see. Do you have anything against if I add the flag to the config and getters/setters to the widgets? The flag will be set from the setVisible(true) call.

As this is a state computed by the client-side and needed by server-side too, your approach is OK.

On a side note: Hynek/Marius, have you encountered this situation until now:

   public void draw()
   {
      ... this translates to the current container's origin
      gd.draw(origin, new Runnable()
      {
         @Override
         public void run()
         {
            // custom drawing for the container 
            // draw the container's widgets - this ends up calling AbstractContainer.draw
            ThisContainer.super.draw();
         }
      });
   }

There is a contradiction here: the container's child widgets have their location set relative to the parent's location, so their drawing needs to be done within a gd.draw call (which translates to parent's origin first). But, when AbstractContainer.draw is called, the boundary in screen.setDrawingArea(boundary); is a rectangle relative to the window's origin - this contradicts the current relative origin, which is set to the container's origin...

So I hope you see my dilema. My idea is either to add a parameter to AbstractContainer.draw - to let it know the relative origin - or to somehow ensure that screenLocation will return a correct location, which is relative to the gd's current origin.

If you have other ideas, let me know.

#336 Updated by Hynek Cihlar over 9 years ago

Constantin Asofiei wrote:

Hynek Cihlar wrote:

I see. Do you have anything against if I add the flag to the config and getters/setters to the widgets? The flag will be set from the setVisible(true) call.

As this is a state computed by the client-side and needed by server-side too, your approach is OK.

On a side note: Hynek/Marius, have you encountered this situation until now:
[...]

There is a contradiction here: the container's child widgets have their location set relative to the parent's location, so their drawing needs to be done within a gd.draw call (which translates to parent's origin first). But, when AbstractContainer.draw is called, the boundary in screen.setDrawingArea(boundary); is a rectangle relative to the window's origin - this contradicts the current relative origin, which is set to the container's origin...

So I hope you see my dilema. My idea is either to add a parameter to AbstractContainer.draw - to let it know the relative origin - or to somehow ensure that screenLocation will return a correct location, which is relative to the gd's current origin.

I would not touch the screenLocation as this would IMHO brake its contract - screen location should be screen location. I would either add the parameter to AbstractContainer.draw or better yet ask the driver for the translated origin and offset boundary.

Btw. should the context restoration in SwingGuiDriver.draw be done in a finally block?

#337 Updated by Constantin Asofiei over 9 years ago

Hynek Cihlar wrote:

... or better yet ask the driver for the translated origin and offset boundary.

This one is interesting - I'll add it.

Btw. should the context restoration in SwingGuiDriver.draw be done in a finally block?

Yes, it wouldn't hurt - I'll change it.

#338 Updated by Greg Shah over 9 years ago

Do you have anything against if I add the flag to the config and getters/setters to the widgets? The flag will be set from the setVisible(true) call.

Good.

#339 Updated by Greg Shah over 9 years ago

Reposted from #2415 (by MAG):

Passed regression tests. Committed revision 10625.

The following files were deleted:
src/com/goldencode/p2j/ui/client/AbstractMessageArea.java
src/com/goldencode/p2j/ui/client/gui/InsertIndicator.java

#340 Updated by Marius Gligor over 9 years ago

Today I worked to fix frame conversion issues:

1. For frame scoping I changed the frame_scoping.rules by adding a FRAME_SCOPE node on FRAME_ALLOC node processing if not already exists.

2. For COLON (:) assignment I changed methods_attributes.rules to generate get/set Width and get/set Height for frames only.
For other widgets get/set WidthChars and get/set HeightChars should be generated due to Sizeable interface constraints.

Please take a look over my rules changes and let me know if the changes are OK or not.

#341 Updated by Vadim Gindin over 9 years ago

How to get WindowWidget having GenericFrame or GenericWidget? Some code on server side needs to use Window handling: VIEW, HIDE, ENABLE methods. Can I just look at parents like it implemented on client side?

#342 Updated by Greg Shah over 9 years ago

How to get WindowWidget having GenericFrame or GenericWidget? Some code on server side needs to use Window handling: VIEW, HIDE, ENABLE methods. Can I just look at parents like it implemented on client side?

If I understand correctly, the PARENT attribute of a widget defaults to the containing FIELD-GROUP but can be assigned something else, right? So I don't think that getParent() is reliable.

However, ff you have a widget reference you can get its ID. If you have a widget ID, you can get its frame using LogicalTerminal.frameIdFromWidgetId().

The LogicalTerminal.windowRegistry has the currently existing windows, but I don't think we track any guaranteed way to get from a given frame to its owning window instance. Nor does the window track frames it contains.

I suspect we need to fix this on the server side.

#343 Updated by Greg Shah over 9 years ago

Code Review mag_upd20141013a.zip

I don't think either of these changes is correct.

1. In methods_attributes.rules, ref can't be relied upon to be kw_frame to distinguish between frames and non-frames. The reference can be any handle. I think we need to leave it as only emitting get/setHeightChars() no matter what widget type. I guess your original idea to just add methods in GenericFrame for this will work, but those methods will have to just call get/setHeight(). We could also rename GenericFrame.get/setHeight() to GenericFrame.get/setHeightChars(). Doing so would cause quite a bit of changes to the MAJIC frame defs and any hand-written code.

2. Adding the frame_scope node whenever it is null seems wrong. Unfortunately, I have not really dug into this code enough to say that definitively. The overall design is poor because the code is so disconnected (everything is indirectly connected via multiple layers of maps/sets and layers of functions) that it is very hard to keep track of the core logic. I still don't understand what is the root cause of your problem here. I would expect that the VIEW of the frame would have caused references that would have properly triggered the addition of the right nodes to the right maps/sets, such that the downstream code would be OK. But the is_frame_referrer function doesn't list kw_view, kw_view only is listed as a is_widget_referrer. But there are no widgets here, so this is probably the problem. You can use the 4GL COMPILE statement's xref output to looks at the frame scope for the empty frame procedure. Test if it is the frame attribute (height) reference or the VIEW itself (or both) that is causing the frame scope to exist. Then we will need to make changes to properly honor those as "referrers".

Constantin: what do you think?

#344 Updated by Constantin Asofiei over 9 years ago

Greg Shah wrote:

Code Review mag_upd20141013a.zip
1. In methods_attributes.rules, ref can't be relied upon to be kw_frame to distinguish between frames and non-frames. The reference can be any handle.

The problem is related to accessing the attribute via the FRAME keyword - in this mode, the frame is accessed directly, not via the frame's widget (as when the frame is accessed via the handle). If you look into FrameWidget, you will see there are set/getWidth/HeightChars methods (as for other widgets); in GenericFrame, there are only set/getWidth/Height methods. I think we should make this consistent, and let GenericFrame work with the same APIs as FrameWidget, by changing CommonFrame/GenericFrame set/GetWidth/Height methods to use the same names as the ones defined in the Sizeable interface. Better, we should let CommonFrame inherit the APIs from the Sizeable interface, and remove these from the CommonFrame.

2. Adding the frame_scope node whenever it is null seems wrong.

I agree. From my work in frame_scope.rules, is best to find which case triggers the frame scope and add these to the functions/rulesets which determine if a frame scope is needed.

#345 Updated by Marius Gligor over 9 years ago

FrameWidget has both set/getWidth/WidthChars and set/getHeight/HeightChars We should keep the same methods for GenericFrame as well.
Even more. Looking into the generated code after conversion I found that set/getWith and set/getHeight are also used by rules in frame_generator.xml
If we rename the set/getWith as set/getWidthChars and set/getHeight as set/getHeightChars we have to change also some rules in frame_generator.xml.
If we keep set/getWith and set/getHeight and add set/getWidthChars and set/getHeightChars no changes in conversion rules are necessary and the GenericFrame API will be consistent with FrameWidget API.

Regarding inheritance from Sizeable I agree.

#346 Updated by Vadim Gindin over 9 years ago

I fixed HIDE error from previous regression testing and It reduced number of gso_* failed tests from 90 to 26. tc_* failed tests count are still big. I tried to interpret remained gso_* failed tests. They was not reproduced manually (on devsrv01). The problem I found is the output contains strange string right in the Syman Menu or in one of its submenus. Here is the gso_428 screen from testing report (step 23):

confidential information redacted

We can see in that screen unwanted extra output - letter 's' after (R)eturn word in right bottom corner.
How did it get there?

Similar error happens in several tests. Here is Syman Menu in the test gso_426 (step 1):

MAJIC                             Syman Menu                    10/13/14 17:44                                         
┌────────────────────── TIMCO - Greensboro GSO TIPR833K ───────────────────────┐                                        
│ I  Inventory                           F  Syman - Master File Maintenance    │                                        
│ O  Order Entry                         C  Codes and Parameters               │                                        
│ V  Service Order Entry                 M  Menu of Outputs and Reports        │                                        
│ P  Purchasing                          U  Utilities                          │                                        
│ G  Shipping                            N  Inquiry Menu                       │                                        
│ D  Data Collection                                                           │                                        
│                                        E  Estimating                         │                                        
│ 1  General Ledger                      J  Job Definition                     │                                        
│ 2  Accounts Receivable                 A  Component Tracking                 │                                        
│ 3  Accounts Payable                    W  Work Center Capacity & Dispatching │ 
│ 4  Payroll                                                                   │                                        
│ 5  Fixed Assets                        R  Quit MAJIC/Symix                   │                                        
│ 6  Customer Menu                                                             │                                        
│ 7  RFQ Menu                                                                  │                                        
│ 8  Quality Assurance                                                         │                                        
│                                                                              │                                        
└──────────────────────────────[     No mail    ]──────────────────────────────┘                                        
   [F1]-Launch [?]-Browse [F2]-Help                                                                                     
   Function: in                                 Menu: symix                                                             
                                                                         Insert     

We can see extra and unwanted word "Insert" also displayed in rigth bottom corner.

I also found in some tests, that the right border of window is not displayed. For example gso_186 (step 16):

10/13/2014                 SYMAN SERVICE ORDERING                   17:18:32                                            
┌───── Repair Station: TIPR833K  TIMCO - GREENSBORO                       ───┐                                        
confidential information redactedNo                                          
└──────────────────────────────────────────────────────────────────────────────┘                                        
(F)ind (N)ext (P)rev (A)dd (U)pdate (D)elete (O)utput (7)Page2 (R)eturn                                                 
Enter choice or <SPACE> for list of additional options: N                                                               
Enter data or press F4 to end. 

All those errors are not reproduced during manually testing on devsrv01. Could you advice me why these errors could happen? Thanks.

#347 Updated by Constantin Asofiei over 9 years ago

Marius Gligor wrote:

FrameWidget has both set/getWidth/WidthChars and set/getHeight/HeightChars We should keep the same methods for GenericFrame as well.

I think is best to clean these, as the HEIGHT-CHARS/WIDTH-CHARS are accessed via the handle.unwrapSizeable API, and only what is in Sizeable interface can be accesed.

If we keep set/getWith and set/getHeight and add set/getWidthChars and set/getHeightChars no changes in conversion rules are necessary and the GenericFrame API will be consistent with FrameWidget API.

I don't like it when we have two ways of doing the same thing - as we already found, at some point it will cause problems. I think is best to fix the conversion rules so that the {set|get}{Height|Width}Chars APIs are emitted always, and get rid of the {set|get}{Width|Height} versions.

#348 Updated by Vadim Gindin over 9 years ago

  • File gso_186_screen.txt added
  • File gso_426_screen.txt added
  • File gso_428_screen.txt added

Sorry, Redmine corrupts output screens in my previous note in spite of it's preview displayed them correctly. I'm attaching them in corresponding txt files. Besides they are displayed correctly in mail.

#349 Updated by Hynek Cihlar over 9 years ago

Vadim Gindin wrote:

I fixed HIDE error from previous regression testing and It reduced number of gso_* failed tests from 90 to 26. tc_* failed tests count are still big. I tried to interpret remained gso_* failed tests. They was not reproduced manually (on devsrv01). The problem I found is the output contains strange string right in the Syman Menu or in one of its submenus. Here is the gso_428 screen from testing report (step 23):

Are these outputs based on the clean trunk or your changes?

#350 Updated by Vadim Gindin over 9 years ago

Hynek, they are based on my update. Here it is.

#351 Updated by Marius Gligor over 9 years ago

Here are the results of compiling the frame test f-1.p using xref option:

c:\users\mag\documents\f-1.p c:\users\mag\documents\f-1.p 1 COMPILE c:\users\mag\documents\f-1.p
c:\users\mag\documents\f-1.p c:\users\mag\documents\f-1.p 1 CPINTERNAL ISO8859-15
c:\users\mag\documents\f-1.p c:\users\mag\documents\f-1.p 1 CPSTREAM ISO8859-15
c:\users\mag\documents\f-1.p c:\users\mag\documents\f-1.p 1 STRING "f" 1 NONE UNTRANSLATABLE 
c:\users\mag\documents\f-1.p c:\users\mag\documents\f-1.p 1 STRING "Empty Frame" 11 NONE TRANSLATABLE 

#352 Updated by Hynek Cihlar over 9 years ago

Vadim Gindin wrote:

Hynek, they are based on my update. Here it is.

I didn't find anything suspicious. I would create a stripped down test plan containing only your failing test suite and the necessary dependencies, run it in debug mode and connect your debugger (Eclipse). Then debug what is being output to the driver/drawing primitives.

#353 Updated by Marius Gligor over 9 years ago

I did the changes for set/get WidthChars/HeightChars by inheriting from Sizeable API.

#354 Updated by Hynek Cihlar over 9 years ago

Greg I have a question about the window_sizing test cases. Why some of the calls to move-win function don't use the result of round-trip-* methods?

For example window_positioning_that_works.p has the following call:
move-win(hwin, true, -11.1, -11.1, false, 0.0, 0.0, false, 0, 0, false, 0, 0, true).

The expected row value is set to -11.1, which works ok in environments that have 21 pixels per row. But in environments with 11 pixels per row the expected value should be -11.09 due to the row->y->row round trip.

#355 Updated by Greg Shah over 9 years ago

Constantin Asofiei wrote:

Marius Gligor wrote:

FrameWidget has both set/getWidth/WidthChars and set/getHeight/HeightChars We should keep the same methods for GenericFrame as well.

I think is best to clean these, as the HEIGHT-CHARS/WIDTH-CHARS are accessed via the handle.unwrapSizeable API, and only what is in Sizeable interface can be accesed.

Agreed.

If we keep set/getWith and set/getHeight and add set/getWidthChars and set/getHeightChars no changes in conversion rules are necessary and the GenericFrame API will be consistent with FrameWidget API.

I don't like it when we have two ways of doing the same thing - as we already found, at some point it will cause problems. I think is best to fix the conversion rules so that the {set|get}{Height|Width}Chars APIs are emitted always, and get rid of the {set|get}{Width|Height} versions.

Agreed.

#356 Updated by Greg Shah over 9 years ago

Code Review mag_upd20141014a

The changes to CommonFrame and GenericFrame seem fine.

The frame_scoping.rules you included has no changes. In addition, the frame_generator.xml and possibly other conversion rules will be needed to change the get/setHeight() and get/setWidth() into the new versions.

#357 Updated by Greg Shah over 9 years ago

Vadim: Constantin is reviewing your vig_upd20141013a.zip update and will provide some feedback.

We can see extra and unwanted word "Insert" also displayed in rigth bottom corner.

This one is suspicious since Marius just checked in some changes in this area. I don't want to confuse regressions in the trunk with regressions in your update. Keep copies of your current test results. Then please reset your testing environment and do a run with just the trunk (and none of your changes). Make sure it cannot show any of the problems you are finding.

#358 Updated by Marius Gligor over 9 years ago

Sorry was my fault. For frame_scoping.rules I didn't found a solution so far.
The rules in frame_generator.xml were changes. Please have a look.

#359 Updated by Greg Shah over 9 years ago

Hynek Cihlar wrote:

Greg I have a question about the window_sizing test cases. Why some of the calls to move-win function don't use the result of round-trip-* methods?

For example window_positioning_that_works.p has the following call:
move-win(hwin, true, -11.1, -11.1, false, 0.0, 0.0, false, 0, 0, false, 0, 0, true).

The expected row value is set to -11.1, which works ok in environments that have 21 pixels per row. But in environments with 11 pixels per row the expected value should be -11.09 due to the row->y->row round trip.

The move-win() function and the test suite in general evolved greatly as I was working on it. I did not understand the extent of the rounding and round-tripping behavior I was going to find, until I already had quite a bit of code written. The round-trip-* functions should be used in more places, but I got things working enough without them and left it as it was. Sorry for that.

#360 Updated by Greg Shah over 9 years ago

Code Review mag_upd20141014b.zip

It looks good.

#361 Updated by Hynek Cihlar over 9 years ago

Greg Shah wrote:

Hynek Cihlar wrote:
The move-win() function and the test suite in general evolved greatly as I was working on it. I did not understand the extent of the rounding and round-tripping behavior I was going to find, until I already had quite a bit of code written. The round-trip-* functions should be used in more places, but I got things working enough without them and left it as it was. Sorry for that.

No problem, I'll add them.

#362 Updated by Constantin Asofiei over 9 years ago

Vadim, about vig_upd20141013a.zip:

Browse.java:
- line 1989/2582: avoid resolving ancestor() twice...
- line 2584: why are you passing -1 to clearPutScreenInMessageArea instead of the ancestor window's ID?

WidgetRegistry:
- please clean the formatting on lines 367/417/491

Window.java
- you are mixing static with instance fields
- why are you keeping window's status type in a context-local variable? Can't this be kept with the window's instance? Because this is already private to the window, right? And it this data can't exist if the associated window doesn't exist.

FramePlacementManager:
- why are getNewRow and hideMarkedFrames working with the default window and not with the frame's window?

LogicalTerminal:
- 10721: when the line is too long, split it, as in:

Object referent = ProcedureManager.thisProcedure().get()
handle procCurWin = ProcedureManager.getCurrentWindow(referent);

- you need a message(Object[], boolean, Accessor, boolean, String, ColorSpec) too
- targetWindowWorker. This returns the window's server-side resource Id and you are sending to the client side this value, which is not the same as the window's widget ID. This needs to return i.e. ((WindowWidget)hWin.getResource()).config.id.getId(). On the same note, the windowId in ThinClient.view(..., int windowId) is never used by the client-side - is this for another task?

GenericFrame:
- what is your intent with the downBody field? This can't be easily integrated on server-side yet...
- you are transforming a VIEW FRAME f1 into a VIEW FRAME f1 IN CURRENT-WINDOW - what if the frame is already displayed in a window which is not the current window? Please make sure that your changes do not break this: if the frame is already realized when i.e. VIEW FRAME is used, then use the frame's window, not the current window.

ClientExports.java:
- view:1099 (and others, like statusInput) - please document what means when windowId is set to -1. On client-side, -1 usually references "no widget is associated/found". Also, on client-side, it is possible to have widgets with negative IDs (virtual widgets). I'm worried for this not to get mixed up at some point.

ThinClient.java:
- initializePrep:2506 needs to be removed (this line was removed with some previous update)
- targetWindowWorker - please specify what -1 means in the javadoc. Again, this doesn't keep track of the Frame's associated window (if there is such), so please document this too, as it can't be safely used from viewWorker (and others).

I need to finish checking the Window and ThinClient classes... will take care of these tomorrow morning my time. As a side note, please avoid moving methods around, especially when there are large changes (even if they are not sorted properly). This makes the review difficult.

#363 Updated by Vadim Gindin over 9 years ago

Thank you for review. My comments are below.

Constantin Asofiei wrote:

Vadim, about vig_upd20141013a.zip:

Browse.java:
- line 1989/2582: avoid resolving ancestor() twice...

These are two different methods. What do you propose - to make new field Window that will store resolving result. It looks not very good: we will have to look at this field to update it on time. Another way - make new method that will return Window but it does not help us to avoid excess code.

Actually there several places where ancestor resolving is needed and it would be convenient to have a method that will return Window right away, but I'm afraid it is not possible, because ancestor is not always Window
What do you think?

- line 2584: why are you passing -1 to clearPutScreenInMessageArea instead of the ancestor window's ID?

An argument of that method is just line number but not window id. Have a look at it's javadoc.

Window.java
- you are mixing static with instance fields
- why are you keeping window's status type in a context-local variable? Can't this be kept with the window's instance? Because this is already private to the window, right? And it this data can't exist if the associated window doesn't exist.

statusType has to be kept in statusStack that is in turn shared between all windows. statusStack contains StatusData objects. Each of them correspondent to one external procedure. See details in the notes #215, #223 and others.

FramePlacementManager:
- why are getNewRow and hideMarkedFrames working with the default window and not with the frame's window?

It seems that is my mistake.

LogicalTerminal:
- 10721: when the line is too long, split it, as in:
[...]
- you need a message(Object[], boolean, Accessor, boolean, String, ColorSpec) too
- targetWindowWorker. This returns the window's server-side resource Id and you are sending to the client side this value, which is not the same as the window's widget ID. This needs to return i.e. ((WindowWidget)hWin.getResource()).config.id.getId(). On the same note, the windowId in ThinClient.view(..., int windowId) is never used by the client-side - is this for another task?

About Id in targetWindowWorker only GenericWidget.getId method is used there. It is implemented exactly in this way: return config.id == null ? -1 : config.id.getId();

About ThinClient.view - windowId is transfered there to viewWorker method.

GenericFrame:
- what is your intent with the downBody field? This can't be easily integrated on server-side yet...
- you are transforming a VIEW FRAME f1 into a VIEW FRAME f1 IN CURRENT-WINDOW - what if the frame is already displayed in a window which is not the current window? Please make sure that your changes do not break this: if the frame is already realized when i.e. VIEW FRAME is used, then use the frame's window, not the current window.

I'll check it. Thank you.

ClientExports.java:
- view:1099 (and others, like statusInput) - please document what means when windowId is set to -1. On client-side, -1 usually references "no widget is associated/found". Also, on client-side, it is possible to have widgets with negative IDs (virtual widgets). I'm worried for this not to get mixed up at some point.

Interesting case. If we will be accurate this should not happen because windowId in vast majority cases just transfered to targetWindowWorker where this situation is correctly processed.

ThinClient.java:
- initializePrep:2506 needs to be removed (this line was removed with some previous update)

Just remove Window.getDefaultWindow() line in that method?

- targetWindowWorker - please specify what -1 means in the javadoc. Again, this doesn't keep track of the Frame's associated window (if there is such), so please document this too, as it can't be safely used from viewWorker (and others).

-1 always means that window is not specified and should be calculated as some default value using the simple algorithm returning default or current window.

I need to finish checking the Window and ThinClient classes... will take care of these tomorrow morning my time. As a side note, please avoid moving methods around, especially when there are large changes (even if they are not sorted properly). This makes the review difficult.

#364 Updated by Constantin Asofiei over 9 years ago

Vadim Gindin wrote:

Browse.java:
- line 1989/2582: avoid resolving ancestor() twice...

These are two different methods.

I was referring that you are calling ancestor() twice in this code, in the places I mentioned:

         if (ancestor() instanceof Window)
         {
            ((Window)ancestor()).message(buf.toString());
         }

why not save the result i.e.:
         Widget<?> w = ancestor();
         if (w instanceof Window)
         {
            ((Window) w).message(buf.toString());
         }

- line 2584: why are you passing -1 to clearPutScreenInMessageArea instead of the ancestor window's ID?

An argument of that method is just line number but not window id. Have a look at it's javadoc.

OK, got it.

Window.java

statusType has to be kept in statusStack that is in turn shared between all windows. statusStack contains StatusData objects. Each of them correspondent to one external procedure. See details in the notes #215, #223 and others.

Thanks, I see it know.

About Id in targetWindowWorker only GenericWidget.getId method is used there. It is implemented exactly in this way: return config.id == null ? -1 : config.id.getId();

OK.

About ThinClient.view - windowId is transfered there to viewWorker method.

Yes, but viewWorker doesn't uses it at all...

ClientExports.java:
- view:1099 (and others, like statusInput) - please document what means when windowId is set to -1. On client-side, -1 usually references "no widget is associated/found". Also, on client-side, it is possible to have widgets with negative IDs (virtual widgets). I'm worried for this not to get mixed up at some point.

Interesting case. If we will be accurate this should not happen because windowId in vast majority cases just transfered to targetWindowWorker where this situation is correctly processed.

OK, then keep an eye on it and make sure to document what -1 means in the javadoc.

ThinClient.java:
- initializePrep:2506 needs to be removed (this line was removed with some previous update)

Just remove Window.getDefaultWindow() line in that method?

Yes.

- targetWindowWorker - please specify what -1 means in the javadoc. Again, this doesn't keep track of the Frame's associated window (if there is such), so please document this too, as it can't be safely used from viewWorker (and others).

-1 always means that window is not specified and should be calculated as some default value using the simple algorithm returning default or current window.

OK. But make sure if this is called when the frame is realized and associated with a window is treated correctly.

#365 Updated by Constantin Asofiei over 9 years ago

Last review part of the vig_upd20141013a.zip:

ThinClient:
  1. where viewWorker/view/etc is called with windowId = -1, please post a TODO so that will be fixed when i.e. ENABLE and other stmts are addressed
  2. refreshStartRow/queryClosed/validateWidget: save the ancestor() in a variable and use that, i.e.
          if (w instanceof Window)
          {
             ((Window) w).clearPutScreenInMessageArea(-1);
          }
    
    
  3. do we really need to remove the statusInputRevert? You are moving logic specfic to client-side to the server-side. I think is best to keep this method and adjust it to work with a window ID, if needed.
  4. promptFor:
        TitledWindow wnd = frame.ancestor();
        ..
        // TODO is wnd allways Window?
          if (!(wnd instanceof Window)) 
          {
             throw new IllegalStateException("wnd is not a Window instance.");
          }
    

    Window is a TitledWindow, but not all TitledWindow's are Window. But, considering that a frame can only bet attached to a Window instance, your safety code is OK. But please make the message more clear (i.e. "Frame <frame-name> <frame-id> is not attached to a Window instance."). Please check all cases where you have this message.
    More, if you are working with a real Window downstream you can save it in a dedicated var, so you don't have to cast each time a Window API is called.
  5. view(Widget, ScreenBuffer, int[], boolean) - you are passing -1 as windowID - this should reflect the frame's window ID (or the viewWorker needs to be carefull to resolve the frame's window first, instead of using the current window)
  6. viewWorker:8471, Window.resolveWindow().clearPutScreenInMessageArea(-1); - I think this should too be relative to the window to which the Browse is associated. Please review all cases when a Window.resolveWindow is called or targetWindowWorker is used and make sure to either fix this (i.e. use the frame's window) or add TODOs so we can address this in the future. As I mentioned before, we need to make sure the window is resolved properly. I think you can use Window.resolveWindow(widget) in cases when you need to be aware of the widget's window, but please double check this is true.
  7. hideFramesInt - again, you are calling Window.resolveWindow() instead of using the frame's window.
  8. waitForWorker:9471 - frame's window needs to be used
  9. startInputStatus/stopInputStatus - can the current window be changed by code executed during the start/stopInputStatus bracket? I can't tell for sure, but if triggers are involved/widgets are enabled in multiple windows, when stopInputStatus is called the current window might not be the same as the window targeted by the startInputStatus.
  10. pauseBeforeEnd - I remeber that during some of my multi-window testing, the message Procedure complete. Press space bar to continue. was being shown only on the DEFAULT-WINDOW - and if the default window was hidden, then the message was not being shown and no pause was being performed.
  11. notifyUnbind - you are using UiUtils.getTopLevelComponents(Window.getDefaultWindow()) - if this API is not meant to be fixed by your current work, please add a TODO so that we will now this will need to be fixed in the future. As I mentioned before, please make sure all such cases are added a TODO.
  12. tinyInput - this is called and used only by MESSAGE ... UPDATE/SET - please move it to the Window class, as an instance method. More, if is left in ThinClient, it should have received as parameter the Window instance.
  13. requestHelp (and maybe others): please make sure that Window.resolveWindow() is called only once per method.
  14. validateWidget - I think the protections like widget.ancestor() instanceof Window are too aggressive here. It might hide real problems - either ensure that an explicit IllegalStateException is throw if the widget's window can't be resolved or let a ClassCastException be throw by the runtime, when you make the cast.
  15. setNeedPause - this is called from various places which target an explicit Window ID. Either add a int windowId parameter or add a TODO that this needs more work.
  16. view(int frameId) - same, you need the frame's window when view_ is called.
  17. stopNoAvailableWidgets - this too might need some more work... I can't easily tell which window might target.
  18. targetWindowWorker - please specify the window ID in the exception message.
Window.java:
  1. reset - has no javadoc.
  2. pushStatus. the code looks better like this:
          if (OutputManager.getDriver().inBatchMode())
          {
             // no-op in batch mode
             return;
          }
    
          WorkArea wrk = wa.get();
          ThinClient tc = ThinClient.getInstance();
    
          Map<Integer, Integer> wndStatusTypes = new HashMap<Integer, Integer>();
          for (Window<?> wnd : tc.getOutputManager().getRegistry().getWindows())
          {
             int wndId = UiUtils.getWidgetId(wnd).getId();
             if (wndId == -1)
             {
                throw new IllegalStateException("Window doesn't have ID");
             }
             else
             {
                wndStatusTypes.put(wndId, wnd.getStatusType());
             }
    
             if (wnd.getStatusType() != Window.ST_DEFAULT)
             {
                wnd.status(null);
             }
          }
    
          int inputActive = tc.getInputActive();
          for (int i = 0; i < cnt; i++)
          {
             wrk.statusStack.push(new StatusData(wndStatusTypes, inputActive));
          }
    
          // this needs to be done only once
          tc.setInputActive(0); 
    
  3. popStatus - the windows I think need to be iterated by the independentEventDrawingBracket's Runnable. wnd.setStatusType(type); might need to be called outside of the independentEventDrawingBracket.
  4. clearScreenDirectly (and others) - please save the screen() result in a var and use that (check all cases where you call screen()).
  5. splitMessage/message - you need to use the window's dimension, as in clearScreenDirectly (check all cases where you call TC.getScreenSize).

#366 Updated by Marius Gligor over 9 years ago

I tested some frame location options, Progress AT pharse. The option AT COLUMN c ROW w is implemented and works.
The option AT X x Y y is not yet implemented because is GUI specific. The X and Y are expressed in native units (pixels).
The following test case:

define frame f with width 30 AT COLUMN 5 ROW 4 title "Empty Frame".
frame f:height = 3.
view frame f.
MESSAGE FRAME f:X.

returns a value of 20 which correspond to COLUMN 5. Basically the COLUMN position character units are converted into native units (pixels) 20.
Same rules are applied for Y value which return ROW 4 converted in pixels.
In other words is a tight relation between position in character units and native units.
IMO we should implement the AT X x Y y option as well for GUI. Please let me know your opinion.

#367 Updated by Greg Shah over 9 years ago

In other words is a tight relation between position in character units and native units.

I have explored this for the window widget. Please read note 220 above for a summary of my results. Hynek has taken those testcases even further. He is working on a complete implementation right now, but only for the window widget.

However, as part of that work, he will undoubtably solve some common problems and there will at least be some common helper methods to handle the coupling of ROW to Y and COL to X. My guess is that the same algorithms are probably used in all widgets. I don't want to duplicate efforts. On the other hand, I also don't want to inhibit the work to get a working GUI frame.

Hynek: what do you think?

#368 Updated by Hynek Cihlar over 9 years ago

Greg Shah wrote:

In other words is a tight relation between position in character units and native units.

I have explored this for the window widget. Please read note 220 above for a summary of my results. Hynek has taken those testcases even further. He is working on a complete implementation right now, but only for the window widget.

However, as part of that work, he will undoubtably solve some common problems and there will at least be some common helper methods to handle the coupling of ROW to Y and COL to X. My guess is that the same algorithms are probably used in all widgets. I don't want to duplicate efforts. On the other hand, I also don't want to inhibit the work to get a working GUI frame.

Yes, this is what I am currently working on. Although the task (#2388) is related to Window widget only, I am implementing the logic on the level of BaseEntity/BaseConfig. Whether all the widgets share the same logic this should be the subject of future work. At the moment I have no reason to believe the widgets will behave differently in this regard, but this is 4GL so you never know.

In terms of the feature availability I am nearing the completion but I expect at least two days until it is fully released.

#369 Updated by Vadim Gindin over 9 years ago

regression testing trunk without my update gave 1 failed gso_* test (gso_290) and 19 failed tc_* tests.

#370 Updated by Greg Shah over 9 years ago

regression testing trunk without my update gave 1 failed gso_* test (gso_290) and 19 failed tc_* tests.

Are any of those failures a duplicate of the strange behavior you describe in note 346?

#371 Updated by Vadim Gindin over 9 years ago

I would say no. Most of tc_ failures look like when in Syman Menu user press R (that is quit command) and after quit confirmation user executes several commands like these:

vig@devsrv01:~$ ^C                                                                                                      
vig@devsrv01:~$ d^C                                                                                                     
vig@devsrv01:~$ ^C                                                                                                      
vig@devsrv01:~$ 4^C                                                                                                     
vig@devsrv01:~$ 4^C                                                                                                     
vig@devsrv01:~$ 4^C                                                                                                     
vig@devsrv01:~$ 3^C                                                                                                     
vig@devsrv01:~$ ^C                                                                                                      
vig@devsrv01:~$ ^C                                                                                                      
vig@devsrv01:~$                                                                                                  

After such sequence test fails.

By the way I saw such errors earlier. Why they happen? It does not looks like app error because the user already exited from the MAJIC. I mean why such scenario is marked as failure of converted MAJIC app?

Anyway other tc_* errors are clock dependent like tc_job_002 and should not be concerned. gso_* failed test and several tc_* test contains some error but they do not look like my errors.

#372 Updated by Greg Shah over 9 years ago

By the way I saw such errors earlier. Why they happen? It does not looks like app error because the user already exited from the MAJIC. I mean why such scenario is marked as failure of converted MAJIC app?

These are failures because this is unexpected. The test harness should not be typing MAJIC application input into the shell prompt. Such a case suggests that there is some kind of failure where MAJIC was exited and never entered properly again. This can be due to a client abend or it can be due to some other problem. I can't say why the harness is unreliable in this way.

Anyway other tc_* errors are clock dependent like tc_job_002 and should not be concerned. gso_* failed test and several tc_* test contains some error but they do not look like my errors.

OK. That means that the drawing issues you saw previously are somehow caused by your update. Please cleanup the issues highlighted in the recent code review. Upload the fixed version and let's get that reviewed again. When it is clean, run testing on it again and if the issues are still present, then perhaps you can put some debugging code in that can generate/log data to help identify the problem.

#373 Updated by Marius Gligor over 9 years ago

Here is an intermediate work for GUI frame implementation. So far I tested some options like NO-BOX, SIZE phrase, AT phrase, BGCOLOR and FGCOLOR, CENTERED.
Then I became in contact contact with SCROLLABLE option. As I understood if SCROLLABLE is TRUE the frame virtual space is different than physical space.
Widgets are layout inside the frame on virtual space, frame is draw using physical space but the frame virtual space could be scrolled.
This should be done simple when drawing by changing the origin of the frame panel which contains widgets without affect widgets layout.
Something similar I implemented for Window workspace area. You could test your simple empty frame example using this changes and you could see how it works.
Obviously is just an intermediate work and more effort should be done until will be finished.

I'm going now to look up deep inside the Frame class code to understand how it works. It's not so easy because the class has around 6400 lines of code!
So far I observed two interesting classes a ScrollContainer and a ScrollPane used for scrollable frames.
ScrollPane is already implemented GUI and I did some minor improvements since this widget is widely used. Apart MessageArea and scrollable frame I used ScrollPane widget to implement Window workarea as well.
ScrollContainer isn't UI specific but we are advised to carefully review the code in order to see if it works properly on both ChUI and GUI interfaces.

#374 Updated by Vadim Gindin over 9 years ago

I corrected most of Constantin's remarks. Have a look please.

#375 Updated by Constantin Asofiei over 9 years ago

Vadim Gindin wrote:

I corrected most of Constantin's remarks. Have a look please.

Please specify either what is fixed or what remains to be fixed, whichever list is shorter. It makes it easier for review.

progress.g
  1. you added the in_window_clause to enable_stmt. Does this apply for DISABLE statement, too?
ThinClient:
  1. getChanges - you are collecting only the frames from a single window. I don't think this is correct, we should go through all the frames in all windows... Maybe you need a UiUtils.getFrameIds() which returns all frames?
  2. as a general rule, use single-line comments via "//", and not multi-line comments
  3. place a TODO in pauseBeforeEnd that this needs more work (i.e. the message is always shwon in the DEFAULT-WINDOW, pause is not performed if default is hidden)
  4. enable - you have an extra new-line at the method signature
  5. viewWorker - add TODO that if the frame is (or is not) realized, the frame needs to be attached to the window (or the frame's window needs to be used).
  6. please check other usages of the screenSize field and replace it/mark it so that it will use the window's screen size. I think this field needs to be removed.
AbstractWidget
  1. window() method: I'm OK with it, but please document that this needs to be used only with realized widgets - it can't be used with widgets which are not yet attached to a window. Also, document the throws in javadoc.
Window:
  1. popStatus: I meant the windows should be iterated like this:
             final ThinClient tc = ThinClient.getInstance();
             tc.independentEventDrawingBracket(new Runnable()
             {
                @Override
                public void run()
                {
                   for(final Window<?> wnd : tc.getOutputManager().getRegistry().getWindows())
                   {
                      int wndId = UiUtils.getWidgetId(wnd).getId();
                      final Integer type = storedStatus.types.get(wndId);
    ...
    

    so that everything is done in a single drawing bracket...
  2. the Window.reset javadoc is different than the one in the base version of this file - please look at the base version and take the javadoc from there, as the method's body hasn't change (and I don't think its usage either).
GenericFrame (and maybe others):
  1. you have cases where you transform a DISPLAY into a DISPLAY ... IN WINDOW CURRENT-WINDOW; please go through all cases treated with this update (DISPLAY, VIEW, etc) and make sure you are not forcing a window when the statement did not specify one. Again, the reason is that if the frame is realized and attached to a window, not specifying the IN WINDOW clause means that the frame's window needs to be used. And if the client-side ends receiving a valid window ID when no IN WINDOW clause is present, it will not be able to distinguish between a case when the window is explicitly forced and a case when the window needs to be computed.

#376 Updated by Marius Gligor over 9 years ago

Some useful examples regarding window and frame sizes:

1. The window client area in GUI is 80 columns and 24 rows. In picture frame-1.png is depicted an empty frame having 80 columns and 22 rows. Message line area is 80 columns and 2 rows in size. The status line is count separate.

2. The window cannot be resized to grow. We can only make window lower in size. Picture frame-2.png depict the same frame on a window having a lower size than max size. Scroll bars are used in this case and the scroll bars are attached to window work space.

3. Picture frame-3.png depict a frame having 81 columns and 16 rows in size. In this case the scroll bars are attached to frame not to window space.

4. Picture frame-4.png is also an interesting case. The same frame is moved to column 8 row 2.

5. If the window is resized both work space and frame have scroll bars attached like is depicted in picture frame-5.png.

In conclusion the scroll bars are show on window workspace only when window is resized to a lower size and the virtual size of the workspace is greater than physical size. Depending on width and height comparison only horizontal, vertical or both scroll bars are show AKA "Show scroll bars when needed" For frames both scroll bars are show always if the frame size exceed workspace size! Frame SCROLLABLE option does not force frame scroll bars to be show. In other words the scroll bars visibility is depends on comparing sizes when drawing. Another interesting observation is that a frame looks like window widget as we can see in picture frame-4 where frame has the title bar and a scrollable work space area.

#377 Updated by Greg Shah over 9 years ago

you have cases where you transform a DISPLAY into a DISPLAY ... IN WINDOW CURRENT-WINDOW; please go through all cases treated with this update (DISPLAY, VIEW, etc) and make sure you are not forcing a window when the statement did not specify one. Again, the reason is that if the frame is realized and attached to a window, not specifying the IN WINDOW clause means that the frame's window needs to be used. And if the client-side ends receiving a valid window ID when no IN WINDOW clause is present, it will not be able to distinguish between a case when the window is explicitly forced and a case when the window needs to be computed.

I think we need to track this case on the server side and honor it in our targetWindowWorker(). Perhaps the frame instance should be passed to that method? That will allow the targetWindowWorker() to check frame realization and any assigned window that already exists. It would also allow the assigned window to be saved.

In cases like STATUS or MESSAGE, frame could be null and that logic would be bypassed.

#378 Updated by Marius Gligor over 9 years ago

Here are my first changes to abstract the code for frames and other minor improvements. Three classes are involved:

Frame which contains common code.
FrameImpl the ChUI implementation for frames.
FrameGuiImpl the GUI implementation for frames.

Despite the complexity of Frame code I think that almost all code is reusable in GUI implementation. This should be TRUE for other widgets as well as long as we are using characters units for common code and native units (pixels) on GUI drawing only. Here I think that character and native position and dimension for widgets should be maintained in synch.
In other words when for example the width in character units is changed the width in pixels should be also update. Or use only character units and do the conversion from character units to native units whenever we request physical location or dimension.

What I found so far as difference between ChUI and GUI is obviously the drawing code and the code using colors. Drawing code is already separated.
For colors because Frame.applyConfig is a complex code I implemented an abstraction only for colors comparison.
The drawing algorithm also contains some common flows and on the next step I'm going to find how ChUI draw is implemented and do the same for GUI or if it's possible create abstract code. Nevertheless finally we could test GUI frame implementation only when we will start to add widgets to frame.
Perhaps some code should be added in GUI for font changes as well.

Please take a look over my changes for Frame, FrameImpl and FrameGuiImpl and let me know your remarks.

#379 Updated by Vadim Gindin over 9 years ago

I made corrections corresponding to latest remarks. See remarks statuses below (marked with done).

Constantin Asofiei wrote:

Last review part of the vig_upd20141013a.zip:
ThinClient:
  1. where viewWorker/view/etc is called with windowId = -1, please post a TODO so that will be fixed when i.e. ENABLE and other stmts are addressed done
  2. refreshStartRow/queryClosed/validateWidget: save the ancestor() in a variable and use that, i.e.
    [...] done
  3. do we really need to remove the statusInputRevert? You are moving logic specfic to client-side to the server-side. I think is best to keep this method and adjust it to work with a window ID, if needed. When I removed it I had following argument: it was called from only one place, so that seemed not sufficient to have separate method in ClientExports interface.
  4. promptFor:
    [...]
    Window is a TitledWindow, but not all TitledWindow's are Window. But, considering that a frame can only bet attached to a Window instance, your safety code is OK. But please make the message more clear (i.e. "Frame <frame-name> <frame-id> is not attached to a Window instance."). Please check all cases where you have this message. done
    More, if you are working with a real Window downstream you can save it in a dedicated var, so you don't have to cast each time a Window API is called. done
  5. view(Widget, ScreenBuffer, int[], boolean) - you are passing -1 as windowID - this should reflect the frame's window ID (or the viewWorker needs to be carefull to resolve the frame's window first, instead of using the current window) done
  6. viewWorker:8471, Window.resolveWindow().clearPutScreenInMessageArea(-1); - I think this should too be relative to the window to which the Browse is associated. Please review all cases when a Window.resolveWindow is called or targetWindowWorker is used and make sure to either fix this (i.e. use the frame's window) or add TODOs so we can address this in the future. As I mentioned before, we need to make sure the window is resolved properly. I think you can use Window.resolveWindow(widget) in cases when you need to be aware of the widget's window, but please double check this is true. done
  7. hideFramesInt - again, you are calling Window.resolveWindow() instead of using the frame's window. done
  8. waitForWorker:9471 - frame's window needs to be used done
  9. startInputStatus/stopInputStatus - can the current window be changed by code executed during the start/stopInputStatus bracket? I can't tell for sure, but if triggers are involved/widgets are enabled in multiple windows, when stopInputStatus is called the current window might not be the same as the window targeted by the startInputStatus.
  10. pauseBeforeEnd - I remember that during some of my multi-window testing, the message Procedure complete. Press space bar to continue. was being shown only on the DEFAULT-WINDOW - and if the default window was hidden, then the message was not being shown and no pause was being performed.
  11. notifyUnbind - you are using UiUtils.getTopLevelComponents(Window.getDefaultWindow()) - if this API is not meant to be fixed by your current work, please add a TODO so that we will now this will need to be fixed in the future. As I mentioned before, please make sure all such cases are added a TODO. done
  12. tinyInput - this is called and used only by MESSAGE ... UPDATE/SET - please move it to the Window class, as an instance method. More, if is left in ThinClient, it should have received as parameter the Window instance. done
  13. requestHelp (and maybe others): please make sure that Window.resolveWindow() is called only once per method. done
  14. validateWidget - I think the protections like widget.ancestor() instanceof Window are too aggressive here. It might hide real problems - either ensure that an explicit IllegalStateException is throw if the widget's window can't be resolved or let a ClassCastException be throw by the runtime, when you make the cast. done
  15. setNeedPause - this is called from various places which target an explicit Window ID. Either add a int windowId parameter or add a TODO that this needs more work. done
  16. view(int frameId) - same, you need the frame's window when view_ is called. done
  17. stopNoAvailableWidgets - this too might need some more work... I can't easily tell which window might target. done - current window
  18. targetWindowWorker - please specify the window ID in the exception message. done
Window.java:
  1. reset - has no javadoc. done
  2. pushStatus. the code looks better like this:
    [...] done
  3. popStatus - the windows I think need to be iterated by the independentEventDrawingBracket's Runnable. wnd.setStatusType(type); might need to be called outside of the independentEventDrawingBracket. done
  4. clearScreenDirectly (and others) - please save the screen() result in a var and use that (check all cases where you call screen()). done
  5. splitMessage/message - you need to use the window's dimension, as in clearScreenDirectly (check all cases where you call TC.getScreenSize). done

Other answers and conclusions.
1. DISABLE statement does not support IN WINDOW clause. (about progress.g)
2. ThinClient.viewWorker really does not use window. It because it works through frame. Probably target window is selected somewhere deeper, somewhere in repaint code. I didn't find it. May be it is not implemented yet.
3. About your last remark for GenericFrame. As far as I can understand display methods do not force window passing if there are no IN WINDOW clause in a source statement.
4. Remarks of the note 375 are fixed except the last point window argument forcing.

#380 Updated by Greg Shah over 9 years ago

Code Review mag_upd20141016a.zip

The code looks really good.

There are some minor code standard issues (use of if( instead of if ( and some explicit imports), but that is not a big deal. WindowGuiImpl and GuiWidgetFactory each need a history entry.

#381 Updated by Greg Shah over 9 years ago

Code Review mag_upd20141017a.zip

I like where this is going.

1. Do you think that the Frame color management code for managing bgcolor/fgcolor/dcolor/pfcolor (and even the Frame.Colors inner class) could be common code that is placed further up the widget hierarchy (e.g. AbstractWidget or AbstractContainer)?

2. Is FrameGuiImpl.setColumns() required when there is already a Frame.setColumns() that looks logically the same?

3. Let's move ui.chui.FrameImpl to ui.client.chui.FrameChuiImpl. Any code that is properly abstracted and designed for ChUI only, should live in that directory. Ultimately, we want to remove ui/chui/ when all code is moved elsewhere.

#382 Updated by Vadim Gindin over 9 years ago

I fixed some remained remarks and added frames windows map to LogicalTerminal. That helps to keep track of windows, frames belongs to and use them to define target window handle for some operations (see new method targetWindowWorker). I marked fixed remarks in the note 379. Remained one or two.

#383 Updated by Vadim Gindin over 9 years ago

I forgot to add, that I reverted display*, view* and enable* methods in GenericFrame as you advised earlier. I get previous implementation back: methods without hWin got those previous implementation.

Some questions:
1. startInputStatus/stopInputStatus - you noted that the window probably can be the other in stopInputStatus than in the startInputStatus. Interesting.. I should check it. Could you advice me how?
2. About frame window usage. It is not the rule, that frame window is used if the frame is realized. I checked ENABLE and found the following. If I'm trying to ENABLE .. IN WINDOW widgets that already realized in some other window, they are moving to new window specified in IN WINDOW statement. I'll checking other statements.
3. About TC.screenSize removing. I replaced all its usages in Window class, but I'm not sure I can do it in ThinClient usages - not in all cases. What do you think?

P.S.
4. pauseBeforeEnd - I'll check it.
5. hideFramesInt - I'll check it.

#384 Updated by Constantin Asofiei over 9 years ago

Greg, this is for #2340. From your list:

1. Implementing proper keyboard and mouse event processing at the 4GL event level. This core event processing needs to be implemented soon.

Legacy mouse events are raised properly. I don't understand how is GUI mode special, so that it needs to treat the keyboard differently. Keys are read properly (i.e. a PAUSE will read the key and terminate), but there is a problem in the MESSAGE-AREA in GUI - the message list can't be scrolled via the keyboard keys (UP/DOWN/LEFT/RIGHT).

2. Making the min/max/restore buttons function properly.

These work properly. What is missing is a way to configure the max/min window dimensions in the directory/client.xml.

3. Implementing the generated 4GL events for the min/max/restore buttons.

These work properly.

4. Making the simulated system menu work properly.

These work. The only options I didn't touch are the Move and Size options - these are disabled for now.

Some additional notes:
  1. I've removed the GuiOutputManager.repaint(Widget) API - this was drawing immediately, instead of posting a repaint event and let the common drawing work do its work. ALL: please ensure the drawing is done via event posting and the AbstractContainer.draw API, avoid drawing directly. In some cases, you might find it useful to move the widget being drawn to top, before posting the repaint event.
  2. there is a small piece of code in GuiSimulator.draw, when the CLIP primitive is executed, on line 550:
                // debugging aid: enable these lines to outline the clipped area
                if (false)
                {
                   g2.setColor(Color.green);
                   g2.drawRect(ps.x, ps.y, ps.width, ps.height);
                }
    

    If you enable this code, it will draw a green rectangle surrounding the clipped area, before performing the clip. This allows you to know where the simulator is trying to draw something.
  3. now all drawing is being executed in batches (better said they are atomic). When a START_BATCH primitive is sent, the drawing in GuiSimulator.drawOnScreenBitmap will not finish until all the open batches have ended. This is needed because the AWT thread processing the paint event queue might finish the work before the P2J runtime has finished sending all paint primitives, so flickering might occur in certain cases.
  4. the window's icon is read from the /server/runtime/default/window-icon or /server/runtime/<account-id>/window-icon node. .ico files are not supported by AWT/SWING. Only png/jpeg/gif/bmp should be used (i.e. what the JVM implementation can handle).
  5. there is a new client-side state which is sent to the server-side: the ClientState.virtualLastKey holds the ID of a client-side event which originates from a non-keyboard device (i.e. this is a window or a mouse event). When this is set, it will populate the LAST-KEY attributes properly, on server-side.
  6. I can not find a way to disable the window's OS popup menu to appear when the ALT+SPACE key is pressed. If this is used to maximize/resize/etc the window, it will act on the underlying OS window.
  7. I did not find a way yet of intercepting the ALT-F4 (i.e. window close triggered via the OS), and "consume" this event so that the OS does not terminate the application. On windev01, when pressing ALT-F4, then WINDOW-CLOSE event/action is generated, and regardless if the trigger returns NO-APPLY or not, the event is ignored. There is a catch here: you need to run your GUI program from the command line; the procedure editor will terminate the program if the default-window is closed (and this is not how 4GL acts normally).

#385 Updated by Greg Shah over 9 years ago

I don't understand how is GUI mode special, so that it needs to treat the keyboard differently.

It isn't special. My only concern was to ensure that the GUI driver did in fact provide key events as required for widgets and READKEY.

.ico files are not supported by AWT/SWING.

How about:

http://image4j.sourceforge.net/

I can not find a way to disable the window's OS popup menu to appear when the ALT+SPACE key is pressed. If this is used to maximize/resize/etc the window, it will act on the underlying OS window.
I did not find a way yet of intercepting the ALT-F4 (i.e. window close triggered via the OS), and "consume" this event so that the OS does not terminate the application.

Are you describing the Java implementation here?

I'll do the code review next.

#386 Updated by Constantin Asofiei over 9 years ago

Greg Shah wrote:

I can not find a way to disable the window's OS popup menu to appear when the ALT+SPACE key is pressed. If this is used to maximize/resize/etc the window, it will act on the underlying OS window.
I did not find a way yet of intercepting the ALT-F4 (i.e. window close triggered via the OS), and "consume" this event so that the OS does not terminate the application.

Are you describing the Java implementation here?

In our Java implementation for GUI, pressing ALT-F4 will close the window and terminate the application. In 4GL, pressing ALT-F4 will raise a WINDOW-CLOSE event, but the application will not be terminated. To properly duplicate this, I think we need to intercept and "consume" ALT-F4 at the OS level...

#387 Updated by Greg Shah over 9 years ago

In regard to the ALT-F4 problem, isn't this due to the setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); in AbstractClient.init()? Setting it to JFrame.DO_NOTHING_ON_CLOSE would solve the problem. This should probably be done in the GuiSimulator constructor, where we customize the containing JFrame to remove decorations etc...

#388 Updated by Marius Gligor over 9 years ago

Here are my latest changes for frame GUI support which is still an intermediate work.

1. I fixed previous code review issues. The class FrameImpl was renamed to FrameChuiImpl and moved in package com.goldencode.p2j.ui.client.chui

2. Regarding Colors structure defined inside the Frame class so far I didn't found any other widgets to use it.
However we could move the structure to AbstractWidget or maybe better could be extracted as a separate class.

Apart code review issues I fixed also:

3. Clipping rectangles management in class GuiSimulator. Having this management the widgets from containers could be scrolled without drawing outside container area.
Basically each widget should define a clipping rectangle before drawing it self. So far I tested by scrolling a frame inside window workspace but should be tested
also when a scrollable frame is functional.

4. When the window is resized the right and bottom border became dirty so I designed also a window clean border code when window is resized see WindowLayout.
It's most efficient than cleaning the entire window.

5. I implemented show scroll bars policy for ScrollPaneGuiImpl

6. Other small changes.

Doing tests I observed that ChUI implementation count the frame border as 1 character in size. This is not compatible with GUI implementation on which the border is 1 pixel in size.
As a result some coordinates calculated in ChUI are different than expect values for GUI frames for character units. Here we have to check carefully the Frame code and do more code separation.
I attached some screen snapshots which depict an empty frame and show scroll bars policy.

#389 Updated by Constantin Asofiei over 9 years ago

Review for vig_20141020a.zip:

  1. ClientExports.statusInputRevert
    - please add it back, regardless if is used a single time or not, it has logic which belongs on the client-side. More, it is not used in a single location, it is used in three locations. And if it needs to be used in the future, that logic can't be easily duplicated on server-side without having to remember/search what that logic would be.
  2. progress.g - please add a history entry. Also, can the in_window_clause and the frame_phrase be in different locations? I.e. are both of these valid: ENABLE ... WITH ... IN WINDOW h. and ENABLE ... IN WINDOW h WITH .... If both are valid in 4GL, make sure both cases can convert properly.
  3. getScreenDimension usage instead of TC.getScreenSize - should have caught this sooner. getScreenDimension includes only the "area available for placement of frames", thus the message/status area is not included. I think this might be the reason you were seeing incorrect texts in the status/message area as regressions. The original TC.screenSize field was set to include the entire window (with the message/status area rows). Thus, I think is best to replace it with the window's real dimension (as returned by Window.dimension). We might have some problems in GUI (as this currently contains the simulated OS decorations), but we will address that later. To make sure the same dimensions are used in ChUI, do a debug and see what TC.screenSize holds in latest P2J - the window.dimension() call should return the same values.
  4. LT.targetWindowWorkerInt - the checkRealized parameter is never used... do you plan to add implementation later?
  5. LT.framesWindows - I think you are correct that the server-side needs to know the frame's parent window (if there is such). But I think is a better approach of sync'ing this state between the server and client-side. Add a int FrameConfig.windowID parameter which will be set by client-side whenever the frame's window is changed, and use that instead. If -1 is used, you can assume the frame is not realized. I think the location where the FrameConfig.windowId needs to be set is the Window.addFrame - this will set it to the window's ID.
  6. LT.targetWindowWorker(..., boolea checkRealized) - please post an example when you think this parameter will be set to false, because all your current calls are setting it to true.
  7. TC.screenSize - the remainder usages are these:
    - hideFramesInt(Frame) - I think this case can be replaced with the frame's window as determined on line 8809 in your update
    - positionCursor() - this is something ChUI-specific, thus replace it with the default-window's dimension.
    - promptFor(int, int[], ScreenBuffer, int, EventList, boolean) - again, this should be the frame's window, as determined on line 7730 in your update.
    - putCursor(double, double) - this is again something ChUI specific, thus replace it with the default-window's dimension.
    - refreshScreen() - this one is a little tricky. Considering the callpahts, ProcessDaemon.launch -> TC.resume -> TC.refreshScreen and TerminalStream.closeOut -> TC.refreshScreen, I think both cases are related to ChUI and can be replaced with the default-window's dimension.
    - setScreenSize() - this can be removed completely

About your questions:

2. ThinClient.viewWorker really does not use window. It because it works through frame. Probably target window is selected somewhere deeper, somewhere in repaint code. I didn't find it. May be it is not implemented yet.

This is interesting. I think this will need some more work, but with another task; the frame is currently being attached to the WINDOW in the WidgetRegistry.pushDefinition code at lines 353:

            if (frame.parent() == null)
            {
               Window.getDefaultWindow().addFrame((Widget) frame, 
                                                  frame.location().y,  // direct access
                                                  frame.location().x); // direct access
            }

3. About your last remark for GenericFrame. As far as I can understand display methods do not force window passing if there are no IN WINDOW clause in a source statement.

Exactly, in 4GL, if the IN WINDOW clause is not used, then it will use either the window to which the frame is already attached OR it will compute the window to which the frame will be displayed. If IN WINDOW is missing, your previous code was computing a window handle which might have beend different than the frame's window (if it was attached).

1. startInputStatus/stopInputStatus - you noted that the window probably can be the other in stopInputStatus than in the startInputStatus. Interesting.. I should check it. Could you advice me how?

Can really tell on the top of my head. At this time, I think is best to add a TODO/WARNING in both methods that the window might be different when stopInputStatus is called.

2. About frame window usage. It is not the rule, that frame window is used if the frame is realized. I checked ENABLE and found the following. If I'm trying to ENABLE .. IN WINDOW widgets that already realized in some other window, they are moving to new window specified in IN WINDOW statement. I'll checking other statements.

Well, the frame is realized, as some of its widgets are displayed. The idea is: a frame is considered realized when is shown on a window - no matter if all widgets are visible or not.

3. About TC.screenSize removing. I replaced all its usages in Window class, but I'm not sure I can do it in ThinClient usages - not in all cases. What do you think?

See above for comments related to this.

Please go through the notes in 362 and answer what was not addressed (i.e. GenericFrame.downBody and maybe others).

#390 Updated by Constantin Asofiei over 9 years ago

Greg Shah wrote:

In regard to the ALT-F4 problem, isn't this due to the setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); in AbstractClient.init()? Setting it to JFrame.DO_NOTHING_ON_CLOSE would solve the problem. This should probably be done in the GuiSimulator constructor, where we customize the containing JFrame to remove decorations etc...

You are correct, DO_NOTHING_ON_CLOSE is the solution. I tried doing this in GuiSimulator c'tor, but this is called before the AsbstractClient.init in GuiClient c'tor and AbstractClient.init() was overriding my setting... I'll override init in GuiClient and set the close operation properly. Any idea on how to disable ALT-SPACE, which shows the window's OS popup menu? (try ALT-SPACE on any program you have active and you will see what I mean).

#391 Updated by Constantin Asofiei over 9 years ago

Greg Shah wrote:

I don't understand how is GUI mode special, so that it needs to treat the keyboard differently.

It isn't special. My only concern was to ensure that the GUI driver did in fact provide key events as required for widgets and READKEY.

OK, I think you are correct to be concerned, to some extent. Keys are read properly, but not all keys are interpreted the same way in GUI i.e.:
- in P2J, ALT-F4 doesn't show as the proper key code on my windows machine
- in 4GL, ESC is a replacement for what F4/END-ERROR does on ChUI
- in 4GL, F4 looks like it triggers CLOSE event
- in 4GL, F1 is linked to HELP and F2 is linked to GO event.

I think we should treat this in a separate task - we might need a way to make the Keyboard mappings configurable depending on the GUI/ChUI mode.

.ico files are not supported by AWT/SWING.

How about:

http://image4j.sourceforge.net/

I was looking for a way of "pluging-in" a certain image type into the JVM, without having to manually handle i.e. ICO cases. I'm concerned about the cases when the file extension doesn't represent the file format.

#392 Updated by Greg Shah over 9 years ago

I was looking for a way of "pluging-in" a certain image type into the JVM, without having to manually handle i.e. ICO cases. I'm concerned about the cases when the file extension doesn't represent the file format.

There is this (BSD license):

https://github.com/haraldk/TwelveMonkeys

#393 Updated by Greg Shah over 9 years ago

I think we should treat this in a separate task - we might need a way to make the Keyboard mappings configurable depending on the GUI/ChUI mode.

Agreed. Please create a task for that.

#394 Updated by Constantin Asofiei over 9 years ago

Greg Shah wrote:

I was looking for a way of "pluging-in" a certain image type into the JVM, without having to manually handle i.e. ICO cases. I'm concerned about the cases when the file extension doesn't represent the file format.

There is this (BSD license):

https://github.com/haraldk/TwelveMonkeys

Great, this is exactly what I was looking for. All is needed is to add the jars to the classpath and the support is there. We don't have to include these now, is good to now they are supported.

Greg Shah wrote:

I think we should treat this in a separate task - we might need a way to make the Keyboard mappings configurable depending on the GUI/ChUI mode.

Agreed. Please create a task for that.

See #2423

#395 Updated by Greg Shah over 9 years ago

In regard to the ALT+Space issue, I wonder if something like this will help:

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class TestSwingFrame
{
   public static void main(String[] args)
   throws Exception
   {
      JFrame frame = new JFrame();
      frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);

      KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher(new KeyEventDispatcher()
      {
         @Override
         public boolean dispatchKeyEvent(KeyEvent evt)
         {
            if (evt.getKeyCode() == KeyEvent.VK_ALT)
            {
               System.out.println("ALT! " + evt.toString());

               // this means the event has been handled and needs no further processing
               return true;
            }

            // allow further processing
            return false;
         }
      });

      frame.setSize(300, 100);
      frame.setVisible(true);
   }
}

I can't test it on windev01 because right now I can't access it through the CAG. Linux/KDE doesn't have the same ALT approach to get the system menu, so I can't test it here either.

#396 Updated by Constantin Asofiei over 9 years ago

Greg Shah wrote:

In regard to the ALT+Space issue, I wonder if something like this will help:

I've tested it on windows by using if (evt.getKeyCode() == (int) ' ' && evt.isAltDown()) to intercept ALT+Space, and I can say this after a breakpoint is placed in dispatchKeyEvent:
  • after ALT+Space is pressed, the window's OS popup menu is shown LE: immediately
  • the breakpoint is intercepted and the System.out.println(...); return true; are executed

My conclusion is that the ALT+Space hook is somewhere lower, in the OS event processing. Do you think is possible to intercept this in some native code (just to disable the popup menu) and after that re-apply the keys, so it is received by the application? As a side note, this is not a show-stopper, is just something nice to have. As an alternative, this will prevent window maximizing via OS:

      frame.addWindowStateListener(new WindowStateListener()
      {
         public void windowStateChanged(WindowEvent e)
         {
            if ((e.getNewState() & Frame.MAXIMIZED_BOTH) == Frame.MAXIMIZED_BOTH)
            {
               resizeWindow(getWidth(), getHeight());
            }
         }
      });

#397 Updated by Greg Shah over 9 years ago

Do you think is possible to intercept this in some native code (just to disable the popup menu) and after that re-apply the keys, so it is received by the application?

It definitely is possible. The easiest way on WIN32 would probably be registering an application-specific accelerator table with the same key combinations as used by the "system accelerator table". See:

http://msdn.microsoft.com/en-us/library/windows/desktop/ms646335%28v=vs.85%29.aspx

There are other potential solutions that are far nastier, so I hope this may work.

#398 Updated by Greg Shah over 9 years ago

Code Review ca_upd20141021b.zip

The update is very good.

1. LegacyOSEvents seems to map to the Progress 4GL "Portable Mouse Events" (e.g. MOUSE-SELECT-DOWN), at least for the MouseEvent case. When used for WINDOW-* events the 4GL calls these "high level widget events". I worry that the name is confusing, since these "portable" or "high level widget" events really have nothing to do with the operating system, but are 4GL concepts.

2. Will the approach used in Keyboard.java cause the "physical button mouse events" (e.g. LEFT-MOUSE-DOWN) to take precedence over the portable mouse events? The 4GL docs state this is true for trigger firing.

3. There is no support for the MOUSE-{EXTEND | MOVE}-* portable mouse events.

4. There is no support for the MIDDLE-MOUSE-* physical button mouse events.

#399 Updated by Constantin Asofiei over 9 years ago

Greg Shah wrote:

1. LegacyOSEvents seems to map to the Progress 4GL "Portable Mouse Events" (e.g. MOUSE-SELECT-DOWN), at least for the MouseEvent case. When used for WINDOW-* events the 4GL calls these "high level widget events". I worry that the name is confusing, since these "portable" or "high level widget" events really have nothing to do with the operating system, but are 4GL concepts.

Yes, you are correct, the OS part is especially confusing... but I'm a little stuck on naming it. I would go either with HighLevelEvent or create separate sub-classes for each case, i.e. WindowEvent and PortableMouseEvent.

2. Will the approach used in Keyboard.java cause the "physical button mouse events" (e.g. LEFT-MOUSE-DOWN) to take precedence over the portable mouse events? The 4GL docs state this is true for trigger firing.

I couldn't duplicate this in 4GL tests: if you have 2 triggers, one with physical button mouse events and one with portable mouse events, they seem to have the same level of precedence (no matter how you switch the triggers, the last one registered for either e.g. LEFT-MOUSE-DOWN/MOUSE-SELECT-DOWN will be fired). More, the physical button mouse events seem to be just aliases for the portable mouse events: the LAST-EVENT's attributes all refer to the portable events, regardless if the trigger was for the physical button.

3. There is no support for the MOUSE-{EXTEND | MOVE}-* portable mouse events.
4. There is no support for the MIDDLE-MOUSE-* physical button mouse events.

All these couldn't be duplicated on windev01. Not sure, but the fact that we are accessing windev01 via a remote connection might have something to do; it might be possible that when we are physically using a mouse, things to behave differently.

Attached contains some more fixes:
  1. do not allow window maximize via OS (it just sets it back to the previous dimensions)
  2. Java raises MOUSE_PRESSED/RELEASED/CLICKED for a click, not just a MOUSE_CLICKED, thus MOUSE_PRESSED/RELESED must not raise 4GL events if a click was captured.
  3. MessageAreaGuiImpl.setMessageText needs to do its work in a TC.eventDrawingBracket
  4. removed the window clear in WindowGuiImpl - Marius's border cleaning algorithm does better work
  5. prevent window closing via ALT+F4

#400 Updated by Greg Shah over 9 years ago

Code Review mag_upd20141021a.zip

The results look very good.

1. FrameGuiImpl.initialize() needs javadoc.

2. About color management code:

Regarding Colors structure defined inside the Frame class so far I didn't found any other widgets to use it.
However we could move the structure to AbstractWidget or maybe better could be extracted as a separate class.

Yes, it could be a separate class.

Regarding whether other widgets use it, FrameGuiImpl is the first "real" GUI widget. All of the real GUI widgets will have similar color logic. I also see that the "fake" ScrollPaneGuiImpl, ScrollableContainer and the "real" FrameGuiImpl widget have duplicated data members (bgColor, fgColor, sysBgColor, sysFgColor) and the colors() method that is duplicated. This looks like code that should be put into a common location.

#401 Updated by Greg Shah over 9 years ago

create separate sub-classes for each case, i.e. WindowEvent and PortableMouseEvent.

This is probably best.

I couldn't duplicate this in 4GL tests: if you have 2 triggers, one with physical button mouse events and one with portable mouse events, they seem to have the same level of precedence (no matter how you switch the triggers, the last one registered for either e.g. LEFT-MOUSE-DOWN/MOUSE-SELECT-DOWN will be fired). More, the physical button mouse events seem to be just aliases for the portable mouse events: the LAST-EVENT's attributes all refer to the portable events, regardless if the trigger was for the physical button.

OK, I guess this is one more place where the 4GL docs are wrong. Perhaps some javadoc to this effect will help us remember this fact.

All these couldn't be duplicated on windev01. Not sure, but the fact that we are accessing windev01 via a remote connection might have something to do; it might be possible that when we are physically using a mouse, things to behave differently.

Yes, I expect you're right. The RDP doesn't implement a 3-button mouse. Implement these as best you can guess they would probably work.

The 4GL doc "Programming Interfaces" in chapter 5 ("Handling User Input") section "Using mouse buttons and events" says that the "extend" mouse button is CTRL + left mouse. It says move is also the left mouse button, like select.

#402 Updated by Greg Shah over 9 years ago

Code Review ca_upd20141021c.zip

The changes look good.

#403 Updated by Greg Shah over 9 years ago

Details on #2424:

Please start by extending the testcases/uast/window_sizing/ testcases to explore the window sizing related features (see below). Then implement the necessary support to make the window fully compatible with the 4GL.

Features needed:

  • Manual (user-driven via mouse or keyboard) sizing of the window must be finished and made compatible.
  • Scrollbars/scrolling/viewport support must be finished and made compatible. This includes support for both horizontal and vertical scrollbars for window.
  • The window and SESSION attributes listed below.

RESIZE - logical value which is read/write until window realization, then just readable
THREE-D - logical value which is read/write until window realization, then just readable (this one only needs to be implemented in regard to the window widget)
SCREEN-LINES - this is the visible client area height in character units, it is a readable decimal value
HEIGHT-CHARS (same as HEIGHT) - external user-visible size of the window including border/decorations, read/write decimal
WIDTH-CHARS (same as WIDTH) - external user-visible size of the window including border/decorations, read/write decimal
HEIGHT-PIXELS - external user-visible size of the window including border/decorations, read/write integer
WIDTH-PIXELS - external user-visible size of the window including border/decorations, read/write integer
VIRTUAL-HEIGHT-CHARS - size of the laid-out viewable rectangle, only a portion of which may be shown to the user
VIRTUAL-WIDTH-CHARS - size of the laid-out viewable rectangle, only a portion of which may be shown to the user
VIRTUAL-HEIGHT-PIXELS - size of the laid-out viewable rectangle, only a portion of which may be shown to the user
VIRTUAL-WIDTH-PIXELS - size of the laid-out viewable rectangle, only a portion of which may be shown to the user
MIN-HEIGHT-CHARS - smallest allowed external size of the window
MIN-WIDTH-CHARS - smallest allowed external size of the window
MIN-HEIGHT-PIXELS - smallest allowed external size of the window
MIN-WIDTH-PIXELS - smallest allowed external size of the window
MAX-HEIGHT-CHARS - largest allowed external size of the window
MAX-WIDTH-CHARS - largest allowed external size of the window
MAX-HEIGHT-PIXELS - largest allowed external size of the window
MAX-WIDTH-PIXELS - largest allowed external size of the window
FULL-HEIGHT-CHARS - maximum client area size
FULL-WIDTH-CHARS - maximum client area size
FULL-HEIGHT-PIXELS - maximum client area size
FULL-WIDTH-PIXELS - maximum client area size
SESSION:DISPLAY-TYPE
SESSION:WINDOW-SYSTEM
SESSION:HEIGHT-CHARS
SESSION:WIDTH-CHARS
SESSION:HEIGHT-PIXELS
SESSION:WIDTH-PIXELS
SESSION:WORK-AREA-HEIGHT-PIXELS
SESSION:WORK-AREA-WIDTH-PIXELS
SESSION:WORK-AREA-X
SESSION:WORK-AREA-Y

#404 Updated by Hynek Cihlar over 9 years ago

Attached is the implementation of #2388 - finish GUI window move/position support.

Also note that:
- I refactored and improved CoordinatesConversion and related classes to allow conversion on the server side as well.
- I added realized flag at the WidgetConfig level (this was to be able to run some of the test cases).
- I improved window dynamic create so that the window is created and its state is synchronized between client and server (this was to be able to run some of the test cases).
- Position attributes changes induced in the client are not being propagated to the server. In theory this should work with the help of the config state synchronization facility. I would leave this for #2424 as client->server state sync will be needed there.
- Proper file history entries are coming up.
- The commit of updated test cases is coming up.
- Regression test is in progress but so far looks good.

Please review and also comment on the few added TODOs if you can. Thanks!

#405 Updated by Hynek Cihlar over 9 years ago

Sorry, I forgot to mention that hc_upd20141021b.zip deletes:

src/com/goldencode/p2j/ui/ChuiCoordinatesConversion.java
src/com/goldencode/p2j/ui/GuiCoordinatesConversion.java
src/com/goldencode/p2j/ui/OutputManagerProvider.java
src/com/goldencode/p2j/ui/StaticOutputManagerProvider.java
src/com/goldencode/p2j/ui/ClientCoordinatesConversionParams.java (moved to src/com/goldencode/p2j/ui/client/ClientCoordinatesConversionParams.java)
src/com/goldencode/p2j/ui/DefaultOutputManagerProvider.java (moved to src/com/goldencode/p2j/ui/client/DefaultOutputManagerProvider.java)

Hynek Cihlar wrote:

Attached is the implementation of #2388 - finish GUI window move/position support.

#406 Updated by Vadim Gindin over 9 years ago

Constantin Asofiei wrote:
..

  1. getScreenDimension usage instead of TC.getScreenSize - should have caught this sooner. getScreenDimension includes only the "area available for placement of frames", thus the message/status area is not included. I think this might be the reason you were seeing incorrect texts in the status/message area as regressions. The original TC.screenSize field was set to include the entire window (with the message/status area rows). Thus, I think is best to replace it with the window's real dimension (as returned by Window.dimension). We might have some problems in GUI (as this currently contains the simulated OS decorations), but we will address that later. To make sure the same dimensions are used in ChUI, do a debug and see what TC.screenSize holds in latest P2J - the window.dimension() call should return the same values.

..

You want me to replace Window.getScreenDimension with Window.dimension in places where TC.screenSize was before my update?

#407 Updated by Constantin Asofiei over 9 years ago

Vadim Gindin wrote:

Constantin Asofiei wrote:
..

  1. getScreenDimension usage instead of TC.getScreenSize - should have caught this sooner. getScreenDimension includes only the "area available for placement of frames", thus the message/status area is not included. I think this might be the reason you were seeing incorrect texts in the status/message area as regressions. The original TC.screenSize field was set to include the entire window (with the message/status area rows). Thus, I think is best to replace it with the window's real dimension (as returned by Window.dimension). We might have some problems in GUI (as this currently contains the simulated OS decorations), but we will address that later. To make sure the same dimensions are used in ChUI, do a debug and see what TC.screenSize holds in latest P2J - the window.dimension() call should return the same values.

..

You want me to replace Window.getScreenDimension with Window.dimension in places where TC.screenSize was before my update?

Yes, but first please confirm that window.dimension returns the same value as TC.screenSize, in ChUI mode (as a P2J build without your update).

#408 Updated by Greg Shah over 9 years ago

Another note for #2424:

The window widget only becomes scrollable when the virtual size is greater than the maximum/current window size. If they are equal or if the virtual size is less than the actual size, no scrollable support is added.

We need to confirm which size is used as a base when determining the frame's size: virtual, current, max window size? One would think it would be the virtual size.

Finally, we need to confirm that the window's scrollable support is just scrolling a viewport for the client-area's virtual size and that it doesn't change the layout of existing or future frames.

#409 Updated by Vadim Gindin over 9 years ago

Constantin Asofiei wrote:

Vadim Gindin wrote:

Constantin Asofiei wrote:
..

  1. getScreenDimension usage instead of TC.getScreenSize - should have caught this sooner. getScreenDimension includes only the "area available for placement of frames", thus the message/status area is not included. I think this might be the reason you were seeing incorrect texts in the status/message area as regressions. The original TC.screenSize field was set to include the entire window (with the message/status area rows). Thus, I think is best to replace it with the window's real dimension (as returned by Window.dimension). We might have some problems in GUI (as this currently contains the simulated OS decorations), but we will address that later. To make sure the same dimensions are used in ChUI, do a debug and see what TC.screenSize holds in latest P2J - the window.dimension() call should return the same values.

..

You want me to replace Window.getScreenDimension with Window.dimension in places where TC.screenSize was before my update?

Yes, but first please confirm that window.dimension returns the same value as TC.screenSize, in ChUI mode (as a P2J build without your update).

Constantin, I've checked it. The values are the same: TC.screenSize = Window.dimension for window.

#410 Updated by Marius Gligor over 9 years ago

I have a question regarding screen coordinates. OpenEdge use rows and columns for screen coordinates in character units. For example the frame title bar is 1.0 row (character) in height.
In P2J I used the default font which is family=Dialog, name=System, style=plain, size=10 The font height calculated using font metrics gives 14 pixels.
Converting native 14 pixels to row gives 1.27 characters. My expectation is to get 1.0 Is my assertion true?

#411 Updated by Hynek Cihlar over 9 years ago

How did you convert the 14 pixels to characters?

Marius Gligor wrote:

I have a question regarding screen coordinates. OpenEdge use rows and columns for screen coordinates in character units. For example the frame title bar is 1.0 row (character) in height.
In P2J I used the default font which is family=Dialog, name=System, style=plain, size=10 The font height calculated using font metrics gives 14 pixels.
Converting native 14 pixels to row gives 1.27 characters. My expectation is to get 1.0 Is my assertion true?

#412 Updated by Marius Gligor over 9 years ago

screen().coordinates().rowFromNative(14)

#413 Updated by Greg Shah over 9 years ago

Code Review hc_upd20141021b.zip

This is really good. It cleans up many lingering issues, so I am excited to see it get integrated into the trunk. My only questions/comments:

1. Why is there a dependency on GuiOutputManager in FramePlacementManager.setFrameLocation()? Also, getting the window ID of the ancestor seems to be a common activity. To avoid actually needing to get the TitledWindow instance and then pulling the tw.config().id out, it seems the client code would be simpler/cleaner if we had an AbstractWidget.ancestorId() method.

2. In CoordinatesConversion, the CHUI member should be at the top of the class and the public static CoordinatesConversion chuiInstance() method should be below the constructor.

#414 Updated by Marius Gligor over 9 years ago

Hynek Cihlar wrote:

How did you convert the 14 pixels to characters?

Marius Gligor wrote:

I have a question regarding screen coordinates. OpenEdge use rows and columns for screen coordinates in character units. For example the frame title bar is 1.0 row (character) in height.
In P2J I used the default font which is family=Dialog, name=System, style=plain, size=10 The font height calculated using font metrics gives 14 pixels.
Converting native 14 pixels to row gives 1.27 characters. My expectation is to get 1.0 Is my assertion true?

screen().coordinates().rowFromNative(11) gives 1.0

#415 Updated by Hynek Cihlar over 9 years ago

Marius Gligor wrote:

screen().coordinates().rowFromNative(11) gives 1.0

The rowFromNative will end up using the FontManager.getPixelsPerRow to calculate the result characters value. You may check what is the value returned by FontManager.getPixelsPerRow and which font it uses and then compare with the font used to render the title bar.

#416 Updated by Marius Gligor over 9 years ago

OK. I'll check. Thanks!

#417 Updated by Hynek Cihlar over 9 years ago

Greg Shah wrote:

Code Review hc_upd20141021b.zip

1. Why is there a dependency on GuiOutputManager in FramePlacementManager.setFrameLocation()?

Yes, this was an oversight. Dependency on the concrete output manager implementation is not required. Fixed.

Also, getting the window ID of the ancestor seems to be a common activity. To avoid actually needing to get the TitledWindow instance and then pulling the tw.config().id out, it seems the client code would be simpler/cleaner if we had an AbstractWidget.ancestorId() method.

Yes, this makes sense. I will add the ancestorId() method.

2. In CoordinatesConversion, the CHUI member should be at the top of the class and the public static CoordinatesConversion chuiInstance() method should be below the constructor.

Fixed.

#418 Updated by Vadim Gindin over 9 years ago

Constantin,

I've made all corrections corresponding to your remarks. All of them was addressed (including the note 362). Here are some answers
1. FramePlacementManager.getNewRow and FramePlacementManager.hideMarkedFrames methods are CHUI-specific as the all class itself, if I understood correctly. But if it is not, I'm not sure about window of what frame should I get there.
2. GenericFrame.downBody was added during some other task. Unfortunately I don't remember what task it was. Something about down-frames. I added some algorithm of row numbers counting. Yes, you're rigth, downBody does not solving any problem now because of client-side problems.
3. I added checkRealized usage to LT.targetWindowWorkerInt method. LT.enable(GenericFrame frame, int[] widgetId) set checkRealized=false.

Other remarks are corrected. Have a look please.

#419 Updated by Vadim Gindin over 9 years ago

I forgot an update itself

#420 Updated by Marius Gligor over 9 years ago

I checked. FontManager use the same font but seems to be a bug in FontManager :
getPixelsPerRow should return wa.defaultFont.legacyHeight and getPixelsPerColumn should return wa.defaultFont.legacyWidth (legacyWidth + (int) (legacyWidth / 2.0) + (wa.isThreeD ? 2 : 0))
After I changed the return values inside the two methods I obtained 1.0 as a result of conversion from 14 which is the correct value.

#421 Updated by Greg Shah over 9 years ago

Details for #2425:

Please implement the rectangle widget on GUI in a way that is compatible with how the 4GL draws. Include support for the following rectangle-specific attributes: EDGE-CHARS, EDGE-PIXELS, FILLED, GRAPHIC-EDGE, GROUP-BOX, ROUNDED. Make sure the FGCOLOR/BGCOLOR support is working as well.

#422 Updated by Hynek Cihlar over 9 years ago

Marius Gligor wrote:

I checked. FontManager use the same font but seems to be a bug in FontManager :
getPixelsPerRow should return wa.defaultFont.legacyHeight and getPixelsPerColumn should return wa.defaultFont.legacyWidth (legacyWidth + (int) (legacyWidth / 2.0) + (wa.isThreeD ? 2 : 0))
After I changed the return values inside the two methods I obtained 1.0 as a result of conversion from 14 which is the correct value.

Great! I am about to release some changes to window positioning so I can include this in it as well.

#423 Updated by Constantin Asofiei over 9 years ago

This is replacement of 1021c.zip, for #2340. It passed runtime testing (cumulative) and it addresses the issues in note 401.

A key point is that KEYCODE for MOUSE-MOVE-* events returns the same codes as KEYCODE for MOUSE-SELECT- events... More, the codes for MOUSE-MOVE-* are incorrect in the official docs, the reported KEYCODE values for MIDDLE-MOUSE-* are the same with what the docs state for MOUSE-MOVE-*, so I've changed Keyboard$WorkArea.basicKeys to reflect the correct values.

About MOUSE-MOVE-*: I wonder if the support for this is incomplete in 4GL, as I couldn't duplicate these on windev01 by moving a widget around the window or other means.

#424 Updated by Constantin Asofiei over 9 years ago

Vadim, review for your 22a.zip:
  • LogicalTerminal: you have this on line 614 import sun.reflect.generics.visitor.*; - is it needed?
  • FramePlacementManager is missing in this update (and your changes can't compile without it).
  • GenericFrame: please remove the commented code related to downBody
  • GenericFrame: why have you renamed viewWorker to prepareView?
  • you haven't answered the conversion questions related to the position of IN WINDOW and WITH .. clauses for ENABLE stmt. At least, add a TODO in progress.g that this might need to be fixed.
  • ClientExports.hide:220 (and maybe others): please go through all your TODOs (added by this update) and either address them or let me know what are they related to
  • GenericFrame.targetWindowWorker(..., boolean checkRealized) - the (handle, boolean, boolean) version always sets it to true, and the other version always sets it to false... I think is better to remove the parameter and just call targetWindowWorkerInt with the proper value (true or false).

I think the logic is OK and good enough for now. You can put it in testing after you finish the cleanup and finish addressing/answering the issues in this note, plus 389 and 369 notes.

#425 Updated by Marius Gligor over 9 years ago

Here are my latest changed for GUI empty frame implementation.

#426 Updated by Greg Shah over 9 years ago

Code Review ca_upd20141023a.zip

I am fine with these changes. Please check them in.

#427 Updated by Constantin Asofiei over 9 years ago

Greg Shah wrote:

Code Review ca_upd20141023a.zip

I am fine with these changes. Please check them in.

Committed to bzr rev 10634.

#428 Updated by Greg Shah over 9 years ago

Code Review mag_upd20141023a.zip

It looks really good. The only issue I see is that the ui/chui/FrameImpl.java is included in the zip file.

Please merge with bzr rev 10634 and then put that version of the update into regression testing. It will need both conversion and runtime testing.

#429 Updated by Vadim Gindin over 9 years ago

Next update.

Constantin Asofiei wrote:

Vadim, review for your 22a.zip:
  • LogicalTerminal: you have this on line 614 import sun.reflect.generics.visitor.*; - is it needed?

removed

  • FramePlacementManager is missing in this update (and your changes can't compile without it).

Sorry, I fixed getNewRow and hideFramesInt, but I suspect that all this class is intended for CHUI. Am I wrong? Also these methods use Window.findFrames. This method also looks like CHUI-specific. It's also unclear its usage for GUI environment: find frames for one current window or for all windows. What do you think?

  • GenericFrame: please remove the commented code related to downBody

removed

  • GenericFrame: why have you renamed viewWorker to prepareView?

I did it because these methods are specific for concrete cases. viewWorker is expected as common implementation method for all cases (not the rule - just impression) from my point of view. Therefore I wanted to distinguish them.

  • you haven't answered the conversion questions related to the position of IN WINDOW and WITH .. clauses for ENABLE stmt. At least, add a TODO in progress.g that this might need to be fixed.

Sorry, I checked it yesterday but forgot to write about it. I found that both of orders (WITH FRAME IN WINDOW and IN WINDOW WITH FRAME) are correct and converted correctly with the current rule.

  • ClientExports.hide:220 (and maybe others): please go through all your TODOs (added by this update) and either address them or let me know what are they related to

fixed

  • GenericFrame.targetWindowWorker(..., boolean checkRealized) - the (handle, boolean, boolean) version always sets it to true, and the other version always sets it to false... I think is better to remove the parameter and just call targetWindowWorkerInt with the proper value (true or false).

done

I think the logic is OK and good enough for now. You can put it in testing after you finish the cleanup and finish addressing/answering the issues in this note, plus 389 and 369 notes.

Probably you meant 379 instead of 369. I confirm, all remarks are addressed. Most of them are fixed, and for some of them I put TODO. I only added TC.pauseBeforeEnd fix.

Have a look please.

#430 Updated by Hynek Cihlar over 9 years ago

Related to #2388.

The attached change set updates hc_upd20141021b and in addition contains:

- all changes related to review from note 413
- merge of Constantin's update 1023a
- fix of the bug in FontManager.getPixelsPerColumn and FontManager.getPixelsPerRow discovered by Marius (see note 420)

Regression test is in progress. Please review.

#431 Updated by Constantin Asofiei over 9 years ago

Vadim Gindin wrote:

Next update.

Vadim, for 1024a.zip update; I think this should be the final iteration of reviews. While you address the issues in this note, go ahead with a runtime testing, as these changes should not impact the logic. They are just some improvements. So here they are:
  • please replace all -1 in method calls where is set as windowID, with a WindowConfig.RESOLVE_WINDOW (which is a constant set to -1); I know, they are a lot of places, but this will make the code cleaner to read (and if we decide/need to change this to some other value, it can be changed easily).
  • GenericFrame is missing a history entry
  • GenericFrame.prepareView(Stream, FrameElement[], boolean, handle) - please rename it back to viewWorker; from the javadoc (and its usage), this method is the central point of work for VIEW and DISPLAY statements. Also, change the javadoc to include that the method corresponds to VIEW [STREAM s] FRAME [IN WINDOW] and DISPLAY [STREAM s] ... [IN WINDOW] statements.
  • GenericFrame: your logic in display(FrameElement[], handle) and display(FrameElement[]) is duplicated. Don't just copy and paste code, make sure if the logic is the same, both methods end up calling a central point for that logic. Same for displayUnlessHidden(FrameElement[] [, handle]), display(Stream, FrameElement[] [, handle]), enable(GenericWidget[] [, handle]), view(FrameElement[] [, handle])
  • LogicalTerminal.getWindowById - why do you explicitly check for active/current/default-window, and not just check the LT.windowRegistry map? Is it possible for the active/current/default-window to exist and not be part of the LT's window registry?
  • Browse.saveCurrentWindow/processEvent - why not use the AbstractWidget.window API you've added? Same for TC.refreshStartRow, TC.queryClosed - please check where you do ancestor instanceof Window and replace the code with widget.window().<some-api-call>, if possible. Also, adding a conditional test to a place where there was non before (and not logging any message when the condition fails), might hide real problems. Thus, better let the code fail, if the window can not be resolved (AbstractWidget.window() always fails if the widget is not attached to a window, and this is good). Add a Widget.window too, so that when only a Widget reference is available, the window() API can be used.
  • UiUtils is missing history entry

#432 Updated by Marius Gligor over 9 years ago

Here are my new changes merged with latest repository updates.

1. GUI frames have a scrollable container having scroll bars which are visible when the frame
size width or height is biggest than workspace size. Obviously scroll bars should be scrolled by mouse. I observed that frame GUI widgets having negative ID's are not automatically registered and as a result cannot respond to mouse events because on MouseHandle. handleMouseEvent line 123 a null value is get for mouse source. To fix that I created a method to register widgets which is used currently for frames.

I would like to discuss about a critical issue related to clipping management in P2J GUI engine. Bellow are my conclusions and I'm looking to find other opinions,

A). In Java Swing each component (widget) has it own Graphical context. No more than one clipping rectangle could be defined on a Graphical context.
Each widget can define (recommended) it own clipping rectangle to protect against drawing outside it area. The clipping area of a widget does not affect the clipping area of other widgets because they are using different Graphical contexts. A container could define a clipping area and let it widgets to be draw only inside this area even widgets define their own clippings. For efficiency the clipping area of a container could be dimensioned to contains only the part that should be redraw. I sow that the same approach is intended to be used in P2J GUI engine. I'm afraid that this is not possible and will explain in paragraph B.

B). In P2J GUI engine we have only one a Graphical context which correspond to Swing frame content pane, a JComponent (GuiSimulator). All P2J GUI widgets like title bar and it contained widgets, workspace area and it contained widgets, message area and status line are draw on the same Graphical context and we could have only one clipping rectangle at one moment. Each widget could (recommended) set it own clipping rectangle to protect his drawing area. Unlike Swing our widgets are virtual components drawing on a canvas.
For scrollable containers this is mandatory because the scrolling means just to adjust it view (content pane) location. The contained widgets are not relocated they remain at the same location relative to the container view. Adjusting container view location and drawing it we obtain the scrolling effect. Drawing should not be done outside container bounds. But each widget inside the container (view) could define it drawing area (clipping rectangle) and this does not work in the current implementation.
We have already a stack on which we push/pop clipping rectangles but this does not work for scrollable containers. Doing many, many, many tests I found a way to fix this issue as follow:

1. I used clipRect instead setRect in GuiSimulator for CLIP operation.
2. I eliminated the clipping rectangle settings in AbstractContainer.draw They are GUI specific and does nothings in ChUI. As I understood a clipping rectangle is calculated in order to improve drawing operations. This could be useful in ChUI but not in P2J GUI like I explained.
3. I replaced the call of AbstractContainer.draw in WindowTitleBar.draw by calling the draw method on each contained widget.

With these changes in place the P2J GUI engine works fine. I tested using an empty frame. You could test my changes by converting a simple empty frame test case.
Perhaps other solutions could be found but this is what I found so far and is simple.
This is a critical issue and we have to find the best solution otherwise the P2J GUI could be compromised!

Please let my know your opinions.

#433 Updated by Greg Shah over 9 years ago

Code Review hc_upd20141023b.zip

1. CaptionButton doesn't have any changes except your history entry.

2. PopupMenu is missing a history entry.

3. GuiOutputManager has a merge problem with the repaint() method.

4. In the FontManager, for #2416 Marius moved the rounding code to getPixelsPerColumn() and out of getPixelsPerRow(). In your change, you left the rounding code in getPixelsPerRow() but swapped the height/width values in both methods. Having reviewed both, I am a bit confused. What is correct?

#434 Updated by Greg Shah over 9 years ago

Code Review mag_upd20141024a.zip

1. Shouldn't ui/chui/FrameImpl.java be removed from the update?

2. MouseHandler has no changes from the current bzr version, I suspect it can be removed.

I'm still thinking about the clipping changes.

Constantin: what are your thoughts?

#435 Updated by Constantin Asofiei over 9 years ago

Marius, first, some issues with the update:
  1. the window popup menu (right click on the window title bar) is broken now, after the clipping changes in your update
  2. how should the code look, to draw an empty frame? I've tried this and it didn't work in P2J:
    form with frame f1 title "this is a frame" size 40 by 40.
    frame f1:visible = true.
    

    It works only if I manually add a f1.openScope() call in the converted Java source. I guess some more conversion changes are needed.
  3. make sure the scrollbars work (so we don't have to come back to them) when:
    - the knob is dragged up/down or left/right
    - the mouse wheel is pressed
    - left-mouse is kept pressed on the scrollbar button.
    - mouse click on the empty space between the knob and the scrollbar buttons.
  4. for the message area, 4GL allows it to scroll it via UP/DOWN cursor keys - when you have time, please fix this too.
Now, about the clipping problem; some initial thoughts:
  • > 2. I eliminated the clipping rectangle settings in AbstractContainer.draw They are GUI specific and does nothings in ChUI. As I understood a clipping rectangle is calculated in order to improve drawing operations. This could be useful in ChUI but not in P2J GUI like I explained.
    You are right that in ChUI they are a no-op... but removing them from there, it will mean each widget needs to handle its own clipping, which will clutter the code (and if someone is not familiar with this aspect, it will take some time to figure out that clipping is needed). I prefer to try to hide logic which needs to be duplicated in many places in an abstraction layer.
  • in your changes, the widget's clipping rectangle is the same as the widget's size... but what if we don't need to completely redraw the entire widget? Consider the case when there are stacked/overlayed widgets, and the top widget is removed: the widgets covered by this one might be only partially covered, and when the top one is hidden/removed, only the covered portion should be drawn. We need to either prove or disprove that the widget drawing is done fully in GUI, and the widgets are never drawn partially; at least in ChUI I think there were cases about this, and this was the reason we added a ScreenBitmap to mark the areas being drawn (and allow partial drawing of widgets).
  • I'm concerned when logic which looks like it is/should be common for all widgets is treated in a custom way for some widgets. And here I refer to the WindowTitleBar.draw changes. Considering your current code, why not set the clipping rectangles in each title bar widget (CaptionButton, WindowTitle, etc), and let super.draw() be called?

#436 Updated by Hynek Cihlar over 9 years ago

Greg Shah wrote:

Code Review hc_upd20141023b.zip

1. CaptionButton doesn't have any changes except your history entry.

2. PopupMenu is missing a history entry.

3. GuiOutputManager has a merge problem with the repaint() method.

I fixed the merging issues, thank you for spotting them.

4. In the FontManager, for #2416 Marius moved the rounding code to getPixelsPerColumn() and out of getPixelsPerRow(). In your change, you left the rounding code in getPixelsPerRow() but swapped the height/width values in both methods. Having reviewed both, I am a bit confused. What is correct?

According to Constantin's findings (see Note 49), my version should be the correct one, i.e. the getPixelsPerColumn() should really return defaultFont.legacyWidth.

#437 Updated by Marius Gligor over 9 years ago

I will remove the FontManager changes from my changes.

#438 Updated by Constantin Asofiei over 9 years ago

Marius, another thought: I think findMouseSource, when called for a ScrollableContainer (maybe ViewPort too?) needs to translate the widget's boundary (which is relative to the scrollable container) so that it is relative to the currently shown view. In your current update, if you scroll the workspace to the bottom (so that the frame's bottom scrollbar is shown), clicking on the "up" button for the vertical scrollbar will do nothing (as the button's coordinates are relative to the container, not the current view).

#439 Updated by Constantin Asofiei over 9 years ago

Marius, one more thing: see the testcases/uast/window_events/mouseevts.p file. This will show a message each time a mouse is clicked/window resized/etc - with your update, this is no longer working.

#440 Updated by Hynek Cihlar over 9 years ago

Greg Shah wrote:

Code Review hc_upd20141023b.zip

1. CaptionButton doesn't have any changes except your history entry.

2. PopupMenu is missing a history entry.

3. GuiOutputManager has a merge problem with the repaint() method.

Attached is the fix of the points above. Please review.

#441 Updated by Greg Shah over 9 years ago

Code Review hc_upd20141024a.zip

It looks good.

#442 Updated by Marius Gligor over 9 years ago

Constantin Asofiei wrote:

Marius, one more thing: see the testcases/uast/window_events/mouseevts.p file. This will show a message each time a mouse is clicked/window resized/etc - with your update, this is no longer working.

Constantin I fixed this issue by putting back the code for WindowTitleBar.findMouseSource.

#443 Updated by Vadim Gindin over 9 years ago

Constantin Asofiei wrote:
..

  • please replace all -1 in method calls where is set as windowID, with a WindowConfig.RESOLVE_WINDOW (which is a constant set to -1); I know, they are a lot of places, but this will make the code cleaner to read (and if we decide/need to change this to some other value, it can be changed easily).

done

  • GenericFrame is missing a history entry

added

  • GenericFrame.prepareView(Stream, FrameElement[], boolean, handle) - please rename it back to viewWorker; from the javadoc (and its usage), this method is the central point of work for VIEW and DISPLAY statements. Also, change the javadoc to include that the method corresponds to VIEW [STREAM s] FRAME [IN WINDOW] and DISPLAY [STREAM s] ... [IN WINDOW] statements.

done

  • GenericFrame: your logic in display(FrameElement[], handle) and display(FrameElement[]) is duplicated. Don't just copy and paste code, make sure if the logic is the same, both methods end up calling a central point for that logic. Same for displayUnlessHidden(FrameElement[] [, handle]), display(Stream, FrameElement[] [, handle]), enable(GenericWidget[] [, handle]), view(FrameElement[] [, handle])

I also added new parameter boolean windowClause. I wanted to prevent interpreting hWin=null as statement without IN WINDOW clause for all client methods with hWin parameter

  • LogicalTerminal.getWindowById - why do you explicitly check for active/current/default-window, and not just check the LT.windowRegistry map? Is it possible for the active/current/default-window to exist and not be part of the LT's window registry?

Yes, as far as understood active/current/default-window are exactly static windows and are not contained in window registry. Window registry is intended for only dynamic windows unlike client-side widget registry.

  • Browse.saveCurrentWindow/processEvent - why not use the AbstractWidget.window API you've added? Same for TC.refreshStartRow, TC.queryClosed - please check where you do ancestor instanceof Window and replace the code with widget.window().<some-api-call>, if possible. Also, adding a conditional test to a place where there was non before (and not logging any message when the condition fails), might hide real problems. Thus, better let the code fail, if the window can not be resolved (AbstractWidget.window() always fails if the widget is not attached to a window, and this is good). Add a Widget.window too, so that when only a Widget reference is available, the window() API can be used.

done

  • UiUtils is missing history entry

done

#444 Updated by Constantin Asofiei over 9 years ago

Vadim Gindin wrote:

  • LogicalTerminal.getWindowById - why do you explicitly check for active/current/default-window, and not just check the LT.windowRegistry map? Is it possible for the active/current/default-window to exist and not be part of the LT's window registry?

Yes, as far as understood active/current/default-window are exactly static windows and are not contained in window registry. Window registry is intended for only dynamic windows unlike client-side widget registry.

OK.

Please replace -1 occurrences in these locations, too:
  • ErrorWriterBatch:86
  • ErrorWriterInteractive:54, 92, 119, 130, 140, 143
  • FrameConfig:183
  • ClientExports: javadoc with texts "Id of target window or -1 for current or default window"
  • LogicalTermina:4822
  • DatabaseAuthenticationHook:162, 164, 184, 390, 391,
  • DefaultLoginPanel:148, 180, 182, 203, 246, 247
  • ThinClient:8055

You can go ahead and put into into testing; upload here the final update and the testing results.

#445 Updated by Vadim Gindin over 9 years ago

Testing results of vig_upd20141025a.zip are following.

                                                               Status Code Summary                                                    

   Test Set                      NOT_RUN PASSED FAILED FAILED_DEPENDENCY                                                
   1 - prepare_tests                    0      3      0                 0                                               
   2 - gso_tests                        0    109    154                 0                                               
   3 - gc_tests                         0      4      3                 0                                               
   4 - navigation                       0      4      1                 0                                               
   5 - gso_vt220_tests                  0      5      1                 0                                               
   6 - gso_batch_mode_tests             0      2      0                 0                                               
   7 - gso_199_test                     0      0      1                 0                                               
   8 - gso_221_test                     0      0      2                 0                                               
   9 - gso_235_test                     0      2      0                 0                                               
   10 - gso_rfq_tests                   0      5      4                 0                                               
   11 - tc_tests                        0     35    385               127                                               
   12 - tc_po_receiving_003_test        0      1      2                 0                                               
   13 - gso_461_test                    0      0      3                 0                                                  14 - gso_489_gc_63-64_tests          0      4      1                 0                                               
   Total                                0    174    557               127                                                                             

#446 Updated by Vadim Gindin over 9 years ago

Fixed remained -1.

#447 Updated by Constantin Asofiei over 9 years ago

Vadim, please create a task in the Majic Conversion project and upload there the MAJIC changes required for your 1027a.zip. Attached version I think should fix your main problem (window size doesn't have to be set when previously TC.setScreenSize was being called - the window's size is already known, and changing it will cause a full repaint which will get rid of any PUT SCREEN data).

#448 Updated by Marius Gligor over 9 years ago

Here are my today changes. I fixed the following issues:

1. Test case testcases/uast/window_events/mouseevts.p is working again.
2. Mouse detection for scroll bars in scrollable container.
3. Implements mouse handlers for scroll bar widget.
According to my tests mouse wheel event is not fired! I'm still looking to find why.

#449 Updated by Greg Shah over 9 years ago

Code Review mag_upd20141027a.zip

The code looks good. The only thing I see is this:

ScrollBarGuiImpl.REAPEAT should be ScrollBarGuiImpl.REPEAT. We also should allow this to be configurable as different customers and even different users within a customer will need different settings for this. Accessibility issues are a good example of this requirement. Put a TODO in the code for this. I want you to focus your remaining time on other things.

#450 Updated by Marius Gligor over 9 years ago

Here are my today changes.

1. I fixed mouse wheel events issue and I implemented mouse wheel event handler for scroll bars and also for scrollable list.
Message area is now scrollable with mouse wheel as well.

2. Fixed code review 1027a

#451 Updated by Greg Shah over 9 years ago

Code Review mag_upd20141028a.zip

The changes look good.

Is there anything else needed before this first pass at GUI frame can be considered complete?

#452 Updated by Marius Gligor over 9 years ago

Basically the GUI empty frame implementation could be considered done.
My implementation contains changes in clip rectangle management which differs than current implementation.
You said that you will decide about this issue and if we keep the changes or not.

#453 Updated by Greg Shah over 9 years ago

My implementation contains changes in clip rectangle management which differs than current implementation.

Good point.

Constantin has suggested that "manually" setting the clipping rectangle for each draw method can be error prone. He suggests to modify the GuiDriver.draw() method to add the clipping boundary as a parameter. The reasoning is if we find it necessary to refactor the drawing code at some point in the future, it is more work to adjust all the places that clipping is done. Plus, if we forget that the drawing area needs to be manually set when working on the GUI widgets, it might be time consuming to figure out what is wrong.

I think his approach is a good idea. Please go forward with this.

Here are some additional questions:

1. Why do you sometimes explicitly call startBracket() and endBracket() when WindowGuiImpl.draw() already brackets the drawing code in batch calls, before calling Window.draw()? Are there drawing paths that don't flow through this location?

2. Why does the FrameGuiImpl have a conditional call to screen().sync() at the end, after the bracket is closed? In GUI, isn't the GuiSimulator.screenBuffer drawn on the swing frame's canvas after each component repaint?

#454 Updated by Marius Gligor over 9 years ago

OK I will do the changes in GuiDriver.draw(). Here I have a question.
Should we create another GuiDriver.draw() with clip rectangle as a parameter or just change the existing draw() method?

1. startBracket() and endBracket() remains from my tests and I have to remove this code.

2. screen().sync() was taken from ChUI implementation and I don't know if in GUI should be used. If not I will eliminate.

#455 Updated by Constantin Asofiei over 9 years ago

Marius Gligor wrote:

Basically the GUI empty frame implementation could be considered done.

Please check this scenario too (from note 438):
- use a frame which is larger than the workspace/client area, and scrollable - thus scrollbars are shown for both the workspace and the frame
- you scroll the workspace so that the frame's horizontal scrollbar is shown.
- try to click on the frame's scrollbar buttons (which are visible) - do they react?

Also, please let us know the state of these issues, from note 435:

2. how should the code look, to draw an empty frame? I've tried this and it didn't work in P2J:
form with frame f1 title "this is a frame" size 40 by 40.
frame f1:visible = true.
It works only if I manually add a f1.openScope() call in the converted Java source. I guess some more conversion changes are needed.

4. for the message area, 4GL allows you to scroll it via UP/DOWN cursor keys.

#456 Updated by Marius Gligor over 9 years ago

Regarding scrolling message are via UP/DOWN cursor key is easy to implements seems the code has more in common with mouse scrolling.
Unfortunately at this stage we cannot test this in P2J because we cannot change the focus to message area in order to receive key events.
Our simple test just show a view and than wait for a key event but on status bar.

#457 Updated by Marius Gligor over 9 years ago

Regarding generation of openScope on conversion I provided a solution some time ago but was not accepted.
I will try to find another solution.

#458 Updated by Greg Shah over 9 years ago

2. screen().sync() was taken from ChUI implementation and I don't know if in GUI should be used. If not I will eliminate.

I don't think this code will be used for redirected terminal support (it doesn't work right now in the GUI client). I think you can remove it.

#459 Updated by Constantin Asofiei over 9 years ago

Marius Gligor wrote:

Regarding generation of openScope on conversion I provided a solution some time ago but was not accepted.
I will try to find another solution.

I think you can use COMPILE <file.p> LISTING <output.txt>.. For a code like this:

def var i as int.

repeat i = 1 to 10:
   display i with frame f1 down.
end.

repeat i = 1 to 5:
   display i with frame f2 down.
end.

it will give you this:
a.p                                   10/28/2014 18:10:51   PROGRESS(R) Page 1

{} Line Blk
-- ---- ---
      1     def var i as int.
      2
      3   1 repeat i = 1 to 10:
      4   1    display i with frame f1 down.
      5     end.
      6
      7   1 repeat i = 1 to 5:
      8   1    display i with frame f2 down.
      9     end.
 a.p                                   10/28/2014 18:10:51   PROGRESS(R) Page 2

     File Name       Line Blk. Type   Tran            Blk. Label
-------------------- ---- ----------- ---- --------------------------------
a.p                     0 Procedure   No
a.p                     3 Repeat      No
    Frames:  f1

a.p                     7 Repeat      No
    Frames:  f2

For each block, the frames scoped to that block will be listed. You can experiment with various statements (like FORM, VIEW, FRAME <fname>:<ATTRIBUTE/METHOD>) and see which do and which do not set a frame scope, and compare this with the P2J converted code.

#460 Updated by Constantin Asofiei over 9 years ago

This is for #2229 (replacement for ca_upd20141027a.zip / vig_upd20141027a.zip). It passed runtime/conversion testing, but I'm running it one more time to ensure the failures are false negatives.

#461 Updated by Greg Shah over 9 years ago

Code Review ca_upd20141029a.zip

The changes look good. Please check them in when testing passes.

There is one part of the code that could use some minor changes (which can be done after the current code is checked in): In FramePlacementManager.hideFrames(), it seems like we could check ThinClient.isHonorPBH() one time only and at the top of the hideFrames() method. Then we can bypass both the doPause/pauseWnds management at the top as well as the actual pausing logic at the bottom. Also, it is a small thing but the pauseWnds.add(frm.window()); would be slightly more efficient as pauseWnds.add(wnd);.

#462 Updated by Constantin Asofiei over 9 years ago

Another frustrating fact about events: although the WINDOW-* events are reporting LAST-EVENT:CODE values (other than -1), these values are not reported by the KEY-CODE("WINDOW-*") function: this always returns -1... Progress either uses different tables for PROGRESS and KEYPRESS events or something else is happening. The collisions are (for GUI WINDOW-* events):
  1. WINDOW-CLOSE: 1078 - ALT-6
  2. WINDOW-MAXIMIZED: 1094 - ALT-F
  3. WINDOW-MINIMIZED: 1095 - ALT-G
  4. WINDOW-RESTORED: 1096 - ALT-H
  5. WINDOW-RESIZED: 1120 - ALT-`

#463 Updated by Marius Gligor over 9 years ago

Here are my today changes. What I fixed so far from code review 2810a:

1. I changed GuiDriver.draw() to manage clip rectangles.

2. I fixed scroll bar mouse events detections.

3. I added key events which allow scrolling message area via keys. This was not tested.
Do you have an idea of a simple script that could be used to test this issue at this stage?

4. I did also some improvements.
- Scroll bar default size is configurable from GuiOptions
- Repeating time for mouse press on scroll bars is also configurable in GuiOptions.
- Other changes as a result of my own code review.

On the next step I'm going to find a solution for static frames openScope issue.

#464 Updated by Greg Shah over 9 years ago

Code Review mag_upd20141029a.zip

The code changes look good. Please add a history entry to NativeDimension, GuiDriver and SwingGuiDriver.

#465 Updated by Marius Gligor over 9 years ago

NativeDimension was changed for testing purposes and I reverted the changes.
Unfortunately I found another problem and I have to fix it:
- I have an empty frame with scroll bars. When I resized the main window bigger and work area has no scroll bars frame scroll bars did not react to mouse events!

#466 Updated by Marius Gligor over 9 years ago

I just checked and mouse detection works fine but the window is not updated after drawing in this case.
If I resized window after scrolling the window is refreshed and looks good.
I'm using

      ThinClient.getInstance().eventDrawingBracket(false, true, new Runnable()
      {
         @Override
         public void run()
         {
            repaint();
         }
      });      

to do the refresh and it is possible to be a problem with BitmapScreen when window is resized.
I have to do further investigations.

#467 Updated by Marius Gligor over 9 years ago

I fixed the issue by using ancestor().repaint() instead repaint() in ScrollBarGuiImpl.refersh() and ScrollBarGuiButton.redraw()
It works an all cases but I'm not sure that is the right solution.
Maybe Constantin could help us with a hint.

#468 Updated by Constantin Asofiei over 9 years ago

Greg Shah wrote:

Code Review ca_upd20141029a.zip

The changes look good. Please check them in when testing passes.

1029a.zip was committed to bzr rev 10638.

#469 Updated by Constantin Asofiei over 9 years ago

Marius Gligor wrote:

I fixed the issue by using ancestor().repaint() instead repaint() in ScrollBarGuiImpl.refersh() and ScrollBarGuiButton.redraw()
It works an all cases but I'm not sure that is the right solution.
Maybe Constantin could help us with a hint.

I'm not entirely sure I understood your scenario correctly. But I think using ancestor() to trigger the repaint is too aggressive: if the scrollbar is attached to a frame, it will trigger repainting of the entire window. Please try using parent() (or go up the hierarchy until the container widget is found) and trigger repaint for the widget (which, in the case of the workarea's scrollbars, will be the workarea).

#470 Updated by Marius Gligor over 9 years ago

I found and fixed the repaint() issue. The problem is Frame.getClipRect() which is ChUI specific because it counts borders in chars. Was moved to FrameChuiImpl
Also the changes are merged with the latest updates from bzr remote repository. I'm going to put these changes into conversion and runtime regression tests.

#471 Updated by Marius Gligor over 9 years ago

  • File PendingInvoiceDetailsFrame.java added
  • File mag_upd20141030b.zip added
  • File testing_20141030_053652.log added

Conversion of Majic fails using my changes (41 compile errors). I did a small change in rules but failed again. It's not a conversion rule issue.
Some Java classes from Majic extends CommonFrame and are using setWidth and setHeight which was replaced by setWidthChars and setHeighChars (see attached example)
The solution might be to change Majic source code or to provide also setWidth and setHeight in CommonFrame

#472 Updated by Constantin Asofiei over 9 years ago

Marius Gligor wrote:

Conversion of Majic fails using my changes (41 compile errors). I did a small change in rules but failed again. It's not a conversion rule issue.
Some Java classes from Majic extends CommonFrame and are using setWidth and setHeight which was replaced by setWidthChars and setHeighChars (see attached example)
The solution might be to change Majic source code or to provide also setWidth and setHeight in CommonFrame

In a new folder, clone the MAJIC project (git clone /opt/secure/code/majic_repo/majic.git), checkout the staging branch and download this to your machine (you can skip the run/ folder, which is large). You need to fix any compilation issues in the srcnew/ and src/ folder by hand (this is not generated code, is hand-written code).

#473 Updated by Marius Gligor over 9 years ago

I did git clone /opt/secure/code/majic_repo/majic.git on a new folder then git checkout -b staging
I downloaded the Majic on my machine I added the P2J project to Majic and I tried to build ant all but I've got errors like:

Compiling 143 source files to /home/mag/remote/majic/build/classes
    [javac] /home/mag/remote/majic/src/aero/timco/majic/BaseReport.java:37: error: package aero.timco.majic.menu does not exist
    [javac] import aero.timco.majic.menu.Filename;

I checked and package package aero.timco.majic.menu does not exist!

#474 Updated by Constantin Asofiei over 9 years ago

Marius Gligor wrote:

I did git clone /opt/secure/code/majic_repo/majic.git on a new folder then git checkout -b staging
I downloaded the Majic on my machine I added the P2J project to Majic and I tried to build ant all but I've got errors like:
[...]
I checked and package package aero.timco.majic.menu does not exist!

Sorry, forgot to mention: you need the majic jars (from build/lib), using a conversion without your update (or some previous saves if you have them)... but I can just search for all getWidth()/getHeight() in the ui package (the frame definition classes), fix the references, apply the update to the ~/testing/majic folder and do ant all there.

#475 Updated by Marius Gligor over 9 years ago

Unfortunately I have no Majic jars so I'm going to start a conversion without my changes.

#476 Updated by Marius Gligor over 9 years ago

I the mean time I will do the changes "by hand" and I will test first on my machine when conversion is done.

#477 Updated by Greg Shah over 9 years ago

Code Review mag_upd20141030b.zip

The changes look fine. When you have the hand-coded MAJIC changes done, please do regression test the result.

#478 Updated by Greg Shah over 9 years ago

  • File deleted (PendingInvoiceDetailsFrame.java)

#479 Updated by Greg Shah over 9 years ago

I deleted the MAJIC code since this is a customer's confidential material which we can't post in an "open" project that will be seen by multiple customers.

#480 Updated by Marius Gligor over 9 years ago

I changed Majic classes by replacing get/set Width/Height with get/set WidthChars/HeightChars. I tried to compile Majic project on my machine but it does not work, I still have compile errors.
However I have no compile errors related to frames set width and height so I uploaded both changes for Majic (testing/updates/majic) and for P2J (testing/updates/p2j) and I started a new Majic conversion.
I saw that you removed Majic Java files from Redmine and I think that my changes should not be posted on Redmine as well.

#481 Updated by Marius Gligor over 9 years ago

  • File majic_logs.zip added

The Majic conversion ended but with strange compile errors. I have no errors for set/get Width/Height but instead other strange errors occur!
The same errors I've got on my local station when I tried to compile Majic. Do you have any idea?

#482 Updated by Constantin Asofiei over 9 years ago

Marius Gligor wrote:

The Majic conversion ended but with strange compile errors. I have no errors for set/get Width/Height but instead other strange errors occur!
The same errors I've got on my local station when I tried to compile Majic. Do you have any idea?

Your changes are made using the master branch instead of the staging branch... use "git checkout staging" to get the right files.

#483 Updated by Marius Gligor over 9 years ago

As I remember I use staging branch:

git clone /opt/secure/code/majic_repo/majic.git
git checkout staging

Should I do other git commands?

#484 Updated by Constantin Asofiei over 9 years ago

Marius Gligor wrote:

As I remember I use staging branch:

[...]

Should I do other git commands?

The commands are correct. Please make sure you have archived/downloaded the correct folder... if you extract your #2431 update into the staging branch and do a git diff, you will notice that history entry numbers are colliding (thus your base versions for the files are not the correct ones).

#485 Updated by Marius Gligor over 9 years ago

- I created a folder test on my home directory on devsrv01.
- Inside this directory I did: git clone /opt/secure/code/majic_repo/majic.git
- I changed directory to test/majic and I did git checkout staging
- I did git status and the answer is:

# On branch staging
nothing to commit, working directory clean

- I created a zip having all test folder files and directories and downloaded to my machine.
- I extracted Majic project files into a local directory.
- I added P2J project to Majic
- I added Majic jars to majic/lib folder
- Then I did ant all

Unfortunately the project is not compiled I have the same compile errors. What's wrong here?

#486 Updated by Constantin Asofiei over 9 years ago

Marius Gligor wrote:

- I created a folder test on my home directory on devsrv01.
- Inside this directory I did: git clone /opt/secure/code/majic_repo/majic.git
- I changed directory to test/majic and I did git checkout staging
- I did git status and the answer is:
[...]
- I created a zip having all test folder files and directories and downloaded to my machine.
- I extracted Majic project files into a local directory.
- I added P2J project to Majic
- I added Majic jars to majic/lib folder
- Then I did ant all

Unfortunately the project is not compiled I have the same compile errors. What's wrong here?

I keep forgetting that for developing I don't use ant to build MAJIC... instead I add the majic jars to my project's classpath and the project compiles only the hand-written src/ and srcnew/ files. You can either make a project in your IDE and compile from there (ensuring that P2J jars and majic jars are added) - all src/ and srcnew/ classes should compile OK. Or, as an alternative (to use ant) is to archive & download the entire converted sources (src/ folder), download & unzip them to src/, apply your update and do an ant all...

#487 Updated by Marius Gligor over 9 years ago

I download the entire Majic project, all sources. I didn't applied my changes but is compiled with errors using ant all!
What do you think if I'll prepare the test environment as usual and download the Majic project from here?

#488 Updated by Marius Gligor over 9 years ago

I think is not necessary. I checked and I found that I have indeed other files with history from 2013.

#489 Updated by Marius Gligor over 9 years ago

The CTRL-C test is running from about 3 hours. I downloaded server log and I found many errors (see attached log).
Yesterday I did a small change in conversion rules:

                  <!-- SKIP/SPACE -->
                  <rule>node.type == prog.kw_skip or
                        node.type == prog.kw_space
                     <action>ref = node.getFirstChild()</action>

                     <rule>node.type == prog.kw_skip
                        <action on="true">aname = "setHeightChars"</action>
                        <action on="false">aname = "setWidthChars"</action>
                     </rule>

Before changes was:
                  <!-- SKIP/SPACE -->
                  <rule>node.type == prog.kw_skip or
                        node.type == prog.kw_space
                     <action>ref = node.getFirstChild()</action>

                     <rule>node.type == prog.kw_skip
                        <action on="true">aname = "setHeight"</action>
                        <action on="false">aname = "setWidth"</action>
                     </rule>

I think that I have stop CTRL-C test, restore the changes and start again with a Majic conversion.

#490 Updated by Constantin Asofiei over 9 years ago

Marius Gligor wrote:

The CTRL-C test is running from about 3 hours. I downloaded server log and I found many errors (see attached log).
Yesterday I did a small change in conversion rules:
[...]
Before changes was:
[...]
I think that I have stop CTRL-C test, restore the changes and start again with a Majic conversion.

I think is best to rename SkipEntity.setWidth/Height to setWidthChars/HeightChars.

#491 Updated by Marius Gligor over 9 years ago

Constantin Asofiei wrote:

Marius Gligor wrote:

The CTRL-C test is running from about 3 hours. I downloaded server log and I found many errors (see attached log).
Yesterday I did a small change in conversion rules:
[...]
Before changes was:
[...]
I think that I have stop CTRL-C test, restore the changes and start again with a Majic conversion.

I think is best to rename SkipEntity.setWidth/Height to setWidthChars/HeightChars.

I did the changes for SkipEntity, I prepared a new conversion test environment, I uploaded Majic and P2J changes but the conversion did not start!

BUILD FAILED
/opt/secure/clients/timco/testing/build_rt.xml:401: exec returned: 1

Total time: 10 seconds
Buildfile: /opt/secure/clients/timco/testing/build_rt.xml

save-generated:

BUILD FAILED
/opt/secure/clients/timco/testing/build_rt.xml:298: The following error occurred while executing this line:
/home/mag/testing/majic/build.xml:210: /home/mag/testing/majic/p2j/build/lib not found.

#492 Updated by Marius Gligor over 9 years ago

I restarted Majic conversion. Now it works again.

#493 Updated by Marius Gligor over 9 years ago

I found that SkipEntity is used also by Majic classes so further changes should be made in Majic project.
I'm afraid that with SkipEntity changes the conversion will fail.

#494 Updated by Greg Shah over 9 years ago

Let's avoid the SkipEntity changes and back out the related change to frame_generator.xml.

#495 Updated by Marius Gligor over 9 years ago

OK Greg. Here are the reverted changes. I'm going to put these on conversion and runtime tests.

#496 Updated by Greg Shah over 9 years ago

Copied here from #2425:

Here are my changes that I did so far for rectangle implementation. ScrollGuiContainer is the GUI implementation of ScrollContainer used in Frame class. ScrollGuiContainer and ScrollContainer should be created via widget factory instead of using new operator in Frame line 832).
RectangleGuiImpl should be also create via GuiWidgetFactory by adding it to the widgets map inside the static block.

#497 Updated by Greg Shah over 9 years ago

In regard to #2425:

1. Do you have testcases to check in? If so, please put them in testcases/uast/rect/.

2. Please make a list of your recommended next steps for this task.

#498 Updated by Marius Gligor over 9 years ago

I have no special test cases. So far I started from empty frame test case and I added a rectangle.

define rectangle r size 4 by 4 no-fill.
define frame f r with width 30 title "Empty Frame".
frame f:height = 12.
view frame f.

After doing the changes for rectangle and frame control pane creation as I already described on the next step the rectangle drawing has to be implemented using various options.
No mouse and keyboard events should be implemented for rectangles. If not all options are yet supported on P2J, conversion rules should be defined as well.

#499 Updated by Marius Gligor over 9 years ago

Majic conversion ended. No errors. I started regression tests.

#500 Updated by Marius Gligor over 9 years ago

CTRL-C runtime test passed without any error! Now the MAIN part is running.

#501 Updated by Hynek Cihlar over 9 years ago

In reference to #2388.

The attached file fixes regressions found during regression testing.

Also the regressions led me to do some other changes in the Coordinate class:
- I renamed round methods to scale methods. Before the method tried to do both - scaling the character value to the default precision and rounding depending on the UI type. The problem was that at the level of Coordinate class there is not enough context to do the rounding part right. Thus only scaling was left and rounding responsibility was moved out to the callers.
- I removed the isChui method, it was not needed any more. Anyway it was too heavy-weight for a class that should provide only the elementary type operations.

I am still getting some suspicious errors from the regression tests but I think they are not related to my changes. I will give it a little more time to be absolutely sure.

Please review.

The following files were removed by the update:

src/com/goldencode/p2j/ui/ChuiCoordinatesConversion.java
src/com/goldencode/p2j/ui/ClientCoordinatesConversionParams.java
src/com/goldencode/p2j/ui/DefaultOutputManagerProvider.java
src/com/goldencode/p2j/ui/GuiCoordinatesConversion.java
src/com/goldencode/p2j/ui/OutputManagerProvider.java
src/com/goldencode/p2j/ui/StaticOutputManagerProvider.java

#502 Updated by Greg Shah over 9 years ago

Code Review hc_upd20141104a.zip

It looks really good.

1. Should LogicalTerminalConversionParams store the result of the first call to isChui() in a context local var to avoid future trips to the client?

2. BrowseConfig, BrowseColumnConfig, BrowseColumnWidget, ControlConfig and Editor need a history entry.

3. GenericWidget._isRealized() return value javadoc description is missing.

#503 Updated by Eugenie Lyzenko over 9 years ago

This is the conversion support for rectangle widget attributes: EDGE-CHARS, EDGE-PIXELS, FILLED, GRAPHIC-EDGE, GROUP-BOX, ROUNDED.

Continue working on runtime implementation.

#504 Updated by Greg Shah over 9 years ago

Code Review evl_upd20141104a.zip

The changes are good. Please focus next on getting the stubs in the runtime so that converted code for these attributes will compile properly. At that point I'll want you to go into testing so that we can check in that code. Then the runtime implementation will be the next priority.

When you work on the runtime implementation, don't forget about Marius' previous work (notes 496 and 498 above).

#505 Updated by Eugenie Lyzenko over 9 years ago

  • File majic_baseline_update_evl_20141030a.zip added

OK. Working on conversion stubs. The attachment contains the testcases I used to check the rule changes consistency.

#506 Updated by Constantin Asofiei over 9 years ago

This is replacement of mag_upd20141031b.zip (for #2416). One more regression testing is running - should be clear.

Main problem was related to BROWSE, which used BrowseConfig.width and BaseEntity.widthChars. I've removed BrowseConfig.width, changed conversion rules to emit the setWidthChars API and fixed logic accordingly.

The SkipEntity.setWidth/Height APIs remain as is, as SKIP has no concept of height/width-chars attributes.

#507 Updated by Eugenie Lyzenko over 9 years ago

  • File deleted (majic_baseline_update_evl_20141030a.zip)

#508 Updated by Eugenie Lyzenko over 9 years ago

This is correct rectangle tests, sorry.

#509 Updated by Greg Shah over 9 years ago

In regard to #2425:

I forgot to mention that as part of this task we need to support the DEFINE RECTANGLE widget options (if the support isn't already there):

EDGE-CHARS
EDGE-PIXELS
NO-FILL
GRAPHIC-EDGE
GROUP-BOX
ROUNDED
FGCOLOR
BGCOLOR
DCOLOR
PFCOLOR

#510 Updated by Greg Shah over 9 years ago

Code Review ca_upd20141105a.zip

Everything looks good. That browse bug seems like it was subtle (and it was possibly 2 bugs if I read the code changes correctly). Good job.

The history entry in BaseEntity references the removal of set/getHeight but the methods removed were setHeight/setWidth.

#511 Updated by Constantin Asofiei over 9 years ago

Greg Shah wrote:

The history entry in BaseEntity references the removal of set/getHeight but the methods removed were setHeight/setWidth.

Attached is replacement of ca_upd20141105a.zip (fixed the history and merged GuiDriver). Passed testing, committed to bzr rev 10645.

#512 Updated by Constantin Asofiei over 9 years ago

This is for #2229, IN WINDOW clause support for these statements:PROMPT-FOR/SET/UPDATE/INSERT.

The following statements can not explicitly specify a window handle; if a frame is referenced, the window is determined by the runtime.

NEXT-PROMPT
COLOR/UNDERLINE
CHOOSE
DO/FOR

Conversion/runtime testing is in progress.

#513 Updated by Greg Shah over 9 years ago

Code Review ca_upd20141106c.zip

The changes look good.

When do you suggest we resolve the new TODOs in ThinClient.viewWorker() (the ones related to moving a frame between windows)?

#514 Updated by Constantin Asofiei over 9 years ago

Greg Shah wrote:

When do you suggest we resolve the new TODOs in ThinClient.viewWorker() (the ones related to moving a frame between windows)?

I think we need the runtime for multiple windows (CREATE WINDOW statement) completed before adding support for this.

#515 Updated by Greg Shah over 9 years ago

I think we need the runtime for multiple windows (CREATE WINDOW statement) completed before adding support for this.

The only thing on my list for window support is #2424 (GUI window sizing and scrolling). Other than that and the completion of #2229, I thought window support would be complete.

CREATE WINDOW itself works. Attributes can be set/read. Dynamic and static frames can be used in them. With #2229, all the UI statements that accept frame phrases have now been enhanced (if needed) to support explicit window targeting. Implicit window usage is already there too, although I don't know if we've been able to run all the window_parenting/ test cases yet to confirm that the behavior is right. I wouldn't be surprised if some tweaks were needed there.

Otherwise I don't really know of something to do. I must have missed it. What is still open in this regard?

#516 Updated by Constantin Asofiei over 9 years ago

Greg Shah wrote:

Otherwise I don't really know of something to do. I must have missed it. What is still open in this regard?

Has anyone tested the GUI runtime for multiple windows? I didn't yet, if this is supposed to work I need to experiment a little and see how stable it is (in terms of events and keys).

#517 Updated by Greg Shah over 9 years ago

Constantin Asofiei wrote:

Greg Shah wrote:

Otherwise I don't really know of something to do. I must have missed it. What is still open in this regard?

Has anyone tested the GUI runtime for multiple windows? I didn't yet, if this is supposed to work I need to experiment a little and see how stable it is (in terms of events and keys).

I don't think much (if any) testing has occurred.

I do worry that there will be issues in focus processing and in the implicit window selection.

#518 Updated by Eugenie Lyzenko over 9 years ago

The update for review contains conversion support for rectangle widget(including define rectangle statement). It is possible to convert and compile(at least before last date ordering conversion issue). Merged with the recent code base. Also the testcases update attached.

#519 Updated by Greg Shah over 9 years ago

Code Review evl_upd20141106a.zip

1. EDGE-CHARS should be DECIMAL instead of INTEGER.

2. RectangleConfig needs its applyConfig(), readExternal() and writeExternal() methods updated to support the new data members (groupBox and rounded).

3. Do we really need both setNoFill() and setFilled()? If you use the NO-FILL widget option in DEFINE RECTANGLE, I assume the 4GL sets the FILLED attribute to false. Is that correct? If so, then let's get rid of setNoFill() and just use setFilled(false) from frame_generator.xml. Also please change the RectangleConfig data member from noFill to filled to be more consistent.

#520 Updated by Greg Shah over 9 years ago

Also the testcases update attached.

Please check in your testcases as you go. It is good that you are posting them here too. Every time you post them here, also please do check them into bzr.

#521 Updated by Constantin Asofiei over 9 years ago

Greg Shah wrote:

I do worry that there will be issues in focus processing and in the implicit window selection.

The runtime to create the dynamic windows is buggy at this time. I will focus on making this to work properly, plus add the support to move an empty frame between windows.

#522 Updated by Greg Shah over 9 years ago

The runtime to create the dynamic windows is buggy at this time. I will focus on making this to work properly, plus add the support to move an empty frame between windows.

This is a good idea. Please test out the window_parenting/ testcases as part of that work.

#523 Updated by Eugenie Lyzenko over 9 years ago

This updates for your review fixes the notes for previous one.

#524 Updated by Greg Shah over 9 years ago

Code Review evl_upd20141106b.zip

Everything is good, except for some confusion that I caused. In my previous code review, I stated that edge-chars was decimal. I really should have been more clear. The use of double to store edge-chars is correct. My concern was/is with the RectangleWidget.setEdgeChars(integer) method. It should be able to take both integer or decimal types. To do this, the type should be set to NumberType and then the doubleValue() can be obtained from that. Please put the decimal back to double and fix the setEdgeChars() signature.

Sorry for the confusion.

#525 Updated by Eugenie Lyzenko over 9 years ago

The rectangle testcases has been committed in bzr as 1225.

#526 Updated by Eugenie Lyzenko over 9 years ago

The updates reverts EDGE-CHARS internal storage to double and changes setter signature to NumberType.

#527 Updated by Greg Shah over 9 years ago

Code Review evl_upd20141106c.zip

Very good. One minor issue:

      Integer intChars = new Integer(chars);
      setEdgeChars(intChars.doubleValue());

It is safe to cast (double) chars here. There is no need to instantiate an Integer. Please fix that and get the resulting update regression tested (conversion and runtime).

#528 Updated by Eugenie Lyzenko over 9 years ago

OK, fixed. The testing will start shortly for attached update.

#529 Updated by Greg Shah over 9 years ago

Code Review evl_upd20141106d.zip

Looks good.

#530 Updated by Hynek Cihlar over 9 years ago

In regard to #2388.

The attached file resolves the issues raised in the previous review of hc_upd20141104a.zip. In addition there are changes related to the merged trunk and related runtime errors fixes.

Also I fixed the javadoc errors I introduced (by other Redmine issues as well), credits to Constantin for spotting them.

Regression test is in progress. Please review.

#531 Updated by Hynek Cihlar over 9 years ago

Hynek Cihlar wrote:

In regard to #2388.

Also I fixed the javadoc errors I introduced (by other Redmine issues as well), credits to Constantin for spotting them.

An update fixing two spots in the previous javadoc fixes.

#532 Updated by Greg Shah over 9 years ago

Code Review hc_upd20141106c.zip

It looks good.

#533 Updated by Eugenie Lyzenko over 9 years ago

The conversion testing has been completed. The generated code is the binary same before and after update. Starting the runtime regression testing.

#534 Updated by Hynek Cihlar over 9 years ago

In regard to #2388.

Regression testing of hc_upd20141106c.zip passed and the changes were committed to trunk in revision 10648.

#535 Updated by Eugenie Lyzenko over 9 years ago

The question. The changes in hc_upd20141106c.zip touch the update I'm currently testing. I guess it will be safe just merge my code with the recent update if testing will be OK. But if this is not acceptable and we need new round for merged code please let me know.

#536 Updated by Greg Shah over 9 years ago

I guess it will be safe just merge my code with the recent update if testing will be OK. But if this is not acceptable and we need new round for merged code please let me know.

I would rather be safe than sorry. Stanislav also has a big update that changes some of the same files as you. Assuming his passes testing, I'm going to let his get checked in first. Then you can merge up and retest. Assuming your current test succeeds, the followup testing is really just helping us know that the merge was correct.

#537 Updated by Eugenie Lyzenko over 9 years ago

OK. What about conversion testing? If the rule files were not involved can we skip this step?

#538 Updated by Greg Shah over 9 years ago

What about conversion testing? If the rule files were not involved can we skip this step?

Unfortunately, the rules files are the ones with the most conflicts.

#539 Updated by Eugenie Lyzenko over 9 years ago

Unfortunately, the rules files are the ones with the most conflicts.

OK. Not a problem.

#540 Updated by Constantin Asofiei over 9 years ago

This is replacement of ca_upd20141106c.zip and is merged with rev 10649. I'm putting it through testing again. I don't have any conflicts with evl_upd20141106c.zip; can't tell about Stanislav's pending changes.

#541 Updated by Greg Shah over 9 years ago

Code Review ca_upd20141107c.zip

Everything looks fine.

#542 Updated by Eugenie Lyzenko over 9 years ago

The change evl_upd20141106d passed the regression testing. This update is merge with the recent code base(not yet merged with Stanislav's pending changes). Will start the new round of testing soon.

#543 Updated by Constantin Asofiei over 9 years ago

Hynek, rev 10648 / hc_upd20141106c.zip has a regression in GSO 334... the PUT SCREEN is cleared for some reason on step 14. I've double checked with rev 10647 and GSO 334 works properly, so the problem must be in rev 10648.

#544 Updated by Hynek Cihlar over 9 years ago

Constantin Asofiei wrote:

Hynek, rev 10648 / hc_upd20141106c.zip has a regression in GSO 334... the PUT SCREEN is cleared for some reason on step 14. I've double checked with rev 10647 and GSO 334 works properly, so the problem must be in rev 10648.

Thanks, I'm on it.

#545 Updated by Greg Shah over 9 years ago

About #2425:

Please merge up with bzr 10651 and get that tested. If it passes, please go ahead and check it in. You do NOT need to repeat the CTRL-C testing. Just make sure the conversion and main runtime regression tests are OK.

#546 Updated by Eugenie Lyzenko over 9 years ago

Please merge up with bzr 10651 and get that tested. If it passes, please go ahead and check it in. You do NOT need to repeat the CTRL-C testing. Just make sure the conversion and main runtime regression tests are OK.

OK. What about GSO 334 regression? Just ignore it for now?

Also I have found one more issue with 10651. Consider the following code:

...
create rectangle rh assign
   frame = frame f:handle
   visible = true
   edge-chars = 2
   edge-pixels = 5
   filled = false
   graphic-edge = true
   group-box = false
   rounded = true
   fgcolor = 14
   bgcolor = 1
   dcolor = 2
   pfcolor = 3
   row = 2
   column = 2.
...

It is now converted to:

...
            rh.unwrapCommonWidget().setDColor(new integer(2));
...

And this code is not compiled:
...
    [javac] /home/evl/timco_new/p2j/src/com/goldencode/testcases/rectangle/RectTest5.java:41: error: cannot find symbol
    [javac]             rh.unwrapCommonWidget().setDColor(new integer(2));
    [javac]               ^
    [javac]   symbol:   method unwrapCommonWidget()
    [javac]   location: variable rh of type handle
...

This is caused by change in method_attributes.rules from:

...
               <rule>ftype == prog.kw_dcolor
                  <action>methodText = "getDColor"</action>
                  <rule>isAssign
                     <action>methodText = "setDColor"</action>
                  </rule>
               </rule>
...

to
...
               <rule>ftype == prog.kw_dcolor
                  <action>hwrap = "CommonWidget"</action>
                  <action>methodText = "getDColor"</action>
                  <rule>isAssign
                     <action>methodText = "setDColor"</action>
                  </rule>
               </rule>
...

We need to fix it to be able to run full rectangle test set.

#547 Updated by Greg Shah over 9 years ago

OK. What about GSO 334 regression? Just ignore it for now?

Yes. As long as it fails the same way as now, ignore it. If your changes make it fail differently, then it is a real issue.

<action>hwrap = "CommonWidget"</action>

Yes, this line should be removed. The default of <action>hwrap = "Widget"</action> is already correct I think. Please fix this.

Also, it looks like we don't have getDColor() implemented in BaseEntity. I'm not sure why, but please fix that too.

#548 Updated by Eugenie Lyzenko over 9 years ago

Fix for DCOLOR attribute in rule file. In addition to implementing getDColor() I added getPfColor() which was not implemented too. If no objections - I'll start testing for this update.

#549 Updated by Greg Shah over 9 years ago

Code Review evl_upd20141111b.zip

It looks good.

If no objections - I'll start testing for this update.

Please do start testing.

#550 Updated by Eugenie Lyzenko over 9 years ago

Conversion testing has passed. Generated code are identical. Continue with runtime testing.

#551 Updated by Eugenie Lyzenko over 9 years ago

OK. What about GSO 334 regression? Just ignore it for now?

Yes. As long as it fails the same way as now, ignore it. If your changes make it fail differently, then it is a real issue.

I've found the TC-CODES-EMPLOYEES-021 also fails the similar way. Need clarification if this came from 10648 or not. Constantin, any comments?

#552 Updated by Constantin Asofiei over 9 years ago

Eugenie Lyzenko wrote:

OK. What about GSO 334 regression? Just ignore it for now?

Yes. As long as it fails the same way as now, ignore it. If your changes make it fail differently, then it is a real issue.

I've found the TC-CODES-EMPLOYEES-021 also fails the similar way. Need clarification if this came from 10648 or not. Constantin, any comments?

Did you check it manually? This test fails intermittently, and the failures don't look related to PUT SCREEN (more like a timeout/sync issue). Also, it passed when I released rev 10650.

#553 Updated by Eugenie Lyzenko over 9 years ago

Finally the main part completed without regressions(except GSO 334). The TC-CODES-EMPLOYEES-021 is also OK. The report files are in GCD share: 10651_6ea5e05_20141112_evl.zip.

Will check in and distribute the update shortly.

#554 Updated by Eugenie Lyzenko over 9 years ago

The update evl_upd20141111b.zip has been committed in bzr as 10652.

#555 Updated by Constantin Asofiei over 9 years ago

Hynek, can you give me an example why the window needs to be added to the widget registry, too (and not only to the window registry)? I'm referring about this TODO in WindowGuiImpl:

      // TODO: find better place to add the widget to the registry
      //       First, the instantiation may fail in which case a failed
      //       instance will stay in the registry.
      //       Second, this should be performed somewhere higher on the abstraction level,
      //       since any widget will need this.
      //       A possible place could be widget factory, but that doesn't have reference
      //       to the output manager.
      screen().getRegistry().addWidget(this);

The TC.getWidget should be used to retrieve a widget, and when searching for a window this should interrogate the window registry.

#556 Updated by Hynek Cihlar over 9 years ago

Constantin Asofiei wrote:

Hynek, can you give me an example why the window needs to be added to the widget registry, too (and not only to the window registry)? I'm referring about this TODO in WindowGuiImpl:
[...]
The TC.getWidget should be used to retrieve a widget, and when searching for a window this should interrogate the window registry.

I believe this was for the CREATE WINDOW statement, the logic behind required the window to be in the widget registry.

When screen definitions are pushed to the client with the newly created window widget, reconstruct WidgetRegi@stry.reconstructWidget is called which ultimately calls WidgetFactory.create. Without the window registered as a widget, this call failed. This seemed logical to me as the Window itself is a widget (AbstractWidget).

#557 Updated by Constantin Asofiei over 9 years ago

Hynek Cihlar wrote:

Constantin Asofiei wrote:

Hynek, can you give me an example why the window needs to be added to the widget registry, too (and not only to the window registry)? I'm referring about this TODO in WindowGuiImpl:
[...]
The TC.getWidget should be used to retrieve a widget, and when searching for a window this should interrogate the window registry.

I believe this was for the CREATE WINDOW statement, the logic behind required the window to be in the widget registry.

When screen definitions are pushed to the client with the newly created window widget, reconstruct WidgetRegi@stry.reconstructWidget is called which ultimately calls WidgetFactory.create. Without the window registered as a widget, this call failed. This seemed logical to me as the Window itself is a widget (AbstractWidget).

OK, I understand the problem. I think it is better to change the WidgetRegistry.getComponent APIs to include window searching (via WindowManager), instead of adding the windows to the registry.

#558 Updated by Constantin Asofiei over 9 years ago

Greg, this is the first pass at fixing the runtime for multiple windows. What are WIP at this time:
  • frame placement/movement between windows
  • window parenting testcases
  • some regressions in MAJIC.
  • window activation: in Java, the OS window gets pushed on top when is brought from hidden to visible. This is not how 4GL/MDI works: the active window/window z-order doesn't change: showing a window again will leave it on the same position, in z-order. Need to check how MDI in Swing can be simulated.

Please review (is built on top of 10653). Hynek, you can take a look too; btw, can you tell me which fonts you used as default for testing? system doesn't work (as is a bitmap font) and the window looks weird now - window toolbar doesn't look OK.

#559 Updated by Hynek Cihlar over 9 years ago

Constantin Asofiei wrote:

Hynek, you can take a look too; btw, can you tell me which fonts you used as default for testing? system doesn't work (as is a bitmap font) and the window looks weird now - window toolbar doesn't look OK.

Actually I didn't change the default font If I remember correctly. The window looks weird because the drawing code has been implemented with some wrong assumptions which don't hold anymore. Please anybody correct me if I'm wrong.

#560 Updated by Constantin Asofiei over 9 years ago

Hynek Cihlar wrote:

Constantin Asofiei wrote:

Hynek, you can take a look too; btw, can you tell me which fonts you used as default for testing? system doesn't work (as is a bitmap font) and the window looks weird now - window toolbar doesn't look OK.

Actually I didn't change the default font If I remember correctly. The window looks weird because the drawing code has been implemented with some wrong assumptions which don't hold anymore. Please anybody correct me if I'm wrong.

Ah, OK, I'll look into it and fix it then.

#561 Updated by Greg Shah over 9 years ago

Code Review ca_upd20141113c.zip

That is a lot of change. It is very good. I shouldn't be surprised (but I was) at the number of places that had hard coded or implicit dependencies on a single window implementation. I very much like the approach of making the widgets handle operations themselves (like sync(), clear()) or passing the widgets in to worker methods so that everything is widget-relative.

1. ThinClient.postOSEvent() double-posts the same event to the EventManager. Is that intentional? If so, why?

2. ThinClient.deselectRows() should just contain a final Browse browse = getWidget(browseId); instead of calling the method twice (once inside the event bracket).

Other than that, I really didn't find much wrong.

#562 Updated by Constantin Asofiei over 9 years ago

Greg Shah wrote:

1. ThinClient.postOSEvent() double-posts the same event to the EventManager. Is that intentional? If so, why?

Thanks for catching this, the inner one was not supposed to remain there.

2. ThinClient.deselectRows() should just contain a final Browse browse = getWidget(browseId); instead of calling the method twice (once inside the event bracket).

Fixed.

#563 Updated by Eugenie Lyzenko over 9 years ago

This is the first step for you to review to the runtime implementation. The rectangle wiget is creating and drawing with the tests I did write before. Currently I'm working on ROUNDED attribute feature(this requires many classes to be touched) and perform additional debugging. The next step will be ready soon.

#564 Updated by Eugenie Lyzenko over 9 years ago

The next update for your review implements ROUNDED feature. The debugging is still required because the tests shows incorrect coordinates implementation for GUI mode. We need this to be fixed because none GUI widgets will work properly with this issue.

#565 Updated by Greg Shah over 9 years ago

Code Review evl_upd20141117a.zip

I like the changes. The only thing I want to point out is that the mag_upd20141028a.zip update included a src/com/goldencode/p2j/ui/client/gui/ScrollGuiContainer.java that may have some use.

The debugging is still required because the tests shows incorrect coordinates implementation for GUI mode. We need this to be fixed because none GUI widgets will work properly with this issue.

Please provide more details. Hynek is working on changes that affect the coordinate system and I don't want to duplicate work.

#566 Updated by Eugenie Lyzenko over 9 years ago

Greg, please clarify, I can not find the file src/com/goldencode/p2j/ui/client/gui/ScrollGuiContainer.java neither in mag_upd20141028a.zip nor in main code tree. Does this file exist somewhere? Or I need to create and implement it?

#567 Updated by Greg Shah over 9 years ago

Eugenie Lyzenko wrote:

Greg, please clarify, I can not find the file src/com/goldencode/p2j/ui/client/gui/ScrollGuiContainer.java neither in mag_upd20141028a.zip nor in main code tree. Does this file exist somewhere? Or I need to create and implement it?

It is there in the mag_upd20141028a.zip that can be found in note 496 above. It is a new file, so it is not yet in P2J. But the code is definitely there in the zip file.

#568 Updated by Eugenie Lyzenko over 9 years ago

OK. I've found the files in correct mag_upd20141028a.zip.

Please provide more details. Hynek is working on changes that affect the coordinate system and I don't want to duplicate work.

The coordinates for GUI primitives require pixels, not chars. If we take the coordinates in chars, convert them to pixels using font width - the result will be incorrect(one char wrong increment to the left) - looks like the 4GL GUI is 1 based coordinate system, not 0 based. If we use physicalLocation() to compute coords - this gives result more than expected(like if font width is too big). I think we need to choose what we will use as measurement units in this case, chars or pixels. Chars will be dependent on the font selected and can potentially produce different results on different systems.

The other consideration is for using screenLocation() call. This causes deep recursive calls to itself so consumes a lot of CPU usage and very difficult to debug. I think we need to change approach when looking for absolute coordinates from the upmost container.

#569 Updated by Hynek Cihlar over 9 years ago

Eugenie Lyzenko wrote:

The coordinates for GUI primitives require pixels, not chars.

Although I don't know your exact use case I think you don't need to care much about the conversion when implementing the rectangle widget. It should be enough for you to take the pixel coordinate values pushed from the server to the client. The conversion is (at the moment only on the server for position attributes, see BaseEntity.setXorY and BaseEntity.setColumnOrRow) or will be (sizing attributes, to be implemented) handled for you.

If we take the coordinates in chars, convert them to pixels using font width - the result will be incorrect(one char wrong increment to the left) - looks like the 4GL GUI is 1 based coordinate system, not 0 based.

Yes, character coordinates in 4GL are 1-based, whereas pixel coordinates are 0-based. However the character values are internally converted to 0-based as soon as they are set in the server components, see BaseEntity.setColumnOrRow, and since then they are internally treated as 0-based.

If we use physicalLocation() to compute coords - this gives result more than expected(like if font width is too big).

Can you post the width you get and the width you expect?

I think we need to choose what we will use as measurement units in this case, chars or pixels. Chars will be dependent on the font selected and can potentially produce different results on different systems.

Maybe it is not that obvious for the rectangle widget, but take a window title for example. If we use character height as a base (according to the title font), the actual title height will nicely accommodate the title text.

#570 Updated by Eugenie Lyzenko over 9 years ago

Hynek,

What if the coordinates can not be defined on the server side? For example if the widget layout must be done automatically on client?

...
define rectangle r0 size 4 by 4 no-fill rounded group-box edge-chars 2 dcolor 1 bgcolor 0 fgcolor 13 pfcolor 3.
define rectangle r1 size 4 by 4 no-fill rounded edge-pixels 5 dcolor 2 bgcolor 0 fgcolor 11 pfcolor 3.

define frame f r0 r1 with size 30 by 12 title "Rectangle Test #6".
...

Where can I find the pixels coords in this case?

Take a look at 4GL and P2J pictures for both char based and physical based approaches attached. Both P2J pictures shows incorrect layout.

#571 Updated by Hynek Cihlar over 9 years ago

Eugenie Lyzenko wrote:

Hynek,

What if the coordinates can not be defined on the server side? For example if the widget layout must be done automatically on client?

That would depend on the layout logic. For things like alignment, this is easy - just take the starting value and calculate the result, no need to take care for units of measure. In case the layout involves characters, you will either set the character values directly or convert them to pixels using the target font. The framework should take care of conversion to or from pixels after the layout is finished, but this is yet to be implemented.

[...]
Where can I find the pixels coords in this case?

I don't know how the code is converted, but it should work the same way as setting COLUMN attribute for example. The setter will take care of converting the character value into pixel and the changes will be pushed to the client component where the converted COLUMN can be read using physicalLocation().

Take a look at 4GL and P2J pictures for both char based and physical based approaches attached. Both P2J pictures shows incorrect layout.

Two reasons. (1) The system font used during the char-pixel conversion has different metrics in the 4GL and P2J environments. (2) The positional/sizing attributes support is still in progress. AFAIK only conversion of window positional attributes changed on the server is implemented.

#572 Updated by Constantin Asofiei over 9 years ago

Hynek, do you have a state for GSO 334? Because I think it got fixed by my changes, unintentionally. Please provide some details about your findings related to the problem, I want to understand if I've fixed the root cause or the effect of the problem. If you need to go into MAJIC details, create a task in the MAJIC conversion project and we'll discuss there.

#573 Updated by Hynek Cihlar over 9 years ago

Constantin Asofiei wrote:

Hynek, do you have a state for GSO 334? Because I think it got fixed by my changes, unintentionally. Please provide some details about your findings related to the problem, I want to understand if I've fixed the root cause or the effect of the problem.

The code which introduced the regression is in WindowWidget.setVisible. The call to super.setVisible method causes additional window repaints events with at least one of them posted outside of event bracket and thus interfering with the PUT SCREENs issued for another frame. This is how the text "Card #" gets removed.

The right solution I think is to make sure there are no unnecessary window repaints and that repaint events are posted inside the event bracket. So far I was only able to implement a workaround solution - WindowWidget.setVisible only calls the super method in gui mode.

I would be very much interested to see your solution.

#574 Updated by Constantin Asofiei over 9 years ago

Hynek Cihlar wrote:

Constantin Asofiei wrote:

Hynek, do you have a state for GSO 334? Because I think it got fixed by my changes, unintentionally. Please provide some details about your findings related to the problem, I want to understand if I've fixed the root cause or the effect of the problem.

The code which introduced the regression is in WindowWidget.setVisible. The call to super.setVisible method causes additional window repaints events with at least one of them posted outside of event bracket and thus interfering with the PUT SCREENs issued for another frame. This is how the text "Card #" gets removed.

The right solution I think is to make sure there are no unnecessary window repaints and that repaint events are posted inside the event bracket. So far I was only able to implement a workaround solution - WindowWidget.setVisible only calls the super method in gui mode.

I would be very much interested to see your solution.

OK, then I think my changes fix this in the proper way. Part of the window-visibility work, the WindowWidget.setVisible was removed, because it is no longer necessary to explicitly call LT.hideWindow... the infrastructure which takes care of changes in widget attributes takes care of this.

#575 Updated by Hynek Cihlar over 9 years ago

Constantin Asofiei wrote:

OK, then I think my changes fix this in the proper way. Part of the window-visibility work, the WindowWidget.setVisible was removed, because it is no longer necessary to explicitly call LT.hideWindow... the infrastructure which takes care of changes in widget attributes takes care of this.

Yes, this is it! Thank you for postponing my "make or brake" point little further :-).

Are you planning to distribute the change any time soon so I can discard my workaround?

#576 Updated by Constantin Asofiei over 9 years ago

Hynek Cihlar wrote:

Constantin Asofiei wrote:

OK, then I think my changes fix this in the proper way. Part of the window-visibility work, the WindowWidget.setVisible was removed, because it is no longer necessary to explicitly call LT.hideWindow... the infrastructure which takes care of changes in widget attributes takes care of this.

Yes, this is it! Thank you for postponing my "make or brake" point little further :-).

Are you planning to distribute the change any time soon so I can discard my workaround?

Yes, I still have a MAJIC regression I need to solve, but I think tomorrow or Thursday should be released.

#577 Updated by Eugenie Lyzenko over 9 years ago

This updates for review integrates ScrollGuiContainer into GUI hierarchy. The appropriate container now creates by WidgetFactory class. Also the painting method for RectangleGuiImpl has been reworked to meet standards of the GuiDriver painter.

What is buggy/not working:
1. The clipping is turned off due to incorrect clip rectangle calculation.
2. It is still not clear what coordinate we should use for GUI widgets.
3. The GROUP-BOX attribute behavior depends on the Windows theme currently in use. It is not clear how we can support this in Linux. Currently the behavior simulates Windows XP theme.

#578 Updated by Greg Shah over 9 years ago

Code Review evl_upd20141118a.zip

This is a good step forward.

Please change the code in RectangleGuiImpl.fillRectangle() from this:

      if (isRounded)
      {
         gd.fillRoundRect(orig.x + borderSize + 1, orig.y + borderSize + 1,
                          dim.width - borderSize, dim.height - borderSize,
                          ROUND_DIAMETER);
      }
      else
      {
         gd.fillRect(orig.x + borderSize + 1, orig.y + borderSize + 1,
                     dim.width - borderSize, dim.height - borderSize);
      }

to this:

      int rx = orig.x + borderSize + 1;
      int ry = orig.y + borderSize + 1;
      int rw = dim.width - borderSize;
      int rh = dim.height - borderSize;

      if (isRounded)
      {
         gd.fillRoundRect(rx, ry, rw, rh, ROUND_DIAMETER);
      }
      else
      {
         gd.fillRect(rx, ry, rw, rh);
      }

In my opinion, it is easier to read and understand in the second version.

#579 Updated by Greg Shah over 9 years ago

1. The clipping is turned off due to incorrect clip rectangle calculation.

Is this related to the known issues in coordinate processing?

2. It is still not clear what coordinate we should use for GUI widgets.

It seems like we should wait until Hynek's upcoming changes are ready before we worry about this.

3. The GROUP-BOX attribute behavior depends on the Windows theme currently in use. It is not clear how we can support this in Linux. Currently the behavior simulates Windows XP theme.

This should be configurable. The idea is that we will add a configuration flag to the directory and that windows OS flag will tell us how to draw. The flag should be obtained via the "relative" lookup that allows setting a global default, server-default, per-server, per-group or per-account value. Something like this will do:

      Directory dir   = DirectoryManager.getInstance();
      String    winOs = dir.getString(Directory.ID_RELATIVE, "windows-os-compat-level", "windows7");

The most important theme initially is Windows 7. You can allow the Windows XP as a choice too, but I don't think we need to worry about Vista right now.

#580 Updated by Constantin Asofiei over 9 years ago

Eugenie Lyzenko wrote:

1. The clipping is turned off due to incorrect clip rectangle calculation.

Please try this update - it solves the problem for the window title's popup menu (right click on the title), I'm curious if it solves your problem, too. If it does, feel free to include it in your update.

Basically, instead of calling clipRectangle(origin, dim), call clipRectangle(origin, dim, true), so that the clip rectangle for a parent container is limited to the touched widgets. I still don't completely feel good about how we do this currently (if two non-adjacent widgets need to be drawn, and the union clipping rectangle contains a third widget which doesn't require drawing, when painting the frame's background it will get erased...), but it does the work for now. And I don't want to completely disable clipping (i.e. fully redraw the frame/window on each repaint), because this might flush changes in the screen buffer for other widgets too early.

#581 Updated by Constantin Asofiei over 9 years ago

And the update for note 580..

#582 Updated by Eugenie Lyzenko over 9 years ago

The most important theme initially is Windows 7. You can allow the Windows XP as a choice too, but I don't think we need to worry about Vista right now.

Greg, let me clarify one point here. The key thing to take into account is the visual theme used, not exact OS level. XP can use XP theme or Classic theme, this is just a skin for Windows "widgets" Windows 7 can use aero, XP or classic themes. Currently when you log on to the WINDEV01 - you can see it uses Classic theme. So this is just a style question. On the other hand 4GL knows only two styles - XP or Classic. So instead of "windows-os-compat-level" we can use something like "windows-os-ui-theme". What do you think? Moreover this can be changed when application is running.

#583 Updated by Eugenie Lyzenko over 9 years ago

1. The clipping is turned off due to incorrect clip rectangle calculation.

Is this related to the known issues in coordinate processing?

This is separate issue I think. Clipping calculation does not consider widget place assuming it is always at (0,0) coordinate.

#584 Updated by Greg Shah over 9 years ago

we can use something like "windows-os-ui-theme". What do you think? Moreover this can be changed when application is running.

OK, this makes sense.

Go ahead and implement support for both "xp" and "classic".

Moreover this can be changed when application is running.

How does the user cause this to occur?

When this happens, how does the 4GL respond?

#585 Updated by Eugenie Lyzenko over 9 years ago

Constantin Asofiei wrote:

And the update for note 580..

This does not work for clipping. Nothing changed for clipping.

#586 Updated by Eugenie Lyzenko over 9 years ago

Constantin Asofiei wrote:

Basically, instead of calling clipRectangle(origin, dim), call clipRectangle(origin, dim, true), so that the clip rectangle for a parent container is limited to the touched widgets. I still don't completely feel good about how we do this currently (if two non-adjacent widgets need to be drawn, and the union clipping rectangle contains a third widget which doesn't require drawing, when painting the frame's background it will get erased...), but it does the work for now. And I don't want to completely disable clipping (i.e. fully redraw the frame/window on each repaint), because this might flush changes in the screen buffer for other widgets too early.

Just for your info. I have disabled clipping only for GUI rectangle widget drawing. Until the clipping issue is fixed. All other placed do clip as before.

#587 Updated by Constantin Asofiei over 9 years ago

Replacement of ca_upd20141113c.zip. Does not contain the PARENT attribute changes (these will be a separate update, on top of this one). Runtime testing is running again, hopefully there will be no new issues. The sizing of window caption buttons/icon is fixed.

#588 Updated by Greg Shah over 9 years ago

Code Review ca_upd20141119d.zip

The changes look good.

When moving frames between windows in ThinClient.viewWorker(), why is the repaint triggered before the frame is detached from the old window? I see you are doing it on purpose, I just don't understand what makes it necessary.

#589 Updated by Constantin Asofiei over 9 years ago

Greg Shah wrote:

When moving frames between windows in ThinClient.viewWorker(), why is the repaint triggered before the frame is detached from the old window? I see you are doing it on purpose, I just don't understand what makes it necessary.

Because repaint requires knowledge about the parent window... and detaching it will set the frame's parent to null, thus the window can no longer be resolved. The same reason applies to why the window is explicitly selected inside the drawing bracket.

#590 Updated by Greg Shah over 9 years ago

OK, that makes sense. Please add that explanation as a comment in that code.

#591 Updated by Eugenie Lyzenko over 9 years ago

The update for review includes complete support for GROUP-BOX attribute. Classic theme requires special rectangle shape - shaded double line not rounded border. It is drawing by set of line drawing primitives using two colors - white and light grey.

The directory setting to customize for XP theme is:

...
            <node class="string" name="windows-os-ui-theme">
              <node-attribute name="value" value="xp"/>
            </node>
...

Also I have found one more bug not related to rectangle implementation, looks like coord recalculation issue. The code to see the bug:

...
define rectangle r size 4 by 4 no-fill.
define frame f r with size 60 by 12 title "Rectangle Test #3, GROUP-BOX, ROUNDED".

r:group-box = false.
r:rounded = true.
r:bgcolor = 11.

view frame f.

message "GROUP-BOX = " r:group-box "ROUNDED = " r:rounded "Press a key to invert.".
pause.

hide all.

r:filled = true.
r:group-box = true.
r:rounded = false.

view frame f.

message "GROUP-BOX = " r:group-box "ROUNDED = " r:rounded "Press a key to finish.".
pause.
...

#592 Updated by Greg Shah over 9 years ago

Code Review evl_upd20141119a.zip

1. The drawShadedDoubleLineBorder() should not be using hard coded colors. I suspect that one of the named "system" colors should be used here OR we will need to add one.

2. Does GROUP-BOX = TRUE really override EDGE-PIXELS?

#593 Updated by Eugenie Lyzenko over 9 years ago

Greg Shah wrote:

Code Review evl_upd20141119a.zip

2. Does GROUP-BOX = TRUE really override EDGE-PIXELS?

Looks so. The ROUNDED is ignored in this case. And the border width is predefined. See page 1638 of the OpenEdge Development: ABL Reference.
And this is confirmed by testcases running on WINDEV01.

#594 Updated by Eugenie Lyzenko over 9 years ago

Reworked to use system color table to get light/dark colors.

#595 Updated by Greg Shah over 9 years ago

Code Review evl_upd20141119b.zip

It looks good.

Is this in a good state for regression testing? It seems like it would be OK. I'd like to get it tested and checked in ASAP if possible. If you think it is OK, please start testing.

Also: document the list of remaining work on #2425 here.

#596 Updated by Eugenie Lyzenko over 9 years ago

Greg Shah wrote:

Code Review evl_upd20141119b.zip

It looks good.

Is this in a good state for regression testing? It seems like it would be OK. I'd like to get it tested and checked in ASAP if possible. If you think it is OK, please start testing.

OK. The testing will be started soon.

Also: document the list of remaining work on #2425 here.

OK.

#597 Updated by Eugenie Lyzenko over 9 years ago

TODO list for GUI rectangle widget.

1. Turn on clipping and verify it is working properly.
2. Find out what coordinates should be used for upper left corner(start point of the widget). Pixels or chars, 0 or 1 based.
3. Check rectangle for stress condition, width or height == 0 or negative, starting point x, y are negative, border width too big(>= half size).
4. Implement exception for trying to set GUI related attributes to ChUI rectangle.
5. Test and fix possible issues for dynamic rectangle widget in GUI mode.
6. Write more complex *.p testcases for many rectangles in frame, especially intersecting, considering point 3 above. Also combine with other widgets in a same frame.

#598 Updated by Eugenie Lyzenko over 9 years ago

Moreover this can be changed when application is running.

How does the user cause this to occur?

When this happens, how does the 4GL respond?

Unfortunately the only theme available for me to choose on WINDEV01 is classic. So for now we can not test it.

#599 Updated by Eugenie Lyzenko over 9 years ago

The main part of the regression cycle for evl_upd20141119b.zip has been started.

#600 Updated by Constantin Asofiei over 9 years ago

Advancing with MAJIC regression fixes... no new issues found, only some failures from an early failed driver thread, running again to clear them. If it passes, will release it.

#601 Updated by Greg Shah over 9 years ago

Code Review ca_upd20141120c.zip

Everything is fine. Check it in when it passes.

#602 Updated by Constantin Asofiei over 9 years ago

Greg Shah wrote:

Code Review ca_upd20141120c.zip

Passed testing, released to rev 10660

#603 Updated by Eugenie Lyzenko over 9 years ago

The main part of testing for evl_upd20141119b.zip completed without regressions. Waiting for CTRL-C part to be done.

#604 Updated by Eugenie Lyzenko over 9 years ago

This is merge with 10660. The testing will be started shortly.

#605 Updated by Greg Shah over 9 years ago

Code Review evl_upd20141120a.zip

If this passes testing, please do check it in and distribute it.

You don't need to re-do CTRL-C testing.

#606 Updated by Eugenie Lyzenko over 9 years ago

Greg Shah wrote:

Code Review evl_upd20141120a.zip

If this passes testing, please do check it in and distribute it.

OK.

You don't need to re-do CTRL-C testing.

I'll have to do because I've interrupted even first attempt of CTRL-C.

#607 Updated by Eugenie Lyzenko over 9 years ago

The main part completed without regressions. The CTRL-C part has been started. In a expected no problem case I'll check in update in a next 2 hours or so today.

#608 Updated by Eugenie Lyzenko over 9 years ago

Testing completed. No regressions found, the results are in 10660_e83af3b_20141121_evl.zip. Had to run 3-way CTRL-C tests separately to get all passed. Starting to check in and distribute.

#609 Updated by Eugenie Lyzenko over 9 years ago

The update evl_upd20141120a.zip has been committed in bzr as 10662.

#610 Updated by Hynek Cihlar over 9 years ago

I need to test the behavior of the following attributes on multi-display setup. Any idea how?

SESSION:HEIGHT-CHARS
SESSION:WIDTH-CHARS
SESSION:HEIGHT-PIXELS
SESSION:WIDTH-PIXELS
SESSION:WORK-AREA-HEIGHT-PIXELS
SESSION:WORK-AREA-WIDTH-PIXELS
SESSION:WORK-AREA-X
SESSION:WORK-AREA-Y

#611 Updated by Greg Shah over 9 years ago

Send an email to Guy Mills describing the testing you need. Ask him if they have any installations that would be suitable and if he would be willing to have the customer team run the tests there.

Try to limit the effort needed by creating 4GL code that can generate the output for them, so that we don't place a burden on the customer team.

#612 Updated by Hynek Cihlar over 9 years ago

Ok. The test will require the windows to be moved around manually. But it should be easy to follow if the instructions are embedded into the test's source code.

Greg Shah wrote:

Send an email to Guy Mills describing the testing you need. Ask him if they have any installations that would be suitable and if he would be willing to have the customer team run the tests there.

Try to limit the effort needed by creating 4GL code that can generate the output for them, so that we don't place a burden on the customer team.

#613 Updated by Hynek Cihlar over 9 years ago

Greg, also unless you think otherwise, I will leave this after the customer demo and for now assume one display.

Hynek Cihlar wrote:

Ok. The test will require the windows to be moved around manually. But it should be easy to follow if the instructions are embedded into the test's source code.

Greg Shah wrote:

Send an email to Guy Mills describing the testing you need. Ask him if they have any installations that would be suitable and if he would be willing to have the customer team run the tests there.

Try to limit the effort needed by creating 4GL code that can generate the output for them, so that we don't place a burden on the customer team.

#614 Updated by Greg Shah over 9 years ago

I will leave this after the customer demo and for now assume one display.

Good idea.

#615 Updated by Greg Shah over 9 years ago

-------- Original Message --------
Subject: Re: next steps for GUI and an upcoming trip/demo
Date: Sat, 22 Nov 2014 19:16:38 +0200
From: Constantin Asofiei <>
To:
CC: Hynek Cihlar <>, "Faulhaber, Eric" <>

Greg,

The default window positioning follows the algorithm described here:
http://blogs.msdn.com/b/oldnewthing/archive/2012/11/26/10371440.aspx

I'm already on it.

Thanks,
Constantin

#616 Updated by Constantin Asofiei over 9 years ago

This update fixes the following:

1. Incomplete dynamic widget/create window support. I know that GuiWidgetFactory.createWindow() has a TODO for window registration. But other than that I am not sure what else is missing.

The problems mentioned by this TODO are no longer of concern, so it was removed. The only issue left for CTRL-BREAK in GUI is some state cleanup, which prevents the GUI client to reinitialize properly if CTRL-C is used (instead of CTRL-BREAK, as I still don't know how to send this key in 4GL) to restart the client - no the client just freezes.

2. Multi-window support. In process with #2229/#1797. This seems pretty close, with the ca_upd20141119d.zip update. Apart from that, is there anything else needed besides the GuiWidgetFactory.createWindow() TODO above?

More fixes to allow proper ENTRY/LEAVE events during focus lost/gained (to another OS or P2J window).

5. Window visibility issue (Swing brings it to the top but Windows doesn't).

Fixed - stacking is enforced each time a window is hidden/made visible.

8. Mismatching font and/or drawing differences when comparing our Swing GUI on Linux to the Windows 4GL GUI.

Window sizing (and title bar) is OK now; only issue left is to finish a proper test client configuration (fonts, etc).

12. Inability to use keys to scroll the message line widget.

Fixed, now keys can be used to scroll in the messagearea, and focus is switched properly between windows.

Please review; this is currently put in runtime testing.

PS: Hynek, once this passes I will release it, so you can pick up and finish the client-side window location/dimension issues (the X/Y/COl/ROW/etc attributes).

#617 Updated by Greg Shah over 9 years ago

Code Review ca_upd20141123c.zip

There is quite a bit of important clean-up being done here. It is good stuff. Unfortunately, the window stacking workaround is nasty but I don't know that there is any better way. Some minor notes:

1. In WindowManager.placeWindow(), please explain that the algorithm is replicating the one used in WIN32 window placement and note this Redmine task number and note 615 where more details can be found. We probably should capture that page as a PDF and upload it here too.

2. The sizing calcs and transforms in WindowTitleBar.doLayout() are not intuitively obvious. I'm worried that without some additional comments, future edits may break that code for lack of understanding.

3. Window.java is missing a history entry.

#618 Updated by Hynek Cihlar over 9 years ago

In regard to #2424.

I am working on the synchronization of linked coordinate attributes (x/column, width-pixels/width-chars, etc.) on the client and came up with two approaches.

(1) Extend ConfigManager.getConfigUpdates, the place where dirty configs are "commited", by a call to a hook method for each changed widget. The hook method would receive a list of names of the changed config fields. The hook method would be defined on the AbstractWidget class. The logic in the hook method would then check for the interested fields and accordingly perform updates in the associated config instance. ConfigManager.getConfigUpdates would pickup the updates and merge them with the original dirty configs. The update of the linked fields would be performed only when ConfigManager.getConfigUpdates is called.

(2) Create an aspect that would be called on each change of any of the linked fields. The value of the linked field would be updated right after the original field is set. The update of the linked field would go into the dirty configs and would be picked by by ConfigManager the usual way.

I am inclining more to (2) because
- the linked fields are updated right away and thus can be used by the widget logic if needed,
- the aspect ensures strong type checks - no problem if a field name changes for example,
- no need to further complicate ConfigManager,
- no need to introduce the reference from config manager to widgets.

Please comment.

#619 Updated by Constantin Asofiei over 9 years ago

Hynek Cihlar wrote:

I am inclining more to (2) because

From what you noted, I'm inclined too. But you need to ensure performance will not be affected by this (too much...). You can use profiling to determine how performance is affected, but you should try to build some test (in ChUI) which creates lots of frames (i.e. external program A invokes external program B in a loop, while program B does lots of work with a local frame - here make sure the attributes you are intercepting will be affected).

Note that passing the entire JoinPoint instance to the aspect will have a performance hit... that's a reason why ConfigFieldSetterAspect.beforeSetField receives only two parameters: the instance to which the changed field belongs, and static details about the changed field. Also, limit the aspect so that it gets woven only in code which really requires it (i.e. client-side only).

#620 Updated by Constantin Asofiei over 9 years ago

This one is replacement for 1123c.zip and it passed runtime testing. It also fixes another GUI issue: the image buffer where painting is done should fallow the frame's size; Creating an image the size of the current desktop is not OK, if i.e. the window is resized beyond this dimension. Also, this reduces the memory needed by the client.

What is WIP:
  • CTRL-BREAK in GUI (need to check for both Windows and Linux)
  • GUI client re-initialization

#621 Updated by Constantin Asofiei over 9 years ago

Attached the details from the webpage in note 615 in pdf format.

#622 Updated by Greg Shah over 9 years ago

Code Review ca_upd20141124c.zip

I'm fine with the changes.

BTW, the GuiSimulator.resizeScreenBuffers() javadoc states that "This will be a no-op if either the width or the height is not a positive number.". However, it is only a no-op if either the values are 0. Negative values will pass through.

#623 Updated by Constantin Asofiei over 9 years ago

Greg Shah wrote:

Code Review ca_upd20141124c.zip

I'm fine with the changes.

BTW, the GuiSimulator.resizeScreenBuffers() javadoc states that "This will be a no-op if either the width or the height is not a positive number.". However, it is only a no-op if either the values are 0. Negative values will pass through.

I can include this in the next pass (which hopefully will be tomorrow with the 620 WIP issues solved). I should release this now so Hynek can merge.

#624 Updated by Greg Shah over 9 years ago

I should release this now so Hynek can merge.

Yes, please do.

#625 Updated by Constantin Asofiei over 9 years ago

Greg Shah wrote:

I should release this now so Hynek can merge.

Yes, please do.

ca_upd20141124c.zip was released to bzr rev 10664.

#626 Updated by Eugenie Lyzenko over 9 years ago

Need to discuss one point I have discovered while GUI button widget implementation.

The P2J code uses Window related classes to find first/next available frame to target the focus/entry or other events. The code to find frame looks like this(UiUtil.java(432)):

...
      Widget<?>[] items = Window.getDefaultWindow().getContentPane()
                                                   .widgets();
      Scanning items for instance of the @Frame@
...

In GUI mode this code does not work because all frames and widgets inside are located in new special container WindowWorkSpace workspace; so in the code above there will be no frames at all. If we have no frames - we have no widgets to deliver the event and this means we are in a trouble for event processing.

So the question: do we really need one more container layer(two to be exact) in GUI mode?

I have found some solution to avoid this issue:
1. Replace code above with:

...
      Widget<?>[] items = Window.getDefaultWindow().getWorkspaceContentPane()
                                                   .widgets();
...

2. The new method getWorkspaceContentPane() will return getContentPane() for Window and WindowChuiImpl classes and workspace.getContentPane() for WindowGuiImpl class.

This way we save old approach for ChUI code and use new one for GUI code. What do you think? Without this consideration every GUI code that is dependent on the result of the Window.getDefaultWindow().getContentPane() is potentially dangerous and would produce the issues.

#627 Updated by Greg Shah over 9 years ago

-------- Original Message --------
Subject: Re: CTRL-BREAK processing in GUI
Date: Tue, 25 Nov 2014 10:54:52 +0000
From: Guy Mills
To: Constantin Asofiei
CC: Greg Shah

Hi Constantin,
I tried modifying your procedure so that the STOP would be trapped, and maybe display the key combination, but to no avail - it just redisplays the previous event (code below).
So it appears that CTRL-BREAK is a special "untrappable" key combination. I double checked on the Progress KB, and this indeed appears to be the case.

See:

http://knowledgebase.progress.com/articles/Article/P159417
http://knowledgebase.progress.com/articles/Article/preventuserclosingaform

So I think what you're proposing sounds reasonable - if Java can trap that keycombination.

Regards,
Guy

ON ANY-KEY ANYWHERE
DO:
   MESSAGE LAST-EVENT:CODE LAST-EVENT:LABEL LAST-EVENT:FUNCTION LAST-KEY.
   RETURN.
END.

PAUSE.

DO ON STOP UNDO, RETRY:
   IF RETRY THEN
   DO:
      MESSAGE LAST-EVENT:CODE LAST-EVENT:LABEL LAST-EVENT:FUNCTION LAST-KEY view-as alert-box.
      RETURN.
   END.
   WAIT-FOR CLOSE OF CURRENT-WINDOW.
END.

On 24 November 2014 at 16:15, Constantin Asofiei <> wrote:

Guy,

Thanks. So, I guess the CTRL-BREAK key is not intercepted by the trigger... do you know any other way to intercept it and find the key code 4GL is using for this?

If not, I think remapping CTRL-CTRL-S key (what Java is capturing when physical CTRL-BREAK keys are pressed) to the CTRL-BREAK key (code 541) should do the trick.

Thanks,
Constantin

On 24.11.2014 18:08, Guy Mills wrote:
Hi Constantin,
I've just had a chance to look at this.
In Progress GUI, your procedure does nothing when the break key is pressed, and restarts with ctrl-break.
NB. I use ctrl-break regularly - when testing - to get out of loops.
Regards,
Guy

On 20 November 2014 at 14:02, Constantin Asofiei <> wrote:

Hello Guy,

I need your help with a problem. According to official docs, pressing CTRL-BREAK in a GUI window will act the same way as when CTRL-C is pressed in a ChUI window: a STOP condition will be raised which, if not handled by the business logic, will restart the program.

I have a problem duplicating this in GUI, on windev01. Hitting CTRL-BREAK (via my keyboard or the on-screen keyboard) will raise an event for the CTRL-CTRL-S key (code 2067). Pressing BREAK (or PAUSE via the on-screen keyboard) will do nothing.

In Swing, pressing the BREAK key will raise an event for the CTRL-S key (code 19) and CTRL-BREAK will raise an event for the CTRL-CTRL-S key.

So, where I need your help: please run this program in GUI on your local machine (so that keys are received by 4GL directly, not via a terminal) and let me know what is shown when BREAK and CTRL-BREAK are pressed.

         ON ANY-KEY ANYWHERE
         DO:
            MESSAGE LAST-EVENT:CODE LAST-EVENT:LABEL LAST-EVENT:FUNCTION LAST-KEY.
            RETURN.
         END.

         PAUSE.
         WAIT-FOR CLOSE OF CURRENT-WINDOW.

Make sure you run it via "prowin32 -p <program-name>".

If your findings are the same as my findings, do you know if the 4GL's GUI client has some other key which works in the same was as the CTRL-C key works in the ChUI client (STOP condition is raised, etc)?

Thanks,
Constantin

#628 Updated by Greg Shah over 9 years ago

I have found some solution to avoid this issue:
1. Replace code above with:
[...]

2. The new method getWorkspaceContentPane() will return getContentPane() for Window and WindowChuiImpl classes and workspace.getContentPane() for WindowGuiImpl class.

This way we save old approach for ChUI code and use new one for GUI code. What do you think? Without this consideration every GUI code that is dependent on the result of the Window.getDefaultWindow().getContentPane() is potentially dangerous and would produce the issues.

I'm not sure about this. I agree that the direct use of the content pane of a window by outside code is dangerous. But adding a getWorkspaceContentPane() just continues this practice. It seems like we could use a safer method like Window.findFrames() to get the frames list and that would be a better way to eliminate the danger.

Constantin: what do you think?

#629 Updated by Constantin Asofiei over 9 years ago

Greg Shah wrote:

I have found some solution to avoid this issue:
1. Replace code above with:
[...]

2. The new method getWorkspaceContentPane() will return getContentPane() for Window and WindowChuiImpl classes and workspace.getContentPane() for WindowGuiImpl class.

This way we save old approach for ChUI code and use new one for GUI code. What do you think? Without this consideration every GUI code that is dependent on the result of the Window.getDefaultWindow().getContentPane() is potentially dangerous and would produce the issues.

I'm not sure about this. I agree that the direct use of the content pane of a window by outside code is dangerous. But adding a getWorkspaceContentPane() just continues this practice. It seems like we could use a safer method like Window.findFrames() to get the frames list and that would be a better way to eliminate the danger.

Constantin: what do you think?

I agree, it looks cleaner to expose only what the client requests, in this case the frames.

On a side note: I see that UiUtils works mostly with Window.getDefaultWindow() - this is not correct, when multiple windows are involved; I think it should work with the WindowManager.topWindow... but this is not common just to buttons, focus processing in GUI is something on its own.

Greg: after the FILL-IN is added too, I think we have enough functionality to start investigating the focus management in GUI.

#630 Updated by Hynek Cihlar over 9 years ago

Advice request.

BaseConfig.applyConfig doesn't contain only simple assignments to the config fields but also calls to abstract methods. Thanks to this the ui aspects (my aspect implementing sync of the linked attributes as well as ConfigFieldSetterAspect) are triggered inside of these method calls even though they are not expected to.

A naive solution would be to set the field directly and call a newly created abstract method afterXYZFieldSet(). The problem is that some of the overriden implementations contain "business logic". For example FrameConfig.setColumn() contains the following:

      if (!((Frame<?>) instance).canSetColumn(column))
      {
         return;
      }

I am afraid the correct solution is to move the logic out of the config classes (to the server widgets), remove the method calls from applyConfig and make sure the state is kept in the config class so no state transfer is needed from config to widget instances.

#631 Updated by Constantin Asofiei over 9 years ago

Hynek Cihlar wrote:

Advice request.

BaseConfig.applyConfig doesn't contain only simple assignments to the config fields but also calls to abstract methods. Thanks to this the ui aspects (my aspect implementing sync of the linked attributes as well as ConfigFieldSetterAspect) are triggered inside of these method calls even though they are not expected to.

A naive solution would be to set the field directly and call a newly created abstract method afterXYZFieldSet(). The problem is that some of the overriden implementations contain "business logic". For example FrameConfig.setColumn() contains the following:

[...]

I am afraid the correct solution is to move the logic out of the config classes (to the server widgets), remove the method calls from applyConfig and make sure the state is kept in the config class so no state transfer is needed from config to widget instances.

I think I understand your problem. The main issue here is that the existing logic in i.e. setColumn can't be removed easily. What about this: if you are concerned that your aspect is being executed from code being called from applyConfig, why not disable the aspect logic while this is being executed? applyConfig is called only from ConfigManager's applyConfigUpdates(WidgetConfigUpdates) and @replaceConfig(WidgetConfig, WidgetConfig) - bracket these calls in a try/finally and disable the logic of your aspect (so is a no-op) while applyConfig is executed.

#632 Updated by Hynek Cihlar over 9 years ago

Constantin Asofiei wrote:

why not disable the aspect logic while this is being executed? applyConfig is called only from ConfigManager's applyConfigUpdates(WidgetConfigUpdates) and @replaceConfig(WidgetConfig, WidgetConfig) - bracket these calls in a try/finally and disable the logic of your aspect (so is a no-op) while applyConfig is executed.

Actually this is not bad at all. This is pretty much a cflow without its overhead.

#633 Updated by Constantin Asofiei over 9 years ago

Second (and final) pass at the issues left in note 620:
  • CTRL-BREAK in GUI
  • GUI client re-initialization
Plus:
  • fixed problems related WINDOW resource delete
  • when control is on server-side, the GUI windows must not capture and/or process events! They are in a "frozen" state.

#634 Updated by Greg Shah over 9 years ago

Code Review ca_upd20141125d.zip

It looks very good. If it passes testing, check it in.

#635 Updated by Constantin Asofiei over 9 years ago

Greg Shah wrote:

Code Review ca_upd20141125d.zip

It looks very good. If it passes testing, check it in.

Committed revision 10666.

#636 Updated by Constantin Asofiei over 9 years ago

Eugenie,

Please post the list of widget attributes/methods (common for both FILL-IN and BUTTON widgets) you've already implemented/planning to implement for the GUI BUTTON task.

#637 Updated by Constantin Asofiei over 9 years ago

Eugenie, better yet, please let me know if you plan on implementing dynamic features related to frame/button, or if you plan to work only with static widgets/frames.

Greg: currently, there are still some missing parts related to registering dynamic widgets to a frame or working with a dynamic frame (for example frame-handle:visible does not work in P2J - the new state is not pushed to the client-side).

Also, when working on the dynamic widget support we should ensure that it works in ChUI first, and after that move to GUI - this will ensure the dynamic support is properly abstracted and works for both... and when GUI is reached, only widget drawing will be needed.

#638 Updated by Greg Shah over 9 years ago

post the list of widget attributes/methods (common for both FILL-IN and BUTTON widgets) you've already implemented/planning to implement for the GUI BUTTON task

I am posting my current update (still being modified) to ensure that everyone can see the list of attrs/methods/options that I have added already. It also shows that where attrs/methods are only used by a small number of widgets, I am creating new interfaces rather than add to CommonWidget. For things that are truly widespread, I am still using CommonWidget.

For quick reference:

Attributes

MOVABLE
MODIFIED
SELECTED
INNER-CHARS
INNER-LINES
CURSOR-LINE
NUM-LINES
CURSOR-CHAR
CENTERED
SCROLLBAR-VERTICAL
SCROLLBAR-HORIZONTAL
LIST-ITEMS

Methods

DELETE-LINE
INSERT-STRING
READ-FILE
REPLACE-SELECTION-TEXT
ADD-LAST
DELETE

Options
V6FRAME
SCROLLBAR-VERTICAL
NO-UNDERLINE

In some of the above cases there was partial support, but I finished it. I also did cleanup and improvements to some other attrs/methods that already existed.

There are many other fixes and improvements in this update.

when working on the dynamic widget support we should ensure that it works in ChUI first, and after that move to GUI - this will ensure the dynamic support is properly abstracted and works for both... and when GUI is reached, only widget drawing will be needed.

Yes, this makes sense.

#639 Updated by Eugenie Lyzenko over 9 years ago

This update for review(merged with the recent code base) includes current status of the button GUI widget plus several other fixes.

The fixes:
1. Rectangle widget now returns 4GL compatible data types, logical, integer, decimal on the server side.
2. Rectangle GUI widget coordinates fix. Draw painting we use moves coord system to widget origin, so the starting point is (0, 0) or (1, 1) to be exact.
3. Fix for focused widget search. Instead of using content pane the method getWidgets() is calling from resolved Window.

About button implementation itself. What now is ready:
1. Drawing unpressed button(focused, unfocused, enabled, disabled)
2. React to the focus movement

What to do left:
1. Implement button in pressed state.
2. Turn on mouse events handling(including TOOL-TIP attribute processing)
3. Fix reaction to several keys. GUI does not move focus by arrow keys, only by TAB. Also pressing spacebar is the same as Enter plus button draws in pressed/released states. BTW Enter key does not have this visual effect.
4. Bug fixing. The real point I worry about is painting issue not directly related to GUI button itself. Take a look at the picture attached. We have extra widget(not only button) painting on the window title area.

Continue working.

#640 Updated by Eugenie Lyzenko over 9 years ago

Constantin,

The first I'm planning to implement all you can see on the screen, probably BUTTON GUI specifics, implementing base functionality first. Then I'll start finding what is left(not implemented with the BUTTON base class). That is my plan.

As to dynamic widget, let's make them working in ChUI first, then merge with GUI code. Especially ability to view the empty frame(this is required for serious testing the dynamic widgets).

#641 Updated by Eugenie Lyzenko over 9 years ago

This update includes one file I missed in previous one. Please use this drop instead.

#642 Updated by Hynek Cihlar over 9 years ago

Constantin Asofiei wrote:

but you should try to build some test (in ChUI) which creates lots of frames (i.e. external program A invokes external program B in a loop, while program B does lots of work with a local frame - here make sure the attributes you are intercepting will be affected).

When I enable the frame in program B the execution always stops with "Press space bar to continue." before control is returned to program A. Is there any way to turning off this message so that the test can be run without user interaction?

#643 Updated by Constantin Asofiei over 9 years ago

Hynek Cihlar wrote:

Constantin Asofiei wrote:

but you should try to build some test (in ChUI) which creates lots of frames (i.e. external program A invokes external program B in a loop, while program B does lots of work with a local frame - here make sure the attributes you are intercepting will be affected).

When I enable the frame in program B the execution always stops with "Press space bar to continue." before control is returned to program A. Is there any way to turning off this message so that the test can be run without user interaction?

That is an implicit pause when the frame is hidden implicitly. Use a HIDE ALL NO-PAUSE in program B, just before it terminates.

#644 Updated by Greg Shah over 9 years ago

Code Review evl_upd20141126b.zip

It is really good! And I'm pretty excited to see "real" GUI buttons drawing in our UI.

4. Bug fixing. The real point I worry about is painting issue not directly related to GUI button itself. Take a look at the picture attached. We have extra widget(not only button) painting on the window title area.

Perhaps Constantin will have some ideas here.

#645 Updated by Constantin Asofiei over 9 years ago

Eugnie,

4. Bug fixing. The real point I worry about is painting issue not directly related to GUI button itself. Take a look at the picture attached. We have extra widget(not only button) painting on the window title area.

Please post a simple test which shows this problem.

#646 Updated by Eugenie Lyzenko over 9 years ago

The testcases rectangle/rect_tets3.p can be taken from bzr. The buggy screenshot attached(do not worry about rectangle interior itself)

#647 Updated by Constantin Asofiei over 9 years ago

Eugenie Lyzenko wrote:

The testcases rectangle/rect_tets3.p can be taken from bzr. The buggy screenshot attached(do not worry about rectangle interior itself)

The problem I think is this code in TC.viewWorker:8698

      ScreenBitmap bitmap = widgetDrawingOn(frame);

      for (int i = 0; i < list.length; i++)
      {
         if (list[i] != null)
         {
            ...
            list[i].draw();

This calls the widget drawing directly. After looking at the ChUI drawing code for BUTTON, I think the assumption in ChUI is that the cursor (i.e. origin) is always moved to the physical widget's top-left location, i.e. ButtonImpl.draw:

   public void draw()
   {
      // get the absolute origin of this component
      Point origin = screenLocation();

      screen().at(origin);

In GUI, this is changed... it is assumed that the origin is always translated to the parent's origin, before drawing the widget; code which draws the widget directly (without going through code which translates the origin to its parent origin) will not work properly. More, there are cases when widget drawing is called from within the parent's drawing code (thus the origin is already translated to the parent's origin); for this reason, using screenPhysicalLocation is not correct...

Please ignore it for now; this is common for all widgets, not just button/rectangle.

On a side note:
  • if you need the widget's physical origin, use physicalLocation
  • within the GuiDriver.draw code, all drawing is already assuming that the origin was translated to the widget's physical location. Thus, you don't need to access the widget's physical location; i.e. this code in RectangleGuiImpl.draw:137 will surely fail when the rectangle is positioned to some other location than (0,0). See the p parameter for the drawShadedDoubleLineBorder and others:
          gd.draw(p, null, new Runnable()
          {
             @Override
             public void run()
             {
                // draw rectangle border
                if (borderSize > 0)
                {
                   if (config.groupBox && !isXpStyle)
                   {
                      drawShadedDoubleLineBorder(p, d, lightShadow, darkShadow);
                   }
                   else
                   {
                      drawRectangleBorder(p, d, borderSize, gc.fgColor, isRounded);
                   }
                }
    
                // fill rectangle
                if (config.filled && borderSize >= 0)
                {
                   fillRectangle(p, d, borderSize, gc.bgColor, isRounded);
                }
             }
    
          });
    

#648 Updated by Eugenie Lyzenko over 9 years ago

This update for review adds proper handling for spacebar key. Also it includes pressing state drawing implementation and disabling arrow keys as focus movement commands. Only Tab, Back-Tab work in GUI mode.

Also includes small fix for rectangle widget related to GROUP-BOX drawing approach. I've found the GROUP-BOX == true disables rectangle filling.

Continue working to enable mouse support.

#649 Updated by Greg Shah over 9 years ago

Here is the latest version of my update that has many attr/method changes. This is merged up to bzr rev 10666.

#650 Updated by Eugenie Lyzenko over 9 years ago

This update for review includes mouse handling support. The buttons now can be pressed by mouse. To do this working the findMouseSource() method was added to the WindowWorkSpace and FrameGuiImpl classes to include both in mouse source finding chain, in last we have to take into account the frame title bar otherwise the finding will fail.

Continue working on tooltip feature implementation.

#651 Updated by Constantin Asofiei over 9 years ago

Eugenie Lyzenko wrote:

Continue working on tooltip feature implementation.

Please make sure the tooltip implementation is generic enough to be added to any kind of widget. I guess you will create a MouseWidgetAction and register an instance for each widget which has a tooltip?

#652 Updated by Greg Shah over 9 years ago

Code Review evl_upd20141128a.zip

I'm fine with the changes. Good work!

Please get this runtime regression tested.

#653 Updated by Hynek Cihlar over 9 years ago

I found an issue with config state synchronization.

When a client widget is initialized with AbstractWidget.initialize default config values are passed to the widget instance from the server. After the initialization the widget's config is added to config manager, with ConfigManager.getInstance().addWidgetConfig. The problem is when during the widget initialization the config state is changed. In such a case the changes will not be picked by ConfigManager.getConfigUpdates when sending a reply to the server and the changes will be overwritten on the next server message. The reason for this is that the ConfigManager.getInstance().addWidgetConfig is called after the init changes and thus active and backup configs are the same.

I am assuming config state may change from the call of AbstractWidget.initialize. So the fix is to pass two config states to ConfigManager.addWidgetConfig - the active config state and the backup config state, in other words the config reference after the initialization changes and config reference before. See the attached diff.

This change unfortunately opens another can of worms. Thanks to the fix above the state after initialization may differ from the "uninitialized" state which may brake widget logic relying on the uninitialized config values. An example is the button widget. After the button is initialized the config.widthChars now with non-zero value is sent back to the server. And when ButtonWidget.setLabel is called, the button's width is not expanded because (1) ControlConfig.setWidhChars (called during server sync with the client config state) sets config.autoResize to false and (2) config.widthChars is non-zero (zero value acts as a shortcut bypassing the config.autoResize set to false). The solution to this is removing the logic from the config class, either by getting rid of the expression autoResize = false or better yet removing BaseConfig.setWidthChars altogether.

#654 Updated by Hynek Cihlar over 9 years ago

Sample code showing the problem. The program output is 0 instead of 3.

def button b.
def frame f b.
ENABLE ALL WITH FRAME f.
message b:width-chars.

On 29.11.2014 17:10, Constantin Asofiei wrote:

Please post an example which shows this problem...

-------- Original Message --------
Subject: [User Interface - Feature #2252] implement GUI client support
Date: Sat, 29 Nov 2014 10:48:46 -0500
From:

Issue #2252 has been updated by Hynek Cihlar.

File hc_diff20141129a.diff added

I found an issue with config state synchronization.

#655 Updated by Constantin Asofiei over 9 years ago

Hynek Cihlar wrote:

I am assuming config state may change from the call of AbstractWidget.initialize. So the fix is to pass two config states to ConfigManager.addWidgetConfig - the active config state and the backup config state, in other words the config reference after the initialization changes and config reference before. See the attached diff.

I think this is a good step.

This change unfortunately opens another can of worms. Thanks to the fix above the state after initialization may differ from the "uninitialized" state which may brake widget logic relying on the uninitialized config values. An example is the button widget. After the button is initialized the config.widthChars now with non-zero value is sent back to the server. And when ButtonWidget.setLabel is called, the button's width is not expanded because (1) ControlConfig.setWidhChars (called during server sync with the client config state) sets config.autoResize to false and (2) config.widthChars is non-zero (zero value acts as a shortcut bypassing the config.autoResize set to false). The solution to this is removing the logic from the config class, either by getting rid of the expression autoResize = false or better yet removing BaseConfig.setWidthChars altogether.

I'm still reluctant that it is easy to remove the explicit setters from the WidgetConfig hierarchy, without having to rely on AspectJ or other manual changes to trigger a widget repaint (when i.e. the server-side has explicitly set the widget's size).

What about this:
  • when working with attributes on the client-side and server-side, you need to be aware of an attribute being set explicitly by the server-side and being computed implicitly by the client-side. In case of the AUTO-RESIZE which is set to false in setWidthChars, considering how it is used know, it is only a client-side state which should never reach the server-side. Making the field transient might solve this (although in this case we can no longer say the field is for the AUTO-RESIZE attribute, but the conversion rules don't support this attribute anyway).
  • about WidgetConfig.state being set in setModified - the problem here I think is that, when setModified is called from applyConfig, the state field should not be changed. In applyConfig, try changing the setModified(cfg.modified) line to modified = cfg.modified (so that the state field is no longer being set).

#656 Updated by Eugenie Lyzenko over 9 years ago

Greg Shah wrote:

Please get this runtime regression tested.

The resting completed without regressions. Main part in single round, CTRL-C - had to start 3-way tests separately.

So it is ready to be committed and distributed.

#657 Updated by Hynek Cihlar over 9 years ago

Constantin Asofiei wrote:

Hynek Cihlar wrote:
I'm still reluctant that it is easy to remove the explicit setters from the WidgetConfig hierarchy, without having to rely on AspectJ or other manual changes to trigger a widget repaint (when i.e. the server-side has explicitly set the widget's size).

Yes, you are right. I didn't realize we also use the config instances to trigger actions on the widgets (like redraw).

What about this:
  • when working with attributes on the client-side and server-side, you need to be aware of an attribute being set explicitly by the server-side and being computed implicitly by the client-side. In case of the AUTO-RESIZE which is set to false in setWidthChars, considering how it is used know, it is only a client-side state which should never reach the server-side. Making the field transient might solve this (although in this case we can no longer say the field is for the AUTO-RESIZE attribute, but the conversion rules don't support this attribute anyway).

What would be the best way to check whether WIDTH-CHARS was explicitly set by the server?

#658 Updated by Constantin Asofiei over 9 years ago

Hynek Cihlar wrote:

What about this:
  • when working with attributes on the client-side and server-side, you need to be aware of an attribute being set explicitly by the server-side and being computed implicitly by the client-side. In case of the AUTO-RESIZE which is set to false in setWidthChars, considering how it is used know, it is only a client-side state which should never reach the server-side. Making the field transient might solve this (although in this case we can no longer say the field is for the AUTO-RESIZE attribute, but the conversion rules don't support this attribute anyway).

What would be the best way to check whether WIDTH-CHARS was explicitly set by the server?

Something which complicates things is the fact that we save the widget's location and size in fields in both WidgetConfig and AbstractWidget instances... ideally, the state should be only at the WidgetConfig instance (this will be needed especially when we will have to isolate widget state from concrete implementation, as a widget can be used both in GUI and ChUI, when redirecting the output to a stream). At this point in P2J, when server-side sets the WIDTH-CHARS, it will automatically update the widget's internal size... but can't tell if this is enough for all cases or not.

Also, when the server-side sets the size explicitly, the client-side (don't take this as a definite answer, this is how I think it should work in 4GL) should bypass the implicit widget sizing, and force the widget to have the specified size (or show an error message if this is not possible).

The conclusion is I can't tell you a best way to do what you asked, but before going further, please check where/if P2J behaves wrong (we might already have covered this).

#659 Updated by Hynek Cihlar over 9 years ago

Another reason I ask is the following sample.

def button b.
def frame f b.
ENABLE ALL WITH FRAME f.
message b:width-chars b:auto-resize.
b:width-chars = b:width-chars.
message b:width-chars b:auto-resize.

The output in 4GL is:

3 yes
3 no

The idea I had in mind was that I would compare width-chars value coming from the server with the width-chars on the client. But this will obviously not work.

Constantin Asofiei wrote:

Hynek Cihlar wrote:

What about this:
  • when working with attributes on the client-side and server-side, you need to be aware of an attribute being set explicitly by the server-side and being computed implicitly by the client-side. In case of the AUTO-RESIZE which is set to false in setWidthChars, considering how it is used know, it is only a client-side state which should never reach the server-side. Making the field transient might solve this (although in this case we can no longer say the field is for the AUTO-RESIZE attribute, but the conversion rules don't support this attribute anyway).

What would be the best way to check whether WIDTH-CHARS was explicitly set by the server?

Something which complicates things is the fact that we save the widget's location and size in fields in both WidgetConfig and AbstractWidget instances... ideally, the state should be only at the WidgetConfig instance (this will be needed especially when we will have to isolate widget state from concrete implementation, as a widget can be used both in GUI and ChUI, when redirecting the output to a stream). At this point in P2J, when server-side sets the WIDTH-CHARS, it will automatically update the widget's internal size... but can't tell if this is enough for all cases or not.

Also, when the server-side sets the size explicitly, the client-side (don't take this as a definite answer, this is how I think it should work in 4GL) should bypass the implicit widget sizing, and force the widget to have the specified size (or show an error message if this is not possible).

The conclusion is I can't tell you a best way to do what you asked, but before going further, please check where/if P2J behaves wrong (we might already have covered this).

#660 Updated by Constantin Asofiei over 9 years ago

Hynek Cihlar wrote:

The idea I had in mind was that I would compare width-chars value coming from the server with the width-chars on the client. But this will obviously not work.

Adding compatible runtime support for the AUTO-RESIZE attribute might prove to be helpful... how I see this:
  • initially, this flag is set to true
  • when the server-side sets the i.e. WIDTH-CHARS, it sets the AUTO-RESIZE to false, before pushing the new configuration to the client; this is not done in the WidgetConfig classes, but in the GenericWidget APIs. The client-side will see that the AUTO-RESIZE is false, thus will force the widget to be of the specified size.

Please check first if the existing logic dependent on the ControlConfig.autoResize can be adjusted so that it will work with the AUTO-RESIZE attribute (I'm concerned of the parts where client-side sets this to false, so that it will compute the widget size only once).

#661 Updated by Greg Shah over 9 years ago

Eugenie: please do commit and release evl_upd20141128a.zip.

#662 Updated by Eugenie Lyzenko over 9 years ago

Greg Shah wrote:

Eugenie: please do commit and release evl_upd20141128a.zip.

The test results file is 10666_e83af3b_20141129_evl.zip. On the GCD share. The update will be committed shortly.

#663 Updated by Eugenie Lyzenko over 9 years ago

The update evl_upd20141128a.zip has been committed in bzr as 10668. Also I have committed the testcases I have used to verify GUI button functionality.

#664 Updated by Greg Shah over 9 years ago

This is the latest version that continues to evolve to fix more bugs. Inline var defs (variables defined in a format phrase within FORM/DEFINE FRAME/PROMPT-FOR/SET/UPDATE) are much improved with this version. It is still not done.

Merged up with bzr rev 10668.

#665 Updated by Hynek Cihlar over 9 years ago

  • File hc_diff20141130a.zip added

It seems we have broken alert boxes, at least the following code causes an NPE in ThinClient on the trunk.

MESSAGE "NPE" VIEW-AS ALERT-BOX.

From the code this wasn't obvious to me but it looks like alert boxes should be assigned widget ids. The fix is attached.

#666 Updated by Hynek Cihlar over 9 years ago

  • File deleted (hc_diff20141130a.zip)

#667 Updated by Hynek Cihlar over 9 years ago

Hynek Cihlar wrote:

It seems we have broken alert boxes, at least the following code causes an NPE in ThinClient on the trunk.

[...]

From the code this wasn't obvious to me but it looks like alert boxes should be assigned widget ids. The fix is attached.

The diff file one more time.

#668 Updated by Constantin Asofiei over 9 years ago

Hynek Cihlar wrote:

It seems we have broken alert boxes, at least the following code causes an NPE in ThinClient on the trunk.

[...]

From the code this wasn't obvious to me but it looks like alert boxes should be assigned widget ids. The fix is attached.

Are you sure this is not related to your changes? In latest bzr rev, the code you posted works fine...:

MESSAGE "NPE" VIEW-AS ALERT-BOX.

#669 Updated by Hynek Cihlar over 9 years ago

Constantin Asofiei wrote:

Are you sure this is not related to your changes? In latest bzr rev, the code you posted works fine...:

I was running the code with a fresh build of the clean trunk. Let me double check.

#670 Updated by Hynek Cihlar over 9 years ago

Hynek Cihlar wrote:

Constantin Asofiei wrote:

Are you sure this is not related to your changes? In latest bzr rev, the code you posted works fine...:

I was running the code with a fresh build of the clean trunk. Let me double check.

So it was happening only when widget browser was active. I think you can ignore the diff file above and I will fix the fix.

#671 Updated by Constantin Asofiei over 9 years ago

Hynek Cihlar wrote:

Hynek Cihlar wrote:

Constantin Asofiei wrote:

Are you sure this is not related to your changes? In latest bzr rev, the code you posted works fine...:

I was running the code with a fresh build of the clean trunk. Let me double check.

So it was happening only when widget browser was active. I think you can ignore the diff file above and I will fix the fix.

Is this related to widget highlight, when widget browser is active in ChUI mode? If so, I think is best to disable the highlight in this case.

#672 Updated by Hynek Cihlar over 9 years ago

Constantin Asofiei wrote:

Is this related to widget highlight, when widget browser is active in ChUI mode? If so, I think is best to disable the highlight in this case.

No the problem was that widget browser didn't expect alert box to be a widget ancestor and the class cast exception was not visible in the debugger which got me confused.

#673 Updated by Greg Shah over 9 years ago

Here is my latest, with many more fixes.

#674 Updated by Greg Shah over 9 years ago

The missing file...

#675 Updated by Hynek Cihlar over 9 years ago

Here is the proper fix of the problem with alert boxes I reported. I also included other widget browser changes I had buffered in my workspace, like displaying the widget config fields in the property table.

Please review.

#676 Updated by Eugenie Lyzenko over 9 years ago

This updates for review contains the tooltip implementation. The working is illustrated by the pictures attached. The new ToolTip.java class has been added to the GUI client package to separate this feature from button. So the tooltip can be used the same way with any widget that needs this feature.

Continue debugging. But I think it is ready to be tested for regressions. Looks like the possible issues are not button specific and is related to the coordinate system implementation or may be GUI container implementation like GUI Window or GUI Frame.

#677 Updated by Greg Shah over 9 years ago

This is the version of my changes that I will start conversion and runtime regression testing. The conversion support is complete. Many, many bugs and new language syntax are fixed/added.

#678 Updated by Eugenie Lyzenko over 9 years ago

The 4GL can handle *.ico pictures to display them in GUI frame.

While Java can handle jpeg, gif, bmp, wbmp, png. So we need only *.ico support to be added.

#679 Updated by Constantin Asofiei over 9 years ago

Eugenie Lyzenko wrote:

The 4GL can handle *.ico pictures to display them in GUI frame.

While Java can handle jpeg, gif, bmp, wbmp, png. So we need only *.ico support to be added.

See notes 392, 393, 394 - TwelveMonkeys implements plugins which add support for new image types.

#680 Updated by Greg Shah over 9 years ago

My latest changes with some additional parser and schema parser improvements.

#681 Updated by Eugenie Lyzenko over 9 years ago

The image handling for client GUI code, for example to draw the *.ico file in the title bar can be added just using the plugins from
https://github.com/haraldk/TwelveMonkeys

The we need to do is to take binaries from TwelveMonkeys and include these files into client side classpath:
common-lang-3.0.1.jar common-io-3.0.1.jar common-image-3.0.1.jar imageio-core-3.0.1.jar imageio-metadata-3.0.1.jar imageio-ico-3.0.1.jar

No need to change anything in P2J sources. The call in ImageGuiImpl

...
         try
         {
            img = ImageIO.read(new ByteArrayInputStream(byteImg));
         }
...

will just work.

The supported icon format files that was verified are: 32bpp, 8bpp, 4bpp.

As to my opinion - if we need just *.ICO files support may be it is better to write our own module to do this than be dependent from external code/libraries that for example once can become not free to use.

#682 Updated by Greg Shah over 9 years ago

As to my opinion - if we need just *.ICO files support may be it is better to write our own module to do this than be dependent from external code/libraries that for example once can become not free to use.

I generally agree with this but:

  • The code in TwelveMonkeys ImageIO is licensed via the BSD license. This is a very permissive license that ensures we can always take the current code (as it is today) and if they ever change the license we can continue using this code forever. In fact we can even modify, fix and improve the code and still use it forever.
  • We don't have much time.

For these reasons I plan to use this as long as the TwelveMonkeys ImageIO code works reliably, has no limitations that cause us compatibility or functional problems and is not a performance problem.

Please do checkout the source code for the current version and archive it (and a copy of the license) in the ~/shared/projects/p2j/twelvemonkeys_imageio/ directory. This will ensure that we can always get back to this version.

#683 Updated by Greg Shah over 9 years ago

Code Review hc_upd20141201b.zip

The changes look good. You can check them in since they don't affect production code.

#684 Updated by Greg Shah over 9 years ago

Code Review evl_upd20141201a.zip

This is good. Since this code can only be reached in GUI, you can go ahead and check it in.

A question: how compatible is the appearance and position of this implementation with the one in the 4GL?

#685 Updated by Eugenie Lyzenko over 9 years ago

This is good. Since this code can only be reached in GUI, you can go ahead and check it in.

OK.

A question: how compatible is the appearance and position of this implementation with the one in the 4GL?

I have performed investigation with gui_btn_test2.p to have the same color and position. The color was taken from screenshot by GIMP color grabbing tool. I suggested 4GL places the tooltip with right-down delta shift from the current mouse pointer position. The delta currently used in P2J is 16 pixels. But may be it depends on the current mouse cursor size.

#686 Updated by Eugenie Lyzenko over 9 years ago

The current build archive TwelveMonkeys-master.zip has been uploaded to share. Also I have uploaded prebuilt binaries there. Unfortunately I can not do git clone git@github.com:haraldk/TwelveMonkeys.git due to some permission issues with repository.

#687 Updated by Greg Shah over 9 years ago

I suggested 4GL places the tooltip with right-down delta shift from the current mouse pointer position. The delta currently used in P2J is 16 pixels. But may be it depends on the current mouse cursor size.

OK. Do try to figure out the algorithm so we can know if we have more work there.

Most likely this is something provided by WIN32 "for free". It may not have any 4GL-specific behavior.

Also: does it react to events the same way as in the 4GL? For example, right now it is automatically hidden when the mouse exits the owner button widget. But are there any other behaviors that need to be handled? For example, does the tooltip redraw, hide or move when the mouse is moved within the owner widget without leaving? And what happens when the button is pressed?

#688 Updated by Eugenie Lyzenko over 9 years ago

The evl_upd20141201a.zip update has been committed in bzr as 10670.

#689 Updated by Constantin Asofiei over 9 years ago

Some NPE fixes related to client restart on CTRL-C (or restart caused by other unrelated abends).

#690 Updated by Greg Shah over 9 years ago

Code Review ca_upd20141204d.zip

The changes look good. Please get it tested.

#691 Updated by Eugenie Lyzenko over 9 years ago

This update for review includes conversion and runtime support for methods LOAD-ICON and LOAD-SMALL-ICON for window widget. For now it works with icons integrated in p2j.jar file. Tomorrow I'll work to add more icon searching capabilities.

BTW icons from the customer in original state will not be loaded with TwelveMonkeys plugin due to unsupported format(1bpp I guess). So I had to recompose them into 4bpp t be able to work.

#692 Updated by Eugenie Lyzenko over 9 years ago

This update for review includes all required to work with icon loading into window title bar. Including testcases to check implementation with fixed icons for usable 4bpp formats.

The arbitrary icon file can be put in PROPATH and be read. The only icon is embedded into p2j.jar file is "gclogo.ico". This is "last resort" when other sources do not have the icon.

Also no more need to include TwelveMonkeys plugin into client classpath, it is now included in p2j.jar manifest.

#693 Updated by Constantin Asofiei over 9 years ago

Greg Shah wrote:

Code Review ca_upd20141204d.zip

The changes look good. Please get it tested.

Passed runtime testing, released to bzr rev 10673.

#694 Updated by Greg Shah over 9 years ago

Code Review evl_upd20141205a.zip

This is a really good update. My only concern is that LogicalTerminal.loadImage() should not unconditionally lowercase the filename. This won't work for mixed case names or uppercase names on Linux/UNIX. Doesn't FileSystemOps.searchPath() already have the functionality to honor/mimic the source system's case sensitivity/insensitivity? I don't think we need to do anything to the name. But this should be tested.

Other than that I think this is ready for regression testing (both conversion and runtime).

#695 Updated by Constantin Asofiei over 9 years ago

Greg, this is for the "ghost" drawing problems. It affects only the GUI code, so it can be released.

Eugenie:
  • the problems were basically related to this:
    1. the widgetDrawingOn/Off bracket needs to translate to the frame's location, before drawing the widgets
    2. in ButtonGuiImpl, you were calling drawing code directly from mouse events. This is incorrect: you need to rely on repaint() to notify the underlying infrastructure that a draw is needed, as the drawing needs to be done in the proper context (i.e. with the origin already translated to the parent's origin, when the widget's draw() is called).
  • unfortunately there is one more regression: the window scrollbars are no longer responsive after H003/H004 in WindowWorkspace. Please try to fix this, too.

#696 Updated by Eugenie Lyzenko over 9 years ago

...Doesn't FileSystemOps.searchPath() already have the functionality to honor/mimic the source system's case sensitivity/insensitivity?

You are right, we already has case sensitivity included, so this was double work. The update attached removes this issue.

#697 Updated by Eugenie Lyzenko over 9 years ago

2. in ButtonGuiImpl, you were calling drawing code directly from mouse events.

What do you mean? Except show/hide for tooltip.

This is incorrect: you need to rely on repaint() to notify the underlying infrastructure that a draw is needed, as the drawing needs to be done in the proper context (i.e. with the origin already translated to the parent's origin, when the widget's draw() is called).

The tool tip is not an widget. Moreover it is belonging to any containers or another widgets that hold another. We can not wait for next repainting because tooltip should be drawing immediately.

#698 Updated by Greg Shah over 9 years ago

Code Review ca_upd20141205d.zip

Its good. Release it.

#699 Updated by Greg Shah over 9 years ago

Code Review evl_upd20141205b.zip

I like it. Please get it tested.

#700 Updated by Eugenie Lyzenko over 9 years ago

unfortunately there is one more regression: the window scrollbars are no longer responsive after H003/H004 in WindowWorkspace. Please try to fix this, too.

Which one is problematic, H003 or H004?

#701 Updated by Constantin Asofiei over 9 years ago

Eugenie Lyzenko wrote:

2. in ButtonGuiImpl, you were calling drawing code directly from mouse events.

What do you mean?

Look at ButtonGuiImpl.mousePressed/mouseReleased/handleBasicEvents: you were calling refresh, which executes the drawing immediately. The correct usage is repaint.

This is incorrect: you need to rely on repaint() to notify the underlying infrastructure that a draw is needed, as the drawing needs to be done in the proper context (i.e. with the origin already translated to the parent's origin, when the widget's draw() is called).

The tool tip is not an widget. Moreover it is belonging to any containers or another widgets that hold another. We can not wait for next repainting because tooltip should be drawing immediately.

I'm not talking about the tooltip, although this can be improved, too; it's activation logic should be detached from the widget: the widget should just inform the driver "if the mouse hovers over me, then show this tooltip" by registering a MouseWidgetAction implementation with its id and the actual tooltip. The way you've added it now, the tooltip activation logic needs to be duplicated in each and every widget... also, the hovering concept is not duplicated at all, on mouse enter the tooltip is shown immediately, which is not how 4GL works.

Also, the following doesn't work at runtime: btn:tooltip in frame f1 = "bla".

Which one is problematic, H003 or H004?

If you look into the bzr log for this file, these two were committed at the same time...

#702 Updated by Eugenie Lyzenko over 9 years ago

Greg Shah wrote:

Code Review evl_upd20141205b.zip

I like it. Please get it tested.

OK. The conversion testing has been started.

#703 Updated by Constantin Asofiei over 9 years ago

Greg Shah wrote:

Code Review ca_upd20141205d.zip

Its good. Release it.

Released to rev 10674.

#704 Updated by Eugenie Lyzenko over 9 years ago

unfortunately there is one more regression: the window scrollbars are no longer responsive after H003/H004 in WindowWorkspace. Please try to fix this, too.

Constantin,

I need code sample for scrollbar that is known as worked before the changes. The test you used to see the scrollbar is working.

#705 Updated by Constantin Asofiei over 9 years ago

Eugenie Lyzenko wrote:

unfortunately there is one more regression: the window scrollbars are no longer responsive after H003/H004 in WindowWorkspace. Please try to fix this, too.

Constantin,

I need code sample for scrollbar that is known as worked before the changes. The test you used to see the scrollbar is working.

See button/gui_btn_test0.p : after the first key is pressed and the frame is shown, resize the window and scrollbars will appear. If you try to press the scrollbar buttons or drag the knob, you will see there is no response.

#706 Updated by Eugenie Lyzenko over 9 years ago

The conversion testing for evl_upd20141205b.zip completed. The generated files are identical.

Started the runtime testing cycle.

#707 Updated by Constantin Asofiei over 9 years ago

Greg,

This version (although needs more cleanup/javadocs) is under regression testing. Please take a look, if you have time...

The cursor part in ChUI is already somehow "buggy" in P2J, in certain cases (and this is a small word for the real 4GL behaviour at least for numeric inputs); I've tried to improve these, as part of determining a common behaviour. Note that I underestimated the effort for the labels: this is strongly linked with the frame layout, as it computes incorrect "next-X" values for the fill-ins, thus the fill-ins are placed... all over the place.

What it works in GUI (although some visual improvements can be made), for editable mode:
  • caret
  • mouse focus and caret positioning
  • text selection via SHIFT-(cursor keys) or HOME/END
  • fill-in content overflow (when the actual text width doesn't fit the editable area) and navigation via cursor keys

#708 Updated by Eugenie Lyzenko over 9 years ago

Default Progress color table(always exists in Windows)

Color Number Windows RGB Values Actual Color Defined
---------------------------
0  0,   0,   0   Black
1  0,   0,   128 Dark blue
2  0,   128, 0   Dark green
3  0,   128, 128 Blue green
4  128, 0,   0   Red
5  128, 0,   128 Purple
6  128, 128, 0   Olive
7  128, 128, 128 Gray
8  192, 192, 192 Light gray
9  0,   0,   255 Blue
10 0,   255, 0   Green
11 0,   255, 255 Turquoise
12 255, 0,   0   Red
13 255, 0,   255 Pink
14 255, 255, 0   Yellow
15 255, 255, 255 White

#709 Updated by Greg Shah over 9 years ago

In what class do you propose to define these values? This should be separate from the loading code (like how we store the default system colors in SysColor).

Do you have the changes ready to load this by default when no configuration exists?

#710 Updated by Eugenie Lyzenko over 9 years ago

In what class do you propose to define these values? This should be separate from the loading code (like how we store the default system colors in SysColor).

This update fixes the color table issue and toolbar regression.

Do you have the changes ready to load this by default when no configuration exists?

Yes, if no colors in directory, the default ones will be used. I've disabled my directory colors and it works as expected.

#711 Updated by Greg Shah over 9 years ago

Code Review evl_upd20141206a.zip

It looks good. Off the top of my head I think the color-table support is only really used for GUI.

Constantin: Do we ever go through this path for ChUI?

#712 Updated by Greg Shah over 9 years ago

Code Review ca_upd20141205e.zip

This is awesome! I'm blown away that you've been able to get so far in editing with just minor changes to the DisplayFormat classes. On the other hand, obviously the ChUI and GUI implementation classes for FillIn are much more complicated now. The overall approach is very good. It is understandable that there is still some work to do in fully abstracting ChUI and GUI. I'm also not surprised that our editing of numeric inputs (and date too?) is buggy. It took a while to get this stabilized and I don't think we took a comprehensive approach to getting it right.

Some smaller items:

1. In FillInConfig, the selectionStart and selectionEnd members need to be added to applyConfig().

2. I think the idea behind the names in SysColor is that they mirror names for real Windows system color constants. I'm guessing that COLOR-FILLIN-BG and COLOR-FILLIN-FG are not WIN32 inspired? If so, I'd prefer to figure out what these map to in WIN32 system color constant terms. This is not urgent.

3. This comment // modify the next character (in GUI 4GL, ALT is a modifier key) in WinKeyboardReader.processShift() needs to be updated.

4. You mention this:

         // TODO: maybe this can be improved? else we will end up with this idiom all over the
         // place...
         boolean cursorNav = ThinClient.getInstance().isChui();

While I don't expect this to be done as part of this task, I do think we need to design and build a single, clean and sensible configuration system. Today we read configuration from many places and each approach is ad-hoc. I think the client needs to have a configuration phase where is reads its configuration (client bootstrap, server directory...) and then instantiates a single centralized configuration object that stores all the client values. This would not just be for UI but even for values like date/decimal formats and file system/environment values (e.g. case-sensitivity, propath...). It should be initialized before any converted code can execute and then the client can simply refer to these in memory values. Some classes may just read from it once and store a flag. I think the FillIn use probably falls into that category. Others may need to read it on the fly, since it is possible for some values to change based on the execution of converted code (e.g. propath assignment).

#713 Updated by Constantin Asofiei over 9 years ago

Greg Shah wrote:

Code Review evl_upd20141206a.zip

It looks good. Off the top of my head I think the color-table support is only really used for GUI.

Constantin: Do we ever go through this path for ChUI?

No, ChUI (and MAJIC) do not touch this code, except LT.getChanges does call ColorTable.clearDirtyFlag which will initialize the ColorTable class.

Eugenie, please do only a simple test in MAJIC: apply your update, start the server and do some simple navigation with the MAJIC client. If this works, then you can release it.

#714 Updated by Eugenie Lyzenko over 9 years ago

Eugenie, please do only a simple test in MAJIC: apply your update, start the server and do some simple navigation with the MAJIC client. If this works, then you can release it.

Currently I'm testing previous update for regression on devsrv01. As soon the testing finished(at least main part) I can do such tests. I've made local testing in ChUI mode for button testcase and it works as expected.

#715 Updated by Eugenie Lyzenko over 9 years ago

The main part for evl_upd20141205b.zip completed without regressions. Waiting for CTRL-C to be done.

#716 Updated by Greg Shah over 9 years ago

I don't think we need to wait for CTRL-C in this case. The changes are quite far away. Please go ahead and check in evl_upd20141205b.zip.

#717 Updated by Eugenie Lyzenko over 9 years ago

Greg Shah wrote:

I don't think we need to wait for CTRL-C in this case. The changes are quite far away. Please go ahead and check in evl_upd20141205b.zip.

OK. The testing results are in 10674_532468b_20141206_evl.zip.

#718 Updated by Eugenie Lyzenko over 9 years ago

The update evl_upd20141205b.zip has been committed in bzr as 10675.

#719 Updated by Eugenie Lyzenko over 9 years ago

Simple navigation tests for evl_upd20141206a.zip show no regression. So I'm starting to commit and release this update.

#720 Updated by Eugenie Lyzenko over 9 years ago

The update evl_upd20141206a.zip committed in bzr as 10676.

#721 Updated by Constantin Asofiei over 9 years ago

Greg, I want to reduce the load on the changes I need to maintain; following is a GUI-only subset of 1205e.zip which I'm certain will remain unchanged, as I'm moving through fixing ChUI regressions (looks like only the stream output was affected...).

I will release this next if it looks OK to you.

#722 Updated by Greg Shah over 9 years ago

Code Review ca_upd20141206b.zip

It looks good, release it.

#723 Updated by Constantin Asofiei over 9 years ago

Greg Shah wrote:

Code Review ca_upd20141206b.zip

It looks good, release it.

Released to bzr rev 10677.

#724 Updated by Greg Shah over 9 years ago

My latest update merged with bzr rev 10677.

#725 Updated by Hynek Cihlar over 9 years ago

This is for #2424.

The attached file includes changes for review and contains the following.

- Implemented synchronization of linked widget coordinate attributes.
- Implemented runtime support for widget coordinate attributes.
- Added Widget.syncWithConfig(), so far limited to window widget and only some cases.
- Implemented runtime support for several SESSION attributes.
- Improved config state client-server synchronization.
- Improved server-client state transfer of the default window.
- Improved window mouse drag and mouse resize behavior.
- Implemented synchronization with the server window coordinate attributes.
- Improved window layout algorithm to honor the requested window size.

What's missing.

- Runtime support for some attributes is not complete yet.
- This change set doesn't touch scrolling.

Regression test is in progress.

Please review. Constantin, it would be good if you could also look at this.

#726 Updated by Constantin Asofiei over 9 years ago

Hynek, I don't see anything wrong with the logic. BTW, I like the idea using the withinClientPoint to reduce the aspect footprint. Have you done some performance tests? The only comments are have are mostly cosmetics:

methods_attributes.rules
- Greg added the load_descriptors function... see H111 for details how to use it - the idea is, the description of new mthds/attrs should be defined there

SyncCoordinatesAspect
- class javadoc ends abruptly

BaseEntity
- is missing history entry

LogicalTerminal
- you don't need to add LegacyAttribute annotations there, only at the interface defining the resource is needed.

WindowGuiImpl
- getInsMode - is missing an asterix in the javadoc

SwingGuiPrimitives
- you've added new APIs which require a windowID, but you don't select the simulator for that window. The currently selected simulator is always used. What if no window is selected when these APIs are called? Usually, the SwingGuiPrimitives APIs don't require a window id... selectWindow should be called before calling these APIs

Also, please make sure to test the following:
- client restart via CTRL-C in ChUI and CTRL-PAUSE/BREAK for windows client
- we need to double check if appserver calls are working properly... Ovidiu might help with this, to run some basic tests in his appserver framework.

#727 Updated by Hynek Cihlar over 9 years ago

Constantin Asofiei wrote:

Have you done some performance tests?

Yes, but so far only in ChUI. The performance hit of the new aspect seems to be negligible. However what surprised me was the difference in ChUI performance between P2J and 4GL. A test running cca 80 seconds in P2J took cca 3 seconds in 4GL.

The only comments are have are mostly cosmetics:

methods_attributes.rules
- Greg added the load_descriptors function... see H111 for details how to use it - the idea is, the description of new mthds/attrs should be defined there

Sorry for my ignorance, but what does H111 stand for?

SyncCoordinatesAspect
- class javadoc ends abruptly

Fixed.

BaseEntity
- is missing history entry

Fixed.

LogicalTerminal
- you don't need to add LegacyAttribute annotations there, only at the interface defining the resource is needed.

Even if this is called from a proxy? Btw. should I delclare these methods in the CommonSession interface?

WindowGuiImpl
- getInsMode - is missing an asterix in the javadoc

Fixed.

SwingGuiPrimitives
- you've added new APIs which require a windowID, but you don't select the simulator for that window. The currently selected simulator is always used. What if no window is selected when these APIs are called? Usually, the SwingGuiPrimitives APIs don't require a window id... selectWindow should be called before calling these APIs

Actually I made a mistake. These new methods should have used getSimulator(int windowId) to retrieve the correct simulator. See the attached file.

Also, please make sure to test the following:
- client restart via CTRL-C in ChUI and CTRL-PAUSE/BREAK for windows client
- we need to double check if appserver calls are working properly... Ovidiu might help with this, to run some basic tests in his appserver framework.

Will test.

#728 Updated by Hynek Cihlar over 9 years ago

Pls ignore hc_upd20141207e.zip, it didn't contain the changes in SwingGuiPrimitives. See the attached instead.

#729 Updated by Constantin Asofiei over 9 years ago

Hynek Cihlar wrote:

Constantin Asofiei wrote:

Have you done some performance tests?

Yes, but so far only in ChUI. The performance hit of the new aspect seems to be negligible. However what surprised me was the difference in ChUI performance between P2J and 4GL. A test running cca 80 seconds in P2J took cca 3 seconds in 4GL.

Please point me to the test.

methods_attributes.rules
- Greg added the load_descriptors function... see H111 for details how to use it - the idea is, the description of new mthds/attrs should be defined there

Sorry for my ignorance, but what does H111 stand for?

The history entry in the file.

LogicalTerminal
- you don't need to add LegacyAttribute annotations there, only at the interface defining the resource is needed.

Even if this is called from a proxy? Btw. should I delclare these methods in the CommonSession interface?

Yes, you need to declare them in CommonSession. Usually, when you work with system handles, consider that you can access them via a "untyped" handle var, so please ensure you cover code like this:

h = session.
message h:<some-session-attr/mthd>.

This will go over a different call-path than the plain SESSION:<some-session-attr/mthd> construct.

Also, please make sure to test the following:
- client restart via CTRL-C in ChUI and CTRL-PAUSE/BREAK for windows client
- we need to double check if appserver calls are working properly... Ovidiu might help with this, to run some basic tests in his appserver framework.

Will test.

#730 Updated by Hynek Cihlar over 9 years ago

Constantin, thanks for the inputs. I will finish your suggestions in the morning. Btw. the regression testing goes well so far. The Ctrl-C part has finished with three failures which don't seem to be related to my changes.

#731 Updated by Hynek Cihlar over 9 years ago

Please review the attached changes. All points from the review addressed, except for the load_descriptors in methods_attributes.rules, I will keep this as a TODO.

Regression test is in progress. Also appserver calls test is in progress.

#732 Updated by Constantin Asofiei over 9 years ago

Hynek Cihlar wrote:

Please review the attached changes. All points from the review addressed, except for the load_descriptors in methods_attributes.rules, I will keep this as a TODO.

I'm OK with the changes; but:
  • add a history entry to CommonSession
  • why do you need to explicitly differentiate between ChUI/non-ChUI in LT.getHeightChars and others?
          int wndId = locate().currentWindow.getId();
          int height = getClient().getDisplayHeight(wndId);
          if (isChui())
          {
             return new decimal(height);
          }
          else
          {
             return new decimal(coordinates().rowFromPixels(height));
          }
    

    I was expecting to use rowFromNative API to convert from native units to chars...

#733 Updated by Hynek Cihlar over 9 years ago

Constantin Asofiei wrote:

Hynek Cihlar wrote:

Please review the attached changes. All points from the review addressed, except for the load_descriptors in methods_attributes.rules, I will keep this as a TODO.

I'm OK with the changes; but:
  • add a history entry to CommonSession
  • why do you need to explicitly differentiate between ChUI/non-ChUI in LT.getHeightChars and others?
    [...]
    I was expecting to use rowFromNative API to convert from native units to chars...

Good point.

The reason to differentiate between ChUI/non-ChUI for the pixel attributes is that there is no method to do native-pixel conversion in CoordinatesConversion class. I added a note in the code to implement this as I want to also rethink the naming convention with this addition and also merge the width*/column* and height*/row* methods.

There was no reason to differentiate ChUI/non-ChUI for LT.getHeightChars, and this was fixed.

Also history entry added to CommonSession.java.

Please review.

#734 Updated by Constantin Asofiei over 9 years ago

Hynek Cihlar wrote:

There was no reason to differentiate ChUI/non-ChUI for LT.getHeightChars, and this was fixed.

Also history entry added to CommonSession.java.

Please review.

I'm good with the changes.

#735 Updated by Constantin Asofiei over 9 years ago

Hynek,

My attached update is built on top of your 1208b.zip update (is still unfinished, but it doesn't have any ChUI regressions). The uast/demo/calc.p program is a demo calculator which works in GUI 4GL. In GUI P2J, the only problem is that the widgets are not placed in the proper locations.

Please check if you can fix this easily; although I have a feeling the real cause is somewhere in the frame layout processing... it might not be aware of a coordinate set by the server-side and a coordinate computed automatically.

I'll try to re-write the calc app without relying on the X/Y coordinates in the mean time.

#736 Updated by Constantin Asofiei over 9 years ago

Constantin Asofiei wrote:

I'll try to re-write the calc app without relying on the X/Y coordinates in the mean time.

OK, using static coords via the format setting at the frame/widget definition works. So, Hynek, you can move back at stabilizing your current update, so you can release it.

I'll post the new calc.p to the testcases repo after some esthetic touchups.

#737 Updated by Constantin Asofiei over 9 years ago

Constantin Asofiei wrote:

Constantin Asofiei wrote:

I'll try to re-write the calc app without relying on the X/Y coordinates in the mean time.

OK, using static coords via the format setting at the frame/widget definition works. So, Hynek, you can move back at stabilizing your current update, so you can release it.

I'll post the new calc.p to the testcases repo after some esthetic touchups.

In the end only char coords and sizes defined at the format phrase allowed P2J to work properly. See uast/demo/calc-static-chars.p which works in P2J rev 10678, hc_upd20141208b.zip and ca_upd20141208d.zip .

The calc-static-pixels.p is the alternative in pixel units.

#738 Updated by Eugenie Lyzenko over 9 years ago

This update for review is first step for image widget conversion and runtime support. But enough to see the screen shot attached. Just put the picture "man_on_moon.png" into PROPATH and convert and run image4.p(will be uploaded shortly).

Continue working.

#739 Updated by Eugenie Lyzenko over 9 years ago

Merged with recent changes.

#740 Updated by Eugenie Lyzenko over 9 years ago

This update for review contains reworked tooltip implementation. Now it is not associated with button so can easily be used with any other widget that needs tooltip. The only is required is to register widget for tooltip worker.

The tooltip behavior is simulating the one we see in Windows. There is initial delay between mouse is over widget and tooltip showing - 100 ms. Also there is lifetime - 5000 ms, after this time tooltip should disappear unconditionally.

The update is synced with the recent code base from bzr. Without recent updates that was not tested and checked in.

#741 Updated by Greg Shah over 9 years ago

Code Review evl_upd20141209a.zip

This is good. Please make the changes listed below and get this tested.

1. The update zip has the path rules/annotation/ which really should be rules/annotations/.

2. A minor improvement to progress.g is to make line 10058 change from this:

sym.addWidget(#i.getText(), WID_IMAGE);

to this:

sym.addWidget(varname, WID_IMAGE);

3. Constantin's pending changes are still in progress and I want to get this into testing, so please remove those changed from the GuiWidgetFactory.java.

#742 Updated by Greg Shah over 9 years ago

Code Review evl_upd20141212a.zip

1. Please add support for the SESSION:TOOLTIPS attribute to enable/disable tooltips in the client.

2. I see the following in the 4GL docs:

You can add or change the TOOLTIP attribute at any time. If TOOLTIP is set to "" or
the Unknown value (?), then the ToolTip is removed. No ToolTip is the default.

What happens in this case? Do we implement it properly?

3. In ButtonGuiImpl.initialize(), should we always call registerTooltipWorker() unconditionally? What if SESSION:TOOLTIPS is false OR the tooltip is assigned "" or ?? In such cases I suspect that we don't want the extra listener always processing mouse events.

4. Shouldn't ToolTip.run() clear the tooltip in a finally block after the Thread.sleep(DURATION_MS); is done?

#743 Updated by Eugenie Lyzenko over 9 years ago

The attached update is will be tested shortly for conversion and runtime regressions.

#744 Updated by Eugenie Lyzenko over 9 years ago

1. Please add support for the SESSION:TOOLTIPS attribute to enable/disable tooltips in the client.

OK.

2. I see the following in the 4GL docs:

You can add or change the TOOLTIP attribute at any time. If TOOLTIP is set to "" or
the Unknown value (?), then the ToolTip is removed. No ToolTip is the default.

What happens in this case? Do we implement it properly?

Currently if tooltip is "" it will not be shown. But agree, we need to handle the Unknown(?) value too. Will be fixed in next update.

3. In ButtonGuiImpl.initialize(), should we always call registerTooltipWorker() unconditionally? What if SESSION:TOOLTIPS is false OR the tooltip is assigned "" or ?? In such cases I suspect that we don't want the extra listener always processing mouse events.

In the case we need to call registerTooltipWorker() - we will have to do this every time the tooltip should be seen. And deregister then when tooltip is gone("" or ?). Do you think this additional processing does not terminate the profit we give from conditional listener registration?

4. Shouldn't ToolTip.run() clear the tooltip in a finally block after the Thread.sleep(DURATION_MS); is done?

Yes, this is the question I'm thinking about too. In perfect condition this is what should happening. But the screen is not clearing from tooltip thread. For example by owner.repaint() call. I think the reason is the tooltip is running in separate thread and repainting command is not handling properly. This needs more debugging(because the owner widget goes to draw() method but screen is not changing).

#745 Updated by Greg Shah over 9 years ago

3. In ButtonGuiImpl.initialize(), should we always call registerTooltipWorker() unconditionally? What if SESSION:TOOLTIPS is false OR the tooltip is assigned "" or ?? In such cases I suspect that we don't want the extra listener always processing mouse events.

In the case we need to call registerTooltipWorker() - we will have to do this every time the tooltip should be seen. And deregister then when tooltip is gone("" or ?). Do you think this additional processing does not terminate the profit we give from conditional listener registration?

I'm not saying that we should register the tooltip when it should be seen. I'm saying that when the tooltip is "" or ? or tooltips are turned off, then no registration should occur. When SESSION:TOOLTIPS is turned on or the widget's tooltip is set to something non-empty, then we would register it.

I think the reason is the tooltip is running in separate thread and repainting command is not handling properly.

Yes, we must repaint in a "drawing bracket" that is executed on the Swing event thread.

#746 Updated by Greg Shah over 9 years ago

Code Review evl_upd20141215a.zip

It looks good. You can check it in if it passes testing.

#747 Updated by Eugenie Lyzenko over 9 years ago

Code Review evl_upd20141215a.zip

It looks good. You can check it in if it passes testing.

Really I've lost one important file for this update. ../p2j/ui/client/Image.java. No building without this file. Check the fixed version. It will be put into testing.

#748 Updated by Eugenie Lyzenko over 9 years ago

The conversion testing completed. The generated codes are identical. Starting the runtime testing.

#749 Updated by Greg Shah over 9 years ago

Code Review evl_upd20141215b.zip

My only question is about the new constructor in Image.java. It ignores the passed in ImageConfig instance. Is that intentional?

#750 Updated by Eugenie Lyzenko over 9 years ago

My only question is about the new constructor in Image.java. It ignores the passed in ImageConfig instance. Is that intentional?

Yes, as far as I know the required config processing is happening a bit later in initialize() method which is called in widget reconstruction code after the widget is registered in registry.

#751 Updated by Eugenie Lyzenko over 9 years ago

1. Please add support for the SESSION:TOOLTIPS attribute to enable/disable tooltips in the client.

The implementation plan is:

1. The server side code will be located in p2j/util/SessionUtils class. Here we call current client session via LT.getClient() for get/set attribute.
2. The ThinClient class will store this attribute inside the current OutputManager instance. For ChUI the calls will be ignored or produce required error messages. For GUI mode - store/return current value. Also the ThinClient getter will be called in places dependent from this value(for example tooltip initialization code for appropriate widgets).

Let me know if any notes/objections.

#752 Updated by Greg Shah over 9 years ago

1. The server side code will be located in p2j/util/SessionUtils class. Here we call current client session via LT.getClient() for get/set attribute.

That is fine, so long as you also keep a context-local copy in SessionUtils so that we don't have to travel down to the client for a read of the attribute. Obviously, when the attribute is written by the business logic, we will have to push any change down to the client as you have noted.

At client startup, the default value should be read from the directory.

#753 Updated by Eugenie Lyzenko over 9 years ago

The main part of the evl_upd20141215b.zip runtime testing completed without regressions. Continue testing for CTRL-C part.

#754 Updated by Eugenie Lyzenko over 9 years ago

The CTRL-C part passed in a single round. The test results is 10680_532468b_20141216_evl.zip - on the shared directory. Starting to commit and distribute.

#755 Updated by Eugenie Lyzenko over 9 years ago

The evl_upd20141215b.zip has been committed in bzr as 10681.

#756 Updated by Eugenie Lyzenko over 9 years ago

This update for review is not yet completed for tooltip implementation and image integration into button. But it presents approach taken for SESSION:TOOLTIPS attribute set/get. Just for you to know the way I'm going while it is not too far for massive undoing.

The idea is:
1. Server side part start first in SessionUtils code. We read the directory for override and set up initial value for attribute. Then client starts and ask the server for initial value.
2. Then when business logic changes the value(on the server side) the new one is stored in server side per-session area and is pushing into client.
3. The client side always ask the client side value(which is the synced with the current server side at #2). The client code itself does not change the value of the SESSION:TOOLTIPS. This is happening only in server side code.

#757 Updated by Greg Shah over 9 years ago

Code Review evl_upd20141217a.zip

It is very good. My only suggestion is that SessionUtils.setSessionTooltips() needs to handle null and unknown value for the passed logical. This should be made compatible with how the 4GL handles unknown.

#758 Updated by Eugenie Lyzenko over 9 years ago

It is very good. My only suggestion is that SessionUtils.setSessionTooltips() needs to handle null and unknown value for the passed logical. This should be made compatible with how the 4GL handles unknown.

OK. I've changed setter to make SESSION:TOOLTIPS == false for these cases.

#759 Updated by Eugenie Lyzenko over 9 years ago

This update for review contains project of the complete tooltip solution. If there is no tooltips or session based TOOLTIPS attribute is false - we have no tooltips visible. Setting TOOLTIPS to true or widget tooltip text to something non-empty(if TOOLTIPS attribute is true) will activate tooltip feature.

The approach behind this implementation is:
1. The tooltip handler registration is different for cases when tooltip must be active and not.
2. In the case when tooltip handler must not be active it is stored in the list of pending tooltip workers. This means there is no actual handler registration and we do not loose the CPU time for tooltips we do not currently need.
3. When the tooltip activation events occurs(SESSION:TOOLTIPS become true or tooltip text become non-empty), the pending list is processing by registration required tooltips workers. If SESSION:TOOLTIPS become true - all pending tooltip handlers with non-empty text are registering and become active. If tooltip text become valuable - only handler for particular widget is registering if current SESSION:TOOLTIPS is true.
4. If the entry from pending list is registering as new tooltip handler - it is removing from pending workers list.

The tooltip engine has been improved to automate the owner widget repainting after duration timeout.

Also one point to discuss regarding tooltip functions in widgets. For example ButtonWidget and BaseEntity both have the setTooltip(String tooltip) methods doing exactly the same. I do not think we need to implement tooltip related methods in every widget that needs this feature. May be it is better to implement common code in BaseEntity and add something that needs unusual processing in classes that extends BaseEntity? What do you think?

#760 Updated by Hynek Cihlar over 9 years ago

In regard to #2424.

The attached update resolves all the discovered regressions, i.e. appserver/batch mode unhandled UnstoppableExitException and chui frame item layout issues.

I have a regression run in progress. Please review.

#761 Updated by Eugenie Lyzenko over 9 years ago

This is the bug fixing for recent update after new features testing:

1. When setting tooltip to unknown we need to set the tooltip string as null.
2. Fix in SwingGuiDriver.registerPendingTooltipWorkers() for defining the condition to leave the method when tooltip disabled on session level.

#762 Updated by Greg Shah over 9 years ago

Code Review evl_upd20141218b.zip

1. Shouldn't the SwingGuiDriver.registerPendingTooltipWorkers() deregister the workers if the SESSION:TOOLTIPS changes from true to false? Perhaps the ThinClient.setSessionTooltips() should call a deregister method instead of the register method.

2. If SESSION:TOOLTIPS is assigned true when it is already true or false when it is already false, then ThinClient.setSessionTooltips() should do nothing.

3. The SwingGuiDriver, GuiDriver and ToolTip classes should explicitly import ThinClient instead of all of the chui.* package, so that we can easily know that when ThinClient is moved out of chui, that there are no other dependencies. This is an exception to our normal practice of wildcard imports but we are doing it knowing this is a temporary measure.

4. I'd like to reduce the dependence of this solution upon direct use of ThinClient. Is it reasonable to store the widget itself (instead of the ID) in the pending worker map? If so, then we can replace the ThinClient parameter from registerPendingTooltipWorkers() with a simple boolean (the value of SESSION:TOOLTIPS). This will also allow us to eliminate the references to ThinClient in both SwingGuiDriver and in GuiDriver.

5. Please put the hide() in ToolTip.run() in a finally block.

6. The ToolTip.isActive() is a public method which should be located above the private methods.

7. Instead of storing the client-side SESSION:TOOLTIPS value in ThinClient, please store it in ToolTip as a static value. That way it is kept "close" to where it is being used and the tool-tip related code doesn't have to have linkages to ThinClient.

8. Your question:

I do not think we need to implement tooltip related methods in every widget that needs this feature. May be it is better to implement common code in BaseEntity and add something that needs unusual processing in classes that extends BaseEntity? What do you think?

Yes, I think this makes good sense.

#763 Updated by Eugenie Lyzenko over 9 years ago

1. Shouldn't the SwingGuiDriver.registerPendingTooltipWorkers() deregister the workers if the SESSION:TOOLTIPS changes from true to false? Perhaps the ThinClient.setSessionTooltips() should call a deregister method instead of the register method.

In case SESSION:TOOLTIPS changes from true to false the SwingGuiDriver.registerPendingTooltipWorkers() does nothing. In my approach once the handler is registered it is not deregistering further. It is intentional to reduce deregistration/registration calls because I think in a real application the tooltip states will not be changed very often.

2. If SESSION:TOOLTIPS is assigned true when it is already true or false when it is already false, then ThinClient.setSessionTooltips() should do nothing.

OK.

3. The SwingGuiDriver, GuiDriver and ToolTip classes should explicitly import ThinClient instead of all of the chui.* package, so that we can easily know that when ThinClient is moved out of chui, that there are no other dependencies. This is an exception to our normal practice of wildcard imports but we are doing it knowing this is a temporary measure.

OK.

4. I'd like to reduce the dependence of this solution upon direct use of ThinClient. Is it reasonable to store the widget itself (instead of the ID) in the pending worker map? If so, then we can replace the ThinClient parameter from registerPendingTooltipWorkers() with a simple boolean (the value of SESSION:TOOLTIPS). This will also allow us to eliminate the references to ThinClient in both SwingGuiDriver and in GuiDriver.

OK. This will require to change a bit the way we call handler registration from server side(in this case we have to use ID, not widget), not a problem just FYI.

5. Please put the hide() in ToolTip.run() in a finally block.

OK.

6. The ToolTip.isActive() is a public method which should be located above the private methods.

OK.

7. Instead of storing the client-side SESSION:TOOLTIPS value in ThinClient, please store it in ToolTip as a static value. That way it is kept "close" to where it is being used and the tool-tip related code doesn't have to have linkages to ThinClient.

OK.

#764 Updated by Greg Shah over 9 years ago

1. Shouldn't the SwingGuiDriver.registerPendingTooltipWorkers() deregister the workers if the SESSION:TOOLTIPS changes from true to false? Perhaps the ThinClient.setSessionTooltips() should call a deregister method instead of the register method.

In case SESSION:TOOLTIPS changes from true to false the SwingGuiDriver.registerPendingTooltipWorkers() does nothing. In my approach once the handler is registered it is not deregistering further. It is intentional to reduce deregistration/registration calls because I think in a real application the tooltip states will not be changed very often.

Is this how the 4GL does it? I suspect that if the application sets SESSION:TOOLTIPS to false, that no more tooltips will display after that time. If so, then we need to deregister our tooltips too.

#765 Updated by Greg Shah over 9 years ago

Code Review hc_upd20141218c.zip

The code looks good. The only note is that there is a .classpath included which probably should not be there.

#766 Updated by Eugenie Lyzenko over 9 years ago

Is this how the 4GL does it? I suspect that if the application sets SESSION:TOOLTIPS to false, that no more tooltips will display after that time. If so, then we need to deregister our tooltips too.

Yes, 4GL does not display tooltips when application sets SESSION:TOOLTIPS to false. The current P2J will not display them in this case(but the handlers remain registered). If we will deregister all handlers - this mean we will have to register them again if sometimes SESSION:TOOLTIPS will become true. Is this what we need?

One more point. I have removed ThinClient dependencies but I need the widget ID to be passed in GuiDriver.registerPendingTooltipWorkers() as only parameter. This needs to register single handler(when SESSION:TOOLTIPS already true) if tooltip text for particular widget become non-empty. Is it OK?

#767 Updated by Greg Shah over 9 years ago

The current P2J will not display them in this case(but the handlers remain registered). If we will deregister all handlers - this mean we will have to register them again if sometimes SESSION:TOOLTIPS will become true. Is this what we need?

I think so, otherwise the handlers will execute and slow down the system (at least slightly).

I have removed ThinClient dependencies but I need the widget ID to be passed in GuiDriver.registerPendingTooltipWorkers() as only parameter. This needs to register single handler(when SESSION:TOOLTIPS already true) if tooltip text for particular widget become non-empty. Is it OK?

For now, that sounds fine.

#768 Updated by Eugenie Lyzenko over 9 years ago

I think so, otherwise the handlers will execute and slow down the system (at least slightly).

OK.

#769 Updated by Constantin Asofiei over 9 years ago

Guys, does anyone know where the color names from SysColor class were captured? I can't find any reference in redmine...

This link has some constants related to the win32 GetSysColor API: http://msdn.microsoft.com/en-us/library/windows/desktop/ms724371(v=vs.85).aspx and it looks like there are already constants related to tooltip background/foreground, COLOR_INFOBK and COLOR_INFOTEXT.

#770 Updated by Constantin Asofiei over 9 years ago

Attached version is for #2451 , implementation for FILL-IN/TEXT/LITERAL in GUI. Remaining work:
  1. GUI fill-in width - need to implement the formula
  2. literals in DISPLAY statement with VIEW-AS TEXT - the metrics for these texts need to be captured in their formatted view!
  3. for some cases (literals in FORM statements, etc), the width/height is computed once, and if content is changed, that width/height is not recomputed: need to find if passing the literal at the config and keep it in a read-only state is enough to determine the size.
  4. fill-in's: initial width is given by the format length, i.e. the "yes/no" for logical values (not just "yes")... for date, the max length from the yes/no alternatives is used.
  5. layout: widget location needs to be aware of the frame's 1px border! This is common for all widgets.
  6. date format: must not allow clearing or backspace/delete
  7. side labels
  8. text selection support via mouse is not added yet - this should be postponed when EDITOR is implemented, as the algorithm should involve multiple rows, and check if it can be implemented at the driver level
  9. SysColor - fix the color names for FILL-IN

#771 Updated by Greg Shah over 9 years ago

does anyone know where the color names from SysColor class were captured?

I believe Marius pulled those from the Windows headers or docs. The reference you found is as good a source as any other. It is fairly safe to do that because there are tens (hundreds?) of thousands of compiled applications which rely upon those constants, so Microsoft can't really change them. Of course, we are not really relying upon the values being the same since we don't call GetSysColor, but I think he used those values to be consistent. We need to ensure that we have mappings for all of the system colors that can be used from the 4GL widgets.

#772 Updated by Greg Shah over 9 years ago

Code Review ca_upd20141220b.zip

This is really good. If I understand correctly, it has passed testing. I'm OK for you to check it in, if you are OK with it.

#773 Updated by Eugenie Lyzenko over 9 years ago

Constantin,

This link has some constants related to the win32 GetSysColor API: http://msdn.microsoft.com/en-us/library/windows/desktop/ms724371(v=vs.85).aspx and it looks like there are already constants related to tooltip background/foreground, COLOR_INFOBK and COLOR_INFOTEXT.

With only exception - the tooltip background color is light yellow(255, 255, 231), not white

#774 Updated by Constantin Asofiei over 9 years ago

Greg Shah wrote:

Code Review ca_upd20141220b.zip

This is really good. If I understand correctly, it has passed testing. I'm OK for you to check it in, if you are OK with it.

Replacement for ca_upd20141220b.zip - only change is SysColor is added a history entry.

Passed runtime/conversion testing, released to bzr rev 10685.

#775 Updated by Hynek Cihlar over 9 years ago

The attached file adds merge with trunk and removes the .classpath file. It has passed regression testing.

Please review.

Greg Shah wrote:

Code Review hc_upd20141218c.zip

The code looks good. The only note is that there is a .classpath included which probably should not be there.

#776 Updated by Greg Shah over 9 years ago

Code Review hc_upd20141221c.zip

I'm fine with the changes. Please check them in.

#777 Updated by Hynek Cihlar over 9 years ago

1221c committed to bzr revision 10687.

Greg Shah wrote:

Code Review hc_upd20141221c.zip

I'm fine with the changes. Please check them in.

#778 Updated by Eugenie Lyzenko over 9 years ago

This update for review includes resolution for previous notes including tooltip deregistration on demand and moving setting tooltip to the BaseEntity widget. I guess need more testing to verify but you can see the implementation details. The base idea is to move tooltip handlers from active actions map in MouseHandler class to the pending tooltip map. This way we can easily register these handlers again in respective conditions. For now deregistration in unconditional, meaning setting tooltip to empty will cause tooltip deregistration not depending on current value of the SESSION:TOOLTIPS attribute.

#779 Updated by Greg Shah over 9 years ago

Code Review evl_upd20141222a.zip

I'm fine with the changes. It looks good!

Please finish your manual testing. If no changes are needed, you can put it into regression testing.

#780 Updated by Eugenie Lyzenko over 9 years ago

Code Review evl_upd20141222a.zip

Please finish your manual testing. If no changes are needed, you can put it into regression testing.

I've made testing for registration/deregistration and for SESSION:TOOLTIPS overridding in directory. Everything works as expected.

So I'm starting the conversion and runtime regression testing.

#781 Updated by Eugenie Lyzenko over 9 years ago

The conversion testing for evl_upd20141222a.zip completed. The generated sources are identical.

Continue with runtime testing.

#782 Updated by Eugenie Lyzenko over 9 years ago

The runtime testing for evl_upd20141222a.zip has been completed. All including CTRL-C tests are OK.

The only exception is the test TC-INQUIRY-INVENTORY-015 failure. But this is the regression from previous updates. The test round without evl_upd20141222a.zip shows the same failure. Should I have to wait for the fix before committing my update?

#783 Updated by Greg Shah about 9 years ago

There is no need to wait for the fix. Please check in and distribute evl_upd20141222a.zip.

#784 Updated by Greg Shah about 9 years ago

Eugenie: on second thought, please hold off of checking in and distributing the evl_upd20141222a.zip. I have been working to get a very large set of updates through testing and it just passed. I need to get that checked in before you. You'll need to merge and re-test. Sorry about that. :( But these updates (that contains work from Eric and myself), are large and intrusive. I think merging them and retesting is more work than for your update, otherwise I would not make the request.

The attached updates have passed conversion and main runtime regression testing but are finishing CTRL-C testing now. Make sure the updates are applied in the order specified.

The ges_upd20141222a.zip also contains files modified by Eric, so this is very much a combined set of changes that must go together.

The MAJIC changes in #2471 are needed to match this set of updates, otherwise MAJIC will not convert and compile properly. There are a large number of changes to the generated MAJIC code, those changes have been reviewed and are OK. The changes are generally related to messageBox() (see below) or in the order in which the widget configuration occurs for widgets defined inline using the format phrase (e.g. DEFINE FRAME fr num AS INT.). The addWidget() calls now will also have the proper widget name as the 2nd parm, where it was blank previously.

Summary of changes:

1. Many new attributes/methods/options are added. Where attrs/methods are only used by a small number of widgets, I am creating new interfaces rather than add to CommonWidget. For things that are truly widespread, I am still using CommonWidget.

Attributes
MOVABLE
MODIFIED
SELECTED
INNER-CHARS
INNER-LINES
CURSOR-LINE
NUM-LINES
CURSOR-CHAR
CENTERED
SCROLLBAR-VERTICAL
SCROLLBAR-HORIZONTAL
LIST-ITEMS

Methods
DELETE-LINE
INSERT-STRING
READ-FILE
REPLACE-SELECTION-TEXT
ADD-LAST
DELETE

Options
V6FRAME
SCROLLBAR-VERTICAL
NO-UNDERLINE

In some of the above cases there was partial support, but I finished it. I also did cleanup and improvements to some other attrs/methods that already existed. Most of the runtime remains unimplemented, but conversion is complete.

2. Added missing signature variants to some of the runtime. The largest set of changes is for LogicalTerminal.messageBox() where there was missing support for using character for the title parameter. Previously only String could be used. MAJIC was updated to cast to String in all the related use cases.

3. Added FRAME-NAME function for conversion and runtime.

4. Inline format phrase variable definition was completely reworked. This was necessary to add PROMPT-FOR/SET/UPDATE support while still supporting the versions used in FORM, DEFINE FRAME and DISPLAY. These are quite tricky because they have an effect on frame scoping, screen buffer processing, frame generation, frame element processing, format string processing, variable definitions, variable initialization... you get the idea.

5. Fixed many javadoc errors.

6. In schema parsing, added UPDATE TABLE and UPDATE INDEX constructs (they are matched and dropped from the resulting tree). Also added some optional trailer support for bufpool.

7. Fixed many 4GL code parsing problems. Made some initial changes to handle the INPUT-VALUE attribute better. Improvements in
INPUT builtin func differentiation from INPUT mode in function call parameter parsing. Support for user-defined function implicit parameter quirk. An implicit prefer widgets mode must be enabled when lvalue is parsing an attribute/method referent. Added bufpool and buffer-pool schema keywords. Added write-json() method. Extended the menu-item embedded DOT quirk to more cases. Added top-only, three-d and color_spec undocumented browse options. COLON and TO in format phrases can now be decimal literals (not just integers).

8. We no longer remap buffer names which reference the temp-table buffer for a DEFINE PARAMETER TABLE FOR temp-table-name statement, only change the javaname annotation for the temp-table node within that statement itself, so the TemporaryBuffer.associate call references the parameter's name as its first argument.

9. Added partial support for DBVERSION built-in function.

10. Added some new metadata support and reworked how metadata conversion occurs.

11. Refactored DatabaseManager.mapComputedCharacterColumns(), extracting a worker method which also is called from registerDynamicTable().

12. Other minor conversion/runtime changes to allow compilation for a wider range of 4GL constructs.

#785 Updated by Greg Shah about 9 years ago

The changes passed regression testing. They are checked in as follows:

  1. ges_upd20141222a.zip - bzr rev 10688
  2. ecf_upd20141217a.zip - bzr rev 10689
  3. ecf_upd20141218b.zip - bzr rev 10690
  4. ecf_upd20141222a.zip - bzr rev 10191

#786 Updated by Eugenie Lyzenko about 9 years ago

Eugenie: on second thought, please hold off of checking in and distributing the evl_upd20141222a.zip. I have been working to get a very large set of updates through testing and it just passed. I need to get that checked in before you. You'll need to merge and re-test. Sorry about that. :( But these updates (that contains work from Eric and myself), are large and intrusive. I think merging them and retesting is more work than for your update, otherwise I would not make the request.

The merged update is attached. I'm starting the regression tests.

#787 Updated by Greg Shah about 9 years ago

Code Review evl_upd20150103a.zip

The merge looks good. If it passes testing, please check it in.

#788 Updated by Eugenie Lyzenko about 9 years ago

Greg Shah wrote:

Code Review evl_upd20150103a.zip

The merge looks good. If it passes testing, please check it in.

Conversion testing completed. The generated code are identical. Starting the runtime testing.

#789 Updated by Greg Shah about 9 years ago

Summary of remaining work on image, icons, button and tooltip support:

Icons

1. I couldn't get the customer icons to load using simple testcases. It didn't matter which icon files I tried or what I set the propath to. I am worried that the support is not complete or has some bugs.

2. Window.loadSmallIcon() runtime support.

3. By default, the Window should display the Golden Code icon. Right now, it only shows that icon as a fall-back when the converted code tries to load other icons and fails.

Button

1. Sometimes button seems to lose track of mouse events. Perhaps it has something to do with dragging and then releasing the mouse outside of the button, but I'm not sure. When this occurs, the mouse will stay pressed and will not release even though the mouse button is no longer being held down. You have to click and release the mouse on the button again to get it to fix itself.

2. Image handling for buttons, via the methods:

LOAD-MAGE-UP
LOAD-IMAGE-DOWN
LOAD-IMAGE-INSENSITIVE

Reproduce native 4GL behavior for loading/using images in buttons. Including dynamic loading.

Image

Full Image phrase support for DEFINE BUTTON and DEFINE IMAGE widgets:
size-phrase({SIZE | SIZE-CHARS | SIZE-PIXELS} width BY height)
CONVERT-3D-COLORS
STRETCH-TO-FIT
RETAIN-SHAPE
TRANSPARENT

Tooltips

Implement this feature to every widget that needs. Verify and test there will be no artifacts from tooltip implementation.

#790 Updated by Eugenie Lyzenko about 9 years ago

Greg,

1. I couldn't get the customer icons to load using simple testcases. It didn't matter which icon files I tried or what I set the propath to. I am worried that the support is not complete or has some bugs.

Do you use this to load icon?:

...
current-window:load-icon("customer_4bpp.ico").
...

Or some other way? Please give me the example. Because I've just tested code above and it works.

#791 Updated by Greg Shah about 9 years ago

I was trying like this:

def var hwin as handle.
create window hwin
   assign width-chars  = 40
          height-chars = 20
          row          = 10
          column       = 50.

hwin:load-icon("customer_4bpp.ico").          
hwin:visible = true.

I also tried many variations that had differing relative paths ("./customer_4bpp.ico", "./icons/customer_4bpp.ico", "icons/customer_4bpp.ico"...) and I tried both icon files ("customer_16x16x4bpp.ico" too).

I didn't try it directly with CURRENT-WINDOW. Please see if the above handle-based hwin code works for you.

#792 Updated by Eugenie Lyzenko about 9 years ago

I didn't try it directly with CURRENT-WINDOW. Please see if the above handle-based hwin code works for you.

The code that works:

...
def var hwin as handle.
hwin = current-window:handle.

hwin:load-icon("customer_4bpp.ico").          
hwin:visible = true.
...

The dynamic window created code fails with exception:

...
java.lang.RuntimeException: No renderer is registered for id = 4
        at com.goldencode.p2j.ui.client.gui.driver.swing.SwingGuiPrimitives.getSimulator(SwingGuiPrimitives.java:945)
        at com.goldencode.p2j.ui.client.gui.driver.swing.SwingGuiPrimitives.selectWindow(SwingGuiPrimitives.java:109)
        at com.goldencode.p2j.ui.client.gui.driver.swing.SwingGuiDriver.selectWindow(SwingGuiDriver.java:533)
        at com.goldencode.p2j.ui.client.gui.driver.swing.SwingGuiDriver.enableEvents(SwingGuiDriver.java:1417)
        at com.goldencode.p2j.ui.client.gui.driver.GuiOutputManager.enableOSEvents(GuiOutputManager.java:237)
        at com.goldencode.p2j.ui.chui.ThinClient.getChanges(ThinClient.java:10817)
        at com.goldencode.p2j.net.Protocol.attachChanges(Protocol.java:274)
        at com.goldencode.p2j.net.Queue.enqueueOutbound(Queue.java:810)
        at com.goldencode.p2j.net.Dispatcher.processInbound(Dispatcher.java:765)
        at com.goldencode.p2j.net.Conversation.block(Conversation.java:319)
        at com.goldencode.p2j.net.Conversation.waitMessage(Conversation.java:257)
        at com.goldencode.p2j.net.Queue.transactImpl(Queue.java:1128)
        at com.goldencode.p2j.net.Queue.transact(Queue.java:585)
        at com.goldencode.p2j.net.BaseSession.transact(BaseSession.java:223)
        at com.goldencode.p2j.net.HighLevelObject.transact(HighLevelObject.java:163)
        at com.goldencode.p2j.net.RemoteObject$RemoteAccess.invokeCore(RemoteObject.java:1423)
        at com.goldencode.p2j.net.InvocationStub.invoke(InvocationStub.java:97)
        at com.sun.proxy.$Proxy4.standardEntry(Unknown Source)
        at com.goldencode.p2j.main.ClientCore.start(ClientCore.java:286)
        at com.goldencode.p2j.main.ClientCore.start(ClientCore.java:95)
        at com.goldencode.p2j.main.ClientDriver.start(ClientDriver.java:227)
        at com.goldencode.p2j.main.CommonDriver.process(CommonDriver.java:423)
        at com.goldencode.p2j.main.ClientDriver.process(ClientDriver.java:112)
        at com.goldencode.p2j.main.ClientDriver.main(ClientDriver.java:290)
...

May be this means something is wrong with create window statement conversion? Looks like the created window is not become active(or default) - it does not get the output driver to be drawn. Is it supposed the new dynamic window be shown in separate window in addition to the default one(I mean we should see two 4GL windows in this case)?

#793 Updated by Greg Shah about 9 years ago

Is it supposed the new dynamic window be shown in separate window in addition to the default one(I mean we should see two 4GL windows in this case)?

Yes, this would be the behavior I think.

Please fix this case.

#794 Updated by Eugenie Lyzenko about 9 years ago

The runtime testing for evl_upd20150103a.zip completed including CTRL-C. No regressions except knowing TC-INQUIRY-INVENTORY-015. CTRL-C 3 way tests have to be executed in separate session to get passed. Results - 10691_65fcb0a_20150105_evl.zip.

Preparing to check in and distribute.

#795 Updated by Eugenie Lyzenko about 9 years ago

The evl_upd20150103a.zip has been committed in bzr as 10693.

#796 Updated by Hynek Cihlar about 9 years ago

The attached update resolves the runtime regression introduced by hc_upd20141221c. The problem was in unwanted change of frame col/row values from BaseConfig.INV_COORD to 0 which was wrongly interpreted as the frame being placed.

The change has passed regression testing. Please review.

#797 Updated by Greg Shah about 9 years ago

Code Review hc_upd20150103a.zip

The change is fine. Please check it in.

#798 Updated by Hynek Cihlar about 9 years ago

Committed to bzr revision 10694.

Greg Shah wrote:

Code Review hc_upd20150103a.zip

The change is fine. Please check it in.

#799 Updated by Constantin Asofiei about 9 years ago

First pass at the SIDE-LABEL-HANDLE attribute. This can be used with these widgets: COMBO-BOX, EDITOR, FILL-IN, RADIO-SET, SELECTION-LIST, SLIDER and TEXT. The returned resource is a LITERAL widget (as this is how is reported by 4GL). On client-side this is a Label instance.

Tests are in testcases/uast/label. I'm putting it through runtime testing and see how it behaves.

The ROW/COLUMN attributes rely on some more generic changes (related to bi-directional sync'ing of these attributes).

#800 Updated by Greg Shah about 9 years ago

Code Review ca_upd20150105c.zip

The update looks quite good.

The only thing I would suggest is to move processSideLabel() from ScreenBuffer to ThinClient. This removes client-specific logic from a generic class and leaves it placed on the client-side only. The code needs no special access to the internals of ScreenBuffer, so it should move easily.

#801 Updated by Eugenie Lyzenko about 9 years ago

The update for review contains LOAD-MAGE-UP, LOAD-IMAGE-DOWN, LOAD-IMAGE-INSENSITIVE implementation for conversion and runtime. Including dynamic loading and preloading images with DEFINE BUTTON statement.

Also small fix for javadoc bug in MouseHandler.java.

#802 Updated by Greg Shah about 9 years ago

Code Review

This is good. Some minor things:

1. Please move the methods_attributes.rules changes into the load_descriptors function. All new methods and attributes that are not for system handles should be placed there.

2. Please restore the 3 javadoc params that were deleted from ButtonGuiImpl.drawButtonImages().

3. All the ButtonWidget.loadImage*(character) methods are silently returning when you pass unknown value as the parameter. Is that how the 4GL does it?

Make the above changes, upload the result and go ahead with regression testing.

#803 Updated by Eugenie Lyzenko about 9 years ago

Greg Shah wrote:

Code Review

This is good. Some minor things:

1. Please move the methods_attributes.rules changes into the load_descriptors function. All new methods and attributes that are not for system handles should be placed there.

The change to:

...
         <rule>list.put(prog.kw_load_i_u, execLib("cr_descr", "Widget"                     , null                    , "loadImageUp"            , true       ))</rule>
...

causes exception:

...
EXPRESSION EXECUTION ERROR:
---------------------------
throwException(errmsg)
^  { Unsupported method or attribute KW_LOAD_I_U. [COLON id <6743098654996> 31:8] }
---------------------------
Elapsed job time:  00:00:01.273
ERROR:
java.lang.RuntimeException: ERROR!  Active Rule:
-----------------------
      RULE REPORT      
-----------------------
Rule Type :   DESCENT
Source AST:  [ : ] BLOCK/STATEMENT/KW_ON/TRIGGER_BLOCK/BLOCK/ASSIGNMENT/COLON/ @31:8 {6743098654996}
Copy AST  :  [ : ] BLOCK/STATEMENT/KW_ON/TRIGGER_BLOCK/BLOCK/ASSIGNMENT/COLON/ @31:8 {6743098654996}
Condition :  throwException(errmsg)
Loop      :  false
--- END RULE REPORT ---

    at com.goldencode.p2j.pattern.PatternEngine.run(PatternEngine.java:1004)
    at com.goldencode.p2j.convert.ConversionDriver.processTrees(ConversionDriver.java:922)
    at com.goldencode.p2j.convert.ConversionDriver.back(ConversionDriver.java:826)
...

What I have missed here?

#804 Updated by Greg Shah about 9 years ago

This:

         <rule>list.put(prog.kw_load_i_u, execLib("cr_descr", "Widget"                     , null                    , "loadImageUp"            , true       ))</rule>

should be this:

         <rule>list.put(prog.kw_load_i_u, execLib("cr_descr", "Widget"                     , "loadImageUp"           , null                  , true       ))</rule>

The method name should be in the getter column, not the setter column. For methods, setter should be null because you cannot assign a method (so it is never used).

#805 Updated by Eugenie Lyzenko about 9 years ago

3. All the ButtonWidget.loadImage*(character) methods are silently returning when you pass unknown value as the parameter. Is that how the 4GL does it?

Yes. The attached file has the changes for the notes to put into regression tests.

#806 Updated by Greg Shah about 9 years ago

Code Review evl_upd20150106b.zip

load-small-icon() is missing from the newer methods_attributes.rules.

#807 Updated by Eugenie Lyzenko about 9 years ago

Greg Shah wrote:

Code Review evl_upd20150106b.zip

load-small-icon() is missing from the newer methods_attributes.rules.

Fixed with update attached.

#808 Updated by Greg Shah about 9 years ago

Code Review evl_upd20150106c.zip

Everything looks good. Please go ahead with testing.

#809 Updated by Eugenie Lyzenko about 9 years ago

The new file for regression testing. There was missing enclosing quote (") in methods_attributes.rules file. This caused conversion exception.

Restarting conversion testing.

#810 Updated by Greg Shah about 9 years ago

Code Review evl_upd20150107a.zip

It looks fine.

#811 Updated by Eugenie Lyzenko about 9 years ago

The conversion testing completed. Generated code files are identical. Starting the runtime regression tests.

#812 Updated by Constantin Asofiei about 9 years ago

This is replacement for ca_upd20150105c.zip , adds SIDE-LABEL-HANDLE support. The positioning via ROW/COLUMN attributes is not yet complete.

It has passed runtime testing.

#813 Updated by Greg Shah about 9 years ago

Code Review ca_upd20150108a.zip

I'm fine with the code. Please check it in.

#814 Updated by Constantin Asofiei about 9 years ago

Greg Shah wrote:

Code Review ca_upd20150108a.zip

I'm fine with the code. Please check it in.

Committed to bzr rev 10697.

#815 Updated by Hynek Cihlar about 9 years ago

In ref to #2424.

The attached change set resolves widget positioning in a frame and passed regression testing. Please review.

#816 Updated by Greg Shah about 9 years ago

Code Review hc_upd20150112a.zip

It looks good. Please check it in.

#817 Updated by Hynek Cihlar about 9 years ago

Committed to bzr revision 10704.

Greg Shah wrote:

Code Review hc_upd20150112a.zip

It looks good. Please check it in.

#818 Updated by Constantin Asofiei about 9 years ago

Second part of the SIDE-LABEL-HANDLE support, to allow changing the ROW/COLUMN attributes from the server-side. Runtime testing is in progress.

The remaining issue is related to moving widgets in a down frame; root cause: server-side has only 1 widget which is associated with the entire frame body.

Hynek: please check some of your hand-written tests.

#819 Updated by Hynek Cihlar about 9 years ago

The label moves ok and the position attributes are properly reported back to the server.

Btw. there are some (chui) layout differences from 4GL:
- Assigning row/col attributes of a widget moves also the label vs. 4GL moves only the widget.
- Moving one widget affects positions of other widgets in the same frame (in general the layout results in some cases are different from 4GL, this is not related to the side-label changes).
- The reported initial widget positions are wrong in P2J (this is something I want to address).

See uast/label/label5.p.

Also:
[javadoc] /home/hc/gcd/p2j_repo/p2j/src/com/goldencode/p2j/ui/WidgetId.java:126: warning - Tag @link: can't find downIdx in com.goldencode.p2j.ui.WidgetId
[javadoc] /home/hc/gcd/p2j_repo/p2j/src/com/goldencode/p2j/ui/client/Label.java:409: warning - @param argument "frame" is not a parameter name.

Constantin Asofiei wrote:

Hynek: please check some of your hand-written tests.

#820 Updated by Greg Shah about 9 years ago

Code Review ca_upd20150114b.zip

It looks like there were some tricky latent bugs that you had to solve here. I see an == vs equals() issue and several places where the "next" ID was being repeatedly created when it should have been reused.

1. In ThinClient.setLocation(), please put a comment explaining why the resolveWidgetId() call is needed. I guess it is to convert the server-side id into a possible down iteration id which can be different.

2. Please put a comment in ComboBox.setLabelInstance(), LabeledBorderedPanel.setLabelInstance() and LabeledDataContainer.setLabelInstance() to that label.linkTo(this.label, ... must be called before the this.label = label;. Unless one looks at the linkTo() implementation it is not obvious why the linkage is apparently occurring to the old label reference.

3. There is minor cleanup needed in the header entry of WidgetId.

#821 Updated by Greg Shah about 9 years ago

The remaining issue is related to moving widgets in a down frame; root cause: server-side has only 1 widget which is associated with the entire frame body.

Do you anticipate it taking much time? You already seem to have most of the down iteration mapping in place.

#822 Updated by Hynek Cihlar about 9 years ago

Constantin Asofiei wrote:

Second part of the SIDE-LABEL-HANDLE support, to allow changing the ROW/COLUMN attributes from the server-side. Runtime testing is in progress.

Constantin one more point. I have removed WidgetItem and instead of saving/restoring the widget positions during layout, the position from config is taken as the base for the layout logic. I will base my changes on yours.

#823 Updated by Hynek Cihlar about 9 years ago

Greg Shah wrote:

Code Review ca_upd20150114b.zip

It looks like there were some tricky latent bugs that you had to solve here. I see an == vs equals() issue and several places where the "next" ID was being repeatedly created when it should have been reused.

This was correct, previously the id was declared as int in the method signature ;-).

#824 Updated by Constantin Asofiei about 9 years ago

Hynek Cihlar wrote:

Constantin Asofiei wrote:

Second part of the SIDE-LABEL-HANDLE support, to allow changing the ROW/COLUMN attributes from the server-side. Runtime testing is in progress.

Constantin one more point. I have removed WidgetItem and instead of saving/restoring the widget positions during layout, the position from config is taken as the base for the layout logic. I will base my changes on yours.

Hynek, does the logic in the ca_upd20150114b.zip update still make sense, once you remove the WidgetItem dependencies?

#825 Updated by Hynek Cihlar about 9 years ago

Constantin Asofiei wrote:

Hynek Cihlar wrote:

Constantin Asofiei wrote:

Second part of the SIDE-LABEL-HANDLE support, to allow changing the ROW/COLUMN attributes from the server-side. Runtime testing is in progress.

Constantin one more point. I have removed WidgetItem and instead of saving/restoring the widget positions during layout, the position from config is taken as the base for the layout logic. I will base my changes on yours.

Hynek, does the logic in the ca_upd20150114b.zip update still make sense, once you remove the WidgetItem dependencies?

I think most of it does. It should be quite straightforward to adapt.

#826 Updated by Constantin Asofiei about 9 years ago

Hynek, I'm planning on looking into solving these problems (based on my previous update):
  • Assigning row/col attributes of a widget moves also the label vs. 4GL moves only the widget (easy fix, WidgetItem needs to track widget Ids, not widget instances)
  • Moving one widget affects positions of other widgets in the same frame (in general the layout results in some cases are different from 4GL, this is not related to the side-label changes). I didn't start it yet; I think layout needs to be avoided in some cases - let me know if you want to look into it
  • moving widgets in a down frame; not sure yet, might be related to the layout issue.

#827 Updated by Hynek Cihlar about 9 years ago

Constantin Asofiei wrote:

Hynek, I'm planning on looking into solving these problems (based on my previous update):
  • Assigning row/col attributes of a widget moves also the label vs. 4GL moves only the widget (easy fix, WidgetItem needs to track widget Ids, not widget instances)

Please send me your update when this is fixed.

  • Moving one widget affects positions of other widgets in the same frame (in general the layout results in some cases are different from 4GL, this is not related to the side-label changes). I didn't start it yet; I think layout needs to be avoided in some cases - let me know if you want to look into it

Yes I can look into it when I am already digging inside.

#828 Updated by Constantin Asofiei about 9 years ago

This is replacement for ca_upd20150114b.zip and passed runtime testing. The Assigning row/col attributes of a widget moves also the label vs. 4GL moves only the widget is not fixed - the initial solution regressed other cases, looking into an alternative.

#829 Updated by Greg Shah about 9 years ago

Code Review ca_upd20150115a.zip

It's good. Please check it in.

#830 Updated by Constantin Asofiei about 9 years ago

Greg Shah wrote:

Code Review ca_upd20150115a.zip

It's good. Please check it in.

Released to rev 10708.

#831 Updated by Constantin Asofiei about 9 years ago

Greg,

  • moving widgets in a down frame; not sure yet, might be related to the layout issue.

This is related to the fact that in a down frame, the widget coordinates are relative to their parent FIELD-GROUP widget. Currently, we parent all frame's down body widgets to the ScrollContainer. As I recall, dynamic frames can not have a down body, thus (although is worth a check) I think it is highly unlikely someone would mess up the down body in real life applications. If down frame widgets are not moved by changing their ROW/COLUMN attribute, then I think we should leave this as is for now.

#832 Updated by Greg Shah about 9 years ago

  • vendor_id deleted (GCD)

If down frame widgets are not moved by changing their ROW/COLUMN attribute, then I think we should leave this as is for now.

I agree. The instances I have found so far are definitely non-DOWN frames, but I haven't checked them all.

1. Can you add an UnimplementedFeature.missing("Moving DOWN frame widgets is not implemented.") but only emit this in the case where the move is detected on a down frame? That way we won't fill up the logs with bogus entries.

2. Add a new redmine task for that work and link it to both this task and to #2162.

#833 Updated by Constantin Asofiei about 9 years ago

Greg Shah wrote:

If down frame widgets are not moved by changing their ROW/COLUMN attribute, then I think we should leave this as is for now.

I agree. The instances I have found so far are definitely non-DOWN frames, but I haven't checked them all.

1. Can you add an UnimplementedFeature.missing("Moving DOWN frame widgets is not implemented.") but only emit this in the case where the move is detected on a down frame? That way we won't fill up the logs with bogus entries.

Done

2. Add a new redmine task for that work and link it to both this task and to #2162.

Done - see #2490

Attached update should fully separate the movement of a widget and its side-label. Hynek, please check your tests, too.

Runtime testing is in progress.

Note: the WidgetDownId.equals can't be safely used to identify widgets in a down frame. This is because of the one-to-many relation between a server-side widget and its client-side counterparts, for down frames. When automatic configuration synchronization was added, the server-side needed to receive only the widget configurations for the first iteration in a down frame (as this is the only ID which exists on the server-side).

#834 Updated by Greg Shah about 9 years ago

  • vendor_id set to GCD

Code Review ca_upd20150115b.zip

I'm fine with the changes.

#835 Updated by Hynek Cihlar about 9 years ago

Constantin Asofiei wrote:

Hynek, please check your tests, too.

Yes, works ok.

#836 Updated by Constantin Asofiei about 9 years ago

Greg Shah wrote:

Code Review ca_upd20150115b.zip

I'm fine with the changes.

0115b.zip passed runtime testing.

#837 Updated by Constantin Asofiei about 9 years ago

Constantin Asofiei wrote:

Greg Shah wrote:

Code Review ca_upd20150115b.zip

I'm fine with the changes.

0115b.zip passed runtime testing.

Released to rev 10712.

#838 Updated by Constantin Asofiei about 9 years ago

Fix for side-label in shared frames. Built on top of #2495 ca_upd20150122c.zip

#839 Updated by Greg Shah about 9 years ago

Code Review ca_upd20150123a.zip

The changes look good. The result is cleaner too from a design perspective, so it is a good improvement in general. Please get it tested.

#840 Updated by Hynek Cihlar about 9 years ago

The attached update adds support for moving frame widgets by setting col/row/x/y attributes from application code. This also resolves other layout issues. Regression test is in progress.

Please review.

Constantin, this also touches some of your side-label changes, please have a look too. Also note that there is an NPE in ThinClient.processSideLabel when running the POC code (lbl being null).

#841 Updated by Constantin Asofiei about 9 years ago

Replacement for ca_upd20150123a.zip, side-labels in shared frames.

Passed runtime testing, released to rev 10725.

#842 Updated by Constantin Asofiei about 9 years ago

Hynek Cihlar wrote:

Constantin, this also touches some of your side-label changes, please have a look too. Also note that there is an NPE in ThinClient.processSideLabel when running the POC code (lbl being null).

Please merge with 10725 and re-check your NPE case. If is still there, send me an email with the scenario.

#843 Updated by Hynek Cihlar about 9 years ago

Constantin Asofiei wrote:

Hynek Cihlar wrote:

Constantin, this also touches some of your side-label changes, please have a look too. Also note that there is an NPE in ThinClient.processSideLabel when running the POC code (lbl being null).

Please merge with 10725 and re-check your NPE case. If is still there, send me an email with the scenario.

An update, the NPE is caused by my changes. I have changed the side-label management slightly. Is the call to buffer.putScreenValue in TC.processSideLabel required? In what case?

#844 Updated by Constantin Asofiei about 9 years ago

Hynek Cihlar wrote:

Constantin Asofiei wrote:

Hynek Cihlar wrote:

Constantin, this also touches some of your side-label changes, please have a look too. Also note that there is an NPE in ThinClient.processSideLabel when running the POC code (lbl being null).

Please merge with 10725 and re-check your NPE case. If is still there, send me an email with the scenario.

An update, the NPE is caused by my changes. I have changed the side-label management slightly. Is the call to buffer.putScreenValue in TC.processSideLabel required? In what case?

The idea was to ensure the screen buffer is sync'ed bi-directionally, but on a second thought, the side-label can't be changed by client-side.

Even if you remove processSideLabel, the NPE should not happen, so I suspect there is some other cause. Please send me a re-create and the merged update.

#845 Updated by Hynek Cihlar about 9 years ago

Constantin Asofiei wrote:

Hynek Cihlar wrote:

Constantin Asofiei wrote:

Hynek Cihlar wrote:

Constantin, this also touches some of your side-label changes, please have a look too. Also note that there is an NPE in ThinClient.processSideLabel when running the POC code (lbl being null).

Please merge with 10725 and re-check your NPE case. If is still there, send me an email with the scenario.

An update, the NPE is caused by my changes. I have changed the side-label management slightly. Is the call to buffer.putScreenValue in TC.processSideLabel required? In what case?

The idea was to ensure the screen buffer is sync'ed bi-directionally, but on a second thought, the side-label can't be changed by client-side.

Even if you remove processSideLabel, the NPE should not happen, so I suspect there is some other cause. Please send me a re-create and the merged update.

Yes, when the processSideLabel is removed, the NPE does not happen. The merged changes are attached (still with the original processSideLabel though).

I have experienced this during key input in some login forms.

The fix should be obvious, I'll remove the processSideLabel method.

#846 Updated by Constantin Asofiei about 9 years ago

Hynek Cihlar wrote:

An update, the NPE is caused by my changes. I have changed the side-label management slightly. Is the call to buffer.putScreenValue in TC.processSideLabel required? In what case?

OK, I think the problem is in this code in Label.linkTo:

  public void linkTo(Label<O> oldLbl, int frameId, int serverSideId)
   {
      if (serverSideId == -1 || oldLbl == null)
      {
         return;
      }

If oldLbl is null, you are exiting too early. The code which registers the widget label and its config instances is no longer executed:
         ClientConfigManager mgr = ConfigManager.getInstance();

         // switch the internal ID for this label (from virtual to real)
         mgr.switchId(oldId, newId);

         // mark as dirty all configs which are not the same as what the server has...
         mgr.trackAllChanges(lblCfg);

         OutputManager.instance().getRegistry().addWidget((Widget) this);

After re-enabling this code for the case oldLbl is null, the NPE is no longer there.

#847 Updated by Hynek Cihlar about 9 years ago

Constantin Asofiei wrote:

After re-enabling this code for the case oldLbl is null, the NPE is no longer there.

Yes, this is it. I forgot to remove the check with other changes I removed. Thanks for finding it.

#848 Updated by Greg Shah about 9 years ago

Code Review hc_upd20150129b.zip

My review of ZCL is not very very deep. But overall, I'm fine with the update. One minor thing is that the WidgetBrowser needs a history entry and copyright date update.

#849 Updated by Hynek Cihlar about 9 years ago

Greg Shah wrote:

Code Review hc_upd20150129b.zip

My review of ZCL is not very very deep. But overall, I'm fine with the update. One minor thing is that the WidgetBrowser needs a history entry and copyright date update.

Thanks for catching the WidgetBrowser. I didn't plan to release it yet.

The 0129b passed Ctrl+C and failed Main part but not due to layout issue. I will merge with trunk, remove widget browser changes and restart testing.

#850 Updated by Hynek Cihlar about 9 years ago

The attached update is a preview of business logic cleanup from config classes. There are some missing pieces - especially documentation and incomplete server-side config management for Browse*Widget. Other than that, the changes are stable for the preview.

The idea is to remove the WidgetConfig.syncWithWidget method and any related business logic. Instead the widget itself is notified when the config is updated. This happens (1) when client is pushed config changes from server, (2) when server receives changes from client, (3) when config is "replaced" (ConfigManager.replaceConfig), (4) ad-hoc with the help of ConfigManager.notifyConfigUpdate.

When a widget is notified that its config may have changed, it performs all necessary actions to make itself in sync. In the notification call, the widget also receives the previous state of the config which allows to omit any heavy-weight sync operations when not needed (the subjected values did not change).

Otherwise the changes should be self-explanatory.

Constantin and anybody else, please review and comment.

#851 Updated by Constantin Asofiei about 9 years ago

Hynek, about your 0318a.zip changes: can you think of a way to get rid of the setters/getters from the WidgetConfig hierarchy? These would be the only thing remaining to cleaning up these classes for good. Otherwise, the changes look good to me.

#852 Updated by Constantin Asofiei about 9 years ago

Greg, this is for the TEXT/FILL-IN drawing in GUI (#2451): it fixes the widget height/width and also adds a first pass at the LABEL in GUI (side-label actually).

#853 Updated by Greg Shah about 9 years ago

Code Review ca_upd20150323b.zip

1. Does your frame_scoping.rules change cause a frame's scope to expand or otherwise change the block with which it is associated? My understanding is that FORM statements should not do that while DEFINE FRAME should.

2. Am I correct that ControlTextWidget.setAtFormatLength() doesn't need to push screen definition because it is only used during frame definition instantiation? If so, perhaps a comment should be added there to make it clear.

3. The pixelWidth calculation in FillInGuiImpl.nativeWidth() has a surprising calculation for the !fixedFontFormat && !explicit && fmtWidth >= 1 && fmtWidth <= 12 case. This seems very specific. Can you provide some more detail for me to understand where it comes from?

#854 Updated by Hynek Cihlar about 9 years ago

Constantin Asofiei wrote:

Hynek, about your 0318a.zip changes: can you think of a way to get rid of the setters/getters from the WidgetConfig hierarchy?

I left those setters/getters which implement elementary logic of the underlying type. For example rounding of the positional double values. If this is removed, to a helper class for example, the responsibility to execute this elementary logic will be left on the poor developer.

#855 Updated by Hynek Cihlar about 9 years ago

Constantin, here is an update to 0318a.zip. I have added the config processing to server-side widgets as well. For this I had to unify the config related API for both the client-side and server-side class hierarchies, plus related changes.

See the new classes WithConfig and WidgetWithConfig.

The update also contains all javadocs and standard file header entries. This is a feature-freeze update, although please note that I haven't worked in your comments regarding the elementary config setters.

Regression test is in progress, please review.

#856 Updated by Hynek Cihlar about 9 years ago

Btw., what was the motivation behind the BaseConfig dynamic getters/setters? Were these introduced only to provide a "convenience" mechanism to access the config fields in an abstract way?

I think the extra work of casting the config instances to the expected types has the extra benefits of type safety and coverage of refactoring tools.

#857 Updated by Constantin Asofiei about 9 years ago

Greg Shah wrote:

Code Review ca_upd20150323b.zip

1. Does your frame_scoping.rules change cause a frame's scope to expand or otherwise change the block with which it is associated? My understanding is that FORM statements should not do that while DEFINE FRAME should.

Yes, FORM needs to let the frame's scope expand. See this example where the frame is scoped to the REPEAT:

a.p                                   03/24/2015 13:53:23   PROGRESS(R) Page 1

{} Line Blk
-- ---- ---
      1     def var i as int.
      2
      3   1 repeat :
      4   1     display i with frame f1.
      4     end.
 a.p                                   03/24/2015 13:53:23   PROGRESS(R) Page 2

     File Name       Line Blk. Type   Tran            Blk. Label
-------------------- ---- ----------- ---- --------------------------------
a.p                     0 Procedure   No
a.p                     3 Repeat      No
    Frames:  f1

If a FORM stmt is added in the root procedure block, then the frame's scope is expanded:
a.p                                   03/24/2015 13:54:24   PROGRESS(R) Page 1

{} Line Blk
-- ---- ---
      1     def var i as int.
      2     form i with frame f1.
      3
      4   1 repeat :
      5   1     display i with frame f1.
      5     end.
 a.p                                   03/24/2015 13:54:24   PROGRESS(R) Page 2

     File Name       Line Blk. Type   Tran            Blk. Label
-------------------- ---- ----------- ---- --------------------------------
a.p                     0 Procedure   No
    Frames:  f1

a.p                     4 Repeat      No

2. Am I correct that ControlTextWidget.setAtFormatLength() doesn't need to push screen definition because it is only used during frame definition instantiation? If so, perhaps a comment should be added there to make it clear.

Will add it.

3. The pixelWidth calculation in FillInGuiImpl.nativeWidth() has a surprising calculation for the !fixedFontFormat && !explicit && fmtWidth >= 1 && fmtWidth <= 12 case. This seems very specific. Can you provide some more detail for me to understand where it comes from?

Yes, I know is very specific. This was the hard part to determine how the width is computed. I have a program in testcases/uast/fillin/CheckMetricsFillin.java which goes through the collected 4GL metrics and checks if the formula provides the same metrics. The key part is this: if no explicit font is provided (the FONT clause is missing), the format length is between 1 and 12 chars and if this is not a widget which expects a fixed font, then this special formula is used. Can't explain why they chose this, it may be either 4GL or windows specific.

#858 Updated by Constantin Asofiei about 9 years ago

Hynek Cihlar wrote:

Constantin Asofiei wrote:

Hynek, about your 0318a.zip changes: can you think of a way to get rid of the setters/getters from the WidgetConfig hierarchy?

I left those setters/getters which implement elementary logic of the underlying type. For example rounding of the positional double values. If this is removed, to a helper class for example, the responsibility to execute this elementary logic will be left on the poor developer.

If this is just rounding and there is no code which is specific only to either server or client-side and is executed always, then why not do it via an aspectj rule?

#859 Updated by Greg Shah about 9 years ago

Yes, FORM needs to let the frame's scope expand. See this example where the frame is scoped to the REPEAT:

Does this change the scoping location in many places in MAJIC?

I wonder how we missed this originally. It seems a little too straightforward for us to have gotten this wrong.

Yes, I know is very specific. This was the hard part to determine how the width is computed. I have a program in testcases/uast/fillin/CheckMetricsFillin.java which goes through the collected 4GL metrics and checks if the formula provides the same metrics. The key part is this: if no explicit font is provided (the FONT clause is missing), the format length is between 1 and 12 chars and if this is not a widget which expects a fixed font, then this special formula is used. Can't explain why they chose this, it may be either 4GL or windows specific.

OK, it is best to put some comments into this code to explain where this comes from and how it was found.

#860 Updated by Hynek Cihlar about 9 years ago

Constantin Asofiei wrote:

Hynek Cihlar wrote:

Constantin Asofiei wrote:

If this is just rounding and there is no code which is specific only to either server or client-side and is executed always, then why not do it via an aspectj rule?

Yes, this would certainly work. But for the price of making the code less readable. I wouldn't mind myself to keep this kind of logic in the config classes as this doesn't pose any unwanted dependencies. But if you want to have the config classes unconditionally pure, then there is, I am afraid, no other choice.

#861 Updated by Constantin Asofiei about 9 years ago

This is replacement of 0323b.zip - it has passed conversion and runtime testing.

Does this change the scoping location in many places in MAJIC?

The frame scoping in MAJIC is not changed. The only changes related to frame definitions are cases where the frame definition (the instance field which defines it in the Java class) is in another location, but remains in the correct section - defined as an instance field for the java class.

OK, it is best to put some comments into this code to explain where this comes from and how it was found.

Done.

#862 Updated by Greg Shah about 9 years ago

Code Review ca_upd20150324a.zip

I good with it. Please check it in.

#863 Updated by Constantin Asofiei about 9 years ago

Greg Shah wrote:

Code Review ca_upd20150324a.zip

I good with it. Please check it in.

Committed revision 10821.

#864 Updated by Constantin Asofiei about 9 years ago

Hynek, about your 0323a.zip: you have some ambiguities with the config() method, one defined at Widget and the other at WithConfig - maybe the Widget.config() and AbstractWidget.config() need to be removed?

Widget:
   public <W extends WidgetConfig> W config();
WithConfig:
   T config();

Hynek Cihlar wrote:

Constantin Asofiei wrote:

If this is just rounding and there is no code which is specific only to either server or client-side and is executed always, then why not do it via an aspectj rule?

Yes, this would certainly work. But for the price of making the code less readable. I wouldn't mind myself to keep this kind of logic in the config classes as this doesn't pose any unwanted dependencies. But if you want to have the config classes unconditionally pure, then there is, I am afraid, no other choice.

The setRow/Column/WidthChars/HeightChars can be removed and the logic replaced with a AspectJ rule: no class overrides these and the scale needs to be ensured when they are set, always. This way future errors will be limited, as there will be only one way to set the row/column/widthChars/heightChars fields: direct field access, with AspectJ doing the work behind the scenes.

The other set/getColon and set/getTo are not for real fields, so these can remain.

The setModified can remain too.

#865 Updated by Constantin Asofiei almost 9 years ago

Greg, this is for the GUI label and widget/frame layout. The only issue which bugs me are some edge cases when COLON is used (when the computed length in character units of the label + the colon char is less than our internal 0-based COLON value, so colon-colonDelta gives a negative result). I think comparing our internal 0-based colon value with label lengths (in character units) is not fully correct.

Runtime testing is in progress.

Hynek: please point me to your tests which set the size/location via the widget attributes.

#866 Updated by Hynek Cihlar almost 9 years ago

Constantin,

please see testcases/uast/frame_layout. The tests are interactive, the best way to test is to run them in Progress environment and visually compare.

#867 Updated by Greg Shah almost 9 years ago

Code Review ca_upd20150406c.zip

1. In LabelImpl.nativeHeight(), if there is more than one line (the label has multiple embedded newlines) and the underlined attribute is true, does the underline change the height of all lines? Or in the 4GL is there only an underline below the last line of the text?

2. In FillInGuiImpl.nativeHeight(), this code confuses me:

      int font = gf.resolveFontNum();
      if (font == FontManager.DEFAULT_FIXED_FONT)
      {
         // fixed-font is used only for width
         font = FontManager.DEFAULT_FONT;
      }

Isn't it possible that the programmer defined the fill-in to use the default fixed font? If so, why wouldn't that also be used for the height metrics?

3. There is an blank line between the WidgetItem.align member and its javadoc.

Hynek: please review the ZCL changes.

#868 Updated by Constantin Asofiei almost 9 years ago

Greg Shah wrote:

Code Review ca_upd20150406c.zip

1. In LabelImpl.nativeHeight(), if there is more than one line (the label has multiple embedded newlines) and the underlined attribute is true, does the underline change the height of all lines? Or in the 4GL is there only an underline below the last line of the text?

Yes, there is only one underline.

2. In FillInGuiImpl.nativeHeight(), this code confuses me:

[...]

Isn't it possible that the programmer defined the fill-in to use the default fixed font? If so, why wouldn't that also be used for the height metrics?

You can't explicitly reference the default fixed font, but you can reference a font which is the same (in terms of font name and size) as the default fixed font. The idea is this: if no font is explicitly provided (at the widget or the frame), then the fill-in's height is computed using the default font, always (even if the content may be drawn using the default fixed font). That's why in nativeHeight I force the default font to be used, instead of default fixed font.

Hynek: please review the ZCL changes.

My ZCL's fixedRow/fixedColumn are very problematic... need to find an alternative, otherwise the dynamic label/widget placing no longer works.

#869 Updated by Constantin Asofiei almost 9 years ago

Hynek Cihlar wrote:

Constantin,

please see testcases/uast/frame_layout. The tests are interactive, the best way to test is to run them in Progress environment and visually compare.

Not all of them are supposed to work properly in P2J, right? Because at least label_length.p is not, with bzr rev 10830. The good news I think I may be able to fix this.

#870 Updated by Hynek Cihlar almost 9 years ago

Greg Shah wrote:

Hynek: please review the ZCL changes.

ZCL.RegularModeVariables.setStartColumn(), line 1788 (also line 1997):
In GUI, is startColumn really expected to be character equivalent of 1 pixel?

#871 Updated by Constantin Asofiei almost 9 years ago

Hynek Cihlar wrote:

Greg Shah wrote:

Hynek: please review the ZCL changes.

ZCL.RegularModeVariables.setStartColumn(), line 1788 (also line 1997):
In GUI, is startColumn really expected to be character equivalent of 1 pixel?

Good catch, that is inside a ATTR-SPACE related branch, so I'll change it back to 1. I don't know if ATTR-SPACE has any usage in GUI, for now I'm assuming it affects only ChUI.

#872 Updated by Hynek Cihlar almost 9 years ago

Constantin Asofiei wrote:

My ZCL's fixedRow/fixedColumn are very problematic... need to find an alternative, otherwise the dynamic label/widget placing no longer works.

Constantin, can you be more specific, why are they problematic?

#873 Updated by Constantin Asofiei almost 9 years ago

Hynek Cihlar wrote:

Constantin Asofiei wrote:

My ZCL's fixedRow/fixedColumn are very problematic... need to find an alternative, otherwise the dynamic label/widget placing no longer works.

Constantin, can you be more specific, why are they problematic?

If I set it during frame layout and restore it before frame layout (from the savedWidgets array), there is no way to tell if the frame/col was set explicitly by the business logic or during layout. I'm moving to an approach where the AbstractWidget.size is initially set to INV_COORD so that ZLC can compute the widget location only once (on first layout) and reuse that until the business logic changes it.

I'm still looking for reasons why there is a need to recompute the frame layout each time pushScreenDefinition is called (because lets say the LABEL or BGCOLOR was changed), but I can't seem to find one... I think this is the main reason behind all the widget location problems when LABEL or other widget attributes are changed explicitly in the business logic.

#874 Updated by Hynek Cihlar almost 9 years ago

Constantin Asofiei wrote:

Not all of them are supposed to work properly in P2J, right? Because at least label_length.p is not, with bzr rev 10830. The good news I think I may be able to fix this.

I think they all worked, at least at some point, including label_length.p.

#875 Updated by Hynek Cihlar almost 9 years ago

Constantin Asofiei wrote:

If I set it during frame layout and restore it before frame layout (from the savedWidgets array), there is no way to tell if the frame/col was set explicitly by the business logic or during layout. I'm moving to an approach where the AbstractWidget.size is initially set to INV_COORD so that ZLC can compute the widget location only once (on first layout) and reuse that until the business logic changes it.

I had the same problem with BaseConfig.fixedColumn/fixedRow. I decided to remove these and replace them with more elementary piece of information that is unambiguous to interpret. This let to some denormalization but less complicated model. I will post more details today.

#876 Updated by Constantin Asofiei almost 9 years ago

Hynek Cihlar wrote:

Constantin Asofiei wrote:

If I set it during frame layout and restore it before frame layout (from the savedWidgets array), there is no way to tell if the frame/col was set explicitly by the business logic or during layout. I'm moving to an approach where the AbstractWidget.size is initially set to INV_COORD so that ZLC can compute the widget location only once (on first layout) and reuse that until the business logic changes it.

I had the same problem with BaseConfig.fixedColumn/fixedRow. I decided to remove these and replace them with more elementary piece of information that is unambiguous to interpret. This let to some denormalization but less complicated model. I will post more details today.

Yeah, fixedColumn/fixedRow, that is what I'm referring to. Please check the label_length.p with your changes, I don't want to chase the same thing as you do...

#877 Updated by Hynek Cihlar almost 9 years ago

Constantin Asofiei wrote:

Yeah, fixedColumn/fixedRow, that is what I'm referring to. Please check the label_length.p with your changes, I don't want to chase the same thing as you do...

I am afraid I will have to do a complete retest anyway after merging in your changes due to the volume of conflicts.

#878 Updated by Constantin Asofiei almost 9 years ago

Hynek Cihlar wrote:

Constantin Asofiei wrote:

Yeah, fixedColumn/fixedRow, that is what I'm referring to. Please check the label_length.p with your changes, I don't want to chase the same thing as you do...

I am afraid I will have to do a complete retest anyway after merging in your changes due to the volume of conflicts.

I meant using 10830 + your changes, as label_length.p is broken in this rev.

#879 Updated by Hynek Cihlar almost 9 years ago

Constantin Asofiei wrote:

Hynek Cihlar wrote:

Constantin Asofiei wrote:

Yeah, fixedColumn/fixedRow, that is what I'm referring to. Please check the label_length.p with your changes, I don't want to chase the same thing as you do...

I am afraid I will have to do a complete retest anyway after merging in your changes due to the volume of conflicts.

I meant using 10830 + your changes, as label_length.p is broken in this rev.

It seemed to work quite well in vanilla 10830. Or did you find otherwise?

#880 Updated by Constantin Asofiei almost 9 years ago

Hynek Cihlar wrote:

Constantin Asofiei wrote:

Hynek Cihlar wrote:

Constantin Asofiei wrote:

Yeah, fixedColumn/fixedRow, that is what I'm referring to. Please check the label_length.p with your changes, I don't want to chase the same thing as you do...

I am afraid I will have to do a complete retest anyway after merging in your changes due to the volume of conflicts.

I meant using 10830 + your changes, as label_length.p is broken in this rev.

It seemed to work quite well in vanilla 10830. Or did you find otherwise?

First failure is at label_length.p COLON TEST step 3:
  1. lindev01:
    
    ┌──────────────────────────────────COLON TEST──────────────────────────────────┐
    │    EEEEEEEEEEEEEEE: 10                                                       │
    │              YYYYY: 30                                                       │
    │              YYYYY: 40                                                       │
    └──────────────────────────────────────────────────────────────────────────────┘
    
    Press space bar to continue.
    
  2. P2J
    
    ┌──────────────────────────────────COLON TEST──────────────────────────────────
    │              SSSSS: 10                                                       
    │              YYYYY: 30                                                       
    │              YYYYY: 40                                                       
    └──────────────────────────────────────────────────────────────────────────────
    
    **Unable to set SCREEN-VALUE.  LITERAL widget does not fit in FRAME f1. (4054) 
    
    Press space bar to continue.                                                   
    

Another failure:

┌───────────────────────────────────AT TEST────────────────────────────────────┐
│         EEEEEEEEEEEE          10                                             │
│                   YYYYY: 30                                                  │
│                   YYYYY: 40                                                  │
└──────────────────────────────────────────────────────────────────────────────┘

And another:

┌───────────────────────────────────TO TEST────────────────────────────────────┐
│        EEEEEEEEEEEE          10                                              │
│                       YYYYY: 30                                              │
│                       YYYYY: 40                                              │
└──────────────────────────────────────────────────────────────────────────────┘

#881 Updated by Hynek Cihlar almost 9 years ago

Constantin Asofiei wrote:

First failure is at label_length.p COLON TEST step 3:

Thank you for the outputs. You are right, there are three errors indeed. Good news is that they are all resolved with my changes.

#882 Updated by Constantin Asofiei almost 9 years ago

Hynek Cihlar wrote:

Constantin Asofiei wrote:

First failure is at label_length.p COLON TEST step 3:

Thank you for the outputs. You are right, there are three errors indeed. Good news is that they are all resolved with my changes.

If you still need more time to release the entire changes, please check if you can extract and test them, so they can be released in a separate update.

#883 Updated by Hynek Cihlar almost 9 years ago

Constantin Asofiei wrote:

Hynek Cihlar wrote:

Constantin Asofiei wrote:

First failure is at label_length.p COLON TEST step 3:

Thank you for the outputs. You are right, there are three errors indeed. Good news is that they are all resolved with my changes.

If you still need more time to release the entire changes, please check if you can extract and test them, so they can be released in a separate update.

I'm afraid this can't be done. The fixed behavior depends on the overall cleanup and differences in the config model.

#884 Updated by Hynek Cihlar almost 9 years ago

The attached update:
- removes business logic from config classes,
- refactors location fields in BaseConfig,
- contains other related changes.

Some of the entry points for the change set are:
- ConfigOwner
- WidgetWithConfig
- ConfigSyncManager
- SyncConfigChanges
- BaseConfig
- ConfigHelper

WidgetItem.java was removed by this update.

Majic regression testing is in progress. Please review.

#885 Updated by Greg Shah almost 9 years ago

Code Review hc_upd20150407b.zip

Overall, this is a really great step forward. Although the aspect code is both indirect and tricky, I think the use of it for this problem is appropriate.

1. My primary concern with the new approach is the potential negative performance impact of using the aspects on both client and server instead of just on the client. If I remember correctly, Constantin carefully excluded the server in the past because of the significant negative impact it had.

2. I also worry that the approach is pretty hard to properly understand what is really going on so we will have to be very vigilant over code changes in the future which may be dangerous but look overtly OK. I am open to any ideas of how we make this more obvious or less error prone.

3. I find the idiom widget.getId().getId() to be confusing. Getting the int widget id is a common thing and should be a single method call that is easy to read and easy to get right. I also prefer not to use UiUtils.getWidgetIdAsInt(widget) as it is very verbose.

4. I wish we were already supporting Java 8 because callers of ConfigManager.syncConfigChanges() would benefit from lambda expressions.

5. Can you help me understand when we need to use ConfigManager.syncConfigChanges() and when it is safe to directly set a config member?

6. There are places where you no longer call pushScreenDefinition() after assigning a config member. What is the thinking behind those changes?

7. Can you please explain the use of ThreadLocal in ConfigSyncManager and why it is safe as compared with our normal ContextLocal usage?

8. ClientExports and WindowLayout are missing a history entry.

#886 Updated by Constantin Asofiei almost 9 years ago

Hynek, beside what Greg noted:
  • AbstractWidget.afterConfigUpdateBase - beforeUpdate param has no javadoc
  • FillIn.afterConfigUpdate: I think a functionality (when reverting back to the prev format) is lost. Shouldn't prevFormat be initialized with the beforeUpdate.format value?
  • ConfigManager.resolveConfigOwner - please place it after the static methods
  • BaseEntity.setColumnOrRowWorker - you are setting the align to left, while setXorY does not change it. Is this by intent?
  • BaseConfig.column - is missing the "Use {@link ConfigHelper} to access the positional fields." comment

#887 Updated by Hynek Cihlar almost 9 years ago

Greg Shah wrote:

Code Review hc_upd20150407b.zip

Overall, this is a really great step forward. Although the aspect code is both indirect and tricky, I think the use of it for this problem is appropriate.

1. My primary concern with the new approach is the potential negative performance impact of using the aspects on both client and server instead of just on the client. If I remember correctly, Constantin carefully excluded the server in the past because of the significant negative impact it had.

Was the impact contributed just by the aspect overhead or the useful logic itself? Maybe it would be a good idea to measure the effect of the new aspects.

2. I also worry that the approach is pretty hard to properly understand what is really going on so we will have to be very vigilant over code changes in the future which may be dangerous but look overtly OK. I am open to any ideas of how we make this more obvious or less error prone.

Do you mean the aspect approach or the way the config synchronization is implemented?

3. I find the idiom widget.getId().getId() to be confusing. Getting the int widget id is a common thing and should be a single method call that is easy to read and easy to get right. I also prefer not to use UiUtils.getWidgetIdAsInt(widget) as it is very verbose.

Agree. Ideally I would remove the WidgetId.getId altogether, the returned int is not always the whole story. For example WidgetDownId internally uses two integers for its identity. Alternatively I can introduce new method next to Widget.getId(), Widget.getIdInt() maybe?

4. I wish we were already supporting Java 8 because callers of ConfigManager.syncConfigChanges() would benefit from lambda expressions.

Same wish here.

5. Can you help me understand when we need to use ConfigManager.syncConfigChanges() and when it is safe to directly set a config member?

ConfigManager.syncConfigChanges() (or the SyncConfigChanges annotation) must be used every time the config change may have impact on the state of the associated widget and this updated state must be available right away (not just after the client-server round trip).

The question could also be whether we even need this kind of config synchronization mechanism. In very simple cases it would be indeed enough to manage the state by hand - change the config and change the widget instance manually. When the config-widget state synchronization becomes more complex, it becomes handy to encapsulate the synchronization logic in a method (WidgetConfig.syncWithWidget() or the new ConfigOwner.afterConfigUpdate()). And when the synchronization involves a whole structure of widgets (like during frame setup) then I think it becomes handy to somehow automate this.

I also attempted to make the synchronization logic (the code in ConfigOwner.afterConfigUpdate()) idempotent - the method can be executed anytime always resulting in a consistent system.

6. There are places where you no longer call pushScreenDefinition() after assigning a config member. What is the thinking behind those changes?

These places were either replaced by modifying widgets directly (by calling the widget methods) or by ConfigManager.syncConfigChanges()/SyncConfigChanges.

7. Can you please explain the use of ThreadLocal in ConfigSyncManager and why it is safe as compared with our normal ContextLocal usage?

The "problem" with ContextLocal is that it is too abstract. It could be (and probably is) implemented in a way that ThreadLocal is not even needed. On the other hand, I need to establish a synchronization scope on the code level - for example by marking a method with SyncConfigChanges annotation and monitor config changes up the call stack.

8. ClientExports and WindowLayout are missing a history entry.

Fixed.

#888 Updated by Hynek Cihlar almost 9 years ago

Constantin Asofiei wrote:

Hynek, beside what Greg noted:
  • AbstractWidget.afterConfigUpdateBase - beforeUpdate param has no javadoc

Fixed.

  • FillIn.afterConfigUpdate: I think a functionality (when reverting back to the prev format) is lost. Shouldn't prevFormat be initialized with the beforeUpdate.format value?

I intentionally removed FillInConfig.prevFormat and at the moment I am not sure why and even whether this was a good thing to do. Let me look at it.

  • ConfigManager.resolveConfigOwner - please place it after the static methods
  • BaseEntity.setColumnOrRowWorker - you are setting the align to left, while setXorY does not change it. Is this by intent?

Good point, setXorY should also set the left align.

  • BaseConfig.column - is missing the "Use {@link ConfigHelper} to access the positional fields." comment

Fixed.

#889 Updated by Greg Shah almost 9 years ago

Was the impact contributed just by the aspect overhead or the useful logic itself?

I think Constantin would know better about this.

Maybe it would be a good idea to measure the effect of the new aspects.

Yes, I think so.

Do you mean the aspect approach or the way the config synchronization is implemented?

Both.

The aspects make things difficult for 2 reasons: they are hidden/indirect AND the conditions that engage them are defined in a non-Java somewhat cryptic language in which small changes can have massive impact.

The config synchronization itself has quite a bit of "hidden machinery" in addition to the aspects, making it a very complex system in its own right.

Your javadoc is pretty good. But I do think we will need some overall description of the "system" that may help people orient themselves.

Alternatively I can introduce new method next to Widget.getId(), Widget.getIdInt() maybe?

Yes, this is a good idea.

7. Can you please explain the use of ThreadLocal in ConfigSyncManager and why it is safe as compared with our normal ContextLocal usage?

The "problem" with ContextLocal is that it is too abstract. It could be (and probably is) implemented in a way that ThreadLocal is not even needed. On the other hand, I need to establish a synchronization scope on the code level - for example by marking a method with SyncConfigChanges annotation and monitor config changes up the call stack.

Are you sure that ThreadLocal is safe here? In other words, can we rely on all dependent processing to always be on that same thread?

#890 Updated by Constantin Asofiei almost 9 years ago

Greg Shah wrote:

Was the impact contributed just by the aspect overhead or the useful logic itself?

I think Constantin would know better about this.

Server-side doesn't need to track widget attribute changes. If an attribute gets changed, we rely on the LT.pushScreenDefinition to notify the client side about the change, at the proper time. That's why ConfigFieldSetterAspect excludes server-side classes.

And about the overhead: try to determine the CPU time/invocation count for your new aspects. In JVisualVM, it might help to include only the P2J aspects.ui package, to reduce the noise.

#891 Updated by Greg Shah almost 9 years ago

Server-side doesn't need to track widget attribute changes. If an attribute gets changed, we rely on the LT.pushScreenDefinition to notify the client side about the change, at the proper time. That's why ConfigFieldSetterAspect excludes server-side classes.

If I correctly understand the proposed code, the server side must now track changes.

#892 Updated by Hynek Cihlar almost 9 years ago

Hynek Cihlar wrote:

Constantin Asofiei wrote:

Hynek, beside what Greg noted:
  • AbstractWidget.afterConfigUpdateBase - beforeUpdate param has no javadoc

Fixed.

  • FillIn.afterConfigUpdate: I think a functionality (when reverting back to the prev format) is lost. Shouldn't prevFormat be initialized with the beforeUpdate.format value?

I intentionally removed FillInConfig.prevFormat and at the moment I am not sure why and even whether this was a good thing to do. Let me look at it.

Ok, the idea was to take advantage of the new feature of ConfigOwner.afterConfigUpdate and use the beforeUpdate instance to revert the format when setAttrFormat() fails. Unfortunately the implementation was incorrect. Please see the attached hc_upd20150408b.zip with a fix.

#893 Updated by Hynek Cihlar almost 9 years ago

Greg Shah wrote:

The aspects make things difficult for 2 reasons: they are hidden/indirect AND the conditions that engage them are defined in a non-Java somewhat cryptic language in which small changes can have massive impact.

The config synchronization itself has quite a bit of "hidden machinery" in addition to the aspects, making it a very complex system in its own right.

I think this is the price to pay for having the configs publicly accessible. I think the configs should have served only the purpose of simple DTOs with widgets capable to serialize to and from these.

Your javadoc is pretty good. But I do think we will need some overall description of the "system" that may help people orient themselves.

I will add such description.

7. Can you please explain the use of ThreadLocal in ConfigSyncManager and why it is safe as compared with our normal ContextLocal usage?

The "problem" with ContextLocal is that it is too abstract. It could be (and probably is) implemented in a way that ThreadLocal is not even needed. On the other hand, I need to establish a synchronization scope on the code level - for example by marking a method with SyncConfigChanges annotation and monitor config changes up the call stack.

Are you sure that ThreadLocal is safe here? In other words, can we rely on all dependent processing to always be on that same thread?

With the current state of code I think it is safe, AFAIK there is no parallel or asynchronous processing involved. I would leave this as the developer's responsibility. The documentation should mention that the synchronization scope doesn't cross thread boundary.

#894 Updated by Hynek Cihlar almost 9 years ago

Constantin Asofiei wrote:

And about the overhead: try to determine the CPU time/invocation count for your new aspects. In JVisualVM, it might help to include only the P2J aspects.ui package, to reduce the noise.

Constantin, do you have any dedicated tests for this?

#895 Updated by Constantin Asofiei almost 9 years ago

Hynek Cihlar wrote:

Constantin Asofiei wrote:

And about the overhead: try to determine the CPU time/invocation count for your new aspects. In JVisualVM, it might help to include only the P2J aspects.ui package, to reduce the noise.

Constantin, do you have any dedicated tests for this?

No, I was using the reports in the tc_pay_emp_wr_adp_001, tc_pay_sfc_003 and gso_185 tests as reference.

#896 Updated by Constantin Asofiei almost 9 years ago

This is for the #2229, WINDOW:PARENT attribute. It adds runtime support for window families: for the WINDOW-MINIMIZED and WINDOW-RESTORE events, it was needed to separate the OS (de)iconification from the OS events. The window (de)iconification events can't be interrupted by a RETURN NO-APPLY, but it can interrupt the 4GL trigger chain.

Also, there are some fixes related to the window's TITLE attribute.

#897 Updated by Greg Shah almost 9 years ago

Code Review ca_upd201504315c.zip

This is a really good update. The subject matter is tricky but you have implemented it well. I think it is as understandable as it is going to get.

You can check it in if it passes regression testing. I suspect it will pass since most of the new functionality is GUI-specific.

#898 Updated by Greg Shah almost 9 years ago

BTW, I think the ca_upd201504315c.zip update is for #1798 not #2229.

#899 Updated by Hynek Cihlar almost 9 years ago

Constantin Asofiei wrote:

And about the overhead: try to determine the CPU time/invocation count for your new aspects. In JVisualVM, it might help to include only the P2J aspects.ui package, to reduce the noise.

I have tested different parts of the Majic code base and even in the worst case scenarios of building and laying out frames, the server overhead of the config changes tracking and widget synchronization is very small. For example the CPU-time overhead of config synchronization when invoking Main-menu/Inventory screen is less then 2 ms. I also tried to compare the total CPU times with and without my changes in different scenarios and the deltas are well below error margin.

Also, I found negligible overhead of aspectj itself. The only interesting method in terms of number of invocations is aspectOf() generated for every aspect class. In case of the mentioned Main-menu/Inventory screen, the method never exceeded 0.05 ms.

#900 Updated by Hynek Cihlar almost 9 years ago

Greg Shah wrote:

Alternatively I can introduce new method next to Widget.getId(), Widget.getIdInt() maybe?

Yes, this is a good idea.

After the second thought I would rather rename the method WidgetId.getId() to asInt(). This would make more sense even in the context of the WidgetId class itself. No new method on Widget interface would be needed and getting the numeric id from a widget would be intuitive: w.getId().asInt().

#901 Updated by Constantin Asofiei almost 9 years ago

Greg Shah wrote:

BTW, I think the ca_upd201504315c.zip update is for #1798 not #2229.

Correct. I've added notes to #1798 and the update was released to 10836.

#902 Updated by Greg Shah almost 9 years ago

Hynek Cihlar wrote:

Greg Shah wrote:

Alternatively I can introduce new method next to Widget.getId(), Widget.getIdInt() maybe?

Yes, this is a good idea.

After the second thought I would rather rename the method WidgetId.getId() to asInt(). This would make more sense even in the context of the WidgetId class itself. No new method on Widget interface would be needed and getting the numeric id from a widget would be intuitive: w.getId().asInt().

I like it.

#903 Updated by Hynek Cihlar almost 9 years ago

Constantin, LiteralWidget.setColumnOrRowWorker() contains config.align == ControlEntity.ALIGN_RIGHT condition. I am trying to come up with a valid case for this. When column is explicitly set, the align should be always left, right? If so, this condition should never become true.

#904 Updated by Constantin Asofiei almost 9 years ago

Hynek Cihlar wrote:

Constantin, LiteralWidget.setColumnOrRowWorker() contains config.align == ControlEntity.ALIGN_RIGHT condition. I am trying to come up with a valid case for this. When column is explicitly set, the align should be always left, right? If so, this condition should never become true.

The only way of ending up right-aligned is via a TO clause at the definition, which doesn't call setColumnOrRowWorker. But I do have a concern, as that code is limited to an unrealized widget: maybe if the widget is not yet realized, setting the COLUMN attribute still "sees" the right-alignment and re-computes the widget's width, based on the original TO clause? Try this: use the TO clause, and before showing the widget, set its COLUMN to something else... and see what happens.

#905 Updated by Hynek Cihlar almost 9 years ago

Constantin Asofiei wrote:

Hynek Cihlar wrote:

Constantin, LiteralWidget.setColumnOrRowWorker() contains config.align == ControlEntity.ALIGN_RIGHT condition. I am trying to come up with a valid case for this. When column is explicitly set, the align should be always left, right? If so, this condition should never become true.

The only way of ending up right-aligned is via a TO clause at the definition, which doesn't call setColumnOrRowWorker. But I do have a concern, as that code is limited to an unrealized widget: maybe if the widget is not yet realized, setting the COLUMN attribute still "sees" the right-alignment and re-computes the widget's width, based on the original TO clause? Try this: use the TO clause, and before showing the widget, set its COLUMN to something else... and see what happens.

I'll try. How do I reference a form literal in 4GL? Thanks.

#906 Updated by Constantin Asofiei almost 9 years ago

This case brings you to a literal, although in P2J first-child doesn't yet work. I think that is really dead code, as I can't think of a way to reference the literal without relying on FIRST-CHILD.

form "a" with frame f1 no-labels.
view frame f1.
message frame f1:first-child:first-child:type.

Also, there is another way to end up with a right-aligned widget and a setColumn call: look at the gen_at_phrase_ex and gen_at_phrase functions in frame_generator.xml. The good part is that the setColumn is called before setAlign, so the alignment is left when setColumnOrRowWorker is called. Again, another reason to think that part is dead code...

#907 Updated by Constantin Asofiei almost 9 years ago

OK, this is not dead code. The problem the code was trying to fix was related to side-labels and changing the side-label's COLUMN attribute, before the label was realized.

def var ch as char.
form ch label "something" with frame f1 side-labels no-box.
ch:side-label-handle:column = 1. /* this forces the label to be "invisible" */ 
view frame f1.

Currently side-labels end up right-aligned, until they are changed via the LABEL attribute, when they are forced left-aligned.

#908 Updated by Hynek Cihlar almost 9 years ago

Very well, I implemented this for X attribute as well as it follows the same logic.

#909 Updated by Constantin Asofiei almost 9 years ago

Hynek Cihlar wrote:

Very well, I implemented this for X attribute as well as it follows the same logic.

Please update your current version of the config rework, I want to continue my layout work based on it.

#910 Updated by Hynek Cihlar almost 9 years ago

Constantin Asofiei wrote:

Hynek Cihlar wrote:

Very well, I implemented this for X attribute as well as it follows the same logic.

Please update your current version of the config rework, I want to continue my layout work based on it.

Attached.

#911 Updated by Hynek Cihlar almost 9 years ago

Attached is an update to the config refactoring work. The changes from last review are: worked-in comments, Majic regression fixes, Javadoc fixes, GUI fixes, latent memory leak fix, other related fixes.

Not included is the documentation improvement of the changes in config-widget state synchronization. I am planning to do this tomorrow with a fresh head.

Although I tested GUI mode for potential regressions, the tests were limited to window and basic frame layouts.

I have fixed all identified Majic regressions from previous test runs and at the moment running retest.

Please review.

#912 Updated by Greg Shah almost 9 years ago

Code Review hc_upd20150420g.zip

This is a really great step forward. Some comments and questions:

1. I don't understand the comment on lines 766-777 of AbstractWidget:

         // this.location is effectively used for widgets without config;
         // use the scaled config values

This is the path that does have a BaseConfig, so the comment confuses me.

2. The latent memory leak was in Frame.calcFixedRect()? I guess that the reason you saw it was that the new approach requires more memory. Does it require increasing the MAJIC client heap size? (I really hope not as this would have an impact on their production systems)

3. How important are the TODOs in GenericFrame.setColumn|Row() and RadioButton (the location and physicalLocation methods)?

4. You are missing history entries for: WidgetId, FramePlacementManager, EditableWidget, MouseMoveable, MousePopupable, MouseResizable, GuiOutputManager, FrameData, OutputManager, ButtonWidget, DynamicWidgetFactory, EventList, ImageWidget, MenuDescription, ScreenDefinition, WindowWidget.

#913 Updated by Hynek Cihlar almost 9 years ago

Greg Shah wrote:

Code Review hc_upd20150420g.zip

This is a really great step forward. Some comments and questions:

1. I don't understand the comment on lines 766-777 of AbstractWidget:

[...]

This is the path that does have a BaseConfig, so the comment confuses me.

The reason I set the AbstractWidget.location together with the config fields is only for clarity, IMHO it may help prevent confusion during debugging. The sole presence of the location field is unfortunate, but I didn't come with a better solution to handle widgets with no configs.

I'll improve the comment.

2. The latent memory leak was in Frame.calcFixedRect()? I guess that the reason you saw it was that the new approach requires more memory. Does it require increasing the MAJIC client heap size? (I really hope not as this would have an impact on their production systems)

Exactly, the bug let me believe the new approach required more memory until I started to investigate why. Fortunately the aspects only introduce static fields in the woven classes and the new config fields I introduced have negligable impact on memory footprint.

3. How important are the TODOs in GenericFrame.setColumn|Row()

The TODO related to the commented out config.positionChanged was to point out that there is a piece of code which doesn't do what it was supposed to do. I wanted to do as little functional changes as necessary thus I didn't attempt to fix it myself. Also I explicitly stated in what update this was commented out since the other changes on the client also affect the logic related to config.positionChanged.

and RadioButton (the location and physicalLocation methods)?

I find it weird to have instances of different widget classes sharing the same config instance. This already proved to be a source of problems. I didn't want to fix this in my update so I put in the TODOs.

4. You are missing history entries for: WidgetId, FramePlacementManager, EditableWidget, MouseMoveable, MousePopupable, MouseResizable, GuiOutputManager, FrameData, OutputManager, ButtonWidget, DynamicWidgetFactory, EventList, ImageWidget, MenuDescription, ScreenDefinition, WindowWidget.

Right, this is due to the rename of WidgetId.getId() to WidgetId.asInt(). Will fix.

#914 Updated by Hynek Cihlar almost 9 years ago

The attached replaces hc_upd20150420g.zip and contains changes based on the review, Majic regression fixes and improved docs.

Majic still fails on me, so regression testing is WIP.

#915 Updated by Hynek Cihlar almost 9 years ago

I have Majic changes for review, should I post them here?

#916 Updated by Constantin Asofiei almost 9 years ago

Hynek Cihlar wrote:

I have Majic changes for review, should I post them here?

No, create a new task in the Majic Conversion project and post it there (link it to this task/comment number/update/etc).

#917 Updated by Greg Shah almost 9 years ago

Code Review hc_upd20150421c.zip

Everything looks good. I appreciate the improved comments and javadoc. It is very helpful.

As a separate note, #2553 is the task which holds the matching MAJIC update.

#918 Updated by Constantin Asofiei almost 9 years ago

Hynek, by any chance, do you have any FORMAT-related issues? Because this test is not working:

def var ch as  char.

ch = "12345678".
form ch with frame f1 no-labels.
view frame f1.

color display message ch with frame f1.
display ch  with frame f1 size 40 by 20. 
pause.

ch:format = "x(20)". /* this re-adjusts the widget's width */
pause.

There are some issues in Fillin:

   public void afterConfigUpdate(C beforeUpdate)
   {
      super.afterConfigUpdate(beforeUpdate);

      FillInConfig c = config();

      String prevFormat = null; /** why is this not initialized to beforeUpdate.format? */

      try
      {
         if (!(c.format != null && c.format.equals(getFormat())))
         {
            setAttrFormat(c.format);
         }

         prevFormat = c.format;
      }
      catch (ConditionException e) 
      {
         // rollback to previous format
         c.format = prevFormat; /* rollback does not work as prevFormat is not initialized if setAttrFormat fails... */

         throw e;
      }
      catch (Exception e)
      {
         throw new RuntimeException("Unable to set format [" + c.format + "]", e);
      }
   }

I think setAttrFormat needs to receive the "old format" as a parameter, because at the time this is called from afterConfigUpdate, the widget's config is already updated with the new format (and access to the "beforeUpdate" config is not possible from here).

   public boolean setAttrFormat(String format)
   throws DisplayFormatParsingException
   {
      String oldFormat = config.format; /* this is not correct, if called from afterConfigUpdate */
      ...

      boolean formatUnchanged = config.format != null && 
                                format != null && 
                                format.equals(config.format);  /* again, if we call from afterConfigUpdate, this is always true! */

      // update config.format before updateSize() which can trigger 
      // config synchronization
      config.format = config.appFormat.getFormatDef(); // direct access

      updateSize(); /* this updates the widget's size-related config attributes, but does not update the widget's AbstractContainer.size field...*/
      display();

      ...
   }

   protected void updateSize()
   {
      if (config.autoResize)
      {
         ConfigManager.syncConfigChanges(new Runnable()  /* if we are already in a ConfigManager.syncConfigChanges call, the functionality which was in the setWidthChars is lost, as afterConfigUpdate is not called again... */
         {
            @Override
            public void run()
            {
               CoordinatesConversion cc = screen().coordinates();

               config.widthChars = cc.widthFromNative(nativeWidth());

               if (config.heightChars <= 0)
                  config.heightChars = cc.heightFromNative(nativeHeight());
            }
         });
      }
   }

And even if we make these changes, the widget's size does not get update. This is related to not allowing nested "afterConfigUpdate" calls. This is correct to prevent recursion, but is not correct in terms of: what happens if the "afterConfigUpdate" ends up changing the widthChars, from the "setAttrFormat" call, from example? There are valid cases which I think need to track some dirty state, so that afterConfigUpdate is executed by ConfigSyncManager.markScopeEnd until the "dirty" flag is no longer set.

#919 Updated by Constantin Asofiei almost 9 years ago

Constantin Asofiei wrote:

And even if we make these changes, the widget's size does not get update. This is related to not allowing nested "afterConfigUpdate" calls. This is correct to prevent recursion, but is not correct in terms of: what happens if the "afterConfigUpdate" ends up changing the widthChars, from the "setAttrFormat" call, from example? There are valid cases which I think need to track some dirty state, so that afterConfigUpdate is executed by ConfigSyncManager.markScopeEnd until the "dirty" flag is no longer set.

Calling explicitly super.afterConfigUpdate() in FillIn.afterConfigUpdate, seems to solve the problem, for the FORMAT case:

         if (!(c.format != null && c.format.equals(getFormat())))
         {
            setAttrFormat(c.format, prevFormat);

            // call again super
            super.afterConfigUpdate(beforeUpdate);
         }

So we have two options:
  1. identify all cases which need to call super.afterConfigUpdate, and fix each one explicitly
  2. do something automatic...

#920 Updated by Hynek Cihlar almost 9 years ago

Constantin Asofiei wrote:

So we have two options:
  1. identify all cases which need to call super.afterConfigUpdate, and fix each one explicitly

It is a pure luck that this approach worked. The recursive config changes were by luck covered by the super implementation.

  1. do something automatic...

I am affraid this would complicate things even more.

I think this is a good example of the case when, instead of relying on a synchronization mechanism, the widget should handle its state itself. I would contain the logic in afterConfigUpdate synchronizing changes performed by FillIn.updateSize into a separate method, call this method from afterConfigUpdate, remove ConfigManager.syncConfigChanges call from FillIn.updateSize and instead call directly the new method.

Btw. I indeed had format issues, but these were triggered by FillIn.setValue so I didn't realize this recursion.

#921 Updated by Hynek Cihlar almost 9 years ago

Hynek Cihlar wrote:

I think this is a good example of the case when, instead of relying on a synchronization mechanism, the widget should handle its state itself. I would contain the logic in afterConfigUpdate synchronizing changes performed by FillIn.updateSize into a separate method, call this method from afterConfigUpdate, remove ConfigManager.syncConfigChanges call from FillIn.updateSize and instead call directly the new method.

And of course I will fix it. Thanks for finding it!

#922 Updated by Hynek Cihlar almost 9 years ago

The attached update is a replacement of hc_upd20150421c.zip. It contains changes based on the last review, Majic regression fixes and javadoc improvements. This update fixes all the known regressions. Majic regression testing is in progress.

Please review.

#923 Updated by Hynek Cihlar almost 9 years ago

Renamed hc_upd20140424f.zip to hc_upd20150424f.zip.

#924 Updated by Hynek Cihlar almost 9 years ago

The attached is a replacement of hc_upd20150424f.zip and adds some more javadocs.

#925 Updated by Hynek Cihlar almost 9 years ago

The attached is a replacement of hc_upd20150424g.zip and fixes javadoc warnings.

#926 Updated by Greg Shah almost 9 years ago

Code Review hc_upd20150424h.zip

ScrollContainer is missing a history entry. Otherwise this update looks very good.

#927 Updated by Constantin Asofiei almost 9 years ago

Hynek, what about this case? Are you sure formatUnchaged is computed properly?

public boolean setAttrFormat(String format)
   throws DisplayFormatParsingException
   {
      String oldFormat = config.format; /* when called from afterConfigUpdate it will contain the new format not the old one */
      ...

      boolean formatUnchanged = config.format != null && 
                                format != null && 
                                format.equals(config.format);  /* if we call from afterConfigUpdate, this is always true! */
      ...

#928 Updated by Hynek Cihlar almost 9 years ago

Constantin Asofiei wrote:

Hynek, what about this case? Are you sure formatUnchaged is computed properly?
[...]

When I was moving the logic from config classes I tried to do as little functional changes as needed. FillIn.setAttrFormat() used to be called from syncWithWidget() where config.format was also already set with new value.

The formatUnchanged will not always become true when called from afterConfigUpdate. Consider null being passed to the method. In this case format will be assigned a different value.

I hope that functionally setAttrFormat behaves the same as before my change. Whether it behaves correctly I am not sure. Did you find a case where it doesn't work?

#929 Updated by Hynek Cihlar almost 9 years ago

Actually you are right, formatUnchanged will always be true when called from afterConfigUpdate as it was syncWithWidget, because of the null check on config.format. In this case I actually do change the logic because I don't exit right away when this condition becomes false. I'll fix this.

#930 Updated by Hynek Cihlar almost 9 years ago

The attached update replaces hc_upd20150424h.zip.

Fixes redraw problem with multi selection lists (and radio buttons), and adds missing history entry.

Constantin, this also addresses FillIn.setAttrFormat(). I reverted the implementation to the trunk version as the changes are no longer needed after updateSize() no longer causes execution of afterConfigUpdate() and added a TODO to point out the potential issue with format change detection when called from afterConfigUpdate().

#931 Updated by Greg Shah almost 9 years ago

Code Review hc_upd20150427b.zip

It's good. I have my "fingers crossed" that regression testing goes well.

#932 Updated by Hynek Cihlar almost 9 years ago

Greg Shah wrote:

It's good. I have my "fingers crossed" that regression testing goes well.

The test ended with three failed tests (and three unexecuted dependencies). One of them is a real regression related to wrong frame virtual width calculation. Fix is attached and regression test restarted.

#933 Updated by Greg Shah almost 9 years ago

Code Review hc_upd20150428a.zip

It looks fine. If it passes, you can check it in.

#934 Updated by Hynek Cihlar almost 9 years ago

The attached is a replacement of hc_upd20150428a.zip. It contains a trivial fix and passes Majic regression tests.

Since the fix only reverts Frame.adjustHeight() to an earlier version which already passed review I am going to check it in.

#935 Updated by Hynek Cihlar almost 9 years ago

hc_upd20150428b.zip committed to revision 10841.

#936 Updated by Constantin Asofiei almost 9 years ago

Hynek,
Regarding the GUI window problems, I think the main issue is in WindowGuiImpl, where moveBy was using invalid coords:

   public void afterConfigUpdate(WindowConfig beforeUpdate)
   {
      super.afterConfigUpdate(beforeUpdate);

      if (isDisplayed() && config.realized)
      {
         NativePoint loc = physicalLocation();
         if (loc.x != config.x || loc.y != config.y)
         {
            if (config.x != BaseConfig.INV_COORD && config.y != BaseConfig.INV_COORD) /* do this only if coordinates are set */
            {
               moveBy(config.x - loc.x, config.y - loc.y);
            }
         }

#937 Updated by Hynek Cihlar almost 9 years ago

Constantin Asofiei wrote:

Hynek,
Regarding the GUI window problems, I think the main issue is in WindowGuiImpl, where moveBy was using invalid coords:
[...]

Constantin, very well. This fixes the initial window position. I just used ConfigHelper to get the assigned window location. The update is attached.

#938 Updated by Constantin Asofiei almost 9 years ago

Hynek Cihlar wrote:

Constantin Asofiei wrote:

Hynek,
Regarding the GUI window problems, I think the main issue is in WindowGuiImpl, where moveBy was using invalid coords:
[...]

Constantin, very well. This fixes the initial window position. I just used ConfigHelper to get the assigned window location. The update is attached.

Please add a history entry and release it.

#939 Updated by Hynek Cihlar almost 9 years ago

Constantin Asofiei wrote:

Hynek Cihlar wrote:

Constantin Asofiei wrote:

Hynek,
Regarding the GUI window problems, I think the main issue is in WindowGuiImpl, where moveBy was using invalid coords:
[...]

Constantin, very well. This fixes the initial window position. I just used ConfigHelper to get the assigned window location. The update is attached.

Please add a history entry and release it.

Yes, I am fixing another regression found by Vadim. I will put the fix into the same update when ready.

#940 Updated by Constantin Asofiei almost 9 years ago

Hynek Cihlar wrote:

Constantin Asofiei wrote:

Hynek Cihlar wrote:

Constantin Asofiei wrote:

Hynek,
Regarding the GUI window problems, I think the main issue is in WindowGuiImpl, where moveBy was using invalid coords:
[...]

Constantin, very well. This fixes the initial window position. I just used ConfigHelper to get the assigned window location. The update is attached.

Please add a history entry and release it.

Yes, I am fixing another regression found by Vadim. I will put the fix into the same update when ready.

Please post some details about the issue here, if you haven't solved it yet :).

#941 Updated by Hynek Cihlar almost 9 years ago

Constantin Asofiei wrote:

Please post some details about the issue here, if you haven't solved it yet :).

This is the email thread. So far I haven't been able to reproduce the NPE Vadim reported.

Vadim,

when I detach the popup from the button and remove the menu event handlers (which cause the NPE I have mentioned) I get a running program with no exceptions. Could you please give me the sample code which casuses the NPE and/or callstack of the exception you get? And please post it to redmine #2252.

Thanks,
Hynek

On 04/29/2015 04:19 PM, Vadim Gindin wrote:
> No, Hynek.
>
> You can just remove all menu-related code from testing procedure. My NPE related to the situation when Frame.layoutManager is null and doLayout() can't be executed.
>
> Regards,
> Vadim Gindin
>
> On 29.04.2015 19:25, Hynek Cihlar wrote:
>> Vadim,
>>
>> the exception happens during the execution of list0.addEvent("choose", MenuItemWidget.findMenuItemStatic("ffff")); in the converted code. Eventually MenuItemWidget.findMenuItemStatic is called which is unimplemented (always returns null) and this causes the NPW, at least in my case. Do you see the same callstack?
>>
>> Thanks,
>> Hynek
>>
>> On 04/29/2015 02:53 PM, Vadim Gindin wrote:
>>> Hello Hynek!
>>>
>>> I've updated my workspace after your update and faced with NullPointerException in Frame.doLayout(). It happens that getLayout() method called there can return null and return it in my testcase. Did you faced with it? I've attached my testcase. There are popup-menu is attached to button. You can skip this attachment.
>>>
>>> Regards,
>>> Vadim Gindin
>>

#942 Updated by Hynek Cihlar almost 9 years ago

The attached fixes GUI window positioning. Only GUI code is affected. Please review.

#943 Updated by Constantin Asofiei almost 9 years ago

Hynek Cihlar wrote:

The attached fixes GUI window positioning. Only GUI code is affected. Please review.

The changes are OK, you can release it.

#944 Updated by Hynek Cihlar almost 9 years ago

hc_upd20150429b.zip committed to bzr rev 10843.

#945 Updated by Constantin Asofiei almost 9 years ago

Attached is replacement of ca_upd20150406c.zip (note 865), frame layout and misc GUI fixes:
  • Rectangle(Point, Dimension) now receives base units, to properly compute its top/left and bottom/right corners
  • misc fixes related to "ghosting" - some drawing was done relative to the frame's origin, and not container's origin (to exclude the border)

Runtime/conversion testing is in progress.

Please review.

#946 Updated by Hynek Cihlar almost 9 years ago

FYI, the issue Vadim was facing was related to project setup.

#947 Updated by Greg Shah almost 9 years ago

Code Review ca_upd20150429a.zip

This is a really good update. I suspect it is cleaning up a lot of problems.

1. I wonder if the FrameGuiImpl.getLabelHeight(), FillInGuiImpl.nativeHeight() and LabelGuiImpl.nativeHeight() could be implemented with common code. The font fallback and sizing calculations (the legacyHeight calc that adds padding and factors in 3D) seems like it could be shared.

2. FramePlacementManager has a 161 history entry with no 160.

#948 Updated by Constantin Asofiei almost 9 years ago

Greg Shah wrote:

Code Review ca_upd20150429a.zip

This is a really good update. I suspect it is cleaning up a lot of problems.

1. I wonder if the FrameGuiImpl.getLabelHeight(), FillInGuiImpl.nativeHeight() and LabelGuiImpl.nativeHeight() could be implemented with common code. The font fallback and sizing calculations (the legacyHeight calc that adds padding and factors in 3D) seems like it could be shared.

I'll rework this with the EDITOR work, I don't want to hold the layout changes anymore.

2. FramePlacementManager has a 161 history entry with no 160.

Fixed

Attached update passed runtime testing and is committed to bzr rev 10844.

#949 Updated by Constantin Asofiei almost 9 years ago

Fixes following issues:
  1. frame title in GUI - centered vertically and fixed frame height problems. Also, it uses the OS window title font, not the FRAME:TITLE-FONT font.
  2. window size in GUI (default or implicit)
  3. window title text (and others) centered vertically
  4. font scaling switched from using legacy metric scaling to DPI scaling (from 72 to OS DPI)
  5. a ghosting issue when focus is lost from the message area to something else (might apply to other cases previously seen).

All changes are in GUI code, no testing needed.

#950 Updated by Greg Shah almost 9 years ago

Code Review ca_upd20150507a.zip

I'm generally fine with the changes. Unfortunately, your nice changes are going to be a be painful for me to merge because they directly modify things that I have refactored. That's OK, it is my problem to deal with.

Please merge to 10848.

#951 Updated by Constantin Asofiei almost 9 years ago

Greg Shah wrote:

Code Review ca_upd20150507a.zip

I'm generally fine with the changes. Unfortunately, your nice changes are going to be a be painful for me to merge because they directly modify things that I have refactored. That's OK, it is my problem to deal with.

Please merge to 10848.

Merged with 10848, only ThinClient was changed.

#952 Updated by Greg Shah almost 9 years ago

Code Review ca_upd20150508a.zip

It's good. Please check it in.

#953 Updated by Constantin Asofiei almost 9 years ago

Greg Shah wrote:

Code Review ca_upd20150508a.zip

It's good. Please check it in.

Committed revision 10849.

#954 Updated by Greg Shah almost 9 years ago

font scaling switched from using legacy metric scaling to DPI scaling (from 72 to OS DPI)

What are the implications of this? Are the calculated metrics are now the same as the ones obtained from the WIN32 APIs? In other words, can we get rid of the Windows text metrics capturing?

#955 Updated by Constantin Asofiei almost 9 years ago

Greg Shah wrote:

font scaling switched from using legacy metric scaling to DPI scaling (from 72 to OS DPI)

What are the implications of this? Are the calculated metrics are now the same as the ones obtained from the WIN32 APIs? In other words, can we get rid of the Windows text metrics capturing?

The current P2J still relies on the captured metrics for the layout purposes. I hope we can remove the dependency on the legacy metrics, but I need to prove that the captured/legacy font and text metrics are the same as the DPI-scaled metrics, before doing this.

#956 Updated by Constantin Asofiei almost 9 years ago

Fixed a regression in rev 10849/ ca_upd20150508a.zip - window resize via mouse was no longer working properly.

#957 Updated by Greg Shah almost 9 years ago

Code Review ca_upd20150508b.zip

I'm fine with the changes. Check them in.

#958 Updated by Constantin Asofiei almost 9 years ago

Greg Shah wrote:

Code Review ca_upd20150508b.zip

I'm fine with the changes. Check them in.

Committed revision 10850.

#959 Updated by Hynek Cihlar almost 9 years ago

I just found the following in ScrollBarGuiImpl. Does anybody know the reason why mouse clicks are handled this way in the scroll bars? Why MouseListener.mouseClicked() is not handled directly?

The code btw. causes concurrent modifications to the UI states and unexpected exceptions when rapidly scrolling the bars. This surely must be fixed either by handling MouseListener.mouseClicked() directly or synchronizing the mouseClicked() call on the UI thread.

   @Override
   public void mousePressed(final MouseEvent e)
   {
      pressed = true;
      if (!isOverThumbButton(e))
      {
         ExecutorService executor = Executors.newSingleThreadExecutor();
         executor.execute(new Runnable() {

            @Override
            public void run()
            {
               while (pressed)
               {
                  try
                  {
                     // wait to see if not a click event
                     Thread.sleep(GuiOptions.REPEAT_MILLIS);
                     // fire mouse clicked
                     if (pressed)
                     {
                        mouseClicked(e);
                     }
                  } 
                  catch (InterruptedException ex)
                  {
                     // nop
                  }
               }
            }

         });
      }
   }

#960 Updated by Hynek Cihlar almost 9 years ago

The attached update improves window scrolling support. This is a first phase update focusing on happy code paths. I am planning another one with complete handling of negative code paths, edge cases, etc.

Please review. Constantin, I've changed WindowLayout.doLayout() please check that as well.

Refernces #2424.

#961 Updated by Constantin Asofiei almost 9 years ago

Hynek Cihlar wrote:

The attached update improves window scrolling support. This is a first phase update focusing on happy code paths. I am planning another one with complete handling of negative code paths, edge cases, etc.

Please review. Constantin, I've changed WindowLayout.doLayout() please check that as well.

Refernces #2424.

WindowGuiLayout uses ConfigManager.isInsideApplyConfig which has been removed, thus compile fails... the scenarios I'm using to test the frame resize are these:
  1. setting default-window:width/height-chars attributes - then resize the window via mouse
  2. implicit window size - then resize the window via mouse.

#962 Updated by Constantin Asofiei almost 9 years ago

Constantin Asofiei wrote:

Hynek Cihlar wrote:

The attached update improves window scrolling support. This is a first phase update focusing on happy code paths. I am planning another one with complete handling of negative code paths, edge cases, etc.

Please review. Constantin, I've changed WindowLayout.doLayout() please check that as well.

Refernces #2424.

WindowGuiLayout uses ConfigManager.isInsideApplyConfig which has been removed, thus compile fails... the scenarios I'm using to test the frame resize are these:
  1. setting default-window:width/height-chars attributes - then resize the window via mouse
  2. implicit window size - then resize the window via mouse.

Looks like letting this code in WindowGuiImpl.afterConfigUpdate:1179 execute unconditionally works:

            if (ConfigManager.getInstance().isInsideApplyConfig()) // remove this condition
            {
               wconfig.widthPixels += dx;
               wconfig.heightPixels += dy;
            }

#963 Updated by Hynek Cihlar almost 9 years ago

The attached replaces hc_upd20150508a.zip and fixes a compilation error. Constantin, what was the purpose of

if (ConfigManager.getInstance().isInsideApplyConfig())
{
   wconfig.widthPixels += dx;
   wconfig.heightPixels += dy;
}

in WindowGuiImpl.afterConfigUpdate()?

#964 Updated by Hynek Cihlar almost 9 years ago

And the file...

Hynek Cihlar wrote:

The attached replaces hc_upd20150508a.zip and fixes a compilation error. Constantin, what was the purpose of

[...]

in WindowGuiImpl.afterConfigUpdate()?

#965 Updated by Constantin Asofiei almost 9 years ago

Hynek Cihlar wrote:

The attached replaces hc_upd20150508a.zip and fixes a compilation error. Constantin, what was the purpose of

[...]

in WindowGuiImpl.afterConfigUpdate()?

I think my complication was caused by the fact that I was saving the width/height at the workspace, before resizing... and when the layout was re-done, the workspace already had the new dimension, so removing the deltas from it was no longer necessary.

Leaving WindowGuiImpl.afterConfigUpdate:1149 like this will work too:

         if (dim.width != config.widthPixels || dim.height != config.heightPixels)
         {
            int dx = dim.width - config.widthPixels;
            int dy = dim.height - config.heightPixels;

            this.resize(dx, dy, false, false, true);
         }

#966 Updated by Greg Shah almost 9 years ago

Code Review hc_upd20150508b.zip

I'm fine with the code once you have agreed with Constantin on the issue in note 965.

The only other concern is that the SESSION:THREE-D value needs to be cached on the server side. We must not take a round trip to the client each time it is queried. Cache it in SessionUtils.WorkArea when it is assigned so that reads are quick. As far as I understand, it will have a default (which can be the same default as on the client) and the only way to change it is to assign SESSION:THREE-D. That means that we never have to take a trip to the client to read the value. We can probably even avoid the trip to the client on any assignment that doesn't change the value (e.g. it is already set to true and set3D is called with true as the parameter).

Finally, you will need to coordinate your check in with Eugenie, who has some conflicting changes (ScrollPaneGuiImpl.java and WindowGuiImpl.java) in #2546 evl_upd20150508b.zip which are being regression tested now.

Since those conflicts are on the GUI side, no regression testing will be needed after the merge.

#967 Updated by Hynek Cihlar almost 9 years ago

Constantin Asofiei wrote:

Hynek Cihlar wrote:

The attached replaces hc_upd20150508a.zip and fixes a compilation error. Constantin, what was the purpose of

[...]

in WindowGuiImpl.afterConfigUpdate()?

I think my complication was caused by the fact that I was saving the width/height at the workspace, before resizing... and when the layout was re-done, the workspace already had the new dimension, so removing the deltas from it was no longer necessary.

Leaving WindowGuiImpl.afterConfigUpdate:1149 like this will work too:
[...]

Just confirming the code works fine. I will include it in my update.

#968 Updated by Hynek Cihlar almost 9 years ago

Tha attached file replaces hc_upd20150508b.zip. It is merged with trunk, and was committed to bzr rev 10855.

#969 Updated by Hynek Cihlar almost 9 years ago

The attached update fixes window scrollable size calculation when window virtual size not set. The change only affects GUI code, Majic regression testing not needed. Commmitted to bzr rev. 10856.

#970 Updated by Hynek Cihlar almost 9 years ago

The update improves drawing of window caption buttons. They are now more alike those from standard Windows theme. Can someone please review the change?

#971 Updated by Constantin Asofiei almost 9 years ago

Hynek Cihlar wrote:

The update improves drawing of window caption buttons. They are now more alike those from standard Windows theme. Can someone please review the change?

Beside a javadoc problem in WindowTitleBar new c'tor (a param is missing javadoc), I'm OK with the changes. You can release them.

#972 Updated by Hynek Cihlar almost 9 years ago

The javadoc problem fixed and the update committed to bzr rev 10857.

#973 Updated by Eugenie Lyzenko almost 9 years ago

Hynek Cihlar wrote:

The update improves drawing of window caption buttons. They are now more alike those from standard Windows theme.

The buttons looks better bit why not to use images to draw these buttons? In this case we have a chance to make the buttons exactly the same as in Windows.

#974 Updated by Hynek Cihlar almost 9 years ago

Eugenie Lyzenko wrote:

Hynek Cihlar wrote:

The update improves drawing of window caption buttons. They are now more alike those from standard Windows theme.

The buttons looks better bit why not to use images to draw these buttons? In this case we have a chance to make the buttons exactly the same as in Windows.

Good question. The problem is that bitmaps don't scale very well. Windows caption buttons are resizable and they don't maintain aspect ratio.

A related problem is also that different versions/themes of Windows draw the caption buttons differently.

The buttons are still not perfect. For example the classic theme of the Windows 2008 server we are trying to mimic uses 3D shading effect. The buttons (and other UI elements, like scroll bars) should have "shadow" on the right and bottom edges.

#975 Updated by Constantin Asofiei almost 9 years ago

Hynek, when you have time, please take a look at testcases/uast/demo/movie-ratings-dynamic.p - in P2J, when setting column/row/width/height (Later Edit: via attributes), the frame size is re-adjusted... this doesn't happen in 4GL. I wonder if we need to add init/clientHeight/Width (as you did for location).

#976 Updated by Hynek Cihlar almost 9 years ago

See the attached update, now the frame seems to be stable.

The problem was in the char->pixel->char conversion. The config char height in this case was adjusted but the adjustment was not reflected in the client frame instance. Due to the difference the frame was readjusting on every server push.

The update is based on ca_upd20150510d.zip.

Constantin Asofiei wrote:

Hynek, when you have time, please take a look at testcases/uast/demo/movie-ratings-dynamic.p - in P2J, when setting column/row/width/height (Later Edit: via attributes), the frame size is re-adjusted... this doesn't happen in 4GL. I wonder if we need to add init/clientHeight/Width (as you did for location).

#977 Updated by Constantin Asofiei almost 9 years ago

Hynek Cihlar wrote:

See the attached update, now the frame seems to be stable.

The problem was in the char->pixel->char conversion. The config char height in this case was adjusted but the adjustment was not reflected in the client frame instance. Due to the difference the frame was readjusting on every server push.

Doesn't work for me... the frame should have the same size as before the widgets start to be placed on the frame via their attributes - that's why I've added a "pause" with the viewed frame, to see the frame size decided by layout manager; this must not change when placing widgets.

#978 Updated by Hynek Cihlar almost 9 years ago

Constantin Asofiei wrote:

Hynek Cihlar wrote:

See the attached update, now the frame seems to be stable.

The problem was in the char->pixel->char conversion. The config char height in this case was adjusted but the adjustment was not reflected in the client frame instance. Due to the difference the frame was readjusting on every server push.

Doesn't work for me... the frame should have the same size as before the widgets start to be placed on the frame via their attributes - that's why I've added a "pause" with the viewed frame, to see the frame size decided by layout manager; this must not change when placing widgets.

It does but it addresses a different issue. I see now what you meant by "adjustment".

#979 Updated by Hynek Cihlar almost 9 years ago

The problem seems to be in mixing the window size vs. the window workspace size. When the frame layouts itself it must be consistent in what size it asks for. This is WIP.

Hynek Cihlar wrote:

Constantin Asofiei wrote:

Hynek Cihlar wrote:

See the attached update, now the frame seems to be stable.

The problem was in the char->pixel->char conversion. The config char height in this case was adjusted but the adjustment was not reflected in the client frame instance. Due to the difference the frame was readjusting on every server push.

Doesn't work for me... the frame should have the same size as before the widgets start to be placed on the frame via their attributes - that's why I've added a "pause" with the viewed frame, to see the frame size decided by layout manager; this must not change when placing widgets.

It does but it addresses a different issue. I see now what you meant by "adjustment".

#980 Updated by Hynek Cihlar almost 9 years ago

Constantin Asofiei wrote:

Hynek, when you have time, please take a look at testcases/uast/demo/movie-ratings-dynamic.p - in P2J, when setting column/row/width/height (Later Edit: via attributes), the frame size is re-adjusted... this doesn't happen in 4GL. I wonder if we need to add init/clientHeight/Width (as you did for location).

Constantin, I played a bit more with the program sample and there are couple of issues. But the one that makes the frame resize is caused by the layout manager. It calculates wrong size of the frame before the main layout pass.

#981 Updated by Constantin Asofiei almost 9 years ago

Hynek Cihlar wrote:

Constantin Asofiei wrote:

Hynek, when you have time, please take a look at testcases/uast/demo/movie-ratings-dynamic.p - in P2J, when setting column/row/width/height (Later Edit: via attributes), the frame size is re-adjusted... this doesn't happen in 4GL. I wonder if we need to add init/clientHeight/Width (as you did for location).

Constantin, I played a bit more with the program sample and there are couple of issues. But the one that makes the frame resize is caused by the layout manager. It calculates wrong size of the frame before the main layout pass.

I think is related to something I was suspecting it will cause us issues: when pushScreenDefinition is called (from an attribute change), the frame layout code is executed again, which is too aggressive - layout should be done only once, when the frame is realized; all subsequent pushScreenDefinition calls as a result of a location (X/Y/COL/ROW), size (WIDTH/HEIGHT-PIXELS/CHARS), format (FORMAT) and maybe other attribute change, needs to work with only the target widget - the frame and all other widgets must remain untouched.

#982 Updated by Hynek Cihlar almost 9 years ago

Constantin Asofiei wrote:

I think is related to something I was suspecting it will cause us issues: when pushScreenDefinition is called (from an attribute change), the frame layout code is executed again, which is too aggressive - layout should be done only once, when the frame is realized; all subsequent pushScreenDefinition calls as a result of a location (X/Y/COL/ROW), size (WIDTH/HEIGHT-PIXELS/CHARS), format (FORMAT) and maybe other attribute change, needs to work with only the target widget - the frame and all other widgets must remain untouched.

I agree, frame layout is executed unnecessarily too often. It looks like layout is never changed after the frame is realized except of the individual widget changes. Even changes like a different frame font doesn't cause a re-layout in 4GL.

Still I think the layout algorithm should give stable results regardless whether it is executed first or second time.

#983 Updated by Hynek Cihlar almost 9 years ago

The attached update fixes a mismatch in frame size caused by char->pixel conversion. This prevents frame size adjustments during frame init. The update passed Majic regression tests. Please review.

#984 Updated by Greg Shah almost 9 years ago

Code Review hc_upd20150513b.zip

I'm OK with it.

Constantin?

#985 Updated by Constantin Asofiei almost 9 years ago

Greg Shah wrote:

Code Review hc_upd20150513b.zip

I'm OK with it.

Constantin?

The changes look OK.

#986 Updated by Hynek Cihlar almost 9 years ago

hc_upd20150513b.zip committed to bzr rev 10862.

#987 Updated by Hynek Cihlar almost 9 years ago

As part of #2559 I have created a set of icon files in SVG format. The application jar file will hold rastr exports of the original files. What is the repo location where to put the original SVGs?

#988 Updated by Constantin Asofiei almost 9 years ago

Hynek, have you had a chance to work on this? If not, I'll take it.

Hynek Cihlar wrote:

Still I think the layout algorithm should give stable results regardless whether it is executed first or second time.

I think some re-layout should be done, but on a limited bases. More, the layout now is more expensive than it used to be (as we need to measure texts), so re-doing it every time the frame def is pushed is time consuming.

For example, the side-label's font can't be set at the frame definition, so the label is measured and placed using the frame (or default) font. Later, if the side-label's font is changed, then we have two cases:
  1. if the widget is realized, then its location is not changed (but its size does change)
  2. if the widget is not realized, some kind of re-layout is done, but only for the affected label

#989 Updated by Hynek Cihlar almost 9 years ago

Constantin Asofiei wrote:

Hynek, have you had a chance to work on this?

No.

If not, I'll take it.

Wonderful!

Hynek Cihlar wrote:

Still I think the layout algorithm should give stable results regardless whether it is executed first or second time.

I think some re-layout should be done, but on a limited bases. More, the layout now is more expensive than it used to be (as we need to measure texts), so re-doing it every time the frame def is pushed is time consuming.

For example, the side-label's font can't be set at the frame definition, so the label is measured and placed using the frame (or default) font. Later, if the side-label's font is changed, then we have two cases:
  1. if the widget is realized, then its location is not changed (but its size does change)
  2. if the widget is not realized, some kind of re-layout is done, but only for the affected label

I think this will require some major overhaul of the layout logic. Currently it works in two phases - in the first it only consideres the "initial" item locations, set at frame definition. Only when all items are at the initial positions it eventually positions them again with the assigned locations, i.e. locations set after the frame is defined. I guess the "initial location" will have to be redefined to a location set (whether during frame def or after) before frame realization.

#990 Updated by Greg Shah almost 9 years ago

Hynek Cihlar wrote:

As part of #2559 I have created a set of icon files in SVG format. The application jar file will hold rastr exports of the original files. What is the repo location where to put the original SVGs?

How are you converting the SVG to bitmaps? Do you do this during the P2J build or statically?

#991 Updated by Hynek Cihlar almost 9 years ago

Greg Shah wrote:

How are you converting the SVG to bitmaps? Do you do this during the P2J build or statically?

Statically. I just want to preserve the original vectors in case different icon sizes are needed for example.

#992 Updated by Greg Shah almost 9 years ago

Create a new repo under ~/repo/p2j_repo/ called images. We can keep things like SVG files there, similar to how we keep ~/repo/p2j_repo/diagrams/.

#993 Updated by Hynek Cihlar almost 9 years ago

The attached implements ALERT-BOX widget in Swing GUI. As related changes it also adds support for modal windows and paragraph layout. Refs #2559.

Please review.

#994 Updated by Greg Shah almost 9 years ago

Code Review hc_upd20150612b.zip

This is a really nice improvement. I especially like the way you abstracted the alert-box functionality into an interface and the common implementation that is shared via delegation, enabling the inheritance from the window hierarchy for the main classes.

1. The AbstractWidget parent/ancestor lookup processing is much improved. It is easier to read and understand. It has much less duplication. While I certainly prefer the new way, my only concern is whether it is fully compatible with the old code. What kind of testing have you done to check this?

2. In the ModalWindow javadoc, you state The window sits at the top of widget hierarchy. I think you are referring to z-order here. But it reads as if you may be referring to the window-parent hierarchy. Please clarify this in the text.

3. What needs to be done to resolve the TODO in ModalWindow.resolveTitleFont()?

4. I see that ModalWindow has disabled the features related to resizing, workspaces, min/max/restore, message and status areas. Are all of these features completely unavailable in all forms of modal window? For example, can't dialog boxes have status areas? If none of these features are ever to be made available, put some comments into the code to note this fact.

5. Please remove the direct references to java.awt.Font and java.awt.image.BufferedImage in AlertBoxGuiImpl, which should not have any AWT/Swing code in it. I don't see any reason to keep the references, but perhaps I'm missing something.

6. The use of addWidgetsRecursive() (used in ModalWindow, WindowGuiImpl, EditorGuiImpl and FrameGuiImpl) doesn't seem to be matched by a removeWidgetsRecursive() (only used in TitledWindow). Is this OK?

#995 Updated by Hynek Cihlar almost 9 years ago

Greg Shah wrote:

1. The AbstractWidget parent/ancestor lookup processing is much improved. It is easier to read and understand. It has much less duplication. While I certainly prefer the new way, my only concern is whether it is fully compatible with the old code. What kind of testing have you done to check this?

I didn't do any specific tests for the parent/ancestor lookup processing. But from the manual testing and Majic regression tests, the new implementation seems to be compatible with the previous.

2. In the ModalWindow javadoc, you state The window sits at the top of widget hierarchy. I think you are referring to z-order here. But it reads as if you may be referring to the window-parent hierarchy. Please clarify this in the text.

Actually I was referring to the window-parent hierarchy. I will clarify the text.

3. What needs to be done to resolve the TODO in ModalWindow.resolveTitleFont()?

The ALERT-BOX in 4GL is implemented in the means of Windows Message box. Its title and body font can't be set from 4GL code. The actual fonts are retrieved from Window's Color/Appearance scheme, namely from the items "Active Title Bar", "Inactive Title Bar" and Message Box for the body/button font.

The font settings for "Active Title Bar" and "Inactive Title Bar" are connected. So I think this is what we currently map to FontManager.WINDOW_TITLE_FONT.

To make this according to 4GL/Windows:
1. AlertBoxGuiImpl.resolveTitleFont() must return FontManager.WINDOW_TITLE_FONT.
2. New system font MESSAGE_BOX must be defined in FontTable.standardFontTable and used in AlertBoxGuiImpl.

I will improve this.

Btw., WindowGuiImpl.resolveTitleFont() allows to override the title font by the value of the window's BaseConfig.titleFont. I didn't find a way to change the font from 4GL code. Is this correct?

4. I see that ModalWindow has disabled the features related to resizing, workspaces, min/max/restore, message and status areas. Are all of these features completely unavailable in all forms of modal window?

They are cetainly unavailable for alert boxes and dialogs.

For example, can't dialog boxes have status areas?

I think they can't.

If none of these features are ever to be made available, put some comments into the code to note this fact.

I'll put a comment in the code to make this clear.

5. Please remove the direct references to java.awt.Font and java.awt.image.BufferedImage in AlertBoxGuiImpl, which should not have any AWT/Swing code in it. I don't see any reason to keep the references, but perhaps I'm missing something.

True, AlertBoxGuiImpl is not AWT/Swing-only implementation so I removed the references to AWT types.

6. The use of addWidgetsRecursive() (used in ModalWindow, WindowGuiImpl, EditorGuiImpl and FrameGuiImpl) doesn't seem to be matched by a removeWidgetsRecursive() (only used in TitledWindow). Is this OK?

I think this is OK. Since all the recursively added widgets are part of the ModalWindow or WindowGuiImpl widget hierarchy, they will be removed as part of TitledWindow.destroy() where removeWidgetsRecursive((Widget) this) is called.

I will post an update when I resolve the regressions I found in the Majic regression tests.

#996 Updated by Greg Shah almost 9 years ago

Btw., WindowGuiImpl.resolveTitleFont() allows to override the title font by the value of the window's BaseConfig.titleFont. I didn't find a way to change the font from 4GL code. Is this correct?

I think this is correct.

Constantin?

#997 Updated by Constantin Asofiei almost 9 years ago

Greg Shah wrote:

Btw., WindowGuiImpl.resolveTitleFont() allows to override the title font by the value of the window's BaseConfig.titleFont. I didn't find a way to change the font from 4GL code. Is this correct?

I think this is correct.

Constantin?

Yes, 4GL doesn't allow changing the window's caption font.

#998 Updated by Hynek Cihlar almost 9 years ago

For #2559, I have resolved all the points from the last review, fixed all regressions and other bugs found. The changes are committed to task branch 2559 and pass Majic regression tests. Please review.

#999 Updated by Greg Shah almost 9 years ago

Code Review Task Branch 2559 rev 10881

I'm good with the changes. Please merge to trunk, commit and notify.

#1000 Updated by Hynek Cihlar almost 9 years ago

Task branch 2559 has been committed to bzr trunk, revision 10882.

#1001 Updated by Hynek Cihlar almost 9 years ago

For #2559, please review regression fixes committed to task branch 2559b. The changes do not affect ChUI so no Majic regression testing is required.

#1002 Updated by Eugenie Lyzenko almost 9 years ago

Hynek Cihlar wrote:

For #2559, please review regression fixes committed to task branch 2559b. The changes do not affect ChUI so no Majic regression testing is required.

There are new drawing issues.

1. As you can see on 0620_0.jpg the window has vertical scrollbar that is not required. Even if it would be required the upper scroll button is hidden by the window title.

2. To much painting I guess. Every mouse move causes the window to be repainted. The result - on the picture 0620_0.jpg the mouse is over the opened drop-down and it is visible, on the picture 0620_1.jpg the mouse is over the rest frame workspace(not covered by opened drop-down) and this causes the drop-down to be overlapped by the frame area. Looks like the drop-down is closed but really it is opened but not visible. Why do we need the full repainting for mouse move?

#1003 Updated by Greg Shah almost 9 years ago

Code Review Task Branch 2559b Revision 10883

I'm fine with the changes.

Am I correct to assume the other items Eugenie has found are not related to the fixes in this revision?

Also, I don't see any fix for the button mouse processing problem Eugenie reported. Is that fix still in process?

#1004 Updated by Hynek Cihlar almost 9 years ago

Greg Shah wrote:

Code Review Task Branch 2559b Revision 10883

I'm fine with the changes.

Am I correct to assume the other items Eugenie has found are not related to the fixes in this revision?

Correct, these fixes don't target the other issues. I'll fix them as part of 2559b as well.

Also, I don't see any fix for the button mouse processing problem Eugenie reported. Is that fix still in process?

The problem with the buttons was caused by LineBorder setting its insets to 1 character. The result was a shift for every LineBorder in the widget hierarchy and physical location not matched with the rendered location. So the buttons (and other widgets) were misplaced. This was a latent bug uncovered by on of my changes, in particular enabling the conversion of AbstractWidget.location to AbstractWidget.physicalLocation.

#1005 Updated by Hynek Cihlar almost 9 years ago

Eugenie Lyzenko wrote:

Hynek Cihlar wrote:

For #2559, please review regression fixes committed to task branch 2559b. The changes do not affect ChUI so no Majic regression testing is required.

There are new drawing issues.

1. As you can see on 0620_0.jpg the window has vertical scrollbar that is not required. Even if it would be required the upper scroll button is hidden by the window title.

The main window height was not properly calculated and so the scrollbar was shown when it should not have. This is a bug I have introduced and fix will be shortly available in the task branch 2559b.

As far as the scrollbar drawing issues go, these seem to have been introduced by bzr rev 10881. Eugenie, can you please look at it?

2. To much painting I guess. Every mouse move causes the window to be repainted. The result - on the picture 0620_0.jpg the mouse is over the opened drop-down and it is visible, on the picture 0620_1.jpg the mouse is over the rest frame workspace(not covered by opened drop-down) and this causes the drop-down to be overlapped by the frame area. Looks like the drop-down is closed but really it is opened but not visible. Why do we need the full repainting for mouse move?

You are right, widget redraws are triggered by mouse move events. But this is something which existed even before my update. I am still investigating this.

#1006 Updated by Eugenie Lyzenko almost 9 years ago

The main window height was not properly calculated and so the scrollbar was shown when it should not have. This is a bug I have introduced and fix will be shortly available in the task branch 2559b.

As far as the scrollbar drawing issues go, these seem to have been introduced by bzr rev 10881. Eugenie, can you please look at it?

As you noted the issue is wrong window height calculation. I think when it will be fixed the scrollbar in main window will gone. As to your note about 10881 I think we have mutual conflict for 10881 and update you released. Because I have not seen the issue with my tests at the time the 10881 was released.

You are right, widget redraws are triggered by mouse move events. But this is something which existed even before my update. I am still investigating this.

Yes, but something was changed that triggers the wrong painting and I want to know what it is. I suggest the order of painting is a good candidate. If the container is about to be painted but created before drop-down - it can be moved in a front of Z-ordering and this can be the root cause. Have you changed/modified painting order of the widgets?

#1007 Updated by Hynek Cihlar almost 9 years ago

Eugenie Lyzenko wrote:

The main window height was not properly calculated and so the scrollbar was shown when it should not have. This is a bug I have introduced and fix will be shortly available in the task branch 2559b.

As far as the scrollbar drawing issues go, these seem to have been introduced by bzr rev 10881. Eugenie, can you please look at it?

As you noted the issue is wrong window height calculation. I think when it will be fixed the scrollbar in main window will gone. As to your note about 10881 I think we have mutual conflict for 10881 and update you released. Because I have not seen the issue with my tests at the time the 10881 was released.

Eugenie, in ScrollBarGuiImpl.drawScrollBarThumb(int, int, double) when range becomes smaller then visibleRange the thumb size and top button position are calculated wrong. The button is drawn at coordinates outside of the visible region, that is why the scrollbar on your screenshot is missing the top button.

Also in ScrollPaneGuiImpl, line 469, the calculated max value being passed to setMax() is truncated and so the thumb size increments are bigger then they should be. You can see this when resizing the main window, the thumb size "jumps" by these increments.

Also the algorithm to calculate thumb position doesn't seem to give proper thumb position when scrolling. The thumb travels too fast hitting the end before the scrollable area itself gets to the end.

Yes, but something was changed that triggers the wrong painting and I want to know what it is.

This is most likely related to the latent bug in LineBorder. It's been fixed in the task branch 2559b (you can check it out by bzr checkout ~/secure/code/p2j_repo/p2j/active/2559b). You can either try the fix or send me the test case you were referring to and I will test it myself.

#1008 Updated by Greg Shah almost 9 years ago

Hynek: I think you should merge task branch 2559b revision 10883 with trunk and commit it. This will allow Eugenie to take your changes, which are safe for now.

This means you'll have to move your other pending changes to 2559c and revert any commits in 2559b before archiving.

What do you think?

#1009 Updated by Hynek Cihlar almost 9 years ago

Greg, there is a change that affects ChUI so I would like to finish regression testing first.

#1010 Updated by Hynek Cihlar almost 9 years ago

The task branch 2559b has been merged with trunk. Eugenie, you can now merge the fixes by updating the trunk branch.

#1011 Updated by Eugenie Lyzenko almost 9 years ago

Hynek Cihlar wrote:

The task branch 2559b has been merged with trunk. Eugenie, you can now merge the fixes by updating the trunk branch.

OK. Confirm the painting issues I've recently found are gone.

#1012 Updated by Constantin Asofiei almost 9 years ago

Hynek Cihlar wrote:

The task branch 2559b has been merged with trunk. Eugenie, you can now merge the fixes by updating the trunk branch.

Please take a look at the widget browser - highlighting the widget no longer works with rev 10885.

#1013 Updated by Constantin Asofiei almost 9 years ago

Constantin Asofiei wrote:

Hynek Cihlar wrote:

The task branch 2559b has been merged with trunk. Eugenie, you can now merge the fixes by updating the trunk branch.

Please take a look at the widget browser - highlighting the widget no longer works with rev 10885.

Nevermind, it was a side-effect from my changes...

#1014 Updated by Hynek Cihlar almost 9 years ago

Constantin Asofiei wrote:

Constantin Asofiei wrote:

Hynek Cihlar wrote:

The task branch 2559b has been merged with trunk. Eugenie, you can now merge the fixes by updating the trunk branch.

Please take a look at the widget browser - highlighting the widget no longer works with rev 10885.

Nevermind, it was a side-effect from my changes...

Still, there is a bug causing the highlighted area to be drawn incorrectly, with an offset. This seems to be a combination of a bug in one of the controls and the way widget browser restores the highlight.

#1015 Updated by Constantin Asofiei almost 9 years ago

Greg, do we need SPACE in GUI? I was playing with some ChUI tests and GUI doesn't support yet the SPACE clause.

#1016 Updated by Greg Shah almost 9 years ago

Constantin Asofiei wrote:

Greg, do we need SPACE in GUI? I was playing with some ChUI tests and GUI doesn't support yet the SPACE clause.

Yes, SPACE is in use (as is SKIP).

#1017 Updated by Hynek Cihlar almost 9 years ago

For #2559 I have:

Fixed calculation of workspace size in redirection mode.
Fixed some unhandled exceptions when showing a modal window.
Fixed some javadocs.

Committed to task branch 2559d, please review.

#1018 Updated by Greg Shah almost 9 years ago

Code Review Task Branch 2559d Revision 10888

The changes look good to me. Please get them tested.

#1019 Updated by Hynek Cihlar over 8 years ago

Task branch 2559d passed regression testing and was committed to trunk as revision 10888.

#1020 Updated by Constantin Asofiei over 8 years ago

Rebased task branch 1796b from P2J trunk revision 10888 (branch revision 10890).

#1021 Updated by Hynek Cihlar over 8 years ago

Rebased task branch 2559e from P2J trunk revision 10894 (branch revision 10893).

#1022 Updated by Constantin Asofiei over 8 years ago

Rebased task branch 1796b from P2J trunk revision 10893 (branch revision 10898).

#1023 Updated by Hynek Cihlar over 8 years ago

For #2559 I have:

Implemented window modality independently on the actual UI driver.
Improved positioning of top-level windows on systems with multiple displays.
Improved parent-child relatioship of top-level windows.
Implemented support for call-stack logging.

Committed to task branch 2559e revision 10896. Regression testing is in progress. Please review.

#1024 Updated by Constantin Asofiei over 8 years ago

Greg, a conversion question; in 4GL, the following frames are equivalent:

display "ab" with frame f1.
display "a" + "b" with frame f2.

In P2J, only f1's expression has its format set to 2, as this is a constant; for f2, P2J assumes that the expression can't be evaluated at conversion time so the format will not be set.

Thus: what do you think is the proper way to solve this? Let the parser concatenate the string literals or do it at conversion time (and only when we need to determine if the expression evaluates to a constant, thus format length can be computed)?

#1025 Updated by Greg Shah over 8 years ago

Code Review Task Branch 2559e Revision 10896

This is good.

1. It is not a big deal, but I'd prefer a better way to abstract the WindowManager code such that it didn't have GUI-specific logic (direct references to GuiDriver). We are trying to evolve the ui/client/ directory to be completely neutral to ChUI/GUI and this adds a new dependency. If we don't have a good idea to solve the abstraction problem, then we can defer it.

2. We can eliminate the apache dependency in WindowManager by using Utils.integerCollectionToPrimitive().

3. Is it better for LogHelper.dumpStackTrace() to output to STDERR instead of STDOUT? With STDOUT, these could not be used on a ChUI client.

#1026 Updated by Hynek Cihlar over 8 years ago

Greg Shah wrote:

Code Review Task Branch 2559e Revision 10896

This is good.

1. It is not a big deal, but I'd prefer a better way to abstract the WindowManager code such that it didn't have GUI-specific logic (direct references to GuiDriver). We are trying to evolve the ui/client/ directory to be completely neutral to ChUI/GUI and this adds a new dependency. If we don't have a good idea to solve the abstraction problem, then we can defer it.

I see two solutions.

1. Promote WindowManager to be both ChUI and GUI specific and move it to a better namespace.

2. Factor out the GUI specific logic into a new GUI class. The GUI-specific logic would also include other GUI-specific methods like placeWindow().

2. We can eliminate the apache dependency in WindowManager by using Utils.integerCollectionToPrimitive().

Done.

3. Is it better for LogHelper.dumpStackTrace() to output to STDERR instead of STDOUT? With STDOUT, these could not be used on a ChUI client.

Good point. Done.

#1027 Updated by Hynek Cihlar over 8 years ago

Hynek Cihlar wrote:

Greg Shah wrote:

Code Review Task Branch 2559e Revision 10896

This is good.

1. It is not a big deal, but I'd prefer a better way to abstract the WindowManager code such that it didn't have GUI-specific logic (direct references to GuiDriver). We are trying to evolve the ui/client/ directory to be completely neutral to ChUI/GUI and this adds a new dependency. If we don't have a good idea to solve the abstraction problem, then we can defer it.

I see two solutions.

1. Promote WindowManager to be both ChUI and GUI specific and move it to a better namespace.

2. Factor out the GUI specific logic into a new GUI class. The GUI-specific logic would also include other GUI-specific methods like placeWindow().

Greg, do you have any preferences on this? Also, regression testing of 2559e passed.

#1028 Updated by Greg Shah over 8 years ago

Go ahead and merge 2559e into the trunk.

The next time we have some work in WindowManager, we can make some factoring improvements. But let's not worry about this right now. I think the best approach is to create GUI and ChUI subclasses of WindowManager that can have more specialized functionality, while leaving most logic in the base class.

#1029 Updated by Hynek Cihlar over 8 years ago

Greg Shah wrote:

I think the best approach is to create GUI and ChUI subclasses of WindowManager that can have more specialized functionality, while leaving most logic in the base class.

Yes, this corresponds with point 2 above. I only didn't expect any ChUI-specific features, hence no ChUI-specific sublass.

#1030 Updated by Greg Shah over 8 years ago

I only didn't expect any ChUI-specific features, hence no ChUI-specific sublass.

I see. Good.

#1031 Updated by Hynek Cihlar over 8 years ago

Task branch 2559e committed to trunk as revision 10894.

#1032 Updated by Greg Shah over 8 years ago

Constantin Asofiei wrote:

Greg, a conversion question; in 4GL, the following frames are equivalent:
[...]
In P2J, only f1's expression has its format set to 2, as this is a constant; for f2, P2J assumes that the expression can't be evaluated at conversion time so the format will not be set.

Thus: what do you think is the proper way to solve this? Let the parser concatenate the string literals or do it at conversion time (and only when we need to determine if the expression evaluates to a constant, thus format length can be computed)?

Although it could be resolved in either the lexer or the parser, I think it is best to be done very early in annotations. The reasons:

  1. the logic is simplest there
  2. we can most easily implement this for all cases (not just for cases related to frame definitions)
  3. it allows us to leave the original AST closer to the original 4GL code, which one day we may want to be able to anti-parse back out to 4GL without losing "knowledge"

The most likely reason for it to be used in the 4GL code is for readability (e.g. breaking long strings into multiple lines). Merging such cases into a single literal in annotations gives us more flexibility in the future.

#1033 Updated by Hynek Cihlar over 8 years ago

Rebased task branch 2424 from P2J trunk revision 10894 (branch revision 10896).

#1034 Updated by Constantin Asofiei over 8 years ago

Rebased task branch 1796b from P2J trunk revision 10894 (branch revision 10906).

#1035 Updated by Greg Shah over 8 years ago

CUT/COPY/PASTE have alternative key mappings in Windows. I think we need to add those to GuiKeyboard.standardKeyFunctions():

=== modified file 'src/com/goldencode/p2j/ui/client/gui/GuiKeyboard.java'
--- src/com/goldencode/p2j/ui/client/gui/GuiKeyboard.java    2014-12-21 11:04:18 +0000
+++ src/com/goldencode/p2j/ui/client/gui/GuiKeyboard.java    2015-07-08 13:42:22 +0000
@@ -2,7 +2,7 @@
 ** Module   : GuiKeyboard.java
 ** Abstract : Keyboard configuration for Windows GUI clients. 
 **
-** Copyright (c) 2014, Golden Code Development Corporation.
+** Copyright (c) 2014-2015, Golden Code Development Corporation.
 ** ALL RIGHTS RESERVED. Use is subject to license terms.
 **
 **           Golden Code Development Corporation
@@ -11,6 +11,7 @@
 ** -#- -I- --Date-- ---------------------------------Description----------------------------------
 ** 001 CA  20141029 Created initial version.
 ** 002 CA  20141220 Added mapping for COPY/CTRL-C key function.
+** 003 GES 20150708 Added alternative mappings for CUT/COPY/PASTE key functions.
 */

 package com.goldencode.p2j.ui.client.gui;
@@ -45,8 +46,8 @@
       res.put(CURSOR_LEFT,  new String[] {"CURSOR-LEFT"});
       res.put(CURSOR_RIGHT, new String[] {"CURSOR-RIGHT"});
       res.put(CURSOR_UP,    new String[] {"CURSOR-UP"});  
-      res.put(COPY,         new String[] {"CTRL-C"});
-      res.put(CUT,          new String[] {"CTRL-X"});
+      res.put(COPY,         new String[] {"CTRL-C", "CTRL-INS"});
+      res.put(CUT,          new String[] {"CTRL-X", "SHIFT-DEL"});

       res.put(DELETE_CHARACTER, new String[] {"DEL"});

@@ -74,7 +75,7 @@

       res.put(PAGE_DOWN,  new String[] {"PAGE-DOWN", "PGDN", "NEXT-PAGE", "NEXT-SCRN"});
       res.put(PAGE_UP,    new String[] {"PAGE-UP", "PGUP", "PREV-PAGE", "PREV-SCRN"});
-      res.put(PASTE,      new String[] {"CTRL-V"});
+      res.put(PASTE,      new String[] {"CTRL-V", "SHIFT-INS"});
       res.put(PREV_FRAME, new String[] {"SHIFT-F6"});
       res.put(PUT,        new String[] {"F6"});

Any objections? These changes can also be seen in task branch 1811o revision 10896.

#1036 Updated by Hynek Cihlar over 8 years ago

This relates to #2424.

I identified a problem related to the max allowed window size. In GUI, a window widget truncates height/width to some maximum values. See below.

def var h as handle.
create window h.
view h.
h2:HEIGHT-CHARS = 5000.

There is a limit of the pixel height which will be applied and as a consequence the character height adjusted as well. In this case the resulted height will be cca 65450 pixels and cca 3117 characters.

We have assumed that these maximum values were constants, but this is not true. It seems that 4GL calculates these maximum values based on window decorations - i.e. window caption size and border size.

I didn't find any way to get the dimensions of window decorations from a 4GL program. This complicates testing, as the test case has no way to calculate the limits, as well as runtime behavior, as the limits must be calculated from the decorations.

The question is how far should we go to replicate this? I can't imagine a valid case of assigning these limit values. Obviously the simplest solution would be to stick to some constant values and somehow patch the automated testing.

#1037 Updated by Greg Shah over 8 years ago

It seems that 4GL calculates these maximum values based on window decorations - i.e. window caption size and border size.

The window decoration dimensions are values that we hard code in P2J based on the chosen Windows theme, correct?

Please document the algorithm used by the 4GL which relies on these sizes.

I didn't find any way to get the dimensions of window decorations from a 4GL program. This complicates testing, as the test case has no way to calculate the limits, as well as runtime behavior, as the limits must be calculated from the decorations.

I'm OK with providing the test suite with the decoration sizes needed to check the resulting sizes against. These will only change when we change the Windows theme that is configured in P2J. Generally, these will be the same from run to run, since I don't expect us to change the theme often.

The question is how far should we go to replicate this?

I'd like to see the algorithm before we make this call.

#1038 Updated by Hynek Cihlar over 8 years ago

Greg Shah wrote:

The window decoration dimensions are values that we hard code in P2J based on the chosen Windows theme, correct?

For window caption, this is true. The caption height is determined based on the height of the used window title font. This is externalized in a P2J directory.

The window border size is however hardcoded to a constant value.

I'm OK with providing the test suite with the decoration sizes needed to check the resulting sizes against. These will only change when we change the Windows theme that is configured in P2J. Generally, these will be the same from run to run, since I don't expect us to change the theme often.

A Windows theme may differ with Windows versions. Also the global text size scaling factor may influence the caption size.

#1039 Updated by Greg Shah over 8 years ago

The window border size is however hardcoded to a constant value.

I expect that we will allow this to be configured as well. The default value should be part of the theme.

A Windows theme may differ with Windows versions.

Yes, but for us it is going to be something that we configure. We really need to abstract all the theme values (sizes, fonts, colors...) into a set of classes (one for each theme we support). Then at runtime, we would lookup the configured theme for the user's session (and if not configured, use a default theme). All the values that the 4GL would have to lookup from the Windows APIs would be in that theme. This may go beyond the concept of a "Windows theme", but it is the best way to do it in my opinion.

Also the global text size scaling factor may influence the caption size.

This is something we must know already, right?

#1040 Updated by Hynek Cihlar over 8 years ago

Greg Shah wrote:

A Windows theme may differ with Windows versions.

Yes, but for us it is going to be something that we configure. We really need to abstract all the theme values (sizes, fonts, colors...) into a set of classes (one for each theme we support). Then at runtime, we would lookup the configured theme for the user's session (and if not configured, use a default theme). All the values that the 4GL would have to lookup from the Windows APIs would be in that theme. This may go beyond the concept of a "Windows theme", but it is the best way to do it in my opinion.

As I understand, the expected result is to provide the same look-and-feel of the native 4GL environment including OS-drawn UI elements like window decorations. So yes, externalizing the theme elements is probably the best way.

Also the global text size scaling factor may influence the caption size.

This is something we must know already, right?

Yes, P2J widgets rendering text use the actual font sizes. I was more concerned about the test cases. If we use constant size limits, these may not work on the same Windows version with the same theme. A way out of this could be an interactive calibration process that would provide these (and possibly other) dynamic values that cannot be determined from 4GL runtime.

#1041 Updated by Greg Shah over 8 years ago

A way out of this could be an interactive calibration process that would provide these (and possibly other) dynamic values that cannot be determined from 4GL runtime.

Yes, I'm OK with providing input to the test code so that it can calculate the comparison values. We may want to configure that via a configuration file that is read at the start of testing. I imagine that file won't change often.

#1042 Updated by Hynek Cihlar over 8 years ago

Greg Shah wrote:

The question is how far should we go to replicate this?

I'd like to see the algorithm before we make this call.

WINDOW:HEIGHT*/WIDTH* attributes represent the window work space area, that is the window's external size less decorations, status and message area. Changing window title bar size and window border size in the Windows theme settings affects WINDOW:HEIGHT-PIXELS/WIDTH-PIXELS linearly. When pixel HEIGHT/WIDTH is added to the observed window decoration sizes the result is a constant of 65529 pixels for both width and height.

I am not sure how the Windows font scaling affects this equation (it can't be changed in the Windows remote session) but I think it is reasonable to assume that the different font size would affect the title's size, message and status area. This would lead to different max sizes reported by WINDOW:HEIGHT*/WIDTH* but the external size would still be constant.

The window_sizing tests will have the max sizes parametrized. The value will be simply determined by running a simple special-purpose 4GL program.

#1043 Updated by Greg Shah over 8 years ago

OK, please go ahead and implement a compatible max sizing algorithm.

Also, it seems to me that now is the time to go ahead and implement a cleaner set of classes for encoding the themes.

I am not sure how the Windows font scaling affects this equation (it can't be changed in the Windows remote session) but I think it is reasonable to assume that the different font size would affect the title's size, message and status area. This would lead to different max sizes reported by WINDOW:HEIGHT*/WIDTH* but the external size would still be constant.

Unless Constantin can think of a way to check this, leave a TODO for checking that the global font scaling case is working as expected.

#1044 Updated by Hynek Cihlar over 8 years ago

Greg Shah wrote:

Also, it seems to me that now is the time to go ahead and implement a cleaner set of classes for encoding the themes.

Ok.

You mentioned you would like to see a set of classes each representing an actual supported theme. The way I interpret this is that when new theme needs to be supported P2J must be recompiled. I think this is a bit limiting factor. How about a class representing any of the themes with instances of this class representing all supported themes? The class would declare fields covering all the interesting theme parameters.

Each theme would be identified with a Windows version and theme name, two themes with the same names may have different parameters between Windows versions.

Unless Constantin can think of a way to check this, leave a TODO for checking that the global font scaling case is working as expected.

Ok.

#1045 Updated by Hynek Cihlar over 8 years ago

For #2424, please assess whether any of these should be replicated in P2J.

Case 1

DEF VAR h AS HANDLE.
CREATE WINDOW h.
h:MAX-HEIGHT-CHARS = 4999.
VIEW h.
h:HEIGHT-CHARS = 5000.
MESSAGE h:HEIGHT-CHARS.

This prints:
3116.95

DEF VAR h AS HANDLE.
CREATE WINDOW h.
h:MAX-HEIGHT-CHARS = 5000.
VIEW h.
h:HEIGHT-CHARS = 5000.
MESSAGE h:HEIGHT-CHARS.

This prints:
39.48

Case 2

DEF VAR h AS HANDLE.
CREATE WINDOW h.
h:MAX-HEIGHT-CHARS = 5000.
VIEW h.
h:HEIGHT-CHARS = 5000.
MESSAGE h:HEIGHT-CHARS.
h:HEIGHT-CHARS = 5000.
MESSAGE h:HEIGHT-CHARS.

This prints:
39.48
3120.71

Case 3

DEF VAR h AS HANDLE.
CREATE WINDOW h.
VIEW h.
h:HEIGHT-CHARS = 5000.
MESSAGE h:HEIGHT-CHARS.
h:HEIGHT-CHARS = 5000.
/*h:WIDTH-CHARS = 1.*/
MESSAGE h:HEIGHT-CHAR

This prints:
3116.95
3120.71

DEF VAR h AS HANDLE.
CREATE WINDOW h.
VIEW h.
h:HEIGHT-CHARS = 5000.
MESSAGE h:HEIGHT-CHARS.
h:HEIGHT-CHARS = 5000.
h:WIDTH-CHARS = 1.
MESSAGE h:HEIGHT-CHAR

This prints:
3116.95
3116.95

The above samples use HEIGHT-CHARS attribute, but similar behavior is exhibited by WIDTH-CHARS, HEIGHT-PIXELS and WIDTH-PIXELS.

#1046 Updated by Greg Shah over 8 years ago

I am guessing that when converted to a pixel value (based on the default font's metrics), that (at least some of) these cases the maximum/minimum value can be calculated based on truncation at some fixed pixel value.

For example, 32767 / 3116.95 = 10.5125202522. This 10.5 value looks suspiciously like a possible height in pixels of a single character in the font that is being used.

And 39.48 * 10.5125202522 = 415.0342995557 which looks like 400 + the size of the title bar and borders.

Please try to determine the algorithms behind these quirks and do implement it. Although it is hard to see many ways in which these can be used productively, we have found (over and over) that taking short cuts does not pay off in the end. Eventually we find some stupid code that relies upon these behaviors and then someone has to spend the time to debug (often subtle issues) and find out that we are missing something. We have found that the time to implement these things is up front, having carefully explored all the ridiculous behavior.

#1047 Updated by Hynek Cihlar over 8 years ago

The value of 39.48 seems to be the height of the display less window decorations. The value indeed copies screen resolution when I start the remote session with different display settings of the host computer.

The different values of 3116.95 and 3120.71 are more puzzling to me. So far I haven't figured out any rational logic behind this. But I am working on it.

#1048 Updated by Hynek Cihlar over 8 years ago

It seems that 4GL internally limits coordinates to smaller values than allowed in positional attributes (X, Y).

Here is a sample code.

DEF VAR h AS HANDLE.
DEF VAR r AS HANDLE.

h = DEFAULT-WINDOW.

h:HEIGHT-PIXELS = 33300.
MESSAGE "Window height-pixels: " h:HEIGHT-PIXELS.

DISPLAY "" WITH FRAME f.

FRAME f:X = 100.
FRAME f:Y = 33200.
FRAME f:WIDTH-PIXELS = 100.
FRAME f:HEIGHT-PIXELS = 100.

MESSAGE "Frame 1 y: " FRAME f:Y.

DISPLAY "" WITH FRAME f2.

FRAME f2:X = 250.
FRAME f2:Y = 32700.
FRAME f2:WIDTH-PIXELS = 100.
FRAME f2:HEIGHT-PIXELS = 400.

MESSAGE "Frame 2 y: " FRAME f2:Y.

CREATE RECTANGLE r.

r:X = 10.
r:Y = 300.
r:WIDTH-PIXELS = 80.
r:HEIGHT-PIXELS = 80.
r:FRAME = FRAME f2:HANDLE.

VIEW r.

PAUSE.

See the program output in the screenshot attached. It shows an application window of dimensions 400x33300 pixels. The window is moved to negative Y so that the bottom of the window is visible on the screen.

The message area is not at the usual place but instead at the position 32767 pixels relative to the origin of the window workspace. This seems to be the maximum real Y the message area can be rendered at.

The frame on the left is assigned Y of 33200 pixels, but the actual rendered position is again 32767 pixels relative to the origin of the window workspace. While the frame is rendered at Y of 32767, the reported Y is 33200.

The frame on the right is rendered at the assigned position. Also the rectangle is rendered at the expected position.

Another interesting point is that the main window can be moved to a minimum Y-position of -32768.

This leads me to a conclusion that the actual pixel positions a main window or widgets can reach are truncated to the min/max values of a 2's complement 16bit number relative to screen origin or widget's parent.

Again, is this something we want to replicate in P2J?

#1049 Updated by Greg Shah over 8 years ago

The window is moved to negative Y so that the bottom of the window is visible on the screen.

Is this implicitly done when the window is too large to fit on the current screen?

The message area is not at the usual place but instead at the position 32767 pixels relative to the origin of the window workspace. This seems to be the maximum real Y the message area can be rendered at.

A strange quirk.

32767 pixels relative to the origin of the window workspace. While the frame is rendered at Y of 32767, the reported Y is 33200.

Another instance of the same quirk, I guess.

Another interesting point is that the main window can be moved to a minimum Y-position of -32768.

Negative Y coordinates seem necessary for the case where there are multiple screens.

This leads me to a conclusion that the actual pixel positions a main window or widgets can reach are truncated to the min/max values of a 2's complement 16bit number relative to screen origin or widget's parent.

I think your conclusion makes sense.

Again, is this something we want to replicate in P2J?

The support for negative X and Y must be there. Any implicit movement of the window when it is too big must be there.

The only concerning part is the truncation at 32767. It is pretty strange and I don't see much application utility in it. On the other hand, it doesn't seem too hard to implement. Are we really saving much time to avoid this?

#1050 Updated by Hynek Cihlar over 8 years ago

Greg Shah wrote:

The window is moved to negative Y so that the bottom of the window is visible on the screen.

Is this implicitly done when the window is too large to fit on the current screen?

No, I moved the window manually (by sending a Win32 move message to it (WM_MOVE)).

This leads me to a conclusion that the actual pixel positions a main window or widgets can reach are truncated to the min/max values of a 2's complement 16bit number relative to screen origin or widget's parent.

I think your conclusion makes sense.

Again, is this something we want to replicate in P2J?

The support for negative X and Y must be there.

Yes, this is already implemented.

The only concerning part is the truncation at 32767. It is pretty strange and I don't see much application utility in it. On the other hand, it doesn't seem too hard to implement. Are we really saving much time to avoid this?

To implement this, we would have to modify the client model to distinguish the position reported by attributes and the actual rendered positions. Window layout manager and frame layout logic would have to be updated as well - this would have to cover frame items as well. I think at least one man-day worth of efforts.

#1051 Updated by Greg Shah over 8 years ago

On the other hand, it doesn't seem too hard to implement. Are we really saving much time to avoid this?

To implement this, we would have to modify the client model to distinguish the position reported by attributes and the actual rendered positions. Window layout manager and frame layout logic would have to be updated as well - this would have to cover frame items as well. I think at least one man-day worth of efforts.

Although this isn't too much time, I think the areas that have to be touched are already fragile.

How about this: on the server, detect when this condition would arise and only in that case call UnimplementedFeature.todo(). This way we will see if we ever encounter this and it should be clear what the problem is. It will leave the client code untouched for now.

#1052 Updated by Hynek Cihlar over 8 years ago

Greg Shah wrote:

On the other hand, it doesn't seem too hard to implement. Are we really saving much time to avoid this?

To implement this, we would have to modify the client model to distinguish the position reported by attributes and the actual rendered positions. Window layout manager and frame layout logic would have to be updated as well - this would have to cover frame items as well. I think at least one man-day worth of efforts.

Although this isn't too much time, I think the areas that have to be touched are already fragile.

Yes.

How about this: on the server, detect when this condition would arise and only in that case call UnimplementedFeature.todo(). This way we will see if we ever encounter this and it should be clear what the problem is. It will leave the client code untouched for now.

Very well! Will do.

#1053 Updated by Sergey Ivanovskiy over 8 years ago

Greg, Hynek
What is the reason to implement a JFrame for any normal 4GL window and a JWindow for alert-boxes/dialog-boxes? What is the target behavior of such pairs?
Would you like to explore visibility/z-order/task-switching/focus dependencies of JFrame and JWindow?

Don't consider it as a suggestion but if JWindow is replaced by JDialog, then a desktop task switching will be more fitted, and JDialog gives possibilities to control fine tuning of modality.

#1054 Updated by Hynek Cihlar over 8 years ago

Sergey Ivanovskiy wrote:

Don't consider it as a suggestion but if JWindow is replaced by JDialog, then a desktop task switching will be more fitted,

Could you be more specific?

and JDialog gives possibilities to control fine tuning of modality.

Originally JDialogs were indeed used, but there were problems with positioning on systems with multiple displays. Thus modality was taken out of the driver and implemented in higher layers. The advantage is that modality now works in all GUI drivers.

#1055 Updated by Constantin Asofiei over 8 years ago

Rebased task branch 1796b from P2J trunk revision 10895 (branch revision 10914).

#1056 Updated by Sergey Ivanovskiy over 8 years ago

Hynek Cihlar wrote:

Sergey Ivanovskiy wrote:

Don't consider it as a suggestion but if JWindow is replaced by JDialog, then a desktop task switching will be more fitted,

Could you be more specific?

and JDialog gives possibilities to control fine tuning of modality.

Originally JDialogs were indeed used, but there were problems with positioning on systems with multiple displays. Thus modality was taken out of the driver and implemented in higher layers. The advantage is that modality now works in all GUI drivers.

Thanks Hynek, my questions are raised due to this code #1811 #note-725 and its meaning related to UI implementation is hidden from me for now. :(

#1057 Updated by Constantin Asofiei over 8 years ago

Rebased task branch 1796b from P2J trunk revision 10896 (branch revision 10915).

#1058 Updated by Constantin Asofiei over 8 years ago

Rebased task branch 1796b from P2J trunk revision 10897 (branch revision 10916).

#1059 Updated by Hynek Cihlar over 8 years ago

Rebased task branch 2424b from P2J trunk revision 10897 (branch revision 10898).

#1060 Updated by Constantin Asofiei over 8 years ago

Rebased task branch 1796b from P2J trunk revision 10898 (branch revision 10923).

Please review branch 1796b, revision 10924 - MAJIC should be fine (one more run to clear false negatives), need to finish checking standalone tests.

#1061 Updated by Constantin Asofiei over 8 years ago

Constantin Asofiei wrote:

Rebased task branch 1796b from P2J trunk revision 10898 (branch revision 10923).

Please review branch 1796b, revision 10924 - MAJIC should be fine (one more run to clear false negatives), need to finish checking standalone tests.

MAJIC runtime/conversion testing has passed. There are expected changes in the generated MAJIC code.

Revision 10925 can be merged with trunk if review is OK.

#1062 Updated by Greg Shah over 8 years ago

Code Review Task Branch 1796b Revision 10923

Interesting, I didn't realize that the num + date form of the + operator was valid.

For a future improvement: should we implement an empty finishConfigProcessing() in GenericWidget so that GenericFrame.finishConfigProcessing() does not have to have widget-specific logic? The BrowseWidget would have a real implementation. The only concern is if there is a scenario where the MenuContainerWidget.finishConfigProcessing() is a conflict.

Stanislav: please review these changes, as there are many that are browse-related. I think they are fine, but perhaps you will see something that I missed.

Constantin/Stanislav: please discuss the order of your updates. Stanislav has 2422b in testing right now, which has conflicts with 1796b. If the 2422b has any open issues in regression testing, then I'd prefer to allow 1796b to be merged to trunk and committed. This will save "churn" for 1796b. However, if 2422b is ready to be merged to trunk and committed, then we need to determine which one goes first. I'll let the two of you decide.

Constantin: what work is left for #1796? Is it just the todos in the code? Should they be resolved now or scheduled for later?

#1063 Updated by Constantin Asofiei over 8 years ago

Greg Shah wrote:

Constantin: what work is left for #1796?

The next issues I have on the list are these (in order if priority):
  1. solved - drawing of DOWN frames in GUI (easy to solve)
  2. solved - widget positioning in DOWN frames (correct support of FRAME- coordinate attributes and X, Y, ROW, COLUMN attributes for DOWN frames).
  3. solved - pushScreenDefinition lock for CREATE ... ASSIGN case

Is it just the todos in the code? Should they be resolved now or scheduled for later?

The TODOs are these:
  1. widget can not go outside of the frame's size, if frame is realized, height/width must not exceed window size! - these are edge cases for widget positioning/dimension, can be left for later
  2. solved - Frame.postprocess - TODO for relayout() call in case when dynamic down needs to be re-computed - I'll try to solve this one now. If I can't find an easy fix, I'll leave it for later.
  3. Frame.getMinimumSize - this can be left for later, as it is used only in an error message in Frame.canSetWidthChars
  4. removed - ScrollGuiContainer.draw - why are we not clipping here? - I think this one can be removed; a null clipping rectangle does not reset the clipping rectangle, but instead it inherits the one from any parent draw calls.
  5. ZeroColumnLayout.minimumSize - only if layout was not already performed - I think the minimumSize API is called only during layout, I can't find relevant cases where is called outside of it.
  6. GenericFrame.down - why not use redirOut, in case of named streams? - to me it seems there is a flaw here; if redirOut is set, then we are sending the DOWN to the unnamed stream, not the actual stream... I'm not sure of the implications if I change it to the redirOut's ID.

Hynek, beside this there are some frame size issues: the frame size is not computed correct in these tests in testcases/uast/frame_layout: frame-scrolling-size.p, at_grows_frame.p, half_fixed_position.p. Do you think these will be covered by your frame scrolling changes?

#1064 Updated by Hynek Cihlar over 8 years ago

Constantin Asofiei wrote:

Hynek, beside this there are some frame size issues: the frame size is not computed correct in these tests in testcases/uast/frame_layout: frame-scrolling-size.p, at_grows_frame.p, half_fixed_position.p. Do you think these will be covered by your frame scrolling changes?

This may be related to the VIRT* attributes of the Window widget I am working on. I will test the cases you mention.

#1065 Updated by Greg Shah over 8 years ago

In regard to the #1796 remaining items: anything left for later should have its own task created and linked here as a related task. If that task needs to be done for M12, set the target version accordingly.

#1066 Updated by Greg Shah over 8 years ago

Are the issues documented in #2567 notes 12 (CA - #1796) and 19 (CA - #1796) already addressed in 1796b?

Hynek: Are you planning to resolve the #2567 note 15 problem in your #2424 changes?

#1067 Updated by Hynek Cihlar over 8 years ago

Greg Shah wrote:

Are the issues documented in #2567 notes 12 (CA - #1796) and 19 (CA - #1796) already addressed in 1796b?

Hynek: Are you planning to resolve the #2567 note 15 problem in your #2424 changes?

The problem with wrong X/Y values will be resolved with #2424. I am assuming the other problem in note 15 is/will be handled by Constantin.

#1068 Updated by Constantin Asofiei over 8 years ago

Greg Shah wrote:

For a future improvement: should we implement an empty finishConfigProcessing() in GenericWidget so that GenericFrame.finishConfigProcessing() does not have to have widget-specific logic? The BrowseWidget would have a real implementation. The only concern is if there is a scenario where the MenuContainerWidget.finishConfigProcessing() is a conflict.

Yes, it's cleaner to do it this way. MenuContainerWidget.finishConfigProcessing() can never be attached to a frame AFAIK, so this will not be a conflict. I'll change it now.

#1069 Updated by Constantin Asofiei over 8 years ago

Please review branch 1796b revision 10926. It adds support for drawing down frames in GUI, fixes note 1068 and some other issues.

I'll try to solve the TODO in Frame.postprocess before releasing 1796b.

#1070 Updated by Stanislav Lomany over 8 years ago

I'm OK with the update. There is a regression in 2422b and, besides, there is conflicting change in DOWN processing, so I let Constantin to check in first.

#1071 Updated by Greg Shah over 8 years ago

Code Review Task Branch 1796b Revision 10926

1. Should GenericWidget.finishConfigProcessing() be protected instead of package private, so that someone outside of the com.goldencode.p2j.ui package could subclass?

2. ConfigFieldSetterAspect needs a copyright update for 2015.

You can merge/check in when testing passes.

#1072 Updated by Constantin Asofiei over 8 years ago

Branch 1796b revision 10927 was merged to trunk revision 10899. Branch 1796b was archived.

#1073 Updated by Constantin Asofiei over 8 years ago

Created branch 1796c from trunk revision 10899.

#1074 Updated by Eugenie Lyzenko over 8 years ago

Constantin,

The trunk 10899 after merging 1796b introduces significant regression in all my GUI combo-box tests. Frame with top labels places widgets incorrectly(one char up from expected place). The result - unable to work with widgets by mouse, the mouse source can not be determined correctly. The screenshot attached with wrong places in red. The fill-in cursor is also in wrong place.

Unfortunately it is show stopper for my work. So I have to return to the previous trunk base and defer my branch rebase.

#1075 Updated by Constantin Asofiei over 8 years ago

Eugenie Lyzenko wrote:

Constantin,

The trunk 10899 after merging 1796b introduces significant regression in all my GUI combo-box tests. Frame with top labels places widgets incorrectly(one char up from expected place). The result - unable to work with widgets by mouse, the mouse source can not be determined correctly. The screenshot attached with wrong places in red. The fill-in cursor is also in wrong place.

Unfortunately it is show stopper for my work. So I have to return to the previous trunk base and defer my branch rebase.

The body doesn't account for the frame's title - comment for now the title and you will have back the combo responsiveness. I'm working on a fix in the mean time.

#1076 Updated by Constantin Asofiei over 8 years ago

Please review branch 1796c rev 10900 and 10901:
  • 10900: it fixes the TODO in Frame.postprocess (from note 1063)
  • 10901: it fixes a regression in drawing frames with titles in GUI

Runtime testing has passed for rev 10900 - I'd like to merge it.

#1077 Updated by Greg Shah over 8 years ago

Code Review Task Branch 1796c Revision 10901

I am fine with the changes.

Go ahead and merge to trunk.

#1078 Updated by Constantin Asofiei over 8 years ago

Greg Shah wrote:

Go ahead and merge to trunk.

Branch 1796c was merged to trunk rev 10900 and archived. Created branch 1796d from trunk rev 10900.

#1079 Updated by Hynek Cihlar over 8 years ago

Rebased task branch 2424b from P2J trunk revision 10900 (branch revision 10907).

#1080 Updated by Constantin Asofiei over 8 years ago

Hynek, do you have a testcases for this error, when setting the X or Y attribute in ChUI:

         String msg = String.format(
               "**Unable to set attribute %s on %s widget in the current environment", 
               x ? "X" : "Y", 
               type());

I ask because the following test works fine in ChUI:

def var i as int.
def var ch as char.

form i ch with frame f1 10 down size 40 by 20.

do i = 1 to 10:
   ch = string(i).
   display i ch with frame f1.
   down with frame f1.
end.

up 5 with frame f1.
i:bgcolor = 3.
i:row = 10.
pause.
i:col = 2.
pause.
i:y = 80.
pause.
i:x = 100.
pause.

#1081 Updated by Hynek Cihlar over 8 years ago

Constantin Asofiei wrote:

Hynek, do you have a testcases for this error, when setting the X or Y attribute in ChUI:
[...]

Yes, the code you mention handles window positioning in ChUI. Obviously non-window widgets can be positioned fine by the X/Y attributes. I will put this on my todo list.

#1082 Updated by Constantin Asofiei over 8 years ago

Hynek Cihlar wrote:

Constantin Asofiei wrote:

Hynek, do you have a testcases for this error, when setting the X or Y attribute in ChUI:
[...]

Yes, the code you mention handles window positioning in ChUI. Obviously non-window widgets can be positioned fine by the X/Y attributes. I will put this on my todo list.

If is enough to just let BaseEntity.canSetPixelPositionInChui return true by default and override in WindowWidget.canSetPixelPositionInChui to return false, then I'll make the change - it affects my work with FRAME- attributes.

#1083 Updated by Hynek Cihlar over 8 years ago

Constantin Asofiei wrote:

If is enough to just let BaseEntity.canSetPixelPositionInChui return true by default and override in WindowWidget.canSetPixelPositionInChui to return false, then I'll make the change - it affects my work with FRAME- attributes.

Yes, overriding BaseEntity.canSetPixelPositionInChui should be enough. I am removing this from my todo list. Thanks.

#1084 Updated by Constantin Asofiei over 8 years ago

Please review branch 1796d, rev 10901 - it includes FRAME- attribute support for all cases of frames: it was simple, just compute offsets (on client-side) from which a certain widget is drawn (from the frame's top-label header) and adjust the X/Y/ROW/COLUMN and FRAME-X/Y/ROW/COLUMN accordingly, all on server-side. When there are no top-labels and no down body, the offsets will be 0, so nothing is changed in how frame and field-group relative coordinates are processed.

From note 1063 I have left only "pushScreenDefinition lock for CREATE ... ASSIGN case" - please let me know if this is a high priority or not.

#1085 Updated by Hynek Cihlar over 8 years ago

Constantin, wnd.setMessageText(null, null) in ThinClient.pause removes any existing messages from the window message area which seems to be in contrast how 4GL behaves. Is there any use case that indeed clears the messages? If not, I will remove the occurrences of wnd.setMessageText(null, null).

#1086 Updated by Constantin Asofiei over 8 years ago

Hynek Cihlar wrote:

Constantin, wnd.setMessageText(null, null) in ThinClient.pause removes any existing messages from the window message area which seems to be in contrast how 4GL behaves. Is there any use case that indeed clears the messages? If not, I will remove the occurrences of wnd.setMessageText(null, null).

I don't have an exact test, but I'm pretty sure this is something which is ChUI specific - message area in some cases does get reset. Maybe is worth it to call this only for ChUI mode?

#1087 Updated by Hynek Cihlar over 8 years ago

Constantin Asofiei wrote:

Hynek Cihlar wrote:

Constantin, wnd.setMessageText(null, null) in ThinClient.pause removes any existing messages from the window message area which seems to be in contrast how 4GL behaves. Is there any use case that indeed clears the messages? If not, I will remove the occurrences of wnd.setMessageText(null, null).

I don't have an exact test, but I'm pretty sure this is something which is ChUI specific - message area in some cases does get reset. Maybe is worth it to call this only for ChUI mode?

Indeed, in ChUI, pause clears the messages. I have committed a fix to task branch 2424b revision 10908.

#1088 Updated by Hynek Cihlar over 8 years ago

Rebased task branch 2424b from P2J trunk revision 10901 (branch revision 10910).

#1089 Updated by Constantin Asofiei over 8 years ago

Rebased task branch 1796d from P2J trunk revision 10901 (branch revision 10905).

#1090 Updated by Greg Shah over 8 years ago

Code Review Task Branch 1796d Revision 10906

FillInGuiImpl, FrameGuiImpl, LabelGuiImpl, ScrollPaneGuiImpl, WindowGuiImpl need history entries. Otherwise, I'm good with the changes.

Once you have the CREATE ASSIGN locking fix, plan to merge up with Stanislav's 2422b update that should be passing soon. Then you can go into testing next.

#1091 Updated by Constantin Asofiei over 8 years ago

Greg Shah wrote:

Once you have the CREATE ASSIGN locking fix, plan to merge up with Stanislav's 2422b update that should be passing soon. Then you can go into testing next.

I've managed to find a test which I think it shows that CREATE ASSIGN has no "batching" behavior and all assignments are done in sequence. SENSITIVE attribute can not be set UNTIL AFTER the widget has been attached to a frame, regardless where it is set (in CREATE ASSIGN or later). The following test:

def var h as handle.

define frame fx with size 20 by 20.

create fill-in h
assign x = 10
       y = 10
       sensitive = true
       format = "x(10)" 
       data-type = "character" 
       frame = frame fx:handle.

view frame fx.

wait-for close of current-window.

produces this error:
**Unable to process SENSITIVE attribute.  FILL-IN widget is not in a frame.
(4073)

But, what we can do is use the frame sync locking as an improvement, to send all configs in a batch, to client-side. So, I'll continue with the conversion changes.

#1092 Updated by Constantin Asofiei over 8 years ago

Please review branch 1796d:
  • revisions 10907, 10908, 10909 contain more fixes for drawing a GUI frame (down/title/side-label/box combinations). The only issue left at this time is a "frame focus": on mouse click, the frame's title is highlighted, even if the focused widget is not part of the frame being clicked. But the weird part is that the FOCUS handle reports the actual focus, not the newly-clicked frame. So, any frame which doesn't have the focused widget will have the title drawn in "disabled state" for now.
  • revision 10910 adds support for the frame lock/unlock for CREATE ASSIGN. I've added new parser tokens (FRAME_LOCK and FRAME_UNLOCK) for which nodes are created by annotations/embedded_attribute_assign_rewrite.rules. This will also pass as an argument the widget handle which requires its frame to be locked. So the generated code will look like:
                DynamicWidgetFactory.createFillIn(h);
                DynamicWidgetFactory.pushScreenLock(h);
                ...
                DynamicWidgetFactory.pushScreenUnlock(h);
    

    Why I chose the approach of passing the handle as an argument: in the feature, the frame lock/unlock feature can be used for any contiguous widget attribute assignment, either when writing P2J-compatible java code by hand or by some custom rules - so P2J may be able to batch assignments even outside of CREATE ASSIGN.

#1093 Updated by Greg Shah over 8 years ago

Code Review Task Branch 1796d Revision 10910

My only questions:

1. Why are the FRAME_LOCK/FRAME_UNLOCK nodes needed? Why not just implement this as descent/ascent rules?

2. The FRAME_LOCK node is created as the previous sibling of the stmtref (STATEMENT/CREATE_WIDGET). Doesn't that yield this incorrect ordering:

            DynamicWidgetFactory.pushScreenLock(h);  <--- h is invalid at this point and it won't work
            DynamicWidgetFactory.createFillIn(h);
            ...
            DynamicWidgetFactory.pushScreenUnlock(h);

Did I miss something in my analysis?

#1094 Updated by Constantin Asofiei over 8 years ago

Greg Shah wrote:

Code Review Task Branch 1796d Revision 10910

My only questions:

1. Why are the FRAME_LOCK/FRAME_UNLOCK nodes needed? Why not just implement this as descent/ascent rules?

Doing this on ascent/descent requires lots of hacks to emit the references to than handle var/field, so that is emitted as an argument. Using these new node types lets the statements emit naturally, without complicating things. If we remove the argument, then we can do this on descent/ascent with no problem.

2. The FRAME_LOCK node is created as the previous sibling of the stmtref (STATEMENT/CREATE_WIDGET). Doesn't that yield this incorrect ordering:

[...]

Did I miss something in my analysis?

Using stmtref.indexPos as location for FRAME_LOCK node will move the existing stmtref one position to the right and FRAME_LOCK will take its place, as previous sibling. Note that here stmtref is the STATEMENT parent node for the KW_ASSIGN. So the order of the nodes will be:

    <ast col="0" id="5463198400540" line="0" text="statement" type="STATEMENT">
      <ast col="1" id="5463198400541" line="5" text="create" type="CREATE_WIDGET">
         ...
      </ast>
      <ast col="0" id="5463198400676" line="0" text="" type="FRAME_LOCK">
        ...
      </ast>
      <ast col="0" id="5463198400675" line="0" text="" type="STATEMENT">
        <ast col="1" id="5463198400549" line="6" text="assign" type="KW_ASSIGN">
           ...
        </ast>
      </ast>
      <ast col="0" id="5463198400678" line="0" text="" type="FRAME_UNLOCK">
         ...
      </ast>

#1095 Updated by Constantin Asofiei over 8 years ago

Rebased task branch 1796d from P2J trunk revision 10902 (new branch revision 10912).

Testing has already passed for pre-rebase rev 10910 - I'm running one more time to be sure the code is compatible with trunk rev 10902.

Please review branch 10912 - I've added progress.g, which was missing from previous commit.

#1096 Updated by Greg Shah over 8 years ago

Code Review Task Branch 1796d Revision 10912

I'm fine with the changes. And we can stick with the new token approach to locking. If it passes testing, please merge to trunk.

#1097 Updated by Constantin Asofiei over 8 years ago

Greg Shah wrote:

Code Review Task Branch 1796d Revision 10912

I'm fine with the changes. And we can stick with the new token approach to locking. If it passes testing, please merge to trunk.

Branch 1796d rev 10913 (with some header/javadoc fixes) passed testing and was merged to trunk rev 10903 and archived.

#1098 Updated by Constantin Asofiei over 8 years ago

Hynek, sorry for the delay about this one:

I am not sure how the Windows font scaling affects this equation (it can't be changed in the Windows remote session) but I think it is reasonable to assume that the different font size would affect the title's size, message and status area. This would lead to different max sizes reported by WINDOW:HEIGHT*/WIDTH* but the external size would still be constant.

In 4GL, the window's message and status area are linked with the configured DEFAULT-FONT in progress.ini. Only the window's title is linked with some OS font.

#1099 Updated by Hynek Cihlar over 8 years ago

Constantin Asofiei wrote:

Hynek, sorry for the delay about this one:

I am not sure how the Windows font scaling affects this equation (it can't be changed in the Windows remote session) but I think it is reasonable to assume that the different font size would affect the title's size, message and status area. This would lead to different max sizes reported by WINDOW:HEIGHT*/WIDTH* but the external size would still be constant.

In 4GL, the window's message and status area are linked with the configured DEFAULT-FONT in progress.ini. Only the window's title is linked with some OS font.

Constantin, thanks for the note. It is as you say.

In addition to the title font set in OS theme settings, there exists this global font scaling which also affects the title rendering. The result may be for example two systems with the same theme settings having differently rendered window titles.

But this should not be a big deal anyway.

#1100 Updated by Hynek Cihlar over 8 years ago

Rebased task branch 2424b from P2J trunk revision 10906 (branch revision 10916).

#1101 Updated by Greg Shah over 8 years ago

Code Review Task Branch 2424b Revision 10916

Overall, the update is quite good. I assume you are planning to add history entries to all the files.

1. There is a debug println in methods_attributes.rules line 528.

2. SyncCoordinatesAspect has explicit imports that should be wildcards. There is also some missing javadoc for the suspend/resume methods and thread-local data member.

3. BaseEntity.validateSize() is missing javadoc.

4. BaseEntity.setSizePixels() has a TODO that has no text so it is not clear what the missing feature is.

5. ConfigHelper has an import that should be a wildcard. There is missing javadoc for the new getters.

6. Coordinate.RoundingMode needs javadoc.

7. CoordinatesConversion has an import that should be a wildcard. There is missing javadoc for columnFromPixels() and rowFromPixels().

8. WindowConfig.unrealizedMaxHeightPixels is missing javadoc.

9. Why did you remove the WindowWidget.setMaxHeightChars(double)/setMaxWidthChars(double) variants? This seems like a valid use case from converted code.

10. WindowWidget.validateSize() is missing javadoc.

11. There is a merge problem with the history entries in ThinClient.

#1102 Updated by Hynek Cihlar over 8 years ago

Greg Shah wrote:

Code Review Task Branch 2424b Revision 10916

Greg, the code still needs cleanup and is missing some javadocs and proper file history entries. This will be done today.

9. Why did you remove the WindowWidget.setMaxHeightChars(double)/setMaxWidthChars(double) variants? This seems like a valid use case from converted code.

These should not have been removed, thanks for noticing.

Thanks,
Hynek

#1103 Updated by Hynek Cihlar over 8 years ago

Constantin Asofiei wrote:

Hynek, beside this there are some frame size issues: the frame size is not computed correct in these tests in testcases/uast/frame_layout: at_grows_frame.p.

In the case of at_grows_frame.p the frame's virtual size is not properly calculated. My changes related to #2424 don't solve this.

#1104 Updated by Hynek Cihlar over 8 years ago

Constantin Asofiei wrote:

Hynek, beside this there are some frame size issues: the frame size is not computed correct in these tests in testcases/uast/frame_layout: frame-scrolling-size.p, half_fixed_position.p.

frame-scrolling-size.p abends for me, I didn't investigate further:

java.lang.RuntimeException: Invalid frame ID 4
    at com.goldencode.p2j.ui.chui.ThinClient.getFrame(ThinClient.java:12085)
    at com.goldencode.p2j.ui.chui.ThinClient.getChanges(ThinClient.java:11688)
    at com.goldencode.p2j.net.Protocol.attachChanges(Protocol.java:274)
    at com.goldencode.p2j.net.Queue.enqueueOutbound(Queue.java:810)
    at com.goldencode.p2j.net.Dispatcher.processInbound(Dispatcher.java:765)

half_fixed_position.p seems to be the same case as at_grows_frame.p. Frame's virtual width should be increased and all widgets fit on one line. Again, not affected with #2424.

#1105 Updated by Constantin Asofiei over 8 years ago

Hynek Cihlar wrote:

frame-scrolling-size.p abends for me, I didn't investigate further:

Something has regressed, the test does not abend with trunk rev 10906.

#1106 Updated by Hynek Cihlar over 8 years ago

Constantin Asofiei wrote:

Hynek Cihlar wrote:

frame-scrolling-size.p abends for me, I didn't investigate further:

Something has regressed, the test does not abend with trunk rev 10906.

Strange, it does abend for me with trunk rev 10906. I have cleaned and rebuilt p2j and reconverted the test.

#1107 Updated by Constantin Asofiei over 8 years ago

Hynek Cihlar wrote:

Constantin Asofiei wrote:

Hynek Cihlar wrote:

frame-scrolling-size.p abends for me, I didn't investigate further:

Something has regressed, the test does not abend with trunk rev 10906.

Strange, it does abend for me with trunk rev 10906. I have cleaned and rebuilt p2j and reconverted the test.

I was checking in ChUI... in GUI does abend for me, too.

#1108 Updated by Hynek Cihlar over 8 years ago

Please review task branch 2424b, revision 10921. This among others resolves the comments from the review of revision 10916. Regression test is in progress.

#1109 Updated by Greg Shah over 8 years ago

Code Review Task Branch 2424b Revision 10921

I'm good with the changes.

the code still needs cleanup and is missing some javadocs and proper file history entries.

Yes, I understood this. It is not a negative reflection on you. I wanted to do a review so that you could incorporate any changes needed and thus get this turned around as quickly as possible.

#1110 Updated by Hynek Cihlar over 8 years ago

Branch 2424b has passed conversion and runtime regression tests, was merged to trunk rev 10907, and archived.

#1111 Updated by Hynek Cihlar over 8 years ago

Created task branch 2424c. This will hold some generic scrolling fixes and potential changes related to frame scrolling.

#1112 Updated by Hynek Cihlar over 8 years ago

Greg Shah wrote:

Code Review Task Branch 2424b Revision 10921

I'm good with the changes.

the code still needs cleanup and is missing some javadocs and proper file history entries.

Yes, I understood this. It is not a negative reflection on you. I wanted to do a review so that you could incorporate any changes needed and thus get this turned around as quickly as possible.

This is surely no problem at all. I am glad you went ahead with the review.

#1113 Updated by Greg Shah over 8 years ago

Hynek: Are you planning to include fixes for at_grows_frame.p/half_fixed_position.p and frame-scrolling-size.p in 2424c?

#1114 Updated by Hynek Cihlar over 8 years ago

Greg Shah wrote:

Hynek: Are you planning to include fixes for at_grows_frame.p/half_fixed_position.p and frame-scrolling-size.p in 2424c?

Yes, unless Constantin already has a solution.

#1115 Updated by Constantin Asofiei over 8 years ago

Hynek, about SwingEmulatedWindow.layoutParagraphWorker (we need an equivalent for the web client) - this is supposed to draw some text so that it fits a certain width. I have some questions here:
  1. how confident are you this splits the text exactly how 4GL does it?
  2. do you know the rules by which the text is split in lines? What delimiters are used to identify the words?

#1116 Updated by Hynek Cihlar over 8 years ago

Constantin Asofiei wrote:

Hynek, about SwingEmulatedWindow.layoutParagraphWorker (we need an equivalent for the web client) - this is supposed to draw some text so that it fits a certain width. I have some questions here:
  1. how confident are you this splits the text exactly how 4GL does it?
  2. do you know the rules by which the text is split in lines? What delimiters are used to identify the words?

The functionality was created for laying out text in ALERT-BOX GUI widget. In native 4GL the widget is not implemented by 4GL but it directly maps to the Windows message box control.

The algorithm used in SwingEmulatedWindow.layoutParagraphWorker uses java.awt.font.LineBreakMeasurer which works as follows: Every word that fits within the wrapping width is placed on the line. If the first word does not fit, then all of the characters that fit within the wrapping width are placed on the line. At least one character is placed on each line. Words are separated with white spaces. No hyphen is used to brake words.

Windows message box control uses the same algorithm for braking long texts.

#1117 Updated by Hynek Cihlar over 8 years ago

Rebased task branch 2424c from P2J trunk revision 10923 (branch revision 10930).

#1118 Updated by Constantin Asofiei over 8 years ago

Created branch 2563c from trunk rev 10923 with a fix for the editor drawing issue: EditorGuiImpl.refresh must call repaint, not perform drawing (revision 10924)

#1119 Updated by Constantin Asofiei over 8 years ago

Created branch 2451d from trunk rev 10923. Branch rev 10924/10925 is meant to fix some issues related to positioning/drawing numeric fill-in's when widget width is longer than editable/format length. Also I found some GUI behavior which I've overlooked until now, in order of complexity:
  1. solved - only zzz give right-aligned widgets, 999 will be left-aligned (actually this is common for ChUI too)
  2. solved - 999 format in GUI works in "overwrite" mode (as if INS key is on) unless the caret is after the last right-side character: in this case, all chars input there (while caret is past the last pos) are inserted, as if INS is off.
  3. backspace is applied in P2J to the current position, not to the left-side positioned digit. This is a difference between 4GL GUI and ChUI...
  4. solved - zzz format is left-padded with spaces (as needed), but in GUI if there are no digits, the fill-in content will be empty or, if exists, only the left/right user-chars are shown. Actually, the formatted result (when editing) for all numeric formats are right-trimmed and also SCREEN-VALUE reports the right-trimmed value. The STRING function does not right-trim the format.
  5. digit inserting for certain formats is problematic in GUI. This is mostly related to the fact that P2J (and ChUI 4GL) for numeric formats it moves the leading digits plus the current digit one on step left-side and the inserted digit is placed on the current index. This is not how GUI behaves: inserting a digit is done before the caret (and the current index).

#1120 Updated by Hynek Cihlar over 8 years ago

It seems we have two classes that implement the "viewport" part of the widget scrolling feature - Viewport and ScrollContainer. They both serve the similar purpose of providing a visible portion of a larger area being scrolled underneath. They also seem to provide duplicate implementations for some of the viewport logic while some are implemented differently (for example Viewport stores the visible scroll size in the standard widget size attributes but ScrollContainer introduces new fields for the same). ScrollContainer is used for frame widgets in conjunction with Viewport (as a child widget) while non-frame widgets only use Viewport.

Why do we provide two different implementations of the viewport feature? Why is ScrollContainer being attached to a Viewport when it seems to be superior in terms of provided functionalities?

I am trying to understand the intentions of this design in order to improve and unite the scroll bar visuals across different widgets.

#1121 Updated by Greg Shah over 8 years ago

I think the dual-implementation is purely historical. Sergey Yevtushenko wrote the original ViewPort when we were replacing Charva as the backing support for ChUI. The idea was to eliminate that library because it simply did very little for us, but imposed quite a bit of additional requirements/overhead. The implementation of ViewPort certainly would not have considered any of the detailed requirements of GUI. We had not started GUI yet.

The ScrollContainer was created by Marius when he was implementing an early version of GUI. He potentially did not even know that ViewPort existed.

Do not feel constrained in any way by this history. If ViewPort can be eliminated, that would be great.

#1122 Updated by Hynek Cihlar over 8 years ago

Greg Shah wrote:

I think the dual-implementation is purely historical. Sergey Yevtushenko wrote the original ViewPort when we were replacing Charva as the backing support for ChUI. The idea was to eliminate that library because it simply did very little for us, but imposed quite a bit of additional requirements/overhead. The implementation of ViewPort certainly would not have considered any of the detailed requirements of GUI. We had not started GUI yet.

The ScrollContainer was created by Marius when he was implementing an early version of GUI. He potentially did not even know that ViewPort existed.

Do not feel constrained in any way by this history. If ViewPort can be eliminated, that would be great.

Ok, I will attempt to merge Viewport and ScrollContainer into one entity. This should simplify the design quite a bit and resolve some of the issues I am facing.

#1123 Updated by Constantin Asofiei over 8 years ago

Rebased branch 2451d from trunk rev 10924 (new branch rev 10926). Rev 10927 contains right-trimming of numeric fill-ins at editing (is common for both ChUI and GUI). Also some attempts at fixing backspace/digit insert in GUI - the NumberFormat is pretty sensitive and I'm not quite sure how to integrate the GUI rules. I'll leave this on hold and use 1811 as priority.

Rebased branch 2563c from trunk rev 10924 (new branch rev 10926). This can be released.

#1124 Updated by Constantin Asofiei over 8 years ago

There is a regression in trunk in the MAJIC function browser - the highlighted text is not removed from the previous row when navigating via cursor. I think this is related to some of my previous layout or down-frame related changes.

#1125 Updated by Greg Shah over 8 years ago

Code Review Task Branch 2563c Revision 10926

I'm fine with the changes. You can merge to trunk.

#1126 Updated by Constantin Asofiei over 8 years ago

Greg Shah wrote:

Code Review Task Branch 2563c Revision 10926

I'm fine with the changes. You can merge to trunk.

Rebased branch 2563c from trunk rev 10925. Rev 10928 contains a better fix for this - I've checked mouse support, selection, undo, caret and is OK now. EditorGuiImpl.refresh() needs to redraw because it can be called from multiple call paths - either from an event processing loop or even originate from server-side, when a editor 4GL method is called.

#1127 Updated by Greg Shah over 8 years ago

Code Review Task Branch 2563c Revision 10928

It looks good. You can merge to trunk.

#1128 Updated by Constantin Asofiei over 8 years ago

Greg Shah wrote:

Code Review Task Branch 2563c Revision 10928

It looks good. You can merge to trunk.

Merged to trunk rev 10926 and archived.

#1129 Updated by Hynek Cihlar over 8 years ago

Rebased task branch 2424c from P2J trunk revision 10927 (branch revision 10943).

#1130 Updated by Hynek Cihlar over 8 years ago

I identified a new issue related to size calculation of scroll pane and its child widgets manifesting as frame scroll container size being not correct. I didn't notice this bug sooner as the size differences are small, equal to the size of the frame border.

The core of the problem is that the sizing logic isn't properly formulated (there are multiple places where the size is calculated and the places interfere with each other - ScrollPane.setSize(), ScrollPaneGuiImpl.adjustViewportSize(), Viewport.setSize(), FrameGuiImpl.resizeScrollPane()) and that ScrollPane/ScrollPaneGuiImpl is packed with too many responsibilities - besides holding the scroll components and handling some of the scroll bar logic it also implements a border panel, a single-purpose draw method for frame items and serves as the direct content container for frames.

The solution to this is to better isolate the ChUI and GUI size calculation logic in ScrollPane/ScrollPaneGuiImpl, not to use ScrollPaneGuiImpl as the direct content container in frames, and to replace the border panel implementation in ScrollPaneGuiImpl with BorderPanel class. This all will allow to eliminate the complicated size calculation logic scattered across the multiple classes.

#1131 Updated by Hynek Cihlar over 8 years ago

I needed to add GUI drawing logic to BorderedPanel. Instead of mixing ChUI and GUI code in one class I split it in two new classes BorderedPanelImpl and BorderedPanelGuiImpl with BorderedPanel as a base class. With this change the class can no longer be used as a base class for widgets that require a border appearance, instead one of the concrete border classes must be used as a composite. This change allowed to encapsulate the border GUI drawing in a single place and to remove the duplicate implementations of border drawing. Anyway I think it was too constraining to model the border appearance through inheritance, yet border is only one of the many widget visuals and should not deserve any special treatment.

#1132 Updated by Hynek Cihlar over 8 years ago

Rebased task branch 2424c from P2J trunk revision 10929 (branch revision 10949).

#1133 Updated by Hynek Cihlar over 8 years ago

Rebased task branch 2424c from P2J trunk revision 10930 (branch revision 10950).

#1134 Updated by Hynek Cihlar over 8 years ago

Please review 2424c revision 10954. Although it is not yet free of issues, it is close to be finished.
The changes provide the followings,

- Scrolling support overhaul.
- Added conversion methods for Insets.
- Fixed the value of config realized field for default window.
- MIN/MAX size attribute values must be fixed after window is realized.
- Widgets are automatically detached from their parents when destroyed.
- Improved GUI window resize performance.
- Fixed cursor position to be stable in respect to the widget corner while dragging.
- Removed repaint() call from AbstractContainer.setSize().
- Border panel refactored to make it suitable for composition.

#1135 Updated by Greg Shah over 8 years ago

Code Review Task Branch 2424c Revision 10954

I like the improvements very much! It certainly is more regular and easier to understand. Nice work! I did check in some minor cleanups as rev 10955.

1. One future improvement would be to improve abstraction such that there would not be widget-specific code in classes like ScrollPanelImpl. We have quite a bit of code there that is specific to classes like DropDown (as a parent), SelectionListBody (as a child) and Frame (as a parent). There are similar dependencies in ScrollPaneGuiImpl. This is not something for now.

2. Please add javadoc to ScrollableSelectionListGuiImpl.fixTopRow().

#1136 Updated by Hynek Cihlar over 8 years ago

Greg Shah wrote:

1. One future improvement would be to improve abstraction such that there would not be widget-specific code in classes like ScrollPanelImpl. We have quite a bit of code there that is specific to classes like DropDown (as a parent), SelectionListBody (as a child) and Frame (as a parent). There are similar dependencies in ScrollPaneGuiImpl. This is not something for now.

Exactly, this is especially true for ChUI code. Another common pattern which is not ideal is implementing GUI widget/logic by extending ChUI-specific classes and hiding the ChUI implementations.

2. Please add javadoc to ScrollableSelectionListGuiImpl.fixTopRow().

Fixed.

#1137 Updated by Hynek Cihlar over 8 years ago

Update for 2424c. I have cleaned up all known ChUI regressions and I will be starting a Majic test run. I still have some unfinished GUI testing.

#1138 Updated by Greg Shah over 8 years ago

Code Review Task Branch 2424c Revision 10956

I'm good with the changes, except that DefaultList.getColumns() needs javadoc. If this passes testing, please merge to trunk ASAP. If it requires GUI-only fixes, you can still merge to trunk.

#1139 Updated by Hynek Cihlar over 8 years ago

Greg Shah wrote:

Code Review Task Branch 2424c Revision 10956

I'm good with the changes, except that DefaultList.getColumns() needs javadoc. If this passes testing, please merge to trunk ASAP. If it requires GUI-only fixes, you can still merge to trunk.

Greg I have more changes, being merged right now. I will let you know when checked in.

#1140 Updated by Hynek Cihlar over 8 years ago

Please review task branch 2424c, revision 10957.

#1141 Updated by Greg Shah over 8 years ago

Code Review Task Branch 2424c Revision 10957

I'm fine with the changes. Please add javadoc to ScrollableListImpl.scroll().

#1142 Updated by Hynek Cihlar over 8 years ago

Greg Shah wrote:

Code Review Task Branch 2424c Revision 10957

Please add javadoc to ScrollableListImpl.scroll().

Checked in to 10958.

#1143 Updated by Greg Shah over 8 years ago

It's good. If it passes testing, merge to trunk.

#1144 Updated by Hynek Cihlar over 8 years ago

Fixes for new regressions in 2424c are being finalized. I will be restarting Majic regression shortly.

#1145 Updated by Greg Shah over 8 years ago

Code Review Task Branch 2424c Revision 10960

The changes are good. I especially like the ensureVisibility() simplifications.

#1146 Updated by Hynek Cihlar over 8 years ago

More fixes checked in to task branch 2424c, revision 10961. Restarted Majic regression tests.

#1147 Updated by Greg Shah over 8 years ago

Code Review Task Branch 2424c Revision 10961

I'm OK with the changes.

Do you expect to pass testing today? If not, I may need to move others in front of you.

#1148 Updated by Hynek Cihlar over 8 years ago

Greg Shah wrote:

Code Review Task Branch 2424c Revision 10961

I'm OK with the changes.

Do you expect to pass testing today? If not, I may need to move others in front of you.

Ctrl-C part has passed. The main part should finish in cca 2 hours. I am giving it 75%.

#1149 Updated by Hynek Cihlar over 8 years ago

The regression test of 2424c failed with an exception caused by duplicate detachment of alert box widget. Fix checked in revision 10962 together with some other GUI fixes. Regression test restarted.

#1150 Updated by Greg Shah over 8 years ago

Code Review Task Branch 2424c Revision 10962

The changes are fine.

Is this a candidate for merge to trunk or do you have more expected GUI fixes to come?

#1151 Updated by Hynek Cihlar over 8 years ago

Greg Shah wrote:

Code Review Task Branch 2424c Revision 10962

The changes are fine.

Is this a candidate for merge to trunk or do you have more expected GUI fixes to come?

Yes, there are more GUI fixes to be checked in.

The last run ended with more exceptions. They are caused by AbstractContainer.detach(), when widget is not removed from its parent container (because it is not there) a runtime exception is thrown. The idea is to catch this to prevent invalid widget tree. In some cases the widget is just detached multiple times, and it doesn't mean we are getting an invalid tree. I think I will requalify this and instead of throwing the exception I will just put a warning entry in the log.

#1152 Updated by Hynek Cihlar over 8 years ago

The list of open 2424c issues:

- incorrect width of report output
- out of memory error during execution of gso_185
- GUI - content widgets of a bordered panel are not always redrawn

I will continue tomorrow (Sunday).

#1153 Updated by Greg Shah over 8 years ago

I will continue tomorrow (Sunday).

OK.

Since both #2606 and #1811 are heavily dependent upon 2424c, we need to you complete this update ASAP. That means you are still at the front of the line.

#1154 Updated by Hynek Cihlar over 8 years ago

Greg Shah wrote:

I will continue tomorrow (Sunday).

OK.

Since both #2606 and #1811 are heavily dependent upon 2424c, we need to you complete this update ASAP. That means you are still at the front of the line.

Ok.

#1155 Updated by Hynek Cihlar over 8 years ago

Hynek Cihlar wrote:

The list of open 2424c issues:

- incorrect width of report output

I have fixed one problem with redirected output checked in 2424c, revision 10965. There is at least another one. If anybody wants to participate and take it, I'll be happy to provide more details.

#1156 Updated by Constantin Asofiei over 8 years ago

Hynek Cihlar wrote:

Hynek Cihlar wrote:

The list of open 2424c issues:

- incorrect width of report output

I have fixed one problem with redirected output checked in 2424c, revision 10965. There is at least another one. If anybody wants to participate and take it, I'll be happy to provide more details.

If you you point me the test results folder on devsrv01 and the failed test names, I can take a look at it.

#1157 Updated by Hynek Cihlar over 8 years ago

Constantin Asofiei wrote:

If you you point me the test results folder on devsrv01 and the failed test names, I can take a look at it.

Wonderful. The test results folder /home/hc/testing/majic_baseline/results/20150905_145042. gso_184wf is the failed test. I am not sure how to reproduce it.

#1158 Updated by Constantin Asofiei over 8 years ago

Hynek, this looks like a frame height issue when the stream is redirected to terminal. All the frames are displayed, but they are "pushed" over top as some other frames (fVendTotsFrame and fVendFtr132Frame) output more lines than they should to. I've checked with trunk and their size is the same. I'll continue investigation.

On a side note, there are files without header entries.

#1159 Updated by Hynek Cihlar over 8 years ago

Constantin Asofiei wrote:

Hynek, this looks like a frame height issue when the stream is redirected to terminal. All the frames are displayed, but they are "pushed" over top as some other frames (fVendTotsFrame and fVendFtr132Frame) output more lines than they should to. I've checked with trunk and their size is the same. I'll continue investigation.

Yes I've been trying to reconstruct the failing frame in my local env and redirect it to the terminal. But with no success.

On a side note, there are files without header entries.

Thanks for the note. The code is not production complete yet, it also contains some neutral debug changes.

#1160 Updated by Constantin Asofiei over 8 years ago

The key part I think is to set the page-size for the stream. This test duplicates the problem:

def var i as dec.
def var ch as char.
ch = "terminal".

def stream rpt.
output stream rpt to value(ch) page-size 60.

form header "b a a a a a c c c d d d d e e e ef f f f f a a a a" at 27 page-number(rpt) to 132 skip skip(1) with page-top width 132 no-labels no-box no-attr-space frame f-title132.
view stream rpt frame f-title132.

repeat i = 1 to 10:
    display stream rpt i at 72 with frame f-tots title "sub-totltas" width 132 centered down.
accumulate (i * -1) (total).
 if i = 1 then do:
     display stream rpt
     "=============" at 67
     accum total (i * -1) format "-zzz,zzz,zz9.99" at 68 no-label
      with frame f-ftr132 no-box width 132.
      leave.
 end.
end.

output stream rpt close.

#1161 Updated by Constantin Asofiei over 8 years ago

And a cleaned-up version - the frame width has nothing to do, only the DOWN is problematic. Do you recall having done any down-related changes?

def var i as dec.
def var ch as char.
ch = "terminal".

def stream rpt.
output stream rpt to value(ch) page-size 60.

form header "title" at 27 page-number(rpt) skip skip(1) with page-top no-labels no-box no-attr-space frame f-title132.
view stream rpt frame f-title132.

repeat i = 1 to 10:
  display stream rpt i with frame f-tots title "sub-totals" centered down.
  accumulate (i * -1) (total).
  if i = 1 then do:
     display stream rpt
     "=============" skip
     accum total (i * -1) format "-zzz,zzz,zz9.99" no-label
      with frame f-ftr132 no-box.
      leave.
  end.
end.

output stream rpt close.

#1162 Updated by Hynek Cihlar over 8 years ago

Constantin Asofiei wrote:

And a cleaned-up version - the frame width has nothing to do, only the DOWN is problematic. Do you recall having done any down-related changes?
[...]

There must be more, because the following seems to work fine, regardless of the page-size value.

def var i as int.
def stream r.
def var ch as char.
ch = "terminal".

output stream r to value(ch) page-size 60.

form header "header" with no-box no-labels page-top frame f1.
view stream r frame f1.

form header "footer" with no-box no-labels page-bottom frame f2.
view stream r frame f2.

do i = 1 to 100:
   display stream r skip with frame f-skip3.
   down stream r with no-box no-labels frame f0.
   display stream r "test" + string(i) with frame f0.
end.

output stream r close.

Though your example can be used to track this issue down. Are you still working on it?

#1163 Updated by Constantin Asofiei over 8 years ago

Hynek Cihlar wrote:

Constantin Asofiei wrote:

And a cleaned-up version - the frame width has nothing to do, only the DOWN is problematic. Do you recall having done any down-related changes?
[...]

There must be more, because the following seems to work fine, regardless of the page-size value.

I meant the DOWN option at the frame, not the DOWN statement.

The problem I think is related to BorderedPanelImpl.drawPanel - the border instance field is null for trunk, but is non-null for 2424c - this is for frame f-tots in my example. Drawing the border forces the entire height of the frame to be output - which is not correct. You can take it from here.

#1164 Updated by Hynek Cihlar over 8 years ago

In the 2424c test results the test gc_62 fails on the following frame.

define frame f1
    comma-list no-label view-as selection-list multiple inner-chars 56 inner-lines 17 scrollbar-horizontal scrollbar-vertical
    skip
    ok-button
    cancl-button
    with overlay centered title "Title".

The harness expects a frame with no scroll bars (frame or selection-list). However I think the correct behavior should be to show the frame scroll bar as the content doesn't fit - list inner lines 17 + borders 4 + buttons 1 comes to 22 chars of height for the whole frame. The available size is 21 chars (24 - 3 lines for message area and status) - and also to show vertical scroll bar in the selection-list widget.

2424c seems to get the frame scroll bar right and hence the test fails. Can anybody try this
test in the native environment?

#1165 Updated by Constantin Asofiei over 8 years ago

Hynek, I think 2424c is right to add scrollbars to the frame. There is no "native env" where we can test the MAJIC 4GL code, we need to create standalone tests to duplicate the logic/issue and test them on lindev01.

Eugenie, any idea when GC 62 was added and if the screen was captured from the legacy 4GL environment?

#1166 Updated by Eugenie Lyzenko over 8 years ago

Constantin Asofiei wrote:

Eugenie, any idea when GC 62 was added and if the screen was captured from the legacy 4GL environment?

24 July 2014. This is certainly not a native 4GL environment.

What is the screen difference for failed test?

I think for the multiple mode selection list used here we can create standalone test that does not need specific environment and can be run on existed 4GL ChUI system(Windows or Linux) we can access.

#1167 Updated by Hynek Cihlar over 8 years ago

Eugenie Lyzenko wrote:

Constantin Asofiei wrote:

Eugenie, any idea when GC 62 was added and if the screen was captured from the legacy 4GL environment?

24 July 2014. This is certainly not a native 4GL environment.

What is the screen difference for failed test?

This is the screen produced by 2424c.


09/05/201┌───────────────Select Standard PO Text Blocks───────────────┐ 14:53:50
┌────────│┌──────────────────────────────────────────────────────────┐ ────────┐
│    PO: ││    1 - Drug Program                                      │ ed)     │
│        ││    2 - Hazmat Customer (will carry)                      │ gular)  │
│Vendor: ││    3 - Hazmat Customer (will NOT carry)                  │         │
│        ││    4 - Direct Ship Authority                             │         │
│        ││    5 - 8130-3 Required                                   │         │
│        ││    6 - 8130-3 with Dual Release Required                 │         │
│        ││    7 - Confidential and Proprietary (Email)              │         │
│        ││    8 - Confidential and Proprietary (Document)           │         │
│        ││    9 - EASA Registered Aircraft                          │ 0       │
│     Buy││   10 - Tops Cleaners Statement                           │         │
│ Request││   11 - Do Not Use PMA Parts                              │         │
│Vendor O││   12 - DPAS Statement                                    │         │
│        ││   13 - Shelf Life Statement                              │         │
│       T││   14 - Pass Through For Customer                         │         │
│        ││                                                          │         │
│Payment ││                                                          │         │
│Notes: (││                                                          │ uy?: no │
└────────│└──────────────────────────────────────────────────────────┘ ────────┘
         └────────────────────────────────────────────────────────────┘

Enter data or press F4 to end.

And this is the expected one.

08/21/201┌───────────────Select Standard PO Text Blocks───────────────┐ 15:41:15
┌────────│┌──────────────────────────────────────────────────────────┐│────────┐
│    PO: ││    1 - Drug Program                                      ││ed)     │
│        ││    2 - Hazmat Customer (will carry)                      ││gular)  │
│Vendor: ││    3 - Hazmat Customer (will NOT carry)                  ││        │
│        ││    4 - Direct Ship Authority                             ││        │
│        ││    5 - 8130-3 Required                                   ││        │
│        ││    6 - 8130-3 with Dual Release Required                 ││        │
│        ││    7 - Confidential and Proprietary (Email)              ││        │
│        ││    8 - Confidential and Proprietary (Document)           ││        │
│        ││    9 - EASA Registered Aircraft                          ││0       │
│     Buy││   10 - Tops Cleaners Statement                           ││        │
│ Request││   11 - Do Not Use PMA Parts                              ││        │
│Vendor O││   12 - DPAS Statement                                    ││        │
│        ││   13 - Shelf Life Statement                              ││        │
│       T││   14 - Pass Through For Customer                         ││        │
│        ││                                                          ││        │
│Payment ││                                                          ││        │
│Notes: (││                                                          ││uy?: no │
└────────│└──────────────────────────────────────────────────────────┘│────────┘
         │<OK> <Cancel>                                               │
         └────────────────────────────────────────────────────────────┘

Enter data or press F4 to end.

The following program produces output with frame and list scroll bars on, on lindev01.

define frame f1
    comma-list no-label view-as selection-list multiple inner-chars 56 inner-lines 17 scrollbar-horizontal scrollbar-vertical
    skip
    ok-button
    cancl-button
    with overlay centered title "Title".

#1168 Updated by Hynek Cihlar over 8 years ago

Constantin Asofiei wrote:

The problem I think is related to BorderedPanelImpl.drawPanel - the border instance field is null for trunk, but is non-null for 2424c - this is for frame f-tots in my example. Drawing the border forces the entire height of the frame to be output - which is not correct. You can take it from here.

Constantin, please review a fix in 2424c, revision 10966.

Interestingly, with this update I get a weird offset of the frame title and the first fill-in. I traced this down to the output manager and all the coordinates are ok, compared to trunk. See the attached screen shot.

#1169 Updated by Constantin Asofiei over 8 years ago

24 July 2014. This is certainly not a native 4GL environment.

Hynek: GC 62 will require screen updates to reflect to correct behaviour.

#1170 Updated by Hynek Cihlar over 8 years ago

Constantin Asofiei wrote:

24 July 2014. This is certainly not a native 4GL environment.

Hynek: GC 62 will require screen updates to reflect to correct behaviour.

This will also need a fix in selection-list widget, it must show its scroll bar when directed (the scrollbar-vertical option). Should I update the screens as part of 2424c or is it ok do it after?

#1171 Updated by Constantin Asofiei over 8 years ago

Hynek Cihlar wrote:

Constantin Asofiei wrote:

24 July 2014. This is certainly not a native 4GL environment.

Hynek: GC 62 will require screen updates to reflect to correct behaviour.

This will also need a fix in selection-list widget, it must show its scroll bar when directed (the scrollbar-vertical option). Should I update the screens as part of 2424c or is it ok do it after?

Create a separate task in the Majic Conversion project, link it to 2424 and post the baseline changes there. You will need to release the baseline changes together with 2424c.

#1172 Updated by Eugenie Lyzenko over 8 years ago

The source file is:
syman/po/text-block-select.p:

...
define variable comma-list as character.
define variable temp-list  as character.
define variable txt-num1   as character.
define variable txt-num2   as character.

define button   ok-button     label "OK"      auto-go.
define button   cancl-button  label "Cancel"  auto-endkey.

define frame f1
    comma-list no-label view-as selection-list multiple inner-chars 56 inner-lines 17 scrollbar-horizontal scrollbar-vertical
    skip
    ok-button
    cancl-button
    with overlay centered title "Select Standard PO Text Blocks".
...

So I think the expected screen is CORRECT. The OK and CANCEL button should be visible because:
scrollbar-horizontal scrollbar-vertical are the part of the selection-list definition, not the frame f1. Frame does NOT have vertical scrollbar.

This means the issue is in P2J, not in "wrong baseline" test screen.

08/21/201┌───────────────Select Standard PO Text Blocks───────────────┐ 15:41:15
┌────────│┌──────────────────────────────────────────────────────────┐│────────┐
│    PO: ││    1 - Drug Program                                      ││ed)     │
│        ││    2 - Hazmat Customer (will carry)                      ││gular)  │
│Vendor: ││    3 - Hazmat Customer (will NOT carry)                  ││        │
│        ││    4 - Direct Ship Authority                             ││        │
│        ││    5 - 8130-3 Required                                   ││        │
│        ││    6 - 8130-3 with Dual Release Required                 ││        │
│        ││    7 - Confidential and Proprietary (Email)              ││        │
│        ││    8 - Confidential and Proprietary (Document)           ││        │
│        ││    9 - EASA Registered Aircraft                          ││0       │
│     Buy││   10 - Tops Cleaners Statement                           ││        │
│ Request││   11 - Do Not Use PMA Parts                              ││        │
│Vendor O││   12 - DPAS Statement                                    ││        │
│        ││   13 - Shelf Life Statement                              ││        │
│       T││   14 - Pass Through For Customer                         ││        │
│        ││                                                          ││        │
│Payment ││                                                          ││        │
│Notes: (││                                                          ││uy?: no │
└────────│└──────────────────────────────────────────────────────────┘│────────┘
         │<OK> <Cancel>                                               │
         └────────────────────────────────────────────────────────────┘

Enter data or press F4 to end.

#1173 Updated by Constantin Asofiei over 8 years ago

Eugenie Lyzenko wrote:

The source file is:
syman/po/text-block-select.p:

Can you extract the logic in a sample test and run it on lindev01?

#1174 Updated by Constantin Asofiei over 8 years ago

Hynek, I've found the root cause: at the time FrameChuiImpl.draw is called, the viewPort instance is located at (0,0), thus Point z = contentPane.screenLocation(); will retrieve the wrong coordinate. The viewPort's location is set when FrameChuiImpl.draw:249 - frameScroll.draw(nonbody); is called, as this calls rootPanel.doLayout();. I think we need to ensure doLayout is called either before drawing is performed (during frame layout?) or at the beginning of the drawing code.

#1175 Updated by Hynek Cihlar over 8 years ago

Eugenie Lyzenko wrote:

The source file is:
syman/po/text-block-select.p:
[...]
So I think the expected screen is CORRECT. The OK and CANCEL button should be visible because:
scrollbar-horizontal scrollbar-vertical are the part of the selection-list definition, not the frame f1. Frame does NOT have vertical scrollbar.

Eugenie, please see the note 1164.

This means the issue is in P2J, not in "wrong baseline" test screen.

The extracted frame definition run on lindev01 indicates otherwise, see below.

┌───────────────Select Standard PO Text Blocks───────────────┐
│┌──────────────────────────────────────────────────────────┐ 
││                                                           
││                                                            
││                                                            
││                                                            
││                                                            
││                                                            
││                                                            
││                                                            
││                                                            
││                                                            
││                                                            
││                                                            
││                                                            
││                                                            
││                                                            
││                                                            
││                                                            
│└──────────────────────────────────────────────────────────┘ 
└────────────────────────────────────────────────────────────┘

Procedure complete. Press space bar to continue.

#1176 Updated by Hynek Cihlar over 8 years ago

Constantin Asofiei wrote:

Hynek, I've found the root cause: at the time FrameChuiImpl.draw is called, the viewPort instance is located at (0,0), thus Point z = contentPane.screenLocation(); will retrieve the wrong coordinate. The viewPort's location is set when FrameChuiImpl.draw:249 - frameScroll.draw(nonbody); is called, as this calls rootPanel.doLayout();. I think we need to ensure doLayout is called either before drawing is performed (during frame layout?) or at the beginning of the drawing code.

Wow, great find! Please see the checked in fix in 2424c/10967.

#1177 Updated by Constantin Asofiei over 8 years ago

Hynek Cihlar wrote:

Constantin Asofiei wrote:

Hynek, I've found the root cause: at the time FrameChuiImpl.draw is called, the viewPort instance is located at (0,0), thus Point z = contentPane.screenLocation(); will retrieve the wrong coordinate. The viewPort's location is set when FrameChuiImpl.draw:249 - frameScroll.draw(nonbody); is called, as this calls rootPanel.doLayout();. I think we need to ensure doLayout is called either before drawing is performed (during frame layout?) or at the beginning of the drawing code.

Wow, great find! Please see the checked in fix in 2424c/10967.

What about the rootPane.doLayout() call in ScrollPaneImpl.draw:182 - is this still needed? Otherwise the changes look good.

#1178 Updated by Eugenie Lyzenko over 8 years ago

Eugenie, please see the note 1164.

This means the issue is in P2J, not in "wrong baseline" test screen.

The extracted frame definition run on lindev01 indicates otherwise, see below.

Yes, you are right but I'm not, the test:
...

define variable comma-list as character view-as selection-list list-items
       " 1 - Drug Program",
       " 2 - Hazmat Customer (will carry)",
       " 3 - Hazmat Customer (will NOT carry)",
       " 4 - Direct Ship Authority",
       " 5 - 8130-3 Required",
       " 6 - 8130-3 with Dual Release Required",
       " 7 - Confidential and Proprietary (Email)",
       " 8 - Confidential and Proprietary (Document)",
       " 9 - EASA Registered Aircraft",
       "10 - Tops Cleaners Statement",
       "11 - Do Not Use PMA Parts",
       "12 - DPAS Statement",
       "13 - Shelf Life Statement",
       "14 - Pass Through For Customer" 
       multiple inner-chars 56 inner-lines 17 scrollbar-horizontal scrollbar-vertical.

define button   ok-button     label "OK"      auto-go.
define button   cancl-button  label "Cancel"  auto-endkey.

define frame f1
    comma-list no-label
    skip
    ok-button
    cancl-button
    with overlay centered title "Select Standard PO Text Blocks".

enable all with frame f1.
wait-for choose of ok-button.
...

shows the result on linux 4GL:
...

         ┌───────────────Select Standard PO Text Blocks───────────────┐
         │┌──────────────────────────────────────────────────────────┐ 
         ││   1 - Drug Program                                        
         ││   2 - Hazmat Customer (will carry)                         
         ││   3 - Hazmat Customer (will NOT carry)                     
         ││   4 - Direct Ship Authority                                
         ││   5 - 8130-3 Required                                      
         ││   6 - 8130-3 with Dual Release Required                    
         ││   7 - Confidential and Proprietary (Email)                 
         ││   8 - Confidential and Proprietary (Document)              
         ││   9 - EASA Registered Aircraft                             
         ││  10 - Tops Cleaners Statement                              
         ││  11 - Do Not Use PMA Parts                                 
         ││  12 - DPAS Statement                                       
         ││  13 - Shelf Life Statement                                 
         ││  14 - Pass Through For Customer                            
         ││                                                            
         ││                                                            
         ││                                                            
         │└──────────────────────────────────────────────────────────┘ 
         └────────────────────────────────────────────────────────────┘

Enter data or press F4 to end.

...

Bottom 3 lines of the window are reserved, so the frame inits the vertical scrollbar.

#1179 Updated by Hynek Cihlar over 8 years ago

Constantin Asofiei wrote:

Wow, great find! Please see the checked in fix in 2424c/10967.

What about the rootPane.doLayout() call in ScrollPaneImpl.draw:182 - is this still needed?

Right, not needed.

#1180 Updated by Hynek Cihlar over 8 years ago

Hynek Cihlar wrote:

The list of open 2424c issues:
- out of memory error during execution of gso_185

The out of memory is caused by a leak of side label config instances, also trunk is affected. Fix is in progress.

#1181 Updated by Hynek Cihlar over 8 years ago

Rebased task branch 2424c from P2J trunk revision 10935 (branch revision 10984).

#1182 Updated by Hynek Cihlar over 8 years ago

Please review task branch 2424c revision 10992. Since the last review at revision 10957 the changes contain mostly stabilization fixes, memory leaks fixes and related enhancements.

Although I am still working on a clean Majic regression test run with no failures, the manual retests indicate there are no Majic regressions left.

GUI still requires some draw fixes, these should be cleaned up shortly.

#1183 Updated by Greg Shah over 8 years ago

Code Review Task Branch 2424c Revision 10992

1. Do you plan to resolve the TODOs in SelectionListGuiImpl.adjustSizeImpl()?

2. FrameGuiImpl.doLayout(), DefaultList.getColumns() are missing javadoc.

3. WidgetConfigDef history entries 003 and 004 should be a single entry.

4. ScrollableListImpl, OutputManager need history entries.

#1184 Updated by Hynek Cihlar over 8 years ago

Greg Shah wrote:

Code Review Task Branch 2424c Revision 10992

1. Do you plan to resolve the TODOs in SelectionListGuiImpl.adjustSizeImpl()?

Yes, I would like to resolve it before checking in. I am currently fixing border panels overdrawing useful content, this somehow interferes with the clipping logic. Then I will move to the selection list layout.

#1185 Updated by Hynek Cihlar over 8 years ago

During Majic regression testing, I received

3. failure in step 29: 'java.lang.RuntimeException: java.lang.RuntimeException: 2: No such file
at com.goldencode.harness.test.FileComparison.execute(FileComparison.java:144)
at com.goldencode.harness.test.Test.execute(Test.java:278)
at com.goldencode.harness.Driver.run(Driver.java:121)
Caused by: java.lang.RuntimeException: 2: No such file
at com.goldencode.harness.transport.SFTPSession.get(SFTPSession.java:284)
at com.goldencode.harness.test.FileComparison.download(FileComparison.java:190)
at com.goldencode.harness.test.FileComparison.execute(FileComparison.java:129)
at com.goldencode.harness.test.Test.execute(Test.java:278)
at com.goldencode.harness.Driver.run(Driver.java:121)
Caused by: com.jcraft.jsch.SftpException: No such file
at com.jcraft.jsch.ChannelSftp.throwStatusError(ChannelSftp.java:2793)
at com.jcraft.jsch.ChannelSftp._stat(ChannelSftp.java:2149)
at com.jcraft.jsch.ChannelSftp._stat(ChannelSftp.java:2166)
at com.jcraft.jsch.ChannelSftp.get(ChannelSftp.java:878)
at com.jcraft.jsch.ChannelSftp.get(ChannelSftp.java:838)
at com.goldencode.harness.transport.SFTPSession.get(SFTPSession.java:278)
at com.goldencode.harness.test.FileComparison.download(FileComparison.java:190)
at com.goldencode.harness.test.FileComparison.execute(FileComparison.java:129)
at com.goldencode.harness.test.Test.execute(Test.java:278)
at com.goldencode.harness.Driver.run(Driver.java:121)

in test tc_misc_reports_012. Is this familiar to anybody? I am assuming this is a temporary error.

#1186 Updated by Constantin Asofiei over 8 years ago

Hynek Cihlar wrote:

During Majic regression testing, I received

3. failure in step 29: 'java.lang.RuntimeException: java.lang.RuntimeException: 2: No such file
at com.goldencode.harness.test.FileComparison.execute(FileComparison.java:144)
at com.goldencode.harness.test.Test.execute(Test.java:278)
at com.goldencode.harness.Driver.run(Driver.java:121)
Caused by: java.lang.RuntimeException: 2: No such file
at com.goldencode.harness.transport.SFTPSession.get(SFTPSession.java:284)
at com.goldencode.harness.test.FileComparison.download(FileComparison.java:190)
at com.goldencode.harness.test.FileComparison.execute(FileComparison.java:129)
at com.goldencode.harness.test.Test.execute(Test.java:278)
at com.goldencode.harness.Driver.run(Driver.java:121)
Caused by: com.jcraft.jsch.SftpException: No such file
at com.jcraft.jsch.ChannelSftp.throwStatusError(ChannelSftp.java:2793)
at com.jcraft.jsch.ChannelSftp._stat(ChannelSftp.java:2149)
at com.jcraft.jsch.ChannelSftp._stat(ChannelSftp.java:2166)
at com.jcraft.jsch.ChannelSftp.get(ChannelSftp.java:878)
at com.jcraft.jsch.ChannelSftp.get(ChannelSftp.java:838)
at com.goldencode.harness.transport.SFTPSession.get(SFTPSession.java:278)
at com.goldencode.harness.test.FileComparison.download(FileComparison.java:190)
at com.goldencode.harness.test.FileComparison.execute(FileComparison.java:129)
at com.goldencode.harness.test.Test.execute(Test.java:278)
at com.goldencode.harness.Driver.run(Driver.java:121)

in test tc_misc_reports_012. Is this familiar to anybody? I am assuming this is a temporary error.

Can you check if the report file is in your home folder in devsrv01? The report is generated in the user's home folder, and then the harness copies it to majic_baseline/results/<timestamp>/downloads, and if for some reason it can't copy it, you see this error.

#1187 Updated by Hynek Cihlar over 8 years ago

Constantin Asofiei wrote:

Can you check if the report file is in your home folder in devsrv01? The report is generated in the user's home folder, and then the harness copies it to majic_baseline/results/<timestamp>/downloads, and if for some reason it can't copy it, you see this error.

The report file tc_misc_reports_012.txt is not in my home folder and I didn't find anything suspicious around the time the report was generated.

#1188 Updated by Constantin Asofiei over 8 years ago

Hynek Cihlar wrote:

Constantin Asofiei wrote:

Can you check if the report file is in your home folder in devsrv01? The report is generated in the user's home folder, and then the harness copies it to majic_baseline/results/<timestamp>/downloads, and if for some reason it can't copy it, you see this error.

The report file tc_misc_reports_012.txt is not in my home folder and I didn't find anything suspicious around the time the report was generated.

OK, then please check this:
  1. from previous results where this test passed, check how long it took for the report to generate
  2. generate the report manually and check how long it takes to complete. If it finishes in a significant amount of time slower than the expected good time, then there is a problem.

When I first added AspectJ, some reports had a huge slowdown in generation. We need to make sure that the report generation time is not affected.

#1189 Updated by Hynek Cihlar over 8 years ago

Constantin Asofiei wrote:

Hynek Cihlar wrote:

Constantin Asofiei wrote:

Can you check if the report file is in your home folder in devsrv01? The report is generated in the user's home folder, and then the harness copies it to majic_baseline/results/<timestamp>/downloads, and if for some reason it can't copy it, you see this error.

The report file tc_misc_reports_012.txt is not in my home folder and I didn't find anything suspicious around the time the report was generated.

OK, then please check this:
  1. from previous results where this test passed, check how long it took for the report to generate
  2. generate the report manually and check how long it takes to complete. If it finishes in a significant amount of time slower than the expected good time, then there is a problem.

Sounds like a good plan!

When I first added AspectJ, some reports had a huge slowdown in generation. We need to make sure that the report generation time is not affected.

Ok.

#1190 Updated by Hynek Cihlar over 8 years ago

Constantin, please review BorderedPanelGuiImpl.draw() in 2424c, revision 10992.

BorderedPanelGuiImpl is used as the window's root panel, see WindowGuiImpl.contentPane. It is responsible for drawing the window face and managing the child widgets. Based on the current clipping state it clears the background in BorderedPanelGuiImpl.draw() and then lets AbstractContainer.draw() to draw the children.

The problem is that clipping doesn't seem to be right in BorderedPanelGuiImpl.draw() when clearing the background. For example when the window status is invalidated as the result of pause() the clip rectangle retrieved with OutputManager.withDrawFragments spans more than the window status itself. This results in other stuff being incorrectly covered by WindowGuiImpl.contentPane.

BorderedPanelGuiImpl is similarly used in other places, but no problem there.

#1191 Updated by Hynek Cihlar over 8 years ago

Constantin Asofiei wrote:

Hynek Cihlar wrote:

Constantin Asofiei wrote:

Can you check if the report file is in your home folder in devsrv01? The report is generated in the user's home folder, and then the harness copies it to majic_baseline/results/<timestamp>/downloads, and if for some reason it can't copy it, you see this error.

The report file tc_misc_reports_012.txt is not in my home folder and I didn't find anything suspicious around the time the report was generated.

OK, then please check this:
  1. from previous results where this test passed, check how long it took for the report to generate

A passed test shows the same time as the failed one.

  1. generate the report manually and check how long it takes to complete. If it finishes in a significant amount of time slower than the expected good time, then there is a problem.

A manual check didn't show anything suspicious, the report was properly created in the expected time frame and the whole test went fine.

#1192 Updated by Constantin Asofiei over 8 years ago

Hynek Cihlar wrote:

Constantin, please review BorderedPanelGuiImpl.draw() in 2424c, revision 10992.

BorderedPanelGuiImpl is used as the window's root panel, see WindowGuiImpl.contentPane. It is responsible for drawing the window face and managing the child widgets. Based on the current clipping state it clears the background in BorderedPanelGuiImpl.draw() and then lets AbstractContainer.draw() to draw the children.

The problem is that clipping doesn't seem to be right in BorderedPanelGuiImpl.draw() when clearing the background. For example when the window status is invalidated as the result of pause() the clip rectangle retrieved with OutputManager.withDrawFragments spans more than the window status itself. This results in other stuff being incorrectly covered by WindowGuiImpl.contentPane.

Please check which widgets have PaintEvent posted, in the test where you have incorrect drawing. ScreenBitmap should contain all invalidated rectangles, posted via PaintEvents. Maybe some widget is repainted when it should not. If all rectangles are OK, then it may be a problem in the fragment computation. BTW, the code in OutputManager.withDrawFragments clears the area line-by-line (vertically or horizontally). For GUI (especially the Web client), this may be time consuming...

#1193 Updated by Hynek Cihlar over 8 years ago

Constantin Asofiei wrote:

Please check which widgets have PaintEvent posted, in the test where you have incorrect drawing. ScreenBitmap should contain all invalidated rectangles, posted via PaintEvents. Maybe some widget is repainted when it should not. If all rectangles are OK, then it may be a problem in the fragment computation.

The invalidated rectangles didn't seem right, I will double check that.

BTW, the code in OutputManager.withDrawFragments clears the area line-by-line (vertically or horizontally). For GUI (especially the Web client), this may be time consuming...

Yes, I am aware of this. Is the line by line processing necessary?

#1194 Updated by Greg Shah over 8 years ago

Don't we have an assumption that all the drawing within a given drawing cycle is done within a single outermost clipping rectangle?

As the drawing of more deeply nested components occurs, then clipping rectangle is narrowed and then when they are done, we widen the clipping back to the previous nesting level's clip rectangle.

Is there any scenario where event processing occurs such that the status area is updated while in one of these nested component's drawing cycle? In such a case, the status area's drawing processing would try to set a clip rectangle that was outside of the more narrow clipping of the "enclosing" drawing cycle.

#1195 Updated by Hynek Cihlar over 8 years ago

Greg Shah wrote:

Don't we have an assumption that all the drawing within a given drawing cycle is done within a single outermost clipping rectangle?

As the drawing of more deeply nested components occurs, then clipping rectangle is narrowed and then when they are done, we widen the clipping back to the previous nesting level's clip rectangle.

Yes I think this is how it should work.

Is there any scenario where event processing occurs such that the status area is updated while in one of these nested component's drawing cycle?

I am not aware of such a case. In my scenario, status area should be the outermost rectangle. I will investigate further.

#1196 Updated by Greg Shah over 8 years ago

Code Review Task Branch 2424c Revision 10993

All of the following can be resolved without needing re-testing. Please fix these things and merge to trunk.

1. NativeRectangle and Rectangle need history entries.

2. PaintStructure and SwingEmulatedWindow have some debugging code and data that should be removed.

3. Items 2 through 4 from note 1183 are not resolved.

#1197 Updated by Hynek Cihlar over 8 years ago

Greg Shah wrote:

Code Review Task Branch 2424c Revision 10993

All of the following can be resolved without needing re-testing. Please fix these things and merge to trunk.

1. NativeRectangle and Rectangle need history entries.

2. PaintStructure and SwingEmulatedWindow have some debugging code and data that should be removed.

3. Items 2 through 4 from note 1183 are not resolved.

Items 1-3 fixed, changes checked in to 2424c.

#1198 Updated by Hynek Cihlar over 8 years ago

2424c merged to trunk as revision 10937. 2424c archived.

#1199 Updated by Hynek Cihlar over 8 years ago

Created task branch 2424d. This will be mainly for GUI fixes, leftovers from 2424c.

#1200 Updated by Hynek Cihlar over 8 years ago

Please review task branch 2424d, revision 10939. The changes contain leftover GUI fixes from 2424c.

#1201 Updated by Greg Shah over 8 years ago

Code Review Task Branch 2424d Revision 10939

It looks good. Please add javadoc for the EditorGuiImpl.EditorScrollContainer methods.

Unfortunately, with the BorderLayout and OutputManager changes, I guess we need to regression test. Perhaps it would be best to merge these changes into 1811q since we are trying to finalize that code. devsrv01 is locked right now anyway. What do you think?

#1202 Updated by Hynek Cihlar over 8 years ago

Greg Shah wrote:

Code Review Task Branch 2424d Revision 10939

Unfortunately, with the BorderLayout and OutputManager changes, I guess we need to regression test. Perhaps it would be best to merge these changes into 1811q since we are trying to finalize that code. devsrv01 is locked right now anyway. What do you think?

Yes, agree. Do you want me to rebase 1811q and merge 2424d?

#1203 Updated by Greg Shah over 8 years ago

Do you want me to rebase 1811q and merge 2424d?

Yes.

Let's give Constantin and Sergey a chance to check in any outstanding changes first. I'll post on #1811 to notify. When they have confirmed that they are ready, you can go ahead.

#1204 Updated by Hynek Cihlar over 8 years ago

Changes from task branch 2424d merged to 1811q at revision 11021. 2424d archived.

#1205 Updated by Constantin Asofiei over 8 years ago

Hynek, there is an issue in BorderedPanelGuiImpl.draw:167:

            CoordinatesConversion c = screen().coordinates();
            NativeInsets ninsets = c.insetsToNative(insets);

            NativePoint p = physicalLocation();
            p = p.translate(ninsets.left, ninsets.top);

This code re-adjusts the panel's coordinates at drawing. But this interferes when a child widget's screenPhysicalLocation is needed (as in TC.processEventsWorker:14710, where a widget is re-drawn directly). Thus, any code which relies on screenPhysicalLocation will not be aware of the BorderedPanelGuiImpl location determined at drawing... the coordinates need to be computed and exposed via the physicalLocation() and location() APIs correctly.

So, do you think it is OK to override the setLocation and setPhysicalLocation in BorderedPanelGuiImpl to adjust the location based on the insets? Or maybe adjust the coordinates via insets in some doLayout code?

#1206 Updated by Hynek Cihlar over 8 years ago

Constantin Asofiei wrote:

So, do you think it is OK to override the setLocation and setPhysicalLocation in BorderedPanelGuiImpl to adjust the location based on the insets? Or maybe adjust the coordinates via insets in some doLayout code?

Does it mean that the location is translated multiple times? First at the bordered layout and second at TC.processEventsWorker?

#1207 Updated by Constantin Asofiei over 8 years ago

Hynek Cihlar wrote:

Constantin Asofiei wrote:

So, do you think it is OK to override the setLocation and setPhysicalLocation in BorderedPanelGuiImpl to adjust the location based on the insets? Or maybe adjust the coordinates via insets in some doLayout code?

Does it mean that the location is translated multiple times? First at the bordered layout and second at TC.processEventsWorker?

No, I don't think is about translating it, I think is about reporting it correctly. When draw (for example a FILL-IN) is called normally, from the WindowGuiImpl.draw, the translation is done using each widget's location as reported by the location() API; but when BorderedPanelGuiImpl.draw is reached, it adds 1 pixel to the translated origin, thus all further drawing is done with a 1-pixel shift from the top-left corner. But when widget's drawing is done independently (for example TC.processEventsWorker:14710 at focus switch), the widget's location (as reported by the screenPhysicalLocation() API) does not account for the 1-pixel shift done when BorderedPanelGuiImpl.draw is called.

#1208 Updated by Hynek Cihlar over 8 years ago

Constantin Asofiei wrote:

Hynek Cihlar wrote:

Constantin Asofiei wrote:

So, do you think it is OK to override the setLocation and setPhysicalLocation in BorderedPanelGuiImpl to adjust the location based on the insets? Or maybe adjust the coordinates via insets in some doLayout code?

Does it mean that the location is translated multiple times? First at the bordered layout and second at TC.processEventsWorker?

No, I don't think is about translating it, I think is about reporting it correctly. When draw (for example a FILL-IN) is called normally, from the WindowGuiImpl.draw, the translation is done using each widget's location as reported by the location() API; but when BorderedPanelGuiImpl.draw is reached, it adds 1 pixel to the translated origin, thus all further drawing is done with a 1-pixel shift from the top-left corner. But when widget's drawing is done independently (for example TC.processEventsWorker:14710 at focus switch), the widget's location (as reported by the screenPhysicalLocation() API) does not account for the 1-pixel shift done when BorderedPanelGuiImpl.draw is called.

I see. I wouldn't override the location() and physicalLocation(). I think the insets region should be transparent/inaccessible to the child widgets, this I believe makes the draw logic less complicated - less things to worry about. I would rather override screenLocation/screenPhysicalLocation in BorderedPanel and compensate for the insets there. What do you think?

#1209 Updated by Constantin Asofiei over 8 years ago

Hynek Cihlar wrote:

Constantin Asofiei wrote:

Hynek Cihlar wrote:

Constantin Asofiei wrote:

So, do you think it is OK to override the setLocation and setPhysicalLocation in BorderedPanelGuiImpl to adjust the location based on the insets? Or maybe adjust the coordinates via insets in some doLayout code?

Does it mean that the location is translated multiple times? First at the bordered layout and second at TC.processEventsWorker?

No, I don't think is about translating it, I think is about reporting it correctly. When draw (for example a FILL-IN) is called normally, from the WindowGuiImpl.draw, the translation is done using each widget's location as reported by the location() API; but when BorderedPanelGuiImpl.draw is reached, it adds 1 pixel to the translated origin, thus all further drawing is done with a 1-pixel shift from the top-left corner. But when widget's drawing is done independently (for example TC.processEventsWorker:14710 at focus switch), the widget's location (as reported by the screenPhysicalLocation() API) does not account for the 1-pixel shift done when BorderedPanelGuiImpl.draw is called.

I see. I wouldn't override the location() and physicalLocation(). I think the insets region should be transparent/inaccessible to the child widgets, this I believe makes the draw logic less complicated - less things to worry about. I would rather override screenLocation/screenPhysicalLocation in BorderedPanel and compensate for the insets there. What do you think?

Yes, this should work. But add some comments that this needs to be in sync with the drawing code in BorderedPanelGuiImpl.draw.

#1210 Updated by Hynek Cihlar over 8 years ago

Constantin Asofiei wrote:

Yes, this should work. But add some comments that this needs to be in sync with the drawing code in BorderedPanelGuiImpl.draw.

I will check in the fix to 1811q.

#1211 Updated by Greg Shah almost 8 years ago

  • Status changed from New to Closed

#1212 Updated by Greg Shah over 7 years ago

  • Target version changed from Milestone 12 to GUI Support for a Complex ADM2 App

#1213 Updated by Greg Shah over 7 years ago

  • File deleted (majic_logs.zip)

#1214 Updated by Greg Shah over 7 years ago

  • File deleted (gso_186_screen.txt)

#1215 Updated by Greg Shah over 7 years ago

  • File deleted (gso_426_screen.txt)

#1216 Updated by Greg Shah over 7 years ago

  • File deleted (gso_428_screen.txt)

#1217 Updated by Greg Shah over 7 years ago

  • File deleted (testing_20141030_053652.log)

#1218 Updated by Greg Shah about 7 years ago

I'm moving this discussion here so that there will be a searchable record of this outside of email.

Eugenie wrote:

I'm working on collecting attributes for Browse widget. The goal is to describe the support level of every widget. The progress.g file declares the TOP-ONLY attribute is valid for Browse widget(although not documented).

How do you estimate the runtime support for this attribute in Browse widget? I have found the TOP-ONLY is fully implemented but for frame widget, not browse. Browse widget has no runtime support. Have I missed for something? Any browse support for this attribute?

Stanislav responded:

This attribute is not valid for browse, there must be an error in progress.g.

To be clear, we are talking about TOP-ONLY as an option, not an attribute.

Although it is possible that it has no functionality in the 4GL, I did find this in a browse options phrase in customer source code that was not failing in the 4GL (it compiled). I considered it an "undocumented feature". See #2252-784 for the notice. If it has no functionality, then it may be possible that the 4GL shares common code between the frame phrase and the browse options phrase and when there are invalid combinations the 4GL just ignores them.

Stanislav: Did you test if it has functionality? I agree that logically, it doesn't make much sense. But then again sometimes the 4GL makes no sense.

#1219 Updated by Greg Shah about 7 years ago

By the way, we don't need to test this right now if it has never been tested before. We can mark it as "basic" support and put in a comment that "we believe this has no functionality and being able to specify it in a browse options phrase is just a parsing quirk in the 4GL, BUT that we have not yet tested it".

#1220 Updated by Eugenie Lyzenko about 7 years ago

Greg Shah wrote:

By the way, we don't need to test this right now if it has never been tested before. We can mark it as "basic" support and put in a comment that "we believe this has no functionality and being able to specify it in a browse options phrase is just a parsing quirk in the 4GL, BUT that we have not yet tested it".

OK. Going to change the both support levels to stub for browse widget and this option.

And may be the usage it within browse might mean "the browse data is always visible(can not be over-layed with other browse widgets without this option)".

#1221 Updated by Greg Shah about 7 years ago

To be clear, the top-only option is fully supported for frame (also as an attribute).

Also available in: Atom PDF