// ========================================================================== // Class Implementation : COXWorkspaceState // ========================================================================== // Source file : OXWorkspaceState.cpp // Version: 9.3 // This software along with its related components, documentation and files ("The Libraries") // is © 1994-2007 The Code Project (1612916 Ontario Limited) and use of The Libraries is // governed by a software license agreement ("Agreement"). Copies of the Agreement are // available at The Code Project (www.codeproject.com), as part of the package you downloaded // to obtain this file, or directly from our office. For a copy of the license governing // this software, you may contact us at legalaffairs@codeproject.com, or by calling 416-849-8900. // ////////////////////////////////////////////////////////////////////////// #include "stdafx.h" #if (_MFC_VER < 0x0420) // This file uses classes that were introduced in MFC Version 4.2 // These classes are now officially documented by Microsoft, but did not exist in previous versions // Therefore this file will be completely excluded for older versions of MFC #pragma message("Warning : OXWorkspaceState.cpp not included because MFC Version < 4.2") #else // The entire file // need this file for CControlBarInfo class #include // MFC extensions for help constants #include "OXWorkspaceState.h" #include "OXSplitterColRowState.h" #include "OXSizeCtrlBar.h" #include "OXSizeDockBar.h" #include "UTB64Bit.h" #ifdef _DEBUG #undef THIS_FILE static char BASED_CODE THIS_FILE[] = __FILE__; #endif const int COXWorkspaceState::m_nSerializeSchemaVersion = 1; IMPLEMENT_SERIAL(COXWorkspaceState, CObject, COXWorkspaceState::m_nSerializeSchemaVersion | VERSIONABLE_SCHEMA) #define new DEBUG_NEW static const TCHAR szSoftware[] = _T("Software"); static const TCHAR szWorkspaceState[] = _T("WorkspaceState"); static const TCHAR szWorkspaceStateDefaultValue[] = _T("Main"); ///////////////////////////////////////////////////////////////////////////// // Definition of static members const int COXWorkspaceState::m_nMagicNumber = 0x1234FEDC; // Data members ------------------------------------------------------------- // protected: // CSize m_screenSize; // --- The size of the entire video screen in pixels (computed during runtilme) // BOOL m_bSaveMainWndProps; // --- WHether the properties of the main window should be saved and restored // WINDOWPLACEMENT m_mainWndPlacement; // --- The placement of the main window // BOOL m_bSaveBarProps; // ---- Whether the properties of the control bars should be saved and restored // CDockState* m_pDockState; // --- The state of the control bars // BOOL m_bSaveChildFrames; // ---- Whether the properties of child frame windows should be saved and restored // BOOL m_bSaveSplitterPanes; // ---- Whether the properties of splitter panes should be saved and restored // CObArray* m_pChildFrameStates; // --- The properties of the child frame windows // int m_nSerializeSchemaVersionLoad; // --- The schema version number that is read from archive // private: // Member functions --------------------------------------------------------- // public: COXWorkspaceState::COXWorkspaceState() : m_pDockState(NULL), m_pChildFrameStates(NULL), m_pSplitterPanes(NULL) { Initialize(); ASSERT_VALID(this); } BOOL COXWorkspaceState::IsMainWindowIncluded() const { ASSERT_VALID(this); return m_bSaveMainWndProps; } BOOL COXWorkspaceState::IsBarPropertyIncluded() const { ASSERT_VALID(this); return m_bSaveBarProps; } BOOL COXWorkspaceState::IsChildFrameIncluded() const { ASSERT_VALID(this); return m_bSaveChildFrames; } BOOL COXWorkspaceState::IsSplitterPaneIncluded() const { ASSERT_VALID(this); return m_bSaveSplitterPanes; } void COXWorkspaceState::IncludeMainWindow(BOOL bInclude /* = TRUE */) { ASSERT_VALID(this); m_bSaveMainWndProps = bInclude; ASSERT_VALID(this); } void COXWorkspaceState::IncludeBarProperty(BOOL bInclude /* = TRUE */) { ASSERT_VALID(this); m_bSaveBarProps = bInclude; ASSERT_VALID(this); } void COXWorkspaceState::IncludeChildFrame(BOOL bInclude /* = TRUE */) { ASSERT_VALID(this); m_bSaveChildFrames = bInclude; ASSERT_VALID(this); } void COXWorkspaceState::IncludeSplitterPane(BOOL bInclude /* = TRUE */) { ASSERT_VALID(this); m_bSaveSplitterPanes = bInclude; ASSERT_VALID(this); } BOOL COXWorkspaceState::ComputeProperties() { ASSERT_VALID(this); CWnd* pMainWnd = NULL; CFrameWnd* pMainFrame = NULL; // Get the main window and the main frame pMainWnd = AfxGetMainWnd(); if (pMainWnd != NULL) pMainFrame = pMainWnd->GetTopLevelFrame(); // Get the position of the main window ::ZeroMemory(&m_mainWndPlacement, sizeof(WINDOWPLACEMENT)); if (m_bSaveMainWndProps && (pMainWnd != NULL)) { m_mainWndPlacement.length = sizeof(WINDOWPLACEMENT); VERIFY(pMainWnd->GetWindowPlacement(&m_mainWndPlacement)); } // Get the current state of the control bars if (m_bSaveBarProps && (pMainFrame != NULL)) { pMainFrame->GetDockState(*m_pDockState); ComputeDockingWindowsState(m_pDockState->m_arrBarInfo); } EmptySplitterPanes(m_pSplitterPanes); if (m_bSaveSplitterPanes) ComputeSplitterPanes(pMainFrame); EmptyChildFrames(m_pChildFrameStates); if (m_bSaveChildFrames) ComputeChildFrameState(); return TRUE; } BOOL COXWorkspaceState::ApplyProperties() const { ASSERT_VALID(this); CWnd* pMainWnd = NULL; CFrameWnd* pMainFrame = NULL; // Get the main window and the main frame pMainWnd = AfxGetMainWnd(); if (pMainWnd != NULL) pMainFrame = pMainWnd->GetTopLevelFrame(); BOOL bIsLocked=FALSE; // Set the position of the main window TRY { if (m_bSaveMainWndProps && (pMainWnd != NULL)) { WINDOWPLACEMENT mainWndPlacementCopy; ::CopyMemory(&mainWndPlacementCopy, &m_mainWndPlacement, sizeof(WINDOWPLACEMENT)); int nCmdShow=mainWndPlacementCopy.showCmd; // Check whether the last state of the main window was minimized if(nCmdShow==SW_SHOWMINIMIZED) { // ... Remove the minimize state and set the restore state nCmdShow=SW_SHOWNORMAL; } if(!pMainWnd->IsWindowVisible()) mainWndPlacementCopy.showCmd=SW_HIDE; VERIFY(pMainWnd->SetWindowPlacement(&mainWndPlacementCopy)); CWinApp* pApp=AfxGetApp(); if(pApp!=NULL) pApp->m_nCmdShow=nCmdShow; } // Set the current state of of the control bars // (Even though the main window has its update locked, // toolbars will be shown directly because they are not childs of the mainframe) if (m_bSaveBarProps && (pMainFrame != NULL)) { //////// // remove TBSTYLE_FLAT style out of CToolBar CObArray arrFlatBars; int i=0; for (i=0; im_arrBarInfo.GetSize(); i++) { CControlBarInfo* pInfo=(CControlBarInfo*)m_pDockState->m_arrBarInfo[i]; ASSERT(pInfo!=NULL); pInfo->m_pBar=pMainFrame->GetControlBar(pInfo->m_nBarID); if (pInfo->m_pBar!=NULL) { if(pInfo->m_pBar->IsKindOf(RUNTIME_CLASS(CToolBar)) && pInfo->m_pBar->GetStyle()&TBSTYLE_FLAT) { arrFlatBars.Add((CObject*)pInfo->m_pBar); pInfo->m_pBar->ModifyStyle(TBSTYLE_FLAT,0); } COXSizeControlBar* pSzControlBar = DYNAMIC_DOWNCAST(COXSizeControlBar, pInfo->m_pBar); if (pSzControlBar != NULL) { } } } //////// pMainFrame->SetDockState(*m_pDockState); ApplyDockingWindowsState(m_pDockState->m_arrBarInfo); // Refresh all floating windows for (i = 0; i < m_pDockState->m_arrBarInfo.GetSize(); i++) { CControlBarInfo* pInfo=(CControlBarInfo*)m_pDockState->m_arrBarInfo[i]; ASSERT(pInfo!=NULL); pInfo->m_pBar=pMainFrame->GetControlBar(pInfo->m_nBarID); if (pInfo->m_pBar != NULL && pInfo->m_pBar->IsFloating()) { CRect rect; pInfo->m_pBar->GetParentFrame()->GetWindowRect(rect); rect.bottom += 1; pInfo->m_pBar->GetParentFrame()->MoveWindow(rect); } } //////// // set TBSTYLE_FLAT style for CToolBar for (i=0; iModifyStyle(0,TBSTYLE_FLAT); } //////// } if (m_bSaveSplitterPanes) ApplySplitterPanes(pMainFrame); // Set the current state of the frame windows if (m_bSaveChildFrames) ApplyChildFrameState(); } CATCH_ALL(px) { TRACE0("COXWorkspaceState::ApplyProperties : Catching exception, re-throwing\n"); // Re-enable main window if (pMainWnd != NULL && bIsLocked) pMainWnd->UnlockWindowUpdate(); // Throw the exception again THROW_LAST(); } END_CATCH_ALL return TRUE; } void COXWorkspaceState::Serialize(CArchive& ar) { ASSERT_VALID(this); // Check the version // (If version == -1, the version is unknown, this occurs when Serialize() is called directly) if (ar.IsLoading()) { m_nSerializeSchemaVersionLoad = (int)ar.GetObjectSchema(); if (m_nSerializeSchemaVersion < m_nSerializeSchemaVersionLoad) { TRACE1("COXWorkspaceState::Serialize : Unexpected schema version : %i, throwing CArchiveException\n", m_nSerializeSchemaVersionLoad); AfxThrowArchiveException(CArchiveException::badSchema); } } // Call base class implementation CObject::Serialize(ar); // Serialize magic number and version number so that when Serialize // is called directly versioning can still be used if (ar.IsStoring()) { ar << m_nMagicNumber; ar << m_nSerializeSchemaVersion; } else { int nInternalMagicNumber = -1; int nInternalVersion = -1; ar >> nInternalMagicNumber; if (nInternalMagicNumber != m_nMagicNumber) { TRACE1("COXWorkspaceState::Serialize : Unexpected magic number : 0x%X, throwing CArchiveException\n", nInternalMagicNumber); AfxThrowArchiveException(CArchiveException::badSchema); } ar >> nInternalVersion; if (m_nSerializeSchemaVersion < nInternalVersion) { TRACE1("COXWorkspaceState::Serialize : Unexpected version number : %i, throwing CArchiveException\n", nInternalVersion); AfxThrowArchiveException(CArchiveException::badSchema); } // ... Internal version number take priority over MFC m_nSerializeSchemaVersionLoad = nInternalVersion; } // Serialize all data if (ar.IsStoring()) StoreProperties(ar); else LoadProperties(ar); ASSERT_VALID(this); } BOOL COXWorkspaceState::StoreToFile(LPCTSTR pszPath, BOOL bSaveOpenDocs /* = TRUE */, BOOL bComputeProperties /* = TRUE */, BOOL bCloseApplication /* = TRUE */) { ASSERT_VALID(this); // ... When storing : first let all the documents save themselves // Because this may change their name if(bSaveOpenDocs) { AfxGetApp()->SaveAllModified(); // if this function has been called when application is about to be closed // we don't want it to call SaveAllModified() function on the files that // user didn't want to save. in order to do that we have to go through // all application's document and clear modified flag if(bCloseApplication && AfxGetApp()->m_pDocManager!=NULL) { POSITION pos=AfxGetApp()->m_pDocManager->GetFirstDocTemplatePosition(); while(pos!=NULL) { CDocTemplate* pTemplate= AfxGetApp()->m_pDocManager->GetNextDocTemplate(pos); ASSERT_KINDOF(CDocTemplate,pTemplate); POSITION posDoc=pTemplate->GetFirstDocPosition(); while(posDoc!=NULL) { CDocument* pDoc=pTemplate->GetNextDoc(posDoc); pDoc->SetModifiedFlag(FALSE); } } } } // ... When storing first establish the values off all properties if (bComputeProperties) ComputeProperties(); BOOL bSuccess = TRUE; TRY { StoreLoadFile(pszPath, TRUE); } CATCH_ALL(px) { #ifdef _DEBUG const int nMaxErrorMsgLength = 1024; CString sErrorMsg; px->GetErrorMessage(sErrorMsg.GetBuffer(nMaxErrorMsgLength), nMaxErrorMsgLength); sErrorMsg.ReleaseBuffer(); TRACE1("COXWorkspaceState::StoreToFile : Catching CException (%s)\n", sErrorMsg); #endif // _DEBUG bSuccess = FALSE; } END_CATCH_ALL ASSERT_VALID(this); return bSuccess; } BOOL COXWorkspaceState::LoadFromFile(LPCTSTR pszPath, BOOL bApplyProperties /* = TRUE */) { ASSERT_VALID(this); BOOL bSuccess = TRUE; TRY { StoreLoadFile(pszPath, FALSE); } CATCH_ALL(px) { #ifdef _DEBUG const int nMaxErrorMsgLength = 1024; CString sErrorMsg; px->GetErrorMessage(sErrorMsg.GetBuffer(nMaxErrorMsgLength), nMaxErrorMsgLength); sErrorMsg.ReleaseBuffer(); TRACE1("COXWorkspaceState::LoadFromFile : Catching CException (%s)\n", sErrorMsg); #endif // _DEBUG bSuccess = FALSE; } END_CATCH_ALL // ... When loading apply the just read properties if (bApplyProperties && bSuccess) ApplyProperties(); ASSERT_VALID(this); return bSuccess; } BOOL COXWorkspaceState::StoreToRegistry(LPCTSTR pszValueName /* = NULL */, LPCTSTR pszCompany /* = NULL */, LPCTSTR pszApplication /* = NULL*/ , HKEY hKeyRoot /* = HKEY_CURRENT_USER */, BOOL bSaveOpenDocs /* = TRUE */, BOOL bComputeProperties /* = TRUE */, BOOL bCloseApplication /* = TRUE */) { ASSERT_VALID(this); // ... When storing : first let all the documents save themselves // Because this may change their name if (bSaveOpenDocs) { AfxGetApp()->SaveAllModified(); // if this function has been called when application is about to be closed // we don't want it to call SaveAllModified() function on the files that // user didn't want to save. in order to do that we have to go through // all application's document and clear modified flag if(bCloseApplication && AfxGetApp()->m_pDocManager!=NULL) { POSITION pos=AfxGetApp()->m_pDocManager->GetFirstDocTemplatePosition(); while(pos!=NULL) { CDocTemplate* pTemplate= AfxGetApp()->m_pDocManager->GetNextDocTemplate(pos); ASSERT_KINDOF(CDocTemplate,pTemplate); POSITION posDoc=pTemplate->GetFirstDocPosition(); while(posDoc!=NULL) { CDocument* pDoc=pTemplate->GetNextDoc(posDoc); pDoc->SetModifiedFlag(FALSE); } } } } // ... When storing first establish the values off all properties if (bComputeProperties) ComputeProperties(); CString sValueName(pszValueName); CString sCompany(pszCompany); CString sApplication(pszApplication); CString sContents; if (sValueName.IsEmpty()) sValueName = szWorkspaceStateDefaultValue; if (sCompany.IsEmpty()) sCompany = AfxGetApp()->m_pszRegistryKey; if (sCompany.IsEmpty()) { TRACE0("COXWorkspaceState::StoreToRegistry : No valid company name is provided, failing\n"); return FALSE; } if (sApplication.IsEmpty()) sApplication = AfxGetApp()->m_pszProfileName; // Get the contents from the list CByteArray binaryState; BOOL bSuccess = GetBinaryWorkspaceState(&binaryState); if (bSuccess) bSuccess = StoreLoadRegistry(TRUE, sValueName, sCompany, sApplication, hKeyRoot, &binaryState); #ifdef _DEBUG if (!bSuccess) TRACE0("COXWorkspaceState::StoreToRegistry : Failed to store to registry\n"); #endif // _DEBUG ASSERT_VALID(this); return bSuccess; } BOOL COXWorkspaceState::LoadFromRegistry(LPCTSTR pszValueName /* = NULL */, LPCTSTR pszCompany /* = NULL */, LPCTSTR pszApplication /* = NULL*/ , HKEY hKeyRoot /* = HKEY_CURRENT_USER */, BOOL bApplyProperties /* = TRUE */) { ASSERT_VALID(this); CString sValueName(pszValueName); CString sCompany(pszCompany); CString sApplication(pszApplication); CString sContents; if (sValueName.IsEmpty()) sValueName = szWorkspaceStateDefaultValue; if (sCompany.IsEmpty()) sCompany = AfxGetApp()->m_pszRegistryKey; if (sCompany.IsEmpty()) { TRACE0("COXWorkspaceState::LoadFromRegistry : No valid company name is provided, failing\n"); return FALSE; } if (sApplication.IsEmpty()) sApplication = AfxGetApp()->m_pszProfileName; // Get the contents from the list CByteArray binaryState; BOOL bSuccess = StoreLoadRegistry(FALSE, sValueName, sCompany, sApplication, hKeyRoot, &binaryState); if (bSuccess) bSuccess = SetBinaryWorkspaceState(&binaryState); // ... When loading apply the just read properties if (bApplyProperties && bSuccess) ApplyProperties(); #ifdef _DEBUG if (!bSuccess) TRACE0("COXWorkspaceState::LoadFromRegistry : Failed to load from registry\n"); #endif // _DEBUG ASSERT_VALID(this); return bSuccess; } #ifdef _DEBUG void COXWorkspaceState::AssertValid() const { CObject::AssertValid(); // The pointer object must always be valid and may never be NULL ASSERT_VALID(m_pDockState); ASSERT_VALID(m_pChildFrameStates); ASSERT_VALID(m_pSplitterPanes); } void COXWorkspaceState::Dump(CDumpContext& dc) const { CObject::Dump(dc); } #endif //_DEBUG COXWorkspaceState::~COXWorkspaceState() { ASSERT_VALID(this); // Empty all lists EmptyChildFrames(m_pChildFrameStates); EmptySplitterPanes(m_pSplitterPanes); // Delete dynamically created members delete m_pDockState; m_pDockState = NULL; delete m_pChildFrameStates; m_pChildFrameStates = NULL; delete m_pSplitterPanes; m_pSplitterPanes = NULL; } // protected: void COXWorkspaceState::Initialize() // --- In : // --- Out : // --- Returns : // --- Effect : Initialized the data members of this object { m_screenSize.cx = ::GetSystemMetrics(SM_CXSCREEN); m_screenSize.cy = ::GetSystemMetrics(SM_CYSCREEN); m_bSaveMainWndProps = TRUE; ::ZeroMemory(&m_mainWndPlacement, sizeof(WINDOWPLACEMENT)); m_bSaveBarProps = TRUE; if (m_pDockState == NULL) m_pDockState = new CDockState(); m_pDockState->Clear(); if (m_pChildFrameStates == NULL) m_pChildFrameStates = new CObArray(); m_bSaveChildFrames = TRUE; m_bSaveSplitterPanes = TRUE; EmptyChildFrames(m_pChildFrameStates); m_bSaveSplitterPanes = TRUE; if (m_pSplitterPanes == NULL) m_pSplitterPanes = new CObArray(); EmptySplitterPanes(m_pSplitterPanes); m_nSerializeSchemaVersionLoad = -1; ASSERT_VALID(this); } BOOL COXWorkspaceState::ComputeChildFrameState() // --- In : // --- Out : // --- Returns : Whether it succeeded or not // --- Effect : Computes all the states of the child frame windows and adds them // to an internal collection { // Iterate all views POSITION MDIChildWndPos = NULL; CFrameWnd* pFrameWnd = NULL; BOOL bAllSucceeded = TRUE; MDIChildWndPos = GetFirstMDIChildWndPosition(); while(MDIChildWndPos != NULL) { pFrameWnd = GetNextMDIChildWnd(MDIChildWndPos); ASSERT(pFrameWnd != NULL); COXChildFrameState* pChildFrameState = new COXChildFrameState; pChildFrameState->IncludeSplitterPane(m_bSaveSplitterPanes); if (pChildFrameState->ComputeProperties(pFrameWnd)) m_pChildFrameStates->Add(pChildFrameState); else { TRACE0("COXWorkspaceState::ComputeChildFrameState : Failed to compute properties\n"); bAllSucceeded = FALSE; delete pChildFrameState; } } return bAllSucceeded; } BOOL COXWorkspaceState::ApplyChildFrameState() const // --- In : // --- Out : // --- Returns : Whether it succeeded or not // --- Effect : Applies all the states of the child frame windows that are in the // internal collection { ASSERT_VALID(this); BOOL bAllSucceeded = TRUE; // Delegate the apply to all the child frame states in our list // Iterate the child frame sates in backward direction, this way // the last handles child will become the active one int nChildFrameIndex = 0; COXChildFrameState* pChildFrameState = NULL; for (nChildFrameIndex = PtrToInt(m_pChildFrameStates->GetSize() - 1); 0 <= nChildFrameIndex ; nChildFrameIndex--) { pChildFrameState = DYNAMIC_DOWNCAST(COXChildFrameState, m_pChildFrameStates->GetAt(nChildFrameIndex)); if (pChildFrameState != NULL) if (!pChildFrameState->ApplyProperties()) { TRACE0("COXChildFrameState::ApplyChildFrameState : Failed to apply properties\n"); bAllSucceeded = FALSE; } } ASSERT_VALID(this); return bAllSucceeded; } void COXWorkspaceState::StoreProperties(CArchive& ar) // --- In : ar : Archive used in serialization // --- Out : // --- Returns : // --- Effect : Stores the properties of this object to archive // This action may throw an exception on failure { ASSERT_VALID(this); ASSERT(ar.IsStoring()); // Some sanity checks ASSERT((m_bSaveMainWndProps == FALSE) || (m_bSaveMainWndProps == TRUE)); ASSERT((m_bSaveBarProps == FALSE) || (m_bSaveBarProps == TRUE)); ASSERT((m_bSaveChildFrames == FALSE) || (m_bSaveChildFrames == TRUE)); ASSERT((m_bSaveSplitterPanes == FALSE) || (m_bSaveSplitterPanes == TRUE)); // ... General ar << m_screenSize; // ... Main window ar << m_bSaveMainWndProps; ar << m_mainWndPlacement.flags; ar << m_mainWndPlacement.showCmd; ar << m_mainWndPlacement.ptMinPosition; ar << m_mainWndPlacement.ptMaxPosition; ar << m_mainWndPlacement.rcNormalPosition; // ... Bars ar << m_bSaveBarProps; ar << m_pDockState; // ... Child frames ar << m_bSaveChildFrames; ar << m_bSaveSplitterPanes; ar << m_pChildFrameStates; m_mapBarID2TabIdx.Serialize(ar); // ... Splitter panes ar << m_bSaveSplitterPanes; ar << m_pSplitterPanes; ASSERT_VALID(this); } void COXWorkspaceState::LoadProperties(CArchive& ar) // --- In : ar : Archive used in serialization // --- Out : // --- Returns : // --- Effect : loads the properties of this object from archive // This action may throw an exception on failure { ASSERT_VALID(this); ASSERT(ar.IsLoading()); // ... General ar >> m_screenSize; // ... Main window ar >> m_bSaveMainWndProps; ar >> m_mainWndPlacement.flags; ar >> m_mainWndPlacement.showCmd; ar >> m_mainWndPlacement.ptMinPosition; ar >> m_mainWndPlacement.ptMaxPosition; ar >> m_mainWndPlacement.rcNormalPosition; // ... Bars CDockState* pOldDockState = NULL; ar >> m_bSaveBarProps; pOldDockState = m_pDockState; ar >> m_pDockState; delete pOldDockState; // ... Child frames ar >> m_bSaveChildFrames; ar >> m_bSaveSplitterPanes; CObArray* pOldChildFrameStates = NULL; pOldChildFrameStates = m_pChildFrameStates; ar >> m_pChildFrameStates; EmptyChildFrames(pOldChildFrameStates); delete pOldChildFrameStates; m_mapBarID2TabIdx.RemoveAll(); m_mapBarID2TabIdx.Serialize(ar); // ... Splitter panes ar >> m_bSaveSplitterPanes; CObArray* pOldSplitterPanes= NULL; pOldSplitterPanes = m_pSplitterPanes; ar >> m_pSplitterPanes; EmptySplitterPanes(pOldSplitterPanes); delete pOldSplitterPanes; // Some sanity checks ASSERT((m_bSaveMainWndProps == FALSE) || (m_bSaveMainWndProps == TRUE)); ASSERT((m_bSaveBarProps == FALSE) || (m_bSaveBarProps == TRUE)); ASSERT((m_bSaveChildFrames == FALSE) || (m_bSaveChildFrames == TRUE)); ASSERT((m_bSaveSplitterPanes == FALSE) || (m_bSaveSplitterPanes == TRUE)); ASSERT_VALID(this); } void COXWorkspaceState::StoreLoadFile(LPCTSTR pszPath, BOOL bStoring) // --- In : pszPath : The file path to use // bStoring : Whether the properties should be stored or loaded // --- Out : // --- Returns : // --- Effect : Stores or loads the properties of this object by using a file // This action may throw an exception on failure { ASSERT_VALID(this); // Open the file CFile file; CFileException* pxFile = NULL; UINT nOpenFlags = 0; if (bStoring) nOpenFlags = CFile::modeCreate | CFile::modeWrite | CFile::shareExclusive; else nOpenFlags = CFile::modeRead | CFile::shareDenyWrite; pxFile = new CFileException; if (!file.Open(pszPath, nOpenFlags, pxFile)) THROW(pxFile); else pxFile->Delete(); // Wrap a CArchive around it CArchive ar(&file, bStoring ? CArchive::store : CArchive::load); // Serialize the properties Serialize(ar); // Clean everything up ar.Close(); file.Close(); ASSERT_VALID(this); } BOOL COXWorkspaceState::SetBinaryWorkspaceState(CByteArray* pBinaryState) // --- In : pBinaryState : Valid CByteArray object // --- Out : // --- Returns : Whether it succeeded or not // --- Effect : Serializes a binary represntation to this object (load) { ASSERT(pBinaryState != NULL); ASSERT_VALID(this); BOOL bSuccess = TRUE; TRY { // Use a memory file to serialize the data in memory CMemFile memFile; // Copy CByteArray to a memFile BYTE* pBinData = NULL; int nDataSize = 0; nDataSize = PtrToInt(pBinaryState->GetSize()); pBinData = pBinaryState->GetData(); ASSERT((nDataSize == 0) || AfxIsValidAddress(pBinData, nDataSize, FALSE)); memFile.Write(pBinData, nDataSize); memFile.Seek(0, CFile::begin); // ... Wrap a CArchive around it CArchive ar(&memFile, CArchive::load); // ... Serialize the properties Serialize(ar); // Clean everything up ar.Close(); memFile.Close(); } CATCH_ALL(px) { #ifdef _DEBUG const int nMaxErrorMsgLength = 1024; CString sErrorMsg; px->GetErrorMessage(sErrorMsg.GetBuffer(nMaxErrorMsgLength), nMaxErrorMsgLength); sErrorMsg.ReleaseBuffer(); TRACE1("COXWorkspaceState::SetBinaryWorkspaceState : Catching CException (%s)\n", sErrorMsg); #endif // _DEBUG bSuccess = FALSE; } END_CATCH_ALL ASSERT_VALID(this); return bSuccess; } BOOL COXWorkspaceState::GetBinaryWorkspaceState(CByteArray* pBinaryState) // --- In : pBinaryState : Valid CByteArray object // --- Out : // --- Returns : Whether it succeeded or not // --- Effect : Serializes this object to a binary represntation (store) { ASSERT(pBinaryState != NULL); ASSERT_VALID(this); BOOL bSuccess = TRUE; TRY { // Use a memory file to serialize the data in memory CMemFile memFile; // ... Wrap a CArchive around it CArchive ar(&memFile, CArchive::store); // ... Serialize the properties Serialize(ar); // ... Flush and close ar.Close(); // Copy memfile contents to CByteArray BYTE* pBinData = NULL; BYTE* pMemData = NULL; int nDataSize = 0; nDataSize = (int) memFile.GetLength(); pBinaryState->SetSize(nDataSize); pBinData = pBinaryState->GetData(); ASSERT(AfxIsValidAddress(pBinData, nDataSize, TRUE)); pMemData = memFile.Detach(); ASSERT(AfxIsValidAddress(pMemData, nDataSize, FALSE)); ::CopyMemory(pBinData, pMemData, nDataSize); // Clean everything up memFile.Close(); free(pMemData); } CATCH_ALL(px) { #ifdef _DEBUG const int nMaxErrorMsgLength = 1024; CString sErrorMsg; px->GetErrorMessage(sErrorMsg.GetBuffer(nMaxErrorMsgLength), nMaxErrorMsgLength); sErrorMsg.ReleaseBuffer(); TRACE1("COXWorkspaceState::GetBinaryWorkspaceState : Catching CException (%s)\n", sErrorMsg); #endif // _DEBUG bSuccess = FALSE; } END_CATCH_ALL ASSERT_VALID(this); return bSuccess; } BOOL COXWorkspaceState::StoreLoadRegistry(BOOL bStoring, LPCTSTR pszValueName, LPCTSTR pszCompany, LPCTSTR pszApplication, HKEY hKeyRoot, CByteArray* pBinaryState) // --- In : bStoring : Whether the value should be stored or loaded // pszValueName The name of the value to set. // (A default name will be used when this is NULL) // pszCompany : The name of the subkey with which a value is associated. // If the parameter is NULL, AfxGetApp()->m_pszRegistryKey is used // (use AfxGetApp()->SetRegistryKey() to set this to your company name) // pszApplication : Name of this application // If the paramater is NULL, AfxGetApp()->m_pszProfileName is used // hKeyRoot : An open key in the registry or any of the following predefined handle values: // HKEY_CLASSES_ROOT, HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE, HKEY_USERS // bSaveOpenDocs : Whether open document that have been changed should be // saved first (unnamed docs will then receive a name) // bComputeProperties : Whether the current workspace should be recomputed // (Same as ComputeProperties()) // --- Out : // --- Returns : // --- Effect : Stores or loads the properties of this object using the registry { ASSERT(hKeyRoot != NULL); ASSERT((pszCompany != NULL) && (*pszCompany != _T('\0'))); ASSERT((pszApplication != NULL) && (*pszApplication != _T('\0'))); ASSERT((pszValueName != NULL) && (*pszValueName != _T('\0'))); ASSERT(pBinaryState != NULL); REGSAM samDesired = 0; if (bStoring) samDesired = KEY_WRITE | KEY_READ; else samDesired = KEY_READ; // Open key for hKeyRoot\\\\ HKEY hSoftwareKey = NULL; HKEY hCompanyKey = NULL; HKEY hApplicationKey = NULL; HKEY hWorkspaceKey = NULL; if (::RegOpenKeyEx(hKeyRoot, szSoftware, 0, samDesired, &hSoftwareKey) == ERROR_SUCCESS) { DWORD dw; if (::RegCreateKeyEx(hSoftwareKey, pszCompany, 0, REG_NONE, REG_OPTION_NON_VOLATILE, samDesired, NULL, &hCompanyKey, &dw) == ERROR_SUCCESS) { if (::RegCreateKeyEx(hCompanyKey, pszApplication, 0, REG_NONE, REG_OPTION_NON_VOLATILE, samDesired, NULL, &hApplicationKey, &dw) == ERROR_SUCCESS) { ::RegCreateKeyEx(hApplicationKey, szWorkspaceState, 0, REG_NONE, REG_OPTION_NON_VOLATILE, samDesired, NULL, &hWorkspaceKey, &dw); } } } if (hSoftwareKey != NULL) ::RegCloseKey(hSoftwareKey); if (hCompanyKey != NULL) ::RegCloseKey(hCompanyKey); if (hApplicationKey != NULL) ::RegCloseKey(hApplicationKey); if (hWorkspaceKey == NULL) { TRACE0("COXWorkspaceState::StoreLoadRegistry : Failed to open workspace key, failing\n"); if (!bStoring) pBinaryState->RemoveAll(); return FALSE; } LONG nResult = 0; if (bStoring) { // Store the value nResult = ::RegSetValueEx(hWorkspaceKey, pszValueName, NULL, REG_BINARY, (LPBYTE)pBinaryState->GetData(), PtrToLong(pBinaryState->GetSize())); } else { // Load the value DWORD dwType, dwCount; nResult = ::RegQueryValueEx(hWorkspaceKey, (LPTSTR)pszValueName, NULL, &dwType, NULL, &dwCount); if (nResult == ERROR_SUCCESS) { // ... Workspace must be save in binary format ASSERT(dwType == REG_BINARY); pBinaryState->SetSize(dwCount); nResult = ::RegQueryValueEx(hWorkspaceKey, (LPTSTR)pszValueName, NULL, &dwType, (LPBYTE)pBinaryState->GetData(), &dwCount); ASSERT(dwType == REG_BINARY); } } ::RegCloseKey(hWorkspaceKey); if (nResult != ERROR_SUCCESS) { TRACE1("COXWorkspaceState::StoreLoadRegistry : Failed to access workspace value (%s), failing\n", pszValueName); if (!bStoring) pBinaryState->RemoveAll(); return FALSE; } return TRUE; } void COXWorkspaceState::EmptyChildFrames(CObArray* pChildFrameStates) // --- In : pChildFrameStates: Collection to use // --- Out : // --- Returns : // --- Effect : Clears the collection by deleting all its members and // clearing the collection itself { ASSERT_VALID(pChildFrameStates); int nChildFrameIndex = 0; CObject* pChildFrameState = NULL; for (nChildFrameIndex = 0; nChildFrameIndex < pChildFrameStates->GetSize(); nChildFrameIndex++) { pChildFrameState = pChildFrameStates->GetAt(nChildFrameIndex); delete pChildFrameState; pChildFrameStates->SetAt(nChildFrameIndex, NULL); } pChildFrameStates->RemoveAll(); } POSITION COXWorkspaceState::GetFirstMDIChildWndPosition() // --- In : // --- Out : // --- Returns : The first position of the child windows // (NULL if the end has been reached) // --- Effect : Used to iterate all the MDI child windows { CMDIFrameWnd* pMainMDIFrameWnd = DYNAMIC_DOWNCAST(CMDIFrameWnd, AfxGetMainWnd()); if (pMainMDIFrameWnd == NULL) { TRACE0("COXWorkspaceState::GetFirstMDIChildWndPosition : Unable to get the main frame window\n"); return NULL; } HWND hChildWnd = ::GetWindow(pMainMDIFrameWnd->m_hWndMDIClient, GW_CHILD); CWnd* pChildWnd = CWnd::FromHandlePermanent(hChildWnd); CMDIChildWnd* pMDIChildWnd = DYNAMIC_DOWNCAST(CMDIChildWnd, pChildWnd); if ((pMDIChildWnd != NULL) && (pMDIChildWnd->GetWindow(GW_OWNER) == NULL)) return (POSITION)hChildWnd; else return NULL; } CMDIChildWnd* COXWorkspaceState::GetNextMDIChildWnd(POSITION& pos) // --- In : pos : The current position in the iteration // --- Out : The next position in the iteration (NULL if the end has been reached) // --- Returns : The current child frame window // --- Effect : Used to iterate all the MDI child windows { CMDIChildWnd* pPrevMDIChildWnd = DYNAMIC_DOWNCAST(CMDIChildWnd, CWnd::FromHandlePermanent((HWND)pos)); ASSERT(pPrevMDIChildWnd != NULL); HWND hChildWnd = ::GetWindow(pPrevMDIChildWnd->GetSafeHwnd(), GW_HWNDNEXT); CWnd* pChildWnd = CWnd::FromHandlePermanent(hChildWnd); CMDIChildWnd* pMDIChildWnd = DYNAMIC_DOWNCAST(CMDIChildWnd, pChildWnd); if ((pMDIChildWnd != NULL) && (pMDIChildWnd->GetWindow(GW_OWNER) == NULL)) pos = (POSITION)hChildWnd; else pos = NULL; return pPrevMDIChildWnd; } BOOL COXWorkspaceState::ComputeSplitterPanes(CFrameWnd* pFrameWnd) // --- In : // --- Out : // --- Returns : Whether it succeeded or not // --- Effect : Computes all the states of the splitter panes and adds them // to an internal collection { ASSERT_VALID(this); // Check for a CSplitterWnd child window CSplitterWnd* pSplitterWnd = GetSplitterWindow(pFrameWnd); if (pSplitterWnd == NULL) // ... No splitter window found : nothing to do return TRUE; BOOL bAllSucceeded = TRUE; int nRowColIndex = 0; // Calculate the row properties for (nRowColIndex = 0; nRowColIndex < pSplitterWnd->GetRowCount(); nRowColIndex++) { COXSplitterColRowState* pSplitterColRowState = new COXSplitterColRowState; if (pSplitterColRowState->ComputeProperties(pSplitterWnd, nRowColIndex, TRUE)) m_pSplitterPanes->Add(pSplitterColRowState); else { TRACE0("COXChildFrameState::ComputeSplitterPanes : Failed to compute properties (row)\n"); bAllSucceeded = FALSE; delete pSplitterColRowState; } } // Calculate the column properties for (nRowColIndex = 0; nRowColIndex < pSplitterWnd->GetColumnCount(); nRowColIndex++) { COXSplitterColRowState* pSplitterColRowState = new COXSplitterColRowState; if (pSplitterColRowState->ComputeProperties(pSplitterWnd, nRowColIndex, FALSE)) m_pSplitterPanes->Add(pSplitterColRowState); else { TRACE0("COXChildFrameState::ComputeSplitterPanes : Failed to compute properties (column)\n"); bAllSucceeded = FALSE; delete pSplitterColRowState; } } ASSERT_VALID(this); return bAllSucceeded; } BOOL COXWorkspaceState::ApplySplitterPanes(CFrameWnd* pFrameWnd) const // --- In : // --- Out : // --- Returns : Whether it succeeded or not // --- Effect : Applies all the states of the splitter panes that are in the // internal collection { ASSERT_VALID(this); // Check for a CSplitterWnd child window CSplitterWnd* pSplitterWnd = GetSplitterWindow(pFrameWnd); if (pSplitterWnd == NULL) // ... No splitter window found : nothing to do return TRUE; BOOL bAllSucceeded = TRUE; int nSplitterColRowStateIndex = 0; COXSplitterColRowState* pSplitterColRowState = NULL; for(nSplitterColRowStateIndex = 0; nSplitterColRowStateIndex < m_pSplitterPanes->GetSize(); nSplitterColRowStateIndex++) { pSplitterColRowState = DYNAMIC_DOWNCAST(COXSplitterColRowState, m_pSplitterPanes->GetAt(nSplitterColRowStateIndex)); if (pSplitterColRowState != NULL) { if (!pSplitterColRowState->ApplyProperties(pSplitterWnd)) { TRACE0("COXChildFrameState::ApplySplitterPanes : Failed to apply properties\n"); bAllSucceeded = FALSE; } } } // Make the changes visible pSplitterWnd->RecalcLayout(); ASSERT_VALID(this); return bAllSucceeded; } void COXWorkspaceState::EmptySplitterPanes(CObArray* pSplitterPanes) // --- In : pSplitterPanes: Collection to use // --- Out : // --- Returns : // --- Effect : Clears the collection by deleting all its members and // clearing the collection itself { ASSERT_VALID(pSplitterPanes); int nSplitterColRowStateIndex = 0; CObject* pSplitterColRowState = NULL; for (nSplitterColRowStateIndex = 0; nSplitterColRowStateIndex < pSplitterPanes->GetSize(); nSplitterColRowStateIndex++) { pSplitterColRowState = pSplitterPanes->GetAt(nSplitterColRowStateIndex); delete pSplitterColRowState; pSplitterPanes->SetAt(nSplitterColRowStateIndex, NULL); } pSplitterPanes->RemoveAll(); } CSplitterWnd* COXWorkspaceState::GetSplitterWindow(CFrameWnd* pFrameWnd) // --- In : pFrameWnd : The MDI child frame to use // --- Out : // --- Returns : The splitter window of the specified frame or NULL otherwise // --- Effect : When spliiter windows are nested, only the top level window is used { if (pFrameWnd == NULL) return NULL; // Search all children for a CSplitterWnd derived object HWND hChildWnd = NULL; CWnd* pChildWnd = NULL; CSplitterWnd* pSplitterWnd = NULL; hChildWnd = ::GetWindow(pFrameWnd->GetSafeHwnd(), GW_CHILD); pChildWnd = CWnd::FromHandlePermanent(hChildWnd); pSplitterWnd = DYNAMIC_DOWNCAST(CSplitterWnd, pChildWnd); while ((hChildWnd != NULL) && (pSplitterWnd == NULL)) { hChildWnd = ::GetWindow(hChildWnd, GW_HWNDNEXT); pChildWnd = CWnd::FromHandlePermanent(hChildWnd); pSplitterWnd = DYNAMIC_DOWNCAST(CSplitterWnd, pChildWnd); } return pSplitterWnd; } void COXWorkspaceState::ComputeDockingWindowsState(CPtrArray& aryBarInfo) { // Get the main window and the main frame CFrameWnd* pMainFrame = NULL; CWnd* pMainWnd = AfxGetMainWnd(); if (pMainWnd != NULL) pMainFrame = pMainWnd->GetTopLevelFrame(); // Loop through all control bars and populate the m_mapBarID2TabIdx map m_mapBarID2TabIdx.RemoveAll(); int iSize = PtrToInt(aryBarInfo.GetSize()); for (int i = 0; i < iSize; i++) { CControlBarInfo* pInfo = (CControlBarInfo*) aryBarInfo[i]; ASSERT(pInfo != NULL); pInfo->m_pBar = pMainFrame->GetControlBar(pInfo->m_nBarID); if (pInfo->m_pBar != NULL) { COXSizeControlBar* pSzBar = DYNAMIC_DOWNCAST(COXSizeControlBar, pInfo->m_pBar); if (pSzBar != NULL) { // Get the tab index COXSizeDockBar* pSzDockBar = (COXSizeDockBar*) pSzBar->m_pDockBar; if (pSzDockBar != NULL && ::IsWindow(pSzDockBar->m_wndDockTabCtrl)) { OXDOCKTABPOSITION oxdtp; oxdtp.nControlBarID = pInfo->m_nBarID; oxdtp.nDockBarID = pSzDockBar->GetDlgCtrlID(); oxdtp.iTabIndex = pSzDockBar->m_wndDockTabCtrl.FindTab(pSzBar); if (oxdtp.iTabIndex == pSzDockBar->m_wndDockTabCtrl.GetCurSel()) oxdtp.bSelected = TRUE; else oxdtp.bSelected = FALSE; m_mapBarID2TabIdx.SetAt(pInfo->m_nBarID, oxdtp); } } } } } void COXWorkspaceState::ApplyDockingWindowsState(CPtrArray& aryBarInfo) const { // Get the main window and the main frame CFrameWnd* pMainFrame = NULL; CWnd* pMainWnd = AfxGetMainWnd(); if (pMainWnd != NULL) pMainFrame = pMainWnd->GetTopLevelFrame(); // Loop through all control bars and add then to their appropriate tab int iSize = PtrToInt(aryBarInfo.GetSize()); for (int i = 0; i < iSize; i++) { CControlBarInfo* pInfo = (CControlBarInfo*) aryBarInfo[i]; ASSERT(pInfo != NULL); pInfo->m_pBar = pMainFrame->GetControlBar(pInfo->m_nBarID); if (pInfo->m_pBar != NULL) { COXSizeControlBar* pSzBar = DYNAMIC_DOWNCAST(COXSizeControlBar, pInfo->m_pBar); if (pSzBar != NULL) { // Lookup this bar in m_mapBarID2TabIdx OXDOCKTABPOSITION oxdtp; BOOL bFound = m_mapBarID2TabIdx.Lookup(pInfo->m_nBarID, oxdtp); if (bFound && oxdtp.iTabIndex != -1) { // Add this bar to its tab control DWORD arDockPos[4] = {AFX_IDW_DOCKBAR_LEFT, AFX_IDW_DOCKBAR_RIGHT, AFX_IDW_DOCKBAR_TOP, AFX_IDW_DOCKBAR_BOTTOM}; for (int i = 0; i < 4; i++) { COXSizeDockBar* pDockBar = DYNAMIC_DOWNCAST(COXSizeDockBar, pMainFrame->GetControlBar(arDockPos[i])); if (pDockBar != NULL && oxdtp.nDockBarID == arDockPos[i]) { // This is the one int iIndex = pDockBar->m_wndDockTabCtrl.FindTab(pSzBar); if (iIndex == -1) { // Remove if tabbed to another dockbar /* COXSizeDockBar* pOtherDockBar = DYNAMIC_DOWNCAST(COXSizeDockBar, pSzBar->m_pDockBar); if (pOtherDockBar != pDockBar) { } */ pDockBar->m_wndDockTabCtrl.InsertTab(pSzBar, oxdtp.iTabIndex, TRUE); } /* if (oxdtp.bSelected) { pDockBar->m_wndDockTabCtrl.SetCurSel(oxdtp.iTabIndex); } */ } } } else { // Remove this from its tab control // Check the left, top, right and bottom dock bars DWORD arDockPos[4] = {AFX_IDW_DOCKBAR_LEFT, AFX_IDW_DOCKBAR_RIGHT, AFX_IDW_DOCKBAR_TOP, AFX_IDW_DOCKBAR_BOTTOM}; for (int i = 0; i < 4; i++) { COXSizeDockBar* pDockBar = DYNAMIC_DOWNCAST(COXSizeDockBar, pMainFrame->GetControlBar(arDockPos[i])); if (pDockBar != NULL) { int iIndex = pDockBar->m_wndDockTabCtrl.FindTab(pSzBar); if (iIndex != -1) pDockBar->m_wndDockTabCtrl.RemoveTab(pSzBar); } } } } } } } // private: #endif // _MFC_VER // ==========================================================================