Where is documentation for custom statements?

Which training video covers the creation of custom statements and functions?

I see that regular statements are stored in _CollectionsLib but I can’t locate it - is it possible to do so?

michael

This Library is in Applications/Panorama X/Contents/Resources/ .
(You right-click on the Panorama X icon and choose Show contents.)

Thanks Kurt - I can’t open that file or any of its package contents but I can access a statement’s code via the OpenView dialog. This shows me the structure of an embedded procedure but I still don’t know how to create a custom procedure.

michael

The wizard for creating custom statements hasn’t been written yet. Some preliminary work was done several years ago, but I don’t believe I have heard anything about it since then. This is what Jim had to say in December of 2012.

I’ve just added the low level support required to implement custom statements. This support is slightly different than earlier versions of Panorama. The change shouldn’t affect anyone except developers that write custom statements or modify existing custom statements (you know who you are).

In the past, custom statements were implemented as farcalls. That worked fine, but it meant that each custom statement was hardcoded to a particular library database. In Panorama 6 and earlier, it’s not possible to move a custom statement from one library database to another (if you did this, ALL procedures that used this custom statement would have to be recompiled, which would be a rather rude thing to do).

In this new version, custom statements don’t reference the library database, so the procedure defining a custom database can be moved from one database to another. In addition, you can actually have a custom statement defined in more than one database library. In this case, whatever library is loaded last is the one that will be used.

I think I’m going to use this new feature to make it easier to “patch” custom statements built in to Panorama. First of all, all of the custom statement library databases that come with Panorama will now be built into the app bundle, and won’t be editable (at least not without mucking about inside the bundle, in which case all bets are off). After loading these internal libraries, Panorama will look in the users’s Application Support folder to see if any additional libraries have been placed there (there will be a special location). If there are any additional libraries, they will be loaded. These could contain new custom statements, or revised versions of Panorama’s custom statements. You only have to include procedures for the custom statements you actually want to override. Your versions of custom statements will not be overwritten if you install a new version of Panorama. If you want to revert to the stock version of the custom statement, you simply need to delete (or rename) your custom statement, or remove your library file from the Application Support folder.

Dave is, as usual, correct. There is no way so far for anyone other than myself to create custom statements or functions. I haven’t quite figured out how I am going to do that since libraries are now inside the Panorama package. So they will probably need to go into /Library/Application Support/PanoramaX, but there is no support for that at this time.

I use a number of custom statements in P6 in a dozen files, and when I did my first test yesterday converting a (small) P6 file to PX, that seemed to be the only thing I couldn’t see how to fix. Fortunately I found this thread.

As a workaround, I suppose I’ll have to put each custom statement into its own procedure in each P6 file that uses it, so it can be called as a subroutine in PX. Has anyone a better idea?

How about storing the custom statements in a dictionary and using the execute statement to run them?

Yes, actually it can be done using a dictionary, although the execute statement required is rather wordy compared with invoking a one-word custom-statement name. The compiler doesn’t like the text of the custom statement procedure to be quoted in the initializedictionary statement, but pipes work fine.

David Duncan

It might be better to have custom statements as procedures in a windowless database, and evoke them using farcalls.

Ok, I have not tested anything I am about to tell you, and it is subject to change. But I think you can get custom statements working now, Panorama X itself uses them extensively.

Probably the best way to set them up is in a separate database. In that database, each custom statement should have a name that contains only upper case ASCII letters (A thru Z), numbers, and underscore characters. For example DOSOMETHING or ACTION12. Optionally, these procedures can contain a procedure information comment block that specifies the parameters. Here is a minimal example.

/*
<PROCEDUREINFO>
<parameter name=INSERTNAME1HERE type=TEXT>description of parameter 1.</parameter>
<parameter name=INSERTNAME2HERE type=TEXT>description of parameter 2.</parameter>
</PROCEDUREINFO>
*/

If a parameter is optional, insert the optional tag, like this:

/*
<PROCEDUREINFO>
<parameter name=INSERTNAME1HERE type=TEXT>description of parameter 1.</parameter>
<parameter name=INSERTNAME2HERE OPTIONAL type=TEXT>description of parameter 2.</parameter>
</PROCEDUREINFO>
*/

Keep in mind that this comment block itself is optional. If it exists, Panorama will use it to check the number of parameters to your statement. If it doesn’t exist, Panorama will allow any number of parameters to your statement.

To activate your statements, first open the database that contains them. You can open it secretly or with windows, doesn’t matter. Then use this statement:

scanlibrary NameOfDatabase

That’s it! It should activate all of the statements in the database. If the database contains other procedures that don’t match the naming restrictions I mentioned above, they will be ignored. So you could mix custom statements with other procedures in the database, as long as the other procedures have some lower case letters or punctuation in the name.

You have to make sure the database stays open. If the database closes, the custom statement won’t work any more. Internally, custom statements work exactly like farcall statements. In fact, they are farcall statements, but Panorama figures out for you which database the procedure is located in, instead of you having to keep track of that.

If you want to activate custom statements individually, that can be done with the registercustomstatement statement. This is not going to be a documented statement, but if you look at the source of the scanlibrary statement (it’s in _PanoramaLib) you can figure it out.

Custom functions are another kettle of fish. Right now they are defined once when Panorama X starts up, and there’s no way to define one separately.

Thanks very much for going to these lengths to assist, I appreciate it.

I’ve now had a chance to examine scanlibrary and suppose that registercustomstatement registers individual statements from the statements database rather than all of them, and would still require the statements database to be open.

I’d prefer not to have additional databases in our factory computers to get lost or messed with or forgotten about, and in fact in the past I have folded several support databases (like customer and product files) into permanent variables in the one Panorama 6 file left on each of our factory computers to avoid having to worry about them. So in this case I decided to put my custom statements into one procedure in that P6 file separated by case statements, so I can call them as needed. I’ve just completed this and it works well.

Although it also worked putting the procedures into a dictionary and using execute to run them, I went for one procedure because it’s easier to follow.

When the time comes, I’ll probably use the scanlibrary solution when I switch my numerous head office files to Panorama X unless by then you’ve come up with a final custom statements solution as in P6.

David Duncan

I believe that if you use registercustomstatement the procedure can be in any open database. I haven’t tested this, but looking at the source code I think there is no reason why the procedure couldn’t be in any database – it doesn’t have to be in a special library database. You could have a database that contained some procedures to be used as custom statements, which you could register in the .Initalize procedure. Of course if this database ever got closed the custom statement would stop working, but it doesn’t sound like that would be a problem for you. The one restriction is that the procedure name must contain only upper case letters, numbers and the _ key. I believe that was a restriction in Panorama 6 also.

I’m not planning on any of this changing. The only possible change I have in mind would be for Panorama to look in a special folder in the /Library/Application Support/PanoramaX folder for library databases (in addition to the library databases inside the Panorama X bundle). But it doesn’t sound like that what you want anyway, so you might want to go ahead and use the registercustomstatement statement, even though it isn’t documented.

I use 20 custom statements in Panorama 6, and 90 procedures in the sole Panorama file in our factories. I did not want to have to add another 20 procedures to my view list, as it is already unwieldy. Now that I have all of the custom statements in one procedure, it is a neat bundle and only requires a call statement to invoke any of them.

It would have been less work using your technique, but I was able to carry out the whole conversion in a couple of hours, so not too bad.

David

@ddd I’m glad you found a solution that works well for you.

By the way, a great tool in Panorama X for reducing the number of items in the View menu is the new callwithin statement (also farcallwithin). This allows you to put a bunch of subroutines under one item in the View menu. You are no longer limited to one subroutine per procedure. I think this is easier than using case statements, and it is also faster because Panorama will jump right to the spot you want. If you haven’t looked at the callwithin statement yet, check it out.

Very nice, Jim, thanks for the tip.

David