The first section of this chapter gives a basic overview of scripting, in the sense of what and where. Later sections go into more detail.
EventsThe screenshot below shows the property dialog for the choice control in the Client form of the RekallDemo database. The choice control has an entry corresponding to each row displayed in a form, and can be used as a quick navigation tool ( Actually, this would be pretty stupid if there were lots of records, but if there are only a few, its quite good. Anyway, this is just an example, not a statement of good database design. ) . The code shown is associated with the On Change event, which occurs when the user changes the selection.
The first thing to note is that the code defines a function called eventFunc. This is true of all events, since this is the name that Rekall will use. If you don't define eventFunc, then the result is undefined; most likely some other event function will get executed, but don't rely on any apparent consistency!
In the case of a choice control On Change event function, it is called with three arguments; the control itself, the number of the row in the query whose data is being displayed in the control, and the value now displayed by the control. The arguments will vary with the type of control and the particular event, except that the control itself is always the first argument to the event function. The control argument is actually an instance of a python class which corresponds to the control (and has the much the same inheritance structure as was described in the previous chapter), although you cannot actually instantiate such a class yourself. Also, you should not save a copy of this anywhere, since it will cease to be valid when control exits from the event function.
In the example here, the code retrieves the index of the selected value (item = ctrl.currentItem(row)), and uses this to navigate to the corresponding query row (ctrl.getBlock().gotoQueryRow(item - 1)). The additional test and the adjustment by one are there since choice controls always show a null value first.
Later in this chapter there is a full description of the methods which can be applied to control, but in this case, ctrl.getBlock() gets the KBBlock in which the choice control is embedded, and the gotoQueryRow(item - 1) does the navigation.
Some event functions (but not this one) should return a true or false result, where a false result will cause further operations to be abandoned. For instance, there is a KBBlock On Action event which is invoked just before an action such as Next Record is performed; if an event function is defined and returns false, then the action does not actually occur. If you are not sure whether or not you need to return a value, it does no harm to return a true result.
As a general comment about events, there are two ways of defining an action in python. The more general is to write a python function called eventFunc; this will be invoked with arguments that are specific to the event, and provide information about the object to which the event occured. The alternative is to write #Foobar, whence a function named something like onBlockFoobar is invoked. This is elaborated on in the scripting section.
Warning:When saving an event, Rekall checks to see if the first non-whitespace character is #, and if the # is followed by a letter (A-Z, either case). If so, it will trim any leading whitespace, and also everything after the name (so, #Foobar rubbish becomes #Foobar). Since python uses # as a comment character, you shouldn't enter an event function starting with a python comment unless the # is followed by whitespace, or it will be zapped ( At some stage, the # character may be changed, for instance to !, to avoid this problem. In truth, # was a bad choice in the first place. I admit it. )
ExpressionsData controls such as text fields have an Expression property which specifies the value to be displayed. Normally this would be an SQL expression used to retrieve a value from the server database. However, the expression may also be blank, in which case no value is fetched and the control is only accessed from scripts; or, as a special case, the expression may be of the form =expr where expr is a valid python expression.
In the latter case, whenever a server database derived value would otherwise be displayed, the expression is evaluated and the result displayed. The main use for this is to display information such as time and date, for instance =time.strftime("%d-%b-%y", time.localtime (time.time())) . Note that this particular expression requires the Python time module to be imported; see further on.
ModulesThe third place to store Python scripts is in modules. These are accessed under the Scripts: py tag of the main database window. Just as for forms and reports, script modules can either be stored in the file system or in a server database
In most respect, Rekall script modules are just the same as standard python modules, and can be used once they have been imported. However, since the python import mechanism does not know about Rekall and where it stores scripts ( Actually, python import can be extended, so some thought may be given to direct import from Rekall in a later release. ) it is necessary to explicitely instruct Rekall to import them. This is the purpose of the form and report Script modules and Import modules properties.
The Script modules property lists those script modules which should be imported for general use when the form or report executes. The effect is to preload the script modules into the python interpreter. For instance, suppose you have script modules moduleA and moduleB, and that the latter needs to import the former. Just writing import moduleA in moduleB will not work, since the python interpreter will not be able to locate it; however adding moduleA to the Script module property will preload it, whence moduleB can successfully import it.
The Import modules property fulfills a similar function with respect to event scripts and expressions. Scripts listed here are available within event scripts and expressions without the need for an python import statement; this is definitely neccessary with expressions where it would not be possible to write a Python import statement. Also, this list provides a means whereby standard python libraries can be loaded for use by event scripts and expressions.