For Programmers: Free Programming Magazines  


Home > Archive > Cobol > May 2004 > Treeviews









You are viewing an archived Text-only version of the thread. To view this thread in it's original format and/or if you want to reply to this thread please [click here]

 

Author Treeviews
James J. Gavan

2004-05-23, 10:30 am

Pete,

I've had a a good read of your document - very informative - but what a
big difference between the approach from the F/J and M/F compilers.

Probably not interested, but if you are I could send you my test Cheese
Treeview Application - trouble is without an Animator it isn't easy to
get your head around invoking different class and their methods.

Your latest version of F/J does it still exclude Collections; is that an
extra add-on ? If so, that is a BIG pity because you don't know what you
are missing.

First thing I noticed just like Procedural COBOL you are caught in the
loop of establishing a Table in Working Storage so that you can control
your Treeview entries, identifying their IDs, Levels etc. The first
thing I noted, running up against the W/S table concept, you had to set
yourself an upper limit, allowing for a maximum of 300 items at the
lowest Level and checking within your program that you didn't exceed
that limit - if you do, you generate an error message. It's OK what you
are doing under the circumstances in which you designed. Any REUSE of
the Treeview component is also set to that upper limit.

M/F - how many entries - how long is a piece of string ? Either for
somebody else, or me (can't remember), David Sands adapted the Dialog
System to produce a very basic equivalent of Windows Explorer. Certainly
the screen sits there blank, seems like ages, but possibly close to a
minute, while it builds the Treeview for your machine - but dependent on
exactly how many folders you have. Your approach would screw that.

I note you have the equivalent of four Roots - no problem with that, but
my test application which is intended to test access to different DB
Tables has the following structure :-

[-] Cheese
[+] AU Australasia
[+] EE Eastern Europe
[-] WE Western Europe
[+} 10 Belgium
[-] 20 England
123456 Cheddar
123457 Derby
[-] 25 France
123444 Dorset Blue Vinny
[+] 30 Germany

** Not a typo - I've deliberately put Dorset Blue Vinny under France -
see changes below. (Forgotten whether or not that is 'Vinny' or 'Vinney'
- but you would have real trouble getting it; back 4 decades ago, it
was only made at some 4 or 5 Dorsetshire farms).

I stressed I want those identities in front for sequencing - because
that's how I want the "picture" to appear for Corrosion Testing - Root -
Amoco Waterton Plant, Level 1 - 01 Main Plant , 02 Satellite Site # 1,
03 Satellite Site # 2, Level 3 (Vessels) - 001a - Flash Drum Containder,
001b - Boiler etc., Level 4 (Items) 000100 - V-BAND on 6 IN ELBOW.
000105 - H-BAND on NE SHELL (south side) - so the major records I want
to access are Level 4 - Items , several tables covering descriptions and
corrosion testing readings.

Back to the Cheese. For convenience rather than set up Tables I used one
ISAM (Continent) and two ISAM Alt Key 1 Files for Country and Cheeses -
that allows me to select on Continent or Country in the Alternate Key -
and bearing in mind the classes for File Handling are already written.
In actuality for Corrosion I will be using Tables so CURSOR SELECT
DISTINCT will be more flexible.

I presume the logic that appears in M/F must surely parallel Windows API
features - because it seems to me that creation of a Treeview is very,
very similar to a Master Menu with dropdown Sub-menus. Both are done
using collections - a Treeview has 'levels' of collections, so does a
Master menu have 'levels' of Collections. The size of the collection -
I don't give a hoot - theoretically limitless, subject to memory. What
is happening is that an Order Collection "ofReferences (objects)" is
being created at each level of the Treeview, with the exception of Level
4 - individual cheese which are contained in the Country Collection.

I read the three cheese files in sequence - e.g. having exhausted
cheeses for a particular country, then I will return to the Country File
and get the next country followed by accessing its cheeses. When I've
exhausted the Country/Cheese sequence, then I return to the Continent
Level and start over again. I noted you allowed for re-creating the
Treview - I don't. Once around the block seems OK to me.

When created I show the Treeview and "expand" at Level 1 - Continent, to
give user a starting point. Clicking on the "buttons' they can expand or
contract levels. (Windows function - no code from me).. Current
selection is always highlighted. There's a simple Popoup menu when they
double click which shows Add, Delete, Change - the logic used in
association with that :-

*>------------------------------------------------------------
Method-id. "POP-PopupMenuChoice".
*>-------------------------------------------------------------
Local-storage section.
01 ls-string object reference.
01 ls-Length pic x(4) comp-5.
01 ls-Text pic x(TextLength).

Linkage section.
01 lnk-choice pic x(4) comp-5.
88 AddIt value 1.
88 ChangeIt value 2.
88 DeleteIt value 3.

Procedure Division using lnk-choice.

invoke os-CurrentTvItem "getLabel" returning ls-string
invoke ls-string "SizeInBytes" returning ls-length
invoke ls-string "getValueWithSize"
using ls-length returning ls-Text

Evaluate true

*> Level-0 = Root
*> Level-1 = Continent : AA xxxxxxxxxxx
*> Level-2 = Country : nn xxxxxxxxxxx
*> Level-3 = Cheese : nnnnnn xxxxxxxxxxx

when ls-Text(1:6) is numeric
Evaluate true
when ChangeIt
invoke os-DBILevel-3 "ChangeRecord"
using os-CurrentTvItem
when DeleteIt
invoke os-DBILevel-3 "deleteRecord"
using os-CurrentTvItem
End-Evaluate

when ls-Text(1:2) is numeric

Evaluate true
*> Add to level below
when Addit
invoke os-CurrentTvItem "expand"
invoke os-DBILevel-3 "addRecord"
using os-CurrentTvItem
when ChangeIt
invoke os-DBILevel-2 "changeRecord"
using os-CurrentTvItem
when DeleteIt
invoke os-DBILevel-2 "deleteRecord"
using os-CurrentTvItem
End-Evaluate

when ls-Text(1:2) is Alphabetic-Upper

Evaluate true
*> Add to level below
when Addit
invoke os-CurrentTvItem "expand"
invoke os-DBILevel-2 "addRecord"
using os-CurrentTvItem

when ChangeIt
invoke os-DBILevel-1 "changeRecord"
using os-CurrentTvItem

when DeleteIt
invoke os-DBILevel-1 "deleteRecord"
using os-CurrentTvItem

End-Evaluate

when ls-Text(1:6) = "Cheese"

Evaluate true
*> Add to level below
when AddIt
invoke os-CurrentTvItem "expand"
invoke os-DBILevel-1 "addRecord"
using os-CurrentTvItem
End-Evaluate

when other
invoke os-Treeview "show"

End-evaluate

End Method "POP-PopupMenuChoice".
*>-------------------------------------------------------------

Depending upon menu choice the current object selected is sent to one of
three DBIs - Level 1, 2 or 3.
One of three Dialogs is generated as an Instance of TabbedDialog for
Adds and Changes :-

ADD - Level 1 - Continent - user enters ID and Name
ADD - Level 2 - Country - user enters ID and Name - Droplist is
shown with 'greyed' Continent
ADD - Level 3 - Cheese - user enters ID and Name - Droplist is
shown with 'greyed' Country

"Add" and "Change" Labels are created in a similar manner from the
Dialog information. For cheese :-

*>--------------------------------------------------------------
Method-id. "makeTvLabel".
*>--------------------------------------------------------------
01 ls-text pic x(textlength).
Linkage section.
01 lnk-string object reference.
Procedure Division returning lnk-string.
initialize ls-text
String Cheese-ProductCode1
" " delimited by size
Cheese-Name delimited by " "
x"00" delimited by size
into ls-Text
End-String
invoke CharacterArray "withLengthValue"
using ws-length, ls-text returning lnk-string
End Method "makeTvLabel".
*>--------------------------------------------------------------

For an "Add" : -

*>--------------------------------------------------------------
Method-id. "writeRecord".
*>--------------------------------------------------------------
01 ls-Item object reference.
01 ls-string object reference.

*> 1 : update File/Table for NEW Record
move Cheese-ProductCode1 to Cheese-ProductCode2
invoke os-CheeseFile "writeRecord"
using Cheese-Record returning Cheese-SqlResult
*> 2 : Add to Treview
Evaluate true
when ResultOK
invoke self "makeTvLabel" returning ls-string ------>see
method above
invoke os-Treeview "addItem"
using os-OldCountry, ls-string returning ls-Item
invoke os-OldCountry "expand"
when FileError
invoke self "PB-Exit"
End-Evaluate

End Method "writeRecord".
*>--------------------------------------------------------------

CHANGE - now this gets more tricky because the user may have made a
blooper like putting Dorset Blue Vinny under France- Unfortunately in
EDP we can't guarantee it wont happen.

Now for changes I could have introduced Drag and Drop as you see in
Windows Explorer. No thank you very much. I once scared myself stiff by
experimenting with moving a COBOL project. Holy Moley where the hell has
it gone ?. I had to use the Explorer "search" to find whee it was. Phew
! Can you imagine the complexities it would create if you gave a user a
Drag and Drop feature in a Treeview controlling records - like giving
them a 007 badge.

CHANGE - Level 1 - Continent - user enters new Name
CHANGE - Level 2 - Country - user enters new Name - and/or selects
'new' Continent from Droplist
CHANGE - Level 3 - Cheese - user enters new Name - and/or selects
'new' Country from Droplist

Too complicated to show whole code here. Name change obvious,
REWRITE/UPDATE and change Treeview Label.

Level 2 - Country with change of Continent - I already know current
Continent, (Ancestor) because I put it as an object in the text area of
the Droplist. Briefly, getting the new location :-

*>-------------------------------------------------------------
Method-id. "getNewContinent".
*>--------------------------------------------------------------
01 n pic x(4) comp-5.
01 ls-Callback object reference.
01 ls-RootItem object reference.

move 1 to n
invoke os-Treeview "ItemAtIndex" using n returning ls-RootItem
invoke ls-RootItem "children" returning os-ContinentTvList
invoke Callback "new"
using self "getNewContinent2 " returning ls-Callback
invoke os-ContinentTvList "do" using ls-Callback
End Method "getNewContinent".

Note : the blank space at the end of the literal "GetNewContinent2 " is
deliberate - it indicates x'00'.
*>--------------------------------------------------------------
Method-id. "getNewContinent2".
*>--------------------------------------------------------------
Linkage section.
01 lnk-Element object reference.
Procedure Division using lnk-Element.
set NewContinentLabel to true
invoke self "getTvLabel" using lnk-Element
if ws-NewContinentKey = Country-Continent
set os-NewContinent to lnk-Element
invoke os-ContinentTvList "quitIteration"
End-if
End Method "getNewContinent2".
*>--------------------------------------------------------------

I also check Level 2 (Old Continent) for "numChildren" to see if it has
any, then "getChildren" which returns me an OrderedCollectioin of
children. So now I'm able to update files/tables, move the Country and
Children to the new Continent Location, "destroy" the old Level
information and re-display. So the user can visually see what happened,
as necessary, I expand the new Continent so that the country and
'children' cheese also show. at the new location. Hey presto ! With a
selection of the Middle East from a droplist I can move New Zealand
along with Bleu de Montagne and Four Herb Gouda slap bang into the
Middle East, or the Arctic if you prefer :-)

Same sort of procedure for moving Dorset Blue Vinny from France to
England, but using the Level 3 DBI.

DELETIONS - using warning messages "Are you sure ?" plus highlighting
that you are going zap "ALL" children records below.

1 - Level 3 - Cheese is simple. Delete File/Table record and destroy
Treeview Label
2 - Level 2 - Country get the children for the Country and progressively
delete them "destroy".
3 - Level 1 - continuously perform 1 and 2 and then finally delete
Continent.

Interesting comparison ?. But as I say very much controlled by Ordered
Collection techniques.

I have to ask - I have now seen I think some four sets of your source
code associated with OO. Always enjoy reading it, like Robert, very
elegant style, although yours is just slightly more stylised, plus the
giveaway with your Level 12s (from memory associated with punch card
layout - I think).. I suppose if I stop and think your code should look
elegant - after FORTY YEARS :-) The Question - I have never
seen you use the magic words "Method-id". Is everything Procedural COBOL
invoking POWERCOBOL routines; don't you ever create any classes of your
own ?
Peter E. C. Dashwood

2004-05-24, 12:30 am

Hi Jimmy,

you ask some good questions and I have responded below...

I have snipped most of your code simply for clarity. Thanks for
posting it.

Pete.

"James J. Gavan" <jjgavan@shaw.ca> wrote in message news:<0q1sc.569864$oR5.33986@pd7tw3no>...
> Pete,
>
> I've had a a good read of your document - very informative - but what a
> big difference between the approach from the F/J and M/F compilers.
>
> Probably not interested, but if you are I could send you my test Cheese
> Treeview Application - trouble is without an Animator it isn't easy to
> get your head around invoking different class and their methods.

<<<
No thanks, Jimmy. It's not that I'm not interested, it's just that
time is at a premium and I have no problems getting my head around
invoking different classes and their methods... or, indeed, with
treeviews or OOP.
>
> Your latest version of F/J does it still exclude Collections; is that an
> extra add-on ? If so, that is a BIG pity because you don't know what you
> are missing.

<<<
Neither PowerCOBOL nor NETCobol have ever "excluded collections". They
are implemented through the NODE object. Of course, you can also build
your own collection objects if that is what you want to do. I have
been using collections for at least as long as you have <G>, in both
Java and OO COBOL.
>
> First thing I noticed just like Procedural COBOL you are caught in the
> loop of establishing a Table in Working Storage so that you can control
> your Treeview entries, identifying their IDs, Levels etc. The first
> thing I noted, running up against the W/S table concept, you had to set
> yourself an upper limit, allowing for a maximum of 300 items at the
> lowest Level and checking within your program that you didn't exceed
> that limit - if you do, you generate an error message. It's OK what you
> are doing under the circumstances in which you designed. Any REUSE of
> the Treeview component is also set to that upper limit.

<<<
No you missed the point. The APPLICATION has these limits; the
Treeview control has NO limits. I wrote this tutorial several years
ago and it was intended for COBOL programmers with little knowledge of
OO. I therefore used Working-Storage to keep it familiar for them. It
would be very easy to replace the WS with a collection object. Today,
(actually, probably even then...) I wouldn't do it this way, but it is
a simple and viable implementation of a complex control. I had a lot
of positive feedback on it.
>

<snipped>
>
> I presume the logic that appears in M/F must surely parallel Windows API
> features - because it seems to me that creation of a Treeview is very,
> very similar to a Master Menu with dropdown Sub-menus. Both are done
> using collections - a Treeview has 'levels' of collections, so does a
> Master menu have 'levels' of Collections. The size of the collection -
> I don't give a hoot - theoretically limitless, subject to memory. What
> is happening is that an Order Collection "ofReferences (objects)" is
> being created at each level of the Treeview, with the exception of Level
> 4 - individual cheese which are contained in the Country Collection.
>

That is exactly how the NODE objects work. These objects (collections)
crop up in many applications and are a normal part of using VB. You
can think of NODE as a standard collection COMPONENT. (It is a
brick...)

> I read the three cheese files in sequence - e.g. having exhausted
> cheeses for a particular country, then I will return to the Country File
> and get the next country followed by accessing its cheeses. When I've
> exhausted the Country/Cheese sequence, then I return to the Continent
> Level and start over again. I noted you allowed for re-creating the
> Treview - I don't. Once around the block seems OK to me.
>

It needs to be recreated in that particular application because the
subsets it is displaying change as the user makes different selections
elsewhere in the app.
>
> When created I show the Treeview and "expand" at Level 1 - Continent, to
> give user a starting point. Clicking on the "buttons' they can expand or
> contract levels. (Windows function - no code from me).. Current
> selection is always highlighted. There's a simple Popoup menu when they
> double click which shows Add, Delete, Change - the logic used in
> association with that :-
>

<<<
Yes, that is all pretty standard.
>

<snip>
>
> Now for changes I could have introduced Drag and Drop as you see in
> Windows Explorer. No thank you very much. I once scared myself stiff by
> experimenting with moving a COBOL project. Holy Moley where the hell has
> it gone ?. I had to use the Explorer "search" to find whee it was. Phew
> ! Can you imagine the complexities it would create if you gave a user a
> Drag and Drop feature in a Treeview controlling records - like giving
> them a 007 badge.
>
>

<<<
I wouldn't give a power drill to a six year old, but I certainly use
one myself. All powerful tools need care and training. I use drag and
drop occasionally in COBOL. It is very powerful.

<snip>
>
> Interesting comparison ?. But as I say very much controlled by Ordered
> Collection techniques.
>

I think it is fine. (Actually, I think most things that work are
fine...<G> )
>
> I have to ask - I have now seen I think some four sets of your source
> code associated with OO. Always enjoy reading it, like Robert, very
> elegant style, although yours is just slightly more stylised, plus the
> giveaway with your Level 12s (from memory associated with punch card
> layout - I think).. I suppose if I stop and think your code should look
> elegant - after FORTY YEARS :-)

<<<
Well, yes... but I haven't been writing OO code for forty years <G>.

And I would not pretend that my approach is perfect. We have discussed
at length here the relative merits of SECTIONs etc. I am persuaded by
Richard's arguments on this, but I haven't changed my style. This is
not obstinacy, it is just what I feel comfortable with. I still use GO
TO to the end of a section, although lately I have been using EXIT
PARAGRAPH. I don't think any of this is really that important (for me)
and that's why I won't argue it here. Many people over the years have
had to maintain my code and no-one has ever complained. (Many have
actually adopted techniques I use and I guess that is a kind of
flattery; I once picked up some COBOL on a site in England and thought
that I must have written it...I hadn't, but I had trained the guy who
did, many years before. He was no longer on the site and it was only
when I asked who had written it that the truth came out <G> )
>
> The Question - I have never
> seen you use the magic words "Method-id". Is everything Procedural COBOL
> invoking POWERCOBOL routines; don't you ever create any classes of your
> own ?
>

That is a very good and fair question. And I see how you could arrive
at that conclusion, based on what I post here. The answer is "Yes, I
do create classes and use "Method-Id" all the time." I just don't post
the code here.
(Remember also, that my focus is on components, not OO Programming as
such.)

When I first started looking at PowerCOBOL (after using MF DIALOG and
the underlying PANELS technology to create COBOL GUI applications for
Windows 3.1) I realised that this OO stuff was pretty powerful
medicine.

PowerCOBOL separates the programmer from the nuts and bolts of OO and
you can certainly create elegant COBOL applications with it. This
stimulated my interest in OO and I realised I would need to "bite the
bullet" and learn this stuff. You well remember the early days of OO
in this forum when we were all trying to come to grips with it. It was
a fairly painful process as the concepts were new and all of us were
subject to different influences and drivers.

PowerCOBOL helped me to get the fundamental concepts of encapsulation,
methods, and properties. It was therefore natural that a lot of what I
wrote was procedural COBOL wrapped in OO wrappers by PowerCOBOL. I'm
glad I did that because it enabled me to be productive very quickly
and encouraged me to persevere with COBOL rather than move totally to
Java or VB.

(My "catharsis" to OO actually happened when I taught myself Java. It
became very clear very quickly and then OO COBOL looked clumsy and
unwieldy by comparison.)

The other thing that influenced me was the fact that components are
actually more useful (for me) than OO Classes. It is an absolute
doddle to create components in PowerCOBOL because it provides the
necessary templates and wrappers and relieves you of all the "stamp
collecting".

These days most of what I do is Web Based so I don't need the GUI
wrappers provided by PowerCOBOL and it is over a year now since I
wrote a PowerCOBOL app.

I still write components and would use PowerCOBOL for this where they
are not required to be web enabled. (I found through bitter experience
that PowerCOBOL does not always function correctly when it has to run
under COM+ and MTS. However, it isn't such a big deal to rewrite a
PowerCOBOL component into standard OO COBOL and wrap it as a COM
server.)

I know you LOVE to see code Jimmy so I'm going to break a "rule" and
post some OO COBOL code that was partly "leveraged" from existing
legacy code. You can count the "Method-Id"s in it if you like <G>.

This is the source code for a COM server component that contains
methods to access and maintain a database. It is a combination of what
were a number of procedural COBOL modules, along with some true OO
Methods. It runs across LAN and Internet using COM+ and MTS. (I was
going to "upgrade" it to SOAP but this is on hold now while we see
what happens with .NET.)

Given that the design was constrained by the need to use existing
code, I'm not sure that I would do it this way from scratch. Probably
I would use Data Objects now. Still, it is an example of an OO
component that is certainly more complex than String2Num...<G>, and it
may persuade you that my OO COBOL experience is not limited to
PowerCOBOL. (BTW, the XML example is also from an OO COBOL component;
I just snipped the "housekeeping" headers for the sake of clarity and
brevity...)

------------------- Sample OO COM Server Class ------------------
IDENTIFICATION DIVISION.
CLASS-ID. WBRCOMSvr INHERITS FJBASE.
*
*AUTHOR. Peter E. C. Dashwod.
*
*Written 2nd October, 2003 for xxxxxxxxxxxxxxx..
*
ENVIRONMENT DIVISION.
CONFIGURATION SECTION.
REPOSITORY.
CLASS COM AS "*COM"
CLASS FJBASE.
IDENTIFICATION DIVISION.
OBJECT.
*
*------------------------ DATA DIVISION ----------------
DATA DIVISION.
WORKING-STORAGE SECTION.
* Common Properties go here...
01 InterfaceControlBlock Pic x(165) PROPERTY.

01 ObjectContextObj OBJECT REFERENCE COM.

01 rmscur-flag pic x value zero.
88 RMScur-open value '1'.
88 RMScur-closed value zero.
01 srcur-flag pic x value zero.
88 SRcur-open value '1'.
88 SRcur-closed value zero.
01 connection-flag pic x value zero.
88 already-connected value '1'.
88 not-already-connected value zero.

01 ws-InterfaceControlBlock.
12 MT-table-name pic x(16).
12 MT-action-block.
15 MT-return-code pic x(5).
* MT-return will contain the SQLSTATE from the DB action...
88 MT-return-OK value zero.
15 MT-message pic x(128).
* MT-message will contain the SQLMSG from the DB action...
15 MT-action pic x.
88 MT-insert value '1'.
88 MT-update value '2'.
88 MT-delete value '3'.
88 MT-fetch value '4'.
12 MT-RoomNum-1 pic x(4).
12 MT-RoomNum-2 pic x(4).
12 MT-count pic 999.

01 passed-record pic x(1024).

COPY WEBINThv.


PROCEDURE DIVISION.
* Factory Methods go here...

* Object Methods go here...

IDENTIFICATION DIVISION.
METHOD-ID. TableMaint AS "TableMaint".
ENVIRONMENT DIVISION.
DATA DIVISION.
WORKING-STORAGE SECTION.
LINKAGE SECTION.
01 TableImage PIC X(1024).

PROCEDURE DIVISION
using TableImage.
A000.
display "..." Function CURRENT-DATE upon syserr
display "Entered TableMaint..." upon syserr
move InterfaceControlBlock to ws-InterfaceControlBlock
display 'IntControlBlk=' ws-InterfaceControlBlock upon syserr
move TableImage to passed-record

set MT-return-OK to TRUE
move '00000' to SQLSTATE
if NOT MT-fetch
* Acquire Object Context...
invoke COM "GETOBJECTCONTEXT"
returning ObjectContextObj
end-invoke
if ObjectContextObj NOT = NULL
display "Object Context was obtained OK." upon syserr
else
display "Needed Object Context failed to instantiate." upon
syserr
end-if
else
display "ObjectContext not required..." upon syserr
end-if
EXEC SQL
CONNECT TO 'MBSwebintdb'
END-EXEC
display "Connecting to DB..." upon syserr

if SQLSTATE NOT = '00000'
move SQLSTATE to MT-Return-Code
move SQLMSG to MT-Message
go to a999
end-if
display 'Context and connection succeeded...' upon syserr
evaluate MT-table-name
when 'WEBINT'
display "invoking WebintMT..." upon syserr
invoke SELF "WebintMT"
end-invoke
when 'WEBINTRMS'
invoke SELF 'WebintrmsMT'
end-invoke
display "invoking WebintrmsMT..." upon syserr

when 'WEBINTSR'
invoke SELF 'WebintsrMT'
end-invoke
display "invoking WebintsrMT..." upon syserr

when other
move '88886' to MT-return-code
move 'No valid table was passed to "TableMaint" Method of
WEBINTComSvr.'
to MT-message
end-evaluate
Sponsored Links







Also available: Server administration forum archive | Web Design forum archive | Software forum archive | Hardware reviews archive

Copyright 2008 codecomments.com