Libraries & objects
About Archicad and BIMcloud libraries, their management and migration, objects and other library parts, etc.

Using GDL Data I/O Add-on to list in layouts

Matthew Johnson
Advocate
I have two objects, one is a marker that users record data into and the second is a listing object that is supposed to take the data from all the markers on a layout page and list them in order. (For those that haven't guessed already I'm working on a revisioning system)

The marker object uses a Data I/O to push the information out to a text file;
ch1 = OPEN ("DATA", "RevisionControl.txt", "MODE = WA")
OUTPUT ch1, GLOB_INTGUID, 1, LayoutID, LayoutNumber, LayoutName, RevID, RevSub, RevNote, RevDate, RevPerson
CLOSE ch1
I'm using the GLOB_INTGUID as the data key because this is then a unique number for each marker that can be updated in the database if the marker object is modified. The LayoutID, LayoutNumber and LayoutName variables are requested from the layout page by the object and the various Rev__ variables are user entered data.

The list object is then supposed to pull this data in from the text file. BUT...
I can only get the INPUT command to pull in one row of data from the file and I have to know the specific key for each row to be able to pull it in.
ch1 = OPEN ("DATA", "RevisionControl.txt", "MODE = RO")
RevData = INPUT (ch1, "???", 1, LayoutID, LayoutNumber, LayoutName, RevID, RevSub, RevNote, RevDate, RevPerson)
CLOSE ch1
Once I find a way to get multiple rows of data in (to an array?) I then need to be able to filter down to just the marker data for objects on this page of the layout book.

Suggestions?
Matthew Johnson - POWE Architects
AC4.5 --> AC27 & Revit 2019 --> 2023
Asus Zenbook Pro 16x i9-13900H w/ Nvidia RTX 4070 4K dual, Windows 11 64bit
I'd rather be sailing.
12 REPLIES 12
sinceV6
Advocate
Hi.

I did something like this some time ago, but just a simple notes object, that would pull data out from a text file.

You will need to loop the INPUT keyword and assign values to an array, like you said, to use the data.

I picked this code snippet up from somewhere:
 
! Example to read all string values from a file 
! and use it in a value list 
DIM sarray[] 
! file in the library, containing parameter data 
filename = "ProjectNotes.txt" 
ch1 = OPEN ("text", filename, "MODE=RO, LIBRARY") 
i = 1 
j = 1 
sarray[1] = "" 
! collect all strings 
DO 
n = INPUT (ch1, i, 1, var) 
IF n > 0 AND VARTYPE (var) = 2 THEN 
sarray = var 
j = j + 1 
ENDIF 
i = i + 1 
WHILE n > 0 
CLOSE ch1 
! parameter popup with strings 


What I did, as I was really experimenting with the CHANNEL and INPUT keywords, was to first count how many rows and columns were in the file, so I could organize data; then I used a couple of loops to put it in a two dimension array and analyzed the size (string size) of each column. This way, I could use the same object to write notes, keynotes or tabulated data from a text file.

Hope that helps.
Best regards.
Matthew Johnson
Advocate
sinceV6,

Thank you for the pointer.

The issue with this procedure however is that it relies on your data source having sequential integer recordIDs starting at 1. As the data source is being created for each project by a number of objects inserted into the layout book I need to have a recordID control system that allows each marker object to have its own individual recordID (for updating to ensure the data for each object is mapped properly) but then I need to have a way to have the list object pull that data without knowing all of the recordIDs for each record.

I can't find a way to pull the records from the file line by line without knowing the recordIDs and to get it to search for all possible GUIDs would cause an infinite loop that will crash on run.
Matthew Johnson - POWE Architects
AC4.5 --> AC27 & Revit 2019 --> 2023
Asus Zenbook Pro 16x i9-13900H w/ Nvidia RTX 4070 4K dual, Windows 11 64bit
I'd rather be sailing.
sinceV6
Advocate
Matthew.-

If you are writing those values, can't you use them as a filter? The way I see it, you are trying to filter with the GLOB_INTGUID -that you are using so that values get correctly mapped for output-, but I would rather write the code so that it filters the lines based on what layout the object getting the data is placed on; this way, you may have 100 placed objects throughout your layouts, but only 10 in one: those are the ones you would like listed, right?

So assign values to the array only if the layoutID value of the record matches the current layout.

Unless of course I'm not getting what you are trying to do...
Ben Cohen
Enthusiast
Hi Mathew

I think you need to write using 'Data' then read using 'Text'. This way you can read the entire text file.
You could also prefix your layout number and name to the GUID as database key - to get the data to sort automatically for you.
Ben Cohen
Mac and PC
Archicad (Latest Version) aus
www.4DLibrary.com.au
Matthew Johnson
Advocate
Ben, Thanks for the idea. I'd missed that Data and Text use slightly different formats for extracting recordIDs.

I'm now working up a version where the recordID that is written to the file is a combination of the LayoutID, RevID and RevSub so that they are pre-ordered in the text file.

I also need to find a way to make the listing object update either automatically or by a control mechanism like a button in the UI.
Matthew Johnson - POWE Architects
AC4.5 --> AC27 & Revit 2019 --> 2023
Asus Zenbook Pro 16x i9-13900H w/ Nvidia RTX 4070 4K dual, Windows 11 64bit
I'd rather be sailing.
sinceV6
Advocate
Completely missed that you were using DATA. I was always referring to using TEXT

As far as I can remember, reloading libraries would update your placed object, but in the notes object I worked, it only retrieved values from a text file. Not sure if it would work when there are other objects writing to the database (at the same time?).

Cheers!
Matthew Johnson
Advocate
So I now have both objects working close to the way I want them to.

The Marker Object pushes data out and the data is ordered by page and then instance;
MASTER SCRIPT
n = REQUEST ("HomeDB_info", "", LayoutID, LayoutNumber, LayoutName, LayoutContext)

index = (LayoutID * 100) + RevID + (RevSub / 100)

ch1 = OPEN ("DATA", "RevisionControl.txt", "MODE = WA")
OUTPUT ch1, index, 1, LayoutID, LayoutNumber, LayoutName, RevID, RevSub, RevNote, RevDate, RevPerson
CLOSE ch1
The Listing Object then reads this data;
MASTER SCRIPT
n = REQUEST ("HomeDB_info", "", ThisLayoutID, ThisLayoutNumber, ThisLayoutName, ThisLayoutContext)

! Create an array to put the data in
DIM RevArray[][5]
i = 1
j = 1
RevArray[1][1] = ""

! Open the text file containing the Revision data
ch1 = OPEN ("TEXT", "RevisionControl.txt", "MODE = RO")

! Collect all strings
DO
	RevData = INPUT (ch1, i, 1, index, LayoutID, LayoutNumber, LayoutName, RevID, RevSub, RevNote, RevDate, RevPerson)
	IF LayoutID = ThisLayoutID AND RevData > 0 THEN
		RevArray[1] = RevID
		RevArray[2] = RevSub
		RevArray[3] = RevNote
		RevArray[4] = RevDate
		RevArray[5] = RevPerson
		j = j + 1
		ENDIF
	i = i + 1
	WHILE RevData > 0

! Close the data source
CLOSE ch1
Problems that still exist;
- If a marker is modified (e.g. RevSub is accidentally set at 5 and then changed to 4) it puts two entries in the database and lists them both.
- The only way to get the Listing Object to update to show the new Marker Object data is to open the Listing Object's properties and change one of the property values thereby causing it to re-build.

This could be overcome if I could somehow get the database file to reset and re-build itself from all of the objects in the layout book but this sounds like just the same hurdle that caused me to start this exercise; the lack of an ability to list objects in the Layout Book!

Is this where I have to learn to program the API?
Matthew Johnson - POWE Architects
AC4.5 --> AC27 & Revit 2019 --> 2023
Asus Zenbook Pro 16x i9-13900H w/ Nvidia RTX 4070 4K dual, Windows 11 64bit
I'd rather be sailing.
Joachim Suehlo
Advisor
Did you read the chapters from Laurent Godel in DNCs GDL Cookbook 3; maybe there are some hints in it that may help.
http://www.nottingham.ac.uk/~lazwww/cookbook/CB_download/cookbook3download.html
Joachim Suehlo . AC12-27 . MAC OSX 13.5 . WIN11
GDL object creation: b-prisma.de
sinceV6
Advocate
Hi.
Isn't that because you are using the data as the recordID to map the values? Each time you modify a value in an object, a new record will be generated, based on what I see in your code.

Maybe I didn't explain myself before: I think you were right to use the GUID value to map the recordID, so it doesn't matter what values the object gives, they should fall in the same record; but once you have the database, instead of trying to find the GUIDs of the objects in the layout, list objects that are in the layout comparing the layoutID value to the current one.

As for the updating thing... did you try reloading libraries?