Closing Frames and Applications
In short the application and how it is created
Assuming a multiframe application, where each opened document gets at least one view created, which is placed in a new created frame. Opening document happens via document and view templates. The a2dDocumentTemplate makes the connection between file extension/contents and the document object to be created in your application. After that there the a2dViewTemplate is used to create the views on that specific document. And during the process the a2dViewConnector is used to organize how the views will be attached to the GUI by using existing or newly created windows and/or frames.
In the end we have several Frames open, which have an attached view to display parts of the documents. There can be several frames having views to display parts of the same document, and also views can display part of all document.
close what
So what will happen when you close a frame. Often there will be two situation. When you start your application, there will be one frame, mentioned the parent frame. This frame might display all opened documents as icons are lines of text. Every document opened will result in an extra frame being created, which will be a child frame of the parent frame. At the same time the application is adding an icon to the parent frame. Exiting the application is by closing the parent frame, which will close all child frames. But closing a child frame does not mean exiting the application, instead it should only close a view and maybe the document.
closing a view on a document
Closing a child frame, which displays (using a view) part of a document, should at least destroy the frame and close the view. Depending upon the application, what will happen more. For instance if there are several views on the document, all displaying different part or different information about the document, closing one view might be the end of the action. But if the document was modified, and this was the last view on the document, normally the user should be asked if he wants to save the modified document. And the user might decide to veto this action, leaving the frame and view intact. Also it would be possible that closing one view should close all other views on the document. It depends on the application what will happen. But for the moment we assume that the view is only closed, and the document stays in memory. Our application has a specific menu that does in fact the same as pressing the window close button.
The following set of actions will be taken to close the view:
EditorFrame::OnMenuCloseFrame(wxCommandEvent & event)
- The menu to start closing the frame
wxWindowBase::Close(bool force=true)
- base function of wxWidgets to close a top window
EditorFrame::OnCloseWindow(wxCloseEvent & event)
- The handler for the close event sent by wxWidgets.
a2dDocumentFrame::OnCloseWindow(wxCloseEvent & event)
- Skipped by the first handler, the basic wxArt2D handler for the frame will be called too.
a2dView::Close( bool force )
- a2dDocumentFrame detected the closing of a child frame, and call closing of the view. Here the user can still veto of force is false.
a2dDocument::OnCloseView( a2dCloseViewEvent& event )
- The document is first informed about closing a view, the application could decide to define in its own derived document class, to tell what needs to happen to the document when a view is closed. But in general it is the best left to the a2dViewConnector.
a2dViewConnector::OnCloseView(a2dCloseViewEvent & event)
- The view by default redirects the view close request to the connector class, since it contains the customization made by the application, which decides what to do when a view or document is to be closed. We assume here that it did not veto the closing of the view, and leaves the document in memory, since there are still more views open on the document.
a2dViewWindow<wxScrolledWindow>::OnCloseView(a2dCloseViewEvent & event)
- When the connector did not veto, a2dView::Close() will inform its m_display window that this view will be closed. It depends again on the application what will happen to the window, but in our case, it will do the default and skip the event in order to make it propagate to its parent window, which is the a2dDocumentFrame to be closed in the first place.
a2dDocumentFrame::OnCloseView(a2dCloseViewEvent & event)
- Now we arrived in the frame which we wanted to close, and the application agreed via the view, document, connector, and display window that it is oke to do so. So the Destroy() method is called resulting in destroying this frame here, and its sub windows.
a2dView::Close()
After the Destroy() was called ( which will take place in idle time by wxWidgets), we first return to a2dView::Close(), where those event started. Here a2dDocument::OnRemoveView( a2dDocumentEvent& event ) will be called via the wxEVT_REMOVE_VIEW event.
a2dDocumentViewScrolledWindow::~a2dDocumentViewScrolledWindow()
- The destroy on the frame also will destroy the m_display window of the view. That the active view is know by the !a2dDocumentFrame, does not mean that the view does use that frame directly to display its information about a document. Normally it is a subwindow that is used for that. There can be more views in a a2dDocumentFrame, like in a wxNotebook situation, where each tab in the notebook, has a a2dViewWindow like window, each having and used by a view to display information. And here a2dDocumentFrame only has a pointer to the active view in one of the notebook pages. Here closing a frame would result in closing all those views.
After all this the frame was closed, and the document is still in memory. If the closing of the frame would close the last view on the document, and the strategy is to save modified documents when the last view is closed, the a2dDocument::Close( bool force ) would have bin called by the connector class.
closing a document
Closing a document via a menu in a child frame, would require closing this and all other views plus frames which are on this same document.
a2dDocument::Close( bool force )
- will call
a2dDocument::OnCloseDocument( a2dCloseDocumentEvent& event )
- will call
a2dDocument::DisConnectAllViews()
- All views will receive a wxEVT_DISCONNECT_ALLVIEWS event, and call
a2dView::OnDisConnectView( a2dDocumentEvent& event )
- If the document in the event is connected to this view, the wxEVT_DISCONNECT_VIEW will be sent to the connector of the view, or if there is no connector attached to the view, the a2dView::Close( bool force ) will be called.
In other types of applications, where there is only a single frame, the frame and views are often preserved when a document is closed, and they will be reused by a new opened document. Closing a document, will then result in calling a2dView::OnDisConnectView(), which disconnects views from the document via the view its connector.
Again this is just an example on how the closing will take place, there are many ways for the application to handle the close event in a different ways, or to shift certain tasks from the view to the connector or visa versa. but what is explained here is the wxArt2D most likely and maybe best way to do things.
closing the application
We now know how to close a frame/vuew on a document, and we also how to handle clsoing of one document. The last case is closing the complete applicition. We assumen various documents are open, and each document has several view on it, which are displayed in child frames.
So we start with the application its Exit menu, and the rest follows:
MyParentFrame::OnMenuExit(wxCommandEvent & event)
MyParentFrame::OnCloseWindow(wxCloseEvent & event)
a2dDocumentCommandProcessor::Clear(bool force)
- here the document command processor is where the list of open document is maintained.
a2dDocumentCommandProcessor::CloseDocuments(bool force=true)
- The list of document is forced to close.
a2dDocument::Close(bool force=true)
- And for each document this mehtid is called.
a2dDocument::OnCloseDocument(a2dCloseDocumentEvent & event)
- just calls the next.
a2dDocument::DisConnectAllViews()
- the document framework does not know about windows, frames and such, it just knows view need to be disconnected from the document. What else needs to be done is in general up to the connector class implementation. In our example, we know that disconnecting a view should result in closing a child frame and it subwindows, end closing and deletion of the view.
a2dView::OnDisConnectView(a2dTemplateEvent event)
- a view that is on the currently closing document, will disconnect itself from the document. And first tell its connector that it busy doing that.
a2dViewConnector::OnDisConnectView(a2dTemplateEvent & event)
- connector will not veto the closing of the event, and will not reuse the view. It therefore leafs it to the view to close itself.
a2dView::Close(bool force=true)
- The view start the closing of the view. In the above handled case of closing a view, the process is repeated from here.
a2dViewConnector::OnCloseView(a2dCloseViewEvent & event)
- the connector will decide to destroy the display window and frames used by the view. If not done by the connector, a2dView::Close() will propagate , the event to the m_display window towards the frame.
a2dViewWindow<wxScrolledWindow>::OnCloseView(a2dCloseViewEvent & event)
- closing event of the view, arrived in the m_display window of the view, and it will skip it for the frame to handle it.
a2dDocumentFrame::OnCloseView(a2dCloseViewEvent & event)
- frame will destroy itself and its sub windows.
a2dView::Close()
After the Destroy() was called ( which will take place in idle time by wxWidgets), we first return to a2dView::Close(), where those event started. Here a2dDocument::OnRemoveView( a2dDocumentEvent& event ) will be called via the wxEVT_REMOVE_VIEW event.
a2dDocumentViewScrolledWindow::~!a2dDocumentViewScrolledWindow()
- The destroy on the frame also will destroy the m_display window of the view. That the active view is know by the a2dDocumentFrame, does not mean that the view does use that frame directly to display its information about a document. Normally it is a subwindow that is used for that. There can be more views in a a2dDocumentFrame, like in a wxNotebook situation, where each tab in the notebook, has a a2dViewWindow like window, each having and used by a view to display information. And here a2dDocumentFrame only has a pointer to the active view in one of the notebook pages. Here closing a frame would result in closing all those views.
What is important
The whole closing procedure, no matter of it comes from a child frame or from the parent frame. It will try to close a view. In that is via a2dView::Close( bool force ). Instead of destroying a frame directly on a close window event, the close window event asks the view first. If the view and the view its connector do agree, the close view event, is sent up the window chain, propagated upwards. Where it eventually will arrive in the frame again. a2dDocumentFrame::OnCloseView() will eventually destroy the frame. The exact thing will happen when all document are closed, which needs to result in all views to close and frames to be destroyed. But there the a2dView::Close() is called by a2dDocument::DisConnectAllViews().
The thing to notice is that the a2dCloseViewEvent which is sent by a2dView::Close() to its m_display window, is propagated in opposite directly to the frame. Normally event like mouse events come from the frame and its subwindows to be redirected to the view, but here it is the other way around.