Andrzej Wytyczak-Partyka wrote:

On 8/12/05, *Andreas Schlüns* <[EMAIL PROTECTED] <mailto:[EMAIL PROTECTED]>> wrote:


    COMPONENT_DETACHING is definetly wrong. It does not describe closing of
    the frame. After such COMPONENT_DETACHING a COMPONENT_ATTACHING can
    follow. That can happen incase the same is reused for loading another
    component (document).

    You have to listen as XCloseListener on every frame you created for a
    callback notifyClosing(). Only here you can be sure, that a frame will
    be closed. And only here you should remove your tab.

    Question: How do you close the document inside the tab ?

     >
     > 2. Whenever a Component is disposed it calls the disposing() method
     >     of listeners attached to it. Those listeners should then
    clear all the
     >     references to this component, but there's no need to call
     > removeEventListener()
     >     because that will be done inside the component itself. So, I
    added an
     >     event listener to the frame component, to check if it's being
    disposed.

    If you are registered as e.g. XCloseListener on a frame, there is no
    need to register yourself as XEventListener too. Because XCloseListener
    is derived from XEventListener. And after
    XCloseListenr::notifyClosing()
    a XEventListener::disposing() will be called automaticly.

    OK - I see. For your purpose it's enough to react on disposing() call's
    sent by the frame. Because there is not realy a different between
    notifyClosing() and disposing(). In both cases the frame will die ...
    and you have to veto against that.


Yes, pretty much. I ended up in implementing the cleanup code in the disposing() call
anyway.

OK.


    It would be different in case your tabbed environment wishes to stop
    closing of frames. But I dont see any reason here doing so.

    => forget the XCloseListener .. listen for disposing() events on
    frames only


OK, I think I'll do that, but for now I'll stick with closeListener for a while, for debug.

But please dont register yourself twice at the same container!
Note: XEventListener is present at the container implicitly by register yourself using ANY derived listener interface.

    For me the dispatch code looks fine. For debugging purposes you can try
    to close frames direct using the XCloseable API ...
    You must get a notifyClosing() and disposing() event !


I figured that one too. And the results are promising. The notifyClosing is called,
and the frames are disposed !
But with dispatch they are not !

???
Normaly this should have the same effect. I dont understand that too.
May be I will find the time to investigate into this problem later .-)
But it doesnt matter - because we decided to use XDesktop::terminate() instead of closing frames manuallay.

     > 4. When the File->Exit is hit the notifyClosing() is called
    properly, I
     > have some other
     >     problems here, but I'm still woking on it.

    So you get this event on closing frames. Here my question again:
    How do you clos your frames for testing ... using menu/toolbar ...?


Like I say - when I  use the File->Exit command from the menu.

BTW: "File->Exit" calls XDesktop::terminate() internal.
terminate() itself iterates over all well known frames (that's why it's important to add all new created frames into the desktop container by calling XFrames->append()!) and try to close it.

bool Desktop::terminate()
{
        for (...)
        {
                frame = impl_getNextFrame();
                try
                        {frame->close();}
                catch
                        {return false;}
        }
        return true;
}

     > 5. I have some problems with m_refCount, after cleaning everything up
     > it's still up to 3,
     >     and that's even if I force the child frames to dispose :-/
     >     I can't find the reason for this yet.

    That can be reasoned by your listener registrations.
    If e.g. all frames was closed manually ( e.g. by using File->Close
    inside
    every open frame) nobody will be responsible to close the TabControl and
    it's windows. So your object will be registered e.g. as
    XTopWindowListener and XWindowListener there.
    You hold the TabControl alive ... and the TabControl holds you.
    Such ring-references can be killed by dispose() e.g. the TabControl
    explicitly.


I thought about that too. I think that here :
disposing()
{
   if(event.Source is one of child frames)
  {
           childInfo = findChild(event.Source)

           clear references in childInfo
           remove childInfo from m_xChildren
// AND HERE WE COULD CHECK IF m_xChildren IS EMPTY :
        if(m_xChildren is empty)
        {
          m_xTabControl.dispose()
          // BUT !! it seems that I also have to explicitly call :
         m_xTabParent.dispose()
         m_xTopWindow.dispose()
// but I think it's because of some other problem. Those should be disposed
         // automatically by the office
         }
  }
}

You are right ... if the last frame was closed you have to close your tabbed component too. But it must be enough to call dispose() on the TabControl. Because the TabControl knows the Top- and the ParentWindow.
And it disposes these two windows.

This cant be done automaticly by the office. Because the TabControl and it's windows are not well known to anybody else inside the office. Only you k now these objects. So you are the owener ... and you have to free these resources.

The only question is when and how ? .-)

Another possible way would be to listener for an event notifyTermination() as XTerminateListener on the XDesktop instance. But this will be duplicate to detect if all frames was closed. Because you saw, that Desktop::terminate() closes all frames.

There exists many ways to implement a feature .-))

    OK ... here the set of listener interfaces and callbacks, which should
    be implemented by your component:
    Here you do the following:
    You call XDesktop::terminate() on the m_xDesktop instance (instead of
    try to close all frames manually using the dispatch .-)
    That will close all open documents (means frames).
    Every closed frame will call you with disposing(xFrame).
    (see e) what you has to do then ...)
    If terminate() returns TRUE, you call dispose() on your m_xTabControl
    member. That will call you back within XEventListener::disposing() for
    - you registration on m_xTopWindow
    - and your registration on m_xTabParentWindow
    Forget these member references then.


OK! I like this idea. I thought about it yesterday, but then I thought that
xdesktop::Terminate is called automatically.
So I'm a bit confused here. I'll try to read more about this.

Desktop::terminate() is called:
a) If you do that .-)
b) If somehwere uses "File->Exit"
c) Or if the last visible frame/document was closed.

But closing of frames must be done by dispatching an URL ".uno:CloseFrame". Because this automatism to close the whole office was designed as an UI feature only. Means: any script programmer has to close the office explicitly. So an API user, which calls ((XCloseabl)frame)->close() will not trigger this automatism. He has to call Desktop::terminate().

Your component is clearly an "UI Feature" ... and it's part of the office itself. So it has to support (or force) this automatic Office termination if the last frame was closed.

What's happen in your use case ?

1)
If a document/frame will be closed by the user clicking into the menu/toolbar it closes frames with a dispatch("uno:CloseFrame"). That will trigger Desktop::terminate() automaticly if the last frame was closed so ! => You can react in the following way: forget your resources inside disposing() and dispose the TabControl if last frame was gone ... or listen for notifTermination() as XTerminatListener and dispose the TabControl there.

2)
If the user clicks to the window closer of the TabbedComponent you will recieve the disposing() event of m_xTopWindow. Her you should call Desktop::terminate() .. free resources inside disposing() callbacks of any closed frame ... and dispose your TabControl in case terminate() returns TRUE.

e.g.

void disposing()
{
        if ( sender == parentwindow )
                parentwindow.clear();
        else
        if ( sender == topwindow )
        {
                if ( desktop.terminate() == true )
                        tabcontrol.dispose();
                topwindow.clear();
        }
        else
        {
                info = list.findFrame( sender )
                info.frame.clear();
                info.window.clear();
                list.erase( info );
        }
}


<snip>

Andreas

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to