/*++ Copyright (c) 1998 Microsoft Corporation Module Name: FTMan File Name: MainFrm.cpp Abstract: Implementation of the CMainFrame class. It is the MFC main frame class for this application Author: Cristian Teodorescu October 20, 1998 Notes: Revision History: --*/ #include "stdafx.h" #include "Item.h" #include "FTListVw.h" #include "FTTreeVw.h" #include "MainFrm.h" #include "Resource.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif // Range limits for OnViewStyle and OnUpdateViewStyle #define AFX_ID_VIEW_MINIMUM ID_VIEW_SMALLICON #define AFX_ID_VIEW_MAXIMUM ID_VIEW_BYNAME ///////////////////////////////////////////////////////////////////////////// // CMainFrame IMPLEMENT_DYNCREATE(CMainFrame, CFrameWnd) BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd) //{{AFX_MSG_MAP(CMainFrame) ON_WM_CREATE() ON_COMMAND(ID_VIEW_TOGGLE, OnViewToggle) ON_COMMAND(ID_VIEW_REFRESH, OnViewRefresh) ON_WM_ACTIVATEAPP() ON_WM_DESTROY() ON_WM_TIMER() //}}AFX_MSG_MAP ON_UPDATE_COMMAND_UI_RANGE(AFX_ID_VIEW_MINIMUM, AFX_ID_VIEW_MAXIMUM, OnUpdateViewStyles) ON_COMMAND_RANGE(AFX_ID_VIEW_MINIMUM, AFX_ID_VIEW_MAXIMUM, OnViewStyle) END_MESSAGE_MAP() static UINT indicators[] = { ID_INDICATOR_NAME, // Name of the tree selected item ID_INDICATOR_TYPE, // Type of the tree selected item ID_INDICATOR_DISKS, // Disks set of the tree selected item ID_INDICATOR_SIZE, // Size of the tree selected item ID_INDICATOR_NOTHING, // Just an empty indicator to let some space between the first 4 indicators and the last one ID_SEPARATOR, // status line indicator }; ///////////////////////////////////////////////////////////////////////////// // CMainFrame construction/destruction CMainFrame::CMainFrame() : m_bEnableAutoRefresh(FALSE), m_bAutoRefreshRequested(FALSE), m_unTimer(0) { // TODO: add member initialization code here } CMainFrame::~CMainFrame() { } int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (CFrameWnd::OnCreate(lpCreateStruct) == -1) return -1; /* if (!m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP | CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) || !m_wndToolBar.LoadToolBar(IDR_MAINFRAME)) */ if (!m_wndToolBar.Create(this, WS_CHILD | WS_VISIBLE | CBRS_TOP | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) || !m_wndToolBar.LoadToolBar(IDR_MAINFRAME)) { TRACE0(_T("Failed to create toolbar\n")); return -1; // fail to create } m_wndToolBar.GetToolBarCtrl().ModifyStyle( 0, TBSTYLE_FLAT ); if (!m_wndStatusBar.Create(this) || !m_wndStatusBar.SetIndicators(indicators, sizeof(indicators)/sizeof(UINT))) { TRACE0(_T("Failed to create status bar\n")); return -1; // fail to create } // Try to compute the optimal size for the status bar indicators ( depending on the application font ) int nAveCharWidth = 0; CDC* pDC = m_wndStatusBar.GetDC(); if( pDC ) { TEXTMETRIC textmetrics; if( pDC->GetTextMetrics(&textmetrics) ) nAveCharWidth = textmetrics.tmAveCharWidth; m_wndStatusBar.ReleaseDC( pDC ); } m_wndStatusBar.SetPaneInfo( 0, m_wndStatusBar.GetItemID(0), 0, nAveCharWidth ? (16 * nAveCharWidth) : 130 ); m_wndStatusBar.SetPaneInfo( 1, m_wndStatusBar.GetItemID(1), 0, nAveCharWidth ? (22 * nAveCharWidth) : 150 ); m_wndStatusBar.SetPaneInfo( 2, m_wndStatusBar.GetItemID(2), 0, nAveCharWidth ? (8 * nAveCharWidth) : 50 ); m_wndStatusBar.SetPaneInfo( 3, m_wndStatusBar.GetItemID(3), 0, nAveCharWidth ? (8 * nAveCharWidth) : 60 ); m_wndStatusBar.SetPaneInfo( 4, m_wndStatusBar.GetItemID(4), SBPS_NOBORDERS, nAveCharWidth ? (2 * nAveCharWidth) : 15 ); m_wndStatusBar.SetPaneStyle( 5, SBPS_NOBORDERS | SBPS_STRETCH ); // TODO: Delete these three lines if you don't want the toolbar to // be dockable m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY); EnableDocking(CBRS_ALIGN_ANY); DockControlBar(&m_wndToolBar); return 0; } BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT /*lpcs*/, CCreateContext* pContext) { // create splitter window if (!m_wndSplitter.CreateStatic(this, 1, 2)) return FALSE; if (!m_wndSplitter.CreateView(0, 0, RUNTIME_CLASS(CFTTreeView), CSize(200, 100), pContext) || !m_wndSplitter.CreateView(0, 1, RUNTIME_CLASS(CFTListView), CSize(100, 100), pContext)) { m_wndSplitter.DestroyWindow(); return FALSE; } // Create timer m_unTimer = SetTimer( ID_TIMER_EVENT, TIMER_ELAPSE, NULL ); if( !m_unTimer ) TRACE( _T("Failure installing timer\n") ); return TRUE; } BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs) { if( !CFrameWnd::PreCreateWindow(cs) ) return FALSE; // TODO: Modify the Window class or styles here by modifying // the CREATESTRUCT cs return TRUE; } /* Public method: RefreshAll Purpose: Refreshes the content of both views by keeping ( when possible ) the expanded and selected items. It is also possible to change the selected items and to add some expanded items Parameters: [IN] CItemIDSet *psetAddTreeExpandedItems Items to add to the currently expanded items set [IN] CItemIDSet *psetTreeSelectedItems Items to select in the tree ( the currently selected items are neglected ) [IN] CItemIDSet *psetListSelectedItems Items to select in the list ( the currently selected items are neglected ) Return value: TRUE if the refresh operation succeeded */ BOOL CMainFrame::RefreshAll( CItemIDSet* psetAddTreeExpandedItems /* =NULL */ , CItemIDSet* psetTreeSelectedItems /* =NULL */, CItemIDSet* psetListSelectedItems /* =NULL */ ) { CWaitCursor wc; TREE_SNAPSHOT snapshotTree; LIST_SNAPSHOT snapshotList; BOOL bResult; CAutoRefresh ar(FALSE); DisplayStatusBarMessage( IDS_STATUS_REFRESH ); CFTTreeView* pTreeView = GetLeftPane(); CFTListView* pListView = GetRightPane(); // Get the snapshots of the tree and list views and do some changes ( if needed ) pTreeView->GetSnapshot(snapshotTree); if( psetAddTreeExpandedItems ) snapshotTree.setExpandedItems += *psetAddTreeExpandedItems; if( psetTreeSelectedItems ) snapshotTree.setSelectedItems = *psetTreeSelectedItems; pListView->GetSnapshot( snapshotList ); if( psetListSelectedItems ) snapshotList.setSelectedItems = *psetListSelectedItems; // Refresh the tree view bResult = pTreeView->Refresh(snapshotTree); // Set the snapshot pf the list view pListView->SetSnapshot( snapshotList ); // All previous requests for auto refresh should be neglected now m_bAutoRefreshRequested = FALSE; DisplayStatusBarMessage( AFX_IDS_IDLEMESSAGE ); return bResult; } ///////////////////////////////////////////////////////////////////////////// // CMainFrame diagnostics #ifdef _DEBUG void CMainFrame::AssertValid() const { CFrameWnd::AssertValid(); } void CMainFrame::Dump(CDumpContext& dc) const { CFrameWnd::Dump(dc); } #endif //_DEBUG ///////////////////////////////////////////////////////////////////////////// // CMainFrame message handlers CFTTreeView* CMainFrame::GetLeftPane() { CWnd* pWnd = m_wndSplitter.GetPane(0, 0); CFTTreeView* pView = DYNAMIC_DOWNCAST(CFTTreeView, pWnd); return pView; } CFTListView* CMainFrame::GetRightPane() { CWnd* pWnd = m_wndSplitter.GetPane(0, 1); CFTListView* pView = DYNAMIC_DOWNCAST(CFTListView, pWnd); return pView; } void CMainFrame::OnUpdateViewStyles(CCmdUI* pCmdUI) { // TODO: customize or extend this code to handle choices on the // View menu. CFTListView* pView = GetRightPane(); // if the right-hand pane hasn't been created or isn't a view, // disable commands in our range if (pView == NULL) pCmdUI->Enable(FALSE); else { DWORD dwStyle = pView->GetStyle() & LVS_TYPEMASK; // if the command is ID_VIEW_LINEUP, only enable command // when we're in LVS_ICON or LVS_SMALLICON mode if (pCmdUI->m_nID == ID_VIEW_LINEUP) { if (dwStyle == LVS_ICON || dwStyle == LVS_SMALLICON) pCmdUI->Enable(); else pCmdUI->Enable(FALSE); } else { // otherwise, use dots to reflect the style of the view pCmdUI->Enable(); BOOL bChecked = FALSE; switch (pCmdUI->m_nID) { case ID_VIEW_DETAILS: bChecked = (dwStyle == LVS_REPORT); break; case ID_VIEW_SMALLICON: bChecked = (dwStyle == LVS_SMALLICON); break; case ID_VIEW_LARGEICON: bChecked = (dwStyle == LVS_ICON); break; case ID_VIEW_LIST: bChecked = (dwStyle == LVS_LIST); break; default: bChecked = FALSE; break; } pCmdUI->SetRadio(bChecked ? 1 : 0); } } } void CMainFrame::OnViewStyle(UINT nCommandID) { // TODO: customize or extend this code to handle choices on the // View menu. CFTListView* pView = GetRightPane(); // if the right-hand pane has been created and is a CFTListView, // process the menu commands... if (pView != NULL) { DWORD dwStyle = -1; BOOL bExtendedNames = TRUE; switch (nCommandID) { case ID_VIEW_LINEUP: { // ask the list control to snap to grid CListCtrl& refListCtrl = pView->GetListCtrl(); refListCtrl.Arrange(LVA_SNAPTOGRID); } break; // other commands change the style on the list control case ID_VIEW_DETAILS: dwStyle = LVS_REPORT; bExtendedNames = FALSE; break; case ID_VIEW_SMALLICON: dwStyle = LVS_SMALLICON; break; case ID_VIEW_LARGEICON: dwStyle = LVS_ICON; break; case ID_VIEW_LIST: dwStyle = LVS_LIST; break; } // change the style; window will repaint automatically if (dwStyle != -1) { pView->ModifyStyle(LVS_TYPEMASK, dwStyle); pView->DisplayItemsExtendedNames( bExtendedNames ); } } } void CMainFrame::OnViewToggle() { // TODO: Add your command handler code here int nRow,nCol; if( !m_wndSplitter.GetActivePane(&nRow,&nCol) ) return; ASSERT( nRow == 0 ); ASSERT( nCol <= 1 ); m_wndSplitter.SetActivePane(0,1-nCol, NULL); } void CMainFrame::OnViewRefresh() { RefreshAll( NULL, NULL, NULL ); } void CMainFrame::OnActivateApp(BOOL bActive, HTASK hTask) { CFrameWnd::OnActivateApp(bActive, hTask); // TODO: Add your message handler code here if( bActive ) { if( m_bEnableAutoRefresh ) { TRACE( _T("OnActivateApp AutoRefresh\n") ); RefreshAll(); } else m_bAutoRefreshRequested = TRUE; } } void CMainFrame::OnDestroy() { if( m_unTimer ) KillTimer( m_unTimer ); CFrameWnd::OnDestroy(); // TODO: Add your message handler code here } void CMainFrame::OnTimer(UINT nIDEvent) { // TODO: Add your message handler code here and/or call default if( ( nIDEvent == ID_TIMER_EVENT ) && m_bEnableAutoRefresh && ( GetActiveWindow() == this ) ) { //TRACE("OnTimer\n"); CFTTreeView* pTreeView = GetLeftPane(); pTreeView->RefreshOnTimer(); } CFrameWnd::OnTimer(nIDEvent); } ///////////////////////////////////////////////////////////////////////////////////////////// // Global functions related to the main frame /* Global function: RefreshAll Purpose: Refreshes the content of both views of the mainframe by keeping ( when possible ) the expanded and selected items. It is also possible to change the selected items and to add some expanded items Parameters: [IN] CItemIDSet *psetAddTreeExpandedItems Items to add to the currently expanded items set [IN] CItemIDSet *psetTreeSelectedItems Items to select in the tree ( the currently selected items are neglected ) [IN] CItemIDSet *psetListSelectedItems Items to select in the list ( the currently selected items are neglected ) Return value: TRUE if the refresh operation succeeded */ BOOL AfxRefreshAll( CItemIDSet* psetAddTreeExpandedItems /* =NULL */ , CItemIDSet* psetTreeSelectedItems /* =NULL */, CItemIDSet* psetListSelectedItems /* =NULL */ ) { CMainFrame* pFrame = (CMainFrame*)AfxGetMainWnd(); ASSERT(pFrame->IsKindOf(RUNTIME_CLASS(CMainFrame))); return pFrame->RefreshAll( psetAddTreeExpandedItems, psetTreeSelectedItems, psetListSelectedItems ); } /* Global function: AfxEnableAutoRefresh() Purpose: Enables / Disables the auto refresh of both views of the mainframe on WM_ACTIVATEAPP Parameters: [IN] BOOL bEnable Specifies whether the auto-refresh is to be enabled or disabled Return value: The previous status of the auto-refresh flag */ BOOL AfxEnableAutoRefresh( BOOL bEnable /* =TRUE */ ) { CMainFrame* pFrame = (CMainFrame*)AfxGetMainWnd(); ASSERT(pFrame->IsKindOf(RUNTIME_CLASS(CMainFrame))); BOOL bPrevious = pFrame->m_bEnableAutoRefresh; // If the flag is enabling and an auto-refresh request came while it was disabled then proceed with auto-refresh if( bEnable && !bPrevious && pFrame->m_bAutoRefreshRequested) { TRACE( _T("Late OnActivateApp AutoRefresh\n") ); AfxRefreshAll(); } else if ( !bEnable && bPrevious ) pFrame->m_bAutoRefreshRequested = FALSE; pFrame->m_bEnableAutoRefresh = bEnable; return bPrevious; } BOOL CMainFrame::OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo) { // TODO: Add your specialized code here and/or call the base class switch( nID ) { case ID_VIEW_UP: case ID_INDICATOR_NAME: case ID_INDICATOR_TYPE: case ID_INDICATOR_DISKS: case ID_INDICATOR_SIZE: case ID_INDICATOR_NOTHING: CFTTreeView* pTreeView = GetLeftPane(); return pTreeView->OnCmdMsg( nID, nCode, pExtra, pHandlerInfo ); } return CFrameWnd::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo); }