Click here to Skip to main content
15,886,362 members
Articles / Desktop Programming / WTL

A WTL DocView framework

Rate me:
Please Sign up or sign in to vote.
4.78/5 (14 votes)
10 Jan 2006CPOL1 min read 65K   1.3K   18  
Implemetation of a simple DocView framework like MFC.
// MDIChildFrameImpl.h: interface for the CMDIChildFrameImpl class.
//
//////////////////////////////////////////////////////////////////////

#if !defined(AFX_MDICHILDFRAMEIMPL_H__F4F3EB88_AA68_4FE6_8DAE_C0A06734C568__INCLUDED_)
#define AFX_MDICHILDFRAMEIMPL_H__F4F3EB88_AA68_4FE6_8DAE_C0A06734C568__INCLUDED_

#include <atlframe.h>
#include "CreateContext.h"

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

class CMDIFrameBase
{
protected:
	CView* m_pViewActive;
public:
	CMDIFrameBase() : m_nWindow(-1), m_pViewActive(NULL)
	{

	}

	virtual void OnUpdateFrameTitle(BOOL bAddToTitle) = 0;
	virtual void UpdateFrameTitleForDocument(LPCTSTR lpszDocName) = 0;
	virtual void InitialUpdateFrame (CDocument* pDoc, BOOL bMakeVisible)=0;

	virtual void BringToTop(int nCmdShow)=0;

	int m_nWindow;
	CString m_strTitle;

protected:
	virtual CView* GetActiveView();

	virtual CDocument* GetActiveDocument();

	void SetActiveView(CView* pViewNew, BOOL bNotify = TRUE);
	virtual void ActivateFrame(int nCmdShow = -1)=0;

	
};

template <class TFrame, class TView, int nID>
class CMDIChildFrameImpl  : 
			public CMDIChildWindowImpl<TFrame>,
			public CMDIFrameBase
{
	
public:
	CMDIChildFrameImpl()
	{
		m_pViewActive = NULL;
	}
	virtual ~CMDIChildFrameImpl()
	{
	}

	virtual HWND GetMDIFrame()
	{
		return ::GetParent(m_hWndClient);
	}

	DECLARE_FRAME_WND_CLASS(NULL, nID)
		
		
	BEGIN_MSG_MAP(CMDIChildFrameImpl)
		MESSAGE_HANDLER(WM_CREATE, OnCreate)
		MESSAGE_HANDLER(WM_SIZE, OnSize)
		MESSAGE_HANDLER(WM_FORWARDMSG, OnForwardMsg)
		MESSAGE_HANDLER(WM_CLOSE, OnClose)
		CHAIN_MSG_MAP(CMDIChildWindowImpl<TFrame>)
		if (uMsg == WM_COMMAND)
			if (GetActiveDocument())
				CHAIN_MSG_MAP_MEMBER((*GetActiveDocument()))
	END_MSG_MAP()

	virtual void InitialUpdateFrame (CDocument* pDoc, BOOL bMakeVisible)
	{
		// if the frame does not have an active view, set to first pane
		CView* pView = GetActiveView();
		_ASSERTE(pView);

		if (bMakeVisible)
		{

			// send initial update to all views (and other controls) in the frame
			SendMessageToDescendants(WM_INITIALUPDATE, 0, 0, TRUE);
			
			// give view a chance to save the focus (CFormView needs this)
			if (pView != NULL)
				pView->OnActivateFrame(WA_INACTIVE, this);
			
			int nCmdShow = -1; 
			ActivateFrame(nCmdShow);

			if (pView != NULL)
				pView->OnActivateView(TRUE, pView, pView);

		}
		
		// update frame counts and frame title (may already have been visible)
		if (pDoc != NULL)
			pDoc->UpdateFrameCounts();
		OnUpdateFrameTitle(TRUE);
	}

	void BringToTop(int nCmdShow)
	{
		// place the window on top except for certain nCmdShow
		if (nCmdShow != SW_HIDE &&
			nCmdShow != SW_MINIMIZE && nCmdShow != SW_SHOWMINNOACTIVE &&
			nCmdShow != SW_SHOWNA && nCmdShow != SW_SHOWNOACTIVATE)
		{
			// if no last active popup, it will return m_hWnd
			HWND hWndLastPop = ::GetLastActivePopup(m_hWnd);
			::BringWindowToTop(hWndLastPop);
		}
	}

	virtual void OnUpdateFrameTitle(BOOL bAddToTitle)
	{
		CDocument* pDocument = GetActiveDocument();
		if (bAddToTitle)
		{
			TCHAR szText[256+_MAX_PATH];
			if (pDocument == NULL)
				lstrcpy(szText, m_strTitle);
			else
				lstrcpy(szText, pDocument->GetTitle());
			if (m_nWindow > 0)
				wsprintf(szText + lstrlen(szText), _T(":%d"), m_nWindow);
			
			// set title if changed, but don't remove completely
			::SetWindowText(m_hWnd, szText);
		}
	}

	virtual void UpdateFrameTitleForDocument(LPCTSTR lpszDocName)
	{
		// copy first part of title loaded at time of frame creation
		TCHAR szText[256+_MAX_PATH];
		
		// get name of currently active view
		lstrcpy(szText, m_strTitle);
		if (lpszDocName != NULL)
		{
			lstrcat(szText, _T(" - "));
			lstrcat(szText, lpszDocName);
			// add current window # if needed
			if (m_nWindow > 0)
				wsprintf(szText + lstrlen(szText), _T(":%d"), m_nWindow);
		}
		// set title if changed, but don't remove completely
		// Note: will be excessive for MDI Frame with maximized child
		::SetWindowText(m_hWnd, szText);
	}

	virtual void ActivateFrame(int nCmdShow = -1)
	{
		BOOL bVisibleThen = (GetStyle() & WS_VISIBLE) != 0;
		CMDIWindow frameWnd = GetMDIFrame();
		frameWnd.m_hWndMDIClient = m_hWndMDIClient;
		_ASSERTE(frameWnd.m_hWnd);

		// determine default show command
		if (nCmdShow == -1)
		{
			// get maximized state of frame window (previously active child)
			BOOL bMaximized;			
			frameWnd.MDIGetActive(&bMaximized);		

			// convert show command based on current style
			DWORD dwStyle = GetStyle();
			if (bMaximized || (dwStyle & WS_MAXIMIZE))
				nCmdShow = SW_SHOWMAXIMIZED;
			else if (dwStyle & WS_MINIMIZE)
				nCmdShow = SW_SHOWMINIMIZED;
		}

		// finally, show the window
		//CMDIFrameBase::ActivateFrame(nCmdShow);
		if (nCmdShow == -1)
		{
			if (!IsWindowVisible())
				nCmdShow = SW_SHOWNORMAL;
			else if (IsIconic())
				nCmdShow = SW_RESTORE;
		}

		// bring to top before showing
		BringToTop(nCmdShow);

		if (nCmdShow != -1)
		{
			// show the window as specified
			ShowWindow(nCmdShow);

			// and finally, bring to top after showing
			BringToTop(nCmdShow);
		}

		// update the Window menu to reflect new child window
		::SendMessage(m_hWndMDIClient, WM_MDIREFRESHMENU, 0, 0);

		// Note: Update the m_bPseudoInactive flag.  This is used to handle the
		//  last MDI child getting hidden.  Windows provides no way to deactivate
		//  an MDI child window.

		BOOL bVisibleNow = (GetStyle() & WS_VISIBLE) != 0;
		if (bVisibleNow == bVisibleThen)
			return;

		if (!bVisibleNow)
		{
			// get current active window according to Windows MDI
			HWND hWnd = (HWND)::SendMessage(m_hWndMDIClient, WM_MDIGETACTIVE, 0, 0);
			if (hWnd != m_hWnd)
			{
				// not active any more -- window must have been deactivated
				//_ASSERTE(!m_bPseudoInactive);
				return;
			}

			// check next window
			_ASSERTE(hWnd != NULL);
			frameWnd.MDINext(0);

			// see if it has been deactivated now...
			hWnd = (HWND)::SendMessage(m_hWndMDIClient,
				WM_MDIGETACTIVE, 0, 0);
			if (hWnd == m_hWnd)
			{
				// still active -- fake deactivate it
				_ASSERTE(hWnd != NULL);
				BOOL bHandled;
				OnMDIActivate(0, NULL, NULL, bHandled);
			}
		}
	}

protected:
	LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	{
		
		LPCREATESTRUCT lpcs = (LPCREATESTRUCT)lParam;
		LPMDICREATESTRUCT lpms = (LPMDICREATESTRUCT)lpcs->lpCreateParams;
		
		CCreateContext<TView>* pContext = (CCreateContext<TView>*)lpms->lParam;		
		if( pContext )
		{
			_ASSERTE(pContext->m_pCurrentView == NULL);	
			m_pViewActive = pContext->m_pCurrentView = new TView;
			m_pViewActive->m_pFrame = this;
			m_hWndClient = pContext->m_pCurrentView->Create(m_hWnd, RECT(), NULL, 0, 0, 0U, pContext);
			
			bHandled = TRUE;
		}
		else
		{
			bHandled = FALSE;
		}
		
		return 1;
	}

	LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	{
		bHandled = FALSE;
		return 0;	
	}
	
	LRESULT OnForwardMsg(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	{
		LPMSG pMsg = (LPMSG)lParam;
		
		if(CMDIChildWindowImpl<TFrame>::PreTranslateMessage(pMsg))
			return TRUE;

		bHandled = FALSE;
		
		return m_pViewActive != NULL ? m_pViewActive->PreTranslateMessage(pMsg) : FALSE;
	}

	LRESULT OnClose(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	{
		// Note: only queries the active document
		CDocument* pDocument = GetActiveDocument();
		if (pDocument != NULL && !pDocument->CanCloseFrame(this))
		{
			// document can't close right now -- don't close it
			bHandled = TRUE;
			return 1;
		}

		// detect the case that this is the last frame on the document and
		// shut down with OnCloseDocument instead.
		if (pDocument != NULL && pDocument->m_bAutoDelete)
		{
			BOOL bOtherFrame = FALSE;
			for (int i=0; i<pDocument->GetViewsCount(); i++)
			{
				CView* pView = pDocument->GetView(i);
				_ASSERTE(pView);
				if (pView->GetParentFrame() != m_hWnd)
				{
					bOtherFrame = TRUE;
					break;
				}
			}
			if (!bOtherFrame)
			{
				pDocument->OnCloseDocument();
				bHandled = FALSE;
				return 0;
			}
			
			// allow the document to cleanup before the window is destroyed
			pDocument->PreCloseFrame(this);
		}

		bHandled = FALSE;
		return 0;
	}
};

#endif // !defined(AFX_MDICHILDFRAMEIMPL_H__F4F3EB88_AA68_4FE6_8DAE_C0A06734C568__INCLUDED_)

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
CEO bring-it-together s.r.o.
Slovakia Slovakia
Jozef Božek is currently a software engineer at bring-it-together s.r.o. in area of large scale infomation systems and mobile applications development.
He has been developing in C++ nearly full time since 2000, in Java since 2004 and in Objective-C since 2009. He is programming using Java EE SDK, iOS SDK, COM/DCOM, MFC, ATL, STL and so on Smile | :)

Comments and Discussions