Who is modifying a Field?

After converting a Panoramas 6 file to Panorama X, I’m getting a strange behavior, and trying to track down the problem. Clicking on any record in the data sheet, or just using up or down record, causes a certain field to be cleared. This does not happen when running under Panorama 6.

I’ve searched the forum and the Help but haven’t found any way to discover who is modifying the field. There are a few other fields that have code to call procedures, but none of those are modifying the mystery field, and I used zlog just to make sure they were not getting triggered.

I used Gary’s wonderful Variable View utility, but it didn’t help me find the culprit.

I’ve use the instrumentation log to try to track what is happening, but so far it hasn’t given me any clues.

There is no .CurrentRecord procedure.

I created a .ModifyRecord routine, and it obediently gets triggered when I move up or down and record, but I haven’t figured out what I could put into this routine to find out who is modifying the field.

I enabled Diagnostic mode, but the field still gets cleared just by moving down or up a record.

Is there any way to monitor a certain field, to find out when it gets modified, and by who?

Maybe - since it’s a new conversion, you have some automated calculation built into the field via the Datasheet. I’ve learned to go through converted files, field by filed with the Properties panel open so I can check for any unexpected carry-overs.

Yea, that’s good advice. I had to click through over 100 fields to see which ones had code in the Field Properties. Not having the Design Sheet anymore means it’s much harder to quickly see all the fields and their properties at once. Gary’s utility is great for seeing a list of the fields, and variables, and I was also searching for a way to generate a list of the fields with their associated code and formulas, but couldn’t find one. None of the info functions seemed to show field code or formulas. Did I miss one?

However, this field gets cleared just by an up or down record, so I am not editing any field that might trigger any code or routine (but, SOMEONE or SOMETHING is editing the field :grin:)

And even though Jim doesn’t recommend using .ModifyRecord, it is at least handy to show me that the record seems to be getting modified. I put the following statement in it:

zlogalways info(“trigger”)

and in the instrumentation log I get:

RUN TOOL (procedure window)
RUN TOOL (procedure window)
RUN TOOL (procedure window)
RUN TOOL (procedure window)
RUN TOOL (procedure window)
RUN TOOL (procedure window)

Yep, six of them when I do one downrecord! So that is another clue, but I still can’t find out who is modifying the record.

I used zlogalways after failing to get any output from zlog.

Here is a procedure that will generate a list of fields with Code in their properties and with the code itself.

 let lvresult=""
 let lvformula=""
field (array( dbinfo("fields",""),1,cr()))  //Moves to first field on left end of data sheet
loop
  lvformula=getdictionaryvalue(getfieldproperties("",info("fieldname")),"PROCEDURE")  //retrieves the formula for the current field
    if lvformula ≠ ""
          lvresult=lvresult+cr()+info("fieldname")+tab()+lvformula  //adds the formula to the list of formulas found
    endif
    right
until info("stopped")
 if lvresult≠""
    filesave "~/Desktop/theCODE.txt",lvresult  //saves the list to a text file
    openwith "Numbers","~/Desktop/theCODE.txt"
else
     Alertsheet "No code found in that database"
endif

No. This has been an idea I’ve thought of before, but it hasn’t actually happened.

Is the data sheet the only window open? If there is a form window open, it’s possible that a form object could be modifying the field.

Great idea, but I think the implementation could be so much simpler. Also, Tom’s code only checks code, not formulas. Here is a possible revised version. Instead of exporting all of the formulas and code, this version generates a list of all fields that contain references to the field you are interested in, but you could easily modify this to output a text file like Tom’s version.

let problemField = "Field Name"
let referencesProblemField = ""
looparray dbinfo("fields"),fname
    let fproperties = getfieldproperties("",fname)
    let fcode = getdictionaryvalue(fproperties,"PROCEDURE")
    let fformula = getdictionaryvalue(fproperties,"FORMULA")
    if fcode+" "+fformula contains problemField
        referencesProblemField = sandwich("",referencesProblemField,cr())+fname
    endif
endloop
displaydata referencesProblemField

Another option would be to simply export a blueprint file for the database, and then use a text editor to search the blueprint.

BINGO Jim, that seems to be it! I had two form windows open, and as soon as I closed them the field stopped getting cleared. I am now busy making copies of those forms, and deleting objects that have formulas, and tracking down the side effect.

And much thanks to CooperT and Jim for the useful routines!

I also figured a blueprint would be mentioned as a possible tactic, but hadn’t gotten the courage to look into them, so thanks also for that option.

FWIW, I don’t think you would have much trouble with understanding blueprints.

Tokyodave - as far as checking that a specific field was modified and by whom, How about this …
When the database opens, your initialize procedure stores the current value of that field. I’m assuming you have a way of identifying who is logged into the database. When the database is closed, are part of your “close” routine, you can check the value of that field again. If it’s different, it’s been changed and you know by whom - sort of. Because “change” can either mean different or it can mean monkeyed with.

If, during a session, I change the content of a field from 5 to 3, and before I close out, I change the 3 back to 5, did I change the value of that field?

I suppose another way is to attach a procedure to the field that triggers when the field is clicked/tabbed out of. It would make the compare then. But I’m pretty sure that “trigger” won’t fire if the field is changed with a procedure (rather than clicking in it and editing).

Paul, please read the original question a bit more closely. He knows for sure that the field is being modified, and he knows it’s not happening due to data entry, but simply due to clicking on another record. What he doesn’t know is why clicking on a record should change a field value, though it appears to be a side effect of an object in a form.

Ah - you are correct Sir! I just read the question at the bottom of his post. Mea Culpa :blush:

SOLVED !!

To recap, if a certain form was open, a field was being cleared, and I was seeing four triggers in the log, every time I did an up or down record. (As mentioned above, to track this down I created a .ModifyRecord procedure, and had it zlogalways info(“trigger”).

I finally discovered a Text List form object that was trying to do a “look up” from a second database. Because that second file was not open, and in fact it didn’t even exist in the folder, an empty value would get stored into the field.

By “look up” what I actually mean is that the Text List object had the Value set to the field, and the Content Data database was set to a nonexistent file. By deleting that Text List object I got rid of two of the triggers I was seeing in the log.

BUT, I was still getting the remaining two triggers in the log, even after I had very laboriously deleted EVERY object from the form, a few at a time, until there was nothing left, a blank form. I would do a select all on the form and I saw nothing selected. I finally tried doing a select all on the form, and then the delete key, and the triggers went away. So there was something invisible on the form. How did I find it?

First I went back to editing the form and did an Undo, so that the invisible thing came back. Then I looked in the Objects panel, after doing a select all on the form, and a Text List object was indicated in the Objects panel, the right-most tab. But it was invisible. So, I went to the Measurements panel, and found that this text list object was zero pixels wide and zero pixels tall. Aha! I could then expand the size so that I could see the thing. And why was this object clearing my field? The Value setting was the field that was getting cleared, and the Content Data database was blank. Very similar to the first Text List object that was deleting data.

(After I finally found this thing, I reset the size to zero wide and zero tall, and I found that when I did a select all I could see a tiny dot, which got bigger when I zoomed in. I had tried zooming in before and never saw anything, but in any event, it’s extremely easy to miss something that tiny.)

I’m wondering if there might be some upgrades to Panorama that could help avoid this kind of problem.

  1. Maybe a warning should appear whenever you edit a form that says: “You have one or more objects that are very tiny (less than 5 pixels wide and 5 pixels tall).” I assume it would be a bad practice in general to purposely create objects like that, and we would certainly want to know if they were created by accident. (I just chose 5 pixels as an example limit.) OR, much simpler, add an indicator in the tool bar that says how many objects are currently selected. I would immediately have been able to see that there was an object selected, even if I couldn’t see it. This would also help when you might have objects way over to the right side or way far down in the form, that you don’t see in the normal size of the form.

  2. This one may be much trickier to circumvent, but it seems that a Text List set to a field, with either no database connected or a nonexistent database connected, will result in data loss just by scrolling through the database. Not sure how best to catch or avoid that problem.

Yes, the first TL object was showing a warning that the connected database was not open, but of course we still don’t want data being deleted just because a file got closed. And the 2nd TL object was so tiny no warning could be seen. But after I expanded the size, no warning was given anyway, since it was not connected to any file.

Note that this set of files was written by me many years ago for a client, who then modified it himself over the years, and is now having me convert it to Pan X, so that’s how strange things have crept in.

Wouldn’t looking at the blue print of a form list all the objects on the form, regardless of size and visibility?

1 Like

Wouldn’t looking at the blue print of a form list all the objects on the form, regardless of size and visibility?

Technically, it seems the answer is yes. But I had no experience yet with blueprints, so didn’t think of trying that. I just now looked at a blueprint for a form with two objects. The blueprint has 180 lines and is five pages long (copied into a text editor)! So at first glance, it is somewhat intimidating, and you need to scroll through it all to digest it, but now that you have suggested it as another option I will keep it mind for the future, thank you!

Perhaps you could pass the Blue Print text to a variable and have a procedure scan that to provide a list of just the objects. Right now, you are looking at objects and A LOT of other details about those objects (size, location, etc.). So you are correct, that can be intimidating. But with a little work, you can have a procedure that does the looking for you and reports just the details you want to know.

I’d imagine three pieces of info would be useful; the object, its location, and its visibility status.

If the full blueprint is overkill and you only need to review a few properties for every every object on the form, the objectinfoarray(formula, query, separator) function, leaving query blank, is what you need.

Write the “formula” to produce a tab delimitated array of the desired properties. The function then produces a two dimensional text array of the desired information, delimitated by tab and “separator.” Then import that text into a new database. If some of the wanted properties might contain CR or LF, have “formula” replace( them with something unique and use a reverse replace( around the resulting array text within importtext…

Gives a PanX database with a record for every object and a field for each wanted property. Analyze that database, optionally saving it, as needed to answer your questions.

What’s the exclamation mark for?

Seriously, most of those 180 lines are boilerpoint - what is the color of each object, the border width, drop shadow dimensions, etc. Each individual blueprint item is quite simple and self explanatory. There is one line for each item in the object’s inspector panels. It’s an exact, one-to-one correspondence.

Imagine if you printed out all of the inspector panels for these two objects – that would be be 180 checkboxes, radio buttons, pop-up menus, etc., and would almost certainly take more than 5 pages to print. The blueprint should be no more intimidating than the inspector panels.

In this case, you are only interested in which objects reference a particular field. Once you’ve opened the blueprint in a text editor, you can quickly find that out using the editor’s search feature. You can ignore everything else in the blueprint, that’s just noise.

An advanced user such as yourself should not be intimidated by blueprints. It’s really a simple, straightforward feature that can be very useful in certain situations.