www.pudn.com > vc开发的精美界面.zip > BCGKeyboardManager.cpp


//******************************************************************************* 
// COPYRIGHT NOTES 
// --------------- 
// This source code is a part of BCGControlBar library. 
// You may use, compile or redistribute it as part of your application  
// for free. You cannot redistribute it as a part of a software development  
// library without the agreement of the author. If the sources are  
// distributed along with the application, you should leave the original  
// copyright notes in the source code without any changes. 
// This code can be used WITHOUT ANY WARRANTIES on your own risk. 
//  
// For the latest updates to this library, check my site: 
// http://welcome.to/bcgsoft 
//  
// Stas Levin  
//******************************************************************************* 
 
// BCGKeyboardManager.cpp: implementation of the CBCGKeyboardManager class. 
// 
////////////////////////////////////////////////////////////////////// 
 
#include "stdafx.h" 
#include "BCGKeyboardManager.h" 
#include "BCGMultiDocTemplate.h" 
#include "BCGFrameWnd.h" 
#include "BCGMDIFrameWnd.h" 
#include "BCGOleIPFrameWnd.h" 
#include "BCGRegistry.h" 
#include "KeyHelper.h" 
#include "BCGToolBar.h" 
#include "RegPath.h" 
 
#ifdef _DEBUG 
#undef THIS_FILE 
static char THIS_FILE[]=__FILE__; 
#define new DEBUG_NEW 
#endif 
 
#define REG_SECTION_FMT	_T("%sBCGKeyboard-%d") 
#define REG_ENTRY_DATA	_T("Accelerators") 
 
CBCGKeyboardManager*	g_pKeyboardManager = NULL; 
 
static const CString strKbProfile = _T("BCGKeyboardManager"); 
 
LPACCEL CBCGKeyboardManager::m_lpAccel = NULL; 
LPACCEL CBCGKeyboardManager::m_lpAccelDefault = NULL; 
int	CBCGKeyboardManager::m_nAccelDefaultSize = 0; 
int	CBCGKeyboardManager::m_nAccelSize = 0; 
HACCEL CBCGKeyboardManager::m_hAccelDefaultLast = NULL; 
HACCEL CBCGKeyboardManager::m_hAccelLast = NULL; 
 
// a special struct that will cleanup automatically 
class _KBD_TERM 
{ 
public: 
	~_KBD_TERM() 
	{ 
		if (CBCGKeyboardManager::m_lpAccel != NULL) 
		{ 
			delete CBCGKeyboardManager::m_lpAccel; 
			CBCGKeyboardManager::m_lpAccel = NULL; 
 
		} 
 
		if (CBCGKeyboardManager::m_lpAccelDefault != NULL) 
		{ 
			delete CBCGKeyboardManager::m_lpAccelDefault; 
			CBCGKeyboardManager::m_lpAccelDefault = NULL; 
		} 
	} 
}; 
 
static const _KBD_TERM kbdTerm; 
 
////////////////////////////////////////////////////////////////////// 
// Construction/Destruction 
////////////////////////////////////////////////////////////////////// 
 
CBCGKeyboardManager::CBCGKeyboardManager() 
{ 
	ASSERT (g_pKeyboardManager == NULL); 
	g_pKeyboardManager = this; 
} 
//****************************************************************** 
CBCGKeyboardManager::~CBCGKeyboardManager() 
{ 
	g_pKeyboardManager = NULL; 
} 
//****************************************************************** 
BOOL CBCGKeyboardManager::UpdateAcellTable (CMultiDocTemplate* pTemplate, 
											LPACCEL lpAccel, int nSize, 
											CFrameWnd* pDefaultFrame) 
{ 
	ASSERT (lpAccel != NULL); 
 
	//-------------------------------- 
	// Create a new accelerator table: 
	//-------------------------------- 
    HACCEL hAccelNew = ::CreateAcceleratorTable(lpAccel, nSize); 
	if (hAccelNew == NULL) 
	{ 
		TRACE(_T("Can't create accelerator table!\n")); 
		return FALSE; 
	} 
 
	if (!UpdateAcellTable (pTemplate, hAccelNew, pDefaultFrame)) 
	{ 
		::DestroyAcceleratorTable (hAccelNew); 
		return FALSE; 
	} 
 
	return TRUE; 
} 
//****************************************************************** 
BOOL CBCGKeyboardManager::UpdateAcellTable (CMultiDocTemplate* pTemplate, 
											HACCEL hAccelNew, 
											CFrameWnd* pDefaultFrame) 
{ 
	ASSERT (hAccelNew != NULL); 
 
	//------------------------------------------------------------- 
	// Find an existing accelerator table associated with template: 
	//------------------------------------------------------------- 
	HACCEL hAccelTable = NULL; 
 
	if (pTemplate != NULL) 
	{ 
		ASSERT (pDefaultFrame == NULL); 
 
		ASSERT_VALID (pTemplate); 
		hAccelTable = pTemplate->m_hAccelTable; 
		ASSERT (hAccelTable != NULL); 
 
		pTemplate->m_hAccelTable = hAccelNew; 
 
		//-------------------------------------------------- 
		// Walk trougth all template's documents and change 
		// frame's accelerator tables: 
		//-------------------------------------------------- 
		for (POSITION pos = pTemplate->GetFirstDocPosition(); pos != NULL;) 
		{ 
			CDocument* pDoc = pTemplate->GetNextDoc (pos); 
			ASSERT_VALID (pDoc); 
 
			for (POSITION posView = pDoc->GetFirstViewPosition();  
				posView != NULL;) 
			{ 
				CView* pView = pDoc->GetNextView (posView); 
				ASSERT_VALID (pView); 
 
				CFrameWnd* pFrame = pView->GetParentFrame (); 
				ASSERT_VALID (pFrame); 
 
				if (pFrame->m_hAccelTable == hAccelTable) 
				{ 
					pFrame->m_hAccelTable = hAccelNew; 
				} 
			} 
		} 
	} 
	else 
	{ 
		if (pDefaultFrame == NULL) 
		{ 
			pDefaultFrame = DYNAMIC_DOWNCAST (CFrameWnd, AfxGetMainWnd ()); 
		} 
 
		if (pDefaultFrame != NULL) 
		{ 
			hAccelTable = pDefaultFrame->m_hAccelTable; 
			pDefaultFrame->m_hAccelTable = hAccelNew; 
		} 
	} 
 
	if (hAccelTable == NULL) 
	{ 
		TRACE(_T("Accelerator table not found!\n")); 
		return FALSE; 
	} 
 
	::DestroyAcceleratorTable (hAccelTable); 
	return TRUE; 
} 
//************************************************************************************************ 
BOOL CBCGKeyboardManager::SaveAccelaratorState (LPCTSTR lpszProfileName,  
	UINT uiResId, HACCEL hAccelTable) 
{ 
	ASSERT (hAccelTable != NULL); 
 
	CString strSection; 
	strSection.Format (REG_SECTION_FMT, lpszProfileName, uiResId); 
 
	CBCGRegistry reg (FALSE, FALSE); 
	if (!reg.CreateKey (strSection)) 
	{ 
		return FALSE; 
	} 
 
	int nAccelSize = ::CopyAcceleratorTable (hAccelTable, NULL, 0); 
 
	LPACCEL lpAccel = new ACCEL [nAccelSize]; 
	ASSERT (lpAccel != NULL); 
 
	::CopyAcceleratorTable (hAccelTable, lpAccel, nAccelSize); 
 
	reg.Write (REG_ENTRY_DATA, (LPBYTE) lpAccel, nAccelSize * sizeof (ACCEL)); 
 
	delete lpAccel; 
	return TRUE; 
} 
//************************************************************************************************ 
BOOL CBCGKeyboardManager::LoadAccelaratorState (LPCTSTR lpszProfileName,  
	UINT uiResId, HACCEL& hAccelTable) 
{ 
	ASSERT (hAccelTable == NULL); 
 
	CString strSection; 
	strSection.Format (REG_SECTION_FMT, lpszProfileName, uiResId); 
 
	CBCGRegistry reg (FALSE, FALSE); 
	if (!reg.Open (strSection)) 
	{ 
		return FALSE; 
	} 
 
	UINT uiSize; 
	LPACCEL lpAccel; 
 
	if (reg.Read (REG_ENTRY_DATA, (LPBYTE*) &lpAccel, &uiSize)) 
	{ 
		int nAccelSize = uiSize / sizeof (ACCEL); 
 
		ASSERT (lpAccel != NULL); 
 
		for (int i = 0; i < nAccelSize; i ++) 
		{ 
			if (!CBCGToolBar::IsCommandPermitted (lpAccel [i].cmd)) 
			{ 
				lpAccel [i].cmd = 0; 
			} 
		} 
 
		hAccelTable = ::CreateAcceleratorTable(lpAccel, nAccelSize); 
	} 
 
	delete lpAccel; 
	return hAccelTable != NULL; 
} 
//************************************************************************************************ 
BOOL CBCGKeyboardManager::LoadState (LPCTSTR lpszProfileName, CFrameWnd* pDefaultFrame) 
{ 
	CString strProfileName = ::BCGGetRegPath (strKbProfile, lpszProfileName); 
 
	CDocManager* pDocManager = AfxGetApp ()->m_pDocManager; 
	if (pDocManager != NULL) 
	{ 
		//--------------------------------------- 
		// Walk all templates in the application: 
		//--------------------------------------- 
		for (POSITION pos = pDocManager->GetFirstDocTemplatePosition (); pos != NULL;) 
		{ 
			CBCGMultiDocTemplate* pTemplate =  
				(CBCGMultiDocTemplate*) pDocManager->GetNextDocTemplate (pos); 
			ASSERT_VALID (pTemplate); 
			ASSERT_KINDOF (CDocTemplate, pTemplate); 
 
			//----------------------------------------------------- 
			// We are interessing CMultiDocTemplate objects with 
			// the sahred menu only.... 
			//----------------------------------------------------- 
			if (!pTemplate->IsKindOf (RUNTIME_CLASS (CMultiDocTemplate)) || 
				pTemplate->m_hAccelTable == NULL) 
			{ 
				continue; 
			} 
 
			UINT uiResId = pTemplate->GetResId (); 
			ASSERT (uiResId != 0); 
 
			HACCEL hAccellTable = NULL; 
			if (LoadAccelaratorState (strProfileName, uiResId, hAccellTable)) 
			{ 
				UpdateAcellTable (pTemplate, hAccellTable); 
			} 
		} 
	} 
 
	//-------------------------------- 
	// Save default accelerator table: 
	//-------------------------------- 
	if (pDefaultFrame == NULL) 
	{ 
		pDefaultFrame = DYNAMIC_DOWNCAST (CFrameWnd, AfxGetMainWnd ()); 
	} 
 
	if (pDefaultFrame != NULL && pDefaultFrame->m_hAccelTable != NULL) 
	{ 
		HACCEL hAccelTable = NULL; 
		if (LoadAccelaratorState (strProfileName, 0, hAccelTable)) 
		{ 
			UpdateAcellTable (NULL, hAccelTable, pDefaultFrame); 
		} 
	} 
 
	return TRUE; 
} 
//************************************************************************************************ 
BOOL CBCGKeyboardManager::SaveState (LPCTSTR lpszProfileName, CFrameWnd* pDefaultFrame) 
{ 
	CString strProfileName = ::BCGGetRegPath (strKbProfile, lpszProfileName); 
 
	CDocManager* pDocManager = AfxGetApp ()->m_pDocManager; 
	if (pDocManager != NULL) 
	{ 
		//--------------------------------------- 
		// Walk all templates in the application: 
		//--------------------------------------- 
		for (POSITION pos = pDocManager->GetFirstDocTemplatePosition (); pos != NULL;) 
		{ 
			CBCGMultiDocTemplate* pTemplate =  
				(CBCGMultiDocTemplate*) pDocManager->GetNextDocTemplate (pos); 
			ASSERT_VALID (pTemplate); 
			ASSERT_KINDOF (CDocTemplate, pTemplate); 
 
			//----------------------------------------------------- 
			// We are interessing CMultiDocTemplate objects with 
			// the sahred menu only.... 
			//----------------------------------------------------- 
			if (!pTemplate->IsKindOf (RUNTIME_CLASS (CMultiDocTemplate)) || 
				pTemplate->m_hAccelTable == NULL) 
			{ 
				continue; 
			} 
 
			UINT uiResId = pTemplate->GetResId (); 
			ASSERT (uiResId != 0); 
 
			SaveAccelaratorState (strProfileName, uiResId, pTemplate->m_hAccelTable); 
		} 
	} 
 
	//-------------------------------- 
	// Save default accelerator table: 
	//-------------------------------- 
	if (pDefaultFrame == NULL) 
	{ 
		pDefaultFrame = DYNAMIC_DOWNCAST (CFrameWnd, AfxGetMainWnd ()); 
	} 
 
	if (pDefaultFrame != NULL && pDefaultFrame->m_hAccelTable != NULL) 
	{ 
		SaveAccelaratorState (strProfileName, 0, pDefaultFrame->m_hAccelTable); 
	} 
 
	return TRUE; 
} 
//****************************************************************** 
void CBCGKeyboardManager::ResetAll () 
{ 
	CDocManager* pDocManager = AfxGetApp ()->m_pDocManager; 
	if (pDocManager != NULL) 
	{ 
		//--------------------------------------- 
		// Walk all templates in the application: 
		//--------------------------------------- 
		for (POSITION pos = pDocManager->GetFirstDocTemplatePosition (); pos != NULL;) 
		{ 
			CBCGMultiDocTemplate* pTemplate =  
				(CBCGMultiDocTemplate*) pDocManager->GetNextDocTemplate (pos); 
			ASSERT_VALID (pTemplate); 
			ASSERT_KINDOF (CDocTemplate, pTemplate); 
 
			//----------------------------------------------------- 
			// We are interessing CMultiDocTemplate objects with 
			// the sahred menu only.... 
			//----------------------------------------------------- 
			if (!pTemplate->IsKindOf (RUNTIME_CLASS (CMultiDocTemplate)) || 
				pTemplate->m_hAccelTable == NULL) 
			{ 
				continue; 
			} 
 
			UINT uiResId = pTemplate->GetResId (); 
			ASSERT (uiResId != 0); 
 
			HINSTANCE hInst = AfxFindResourceHandle( 
				MAKEINTRESOURCE (uiResId), RT_MENU); 
 
			HACCEL hAccellTable = ::LoadAccelerators(hInst, MAKEINTRESOURCE (uiResId)); 
			if (hAccellTable != NULL) 
			{ 
				UpdateAcellTable (pTemplate, hAccellTable); 
			} 
		} 
	} 
 
	//----------------------------------- 
	// Restore default accelerator table: 
	//----------------------------------- 
	CFrameWnd* pWndMain = DYNAMIC_DOWNCAST (CFrameWnd, AfxGetMainWnd ()); 
	if (pWndMain != NULL && pWndMain->m_hAccelTable != NULL) 
	{ 
		UINT uiResId = 0; 
 
		CBCGMDIFrameWnd* pMDIFrame = DYNAMIC_DOWNCAST (CBCGMDIFrameWnd, AfxGetMainWnd ()); 
		if (pMDIFrame != NULL) 
		{ 
			uiResId = pMDIFrame->GetDefaultResId (); 
		} 
		else	// Maybe, SDI frame... 
		{ 
			CBCGFrameWnd* pFrame = DYNAMIC_DOWNCAST (CBCGFrameWnd, AfxGetMainWnd ()); 
			if (pFrame != NULL) 
			{ 
				uiResId = pFrame->GetDefaultResId (); 
			} 
			else	// Maybe, OLE frame... 
			{ 
				CBCGOleIPFrameWnd* pOleFrame =  
					DYNAMIC_DOWNCAST (CBCGOleIPFrameWnd, AfxGetMainWnd ()); 
				if (pOleFrame != NULL) 
				{ 
					uiResId = pOleFrame->GetDefaultResId (); 
				} 
			} 
		} 
		 
		if (uiResId != 0) 
		{ 
			HINSTANCE hInst = AfxFindResourceHandle( 
				MAKEINTRESOURCE (uiResId), RT_MENU); 
 
			HACCEL hAccellTable = ::LoadAccelerators(hInst, MAKEINTRESOURCE (uiResId)); 
			if (hAccellTable != NULL) 
			{ 
				UpdateAcellTable (NULL, hAccellTable); 
			} 
		} 
	} 
} 
//****************************************************************** 
BOOL CBCGKeyboardManager::FindDefaultAccelerator (UINT uiCmd, CString& str,  
												CFrameWnd* pWndFrame, 
												BOOL bIsDefaultFrame) 
{ 
	str.Empty (); 
 
	if (pWndFrame == NULL) 
	{ 
		return FALSE; 
	} 
 
	HACCEL hAccelTable = pWndFrame->GetDefaultAccelerator (); 
	if (hAccelTable == NULL) 
	{ 
		return FALSE; 
	} 
 
	int& nSize = bIsDefaultFrame ? m_nAccelDefaultSize : m_nAccelSize; 
	LPACCEL& lpAccel = bIsDefaultFrame ? m_lpAccelDefault : m_lpAccel; 
 
	SetAccelTable (	lpAccel, 
					bIsDefaultFrame ? m_hAccelDefaultLast : m_hAccelLast, 
					nSize, hAccelTable); 
 
	ASSERT (lpAccel != NULL); 
 
	BOOL bFound = FALSE; 
	for (int i = 0; !bFound && i < nSize; i ++) 
	{ 
		if (lpAccel [i].cmd == uiCmd) 
		{ 
			CKeyHelper helper (&lpAccel [i]); 
			helper.Format (str); 
 
			bFound = TRUE; 
		} 
	} 
 
	return bFound; 
} 
//********************************************************************************************* 
void CBCGKeyboardManager::SetAccelTable (LPACCEL& lpAccel, HACCEL& hAccelLast,  
										 int& nSize, const HACCEL hAccelCur) 
{ 
	ASSERT (hAccelCur != NULL); 
	if (hAccelCur == hAccelLast) 
	{ 
		ASSERT (lpAccel != NULL); 
		return; 
	} 
 
	//-------------------------------- 
	// Destroy old acceleration table: 
	//-------------------------------- 
	if (lpAccel != NULL) 
	{ 
		delete lpAccel; 
		lpAccel = NULL; 
	} 
 
	nSize = ::CopyAcceleratorTable (hAccelCur, NULL, 0); 
 
	lpAccel = new ACCEL [nSize]; 
	ASSERT (lpAccel != NULL); 
 
	::CopyAcceleratorTable (hAccelCur, lpAccel, nSize); 
 
	hAccelLast = hAccelCur; 
}