In this article, you will make the framework easier to work with in terms of adding document templates and such. An attempt is made to make the working as seamless as possible and as close to the way it would work with MFC's existing mechanism as possible.
There are two aims to start with, and then you will work on the details and the intricacies from there.
Aim 1: Means of initializing the root pane to be streamlined.
In Part III, you did not provide for a way to really make it streamlined. There, you had to explicitly set the root pane in one of MainFrame's initialization methods. The root pane being fundamental to the framework, you would like to move it out of something which is application specific. Hence, choose to use a more document template centric approach. For that, you introduce what will be called a root document template. This is more like the main document template that will be used for the root document. This template's purpose is to accomplish the following:
- Create a new document if/when needed.
- Create a new frame if/when needed.
- Create the view.
- The above steps are something that a normal CSingleDocTemplate class would do. In addition to that, this template will set the new view as the root pane for the framework's panemanager.
That's all. So, the application will have a document, frame, and a view (like any SDI app) to start with, the view being very much ready to host panes. To achieve this, you introduce a new CWinApp-derived framework class called XTearOffPaneApp with a method, as shown below:
BOOL InitializeTearOffPanes(UINT nIDResource, CRuntimeClass* pDocumentClass, CRuntimeClass* pFrameClass, CRuntimeClass* pViewClass);
Note: The parameters are identical to what a CDocTemplate constructor would take. The application would have to call this method from its InitInstance().
Aim 2: Means of adding document templates of different kinds
You can add document templates of different types and open documents of those types as tabs, like the way Visual Studio.Net IDE does. Note, however, that there shall be no multiple frames here. All the documents will be hosted in a single frame. To achieve this, you rely on the MFC way of adding document templates—using AddDocTemplate method. However, you need to hook into this to intercept MFC's mechanism of opening files so that all the opened documents are hosted as tabs in the root pane.
Under the Hood
What goes on under the hood...
- The app would have to call InitializeTearOffPanes in InitInstance(). This is used to initialize the tear off panes framework. The purpose of this method is just this: to store the root document template internally for use later on. This method just instantiates a special template class called XTearOffDocTemplate and adds it to CWinApp's list by calling CWinApp::AddDocTemplate().
- Assuming no other templates are added, when the app starts the ProcessShellCommand() would do a OnFileNew() on this one and only one template. The XTearOffDocTemplate class overrides the virtual method OpenDocumentFile() with one specific purpose, which is to InsertRootPane for the pane manager. This is done only one time. If you look at the code for this method, it is very much identical to what the baseclass does. So, I hope you get the idea.
- Now, add more document templates. This is done as is usually done, but with a difference. The document template class to be used must be derived from XTearOffDocTabTemplate. Again, there is a specific purpose behind this. What happens when one uses the file menu to create a new document? The framework will call CWinApp's method OnFileNew(), which in turn calls CDocManager::OnFileNew().
What does this method do? Put simply, if there is more than one template in the list, it throws up a dialog for the user to pick the kind of file to open. On hitting K, it will call OpenDocumentFile on the user's selected template. All is fine until this point. Now, if you were to use a CMultiDocTemplate class, the OpenDocumentFile() of that would create a new frame et al. You sure do not want that, but, you want the document to be opened and a new view created as a tab in the root pane of pane manager. How do you do that? Again, with your friendly OpenDocumentFile() method. You derive a class called XTearOffDocTabTemplate from CMultiDocTemplate and override OpenDocumentFile(). In this override, you call the root template's special method called OpenDocumentFile(), which takes a CCreateContext* pContext. This method will do what's necessary to create a view and add the view to the rootpane as a tab.
Now, try to create a sample application like the one shown below:
The steps to follow are as follows:
- From the downloads section, unzip the files in TearOffAppWizard_vstudio_files.zip files onto your system's Program Files\Microsoft Visual Studio\Common\MSDev98\Template folder.
- Open Microsoft Visual C++. Select File->New. Select XTearOffAppWizard Appwizard from the list. Type in the application name as TearOffSample, as shown in the figure below.
- Click OK.
- In Step 1 of the second dialog, select the Two Panes option. Type in the extension as tea, as shown below
- Click Next.
- In Step 2 of the second dialog, check the Add document tem option. Type in the extension as tod and select the view class as CEditView, as shown below.
- Click Finish.
- Build and run.
In this article, I have made an attempt to finetune the XTearOff framework to simplify usage. Also, I have provided a custom appwizard for XTearOffPanes that can be hooked into Visual Studio's AppWizard engine to generate MFC applications that make use of the XTearOffPanes framework. This would reduce a lot of steps of boiler-plate code a user would have to write by hand just to use the framework. I hope this will be useful to people in adopting the framework easily and focus on the application specifics. The source code for the AppWizard is provided as a bonus.