stopping work on hmg3->4 compatibility

Moderator: Rathinagiri

Post Reply
mrduck
Posts: 497
Joined: Fri Sep 10, 2010 5:22 pm

stopping work on hmg3->4 compatibility

Post by mrduck » Sun Aug 21, 2011 10:37 pm

Hello to everybody.

I anticipated in a message of 2 days ago that I did some work on HMG3 compatibility and that I was going to commit it at the end of the month.

Today with my family and friends I was doing a walk on a steep track on the Alps and while walking I was thinking how to make HMG4 TABs compatible with HMG3 ones when, not being concetrated on the walk, I lose the grip and put my leg into the water...
Later, after lunch, I was having a little sleep :-) and perhaps due to too much food I had, I started to dream about me at my office pc changing HMG code...

... so I decided it was too much... :-)

I decided to stop further study and coding on HMG3 compatibility and concentrate to make HMG4 a stable and realiable tool. I don't have HMG3 code after all....

I had committed a bunch of changes and I ask everybody to have a look at it. There are some issues open and some closed, both about HMG3 compatibility and HMG4. I'm going to list them, adding some considerations... this list is a way to document my studies and my ideas, at least for my own memory.

a) HMG3 is a preprocessor matter
HMG3 strenght is based on heavy preprocessor use. When a window is created

Code: Select all

DEFINE WINDOW xyz ...
a lot of preprocessor code is created on the fly to handle all the typical HMG3 commands, like

Code: Select all

 xyz.widget.setfocus
In HMG3 the above code is translated into a function call

Code: Select all

doMethod( "xyz", "widget", "setfocus" )
while in HMG4, in my commit, there are 2 possible translations, the first is in hmg3.ch and is used when the command is used inside a codeblock

Code: Select all

xyz:widget:setfocus()
the second is used when the command is on a line of its own and translates to

Code: Select all

eval( {||xyz:widget:setfocus()} )
This second style was my first attempt to solve the problem and I think it may be deleted
I left it in hmg.ch just to document it in a commit and can be probably removed later.

With doMethod, HMG3 uses also set/getProperty and again the preprocessor code created on the fly should be changed to comply with HMG4 style.

In include/hmg3.ch file in svn (that originates from HMG3) you will find the code used as template used at runtime and will find some defines updated and some not yet.

b) HMG3 has "alternative" commands
It seems that every widget in HMG3 has at least a couple of possible ways to be defined... with strange situations... I didn't check if it was an error of the people who ported DEFINE WINDOW from 3 to 4 but in HMG4 if you want a MODAL window you must use ONINIT, if you want a MAIN window you must use ON INIT....

Let's see an example, for LABELs, in HMG3 we have (I copy only the first line) only two ways, the xBase style and "oneliner" style:

Code: Select all

// xBase style, command on one row
#command @ <nRow>,<nCol> LABEL <oObj>   ;

// "oneliner" style, every command is on a line of its own
#xcommand DEFINE LABEL <name> =>;
In HMG3 it was almost impossible to create a label (or other widgets) using internal code, since they were a bit more complex.

In HMG4 we have a new way I was not able to find in HMG3 and the OOP way... the OOP way is the "internal" way to create the objects but since it is OOP, easy to use, and present in almost all the samples, it was actually made public.

Code: Select all

// new way to create a label
#command @ <nRow>,<nCol> SAY <oObj>   ;

// OOP way
With Object Label():New( x,y )
Creating a window (and probably other widgets) is a more complicated matter since the syntax is sometimes subtly different (ONINIT -> ON INIT)...

c) a bit of HMG4 history
When HMG4 started widget creation followed this pattern:
With Object Label():New( ) created a Label object,
:row = 20
the setget method checked the ::lCreated variable and depending on its value stored 20 in a member variable (::nRow) or actually called hbQt method to pass the value to the object.

When the enclosing window was activated, each widget :create() method was called and in this method the hbQt object was created and the values stored in DATA members were used to call again the setget method but now the ::lCreated value was different and the value actually used to configure the widget. It was a 2 step process that had some issues and seemed to be full of redundant, difficult to mantain code...

So there was a change: now the hbQt object is created during the New() method and almost all parameters are applied directly to the object, only in few special cases the :create() method is overloaded from basic.prg to handle special situations (see textbox.prg)

Probably dropping usage of ::create() and ::lCreated was an error....

d) give me :create() back
I don't want fulle :create() back, but only part to handle certain situations...
let's see why

In HMG3 using xBase or "oneliner" definitions was almost the same, infact both loaded _HMG_SYSDATA array with parameters value and then called the proper _DefineXXX function, for example, _DefineCombo. Inside this function the library author was able to do all the thinks needed IN THE CORRECT SEQUENCE...

Actual HMG4 code, like explained in point c), directly operates on hbQt objects, so that NO CORRECT SEQUENCE IS GUARANTEED when using oneliner or OOP style !

Example (just the needed code shown):

Code: Select all

  DEFINE COMBOBOX cb_country
    ON CHANGE {|| lbl_descr:text = aCountry[ cb_country:value ] }
    ITEMS aCountry
  END COMBOBOX
  DEFINE LABEL lbl_descr
When run the ON CHANGE code block is associated to the onChange Qt event BEFORE assigning values to the combobox... so at the next line, for each item in aCountry the on change event is run... ok, it may be justa waste of cpu but in this case lbl_descr does not exist yet !!!

I already described this problem in the past because in the first implementation of HMG4 the create() method first applied the onchange codeblock and then assigned the items.. it was just a matter of changing order to solve the problem. Now with the new implementation I was forced to check for ::lCreated = .T. before calling the codebock...

A similar problem happens with SPLITBOX, where using the PLACEMENT command the splitbox is moved based on the first children... so using this command before creating the child gives error... Splitbox already has a create() method and so this parameter must be moved there..

e) about TAB and TAB PAGE
There are several differences between HMG3 and 4 on TAB and TAB PAGEs.
The first problem arise from the command definition

Code: Select all

// HMG3
#command PAGE <caption> [ IMAGE <image> ] ;

//HMG4
#command PAGE <oObj> [ IMAGE <cImage> ] [ <dummy1: OF, PARENT> <oParent> ];
   =>;
   With Object &(<oObj>) := TabPage():New( <oObj>[ , <oParent> ] )   ;;
The different command breaks compatibility ! A caption is used as object name... but caption can be "&Data" or "New tab", both invalid object names... The object name in HMG4 is necessary due to a simple fact: widgets children of a TAB PAGE are accessed in different ways between HMG3 and HMG4 ! Imagine a situation like the following:

Code: Select all

DEFINE WINDOW w
  DEFINE TAB t
    DEFINE PAGE p
      DEFINE LABEL l

// HMG3 accessing label l
w:l:text = "text"

// HMG4 accessing label l
w:t:p:l:text = "text"
In HMG4 you have to specify all the parents, so you NEED to have page names.. in HMG4 you may have the same object name in different tab pages !!! something that seems not possible in HMG3...

I was thinking how to have both possibilities when I put my leg into the water...

For example using oParent:oParent:oParent:addData(...) when HMG3 legacy code is compiled (-DHMG3) and proper definition of PAGE <par> depending on it, so that in HMG4 you must specify a name in TAB and PAGE.

I just put the titles and summary of next points

f) HASH and ON ERROR
now we use ON ERROR and a HASH to keep track of childrens. it solves some kind of problems but it may be a bit slower.
see in basic.prg

g) killing aControls
it was used to keep (another) reference to object children for some special pourpose. Now the Hash also handle this.

h) don't show that window (or, long life to ::lCreated)
if VISIBLE .T. (or :visible = .T.) was present in the window definition of a HMG4 program it appeared on the screen immediately but the children widgets created when the window was on screen were not made visible by Qt and you are forced to add a :show() to have them visible...

This is another aspect of point d): there are some cases where methods or values may be set only in a specific sequence

i) About object names, killing LOCALs, and reference counts...

User avatar
l3whmg
Posts: 694
Joined: Mon Feb 23, 2009 8:46 pm
Location: Italy
Contact:

Post by l3whmg » Mon Aug 22, 2011 4:02 pm

Hi MrDuck,
your experience and inventory list it's very detailed on the other hand more of us don't test his HMG3 programs: this is a big error, my big error.

Anyway, about create I remember a post where I give my answer to Rathinagiri. My answer was: we preserve it. I'm not a wizard, but for some reason I find usefull to have this ability, perhaps for different reasons. Anyway, keep "create" was a must (not at all, ok); ie to "create" pending childrens or to "arrange" pending childrens. Now, Qt object are created within new method and we have two layer: HMG object and QT object with "some" differences to be aligned. Sometimes we need a create to do it.

About Hmg3 setproperty/getproperty: these are powerfull functions and they have the ability to manage in a right way the "properties"; as you write, to have the same performances it seem to be "hard". I think: when HMG3 is born there isn't "alternate syntax", but some prefixed scheme of commands; when alternate syntax was introduced the preprocessor was incremented with some commands, but to respect the previous one was introduced some "variants" (ON INIT / ONINIT).
I'm not sure but probably the reason was like this. On the other hand the right sequence is controlled by HMG3 functions, now we can't have (o more times we can't have) a prefixed/controlled sequence: and this can be a (great) problem.

ASAP I donwload your last commit and check it and report to you my pow.

Many thanks for you job while you are out for your holidays with your family and your leg into the water 8-)
I hope you can have other dream :lol:

Luigi
Luigi from Italy
www.L3W.it

Post Reply