Feature #1790
implement menu support
0%
Related issues
History
#1 Updated by Greg Shah over 11 years ago
MENU, SUB-MENU and MENU-ITEM widget support; DEFINE MENU and DEFINE SUB-MENU stmts, widget options: MENU-ITEM, IN, SUB-MENU, TOGGLE-BOX, MENUBAR
#2 Updated by Greg Shah over 11 years ago
- Target version set to Milestone 12
#3 Updated by Greg Shah almost 10 years ago
- Assignee set to Evgeny Kiselev
For now, we can only do the ChUI version but it should be designed to add GUI later. There will be work on both conversion and runtime for this task. Please start by writing some testcases that will explore/demonstrate the menu features. Then write the conversion rules and create enough runtime Java classes/methods to make the code convert and compile.
For an example, see #1788 for how the rectangle widget was recently added. Of course, menus have interactive behavior so they are more complex, but the idea is the same.
#4 Updated by Evgeny Kiselev over 9 years ago
Conversion problem:
- define menu/sub-menu is not properly support.
- to add menu for current window (like menubar) need to add next code:
assign current-window:menubar = menu mbar:handle.
but it not properly supported. At the moment I'm working on this problem. AddedWindowWidget
next methods:setMenuBar
andgetMenuBar
. Also I've added properly conversion for it.
Next things I'll plan to create Classes Menu
and SubMenu
and interfaces for it. And then will work on conversion for Menu/SubMenu.
#5 Updated by Evgeny Kiselev over 9 years ago
- Status changed from New to WIP
#6 Updated by Greg Shah over 9 years ago
Please check in your 4GL testcases into a testcases/uast/menu/ directory so I can get an idea of the cases you have looked at.
#7 Updated by Evgeny Kiselev over 9 years ago
Greg Shah wrote:
Please check in your 4GL testcases into a testcases/uast/menu/ directory so I can get an idea of the cases you have looked at.
for particular problem, I'm using next testcase:
define sub-menu topic menu-item numbr label "Number" menu-item addr label "Address". define sub-menu move menu-item forward label "Forward" menu-item backward label "Back". define sub-menu quitit menu-item quititem label "E&xit". define menu mbar menubar sub-menu topic label "Topic" sub-menu move label "Move" sub-menu quitit label "E&xit". on choose of menu-item numbr display "Number". on choose of menu-item addr display "Address". on choose of menu-item forward display "forward". on choose of menu-item backward display "backward". assign current-window:menubar = menu mbar:handle. wait-for choose of menu-item quititem.
#8 Updated by Greg Shah over 9 years ago
Make sure you add cases for TOGGLE-BOX in a menu-item definition and MENUBAR in the DEFINE MENU.
I think it also makes sense to include RULE, SKIP, DISABLED, ACCELERATOR and READ-ONLY in the tests. We will leave the color, font, LIKE and TITLE support for later.
#9 Updated by Greg Shah over 9 years ago
Please post your current code for an early review. Your status report noted this:
2) added conversion for current-window object
We already have Vadim working on this feature for #2229 (which is about GUI support). And we already have some limited CURRENT-WINDOW support for ChUI implemented (see rules/convert/variable_references.rules and search for kw_cur_win.
I don't want to duplicate effort here. What do you need to add right now?
#10 Updated by Evgeny Kiselev over 9 years ago
Greg Shah wrote:
I don't want to duplicate effort here. What do you need to add right now?
I need to properly conversion for next line:
assign current-window:menubar = menu mbar:handle.
This code add menu to current window
#11 Updated by Greg Shah over 9 years ago
I need to properly conversion for next line:
[...]
This code add menu to current window
Hopefully you only need to add the MENUBAR attribute support to methods_attributes.rules (and the proper methods to the window widget). I think the CURRENT-WINDOW referent should already resolve properly.
#12 Updated by Evgeny Kiselev over 9 years ago
Greg Shah wrote:
I need to properly conversion for next line:
[...]
This code add menu to current windowHopefully you only need to add the MENUBAR attribute support to methods_attributes.rules (and the proper methods to the window widget). I think the CURRENT-WINDOW referent should already resolve properly.
Yes, you are correct. I didn't do anything else for it.
#13 Updated by Greg Shah over 9 years ago
Please upload your latest changes here.
Please check in all your testcases to testcases/uast/menu/
.
I need to re-assign this task to someone else immediately. Post any notes here about the status or findings of the task.
#14 Updated by Vadim Gindin over 9 years ago
I tried to work on conversion of current-window:menubar = menu mbar:handle
.
I added the following rule to method-attributes.rules (added at line 1894):
<rule>ftype == prog.kw_menu_bar <action>hwrap = "Window"</action> <action>methodText = "getMenubar"</action> <rule>isAssign <action>methodText = "setMenubar"</action> </rule> </rule>
I also added accessors to
CommonWindow
:/** * Get window MENUBAR. * * @return handle. */ @LegacyAttribute(name = "MENUBAR") public handle getMenubar(); /** * Set window MENUBAR. * * @param handle. */ @LegacyAttribute(name = "MENUBAR", setter = true) public void setMenubar(handle menubar);
and empty implementation to
WindowWidget
:@Override public handle getMenubar() { // TODO Auto-generated method stub return null; } @Override public void setMenubar(handle menubar) { // TODO Auto-generated method stub }
After that conversion became successful, but it converts source string to the following code currentWindow().unwrap().readOnlyError("menubar");
. Could you advice me why it doesn't see the setter?
#15 Updated by Greg Shah over 9 years ago
You need to add ftype == prog.kw_menu_bar ||
to the list in the read_only_attribute
function in include/common-progress.rules
. Then it will detect that attribute as a setter.
#16 Updated by Vadim Gindin over 9 years ago
Thanks, it is little unexpected. Why the global read_only_attribute
function is necessary?
The next conversion problem was appeared when I tried to convert define menu m.
. Initially such source procedure could be successfully converted to empty Java class. I added MenuWidget class and started to add conversion rules and faced with errors. I do the following. Because of menu's have own namespace like frames (can be addressed using menu m:handle
like frame f:handle
), I tried to convert 2 statements:
def frame f. def menu m.
Debugging information of these 2 statements are different. Here is the parser output:
block [BLOCK] @0:0 statement [STATEMENT] @0:0 def [DEFINE_FRAME] @1:1 f [SYMBOL] @1:11 statement [STATEMENT] @0:0 def [DEFINE_MENU] @2:1 menu [KW_MENU] @2:5 m [SYMBOL] @2:10
We can see here an unwanted KW_MENU. Probably that is the real problem. It leads to wrong AST:
<ast col="0" id="575525617666" line="0" text="statement" type="STATEMENT"> <annotation datatype="java.lang.Boolean" key="reachable" value="true"/> <ast col="1" id="575525617667" line="1" text="def" type="DEFINE_FRAME"> <annotation datatype="java.lang.Boolean" key="reachable" value="true"/> <ast col="11" id="575525617669" line="1" text="f" type="SYMBOL"> <annotation datatype="java.lang.Boolean" key="reachable" value="true"/> </ast> </ast> </ast> <ast col="0" id="575525617671" line="0" text="statement" type="STATEMENT"> <annotation datatype="java.lang.Boolean" key="reachable" value="true"/> <ast col="1" id="575525617672" line="2" text="def" type="DEFINE_MENU"> <annotation datatype="java.lang.Boolean" key="reachable" value="true"/> <ast col="5" id="575525617675" line="2" text="menu" type="KW_MENU"> <annotation datatype="java.lang.Boolean" key="reachable" value="true"/> <ast col="10" id="575525617678" line="2" text="m" type="SYMBOL"> <annotation datatype="java.lang.Boolean" key="reachable" value="true"/> </ast> </ast> </ast> </ast>
Here we can see corresponding unwanted AST node for KW_MENU.
This problem looks like Lexer problem. It seems the Lexer extracts unwanted token KW_MENU from the source. Unfortunately conforming *.p.lexer file is empty. By the way, I found that before. Why it's empty?
I also tried to find something wrong in progress.g
but I couldn't. Could you advice me something?
#17 Updated by Greg Shah over 9 years ago
Why the global read_only_attribute function is necessary?
Progress doesn't detect assignments to read-only attributes at compile time. I don't know why. Instead, it is a runtime error. In order to duplicate this behavior, we convert assignments to read-only attributes into a special call that will only ever generate the error. Writable attributes must be listed in that function so that this read-only path is not taken.
We can see here an unwanted KW_MENU. Probably that is the real problem. It leads to wrong AST:
Not wrong, just sub-optimal. You would have to write different rules to handle the extra level in the tree. But it is simple enough to get rid of.
This problem looks like Lexer problem. It seems the Lexer extracts unwanted token KW_MENU from the source.
No, it is a parser thing. If the lexer did not generate the token, then the parser would not know this was a define menu statement. The token must be there in the token stream from the lexer.
But we don't have to include the token in the tree. Normally, when I rewrite the KW_DEFINE as a DEFINE_<type> token, I also drop the 2nd keyword from the tree. I didn't do that this time.
Just go into progress.g and make this change:
def_menu_stmt returns [int mtype = WID_MENU] <---- here : (KW_MENU! | KW_SUB_MENU! { mtype = WID_SUB_MENU; } ) m:symbol <---- here ( options { generateAmbigWarnings = false; } : ui_stuff | (KW_MENU_BAR | KW_SUB_M_H | simple_title_string) | (like_menu_clause | menu_element_descriptor) // TODO: are there other parts of menu_element_descriptor or // like_menu_clause etc... which can trigger this deviant // 4GL behavior? | { LA(2) == KW_MENU_ITM }? DOT )* { sym.addMenu(#m.getText(), mtype); } ;
and this one too:
define_stmt : { int mtype = -1; <----- add this here String varname = null;
and this from define_stmt
:
| mtype=def_menu_stmt // also handles SUB-MENU <----- here { if (mtype == WID_MENU) <----- here
#18 Updated by Vadim Gindin over 9 years ago
The more I'm investigating menus, more I'm founding that they are very similar to frames.
1. Definition of menu consists of sub-menu's list as a frame definition consists of widgets list.
2. Menu like Frame has no parent. Menu can be one of 2 types: MENUBAR and POPUP MENU. Menubar can be owned by a Window. POPUP MENU can be owned by different widgets excluding some of them, like IMAGE, TEXT..
Menu has a property OWNER - intended for pointing to OWNER, FRAME contains config.windowId
property, pointing to owning window.
3. Menuitems, sub-menus can be referenced with IN MENU or IN SUBMENU clauses like IN FRAME clause is used for frame widgets.
These peculiarities induce me to create similar conversion rules as for frames. These rules are complex. It is also difficult for me to gather frame conversion rules from different rules files and understand :overall conversion plan" if I can say so. Therefore I need your advice. Here are my questions.
1. Is comparison with frames correct and will it be right to create similar rules?
2. Is it correct to generate similar java code:
- 2 classes: GenericMenu
and CommonMenu
like GenericFrame
and CommonFrame
.
- for each procedure there are custom implementation of CommonMenu
interface is generated.
- this custom impl contains static field configClass
(class of Menu definition also generated here).
3. It probably needed separate MenuRegistry
in a LogicalTerminal
or also MenuItemRegistry
. Is it right?
4. If I'm adding new rules file, do I need to register it somewhere or it will be automatically used during conversion because it will be resided in /rules
subfolder?
Some questions about AST
1. What additional information should be added to AST in annotations? What are common useful annotations for similar tasks? I found the following: name, type, widdef
2. I modified fixups/post_parse_fixups.rules
, adding menu type in the following way:
<rule> (type == prog.define_button or type == prog.define_browse or type == prog.define_rectangle or type == prog.define_menu) and isNote('tempidx')) <action> addDictionaryLong("var_defs", string(getNoteLong("tempidx")), id) </action> <action>removeNote("tempidx")</action> <action>putNote("widdef", true)</action> <action>fprintf("post_parse_fixups.log", "WID_DEF %-40s: %-25s @ %05d : %05d\n", file, text, line, this.getColumn()) </action> </rule>
And I found that annotation
widdef
was not added to AST for menu, but information about prog.define_menu
was added to the log post_parse_fixups.log
. By the way line number in that file was incorrect:Source file:
def frame f. def menu m.
Record in the log:
WID_DEF ./menu/menu.p : def @ 00001 : 00001 WID_DEF ./menu/menu.p : def @ 00001 : 00001
First row corresponds to
def frame f
and the second row corresponds to def menu m
. the last two numbers in each row are line and column. So line for def menu m
is 1, that is incorrect.I'm not sure it is important or not. I just tried to find where this 1 is came from. Have a look conversion rule above and you will see a
line
argument in fprintf
call. I didn't find definition of this var in post_parse_fixups.rules
, I only find that ProgressAst
class contains such field, that may have incorrect value... Does all it make sense to be investigated further?3. In spite of
post_parse_fixups.log
contains a row, related to def menu m
the target AST does not contain any annotations, that should be added by modified conversion rule. No widdef
annotation.
What do you think?
#19 Updated by Greg Shah over 9 years ago
1. Is comparison with frames correct and will it be right to create similar rules?
No, I don't think so.
Menus are significantly simpler than frames:
- few options
- very limited choices for contained items AND they are not full widgets
- only the togglebox option allows "editing" and even this is very simple
- few attributes and methods
- doesn't represent data (except for the togglebox)
- simple structure
- no redirected terminal usage
- no headers
- limited and implicit layout/size control
- no page-top/page-bottom features
- no aggregate phrase support
- no
@
base-field support - no need for a "menu-definition" like with frames (the frame definition is there to cleanly integrate with the converted business logic in getting/setting data into contained widgets
Menus do have some strangeness in their implementation since they are a widget that is not contained in a frame. But other than this fact, they are not close to frames at all.
2. Is it correct to generate similar java code:
- 2 classes: GenericMenu and CommonMenu like GenericFrame and CommonFrame.
- for each procedure there are custom implementation of CommonMenu interface is generated.
- this custom impl contains static field configClass (class of Menu definition also generated here).
Not really. It may be that a CommonMenu
interface is probably needed if CommonWidget
is not a good match. And then there would be a MenuWidget
server-side class and a MenuConfig
... just like with normal widgets.
Please treat this like a widget instead of a frame.
3. It probably needed separate MenuRegistry in a LogicalTerminal or also MenuItemRegistry. Is it right?
I don't see the need for it, unless you have found some reason.
4. If I'm adding new rules file, do I need to register it somewhere or it will be automatically used during conversion because it will be resided in /rules subfolder?
There is no special registration. If you add something to rules/annotations/
and insert that into annotations.xml
, it will work. Likewise you can add something to rules/convert/
and add the reference in core_conversion.xml
.
1. What additional information should be added to AST in annotations? What are common useful annotations for similar tasks? I found the following: name, type, widdef
I don't have any guidance here. We add annotations when we find some downstream decision that we must make based on something previously analyzed or decided at an earlier phase.
2. I modified fixups/post_parse_fixups.rules, adding menu type in the following way:
It seems reasonable.
First row corresponds to def frame f and the second row corresponds to def menu m.
No, this is not right. I think you are just seeing some kind of duplicate message for the first line of that program. Your DEFINE_MENU node doesn't ever get annotated with a tempidx
during parsing, so it doesn't ever enter this block. Prove it to yourself by updating the printf
code like this:
<action>fprintf("post_parse_fixups.log", "WID_DEF %-40s: %-40s @ %05d : %05d\n", file, this.getSymbolicTokenType(), line, this.getColumn()) </action>
The descriptive token type will be much more useful than the text, which will usually be DEF or def or define... You can leave this change since it will make the log more useful.
The bottom line here is that you need to make changes to how the parser's define_stmt
implements menus. Pattern the changes after how buttons work. Buttons don't represent data but they act like widgets that respond to events, just like menus. Of course, buttons are contained inside frames, but that really doesn't matter for parsing purposes. Step through the parser to see how define button
works, especially in how it is processed by the symbol resolver (see SymbolResolver.annotateVariableOptions()
). Make sure that the definitions of menus and menuitems are properly linked with references to those same widgets, using the tempidx
.
3. In spite of post_parse_fixups.log contains a row, related to def menu m the target AST does not contain any annotations, that should be added by modified conversion rule. No widdef annotation.
When there is a tempidx
annotation in the DEFINE_MENU
node, then you will have your widdef
annotation.
#20 Updated by Vadim Gindin over 9 years ago
- File vig_upd20141105a.zip added
I made for DEFINE MENU good AST similar to DEFINE BUTTON except the nested KW_MENU. I tried to find that place where you got rid of similar KW_BUTTON for DEFINE BUTTON but I didn't find that place. Could you remember where it is?
I also have difficulties to find a place where JAST is emitted.
Have a look on my update please.
#21 Updated by Greg Shah over 9 years ago
I made for DEFINE MENU good AST similar to DEFINE BUTTON except the nested KW_MENU. I tried to find that place where you got rid of similar KW_BUTTON for DEFINE BUTTON but I didn't find that place. Could you remember where it is?
In note 17, I suggested the changes needed to get rid of the nested KW_MENU
. The added !
in front of the KW_MENU
and KW_SUB_MENU
in def_menu_stmt
will do it. But I put additional changes there because the calling code was relying upon those keywords, so in my suggested changes the rule had a new return value.
The def_button_stmt
is the similar place where we drop the KW_BUTTON
. But the menu approach must be a bit different since it can match 2 possible cases.
I also have difficulties to find a place where JAST is emitted.
frame_generator.xml
does this for frames and all static widgets contained in frames.
If we wanted to create separate menu definition classes, we would put something new in place for that. It would NOT be complex like frame_generator.xml
, but much simpler. This is probably best.
We could also emit this stuff into the business logic in ui_statements.rules
, but I don't like that. The triggers and method/attribute usage would be in the business logic, but the static definitions are best kept elsewhere.
#22 Updated by Greg Shah over 9 years ago
Code Review vig_upd20141105a.zip
The changes are a good start. Some thoughts:
1. Your progress.g
changes are missing my suggestions from note 17. Since you are using the return value for varname
, that will make it trickier to do this. Right now the calling code relies upon the presence of the KW_MENU
or KW_SUB_MENU
. When you drop those, you will need to return the WID_MENU
or WID_SUBMENU
values instead. The calling code can walk the returned tree (in the #m
value) and read the text of the varname
instead of returning this from def_menu_stmt
.
2. I think the SymbolResolver
will need more work. The lookups probably have to deal with the Variable
wrapper.
#23 Updated by Vadim Gindin over 9 years ago
- File vig_upd20141114a.zip added
The next update, that generates MenuWidget
field in procedure class file.
Questions.
1. I'm not sure, that this is a right place for the field.
2. How should the code for menu items look. Where it could be in a class. In case of frame there are separate frame descripton class, for example MenuF.java that contains frame widgets definition and initialization (in the method setup()
). Should I create similar definition class for Menu with menu items definition and initialization? There are possible other variants: procedure class constructor or body method, but outside of the externalProcedure
block. Please advice.
3. Where to create fields for menu items and submenus? Commonly speaking, menus can be owned by a window or a widget (popup menus) except those of several types.
4. What did you mean in the point 2 in previous note?
#24 Updated by Greg Shah over 9 years ago
Code Review vig_upd20141114a.zip
1. Lines 104 and 105 of annotations/variable_definitions.rules
contain duplicated code.
2. You asked this:
Should I create similar definition class for Menu with menu items definition and initialization?
As I noted above:
If we wanted to create separate menu definition classes, we would put something new in place for that. It would NOT be complex like frame_generator.xml, but much simpler. This is probably best.
In other words: YES. I think this would be a sub-class of MenuDefinition
. MenuDefinition
would be an abstract class with a single void setup(menuWidget)
method. The subclass would have:
- A public member for each
SubMenuWidget
from a corresponding DEFINE_SUB_MENU. - A concrete
setup()
method that would:- The parameter passed in would be the
MenuWidget
that is being setup/configured. - Create
MenuItemWidget
instances and add them to the menu or sub-menu, based on the KW_MENU_ITM instances in the DEFINE_MENU or DEFINE_SUB_MENU. Since these aren't named, they don't need to be members of theMenuDefinition
sub-class. However, they do need to be properly configured, so perhaps they need to be saved as local variables of thesetup()
method. - Create
MenuRule
andSkipEntity
instances and add them to the corresponding sub-menu. - Add each sub-menu widget into the menu or sub-menu parent.
- Configure the options in each of the above widget (and the menu itself)
- All the "add to the menu or sub-menu" processing noted above should be done in the right order such that it would link together the menu items/sub-menus into the proper menu hierarchy.
- The parameter passed in would be the
In addition to a MenuDefinition sub-class, you would have the DEFINE_MENU statement emit a class member in the external procedure something like this:
MenuWidget name = MenuWidget.createMenu(<my_menu_def>.class)
This would be a static factory method that would instantiate the MenuWidget
, instantiate the MenuDefinition
sub-class and then call setup()
to configure/link everything together. The MenuWidget
instance would be returned from createMenu()
.
Any sub-menu widget references would be converted into menu.sub_menu_name member references. I don't see the need to have the getters/setters/widget accessors like with frames. Let's avoid that complexity.
When designing the methods for adding/configuring the menus/sub-menus/menu-items, please first design the approach for supporting CREATE MENU/CREATE SUB-MENU/CREATE MENU-ITEM. In such cases, I guess there is business logic to set attributes to configure PARENT link. I'm not sure how to setup the order of sub-menus and menu-items since there are no methods in the MENU widget to support "adds" or "removals". Anyway, it seems like whatever is done for dynamic cases can also be used in the non-dynamic MenuDefinition
case.
3. In regard to your question:
What did you mean in the point 2 in previous note?
You use addWrappedWorker()
in SymbolResolver.addMenu()
. This probably means that you should use lookupWrappedType(lookupWrapped(menuDict, name))
in SymbolResolver.lookupMenu()
instead of lookupWorkerExact()
.
As part of the proper "linking" and referencing that you will have to do to convert all the business logic references to menus and sub-menus, you will have to make sure that the refids link everything together during parse/post-parse-fixups. This will require some parser/symbol resolver improvements.
#25 Updated by Vadim Gindin over 9 years ago
- File menu.zip added
- File vig_upd20141117a.zip added
Following update generates separate Menu definition class, that is extended from MenuDefinition
and adds setup method there.
Please review the rules.
Questions.
1. Some of rules I just copied from frame_generator.rules
or frame_construction.rules
. Some of them I changed a little. What way will be correct? Is it possible to inherit/override rules?
2. Same question about java templates. Can I also modify existing templates as I did with gen_setUp
template?
3. During conversion there are 2 JAST files are created (source procedure is menu.p
): menu.p.jast
and MenuDefinitionM.jast
. First one is for source procedure and the second one is for Menu definition. But the problem is that menu.p.jast
contains almost the same JAST as MenuDefinitionM.jast
. It seems it is being mistakenly overridden during conversion, but I can't find where it happens. See menu.zip
.
4. I can't generate import com.goldencode.p2j.ui.*;
for MenuWidget
in the main class. I added createImport
call, but it doesn't work. I can't find the reason yet. I suspect, that the problem relates to jroot (i.e. Aast is being added to wrong tree) and correlates with the point 3. Could you help me?
#26 Updated by Greg Shah over 9 years ago
As part of your recent status report, you mention:
By the way I don't know how to implement InvocationHandler, that is required for proxy generation.
I haven't looked at the changes yet, but we don't need any proxy generation for menus. That is my point above when I said this:
I don't see the need to have the getters/setters/widget accessors like with frames. Let's avoid that complexity.
The proxy is only needed for frames because we have an interface that defines getters/setters/widget accessors. We don't need that for menus.
#27 Updated by Greg Shah over 9 years ago
Code Review vig_upd20141117a.zip
1. MenuDefinition
does NOT need to extend InvocationHandler
and it needs no invoke()
method. It is just meant as a simple base class for menu definitions, which for now may only need the setup(MenuWidget)
method. This also means that the MenuWidget.createStaticMenu()
will be much simpler (no proxy stuff).
2. Since we are now generating a separate class file, we should NOT be calling menu_generator.rules
from core_conversion.xml
. Rules used in core_conversion.xml
are there for the conversion of the business logic. They are operating on a jast which is for the original .p.ast
file. Note that the frame_generator.xml
is a separate step in the conversion process, which occurs after annotations and before base structure. You will have to do something similar. See convert/ConversionDriver.java
and the generateFrames()
method. I suspect many of your problems are caused by trying to generate a separate menu definition jast from inside core conversion. By the way, as a separate step menu_generator.rules
should be named menu_generator.xml
.
Answers to your questions:
Some of rules I just copied from frame_generator.rules or frame_construction.rules. Some of them I changed a little. What way will be correct?
Yes, this is OK. Just try to avoid copying things that are not needed. My intention is for this menu def to be much simpler than frame defs.
Is it possible to inherit/override rules?
No.
2. Same question about java templates.
No.
Can I also modify existing templates as I did with gen_setUp template?
Yes, this is fine. As long as you fixup all the other places it is used, there is no problem with making changes.
First one is for source procedure and the second one is for Menu definition. But the problem is that menu.p.jast contains almost the same JAST as MenuDefinitionM.jast. It seems it is being mistakenly overridden during conversion, but I can't find where it happens. See menu.zip.
This is what I mentioned above. The step can't be part of core conversion.
I can't generate import com.goldencode.p2j.ui.*; for MenuWidget in the main class. I added createImport call, but it doesn't work. I can't find the reason yet. I suspect, that the problem relates to jroot (i.e. Aast is being added to wrong tree) and correlates with the point 3. Could you help me?
This is the same cause as mentioned above. Separate the steps and the problem will go away I think.
#28 Updated by Vadim Gindin over 9 years ago
Greg, I'm trying to create separate rules as you wrote. I faced with the following problem. MenuDefinitionM
class is not being created although corresponding rules are being executed. Why it can be offhand?
#29 Updated by Greg Shah over 9 years ago
Is it just the .java
code that is missing? Or are both the .jast
and .java
missing?
#30 Updated by Vadim Gindin over 9 years ago
Only .java
is missing.
#31 Updated by Greg Shah over 9 years ago
Make sure you have the proper setup in the ConversionDriver
. Here is the generateFrames()
:
// enable new file tracking mode JavaPatternWorker.enableNewFileTracking(); processTrees("Frame Generator", "convert/frame_generator", codenames, false, asts, debug); // add generated JASTs to the overall list (used with brew later) JavaPatternWorker.disableNewFileTracking(); frames = JavaPatternWorker.getPersistedFiles();
You must use enableNewFileTracking()
, disableNewFileTracking()
and getPersistedFiles()
to obtain the list of .jast
files that were created.
Then you need to add this array to the ExplicitFileList
in ConversionDriver.convertSourceNamesToJavaAstNames()
. Right now it only handles the "main" jasts created during core_conversion.xml
and those created during frame generation.
#32 Updated by Vadim Gindin over 9 years ago
- File vig_upd20141120a.zip added
The next update. menu-items are still not generated. I tried to do it on fly, but unsuccessful. In a frames it happens more complex with several tree passes. Firstly all frame widgets are marked with frame-id
annotation in annotations/frame_scope.rules
. Then all widgets are collected in a frame map in walk-rules
in convert/frame_generator.xml
. Real conversion is happen in post-rules
: for each collected widget template variable_def_default
is emitted.
Questions.
1. Why my simple "method" doesn't work. graft
method is called but JAST is not emitted?
2. How do you think is there possible to use my method or I will be forced to use frame "method"
3. Do I need separate file for menu annotations? You also wrote earlier that I will need to set refid annotation to properly link ASTs. Do I correctly understand? What for it is used in frames?
#33 Updated by Greg Shah over 9 years ago
Code Review vig_upd20141120a.zip
1. About frames versus menus:
In a frames it happens more complex with several tree passes. Firstly all frame widgets are marked with frame-id annotation in annotations/frame_scope.rules. Then all widgets are collected in a frame map in walk-rules in convert/frame_generator.xml. Real conversion is happen in post-rules: for each collected widget template variable_def_default is emitted.
Frames are MUCH more complicated than menus.
a) A frame definition can be defined in many different language statements (e.g. FORM, DEFINE FRAME, DISPLAY, ENABLE, UPDATE, SET...). These language statements usually (except for FORM and DEFINE FRAME) have other functional behavior that is separate from the frame definition itself. In other words, the frame definition is a kind of side-effect. For that reason, we often have to make copies of the AST nodes to a hidden location that can be used to separate the different conversion needs. This copying has to be done in an earlier conversion pass.
b) Frames are scoped resources. This means that we must find all references to that same frame and analyze their location to determine at which point the frame's scope opens. This is probably the most important reason that frames need multiple passes of processing.
c) The same options and widgets can be specified many times in a file, including with conflicting options/config/settings. The entire set must be processed and some precedence rules honored, before we can know which ones actually matter.
These are the most important reasons for frames having multiple passes. I don't think menus have any of this.
2. About these other questions:
Why my simple "method" doesn't work. graft method is called but JAST is not emitted?
Please explain what you mean by "JAST is not emitted". Is the entire .jast
file missing for a given menu definition? Or are you talking about specific nodes in the .jast
which are missing?
How do you think is there possible to use my method or I will be forced to use frame "method"
I think it is probably possible, however it could well be that some addition post-parse fixups or annotations processing will be needed to prepare the trees.
Do I need separate file for menu annotations?
What do you mean by "separate file for menu annotations"? Even for frames, we don't ever have a separate file just for annotations.
You also wrote earlier that I will need to set refid annotation to properly link ASTs. Do I correctly understand? What for it is used in frames?
For frames we gather up all widgets for a frame and mark them with a "frame-id" annotation (see annotations/frame_scoping.rules
). This lets us link each widget reference back to its containing frame.
Menus are much simpler:
- Each
DEFINE SUB-MENU
creates a named sub-menu widget and its contained menu items or sub-menus. - Each
DEFINE MENU
creates a named menu and there should be a menu definition class for this entire hierarchy. It lists the top-level contained menu-items and sub-menus.
This means that named sub-menus can be referenced in either a DEFINE MENU or in a "container" DEFINE SUB-MENU. This means there is some linking to do to figure out the container for each named sub-menu.
This can't be done fully during parsing, because AST nodes don't have their node IDs assigned yet. That is why we create the tempidx annotations to use to link things at parse time and then at post-parse-fixups we replace the tempidx with the real "refid".
3. ConversionDriver
needs a history entry.
#34 Updated by Vadim Gindin over 9 years ago
1. "JAST is not emitted". I expected that there will be separate field in MenuDefinitionM class for each menu-item. tw.graft
call had to add corresponding AST subtree to MenuDefinitionM.jast. But there is no AST corresponding menu-item field, and therefore there is no field in a result Java class MenuDefinitionM
2. Separate file. For frames I meant frame_scoping.rules
. If I shouldn't create separate annotations file. What file should I use to add annotations for menu (menu-id and some others may be).
#35 Updated by Greg Shah over 9 years ago
Vadim Gindin wrote:
1. "JAST is not emitted". I expected that there will be separate field in MenuDefinitionM class for each menu-item.
tw.graft
call had to add corresponding AST subtree to MenuDefinitionM.jast. But there is no AST corresponding menu-item field, and therefore there is no field in a result Java class MenuDefinitionM
I see. I suspect the problem is due to where you call persistJavaFile()
. This saves the JAST to a .jast
file. It is called during gen_code
which means that before you can ever add your menu items, the .jast
has already been written.
In frame_generator.xml
, gen_code
is processed in post-rules, after everything has been gathered up. So it can work there using that "already gathered" approach.
2. Separate file. For frames I meant
frame_scoping.rules
. If I shouldn't create separate annotations file. What file should I use to add annotations for menu (menu-id and some others may be).
I see. I doubt you need something so "heavy" as that. More likely you can make some minor changes to the parser and to post-parse-fixups to link the sub-menus and containers together. That is probably all you need.
#36 Updated by Vadim Gindin over 9 years ago
I'm trying to generate the field MenuItemWidget menu = new MenuItemWidget(false)
and faced with the following problem. Only new MenuItemWidget()
is generated, i.e. without parameter false
. I used the following template:
<!-- instantiate a final variable using a 1 param constructor --> <ast-root name="variable_def_final_1_param" terse="true" ast_class="com.goldencode.p2j.uast.JavaAst" > <ast id="0" type="ASSIGN" text="="> <ast id="0" type="REFERENCE_DEF" text="${wrapper}"> <annotation datatype="java.lang.String" key="name" value="${javaname}" /> <annotation datatype="java.lang.Boolean" key="final" value="${final}" /> </ast> <ast id="0" type="CONSTRUCTOR" text="${wrapper}"> <annotation datatype="java.lang.Boolean" key="peernode" value="true" /> <ast id="0" type="${type}" text="${text}" /> </ast> </ast> </ast-root>
My call looks like this:
tw.graft("variable_def_final_1_param", null, getSectionAnchor(java.cs_instance_vars).id, "final", "false", "wrapper", "MenuItemWidget", "javaname", javaname, "type", "boolean", "text", "false")
The problem is in type
value. I tried: "boolean"
, "java.lang.Boolean"
and "KW_BOOLEAN"
. The result is the same: parameter value is not generated. JAST looks like this:
<ast col="0" id="644245094418" line="0" text="=" type="ASSIGN"> <ast col="0" id="644245094419" line="0" text="MenuItemWidget" type="REFERENCE_DEF"> <annotation datatype="java.lang.String" key="name" value="mit"/> <annotation datatype="java.lang.Boolean" key="final" value="false"/> </ast> <ast col="0" id="644245094420" line="0" text="MenuItemWidget" type="CONSTRUCTOR"> <ast col="0" id="644245094421" line="0" text="false" type=""/> </ast> </ast>
Take note at the type
attribute in the line: <ast col="0" id="644245094421" line="0" text="false" type=""/>
. It is empty for the values "boolean"
and "java.lang.Boolean"
, and it becomes KW_BOOLEAN
when "KW_BOOLEAN"
was passed. But in all 3 cases result is the same: false
is not set.
What am I doing wrong? What is the right value for the type
attribute?
#37 Updated by Vadim Gindin over 9 years ago
Sorry, I got it: BOOL_FALSE
#38 Updated by Greg Shah over 9 years ago
Please consider emitting the most common settings into the SubMenuWidget/MenuItemWidget
constructor. The unchanged 4GL name (accessed via the NAME attribute) and the label seem like very common settings that virtually every menu-item/sub-menu will have. By emitting the most common options as constructor parameters, the resulting menu definition will be much smaller/cleaner.
#39 Updated by Vadim Gindin over 9 years ago
I have 2 questions. I have simple testcase containing 2 define menu
statements and I'm expecting 2 menu definition files: MenuDefinitionMen1.jast
and MenuDefinitionMen2.jast
.
1. They are equal, i.e. MenuDefinitionMen1.jast
contains definition of menu2
. In other words it was overwritten. Although that resulting classes MenuDefinitionMen1.java
and MenuDefinitionMen2.java
are correct. Why and how to correct that?
2. Menu-items in spite of being processed in menu_generation.xml
are converted to the main class too. Those labels are become a part of body method:
public void body() { "Firs&t"; "S&econd"; "Third"; "Firs&t"; "S&econd"; currentWindow().unwrap().readOnlyError("menubar"); }
It seems that menu-items are treated as frame-widgets somewhere because of those labels. Where it could be?
#40 Updated by Greg Shah over 9 years ago
1. They are equal, i.e. MenuDefinitionMen1.jast contains definition of menu2. In other words it was overwritten. Although that resulting classes MenuDefinitionMen1.java and MenuDefinitionMen2.java are correct. Why and how to correct that?
I'm not sure what is wrong here. It is best for you to debug into the JavaPatternWorker.createJavaFile()
and JavaPatternWorker.persistJavaFile()
to see where things go wrong. I suspect that it may have something to do with re-using the root
AST node, since there can only be one of those at a time in the JavaPatternWorker
, but I'm not sure. You're debugging session should prove the problem.
It seems that menu-items are treated as frame-widgets somewhere because of those labels. Where it could be?
Each KW_LABEL node has a STRING child, right? By default, all strings are output in conversion/literals.rules
. Of course, anything output like that will emit into the business logic as you have found. Search on suppress
and look at line 744 in that rules file. You'll have to add conditions there to avoid KW_SUB_MENU/KW_LABEL/STRING
and KW_MENU_ITM/KW_LABEL/STRING
cases.
#41 Updated by Vadim Gindin over 9 years ago
- File vig_upd20141124a.zip added
The next update with fixed bugs (literals and overridden JAST). It works in conversion of menu with menu-items.
#42 Updated by Greg Shah over 9 years ago
Code Review vig_upd20141124a.zip
This is a good step forward.
1. In menu_generator.xml
, you need more specific matching logic in line 74:
<!-- processing of MENU-ITEMs --> <rule>type == prog.kw_menu_itm
The reason: in the parser, KW_MENU_ITM is matched in 3 different ways:
- as a menu item definition in a DEFINE MENU or DEFINE SUB-MENU statement
- as a widget type in CREATE WIDGET (e.g.
CREATE MENU-ITEM my-item-handle.
) - as a qualifier in a widget reference (e.g.
IF MENU-ITEM my-static-menu-item-name:CHECKED THEN MESSAGE "it's checked!".
)
Your code will match all three, which is not what we would want. Search on KW_MENU_ITM
in progress.g
to see the different usages. Add more specific conditions to the rule. Most likely you should be checking the parent/grandparent types to ensure it is only matching the DEFINE MENU or DEFINE SUB-MENU statement cases.
2. I think you can remove the get_mnode
function in menu_generator.xml
, right?
3. Shouldn't the name parameter to the MenuItem
constructor be the original Progress 4GL name? Right now you are passing the converted javaname
. It is important that the NAME
attribute for a widget to be the legacy 4GL name.
4. Your code merge of the WindowWidget
has the history entries mixed up. Some text from Constantin's H024 appears after your H025 entry.
5. Why have you commented out the use of setDateOrder()
in literals.rules
?
6. It seems to me that the following is what is remaining for conversion support:
- other MENU-ITEM options/settings like READ-ONLY or TOGGLE-BOX
- sub-menu conversion:
- DEFINE SUB-MENU
- sub-menu linkage into menus
- SKIP
- RULE
- CREATE MENU
- CREATE SUB-MENU
- CREATE MENU-ITEM
- attributes and methods
- static options for the menu/sub-menu itself (in DEFINE MENU/DEFINE SUB-MENU statements)
Am I missing anything?
#43 Updated by Vadim Gindin over 9 years ago
Greg Shah wrote:
Code Review vig_upd20141124a.zip
This is a good step forward.
1. In
menu_generator.xml
, you need more specific matching logic in line 74:[...]
The reason: in the parser, KW_MENU_ITM is matched in 3 different ways:
- as a menu item definition in a DEFINE MENU or DEFINE SUB-MENU statement
- as a widget type in CREATE WIDGET (e.g.
CREATE MENU-ITEM my-item-handle.
)- as a qualifier in a widget reference (e.g.
IF MENU-ITEM my-static-menu-item-name:CHECKED THEN MESSAGE "it's checked!".
)Your code will match all three, which is not what we would want. Search on
KW_MENU_ITM
inprogress.g
to see the different usages. Add more specific conditions to the rule. Most likely you should be checking the parent/grandparent types to ensure it is only matching the DEFINE MENU or DEFINE SUB-MENU statement cases.
OK
2. I think you can remove the
get_mnode
function inmenu_generator.xml
, right?
Yes, You're right.
3. Shouldn't the name parameter to the
MenuItem
constructor be the original Progress 4GL name? Right now you are passing the convertedjavaname
. It is important that theNAME
attribute for a widget to be the legacy 4GL name.
Ok, I'll fix it.
4. Your code merge of the
WindowWidget
has the history entries mixed up. Some text from Constantin's H024 appears after your H025 entry.5. Why have you commented out the use of
setDateOrder()
inliterals.rules
?
As you remember there was a problem with conversion related to this rule (reported by Ovidiu if I remember correctly). o I commented it just to be able to continue working on this task. Probably the original problem is already solved. I'll check it. Anyway I didn't plan to commit this change.
6. It seems to me that the following is what is remaining for conversion support:
- other MENU-ITEM options/settings like READ-ONLY or TOGGLE-BOX
- sub-menu conversion:
- DEFINE SUB-MENU
- sub-menu linkage into menus
- SKIP
- RULE
- CREATE MENU
- CREATE SUB-MENU
- CREATE MENU-ITEM
- attributes and methods
- static options for the menu/sub-menu itself (in DEFINE MENU/DEFINE SUB-MENU statements)
Am I missing anything?
No, you are correct. I only can say about MENUBAR option (from your last point) in DEFINE MENU, that defines is menu POPUP (owned by widget) or not (owned by window)
#44 Updated by Vadim Gindin over 9 years ago
I need advices about SUB-MENUs.
1. SUBMENU and MENU have different sets of attributes and probably have different behavior relating to uniqueness rules (I'll check it). So I decided that SUBMENU will have separate widget class.
2. One SUBMENU can be owned by several MENU. It also defined in a separate statement DEFINE SUBMENU that is similar to DEFINE MENU statement. So I decided that SUBMENU also needs to have separate definition class and also specific setup
method in it with SubMenuWidget
parameter.
3. I will need to generate new field in MenuDefinition
for each submenu used in this menu in a following manner (like menu field): MenuDefinitionSM mbar = SubMenuWidget.createStaticSubmenu(MenuDefinitionSM.class, "sm");
4. I'm only planning to use MenuDefinition
abstract class in both cases.
Could you advice me if that is right?
#45 Updated by Greg Shah over 9 years ago
1. SUBMENU and MENU have different sets of attributes and probably have different behavior relating to uniqueness rules (I'll check it). So I decided that SUBMENU will have separate widget class.
OK.
2. One SUBMENU can be owned by several MENU. It also defined in a separate statement DEFINE SUBMENU that is similar to DEFINE MENU statement. So I decided that SUBMENU also needs to have separate definition class and also specific
setup
method in it withSubMenuWidget
parameter.
OK. I didn't realize that it could be used by multiple menu instances. That does suggest there should be a separate SubMenuDefinition
.
3. I will need to generate new field in
MenuDefinition
for each submenu used in this menu in a following manner (like menu field):MenuDefinitionSM mbar = SubMenuWidget.createStaticSubmenu(MenuDefinitionSM.class, "sm");
I'm not sure about this.
Yes, each MenuDefinition
will need a data member for each contained sub-menu. But I don't think that the createStaticSubmenu()
can be used directly in the MenuDefinition
.
When a sub-menu is shared, is it a single instance that is shared? I suspect so. If it is a single instance, then that instance must be instantiated in the business logic (the Java code that is the equivalent of the external procedure .p
file) and then assigned to each of the MenuDefinition
members that represent it.
4. I'm only planning to use
MenuDefinition
abstract class in both cases.
Yes, I think that is OK unless you find that the setup()
method signature is not suitable for both.
#46 Updated by Vadim Gindin over 9 years ago
Greg Shah wrote:
..
2. One SUBMENU can be owned by several MENU. It also defined in a separate statement DEFINE SUBMENU that is similar to DEFINE MENU statement. So I decided that SUBMENU also needs to have separate definition class and also specific
setup
method in it withSubMenuWidget
parameter.OK. I didn't realize that it could be used by multiple menu instances. That does suggest there should be a separate
SubMenuDefinition
.3. I will need to generate new field in
MenuDefinition
for each submenu used in this menu in a following manner (like menu field):MenuDefinitionSM mbar = SubMenuWidget.createStaticSubmenu(MenuDefinitionSM.class, "sm");
I'm not sure about this.
Yes, each
MenuDefinition
will need a data member for each contained sub-menu. But I don't think that thecreateStaticSubmenu()
can be used directly in theMenuDefinition
.When a sub-menu is shared, is it a single instance that is shared? I suspect so. If it is a single instance, then that instance must be instantiated in the business logic (the Java code that is the equivalent of the external procedure
.p
file) and then assigned to each of theMenuDefinition
members that represent it.
Thank you. I need to check if a single instance is shared or a copy is created.
4. I'm only planning to use
MenuDefinition
abstract class in both cases.Yes, I think that is OK unless you find that the
setup()
method signature is not suitable for both.
I would create generic variable in MenuDefinition<PARENT>
or create a separate class SubMenuDefinition
or just extend SubMenuWidget
form MenuWidget
. But I think the last variant is not good.
#47 Updated by Greg Shah over 9 years ago
worked on remarks, added submenu conversion rules, tested submenu reusing case. I found that when submenu is used several times - each time a copy is created. So will it be correct to create a field in concrete MenuDefinition using createStaticSubMenu method?
Yes, that is correct.
#48 Updated by Vadim Gindin over 9 years ago
I have some difficulty. I worked on sub-menu reference parsing and conversion. Have a look at the simple test-case:
define sub-menu sm menu-item Mi label "Forward". define menu mbar menubar sub-menu sm label "SM Submenu". <-- sm - is a "reference"
I enclosed the word "reference" with quotas because sm
is not really a reference it is a copy of defined sub-menu. That peculiarity is a source of my difficulty. I tried to add javaname
annotation to sm
and some others
At this moment an AST corresponding to sub-menu "reference" looks like this:
<ast col="3" id="665719930906" line="5" text="sub-menu" type="KW_SUB_MENU"> <annotation datatype="java.lang.Long" key="tempidx" value="269"/> <ast col="12" id="665719930908" line="5" text="sm" type="SYMBOL"/> <ast col="15" id="665719930911" line="5" text="label" type="KW_LABEL"> <ast col="21" id="665719930913" line="5" text=""SM Submenu"" type="STRING"/> </ast> </ast>
I've just added sym.annotateVariableOptions(..)
call to submenu_descriptor
rule in progress.g
to add tempidx
annotation, that would be replaced with refid
annotation and others in fixups/post_parse_fixup.xml
. There is the place where tempidx
is replaced with corresponding annotations depending on AST type: definition or reference.
So, I don't know what to do here. sm
is a copy of sub-menu, defined earlier. It probably more definition than reference, but it is also differs from definition because all menu-items are defined in a real definition, although several sub-menu options could be set here.
Could you advice me something.
P.S. An AST without any annotations looks like this:
<ast col="3" id="665719930906" line="5" text="sub-menu" type="KW_SUB_MENU"> <ast col="12" id="665719930908" line="5" text="sm" type="SYMBOL"/> <ast col="15" id="665719930911" line="5" text="label" type="KW_LABEL"> <ast col="21" id="665719930913" line="5" text=""SM Submenu"" type="STRING"/> </ast> </ast>
So I could just get var reference from SYMBOL ast, but I think it is not a good way. All var references as far as I understand are marked with
javaname
annotation so I wanted to mark sm
with it.
P.P.S. submenu_descriptor
rule looks like this (without my changes):
submenu_descriptor : // symbol => this is a placeholder for menu namespace processing KW_SUB_MENU^ s:symbol (KW_DISABLED)? (label)? ;
I didn't fully understand specified comment. What does it mean? I expected that there are possible only on form of sub-menu reference: sub-menu sm ...
. How a menu namespace could be specified here?
#49 Updated by Greg Shah over 9 years ago
Progress has a separate namespace for menus. That means that sm
as a menu/sub-menu is different from sm
as a variable. For this reason, we keep a separate namespace for menus in SymbolResolver
.
When a new named, static menu, sub-menu or menu-item is DEFINEd in 4GL code, we must call one of SymbolResolver.addMenu()
(for menus and sub-menus) or SymbolResolver.addMenuItem()
for menu-items.
When a menu, sub-menu or menu-item is referenced in 4GL code (e.g. for sub-menus it is the submenu_descriptor
rule), we need to call SymbolResolver.lookupMenu()
or SymbolResolver.lookupMenuItem()
. Right now it is only setup to tell the caller the token type of the resource. That actually is not very useful. More useful would be to provide a mechanism to annotate the original menu/sub-menu's tempidx into the menu/sub-menu reference so that they can be linked later in fixups/post_parse_fixup.xml
.
You will have to make changes to the parser, the SymbolResolver
and to fixups/post_parse_fixup.xml
to get this to work.
I previously put in the comment // symbol => this is a placeholder for menu namespace processing
because I had not yet implemented all this parse-time linkage processing although I did put in some basic dictionary support into the SymbolResolver
. I is up to you to complete that work.
#50 Updated by Vadim Gindin over 9 years ago
Greg Shah wrote:
Progress has a separate namespace for menus. That means that
sm
as a menu/sub-menu is different fromsm
as a variable. For this reason, we keep a separate namespace for menus inSymbolResolver
.When a new named, static menu, sub-menu or menu-item is DEFINEd in 4GL code, we must call one of
SymbolResolver.addMenu()
(for menus and sub-menus) orSymbolResolver.addMenuItem()
for menu-items.When a menu, sub-menu or menu-item is referenced in 4GL code (e.g. for sub-menus it is the
submenu_descriptor
rule), we need to callSymbolResolver.lookupMenu()
orSymbolResolver.lookupMenuItem()
. Right now it is only setup to tell the caller the token type of the resource. That actually is not very useful. More useful would be to provide a mechanism to annotate the original menu/sub-menu's tempidx into the menu/sub-menu reference so that they can be linked later infixups/post_parse_fixup.xml
.You will have to make changes to the parser, the
SymbolResolver
and tofixups/post_parse_fixup.xml
to get this to work.I previously put in the comment
// symbol => this is a placeholder for menu namespace processing
because I had not yet implemented all this parse-time linkage processing although I did put in some basic dictionary support into theSymbolResolver
. I is up to you to complete that work.
I understand and I already did it. I just asked about post_parse_fixup.xml
step and how to interpret sm
reference. Because it is not a reference and is not a definition of sub-menu. It defines of what annotations I should add: refid
or widdef
or some others. I also need to add javaname
.
#51 Updated by Greg Shah over 9 years ago
I just asked about post_parse_fixup.xml step and how to interpret sm reference. Because it is not a reference and is not a definition of sub-menu.
Anytime we need to be able to look up the original node that defined a resource, we leave behind a tempidx/refid link as an annotation. If you need to be able to get back to that node (for example, to lookup the javaname
) then you will need a refid. Even if these references are copies, they still are close enough to references to use the same trick.
It defines of what annotations I should add: refid or widdef or some others. I also need to add javaname.
There is no standard for what you have to do. Generally, the javaname
will be created on the node that defined the resource. You don't want to calculate the same name conversion in many places, because otherwise we can't properly override the name conversion with hints. To the extent that you need the classname of the sub-menu definition java file, you want to get that from the original definition too. So it seems like you need to treat this like a reference and make sure you have a refid.
Add the other annotations if you need them.
#52 Updated by Vadim Gindin over 9 years ago
- File vig_upd20141128a.zip added
I did sub-menu conversion. It works. Here is an update. But I'm not satisfied by it.
1. I had to use WID_SUB_MENU in resulting AST. Actually I don't fully understand what the difference between WID_SUB_MENU and KW_SUB_MENU or some other WID_* and KW_* tokens. I only found that WID_* tokens are used primarily in SymbolResolver
and KW_* tokens are primarily used in conversion rules. But post_parse_fixups.xml
contains the following rule:
<!-- identify all var references and convert tempidx to real using the dictionary, exclude widgets that can't be frame fields (and thus are not backed by a variable or are not cross-ref'd otherwise like button or browse) --> <!--type == prog.wid_sub_menu or--> <rule> !(type == prog.wid_dialog or type == prog.wid_frame or type == prog.wid_menu or type == prog.wid_menu_itm or type == prog.wid_window) and (evalLib("variables") or evalLib("widget_references")) and type != prog.sys_handle and isNote("tempidx") and dictionaryContains("var_defs", string(getNoteLong("tempidx"))) <action> putNote("refid", lookupDictionaryLong("var_defs", string(getNoteLong("tempidx")))) </action> <action>removeNote("tempidx")</action> <action>fprintf("post_parse_fixups.log", "VAR_REF %-40s: %-25s @ %05d : %05d\n", file, this.getSymbolicTokenType(), line, this.getColumn()) </action> </rule>
That rule is intended to replace tempidx
annotation with refid
annotation for widget references. This rule calls widget_reference
function, that checks AST type and returns true only for WID_* tokens. That means that rule works only with WID_* tokens. That is why I had to replace KW_SUB_MENU with WID_SUB_MENU type in a grammar.
Could you explain me the difference and probably advice more appropriate solution?
2. I also don't fully understand what lvalue
is. Why it is used in menu_reference
and not used in submenu_descriptor
. I suspect that I should used lvalue
there and it would be better solution than the current. What do you think?
#53 Updated by Greg Shah over 9 years ago
Code Review vig_upd20141128a.zip
The changes are pretty good.
1. As note 42 documents, KW_MENU_ITM is matched in 3 possible ways in the parser. That means that a simple type == prog.kw_menu_itm
is not safe to use. variable_definitions.rules
line 106 needs to be more specific.
2. About your questions:
Actually I don't fully understand what the difference between
WID_SUB_MENU
andKW_SUB_MENU
or some otherWID_*
andKW_*
tokens. I only found thatWID_*
tokens are used primarily in SymbolResolver andKW_*
tokens are primarily used in conversion rules.
The KW_SUB_MENU is a token that has matched the text "sub-menu" or "SUB-MENU" or "SuB-meNu". It can only occur in certain locations in 4GL syntax, like DEFINE SUB-MENU
. Anything that is a 4GL keyword will create/match a KW_*
token.
A WID_SUB_MENU
is a specific reference to a named sub-menu widget. It is created from a SYMBOL node in a construct that always looks like SUB-MENU my-sub-menu-name
where the SUB-MENU
text is a KW_SUB_MENU
and the my-sub-menu-name
text is a SYMBOL
. The KW_SUB_MENU
is made into the root node and the SYMBOL
child should have its token type converted from SYMBOL
to WID_SUB_MENU
. So the WID_SUB_MENU
node would never have the text "SUB-MENU", but its text would be a user-defined sub-menu name.
KW_*
nodes are 4GL syntax keywords.
WID_*
nodes are user-defined names that reference widget instances. These are most often used for widgets that aren't implicitly created by a DEFINE VARIABLE
statement (buttons, frames, browses, rectangles, menus, sub-menus, menu-items...). These widget references are meant to be made more distinguishable any other SYMBOL
instances by changing the token type to be a specific widget type.
In progress.g
, your mistake is in submenu_descriptor
where you should change #d.setType(WID_SUB_MENU);
to #s.setType(WID_SUB_MENU);
so that the SYMBOL
node (which is the actual reference to the sub-menu) can be easily distinguished as a sub-menu reference. Using #d
changes the root KW_SUB_MENU
node which should not be changed since it is not the real sub-menu reference.
That rule is intended to replace tempidx annotation with refid annotation for widget references. This rule calls
widget_reference
function, that checks AST type and returns true only forWID_*
tokens. That means that rule works only withWID_*
tokens. That is why I had to replaceKW_SUB_MENU
withWID_SUB_MENU
type in a grammar.
Since we are linking menu/sub-menu/menu-item references similar to how we are doing it for buttons, I think you would allow all 3 of those types to be processed by that section from post_parse_fixups.xml
:
<!-- identify all var references and convert tempidx to real using the dictionary, exclude widgets that can't be frame fields (and thus are not backed by a variable or are not cross-ref'd otherwise like button or browse) --> <rule> !(type == prog.wid_dialog or type == prog.wid_frame or type == prog.wid_window) and (evalLib("variables") or evalLib("widget_references")) and type != prog.sys_handle and isNote("tempidx") and dictionaryContains("var_defs", string(getNoteLong("tempidx"))) <action> putNote("refid", lookupDictionaryLong("var_defs", string(getNoteLong("tempidx")))) </action> <action>removeNote("tempidx")</action> <action>fprintf("post_parse_fixups.log", "VAR_REF %-40s: %-25s @ %05d : %05d\n", file, this.getSymbolicTokenType(), line, this.getColumn()) </action> </rule>
The idea is that we are adding these things into their own namespace (in SymbolResolver
) and using the "DEFINE VARIABLE" approach to linking tempidx
into a refid
. By changing the SYMBOL
to WID_SUB_MENU
, this will still work.
I also don't fully understand what
lvalue
is. Why it is used in menu_reference and not used in submenu_descriptor. I suspect that I should usedlvalue
there and it would be better solution than the current. What do you think?
lvalue
is a term often used in language specifications. It refers to the concept that resources that represent memory locations are assignable and the item being assigned is on the left side of the assignment operator. It is thus a left value
or lvalue
.
In most languages, the syntax is quite simple and there are only "variables" which can be used as lvalues
.
In the 4GL, they a very large number of separate resources that can be used as an lvalue
, each with their own namespace. In addition, they have other non-resource constructs that can appear on the left side of an assignment operator (see assign_type_syntax_stmt_list
). In the end, the lvalue
rule is used for matching references to all these different kind of resources even if it is just a reference in the middle of a sub-expression somewhere. It doesn't only get used on the left side of an assignment operator. It is used as a "general purpose resource reference".
As to your idea that we could use lvalue
inside the submenu_descriptor
, I think it is a good idea. It would allow us to re-use common code. BUT we must make sure that the code can only match a KW_SUB_MENU
in that location (and NOT all the other things that can be matched by lvalue
). So I recommend something like this:
submenu_descriptor : ( { LA(1) == KW_SUB_MENU }? lvalue (KW_DISABLED)? (label)? | // empty alternative ) ;
I haven't tested this, so I'm not sure it will work.
By the way, I think that the menu_reference
will probably not "link" properly since it has no tempidx
annotation. Hopefully menu/sub-menu/menu-item references through lvalue
will properly link.
#54 Updated by Vadim Gindin over 9 years ago
I added SKIP and RULE support to menu conversion rules. It works. SkipEntity
and correspondent class for RULE don't have setParent(menu)
methods. So I had to add WidgetList
functionality to menu and sub-menu definitions: I had to derive MenuDefinition
and SubMenuDefinition
classes from WidgetList
and generate addWidget's
block to generated classes as it goes in a frame definitions.
2 difficulties.¶
1. Frame definition contains initialization block, that looks like this.
{ addWidget(..) addWidget(..) .. }
This block resides right in the inner class after
setup
method. I didn't find a way how to add this block and I had to add addWidget
calls right in setup
method.
2. WidgetList
is expecting to contain GenericWidget
subclasses. MenuDefinition
or SubMenuDefinition
subclasses can contain SkipEntity, RuleEntity, MenuItemWidget and SubMenuDefinition
. The last one is not a GenericWidget and cannot be added to WidgetList
. I had to add a SubMenuWidget self
field to SubMenuDefinition
class and add that field to WidgetList
in case of sub-menu. It looks not good. What do you think?
#55 Updated by Vadim Gindin over 9 years ago
- File vig_upd20141202a.zip added
The next update.
- Added SKIP and RULE elements
- Added generic type to WidgetList
.
- Added self
field to SubMenuDefinition
- Added MENUBAR option
- Added OWNER property to MenuWidget
- Fixed submenu_descriptor
clause in grammar and corresponding conversion rules. (WID_SUB_MENU is set in place of SYMBOL).
The question.
Assignment assign current-window:menubar = menu m:handle.
is converted to currentWindow().unwrapWindow().setMenubar();
. I didn't find the target rule to change to add parameter to setMenubar
method.
#56 Updated by Greg Shah over 9 years ago
1. Frame definition contains initialization block, that looks like this.
[...]
This block resides right in the inner class aftersetup
method. I didn't find a way how to add this block and I had to addaddWidget
calls right insetup
method.
This was done by adding a BLOCK
node to the CS_STATIC_INITS
section of the inner class in the JAST.
<ast col="0" id="10209137262621" line="0" text="" type="CS_STATIC_INITS"> <ast col="0" id="10209137262622" line="0" text="block" type="BLOCK"> <ast col="0" id="10209137262662" line="0" text="addWidget" type="STATIC_METHOD_CALL"> <ast col="0" id="10209137262663" line="0" text="expr7" type="STRING"/> <ast col="0" id="10209137262664" line="0" text="" type="STRING"/> <ast col="0" id="10209137262665" line="0" text="expr7" type="REFERENCE"/> </ast> </ast> </ast>
If I recall correctly, the reason it these addWidget()
calls were not put in the setup()
method was because they needed to exist much earlier in the initialization process.
Do we need the same thing for menus? If not, then leave the calls in setup()
.
2.
WidgetList
is expecting to containGenericWidget
subclasses.MenuDefinition
orSubMenuDefinition
subclasses can containSkipEntity, RuleEntity, MenuItemWidget and SubMenuDefinition
. The last one is not a GenericWidget and cannot be added toWidgetList
. I had to add aSubMenuWidget self
field toSubMenuDefinition
class and add that field toWidgetList
in case of sub-menu. It looks not good. What do you think?
Actually, I think it is fine. We do a similar thing with GenericFrame
which implements both CommonFrame
and the specific frame definition interface but which is NOT a sub-class of GenericWidget
. GenericFrame
has a frame
member that is the FrameWidget
and which is accessed via asWidget()
when needed.
On the other hand, we don't have the same complexity of frames (we have no frame definition interface that is implemented differently for each frame), so I wonder if we can improve this.
Assignment assign current-window:menubar = menu m:handle. is converted to currentWindow().unwrapWindow().setMenubar();. I didn't find the target rule to change to add parameter to setMenubar method.
You get the parameter processing "for free". You don't have to do anything to make that work. The problem here is that you have to write rules to make the MENU menu
, SUB-MENU sub-menu
and MENU-ITEM menu-item
references emit properly. See convert/widget_references.rules
. When that is done, they will emit naturally into the right parameter location. You will need some additional annotations to be created to record the proper data member references and accessor methods. Those should be done during annotations processing.
#57 Updated by Greg Shah over 9 years ago
Those should be done during annotations processing.
Actually, that is not right. You can probably leave behind the needed annotations during menu_generator.xml
processing.
#58 Updated by Greg Shah over 9 years ago
Code Review vig_upd20141202a.zip
This is great! You are very close now.
1. In WindowWidget
, the menubar should not be stored as a handle
but instead as a MenuWidget
. The getMenuBar()
method would just have return new handle(menubar);
as the body. The setMenuBar()
would just store the contained resource instance instead of the handle
itself. In addition, the menubar instance should be stored in the WindowConfig
instead of WindowWidget
itself.
2. It seems heavyweight to treat rule as a widget, but I suspect that it is the easiest/best thing to do. It is something that can't be seen as a widget by the calling code right? It is never named and cannot be obtained via traversal. It has no configuration and no attributes/methods/events. For this reason, at least minimize the widget features used. It doesn't need its own LegacyResource
. It probably does need a widget ID at least.
#59 Updated by Vadim Gindin over 9 years ago
Greg, What are you writing about in the point 2 in previous note?
#60 Updated by Greg Shah over 9 years ago
What are you writing about in the point 2 in previous note?
I am saying that RULE is not a real widget in 4GL terms. For this reason, RuleEntity
and RuleConfig
seem like too much of a solution. On the other hand, if the generated code and runtime code is simpler by treating it as a widget, then we can do so. You have to make a decision on that.
#61 Updated by Vadim Gindin over 9 years ago
Greg, I got stuck a little. I'm trying to convert menu handle parameter to setMenubar
call for the following statement assign current-window:menubar = menu m1:handle.
. I.e. I'm trying to convert menu m1:handle
to parameter. Here is an AST tree for the right part of that assingment:
<ast col="0" id="665719930953" line="0" text="expression" type="EXPRESSION"> <ast col="40" id="665719930954" line="11" text=":" type="COLON"> <ast col="33" id="665719930955" line="11" text="menu" type="KW_MENU"> <ast col="38" id="665719930958" line="11" text="m1" type="WID_MENU"/> </ast> <ast col="41" id="665719930960" line="11" text="handle" type="ATTR_HANDLE"> <annotation datatype="java.lang.Long" key="oldtype" value="1460"/> </ast> </ast> </ast>
I tried to find how
frame f:handle
is converted, but unsuccessful! variable_references.rules
contains rules for converting variables (DEF VAR ..) not for widgets. I found widget_reference.rules
and tried to add the following rules there:<!-- Doesn't work... Why? type == prog.attr_handle evalLib('methods_and_attributes') and --> <rule> this.prevSibling.firstChild.type == prog.wid_menu and this.prevSibling.type == prog.kw_menu and this.prevSibling != null and parent.type == prog.colon <action> lastid = createPeerAst(java.constructor, "handle", closestPeerId) </action> <rule>this.prevSibling != null and this.prevSibling.firstChild != null <action on="true">owner = this.prevSibling.firstChild.text</action> <action on="false">owner = "temporary_value"</action> </rule> <action> lastid = createJavaAst(java.reference, owner, lastid) </action> </rule>
After conversion process I got the following code
currentWindow(new handle(temporary_value)).unwrapWindow().setMenubar();
, but I expected that one currentWindow().unwrapWindow().setMenubar(new handle(m1));
The questions.
1. My attempt is intuitive and I'm not sure that the place and approach are correct. Aren't they?
2. AST node of type ATTR_HANDLE
exists in source tree as you could see. I tried to write my rule for that node, but It'd failed. If I was adding the condition type == prog.attr_handle
my actions was not being executed. As you can see the condition this.prevSibling != null and this.prevSibling.firstChild != null
is also false
("temporary_variable" owner was used). Why?
Could you help me please. Here is 2 aspects. My rule does not use the common mechanism. It's about 2 aspects:
a) defining of "owner" i.e. defining a menu in my case.
b) working with handle attribute.
How to do that correctly and where?
#62 Updated by Vadim Gindin over 9 years ago
Forgot to add another one question. As you could see the place where new parameter was appeared is also wrong:
it must appear in setMenubar()
method, but appeared in currentWindow()
. It seems closesPeerId
has unexpected value (unexpected for me). How to fix it? Can I get closesPeerId
ast siblings for that purpose?
#63 Updated by Greg Shah over 9 years ago
I found
widget_reference.rules
and tried to add the following rules
As I mentioned in note 56 above, you just need to focus on getting the WID_MENU
, WID_SUB_MENU
and WID_MENU_ITM
to emit naturally.
I see you tried to use evalLib('methods_and_attributes')
. evalLib()
and execLib()
are our ways of invoking named functions. You cannot execute entire rule-sets using those methods. On the pattern-engine processing executes entire rule-sets.
But you don't need to do such a thing anyway. The methods_attributes.rules
is already getting executed as part of core_conversion.xml
. So you can let it properly process. All of the rule-sets listed in core_conversion.xml
are executing sequentially for each file. Cooperatively, this results in building a complete JAST. But you must let each piece do its own part.
DO NOT worry about the COLON
or ATTR_HANDLE
processing.
Consider this code from widget_references.rules
:
<!-- convert anything that could be a widget reference --> <rule> evalLib("variables") or evalLib("fields") or evalLib("widget_references") <!-- only process if this is a frame field --> <!-- widget handle is emitted via 'asWidget()' method --> <rule>isNote("frame-id") <action>methodType = java.method_call</action> <rule>type == prog.var_handle <action on="false"> owner = #(java.lang.String) execLib("get_framename", this) </action> <action on="false"> methodTxt = getNoteString("accessor") </action> </rule>
The evalLib("widget_references")
will evaluate true for WID_MENU
, WID_SUB_MENU
and WID_MENU_ITM
, right? Good, that is what we want.
The isNote("frame-id")
will then evaluate false, right? With menus, we don't have a "frame-id" annotation and we probably don't need or want one. But we may need to do something else here to identify those WID_MENU
, WID_SUB_MENU
and WID_MENU_ITM
cases that need to emit into the business logic. The "frame-id" is how we do it for frame widgets. Perhaps all WID_MENU
, WID_SUB_MENU
and WID_MENU_ITM
nodes should always emit. You have to determine that. But we probably need a new section in widget_references.rules
that handles menus. I doubt that we want the menus dropping through the current code because it is designed for frames and frame widgets.
Once past the "frame-id" test, most WID_*
cases will execute methodTxt = getNoteString("accessor")
which is the method call text that will return the widget from the frame. As I stated in note 56:
You will need some additional annotations to be created to record the proper data member references and accessor methods.
During menu_generator.xml
, you MUST leave behind enough information in the WID_*
nodes to allow them to emit the accessor call.
In addition, where the frame reference gets emitted today, you will have to do something similar to emit the menu instance so that the accessor will be called on the right object.
After conversion process I got the following code currentWindow(new handle(temporary_value)).unwrapWindow().setMenubar();, but I expected that one currentWindow().unwrapWindow().setMenubar(new handle(m1));
Your approach is incorrect. Instead please focus on my advice above and below. Some examples of mistakes you are making:
- You are processing at the
COLON
andATTR_HANDLE
nodes when you simply need to do yourwidget_references.rules
processing at theWID_*
node itself. - Your code is misunderstanding the idea of "peerid".
- You have no annotations left behind during menu generation to allow these nodes to know the menu instance name (for
WID_MENU
) or menu instance name and accessor (forWID_SUB_MENU
andWID_MENU_ITM
).
Peer IDs are used to allow CHILD NODES to emit UNDERNEATH their parent's peer node. A peer node is a JAST node and a "peerid" annotation allows that node to be found. The most common way is through closestPeerId
which searches up the AST parent hierarchy until an ancestor is found with a "peerid" annotation. That peerid is then used to get the JAST node that will be the parent for the newly created JAST node. createPeerAst()
creates a new JAST node and saves its ID as the peerid annotation for the CURRENT NODE (copy
). createJavaAst()
should be used when this peering behavior is not appropriate either because the peerid is not wanted or because you are processing at a different node than where the peerid should be placed.
AST node of type ATTR_HANDLE exists in source tree as you could see. I tried to write my rule for that node, but It'd failed. If I was adding the condition type == prog.attr_handle my actions was not being executed. As you can see the condition this.prevSibling != null and this.prevSibling.firstChild != null is also false ("temporary_variable" owner was used).
Please avoid all this. Just focus on the WID_*
nodes.
I hope this answers all your questions. If not, please ask what is still confusing.
#64 Updated by Vadim Gindin over 9 years ago
Greg Shah wrote:
..
I see you tried to useevalLib('methods_and_attributes')
.evalLib()
andexecLib()
are our ways of invoking named functions. You cannot execute entire rule-sets using those methods. On the pattern-engine processing executes entire rule-sets.
..
I just wanted to call the function 'methods_and_attributes' in include/common-progress.rules
not the entire rule-set. This function would pass my ATTR_HANDLE node. I tried to wrote my rule exactly for ATTR_HANDLE. Now I understand that it was wrong.
--
Thanks for good description! Now I understand that I need to emit annotations for each MENU-ITEM and SUB-MENU, containing the names of parent SUB-MENU (if exists) and parent MENU. I also need to check if WID_* nodes are emitted in all cases of usage: definitions and references.
I tried to add such annotation called container-id
but didn't use it before. You advised me to add annotations right in menu_generator.xml
. I added container-id
before in fixups/post_parse_fixups.xml
. Now I think that menu_generator.xml
is better place because fixups/post_parse_fixups.xml
is too early (there was no necessity in such annotations in menu_generator at until now). Right? Now I see that I'll probably need 2 separate annotations: "menu" and "sub-menu" instead of common annotation "container-id".
About "peerid" idea. Really good idea. In my task what would be the target nodes to add peerid
annotations? How about JAST that corresponds to setup
method? I used setUpLastId
variable for that in menu_generator.xml
. Now can I get rid of it and use "peerid" in menu_generator.xml
instead?
Relating to widget_references.rules
lets consider little Progress sample: menu-item mi in sub-menu sm
. That could should be converted to that one sm.mi
in Java class. So should I add peerid
for a JAST node, that corresponds to sm
, and use closestPeerId
when emitting a JAST node for mi
. Did I understand correctly?
#65 Updated by Greg Shah over 9 years ago
Now I think that menu_generator.xml is better place because fixups/post_parse_fixups.xml is too early (there was no necessity in such annotations in menu_generator at until now). Right?
Yes, that is right. While you might be able to link the IDs up, the accessor and menu instance names can only be known in menu_generator.xml
.
In my task what would be the target nodes to add peerid annotations?
For the WID_*
you probably don't need peerid because they won't have any child nodes.
How about JAST that corresponds to setup method? I used setUpLastId variable for that in menu_generator.xml. Now can I get rid of it and use "peerid" in menu_generator.xml instead?
I don't think so. The setup()
method doesn't have a counterpart in the Progress AST. So there is no place to put the peerid annotation to make it work. Even if there was a 4GL peer AST for the annotation, that AST would have to be the direct parent of all the options that are being emitted as method calls. Peerid helps where the natural structure of the tree needs to be the same (or very close) between both the 4GL and Java. Then peerid causes the natural tree structure to be duplicated.
lets consider little Progress sample:
menu-item mi in sub-menu sm
. That could should be converted to that one sm.mi in Java class. So should I add peerid for a JAST node, that corresponds tosm
, and useclosestPeerId
when emitting a JAST node formi
. Did I understand correctly?
Close, but not quite right. Actually, the JAST needs to have a parent node that is type java.member
for mi
and a child node of type java.reference
for sm
:
<ast id="0" type="MEMBER" text="mi"> <ast id="0" type="REFERENCE" text="sm" /> </ast>
When brew.xml
emits this (a.k.a. it anti-parses this into Java source code), it operates depth-first, so the REFERENCE
is emitted and then a .
and finally the MEMBER
.
This means that the mi
could have the peerid. But this would only work if the IN SUB-MENU sm
was the child node of the MENU-ITEM mi
. I think it might be, so this case might work.
#66 Updated by Vadim Gindin over 9 years ago
How about menu handle? I need that menu m1:handle
will be converted to new handle(m1)
. Where it happens with frame? asWidget
only returns FrameWidget
and asWidgetHandle
is not mention in rules at all.
#67 Updated by Greg Shah over 9 years ago
This is a good question. The answer is that we don't actually create a new handle()
constructor for the ATTR_HANDLE
with oldtype == prog.kw_handle
.
Consider this code:
def var h as handle. def var i as int. def frame f i. i = 30. display i with frame f. def temp-table tt field num as int. def buffer b for tt. h = frame f:handle. message "ROW = " + string(frame f:row). message "FRAME NAME = " + frame f:name. h = buffer b:handle. message "BUF NAME = " + buffer b:name.
Here is how it converts (just the last lines that we care about):
h.assign(fFrame.asWidget()); message(concat(new character("ROW = "), valueOf(fFrame.getRow()))); message(concat(new character("FRAME NAME = "), fFrame.name())); h.assign(b); message(concat(new character("BUF NAME = "), b.name()));
No constructors!
This works because when it is a handle type that is being assigned, the handle.assign(WrappedResource)
is used. So we avoid wrapping here and just pass the instance itself.
And when we call a 4GL method or read and attribute we would have to unwrap the resource anyway, so we don't ever wrap it. The only time we actually unwrap a handle is when it is the handle that is being dereferenced, as in: h:name
.
For attributes like MENUBAR
that can be assigned from a handle, make sure you create multiple setter methods:
void setMenuBar(handle mb) { } void setMenuBar(MenuWidget mw) { }
This way it can be used like this:
my-handle = menu my-menu:handle. current-window:menubar = menu my-menu:handle. /* this uses setMenuBar(MenuWidget mw) */ current-window:menubar = my-handle. /* this uses setMenuBar(handle mb) */
#68 Updated by Vadim Gindin over 9 years ago
- File vig_upd20141206a.zip added
I added menu-item
attributes conversion and fixed menubar
conversion.
The question. Although I added relativePath("KW_MENU_ITM/KW_DCOLOR/EXPRESSION/NUM_LITERAL")
to literals.rules
the values are still presented in the body method. Why it could be?
#69 Updated by Greg Shah over 9 years ago
Code Review vig_upd20141206a.zip
1. WindowWidget.setMenubar(handle)
should check for null and unknown can take the same action as the 4GL would in that case. Then if it is not null or unknown, then it should get the contained MenuWidget
and call setMenubar(MenuWidget)
to have common code that does the assignment/setOwner()
call.
2. Let's not create multiple methods that do the same thing. The 4GL does this and it is not great. For example, they have DISABLED
as an option and well as SENSITIVE
as an attribute. If DISABLED
is the same as SENSITIVE=FALSE
then let's convert it to setSensitive(false)
and avoid the extra setDisabled()
method.
3. Shouldn't mnemnonic
, readOnly
, toggleBox
and accelerator
be in the MenuConfig
? Having them in the widget itself is not correct.
4. I'm not sure why frame_generator.xml
has -java.reference
in the litMap
. I see that you have copied it. Can you say what purpose it serves? I also think it may be time to make the core logic in literals.rules
into common code that can be accessed from menu_generator.xml
, frame_generator.xml
and literals.rules
(in core_conversion.xml
). Duplicating all that logic is not good.
5. The use of downPath()
and then the de-referencing of children for all the option setters doesn't seem right. First, it is fighting the tree structure instead of letting it help you. It is much better to match directly on the node being converted and emit that into the right location using createPeerAst()
. And then handle the children separately on their own and let them emit naturally into closestPeerId
. The resulting code will be MUCH easier to write, read and maintain. The frame_generator.xml
is a very bad design to copy, which is why I was wanting to avoid using it as a "template". Of course in such an approach, all that code would not be inside the type prog.kw_menu_itm
condition. But it might be inside an parent != null && parent.type prog.kw_menu_itm and (parent.parent.type prog.define_menu or parent.parent.type prog.define_sub_menu)
.
6. In widget_references.rules
, this looks wrong: <!-- variables -->/l
(the /l
at the end is junk).
7. Your question:
Although I added relativePath("KW_MENU_ITM/KW_DCOLOR/EXPRESSION/NUM_LITERAL") to literals.rules the values are still presented in the body method. Why it could be?
I'm not exactly sure, but I can say that in frame_generator.xml
, the literals that are emitted for frame and widget setters/options are then hidden so they don't emit into the business logic. But I would really prefer an annotation that bypasses processing by literals.rules
instead of calling setHidden(true)
on the literal node.
#70 Updated by Vadim Gindin over 9 years ago
Greg, I have some difficulties with dynamic menus.
1. I missed one attribute in MenuItemWidget
called "SUBTYPE". It has character type and can contain one of following constants: "NORMAL", "SKIP", "RULE". This attribute is used mostly in dynamic scenarios. It can mean that we don't have to use SkipEntity
and RuleEntity
and MenuWidget
and SubMenuWidget
can contain only MenuItemWidget@s. I.e. when the source procedure contain RULE or SKIP I need to create @MenuItemWidget
and set SUBTYPE attribute. There are possible two ways:
a) correct implementation rules to support only MenuItemWidget
as a children of MenuItemWidget
or SubMenuWidget
.
b) In dynamic cases treat the constructs, creating MENU-ITEMs with non-normal SUBTYPEs as creation of SkipEntity
or RuleEntity
What way will be preferrable?
2. If I remember correctly the following constructs CREATE ... ASSIGN ..
was not fully supported by conversion rules. Should I check this variant too?
#71 Updated by Vadim Gindin over 9 years ago
- File vig_upd20141213a.zip added
- About literals, that are stayed in
body
method I found a way to remove it without new annotations. I movedsuppress
var definition earlier and use it in NUM_LITERAL block. It should also be used for other types. But I have one difficulty here: literals was removed but semicolons are stayed. Could you help me? - I removed
menubar
attribute fromMenuWidget
and replaced it withPOPUP-ONLY
that have opposite value. MENUBAR is an option in DEFINE MENU statement, and POPUP-ONLY is an menu attribute. I also checked that one menu cannot be used as main and popup. - WINDOW attribute exist for all three widgets but I think it's a common attribute for all widgets and should be added in
GenericWidget
for example. I didn't added it yet. What do you think? - About MENU attributes I had to emit m1.getSelf() to set values instead of adding all attributes methods to
MenuDefinition
class. - About extracting a common code from
menu_generator.xml
,frame_generator.xml
andliterals.rules
I movedset_attr
andset_attr_ex
functions toinclude/common-progress.rules
. Unfortunately I can't extractlitMap
with them. It didn't work I can't find why. So I had to add new parameter "litMap" to these functions. - I moved
setSubtype
methods toSubTypeAttribute
interface and changesubtype
emission - Dynamic creation is now works.
- Some other minor changes.
- SUBTYPE attribute. How to do: separate classes for RULE and SKIP or MenuItemWidget for them.
- I want to try
lvalue
rule forsubmenu_descriptor
inprogress.g
as you advised earlier. - Different types of references menus, sub-menus and menu-items
- NEW and SHARED attributes in DEFINE MENU statement
- triggers
- something else?
#72 Updated by Vadim Gindin over 9 years ago
- TITLE attribute of the Menu
- LIKE clauses
#73 Updated by Vadim Gindin over 9 years ago
The question about shared menus. The problem is in try to generate menu definition second time when DEFINE SHARED MENU is met. I didn't find any special processing of that case in frame_generator.xml
. I.e. I didn't find any check if current node corresponds to DEFINE SHARED FRAME statement and related frame definition is already generated. So I can conclude that it works only by name, i.e. when frame definition is generated its name is saved in a special map. At the next try to generate frame definition for the frame with the same name we can check this map and bypass generation for that node. I doubt that it really works by name. Don't you remember how shared frame definition generation really works? I.e. how it bypasses generation for the shared frame?
#74 Updated by Greg Shah over 9 years ago
I am working my way through the pending updates and questions.
While I am doing that, I wanted to answer your question about shared menus.
Any NEW SHARED
menu is one that needs to be converted into a menu definition. Any menu that is just SHARED
but has no NEW
is one that is created elsewhere than then "imported" into the current program.
Please convert these two programs to get the idea:
shared-var-creator.p
define new shared variable my-var as int init 14. run shared-var-importer.p.
shared-var-importer.p:
define shared var my-var as int. message my-var.
You will see the references to the SharedVariableManager
in the resulting Java code. The creator program instantiates the variable, initializes it and stores a reference to it (by its legacy 4GL name) in the SharedVariableManager
. The importer just obtains that reference using the same name and then can use it as a local member of the class. But the importer does not instantiate a new var.
I think menus will work the same way.
So I can conclude that it works only by name, i.e. when frame definition is generated its name is saved in a special map. At the next try to generate frame definition for the frame with the same name we can check this map and bypass generation for that node. I doubt that it really works by name. Don't you remember how shared frame definition generation really works? I.e. how it bypasses generation for the shared frame?
Search for prog.kw_shared
in annotations/frame_scoping.rules
. Also look there for how the frameShr
var is being used to create "shared" and "imported" annotations. Those are used downstream in convert/frame_construction.rules@.
If I recall correctly, imported shared frames are still generated as separate frames. I think it was done because the frame definition can be slightly different between the two locations. Write some simple shared frame testcases (new shared and just shared) to see exactly how this works.
Then you must determine if we have a similar problem with menus. Of course, we would prefer to deal with menus like variables but we must match the 4GL's behavior.
#75 Updated by Greg Shah over 9 years ago
1. I missed one attribute in
MenuItemWidget
called "SUBTYPE". It has character type and can contain one of following constants: "NORMAL", "SKIP", "RULE". This attribute is used mostly in dynamic scenarios. It can mean that we don't have to useSkipEntity
andRuleEntity
andMenuWidget
andSubMenuWidget
can contain onlyMenuItemWidget@s. I.e. when the source procedure contain RULE or SKIP I need to create @MenuItemWidget
and set SUBTYPE attribute. There are possible two ways:
a) correct implementation rules to support onlyMenuItemWidget
as a children ofMenuItemWidget
orSubMenuWidget
.
b) In dynamic cases treat the constructs, creating MENU-ITEMs with non-normal SUBTYPEs as creation ofSkipEntity
orRuleEntity
What way will be preferrable?
Interesting. I see that the SUBTYPE
attribute is writable, which means that something that starts as one type can be changed later. That means that option A above is the only proper way to do this. That means you eliminate the SkipEntity
and RuleEntity
. And you implement these based on the MenuItemWidget
SUBTYPE
attribute.
In menu definitions, the widgets are defined statically, so it seems you can pass a SUBTYPE
enum value to the MenuItemWidget
constructor to initialize the correct subtype. By default, the subtype should be NORMAL
so you can possibly avoid passing that enum value in most of the time.
2. If I remember correctly the following constructs
CREATE ... ASSIGN ..
was not fully supported by conversion rules. Should I check this variant too?
I think this is supported. It definitely works for frames. Please do check this too.
#76 Updated by Greg Shah over 9 years ago
But I have one difficulty here: literals was removed but semicolons are stayed. Could you help me?
I suspect that there is some hidden node that exists which is not suppressed. For example, there may be an EXPRESSION
node which then generates something in the JAST that causes the semicolon to emit because it thinks something is there.
WINDOW attribute exist for all three widgets but I think it's a common attribute for all widgets and should be added in GenericWidget for example. I didn't added it yet. What do you think?
Yes, it should be present in CommonWindow
and implemented in GenericWidget
since it is a valid attribute for all widgets in the 4GL (except SHADOW-WINDOW
which we don't support yet).
Unfortunately I can't extract litMap with them. It didn't work I can't find why. So I had to add new parameter "litMap" to these functions.
This was using a bad practice of accessing variables from the containing scope. When you moved the function to a different rule-set, it changed the scope of the function making the litMap
unavailable. Passing it as a parameter is the correct approach.
The code review is next.
#77 Updated by Greg Shah over 9 years ago
Code Review vig_upd20141213a.zip
I generally like the changes.
1. Removing the on="false"
from line 511 of literals.rules
is incorrect. I think that code is required.
2. I don't think menu_construction.rules
needs the litMap
stuff. It is called during core conversion, where the literals.rules
is co-executing directly.
3. I'm not sure if making MENUBAR
and POPUP-ONLY
synonymous is correct, especially since POPUP-ONLY
probably generates an error in ChUI and MENUBAR
probably does not. Did you test that?
4. Did you test if it was safe to make SENSITIVE
and DISABLED
synonymous? A test would be to create a DISABLED
menu item and then see if setting SENSITIVE
to true
causes the item to be usable.
5. Why is setDateOrder()
added to SessionUtils
?
6. The ServerImpl
methods should not have the LegacyAttribute
annotations. In addition, they should call handle.readOnlyError()
instead of throwing their own RuntimeException
.
#78 Updated by Vadim Gindin over 9 years ago
I've tested shared menus. As far as I can understand there are one instance of menu is used for created shared menu and for shared menu. I changed labels in external procedure for shared menu created in main procedure. It was changed. But I couldn't create one popup menu and assign it for 2 buttons. I got the error: "**OWNER/PARENT exists on the BUTTON btn1. Unable to set attribute POPUP-MENU. (4074)".
#79 Updated by Greg Shah over 9 years ago
I changed labels in external procedure for shared menu created in main procedure. It was changed.
Does this mean that when it is used in the called procedure that the labels are different than when it is used in the calling procedure?
But I couldn't create one popup menu and assign it for 2 buttons. I got the error: "**OWNER/PARENT exists on the BUTTON btn1. Unable to set attribute POPUP-MENU. (4074)".
This is understandable. I assume it works if you don't assign it to something in the calling procedure (at least until after it is done being used in the called procedure)?
#80 Updated by Vadim Gindin over 9 years ago
Greg Shah wrote:
I changed labels in external procedure for shared menu created in main procedure. It was changed.
Does this mean that when it is used in the called procedure that the labels are different than when it is used in the calling procedure?
I only mean the following. A menu is defined in calling procedure with several labeled menu-items. In called procedure labels are the same - all is the same, but I can change them in called procedure and I able to see the new labels in shown menu.
From the other point of view I can make the following conclusions. In CHUI we have only one WINDOW, therefore we can have only one MENUBAR. In my tests this menubar is shared between 2 procedures and I can change it in both of them. It confirms that both procedures are working with one object. Another test is about POPUP menu. Such shared menu is assigned as POPUP-MENU for some button in calling procedure. When I'm trying to assign this shared menu in called procedure to another button I'm getting an error that menu already has a PARENT/OWNER. It also confirms that both procedures are working with one instance of menu.
But I couldn't create one popup menu and assign it for 2 buttons. I got the error: "**OWNER/PARENT exists on the BUTTON btn1. Unable to set attribute POPUP-MENU. (4074)".
This is understandable. I assume it works if you don't assign it to something in the calling procedure (at least until after it is done being used in the called procedure)?
Yes, in this case I will be able to assign it in called procedure.
Another one thing. As I could understand only MENU can be shared. MENU-ITEMs or SUB-MENUs - cannot be shared. Moreover, when I'm trying to call some MENU-ITEM from shared MENU in called procedure - it dont' work:menu-item mi in menu m
will raise an error that mi is not found. I only can get a MENU-ITEM or SUB-MENU of a shared MENU using CHILD/SIBLING attributes. It looks strange.
#81 Updated by Vadim Gindin over 9 years ago
- Such objects are emitted as fields of menu (or sub-menu) definition class (
MenuDefinitionM
) without access modifier (i.e. default). The procedure class (References
in my example@) is generated in a package different fromMenuDefinitionM
package. In my simple case theReferences
is generated in the packagecom.goldencode.testcases.menu
andMenuDefinitionM
is generated incom.goldencode.testcases.ui.menu
. It means that our default fields will be unaccessible in a main procedure for references. What to do? May be I should emitpublic
access modifier? - If I want to assign some
MENU m
attribute, for exampletitle
, I'm emittingm.getSelf().setTitle(..)
at this moment. But now I need to emit reference to menu-item of our menu:menu-item mi in menu m
for example. I'll probably need to emitm.mi
instead ofm.getSelf().mi
becausemi
is a field of MenuDefinition not of MenuWidget. The difficulty is how to distinguish these 2 cases.
#82 Updated by Greg Shah over 9 years ago
I changed labels in external procedure for shared menu created in main procedure. It was changed.
Does this mean that when it is used in the called procedure that the labels are different than when it is used in the calling procedure?
I only mean the following. A menu is defined in calling procedure with several labeled menu-items. In called procedure labels are the same - all is the same, but I can change them in called procedure and I able to see the new labels in shown menu.
Are the changes made in the called procedure also visible in the calling procedure? Can the menu-items/sub-menus be different in each procedure for the same shared menu?
Another one thing. As I could understand only MENU can be shared. MENU-ITEMs or SUB-MENUs - cannot be shared. Moreover, when I'm trying to call some MENU-ITEM from shared MENU in called procedure - it dont' work:
menu-item mi in menu m
will raise an error that mi is not found. I only can get a MENU-ITEM or SUB-MENU of a shared MENU using CHILD/SIBLING attributes. It looks strange.
Do all the menu-items and sub-menus defined in the calling procedure still appear and work? If so, I assume they execute triggers in the calling procedure even while the menus are being processed in the called procedure?
#83 Updated by Greg Shah over 9 years ago
Vadim Gindin wrote:
2 questions about MENU-ITEM references or SUB-MENU references.
- Such objects are emitted as fields of menu (or sub-menu) definition class (
MenuDefinitionM
) without access modifier (i.e. default). The procedure class (References
in my example@) is generated in a package different fromMenuDefinitionM
package. In my simple case theReferences
is generated in the packagecom.goldencode.testcases.menu
andMenuDefinitionM
is generated incom.goldencode.testcases.ui.menu
. It means that our default fields will be unaccessible in a main procedure for references. What to do? May be I should emitpublic
access modifier?
Yes, these must be public
, which can be done using an annotation in the JAST.
- If I want to assign some
MENU m
attribute, for exampletitle
, I'm emittingm.getSelf().setTitle(..)
at this moment. But now I need to emit reference to menu-item of our menu:menu-item mi in menu m
for example. I'll probably need to emitm.mi
instead ofm.getSelf().mi
becausemi
is a field of MenuDefinition not of MenuWidget. The difficulty is how to distinguish these 2 cases.
Please provide some example 4GL menu reference code that must convert in 2 different ways so that I can get a better idea about the problem.
#84 Updated by Vadim Gindin over 9 years ago
Greg Shah wrote:
..
Are the changes made in the called procedure also visible in the calling procedure? Can the menu-items/sub-menus be different in each procedure for the same shared menu?
Yes for the first question. No for the second question. I created dynamic menu-item in called procedure and it became visible in calling procedure.
..
Do all the menu-items and sub-menus defined in the calling procedure still appear and work? If so, I assume they execute triggers in the calling procedure even while the menus are being processed in the called procedure?
Yes for the first question. Triggers are work. I didn't understand the last question. What do you mean?
#85 Updated by Greg Shah over 9 years ago
Do all the menu-items and sub-menus defined in the calling procedure still appear and work? If so, I assume they execute triggers in the calling procedure even while the menus are being processed in the called procedure?
Yes for the first question. Triggers are work. I didn't understand the last question. What do you mean?
To make the menu do something useful, one must setup triggers, right?
The place where the menu-items are defined seems like the obvious place where the triggers would also be defined. This is the calling procedure, right?
Since menu items cannot be accessed by name from the called procedure, it seems best to have the triggers in the calling proc.
If you use the menu in the called procedure, does any user selection of a menu item execute the associated trigger in the calling procedure?
#86 Updated by Vadim Gindin over 9 years ago
Yes, it does.
#87 Updated by Greg Shah over 9 years ago
OK, then it seems shared menus are in fact like shared variables. There is really just 1 instance and "importing" should do the job.
Is there any way to reference an "imported" shared menu in a DEFINE SUB-MENU
that is in the called procedure? I guess that would not work, but I want to check to be sure.
#88 Updated by Greg Shah over 9 years ago
- Assignee changed from Evgeny Kiselev to Vadim Gindin
#89 Updated by Vadim Gindin over 9 years ago
- Assignee changed from Vadim Gindin to Evgeny Kiselev
The only way to use "imported" shared menu reference is LIKE clause in DEFINE MENU or DEFINE SUB-MENU statements, for example define menu sm like mbar.
. You are right. It doesn't work: sm remains empty.
By the way. Bring to notice: menu mbar is referenced without KW_MENU keyword. It is also works in the same way for dynamically created menu (probably because of handles), for example: m:title="Some title".
#90 Updated by Vadim Gindin over 9 years ago
- Assignee changed from Evgeny Kiselev to Vadim Gindin
#91 Updated by Vadim Gindin over 9 years ago
I have some difficulty working with references. I've added the following rule to widget_references.rules
:
<rule>type == prog.wid_menu and parent.type == prog.kw_menu <rule>parent.parent == null or parent.parent.type != prog.kw_in <action on="true"> lastid = tw.graft("method_call", null, closestPeerId, "methodtxt", "getSelf", "javaname", text).getId() </action> <action on="false">printfln("TEXT: %s", text)</action> <action on="false">printfln("ID: %d", closestPeerId)</action> <action> on="false"> lastid = createJavaAst(java.reference, text, closestPeerId).getId() </action> </rule> </rule>
Consider we have the following statement:
menu-item mi:label in menu m = "MMMM".
Here is the correspondent AST subtree:<ast col="0" id="751619276865" line="0" text="assignment" type="ASSIGNMENT"> <ast col="30" id="751619276866" line="10" text="=" type="ASSIGN"> <annotation datatype="java.lang.Long" key="peerid" value="755914244133"/> <ast col="13" id="751619276869" line="10" text=":" type="COLON"> <ast col="1" id="751619276870" line="10" text="menu-item" type="KW_MENU_ITM"> <ast col="11" id="751619276873" line="10" text="mi" type="WID_MENU_ITM"/> </ast> <ast col="14" id="751619276875" line="10" text="label" type="ATTR_CHAR"> <annotation datatype="java.lang.Long" key="oldtype" value="649"/> </ast> <ast col="20" id="751619276877" line="10" text="in" type="KW_IN"> <ast col="23" id="751619276879" line="10" text="menu" type="KW_MENU"> <ast col="28" id="751619276882" line="10" text="m" type="WID_MENU"/> </ast> </ast> </ast> <ast col="0" id="751619276885" line="0" text="expression" type="EXPRESSION"> <ast col="32" id="751619276886" line="10" text=""MMMM"" type="STRING"> <annotation datatype="java.lang.Boolean" key="is-literal" value="true"/> <annotation datatype="java.lang.Long" key="peerid" value="755914244135"/> </ast> </ast> </ast> </ast>
Returning to the added rule. It is intended for AST of type WID_MENU. As you can see that AST has attribute text="m"
(variable name of menu). That is confirmed by printed value in the log. But there is some other value "list0" that is transfered to followed createJavaAst
call as a value of attribute text
. Moreover, target menu reference is not appear in generated class. If I'll swap conditions with each other: on="false"
with on="true"
then m.getSelf()
will appear in generated class in a correct place. I don't understand why simplest java.reference
AST is not added, why the text
attribute has a strange value in createJavaAst
call. Could you help me?
#92 Updated by Constantin Asofiei over 9 years ago
- what is the expected converted form for the
menu-item mi:label in menu m = "MMMM".
code? Is it something likem.menuMi().setLabel("MMMM")
? - are you sure you are on the correct 4GL AST? You can debug the
this.id
value to identify it. - what is the intent of the
parent.parent == null
test? Please post the 4GL code which is expected to be treated by it, as it doesn't seem correct. - using the
text
attribute to identify the java var is not correct. You need to identify the menu definition referenced by theWID_MENU
AST, and resolve the java name from it. Thetext
attribute always contains the legacy 4GL name, which is not necessarily the java converted name. I think you need some annotations at theKW_MENU_ITM
, with the ID of the parent menu, the name of the accessor emitted to access the widget in the converted code (i.e.menuMi
), etc. See how ach:name in frame f1
construct gets converted, menu items should follow a similar approach.
#93 Updated by Greg Shah over 9 years ago
You have a syntax problem with your code <action> on="false">
. There is an extra >
there.
Also, you can remove the parent.parent null
test since this code is only executed when there is a type wid_menu which can never have a null grandparent.
#94 Updated by Vadim Gindin over 9 years ago
Oh..
Sorry.
Constantin, thank you too. I'll process your remarks.
#95 Updated by Vadim Gindin over 9 years ago
I'm working with non-standard type of menu-item reference menu-item mi in sub-menu sm
. Peculiarity of this reference type is the fact, that the target menu is not specified and is defined implicitly. The sub-menu sm
can be a child of several menus and the first menu is used in order of DEFINE MENU statements appearance. Here is an example, illustrating this case.
define sub-menu sm menu-item mi label "Source mi label". define menu m1 sub-menu sm label "Sm in m1". define menu m2 sub-menu sm label "Sm in m2". menu-item mi:label in sub-menu sm = "New mi label".
Here are 2 instances of SUB-MENU
sm
: in m1
and in m2
menus. The last statement changes a label of menu-item in a sub-menu of m1
menu (because m1
is defined earlier than m2
).
The reference menu-item mi:label in sub-menu sm
must be converted to the following code sm.mi.setLabel("New mi label");
and this code must appear in menu definition class for m1
- MenuDefinitionM1
only. Not in the procedure class, because there is no sm
field and not in both menu definition classes, because of the described behavior.
I'm adding created menu conversion rules from widget_references.rules
to menu_generator.xml
, but I'm not sure if it is a right way. May be there is a simpler variant: generate full reference in a procedure class:m1.sm.mi.setLabel("New mi label");
. What do you think?
#96 Updated by Vadim Gindin over 9 years ago
Constantin, about IN ...
clauses. I've converted simple test for frames with the trigger
on enter of i in frame f message string(frame f:handle).
and found that AST for widgets list looks like this:
<ast col="0" id="614180323381" line="0" text="" type="WIDGET_LIST"> <ast col="13" id="614180323382" line="5" text="i" type="WID_FILL_IN"> <annotation datatype="java.lang.Long" key="oldtype" value="2388"/> <annotation datatype="java.lang.Long" key="refid" value="614180323331"/> <annotation datatype="java.lang.String" key="javaname" value="i"/> <annotation datatype="java.lang.String" key="accessor" value="widgeti"/> <annotation datatype="java.lang.Long" key="frame-id" value="614180323411"/> <annotation datatype="java.lang.Long" key="peerid" value="618475290679"/> <ast col="15" id="614180323385" line="5" text="in" type="KW_IN"> <ast col="18" id="614180323388" line="5" text="frame" type="KW_FRAME"> <ast col="24" id="614180323391" line="5" text="f" type="WID_FRAME"/> </ast> </ast> </ast> </ast>
As you can see that WID_FRAME or KW_FRAME are not annotated with
refid
or javaname
. Is it because every widget is already annotated with "frame-id"?#97 Updated by Constantin Asofiei over 9 years ago
Vadim Gindin wrote:
... Is it because every widget is already annotated with "frame-id"?
Yes.
You should find a way to disambiguate the IN SUB-MENU clause and annotate the MENU-ITEM with the sub-menu-id somewhere in the annotations phase. Later, in the conversion phase, it will just read the AST referenced by the sub-menu-id annotation and get the java name (or other info).
#98 Updated by Greg Shah over 9 years ago
The reference
menu-item mi:label in sub-menu sm
must be converted to the following codesm.mi.setLabel("New mi label");
and this code must appear in menu definition class form1
-MenuDefinitionM1
only. Not in the procedure class, because there is nosm
field and not in both menu definition classes, because of the described behavior.I'm adding created menu conversion rules from
widget_references.rules
tomenu_generator.xml
, but I'm not sure if it is a right way. May be there is a simpler variant: generate full reference in a procedure class:m1.sm.mi.setLabel("New mi label");
. What do you think?
I think your approach is correct: emit it into the first menu definition and not in the business logic (procedure class).
If there is any duplication of code between widget_references.rules
and menu_generator.xml
, then please do make functions that can be called from both places.
#99 Updated by Vadim Gindin over 9 years ago
I think that procedure class is better place because concrete reference could be a part of some logic in that procedure: conditions, cycles and so on. Don't you mind? I've finished the case "in sub-menu sm" using this variant. There are possible the other variant "menu-item mi in menu m1". And mi can appear in different subtrees and levels of m1's tree. I need to test it and implement
#100 Updated by Greg Shah over 9 years ago
OK, let's go with your plan.
#101 Updated by Vadim Gindin over 9 years ago
Just for documenting purposes.
One SUB-MENU can appear in one MENU tree only once. Therefore when we have a reference menu-item mi in sub-menu sm
it means that MENU-ITEM can be a immediate child of this SUB-MENU or a descendant of some level. We need to convert such reference to something like this: m.sm.sm1.sm2[.smN].mi
, where m
is an implicitly defined MENU reference, the first met MENU containing SUB-MENU sm
, and sm1, sm2, .. smN
- several interim SUB-MENUs. That is why we can use simple algorithm to build full reference on that menu: Just going up the tree, starting from menu-item and collect all interim SUB-MENUS.
The situation with references of type menu-item mi in menu m
is more complex, because MENU-ITEM can appear in different levels of MENU tree. And we will need some sort of depth-first search (DFS) to find concrete MENU-ITEM. Here are couple of tests to illustrate the difference from DFS used in TRPL and the DFS used by Progress.
Here is the sample tree in order of definition in a source procedure. m -> sm1 -> sm2 -> mi m -> sm -> mi m -> mi
The TRPL DFS will return the first path
m -> sm1 -> sm2 -> mi
because it will reach it first. But the reference menu-item mi in menu m
points to that one: m -> mi
.Another sample tree: m -> sm1 -> sm2 -> mi m -> sm -> mi
Here the search result of TRPL DFS will be again
m -> sm1 -> sm2 -> mi
and the reference menu-item mi in menu m
is also points to that path.
These and other tests allow to formulate the search algorithm as follows:
1. Lets assume that cur
is the current node in a MENU tree. Initial value is a DEFINE_MENU node.
2. First we are searching the given MENU-ITEM in all immediate child MENU-ITEMs.
3. If we've found the match than return success.
4. If we've not found the match we are going into the all SUB-MENUs and for each of them we are repeating steps from the step 2.
5. If we've searched all tree and didn't find a match - just return null
P.S. Some off-topic question. Lets assume that we've found some path sm1.sm2.sm3.mi
. Can I emit only one JAST node with the text sm1.sm2.sm3
? It is simpler and It works but it gives incorrect JAST sub-tree. What do you think?
#102 Updated by Greg Shah over 9 years ago
This doesn't seem right. Wouldn't the 4GL do this "lookup" at runtime instead of at compile time? In other words, can you move these things around at runtime such that what we can detect at conversion is no longer correct?
It seems to me that we could write a runtime method that can do this lookup for us, returning back the correct menu-item, no matter how deeply nested it is. Even if the menus cannot be changed at runtime and are truly static, I would rather have this lookup method approach because it will be much cleaner to use and read in the business logic.
#103 Updated by Vadim Gindin over 9 years ago
The reference menu-item mi in menu m
would probably be converted to m.findMenuItem("mi")
. Is that what you mean? Do your proposal relates to menu-item mi in sub-menu sm
too?
#104 Updated by Vadim Gindin over 9 years ago
I.e. adding new method findMenuItem
to the MenuDefinition
class.
#105 Updated by Greg Shah over 9 years ago
I.e. adding new method findMenuItem to the MenuDefinition class.
Almost. I was thinking that m
is really an instance of MenuWidget
right, not a MenuDefinition
. Once the menu has been instantiated, the MenuDefinition
no longer represents the state of the widget. The definition is just for the setup. At runtime, all functionality should be in the widget classes themselves.
#106 Updated by Vadim Gindin over 9 years ago
- File vig_upd20141225a.zip added
- fixed and tested conversion of menu widgets references, based on "find*" methods.
- Parsing conflict temporary fix for the case when menu-item reference follows DEFINE MENU statement. An ambiguity is in fact that DEFINE MENU statements allows DOT in each line of menu_element. TODO fix.
- Added several annotations for references (
in_wid_menu
,in_wid_menu_id
,in_wid_menu
,in_wid_sub_menu_id
) and first met pathfirst-menu-path
. By the wayfirst-menu-path
is now emitted as one AST with dot separated text. For example for the pathm.sm
, wherem
- menu name andsm
- sub-menu name following ast node will be emitted:<ast col="0" id="755914244153" line="0" text="m.sm" type="REFERENCE"/>
This is probably incorrect. What do you think? - Added POPUP-ONLY attribute
- Added SHARED MENU conversion and corresponding methods to
MenuWidget
. Please, have a look. - fixed previous remarks.
- LIKE clauses
- triggers for menus (check if it works correctly)
- try
lvalue
for submenu_descriptor - fix ambiguity with dots in parser.
#107 Updated by Vadim Gindin over 9 years ago
- File several_dots_error.log added
- File one_allowed_dot_error.log added
Just for documenting purposes. The parser problem of ambiguity is in def_menu_stmt
rule from progress.g
:
def_menu_stmt returns [int mtype = -1] : { mtype = WID_MENU; } (KW_MENU! | KW_SUB_MENU! { mtype = WID_SUB_MENU; } ) m:symbol ( options { generateAmbigWarnings = false; } : ui_stuff | (KW_MENU_BAR | KW_SUB_M_H | simple_title_string) | (like_menu_clause | menu_element_descriptor) // TODO: are there other parts of menu_element_descriptor or // like_menu_clause etc... which can trigger this deviant // 4GL behavior? // | { LA(2) == KW_MENU_ITM }? // DOT )* { sym.addMenu(#m.getText(), mtype); } ;
In the current commit I commented out the lines:
// | { LA(2) == KW_MENU_ITM }? // DOT
In the current variant we will get parsing error for the following procedure:
define menu m menu-item mi label "mi lbl". menu-item mi1 label "mi1 lbl". menu-item mi:label in menu m = "New mi lbl".
Because DEFINE_MENU statement allows DOT for each element in it's description although of the fact that it differs from the common rule "One statement - one DOT". I don't know any other statement that also allows several DOTs. Going further, when parser meets
menu-item mi1 label "mi1 lbl".
it doesn't know that this is a part of DEFINE statement and throws an error (see one_allowed_dot_error.log)
If we uncomment back those 2 lines, I noted earlier, than we will get another error while trying to convert the same procedure (see several_dots_error.log). This error happens because when the parser meets menu-item mi:label in menu m = "New mi lbl".
it expects that it will be the next element in DEFINE_MENU elements list and when it meets :
it throws an error.
That is an ambiguity we need to process some way.
#108 Updated by Greg Shah over 9 years ago
I will respond with a code review later, but for now I am responding to your parser ambiguity issue.
In the current commit I commented out the lines:
I know that those lines are needed since as you have noticed, the 4GL has a quirk in how it processes DOT in menus. I don't know why, but we have actually seen this in customer code multiple times.
In fact, I just checked in a parser that extends this code to additional "lookahead" choices.
// TODO: we know that at least the MENU-ITEM and RULE parts of menu_element_descriptor // can trigger this quirk (we've added SUB-MENU and SKIP here to get ahead of // the game (hopefully that is not wrong), but are there other possible // following like_menu_clause etc... which can also be a trigger for this // deviant 4GL behavior? | { LA(2) == KW_MENU_ITM || LA(2) == KW_SUB_MENU || LA(2) == KW_RULE || LA(2) == KW_SKIP }? DOT
Please write testcases to check if KW_SUB_MENU
and KW_SKIP
also trigger this behavior. If they do, then we can remove the TODO. Let's get this area implemented properly.
If we uncomment back those 2 lines, I noted earlier, than we will get another error while trying to convert the same procedure (see several_dots_error.log). This error happens because when the parser meets menu-item mi:label in menu m = "New mi lbl". it expects that it will be the next element in DEFINE_MENU elements list and when it meets : it throws an error.
Interesting. Check if the 4GL responds differently based on whitespace. Is that extra blank line significant?
If we can't detect this based on whitespace, then the correct fix is to look at LT(3)
(only when LA(2)
is KW_MENU_ITM
or possibly KW_SUB_MENU
). If that token's text matches an existing menu-item (or possibly an existing sub-menu), then we would NOT allow a match on the DOT inside the loop.
#109 Updated by Vadim Gindin over 9 years ago
- copy all definitions classes (for menus or submenus) for all tree (sub-menus of all levels and root menu or submenu) and make neccessary renames. Only one rename is necessary: copied root menu/sub-menu file and it's class name.
- non trivial rules and tricky renames, but possible.
+ as a result we will have static definitions classes and we'll be able to use references to copied elements as usual, because we will have all static fields. - Do it dynamically
+ probalby simplier implementation in Java
- unclear how to process references to copied menu elements.
Could you advice me something?
#110 Updated by Vadim Gindin over 9 years ago
- This ambiguity also appears for SUB-MENU
- RULE and SKIP cannot be used as separate statement.
- Whitespace does not affect behavior.
I would propose the following rule:
| { (LA(2) == KW_MENU_ITM && LA(4) != COLON) || (LA(2) == KW_SUB_MENU && LA(4) != COLON) || LA(2) == KW_RULE || LA(2) == KW_SKIP }? DOT
What do you think?
#111 Updated by Greg Shah over 9 years ago
About LIKE clause. I didn't find conversion implementation of LIKE in other statements for example DEFINE VARIABLE, DEFINE FIELD or others. Is it implemented or my case is the first?
Yes, it is implemented.
The way it works is that at parse time (in progress.g
and SymbolResolver
) we rewrite the tree to copy/match the configuration of the target variable, temp-table or temp-table field.
Please see like_clause
in progress.g
and SymbolResolver.addLocalVariableLike()
to see the logic.
By doing this at parse time, we don't need different conversion rules downstream. That is why you haven't found any conversion rules for LIKE.
Talking about LIKE conversion. I see 2 variants:
- copy all definitions classes (for menus or submenus) for all tree (sub-menus of all levels and root menu or submenu) and make neccessary renames. Only one rename is necessary: copied root menu/sub-menu file and it's class name.
- non trivial rules and tricky renames, but possible.
+ as a result we will have static definitions classes and we'll be able to use references to copied elements as usual, because we will have all static fields.- Do it dynamically
+ probalby simplier implementation in Java
- unclear how to process references to copied menu elements.
Avoid all of this. Focus on getting the menu properly configured during parse time and then let it convert using the rules you already have.
#112 Updated by Greg Shah over 9 years ago
Vadim Gindin wrote:
About ambiguity with DOTs. I've made additional testing and found the following.
- This ambiguity also appears for SUB-MENU
- RULE and SKIP cannot be used as separate statement.
- Whitespace does not affect behavior.
I would propose the following rule:
[...]What do you think?
I don't like hard-coding this to COLON because it misses many other possible constructs. We can't put in special logic for each one.
Instead, why not do a lookup in the symbol resolver to see if the LT(3).getText()
is an already existing menu item or sub-menu? By doing that we know for sure that we don't have to "eat" the DOT.
#113 Updated by Greg Shah over 9 years ago
Code Review vig_upd20141225a.zip
This looks pretty good.
1. Does referencing convert/methods_attributes.rules
from menu_generator.xml
do something useful? In core_conversion.xml
, we have multiple <rule-set>
nodes nested inside another <rule-set>
node. In that mode, all the nested <rule-set>
nodes operate on the same tree in sequence, allowing them to cooperatively generate a single output tree that matches the structure and features of the input tree. I'm surprised that referencing this <rule-set>
in a non-nested way would have a positive affect.
2. MenuItemWidget.setSubType(character value)
should handle the case where the value
is unknown.
3. As far as I know, you don't need to extend the frame registry support for shared menus. Shared frames are much more complicated and have multiple instances that shared some but not all state. Menus are different. As we discussed earlier, there is only 1 instance that is really shared in many places. That is very different from frames. So: you don't need the LogicalTerminal
change and you don't need to call releaseSharedWidget()
. If you know about a reason that I am wrong, please let me know.
4. Please update the javadoc in SharedVariableManager
to note that GLOBAL
is not a valid option for shared menus. Mention that it will be silently converted to scoped support.
5. Your question:
Added several annotations for references (in_wid_menu, in_wid_menu_id, in_wid_menu, in_wid_sub_menu_id) and first met path first menu-path. By the way first-menu-path is now emitted as one AST with dot separated text. For example for the path m.sm, where m - menu name and sm - sub-menu name following ast node will be emitted:
<ast col="0" id="755914244153" line="0" text="m.sm" type="REFERENCE"/>
This is probably incorrect. What do you think?
You're right, it is not the best but sometimes it is just so much simpler that we take some "shortcuts". I think it is OK for now.
#114 Updated by Vadim Gindin over 9 years ago
Greg Shah wrote:
Vadim Gindin wrote:
About ambiguity with DOTs. I've made additional testing and found the following.
- This ambiguity also appears for SUB-MENU
- RULE and SKIP cannot be used as separate statement.
- Whitespace does not affect behavior.
I would propose the following rule:
[...]What do you think?
I don't like hard-coding this to COLON because it misses many other possible constructs. We can't put in special logic for each one.
Instead, why not do a lookup in the symbol resolver to see if the
LT(3).getText()
is an already existing menu item or sub-menu? By doing that we know for sure that we don't have to "eat" the DOT.
The difficulty here is the fact, that already existing menu-item or sub-menu
can be a part of DEFINE MENU/SUB-MENU statements. Therefore we can't use this criteria to distinguish menu-item/sub-menu references from using them in DEFINE statements.
#115 Updated by Greg Shah over 9 years ago
The difficulty here is the fact, that already existing menu-item or sub-menu can be a part of DEFINE MENU/SUB-MENU statements. Therefore we can't use this criteria to distinguish menu-item/sub-menu references from using them in DEFINE statements.
OK, then leave it with the COLON for now. Please put in a TODO comment to explain that the exclusion code needs to be improved from just using COLON.
#116 Updated by Vadim Gindin over 9 years ago
The question about SHARED menus implementation. How about MenuWidget.createStaticSharedMenu
? Is its implementation correct and do we need to use TransactionManager
that is commented out at this moment? If no - when to call mgr.untrackSharedConfig
? See details in commented block.
#117 Updated by Greg Shah over 9 years ago
Vadim Gindin wrote:
The question about SHARED menus implementation. How about
MenuWidget.createStaticSharedMenu
? Is its implementation correct and do we need to useTransactionManager
that is commented out at this moment? If no - when to callmgr.untrackSharedConfig
? See details in commented block.
I'm not sure if we need to implement this tracking for shared menus. The use cases for frames are much more complicated than for menus. For example, since it is a single shared instance, the original creation point for that instance probably determines the lifetime in the 4GL for the shared menu. With frames, we have multiple different instances that share the same widget ID and the original frame instance is somewhat "disconnected" from the other instances. I think there are use cases where the original shared frame instance can exit scope while the imported instances still exist. This is probably why we are doing this special tracking by widget ID. I suspect this may not be needed for menus. If I am right, then you can eliminate all of that code.
If I am wrong, then you WILL have to use the TransactionManager
code that is commented out in order to get the cleanup to occur when the containing external procedure exits.
Constantin: do you have any thoughts on this?
#118 Updated by Vadim Gindin over 9 years ago
Greg, I don't understand about LIKE. Lets look at simple statement define menu m like m1
. As a result, Do I need to have AST subtree for m1 identical AST subtree for m?
#119 Updated by Vadim Gindin over 9 years ago
I thought so until now, but I just didn't find the place where the copying is happen.
#120 Updated by Greg Shah over 9 years ago
Vadim Gindin wrote:
Greg, I don't understand about LIKE. Lets look at simple statement
define menu m like m1
. As a result, Do I need to have AST subtree for m1 identical AST subtree for m?
Mostly yes. You need to modify m
so that it would have the same nodes and annotations as if it was explicitly coded the same way that m1
is coded, except with a different name.
As I mentioned, we do this copying in the parser and SymbolResolver
so that the downstream processing won't care whether something was defined LIKE or explicitly defined. The resulting AST must be the same.
Please ask questions about the processing in the like_clause
in progress.g
and SymbolResolver.addLocalVariableLike()
which is not clear.
#121 Updated by Vadim Gindin over 9 years ago
Thank you for quick answer. I've seen this method earlier and decided to write separate method addMenuLike
for menus, that will be simpler. But this method copies only AST of DEFINE_MENU. Target copied AST doesn't contain any children from source AST. Does the copying happen in other place? Another variant, that at parsing moment the source subtree is also empty. What do you think?
#122 Updated by Greg Shah over 9 years ago
Vadim Gindin wrote:
Thank you for quick answer. I've seen this method earlier and decided to write separate method
addMenuLike
for menus, that will be simpler. But this method copies only AST of DEFINE_MENU. Target copied AST doesn't contain any children from source AST. Does the copying happen in other place? Another variant, that at parsing moment the source subtree is also empty. What do you think?
For define variable, we don't need to duplicate all the child nodes. Even for regular (non-LIKE usage) we convert those nodes to annotations and then hide the child nodes. So when we do a LIKE, we only need to copy annotations and we don't have to create duplicate child nodes.
For menus, you will probably need to duplicate the child nodes. We don't have an example today. I think you can probably use duplicateFresh()
and graft()
to make the copies.
#123 Updated by Vadim Gindin over 9 years ago
Now I understand. Thank you!
#124 Updated by Vadim Gindin over 9 years ago
My method is the following
public void addMenuLike(String name, Aast ast) { int ltype = ast.getType(); int type = ltype; String oldname = ast.getText(); type = lookupMenu(oldname); Variable var = new Variable(name, type, null); Aast fopts = null; // we must pattern the variable off another variable Variable like = (Variable) lookupWrapped(menuDict, oldname); fopts = like.getOptions(0); if (fopts != null) { System.out.println(fopts.dumpTree()); var.copyDefaultOptions(fopts); System.out.println(var.getOptions(0).dumpTree()); } if (menuDict.getSymbolAtScope(name, 0) == null) { addWrappedWorker(menuDict, false, name, (TokenDataWrapper) var); } }
The call copyDefaultOptions
copies full subtree as documented. I've compared printed output before and after the call. They are identical and contain children. But resulting *.p.ast contains unchanged subtree:
<ast col="0" id="214748364833" line="0" text="statement" type="STATEMENT"> <ast col="1" id="214748364834" line="7" text="define" type="DEFINE_MENU"> <annotation datatype="java.lang.String" key="name" value="m1"/> <annotation datatype="java.lang.Long" key="type" value="401"/> <annotation datatype="java.lang.Boolean" key="widdef" value="true"/> <annotation datatype="java.lang.String" key="javaname" value="m1"/> <ast col="13" id="214748364837" line="7" text="m1" type="SYMBOL"/> <ast col="16" id="214748364840" line="7" text="like" type="KW_LIKE"> <ast col="21" id="214748364842" line="7" text="m" type="SYMBOL"/> </ast> </ast> </ast>
Why it could be?
#125 Updated by Greg Shah over 9 years ago
The copyDefaultOptions()
only saves a reference (inside the Variable
instance) to the copied subtree. It does not graft the copied tree into the source tree. Please see Variable.setOptions()
and how that method uses overrideIfNotPresent()
.
#126 Updated by Vadim Gindin over 9 years ago
How to hide/remove unnecessary AST nodes? I need to replace DEFINE MENU m1 LIKE m
with DEFINE MENU m ....
. I've tried to call getParent
from DEFINE_MENU ast node but got null. I just wanted to get DEFINE_MENU ast parent, remove its child and graft copied subtree to it by call: parent.graft(..)
. It would be not very good to transfer DEFINE_MENU parent as an additional parameter. Isn't it?
#127 Updated by Greg Shah over 9 years ago
I don't really understand what you are doing. If getParent()
returns null
, then that subtree hasn't yet been grafted into a larger tree. That isn't possible for the normal AST subtrees created by the parser, since they are created already attached into the larger tree. Please provide some more detail to explain.
#128 Updated by Vadim Gindin over 9 years ago
I'm calling sym.addMenuLike(#m.getText(), like_name, ##);
in the end of def_menu_stmt
rule in progress.g
. Inside the addMenuLike
I'm trying to call ast.getParent()
where ast - is the node parameter, corresponding to ##
. It seems I'm all adrift.
#129 Updated by Greg Shah over 9 years ago
The parser will be connecting the ##
node to the rest of the tree AFTER the def_menu_stmt
is done processing. So anything you do before then can only work with the subtree that is being created.
You should not need to remove and re-graft it. Just add children and annotations to the ##
node to make it match the LIKE
subtree. The LIKE
subtree will already exist previously in the overall tree, so this should be fine. But you'll have to find that other tree in order to copy it. Look carefully at the Variable.overrideIfNotPresent()
to see how we only differentially copy things needing to be overridden. At least the define variable approach can have some partial definition where only some of the LIKE
sub-tree is copied.
#130 Updated by Constantin Asofiei over 9 years ago
Greg Shah wrote:
I'm not sure if we need to implement this tracking for shared menus. ... If I am right, then you can eliminate all of that code.
Greg, you are correct. The shared menus don't have the same complexity as the shared frames. A shared menu will always use the master definition, even if you specify different labels at the shared definition. So the track/untrackSharedConfig calls are not needed and can be removed - these APIs were added only because of the shared frame complexities.
#131 Updated by Vadim Gindin over 9 years ago
I'm trying to find out a solution for extra semicolon emission (see note #71). I still can't find a place where it is processed. It really happens for NUMERICAL literals. You wrote that it could happen because of extra AST node (probably hidden). Probably it is. Lets consider following example:
define menu m title "Menu_title" fgcolor 3.
For STRING attribute
title
there are the following subtree:<ast type="KW_TITLE"> <ast type="STRING"/> </ast>
For NUMERICAL attribute
fgcolor
there are the following subtree:<ast type="KW_FGCOLOR"> <ast type="EXPRESSION"> <ast type="NUM_LITERAL" /> </ast> </ast>
As you can see there are extra EXPRESSION ast node. Probably that is the reason. But I still can't find the target place. I looked into
expressions.rules
and literals.rules
without success.#132 Updated by Vadim Gindin over 9 years ago
I found some interesting place in expressions.rules
line 1234:
<!-- Bypass emission of the handle referenced into TABLE-HANDLE FOR and formatting of OLD/NEW VALUE in ASSIGN TRIGGERS --> <rule>relativePath("DEFINE_PARAMETER/KW_TAB_HAND/EXPRESSION") or relativePath("KW_ON/KW_OLD/KW_FORMAT/EXPRESSION") or ...
I added MENU paths from
literals.rules
("DEFINE_MENU/KW_FGCOLOR/EXPRESSION" instead of "DEFINE_MENU/KW_FGCOLOR/EXPRESSION/NUM_LITERAL") here in it became work. I did it blindly and I don't know if it is correct. Probably it will be more correct if I add separate rule for MENU paths. What do you think?#133 Updated by Greg Shah over 9 years ago
You'll have to upload the entire update for me to get a better sense of your approach. We should not have to put lots of exception rules in all over the place in order to get this to work.
If that whole KW_FGCOLOR subtree is hidden AFTER it is used in menu_generator.xml, it really should not be causing any problems and we should not need the downstream exceptions.
#134 Updated by Vadim Gindin over 9 years ago
- File vig_upd20150112a.zip added
- Fixed extra ';' for EXPRESSION/NUM_LITERAL. Check please is it correct. See
expressions.rules
. - Changed
submenu_descriptor
rule in aprogress.g
: addedlvalue
instead of custom logic. - Added LIKE processing.
- Added menu references processing in triggers and WAIT-FOR statement. The peculiarity in behavior is the simple form is also accessible:
wait-for choose of menu-item m
as well as common form likewait-for choose of menu-item m in sub-menu sm
. I've added extra static methods in widget classes likefindMenuItemStatic
orfindSubMenuStatic
. I'm not sure really if it is good. What do you think?
#135 Updated by Greg Shah over 9 years ago
Code Review vig_upd20150112a.zip
Generally, the changes are quite good. I see the following cleanup items. It seems pretty close to something we should put through testing.
0. Is there anything left to implement? I see a mention above about testing trigger support. Everything else seems like it may be complete.
1. In regard to the expressions.rules
change, I can accept the approach but you should create your own dedicated rule for menu element suppression. Right now you are sharing it with the TABLE_HANDLE
code. That is confusing and may lead to problems editing that code in the future. Please split your code into its own section and give it a useful comment.
2. Please do the same thing for the literals.rules
suppression. It should be in its own section with its own comment instead of mixing it into the triggers section. In fact, you are not suppressing the character literal at all, but it is a new suppression of integer literals, so the comment is especially confusing.
3. The methods_attributes.rules
is improperly merged. Some entries have been duplicated. Please bzr diff
it to see the problems.
4. Can the following be removed from the progress.g
TODO in def_menu_stmt
: "we know that at least the MENU-ITEM and RULE parts of menu_element_descriptor can trigger this quirk (we've added SUB-MENU and SKIP here to get ahead of the game (hopefully that is not wrong), but"? I think you have proven that both sub-menu and skip CAN be used there right? If so, then those parts of the TODO should not be there.
5. On line 10114 of progress.g
, I think we should drop the DOT
because it is really just trash. Unless you have a need for it, please change it like this: DOT!
which will drop the token from the tree after matching it.
6. In progress.g
, I like that you used lvalue
in submenu_descriptor
. That is a big improvement. Please remove the commented code AND remove the comment about being a "placeholder". The namespace processing is now there thanks to your changes, so it is no longer a placeholder.
7. In progress.g
the method #itm.getText()
is called 3 times in the menu_item_phrase
exit action. Please cache it in a local var (String txt = #itm.getText();
) and then reuse it. It is a minor optimization but there is no reason not to take it.
8. Making AnnotatedAst.putAnnotationImpl()
into a public
access method is not safe. The reason is that only certain data types are supported by the AST persister plugins. So we only allow very specific types through there.
9. You have a dead rule (about WAIT-FOR) at the bottom of menu_scoping.rules
.
#136 Updated by Vadim Gindin over 9 years ago
The only triggers references are left. What do you think about approach I used for that?
#137 Updated by Greg Shah over 9 years ago
I'm OK with what I saw in the code.
Please post some examples here (both the 4GL and then the converted Java for the triggers). Each trigger should have both a registerTrigger()
in the code and a TriggerBlock
inner class with the trigger code itself. Please paste the examples into
sections so it is easy to review.
#138 Updated by Vadim Gindin over 9 years ago
After I fixed some parsing problem I faced with the following difficulty during conversion of the following trigger:
on choose of menu-item mi in sub-menu sm message "mi in sm".
I got the following AST:
<ast col="14" id="309237645369" line="8" text="menu-item" type="KW_MENU_ITM"> <ast col="24" id="309237645372" line="8" text="mi" type="WID_MENU_ITM"/> <ast col="27" id="309237645375" line="8" text="in" type="KW_IN"> <ast col="30" id="309237645377" line="8" text="sub-menu" type="KW_SUB_MENU"> <ast col="39" id="309237645380" line="8" text="sm" type="WID_SUB_MENU"> <annotation datatype="java.lang.String" key="first-menu-path" value="m"/> </ast> </ast> </ast> </ast>
This AST corresponds to menu-item reference:
menu-item mi in sub-menu sm
and it differs from AST generated for the same menu-item reference in other context. For example for the statement menu-item mi:label in sub-menu sm = "1111".
I will get the following AST:<ast col="1" id="317827580082" line="26" text="menu-item" type="KW_MENU_ITM"> <ast col="11" id="317827580085" line="26" text="mi" type="WID_MENU_ITM"> <annotation datatype="java.lang.String" key="in_wid_sub_menu" value="sm"/> <annotation datatype="java.lang.Long" key="in_wid_sub_menu_id" value="317827580094"/> </ast> </ast> <ast col="14" id="317827580087" line="26" text="label" type="ATTR_CHAR"> <annotation datatype="java.lang.Long" key="oldtype" value="654"/> </ast> <ast col="20" id="317827580089" line="26" text="in" type="KW_IN"> <ast col="23" id="317827580091" line="26" text="sub-menu" type="KW_SUB_MENU"> <ast col="32" id="317827580094" line="26" text="sm" type="WID_SUB_MENU"> <annotation datatype="java.lang.String" key="first-menu-path" value="m2"/> </ast> </ast> </ast>
The difference in these ASTs is in a place of KW_IN AST node: for trigger KW_IN is a child of KW_MENU_ITEM and for the assignment KW_IN is a neighbor of KW_MENU_ITEM.
The question.
Should I fix generated AST for these 2 cases to unified view or I should process both views of ASTs to add my annotations correctly?
#139 Updated by Vadim Gindin over 9 years ago
I suppose I should make the common AST subtree for both cases. How can I make it and where? May be it is also a parser bug?
#140 Updated by Greg Shah over 9 years ago
It is a good question. We already have quite a bit of logic that handles these cases differently. Right now they cannot be unified. Please just put extra logic in to handle the annotations for both cases.
So: NO, do not try to make these into the same AST structure.
#141 Updated by Vadim Gindin over 9 years ago
- File vig_upd20150113a.zip added
- Fixed remarks.
- Fixed
lvalue
rule in progress.g (added KW_SUB_MENU as possible widget qualifier). - Added processing of additional variant of AST for menu references.
#142 Updated by Vadim Gindin over 9 years ago
- File Triggers.java added
- File MenuDefinitionM.java added
- File triggers.p added
Here are the source and generated files for menu references in triggers as you asked earlier.
#143 Updated by Greg Shah over 9 years ago
I think the triggers code looks fine. Is there anything else to do for the conversion?
#144 Updated by Greg Shah over 9 years ago
Code Review vig_upd20150113a.zip
The only problem I see is that you still have a duplicate section for kw_full_h_c
in methods_attributes.rules
.
Otherwise it seems ready to test.
#145 Updated by Vadim Gindin over 9 years ago
- File vig_upd20150114a.zip added
method_attributes.rules
and changed text
with names.convert(text, names.variable)
corresponding to Constantin's remark 4 in the note #92. Only 3 files were changed:
- rules/convert/methods_attributes.rules
- rules/convert/widget_references.rules
- rules/annotations/menu_scoping.rules
Please, recall me, should I change a year of a Copyright block in each modified file to 2015?
#146 Updated by Constantin Asofiei over 9 years ago
Vadim Gindin wrote:
Please, recall me, should I change a year of a Copyright block in each modified file to 2015?
Yes, you need to update the copyright date, to from e.g. 2012-2014
to 2012-2015
, or from e.g. 2013
to 2013-2015
.
#147 Updated by Vadim Gindin over 9 years ago
- File vig_upd20150114b.zip added
Thank you. Here is the current update with these changes.
#148 Updated by Vadim Gindin over 9 years ago
- File vig_upd20150114c.zip added
I missed several files.
#149 Updated by Greg Shah over 9 years ago
Code Review vig_upd20150114c.zip
This is really good. Please put it into both conversion and runtime regression testing.
The one minor change I would still like to see, is for name conversion to occur in only 1 place (probably during menu_generation.rules@. Then that name should be saved in the original definition node as an annotation and when references are emitted "downstream" for a reference in places like widget_references.rules
, then those places should lookup the converted name from the original definition node and use that. This allows us to always share the same name (which may be important if we have to disambiguate the name for some reason or if in the future we add hints to allow name customization). It also makes the downstream code less duplicative and less error prone, since we don't have to remember to re-convert the name everywhere.
DON'T make this change before putting the code into testing. Make this change with your next work which is about getting the runtime working for ChUI.
#150 Updated by Vadim Gindin over 9 years ago
I've ran conv-regression task. It executed, but failed at the end. Here is the end of the log:
... jar: [jar] Building jar: /home/vig/testing/majic/build/lib/majic.jar [jar] Building jar: /home/vig/testing/majic/build/lib/majic_ui.jar convert-all: save-generated: prepare: [copy] Copying 119 files to /home/vig/testing/majic/src [input] Save the generated sources (y/n)? (y, n) [exec] ** Adding the generated sources to 'generated/20150114b/generated_source_backup_20150114b_10707.zip'... [exec] ** Adding the MAJIC/P2J updates to 'generated/20150114b/generated_source_backup_20150114b_10707.zip'... [exec] ** Sources saved to 'generated/20150114b'. conversion-test: [input] Enter the stable folder name (without 'generated/' prefix): [input] Enter the candidate folder name (without 'generated/' prefix): [exec] The folder 'generated/some_folder' do not exist! [exec] Result: 2 BUILD FAILED /opt/secure/clients/timco/testing/build_rt.xml:369: Non-source compare error encountered.
The script asked me to specify stable and candidate folders. I've specified new names ("some_folder, candidate_folder"). But it was expecting the names of existing folders. I don't know what names I had to specify there. Could you help me?
#151 Updated by Greg Shah over 9 years ago
As noted in the timco.html
:
Build and Save a Comparison Version
Before running any conversion regression test, you will need the save off a comparison version of the converted MAJIC project. It is important to have the latest version of the P2J trunk built at the time you run this, so that your saved comparison version will be comparable to a version converted using any changes to P2J that are added later.
To convert MAJIC for the first time (and save off this build as the comparison version):
run_regression.sh build save-generated -Dsave.candidate=y
Multiple targets are passed to ant in the above command.
The conversion and compilation of the result will take a bit less than 1 hour for the MAJIC project. This will run using whatever version of MAJIC and P2J is already there.
The saved off version will be stored in ~/testing/generated/
under a directory that is named with a sortable date (the date it was saved) plus an alphabetic character to index the builds done in that day, so the first saved build of the day will be ~/testing/generated/YYYYMMDDa/
and the second saved build will be ~/testing/generated/YYYYMMDDb
.
#152 Updated by Vadim Gindin over 9 years ago
- File diff_20150114a_src.txt added
Thank you. These folders are different. diff*_ddl.txt is empty, but diff_*_src.txt is not empty. I'm trying to interpret it. By the way I wrote simple script to make an update file from bzr status output:
#!/bin/bash _NOW=$(date +%Y%m%d) _UPDATE="~/work/${USER}_upd${_NOW}a.zip" while read line do if [ $line != 'modified:' ] && [ $line != '.bzrignore' ] && [ $line != 'unknown:' ]; then zip -R ~/work/${USER}_upd${_NOW}a.zip $line fi done < "${1:-/proc/${$}/fd/0}" echo "Update ${_UPDATE} is created"
To run it we shoud use the command bzr status | ./mkupd.sh
, where mkupd.sh
is that script, placed in /p2j
folder. It is needed that all files, that are not intended to be committed, must be added to .bzrignore
and so not be displayed in bzr status
output.
Can It be useful for somebody?
#153 Updated by Vadim Gindin over 9 years ago
I was using an eclipse plugin to merge files last time and didn't accustom to this plugin probably. The reason of the error was in improperly merged frame_generator.xml
. I'm going to run conv-regression
again.
#154 Updated by Greg Shah over 9 years ago
Can It be useful for somebody?
Very cool! I like it.
The only thing we need to do here is to eliminate the dependency on ~/work/
as most systems won't have that path.
#155 Updated by Vadim Gindin over 9 years ago
- File vig_upd20150114d.zip added
The current update has passed conversion and regression testing. Can I commit it?
#156 Updated by Greg Shah over 9 years ago
Yes, please do check in vig_upd20150114d.zip and distribute it.
#157 Updated by Vadim Gindin over 9 years ago
vig_upd20150114d.zip
is committed to bzr with rev №10709
#158 Updated by Vadim Gindin over 9 years ago
Should I commit (without work
folder as you wrote) the script from the note #152? If yes - can I commit it right to p2j
folder?
#159 Updated by Greg Shah over 9 years ago
No, that is not something that is specific to the p2j project. It is a tool that we would add to the standard workstation setup.
Clean it up and then send it out to the team in an email. I'll include it into the zip files for the standard workstation.
#160 Updated by Vadim Gindin over 9 years ago
I trying to decide how to transfer information about main menu (menubar=true) to the client. ScreenBuffer
is not really useful because it linked to a frame and we don't know what frame is the main (common). Should I create some separate class for that or ScreenBuffer
is preferable?
Also I'm a bit confused about drawing implementation. Should I use screen().append(..) string-like methods to draw a menu as it work in ButtonImpl
for example?
#161 Updated by Greg Shah over 9 years ago
ScreenBuffer is not really useful because it linked to a frame and we don't know what frame is the main (common). Should I create some separate class for that or ScreenBuffer is preferable?
ScreenBuffer
is for editing data in widgets that are contained in frames. Menus are outside of any given frame and have no editing widgets, although I guess there may be a little state for things like toggle box menu items. The ScreenBuffer
should not be used.
The majority of the functionality can be pushed from the server to the client as a configuration. You do need to create a similar function to pushFrameDefinition()
. I expect pushMenuDefinition()
will be a good choice. Then anytime the configuration of the menus change, make the config class edits and then just call pushMenuDefinition()
again. It should replace the config on the client with the newer config.
Make a list of the state that can be changed on the client-side and describe it here. We will come up with an approach to transfer that back to the server.
Also I'm a bit confused about drawing implementation. Should I use screen().append(..) string-like methods to draw a menu as it work in ButtonImpl for example?
Generally, yes. However, you will need to implement the top-level menu class as a kind of container. It won't be as complicated as a frame.
Constantin: thoughts?
#162 Updated by Constantin Asofiei over 9 years ago
Constantin: thoughts?
- I suspect that showing the sub-menu (when a menu is activated in the menubar) will need to bring the menubar and the activated sub-menu on top in the window (by changing its z-order). The menubar needs to act as a container to keep the menus (their labels). The sub-menu's body (containing the menu-items) I think can be parented at the menubar, too; it's just a matter of making the appropriate sub-menus visible.
- when drawing, yes, you need to use
screen().append(..)
to draw text andscreen().at(...)
to position the cursor to the appropriate location. Note that in ChUI, the coordinates received byscreen().at(...)
are all relative to the screen - so usescreenLocation
to determine the widget's origin (relative to screen). Check theChuiOutputManager
for other ChUI-specific drawing APIs (like box and vert/horiz line drawing).
#163 Updated by Vadim Gindin over 9 years ago
- File vig_upd20150117a.zip added
Here is the next update. I used ScreenDefinition
(not ScreenBuffer
). Please confirm, that I'm on right way.
#164 Updated by Greg Shah over 9 years ago
Code Review vig_upd20150117a.zip
As a general approach, I'm not entirely convinced it is the best idea to add menu to ScreenDefinition
. However, for now I think you should continue working the solution in that way. Please do not "force fit" the menus into the ScreenDefinition
, which is a class that is very specific to frames today. It may be better to create a new mechanism for sending menus to the client. If you find yourself making the code do "unnatural things", then it is time to design something menu-specific.
In addition, make sure there is a need for a menu-specific registry in LogicalTerminal
. What will it be used for? And if you do need a menu registry, then you must also de-register menus from it.
#165 Updated by Vadim Gindin about 9 years ago
- File server.log added
- File client.log added
I need some advice. I got an error, that happen right in the moment of client call. I've filled ScreenDefinition
with some info on the server-side and trying to execute the command: locate().client.pushScreenDefinition(screenDef);
in the LogicalTerminal.pushScreenDefInt
. ThinClient
do not receive the call and ended with the error (see attached logs). I got SilentUnwindException in client log and nothing in server log. Could you help me?
#166 Updated by Greg Shah about 9 years ago
In the future, when posting something that isn't large, please post it in-line here. Don't attach a file for such things because it makes it harder to review.
com.goldencode.p2j.net.SilentUnwindException: Connection ended abnormally at com.goldencode.p2j.net.Queue.transactImpl(Queue.java:1142) 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:1424) 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:276) at com.goldencode.p2j.main.ClientCore.start(ClientCore.java:99) at com.goldencode.p2j.main.ClientDriver.start(ClientDriver.java:201) at com.goldencode.p2j.main.CommonDriver.process(CommonDriver.java:398) at com.goldencode.p2j.main.ClientDriver.process(ClientDriver.java:1) at com.goldencode.p2j.main.ClientDriver.main(ClientDriver.java:267) Caused by: com.goldencode.p2j.net.ApplicationRequestedStop: Queue stop is requested by application at com.goldencode.p2j.net.Conversation.block(Conversation.java:304) at com.goldencode.p2j.net.Conversation.waitMessage(Conversation.java:257) at com.goldencode.p2j.net.Queue.transactImpl(Queue.java:1128) ... 12 more
and the server log:
[01/23/2015 20:07:23 YEKT] (SecurityManager:FINE) {main} Loaded auth-mode 4, retries 0 [01/23/2015 20:07:23 YEKT] (SecurityManager:FINE) {main} Loaded auth hook as <com.goldencode.p2j.security.GuestAccess> [01/23/2015 20:07:23 YEKT] (SecurityManager:FINE) {main} Loaded anonymous ID <null> [01/23/2015 20:07:23 YEKT] (SecurityManager:INFO) {main} Loaded auth-mode object [01/23/2015 20:07:23 YEKT] (SecurityManager:FINE) {main} Loaded group <everybody> [01/23/2015 20:07:23 YEKT] (SecurityManager:FINE) {main} Loaded group <admins> [01/23/2015 20:07:23 YEKT] (SecurityManager:INFO) {main} Loaded 2 groups, 0 objects ignored [01/23/2015 20:07:23 YEKT] (SecurityManager:FINE) {main} Loaded process <standard> [01/23/2015 20:07:23 YEKT] (SecurityManager:INFO) {main} Loaded 1 processes, 0 objects ignored [01/23/2015 20:07:23 YEKT] (SecurityManager:FINE) {main} Loaded user <bogus> [01/23/2015 20:07:23 YEKT] (SecurityManager:FINE) {main} Loaded user <admin> [01/23/2015 20:07:23 YEKT] (SecurityManager:INFO) {main} Loaded 2 users, 0 objects ignored [01/23/2015 20:07:23 YEKT] (SecurityManager:FINE) {main} No holidays defined in the P2J directory. [01/23/2015 20:07:23 YEKT] (SecurityManager:FINE) {main} Loaded resource plugin for <system> as 0 [01/23/2015 20:07:23 YEKT] (SecurityManager:INFO) {main} Loaded 1 resource plugins, 0 failed [01/23/2015 20:07:23 YEKT] (SecurityManager:WARNING) {main} No custom server extension defined in P2J directory [01/23/2015 20:07:23 YEKT] (SecurityManager:WARNING) {main} No custom client extension defined in P2J directory [01/23/2015 20:07:23 YEKT] (SecurityManager:FINE) {main} ACLs for resource type <system>: [01/23/2015 20:07:23 YEKT] (SecurityManager:FINER) {main} origin /security/acl/system/000100 [01/23/2015 20:07:23 YEKT] (SecurityManager:FINE) {main} instance name <admin> (exact) [01/23/2015 20:07:23 YEKT] (SecurityManager:FINE) {main} rights {true} [01/23/2015 20:07:23 YEKT] (SecurityManager:FINE) {main} subjects admins [01/23/2015 20:07:23 YEKT] (SecurityManager:FINER) {main} origin /security/acl/system/000200 [01/23/2015 20:07:23 YEKT] (SecurityManager:FINE) {main} instance name <change> (exact) [01/23/2015 20:07:23 YEKT] (SecurityManager:FINE) {main} rights {true} [01/23/2015 20:07:23 YEKT] (SecurityManager:FINE) {main} subjects admins [01/23/2015 20:07:23 YEKT] (SecurityManager:FINER) {main} origin /security/acl/system/000300 [01/23/2015 20:07:23 YEKT] (SecurityManager:FINE) {main} instance name <logon> (exact) [01/23/2015 20:07:23 YEKT] (SecurityManager:FINE) {main} rights {true} [01/23/2015 20:07:23 YEKT] (SecurityManager:FINE) {main} subjects *all_others* [01/23/2015 20:07:23 YEKT] (SecurityManager:FINER) {main} origin /security/acl/system/000400 [01/23/2015 20:07:23 YEKT] (SecurityManager:FINE) {main} instance name <shutdown> (exact) [01/23/2015 20:07:23 YEKT] (SecurityManager:FINE) {main} rights {true} [01/23/2015 20:07:23 YEKT] (SecurityManager:FINE) {main} subjects *all_others* [01/23/2015 20:07:23 YEKT] (SecurityManager:INFO) {main} Loaded 4 ACLs for resource type <system> [01/23/2015 20:07:23 YEKT] (SecurityManager:WARNING) {main} Security audit log is disabled [01/23/2015 20:07:23 YEKT] (SecurityManager:INFO) {00000000:00000001:standard} No exported entry points defined in the P2J directory [01/23/2015 20:07:23 YEKT] (com.goldencode.p2j.main.StandardServer:WARNING) Unable to initialize runtime conversion pool; if dynamic database features are not in use, this warning can be ignored safely (otherwise restart server with FINE logging for additional information) [01/23/2015 20:07:23 YEKT] (Scheduler:WARNING) {00000000:00000004:standard} No scheduler configured. [01/23/2015 20:07:23 YEKT] (com.goldencode.p2j.persist.DatabaseManager:WARNING) No databases are configured [01/23/2015 20:07:23 YEKT] (SessionManager.listen():WARNING) {00000000:00000001:standard} INSECURE sockets in use! [01/23/2015 20:07:23 YEKT] (SessionManager.listen():INFO) {00000000:00000001:standard} Server ready [01/23/2015 20:07:30 YEKT] (SecurityManager:FINER) {00000000:00000005:standard} Insecure socket connection. [01/23/2015 20:07:30 YEKT] (SecurityManager:FINER) {00000000:00000005:standard} Getting AUTHTYPE [01/23/2015 20:07:30 YEKT] (SecurityManager:FINER) {00000000:00000005:standard} Got AUTHTYPE: 0 userName: null [01/23/2015 20:07:30 YEKT] (SecurityManager:FINE) {00000000:00000005:standard} hook class is com.goldencode.p2j.security.GuestAccess [01/23/2015 20:07:30 YEKT] (SecurityManager:FINER) {00000000:00000005:standard} Sending AUTHMODEREQ: 4 (action = 1) [01/23/2015 20:07:30 YEKT] (SecurityManager:FINER) {00000000:00000005:standard} Sent AUTHMODEREQ [01/23/2015 20:07:30 YEKT] (SecurityManager:FINER) {00000000:00000005:standard} Sending AUTHCUSTOM [01/23/2015 20:07:30 YEKT] (SecurityManager:FINER) {00000000:00000005:standard} Sent AUTHCUSTOM [01/23/2015 20:07:30 YEKT] (SecurityManager:FINER) {00000000:00000005:standard} Getting AUTHDATA [01/23/2015 20:07:30 YEKT] (SecurityManager:FINER) {00000000:00000005:standard} Getting AUTHDATA authSize=9 [01/23/2015 20:07:30 YEKT] (SecurityManager:FINER) {00000000:00000005:standard} Got AUTHDATA [01/23/2015 20:07:30 YEKT] (SecurityManager:FINER) {00000000:00000005:standard} Received user ID <bogus> [01/23/2015 20:07:30 YEKT] (SecurityManager:FINER) {00000001:00000005:bogus} Search open: resId 0, instance logon, mode 0, handle 1 [01/23/2015 20:07:30 YEKT] (SecurityManager:FINER) {00000001:00000005:bogus} Search next: handle 1, rights {true} [01/23/2015 20:07:30 YEKT] (SecurityManager:FINER) {00000001:00000005:bogus} Search done: handle 1, decision true, cache false [01/23/2015 20:07:30 YEKT] (SecurityManager:FINER) {00000000:00000005:standard} Sending AUTHRESULT0 (action = 0) [01/23/2015 20:07:30 YEKT] (SecurityManager:FINER) {00000000:00000005:standard} Sent AUTHRESULT [01/23/2015 20:07:30 YEKT] (SecurityManager:FINER) {00000000:00000005:standard} Sending LOCALUSERID: bogus [01/23/2015 20:12:34 YEKT] (SecurityManager:FINER) {00000000:00000009:standard} Insecure socket connection. [01/23/2015 20:12:34 YEKT] (SecurityManager:FINER) {00000000:00000009:standard} Getting AUTHTYPE [01/23/2015 20:12:34 YEKT] (SecurityManager:FINER) {00000000:00000009:standard} Got AUTHTYPE: 0 userName: null [01/23/2015 20:12:34 YEKT] (SecurityManager:FINE) {00000000:00000009:standard} hook class is com.goldencode.p2j.security.GuestAccess [01/23/2015 20:12:34 YEKT] (SecurityManager:FINER) {00000000:00000009:standard} Sending AUTHMODEREQ: 4 (action = 1) [01/23/2015 20:12:34 YEKT] (SecurityManager:FINER) {00000000:00000009:standard} Sent AUTHMODEREQ [01/23/2015 20:12:34 YEKT] (SecurityManager:FINER) {00000000:00000009:standard} Sending AUTHCUSTOM [01/23/2015 20:12:34 YEKT] (SecurityManager:FINER) {00000000:00000009:standard} Sent AUTHCUSTOM [01/23/2015 20:12:34 YEKT] (SecurityManager:FINER) {00000000:00000009:standard} Getting AUTHDATA [01/23/2015 20:12:34 YEKT] (SecurityManager:FINER) {00000000:00000009:standard} Getting AUTHDATA authSize=9 [01/23/2015 20:12:34 YEKT] (SecurityManager:FINER) {00000000:00000009:standard} Got AUTHDATA [01/23/2015 20:12:34 YEKT] (SecurityManager:FINER) {00000000:00000009:standard} Received user ID <bogus> [01/23/2015 20:12:34 YEKT] (SecurityManager:FINER) {00000002:00000009:bogus} Search open: resId 0, instance logon, mode 0, handle 2 [01/23/2015 20:12:34 YEKT] (SecurityManager:FINER) {00000002:00000009:bogus} Search next: handle 2, rights {true} [01/23/2015 20:12:34 YEKT] (SecurityManager:FINER) {00000002:00000009:bogus} Search done: handle 2, decision true, cache false [01/23/2015 20:12:34 YEKT] (SecurityManager:FINER) {00000000:00000009:standard} Sending AUTHRESULT0 (action = 0) [01/23/2015 20:12:34 YEKT] (SecurityManager:FINER) {00000000:00000009:standard} Sent AUTHRESULT [01/23/2015 20:12:34 YEKT] (SecurityManager:FINER) {00000000:00000009:standard} Sending LOCALUSERID: bogus
#167 Updated by Greg Shah about 9 years ago
I can't tell anything useful from the logs. You'll have to set breakpoints in the SilentUnwindException
constructor to see where the problem occurs. It should be on the server side I guess, because I don't think we use SilentUnwindException
on the client.
#168 Updated by Vadim Gindin about 9 years ago
I did it and nevertheless the constructor of SilentUnwindException
is called from client-side with the error com.goldencode.p2j.net.ApplicationRequestedStop: Queue stop is requested by application
#169 Updated by Greg Shah about 9 years ago
Hopefully you are continuing to debug. I have no idea what is causing the problem.
#170 Updated by Vadim Gindin about 9 years ago
- File vig_upd20150124a.zip added
I've fixed this bug. It was some sort of serialization bug. I also fixed a drawing of menu-item labels for menubar. Have a look please.
#171 Updated by Vadim Gindin about 9 years ago
- File vig_upd20150128a.zip added
1) I've prepared the next update with separate menu description class. Does it preferable than previous updates with modified ScreenDefinition
?
2) ScreenDefinition
is stayed unchanged in this update. But I'll need to change it anyway, because I need to process POPUP-MENUs attached to some widget (for example to BUTTON). I'm going to include menu widgets configs to ScreenDefinition
as it work for usual widgets. I'm not sure if it is right. What do you think?
#172 Updated by Greg Shah about 9 years ago
Code Review vig_upd20150128a.zip
Overall, this is MUCH better than the previous approach. Well done.
1. Menus need to be deregistered from the LogicalTerminal
registry.
2. I don't understand the need for MenuElementConfig
interface. These values are already directly available in the parent class hierarchy, without any need for getters/setters. In fact, we are trying to eliminate all getters/setters from our config hierarchy. What is the functional reason to add more for menus?
3. You should not leave an empty JPRM column in the file header for files that never had any JPRM numbers (e.g. all new or recent files like MenuItemWidget
, SubMenuWidget
, MenuWidget
).
4. The copyright date for MenuConfig
and WidgetConfigDef
should be 2014-2015
since both files had development work done in both years.
5. There are places were you are using explicit imports which should be converted to wildcard imports (see MenuConfig
, Menu
, MenuChuiImpl
, MenuItemChuiImpl
, MenuWidget
).
6. ThinClient
, ClientExports
are each missing a history entry.
#173 Updated by Greg Shah about 9 years ago
I'd like to see this next set of functionality stabilized and put into testing. What is left to do?
#174 Updated by Vadim Gindin about 9 years ago
I'm working on showing POPUP-MENU for widgets. I'd like to add this too.
About MenuElementConfig
. There is some confusion for me with parentId
property (different fields for different classes somehow). I'll try to handle with this property and get rid of that interface.
#175 Updated by Vadim Gindin about 9 years ago
I need an advice. Assume we have a button with popup-menu assigned. We must press ESC-U for CHUI or F4 for WINDOWS to call this menu when the button has focus. After hot-key is pressed the client-side must display this menu. Does it mean, that I should push menu description to the client-side right in that moment (during processing of a hot-key)? Another variant is to push menu description along with pushing a frame, containing our button. What way is better? I think the first one.
You asked earlier about state list that can be changed from the client side. I also thought earlier that this is the only TOGGLE-BOX property of menu items. But what about VISIBLE property? In described case this property got new value. It also make sense for showing sub-menus in a menu of any type: MENUBAR or POPUP. I don't see other state at this moment.
#176 Updated by Vadim Gindin about 9 years ago
I also want to add, that I faced with conversion bug for frames during conversion of chui_menu_2_purpose.p
. Extra frames were generated and FrameDefinition
was generated incorrectly: expr
(and also extra expressions) were generated instead of buttons. I've simplified the testcase and the bug is gone. I'll have to return to this bug later.
#177 Updated by Greg Shah about 9 years ago
Assume we have a button with popup-menu assigned. We must press ESC-U for CHUI or F4 for WINDOWS to call this menu when the button has focus. After hot-key is pressed the client-side must display this menu.
Can you create a trigger on this event and use no-apply? Something like this:
ON ESC-U OF my-menu DO: RETURN NO-APPLY. END.
If so, does it cancel the menu popup before it is ever displayed?
In all likelihood, the default popup behavior can be driven on the client side without any trip to the server as part of default processing for the frame or widget that has a popup menu associated. The only question is where in the client side processing to add such support? It may have ot be after the triggers are executed OR it could be that triggers don't work in this case.
Regardless, I think the popup menu definition should already be pushed whenever it is defined in the business logic, just like a frame. Any changes to the menus would naturally cause a push again. At the time editing is occurring, the menu should already be there.
Does it mean, that I should push menu description to the client-side right in that moment (during processing of a hot-key)?
I don't think so. At that moment we are on the client side already and we should not need to "up-call" to the server to get a menu def.
Another variant is to push menu description along with pushing a frame, containing our button.
I would prefer if the push of menus stays separate. You already have the menu creation pushing the defs down to the client. Keep the same approach for popup menus.
But what about VISIBLE property? In described case this property got new value. It also make sense for showing sub-menus in a menu of any type: MENUBAR or POPUP.
Are you saying that the client can implicitly change the value of this attribute which can can be seen in the business logic by 4GL code? If so, then this state will have to be sync'd. Though I think we already do that for other widgets today, so why would menus be any different?
I've simplified the testcase and the bug is gone. I'll have to return to this bug later.
OK.
#178 Updated by Vadim Gindin about 9 years ago
Greg Shah wrote:
Can you create a trigger on this event and use no-apply? Something like this:
[...]
If so, does it cancel the menu popup before it is ever displayed?
I've added this trigger and it really cancels menu appearing. The only moment that the trigger was added for the button, not for the menu.
#179 Updated by Greg Shah about 9 years ago
OK. Keep this in mind when you are working on getting the event processing to work properly.
#180 Updated by Vadim Gindin about 9 years ago
- File vig_upd20150130a.zip added
- The first working (in testing mode) variant with popup-menu.
- Fixed javadoc remarks.
- I got rid of
MenuElementConfig
- I commented out
LogicalTerminal.menuRegistry
at this moment. But I'm intuitively think that it will be needed later. So when it will be clear I'll addderegister
methods. - I added DEFAULT-POP-UP processing right to
ThinClient
as it works for some other events like BELL.
- It draws menu-item title only when I press F4. After that it draws menu-item. If I press F4 again - it closes itself.
- Coordinates, got from owner widget config
BaseConfig
is not filled. Fieldsx, y, row, column
have garbage values. I used testing data.
I recall that client-side works only in testing mode.
Please have a look.
#181 Updated by Greg Shah about 9 years ago
Code Review vig_upd20150130a.zip
I think it is moving in the right direction.
1. I think your drawing issues are related to how you are directly calling menu.draw()
in ThinClient
. I wish I could find Constantin's email or redmine post about this topic.
Constantin: do you remember where that is posted?
2. Imports in MenuItemConfig
have expanded from wildcards.
3. In MenuWidget
, the LegacyAttribute
annotation should not be there. Those annotations should be placed in the interface, not the implementation.
4. In methods_attributes.rules
, please use the new load_descriptors
approach for defining new attributes.
#182 Updated by Vadim Gindin about 9 years ago
- I've added POPUP-ONLY to
load_descriptiors
function along with other menu related attributes, createdMenuInterface
and used it there, added this interface toHandleCommon
, but still gotmbar.getSelf().readOnlyError("popup-only");
. - I didn't find probably Constantin's email or redmine post about drawing. I tried to enclose menu.draw() call with
eventDrawingBracket
but the error still happen.
#183 Updated by Greg Shah about 9 years ago
but still got mbar.getSelf().readOnlyError("popup-only");.
You have to add the attribute into the writable attributes list in common-progress.rules
.
I can't find Constantin's note/post either which is why I asked him for the location. He is working on some bugs this morning, I'm sure he'll get to this at some point. In the meantime, consider that the menu visibility should be toggled based on certain events and then a repaint cycle should be triggered, instead of directly calling draw().
#184 Updated by Constantin Asofiei about 9 years ago
Greg Shah wrote:
The main issues related to drawing are these:1. I think your drawing issues are related to how you are directly calling
menu.draw()
inThinClient
. I wish I could find Constantin's email or redmine post about this topic.Constantin: do you remember where that is posted?
- in ChUI, all drawing is relative to the screen's top-left corner (0, 0) - so all cursor positioning, etc, needs to be done in non-relative units. in GUI, this is different, we have locations relative to the parent; see note 647 in #2252 for more about this
- drawing is done directly (by invoking the
draw
API) only in special circumstances. In normal cases, you need to raise a repaint event and let the drawing infrastructure do its work. This sometime means to raise the repaint in aTC.eventDrawingBracket
. But your code inTC.processProgressEvent
doesn't look like it's in the right place:if (action == Keyboard.KA_DEFAULT_POP_UP && (tr == null || !tr.executed) && src != null) { int menuId = src.config().popupMenuId; if (menuId != -1) { Widget<?> menu = tk.getRegistry().getComponent(menuId); if (menu != null) { menu.draw(); } } }
a. I think it should be in either the source's or the menu'sprocessEvent
implementation.
b. you need to callmenu.repaint()
to raise the repaint event, notmenu.draw()
.
Try calling menu.repaint()
first and see if this fixes your drawing problem. If so, check if it can be moved to processEvent
#185 Updated by Vadim Gindin about 9 years ago
I did as you advised. I used menu.setVisible(true)
that calls repaint()
method, that in turn call EventManager.postEvent(new PaintEvent(this, ur));
. But draw
wasn't called at all. By the way. I don't know how to initialize coordinates for new widgets. Is it normal if coordinates have uninitialized values (Integer.MIN_VALUE) at the moment of posting event?
I'm debugging further..
I've also added a flag displayed
, that will mean dropped down
for popup menu or sub-menu. This flag is also a state, that can be changed on the client-side. But I'm not sure if it needed on the server-side.
#186 Updated by Vadim Gindin about 9 years ago
- File vig_upd20150201a.zip added
I didn't find a way to get it work with posting PaintEvent
. But I've fixed the bug adding menu.requestSync()
call.
I've found that in several places such as viewWorker
and ENABLE/DISABLE
processing there are already exist straight calls of draw()
from frame widgets. Another one problem is in the fact that menu is not associated with frame. At the same time any founded event processing is frame-related.
Another one difference is the following: frame drawing (and its widgets) is initiated by concrete call (VIEW, ENABLE) somewhere in procedure or in a trigger. But POPUP menu must be initiated right during hot-key processing (ESC-U or changed).
I also found that during processing of PaintEvent
from events queue the only bitmap rectangle is marked to be repainted and no other drawing logic exists. I didn't find a place except described earlier where draw
is called.
Please have a look if this variant could be acceptable at this moment. I can move the code, calling menu.draw()
to Widget.processKeyEvent()
if you insist. Will you also insist on using of PaintEvent
? If yes could you help me to understand how it should work?
#187 Updated by Vadim Gindin about 9 years ago
MenuChuiImpl.draw()
method:public void draw() { drawPanel(); super.draw(); this.firstFocus(); EventManager.postEvent(new FocusEvent(this.focus(), EventType.FOCUS_GAINED)); }
As a result it must look as follows: button, owning a pop-up menu gaining the focus and do not loose it when pop-up menu is shown. The first menu-item of it became highlighted and gain the focus too.
Going further:
this.firstFocus();
this statement set the first menu-item as a current;EventManager.postEvent(new FocusEvent(this.focus(), EventType.FOCUS_GAINED));
this statement posts FocusEvent.
It don't works. The menu-item is not highlighted. Could you advice something?
#188 Updated by Vadim Gindin about 9 years ago
How to properly test static menus deletion?
#189 Updated by Constantin Asofiei about 9 years ago
Vadim Gindin wrote:
The idea behindWill you also insist on using of
PaintEvent
? If yes could you help me to understand how it should work?
PaintEvent
is to postpone drawing until all the event processing is done (this avoids flickering & other problems like this). Look into how the TC.{{independent}Event}DrawingBracket
APIs work:
- the
OutputManager
is notified that code which needs drawing is to be executed TC.eventBracket
is called which executes some custom code, followed by processing (or discarding) all the collected events. When aPaintEvent
is encountered, it collects "invalidation rectangles" - this are screen areas which require painting.- when
OutputManager
is notified that the code has finished, it will go through the entire widget tree (starting from the window) and will draw only the widgets which intersect the invalidation rectangles. This avoids redrawing the entire screen. Also, only the screen area resulted from intersecting the widgets boundary and the invalidation rectangles will be flushed to the screen.
About the focus issue: there is the AbstractWidget.requestFocus
API - this should be enough to focus the widget. But this API should not be called from the draw
method - here you are AFTER the event processing has finished, so it's too late for this event to be picked up and processed. You need to call this either in the widget's processEvent
or within the Runnable
code passed as parameter to the TC.eventDrawingBracket
API (so the event is added to the TC.currentEventList
).
- if TC's specialized APIs are used, the Runnable code allows custom code related to your action
- widget's
processEvent
API - raise and/or process events; if the widget's appearance is different when i.e. focus is gained, then this allows you to set some flag. - widget drawing: this does the drawing; no more events should be raised here, UNLESS via a
TC.independentEventDrawingBracket
- so they are processed independently. - main conclusion: event processing and drawing need to be separated.
How to properly test static menus deletion?
Call delete object <handle-var-referencing-the-menu>
, i.e.:
def var h as handle. h = menu mbr:handle. delete object h.
Use the NO-ERROR clause to check for raised conditions and the ERROR-STATUS object.
About the event processing for menus: looks like these are similar to the combo-box dropdown and some other cases, especially when a EDITING block is used. I'm working on making a generic way for treating these system events, but I'm not finished yet.
#190 Updated by Vadim Gindin about 9 years ago
- File vig_upd20150210a.zip added
Here is the current update.
It adds to following changes to previous:- An implementation of find* methods,
- Server implementation of delete* methods
- Fixed bug with unwrapping menus.
- Tested server-side implementation of delete* methods for menus
Please review. Can I put run testing of it?
#191 Updated by Greg Shah about 9 years ago
Code Review vig_upd20150210a.zip
This is very close.
1. There is a build directory included in your update zip file.
2. The attributes/methods added need to be included in an interface. It is the interface name that is specified in methods_attributes.rules
, not the widget name, so GenericWidget
is invalid. There is a special case for CommonWidget
which we just unwrap as Widget
. That means that your GenericWidget
(widget class) would be Widget
(emits as unwrapWidget()
on a handle
) instead of CommonWidget
(the real interface name).
3. MenuItemChuiImpl
is missing javadoc for processKeyEvent()
and processKeyListeners()
.
4. I don't want to add references to org.apache.commons.collections.CollectionUtils
to the project. Please remove them from MenuContainerWidget
.
5. For label processing in menu_generator.xml
, is the use of removeQuotes()
correct? I wonder if we need proper progressToJavaString()
usage to convert any possible escaped chars and so forth.
6. AbstractContainer
needs a history entry.
#192 Updated by Vadim Gindin about 9 years ago
I'm debugging difficult bug:
def button btn1 LABEL "Button". def FRAME frame1 btn1. define menu mbar menu-item numbr label "Number" menu-item addr label "Address". on choose of menu-item numbr display "Number". on choose of menu-item addr display "Address". assign btn1:POPUP-MENU = MENU mbar:HANDLE. enable all with FRAME frame1. wait-for close of current-window.
This procedure defines frame frame1
, containing only one button btn1
. Wrong frame definition class is generated for that procedure:
public interface FrameFrame1 extends CommonFrame { public static final Class configClass = FrameFrame1Def.class; public void setExpr3(character parm); public void setExpr3(String parm); public void setExpr3(BaseDataType parm); public FillInWidget widgetExpr3(); public static class FrameFrame1Def extends WidgetList { FillInWidget expr3 = new FillInWidget(); public void setup(CommonFrame frame) { frame.setDown(1); expr3.setDataType("character"); expr3.setFormat("x(7)"); } { addWidget("expr3", "", expr3); } } }
We can see FillInWidget
here instead of Button
. But if we remove the latest trigger in the source procedure, the frame definition will be generated correctly.
I'm debugging frame generation, but I'm getting stuck. Could you propose me possible linkage between trigger and incorrect frame generation?
#193 Updated by Greg Shah about 9 years ago
In the 4GL I suspect that your DISPLAY
statements in the triggers are targeting the the default "unnamed" frame. Somehow we are connecting that with FRAME frame1
in the trigger.
Is this code supposed to work in 4GL ChUI? It doesn't do much that is useful there when I tried it. What are those DISPLAY
statements supposed to do?
#194 Updated by Vadim Gindin about 9 years ago
Greg Shah wrote:
In the 4GL I suspect that your
DISPLAY
statements in the triggers are targeting the the default "unnamed" frame. Somehow we are connecting that withFRAME frame1
in the trigger.
I've tested of what frames is used in triggers and found that new "unnamed" frame is created for each trigger. For our procedure there will be 3 frames: frame1
and 2 unnamed frames for triggers.
..
Wait a minute. It seems that it is a frames naming (class naming) problem. Here is the main procedure class:
public class Frame { FrameFrame1 frame1Frame = GenericFrame.createFrame(FrameFrame1.class, "frame1"); MenuDefinitionMbar mbar = MenuWidget.createStaticMenu(MenuDefinitionMbar.class, "mbar"); FrameFrame0 frame0 = null; FrameFrame1 frame1 = null; ...
As you can see the generated interface for 2nd unnamed frame is FrameFrame1
- the same as the main named frame! It means that interface was just overridden! By the way where triggers processing really happen?
Is this code supposed to work in 4GL ChUI? It doesn't do much that is useful there when I tried it. What are those
DISPLAY
statements supposed to do?
I didn't pursue concrete goal when I was writing this procedure. I just faced with this bug accidentally. But this procedure works for CHUI.
#195 Updated by Greg Shah about 9 years ago
Wait a minute. It seems that it is a frames naming (class naming) problem.
This makes sense. Please put some protection logic in for this naming conflict.
I didn't pursue concrete goal when I was writing this procedure. I just faced with this bug accidentally. But this procedure works for CHUI.
How do you get the menu to display? When I run it, the button appears but I can't make it do anything.
By the way where triggers processing really happen?
Any operation that blocks for user input will be first invoked on the server side. Before we transfer control to the client, we prepare an EventList
to describe the combinations of events and widgets that match triggers and validation expressions.
On the client side, during event processing, we check the current event and the event's widget source to see if there is a match to an existing trigger. Look in ThinClient
for calls to invokeTriggers()
. If there is a match, then the server-side is called back to invoke the trigger on the server. See LogicalTerminal.trigger()
.
Validation expression processing is similar, but it gets tested using ThinClient.validateWidget()
and the server-side call is LogicalTerminal.validate()
.
#196 Updated by Vadim Gindin about 9 years ago
Greg Shah wrote:
Wait a minute. It seems that it is a frames naming (class naming) problem.
This makes sense. Please put some protection logic in for this naming conflict.
Don't you remember where that conversion logic?
I didn't pursue concrete goal when I was writing this procedure. I just faced with this bug accidentally. But this procedure works for CHUI.
How do you get the menu to display? When I run it, the button appears but I can't make it do anything.
There are popup-menu associated with button. To open it up you need to press ESC-U
.
By the way where triggers processing really happen?
Any operation that blocks for user input will be first invoked on the server side. Before we transfer control to the client, we prepare an
EventList
to describe the combinations of events and widgets that match triggers and validation expressions.On the client side, during event processing, we check the current event and the event's widget source to see if there is a match to an existing trigger. Look in
ThinClient
for calls toinvokeTriggers()
. If there is a match, then the server-side is called back to invoke the trigger on the server. SeeLogicalTerminal.trigger()
.Validation expression processing is similar, but it gets tested using
ThinClient.validateWidget()
and the server-side call isLogicalTerminal.validate()
.
I meant conversion logic, that generates unnamed frames for triggers. Could you remember at first sight where it could be?
#197 Updated by Greg Shah about 9 years ago
Don't you remember where that conversion logic?
See the process_frame
function in annotations/frame_scoping.rules
.
I meant conversion logic, that generates unnamed frames for triggers. Could you remember at first sight where it could be?
I think this would also be in annotations/frame_scoping.rules
. However, I doubt there is any specific logic in there for triggers. As far as I know, there is nothing special about them for frame definition purposes.
#198 Updated by Vadim Gindin about 9 years ago
- File vig_upd20150219a.zip added
The next update, containing remarks corrections and overrides bug fix
#199 Updated by Greg Shah about 9 years ago
Code Review vig_upd20150219a.zip
I ma OK with the changes. Please get this update conversion and runtime regression tested.
#200 Updated by Vadim Gindin about 9 years ago
Current update has passed conversion testing. I ran regression testing twice. Only one test has failed during both runs: tc_code_employees_20
. Could you help me to interpet its results. Here is the failing screen from the report:
02/19/2015 EMPLOYEE MASTER (5 of 5) 17:20:04 ┌──────────────────────────────────────────────────────────────────────────────┐ │ Employee: 1029 ********** JR., **** E. │ │ Skill: │ │ Crew Code: │ │ Shift: 0 Days-Off: │ └──────────────────────────────────────────────────────────────────────────────┘ Start Start End End Crew Crew Skil Shift Days Date Time Date Time Dept Code Eff Date Code Sft Eff Date Off ────────── ───── ────────── ───── ──── ──── ────────── ──── ─── ────────── ──── >07/02/1990 07:00 07/02/1990 15:30 7000 D40 01/01/1990 7300 11 01/01/1990 67 11/01/1995 07:00 11/01/1995 15:30 7000 40D 01/01/1990 7300 11 01/01/1990 67 09/25/1999 07:00 09/25/1999 15:30 1500 070 01/01/1990 1540 11 01/01/1990 67 05/18/2002 07:00 05/18/2002 15:30 1100 050 01/01/1990 1130 11 01/01/1990 67 10/18/2003 07:00 10/18/2003 15:30 7000 070 01/01/1990 1540 11 01/01/1990 67 12/20/2003 07:00 12/20/2003 15:30 7000 070 01/01/1990 7500 11 01/01/1990 67 06/12/2004 07:00 06/12/2004 15:30 7000 060 01/01/1990 7500 11 01/01/1990 67 11/01/2004 00:00 11/01/2004 00:00 62E 01/01/1990 1130 11 01/01/1990 67 11/02/2004 00:00 11/02/2004 00:00 62E 01/01/1990 1130 11 01/01/1990 67 (N)ext (P)rev (U)pdate (A)dd (C)opy (F)ind (D)el (O)utput (T)ext (X)Crew (H)elp (E)xtend (1)Up (2)Down (3)Pg Back (4) Pg Frwd (5)Beg (6)End (R)eturn: F
The error:
timeout before the specific screen buffer became available (Mismatched data at line 3, column 22. Expected
e X 22) and found '' (0x0000 at relative Y 3, relative X 22).)
I've manually ran TIMCO from the server and opened that screen:
02/20/2015 EMPLOYEE MASTER (5 of 5) 03:16:31 ┌──────────────────────────────────────────────────────────────────────────────┐ │ Employee: 1029 *** JR., ********* E. │ │ Skill: 1130 IT SOFTWARE DEVEL │ │ Crew Code: 62E *** *** *** *** - ******* │ │ Shift: 11 Days-Off: 67 │ └──────────────────────────────────────────────────────────────────────────────┘ Start Start End End Crew Crew Skil Shift Days Date Time Date Time Dept Code Eff Date Code Sft Eff Date Off ────────── ───── ────────── ───── ──── ──── ────────── ──── ─── ────────── ──── >07/02/1990 07:00 07/02/1990 15:30 7000 D40 08/04/2007 7300 11 01/01/1990 67 11/01/1995 07:00 11/01/1995 15:30 7000 40D 08/04/2007 7300 11 01/01/1990 67 09/25/1999 07:00 09/25/1999 15:30 1500 070 08/04/2007 1540 11 01/01/1990 67 05/18/2002 07:00 05/18/2002 15:30 1100 050 08/04/2007 1130 11 01/01/1990 67 10/18/2003 07:00 10/18/2003 15:30 7000 070 08/04/2007 1540 11 01/01/1990 67 12/20/2003 07:00 12/20/2003 15:30 7000 070 08/04/2007 7500 11 01/01/1990 67 06/12/2004 07:00 06/12/2004 15:30 7000 060 08/04/2007 7500 11 01/01/1990 67 11/01/2004 00:00 11/01/2004 00:00 62E 08/04/2007 1130 11 01/01/1990 67 11/02/2004 00:00 11/02/2004 00:00 62E 08/04/2007 1130 11 01/01/1990 67 (N)ext (P)rev (U)pdate (A)dd (C)opy (F)ind (D)el (O)utput (T)ext (X)Crew (H)elp (E)xtend (1)Up (2)Down (3)Pg Back (4) Pg Frwd (5)Beg (6)End (R)eturn: F
As you can see the point [3, 22] corresponds to line Skill:
. At the failing screen it is empty because of some unknown reason and the same screen in manual run this line contains: Skill: 1130 IT SOFTWARE DEVEL
.
I suspect that this error is not related with my update. Don't you know why it happens?
LE: GES redacted customer personnel info.
#201 Updated by Vadim Gindin about 9 years ago
I've ran regression testing 3rd time. And the test tc_codes_employees_20
has passed. So, we can assume that update has passed regression testing. Can I commit it?
#202 Updated by Greg Shah about 9 years ago
I suspect that this error is not related with my update. Don't you know why it happens?
We don't know for sure. I suspect that there is a flaw in the terminal software that drops characters from time to time. These sort of errors seem to happen more frequently when the system has a heavy load, so the code may be somehow sensitive to that condition.
Someday we will have someone dig into this. The problem is that it cannot be easily recreated, so debugging it will likely involve instrumenting the terminal source code to output log entries when unexpected conditions occur and interpreting the results that are matched up with failing test runs.
So, we can assume that update has passed regression testing. Can I commit it?
Actually, don't you have to merge up to the latest bzr revision?
#203 Updated by Vadim Gindin about 9 years ago
- File vig_upd20150220a.zip added
Here is merged current update with the latest revision.
#204 Updated by Greg Shah about 9 years ago
OK, you can commit vig_upd20150220a.zip.
#205 Updated by Vadim Gindin about 9 years ago
Current update has passed full testing and committed to rev #10766.
#206 Updated by Greg Shah about 9 years ago
In your next update, please resolve these:
[javadoc] /home/ges/projects/p2j/src/com/goldencode/p2j/ui/MenuWidget.java:139: warning - Tag @link: can't find findMenuItem(String, MenuContainerWidget) in com.goldencode.p2j.ui.MenuWidget [javadoc] /home/ges/projects/p2j/src/com/goldencode/p2j/ui/SubMenuWidget.java:100: warning - Tag @link: can't find findMenuItem(String, MenuContainerWidget) in com.goldencode.p2j.ui.MenuWidget
#207 Updated by Greg Shah about 9 years ago
Please post a list of the remaining features needing to be implemented, enhanced and/or bugs needing fixing. You can exclude GUI support from the list.
#208 Updated by Vadim Gindin about 9 years ago
- File vig_upd20150220b.zip added
Javadoc fix.
Remaining features needing to be implemented is empty at this moment. Probably some features will be known during GUI implementation.
#209 Updated by Greg Shah about 9 years ago
At this point are ChUI menus fully functional?
Is there any error handling, event or other missing functionality? I remember some todos in the ThinClient.destroyMenu()
method.
Please add the following attributes next:
MENU: FIRST-CHILD, LAST-CHILD
SUB-MENU: FIRST-CHILD, LAST-CHILD, NEXT-SIBLING, PREV-SIBLING
MENU-ITEM (CHECKED, READ-ONLY and SUBTYPE are done, right?): ACCELERATOR, TOGGLE-BOX, NEXT-SIBLING, PREV-SIBLING
Make sure that these events are supported:
MENU: MENU-DROP
SUB-MENU: MENU-DROP
MENU-ITEM: CHOOSE, VALUE-CHANGED
Have you tested colors, toggle-boxes, accelerators, read-only, rule, skip?
#210 Updated by Vadim Gindin about 9 years ago
You're right. Some of noted points are not implemented. See below
Greg Shah wrote:
At this point are ChUI menus fully functional?
No. I can't finish client-side part because of event-processing. I recall, that Constantin is working on common event mechanism for menus and comboboxes.
Is there any error handling, event or other missing functionality? I remember some todos in the
ThinClient.destroyMenu()
method.
Probably. It is hard to say without working events in GUI and good testing. About destroyMenu
I'm not sure of how to implement it.
NEXT-SIBLING, PREV-SIBLING was implemented in parent classPlease add the following attributes next:
MENU: FIRST-CHILD, LAST-CHILD
SUB-MENU: FIRST-CHILD, LAST-CHILD, NEXT-SIBLING, PREV-SIBLING
BaseEntity
, but at some moment I changed base class to AbstractContainer
.
MENU-ITEM (CHECKED, READ-ONLY and SUBTYPE are done, right?): ACCELERATOR, TOGGLE-BOX, NEXT-SIBLING, PREV-SIBLING
READ-ONLY, SUBTYPE, ACCELERATOR, TOGGLE-BOX are implemented.
Make sure that these events are supported:
MENU: MENU-DROP
SUB-MENU: MENU-DROP
MENU-ITEM: CHOOSE, VALUE-CHANGED
Waiting for common event-processing mechanism.
Have you tested colors, toggle-boxes, accelerators, read-only, rule, skip?
No, I stopped at event-processing. I'm doing what is possible without events at this moment.
#211 Updated by Greg Shah about 9 years ago
At this point are ChUI menus fully functional?
No. I can't finish client-side part because of event-processing. I recall, that Constantin is working on common event mechanism for menus and comboboxes.
Constantin's changes are all checked in as of bzr rev 10760. Anything that is not working properly at this point is something for you to work on.
About destroyMenu I'm not sure of how to implement it.
If it has no purpose, get rid of it.
Please get the ChUI menus fully functional as your top priority. I don't want to add GUI in, before the ChUI cases are all operational.
#212 Updated by Vadim Gindin about 9 years ago
I'm stuck... I can't make menu events working. I don't fully understand how events queue works. Here are the following difficulties.
1. When we have a frame all its fields and other components are stayed "freezed" untill we call ENABLE command. Menus works differently: MENUBAR (menu for window) must be enabled right after it became displayed.
2. Lets look at the following procedure:
def menu m menubar menu-item mi label "&Mikki Mouse" menu-item mi1 label "T&iffany". on choose of menu-item mi message "AAA". assign current-window:menubar = menu m:handle. wait-for choose of menu-item mi.
When I'm running some procedure with frame it waits for some input and ready for answer as it programmed in it.
I'm running described procedure and got the following. After menu is displayed - procedure is assumed as completed and paused before end (ThinClient.pauseBeforeEnd
is called) and waiting for pressing any button to close its window. TransactionManager.popScope
pops the last scope from the stack and calls pauseBeforeEnd
from it.
It looks like I didn't run events cycle and didn't find a way to run it..
I'm recalling that MENUBAR drawing is placed to WindowChuiImpl.setVisible
. I've tried to enclose this drawing in ThinClient.eventBracked
call to push a new EventQueue
to queues stack in EventManager
but it didn't help because it is only a drawing processing.
Could you advice me something?
#213 Updated by Vadim Gindin about 9 years ago
I found that during processing of ThinClient.waitFor
the flag immedExit
is set to true. It probably a reason.. It don't look obvious: immedExit
is set as a result of:
case FocusManager.FOCUS_UNDEF: // undefined, explicit immedExit = !focusManager.focusUndefExplicit(startWidget, list, cop, !pendingExplicit);
Does it really means that I should manually set focus to menu to fix my problem?
#214 Updated by Vadim Gindin about 9 years ago
Mistake..
Here is the place in ThinClient.waitFor
where immedExit is set to true:
case FocusManager.FOCUS_UNDEF: // undefined, implicit immedExit = !focusManager.focusUndefImplicit(list, false); break;
#215 Updated by Vadim Gindin about 9 years ago
Yes, that was the reason.. Sorry for trouble.
#216 Updated by Vadim Gindin about 9 years ago
- File vig_upd20150306a.zip added
- Focus management of menu items
- Sub-menu support
- IDs collision fix
- Added missed implementation for findMenuItemStatic method
- some other fixes.
At this moment there are error during events processing. When I'm pressing '->' in MENUBAR first menu-item (sub-menu) is blended when loosing focus. There are several calls. One of them draws sub-menu correctly but the next one completely blend it from MENUBAR.
Here is my test:
def sub-menu sm menu-item mi1 label "Hekkle Berry F&in". def menu m menubar sub-menu sm label "Subm&enu". menu-item mi label "&Mikki Mouse". on choose of menu-item mi message "AAA". assign current-window:menubar = menu m:handle. wait-for choose of menu-item mi.
It seems I'm stuck with this UI implementation.
#217 Updated by Greg Shah about 9 years ago
When I'm pressing '->' in MENUBAR first menu-item (sub-menu) is blended when loosing focus. There are several calls. One of them draws sub-menu correctly but the next one completely blend it from MENUBAR.
It sounds like there is a z-order problem and/or a problem with drawing in non-visible (covered) areas of a widget.
#218 Updated by Greg Shah about 9 years ago
Code Review vig_upd20150306a.zip
This is a good step forward.
1. It seems like there should be shared code between MenuItemChuiImpl
and SubMenuChuiImpl
for methods like processKeyEvent()
, calcPosition()
and drawTitle()
. What is an approach where that code can be in a common class?
2. MenuChuiImpl.processKeyEvent()
is missing javadoc.
3. In multiple places of your update, you use for(
instead of for (
. MenuChuiImpl.processKeyEvent()
is one example.
4. Menu.java
ends with this: }}
.
#219 Updated by Greg Shah about 9 years ago
If you are stuck, please post specific questions or post more details of the problem so that we can help.
#220 Updated by Vadim Gindin about 9 years ago
1. I have simple MENUBAR with sub-menu and menu. It is drawn succesfully. At starting moment sub-menu has focus. When I'm pressing "->" I expect that menu-item will gain focus and sub-menu will loose it, but during several redrawings sub-menu first loose focus and after some drawing disappear at all. Menu-item do not gain a focus.
In other words, there are several calls of SubMenuChuiImpl.draw
method after I press "->". After one of them sub-menu loose focus and after some other of them - disappear. Why It happen?
2. I'm trying to draw sub-menu body (i.e. sub-menu items). But it doesn't appear at screen. I tried several variants: manually set correct coordinates, manually set color to Color.NORMAL. Nothing is drawn.
It looks like I don't understand something conceptual.
P.S. About z-order. I didn't find something that could be a reason there. More over there are no frames at all, one window. I think z-order mechanism isn't used in my case.
Here is the testcase:
def sub-menu sm menu-item mi1 label "Hekkle Berry F&in". def menu m menubar sub-menu sm label "Subm&enu". menu-item mi label "&Mikki Mouse". on choose of menu-item mi message "AAA". assign current-window:menubar = menu m:handle. wait-for choose of menu-item mi.
I've analyzed DoubleBufferedTerminal
. There is the following conception. There are 2 screen buffers: real screen buffer and cached previous value. The goal is to update only minimal area of the screen where changes was really happen. These changes are defined as a difference between actual screen buffer and cached previous buffer. I suspected that my code leads to incorrect situation in this buffers. I've tried other places of MENUBAR drawing: draw, repaint
methods in WindowChuiImpl but without success. I didn't find the reason, why it happen.
#221 Updated by Greg Shah about 9 years ago
Some thoughts:
1. Menus are different from our normal containers like Frames. With menus, the contained widgets can draw outside of the container's rectangle. For this reason, you may be having clipping problems and/or the drawing algorithms may naturally be assuming that contained widgets are drawing within the contained area.
2. Even without frames being involved, you certainly have multiple widgets which need to draw in overlapping coordinates, so there is definitely a z-order requirement here. For example, you have a menu-item that must draw on top of a sub-menu that must draw on top of the menu-bar. When the sub-menu overdraws the menu-item, that sounds like a z-order issue.
3. Make sure that the visible flag is managed carefully. With frames and other "normal" widgets, the visibility is controlled by high level functions like when a VIEW is called for a frame. With menus and their contents, this is different. The contents must be made visible in response to certain events and then must be hidden again when dismissed. You must find the right places to this to occur. A mismatch could certainly cause things to not draw. I would also worry that the standard widget visibility processing may need modifications to be compatible.
4. You need to make sure that the menu-items and sub-menus are properly integrated with the focus manager such that focus can be properly changed in response to events.
For some ideas on all of the above, you might want to look at how the drop-down draws and handles events with combo-box. This is a temporary "sub-widget" control that displays when needed, displays outside of the controlling widget's dimensions, integrates with focus processing and interacts with the user, including event processing and dynamic drawing.
#222 Updated by Vadim Gindin about 9 years ago
Greg Shah wrote:
Some thoughts:
1. Menus are different from our normal containers like Frames. With menus, the contained widgets can draw outside of the container's rectangle. For this reason, you may be having clipping problems and/or the drawing algorithms may naturally be assuming that contained widgets are drawing within the contained area.
2. Even without frames being involved, you certainly have multiple widgets which need to draw in overlapping coordinates, so there is definitely a z-order requirement here. For example, you have a menu-item that must draw on top of a sub-menu that must draw on top of the menu-bar. When the sub-menu overdraws the menu-item, that sounds like a z-order issue.
I don't fully understand this statement. MENUBAR draws it's items (menu-items and sub-menus) within its area. Dropped down sub-menu body does not overlap other menu parts: other menu-items or sub-menus of different levels. Containers (MENU and SUB-MENU) draws its children (SUB-MENU and MENU-ITEM). But none of these components could overlap. Am I wrong?
3. Make sure that the visible flag is managed carefully. With frames and other "normal" widgets, the visibility is controlled by high level functions like when a VIEW is called for a frame. With menus and their contents, this is different. The contents must be made visible in response to certain events and then must be hidden again when dismissed. You must find the right places to this to occur. A mismatch could certainly cause things to not draw. I would also worry that the standard widget visibility processing may need modifications to be compatible.
4. You need to make sure that the menu-items and sub-menus are properly integrated with the focus manager such that focus can be properly changed in response to events.
For some ideas on all of the above, you might want to look at how the drop-down draws and handles events with combo-box. This is a temporary "sub-widget" control that displays when needed, displays outside of the controlling widget's dimensions, integrates with focus processing and interacts with the user, including event processing and dynamic drawing.
Do you mean ComboBox
here?
Does an "event processing model" documented somewhere? I mean in some web gui frameworks authors create a separate topic in documentation called "Request lifecycle" or something like that.
Thank you for thoughts.
#223 Updated by Greg Shah about 9 years ago
I don't fully understand this statement. MENUBAR draws it's items (menu-items and sub-menus) within its area. Dropped down sub-menu body does not overlap other menu parts: other menu-items or sub-menus of different levels. Containers (MENU and SUB-MENU) draws its children (SUB-MENU and MENU-ITEM). But none of these components could overlap. Am I wrong?
I don't know. I haven't used the 4GL menus, but in every menu system I've ever used, there is often at least a partial overlap between sub-menus and their containing menus or menu-items and their containers (they often appear connected and the connection point is drawn differently than when the sub-menu is not displayed). For example, in Firefox, open View -> Toolbars. The Toolbars sub-menu slightly overlaps with the View sub-menu. If that isn't possible in the 4GL, then that is great. However, I would wonder about overlapping in cases where the right side of the screen is too close to the right side of the container for a contained sub-menu to be drawn.
Do you mean
ComboBox
here?
Yes. ComboBox
has a special drop-down sub-widget that exhibits similar behavior to menus. It takes special processing to make that sub-widget work.
Does an "event processing model" documented somewhere? I mean in some web gui frameworks authors create a separate topic in documentation called "Request lifecycle" or something like that.
I wish we had such a thing. The best way to understand the event loop is to set a breakpoint in ThinClient.processEventsWorker()
and follow the flow of the event processing. This is the top-level portion of the loop. It is very important that you step into ThinClient.processProgressEvent()
and also into Window.processEvent()
. The idea is to duplicate the 4GL event processing here. There can sometimes be some widget-specific or event specific behavior before triggers, then there are triggers (user-defined code blocks) executed, the event can also be treated as a high level event (F1 can also be GO) which can also execute triggers, if the triggers RETURN NO-APPLY then the default processing is generally bypassed, but otherwise the default processing for the widget is executed. Intermixed with this we have the low-level P2J events for drawing, synching, focus management and so forth.
#224 Updated by Constantin Asofiei about 9 years ago
- File vig_upd20150309a.zip added
- File vig_upd20150309a_ca.zip added
- Rectangle: the instances of this class need to be immutable; don't break this
- Menu, SubMenu, MenuItemChuiImpl: event processing should be in the base class; I expect this to be common for both GUI and ChUI (in any case, it can be refactored then, if needed).
- processKeyEvent - you don't have to explicitly call draw()/requestSync(). Rely on raising a PaintEvent instead by calling repaint(), if needed.
- Use the
-Dwidgetbrowser=yes
at the client to see the widget tree; you will note that your Menu is not attached to the window. It's not enough to set the widget's parent, you need to attach it to the window, too, viaWindow.getContentPane().add(widget)
. - all drawing in ChUI is relative to the screen's origin, the top-left corner; so when drawing, if you have coordinates relative to the parent, ensure they are resolved properly.
- when changing focus, the focus management code should repaint the widget accordingly.
See the attached version - it behaves somehow better than your 0309a.zip.
#225 Updated by Vadim Gindin about 9 years ago
The next buffled difficulty. Here is my menu:
Mikki Mouse Submenu Rabbit
Menu-item Mikki Mouse
has focus right after start (title is highlighted). I press '->' and see that only first letter of Submenu
is highlighted. Submenu
is sub-menu. I've added to drawTitle
following lines:
Dimension titleDim = new Dimension(width(), 1); Rectangle titleRect = new Rectangle(this.location(), titleDim); EventManager.postEvent(new PaintEvent(this, titleRect));
this.location()
returns the following point: [x=12, y=0], titleDim
is [height=1, width=8]. Calculated titleRect
is the following: [top=0, left=12, right=19, bottom=0]. These rectangle, as I think, has to conform to sub-menu title Submenu
. So I expect that Submenu
will be highlighted after repaint, but as a result only first letter is highlighted.
Sorry for stupid question, but where is my mistake?
Does the calculated rectangle correct?
P.S. Combobox
has artifical component DropDown
that conforms to expanded values list of Combobox
component. My dropdown list fully differs from DropDown
:
1. DropDown
is scrollable, but menu is not, when sub-menu contains large number of children that more than screen lines number - the error is shown: Menu to large to display on the screen. (5902)
.
2. DropDown
contains strings, but menu contains menu-items (components)
3. DropDown
is hard linked with ComboBox
I think it will be not suitable to use DropDown
and ComboBox
classes for menu goals as a common mechanism. Probably implementation sub-menu window as a separate class similar to DropDown
is make sense. I just suspected that it is possible without separate component. What do you think?
#226 Updated by Vadim Gindin about 9 years ago
Separate question about events. Lets look at Button.processEvent()
method:
/** * Process event and dispatch it to specific method. * * @param event * Event to process. */ @Override public void processEvent(Event event) { super.processEvent(event); if (event instanceof KeyInput) { KeyInput keyEvent = (KeyInput) event; if ((!keyEvent.isConsumed()) && keyEvent.keyCode() == Key.VK_ENTER && isEnabled()) { EventManager.postEvent(new ActionEvent(this, getCommand())); keyEvent.consume(); } return; } if (event instanceof ActionEvent) { for (ActionListener listener : listeners) { listener.onAction(((ActionEvent) event)); } } }
What is the necessity of wrapping KeyInput
event in ActionEvent
here, posting new event to queue, to extract that ActionEvent
from queue later but process it in the same place: the method where ActionEvent
was created?
I just wanted to understand on that example where is the right place to wrap low-level events (such as KeyInput
) and where is the right place to process high-level events. In described example that is the one place for both.
#227 Updated by Vadim Gindin about 9 years ago
The first question in previous note is solved: wrong implementation of menu.width()
#228 Updated by Greg Shah about 9 years ago
I think it will be not suitable to use DropDown and ComboBox classes for menu goals as a common mechanism.
I agree. The idea was for you to see how that works so that you can understand the techniques needed to have an independent drawing/events processing environment.
Probably implementation sub-menu window as a separate class similar to DropDown is make sense. I just suspected that it is possible without separate component. What do you think?
I think your current class hierarchy makes sense. And the 4GL does treat these as real widgets, so that is a good fit for us to treat them that way.
Don't try to rework your class hierarchy. Just use the ideas in the drop-down processing to help you design the menus.
#229 Updated by Vadim Gindin about 9 years ago
The bottom and right borders of sub-menu is not drawn. I've debugged it and found that it because ScreenBitmap
activated rectangles do not contain target sub-menu body rectangle. Will be correct to add sub-menu body rectangle to activated rectangles list using PaintEvent
created after draw
method finished?
#230 Updated by Constantin Asofiei about 9 years ago
Vadim Gindin wrote:
The bottom and right borders of sub-menu is not drawn. I've debugged it and found that it because
ScreenBitmap
activated rectangles do not contain target sub-menu body rectangle. Will be correct to add sub-menu body rectangle to activated rectangles list usingPaintEvent
created afterdraw
method finished?
No, it will not work. These rectangles need to be collected during the event processing, not during drawing - at that time, it's too late to raise and process the PaintEvent's.
What is the necessity of wrapping KeyInput event in ActionEvent here, posting new event to queue, to extract that ActionEvent from queue later but process it in the same place: the method where ActionEvent was created?
If I recall correctly, this is because in some cases two events are raised in 4GL: one for the actual key press and, if that is not consumed, one for the widget's action (like CHOOSE
). And each event can have its own trigger: that's why the ActionEvent is raised, so that the event processing will pick it up and interpret it.
#231 Updated by Constantin Asofiei about 9 years ago
Vadim Gindin wrote:
The bottom and right borders of sub-menu is not drawn. I've debugged it and found that it because
ScreenBitmap
activated rectangles do not contain target sub-menu body rectangle. Will be correct to add sub-menu body rectangle to activated rectangles list usingPaintEvent
created afterdraw
method finished?
PS: check if for the sub-menu a PaintEvent is generated and if so, if the rectangle matches the sub-menu's dimension.
#232 Updated by Vadim Gindin about 9 years ago
Thanks for help!
The next 2 questions.
1. Every opened sub-menu has its own focus. Lets assume we have MENUBAR with 2 opened sub-menus. In this situation focused widgets will be:
a. sub-menu in menubar
b. contained sub-menu
c. menu-item in contained sub-menu.AbstractContainer
has a field current
that contains a widget having focus, so I think such situation, when a several widgets can have focus simultaneously, is supported. Am I right?
2. I'm trying to implement focusing next menu-item in opened sub-menu. I'm calling ThinClient.nextFocus(widget)
in SubMenu.processKeyEvent
where widget is the first menu-item in this sub-menu. This call really changes AbstractContainer.current
field but later it is changed to previous value in the following place: FocusManager.focusChange()
, line 1262, in the call setFocusOn(widget)
. I don't understand why this call is there? and what am I doing wrong, while trying to set focus?
#233 Updated by Greg Shah about 9 years ago
AbstractContainer has a field current that contains a widget having focus, so I think such situation, when a several widgets can have focus simultaneously, is supported. Am I right?
If I understand your question correctly, I believe the answer is yes. The idea is that multiple levels of container can each track the child within them that has the focus. SO: the Window knows which of its contained Frames is focused and the focused Frame knows which widget is in focus. I think this is the same thing as you are doing, with the menu and sub-menus being containers.
2. I'm trying to implement focusing next menu-item in opened sub-menu. I'm calling ThinClient.nextFocus(widget) in SubMenu.processKeyEvent where widget is the first menu-item in this sub-menu. This call really changes AbstractContainer.current field but later it is changed to previous value in the following place: FocusManager.focusChange(), line 1262, in the call setFocusOn(widget). I don't understand why this call is there? and what am I doing wrong, while trying to set focus?
This one is tricky to explain because I don't have the complete answer myself. I can say this:
- The focus does get set back to the original widget at that line BUT focus will shift to the target widget if the ENTRY trigger doesn't exist on the target widget OR if the trigger does exist but does NOT use
RETURN NO-APPLY
. But it is the ENTRY event processing that causes the "final" focus change to occur. - I believe this was done to get the environment/state to look correct for the ENTRY event/trigger processing. I don't have more specifics on this, but I remember it was done on purpose and at the time we didn't have a better way to resolve the issues.
#234 Updated by Vadim Gindin about 9 years ago
I faced with NPE:
java.lang.NullPointerException at com.goldencode.p2j.ui.chui.ThinClient.processProgressEvent(ThinClient.java:14419) at com.goldencode.p2j.ui.client.FocusManager.focusChange(FocusManager.java:1271) at com.goldencode.p2j.ui.chui.ThinClient.nextFocus(ThinClient.java:16356) at com.goldencode.p2j.ui.client.chui.MenuItemChuiImpl.processKeyEvent(MenuItemChuiImpl.java:140) at com.goldencode.p2j.ui.client.widget.TitledWindow.processKeyEvent(TitledWindow.java:297) at com.goldencode.p2j.ui.client.widget.AbstractWidget.processEvent(AbstractWidget.java:1006) at com.goldencode.p2j.ui.client.widget.TitledWindow.processEvent(TitledWindow.java:266) at com.goldencode.p2j.ui.chui.ThinClient.processEventsWorker(ThinClient.java:13910)
Lets look at FocusManager.focusChange():
Widget inFocus = UiUtils.getCurrentFocus(); .. // create and process the ENTRY event now. the ENTRY event will be // responsible for setting focus to the required widget, if it accepts // it KeyInput entry = new KeyInput(inFocus, EventType.KEY_PRESSED, Keyboard.SE_ENTRY, true); tc.processProgressEvent(entry);
Here inFocus
is null. I've digged into UiUtils.getCurrentFocus();
and found the following.
There are following hierarchy: Window -> BorderedPanel -> Menu -> SubMenu -> Menu-item
and all of these nodes are AbstractContainer's
except Menu-item
. AbstractContainer
has field current
- current focused widget.UiUtils.getCurrentFocus()
returns null because AbstractContainer.current
becomes null at some moment. It happens in AbstractContainer.focusWorker
line 1076:
.. for (Widget<O> widget : iter) { if (widget == current) { 1076: current = null; return; } if (checkWidget(widget, direction)) return; }
More concrete: container is Window
and current was BorderedPanel and is set to null. There only one child in the Window
.
I don't understand why it is needed: reset current
to null especially for Window
. As a result: Window.focusWorker(true) returns null when it had current=BorderedPanel
.
#235 Updated by Greg Shah about 9 years ago
I don't understand why it is needed: reset current to null especially for Window. As a result: Window.focusWorker(true) returns null when it had current=BorderedPanel.
I don't know the answer exactly. In think this only can happen for Window because all other widgets have parents. But I think this would only happen if some much deeper focus change processing failed when it should not have failed. Shouldn't the SubMenu
(in Window -> BorderedPanel -> Menu -> SubMenu
) have changed the focus and then terminated its AbstractContainer.focusWorker()
? It would only have asked its parent()
to next|prevFocus()
if none of its children could be focused. I think you have a problem there.
Also, I do wonder if the menus should be considered part of the content pane of the window or if they should be treated separately like the message and status areas?
Constantin: do you have any thoughts on these items?
#236 Updated by Vadim Gindin about 9 years ago
- File vig_upd20150318a.zip added
Here is my current update.
#237 Updated by Constantin Asofiei about 9 years ago
Please post the test you used to get the NPE.
#238 Updated by Vadim Gindin about 9 years ago
Here it is:
def sub-menu sm menu-item mi1 label "Hekkle Berry F&in". menu-item mi2 label "Chuk I Gek". def menu m menubar menu-item mi label "&Mikki Mouse". menu-item mmi label "Rabbi&t" ACCELERATOR "PAGE-DOWN". sub-menu sm label "Subm&enu". on choose of menu-item mi message "AAA". on choose of menu-item mmi message "BBB". assign current-window:menubar = menu m:handle. wait-for choose of menu-item mi.
The error happens when I'm pressing down error having focus on the last menu-item in dropped-down sub-menu.
Greg Shah wrote:
I don't understand why it is needed: reset current to null especially for Window. As a result: Window.focusWorker(true) returns null when it had current=BorderedPanel.
I don't know the answer exactly. In think this only can happen for Window because all other widgets have parents. But I think this would only happen if some much deeper focus change processing failed when it should not have failed. Shouldn't the
SubMenu
(inWindow -> BorderedPanel -> Menu -> SubMenu
) have changed the focus and then terminated itsAbstractContainer.focusWorker()
? It would only have asked itsparent()
tonext|prevFocus()
if none of its children could be focused. I think you have a problem there.
Yes, that is probably a real reason, but I faced with this error several times - not only in my current situation. I thought that it looks strange. Ok, lets consider, if we can't change focus - just leave it as it was, why should we reset it? That is what I asked about.
I'm going to override Container.nextFocus
and Container.prevFocus
at least for SUB-MENU to make it simpler, because there are no necessity to call parents focused item - there are simple cyclic algorithm.
What do you think?
Also, I do wonder if the menus should be considered part of the content pane of the window or if they should be treated separately like the message and status areas?
At this moment menus are contained in the content pane.
#239 Updated by Constantin Asofiei about 9 years ago
Greg Shah wrote:
Also, I do wonder if the menus should be considered part of the content pane of the window or if they should be treated separately like the message and status areas?
Greg, I think you are onto something here... when a window has a menu, its client-area (where frames are drawn) is shifted on row down on the physical screen. See this:
def sub-menu sm menu-item mi1 label "Hekkle Berry F&in". def menu m menubar sub-menu sm label "Subm&enu". menu-item mi label "&Mikki Mouse". on choose of menu-item mi message "AAA". def var ch as char. form ch with frame f1 row 1 col 1. display ch with frame f1. pause. assign current-window:menubar = menu m:handle. pause. wait-for choose of menu-item mi. pause.
Vadim: at some point, you need to check what happens if the sub-menu is drawn over an existing frame (like in my test above).
I'll come back with some thoughts related to the focus management.
#240 Updated by Vadim Gindin about 9 years ago
- File vig_upd20150318b.zip added
I've checked simplified focusWorker
method and it works (NPE is gone). Is it ok?
#241 Updated by Greg Shah about 9 years ago
I thought that it looks strange. Ok, lets consider, if we can't change focus - just leave it as it was, why should we reset it? That is what I asked about.
I don't know why that code is there, but it is dangerous to modify it when we don't know the implications.
And I don't think menu focus processing should ever get to that code anyway.
I'm going to override Container.nextFocus and Container.prevFocus at least for SUB-MENU to make it simpler, because there are no necessity to call parents focused item - there are simple cyclic algorithm.
I don't understand why this is necessary. Perhaps I am overlooking or mistaking something. I see this code in AbstractContainer.focusWorker()
(as checked in to bzr right now):
private void focusWorker(boolean direction) { Iterable<Widget<O>> iter = (direction) ? Iterables.directFrom(widgets, current) : Iterables.reverseFrom(widgets, current); if (iter == null) throw new IllegalStateException("Focused widget does not belong to container"); for (Widget<O> widget : iter) { if (checkWidget(widget, direction)) return; } if (parent() != null) { if (direction) parent().nextFocus(); else parent().prevFocus(); return; }
The way I read this, the SubMenu
(which is a subclass of AbstractContainer
) should be the this
when this method is executing. This code should already be able to shift the focus without the parent()
being involved:
for (Widget<O> widget : iter) { if (checkWidget(widget, direction)) return; }
Why is checkWidget()
returning false
for all contained items?
#242 Updated by Greg Shah about 9 years ago
It looks like the Iterables.direct|reverseFrom()
code doesn't implement the "cyclic" nature of looping back around to the beginning of the elements (or vice versa). So that is why you have to add some special code.
I think we do something similar in Frame
too, but I wonder what containers don't need this feature?
I'm fine with your proposed approach unless we determine that our core AbstractContainer
algorithm really needs this feature too.
#243 Updated by Vadim Gindin about 9 years ago
I have z-order difficulty and need your advice. I have 2 nested sub-menus:
Mikki Mouse Rabbit Submenu ┌──────────────────┐ │ Hekkle Berry Fin │ │ Europa -> │ │ Chuk I Gek │ └──────────────────┘
Here "Mikki Mouse" and "Rabbit" are menu-items ans "Submenu" is sub-menu. Sub-menu "Europa" is nested sub-menu of "Submenu". When I choose it and press "Enter" I got the following:
Mikki Mouse Rabbit Submenu ┌ ───┐ │ in │ │ │ │ │ └─ ──┘
"Europa" sub-menu body overlapped "Sub-menu" body somehow and affects it. If I'll put "Europa" to 0-position in z-order I'll get the following screen:
Submenu Mikki Mouseubmenu ┌┌─────────────┐───┐ ││ Karl Chapek │in │ │ Hekkle Berry Fi │ │ Chuk I Gek │ └──────────────────┘
As you can see the nested sub-menu is displayed ("Karl Chapek" menu-item) but the order of items in menu and sub-menu is corrupted: "Submenu@" has became first element in menu (was third) and its sub-menu "Europa" has became also first element in "Submenu" body (was second). See earlier screens to compare.
It happened because of z-order implementation in AbstractContainer
: z-order is implemented as the order of elements in widgets
list. So when I added parent().moveToZpos(this, 0)
in SubMenuChuiImpl.showBody
I really changed its places in widgets list and therefore affected the common drawing.
I don't know how to fix this issue. Is it possible to process z-order and drawing as separate widgets list somehow?
I've attached my current changes. Z-order change is in SubMenuChuiImpl.showBody
method. Here is my testcase:
def sub-menu insm menu-item mi0 label "Karl Chapek". def sub-menu sm menu-item mi1 label "Hekkle Berry F&in". sub-menu insm label "Europa". menu-item mi2 label "Chuk I Gek". def menu m menubar menu-item mi label "&Mikki Mouse". menu-item mmi label "Rabbi&t" ACCELERATOR "PAGE-DOWN". sub-menu sm label "Subm&enu". assign current-window:menubar = menu m:handle. wait-for choose of menu-item mi.
#245 Updated by Constantin Asofiei about 9 years ago
Vadim, about your update:
SubMenuChuiImpl
- draw: why are you raising a PaintEvent there? When draw() is called, is too late to capture and process these events, as the current event processing loop has already finished
- calcLocation: I think your z-order problem is related to this; each time location() is called, you recompute it based on the widget's place in the parent's widget list. As the z-order changes, the location changes... which is not correct. You need to layout the menu once, and save the computed location in the AbstractWidget.origin field.
Same with dimension: I think this is set once during initial layout, and if the menu's text changes to something else, the width will not get readjusted. Please test and confirm this.
#246 Updated by Vadim Gindin about 9 years ago
Constantin Asofiei wrote:
- draw: why are you raising a PaintEvent there? When draw() is called, is too late to capture and process these events, as the current event processing loop has already finished
I've removed this. Just missed earlier.
- calcLocation: I think your z-order problem is related to this; each time location() is called, you recompute it based on the widget's place in the parent's widget list. As the z-order changes, the location changes... which is not correct. You need to layout the menu once, and save the computed location in the AbstractWidget.origin field.
I'm working on that - looking for appropriate location. It really helps: the order is not changed now, but adding of parent().moveToZpos(this, 0);
stopped help. I got the following screen when trying to display nested sub-menu:
Mikki Mouse Rabbit Submenu ┌ ───┐ │ in │ │ │ │ │ └─ ──┘
So my problem with z-order is stayed unsolved. Could you advice me something?
Same with dimension: I think this is set once during initial layout, and if the menu's text changes to something else, the width will not get readjusted. Please test and confirm this.
You're rigth. Sub-menu width is not recalculated when its menu-item width is being changed. New title is shrinked to sub-menu width:
Submenu Mikki Mouse ┌──────────────────┐ │ Hekkle Berry Fin │ │ Uk-co -> │ │ 12345678901234567 └──────────────────┘
More, after sub-menu is closed remained part of changed menu-item title is stayed as artifact:
Submenu Mikki Mouse 8901234567890123456789
If I'll open sub-menu once again: this artifact unions with sub-menu:
Submenu Mikki Mouse ┌──────────────────┐ │ Hekkle Berry Fin │ │ Uk-co -> │ │ 123456789012345678901234567890123456789 └──────────────────┘
Note, that I set new menu-item title to
0123456789012345678901234567890123456789
and the first letter 0
is not displayed for some reason. It is being overriden by toggle-box symbol (" " or ">"). Strange..#247 Updated by Constantin Asofiei about 9 years ago
Vadim Gindin wrote:
So my problem with z-order is stayed unsolved. Could you advice me something?
Please use the widget browser to check the runtime values for the menu (location, dimension, visibility, etc). It will help you walk the menu tree more easily.
Otherwise, debug the invalidation rectangles collected by ScreenBitmap and see which PaintEvent gets ignored and which get collected; AbstractContainer.draw is the main entry point of drawing, so debug this and check how the drawing gets performed.
When something like you posted happens, usually there is a problem in the invalidation rectangle collected in ScreenBitmap (wrong coordinates, cleared to early) or the drawing coordinates are wrong.
#248 Updated by Vadim Gindin about 9 years ago
I've tried to add JVM option "-Dwidgetbrowser", but WidgetBrowser
wasn't show. I suspect that WidgetBrowserAspect
is not configured. Where it should be configured?
#249 Updated by Constantin Asofiei about 9 years ago
Vadim Gindin wrote:
I've tried to add JVM option "-Dwidgetbrowser", but
WidgetBrowser
wasn't show. I suspect thatWidgetBrowserAspect
is not configured. Where it should be configured?
The correct option is -Dwidgetbrowser=yes
.
#250 Updated by Vadim Gindin about 9 years ago
This variant also don't work. WidgetBrowserAspect.onWidgetDrawn
is not called at all. I didn't find something about WidgetBrowser in docs.
#251 Updated by Constantin Asofiei about 9 years ago
Vadim Gindin wrote:
This variant also don't work.
WidgetBrowserAspect.onWidgetDrawn
is not called at all. I didn't find something about WidgetBrowser in docs.
In ChUI the widgets are not highlighted - just inspect the table with the widget's config state (dimension, location, etc).
#252 Updated by Vadim Gindin about 9 years ago
Constantin, thank you for help!
Yesterday I fixed nested sub-menu drawing. Now It is shown, but also with an error:
Mikki Mouse Rabbit Submenu ┌──────────────────┐ │ Hekkle Berry Fin │ │ Europa -> │ │ Chuk I Gek───┐ │ └─│ Karl Chapek │──┘ └─────────────┘
As you can see the last menu-item "Chuk I Gek" is drawn over "Europa" sub-menu body shown. I'll work on it later.
Now I'm working on the next focus error. In sub-menu "Submenu" focus is drawn incorrectly: when I'm press down-array from menu-item "Hekkle Berry Fin", sub-menu "Europa" is now shown highlighted in spite of the fact, that it gains the focus. Also "Hekkle Berry Fin" still stays highlighted in spite of the fact, that it looses focus. I'm trying to find out, why it happens. I want to clarify some moments:
1. screen().at(..)
calls take a Point
as argument. Does this point must be in absolute coordinates? In my case coordinates are absolute and hasFocus()
return correct values. So at this moment I don't have suspects.
2. During menu-items traversal at some moment I got the message "Procedure complete. Press space bar to continue" and application closes. Logs do not contain errors. Does it mean that some uncaught exception happen, that causes application quit or there could be some other reason?
Thank you
#254 Updated by Constantin Asofiei about 9 years ago
Vadim Gindin wrote:
Now I'm working on the next focus error. In sub-menu "Submenu" focus is drawn incorrectly: when I'm press down-array from menu-item "Hekkle Berry Fin", sub-menu "Europa" is now shown highlighted in spite of the fact, that it gains the focus. Also "Hekkle Berry Fin" still stays highlighted in spite of the fact, that it looses focus. I'm trying to find out, why it happens.
This may be some redrawing issue. Check if when focus is lost/gained a repaint is performed and if so, from where it is done (if it's done in an eventDrawingBracket or not).
1.
screen().at(..)
calls take aPoint
as argument. Does this point must be in absolute coordinates? In my case coordinates are absolute andhasFocus()
return correct values. So at this moment I don't have suspects.
Yes, screen().at()
requires absolute coordinates.
2. During menu-items traversal at some moment I got the message "Procedure complete. Press space bar to continue" and application closes. Logs do not contain errors. Does it mean that some uncaught exception happen, that causes application quit or there could be some other reason?
Usually when there is a hidden abend the client just terminates, so I doubt it was an abend. I think for some reason, your event processing loop decides to finish early.
#255 Updated by Vadim Gindin about 9 years ago
- File vig_upd20150329a.zip added
I'm working on unexpected end error:
Constantin Asofiei wrote:
..
2. During menu-items traversal at some moment I got the message "Procedure complete. Press space bar to continue" and application closes. Logs do not contain errors. Does it mean that some uncaught exception happen, that causes application quit or there could be some other reason?
Usually when there is a hidden abend the client just terminates, so I doubt it was an abend. I think for some reason, your event processing loop decides to finish early.
I still didn't find solution. I suspect that it can happen because of TransactionManager
logic (lines 2271-2274):
if (globalTerm) { processFinalizables(wa, wa.globalBlock, false); }
At some moment
globalTerm
became true
and processFinalizables
is called here. globalTerm
can become true only in one place (line 2212):boolean globalTerm = (wa.blocks.size() == 1);
So by some reason it starts to think that procedure body block is finished and it pops it from the TransactionManager.WorkArea.blocks
stack. What can it mean? May be I'm working with scopes incorrectly? I mean my procedure does not contain frames at all, only menubar. See it in the note #243.
I'm attaching my update just for the case when it can be useful. Don't review it for improvements yet.
#256 Updated by Greg Shah about 9 years ago
If you are using the testcase from note 243, then I wonder if a CHOOSE
event is (accidentally?) being raised for menu-item mi
. If so, then the WAIT-FOR
would return and the procedure would end.
#257 Updated by Vadim Gindin about 9 years ago
Strange behavior for MENU-DROP event.
This event is sent when sub-menu (or pop-up menu) is dropped down. I've wrote simple case and trigger for that event, that outputs the string "menu-drop":
def sub-menu sm menu-item mism label "1984". menu-item mism1 label "John Fowles" toggle-box. def menu m menubar sub-menu ssm label "Orwell". menu-item qqq label "qqq". on menu-drop of sub-menu sm message "menu-drop". assign current-window:menubar = menu m:handle. wait-for choose of menu-item qqq.
As a result the string "menu-drop" was printed twice. It looks like trigger works not only when sub-menu is dropped but when first item gaining a focus. What do you think?
#258 Updated by Vadim Gindin about 9 years ago
The question about sub-menu width.
Constantin, you wrote, that I should set dimension field AbstractContainer.size
when layouting sub-menu. In my current implementation sub-menu has title and body, i.e. body is not a separate component. So width and height of sub-menu depends on its state: whether body is visible or not. So what to do when body is being shown or being hidden? Should I change that field: AbstractContainer.size
?
By the way, why AbstractContainer.dimension()
creates new Dimension
instead of returning AbstractContainer.size
? That probably confused me at start of implementation.
#259 Updated by Constantin Asofiei about 9 years ago
Vadim Gindin wrote:
Strange behavior for MENU-DROP event.
This event is sent when sub-menu (or pop-up menu) is dropped down. I've wrote simple case and trigger for that event, that outputs the string "menu-drop":
[...]
I can't run this test on lindev01, I get this error:
│DEFINE sub-menu ssm statement missing. (3554) │ │ │** Could not understand line 5. (196) │
#260 Updated by Constantin Asofiei about 9 years ago
Vadim Gindin wrote:
The question about sub-menu width.
Constantin, you wrote, that I should set dimension fieldAbstractContainer.size
when layouting sub-menu. In my current implementation sub-menu has title and body, i.e. body is not a separate component. So width and height of sub-menu depends on its state: whether body is visible or not. So what to do when body is being shown or being hidden? Should I change that field:AbstractContainer.size
?
I don't understand why you need to change the size when the body is shown/hidden. The correct way of showing/hiding a widget is set its visible
flag to true or false. Relying on the widget's size to draw/not to draw it doesn't look good.
There are two reasons:By the way, why
AbstractContainer.dimension()
creates newDimension
instead of returningAbstractContainer.size
? That probably confused me at start of implementation.
- you don't want to expose the
size
instance to other code, as you will lose control over it. The only way to change it is via the setWidth/Height APIs - the width() and height() APIs can be overridden by sub-classes to return some custom value, thus the
size
field may not be in sync with what these methods return
#261 Updated by Vadim Gindin about 9 years ago
Constantin Asofiei wrote:
Vadim Gindin wrote:
Strange behavior for MENU-DROP event.
This event is sent when sub-menu (or pop-up menu) is dropped down. I've wrote simple case and trigger for that event, that outputs the string "menu-drop":
[...]I can't run this test on lindev01, I get this error:
[...]
It is just my misprint in sub-menu reference. Sorry. Fixed:
def sub-menu sm menu-item mism label "1984". menu-item mism1 label "John Fowles" toggle-box. def menu m menubar sub-menu sm label "Orwell". menu-item qqq label "qqq". on menu-drop of sub-menu sm message "menu-drop". assign current-window:menubar = menu m:handle. wait-for choose of menu-item qqq.
#262 Updated by Vadim Gindin about 9 years ago
Constantin Asofiei wrote:
Vadim Gindin wrote:
The question about sub-menu width.
Constantin, you wrote, that I should set dimension fieldAbstractContainer.size
when layouting sub-menu. In my current implementation sub-menu has title and body, i.e. body is not a separate component. So width and height of sub-menu depends on its state: whether body is visible or not. So what to do when body is being shown or being hidden? Should I change that field:AbstractContainer.size
?I don't understand why you need to change the size when the body is shown/hidden. The correct way of showing/hiding a widget is set its
visible
flag to true or false. Relying on the widget's size to draw/not to draw it doesn't look good.
Hiding sub-menu body doesn't mean hiding sub-menu itself. Sub-menu body is not a separate widget. In my procedure sub-menu widget will consist of label "Orwell" and body with menu-items "1984" and "John Fowles". At least that was my approach at this moment. Do you advice me to assume that visible
flag in my case will control only body visibility?
There are two reasons:By the way, why
AbstractContainer.dimension()
creates newDimension
instead of returningAbstractContainer.size
? That probably confused me at start of implementation.
- you don't want to expose the
size
instance to other code, as you will lose control over it. The only way to change it is via the setWidth/Height APIs- the width() and height() APIs can be overridden by sub-classes to return some custom value, thus the
size
field may not be in sync with what these methods return
I've seen a contradiction here in the following circumstance: if I will override width()
and height()
methods in my sub-class, than AbstractContainer.dimension()
method will return the other dimension than stored in size
field. That was happen for me because I intuitively overridden width()
, height()
and dimension()
methods so It happens my implementation doesn't use AbstractContainer.size
field at all.
#263 Updated by Constantin Asofiei about 9 years ago
Vadim Gindin wrote:
Hiding sub-menu body doesn't mean hiding sub-menu itself. Sub-menu body is not a separate widget. In my procedure sub-menu widget will consist of label "Orwell" and body with menu-items "1984" and "John Fowles". At least that was my approach at this moment. Do you advice me to assume that
visible
flag in my case will control only body visibility?
I think you need to split the sub-menu and its body into separate widgets. Check how the DropDown class works with the ComboBox widget in P2J.
If I understand correctly, currently the SubMenu class is responsible for drawing both the sub-menu's text and it's body, in case is activated, correct?
I've seen a contradiction here in the following circumstance: if I will override
width()
andheight()
methods in my sub-class, thanAbstractContainer.dimension()
method will return the other dimension than stored insize
field. That was happen for me because I intuitively overriddenwidth()
,height()
anddimension()
methods so It happens my implementation doesn't useAbstractContainer.size
field at all.
Why do you need to override dimension() too - doesn't this give the same values as width() and height(), in the SubMenuChuiImpl class?
#264 Updated by Vadim Gindin about 9 years ago
Constantin Asofiei wrote:
I think you need to split the sub-menu and its body into separate widgets. Check how the DropDown class works with the ComboBox widget in P2J.
I already did it earlier. See note #225. There some differences. The main difference is a sub-tree of components corresponds the source sub-tree. DropDown contains not components but strings. Sure some analogy could be implemented, but I'll have to change all my client implementation but there is no time for that.
If I understand correctly, currently the SubMenu class is responsible for drawing both the sub-menu's text and it's body, in case is activated, correct?
Yes.
Why do you need to override dimension() too - doesn't this give the same values as width() and height(), in the SubMenuChuiImpl class?
It just happen in evaluational manner. I think I can get rid of it.
#265 Updated by Vadim Gindin about 9 years ago
Yesterday I worked on some unusual focusing behavior. When some sub-menu is dropped down first time, its first element gains a focus, but when sub-menu is dropped down second and other times - first element does not gain a focus. I thought that when sub-menu body becomes hidden its focus is reset to null and do not reinitialized next time.
I fixed this behavior except one interesting moment: at the second and following dropping down of sub-menu body there are message "Press space bar to continue." appears in the status/message area:
Orwell qqq ┌───────┐ │ sm -> │ └─┌──────────────┐ │ 1984 │ │ John Fowles │ └──────────────┘ 1984 menu-drop Press space bar to continue.
Here is my testcase:
def sub-menu sm menu-item mism label "1984". menu-item mism1 label "John Fowles" toggle-box. def sub-menu ssm sub-menu sm label "sm". def menu m menubar sub-menu ssm label "Orwell". menu-item qqq label "qqq". on choose of menu-item mism message "1984". on menu-drop of sub-menu sm message "menu-drop". assign current-window:menubar = menu m:handle. wait-for choose of menu-item qqq.
I've tested this case again and found that it is related to triggers. Note that there are 2 triggers are defined. If I'll leave any one of them this peculiarity will gone (first element will gain focus each time sub-menu body is dropped and no messages will be in status/message area).
I've searched our code for this message and found, that it is used in hide* and pause*
methods.
How to test what operation is really used and why and how to correctly implement it?
#266 Updated by Greg Shah about 9 years ago
I would expect that the ThinClient.needPause
flag would possibly be involved. Are you sure this is about the triggers and not about the hiding of the menus? When we hide frames, we pause (just like the 4GL) because the user must have a chance to see the frame before it is hidden. We also do this for down frames when they must scroll some data off (for the same reason that in the 4GL the user is given a chance to see the content). Could you have duplicated this behavior for menus when you copied frame-like behavior?
#267 Updated by Vadim Gindin about 9 years ago
Greg Shah wrote:
I would expect that the
ThinClient.needPause
flag would possibly be involved. Are you sure this is about the triggers and not about the hiding of the menus? When we hide frames, we pause (just like the 4GL) because the user must have a chance to see the frame before it is hidden. We also do this for down frames when they must scroll some data off (for the same reason that in the 4GL the user is given a chance to see the content). Could you have duplicated this behavior for menus when you copied frame-like behavior?
If I comment both triggers from previous procedure or only one of them - the message "Press space bar to continue" is gone. So triggers at least influence on this behavior.
As I remember pause in hiding frame causes the user to press some additional key to really hide a frame. In menus cases there are no such effect. It looks like only a message is displayed. On the other side it also can look like Progress makes pause before focusing default (first) menu-item and outputs this message. This scenario is really similar to what you've wrote. Thank you, I'll think about it.
P.S. As I remember I didn't copied frame-like behavior at all. There are no scroll data or other so probably there was no necessity to do that.
#268 Updated by Vadim Gindin about 9 years ago
Another question about pop-up menu hierarchy. Pop-up menu can be assigned for the following widgets: Browse, Button, Combo-box, Dialog-box, Editor, Fill-in, Frame, Radio-set, Selection-list, Slider, Toggle-box, Window. Some of them aren't Container
descendants (for example Button
). It means that I can't call menu.setParent(button)
because of that reason.
The focus methods depend on parent()
method, for example setFocus
, hasFocus
and so on. So these methods will return incorrect/unexpected result for the cases when menu is assigned to simple widget, not a Container. Here is 2 ways to fix this issue:
1. For all possible pop-up menu owners implement Container
interface.
- not fully corresponds to source widgets hierarchy, because menu is assigned to new property popup-menu
not to parent
property
+ focusing should work "from the box" i.e. without additional work.
2. For Menu classes override necessary focus* methods adding owner processing logic there.
- necessity to fix focusing methods to make focusing work.
+ fully corresponds to source widgets hierarchy, because menu is assigned to new property popup-menu
not to parent
property
3. A cardinal way is to show pop-up menus in a separate window, like it happens for AlertBox
Here is some similarity with alert-box. May be it would be simpler.
What do you think?
#269 Updated by Greg Shah about 9 years ago
I think your option 3 is probably the best. The normal focus processing should be "suspended" during menu processing because the user cannot operate outside of the menus without also dismissing the menus. In other words, we are not in the normal tab/back-tab focus processing when menus are being traversed. Keeping a separate window that gets dismissed seems to be a good way to do this. The menu processing doesn't depend on the widget type that is the owner of the popup, right? For this reason, we don't want to put menu-specific logic in those widgets and we want to minimize changes to those widgets.
#270 Updated by Vadim Gindin about 9 years ago
- File vig_upd20150408a.zip added
Here is my current update, intended for your review. The main functionality is working: MENUBAR and POPUP-MENU: drawing, focusing, navigating, events support, toggle-boxes.
Several changes are remained:- I've already implemented option 2 from the note #268 at the moment of your (Greg's) recommendation to use option 3. Have a look and if you will insist I'll correct it. Not too much changes in other widgets.
- I've made pop-up key listener
MenuChuiImpl.PopupKeyListener
intended to be used only for widgets, that support pop-up menus. Is that ok? It used at this moment only forButton
and I'm going to add it to other widgets. - Bug about unexpected end, described in not #255 when during navigation at some moment procedure ends.
- Bug about default focusing and pausing of sub-menu items, described in the note #265.
- Conversion bug of dynamic menu-item creation (setParent reference)
- Drawing disabled menu-item (mnemonic is not underlined after enabling).
- Some other minor navigating and focusing bugs.
Have a look please.
#271 Updated by Greg Shah about 9 years ago
Code Review vig_upd20150408a.zip
1. It seems to me that there is quite a bit of potentially generic functionality that is being implemented in ChUI-specific classes. For example, the MenuChuiImpl
, SubMenuChuiImpl
and@MenuItemChuiImpl@ has key event processing, an event listener and layout processing which may not be specific to ChUI and/or could be made general purpose. By implementing everything in the ChUI layer, you make it much harder to implement GUI.
2. Why are we registering a ChUI-specific class (PopupListener
) in a generic class (ButtonImpl
)? This may just be part of problem 1 above because if the PopupListener
is not ChUI specific then it is not a problem to reference it from ButtonImpl
.
3. I don't think we always want to have the popup listener registered for every button. Shouldn't we only worry about that if the button actually has a popup menu?
4. My biggest concern with the focus processing changes in AbstractContainer
is that it now has logic hard coded that is specific to its own child classes. Usually this is design approach to avoid unless there is no other alternative.
5. Why are you using tc.isChui()
in FocusManager
? That code should not be ChUI-specific.
6. MenuItemConfig.setModified()
doesn't actually save the modified flag itself. Shouldn't it do the same thing as BaseConfig.setModified()
? And I wonder if setModified()
should really be implemented at WidgetConfig
instead?
7. I'm wondering if the menu widgets should inherit from BaseEntity
/BaseConfig
? You are adding support for attributes like color, font, modified... which are already implemented in BaseEntity
.
8. MenuItemConfig.is{Normal|Rule|Skip}()
should not exist in a config class. Please move these to the widget itself.
9. ButtonImpl
, MenuChuiImpl
, SubMenuChuiImpl
, MenuItemChuiImpl
, Menu
, SubMenu
, AbstractContainer
imports should use wildcards.
10. MessageAreaImpl
is missing a history entry.
#272 Updated by Vadim Gindin about 9 years ago
Greg Shah wrote:
Code Review vig_upd20150408a.zip
1. It seems to me that there is quite a bit of potentially generic functionality that is being implemented in ChUI-specific classes. For example, the
MenuChuiImpl
,SubMenuChuiImpl
and@MenuItemChuiImpl@ has key event processing, an event listener and layout processing which may not be specific to ChUI and/or could be made general purpose. By implementing everything in the ChUI layer, you make it much harder to implement GUI.
I hadn't have a goal to make the most of logic in ChUI-specific classes. I'm not sure about location
, dimension
and other related methods, if this logic is generic, but I'll move event processing to base classes. done.
2. Why are we registering a ChUI-specific class (
PopupListener
) in a generic class (ButtonImpl
)? This may just be part of problem 1 above because if thePopupListener
is not ChUI specific then it is not a problem to reference it fromButtonImpl
.
Ok, there are only a different key: ESC-U for ChUI and SHIFT-F10 for GUI. Done.
3. I don't think we always want to have the popup listener registered for every button. Shouldn't we only worry about that if the button actually has a popup menu?
I tried to add the check to initialize
method and to constructors, but I found that popupMenuId
in those places contains not initialized value. So I can't check it there - before adding listener.
4. My biggest concern with the focus processing changes in
AbstractContainer
is that it now has logic hard coded that is specific to its own child classes. Usually this is design approach to avoid unless there is no other alternative.
I'll check it again.
5. Why are you using
tc.isChui()
inFocusManager
? That code should not be ChUI-specific.
Removed.
6.
MenuItemConfig.setModified()
doesn't actually save the modified flag itself. Shouldn't it do the same thing asBaseConfig.setModified()
? And I wonder ifsetModified()
should really be implemented atWidgetConfig
instead?
done.
7. I'm wondering if the menu widgets should inherit from
BaseEntity
/BaseConfig
? You are adding support for attributes like color, font, modified... which are already implemented inBaseEntity
.
There were several reasons: BaseConfig
contains many attributes that are not used in menu widgets, some attributes like parent are used differently in menus; and some other reasons.
8.
MenuItemConfig.is{Normal|Rule|Skip}()
should not exist in a config class. Please move these to the widget itself.
done.
9.
ButtonImpl
,MenuChuiImpl
,SubMenuChuiImpl
,MenuItemChuiImpl
,Menu
,SubMenu
,AbstractContainer
imports should use wildcards.
done.
10.
MessageAreaImpl
is missing a history entry.
done.
I'll post update later.
#273 Updated by Vadim Gindin about 9 years ago
The question about conversion bug with handles. Lets look at the following procedure:
def menu m. def var mi as handle. create menu-item mi assign parent = menu m:handle label = "Dynamic mi".
Here we have menu reference: menu m
. We should get the attribute "handle" value from this reference. This attribute is unusual. I expect that this attribute "handle" reference should be converted to m.asWidgetHandle()
as in case of any other widget type. Am I right? It doesn't work at this moment and I can't find where it is processed in rules. Could you help me?
#274 Updated by Greg Shah about 9 years ago
Search on prog.kw_handle
in methods_attributes.rules
. There are places there where we emit a special accessor to get the handle from a system handle. There is also the location with this:
<!-- let it have a methodText, so that it can emit to readOnlyError, when is on the left-side of an assignment. else, it will be ignored. --> <rule>ftype == prog.kw_handle and isAssign <action>hwrap = ""</action> <action>methodText = "readOnlyError"</action> </rule>
This ignores the hw_handle
for the common case because generally we pass around the widget/resource itself and not a handle. A handle
type can be directly assigned (using assign()
) from a resource instance and we are trying to avoid extra layers of wrapping/unwrapping.
Even assigning the parent of a widget is done using setParent(GenericWidget> widget)
in BaseEntity
, bypassing the need to wrap the widget in a handle
. For instances that are already a handle
(like a handle variable), we have setParentHandle(handle)
.
We do have some special cases where we emit frames using the CommonFrame
interface instead of emitting an asWidget()
accessor. But for non-frame widgets generally we just emit the widget's accessor (set in frame_scoping.rules
). The widget reference itself is emitted in widget_references.rules
. Menus don't have a frame-id annotation, so they get bypassed by this code.
You have menu-specific code in widget_references.rules
that will probably need updates.
#275 Updated by Vadim Gindin about 9 years ago
From time to time I'm facing with the following conversion problem. Look at the following procedure:
def button b. def frame f b. def var h as widget-handle. assign h = b:handle.
I'm getting the following error when trying to convert this procedure:
------------------------------------------------------------------------------ Code Conversion Annotations ------------------------------------------------------------------------------ Optional rule set [customer_specific_annotations_prep] not found. ./menu/but_handle.p EXPRESSION EXECUTION ERROR: --------------------------- throwException(sprintf(spec, bufname, reftype), this) ^ { Cannot find buffer named p2j_test.book_p2j_test.book for ref type 21! [FIELD_INT id <257698037802> 0:0] } --------------------------- Elapsed job time: 23:00:00.810 ERROR: java.lang.RuntimeException: ERROR! Active Rule: ----------------------- RULE REPORT ----------------------- Rule Type : WALK Source AST: [ book-id ] BLOCK/STATEMENT/DEFINE_FRAME/FORM_ITEM/FIELD_INT/ @0:0 {257698037802} Copy AST : [ book-id ] BLOCK/STATEMENT/DEFINE_FRAME/FORM_ITEM/FIELD_INT/ @0:0 {257698037802} Condition : throwException(sprintf(spec, bufname, reftype), this) Loop : false --- END RULE REPORT --- at com.goldencode.p2j.pattern.PatternEngine.run(PatternEngine.java:1006) at com.goldencode.p2j.convert.ConversionDriver.processTrees(ConversionDriver.java:973) at com.goldencode.p2j.convert.ConversionDriver.back(ConversionDriver.java:834) at com.goldencode.p2j.convert.ConversionDriver.main(ConversionDriver.java:1799) Caused by: com.goldencode.expr.ExpressionException: Expression execution error @1:1 [FIELD_INT id=257698037802] at com.goldencode.p2j.pattern.AstWalker.walk(AstWalker.java:225) at com.goldencode.p2j.pattern.AstWalker.walk(AstWalker.java:160) at com.goldencode.p2j.pattern.PatternEngine.apply(PatternEngine.java:1515) at com.goldencode.p2j.pattern.PatternEngine.processAst(PatternEngine.java:1413) at com.goldencode.p2j.pattern.PatternEngine.processAst(PatternEngine.java:1361) at com.goldencode.p2j.pattern.PatternEngine.run(PatternEngine.java:974) ... 3 more Caused by: com.goldencode.expr.ExpressionException: Expression execution error @1:1 at com.goldencode.expr.Expression.execute(Expression.java:434) at com.goldencode.p2j.pattern.Rule.apply(Rule.java:401) at com.goldencode.p2j.pattern.Rule.executeActions(Rule.java:640) at com.goldencode.p2j.pattern.Rule.coreProcessing(Rule.java:609) at com.goldencode.p2j.pattern.Rule.apply(Rule.java:440) at com.goldencode.p2j.pattern.Rule.executeActions(Rule.java:640) at com.goldencode.p2j.pattern.Rule.coreProcessing(Rule.java:609) at com.goldencode.p2j.pattern.Rule.apply(Rule.java:440) at com.goldencode.p2j.pattern.Rule.executeActions(Rule.java:640) at com.goldencode.p2j.pattern.Rule.coreProcessing(Rule.java:609) at com.goldencode.p2j.pattern.Rule.apply(Rule.java:440) at com.goldencode.p2j.pattern.Rule.executeActions(Rule.java:640) at com.goldencode.p2j.pattern.Rule.coreProcessing(Rule.java:609) at com.goldencode.p2j.pattern.Rule.apply(Rule.java:440) at com.goldencode.p2j.pattern.RuleContainer.apply(RuleContainer.java:530) at com.goldencode.p2j.pattern.RuleSet.apply(RuleSet.java:1) at com.goldencode.p2j.pattern.AstWalker.walk(AstWalker.java:212) ... 8 more Caused by: com.goldencode.p2j.pattern.CommonAstSupport$UserGeneratedException: Cannot find buffer named p2j_test.book_p2j_test.book for ref type 21! [FIELD_INT id <257698037802> 0:0] at com.goldencode.p2j.pattern.CommonAstSupport$Library.throwException(CommonAstSupport.java:2227) at com.goldencode.expr.CE3328.execute(Unknown Source) at com.goldencode.expr.Expression.execute(Expression.java:341) ... 24 more
Because of some reason b
is treated as FIELD_INT. Lets look at corresponding AST:
<ast col="0" id="257698037767" line="0" text="statement" type="STATEMENT"> <annotation datatype="java.lang.Boolean" key="reachable" value="true"/> <ast col="1" id="257698037768" line="3" text="def" type="DEFINE_FRAME"> <annotation datatype="java.lang.Boolean" key="reachable" value="true"/> <ast col="11" id="257698037771" line="3" text="f" type="SYMBOL"> <annotation datatype="java.lang.Boolean" key="reachable" value="true"/> </ast> <ast col="13" id="257698037774" line="3" text="b" type="TABLE"> <annotation datatype="java.lang.String" key="schemaname" value="p2j_test.book"/> <annotation datatype="java.lang.String" key="bufname" value="p2j_test.book"/> <annotation datatype="java.lang.String" key="dbname" value="p2j_test"/> <annotation datatype="java.lang.Long" key="recordtype" value="12"/> <annotation datatype="java.lang.Boolean" key="reachable" value="true"/> </ast> </ast> </ast>
b
ast node has type "TABLE"..
Here is the *.parser file:
block [BLOCK] @0:0 statement [STATEMENT] @0:0 def [DEFINE_BUTTON] @1:1 b [SYMBOL] @1:12 statement [STATEMENT] @0:0 def [DEFINE_FRAME] @3:1 f [SYMBOL] @3:11 b [TABLE] @3:13 statement [STATEMENT] @0:0 def [DEFINE_VARIABLE] @5:1 h [SYMBOL] @5:9 as [KW_AS] @5:11 widget-handle [KW_WID_HAND] @5:14 statement [STATEMENT] @0:0 assign [KW_ASSIGN] @7:1 = [ASSIGN] @7:10 h [VAR_HANDLE] @7:8 expression [EXPRESSION] @0:0 : [COLON] @7:13 b [WID_BUTTON] @7:12 handle [ATTR_HANDLE] @7:14
b
here has also type "TABLE". It looks like parser problem..
I faced with this error before with other procedures. Could you try to convert this procedure? Will you get the same error?
#276 Updated by Constantin Asofiei about 9 years ago
This is a problem with the name resolution: in 4GL, a table can be abbreviated using only the first letter, so a find first b.
will find you the first book. I think P2J is too aggressive when resolving these names; looks like 4GL looks into table names only if the name is used in a context where a table name is needed (i.e. find first b.
). The define button b.
is not a context where a table can be used, so the button will be created in 4GL.
For now, go around this problem by renaming your button to something else (i.e define button btn.
).
#277 Updated by Vadim Gindin about 9 years ago
Greg, I've fixed "handle" problem for menu as you advised. Now assign mi:parent = menu m:handle
is converted to mi.unwrapWidget().setParentHandle(m.getSelf().asWidgetHandle());
. Is it right way or you would want that I'll emit mi.unwrapWidget().setParent(m.getSelf())
?
#278 Updated by Greg Shah about 9 years ago
mi.unwrapWidget().setParent(m.getSelf())
seems best. It is also more consistent with the approach we use for the rest of the widgets.
#279 Updated by Vadim Gindin about 9 years ago
What is <shadow-node .. />
in AST tree?
#280 Updated by Vadim Gindin about 9 years ago
I made the test procedure that is similar to mine. This procedure creates dynamic frame widget (FillIn) and tries to assign a parent attribute of it:
def var somstr as char. def frame f somstr. def var ch as handle. create fill-in ch. assign ch:parent = frame f:first-child.
ch
is usual frame-level widget and for ch
the last statement is converted also as "setParentHandle": ch.unwrapWidget().setParentHandle(fFrame.getFirstChild());
Converted class also has compile error here because fFrame.getFirstChild()
returns GenericWidget
. So It seems that frame widgets do not process parent
attribute somehow separately than other attributes. I also didn't find such rules for frame widgets.
--
setParentHandle
method is emitted in /rules/convert/method_attributes.rules
, line 2673:
<rule>ftype == prog.kw_parent <action>methodText = "getParentHandle"</action> <rule>isAssign <action>methodText = "setParentHandle"</action> </rule> </rule>
I tried to paste some AST type specific logic here to emit "setParent" instead of "setParentHandle" here when widget is a menu-item or sub-menu, but I faced with a problem (see below). Here is the AST sub-tree of the last assignment statement.
<ast col="0" id="249108103209" line="0" text="statement" type="STATEMENT"> <ast col="1" id="249108103210" line="10" text="assign" type="KW_ASSIGN"> <annotation datatype="java.lang.Boolean" key="bracket" value="false"/> <ast col="18" id="249108103213" line="10" text="=" type="ASSIGN"> <annotation datatype="java.lang.Long" key="peerid" value="253403070504"/> <ast col="10" id="249108103216" line="10" text=":" type="COLON"> <ast col="8" id="249108103217" line="10" text="mi" type="VAR_HANDLE"> <annotation datatype="java.lang.Long" key="oldtype" value="2400"/> <annotation datatype="java.lang.Long" key="refid" value="249108103191"/> <annotation datatype="java.lang.Long" key="peerid" value="253403070506"/> </ast> <ast col="11" id="249108103219" line="10" text="parent" type="ATTR_HANDLE"> <annotation datatype="java.lang.Long" key="oldtype" value="1864"/> </ast> </ast> <ast col="0" id="249108103221" line="0" text="expression" type="EXPRESSION"> <ast col="31" id="249108103222" line="10" text=":" type="COLON"> <ast col="20" id="249108103223" line="10" text="sub-menu" type="KW_SUB_MENU"> <ast col="29" id="249108103226" line="10" text="sm" type="WID_SUB_MENU"> <annotation datatype="java.lang.String" key="first-menu-path" value="m"/> </ast> </ast> <ast col="32" id="249108103228" line="10" text="handle" type="ATTR_HANDLE"> <annotation datatype="java.lang.Long" key="oldtype" value="1467"/> </ast> </ast> </ast> </ast>
As you can see from AST mi
has type VAR_HANDLE. The piece of source menu procedure:
create menu-item mi. assign mi:parent = sub-menu sm:handle.
I tried to find a way to get a real widget type from a handle "mi" but unsuccessfully. "refid" annotation only references to a shadow-node in the bottom of tree. "oldtype" is a SYMBOL.
Conclusion.
As a result I didn't find how "parent" attribute is process for frame-level widgets and I also can't define real widget type from menu-item handle "mi" to paste type specific logic in a rule that emits "setParentHandle". More, I found that the analogue procedure also converted with compile error and with "setParentHandle". Could you help me?
#281 Updated by Vadim Gindin about 9 years ago
The question about mnemonic bug. Mnemonic is a char in the menu-item title that is a menu-item hot-key. It is specified as a character following after '&' symbol in a title. For example, assume we have "Me&nu item" menu-item. So mnemonic for this menu-item is 'n'. If '&' is not specified, than the first symbol is assumed as mnemonic, i.e. 'M' in this example.
There are non-obvious behavior of disabled
flag. If menu-item is initially defined with this flag, than Progress assumes, that mnemonic is default (first character) even if '&' is specified in a menu-item title. In other words, if "Me&nu item" is defined as following menu-item mi label "Me&nu item" disabled
, than Progress will not see 'n' it will assume the first letter 'M' as mnemonic independently of real "disabled" state in runtime, i.e. even we will enable menu-item in runtime.
Moreover in this case menu-item will be drawn as follows Me&nu item
without focus, and _Menu item
with focus.
I'll probably need additional state attribute in config class, for example "initialDisabled" and set it only during construction. I'll also find a right place where it happens (only construction place). What place it could be? I thought that I'll create a separate method setDisabled
that will be emitted only from rules and will not be called from any other place. What do you think?
#282 Updated by Greg Shah about 9 years ago
Vadim Gindin wrote:
What is
<shadow-node .. />
in AST tree?
These are nodes that store hidden tokens like whitespace and comments. They do not get walked in most cases so they generally can be ignored.
#283 Updated by Greg Shah about 9 years ago
As you can see from AST mi has type VAR_HANDLE.
That is as it should be. mi
is really a reference to a handle variable, right?
I tried to find a way to get a real widget type from a handle "mi" but unsuccessfully.
Handles can contain anything, even non-widgets. It is something that is only known at runtime. You can't reliably determine widget type from a handle var in the tree.
"refid" annotation only references to a shadow-node in the bottom of tree.
This part is strange. It should be referencing the original define variable
statement.
Please confirm this.
However, this would still not solve your problem since it will just tell you that the var is a handle type.
"oldtype" is a SYMBOL.
This is expected and is OK.
As a result I didn't find how "parent" attribute is process for frame-level widgets and I also can't define real widget type from menu-item handle "mi" to paste type specific logic in a rule that emits "setParentHandle". More, I found that the analogue procedure also converted with compile error and with "setParentHandle". Could you help me?
setParentHandle()
should be used to set the parent when the type is a handle
. When the type is a GenericWidget
, then setParent()
should be used.
We must make all of this the same for menus and for all other widget types, because we can't know what is the type of a handle until runtime.
Constantin is doing some work on widget parent support in #1798. He is unavailable until tomorrow, but will probably have some input for you.
#284 Updated by Greg Shah about 9 years ago
I'll probably need additional state attribute in config class, for example "initialDisabled" and set it only during construction.
Yes, this makes sense.
I'll also find a right place where it happens (only construction place). What place it could be?
This seems like the menu definition itself, right?
I thought that I'll create a separate method setDisabled that will be emitted only from rules and will not be called from any other place. What do you think?
Yes, this makes sense.
#285 Updated by Constantin Asofiei about 9 years ago
- there should be only one
parentId
attribute, now we have one inBaseConfig
and one inMenuItemConfig
. So, why not makeMenuItemConfig
extendBaseConfig
- lots of attributes are duplicated inMenuItemConfig
, besideparentId
. Same forMenuItemWidget
- why not extend fromBaseEntity
, as this already adds support for lots of attributes (parent, dcolor, fgcolor, etc). - about
CommonWiget.get/setParent
- these are for internal usage (as decided in note 239/241/244 of #2068). The conversion rules need to emitget/setParentHandle
, for allPARENT
attribute usage (acting as a getter or setter). If you find a case where thesetParentHandle
receives aCommonWidget
instead of ahandle
, you can add aCommonWidget.setParentHandle(CommonWidget)
version, so the compile works. - when the setter is called, is the widget's responsibility to validate that the argument is a widget of expected type. So doing this work in MenuItemWidget looks OK, but if the same error number (but with different text) is shown when PARENT fails validation (with other widgets), we may want to abstract this in
BaseEntity
orGenericWidget
#286 Updated by Vadim Gindin about 9 years ago
- File vig_upd20150415a.zip added
- Fixes of previous Greg's remarks.
- Fix of parent bug. I added new
setParentHandle
method withCommonWidget
argument. - Fix of the bug with pushDescriptions. Only root menu definition is pushed.
- Fix disabled drawing and focusing bug.
P.S. Constantin, about base classes for config and MenuItemWidget. I can't remember concrete reasons. Can it really be a potential problem? Will you insist to fix it?
#287 Updated by Constantin Asofiei about 9 years ago
Vadim Gindin wrote:
P.S. Constantin, about base classes for config and MenuItemWidget. I can't remember concrete reasons.
Can the reason be related to the fact that menu widgets don't have coordinate/size attributes?
Can it really be a potential problem? Will you insist to fix it?
I don't like it when we repeat things, this is a bad practice which in the long term will bring more harm than good. Plus, if at some point other menu-related attributes are needed (like NAME, WINDOW, etc), we will need to duplicate work across the config instances, instead of having only a central point for them.
An alternative would be to take the fields from SubMenuConfig
and MenuItemConfig
which reside also in BaseConfig
and move them from BaseConfig
to WidgetConfig
, but this would confuse things for BaseEntity
and other classes which inherit directly from GenericWidget
.
You can continue your work without this change for now, but we should find a way to improve this (or if we decide to leave it as is, document this in BaseConfig/BaseEntity/etc so that future readers can find easily that this duplication was done and why).
And some different issues:- you have the
SubMenuConfig.displayed
field: if this is something that the server-side never reads or changes, then mark it astransient
and do not transfer it via applyConfig/writeExternal/readExternal. This will eliminate it from the config auto-sync and will reside only on the client-side. MenuItemConfig.mnemonic
- this is aCharacter
, but you (de)serialize it as nativechar
- if at some point the field becomes null, we will have an unexpected NPE during unboxing.
#288 Updated by Greg Shah about 9 years ago
As I stated in note 271 item 7, I really think that inheriting from BaseEntity
/BaseConfig
does make sense. Otherwise there is too much duplicate code.
Please do go ahead and change this now.
#289 Updated by Vadim Gindin about 9 years ago
- The trigger for sub-menu "sm" is working twice. Why? It prints "menu-drop" string twice first time sub-menu is dropped. Only menu-bar is visible
- Then if I'll choose menu-item "1984" - opened sub-menus become closed. When I'm opening sub-menu "sm" next-time (each next-time), the following happens:
- trigger of sub-menu "sm" prints "menu-drop" first time.
- pause happen with the message in status line: "Press space bar to continue.", sub-menu "sm" becomes opened but no item is focused yet.
- When I press space bar, the trigger of sub-menu "sm" prints "menu-drop" second time and first item of sub-menu "sm" gains focus.
The first question is why the trigger of sub-menu "sm" works twice? It looks like pause
happens between 2 triggers runs. Could you help me to interpret it and find a way to reproduce this behavior?
P.S. I've change base classes of MenuItemWidget and MenuItemConfig to BaseEntity/BaseEntityConfig. But I can't do the same for SubMenu because there are common ancestor of this class and Menu: MenuContainerWidget and those configs are different. MenuConfig does not contain color attributes and other.
Could you help me to interpret it?
#290 Updated by Greg Shah about 9 years ago
P.S. I've change base classes of MenuItemWidget and MenuItemConfig to BaseEntity/BaseEntityConfig. But I can't do the same for SubMenu because there are common ancestor of this class and Menu: MenuContainerWidget and those configs are different. MenuConfig does not contain color attributes and other.
I think the MenuContainerWidget
needs to inherit from BaseEntity
. By the way, the menu widget in the 4GL does in fact support both DCOLOR
and PFCOLOR
. So it seems this is the correct thing to do.
#291 Updated by Constantin Asofiei about 9 years ago
Vadim Gindin wrote:
I'm testing pausing bug from the note №265 and I need help. Here is what I've founded during today's testing.
- The trigger for sub-menu "sm" is working twice. Why? It prints "menu-drop" string twice first time sub-menu is dropped. Only menu-bar is visible
- Then if I'll choose menu-item "1984" - opened sub-menus become closed. When I'm opening sub-menu "sm" next-time (each next-time), the following happens:
- trigger of sub-menu "sm" prints "menu-drop" first time.
- pause happen with the message in status line: "Press space bar to continue.", sub-menu "sm" becomes opened but no item is focused yet.
- When I press space bar, the trigger of sub-menu "sm" prints "menu-drop" second time and first item of sub-menu "sm" gains focus.
Please post your merged code.
#292 Updated by Vadim Gindin about 9 years ago
- File vig_upd20150417a.zip added
Here is my current update.
#293 Updated by Vadim Gindin about 9 years ago
Here it is:
def sub-menu sm menu-item mism label "1984". menu-item mism1 label "John Fowles" toggle-box. def sub-menu ssm sub-menu sm label "sm". def menu m menubar sub-menu ssm label "Orwell". menu-item qqq label "qqq". on menu-drop of sub-menu sm message "menu-drop". on choose of menu-item mism message "1984". on value-changed of menu-item mism1 message "John Fowles". assign current-window:menubar = menu m:handle. wait-for choose of menu-item qqq.
Got from the note №265
#294 Updated by Constantin Asofiei about 9 years ago
- Please check the header for LogicalTerminal, is not merged properly.
- MenuItemWidget - don't add multiple header numbers, if the change is part of the same work.
- MenuItemWidget.setChecked - please ensure that the error message is NOT recorded in the ERROR-STATUS:GET-MESSAGE queue, as you are using displayError. Otherwise, use recordOrShowError with the modal/prefix/isError params set to false. To check this, use the NO-ERROR clause and then check ERROR-STATUS:ERROR/NUM-MESSAGES-GET-MESSAGE
- MenuChuiImpl and others: when you are adding 1/2/3/4 units to the menu's width/location/etc, please add a comment with why this was needed (border, something else?)
- WindowChuiImpl.draw: this code I don't think is ok to be here:
if (config.menubarId != 0) { Widget<ChuiOutputManager> menu = screen().getRegistry().getComponent(config.menubarId); if (menu != null) { if (menu.parent() == null) { getContentPane().add(menu); } menu.setVisible(true); } }
Ifrepaint
posts an event, this can not be captured by the EventManager, as draw is called when the event bracket ends, not during event processing... Shouldn't this better be in the WindowChuiImpl.syncWithConfig ? - please explain why prepParentLocation and childrenLocation are needed: I guess you added this for some menu quirk, correct?
- Menu$PopupKeyListener.onKeyPressed: why not call
menu.repaint()
instead ofmenu.draw
? Is it because the event is not processed in a drawing bracket?
About your testcase: in 4GL, it really seems that the MENU-DROP event is raised twice... are there other type of events for sub-menu which can be caught by a trigger? On a side note, don't forget to check RETURN NO-APPLY, when working with triggers. Also, you can use the SELF and LAST-EVENT handles to check details about the event which invoked the trigger.
Now about your pause issue. When messages are shown in the message area, in ChUI a PAUSE is raised before cleaning up the messages, if both message lines are occupied, but only if the message area is not cleaned up automatically. When the trigger is invoked, the stacktrace is this:
ThinClient.invokeTriggers(Widget, int, boolean) line: 15196 ThinClient.processProgressEvent(Event) line: 14646 ThinClient.processEventsWorker() line: 14085 ThinClient.pop() line: 13164 ThinClient.eventBracket(boolean, Runnable) line: 13147 ThinClient.eventDrawingBracket(Widget<?>, boolean, boolean, Runnable) line: 13073 ThinClient.independentEventDrawingBracket(Widget, Runnable) line: 12972 SubMenuChuiImpl(AbstractWidget<O>).processSystemKey(KeyInput) line: 1625 ThinClient.checkForSystemEvent(KeyInput) line: 12358 ThinClient.waitForEvent(int, boolean, boolean, boolean) line: 12253
I think checkForSystemEvent (or something else?) needs to set the Window.messageNeedPause to true, so that the message area is not automatically cleared by the next MESSAGE stmt...
#295 Updated by Vadim Gindin about 9 years ago
Constantin Asofiei wrote:
About 0417a.zip:
- Please check the header for LogicalTerminal, is not merged properly.
done.
- MenuItemWidget - don't add multiple header numbers, if the change is part of the same work.
done.
- MenuItemWidget.setChecked - please ensure that the error message is NOT recorded in the ERROR-STATUS:GET-MESSAGE queue, as you are using displayError. Otherwise, use recordOrShowError with the modal/prefix/isError params set to false. To check this, use the NO-ERROR clause and then check ERROR-STATUS:ERROR/NUM-MESSAGES-GET-MESSAGE
I've checked it again. Error message is really not recorded to ERROR-STATUS message queue and do not change ERROR-STATUS:ERROR flag.
- MenuChuiImpl and others: when you are adding 1/2/3/4 units to the menu's width/location/etc, please add a comment with why this was needed (border, something else?)
yes, borders and some shifts. done.
- WindowChuiImpl.draw: this code I don't think is ok to be here:
[...]
Ifrepaint
posts an event, this can not be captured by the EventManager, as draw is called when the event bracket ends, not during event processing... Shouldn't this better be in the WindowChuiImpl.syncWithConfig ?
It seems that synWithConfig
is not a good place because when repaint is needed without config changes menu will not be redrawn and will disappear.
- please explain why prepParentLocation and childrenLocation are needed: I guess you added this for some menu quirk, correct?
Yes, you are right. childrenLocation
is the relative location point of children. For the Frame it is the same as location()
of frame itself. bodyLocation
is defined for sub-menu and it returns location of sub-menu body include borders - right under the sub-menu title. Both methods are needed because body is not a separate widget but it is a part of sub-menu.
- Menu$PopupKeyListener.onKeyPressed: why not call
menu.repaint()
instead ofmenu.draw
? Is it because the event is not processed in a drawing bracket?
I've replaced it and it works. done.
...
#296 Updated by Vadim Gindin almost 9 years ago
I'm working on the last founded bug with pause. I've simplified testing procedure as it was possible:
def sub-menu sbm menu-item mii label "iii". def menu m menubar menu-item qqq label "qqq". sub-menu sbm label "Orwell". on menu-drop of sub-menu sbm do: message "menu-drop". display self:type self:name self:label last-event:label. end. assign current-window:menubar = menu m:handle. wait-for choose of menu-item qqq.
This procedure defines MENUBAR with one sub-menu, containing only one menu-item. Only one trigger is defined in this procedure and it is defined for this sub-menu (event: MENU-DROP). I'll analyze how behavior will differ depending on concrete keys, used for opening sub-menu body and closing it. I also added some debug info from self
and last-event
to target "menu-drop" trigger as Constantin advised earlier to find some differences in to subsequent trigger calls.
Action | State, Behavior |
---|---|
Open sub-menu with RETURN, close it with RETURN | no pause, trigger runs twice without stop, body has focused item, last-event:label is "MENU-DROP" |
Open sub-menu with any key, close with LEFT or RIGHT arrow then open with DOWN arrow | pause, sub-menu body stays hidden, "Press space bar to continue" message in the status bar, last-event:label is "MENU-DROP" |
a) I'm pressing space bar | body is shown with menu-item focused, last-event:label is "" |
b) I'm pressing DOWN instead of space bar | body is shown with menu-item focused, last-event:label is "CURSOR-DOWN" |
several times use CURSOR-DOWN to open and LEFT to close (about 4) | see earlier |
same ... | approximately at fifth iteration body starts showing without focus on menu-item (2 pauses), after second pause status area become cleared |
P.S. In both trigger calls all used attributes of SELF or LAST-EVENT are equal, except LAST-EVENT:LABEL, that differs depending on key used to open sub-menu body, so I didn't find the difference between 2 trigger calls.
Questions.- How to duplicate double call of trigger?
- Why actions for RETURN and CURSOR-DOWN keys (used to open sub-menu body) are different? What is the difference?
- What happens after 4 iterations: why sub-menu is shown without focus?
Why this test is so mystical? I'm still don't understand Progress behavior and there for can't implement it. Please help.
#297 Updated by Constantin Asofiei almost 9 years ago
Vadim Gindin wrote:
Questions.
- How to duplicate double call of trigger?
I think you need to explicitly treat this case somewhere in TC.processProgressEvent, so that the event is triggered twice... just post it again into the queue via EventManager.postEvent (check how RETURN NO-APPLY or RETURN ERROR behaves) and it will be processed again. Or, just invoke the trigger again, for MENU-DROP event.
- Why actions for RETURN and CURSOR-DOWN keys (used to open sub-menu body) are different? What is the difference?
You mean why there is no pause on RETURN? I think this might be because RETURN clears some window state, so that when the next message is shown, it no longer needs to do a "pause before cleanup". Or maybe is related to how the menu is exited: are there ENTRY/LEAVE events raised for menus/menu-items/etc?
- What happens after 4 iterations: why sub-menu is shown without focus?
This is because you are using frames. 4GL shows frames in a "top-to-bottom" order. And if the screen is full (no space to show a frame bellow the last displayed frame), then a it starts back from the top, hiding any frame which are intersected - thus a pause is triggered.
For your menu tests, use this version; it avoids using frames and adds some tracking to know surely if an event was raised or not:
def var r as int init 0. def sub-menu sbm menu-item mii label "iii". def menu m menubar menu-item qqq label "qqq". sub-menu sbm label "Orwell". on menu-drop of sub-menu sbm do: message r "menu-drop". def var ch as char. ch = string(r) + " " + self:type + " " + self:name + " " + self:label + " " + last-event:label. put screen row (r mod default-window:screen-lines + 1) col 12 string(ch, "x(60)"). r = r + 1. end. message "bogus message so that the message area is not empty". assign current-window:menubar = menu m:handle. wait-for choose of menu-item qqq.
#298 Updated by Vadim Gindin almost 9 years ago
Constantin Asofiei wrote:
Vadim Gindin wrote:
Questions.
- How to duplicate double call of trigger?
I think you need to explicitly treat this case somewhere in TC.processProgressEvent, so that the event is triggered twice... just post it again into the queue via EventManager.postEvent (check how RETURN NO-APPLY or RETURN ERROR behaves) and it will be processed again. Or, just invoke the trigger again, for MENU-DROP event.
Ok.
RETURN NO-APPLY doesn't affect behavior: body is shown as it is when trigger used without RETURN NO-APPLY.
RETURN ERROR is not permitted in an user interface trigger, so cant be used (leads to error).
- Why actions for RETURN and CURSOR-DOWN keys (used to open sub-menu body) are different? What is the difference?
You mean why there is no pause on RETURN? I think this might be because RETURN clears some window state, so that when the next message is shown, it no longer needs to do a "pause before cleanup". Or maybe is related to how the menu is exited: are there ENTRY/LEAVE events raised for menus/menu-items/etc?
It seems ENTRY/LEAVE events are not raised for menu widgets: I wrote triggers for these events and they wasn't called.
About "no pause on RETURN" strange, but after I ran your procedure, choose sub-menu "Orwell", and pressed Enter - pause happen. At the same moment in my procedure (with frames) there were no pause for RETURN.. Why it could be?
Probably some default state, because the followed RETURN commands are executed without pause. But how to find this default state, that leads to pause?
#299 Updated by Vadim Gindin almost 9 years ago
keycode("MENU-DROP")
is -1. Why?last-event:code
is 1079. What is this? Key codes from 1057 to 1150 correspond to "ALT-plus corresponding character" (as documented in proghand.pdf) Where it is set?
#300 Updated by Vadim Gindin almost 9 years ago
There are some interesting information in langref in the definition of ON statement:
If event-list includes a MENU-DROP event for a menu or submenu, do not interact with the window manager from within the trigger-block. Doing so causes the window manager to lose control of the system, forcing you to reboot or restart the window manager. Actions to avoid include any window system input/output (I/O) or any lengthy processing, especially in statements that cause process interruptions, such as the PAUSE statement with or without I/O. These also include actions that can generate a warning or error message, forcing window system output. Use the NO-ERROR option on supported statements to help avoid this situation. Otherwise, check valid values, especially for run-time resources like widget handles, to prevent Progress from displaying unexpected messages.
What does it mean "interating with the window manager from within the trigger-block"?
#301 Updated by Greg Shah almost 9 years ago
keycode("MENU-DROP")
is -1. Why?
I assume you are describing the 4GL here? I guess the reason is simply that there is no hard coded key on the keyboard that is being pressed to generate this event. I think 4GL generally matches a key code up with a specific keyboard scan code. This is not an event that is tied to a fixed key, so there is no key code.
last-event:code
is 1079. What is this?
Are you talking about the 4GL or P2J?
My understanding is that for events that are not keys or mouse, these are like a "fake" key code that represents the high level event. See Keyboard.eventCode()
in P2J. We have implemented it as the same thing as LASTKEY
. I'm not sure if or how we confirmed that they are equivalent but it is likely to be pretty close. See KeyReader.getLastKey()
.
What does it mean "interating with the window manager from within the trigger-block"?
I'm not exactly sure, but I suspect this means that you should not do anything that causes changes to window visibility, window size or window position. Their description of any window system input/output (I/O)
probably means that one should not display/view/enable/message/pause any content in a window.
It seems to me that the menu-drop event is very special because it occurs in the middle of a complex set of state processing. Progress themselves essentially are telling you to do ALMOST NOTHING in such triggers or else the system can be forced to reboot/restart! In other words, I don't know that we need to duplicate every possible behavior of this event. Please avoid anything in your testcases that uses I/O including the message or pause statements. If you want to just track which menu-drop events have occurred, just store the details of the event into some data structure (e.g. an array) and then "dump" or display this later when the trigger is done.
As long as we provide the basic functionality of this event and match how Progress works in the cases which Progress has documented are safe, then we are OK.
I'll let Constantin respond on the default state question in note 298.
#302 Updated by Vadim Gindin almost 9 years ago
Greg Shah wrote:
keycode("MENU-DROP")
is -1. Why?I assume you are describing the 4GL here? I guess the reason is simply that there is no hard coded key on the keyboard that is being pressed to generate this event. I think 4GL generally matches a key code up with a specific keyboard scan code. This is not an event that is tied to a fixed key, so there is no key code.
Yes I mentioned 4GL. Ok. Are there some artificial events like MENU-DROP, that also have no key?
The problem in this case is the following. I intuitively added MENU-DROP event to Keyboard.evNames1
array. Because of that Keyboard.eventCode("MENU-DROP")
will return concrete value, that depends on index of "MENU-DROP" in evNames1
array in -154
. Now I see that it was wrong because MENU-DROP event has no key (key=-1
).
This key is set to Event
fields such as key, action or, probably, function
and will be used later to lookup trigger. See ThinClient.invokeTriggers(..)
:
TriggerMatch result = new TriggerMatch(evtCode); currentEventList.lookup(frameId, widgetId, true, isKey, result);
This lookup used
evtCode
from result
to lookup trigger.
So, if I'll remove "MENU-DROP" from evNames1
, than ThinClient.invokeTriggers
will not find the trigger assigned for this event. If key is -1 and other int fields of Event will be -1. How to identify that some trigger is assigned exactly to "MENU-DROP" event?
last-event:code
is 1079. What is this?Are you talking about the 4GL or P2J?
My understanding is that for events that are not keys or mouse, these are like a "fake" key code that represents the high level event. See
Keyboard.eventCode()
in P2J. We have implemented it as the same thing asLASTKEY
. I'm not sure if or how we confirmed that they are equivalent but it is likely to be pretty close. SeeKeyReader.getLastKey()
.
How should I implement LAST-EVENT:CODE for MENU-DROP event? Are there some other similar "fake" codes for some other similar event implemented?
What does it mean "interating with the window manager from within the trigger-block"?
I'm not exactly sure, but I suspect this means that you should not do anything that causes changes to window visibility, window size or window position. Their description of
any window system input/output (I/O)
probably means that one should not display/view/enable/message/pause any content in a window.It seems to me that the menu-drop event is very special because it occurs in the middle of a complex set of state processing. Progress themselves essentially are telling you to do ALMOST NOTHING in such triggers or else the system can be forced to reboot/restart! In other words, I don't know that we need to duplicate every possible behavior of this event. Please avoid anything in your testcases that uses I/O including the message or pause statements. If you want to just track which menu-drop events have occurred, just store the details of the event into some data structure (e.g. an array) and then "dump" or display this later when the trigger is done.
Ok, I'll try. Constantin proposed PUT SCREEN
instead of MESSAGE. Don't you know if it uses window manager?
As long as we provide the basic functionality of this event and match how Progress works in the cases which Progress has documented are safe, then we are OK.
Do you mean, that we can stay current implementation as it is implemented this moment? If yes, what about key of MENU-DROP event (see my problem in the beginning of this note)?
I'll let Constantin respond on the default state question in note 298.
#303 Updated by Vadim Gindin almost 9 years ago
I've tried do not use I/O operations in MENU-DROP trigger and accumulate strings in a global array and got the same result as for Constantin procedure. Probably PUT SCREEN do not use window manager. Never mind. I found that "default state" is a pause called from the first message
statement. So it seems that pause prevent menu-item to be focused in dropped down sub-menu body. How to check it that we are "in pause"?
#304 Updated by Greg Shah almost 9 years ago
Are there some artificial events like MENU-DROP, that also have no key?
Yes, everything in Keyboard.evNames1
. These are not real keys, but higher level "functions" (e.g. GO) or higher level events (e.g. MENU-DROP).
The high level functions can actually be assigned to a key (ON F1 GO.
), but higher level events are simply generated by widgets. In both cases there are no key codes involved.
I intuitively added MENU-DROP event to Keyboard.evNames1 array. Because of that Keyboard.eventCode("MENU-DROP") will return concrete value, that depends on index of "MENU-DROP" in evNames1 array in -154.
This all seems fine.
Now I see that it was wrong because MENU-DROP event has no key (key=-1).
Why do you think it was wrong?
So, if I'll remove "MENU-DROP" from evNames1, than ThinClient.invokeTriggers will not find the trigger assigned for this event.
Correct. So don't remove it.
How should I implement LAST-EVENT:CODE for MENU-DROP event? Are there some other similar "fake" codes for some other similar event implemented?
Does the 4GL actually report something useful during the MENU-DROP trigger? What is it?
Ok, I'll try. Constantin proposed PUT SCREEN instead of MESSAGE. Don't you know if it uses window manager?
I don't know, but it is a kind of I/O so I think you should avoid it. As I noted above, can't you just record the state into some procedure-scoped variables and then examine the state later?
Do you mean, that we can stay current implementation as it is implemented this moment? If yes, what about key of MENU-DROP event (see my problem in the beginning of this note)?
Possibly. It depends on whether we are working the same way as the 4GL for the cases that are allowed in the 4GL. We do NOT have to support behavior that is reported by the 4GL as INVALID.
#305 Updated by Vadim Gindin almost 9 years ago
My MENU-DROP trigger is the following:
on menu-drop of sub-menu sbm do: message r "menu-drop". def var ch as char. ch = last-event:label + " " + string(keycode(last-event:label)) + " " + last-event:event-type + " " + string(last-event:code) + " " + last-event:function + " " + last-event:type + " " + string(LASTKEY). outp[r] = ch. r = r + 1. end.
Here is the sample output string for one trigger run:
MENU-DROP -1 PROGRESS 1079 MENU-DROP PSEUDO-WIDGET -1
The first "MENU-DROP" is a last-event:label value (4GL). P2J outputs previous key, for example "CURSOR-DOWN" because of lastKey is not saved for MENU-DROP event. Let's try to look what is happening. Start from ThinClient.processProgressEvent
lines 14487-14496:
// skip developer events U1-U10 if (!Keyboard.isDevEvent(action)) { String evName = Keyboard.eventName(action); this.functionKey = action; if (key != KeyInput.CHAR_UNDEFINED) { this.lastEvent = key; } }
It is a place where last key is saved to
ThinClient.lastEvent
field and it really work only if key
has some value different from KeyInput.CHAR_UNDEFINED
, but for my MENU-DROP event key has exactly this value and so this key is not saved. Why MENU-DROP key equal to KeyInput.CHAR_UNDEFINED
? Have a look at KeyInput
constructor I use to create MENU-DROP event:public KeyInput(Widget src, int id, int key, boolean mode, boolean isKey) { super(src, id); this.key = key; this.eventMode = mode; this.isKey = isKey; actionCode = Keyboard.keyAction(key); if (actionCode == CHAR_UNDEFINED) { actionCode = key; } else if (actionCode < CHAR_UNDEFINED) { // a valid key action is defined; keep the original key code if we // have a real key, or try to "guess" a hypothetical key code that // would correspond the high level event generated by APPLY // statement. int standardCode = isKey ? key : Keyboard.keyCodeForAction(actionCode); if (standardCode != CHAR_UNDEFINED) setKeyCode(standardCode); // do not keep key code as action code if (key == actionCode && actionCode < 0) setKeyCode(CHAR_UNDEFINED); } }
Our
actionCode
is the same as key
and it equal to -154
. You can see in the last if
block of this constructor that key is overridden there for all events with negative actionCode
. That is why -154
is not saved to ThinClient.lastEvent
.
I went further and artificially set key for MENU-DROP event to -154
after constructor is executed and find out that for that last-event:label became "". Why? Have a look at Keyboard.keyLabel()
:
if (code < 0) return ""; ..
As you can see Keyboard.keyLabel()
is also don't work for negative code.
Conclusion:
2 problems "key override in KeyInput constructor" and "keyLabel returns empty string" are happen because of key of MENU-DROP event is negative (-154), and it really is negative because MENU-DROP is added to evNames1
.
#306 Updated by Constantin Asofiei almost 9 years ago
Vadim Gindin wrote:
About "no pause on RETURN" strange, but after I ran your procedure, choose sub-menu "Orwell", and pressed Enter - pause happen. At the same moment in my procedure (with frames) there were no pause for RETURN.. Why it could be?
In your testcase where you were using frame, you didn't have a MESSAGE just before WAIT-FOR. That line was added by me, to check how RETURN behaves when the message area already has some content.
Probably some default state, because the followed RETURN commands are executed without pause. But how to find this default state, that leads to pause?
There are these flags in Window
class, on client-side:
/** * Flag to force message clearing on the next MESSAGE stmt. */ private boolean clearMessage = false; /** *true
if automatic message clearing occurred during trigger * processing.
*/
private boolean autoCleared = false;/** * Separate pause before hide flag for messages.
true
means * pause is due.
*/
private boolean messageNeedPause = false;
They are used to force a pause when the MESSAGE area needs to be cleared, implicitly or explicitly, or to automatically clear the message area. You might need to turn on/off some of these flags, so that in case of RETURN there will be no pause, and in case of other events, there will be a pause, when clearing the message area. I don't know the exact rules for your MENU-DROP case.
#307 Updated by Constantin Asofiei almost 9 years ago
Vadim Gindin wrote:
There are some interesting information in langref in the definition of ON statement:
[...]What does it mean "interating with the window manager from within the trigger-block"?
As Greg noted already, and from the comment above, we should not duplicate behaviour which is not recommended by Progress... so unless you find an easy way to fix the PAUSE statement (when MESSAGE is used), we can add this as a limitation. So, when using MENU-DROP trigger ensure no I/O is used (this includes MESSAGE statement), to avoid implicit PAUSE, for example.
#308 Updated by Greg Shah almost 9 years ago
Here is the sample output string for one trigger run:
MENU-DROP -1 PROGRESS 1079 MENU-DROP PSEUDO-WIDGET -1
I assume this is 4GL output?
If so, then this means that the 4GL is setting a "fake" keycode as 1079 and lastkey is -1. This means you would pass 1079 in as the key to the KeyInput
constructor, right? Of course, it would be best to create a Keyboard.SE_MENU_DROP
"synthetic event" constant that is set to 1079 and then reference that constant. Wouldn't this solve both issues?
You should probably also model your event after other last-event:type = "PROGRESS"
events. See Keyboard.EVENT_TYPES_PG_CODES
, Keyboard.isPGEvent()
.
#309 Updated by Vadim Gindin almost 9 years ago
Greg Shah wrote:
Here is the sample output string for one trigger run:
MENU-DROP -1 PROGRESS 1079 MENU-DROP PSEUDO-WIDGET -1
I assume this is 4GL output?
If so, then this means that the 4GL is setting a "fake" keycode as 1079 and lastkey is -1. This means you would pass 1079 in as the key to the
KeyInput
constructor, right? Of course, it would be best to create aKeyboard.SE_MENU_DROP
"synthetic event" constant that is set to 1079 and then reference that constant. Wouldn't this solve both issues?
I tried that earlier. It breaks trigger search. Trigger search works using the event name from EventDefinition.events
. It calculates event name calling Keyboard.eventName()
that returns "ESC-7". This key label is really corresponds to the key=1079.
You should probably also model your event after other
last-event:type = "PROGRESS"
events. SeeKeyboard.EVENT_TYPES_PG_CODES
,Keyboard.isPGEvent()
.
I've added SE_MENU_DROP there, but this method is utilitarian and is not used in my scenarios.
#310 Updated by Vadim Gindin almost 9 years ago
If so, then this means that the 4GL is setting a "fake" keycode as 1079 and lastkey is -1. This means you would pass 1079 in as the key to the
KeyInput
constructor, right? Of course, it would be best to create aKeyboard.SE_MENU_DROP
"synthetic event" constant that is set to 1079 and then reference that constant. Wouldn't this solve both issues?I tried that earlier. It breaks trigger search. Trigger search works using the event name from
EventDefinition.events
. It calculates event name callingKeyboard.eventName()
that returns "ESC-7". This key label is really corresponds to the key=1079.
It finds "ESC-7" instead of "MENU-DROP" by the key=1079, and that is why it do not find target trigger.
#311 Updated by Vadim Gindin almost 9 years ago
- File vig_upd20150423a.zip added
I didn't find another way beside to make hardcode fix for MENU-DROP event case for LAST-EVENT attributes. All attributes now work except LAST-EVENT:CODE=1079
. In my procedure Progress outputs different values for LAST-EVENT:CODE
and LASTKEY
function, but converted version calls Keyboard.getLastKey()
for both cases. For LASTKEY
it will be Keyboard.lastKey()
, that calls Keyboard.getLastKey()
in turn. We would probably make separate implementation..
Here is my update. Have a look on classes SubMenu, Keyboard, KeyInput
.
#312 Updated by Greg Shah almost 9 years ago
I will look at the code next.
What is left to do to make ChUI menus fully functional?
#313 Updated by Vadim Gindin almost 9 years ago
PAUSE behavior fix is left. The current bug is the following. In Constantin's procedure message "bogus message so that the message area is not empty" is displayed but become hidden after menu is drawn.
After that I'll need to fix that first element if sub-menu "Orwell" will not gain focus first time sub-menu body is drawn because of the pause of message statement.
#314 Updated by Greg Shah almost 9 years ago
Is the pause behavior related to MENU-DROP?
#315 Updated by Vadim Gindin almost 9 years ago
At the first time I met this bug I thought that it is related to MENU-DROP. Now I think it is not related.
#316 Updated by Greg Shah almost 9 years ago
Code Review vig_upd20150423a.zip
This is quite good.
1. In Menu.java
, what is the requirement for import of MenuChuiImpl
and ChuiOutputManager
? Neither of these things should be accessed from the general purpose code in Menu
.
2. I'd like to hear if Constantin has any ideas on how to resolve the MENU-DROP event issue. The KeyInput
/KeyReader
hacks are not good.
3. Do we really want to register the popup key listener for every button or just for the buttons that have a popup menu?
#317 Updated by Constantin Asofiei almost 9 years ago
Vadim Gindin wrote:
If so, then this means that the 4GL is setting a "fake" keycode as 1079 and lastkey is -1. This means you would pass 1079 in as the key to the
KeyInput
constructor, right? Of course, it would be best to create aKeyboard.SE_MENU_DROP
"synthetic event" constant that is set to 1079 and then reference that constant. Wouldn't this solve both issues?I tried that earlier. It breaks trigger search. Trigger search works using the event name from
EventDefinition.events
. It calculates event name callingKeyboard.eventName()
that returns "ESC-7". This key label is really corresponds to the key=1079.It finds "ESC-7" instead of "MENU-DROP" by the key=1079, and that is why it do not find target trigger.
I think MENU-DROP
acts like an OS event, the same way i.e. WINDOW-CLOSE
acts. The same problem was found for the windows events: the event codes are colliding with existing events from the standard key table (see testcases/uast/keyboards/linux-chui.txt
for the standard keys). So a new table was added, Keyboard.osEvents
and Keyboard.osEventCodes
, which has precedence (when searching) over events in the standard key table.
See how the WINDOW-CLOSE event was added and add something similar for the MENU-DROP event.
#318 Updated by Vadim Gindin almost 9 years ago
Constantin Asofiei wrote:
..
I thinkMENU-DROP
acts like an OS event, the same way i.e.WINDOW-CLOSE
acts. The same problem was found for the windows events: the event codes are colliding with existing events from the standard key table (seetestcases/uast/keyboards/linux-chui.txt
for the standard keys). So a new table was added,Keyboard.osEvents
andKeyboard.osEventCodes
, which has precedence (when searching) over events in the standard key table.See how the WINDOW-CLOSE event was added and add something similar for the MENU-DROP event.
I tried this (set SE_MENU_DROP=1079), but for our test procedure it returns:
KEYCODE(LAST-EVENT:LABEL)=1079 LAST-EVENT:CODE=1079 LASTKEY=1079
And Progress outputs:
KEYCODE(LAST-EVENT:LABEL)=-1 LAST-EVENT:CODE=1079 LASTKEY=-1
#319 Updated by Constantin Asofiei almost 9 years ago
Vadim Gindin wrote:
Constantin Asofiei wrote:
..
I thinkMENU-DROP
acts like an OS event, the same way i.e.WINDOW-CLOSE
acts. The same problem was found for the windows events: the event codes are colliding with existing events from the standard key table (seetestcases/uast/keyboards/linux-chui.txt
for the standard keys). So a new table was added,Keyboard.osEvents
andKeyboard.osEventCodes
, which has precedence (when searching) over events in the standard key table.See how the WINDOW-CLOSE event was added and add something similar for the MENU-DROP event.
I tried this (set SE_MENU_DROP=1079), but for our test procedure it returns:
[...]
And Progress outputs:
[...]
I suspect this happens for WINDOW-CLOSE too. In any case, put a comment in P2J's KEYCODE implementation and will fix it some other time (it might be specific to all our registered Keyboard.osEvents).
#320 Updated by Vadim Gindin almost 9 years ago
Constantin, could you advice my why message (that is just before WAIT-FOR) is cleared when menu is drawn? In analogical procedure with frame it is not cleared. Menu and Frame a both contentPane children. I couldn't find why.
#321 Updated by Constantin Asofiei almost 9 years ago
Vadim Gindin wrote:
Constantin, could you advice my why message (that is just before WAIT-FOR) is cleared when menu is drawn? In analogical procedure with frame it is not cleared. Menu and Frame a both contentPane children. I couldn't find why.
Please give an example or point me to the test + scenario you are using. The idea is: the MENU-DROP trigger must have no I/O operations, this includes MESSAGE,DISPLAY,PUT SCREEN, etc or other cases which might result in showing an implicit (i.e. error) message on screen.
#322 Updated by Vadim Gindin almost 9 years ago
My question is not about MENU-DROP now. I use the following procedure:
def var r as int init 1. def var i as int init 1. def var outp as char extent 24. def sub-menu sbm menu-item mii label "iii". def menu m menubar menu-item qqq label "qqq". sub-menu sbm label "Orwell". menu-item print label "print". on choose of menu-item print do: i = 1. repeat while i < r: put screen row i col 22 string(outp[i], "x(60)"). i = i + 1. end. end. on menu-drop of sub-menu sbm do: message r "menu-drop". def var ch as char. ch = last-event:label + " " + string(keycode(last-event:label)) + " " + last-event:event-type + " " + string(last-event:code) + " " + last-event:function + " " + last-event:type + " " + string(LASTKEY). outp[r] = ch. r = r + 1. end. message "bogus message so that the message area is not empty". assign current-window:menubar = menu m:handle. wait-for choose of menu-item qqq.
I found yesterday, that message "bogus message so that the message area is not empty" is drawn, than it is cleared and menubar is drawn. It happens during the start (no user actions needed).
#323 Updated by Constantin Asofiei almost 9 years ago
Vadim Gindin wrote:
My question is not about MENU-DROP now. I use the following procedure:
[...]
I found yesterday, that message "bogus message so that the message area is not empty" is drawn, than it is cleared and menubar is drawn. It happens during the start (no user actions needed).
You mean that is cleared in P2J, correct? Because in 4GL the message remains there.
#324 Updated by Vadim Gindin almost 9 years ago
Yes, in P2J. You can use my last update.
#325 Updated by Constantin Asofiei almost 9 years ago
Vadim Gindin wrote:
I think the cause is that we are pushing the entire window to the client-side:Yes, in P2J. You can use my last update.
- in WindowConfig.syncWithWidget, we are triggering a repaint for the entire window
- when drawing, BorderedPanel.drawPanel clears the entire window (as the repaint event is for the entire window)
- AbstractContainer.draw calls getDrawableWidgets, which returns only the menubar (because this is the top-most found AbstractContainer, so drawing is assumed to start from it...)
- what happens if there is another frame already displayed in the window, when attaching the menubar? I suspect that is cleared, too, by P2J. Please check this.
- why is the menubar on top, in z-order? It might work if we keep this as low as possible... but I can't tell what happens if there are other frames on the screen.
#326 Updated by Constantin Asofiei almost 9 years ago
- there are frames on the screen
- you are in the middle of an update operation (attach/detach the menubar via a trigger?)
- you have PUT SCREEN content on the first row - does this get overwritten by the menubar?
- you have a frame with height 21 (24 - 2 messages - 1 status area), and a menubar is added: what happens with the frame, as it no longer fits the screen height?
#327 Updated by Vadim Gindin almost 9 years ago
Constantin Asofiei wrote:
Some other thoughts about my notes in 325: when attaching/detaching the menubar, the "workspace" area were drawing is done loses 1 row, so all existing content must be redrawn... you need to find what happens if the menubar gets attached/detached while:
- there are frames on the screen
def sub-menu sbm menu-item mii label "iii". def menu m menubar menu-item qqq label "Exit". sub-menu sbm label "Orwell". def var i as int init 0. def frame f i with 22 down no-labels no-box. /*enable all with frame f.*/ repeat while i < 21: display i with frame f. i = i + 1. end. message "bogus1". message "bogus2". pause. assign current-window:menubar = menu m:handle. wait-for choose of menu-item qqq.
Frame is shifted down.
- you are in the middle of an update operation (attach/detach the menubar via a trigger?)
the same as previous - shifted down
- you have PUT SCREEN content on the first row - does this get overwritten by the menubar?
Menu is drawn over the string that was output by PUT SCREEN without clearing.
- you have a frame with height 21 (24 - 2 messages - 1 status area), and a menubar is added: what happens with the frame, as it no longer fits the screen height?
It is shifted down and the last row become hidden.
--
P2J doesn't clear frames before output of menu-bar.
#328 Updated by Constantin Asofiei almost 9 years ago
Vadim Gindin wrote:
Constantin Asofiei wrote:
Some other thoughts about my notes in 325: when attaching/detaching the menubar, the "workspace" area were drawing is done loses 1 row, so all existing content must be redrawn... you need to find what happens if the menubar gets attached/detached while:
- there are frames on the screen
[...]
Frame is shifted down.
I don't think your conclusion is correct. Add a border/side-labels and you will see that the frame's height is adjusted:
def sub-menu sbm menu-item mii label "iii". def menu m menubar menu-item qqq label "Exit". sub-menu sbm label "Orwell". def var i as int init 0. def frame f i with 19 down side-labels. /*enable all with frame f.*/ repeat while i < 19: display i with frame f. i = i + 1. end. message "bogus1". message "bogus2". pause. assign current-window:menubar = menu m:handle. wait-for choose of menu-item qqq.
a scroll is added to the frame:
Exit Orwell ┌─────────────┐ │i: 0 │i: 1 │i: 2 │i: 3 │i: 4 │i: 5 │i: 6 │i: 7 │i: 8 │i: 9 │i: 10 │i: 11 │i: 12 │i: 13 │i: 14 │i: 15 │i: 16 │i: 17 └─────────────┘
And if there are are multiple frames on screen:
def sub-menu sbm menu-item mii label "iii". def menu m menubar menu-item qqq label "Exit". sub-menu sbm label "Orwell". def var i as int init 0. def frame f1 i with 4 down side-labels title "f1". def frame f2 i with 5 down side-labels title "f2". def frame f3 i with 6 down side-labels title "f3". view frame f1. view frame f2. view frame f3. message "bogus1". message "bogus2". pause. assign current-window:menubar = menu m:handle. wait-for choose of menu-item qqq.
with the entire screen height occupied:
┌─────f1──────┐ │i: │ │ │ │ │ │ │ └─────────────┘ ┌─────f2──────┐ │i: │ │ │ │ │ │ │ │ │ └─────────────┘ ┌─────f3──────┐ │i: │ │ │ │ │ │ │ │ │ │ │ └─────────────┘ bogus1 bogus2 Press space bar to continue.
than bottom frame get's re-positioned so that it fully fits, but no implicit pause is triggered, when
f2
is hidden:Exit Orwell ┌─────f1──────┐ │i: │ │ │ │ │ │ │ └─────────────┘ ┌─────f3──────┐ │i: │ │ │ │ │ │ │ │ │ │ │ └─────────────┘
Greg: in ChUI, I think some relayout is being performed, so that the frame's shown on the visible area now fit the new virtual window height. My suggestion is to finish the menu's drawing/event/etc first and work on this in a second phase, as some refactoring might needed (I think the frames in ChUI can't be parented to the window anymore, we need a "workspace" container as we use in GUI).
#329 Updated by Greg Shah almost 9 years ago
My suggestion is to finish the menu's drawing/event/etc first and work on this in a second phase, as some refactoring might needed (I think the frames in ChUI can't be parented to the window anymore, we need a "workspace" container as we use in GUI).
Agreed. And I think that this is a task for someone that has more experience in the layout and frames processing.
Vadim: please create a new task for the UI project which documents this limitation and the known cases/problems. Link to this task as a related task.
#330 Updated by Vadim Gindin almost 9 years ago
Should I include "message hiding" and "pausing bugs" there or fix it?
#331 Updated by Constantin Asofiei almost 9 years ago
Vadim Gindin wrote:
Should I include "message hiding" and "pausing bugs" there or fix it?
Yes, include these two issues in the new task, do not work on them now.
#332 Updated by Vadim Gindin almost 9 years ago
The task #2557 is created. Can I run regression testing for current update? If yes, should I add some menu scenarios to MAJIC?
#333 Updated by Greg Shah almost 9 years ago
Please address my issues 1 and 3 from the code review in note 316. Post that update here. Hopefully it is the final one for ChUI support. Is there anything else you know of that is needed?
If yes, should I add some menu scenarios to MAJIC?
No I don't want to change MAJIC.
We will add automated testing for menus later.
#334 Updated by Vadim Gindin almost 9 years ago
- File vig_upd20150427a.zip added
Greg Shah wrote:
Code Review vig_upd20150423a.zip
This is quite good.
1. In
Menu.java
, what is the requirement for import ofMenuChuiImpl
andChuiOutputManager
? Neither of these things should be accessed from the general purpose code inMenu
.
I've fixed it.
..
3. Do we really want to register the popup key listener for every button or just for the buttons that have a popup menu?
You advised it to me earlier and I tried it, but I found that at the moment of initialization config().popupMenuId
has no value. Therefore If I will use if (config.popupMenuId != -1)
block listener will not be added for all cases. I.e. this config attribute is not set at the moment of construction and initialize()
method call.
I can miss something but I think there are no remained issued there except the following. POPUP-MENU attribute can be set for the following components: Browse, Button, Combo-box, Dialog-box, Editor, Fill-in, Frame, Radio-set,
. I tried it only for Button and I'm going to set it for all remained components. How to do it better: add listener in some base class(like
Selection-list, Slider, Toggle-box, WindowAbstractWidget
or in each of listed components separately?
#335 Updated by Greg Shah almost 9 years ago
Code Review vig_upd20150427a.zip
I'm fine with the changes.
#336 Updated by Greg Shah almost 9 years ago
but I found that at the moment of initialization config().popupMenuId has no value
I guess that only a dynamic widget case might have this assigned at creation time:
CREATE button hbutton ASSIGN popup-menu = hmenu ...
So, it seems like we can still check for something that is not -1 and register at init in that case. Please check it.
BUT for all other cases, we already do a pushScreenDefinition()
when popup-menu
is assigned. Can't we detect when some different menu is assigned and only in that case register the listener?
POPUP-MENU attribute can be set for the following components: Browse, Button, Combo-box, Dialog-box, Editor, Fill-in, Frame, Radio-set, Selection-list, Slider, Toggle-box, Window. I tried it only for Button and I'm going to set it for all remained components. How to do it better: add listener in some base class(like AbstractWidget or in each of listed components separately?
I agree, this needs to be in code that is shared for all relevant widgets. AbstractWidget
seems to be a good choice.
#337 Updated by Vadim Gindin almost 9 years ago
- File vig_upd20150429a.zip added
I've fixed it, by implementing of AbstractWidget.syncWithConfig()
method and also in AbstractWidget.initialize()
method for described dynamic cases. It works. Have a look please and if it is OK, please confirm regression testing of that update.
#338 Updated by Greg Shah almost 9 years ago
Code Review vig_upd20150429a.zip
I'm good with this approach.
It is worth running regression testing on this update. However, please note that Hynek is about to check in a massive update that needs to go first. It will require very careful merging of your update.
You won't be able to check in until after Hynek, but a regression run will tell us if there are any issues to fix.
#339 Updated by Vadim Gindin almost 9 years ago
We can assume that current update has passed regression testing. Only 2 tests are failed: gso_269 and tc_job_002. Should I run testing again after merging with Hynek changes?
#340 Updated by Constantin Asofiei almost 9 years ago
Vadim Gindin wrote:
We can assume that current update has passed regression testing. Only 2 tests are failed: gso_269 and tc_job_002. Should I run testing again after merging with Hynek changes?
Yes, merge the update, post it for review, and then runtime testing.
But first please confirm that GSO 269 is a false negative, by running it by hand.
#341 Updated by Vadim Gindin almost 9 years ago
- File vig_upd20150430a.zip added
Here is the merged update. I didn't check GSO 269 test by hand because I already updated p2j project from trunk with Hynek's changes, i.e. my update become incompatible with p2j. I'll check it if it will fail in the following regression testing.
#342 Updated by Greg Shah almost 9 years ago
Code Review vig_upd20150430a.zip
1. In WidgetConfig.applyConfig()
, shouldn't the assignment be done using ConfigHelper.setModified(this, cfg.modified);
as is done in the latest BaseConfig
? The WidgetConfig.setModified()
would then be removed.
2. AbstractContainer
imports need to use wildcards.
#343 Updated by Vadim Gindin almost 9 years ago
- File vig_upd20150430b.zip added
Greg Shah wrote:
Code Review vig_upd20150430a.zip
1. In
WidgetConfig.applyConfig()
, shouldn't the assignment be done usingConfigHelper.setModified(this, cfg.modified);
as is done in the latestBaseConfig
? TheWidgetConfig.setModified()
would then be removed.2.
AbstractContainer
imports need to use wildcards.
You're right. I've fixed it.
#344 Updated by Greg Shah almost 9 years ago
Code Review vig_upd20150430b.zip
This is good.
#345 Updated by Vadim Gindin almost 9 years ago
This update (after merge) failed regression testing: gso_tests (19) tc_tests (24). I'm working on it.
#346 Updated by Vadim Gindin almost 9 years ago
- File gso_17.zip added
I've checked gso_17 test, the first failed test and found the following. During the test there are gso_17.txt is generated and the test fails in text files comparison of generated file and prepared earlier (expected). I've attached archive with these files and those diff file. Could you help me interpret it and find how it can be related to my changes?
#347 Updated by Vadim Gindin almost 9 years ago
There are a lot of similar errors where generated files differ from expected. But there are another errors exist. I've looked at tc_codes_employees_024 test.
23 CHECK-SCREEN-BUFFER wait = true; millis = ʼ300000ʼ; failing screen = 04/30/2015 EMPLOYEE MASTER (5 of 5) 17:28:38 ┌──────────────────────────────────────────────────────────────────────────────┐ │ Employee: 1029 **************** JR., ** E. │ │ Skill: │ │ Crew Code: │ │ Shift: 0 Days-Off: │ └──────────────────────────────────────────────────────────────────────────────┘ Start Start End End Crew Crew Skil Shift Days Date Time Date Time Dept Code Eff Date Code Sft Eff Date Off ────────── ───── ────────── ───── ──── ──── ────────── ──── ─── ────────── ──── >07/02/1990 07:00 07/02/1990 15:30 7000 D40 01/01/1990 7300 11 01/01/1990 67 11/01/1995 07:00 11/01/1995 15:30 7000 40D 01/01/1990 7300 11 01/01/1990 67 09/25/1999 07:00 09/25/1999 15:30 1500 070 01/01/1990 1540 11 01/01/1990 67 05/18/2002 07:00 05/18/2002 15:30 1100 050 01/01/1990 1130 11 01/01/1990 67 10/18/2003 07:00 10/18/2003 15:30 7000 070 01/01/1990 1540 11 01/01/1990 67 12/20/2003 07:00 12/20/2003 15:30 7000 070 01/01/1990 7500 11 01/01/1990 67 06/12/2004 07:00 06/12/2004 15:30 7000 060 01/01/1990 7500 11 01/01/1990 67 11/01/2004 00:00 11/01/2004 00:00 62E 01/01/1990 1130 11 01/01/1990 67 11/02/2004 00:00 11/02/2004 00:00 62E 01/01/1990 1130 11 01/01/1990 67 (N)ext (P)rev (U)pdate (A)dd (C)opy (F)ind (D)el (O)utput (T)ext (X)Crew (H)elp (E)xtend (1)Up (2)Down (3)Pg Back (4) Pg Frwd (5)Beg (6)End (R)eturn: F FAILED 300.103 timeout before the specific screen buffer became available (Mismatched data at line 3, column 22. Expected '1' (0x0031 at relative Y 3, relative X 22) and found ' ' (0x0020 at relative Y 3, relative X 22).)
I've ran it manually and got the following screen:
05/01/2015 EMPLOYEE MASTER (5 of 5) 02:17:19 ┌──────────────────────────────────────────────────────────────────────────────┐ │ Employee: 1029 *** JR., ********* E. │ │ Skill: 1130 IT SOFTWARE DEVEL │ │ Crew Code: 62E *** *** *** *** - ******* │ │ Shift: 11 Days-Off: 67 │ └──────────────────────────────────────────────────────────────────────────────┘ Start Start End End Crew Crew Skil Shift Days Date Time Date Time Dept Code Eff Date Code Sft Eff Date Off ────────── ───── ────────── ───── ──── ──── ────────── ──── ─── ────────── ──── >07/02/1990 07:00 07/02/1990 15:30 7000 D40 08/04/2007 7300 11 01/01/1990 67 11/01/1995 07:00 11/01/1995 15:30 7000 40D 08/04/2007 7300 11 01/01/1990 67 09/25/1999 07:00 09/25/1999 15:30 1500 070 08/04/2007 1540 11 01/01/1990 67 05/18/2002 07:00 05/18/2002 15:30 1100 050 08/04/2007 1130 11 01/01/1990 67 10/18/2003 07:00 10/18/2003 15:30 7000 070 08/04/2007 1540 11 01/01/1990 67 12/20/2003 07:00 12/20/2003 15:30 7000 070 08/04/2007 7500 11 01/01/1990 67 06/12/2004 07:00 06/12/2004 15:30 7000 060 08/04/2007 7500 11 01/01/1990 67 11/01/2004 00:00 11/01/2004 00:00 62E 08/04/2007 1130 11 01/01/1990 67 11/02/2004 00:00 11/02/2004 00:00 62E 08/04/2007 1130 11 01/01/1990 67 ...
As you can see the header of the table is filled but in my manual run, but that header is empty in testing results (lines "Skill", "Crew Code" are empty and "Shift" contains wrong values). I.e. I couldn't reproduce this error. Could you help me?
LE: GES redacted customer personnel info.
#348 Updated by Constantin Asofiei almost 9 years ago
Vadim Gindin wrote:
There are a lot of similar errors where generated files differ from expected. But there are another errors exist. I've looked at tc_codes_employees_024 test.
[...]
I've ran it manually and got the following screen:
[...]
As you can see the header of the table is filled but in my manual run, but that header is empty in testing results (lines "Skill", "Crew Code" are empty and "Shift" contains wrong values). I.e. I couldn't reproduce this error. Could you help me?
This is a known issue, if manually works fine, you can ignore it.
#349 Updated by Constantin Asofiei almost 9 years ago
Vadim Gindin wrote:
I've checked gso_17 test, the first failed test and found the following. During the test there are gso_17.txt is generated and the test fails in text files comparison of generated file and prepared earlier (expected). I've attached archive with these files and those diff file. Could you help me interpret it and find how it can be related to my changes?
This one is a real issue, as a text/fill-in is not displayed in the report. It might be related to positioning or visible flag...
#350 Updated by Vadim Gindin almost 9 years ago
Constantin Asofiei wrote:
Vadim Gindin wrote:
I've checked gso_17 test, the first failed test and found the following. During the test there are gso_17.txt is generated and the test fails in text files comparison of generated file and prepared earlier (expected). I've attached archive with these files and those diff file. Could you help me interpret it and find how it can be related to my changes?
This one is a real issue, as a text/fill-in is not displayed in the report. It might be related to positioning or visible flag...
How to debug it effectively?
#351 Updated by Constantin Asofiei almost 9 years ago
Vadim Gindin wrote:
Constantin Asofiei wrote:
Vadim Gindin wrote:
I've checked gso_17 test, the first failed test and found the following. During the test there are gso_17.txt is generated and the test fails in text files comparison of generated file and prepared earlier (expected). I've attached archive with these files and those diff file. Could you help me interpret it and find how it can be related to my changes?
This one is a real issue, as a text/fill-in is not displayed in the report. It might be related to positioning or visible flag...
How to debug it effectively?
I think for a first step is better to try to duplicate it. Find which program generates this report (execute it by hand until report output and press F2 to see the program, or search for the frame/report title in the *.p.cache files), the frame which updates this data and create a test similar to how the problematic frame is used.
#352 Updated by Constantin Asofiei almost 9 years ago
Vadim, what update are these results from? Because I can recreate it with your 0430a.zip but not with 0430b.zip.
Also, I see that in your folder you have been testing 0430a.zip (/home/vig/testing/updates/p2j/01_vig_upd20150430a.zip), not 0430b.zip, which addresses the issues mentioned by Greg - and inherently fixes GSO 17.
Thus: please merge the update with latest rev and start a runtime testing (and post it here, too).
#353 Updated by Vadim Gindin almost 9 years ago
- File vig_upd20150501b.zip added
OK. There was some mess with that. I hope, you right, moreover my update passed successfully regression testing before Hynek's change. I've merged it with the latest revision now and fixed FIRST-CHILD change for classes MenuWidget
and SubMenuWidget
.
#354 Updated by Greg Shah almost 9 years ago
Code Review vig_upd20150501b.zip
Please just add a history entry to MenuWidget
. Otherwise it looks good.
#355 Updated by Greg Shah almost 9 years ago
You can check in your code as soon as it passes, unless you have to make some other fix besides the history entry mentioned above.
#356 Updated by Vadim Gindin almost 9 years ago
Constantin Asofiei wrote:
Vadim, what update are these results from? Because I can recreate it with your 0430a.zip but not with 0430b.zip.
Also, I see that in your folder you have been testing 0430a.zip (/home/vig/testing/updates/p2j/01_vig_upd20150430a.zip), not 0430b.zip, which addresses the issues mentioned by Greg - and inherently fixes GSO 17.
Thus: please merge the update with latest rev and start a runtime testing (and post it here, too).
I've tested vig_upd20150501b.zip. Constantin, thank you very much. You're right. Only the following tests are failed: gso_269 and tc_code_employees_21. Because of my mistake we loose some time. Sorry.
#357 Updated by Vadim Gindin almost 9 years ago
So, I've checked gso_269. It also is not reproduced as tc_code_employees_261 manually (as tc_code_employees_264 in the note 347 with the same screen). The screens are the following. Manual run:
05/02/2015 MATERIAL ORDER REQUEST 02:28:59 ┌──────────────────────────────────────────────────────────────────────────────┐ confidential info redacted └──────────────────────────────────────────────────────────────────────────────┘ Enter Required by date
The focus is in the field "Date Required" and it got in this field after the field "Fac" after I pressed "VK_ENTER". In the testing results this transfer (from "Fac" to "Date required") fails with the error message "INVALID FACILITY CODE - PLEASE RETRY":
05/01/2015 MATERIAL ORDER REQUEST 19:24:48 ┌──────────────────────────────────────────────────────────────────────────────┐ confidential info redacted └──────────────────────────────────────────────────────────────────────────────┘ INVALID FACILITY CODE - PLEASE RETRY Enter ? for Facility Codes FAILED 180.081 timeout before the specific screen buffer became available (Mismatched data at line 21, column 1. Ex pected '' (0x0000 at relative Y 21, relative X 1) and found 'I' (0x0049 at relative Y 21, relative X 1).)
The mismatched character coordinates are also confusing..
I've also ran single scenario in automated testing mode (specified gso_269 in majic_single.xml and ran run_single.sh). It asked me a password and now It is working about 10 minutes with the message "Running test plan...". How long it could be executed?
Should I ignore this error?
#358 Updated by Greg Shah almost 9 years ago
Should I ignore this error?
If I understand correctly, you are saying that your manual testing could not recreate the problem. Right?
If so, then yes, this can be ignored.
#359 Updated by Vadim Gindin almost 9 years ago
- File vig_upd20150501c.zip added
There were 2 failed test that was not being recreated during manual testing. So, I've committed current changes with revision 10846 (fixed only some history entries).
#360 Updated by Vadim Gindin almost 9 years ago
I'm trying to draw simple menubar and I have coordinates problem. I expected that [0,0] point will reside under the window title bar, but when I call draw at that point rectangle appears right over window title bar. More, I'm trying to output menu-item title with the color (0, 0, 0) RGB - one of system colors also at that point but it is not printed. Could you advice me why?
#361 Updated by Constantin Asofiei almost 9 years ago
Vadim Gindin wrote:
I'm trying to draw simple menubar and I have coordinates problem. I expected that [0,0] point will reside under the window title bar, but when I call draw at that point rectangle appears right over window title bar. More, I'm trying to output menu-item title with the color (0, 0, 0) RGB - one of system colors also at that point but it is not printed. Could you advice me why?
This is for GUI, right? First of all, never use fixed coordinates in GUI. Second, where is the menubar widget attached currently? To the WindowGuiImpl instance or to the WindowWorkspace? In GUI, WindowGuiImpl emulates the OS window (with all its decorations - border, title, etc). If the menubar must be parented to it, ensure that it is placed properly by WindowLayout.
But before doing this, try to determine what the 4GL reports as coordinates for the menubar; also, what happens if the window becomes scrollable - does the menubar stay fixed or it gets scrolled, too? If it gets scrolled, then the menubar should belong to the WindowWorkspace.
#362 Updated by Vadim Gindin almost 9 years ago
Constantin Asofiei wrote:
Vadim Gindin wrote:
I'm trying to draw simple menubar and I have coordinates problem. I expected that [0,0] point will reside under the window title bar, but when I call draw at that point rectangle appears right over window title bar. More, I'm trying to output menu-item title with the color (0, 0, 0) RGB - one of system colors also at that point but it is not printed. Could you advice me why?
This is for GUI, right? First of all, never use fixed coordinates in GUI. Second, where is the menubar widget attached currently? To the WindowGuiImpl instance or to the WindowWorkspace? In GUI, WindowGuiImpl emulates the OS window (with all its decorations - border, title, etc). If the menubar must be parented to it, ensure that it is placed properly by WindowLayout.
But before doing this, try to determine what the 4GL reports as coordinates for the menubar; also, what happens if the window becomes scrollable - does the menubar stay fixed or it gets scrolled, too? If it gets scrolled, then the menubar should belong to the WindowWorkspace.
MENU widget does not support coordinate attributes and WIDTH/HEIGHT attributes too..
#363 Updated by Constantin Asofiei almost 9 years ago
Vadim Gindin wrote:
MENU widget does not support coordinate attributes and WIDTH/HEIGHT attributes too..
OK, I did some checks and the menubar is not scrolled. So it must be placed by WindowLayout and parented to the WindowGuiImpl instance.
More, if the menubar doesn't fit the window width, menus can be placed on a second, third etc line - does this happen for ChUI, too?
#364 Updated by Vadim Gindin almost 9 years ago
- File vig_upd20150528a.zip added
Constantin Asofiei wrote:
Vadim Gindin wrote:
MENU widget does not support coordinate attributes and WIDTH/HEIGHT attributes too..
OK, I did some checks and the menubar is not scrolled. So it must be placed by WindowLayout and parented to the WindowGuiImpl instance.
Yes, thank you, I did correspondent changes, but it still doesn't work. When I call gd.fillRect(0, 0, dim.width, dim.height);
It draws rectangle in the top left corner of window right over window title bar. I've commented out all menu-item specific code. It also doesn't output simple text when I call:
gd.setColor(gce.fgColor); gd.setGuiFont(fc.font); gd.setFontStyle(fc.font.style); gd.drawString(config().title, 0, 0);
It could print the title on the top left corner when it draws rectangle but it doesn't happen.
Once again: 2 difficulties: coordinates and text.
Could you look at my changes?
More, if the menubar doesn't fit the window width, menus can be placed on a second, third etc line - does this happen for ChUI, too?
No, Progress outputs the error Menu too large to display on the screen. (5902)
when menu does not fit the screen in vertical or horizontal direction.
#365 Updated by Constantin Asofiei almost 9 years ago
Vadim Gindin wrote:
It could print the title on the top left corner when it draws rectangle but it doesn't happen.
Once again: 2 difficulties: coordinates and text.
Could you look at my changes?
I think they are both related to the same problem: you are not doing the layout for the GUI menubar impl, which determines the location for the menu items/sub-menus (what MenuChuiImpl.doLayout does for ChUI). You might need something similar, but this time using string widths in pixels and not number of chars in string.
As always, please use the -Dwidgetbrowser=yes
option and check the runtime values for i.e. location/size - this can save you a lot of headaches, as it tells you where the widget should be placed and if its coordinates are computed properly.
#366 Updated by Vadim Gindin almost 9 years ago
Constantin Asofiei wrote:
Vadim Gindin wrote:
It could print the title on the top left corner when it draws rectangle but it doesn't happen.
Once again: 2 difficulties: coordinates and text.
Could you look at my changes?
I think they are both related to the same problem: you are not doing the layout for the GUI menubar impl, which determines the location for the menu items/sub-menus (what MenuChuiImpl.doLayout does for ChUI). You might need something similar, but this time using string widths in pixels and not number of chars in string.
Oh, Here’s where the dog is buried. Now it is drawn correctly, but menu item titles are still not drawn..
As always, please use the
-Dwidgetbrowser=yes
option and check the runtime values for i.e. location/size - this can save you a lot of headaches, as it tells you where the widget should be placed and if its coordinates are computed properly.
Menubar is not always displayed in the widget browser because of some reason..
#367 Updated by Vadim Gindin almost 9 years ago
Vadim Gindin wrote:
Constantin Asofiei wrote:
Vadim Gindin wrote:
It could print the title on the top left corner when it draws rectangle but it doesn't happen.
Once again: 2 difficulties: coordinates and text.
Could you look at my changes?
I think they are both related to the same problem: you are not doing the layout for the GUI menubar impl, which determines the location for the menu items/sub-menus (what MenuChuiImpl.doLayout does for ChUI). You might need something similar, but this time using string widths in pixels and not number of chars in string.
Oh, Here’s where the dog is buried. Now it is drawn correctly, but menu item titles are still not drawn..
Titles is also coordinates problem. I'll fix it. Thank you for help!
#368 Updated by Vadim Gindin almost 9 years ago
I faced with the problem of defining a widget, mouse is clicked over. I have simple menubar with 3 menu-items and one submenu called "Submenu". When I click on submenu the following is happen. WindowGuiImpl.findMouseSource()
(line 579) gets the point clicked and tries to find the widget containing this point:
java.awt.Point p = evt.getEvent().getPoint(); // search the other widgets widget = contentPane.findMouseSource(new NativePoint(p.x, p.y));
contentPane
calls AbstractContainer.findMouseSource(p)
method. Have a look at it. It takes all container widgets and for each of them calls w.findMouseSource(p.minus(w.physicalLocation()))
. In my case it works in the following way.
p=[160, 44] - is the clicked point.
Window.findMenuSource finds menubar containing it first and calls w.findMouseSource(p.minus(w.physicalLocation()))
for it.
menubar location = [4, 29], so findMouseSource takes: p=[156, 15].
Submenu location = [130, 29] - the absolute point relative to window left-top corner, therefore it has the same y-axis coordinate as menubar itself.
As you can see p=[156, 15] is not resides in submenu and menu.findMouseSource
returns null.
Why? I can only propose that w.physicalLocation()
always returns absolute location of widget (relative to left-top corner of window - not relative to parent widget). Am I right? If yes why p.minus(w.physicalLocation())
is needed, i.e. why not to pass p
itself?
#369 Updated by Constantin Asofiei almost 9 years ago
Vadim Gindin wrote:
I faced with the problem of defining a widget, mouse is clicked over. I have simple menubar with 3 menu-items and one submenu called "Submenu". When I click on submenu the following is happen.
WindowGuiImpl.findMouseSource()
(line 579) gets the point clicked and tries to find the widget containing this point:
[...]
contentPane
callsAbstractContainer.findMouseSource(p)
method. Have a look at it. It takes all container widgets and for each of them callsw.findMouseSource(p.minus(w.physicalLocation()))
. In my case it works in the following way.
p=[160, 44] - is the clicked point.
Window.findMenuSource finds menubar containing it first and callsw.findMouseSource(p.minus(w.physicalLocation()))
for it.
menubar location = [4, 29], so findMouseSource takes: p=[156, 15].
Submenu location = [130, 29] - the absolute point relative to window left-top corner, therefore it has the same y-axis coordinate as menubar itself.As you can see p=[156, 15] is not resides in submenu and
menu.findMouseSource
returns null.Why? I can only propose that
w.physicalLocation()
always returns absolute location of widget (relative to left-top corner of window - not relative to parent widget). Am I right? If yes whyp.minus(w.physicalLocation())
is needed, i.e. why not to passp
itself?
How have you implemented the menu's location? When a container (parent-child relation) is used, the child widget has its coordinates always relative to the parent. And Widget.physicalLocation
will return always these coordinates. For absolute location, we have screenPhysicalLocation
- but this can't be used for your case.
So: you either adjust the menu's location to be relative to its parent or override the findMouseSource
in your MenuBar implementation, so that it searches the the menus using absolute coordinates. But I would prefer to adjust the menu's location to be relative...
#370 Updated by Greg Shah almost 9 years ago
adjust the menu's location to be relative to its parent
This one.
It is important that the physicalLocation()
contract is honored.
#371 Updated by Vadim Gindin almost 9 years ago
If so, what about methods like GuiDriver.drawString(String, int, int)
, GuiDriver.drawLine(int, int, int, int)
or others. Are they accept absolute coordinates in those parameters?
If yes, will be the following code correct in a menu-item draw method:
NativePoint parentLoc = SubMenuGuiImpl.this.parent().screenPhysicalLocation(); // absolute parent location // absolute point to draw in, calculated as absolute parent location shifted by some constant values NativePoint tp = new NativePoint(parentLoc.x + 7, parentLoc.y + 5 + fh); // draw menu-item title gd.drawString(title, tp.x, tp.y);
#372 Updated by Constantin Asofiei almost 9 years ago
Vadim Gindin wrote:
If so, what about methods like
GuiDriver.drawString(String, int, int)
,GuiDriver.drawLine(int, int, int, int)
or others. Are they accept absolute coordinates in those parameters?
That's why we always include these in a GuiDriver.draw(origin, clip, runnable)
call. So, assuming you have a widget tree like (simplified): window > frame > widget, when draw
is called in GUI, the graphics physical origin is translated as this, from an initial (0, 0) point:
- for window: (wx, wy) (this is actually the workspace's location)
- for frame: (wx + fx, wy + fy) where (fx, fy) is frame's location relative to the window workspace
- for widget: (wx + fx + gx, wy + fy + gy) where (gx, gy) is the widget's location relative to the frame
When the gd.draw
stack unwinds, the graphics origin is restored to what it was before the gd.draw
was called. Using this approach, you can assume that when the widget is being drawn, all APIs are working with a graphics origin of (0,0), which at this time is positioned on the the widget's top-left corner - so you don't need the widget's absolute coordinates to perform drawing.
If yes, will be the following code correct in a menu-item draw method:
No, because it doesn't follow the rules above. At the time when MenuItem.draw
is called, the graphics origin must already be translated to the menu-items's parent, so the menu-item can execute a gd.draw
using its location relative to the parent.
It will help if you post how the drawing stacktrace and the widget hierarchy (from the widget browser) looks with your current code.
#373 Updated by Vadim Gindin almost 9 years ago
- File widget_browser.png added
I've made the following changes:
#. I've set menu children physicalLocation
to relative value
#. I used relative point to draw menu-item in gd.draw(origin, clip, core)
But menu-item was drawn over window title again.
Here is my stack:
MenuItemGuiImpl$1.run() line: 239 SwingGuiDriver(AbstractGuiDriver<F>).draw(NativePoint, NativeRectangle, Runnable) line: 1294 MenuItemGuiImpl.drawTitle() line: 213 MenuItemGuiImpl.draw() line: 104 MenuGuiImpl(AbstractContainer<O>).draw() line: 312 MenuGuiImpl.draw() line: 87 BorderedPanel<O>(AbstractContainer<O>).draw() line: 312 BorderedPanel<O>.draw() line: 73 WindowGuiImpl(Window<O>).draw() line: 1491 WindowGuiImpl.draw() line: 377 GuiOutputManager(OutputManager<P>).setInvalidate(Widget<?>, boolean, boolean) line: 1209 ThinClient.eventDrawingBracket(Widget<?>, boolean, boolean, Runnable) line: 13154 ThinClient.eventDrawingBracket(Widget<?>, Runnable) line: 13081 ThinClient.pushWindow(WindowConfig) line: 7189 NativeMethodAccessorImpl.invoke0(Method, Object, Object[]) line: not available [native method] NativeMethodAccessorImpl.invoke(Object, Object[]) line: 57 DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: 43
I'm also attaching widget browser screen shot. I can recall that menu is a added to a window directly - not to a workspace. I set correct menubar location in a WindowLayout
- the same as workspace location.
Have a look please.
#374 Updated by Constantin Asofiei almost 9 years ago
Vadim Gindin wrote:
I've made the following changes:
#. I've set menu childrenphysicalLocation
to relative value
#. I used relative point to draw menu-item in gd.draw(origin, clip, core)But menu-item was drawn over window title again.
Here is my stack:
[...]I'm also attaching widget browser screen shot. I can recall that menu is a added to a window directly - not to a workspace. I set correct menubar location in a
WindowLayout
- the same as workspace location.Have a look please.
I think your problem is this:
MenuGuiImpl(AbstractContainer<O>).draw() line: 312 MenuGuiImpl.draw() line: 87
MenuGuiImpl
calls directly super.draw
- this should be inside a GuiDriver.draw
API call. If you make this change, MenuItemGuiImpl
will be able to use GuiDriver.draw
too, as the graphics origin will be translated to the parent's origin.
For your current code: the graphics origin is never translated, that's why you end up needing absolute coordinates.
#375 Updated by Vadim Gindin almost 9 years ago
You are right and now it works. Thank you very much!
#376 Updated by Vadim Gindin almost 9 years ago
I wanted to ask some common question about repainting in GUI.
For ChUI I need to post new PaintEvent
to event queue to actuate repainting of rectangle specified in this PaintEvent
. More, rectangle is specified using Point
class. At some moment all posted PaintEvent's
are popped from the queue and those rectangles are unionized to one. This common rectangle is used when actual repainting is happen.
#. Does this scenario work for GUI in the same way? I recall that for GUI 2 classes are used to set a point: NativePoint
and Point
when for ChUI only Point
is used.
#. Assume we have:
NativePoint np1 = new NativePoint(someX, someY); Point p = wnd.screen().coordinates().widthFromNative(np1); NativePoint np2 = wnd.screen().coordinates().widthToNative(p);
Is
np1
equal np2
for all possible values?#. Assume we have:
Point p1 = new Point(someX, someY); NativePoint np = wnd.screen().coordinates().widthToNative(p1); Point p2 = wnd.screen().coordinates().widthFromNative(np);
Is
p1
equal p2
for all possible values?#. Do you know some handy coordinates grid application, that would allow to determine mouse pointer coordinates in a window coordinate system? I.e. some application like KRule.
#377 Updated by Constantin Asofiei almost 9 years ago
Vadim Gindin wrote:
#. Does this scenario work for GUI in the same way? I recall that for GUI 2 classes are used to set a point:
NativePoint
andPoint
when for ChUI onlyPoint
is used.
Yes, GUI works in the same way. It's the OutputManager's responsibility to convert these into native units (so that it can pass them to ScreenBitmap).
#. Assume we have:
[...]
Isnp1
equalnp2
for all possible values?
#. Assume we have:
[...]
Isp1
equalp2
for all possible values?
I assume you mean pointFromNative
and pointToNative
here. As we round the character units to 2 decimals, we can't assume pointToNative and pointFromNative to be each other's inverse function.
What are you trying to achieve with this conversion?
#378 Updated by Vadim Gindin almost 9 years ago
Constantin Asofiei wrote:
Vadim Gindin wrote:
#. Does this scenario work for GUI in the same way? I recall that for GUI 2 classes are used to set a point:
NativePoint
andPoint
when for ChUI onlyPoint
is used.Yes, GUI works in the same way. It's the OutputManager's responsibility to convert these into native units (so that it can pass them to ScreenBitmap).
#. Assume we have:
[...]
Isnp1
equalnp2
for all possible values?
#. Assume we have:
[...]
Isp1
equalp2
for all possible values?I assume you mean
pointFromNative
andpointToNative
here. As we round the character units to 2 decimals, we can't assume pointToNative and pointFromNative to be each other's inverse function.What are you trying to achieve with this conversion?
I'm just forced to use this conversion in some methods that uses Point, for example body location calculation. It has to return the point right under the sub-menu title (?) and I need to calculate font height that is calculated as int.
#379 Updated by Vadim Gindin almost 9 years ago
The question about widget (menu-item or sub-menu) state, that could be changed by mouse events: "mouse enter" (mouse pointer is over the widget), "mouse exit" (mouse pointer has left the widget), "mouse pressed" (mouse pointer is over the widget and the left button is pressed) and may be others. I need to draw the widget differently depending on type of concrete mouse event.
AbstractWidget
has methods mouse*()
that are called when corresponding event is happen and drawing is happen in draw()
method.
How to correctly implement different drawing?
I suspect that widget configuration class could have some field or fields: one for each event type or common field for all such event types like WidgetConfig.state
, and I should set correspondent field in correspondent mouse*()
method and call repaint()
.
Am I right?
Are such fields exist or I should add them myself for example to WidgetConfig
?
#380 Updated by Vadim Gindin almost 9 years ago
I've found that such fields are exist not in config classes, but in GUI widget classes itself. For example ButtonGuiImpl.mouseEntered
or ComboBoxGuiImpl.pressed
. I should probably do the same because such fields make sense only for GUI implementations. Is it correct?
#381 Updated by Greg Shah almost 9 years ago
I've found that such fields are exist not in config classes
They would only be put into config classes if the data has to be transferred between the server and client.
I should probably do the same because such fields make sense only for GUI implementations. Is it correct?
Yes.
#382 Updated by Vadim Gindin almost 9 years ago
I'm trying to implement the following behavior. Assume we have menubar. Mouse pointer is located somewhere outside of menubar. We are starting to drag mouse and moving the pointer to some item in menubar. P2J behavior is the same as P2J behavior, when I'm just pressing the mouse button over this item, i.e. draws its rectangle sunk into the surface of menubar.
I faced with the following problem here. MOUSE_DRAGGED event is targeted to the widget over which mouse button is pressed. So mouseDragged()
is not be called for MenuItemGuiImpl
and I only can implement MenuItemGuiImpl.mouseMoved()
(MOUSE_MOVED event) to process founded P2J behavior. So while implementing MOUSE_MOVED event I need to determine is this "mouse move" is made with pressed button, i.e. it is a MOUSE_DRAGGED event with the source, different than menu-item.
MOUSE_DRAGGED event is implemented using additional field WindowGuiImpl.mousePressedSource
, that contains dragging source widget. When mouse button is pressed this field is set to target widget. When mouse button is released this field is reset to null.
I can check this field WindowGuiImpl.mousePressedSource
in MenuItemGuiImpl.mouseMoved()
to determine is the currect MOUSE_MOVE event is MOUSE_DRAGGED event for some other widget and implement founded P2J drawing behavior based on this information.
Will it be correct?
#383 Updated by Constantin Asofiei almost 9 years ago
Vadim Gindin wrote:
I can check this field
WindowGuiImpl.mousePressedSource
inMenuItemGuiImpl.mouseMoved()
to determine is the currect MOUSE_MOVE event is MOUSE_DRAGGED event for some other widget and implement founded P2J drawing behavior based on this information.Will it be correct?
What you are trying to determine is if the mouse ended up hovering the menu-item, while is being dragged, correct?
I think this is solved better using mouseEntered/mouseExited events; using mouseMove will notify the widget too aggressively. Please think of a way to change MouseHandler.applyMouseEvent so that entered/exited events are raised if mouse is dragged. You might need to track the mousePressedSource here, too.
#384 Updated by Vadim Gindin almost 9 years ago
- File vig_upd20150619a.zip added
Here is my current update. Could you review and help me? I can't understand why nested sub-menu body isn't drawn when I click on "Insider". Here is my testcase:
define sub-menu sm0 menu-item mt01 label "Amadeus". menu-item mt02 label "Mozart". define sub-menu sm /*menu-item mt1 label "Lucky" rule. menu-item mt2 label "Luciano" /*toggle-box*/. menu-item mt3 label "Meyer". */ sub-menu sm0 label "Insider". /*skip.*/ menu-item mt4 label "Exit". define menu men1 menubar menu-item mit1 label "Firs&t" menu-item mit2 label "S&econd" menu-item mit3 label "Third". sub-menu sm label "Submenu". assign current-window:menubar = menu men1:handle. wait-for choose of menu-item mt4.
There are some difference in rectangles merging. Probably there is a reason. Where to look at.
#385 Updated by Constantin Asofiei almost 9 years ago
Vadim Gindin wrote:
Here is my current update. Could you review and help me? I can't understand why nested sub-menu body isn't drawn when I click on "Insider". Here is my testcase:
[...]There are some difference in rectangles merging. Probably there is a reason. Where to look at.
Please use the widget browser and verify the "insider" (and other) sub-menu's coordinates - although looks like is drawn in the right place, its coordinates are incorrect. Fixing these should fix the mouse click problems.
#386 Updated by Vadim Gindin almost 9 years ago
- File vig_upd20150619b.zip added
I've fixed it. But now it displays sub-menu twice in 2 different places. Have a look please. Why it can happen?
#387 Updated by Vadim Gindin almost 9 years ago
Please, hepl my with my previous question about duplication. I still didn't find the reason.
Additional question. How the 3D effect is implemented in P2J? I used GuiDriver.draw3DRect()
to draw sub-menu body but it looks more flat than original sub-menu body in windev01. Shouldn't I use this method to draw sub-menu body?
#388 Updated by Vadim Gindin almost 9 years ago
Vadim Gindin wrote:
Please, help me with my previous question about duplication. I still didn't find the reason.
Additional question. How the 3D effect is implemented in P2J? I used
GuiDriver.draw3DRect()
to draw sub-menu body but it looks more flat than original sub-menu body in windev01. Shouldn't I use this method to draw sub-menu body?
#389 Updated by Vadim Gindin almost 9 years ago
Duplication error has gone after the last Hynek's update! Sorry to trouble.
#390 Updated by Constantin Asofiei almost 9 years ago
Vadim Gindin wrote:
Duplication error has gone after the last Hynek's update! Sorry to trouble.
Please post your merged code.
#391 Updated by Constantin Asofiei almost 9 years ago
Vadim Gindin wrote:
Please, hepl my with my previous question about duplication. I still didn't find the reason.
Additional question. How the 3D effect is implemented in P2J? I used
GuiDriver.draw3DRect()
to draw sub-menu body but it looks more flat than original sub-menu body in windev01. Shouldn't I use this method to draw sub-menu body?
Please try GuiDriver.fill3DRect
instead of draw3DRect.
#392 Updated by Vadim Gindin almost 9 years ago
- File vig_upd20150624.zip added
Here is the current update
#393 Updated by Vadim Gindin almost 9 years ago
- File vig_upd20150629.zip added
Constantin, I have a problem with mouse ENTER and EXIT events processing. When I move mouse pointer from one menu-item in MENUBAR to another - only an active menu-item is drawn. The others became invisible. Also, When I move mouse pointer to first menu-item in sub-menu all menu-items in MENUBAR also became invisible.
Here is my update and testcase:
define sub-menu sm0 menu-item mt01 label "Amadeus Mozart". menu-item mt02 label "Ludvig Bethoven". rule. menu-item mt03 label "Adin Shteinzalc". skip. menu-item mt04 label "Jack London". define sub-menu sm menu-item mt4 label "Exit". sub-menu sm0 label "Insider". define menu men1 menubar menu-item mit1 label "Firs&t" menu-item mit2 label "S&econd" menu-item mit3 label "Third". sub-menu sm label "Submenu". assign current-window:menubar = menu men1:handle. wait-for choose of menu-item mt4.
Please help. I'm stuck with it.
#394 Updated by Constantin Asofiei almost 9 years ago
- you are calling a
repaint()
for a certain menu-item; this ensures that an invalidation (clipping) rectangle is added to theScreenBitmap
, only for that widget's bounds - later on,
MenuGuiImpl.draw
is called; this is calling afillRect
for the entire menubar (so all menus are no longer on screen at this point) - when calling
MenuGuiImpl.super.draw();
, although this collects all menu widgets,AbstractContainer.draw:290
(!clippings.isEmpty()
) will be true only for the menu which called repaint (and ScreenBitmap's invalidation rectangle contains the widget's boundary) - thus menus which are not touched by the invalidation rectangle will not be repainted.
The same is happening for your sub-menu case.
A solution would be to repaint the entire menubar or sub-menu on mouseEnter/Exit. But I think the proper way to go is to refactor a litle the menu-bar (and sub-menu drawing): let each individual widget clear itself; if needed, the parent draws the rectangle only once (when is displayed).
#395 Updated by Vadim Gindin almost 9 years ago
Constantin, thank you, I'll try.
Greg, I've faced with parsing error with the following procedure:
define sub-menu sm menu-item mt1 label "dddd". define menu men1 menubar sub-menu sm label "Submenu" disabled.
It will work if we'll change the order of disabled
and label "Submenu"
: sub-menu sm disabled label "Submenu".
, but in the source case it will throw an error during conversion:
menu/gui/parse_disabled.p line 5:35: expecting DOT, found 'disabled' at antlr.Parser.match(Parser.java:213) at com.goldencode.p2j.uast.ProgressParser.define_stmt(ProgressParser.java:8797) at com.goldencode.p2j.uast.ProgressParser.stmt_list(ProgressParser.java:22098) at com.goldencode.p2j.uast.ProgressParser.statement(ProgressParser.java:5712) at com.goldencode.p2j.uast.ProgressParser.single_block(ProgressParser.java:4568) at com.goldencode.p2j.uast.ProgressParser.block(ProgressParser.java:4327) at com.goldencode.p2j.uast.ProgressParser.external_proc(ProgressParser.java:4253) at com.goldencode.p2j.uast.AstGenerator.parse(AstGenerator.java:1441) ..
I've looked at submenu_descriptor
in progress.g
and found that it contains the error. Here is it. Now:
submenu_descriptor : KW_SUB_MENU^ lvalue (KW_DISABLED)? (label)? ;
Should be:
submenu_descriptor : KW_SUB_MENU^ lvalue (label | KW_DISABLED)? ;
But when I did this change, the error didn't disappear. Was I wrong? Could you have a look at it?
#396 Updated by Vadim Gindin almost 9 years ago
Constantin Asofiei wrote:
What I think is happening is this:
- you are calling a
repaint()
for a certain menu-item; this ensures that an invalidation (clipping) rectangle is added to theScreenBitmap
, only for that widget's bounds- later on,
MenuGuiImpl.draw
is called; this is calling afillRect
for the entire menubar (so all menus are no longer on screen at this point)- when calling
MenuGuiImpl.super.draw();
, although this collects all menu widgets,AbstractContainer.draw:290
(!clippings.isEmpty()
) will be true only for the menu which called repaint (and ScreenBitmap's invalidation rectangle contains the widget's boundary) - thus menus which are not touched by the invalidation rectangle will not be repainted.The same is happening for your sub-menu case.
A solution would be to repaint the entire menubar or sub-menu on mouseEnter/Exit. But I think the proper way to go is to refactor a litle the menu-bar (and sub-menu drawing): let each individual widget clear itself; if needed, the parent draws the rectangle only once (when is displayed).
How to distinguish the state when menubar is displayed from the state when it is being repainted?
#397 Updated by Constantin Asofiei almost 9 years ago
Vadim Gindin wrote:
A solution would be to repaint the entire menubar or sub-menu on mouseEnter/Exit. But I think the proper way to go is to refactor a litle the menu-bar (and sub-menu drawing): let each individual widget clear itself; if needed, the parent draws the rectangle only once (when is displayed).
How to distinguish the state when menubar is displayed from the state when it is being repainted?
Add a flag at the widget impl class to track if this is the first draw (after the widget was made visible) or not. This should be set to true after draw is called and set to false when the widget is hidden (visible is set to false).
#398 Updated by Greg Shah almost 9 years ago
But when I did this change, the error didn't disappear. Was I wrong? Could you have a look at it?
Your change does not work because only one of the two options can ever be matched. If they are both present, it will fail.
Please make this change to progress.g
:
submenu_descriptor : KW_SUB_MENU^ lvalue (KW_DISABLED | label)* ;
This allows the parser to match any number of these options, in any order so long as there is no other unexpected option in between.
#399 Updated by Vadim Gindin almost 9 years ago
Constantin Asofiei wrote:
Vadim Gindin wrote:
A solution would be to repaint the entire menubar or sub-menu on mouseEnter/Exit. But I think the proper way to go is to refactor a litle the menu-bar (and sub-menu drawing): let each individual widget clear itself; if needed, the parent draws the rectangle only once (when is displayed).
How to distinguish the state when menubar is displayed from the state when it is being repainted?
Add a flag at the widget impl class to track if this is the first draw (after the widget was made visible) or not. This should be set to true after draw is called and set to false when the widget is hidden (visible is set to false).
I'm trying. During the start Menu.draw()
is called several times in ThinClient.waitForWorker()
. The first several calls draws correct menubar and the last 2 calls are refreshing the window and do not draw menubar rectangle. It looks like at some step the window fully resets its content rigth as it does during the first draw. Is it possible? What could be an other reason?
#400 Updated by Constantin Asofiei almost 9 years ago
Vadim Gindin wrote:
Constantin Asofiei wrote:
Vadim Gindin wrote:
A solution would be to repaint the entire menubar or sub-menu on mouseEnter/Exit. But I think the proper way to go is to refactor a litle the menu-bar (and sub-menu drawing): let each individual widget clear itself; if needed, the parent draws the rectangle only once (when is displayed).
How to distinguish the state when menubar is displayed from the state when it is being repainted?
Add a flag at the widget impl class to track if this is the first draw (after the widget was made visible) or not. This should be set to true after draw is called and set to false when the widget is hidden (visible is set to false).
I'm trying. During the start
Menu.draw()
is called several times inThinClient.waitForWorker()
. The first several calls draws correct menubar and the last 2 calls are refreshing the window and do not draw menubar rectangle. It looks like at some step the window fully resets its content rigth as it does during the first draw. Is it possible? What could be an other reason?
So this can't work as there are legitimate cases where the entire window is redrawn.
Lets change the approach to this: take the menubar's clipping rectangle and, if the ScreenBitmap has an invalidation rectangle set (getOuterRectangle is not null), then intersect it (with the menubar's clipping rectangle) and the intersection result will be the menubar's real clipping rectangle. This ensures that only the portion of the menubar being repainted will be affected. Same for the sub-menu case.
#401 Updated by Vadim Gindin almost 9 years ago
Constantin Asofiei wrote:
Vadim Gindin wrote:
Constantin Asofiei wrote:
Vadim Gindin wrote:
A solution would be to repaint the entire menubar or sub-menu on mouseEnter/Exit. But I think the proper way to go is to refactor a litle the menu-bar (and sub-menu drawing): let each individual widget clear itself; if needed, the parent draws the rectangle only once (when is displayed).
How to distinguish the state when menubar is displayed from the state when it is being repainted?
Add a flag at the widget impl class to track if this is the first draw (after the widget was made visible) or not. This should be set to true after draw is called and set to false when the widget is hidden (visible is set to false).
I'm trying. During the start
Menu.draw()
is called several times inThinClient.waitForWorker()
. The first several calls draws correct menubar and the last 2 calls are refreshing the window and do not draw menubar rectangle. It looks like at some step the window fully resets its content rigth as it does during the first draw. Is it possible? What could be an other reason?So this can't work as there are legitimate cases where the entire window is redrawn.
Lets change the approach to this: take the menubar's clipping rectangle and, if the ScreenBitmap has an invalidation rectangle set (getOuterRectangle is not null), then intersect it (with the menubar's clipping rectangle) and the intersection result will be the menubar's real clipping rectangle. This ensures that only the portion of the menubar being repainted will be affected. Same for the sub-menu case.
Do you propose to use this intersection rectangle as clipping rectangle in MenuGuiImpl.draw()
and SubMenuGuiImpl.draw()
?
#402 Updated by Constantin Asofiei almost 9 years ago
Vadim Gindin wrote:
Lets change the approach to this: take the menubar's clipping rectangle and, if the ScreenBitmap has an invalidation rectangle set (getOuterRectangle is not null), then intersect it (with the menubar's clipping rectangle) and the intersection result will be the menubar's real clipping rectangle. This ensures that only the portion of the menubar being repainted will be affected. Same for the sub-menu case.
Do you propose to use this intersection rectangle as clipping rectangle in
MenuGuiImpl.draw()
andSubMenuGuiImpl.draw()
?
Yes.
#403 Updated by Vadim Gindin almost 9 years ago
- File vig_upd20150701a.zip added
Constantin, could you look at my update?
Is that what you meant?
When I'm moving mouse pointer to menu-item in MENUBAR there rectangle should be drawn around menu-item title. It happen in the method MenuItemGuiImpl.drawTitleRectangle(GuiColorResolver, NativeDimension)
. After I tried the current change with new clipping this rectangle stopped drawing. I can't find why.
Please, have a look it with the simple testcase:
define menu men1 menubar menu-item mit1 label "Firs&t" menu-item mit2 label "S&econd" disabled. menu-item mit3 label "Third". assign current-window:menubar = menu men1:handle. wait-for choose of menu-item mit3.
#404 Updated by Constantin Asofiei almost 9 years ago
Vadim Gindin wrote:
Constantin, could you look at my update?
Is that what you meant?
When I'm moving mouse pointer to menu-item in MENUBAR there rectangle should be drawn around menu-item title. It happen in the method
MenuItemGuiImpl.drawTitleRectangle(GuiColorResolver, NativeDimension)
. After I tried the current change with new clipping this rectangle stopped drawing. I can't find why.Please, have a look it with the simple testcase:
[...]
When drawing, remember, you are always using coordinates relative to the current parent. But ScreenBitmap.getOuterRectangle
works with the entire screen, so this rectangle is in absolute coordinates. What you need to do is translate this rectangle to be relative to the current parent, as in:
if (bitmap.getOuterRectangle() != null && bitmap.getOuterRectangle().intersects(clip)) { NativePoint screenLoc = screenPhysicalLocation(); NativeRectangle nr = bitmap.getOuterRectangle(); nr = nr.translate(-screenLoc.x, -screenLoc.y); // the resulting rectangle will have the same relative origin as your "clip" rectangle, so you can intersect safely clip = clip.intersection(nr); }
#405 Updated by Vadim Gindin almost 9 years ago
- File vig_upd20150701b.zip added
Constantin, your approach seems working at first sight. Now I have 2 problems with the testcase:
define sub-menu sm0 menu-item mt01 label "Amadeus Mozart". menu-item mt02 label "Ludvig Bethoven" disabled toggle-box. rule. menu-item mt03 label "Adin Shteinzalc". skip. menu-item mt04 label "Jack London". define sub-menu sm menu-item mt4 label "Exit". sub-menu sm0 label "Insider". define menu men1 menubar menu-item mit1 label "Firs&t" menu-item mit2 label "S&econd" disabled. sub-menu sm label "Submenu". menu-item mit3 label "Third". menu-item mt02:checked = true. assign current-window:menubar = menu men1:handle. wait-for choose of menu-item mt4.
This testcase defines 2 nested submenus "Insider" is nested in "Submenu".
The problems are the following:
1. Some MENUBAR items ("First") disappear when I move mouse pointer from "Insider" to "Exit" in the sub-menu "Submenu". During mouse events (ENTER/EXIT) processing I'm calling parent().repaint()
that causes sub-menu "Submenu" to be repainted. But sub-menu's rectangle doesn't intersect with "First" menu-item. It looks like that is the reason of "First" disappearing. I'm I right? If yes - does it mean that I should repaint all menu when processing any mouse event?
2. The width of sub-menu "Insider" body is less than clipping rectangle width used to draw it. It is about 121px (measured by KRule) and the clipping rectangle has 131px (debugged clip
in SubMenuGuiImpl.draw()
line 228).
I can't understand why. Could you look it?
#406 Updated by Constantin Asofiei almost 9 years ago
Vadim Gindin wrote:
This testcase defines 2 nested submenus "Insider" is nested in "Submenu".
You have the build/
folder in your zip file, which is not needed.
- a disabled menu handles the mouse press, but looks like this is a 4GL "feature"; on a similar note, a disabled menu item can be highlighted when mouse is hovering it (see "mt02").
- in ChUI the menubar is no longer being drawn properly.
- there is a conversion issue, if the a
sub-menu
(and maybe menu too) exists more than once with the same name in different procedures, but with different content, then only one of it survives... you need to scope/keep the menu details (at conversion time) per the external program defining it. I suppose you have some global map which doesn't differentiate where the menu is defined.
1. Some MENUBAR items ("First") disappear when I move mouse pointer from "Insider" to "Exit" in the sub-menu "Submenu". During mouse events (ENTER/EXIT) processing I'm calling
parent().repaint()
that causes sub-menu "Submenu" to be repainted. But sub-menu's rectangle doesn't intersect with "First" menu-item. It looks like that is the reason of "First" disappearing. I'm I right? If yes - does it mean that I should repaint all menu when processing any mouse event?
The problem is with the bodyLocation
impl: this returns a location relative to parent, but you use it in a paint event (in SubMenu.hideBody
and SubMenu.showBody
), which requires absolute coordinates, not relative coordiantes. So keep in mind: always use absolute coordinates with PaintEvent
.
2. The width of sub-menu "Insider" body is less than clipping rectangle width used to draw it. It is about 121px (measured by KRule) and the clipping rectangle has 131px (debugged
clip
inSubMenuGuiImpl.draw()
line 228).
I can't understand why. Could you look it?
An inner clipping rectangle is always intersected with any outer clipping rectangle, when gd.draw
is called. So if the parent gd.draw
call has a clipping rectangle with a width of 121px, then any inner gd.draw
will be able to clip at most 121px - as this is the maximum width intersection. So something is computed wrong: either the body or the parent's width is incorrect.
#407 Updated by Vadim Gindin almost 9 years ago
Created task branch 1790d from P2J trunk revision 10893
#408 Updated by Vadim Gindin almost 9 years ago
Constantin, could you look at my current changes in 1790d?
Here is my testcase:
ef button but label "button". def frame f but. def sub-menu sbm menu-item mi1 label "mi1". menu-item mi2 label "mi2". def menu ssm menu-item mm label "Elthonnnnnn" toggle-box. sub-menu sbm label "John". menu-item mmm label "Zamir". assign menu-item mm:checked = true. /*assign menu-item mmm:sensitive = false.*/ assign but:popup-menu = menu ssm:handle. enable all with frame f. wait-for choose of but.
Here is simple pop-up menu with one nested submenu. I've debugged sub-menu drawing and found that body location is: [107, 0] and body dimension is [w=58, h=46] in pixels. I can't understand why submenu body width is truncated. It must have width 58px, but as a fact it has 48px approximately. I've also debugged, that in com.goldencode.p2j.ui.client.gui.driver.swing.SwingEmulatedWindow.draw(PaintStructure<Font, BufferedImage>)
corresponding PaintStructure is processed and has the width=58px. No PaintEvent with corresponding rectangle is created.
Could you help me to find why sub-menu body is truncated and where the truncating is happen?
#409 Updated by Constantin Asofiei almost 9 years ago
Vadim Gindin wrote:
As I mentioned in the previous note, is all about nested clipping rectangles:Could you help me to find why sub-menu body is truncated and where the truncating is happen?
- the sub-menu has a clipping rectangle of width 152. its actual width is 107
- the sub-menu's children (the "body") is drawn starting from column 107
- the clipping rectangle for the body has a width of 58 px. But, considering the parent has already a clipping rectangle of width 152 from which 107px are occupied by the "title", it leaves you only a width of 46 pixels to work. But, the body requires a width of 58 px (so you are short of 152 - (107+58) = 13px).
Nested clipping rectangles are always intersected. I think you need to fix the width of the sub-menu's clipping rectangle (enlarge it so that it encloses the the width-est sub-menu hierarchy; here, consider nested sub-menus, etc).
On a second thought, the sub-menu's "body" is completely separated by its "title" - it acts like a different widget, just that is "pinned" at a certain location. What you can do is separate the body and the title drawing, so they are no longer nested. Thus, you will have two separate gd.draw
calls, each one with its own clipping rectangle. And the title will no longer be required to have a clipping rectangle larger than the area being drawn - it will just be the area of the title's rectangle.
#410 Updated by Vadim Gindin almost 9 years ago
I faced with the difficulty. When nested submenus exceed window size (width or height) they do not shrink to window size in Progress and they do shrink in P2J. I don't know how to fix it. As I think rectangles clipping works inside the active window. Am I right? I it is so - how to fix it?
#411 Updated by Greg Shah almost 9 years ago
This is a problem, but do not work on it now. We will leave this as a TODO.
We also have this same problem with the drop-down component of ComboBox
. They will have to be parented by an invisible top-level window that allows them to draw outside of the visible window that they are parented by in Progress 4GL terms.
#412 Updated by Vadim Gindin almost 9 years ago
When I refactored menu classes I removed unneeded fields from classes and those setters, that appear in config classes. I removed for example setDColor(int)
setter. The base class contains only setters: setDColor(NumberedType)
or setDColor(Color)
.
How to correctly emit color setters: should I emit parameters as Color
or NumberedType
instances or I should add setDColor(int) back to menu classes?
#413 Updated by Greg Shah almost 9 years ago
As Constantin and I have noted multiple times:
the MenuContainerWidget needs to inherit from BaseEntity.
Search above for BaseEntity
in this task to see the discussions. If this was done, then you would not have to duplicate so much code for getters/setters.
#414 Updated by Vadim Gindin almost 9 years ago
I faced with the following conversion problem. I have a testcase with different triggers defined and here are 2 of them:
on choose of menu-item mi, sub-menu sm message "mi, sm". on menu-drop, choose of sub-menu sm in menu m, menu m message "md, choose: sm, m".
These triggers are converted to the following code:
EventList list6 = new EventList(); list6.addEvent("choose", new handle[] { MenuItemWidget.findMenuItemStatic("mi"), SubMenuWidget.findSubMenuStatic("sm") }); /* 6 */; registerTrigger(list6, TriggerBlock6.class, Triggers.this); EventList list7 = new EventList(); list7.addEvent(new String[] { "menu-drop", "choose" }, new handle[] { m.getSelf().findSubMenu("sm"), m.getSelf() }); /* 7 */; registerTrigger(list7, TriggerBlock7.class, Triggers.this);
- Compile error: P2J tries to emit an array of handles:
new handle[] {...}
, but - Menu objects references (in triggers and other cases) are converted to
Menu*.find*
static methods calls. They methods always return widget instances not handles. EventList.addEvent(String, Object[])
andEventList.addEvent(String[], Object[])
methods support both values of second parameter: array of widgets and array of handles. So, the easiest way is to emitnew Object[]
instead ofnew handle[]
for the value of second parameter ofaddEvent
.
Is this way acceptable? If yes - could you recall me where that emission is happen?
#415 Updated by Greg Shah almost 9 years ago
So, the easiest way is to emit new Object[] instead of new handle[] for the value of second parameter of addEvent.
Yes, this is OK.
could you recall me where that emission is happen?
See line 2022 of ui_statements.rules
.
#416 Updated by Vadim Gindin almost 9 years ago
It seems, that GUI menu widgets use only system colors. Documentation says that it is possible to set bgcolor and fgcolor for SUB-MENU widget, but these values aren't used.
ACCELERATOR attribute for MENU-ITEM is a key label of a key, assigned to this menu-item. I faced with the following behavior: When I specified ACCELERATOR as "PAGE-DOWN" Progress displayed it as "PgDn" for that MENU-ITEM. For CHUI there are only one label corresponds to "PAGE-DOWN" function. It is a "PAGE-DOWN" itself, but for GUI, there are possible several labels: "PAGE-DOWN", "PGDN", "NEXT-PAGE", "NEXT-SCRN". It seems "PgDn" is the default. Is that supported? If not - should I implement it now or later?
#417 Updated by Greg Shah over 8 years ago
It is a "PAGE-DOWN" itself, but for GUI, there are possible several labels: "PAGE-DOWN", "PGDN", "NEXT-PAGE", "NEXT-SCRN". It seems "PgDn" is the default.
Constantin: what do you think?
#418 Updated by Greg Shah over 8 years ago
Greg Shah wrote:
It is a "PAGE-DOWN" itself, but for GUI, there are possible several labels: "PAGE-DOWN", "PGDN", "NEXT-PAGE", "NEXT-SCRN". It seems "PgDn" is the default.
Constantin: what do you think?
I should be more specific. I see that the order of the alternate key functions is defined in GuiKeyboard.standardKeyFunctions()
. I assume we have some reasons for specifying the order this way, but I don't recall the dependencies. Does changing the order to have "PGDN" first cause a problem with other lookup code?
#419 Updated by Constantin Asofiei over 8 years ago
Greg Shah wrote:
Greg Shah wrote:
It is a "PAGE-DOWN" itself, but for GUI, there are possible several labels: "PAGE-DOWN", "PGDN", "NEXT-PAGE", "NEXT-SCRN". It seems "PgDn" is the default.
Constantin: what do you think?
I should be more specific. I see that the order of the alternate key functions is defined in
GuiKeyboard.standardKeyFunctions()
. I assume we have some reasons for specifying the order this way, but I don't recall the dependencies. Does changing the order to have "PGDN" first cause a problem with other lookup code?
Changing the order will affect kblabel("page-down")
, which returns PAGE-DOWN
, not PGDN
- Keyboard.kbLabel
returns the first item in a LinkedHashSet
.
Vadim: please point the testcase which shows your PGDN
problem problem.
#420 Updated by Vadim Gindin over 8 years ago
Here it is
define sub-menu sm1 menu-item mi label "Mi1 item" accelerator "PAGE-DOWN". menu-item mi1 label "Mi1 i333tem" accelerator "PgUp". define sub-menu sm2 sub-menu sm1 label "SM1 Submenu34343". menu-item mii label "Mi2 item". define menu m1 menubar sub-menu sm2 label "SM2 Submenu". menu-item exit label "Exit". assign current-window:menubar = menu m1:handle. wait-for choose of menu-item exit.
Have a look how the menu-item "Mi1 item" looks. It's accelerator is shown as "PgDn", but it defined as "PAGE-DOWN".
#421 Updated by Constantin Asofiei over 8 years ago
Vadim Gindin wrote:
Here it is
[...]
Have a look how the menu-item "Mi1 item" looks. It's accelerator is shown as "PgDn", but it defined as "PAGE-DOWN".
Try this: is it possible that the accelerator's text (in case of menu) is the shortest label for that function? Using "INSERT" and "RETURN" produces "INS" and "ENTER".
#422 Updated by Vadim Gindin over 8 years ago
Constantin Asofiei wrote:
Vadim Gindin wrote:
Here it is
[...]
Have a look how the menu-item "Mi1 item" looks. It's accelerator is shown as "PgDn", but it defined as "PAGE-DOWN".
Try this: is it possible that the accelerator's text (in case of menu) is the shortest label for that function? Using "INSERT" and "RETURN" produces "INS" and "ENTER".
May be. I'll check it.
1. What about the case of letters? Note, that "PgDn" is shown in the specified testcase, but Documentation defines "PGDN" and specified earlier GuiKeyboard
also defines "PGDN".
2. I would also propose the following. Documentation defines the table of "Alternate Key Labels" (Programming Handbook, Table 6-3). I.e. there could be a primary key label "PAGE-DOWN" and other labels are alternate. "PGDN" is the first alternate label from specified table. I only didn't find the ways of using of alternate key labels. Documentation doesn't cover where they are used and how concrete alternate label is selected for appropriate operation.
What do you think?
#423 Updated by Constantin Asofiei over 8 years ago
Vadim Gindin wrote:
1. What about the case of letters? Note, that "PgDn" is shown in the specified testcase, but Documentation defines "PGDN" and specified earlier
GuiKeyboard
also defines "PGDN".
Yes, that's problematic, too. Maybe 4GL uses a different table for the accelerator labels? Maybe is someting win32/gdi specific?
2. I would also propose the following. Documentation defines the table of "Alternate Key Labels" (Programming Handbook, Table 6-3). I.e. there could be a primary key label "PAGE-DOWN" and other labels are alternate. "PGDN" is the first alternate label from specified table. I only didn't find the ways of using of alternate key labels. Documentation doesn't cover where they are used and how concrete alternate label is selected for appropriate operation.
What do you think?
This can't work, as for RETURN
, the first one, ENTER
, is the one used by menu, too. Also, for DELETE
, it shows Shift+Ctrl+@, not DEL
.
#424 Updated by Vadim Gindin over 8 years ago
Please review the code. Current revision is 10909.
#425 Updated by Constantin Asofiei over 8 years ago
- about mnemonic: what happens if there is more than a
&
char? Menu.getFirstEnabledWidget
- why not override it in the ChUI implementation instead of checking if we are in ChUI or not?MenuItemWidget
- there is an extra line before the last}
.SubMenuConfig
,SubMenuWidget
,MenuItem
,WidgetRegistry
,AbstractWidget
are missing a history entry.menu_generator.xml
,SubMenu
,WindowChuiImpl
,WindowLayout
have 2 history entries - please merge themToggleBoxGuiImpl
- please place the static method on its correct location; double-check other classes, too, if new APIs were addedAbstractWidget.requestFocus
- why do you need the&& !currentFocus.equals(this.parent())
test?AbstractWidget.mouseClicked
- by default this should be a no-op. Are you saying that a pop-up can be attached to any widget? If not, please extract the code in a helper method and call it only from widgets which accept a pop-up.Menu.findMenuItem
-Keyboard.keyCode(accel) == accelCode
is comparing references, not values... you need to useString.equals
to compare string instances.SubMenu.repaint
- you have some extra lines at the end of the method.SubMenu
- please place the abstract methods in the correct place.Window.getMenubar
javadoc is incorrectWindowLayout.doLayout
- I don't understand whymbarHeight
defaults to 23 - what if there is no menubar?- please rebase your branch, I want to test how the drawing is done now.
#426 Updated by Vadim Gindin over 8 years ago
Constantin Asofiei wrote:
Review for branch 1790d, revision 10909:
- about mnemonic: what happens if there is more than a
&
char?
I didn't understand this question. If there are something like this "Menu&&item" than mnemonic should be "&". I'll check it.
Menu.getFirstEnabledWidget
- why not override it in the ChUI implementation instead of checking if we are in ChUI or not?
I've refactored it.
AbstractWidget.requestFocus
- why do you need the&& !currentFocus.equals(this.parent())
test?
I've removed it. This change became not actual.
AbstractWidget.mouseClicked
- by default this should be a no-op. Are you saying that a pop-up can be attached to any widget? If not, please extract the code in a helper method and call it only from widgets which accept a pop-up.
There are a lot of widgets, that support pop-up menus, so it is simpler to implement AbstractWidget.mouseClicked
.
Menu.findMenuItem
-Keyboard.keyCode(accel) == accelCode
is comparing references, not values... you need to useString.equals
to compare string instances.
There are 2 int
values.
WindowLayout.doLayout
- I don't understand whymbarHeight
defaults to 23 - what if there is no menubar?
I forgot about that. Fixed.
- please rebase your branch, I want to test how the drawing is done now.
I've rebase 1790d branch. Current revision is 10917. Now you can try it.
#427 Updated by Constantin Asofiei over 8 years ago
Vadim Gindin wrote:
Constantin Asofiei wrote:
Review for branch 1790d, revision 10909:
- about mnemonic: what happens if there is more than a
&
char?I didn't understand this question. If there are something like this "Menu&&item" than mnemonic should be "&". I'll check it.
I meant something like this Ver&y Lon&g M&enu &Text
.
I've rebase 1790d branch. Current revision is 10917. Now you can try it.
The only issue: can you try to implement the sub-menu drawing/size like I mentioned in note 409?
On a second thought, the sub-menu's "body" is completely separated by its "title" - it acts like a different widget, just that is "pinned" at a certain location. What you can do is separate the body and the title drawing, so they are no longer nested. Thus, you will have two separate gd.draw calls, each one with its own clipping rectangle. And the title will no longer be required to have a clipping rectangle larger than the area being drawn - it will just be the area of the title's rectangle.
What I don't like is that the sub-menus boundary is a rectangle which covers its text and its children as if they are entirely expanded. I would like to have a more separation between the sub-menu "title" and its children.
Also, please test with multiple nesting levels of sub-menus
#428 Updated by Vadim Gindin over 8 years ago
Constantin Asofiei wrote:
Vadim Gindin wrote:
Constantin Asofiei wrote:
Review for branch 1790d, revision 10909:
- about mnemonic: what happens if there is more than a
&
char?I didn't understand this question. If there are something like this "Menu&&item" than mnemonic should be "&". I'll check it.
I meant something like this
Ver&y Lon&g M&enu &Text
.
Acting: mnemonic is the character after the first met &
. Drawing: All substrings of &
with the length > 1 will be replaced by "&". For example the title Ver&y Lon&&&g M&enu &Text
will be displayed as Very Lon&g Menu Text
and it's mnemonic will be y
I'll fix it.
I've rebase 1790d branch. Current revision is 10917. Now you can try it.
The only issue: can you try to implement the sub-menu drawing/size like I mentioned in note 409?
On a second thought, the sub-menu's "body" is completely separated by its "title" - it acts like a different widget, just that is "pinned" at a certain location. What you can do is separate the body and the title drawing, so they are no longer nested. Thus, you will have two separate gd.draw calls, each one with its own clipping rectangle. And the title will no longer be required to have a clipping rectangle larger than the area being drawn - it will just be the area of the title's rectangle.
What I don't like is that the sub-menus boundary is a rectangle which covers its text and its children as if they are entirely expanded. I would like to have a more separation between the sub-menu "title" and its children.
Also, please test with multiple nesting levels of sub-menus
If I'll split sub-menu rectangle by 2 rectangles for a title and for a body, body rectangle will not intersect it's parent. So will redrawing be working?
#429 Updated by Constantin Asofiei over 8 years ago
Vadim Gindin wrote:
If I'll split sub-menu rectangle by 2 rectangles for a title and for a body, body rectangle will not intersect it's parent. So will redrawing be working?
Correct, I didn't think of that - the body is part of the same widget class, not a distinct one. Leave it as is for now - focus on checking if multi-level sub-menu nesting works properly and any other issues you have on your list.
#430 Updated by Vadim Gindin over 8 years ago
Constantin,
Have a look at SubMenuGuiImple.draw()
method and at the second gd.draw()
call in it which draws the body. You can see the call of gd.fill3DRect()
there, but I don't see 3D-effect when body is drawn. Don't you know why?
Thanks
#431 Updated by Constantin Asofiei over 8 years ago
Vadim Gindin wrote:
Constantin,
Have a look at
SubMenuGuiImple.draw()
method and at the secondgd.draw()
call in it which draws the body. You can see the call ofgd.fill3DRect()
there, but I don't see 3D-effect when body is drawn. Don't you know why?Thanks
There are some issues with the body location and the clipping rectangle. I'm looking into it.
#432 Updated by Constantin Asofiei over 8 years ago
- the highlighted text is drawn 2-pixels to the left. I think this is a coordinate problem during layout (or body location?).
- when pressing
First
, the program terminates for some reason. - input is not accepted if there is a
UPDATE
statement instead ofWAIT-FOR
:define sub-menu sm0 menu-item mt01 label "Amadeus Mozart". menu-item mt02 label "Ludvig Bethoven" disabled toggle-box. rule. menu-item mt03 label "Adin Shteinzalc". skip. menu-item mt04 label "Jack London". define sub-menu sm menu-item mt4 label "Exit". sub-menu sm0 label "Insider". define menu men1 menubar menu-item mit1 label "Firs&t" menu-item mit2 label "S&econd" disabled. sub-menu sm label "Submenu". menu-item mit3 label "Third". menu-item mt02:checked = true. assign current-window:menubar = menu men1:handle. def var i as int. update i with frame f1.
Is the menu-bar "blocked" in its own event processing loop? Focus should be able to be switched between menubar and any enabled widget.
#433 Updated by Vadim Gindin over 8 years ago
Constantin,
I wanted to answer about your changes after fixing of the bug I'm currently working on. I need an advice. Here is my procedure:
define sub-menu sm menu-item mi label "smiii". define sub-menu smd sub-menu sm label "smm-sm". define menu m menubar sub-menu smd label "sub" menu-item mi label "miii". assign current-window:menubar = menu m:handle. menu-item mi:label in menu m = "MIMI". menu-item mi:label in sub-menu sm = "MISM". sub-menu sm:label in menu m = "SBM". sub-menu sm:label in sub-menu smd = "SSMM". wait-for choose of menu-item mi in menu m.
I found that this menubar will not be able to receive events. At the same time If I'll move assign current-window:menubar = menu m:handle.
statement after dynamic label settings of menu-item and sub-menu, than MENUBAR will work.
The reason of this bug is in the flag visible
of MENUBAR. It is false
at the start. It become true
in Window.afterConfigUpdate()
method, i.e. when MENUBAR is assigned to a WINDOW. But after that during the server-side calls like menu-item mi:label in menu m = "MIMI".
MENUBAR.visible again become false.
After I change menu config (setting visible=true in my case), updated config along with others must be synchronized with server-side. Synchronizing process is not working because ServerConfigManager.widgetCfg
does not contain menu config.
I'm trying to fix it finding a good place in a server-side to call ServerConfigManager.addWidgetConfig(menuConfig)
. Is it a right way? If yes - could you recommend me such good place for that call?
Strange, but I didn't find where frame config is added to ConfigManager
.
#434 Updated by Constantin Asofiei over 8 years ago
Vadim Gindin wrote:
Constantin,
I wanted to answer about your changes after fixing of the bug I'm currently working on. I need an advice. Here is my procedure:
[...]I found that this menubar will not be able to receive events. At the same time If I'll move
assign current-window:menubar = menu m:handle.
statement after dynamic label settings of menu-item and sub-menu, than MENUBAR will work.The reason of this bug is in the flag
visible
of MENUBAR. It isfalse
at the start. It becometrue
inWindow.afterConfigUpdate()
method, i.e. when MENUBAR is assigned to a WINDOW. But after that during the server-side calls likemenu-item mi:label in menu m = "MIMI".
MENUBAR.visible again become false.After I change menu config (setting visible=true in my case), updated config along with others must be synchronized with server-side. Synchronizing process is not working because
ServerConfigManager.widgetCfg
does not contain menu config.I'm trying to fix it finding a good place in a server-side to call
ServerConfigManager.addWidgetConfig(menuConfig)
. Is it a right way? If yes - could you recommend me such good place for that call?Strange, but I didn't find where frame config is added to
ConfigManager
.
The static c'tor in ClientConfigManager
has the entire WidgetConfig hierarchy - so no need for adding it. Also, server-side never implicitly pushes configs to the client - only client-side does this.
What you need for your menubar (when i.e. LABEL
is changed) is a version of pushScreenDefinition
- a pushMenuDefinition
API which pushes to the client-side the current menubar config. Otherwise, without pushing it explicitly, the menubar will not be updated. A good test for this is adding a PAUSE after each LABEL attribute change, as in:
menu-item mi:label in menu m = "MIMI". pause.
If the menubar is attached to a window, the change is observed immediately on the client-side - so you need a
pushMenuDefinition
to push the menu changes.#435 Updated by Vadim Gindin over 8 years ago
I probably wasn't clear. Synchronizing server->client
works. I already have MenuContainerWidget.pushMenuDefinition
method.
My difficulty is in an opposite direction. The change of visible
flag happen on the client-side. That change is transferred to server-side. LogicalTerminal.applyChanges
calls mgr.applyConfigUpdates(cfgUpdate);
where mgr
is a ServerConfigManager. Now have a look at ConfigManager.applyConfigUpdates(WidgetConfigUpdates cfgUpdate)
:
WidgetId wid = new WidgetId(cfgUpdate.widgetId); WidgetConfigDef wdef = widgetCfg.get(wid); if (wdef == null) { return; }
wdef
is null here, i.e. menu config is not found in this ServerConfigManager
by id transferred from the client-side.
#436 Updated by Constantin Asofiei over 8 years ago
Vadim Gindin wrote:
OK, there are a couple of issues:I probably wasn't clear. Synchronizing
server->client
works. I already haveMenuContainerWidget.pushMenuDefinition
method.
- client-side menu
initialize
methods are incorrect; correct body is:config = ConfigManager.getInstance().resolveWidgetConfig(id, cfg); ConfigManager.getInstance().replaceConfig(config, cfg);
This ensures the configs are registered with theConfigManager
- all the attribute changes in
Window.afterConfigUpdate
(where menu layout/enable is done) are not being tracked - this is called fromConfigManager.replaceConfig
, which disables tracking for this purpose. You need to extract the code fromWindowGuiImpl.afterConfigUpdate
into a separate method and call it fromWindow.pushConfig
.
#437 Updated by Vadim Gindin over 8 years ago
About "PgDn" string origin in accelerator, where "PAGE-DOWN" is specified. Here are the following results:
- VK_NEXT (0x22) - windows virtual key, corresponding to PAGE-DOWN key on a keyboard. [[https://msdn.microsoft.com/ru-ru/library/windows/desktop/dd375731%28v=vs.85%29.aspx]]
- GetKeyNameTxt (user32.lib) - is a special function returning string name of key in a keyboard [[https://msdn.microsoft.com/ru-ru/library/windows/desktop/ms646300%28v=vs.85%29.aspx]]:
The format of the key-name string depends on the current keyboard layout. The keyboard driver maintains a list of names in the form of character strings for keys with names longer than a single character. The key name is translated according to the layout of the currently installed keyboard, thus the function may give different results for different input locales. The name of a character key is the character itself.
Conclusion:
This function returned exactly "PgDn" for VK_NEXT (0x22=34 in a decimal notation). So I think that is the origin of our "PgDn" string, i.e. "PAGE-DONW" accelerator is somehow designates a key on a keyboard with the code VK_NEXT and resulting string got by calling GetKeyNameTxt
function.
How can we reproduce this behavior in P2J and should we do it?
#438 Updated by Vadim Gindin over 8 years ago
I've made these corrections, but it didn't helped. All proposed changes are in the client-side. Menu config change (visible=true) is transfered to server-side successfully, but during its processing in server-side it is not saved to menu config, because ServerConfigManager doesn't contain menu config.
Constantin Asofiei wrote:
Vadim Gindin wrote:
OK, there are a couple of issues:I probably wasn't clear. Synchronizing
server->client
works. I already haveMenuContainerWidget.pushMenuDefinition
method.
- client-side menu
initialize
methods are incorrect; correct body is:
[...]
This ensures the configs are registered with theConfigManager
- all the attribute changes in
Window.afterConfigUpdate
(where menu layout/enable is done) are not being tracked - this is called fromConfigManager.replaceConfig
, which disables tracking for this purpose. You need to extract the code fromWindowGuiImpl.afterConfigUpdate
into a separate method and call it fromWindow.pushConfig
.
In Window.afterConfigUpdate
there are no window config changes, only one menu config change: visible=true. Is it anyway important to move the code to Window.pushConfig
?
#439 Updated by Constantin Asofiei over 8 years ago
Vadim Gindin wrote:
I've made these corrections, but it didn't helped. All proposed changes are in the client-side. Menu config change (visible=true) is transfered to server-side successfully, but during its processing in server-side it is not saved to menu config, because ServerConfigManager doesn't contain menu config.
I've fixed it in 1790d rev 10921 - you were not registering the widget config for the menubar on server-side.
In
Window.afterConfigUpdate
there are no window config changes, only one menu config change: visible=true. Is it anyway important to move the code toWindow.pushConfig
?
I was wrong about this, afterConfigUpdate
does track the changes; only applyConfig
doesn't track them.
#440 Updated by Greg Shah over 8 years ago
This function returned exactly "PgDn" for VK_NEXT (0x22=34 in a decimal notation). So I think that is the origin of our "PgDn" string, i.e. "PAGE-DONW" accelerator is somehow designates a key on a keyboard with the code VK_NEXT and resulting string got by calling GetKeyNameTxt function.
Interesting findings.
How can we reproduce this behavior in P2J and should we do it?
Yes, we must implement this.
The answer to how, is simple: capture the result of the WIN32 API call for each key code that we support. Store that in a map and use it for the accelerator text. Implement this as a new API in the keyboard support classes. The GUI version would use this map as a backing source. The ChUI version can do something else.
Constantin: what do you think?
#441 Updated by Constantin Asofiei over 8 years ago
Greg Shah wrote:
The answer to how, is simple: capture the result of the WIN32 API call for each key code that we support. Store that in a map and use it for the accelerator text. Implement this as a new API in the keyboard support classes. The GUI version would use this map as a backing source. The ChUI version can do something else.
Constantin: what do you think?
I'm OK with the suggestion, I can't think of a better way to do it.
#442 Updated by Vadim Gindin over 8 years ago
Constantin Asofiei wrote:
Greg Shah wrote:
The answer to how, is simple: capture the result of the WIN32 API call for each key code that we support. Store that in a map and use it for the accelerator text. Implement this as a new API in the keyboard support classes. The GUI version would use this map as a backing source. The ChUI version can do something else.
Constantin: what do you think?
I'm OK with the suggestion, I can't think of a better way to do it.
- Doesn't confuse you the following comment from MSDN:
The format of the key-name string depends on the current keyboard layout.
? It means the if the layout is different - such table could also be different. - What about the key codes from MSDN? For example VK_NEXT has code 0x22 (34 in decimal notation). "PAGE-DOWN" key has code 508 in P2J. So it seems, that these MSDN codes are specific for Windows and I will need to have additional map:
P2J key code -> Windows virtual key code
, where Windows virtual key codes got from [[https://msdn.microsoft.com/ru-ru/library/windows/desktop/dd375731%28v=vs.85%29.aspx]]. Is that ok?
#443 Updated by Greg Shah over 8 years ago
The format of the key-name string depends on the current keyboard layout.
Yes, it is a concern. It means that for each keyboard layout to be supported, we need to capture a new set of values.
I would hope that we could "get away" with 1 set per I18N locale, but we will see. Can you design an approach to allow swapping sets of values in at runtime? I suspect we need an interface that provides the lookup API and then we would have classes that implement the interface, one implementer per keyboard layout.
We would start with only supporting the ISO8859-1 environment that is the default for Progress.
As an alternative, we can store the 8859-1 data as the defaults in the keyboard class and then allow overriding that data from the directory OR from an XML file that is loaded from a jar (P2J or application).
What about the key codes from MSDN? For example VK_NEXT has code 0x22 (34 in decimal notation).
As far as I understand it, the Windows key-code is not needed by us, ever. It is not exposed to the 4GL, so we don't need to track it. We just need to map the 4GL key codes to the proper accelerator text.
Of course, the program you use to capture this data should be written to know the mapping between the 4GL key codes and the Windows key codes. It's output should be map entries for the 4GL key code, but it must lookup the Windows key code to pass to the WIN32 API.
#444 Updated by Vadim Gindin over 8 years ago
Greg Shah wrote:
The format of the key-name string depends on the current keyboard layout.
Yes, it is a concern. It means that for each keyboard layout to be supported, we need to capture a new set of values.
I would hope that we could "get away" with 1 set per I18N locale, but we will see. Can you design an approach to allow swapping sets of values in at runtime? I suspect we need an interface that provides the lookup API and then we would have classes that implement the interface, one implementer per keyboard layout.
OK.
We would start with only supporting the ISO8859-1 environment that is the default for Progress.
As an alternative, we can store the 8859-1 data as the defaults in the keyboard class and then allow overriding that data from the directory OR from an XML file that is loaded from a jar (P2J or application).
What about the key codes from MSDN? For example VK_NEXT has code 0x22 (34 in decimal notation).
As far as I understand it, the Windows key-code is not needed by us, ever. It is not exposed to the 4GL, so we don't need to track it. We just need to map the 4GL key codes to the proper accelerator text.
Of course, the program you use to capture this data should be written to know the mapping between the 4GL key codes and the Windows key codes. It's output should be map entries for the 4GL key code, but it must lookup the Windows key code to pass to the WIN32 API.
In other words:
The mapping P2J key code -> Window key code
will only be used in this auxiliary program to get the final mapping P2J key code -> Keyboard key name
corresponding to specific keyboard layout (default ISO8859-1). Such keyboard key name is used in P2J as accelerator. When we will need an other layout we will just execute this auxiliary program with different input parameter (name of layout).
Is that correct?
#445 Updated by Greg Shah over 8 years ago
Is that correct?
Yes, exactly right.
#446 Updated by Vadim Gindin over 8 years ago
I'm working on the following error. If the source procedure contains the statement WAIT-FOR with the event of some menu object (for example MENU-ITEM), than Progress shows the error: Run-time error in WAIT-FOR at line 6 (relative to expanded source) of work/menus/sm.p
and after I press spacebar Progress shows the main window with MENUBAR and works further. I.e. this error do not break an execution. Here is my procedure:
define menu m menubar menu-item mi label "MI E&xit". assign current-window:menubar = menu m:handle. wait-for choose of menu-item mi.
In other words WAIT-FOR statement doesn't like menu objects. I don't know why. I can suspect that WAIT-FOR expect that widgets specified in its events list will be already enabled (as documentation says) and menu-objects do not need to be enabled manually. This is only the hypothesis.
What do you think about it and how to implement this behavior?
#447 Updated by Vadim Gindin over 8 years ago
Short question. I'm confused a little.
When I move mouse pointer outside from the widget (menu-item for example) is the current focus changed?
At this moment FocusListener.onFocusLost
is not called in this case. Is that right?
#448 Updated by Constantin Asofiei over 8 years ago
Vadim Gindin wrote:
Short question. I'm confused a little.
When I move mouse pointer outside from the widget (menu-item for example) is the current focus changed?
At this moment
FocusListener.onFocusLost
is not called in this case. Is that right?
The question here is: do the menu bar/sub-menu/menu items support 4GL-style focus lost/gained events? If not, then I think when the menu bar is activated, we should be in a isolated event loop processing.
To test if the menu widgets support these events, add some entry/leave triggers for the menu widgets. Also, while the menu bar is activated, check if other triggers are invoked. Add a bogus trigger for some key and check if that trigger is visible while navigating the menu. If the trigger is not invoked, then we are in a isolated event loop processing. See how TC.checkForSystemEvent
is working with the combo-box.
#449 Updated by Greg Shah over 8 years ago
Vadim Gindin wrote:
I'm working on the following error. If the source procedure contains the statement WAIT-FOR with the event of some menu object (for example MENU-ITEM), than Progress shows the error:
Run-time error in WAIT-FOR at line 6 (relative to expanded source) of work/menus/sm.p
and after I press spacebar Progress shows the main window with MENUBAR and works further. I.e. this error do not break an execution. Here is my procedure:
[...]
Confirm that the WAIT-FOR does continue to execute by putting a MESSAGE statement after the WAIT-FOR. If this is just a warning but everything functions properly, then the MESSAGE statement should not be executed until you click on the menu item "Exit".
In other words WAIT-FOR statement doesn't like menu objects. I don't know why. I can suspect that WAIT-FOR expect that widgets specified in its events list will be already enabled (as documentation says) and menu-objects do not need to be enabled manually. This is only the hypothesis.
I don't think this is the only reason. Throughout this task you have posted many samples that have only menu-bar, sub-menus and menu items. In all of these you also have a WAIT-FOR. Presumably those samples are working without this warning.
However, in all of those other cases you had some other elements in the program that may be enough to avoid this warning:
- sub-menus
- triggers on the menu/sub-menus/menu-items
- a frame with enabled widgets
I think the presence of any of the above, may be enough to avoid the warning. Please check if adding each of these things (independently) can bypass the warning.
#450 Updated by Vadim Gindin over 8 years ago
Greg Shah wrote:
Vadim Gindin wrote:
I'm working on the following error. If the source procedure contains the statement WAIT-FOR with the event of some menu object (for example MENU-ITEM), than Progress shows the error:
Run-time error in WAIT-FOR at line 6 (relative to expanded source) of work/menus/sm.p
and after I press spacebar Progress shows the main window with MENUBAR and works further. I.e. this error do not break an execution. Here is my procedure:
[...]Confirm that the WAIT-FOR does continue to execute by putting a MESSAGE statement after the WAIT-FOR. If this is just a warning but everything functions properly, then the MESSAGE statement should not be executed until you click on the menu item "Exit".
I confirm: such is the case. MESSAGE is executed only when WAIT-FOR event is happen, i.e. item "Exit" is clicked. So it is just a warning.
In other words WAIT-FOR statement doesn't like menu objects. I don't know why. I can suspect that WAIT-FOR expect that widgets specified in its events list will be already enabled (as documentation says) and menu-objects do not need to be enabled manually. This is only the hypothesis.
I don't think this is the only reason. Throughout this task you have posted many samples that have only menu-bar, sub-menus and menu items. In all of these you also have a WAIT-FOR. Presumably those samples are working without this warning.
However, in all of those other cases you had some other elements in the program that may be enough to avoid this warning:
- sub-menus
- triggers on the menu/sub-menus/menu-items
- a frame with enabled widgets
I think the presence of any of the above, may be enough to avoid the warning. Please check if adding each of these things (independently) can bypass the warning.
I've seen this error long ago. I'd just postpone it for some time. Now I tested it. If a frame with enabled widgets persist in a window - than that error will not appear. Other cases (sub-menus/triggers) do not influence on this error. What do you think?
#451 Updated by Vadim Gindin over 8 years ago
Constantin Asofiei wrote:
Vadim Gindin wrote:
Short question. I'm confused a little.
When I move mouse pointer outside from the widget (menu-item for example) is the current focus changed?
At this moment
FocusListener.onFocusLost
is not called in this case. Is that right?The question here is: do the menu bar/sub-menu/menu items support 4GL-style focus lost/gained events? If not, then I think when the menu bar is activated, we should be in a isolated event loop processing.
To test if the menu widgets support these events, add some entry/leave triggers for the menu widgets. Also, while the menu bar is activated, check if other triggers are invoked. Add a bogus trigger for some key and check if that trigger is visible while navigating the menu. If the trigger is not invoked, then we are in a isolated event loop processing. See how
TC.checkForSystemEvent
is working with the combo-box.
Constantin,
About entry/leave I remember that question about isolated event loop processing earlier. When I added some key trigger to the source procedure - it wasn't called when I was in some sub-menu opened, but I was called when no sub-menu was opened - just menubar.
Sorry, my question wasn't enough clear. Talking about FocusListener.onFocusLost
- it is not called only when I'm moving mouse pointer out of the MENUBAR to empty space inside the window. But If I'll move mouse pointer from one menu-item to another in MENUBAR, than FocusListener.onFocusLost
will be called. That is the strange difference I've asked about.
What do you think?
#452 Updated by Greg Shah over 8 years ago
If a frame with enabled widgets persist in a window - than that error will not appear. Other cases (sub-menus/triggers) do not influence on this error. What do you think?
Please review ThinClient.waitForWorker()
. Identify the path through where:
- There are NO enabled frames.
- There ARE active menus.
In this case, and only this case, generate the warning using the appropriate ErrorManager
interface.
You should also check these:
- Does it matter if there are frames present, but they are NOT enabled? Or is the presence of any existing frame enough to avoid the warning?
- Does this warning affect the ERROR-STATUS:ERROR and/or the ERROR-STATUS recorded message numbers and text? This will change how you use the
ErrorManager
.
#453 Updated by Vadim Gindin over 8 years ago
Greg Shah wrote:
You should also check these:
- Does it matter if there are frames present, but they are NOT enabled? Or is the presence of any existing frame enough to avoid the warning?
Yes, it matter. When frame is not enabled - that warning will be shown. When frame is enabled - warning will not be shown.
- Does this warning affect the ERROR-STATUS:ERROR and/or the ERROR-STATUS recorded message numbers and text? This will change how you use the
ErrorManager
.
NO-ERROR is not supported for WAIT-FOR, so I can't check it.
#454 Updated by Greg Shah over 8 years ago
NO-ERROR is not supported for WAIT-FOR, so I can't check it.
Good point. That means it cannot be supported since ERROR-STATUS only is affected in NO-ERROR mode.
#455 Updated by Vadim Gindin over 8 years ago
Have a look please at FocusManager.undefImplicit()
:
... // find the very first enabled widget Widget first = getFirstEnabledWidget(); // Will be menu-item if (first == null) { // no enabled widgets; check event list for global events if (!UiUtils.checkEventList(list)) { // no global events; should exit immediately return false; } } // found an enabled widget; figure out the owning frame Frame<?> frame = (Frame<?>) UiUtils.locateFrame(first); // will be null for menu-item // My WARNING if (first != null && frame == null) { // ErrorManager.addError(3269, "", false); ErrorManager.displayError(3269, "Run-time error in WAIT-FOR at line 24 (relative to expanded source) of work/menu/sm.p"); return true; } // find the first enabled widget of the frame which accepts ENTRY while (first != null) { this.noFocusAdjustment = true; boolean state = first.focusTraversable(); // send ENTRY event and see the response boolean check = tc.sendEntry(first); ...
Is it a good place and good criteria? Should I really get the owning window and its menubar?
The problem is also in the following behavior. When the warning is shown, the status line contains "Press spacebar to continue", and after I press spacebar it cleans message area (remove warning) and began work normally. How to do the same "waiting for spacebar"?
#456 Updated by Greg Shah over 8 years ago
Is it a good place
Although this method is only called from the waitForWorker()
, it is not guaranteed to only ever be called from there. Putting WAIT-FOR specific logic in there is probably not correct.
I think the logic needs to be directly in the ThinClient
, though if you want to isolate it into a separate private method, that is good.
and good criteria?
It seems a bit "loose".
If FocusManager.getFirstEnabledWidget()
returns a menu widget, then you know there are no frames with enabled widgets, right?
How about calling that method, then checking the returned widget to see if it is a menu widget?
If FocusManager.focusUndefImplicit()
returns false
, then couldn't your code check (using the logic above) if a menu exists and then allow the WAIT-FOR to continue after generating the error?
If you think it is better to put the check inside the FocusManager
, please explain why in some detail.
I also wonder: can other methods like FocusManager.focusInvalidImplicit()
also be affected by this case?
Should I really get the owning window and its menubar?
I think you just need to check if there is a menubar/menu.
When the warning is shown, the status line contains "Press spacebar to continue", and after I press spacebar it cleans message area (remove warning) and began work normally. How to do the same "waiting for spacebar"?
This seems like a simple PAUSE. In fact, you can see in ThinClient.stopNoAvailableWidgets()
how this can be implemented. Your code would be different because it has no stop condition.
#457 Updated by Greg Shah over 8 years ago
Please post a list of all the remaining issues/todos/work for this task.
#458 Updated by Constantin Asofiei over 8 years ago
- for ChUI
pro -p <program-name.p>
- for GUI
prowin32 -p <program-name.p>
#459 Updated by Constantin Asofiei over 8 years ago
And why you need to do this: because the 4GL procedure editor is a 4GL program itself, and the behaviour is altered by this fact (especially initial focus/event processing).
#460 Updated by Vadim Gindin over 8 years ago
Thank you. You or Greg already told me about that some time before. I'm running tests on windev01 using that way, but for CHUI I was running tests in lindev01 instead of proposed method. Is that matter?
#461 Updated by Constantin Asofiei over 8 years ago
Vadim Gindin wrote:
... but for CHUI I was running tests in lindev01 instead of proposed method. Is that matter?
You can do this on either system, lindev01 or windev01, just make sure you are using the command line.
#462 Updated by Vadim Gindin over 8 years ago
Could somebody recall me, how to get procedure name and more important: line number?
#463 Updated by Greg Shah over 8 years ago
It is only available on the server side for now.
Please just an UnimplementedFeature.todo()
in the code that generates the message. In the message, put some kind of generic placeholders in like <line_num>
and <program_name>
. This case should not be hit often, so hopefully we won't have to fix this for the current project.
#464 Updated by Vadim Gindin over 8 years ago
I've rebase my branch 1790d please review. I've committed fix for warning on no enabled widgets. Current branch is 10944.
#465 Updated by Vadim Gindin over 8 years ago
There are the bug. When I click on some menu-item in sub-menu body - body is closed but under the menu-item there is some "trail": that menu-item title is printed after I'll move mouse pointer when (sub-menu body is closed just now). Could you look at it. Why it happen?
#466 Updated by Vadim Gindin over 8 years ago
- drawing for keyboard menu navigation mode.
- API for working with accelerators depending on the current keyboard layout.
- fix clicked menu-item title trail.
- further testing...
#467 Updated by Greg Shah over 8 years ago
Vadim: please rebase from trunk revision 10917.
Constantin is going to do a code review. Make any needed changes from that review.
We will get a final review after that if needed. Then you will put your 1790d branch into regression testing (both conversion and runtime).
The remaining todos can be implemented/fixed in a 1790e branch.
#468 Updated by Constantin Asofiei over 8 years ago
ui_statements.rules
- you haveH112 IAS ...
which I think is merged wrong, as this is a duplicate of H109 - please remove this.MenuConfig
- is missing history entrySubMenuWidget
- please expand the history entry comment to "Removed methods which are already defined in BaseEntity"ThinClient
- you have aTREE
on line 2135 (artifact from rebase, please remove it)
-warnNoEnabledFrames:17665
- remove the empty line at the end of the method
- line 17965: remove the empty line at the end of the classAbstractWidget
- is missing history entry
-mouseClicked:1237
- if the commented code is no longer needed, remove itWindowChuiImpl
-draw()
is just callingsuper.draw()
- remove the method completelyWindow
-draw():1439
- if the commented code is no longer needed, remove itSubMenu
-hideBody:115
- if the commented code is no longer needed, remove it
-setVisible:319
- if the commented code is no longer needed, remove it
-processMnemonicEvent:384
- remove the debugging sysout code
-processMnemonicEvent:388
- if the commented code is no longer needed, remove it
- put the abstract methods in the correct place (after the constructors)MenuItem
- put the static method in the correct place (after the constructors and abstract methods)Menu
-setVisible:144
* If the menu is being shown and not yet attached to a window, attached it to the default * window. ... if (visible && parent() == null) { setParent(Window.<O>getDefaultWindow()); }
Have you tested this? Is this the expected behavior in 4GL? Also, have you tested in GUI if the menu can be attached to a dynamic window, created viaCREATE WINDOW handle.
?
- put thegetFirstEnabledWidget
abstract method in the correct place (and static methods too)
- line 438 - remove the emtpy lineButtonGuiImpl
- is missing history entryToggleBoxGuiImpl
-drawCheckmark
- place the static method in the correct locationMenuGuiImpl
- you need an empty line before the classpackage
statementMenuItemGuiImpl
- you need an empty line before the classpackage
statement
- line 63/64: remove the commentedmouseDragged
field, if you no longer need it
- you have lots of constants like13
,5
,7
- please add class-level constants which describe their purposeSubMenuItemGuiImpl
- you need an empty line before the classpackage
statement
- this is a new file, but you have two history entries - please merge them
-mouseReleased
is commented
-findMouseSource:545
- you have commented code. if is not needed, remove it.
-childrenLocation:566..571
- you have commented code, remove it
- put the static methods in the correct place
- if you click outside of menubar while a sub-menu is opened, you must close the entire sub-menu hierarchy
- from note 465: I think the root cause is the fact that the menu, sub-menu and menu-item's VISIBLE flag is never set/unset by your code. You are replacing functionality which should depend on VISIBLE state with some DISPLAYED config field you've added. For all the menu widgets, in P2J their VISIBLE state is always true - that's why AbstractContainer.draw() catches a repaint for a "not displayed" widget and draws it, because it still sees it as "visible". This is also related to the 4GL menu widgets
VISIBLE
attribute - so please ensure this is tracked properly for all menu widgets; if it's tracked properly, there should be no other artifacts.
#469 Updated by Vadim Gindin over 8 years ago
Constantin Asofiei wrote:
...
Menu
-setVisible:144
[...]
Have you tested this? Is this the expected behavior in 4GL? Also, have you tested in GUI if the menu can be attached to a dynamic window, created viaCREATE WINDOW handle.
?
I've fixed it. Menu must be already attached to its parent in the method setVisible
.
I've retested it: menu can be attached to dynamic window.
...
Other issues (to be worked in 1790e):
- if you click outside of menubar while a sub-menu is opened, you must close the entire sub-menu hierarchy
I implemented such actions in FOCUS_LOST handlers of menu-item widgets.
The key problem here is how to catch that event. Have a look at AbstractWidget.requestFocus()
. This is the only place where EventType.FOCUS_LOST
event is sent. It means, If I'll click some widget, than FOCUS_LOST event will not be sent for the previous widget, because default mouse listener does nothing (doesn't call requestFocus
). That behavior doesn't look obvious. What do you think?
For some other bug I had to add requestFocus
call to mouseExited
handler.
- from note 465: I think the root cause is the fact that the menu, sub-menu and menu-item's VISIBLE flag is never set/unset by your code. You are replacing functionality which should depend on VISIBLE state with some DISPLAYED config field you've added. For all the menu widgets, in P2J their VISIBLE state is always true - that's why AbstractContainer.draw() catches a repaint for a "not displayed" widget and draws it, because it still sees it as "visible". This is also related to the 4GL menu widgets
VISIBLE
attribute - so please ensure this is tracked properly for all menu widgets; if it's tracked properly, there should be no other artifacts.
When MENUBAR is attached to a window or pop-up menu is shown for some widget I call menu.setVisible(true)
that call setVisible(true) for all children recursively. Do you propose to make work with VISIBLE flag more appropriate: when sub-menu body is hiding - call setVisible(false) for all its children recursively. Did I understand you correctly?
#470 Updated by Vadim Gindin over 8 years ago
I've rebased 1790d branch. Current revision is 10945. Have a look please. Can I run conversion/regression testing?
#471 Updated by Vadim Gindin over 8 years ago
Constantin Asofiei wrote:
...
Menu
-setVisible:144
[...]
Have you tested this? Is this the expected behavior in 4GL? Also, have you tested in GUI if the menu can be attached to a dynamic window, created viaCREATE WINDOW handle.
?
I've fixed it. Menu must be already attached to its parent in the method setVisible
.
I've retested it: menu can be attached to dynamic window.
#472 Updated by Constantin Asofiei over 8 years ago
H112 IAS
entry), Menu
abstract methods are still in the wrong place, etc. So:
- you can start a round of runtime testing with rev 10946 - conversion + runtime. Remember to do a conversion with trunk rev 10917 first and save the generated sources, to have a clean base for comparison.
- in the meantime, while testing is running, please go through all the review notes in 468 and make sure they are fixed. Post a note here when you have finished going through the entire list.
#473 Updated by Vadim Gindin over 8 years ago
Conversion testing is passed. Generated sources are identical. I've fixed all remarks, but didn't commit it yet. Can I do it while regression testing is running?
#474 Updated by Constantin Asofiei over 8 years ago
Vadim Gindin wrote:
I've fixed all remarks, but didn't commit it yet. Can I do it while regression testing is running?
Yes, you can start regression testing, as there will be no functional changes, just cleanups.
#475 Updated by Vadim Gindin over 8 years ago
Committed with rev 10947.
#476 Updated by Vadim Gindin over 8 years ago
After last rebase there is a new bug: warning is shown (when no enabled frames are defined). message area is not cleared after I pressed spacebar. I can't find why. Could you help me?
Another bug. There is a different place where warning is shown. Progress: warning is shown before menubar is became visible. Only after I press spacebar - menubar become visible and message area get cleared.
P2J: menubar becomes visible in Window.afterConfigUpdate()
i.e. when menubar is assigned to a window. It happen before WAIT-FOR processing, i.e. before warning show. So I'll have to change the place of warning processing from ThinClient.waitForWorker()
to some other place.
#477 Updated by Greg Shah over 8 years ago
So I'll have to change the place of warning processing from ThinClient.waitForWorker() to some other place.
I don't think moving the warning is the right idea. It seems that the real problem here is that in Progress, the visible attribute is not true before the WAIT-FOR.
#478 Updated by Vadim Gindin over 8 years ago
I've checked it just now. Here the procedure
define menu m1 menubar menu-item exit label "E&x&it". message "before: " + string(menu m1:visible). assign current-window:menubar = menu m1:handle. message "after: " + string(menu m1:visible). wait-for choose of menu-item exit. message "end: " + string(menu m1:visible).
It prints:
before: no after: yes end: yes (After I click "Exit")
It looks like menubar is visible before WAIT-FOR - just right after menubar assignment.
#479 Updated by Greg Shah over 8 years ago
It looks like menubar is visible before WAIT-FOR - just right after menubar assignment.
The visible
attribute is true
, but does the menu appear on the screen?
#480 Updated by Vadim Gindin over 8 years ago
Greg Shah wrote:
It looks like menubar is visible before WAIT-FOR - just right after menubar assignment.
The
visible
attribute istrue
, but does the menu appear on the screen?
Menubar appears on the screen after the warning is shown: after I press spacebar.
#481 Updated by Vadim Gindin over 8 years ago
- File testing_08_10.txt added
Regression testing is finished. There are several failed tests: gso_245, gso_206, gso_238, gso_269, tc_codes_employees_021, tc_codes_employees_24, tc_dc_slot_24, tc_dc_slot_25, tc_job_002, tc_job_clock_004.
tc_tests are looks as not related to menus. I met tc_codes_employees_021, tc_codes_employees_24 earlier. I'm working on gso* failed tests.
Testing results are attached.
#482 Updated by Vadim Gindin over 8 years ago
GSO_206. Strange, but in the test current screen is the different from expected:
timeout before the specific screen buffer became available (Mismatched data at line 0, column 0. Expected ' ' (0x0020 at relative Y 0, relati ve X 0) and found '0' (0x0030 at relative Y 0, relative X 0), template: screens/navigation/payroll.txt.)
Current failing screen:
confidential information redacted
Template (screen/navigation/payroll.txt):
MAJIC Payroll 04/06/2009 13:36 ┌────────────────────── TIMCO - Greensboro GSO TIPR833K ───────────────────────┐ │ │ │ 1 Work Record Inquiry by Number K Employee Work Records Report │ │ 2 Query Work Records by Employee # L Employee Work Records Summary │ │ 3 Employee Work Records M View/Search Timeatt Records │ │ 4 T & A Clock Violation Approvals N View/Search Jobtran Records │ │ 5 T & A Clock Violation Report O Employee Absence Accrual Report │ │ I Shop Floor Record Posting P Employee Wrk Rec Exceptions Report │ │ A Employee Accrual Periods Q Employee Work Record to ADP Output │ │ B Adjust Employee Absence Accruals T ADP Exceptions Report │ │ C Posted Jobtran Editor S T & A - SF Comparison Report │ │ D Rebuild Employee Accrual Records U Work Record Indirect Code Report │ │ E Build/Rebuild Man-Code Buckets V Report on Indirect Codes │ │ F Work Record/T & A Rebalance W Average Time by Crew Report │ │ G Work Records Summary Build X No Employee Clock Out Report │ │ H Floating Holiday Adjustments Y Not Clocked-in Report │ │ J T&A Clock-out Offenders Report R Return │ └──────────────────────────────[ No mail ]──────────────────────────────┘ [F1]-Launch [F4]-Prev Menu [?]-Browse [F2]-Help Function: pay.workrecinq Menu: payroll
Did I understand it right?
#483 Updated by Constantin Asofiei over 8 years ago
Please check the test(s) manually (step-by-step) and confirm the error is still there. There might be timeouts sometime due to devsrv01 load.
#484 Updated by Constantin Asofiei over 8 years ago
Vadim Gindin wrote:
GSO_206. Strange, but in the test current screen is the different from expected:
This is because GSO 206 is executed on the same thread (Driver 1), after GSO 245 - and as GSO 245 failed, it didn't position the client back on the main menu screen. So GSO 206 started with a wrong initial screen, thus the failure.
#485 Updated by Constantin Asofiei over 8 years ago
One more thing: to avoid checking the tests by hand, you can add the failed tests to majic_baseline/majic_single.xml
and then run majic_baseline/run_single.sh
- this can be used to check only a small sub-set of tests. The tests you need to add look like:
<test filename="gso/gso_245/gso_245.xml" /> <test filename="gso/gso_206/gso_206.xml" /> <test filename="gso/gso_238/gso_238.xml" /> <test filename="gso/gso_269/gso_269.xml" />
#486 Updated by Vadim Gindin over 8 years ago
First, I rerun full regression testing. Failed test are the following (intersected with previous run): gso_269, tc_codes_employees_21, tc_codes_employees_24). But now I've ran gso_269 using run_single.sh
and it has passed. Can we assume that regression testing is also passed?
#487 Updated by Constantin Asofiei over 8 years ago
Vadim Gindin wrote:
First, I rerun full regression testing. Failed test are the following (intersected with previous run): gso_269, tc_codes_employees_21, tc_codes_employees_24). But now I've ran gso_269 using
run_single.sh
and it has passed. Can we assume that regression testing is also passed?
Please double-check tc_codes_employees_21, tc_codes_employees_24 manually and if all is OK, then testing is passed.
Is branch 1790d ready for final review?
#488 Updated by Vadim Gindin over 8 years ago
tc_codes_employees_21, tc_codes_employees_24 are also passed testing. Yes, 1790d is ready for review.
#489 Updated by Constantin Asofiei over 8 years ago
Please rebase from trunk rev 10918 first, I'll finish the review shortly.
#490 Updated by Constantin Asofiei over 8 years ago
I'm good with the changes. Once you've rebased with 10918 (there will be no conflicts), you can merge to trunk.
Don't forget to "push overwrite" when you rebase.
#491 Updated by Vadim Gindin over 8 years ago
1790d is rebased with the latest revision. Current branch revision is 10948.
#492 Updated by Vadim Gindin over 8 years ago
The branch 1790d has been merged and committed into the trunk as bzr revision 10919.
#493 Updated by Vadim Gindin over 8 years ago
Created task branch 1790e from P2J trunk revision 10919.
#494 Updated by Greg Shah over 8 years ago
I think that the KW_ACCEL attribute support still needs to be added to methods_attributes.rules
.
#495 Updated by Vadim Gindin over 8 years ago
Ok, I'll fix it.
Why ThinClient.pause()
cleans the message area and status line only for CHUI (isChui()==true)? Is that really a common rule?
#496 Updated by Constantin Asofiei over 8 years ago
Vadim Gindin wrote:
Why
ThinClient.pause()
cleans the message area and status line only for CHUI (isChui()==true)? Is that really a common rule?
Hynek, weren't you working on this (or some similar issue)?
#497 Updated by Vadim Gindin over 8 years ago
Greg Shah wrote:
I think that the KW_ACCEL attribute support still needs to be added to
methods_attributes.rules
.
Did you mean some bug, related to this?
#498 Updated by Vadim Gindin over 8 years ago
It looks like if accelerator is specified = than converted Java-code will contain empty line with the only ';' symbol. Could you recall me where to add kw_accel to suppress this emission?
#499 Updated by Hynek Cihlar over 8 years ago
Constantin Asofiei wrote:
Vadim Gindin wrote:
Why
ThinClient.pause()
cleans the message area and status line only for CHUI (isChui()==true)? Is that really a common rule?Hynek, weren't you working on this (or some similar issue)?
Yes, I found that in GUI pause
doesn't clean existing messages.
#500 Updated by Constantin Asofiei over 8 years ago
Hynek Cihlar wrote:
Constantin Asofiei wrote:
Vadim Gindin wrote:
Why
ThinClient.pause()
cleans the message area and status line only for CHUI (isChui()==true)? Is that really a common rule?Hynek, weren't you working on this (or some similar issue)?
Yes, I found that in GUI
pause
doesn't clean existing messages.
I don't recall, were you working on fixing it?
#501 Updated by Vadim Gindin over 8 years ago
Constantin Asofiei wrote:
I'm currently working on it.Hynek Cihlar wrote:
Constantin Asofiei wrote:
Vadim Gindin wrote:
Why
ThinClient.pause()
cleans the message area and status line only for CHUI (isChui()==true)? Is that really a common rule?Hynek, weren't you working on this (or some similar issue)?
Yes, I found that in GUI
pause
doesn't clean existing messages.I don't recall, were you working on fixing it?
- I'm confused. The fact, that
pause
doesn't clean existing messages for GUI - is it a bug or right implementation?
At this moment I'm clearing message area and status line only for my task. If it is a bug, I'll probably need to fixpause()
implementation. - Another bug:
pause()
call blocks execution until user will click some button twice (not once). Could you propose why it could be?
I've committed my current changes (branch 1790e, rev 10920). Have a look, please.
#502 Updated by Hynek Cihlar over 8 years ago
Constantin Asofiei wrote:
Hynek Cihlar wrote:
Constantin Asofiei wrote:
Vadim Gindin wrote:
Why
ThinClient.pause()
cleans the message area and status line only for CHUI (isChui()==true)? Is that really a common rule?Hynek, weren't you working on this (or some similar issue)?
Yes, I found that in GUI
pause
doesn't clean existing messages.I don't recall, were you working on fixing it?
See trunk revision 10907.
#503 Updated by Greg Shah over 8 years ago
Vadim Gindin wrote:
It looks like if accelerator is specified = than converted Java-code will contain empty line with the only ';' symbol. Could you recall me where to add kw_accel to suppress this emission?
You added KW_ACCEL option support for language statements where menu items are defined.
What is missing is the support for KW_ACCEL as an attribute (e.g. menu-item:ACCELERATOR). This is in methods_attributes.rules
, an entry must be added to the load_descriptors
function. Of course, there are other places that may need editing such as adding the attribute keyword into the list of writable attributes in common-progress.rules
, adding the @LegacyAttribute
annotation to the interface getters/setters... You have added attributes before. Let me know if you have questions.
#504 Updated by Vadim Gindin over 8 years ago
Greg, thank you, I fixed it at the day before yesterday. By the way there is another one conversion bug: ';' remained in converted code for "ACCELERATOR" attribute. Could you recall me where to fix it?
I've committed API for Windows keyboard layouts for accelerators. Have a look please.
Greg Shah wrote:
Vadim Gindin wrote:
It looks like if accelerator is specified = than converted Java-code will contain empty line with the only ';' symbol. Could you recall me where to add kw_accel to suppress this emission?
You added KW_ACCEL option support for language statements where menu items are defined.
What is missing is the support for KW_ACCEL as an attribute (e.g. menu-item:ACCELERATOR). This is in
methods_attributes.rules
, an entry must be added to theload_descriptors
function. Of course, there are other places that may need editing such as adding the attribute keyword into the list of writable attributes incommon-progress.rules
, adding the@LegacyAttribute
annotation to the interface getters/setters... You have added attributes before. Let me know if you have questions.
#505 Updated by Greg Shah over 8 years ago
By the way there is another one conversion bug: ';' remained in converted code for "ACCELERATOR" attribute.
Please post the 4GL and the resulting Java here.
#506 Updated by Greg Shah over 8 years ago
Code Review Task Branch 1790e Revision 10922
1. The methods_attributes.rules
change should be in the load_descriptors
function (the "new way"). We are trying to reduce/eliminate the use of the section below (that section is the "old way").
2. The overall approach for accelerator attribute support is incomplete. The getAccelerator()
and setAccelerator()
methods are specific to menu-item, so it is appropriate that they are in MenuItemWidget
. But there is no proper interface definition for this attribute, there is no @LegacyAttribute
annotation, there is no proper handle
unwrapping for it, there is no addition to the HandleCommon
superinterface. It is important that you review and follow the proper requirements (as noted above) for implementing attributes.
3. Keyboard.keyName(), both versions are missing an
@return@ javadoc entry.
4. In the DefaultKeyboardLayout
class javadoc, please add a description of which keyboard layout is being used as the default. Is it a U.S. English keyboard layout...?
5. Is the warnNoEnabledFrames()
behavior correct for both ChUI and GUI?
#507 Updated by Vadim Gindin over 8 years ago
I'll fix these remarks these days. Short question: I need to draw mnemonics using underlined font. I set FontStyle.UNDERLINE
font style right before gd.drawString(..)
call. It don't work. How to draw underlined string correctly?
#508 Updated by Constantin Asofiei over 8 years ago
Vadim Gindin wrote:
Short question: I need to draw mnemonics using underlined font. I set
FontStyle.UNDERLINE
font style right beforegd.drawString(..)
call. It don't work. How to draw underlined string correctly?
There's no support for drawing only an underlined string yet. Only the full fonts can be forced to draw with an underline.
BTW, have you determined what font is used for the mnemonics? In either case, if is underlined, we can define a system font for it and set the underline
clause to it, but this is not finished yet - see FontTable.buildFontSpecifications
. Add this code after line 1318:
else if (tok.startsWith("underline")) { isUnderline = true; }
define an underlined font (i.e
tahoma size 8 underline
) and see if it works.
Underlined fonts/texts was left in a low priority because the 4GL's UNDERLINE
stmt doesn't actually underlines the text, it just draws a line...
#509 Updated by Vadim Gindin over 8 years ago
Constantin Asofiei wrote:
..
BTW, have you determined what font is used for the mnemonics?
I didn't specially determine that font, but it looks the same as the main font used for menus.
[...]
define an underlined font (i.etahoma size 8 underline
) and see if it works.
How to do that?
#510 Updated by Constantin Asofiei over 8 years ago
Vadim Gindin wrote:
Constantin Asofiei wrote:
..BTW, have you determined what font is used for the mnemonics?
I didn't specially determine that font, but it looks the same as the main font used for menus.
[...]
define an underlined font (i.etahoma size 8 underline
) and see if it works.How to do that?
I'll make a change to 1794c to support underline font and setting underline font style (temporarily).
The full mnemonic text needs to be underlined, correct? Otherwise we need support for partially underlined text.
#511 Updated by Constantin Asofiei over 8 years ago
Please take the changes from branch 1794c rev 10927 - I will merge it to trunk later today.
If the mnemonic really uses the same font as the menu, then you can use something like this to draw the mnemonic:
// set temporarily underlined font FontStyle tempStyle = FontStyle.createStyle(font.style.isBold(), font.style.isItalic(), true); gd.setFontStyle(tempStyle); // do work - draw mnemonic // restore style gd.setFontStyle(font.style);
#512 Updated by Constantin Asofiei over 8 years ago
And something else: you can split the menu text drawing in three parts: draw prefix, draw mnemonic, draw suffix.
#513 Updated by Vadim Gindin over 8 years ago
- File simple_sm.p added
Constantin, could you have a look at my CHUI implementation. I faced with the following bug: when sub-menu is hiding screen is not fully cleared of it. See attached procedure. When the latest nested menu is hiding there are its trail is stayed (not cleared). I can't find why. Could you help me? Current revision is 10927.
#514 Updated by Vadim Gindin over 8 years ago
Constantin Asofiei wrote:
Please take the changes from branch 1794c rev 10927 - I will merge it to trunk later today.
If the mnemonic really uses the same font as the menu, then you can use something like this to draw the mnemonic:
[...]
I tried. It doesn't work. I've rebase branch to the latest revision.
#515 Updated by Constantin Asofiei over 8 years ago
Vadim Gindin wrote:
Constantin Asofiei wrote:
Please take the changes from branch 1794c rev 10927 - I will merge it to trunk later today.
If the mnemonic really uses the same font as the menu, then you can use something like this to draw the mnemonic:
[...]I tried. It doesn't work. I've rebase branch to the latest revision.
The underline works now in rev 10936.
#516 Updated by Constantin Asofiei over 8 years ago
Vadim Gindin wrote:
Constantin, could you have a look at my CHUI implementation. I faced with the following bug: when sub-menu is hiding screen is not fully cleared of it. See attached procedure. When the latest nested menu is hiding there are its trail is stayed (not cleared). I can't find why. Could you help me? Current revision is 10927.
The fix is in rev 10937. It was a problem related to wrong-of-order repaint()
and display = false
calls.
Also, in GUI, why is this code in Window.afterConfigUpdate
:
if (ThinClient.getInstance().isChui()) { menubar.setVisible(true); }
This will keep the menubar hidden until the mouse hovers over it...
#517 Updated by Vadim Gindin over 8 years ago
Constantin Asofiei wrote:
Also, in GUI, why is this code in
Window.afterConfigUpdate
:
[...]
This will keep the menubar hidden until the mouse hovers over it...
I need to hide MENUBAR for GUI in the case when no enabled frames, show warning and show MENUBAR only after user will press some key. It seems it wasn't a good decision.
#518 Updated by Vadim Gindin over 8 years ago
Constantin, mnemonics do not work for me..
#519 Updated by Vadim Gindin over 8 years ago
Next bug is the following:MESSAGE MENU-ITEM mi:NEXT-SIBLING.
is converted to message(MenuItemWidget.findMenuItemStatic("mi").getNextSibling());
that calls LogicalTerminal.message(handle hWin)
method. This method expect that the parameter will be the window handle. I.e. it is treated as MESSAGE "" IN WINDOW hWin
statement. But that is wrong. It must be treated as MESSAGE MENU-ITEM mi:NEXT-SIBLING:ID.
Is it a known bug?
P.S. It is not related to menus.
#520 Updated by Constantin Asofiei over 8 years ago
Vadim Gindin wrote:
Next bug is the following:
MESSAGE MENU-ITEM mi:NEXT-SIBLING.
is converted tomessage(MenuItemWidget.findMenuItemStatic("mi").getNextSibling());
that callsLogicalTerminal.message(handle hWin)
method. This method expect that the parameter will be the window handle. I.e. it is treated asMESSAGE "" IN WINDOW hWin
statement. But that is wrong. It must be treated asMESSAGE MENU-ITEM mi:NEXT-SIBLING:ID.
Is it a known bug?P.S. It is not related to menus.
Do not work on this, focus on finishing the menu-specific issues you have left.
#521 Updated by Vadim Gindin over 8 years ago
Constantin, thank you for help. I've rebased the branch. Now current revision is 1941. Please review the code. Can I test it?
#522 Updated by Constantin Asofiei over 8 years ago
expressions.rules
- I don't understand theAdded ';' suppression for ACCELERATOR attribute of MENU-ITEM.
history entry - how is;
involved in ACCELERATOR?Keyboard.java
- is missing history entryKeyboardLayout
- as this is not directly used by theKeyboard
class and is windows-specific, it should be in theclient.gui
packageMenuItemInterface
- you need a blank line before thepackage
statementMenuWidget.java
,SubMenuWidget.java
- instead ofimport java.util.Iterator;
you needimport java.util.*;
- can the commented code at the begining offirstChild
andlastChild
be removed?ThinClient
- is missing history entry
-warnNoEnabledFrames
: I don't think ignoring all conditions usingcatch (Throwable t)
is the way to go. Try pressingESC
- this will raise aSTOP
condition and it should terminate the program immediately.Window
,SubMenu
- is missing history entryMenuItemChuiImpl
- the imports need to use*
, not explicit
- is missing history entry
- you still have commented in the class - is this still needed?SubMenuChuiImpl
- is missing history entry
- you still have commented in the class - is this still needed?WinKeyboardReader
- is missing history entry
- please try something like this: use aPAUSE
statement and pressALT
(without having a menubar). DoesALT
act as "any-key" and terminates thePAUSE
? With your change,ALT
is captured and piped toTypeAhead
, and it might interfere with other statements.Key
- is missing history entryDefaultKeyboardLayout
- remove the empty line before the last}
for the class
- you named the classDefault
, but what is the default? Isn't there a more specific name - i.e. US/etc.GuiKeyboard
- is missing history entry
-KeyboardLayout
needs to be moved in the same package, so remove the import.MenuGuiImpl
- is missing history entry
- why did you comment out the code ingetFirstEnabledWidget
code?MenuItemGuiImpl
- is missing history entry
- the underline does work, remove the comment.SubMenuItemGuiImpl
- is missing history entryWindowGuiImpl
- is missing history entryWindowLayout
- is missing history entry
ALT
acts like a mnemonic on/off key: pressing it twice disables the mnemonic underline- clicking outside the activated menu does not close the menu
- please document all other menu-specific related issues you have left and document it here.
Can I test it?
Not yet, I want to understand what issues are left first.
#523 Updated by Vadim Gindin over 8 years ago
Constantin Asofiei wrote:
Review branch 1790e revision 10941:
expressions.rules
- I don't understand theAdded ';' suppression for ACCELERATOR attribute of MENU-ITEM.
history entry - how is;
involved in ACCELERATOR?
There was a conversion bug: for each specified accelerator, there was empty line with only one symbol ';' in converted class. I'll expand this comment.
MenuWidget.java
,SubMenuWidget.java
- instead ofimport java.util.Iterator;
you needimport java.util.*;
- can the commented code at the begining offirstChild
andlastChild
be removed?
I don't remember why I implemented those methods in that way. I.e. why I specified LegacyResource.MENU
for MenuWidget
.. I looks wrong, because HandleChain.firstResource
expects the second argument to be specified as a type of first child. Isn't it? So I would prefer to stay these comments some time.
-
warnNoEnabledFrames
: I don't think ignoring all conditions usingcatch (Throwable t)
is the way to go. Try pressingESC
- this will raise aSTOP
condition and it should terminate the program immediately.
I used the same approach as used in ThinClient.stopNoAvailableWidgets()
. There are also empty catch block. I'll check it.
DefaultKeyboardLayout
- you named the classDefault
, but what is the default? Isn't there a more specific name - i.e. US/etc.
As I understand it is a keyboard layout from windows settings. It can be different. Probably "Default" is not good fit string for the class name.
MenuGuiImpl
- is missing history entry
- why did you comment out the code ingetFirstEnabledWidget
code?
This method is used only for initial focus setting and is actual for CHUI. For GUI MENUBAR doesn't have default focus. I'll check pop-up menu. I think it also doesn't define default focused element.
MenuItemGuiImpl
- is missing history entry
- the underline does work, remove the comment.
I wrote earlier, that in it doesn't for my machine. Why it could be?
#524 Updated by Constantin Asofiei over 8 years ago
Vadim Gindin wrote:
MenuGuiImpl
- is missing history entry
- why did you comment out the code ingetFirstEnabledWidget
code?This method is used only for initial focus setting and is actual for CHUI. For GUI MENUBAR doesn't have default focus. I'll check pop-up menu. I think it also doesn't define default focused element.
OK, then please add a comment there.
MenuItemGuiImpl
- is missing history entry
- the underline does work, remove the comment.I wrote earlier, that in it doesn't for my machine. Why it could be?
Do you use the directory.xml from the testcases project? Do you have the custom-fonts defined and the .ttf files in the server folder?
#525 Updated by Vadim Gindin over 8 years ago
Constantin Asofiei wrote:
I wrote earlier, that in it doesn't for my machine. Why it could be?
Do you use the directory.xml from the testcases project? Do you have the custom-fonts defined and the .ttf files in the server folder?
Yes, I use directory.xml from the testcases project. About custom-fonts I'm not sure. *.ttf files are exist in server/fonts folder. I ran get-font-metrics procedure for previous task for GUI toggle-box implementation. It probably those custom fonts. Isn't it? Should I delete them?
#526 Updated by Vadim Gindin over 8 years ago
- menuItem.setSensitive call actuates ThinClient.enable method (fixed, but not committed yet)
- drawing of accelerators for disabled menu-items (fixed, but not committed yet)
- check mnemonics drawing in navigation mode.
- clicking on menu-items in sub-menus leaves trails after sub-menu is closed.
- check drawing navigation mode (select first item of menubar, check pop-up menu).
- check ALT key behavior (without MENUBAR).
#527 Updated by Vadim Gindin over 8 years ago
- check drawing navigation mode (check pop-up menu).
- check ALT key behavior (without MENUBAR).
- fix sub-menu body width when menu-items specified with accelerators and it does not contain nested sub-menu
- fix sub-menu closing when clicking in some free space. I wrote about this problem earlier. See the note 451. The key problem here that FOCUS_LOST event is sent only if I click on another widget. If I click in some free space (window's ScrollContainer) FOCUS_LOST is not sent. I asked for advice about this problem. Please have a look.
- fix the following bug. When first child of MENUBAR is SUB-MENU and I press ALT - it is selected (that is correct). The body must not be shown, but it is drawn partially (only first MENU-ITEM). It looks like some clipping problem.
- fix the bug with unexpected exit when I click a menu-item from MENUBAR with assigned trigger, that dynamically sets sensitive flag of other menu widgets.
#528 Updated by Vadim Gindin over 8 years ago
Vadim Gindin wrote:
- fix the bug with unexpected exit when I click a menu-item from MENUBAR with assigned trigger, that dynamically sets sensitive flag of other menu widgets.
This bug relates to any trigger assigned to MENU-ITEM that resides right in a MENUBAR (not inside of some SUB-MENU). The content of the trigger does not matter. Here is the stack trace, that ends with pauseBeforeEnd()
call. Could you propose me some reason why it can happen?
Daemon Thread [Conversation [00000001:bogus]] (Suspended (breakpoint at line 11089 in LogicalTerminal)) LogicalTerminal.pauseBeforeEnd(boolean) line: 11089 LogicalTerminal$4.finished() line: 10593 TransactionManager.processFinalizables(TransactionManager$WorkArea, BlockDefinition, boolean) line: 4990 TransactionManager.popScope() line: 2295 StandardServer.invoke(int, Isolatable) line: 1394 StandardServer.standardEntry(ClientParameters) line: 427 NativeMethodAccessorImpl.invoke0(Method, Object, Object[]) line: not available [native method] NativeMethodAccessorImpl.invoke(Object, Object[]) line: 57 DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: 43 Method.invoke(Object, Object...) line: 606 MethodInvoker.invoke(Object[]) line: 76 Dispatcher.processInbound(InboundRequest, boolean, NetResource) line: 694 Conversation.block() line: 319 Conversation.run() line: 163 Thread.run() line: 745
#529 Updated by Vadim Gindin over 8 years ago
No ConditionException is raised. I've set a breakpoint after the event processing loop in ThinClient.waitForEventWorker
but execution is not stopped on it..
#530 Updated by Greg Shah over 8 years ago
Based on the stack trace in note 528, by the time you see that the exception has already been processed. You are breaking in at the point where the "Procedure is complete..." message is being shown. This is way too late to see the cause of why you are exiting.
#531 Updated by Vadim Gindin over 8 years ago
Greg Shah wrote:
Based on the stack trace in note 528, by the time you see that the exception has already been processed. You are breaking in at the point where the "Procedure is complete..." message is being shown. This is way too late to see the cause of why you are exiting.
- Beside that breakpoint I had set breakpoints in constructors of the class
ConditionException
and none of them had worked. - ALT key doesn't affect pause..
#532 Updated by Vadim Gindin over 8 years ago
Constantin Asofiei wrote:
- please try something like this: use a PAUSE statement and press ALT (without having a menubar). Does ALT act as "any-key" and terminates the PAUSE? With your change, ALT is captured and piped to TypeAhead, and it might interfere with other statements.
I've checked: ALT doesn't terminate the pause. I made ALT as captured and piped to TypeAhead especially to be able to process its press. How we can test if it can interfere other keys? I thought that it couldn't interfere it just because it has a separate code and any combination with ALT will have different code..
#533 Updated by Constantin Asofiei over 8 years ago
Vadim Gindin wrote:
Constantin Asofiei wrote:
- please try something like this: use a PAUSE statement and press ALT (without having a menubar). Does ALT act as "any-key" and terminates the PAUSE? With your change, ALT is captured and piped to TypeAhead, and it might interfere with other statements.
I've checked: ALT doesn't terminate the pause. I made ALT as captured and piped to TypeAhead especially to be able to process its press. How we can test if it can interfere other keys? I thought that it couldn't interfere it just because it has a separate code and any combination with ALT will have different code..
Did you check in GUI or in ChUI? As ALT is configured in the GUI keyboard, the ChUI client will not see it. But the GUI client will interpret it as "any-key" and terminate the PAUSE - this can be seen in 1790e rev 10944; just use a test with only a PAUSE statement.
#534 Updated by Vadim Gindin over 8 years ago
Constantin Asofiei wrote:
Vadim Gindin wrote:
Constantin Asofiei wrote:
- please try something like this: use a PAUSE statement and press ALT (without having a menubar). Does ALT act as "any-key" and terminates the PAUSE? With your change, ALT is captured and piped to TypeAhead, and it might interfere with other statements.
I've checked: ALT doesn't terminate the pause. I made ALT as captured and piped to TypeAhead especially to be able to process its press. How we can test if it can interfere other keys? I thought that it couldn't interfere it just because it has a separate code and any combination with ALT will have different code..
Did you check in GUI or in ChUI? As ALT is configured in the GUI keyboard, the ChUI client will not see it. But the GUI client will interpret it as "any-key" and terminate the PAUSE - this can be seen in 1790e rev 10944; just use a test with only a PAUSE statement.
I've added ignoring ALT for PAUSE statements to ThinClient.waitForEvent()
and added exclusion of ALT from ANY-KEY events processing. Should I do something else with ALT?
#535 Updated by Vadim Gindin over 8 years ago
Remained tasks:
- fix sub-menu closing when clicking in some free space. I wrote about this problem earlier. See the note 451. The key problem here that FOCUS_LOST event is sent only if I click on another widget. If I click in some free space (window's ScrollContainer) FOCUS_LOST is not sent. I asked for advice about this problem. Please have a look. need help
- fix the following bug. When first child of MENUBAR is SUB-MENU and I press ALT - it is selected (that is correct). The body must not be shown, but it is drawn partially (only first MENU-ITEM). It looks like some clipping problem. working on.
- fix the bug with unexpected exit when I click a menu-item from MENUBAR with assigned trigger, that dynamically sets sensitive flag of other menu widgets. need help
P.S. It seems CHUI is also used "short" accelerators: "INS" when I specified "INSERT" ..
#536 Updated by Constantin Asofiei over 8 years ago
Vadim Gindin wrote:
Remained tasks:
- fix sub-menu closing when clicking in some free space. I wrote about this problem earlier. See the note 451. The key problem here that FOCUS_LOST event is sent only if I click on another widget. If I click in some free space (window's ScrollContainer) FOCUS_LOST is not sent. I asked for advice about this problem. Please have a look. need help
- fix the bug with unexpected exit when I click a menu-item from MENUBAR with assigned trigger, that dynamically sets sensitive flag of other menu widgets. need help
Please post 4GL tests which duplicate/show the problem in each case.
#537 Updated by Vadim Gindin over 8 years ago
I've committed actual tests. See below.
Constantin Asofiei wrote:
Vadim Gindin wrote:
Remained tasks:
- fix sub-menu closing when clicking in some free space. I wrote about this problem earlier. See the note 451. The key problem here that FOCUS_LOST event is sent only if I click on another widget. If I click in some free space (window's ScrollContainer) FOCUS_LOST is not sent. I asked for advice about this problem. Please have a look. need help
The test: uast/menu/simple_sm.p
. It defines MENUBAR with SUB-MENU and MENU-ITEM on the first level. You can just open SUB-MENU body, move mouse pointer out of it and click on a empty space in a window. The body will not closed.
- fix the bug with unexpected exit when I click a menu-item from MENUBAR with assigned trigger, that dynamically sets sensitive flag of other menu widgets. need help
The test uast/menu/disabled_enabled.p
. It defines MENUBAR with some elements (disabled and enabled). The first element is the MENU-ITEM "Enable_AAA" with assigned trigger, that just prints some message (the content of the trigger is not matter). When you click on this MENU-ITEM the trigger is executed but procedure ends after that. What I've found is that behavior takes place for all MENU-ITEMS of first level. I suspect that there is some uncaught and "swallowed" exception..
#538 Updated by Constantin Asofiei over 8 years ago
Vadim Gindin wrote:
Remained tasks:
- fix sub-menu closing when clicking in some free space. I wrote about this problem earlier. See the note 451. The key problem here that FOCUS_LOST event is sent only if I click on another widget. If I click in some free space (window's ScrollContainer) FOCUS_LOST is not sent. I asked for advice about this problem. Please have a look. need help
The fix required registering the widget for "any" actions, so that is notified when a mouse click/press is done outside of it. The fix is in rev 10947.
- fix the following bug. When first child of MENUBAR is SUB-MENU and I press ALT - it is selected (that is correct). The body must not be shown, but it is drawn partially (only first MENU-ITEM). It looks like some clipping problem. working on.
I think the mousePressed/mouseEntered were called in the wrong order. Please check the change in WindowGuiImpl rev 10947 with other tests.
- fix the bug with unexpected exit when I click a menu-item from MENUBAR with assigned trigger, that dynamically sets sensitive flag of other menu widgets. need help
Breakpoint in Dispatcher:712 and evaluate the t.printStackTrace()
expression you get an infinite recursion cause. I'm not sure how to fix this.
Caused by: java.lang.StackOverflowError at java.util.ArrayList$Itr.<init>(ArrayList.java:820) at java.util.ArrayList.iterator(ArrayList.java:814) at com.goldencode.p2j.ui.client.widget.AbstractWidget.processKeyListeners(AbstractWidget.java:640) at com.goldencode.p2j.ui.client.widget.AbstractWidget.processKeyEvent(AbstractWidget.java:628) at com.goldencode.p2j.ui.client.widget.AbstractContainer.processKeyEvent(AbstractContainer.java:622) at com.goldencode.p2j.ui.client.Menu.processKeyEvent(Menu.java:328) at com.goldencode.p2j.ui.client.MenuItem.processKeyEvent(MenuItem.java:311) at com.goldencode.p2j.ui.client.widget.AbstractContainer.processKeyEvent(AbstractContainer.java:630) at com.goldencode.p2j.ui.client.Menu.processKeyEvent(Menu.java:328) at com.goldencode.p2j.ui.client.MenuItem.processKeyEvent(MenuItem.java:311) at com.goldencode.p2j.ui.client.widget.AbstractContainer.processKeyEvent(AbstractContainer.java:630) at com.goldencode.p2j.ui.client.Menu.processKeyEvent(Menu.java:328) at com.goldencode.p2j.ui.client.MenuItem.processKeyEvent(MenuItem.java:311) at com.goldencode.p2j.ui.client.widget.AbstractContainer.processKeyEvent(AbstractContainer.java:630) at com.goldencode.p2j.ui.client.Menu.processKeyEvent(Menu.java:328) at com.goldencode.p2j.ui.client.MenuItem.processKeyEvent(MenuItem.java:311) at com.goldencode.p2j.ui.client.widget.AbstractContainer.processKeyEvent(AbstractContainer.java:630) at com.goldencode.p2j.ui.client.Menu.processKeyEvent(Menu.java:328) at com.goldencode.p2j.ui.client.MenuItem.processKeyEvent(MenuItem.java:311)
#539 Updated by Vadim Gindin over 8 years ago
Constantin Asofiei wrote:
Vadim Gindin wrote:
Remained tasks:
- fix sub-menu closing when clicking in some free space. I wrote about this problem earlier. See the note 451. The key problem here that FOCUS_LOST event is sent only if I click on another widget. If I click in some free space (window's ScrollContainer) FOCUS_LOST is not sent. I asked for advice about this problem. Please have a look. need help
The fix required registering the widget for "any" actions, so that is notified when a mouse click/press is done outside of it. The fix is in rev 10947.
I understand the fix. Good idea, but I have ConcurrentModifictionException
from time to time. Here is the trace:
Caused by: java.util.ConcurrentModificationException at java.util.HashMap$HashIterator.nextEntry(HashMap.java:922) at java.util.HashMap$KeyIterator.next(HashMap.java:956) at com.goldencode.p2j.ui.client.gui.driver.MouseHandler.processAnywhereActions(MouseHandler.java:250) at com.goldencode.p2j.ui.client.gui.driver.MouseHandler.access$0(MouseHandler.java:246) at com.goldencode.p2j.ui.client.gui.driver.MouseHandler$2.run(MouseHandler.java:233) at com.goldencode.p2j.ui.chui.ThinClient.eventBracket(ThinClient.java:13477) at com.goldencode.p2j.ui.chui.ThinClient.eventDrawingBracket(ThinClient.java:13426) at com.goldencode.p2j.ui.client.gui.driver.MouseHandler.handleMouseEvent(MouseHandler.java:228) at com.goldencode.p2j.ui.client.gui.driver.AbstractGuiDriver.handleMouseEvent(AbstractGuiDriver.java:1852) at com.goldencode.p2j.ui.client.widget.TitledWindow.processEvent(TitledWindow.java:209) at com.goldencode.p2j.ui.client.gui.WindowGuiImpl.processEvent(WindowGuiImpl.java:1155) at com.goldencode.p2j.ui.chui.ThinClient.processProgressEvent(ThinClient.java:14812) at com.goldencode.p2j.ui.chui.ThinClient.processEventsWorker(ThinClient.java:14433) at com.goldencode.p2j.ui.chui.ThinClient.pop(ThinClient.java:13517) at com.goldencode.p2j.ui.chui.ThinClient.eventBracket(ThinClient.java:13500) at com.goldencode.p2j.ui.chui.ThinClient.eventDrawingBracket(ThinClient.java:13426) at com.goldencode.p2j.ui.chui.ThinClient.applyWorker(ThinClient.java:13208) at com.goldencode.p2j.ui.chui.ThinClient.waitForWorker(ThinClient.java:10691) at com.goldencode.p2j.ui.chui.ThinClient.waitFor(ThinClient.java:10200) at com.goldencode.p2j.ui.chui.ThinClient.waitFor(ThinClient.java:10154) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:606) at com.goldencode.p2j.util.MethodInvoker.invoke(MethodInvoker.java:76) at com.goldencode.p2j.net.Dispatcher.processInbound(Dispatcher.java:694) 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:1425) 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:277) at com.goldencode.p2j.main.ClientCore.start(ClientCore.java:100) at com.goldencode.p2j.main.ClientDriver.start(ClientDriver.java:201) at com.goldencode.p2j.main.CommonDriver.process(CommonDriver.java:398) at com.goldencode.p2j.main.ClientDriver.process(ClientDriver.java:1)
#540 Updated by Constantin Asofiei over 8 years ago
I missed a case where copy
should have been used instead of wa.anyActions
on line 250 please fix it.
#541 Updated by Constantin Asofiei over 8 years ago
- rebase from latest revision
- go through all the review notes in 522 and add history entries, etc (these are not yet fixed in rev 10949)
- remove all the debugging code (i.e.
System.out.println
) and commented/obsolete code
After this, I'll do a final review of the code before putting it into testing.
If you are not close to finish, please post what issues are left.
#542 Updated by Vadim Gindin over 8 years ago
I faced with some new bugs after last commits and rebase. So I'm still close but not yet ready. I'll post current list a little later.
#543 Updated by Greg Shah over 8 years ago
When you post the list of open issues, please include an estimate of how long it will take to resolve those issues. I need to plan when we can get you into testing.
#544 Updated by Vadim Gindin over 8 years ago
- fix the bug with unexpected exit when I click a menu-item from MENUBAR with assigned trigger, that dynamically sets sensitive flag of other menu widgets.
- drawing bugs with sub-menus. When I'm navigating from two neighbor sub-menus to those bodies and back. The first sub-menu title become invisible and after I return to it - the previous selection (highlighting) is not erased. Another one thing: When I move mouse pointer from the sub-menu body to a menu-item, that is a neighbor of that sub-menu, sub-menu became highlighted as selected
- check ALT navigation mode. There is a peculiarity: If I will open sub-menu body using mouse pointer there will be no default selected item, but If I will open the body using keyboard - the first item will be highlighted by default.
- check sub-menu body width when sub-menu contains only simple menu-items even without accelerators and toggle-boxes.
Estimate. I hope it will take not more than 3 days.
#545 Updated by Constantin Asofiei over 8 years ago
Vadim Gindin wrote:
- fix the bug with unexpected exit when I click a menu-item from MENUBAR with assigned trigger, that dynamically sets sensitive flag of other menu widgets.
I see you fixed this in 10950; if there is nothing broken with this in your menu tests, then I'm OK with it. But please remove the SubMenu.setFocusInt
as is a no-op, it just invokes super.
See revision 10951 - I've fixed drawing issues related to highlight, but there are some other issues:
- drawing bugs with sub-menus. When I'm navigating from two neighbor sub-menus to those bodies and back. The first sub-menu title become invisible and after I return to it - the previous selection (highlighting) is not erased. Another one thing: When I move mouse pointer from the sub-menu body to a menu-item, that is a neighbor of that sub-menu, sub-menu became highlighted as selected
- some "ghosting" when a opened sub-menu tree is closed - the previously selected menu item is redrawn
- the opened sub-menu tree is closed on certain cases, when mouse gets outside of the area determined by the smallest rectangle which contains the entire sub-menu tree - in 4GL it does not get closed.
- check ALT navigation mode. There is a peculiarity: If I will open sub-menu body using mouse pointer there will be no default selected item, but If I will open the body using keyboard - the first item will be highlighted by default.
- check sub-menu body width when sub-menu contains only simple menu-items even without accelerators and toggle-boxes.
Please continue with these two. I'll investigate the issues I found.
#546 Updated by Constantin Asofiei over 8 years ago
- focus processing when focus is moved from a higher to a lower level in the menu tree. The catch here was that a
FOCUS_LOST
must be sent to the menu widget (in the focus chain) which is a sibling of the new focused widget. Old version was sendingFOCUS_LOST
to the last widget in the focus chain, which may be on a lower level in the menu tree than the new focused widget. - mouse source calculation when a menu tree is displayed. The menu widget boundary (menubar, sub-menu) is the smallest rectangle which contains all the displayed sub-menus. But when determining which widget is targeted by the mouse event, we can't use this boundary - instead, the actual sub-menu body must be checked.
Incidentally, I think this fixes the two new issues I mentioned in note 545, too.
Next on list are these (in priority order):SubMenuGuiImpl.mousePressed
- it doesn't draw the entire sub-menu body... some state is not set right. Only mouse click actually shows the body fully. If you press the mouse button and keep it pressed, the body is not drawn fully.- clicking on a sub-menu in the menu bar opens it, clicking it again must close it
- when mouse is moved outside the menubar (with no sub-menu opened), the previously hovered item must lose its highlight
#547 Updated by Constantin Asofiei over 8 years ago
Another issue: VK_ENTER
key is used to trigger an open of a sub-menu (or click of menu-item), when a mouse action was performed. This interferes with any ON 'ENTER'
trigger associated with that menu widget. I think instead of simulating a real key, a synthetic event should be used.
#548 Updated by Vadim Gindin over 8 years ago
- I've moved "clicking" logic from
mouseClicked
tomousePressed
that is more convenient place. - I've added hiding body for menubar sub-menus.
- I've added ignoring alien events to
SubMenuGuiImpl.mousePressed
.
That solves problems 1 and 2 from the note 546.
Something new..
If wait-for statement contains, for example, menu-item from some sub-menu it is invisible (visible=false) when sub-menu body is hidden. menu elements from sub-menus was always visible=true, but I changed it to dynamic visibility setting to solve trailing problem. Now I faced with the following problem: If I open sub-menu in a menubar and close it ThinClient.stopNoAvailableWidgets()
will be called and will raise StopConditionError
. Have a look at the code in ThinClient.waitForWorker
that calls ThinClient.stopNoAvailableWidgets()
(lines 10744-10766). You can see there that "exit" widgets (menu-items for example) must be enabled and visible always (independently of body visibility). I think I should add some workaround to waitForWorker
and stay dynamic visibility as it is now. For example, for MenuItem
and SubMenu
classes not to check visibility. What do you think?
P.S. I've tested the situation when menu-item is disabled - procedure ends immediately. So talking about enabled flag it works properly.
#549 Updated by Constantin Asofiei over 8 years ago
Vadim, this is good, I've integrated it with my changes and it fixed some popup issues I was having. Please don't commit anything in the next hour or so, I still have a regression in the window menubar. Once I fix this, I'll commit my changes (related to MENU-DROP and other misc issues).
About the wait-for: I think is safe to assume that wait-for must not check VISIBLE for any MENU-related widget. But a MENU-ITEM can be in DISABLED state - in this case, can the WAIT-FOR wait for it? What happens if it starts ENABLED but it gets changed while WAIT-FOR is active?
#550 Updated by Vadim Gindin over 8 years ago
Constantin Asofiei wrote:
About the wait-for: I think is safe to assume that wait-for must not check VISIBLE for any MENU-related widget. But a MENU-ITEM can be in DISABLED state - in this case, can the WAIT-FOR wait for it? What happens if it starts ENABLED but it gets changed while WAIT-FOR is active?
If waited MENU-ITEM is DISABLED initially than procedure ends right after start. If waited MENU-ITEM become DISABLED dynamically (I tried to set it in a trigger of some other menu-item), than the error appears right after the trigger worked and SENSITIVE flag is set to false, but after I press "space bar" - procedure restarts instead of becoming closed.
#551 Updated by Constantin Asofiei over 8 years ago
- check ALT navigation mode. There is a peculiarity: If I will open sub-menu body using mouse pointer there will be no default selected item, but If I will open the body using keyboard - the first item will be highlighted by default.
- check sub-menu body width when sub-menu contains only simple menu-items even without accelerators and toggle-boxes.
- navigation via ALT (to activate it) keyboard cursors
Please go through the menu tests and see if you find any other issues, and post them here.
I'm planning to work on the ALT/keyboard navigation tomorrow, so please keep me posted if you make any other changes.
#552 Updated by Constantin Asofiei over 8 years ago
Vadim, I'm working on these two (and everything else related to ALT and cursor-key navigation):
- check ALT navigation mode. There is a peculiarity: If I will open sub-menu body using mouse pointer there will be no default selected item, but If I will open the body using keyboard - the first item will be highlighted by default.
- navigation via ALT (to activate it) and keyboard cursors
#553 Updated by Constantin Asofiei over 8 years ago
- File mnemonic_last.png added
Vadim, something about mnemonics: the P2J code is made to underline the first char after the first &
, but in 4GL it underlines the first char after the LAST &
. See attached; the lower-right is the Swing client.
Is P2J doing things backwards or am I missing something?
#554 Updated by Vadim Gindin over 8 years ago
You're right. My mistake. I'll fix it.
Talking about ALT mode: do you use additional field in a *Impl classes? Have a look at SubMenuGuiImpl.enterMenubar.
#555 Updated by Constantin Asofiei over 8 years ago
1790e revision 10956 fixes menubar navigation via cursor keys + ALT: some processing was moved to the onFocusGained
and onFocusLost
, instead of mouseEntered
and mouseExited
.
Navigation for popup-menu via keys was not checked yet - I'll do this next.
Talking about ALT mode: do you use additional field in a *Impl classes? Have a look at SubMenuGuiImpl.enterMenubar.
No, the logic was mostly correct, only the focus gain/lost processing was in the wrong place.
#556 Updated by Vadim Gindin over 8 years ago
I've committed mnemonic character fix. rev 10957
#557 Updated by Constantin Asofiei over 8 years ago
What about MenuItemWidget.setLabelInt
? 10957 fixes the drawing, but please fix the processing which determines which char to set the MenuItemConfig.mnemonic
.
#558 Updated by Constantin Asofiei over 8 years ago
1790e rev 10957 fixes cursor navigation for popup menus. I don't have anything else on my list.
Vadim: please let me know if there are other issues left.
#559 Updated by Vadim Gindin over 8 years ago
Thank you so much! I'm testing. I'll post results.
#560 Updated by Constantin Asofiei over 8 years ago
Vadim Gindin wrote:
Thank you so much! I'm testing. I'll post results.
Please rebase first, and after that start testing.
#561 Updated by Constantin Asofiei over 8 years ago
And something else: after rebase, please go through the notes in 522 and also do a general code cleanup for 1790e.
#562 Updated by Vadim Gindin over 8 years ago
I'm currently fixing mnemonics case: when the last character is '&'. CHUI and GUI behaves differently.
- If a title ends with "&&" than the only one "&" is left in it, but it is not used as mnemonic: first character is used. (works for both GUI and CHUI)
- Otherwise, when a title ends with the only one character "&" CHUI adds a space to the end of the title, but that space is not used as mnemonic - only for drawing as mnemonic. GUI just ignores the last "&" corresponding to the common rule.
#563 Updated by Vadim Gindin over 8 years ago
It seems there are a lot of different (for GUI and CHUI) in mnemonic definition for specific cases when more than one '&' is specified in a label.
The documentation only recommends to use only one mnemonic specification (one '&' character). It does not describe any peculiarities for GUI or CHUI. Here is the doc:
For quick access, the user can select an item from a pull-down menu or menu bar by pressing ALT and one mnemonic character. Progress indicates the mnemonic character by underlining it within the menu. For example, a menu bar might contain the entries File, Edit, and Exit. This means that you can access the File menu by pressing ALT–F, the Edit menu by pressing ALT–E, and the Exit menu by pressing ALT–X. NOTE: If you define a menu mnemonic key combination as an accelerator, the accelerator takes precedence. For more information on key precedence, see Chapter 6, “Handling User Input.” In Progress, you can define mnemonics for items in a menu bar, pull-down menu, or pop-up menu. To specify a mnemonic, insert an ampersand (&) before that letter in the label. For example, to make x the mnemonic for Exit, you specify LABEL "E&xit". Note that in graphical and character interfaces, the first character in an item’s label is the default mnemonic. You can only specify one mnemonic for each label; do not precede more than one letter with an ampersand. To include a literal ampersand within a menu label, use two ampersands. For example, the label "Undo && Restart" is displayed as Undo & Restart.
Here are specific cases:
def menu m menubar menu-item m1 label "&&Toyota&&". menu-item m2 label "&Toyota". menu-item m3 label "&&Toyota". menu-item m4 label "T&&&oyota". menu-item m5 label "Toyota&". menu-item m6 label "Toyota&&". menu-item ext label "E&xi&t". assign current-window:menubar = menu m:handle. wait-for choose of menu-item ext.The differencies are the following:
- For CHUI '&' can be mnemonic itself. To make it as a mnemonic we should specify "&&". For GUI that is impossible
- When '&' is the last symbol and the previous symbol is not '&' CHUI adds '_' symbol to the end of the label just for drawing
- It looks like for CHUI the first '&' defines a mnemonic character, but for GUI - the last one (not checked fully).
#564 Updated by Vadim Gindin over 8 years ago
Can we set aside specific cases implementation for some time?
#565 Updated by Vadim Gindin over 8 years ago
I've rebased the branch 1790e with current trunk revision. Now current branch revision is 10960.
#566 Updated by Constantin Asofiei over 8 years ago
Vadim Gindin wrote:
The differencies are the following:
- For CHUI '&' can be mnemonic itself. To make it as a mnemonic we should specify "&&". For GUI that is impossible
- When '&' is the last symbol and the previous symbol is not '&' CHUI adds '_' symbol to the end of the label just for drawing
- It looks like for CHUI the first '&' defines a mnemonic character, but for GUI - the last one (not checked fully).
I think we need to compute the mnemonic on the client-side, when SubMenu.processMnemonicEvent
is executed: this way, we know if we are in ChUI or GUI and we can calculate the correct one.
We need an API which determines the mnemonic index and it can be used by both drawTitle
and processMnemonicEvent
.
#567 Updated by Greg Shah over 8 years ago
Can we set aside specific cases implementation for some time?
Is this especially difficult or risky to fix? It seems like you can specify the &
rules fairly well. Is it hard to encode the logic?
please go through the notes in 522 and also do a general code cleanup for 1790e.
What is the status of this?
Overall, what is the list of open issues?
#568 Updated by Vadim Gindin over 8 years ago
Greg Shah wrote:
Can we set aside specific cases implementation for some time?
Is this especially difficult or risky to fix? It seems like you can specify the
&
rules fairly well. Is it hard to encode the logic?
I've retested that issue. There are several specific and not obvious cases. I'm going to document it here right now.
please go through the notes in 522 and also do a general code cleanup for 1790e.
What is the status of this?
I wanted to fix mnemonics before to do that.
Overall, what is the list of open issues?
All know issues are fixed (except mnemonics). It would be good to test it some more time.
About mnemonics, Constantin, if you didn't started to fix mnemonics, I could do that today/tomorrow and sure I'll make general code cleanup noted earlier.
#569 Updated by Constantin Asofiei over 8 years ago
Vadim Gindin wrote:
Yes, go ahead and fix the mnemonics. Some notes:All know issues are fixed (except mnemonics). It would be good to test it some more time.
About mnemonics, Constantin, if you didn't started to fix mnemonics, I could do that today/tomorrow and sure I'll make general code cleanup noted earlier.
- in ChUI, the last
&
is used to define the mnemonic - in your note 563 test, the"E&xi&t"
hast
as mnemonic. - remove the
SubMenuConfig.mnemonic
andMenuItemConfig.mnemonic
- the server-side doesn't need it. As there are (subtle) differences between ChUI and GUI, this can be done in theafterConfigUpdate
API for theSubMenu[Chui|Gui]Impl
andMenuItem[Chui|Gui]Impl
. If the title gets changed (you have access to thebeforeUpdate
state), it will save as instance fields the computed mnemonic char and the index of the mnemonic. This way, when the title is drawn (both in Chui and GUI) it will have direct access to the ampIdx, instead of having to duplicate the mnemonic logic indraw
, too.
#570 Updated by Vadim Gindin over 8 years ago
The current '&' processing algorithm MenuItem.prepTitle(String)
is incorrect. Here is the actual algorithm.
- If the sequence has even length (lets name is L), than it is replaced with sequence of '&' of L/2. Go to the next sequence.
- Else if mnemonic is not defined - define it (see below) and replace sequence with the sequence of '&' with the length = L/2 rounded down. Go to the next sequence.
- If all sequences had even length or there were no sequences at all - assign and draw the first character in a label as mnemonic.
- If there is no character (label just ends with '&') CHUI will add '_' character at the end of the label. GUI do nothing. Mnemonic character will not be defined in that case.
- Drawing for CHUI: added '_' will not be drawn as mnemonic (using usual font instead of reversed) and it will be drawn over right padding:
│ Alfa Romeo_│
instead of│ Alfa Romeo_ │
. Selected item is also drawn differently for such case. If MENU-ITEM is selected drawing is also different (recalling that selected item is drawn using reversed font):- If the label is the not longest between its neighbors it will be drawn as without mnemonic (reversed font will be used for all label including added '_').
- Otherwise 2 last characters of the label ('_' and the previous) will be drawn with basic font:
Alfa Rome
with reversed font ando_
with basic font.
- Drawing for GUI: mnemonic search will be continued, but founded mnemonic will be only drawn underlined and not be assigned as a character.
- Drawing for CHUI: added '_' will not be drawn as mnemonic (using usual font instead of reversed) and it will be drawn over right padding:
- Else the first character after the sequence will be assigned and drawn as a mnemonic.
And the last found peculiarity is about mnemonic behavior when a menu or sub-menu contains several items with the same mnemonic. When you press that mnemonic CHUI will press the first found item with that mnemonic, but GUI will only highlight the first founded mnemonic (not press it and not call its trigger). If you'll press mnemonic again GUI will highlight the next found item (using cyclic order, i.e. when the last item is highlighted - the next will be the first founded from the top).
I'll commit 2 tests about mnemonics menu/mnemonic.p
- about '&' processing and menu/mnemlast.p
- about CHUI drawing for the case when '&' is the last character in a label.
#571 Updated by Vadim Gindin over 8 years ago
Constantin, do you propose not to store original label and store only prepared along with mnemonic and mnemonic character index?
#572 Updated by Constantin Asofiei over 8 years ago
Vadim Gindin wrote:
This depends on how theConstantin, do you propose not to store original label and store only prepared along with mnemonic and mnemonic character index?
LABEL
attribute is reported: does 4GL report it as "prepared" or in the original form? In both cases, the mnemonic/mnemonic index needs to be saved at the widget Impl classes (MenuItemGuiImpl, SubMenuGuiImpl, etc). The prepared case depends on the answer to this question:
- if 4GL reports the
LABEL
attribute as the "prepared" version, then keep it there - otherwise, keep it as an instance field in the same place as the mnemonic/mnemonic index.
#573 Updated by Vadim Gindin over 8 years ago
I've faced with the following bug in CHUI: when some sub-menu has no items at all, but it is included in a MENUBAR (or in some sub-menu) window is displayed incorrectly: first menu-bar element does not gain a focus, there are no message or status area displayed. Here is sample procedure:
def sub-menu m9. def sub-menu m10 menu-item mm label "mmm". def sub-menu sm sub-menu m9 label "&Mitsubi&shi". sub-menu m10 label "Hon&da&". menu-item ext label "E&xi&t". define menu m menubar. sub-menu sm label "sm". assign current-window:menubar = menu m:handle. wait-for choose of menu-item ext.
#574 Updated by Constantin Asofiei over 8 years ago
Vadim Gindin wrote:
I've faced with the following bug in CHUI: when some sub-menu has no items at all, but it is included in a MENUBAR (or in some sub-menu) window is displayed incorrectly: first menu-bar element does not gain a focus, there are no message or status area displayed. Here is sample procedure:
[...]
Please add a comment somewhere in the code, don't work on this.
#575 Updated by Vadim Gindin over 8 years ago
Constantin Asofiei wrote:
Vadim Gindin wrote:
I've faced with the following bug in CHUI: when some sub-menu has no items at all, but it is included in a MENUBAR (or in some sub-menu) window is displayed incorrectly: first menu-bar element does not gain a focus, there are no message or status area displayed. Here is sample procedure:
[...]Please add a comment somewhere in the code, don't work on this.
I didn't investigate this bug, so there is not specific place to write a comment.
I've committed my changes to 1790e revno 10963. At this moment all mnemonic features are implemented (GUI and CHUI) except the last one:
And the last found peculiarity is about mnemonic behavior when a menu or sub-menu contains several items with the same mnemonic. When you press that mnemonic CHUI will press the first found item with that mnemonic, but GUI will only highlight the first founded mnemonic (not press it and not call its trigger). If you'll press mnemonic again GUI will highlight the next found item (using cyclic order, i.e. when the last item is highlighted - the next will be the first founded from the top).
#576 Updated by Constantin Asofiei over 8 years ago
Vadim Gindin wrote:
I've committed my changes to 1790e revno 10963.
I'm reviewing rev 10963 now. Please rebase from trunk again.
At this moment all mnemonic features are implemented (GUI and CHUI) except the last one:
And the last found peculiarity is about mnemonic behavior when a menu or sub-menu contains several items with the same mnemonic. When you press that mnemonic CHUI will press the first found item with that mnemonic, but GUI will only highlight the first founded mnemonic (not press it and not call its trigger). If you'll press mnemonic again GUI will highlight the next found item (using cyclic order, i.e. when the last item is highlighted - the next will be the first founded from the top).
What happens if there are two sub-menus with the same mnemonics? Do they get expanded?
Anyway, for this please add a comment in SubMenu.processMnemonicEvent
and can be fixed outside of this branch.
#577 Updated by Constantin Asofiei over 8 years ago
Please let me know once you rebase, I have some changes to commit.
#578 Updated by Constantin Asofiei over 8 years ago
1790e rev 10964 contains some misc formatting/header fixes.
#579 Updated by Constantin Asofiei over 8 years ago
branch 1790e was rebased from trunk rev 10931 (new branch rev 10965).
Regression testing is in progress.
#580 Updated by Constantin Asofiei over 8 years ago
Runtime testing almost passed, need to clear some false negatives.
#581 Updated by Constantin Asofiei over 8 years ago
Conversion testing has passed.
#582 Updated by Greg Shah over 8 years ago
Please merge to trunk when it passes testing.
#583 Updated by Constantin Asofiei over 8 years ago
Branch 1790e was merged to trunk rev 10932 and archived.
#584 Updated by Greg Shah over 8 years ago
- Status changed from WIP to Closed
#585 Updated by Greg Shah over 7 years ago
- Target version changed from Milestone 12 to GUI Support for a Complex ADM2 App
#586 Updated by Greg Shah over 7 years ago
- File deleted (
testing_08_10.txt)
#587 Updated by Greg Shah over 7 years ago
- File deleted (
gso_17.zip)
#588 Updated by Greg Shah about 7 years ago
- Related to Bug #3233: button accelerators do not work added