How to write a Modeless Dialog.


Subject: How to write a Modeless Dialog.
From: Martin Sevior (msevior@mccubbin.ph.unimelb.edu.au)
Date: Fri May 26 2000 - 00:25:45 CDT


HI everyone,

I thought it would be a good idea to provide some documentation for the
modeless dialog framework so here it is :-)

A while ago I thought I had a way to implement a modeless "Insert SYmbol"
dialog. Paul Rohr then asked the question. "Open 4 windows on your
desktop, now which window does your symbol go into?" From a UI point of
view the answer is "The Window Most Recently Focussed". The modeless
dialog framework makes this happen.

The basic ideas are as follows:

hj and Mike provided the unix and Windows code to recognise a change in
the focus state of the open frames. Upon receiving an a focus_in event a
method in fv_View is called. Within this method is a call to an xap_App
method

XAP_App::rememberFocussedFrame( void * pJustFocussedFrame)

This records the most recently focussed frame in a protected variable in
xap_App. xap_App is the bottom most class uniformly accessible to all the
useful abi classes.

So now a modeless dialog knows which fv_View to interogate or manipulate.
All it has to do is look up this frame pointer then call
"getCurrentFrame". There are a couple of ways to do this but the best
is via the xap_Dialog_Modeless class method

xap_Dialog_Modeless::getActiveFrame()

Which returns the most recently focussed frame to any child class of
xap_Dialog_Modeless. This method has checks to verify the frame is
actually present. If it isn't present it returns oldest running frame.
xap_Dialog_Modeless has a couple of other useful methods available to
child classes and abi in general. These are:

isRunning() : UT_TRUE if the dialog is running.
modeless_cleanup() : Which cleans up the various pointers and tables to do
                     with the dialog. You run this upon closing the
                     dialog.

In addition there is code in xap_App to keep track of currently
running modeless dialogs. Things we have to watch out for are:

1. If the dialog is running just activate it, don't rebuild it.

The activate() method must be implemented seperately in the platform
specific code for every modeless dialog via the

XAP_Dialog_Modeless::activate(void)

virtual function. The code for this is really easy. Look at either
Insert_Symbol or WordCount for examples.

2. If abi is closed, gracefully shut down the modeless dialogs.

This method must also be implemented seperately in the platform specific
code for every modeless dialog via:

XAP_Dialog_Modeless::destroy(void)

In addition these is code in the unix modeless dialogs to make xap_App
remember the dialog in its tables. This is:

void XAP_App::rememberModelessId( UT_sint32 id ,
XAP_Dialog_Modeless * pDialog)

This call should be made within RunModeless immediately after calling the
dialog for the first time. It should NOT be called more than once for each
dialog otherwise bad things will happen.

There is one other magic function needed in every gtk modeless dialog. It
is

connectFocusModeless(GTK_WIDGET(mainWindow),m_pApp)

this function is placed in the unix platform sepefic code just after the
top level widget (called mainWindow) is created.

Finally Bruce has implemented a scheme to notify all the running modeless
dialogs of changes in the active frame. The uses the

 setActiveFrame(XAP_Frame *pFrame);

method. This function must be provided by every modeless dialog and it is
executed by xap_App upon a change of Active Frame. pFrame is the new
active frame passed down from xap_App.

setActiveFrame is useful to enable the modeless dialog to change it's
behaviour upon receiving notice of a change in the active frame. For
example "WordCount" changes the statistics displayed to reflect the
current active frame from the setActiveFrame method.

In addition the function:

virtual void notifyCloseFrame(XAP_Frame *pFrame);
 
Must be present and coded."notifyCloseFrame" is called when the active
frame is closed. The Windows front end needs this. See Bruce's code in
Insert_Symbol for examples.

In summary:
----------------------------------------------------------------------
In ap_EditMethods you invoke a Modeless dialog like this:

<Usual stuff about raising frames etc.> then:

        AP_Dialog_WordCount * pDialog
                = (AP_Dialog_WordCount
*)(pDialogFactory->requestDialog(AP_DIALOG_ID_WORDCOUNT));
        UT_ASSERT(pDialog);

        if(pDialog->isRunning()) // Check to see if the dialog is running
        {
                pDialog->activate(); // if so activate it
        }
        else
        {
                pDialog->setCount(pView->countWords()); // Otherwise
                pDialog->runModeless(pFrame); // Construct it.
        }
        UT_Bool bOK = UT_TRUE;
        return bOK;
}
---------------------------------------------------------------------------
You must supply code for the following functions in your modeless dialog.

        //------------------------------------------------------------
        // All these are needed for a modeless dialog

        virtual void useStart(void);
        virtual void useEnd(void);
        virtual void runModal(XAP_Frame * pFrame) = 0;
        virtual void runModeless(XAP_Frame * pFrame) = 0;
        virtual void destroy(void)=0;
        virtual void activate(void)=0;
        void setActiveFrame(XAP_Frame *pFrame);
        virtual void notifyCloseFrame(XAP_Frame *pFrame){};

The useStart(), useEnd() and runModal() are cruft from the fact
XAP_Modeless_Dialog inherits from XAP_Dialog_AppPersistent. They can be
stubbed if you want.
--------------------------------------------------------------------------

In the runModeless method you must include the code:

void XAP_App::rememberModelessId( UT_sint32 id , XAP_Dialog_Modeless *
pDialog)

to register your dialog as running.

---------------------------------------------------------------------------
Finally the unix front end must include the code:

connectFocusModeless(GTK_WIDGET(mainWindow),m_pApp)

to make the cursor in currently active window show up when the dialog is
focussed.
--------------------------------------------------------------------------

Have a look at "Insert_Symbol" and "WordCount" for more clues and feel
free to ask questions if you need more info.

Cheers!

Martin



This archive was generated by hypermail 2b25 : Fri May 26 2000 - 00:25:52 CDT