Form Gets Focus & From Loses Focus alternatives

Author: bdorman@essex.ac.uk (bdorman)

Hi Uniface developers! I'm currently working on task to add auditing to a number of database tables used by a Uniface Application. The audit rows are maintained via table triggers on INSERT/UPDATE/DELETE. My intention is to write what screen made that made the db modification (transaction) to an audit row along with other meta data and a snapshot of the data post modification. All user forms for the application in question are modal; therefore any individual database transaction making any modifications to the database (either by a store or sproc) will be done by a single form. I hoped that by setting the db context info on any focus change, I can then retrieve the form name in the sql trigger code to write to the new audit row (code below). Form Gets Focus sql("SET CONTEXT_INFO '%%$formfocus%%%'", ) Form Loses Focus sql("SET CONTEXT_INFO ''", )  Sadly when activating a modal form, the Form Gets Focus Trigger is never called (on activation or clicking on it). This is a very weird behavior as the $formfocus will update to the new active modal form, but no triggers are called to indicate the change in value. My question is; Has anyone previously attempted to maintain a "current" focus at a database/connection level? If possible I would like to avoid duplicating code, so is there any obvious application level triggers or connector trickery I could use to achieve this result?  The only solution I can only think of is to set to the context info before any database transaction; however I think that solution would be completely unsustainable due to the number of developers, the scale of the application and the number of different ways the database is modified (custom store code, sprocs, etc). Thank you for your time and responses. Regards, Ben

6 Comments

  1. We do it before any database transaction, which does have the issues you've mentioned, however, where it does connect correctly (approx 90% of the time), we can then use call stack to get the entire path through the app to get to the point in the code.  For your point however, if all the forms are modal, does the operation Init and Cleanup work for you? You could have a global variable storing a list of components and take the last one off the list.  operation Init putitem $$contextlist,-1,$componentname($instancename) sql("set context_info '%%$itemnr(-1,$$contextlist)%%%'",) end operation Cleanup delitem $$contextlist,-1 sql("set context_info '%%$itemnr(-1,$$contextlist)%%%'",) end


    Author: Iain Sharp (i.sharp@pcisystems.co.uk)
  2. usually if you work with modal forms, you do it by EXEC trigger. So you can place your "form gets focus" at the top of the exec-trigger and "form loses focus" at the very end (after the "edit" statement). If you use the "exit" statement somewhere in your form, you have to "form loses focus" before the exit.


    Author: ulrich-merkel (ulrichmerkel@web.de)
  3. Iain Sharp said ... For your point however, if all the forms are modal, does the operation Init and Cleanup work for you? You could have a global variable storing a list of components and take the last one off the list.  operation Init ... operation Cleanup ...

    Ben, For what it's worth, in your case, I would have also done exactly what Iain has suggested.


    Author: rkrite (rkrite@gmail.com)
  4. Hi all Thank you for your replies; I'm currently experimenting with the implementation similar to the one Iain has suggested, and will share my final solution once I have confirmed it is functional. To share my current progress I'm still encountering two problems, these are:

    • If a form is created with the "newinstance" proc command, then not made active immediately after, the context will become incorrect.
    • Some developers create new forms with the "run" proc command, this seemingly doesn't implicitly call the Init operation on the newly created form. Although the documentation for run advises using the activate command it isn't considered deprecated and therefore should be supported.

    Both these problems could be fixed with a hybrid solution of using the Exec trigger (called on form activation) to set the context to the current form and the implicit CLEANUP operation to set the context to the parent form. This should work for any method of creating a form as the execute trigger is always called on the form becoming active. Likewise leaving a modal form with exit command will always cause the Cleanup operation to be called (I hope!). Regards, Ben


    Author: bdorman (bdorman@essex.ac.uk)
  5. Hi Ben We do have globale procedures and includes which (try) to track all "activations"of components. There is an STD_OPER include at least which defines the INIT and CLEANUP operations which then calls LP_INIT/LP_CLEANUP (if defined) We do have SP_FRGF/SP_FRLF procedures to track "form get focus"/"form lose focus" We do have SP_ACCEPT/SP_QUIT/SP_EXIT to track ACPT/QUIT/EXEC-triggers Then there are some global procedures which are call indirect by this procedures. To get information about the old way of calling by RUN, I did wrote some "prolog"/"epilog" procedure wich could be called before and after the payload of an operation (incl. EXEC). The whole thing is very trick and every change in the "calling conventions" of UnifAce can break the flow of information. With this tools, I get always (I hope soWink) the "environment" of an instance of a component. BUT: Hello Uniface, what about some more information, accessibale by proccode at runtime? Laugh Regards Ingo


    Author: istiller (i2stiller@gmx.de)
  6. Inigo,  $proccontext("STACK") gives you the current path (including line numbers) from app exec trigger to the current line in code.  The OP wants the current path stored in memory in the DB connection so it doesn't need to be set before every write to the database.  What would possibly be good is some form of switch in the db connectors which set up context_info or something else from which db level triggers could read the call stack information. It's the fact that the logging is done within the database triggers which makes this tricky. Otherwise 'simply' changing all the write/delete triggers of the entity in the model and the component variations thereof to do the logging would work. However, this doesn't trap changes due to direct SQL or stored procedures... 


    Author: Iain Sharp (i.sharp@pcisystems.co.uk)