| You think A5 is missing something? Well, in version 5 Alpha Software lets you add your own commands to Alpha Five. Read this article and you can be on equal footing with Alpha Software's development team! |
A5v5 allows the Xbasic user to modify Alpha Five's own internal structure. You can add new menu items to the Control Panel or to the default form view or browse view menu structure. The generic term for Xbasic code that modifies A5 is "addins."
Alpha Software is adding much of the new functionality of A5 as addins. This allows Alpha Software to rapidly redesign A5 and respond much more quickly than they would be able to respond if all the coding had to be done in "C".
Since addins are primarily used by Alpha Software for in-house development of A5 itself, there is almost no documentation about addins for the outside developer. Nevertheless, by studying the structure of the addins that Alpha Software has produced, and by careful reading of what documentation is available. it is possible to figure out how to write an addin.
If you haven't yet read the article on dot variables, I encourage you to read it now before you go much farther. It will make the scripts that follow more understandable.
My first addin script adds "Set bookmark" and "Go to bookmark" menu choices to the Records drop-down menu in Form view:
Figure 1. A5v5 doesn't come with "Set bookmark" and "Go to bookmark" menu choices - they were created by the addin script I wrote.
You can see that there are 2 new menu items on this form. These menu items are present on every form that doesn't have a custom menu, because I added them to A5v5 itself.
The code to create an addin is short but it introduces some new concepts:
''XBasic
a=addin.create("form_set_bookmark")
a.set_context("form_view")
a.set_menu("Set bookmark","Bookmark this record","|&Records|First|")
a.set_code(<<%template%
with addin.variables()
this_rec=table.current().recno()
end with
%template% )
b=addin.create("form_goto_bookmark")
b.set_context("form_view")
b.set_menu("Go to bookmark","Go to prior bookmarked record",\
"|&Records|First|")
b.set_code(<<%code%
'with addin.variables()
'table.current().fetch_goto(this_rec)
'end with
table.current().fetch_goto(addin.variables().this_rec)
<layout>.resynch()
%code% )
Script 1. Initial bookmark script.
Virtually every line of the addin script introduces a new concept. The concepts we will discuss are:
<<%template% .. %template%
This defines multiple lines of code. The special character is the "<<" which, in conjunction with whatever follows, defines the beginning of a multi-line code segment. The code segment is terminated by repeating whatever initially followed the starting "<<" symbols.
A5v5 introduces the concept of a variable namespace. You are already familiar with the idea of local, shared, and global variables. Think of these as inhabiting different universes, or namespaces. Version 5 adds a new namespace, the addin namespace. Variables in the addin namespace are global to the addin namespace. You can refer to variables in another namespace by prefixing them with the namespace designation, e.g.
username=global.variables().userwill assign the value of the global variable "user" to the local variable "username." You can also refer to a bunch of variables in another namespace by enclosing lines of code in between
with namespace end with
So, in our code,
with addin.variables() this_rec=table.current().recno() end with
assigns the number of the current table's current record to a variable, this_rec, that exists in the addin namespace.
Just to make it clear what is happening, in the code to move to the bookmarked record, I use the "longhand" approach of addin.variables().this_rec.
You may have realized that the code in Script 1 creates a single bookmark reference, this_rec, which applies to all the forms and tables in my database. What if I want to individualize the bookmarks, so that the bookmark for the "checkbook" table is different from the bookmark for the "sendmail" table? I can accomplish this by adding further elements to the addin.variables().bookmark dot variable, and saving the bookmark to those elements instead of to the this_rec variable.. For example, for the "sendmail" table, I can write
with addin.variables() bookmark.sendmail=table.current().recno() end with
when setting the bookmark. Because of a syntactical inconsistency in the current beta version of A5v5, this particular code fragment won't work, but the equivalent statements,
p=addin.variables() p.bookmark.sendmail=table.current().recno()
work just fine. In writing a general-purpose script, I obviously can't hard-code the table name, so I use the eval() function to create the entire dot variable:
''XBasic
a=addin.create("form_set_bookmark")
a.set_context("form_view")
a.set_menu("Set bookmark","Bookmark this record","|&Records|First|")
a.set_code(<<%template%
p=addin.variables()
eval("p.bookmark."+table.current().name_get())=table.current().recno()
%template% )
b=addin.create("form_goto_bookmark")
b.set_context("form_view")
b.set_menu("Go to bookmark",\
"Go to prior bookmarked record","|&Records|First|")
b.set_code(<<%code%
p=addin.variables()
table.current().fetch_goto(eval("p.bookmark."+table.current().name_get()))
<layout>.resynch()
%code% )
Script 2. Separate bookmarks for each table.
Script 2 allows for separate bookmarks for each table in the database. But these bookmarks only exist for the life of the current Alpha Five session. Is there a way to save bookmarks from one session to the next?
You betcha! We can save the bookmarks by saving the dot variables to the database. A5 provides methods for saving dot variables to the database, to the registry, or to text files. In this final refinement, I'll save the bookmark dot variables to the database when the bookmarks are set, and restore them when saved:
''XBasic
a=addin.create("form_set_bookmark")
a.set_context("form_view")
a.set_menu("Set bookmark","Bookmark this record","|&Records|First|")
a.set_code(<<%template%
p=addin.variables()
eval("p.bookmark."+table.current().name_get())=table.current().recno()
:A5.save_settings("bookmarks",p.bookmark)
%template% )
b=addin.create("form_goto_bookmark")
b.set_context("form_view")
b.set_menu("Go to bookmark",\
"Go to prior bookmarked record","|&Records|First|")
b.set_code(<<%code%
p=addin.variables()
p.bookmark.dummy=0
:A5.load_settings("bookmarks",p.bookmark)
table.current().fetch_goto(eval("p.bookmark."+table.current().name_get()))
<layout>.resynch()
%code% )
Script 3. Saving the bookmarks to the database.
Here, :A5.save_settings("bookmarks",p.bookmark) saves all the p.bookmark elements in the current database under a "bookmarks" node. Similarly, :A5.load_settings("bookmarks",p.bookmark) reads all the settings saved under "bookmarks" to p.bookmark elements. Currently the beta version of A5v5 requires you to create one instance of the dot variable before you can use the load_settings() method: that's why I have the line, p.bookmark.dummy=0
I admit I had some trouble understanding this, so for those of you who are struggling the way I was, here is an example from the Interactive Window of how :A5.load_settings() works:
p=addin.variables()
p.bookmark.dummy=0
? p.bookmark
=dummy=0.000000
:A5.load_settings("bookmarks",p.bookmark)
? p.bookmark
=dummy=0.000000
SENDMAIL=1.000000
One caveat: Script 3 saves the bookmark settings to the database. On a network, bookmark settings should be saved to the user's own machine, either in the Windows registry or in a file stored on the user's local workstation. v5 provides methods to save settings to both those locations. But that could be the subject of another article!
12/18/99
Don't forget, we need your feedback to make this site better!