// AMCView.cpp : implementation of the CAMCView class // //+------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1992 - 1999 // // File: amcview.cpp // // Contents: Base view implementation for all console views // Also include splitter window implementation (Horizontal Splitter) // // History: 01-Jan-96 TRomano Created // 16-Jul-96 WayneSc Added code to switch views and split them // //-------------------------------------------------------------------------- // NOTE: // MMC starting from version 1.1 had a code which allowed to copy the view // settings from one view to another and thus the created view would look // the same. AMCDoc was used as temporary storage for those settings. // But the code was NEVER used; hence was not tested and not up-to-date. // Switching to XML persistence would require essential changes to that code, // and at this time we cannot afford using it. // If in the future we decide to support the feature, someone needs to look at // MMC 1.2 sources and bring the code back. Today the code is removed from // active sources. // audriusz. 3/29/2000 //-------------------------------------------------------------------------- #include "stdafx.h" #include "AMC.h" #include "Mainfrm.h" #include "HtmlHelp.h" #include "websnk.h" #include "WebCtrl.h" // AMC Private implementation of the web view control #include "CClvCtl.h" // List view control #include "ocxview.h" #include "histlist.h" // history list #include "AMCDoc.h" // AMC Console Document #include "AMCView.h" #include "childfrm.h" #include "TreeCtrl.h" // AMC Implementation of the Tree Control #include "TaskHost.h" #include "util.h" // GUIDFromString, GUIDToString #include "AMCPriv.h" #include "guidhelp.h" // ExtractObjectTypeGUID #include "amcmsgid.h" #include "cclvctl.h" #include "vwtrack.h" #include "cmenuinfo.h" #ifdef IMPLEMENT_LIST_SAVE // See nodemgr.idl (t-dmarm) #include "svfildlg.h" // Save File Dialog #endif #include "macros.h" #include #include // for _mbslen #include "favorite.h" #include "favui.h" #include "ftab.h" #include "toolbar.h" #include "menubtns.h" // UpdateFavorites menu. #include "stdbar.h" // Standard toolbar. #include "variant.h" #include "rsltitem.h" #include "scriptevents.h" // for IMenuItemEvents extern "C" UINT dbg_count = 0; enum { ITEM_IS_PARENT_OF_ROOT, ITEM_NOT_IN_VIEW, ITEM_IS_IN_VIEW, }; enum EIndex { INDEX_INVALID = -1, INDEX_BACKGROUND = -2, INDEX_MULTISELECTION = -3, INDEX_OCXPANE = -4, INDEX_WEBPANE = -5, }; enum ScopeFolderItems { SFI_TREE_TAB = 1, SFI_FAVORITES_TAB = 2 }; const UINT CAMCView::m_nShowWebContextMenuMsg = ::RegisterWindowMessage (_T("CAMCView::ShowWebContextMenu")); const UINT CAMCView::m_nProcessMultiSelectionChangesMsg = ::RegisterWindowMessage (_T("CAMCView::OnProcessMultiSelectionChanges")); const UINT CAMCView::m_nAddPageBreakAndNavigateMsg = ::RegisterWindowMessage (_T("CAMCView::AddPageBreakAndNavigate")); const UINT CAMCView::m_nJiggleListViewFocusMsg = ::RegisterWindowMessage (_T("CAMCView::JiggleListViewFocus")); const UINT CAMCView::m_nDeferRecalcLayoutMsg = ::RegisterWindowMessage (_T("CAMCView::DeferRecalcLayout")); void CALLBACK TrackerCallback(TRACKER_INFO& info, bool bAcceptChange, bool bSyncLayout); void GetFullPath(CAMCTreeView &ctc, HTREEITEM hti, CString &strPath); BOOL PtInWindow(CWnd* pWnd, CPoint pt); #ifdef DBG CTraceTag tagLayout (_T("CAMCView"), _T("Layout")); CTraceTag tagSplitterTracking (_T("CAMCView"), _T("Splitter tracking")); CTraceTag tagListSelection (_T("Result list"), _T("Selection")); CTraceTag tagViewActivation (_T("View Activation"), _T("View Activation")); #endif /*+-------------------------------------------------------------------------* * CAMCView::ScNotifySelect * * *--------------------------------------------------------------------------*/ SC CAMCView::ScNotifySelect ( INodeCallback* pCallback, HNODE hNode, bool fMultiSelect, bool fSelect, SELECTIONINFO* pSelInfo) { DECLARE_SC(sc, TEXT("CAMCView::ScNotifySelect")); // parameter check sc = ScCheckPointers(pCallback); if (sc) return sc; // pSelInfo can be NULL only for multi-select. if (!pSelInfo && !fMultiSelect) return (sc = E_INVALIDARG); #ifdef DBG Trace (tagListSelection, _T("%s (fSelect=%s, pwnd=0x%08x)"), (fMultiSelect) ? _T("NCLBK_MULTI_SELECT") : _T("NCLBK_SELECT"), (fSelect) ? _T("true") : _T("false"), static_cast(this)); #endif // we want this error (not a failure to broadcast the event) to be returned, // so cache it and assign before return SC sc_notify = (pCallback->Notify (hNode, fMultiSelect ? NCLBK_MULTI_SELECT :NCLBK_SELECT, fSelect, reinterpret_cast(pSelInfo))); // fire event whenever the selection changes, but not if // its a background hit or loss of focus if(fMultiSelect || (pSelInfo->m_bBackground == FALSE && (fSelect == TRUE || pSelInfo->m_bDueToFocusChange == FALSE))) { sc = ScFireEvent(CAMCViewObserver::ScOnResultSelectionChange, this); if (sc) sc.TraceAndClear(); // ignore & continue; } sc = sc_notify; return sc; } /*+-------------------------------------------------------------------------* * GetAMCView * * Returns the CAMCView window for any child of CChildFrame. *--------------------------------------------------------------------------*/ CAMCView* GetAMCView (CWnd* pwnd) { /* * get the input window's parent frame window */ CWnd* pFrame = pwnd->GetParentFrame(); /* * if we couldn't find a parent frame, or that parent frame isn't * of type CChildFrame, fail */ if ((pFrame == NULL) || !pFrame->IsKindOf (RUNTIME_CLASS (CChildFrame))) return (NULL); /* * get the first view of the frame window */ CWnd* pView = pFrame->GetDlgItem (AFX_IDW_PANE_FIRST); /* * if we can't find a window with the right ID, or the one we find * isn't of type CAMCView, fail */ if ((pView == NULL) || !pView->IsKindOf (RUNTIME_CLASS (CAMCView))) return (NULL); return (dynamic_cast(pView)); } //############################################################################ //############################################################################ // // Implementation of class CMMCView // //############################################################################ //############################################################################ /*+-------------------------------------------------------------------------* * class CMMCView * * * PURPOSE: The COM 0bject that exposes the View interface. * *+-------------------------------------------------------------------------*/ class CMMCView : public CTiedComObject, public CMMCIDispatchImpl { typedef CAMCView CMyTiedObject; public: BEGIN_MMC_COM_MAP(CMMCView) END_MMC_COM_MAP() public: //####################################################################### //####################################################################### // // Item and item collection related methods // //####################################################################### //####################################################################### MMC_METHOD1(get_ActiveScopeNode, PPNODE); MMC_METHOD1(put_ActiveScopeNode, PNODE); MMC_METHOD1(get_Selection, PPNODES); MMC_METHOD1(get_ListItems, PPNODES); MMC_METHOD2(SnapinScopeObject, VARIANT, PPDISPATCH); MMC_METHOD1(SnapinSelectionObject, PPDISPATCH); //####################################################################### //####################################################################### MMC_METHOD2(Is, PVIEW, VARIANT_BOOL *); MMC_METHOD1(get_Document, PPDOCUMENT); //####################################################################### //####################################################################### // // Selection changing methods // //####################################################################### //####################################################################### MMC_METHOD0(SelectAll); MMC_METHOD1(Select, PNODE); MMC_METHOD1(Deselect, PNODE); MMC_METHOD2(IsSelected, PNODE, PBOOL); //####################################################################### //####################################################################### // // Verb and selection related methods // //####################################################################### //####################################################################### MMC_METHOD1(DisplayScopeNodePropertySheet, VARIANT); MMC_METHOD0(DisplaySelectionPropertySheet); MMC_METHOD1(CopyScopeNode, VARIANT); MMC_METHOD0(CopySelection); MMC_METHOD1(DeleteScopeNode, VARIANT); MMC_METHOD0(DeleteSelection); MMC_METHOD2(RenameScopeNode, BSTR, VARIANT); MMC_METHOD1(RenameSelectedItem, BSTR); MMC_METHOD2(get_ScopeNodeContextMenu,VARIANT, PPCONTEXTMENU); MMC_METHOD1(get_SelectionContextMenu,PPCONTEXTMENU); MMC_METHOD1(RefreshScopeNode, VARIANT); MMC_METHOD0(RefreshSelection); MMC_METHOD1(ExecuteSelectionMenuItem, BSTR /*MenuItemPath*/); MMC_METHOD2(ExecuteScopeNodeMenuItem, BSTR /*MenuItemPath*/, VARIANT /*varScopeNode = ActiveScopeNode */); MMC_METHOD4(ExecuteShellCommand, BSTR /*Command*/, BSTR /*Directory*/, BSTR /*Parameters*/, BSTR /*WindowState*/); //####################################################################### //####################################################################### // // Frame and view related methods // //####################################################################### //####################################################################### MMC_METHOD1(get_Frame, PPFRAME); MMC_METHOD0(Close); MMC_METHOD1(get_ScopeTreeVisible, PBOOL); MMC_METHOD1(put_ScopeTreeVisible, BOOL); MMC_METHOD0(Back); MMC_METHOD0(Forward); MMC_METHOD1(put_StatusBarText, BSTR); MMC_METHOD1(get_Memento, PBSTR); MMC_METHOD1(ViewMemento, BSTR); //####################################################################### //####################################################################### // // List related methods // //####################################################################### //####################################################################### MMC_METHOD1(get_Columns, PPCOLUMNS); MMC_METHOD3(get_CellContents, PNODE, long, PBSTR); MMC_METHOD2(ExportList, BSTR, ExportListOptions); MMC_METHOD1(get_ListViewMode, PLISTVIEWMODE); MMC_METHOD1(put_ListViewMode, ListViewMode); //####################################################################### //####################################################################### // // ActiveX control related methods // //####################################################################### //####################################################################### MMC_METHOD1(get_ControlObject, PPDISPATCH); }; /* * WM_APPCOMMAND is only defined in winuser.h if _WIN32_WINNT >= 0x0500. * We need these definitions, but can't use _WIN32_WINNT==0x0500 (yet). */ #ifndef WM_APPCOMMAND #define WM_APPCOMMAND 0x0319 #define APPCOMMAND_BROWSER_BACKWARD 1 #define APPCOMMAND_BROWSER_FORWARD 2 #define APPCOMMAND_BROWSER_REFRESH 3 #define FAPPCOMMAND_MOUSE 0x8000 #define FAPPCOMMAND_KEY 0 #define FAPPCOMMAND_OEM 0x1000 #define FAPPCOMMAND_MASK 0xF000 #define GET_APPCOMMAND_LPARAM(lParam) ((short)(HIWORD(lParam) & ~FAPPCOMMAND_MASK)) #endif // WM_APPCOMMAND //############################################################################ //############################################################################ // // Implementation of class CAMCView // //############################################################################ //############################################################################ IMPLEMENT_DYNCREATE(CAMCView, CView); BEGIN_MESSAGE_MAP(CAMCView, CView) //{{AFX_MSG_MAP(CAMCView) ON_WM_MOUSEMOVE() ON_WM_LBUTTONDOWN() ON_WM_LBUTTONUP() ON_WM_CREATE() ON_WM_SETFOCUS() ON_WM_CONTEXTMENU() ON_WM_DESTROY() ON_UPDATE_COMMAND_UI(ID_FILE_SNAPINMANAGER, OnUpdateFileSnapinmanager) ON_WM_SHOWWINDOW() ON_COMMAND(ID_MMC_NEXT_PANE, OnNextPane) ON_COMMAND(ID_MMC_PREV_PANE, OnPrevPane) ON_WM_SETCURSOR() ON_COMMAND(ID_MMC_CONTEXTHELP, OnContextHelp) ON_COMMAND(ID_HELP_SNAPINHELP, OnSnapInHelp) ON_COMMAND(ID_SNAPIN_ABOUT, OnSnapinAbout) ON_COMMAND(ID_HELP_HELPTOPICS, OnHelpTopics) ON_WM_SIZE() ON_WM_SYSKEYDOWN() ON_WM_PALETTECHANGED() ON_WM_QUERYNEWPALETTE() ON_WM_SYSCOLORCHANGE() ON_WM_DRAWCLIPBOARD() ON_WM_SETTINGCHANGE() ON_WM_MENUSELECT() //}}AFX_MSG_MAP // keep this outside the AFX_MSG_MAP markers so ClassWizard doesn't munge it ON_COMMAND_RANGE(ID_MMC_CUT, ID_MMC_PRINT, OnVerbAccelKey) // WARNING: If your message handler has void return use ON_MESSAGE_VOID !! ON_MESSAGE(MMC_MSG_CONNECT_TO_CIC, OnConnectToCIC) ON_MESSAGE(MMC_MSG_CONNECT_TO_TPLV, OnConnectToTPLV) ON_MESSAGE(MMC_MSG_GET_ICON_INFO, OnGetIconInfoForSelectedNode) ON_MESSAGE(WM_APPCOMMAND, OnAppCommand) ON_REGISTERED_MESSAGE (m_nShowWebContextMenuMsg, OnShowWebContextMenu) ON_REGISTERED_MESSAGE (m_nProcessMultiSelectionChangesMsg, OnProcessMultiSelectionChanges) ON_REGISTERED_MESSAGE (m_nAddPageBreakAndNavigateMsg, OnAddPageBreakAndNavigate) ON_REGISTERED_MESSAGE (m_nJiggleListViewFocusMsg, OnJiggleListViewFocus) ON_REGISTERED_MESSAGE (m_nDeferRecalcLayoutMsg, OnDeferRecalcLayout) ON_COMMAND(ID_FILE_PRINT, CView::OnFilePrint) ON_COMMAND(ID_FILE_PRINT_DIRECT, CView::OnFilePrint) ON_COMMAND(ID_FILE_PRINT_PREVIEW, CView::OnFilePrintPreview) ON_NOTIFY(FTN_TABCHANGED, IDC_ResultTabCtrl, OnChangedResultTab) END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CAMCView construction/destruction const CSize CAMCView::m_sizEdge (GetSystemMetrics (SM_CXEDGE), GetSystemMetrics (SM_CYEDGE)); const int CAMCView::m_cxSplitter = 3; //+------------------------------------------------------------------- // // Member: CAMCView::OnMenuSelect // // Synopsis: Handles WM_MENUSELECT for Favorites menu. // // Arguments: [nItemID] - the resource id of menu item. // [nFlags] - MF_* flags // // Returns: none // //-------------------------------------------------------------------- void CAMCView::OnMenuSelect(UINT nItemID, UINT nFlags, HMENU hSysMenu) { DECLARE_SC(sc, TEXT("CAMCView::OnMenuSelect")); CMainFrame* pFrame = AMCGetMainWnd(); sc = ScCheckPointers(pFrame, E_UNEXPECTED); if (sc) return; // Pass onto the mainframe. return pFrame->OnMenuSelect(nItemID, nFlags, hSysMenu); } CAMCView::CAMCView() : m_pResultFolderTabView(new CFolderTabView(this)) // dynamically allocated for decoupling { TRACE_CONSTRUCTOR(CAMCView); // Init pointer members to NULL m_nViewID = 0; m_pTreeCtrl = NULL; m_pListCtrl = NULL; m_pWebViewCtrl = NULL; m_pViewExtensionCtrl = NULL; m_pOCXHostView = NULL; m_nSelectNestLevel = 0; // if the view is a listview, then this member define what the view // mode is for all snapins with that view. m_nViewMode = LVS_REPORT; // REVIEW: Must we persist this - ravi // REVIEW consider moving the above initialzation to the InitSplitter // CommonConstruct // NOTE moved code from InitSplitter into the contructor and deleted InitSplitter // Default values for view. User can set these values with SetPaneInfo; m_PaneInfo[ePane_ScopeTree].pView = NULL; m_PaneInfo[ePane_ScopeTree].cx = -1; m_PaneInfo[ePane_ScopeTree].cxMin = 50; m_PaneInfo[ePane_Results].pView = NULL; m_PaneInfo[ePane_Results].cx = -1; m_PaneInfo[ePane_Results].cxMin = 50; m_pTracker = NULL; m_rectResultFrame = g_rectEmpty; m_rectVSplitter = g_rectEmpty; // m_fDontPersistOCX = FALSE; // root node for the view m_hMTNode = 0; // Bug 157408: remove the "Type" column for static nodes // m_columnWidth[0] = 90; // m_columnWidth[1] = 50; m_columnWidth[0] = 200; m_columnWidth[1] = 0; m_iFocusedLV = -1; m_bLVItemSelected = FALSE; m_DefaultLVStyle = 0; m_bProcessMultiSelectionChanges = false; m_htiCut = NULL; m_nReleaseViews = 0; m_htiStartingSelectedNode = NULL; m_bLastSelWasMultiSel = false; m_eCurrentActivePane = eActivePaneNone; m_fRootedAtNonPersistedDynamicNode = false; m_fSnapinDisplayedHelp = false; m_fActivatingSpecialResultPane = false; m_bDirty = false; m_fViewExtended = false; m_pHistoryList = new CHistoryList (this); m_ListPadNode = NULL; /* * Bug 103604: Mark this as an author mode view if it was created in * author mode. If we're loading a user mode console file, it will * have author mode views and possibly some views that were created * in user mode, but this code will mark all of the views as non-author * mode views. CAMCView::Persist will fix that. */ CAMCApp* pApp = AMCGetApp(); if (pApp != NULL) m_bAuthorModeView = (pApp->GetMode() == eMode_Author); else m_bAuthorModeView = true; } CAMCView::~CAMCView() { TRACE_DESTRUCTOR(CAMCView); // Delete all pointer members. (C++ checks to see if they are NULL before deleting) // The standard ~CWnd destructor will call DestroyWindow() // REVIEW set the pointers to NULL after deleting them // Note Done // CViews "delete this" in PostNcDestroy, no need to delete here //delete m_pTreeCtrl; m_pTreeCtrl = NULL; m_pListCtrl->Release(); m_pListCtrl = NULL; /* * DONT_DELETE_VIEWS * * CViews "delete this" in PostNcDestroy, no need to delete * here if the web view control is derived from CView. See * AttachWebViewAsResultPane (search for "DONT_DELETE_VIEWS") * for the ASSERTs that make sure this code is right. */ //delete m_pWebViewCtrl; //m_pWebViewCtrl = NULL; /* * CViews "delete this" in PostNcDestroy, no need to delete here */ m_pOCXHostView = NULL; m_pResultFolderTabView = NULL; if (m_ViewData.m_spNodeManager != NULL) m_ViewData.m_spNodeManager->CleanupViewData( reinterpret_cast(&m_ViewData)); ASSERT (m_ViewData.m_pMultiSelection == NULL); delete m_pHistoryList; // First destroy the IControlbarsCache as snapins call CAMCViewToolbars // to cleanup toolbars before the CAMCViewToolbars itself gets destroyed. m_ViewData.m_spControlbarsCache = NULL; // (UI cleanup) release toolbars related to this view. m_spAMCViewToolbars = std::auto_ptr(NULL); m_spStandardToolbar = std::auto_ptr(NULL); //m_spStandardToolbar = NULL; //m_spAMCViewToolbars = NULL; } //############################################################################ //############################################################################ // // CAMCView: Object model methods - View Interface // //############################################################################ //############################################################################ /*+-------------------------------------------------------------------------* * * CAMCView::ScGetOptionalScopeNodeParameter * * PURPOSE: Helper function - returns the scope node pointer, if supplied * in the variant, or the Active Scope node pointer, if not * supplied. * * PARAMETERS: * VARIANT varScopeNode : The parameter, which can be empty. NOTE: This is a * reference, so we don't need to call VariantClear on it. * PPNODE ppNode : * bool& bMatchedGivenNode: If true the returned ppNode corresponds to the given node * applies only if given node is in bookmark format. * * RETURNS: * SC * *+-------------------------------------------------------------------------*/ SC CAMCView::ScGetOptionalScopeNodeParameter(VARIANT &varScopeNode, PPNODE ppNode, bool& bMatchedGivenNode) { DECLARE_SC(sc, TEXT("CAMCView::ScGetOptionalScopeNodeParameter")); sc = ScCheckPointers(ppNode); if(sc) return sc; // init the out parameter *ppNode = NULL; bMatchedGivenNode = true; // supply the optional parameter if it is missing if(IsOptionalParamMissing(varScopeNode)) { sc = Scget_ActiveScopeNode(ppNode); return sc; } VARIANT* pvarTemp = ConvertByRefVariantToByValue(&varScopeNode); sc = ScCheckPointers(pvarTemp,E_UNEXPECTED); if(sc) return sc; bool bByReference = ( VT_BYREF == (V_VT(pvarTemp) & VT_BYREF) ); // value passed by reference UINT uiVarType = (V_VT(pvarTemp) & VT_TYPEMASK); // get variable type (strip flags) if(uiVarType == VT_DISPATCH) // do we have a dispatch interface. { IDispatchPtr spDispatch = NULL; if(bByReference) // a reference, use ppDispVal spDispatch = *(pvarTemp->ppdispVal); else spDispatch = pvarTemp->pdispVal; // passed by value, use pDispVal sc = ScCheckPointers(spDispatch.GetInterfacePtr()); if(sc) return sc; // at this point spDispatch is correctly set. QI for Node from it. NodePtr spNode = spDispatch; if(spNode == NULL) return (sc = E_INVALIDARG); *ppNode = spNode.Detach(); // keep the reference. } else if(uiVarType == VT_BSTR) { // Name: get string properly ( see if it's a reference ) LPOLESTR lpstrBookmark = bByReference ? *(pvarTemp->pbstrVal) : pvarTemp->bstrVal; // get the bookmark CBookmark bm; sc = bm.ScLoadFromString(lpstrBookmark); if(sc) return sc; if(!bm.IsValid()) return (sc = E_UNEXPECTED); IScopeTree* const pScopeTree = GetScopeTreePtr(); sc = ScCheckPointers(pScopeTree, E_UNEXPECTED); if(sc) return sc; NodePtr spNode; // Need a bool variable to find if exact match is found or not, cannot return // MMC specific error codes from nodemgr to conui. bMatchedGivenNode = false; sc = pScopeTree->GetNodeFromBookmark( bm, this, ppNode, bMatchedGivenNode); if(sc) return sc; } else return (sc = E_INVALIDARG); // we should have a valid node at this point. if(!ppNode) return (sc = E_UNEXPECTED); return sc; } /*+-------------------------------------------------------------------------* * * CAMCView::Scget_ActiveScopeNode * * PURPOSE: Implements get method for Wiew.ActiveScopeNode property * * PARAMETERS: * PPNODE ppNode - resulting node * * RETURNS: * SC * *+-------------------------------------------------------------------------*/ SC CAMCView::Scget_ActiveScopeNode( PPNODE ppNode) { DECLARE_SC(sc, TEXT("CAMCView::Scget_ActiveScopeNode")); // checking parameters sc= ScCheckPointers(ppNode); if (sc) return sc; // get selected node HNODE hNode = GetSelectedNode(); sc= ScCheckPointers((LPVOID)hNode, E_FAIL); if (sc) return sc; // get node callback INodeCallback* pNodeCallBack = GetNodeCallback(); sc= ScCheckPointers(pNodeCallBack, E_FAIL); if (sc) return sc; // now get an HMTNODE HMTNODE hmtNode = NULL; sc = pNodeCallBack->GetMTNode(hNode, &hmtNode); if (sc) return sc; // geting pointer to scope tree IScopeTree* const pScopeTree = GetScopeTreePtr(); sc= ScCheckPointers(pScopeTree, E_UNEXPECTED); if (sc) return sc; // map to PNODE sc = pScopeTree->GetMMCNode(hmtNode, ppNode); if (sc) return sc; return sc; } /***************************************************************************\ * * METHOD: CExpandSyncModeLock * * PURPOSE: constructing the object of this class locks MMC in syncronous * expansion mode (node expansion will send MMCN_EXPANDSYNC to snapin) * destructor of the class restores the previous mode * \***************************************************************************/ class CExpandSyncModeLock { IScopeTreePtr m_spScopeTree; bool m_fSyncExpandWasRequired; public: CExpandSyncModeLock( IScopeTree *pScopeTree ) : m_spScopeTree(pScopeTree), m_fSyncExpandWasRequired(false) { ASSERT( m_spScopeTree != NULL ); if ( m_spScopeTree ) { m_fSyncExpandWasRequired = (m_spScopeTree->IsSynchronousExpansionRequired() == S_OK); m_spScopeTree->RequireSynchronousExpansion (true); } } ~CExpandSyncModeLock() { if ( m_spScopeTree ) { m_spScopeTree->RequireSynchronousExpansion ( m_fSyncExpandWasRequired ); } } }; /*+-------------------------------------------------------------------------* * * CAMCView::Scset_ActiveScopeNode * * PURPOSE: Implements set method for Wiew.ActiveScopeNode property * * PARAMETERS: * PNODE pNode - node to activate * * RETURNS: * SC * *+-------------------------------------------------------------------------*/ SC CAMCView::Scput_ActiveScopeNode( PNODE pNode) { DECLARE_SC(sc, TEXT("CAMCView::Scput_ActiveScopeNode")); // checking parameters sc= ScCheckPointers(pNode); if (sc) return sc; // geting pointer to scope tree IScopeTree* const pScopeTree = GetScopeTreePtr(); sc= ScCheckPointers(pScopeTree, E_UNEXPECTED); if (sc) return sc; // Converting PNODE to TNODEID MTNODEID ID = 0; sc = pScopeTree->GetNodeID(pNode, &ID); if (sc) return sc; // always require syncronous expansion for Object Model // see bug #154694 CExpandSyncModeLock lock( pScopeTree ); // selecting the node sc = ScSelectNode(ID); if (sc) return sc; return sc; } /***************************************************************************\ * * METHOD: CAMCView::Scget_Selection * * PURPOSE: creates enumerator for Selected Nodes * * PARAMETERS: * PPNODES ppNodes - resulting enumerator * * RETURNS: * SC - result code * \***************************************************************************/ SC CAMCView::Scget_Selection( PPNODES ppNodes ) { DECLARE_SC(sc, TEXT("CAMCView::Scget_SelectedItems")); // check for list view control sc = ScCheckPointers(m_pListCtrl, E_UNEXPECTED); if (sc) return sc; // get enumerator from list control sc = m_pListCtrl->Scget_SelectedItems(ppNodes); if (sc) return sc; return sc; } /***************************************************************************\ * * METHOD: CAMCView::Scget_ListItems * * PURPOSE: * * PARAMETERS: * PPNODES ppNodes - resulting enumerator * * RETURNS: * SC - result code * \***************************************************************************/ SC CAMCView::Scget_ListItems( PPNODES ppNodes ) { DECLARE_SC(sc, TEXT("CAMCView::Scget_ListItems")); // check for list view control sc = ScCheckPointers(m_pListCtrl, E_UNEXPECTED); if (sc) return sc; // get enumerator from list control sc = m_pListCtrl->Scget_ListItems(ppNodes); if (sc) return sc; return sc; } //+------------------------------------------------------------------- // // Member: CAMCView::ScSnapinScopeObject // // Synopsis: Get the IDispatch* from snapin for given ScopeNode object. // // Arguments: varScopeNode - Given ScopeNode object. // ScopeNodeObject [out] - IDispatch for ScopeNode object. // // Returns: SC // //-------------------------------------------------------------------- SC CAMCView::ScSnapinScopeObject (VARIANT& varScopeNode, /*[out]*/PPDISPATCH ScopeNodeObject) { DECLARE_SC(sc, _T("CAMCView::ScSnapinScopeObject")); sc = ScCheckPointers(ScopeNodeObject); if (sc) return sc; *ScopeNodeObject = NULL; bool bMatchedGivenNode = false; // unused NodePtr spNode = NULL; sc = ScGetOptionalScopeNodeParameter(varScopeNode, &spNode, bMatchedGivenNode); if(sc) return sc; INodeCallback* pNC = GetNodeCallback(); sc = ScCheckPointers(spNode.GetInterfacePtr(), pNC, E_UNEXPECTED); if(sc) return sc; sc = pNC->QueryCompDataDispatch(spNode, ScopeNodeObject); if (sc) return sc; return sc; } //+------------------------------------------------------------------- // // Member: CAMCView::ScSnapinSelectionObject // // Synopsis: Get the IDispatch* from snapin for selected items in result pane. // // Arguments: SelectedObject [out] - IDispatch for Selected items object. // // Returns: SC // //-------------------------------------------------------------------- SC CAMCView::ScSnapinSelectionObject (PPDISPATCH SelectedObject) { DECLARE_SC(sc, _T("CAMCView::ScSnapinSelectionObject")); sc = ScCheckPointers(SelectedObject); if (sc) return sc; *SelectedObject = NULL; if (!HasList()) // not a list. Return error return (sc = ScFromMMC(MMC_E_NOLIST)); LPARAM lvData = LVDATA_ERROR; sc = ScGetSelectedLVItem(lvData); if (sc) return sc; HNODE hNode = GetSelectedNode(); sc = ScCheckPointers(hNode, E_UNEXPECTED); if (sc) return sc; INodeCallback* pNodeCallback = GetNodeCallback(); sc = ScCheckPointers(pNodeCallback, E_UNEXPECTED); if(sc) return sc.ToHr(); sc = pNodeCallback->QueryComponentDispatch(hNode, lvData, SelectedObject); if (sc) return sc; return (sc); } /***************************************************************************\ * * METHOD: CAMCView::ScIs * * PURPOSE: compares two views if they are the same * * PARAMETERS: * PVIEW pView - [in] another view * VARIANT_BOOL * pbTheSame - [out] comparison result * * RETURNS: * SC - result code * \***************************************************************************/ SC CAMCView::ScIs (PVIEW pView, VARIANT_BOOL *pbTheSame) { DECLARE_SC(sc, TEXT("CAMCView::ScIs")); // parameter check sc = ScCheckPointers(pView, pbTheSame); if (sc) return sc; *pbTheSame = CComPtr(pView).IsEqualObject(m_spView) ? VARIANT_TRUE : VARIANT_FALSE; return sc; } //+------------------------------------------------------------------- // // Member: CAMCView::ScSelectAll // // Synopsis: Selects all items in the result pane // // Arguments: None // // Returns: SC // //-------------------------------------------------------------------- SC CAMCView::ScSelectAll () { DECLARE_SC(sc, _T("CAMCView::ScSelectAll")); if (! (GetListOptions() & RVTI_LIST_OPTIONS_MULTISELECT) ) return (sc = ScFromMMC(MMC_E_NO_MULTISELECT)); // check for list view control sc = ScCheckPointers(m_pListCtrl, E_UNEXPECTED); if (sc) return sc; // forward to list control sc = m_pListCtrl->ScSelectAll(); if (sc) return sc; return (sc); } /***************************************************************************\ * * METHOD: CAMCView::ScSelect * * PURPOSE: selects item identified by node [implements View.Select()] * * PARAMETERS: * PNODE pNode - node to select * * RETURNS: * SC - result code * \***************************************************************************/ SC CAMCView::ScSelect( PNODE pNode ) { DECLARE_SC(sc, TEXT("CAMCView::ScSelect")); // parameter check sc = ScCheckPointers(pNode); if (sc) return sc; // check for list view control sc = ScCheckPointers(m_pListCtrl, E_UNEXPECTED); if (sc) return sc; // forward to list control sc = m_pListCtrl->ScSelect( pNode ); if (sc) return sc; return sc; } /***************************************************************************\ * * METHOD: CAMCView::ScDeselect * * PURPOSE: deselects item identified by node [implements View.Deselect()] * * PARAMETERS: * PNODE pNode - node to deselect * * RETURNS: * SC - result code * \***************************************************************************/ SC CAMCView::ScDeselect( PNODE pNode) { DECLARE_SC(sc, TEXT("CAMCView::ScDeselect")); // parameter check sc = ScCheckPointers(pNode); if (sc) return sc; // check for list view control sc = ScCheckPointers(m_pListCtrl, E_UNEXPECTED); if (sc) return sc; // forward to list control sc = m_pListCtrl->ScDeselect( pNode ); if (sc) return sc; return sc; } /***************************************************************************\ * * METHOD: CAMCView::ScIsSelected * * PURPOSE: checks the status of item identified by node [implements View.IsSelected] * * PARAMETERS: * PNODE pNode - node to examine * PBOOL pIsSelected - storage for result * * RETURNS: * SC - result code * \***************************************************************************/ SC CAMCView::ScIsSelected( PNODE pNode, PBOOL pIsSelected ) { DECLARE_SC(sc, TEXT("CAMCView::ScIsSelected")); // parameter check sc = ScCheckPointers(pNode, pIsSelected); if (sc) return sc; *pIsSelected = FALSE; // check for list view control sc = ScCheckPointers(m_pListCtrl, E_UNEXPECTED); if (sc) return sc; // forward to list control sc = m_pListCtrl->ScIsSelected( pNode, pIsSelected ); if (sc) return sc; return sc; } //+------------------------------------------------------------------- // // Member: CAMCView::ScExecuteScopeItemVerb // // Synopsis: Get the context and pass it on to nodemgr to execute // given verb. // // Arguments: [verb] - Verb to execute // [varScopeNode] - Optional scope node (if not given, // currently selected item will be used.) // [bstrNewName] - valid for Rename else NULL. // // Returns: SC // //-------------------------------------------------------------------- SC CAMCView::ScExecuteScopeItemVerb (MMC_CONSOLE_VERB verb, VARIANT& varScopeNode, BSTR bstrNewName) { DECLARE_SC(sc, _T("CAMCView::ScExecuteScopeItemVerb")); NodePtr spNode = NULL; bool bMatchedGivenNode = false; // We should navigate to exact node to execute the verb. sc = ScGetOptionalScopeNodeParameter(varScopeNode, &spNode, bMatchedGivenNode); if(sc) return sc; if (! bMatchedGivenNode) return (sc = ScFromMMC(IDS_ACTION_COULD_NOTBE_COMPLETED)); HNODE hNode = NULL; sc = ScGetHNodeFromPNode(spNode, hNode); if (sc) return sc; INodeCallback* pNC = GetNodeCallback(); sc = ScCheckPointers(spNode.GetInterfacePtr(), pNC); if(sc) return sc; sc = pNC->ExecuteScopeItemVerb(verb, hNode, bstrNewName); if (sc) return sc; return (sc); } //+------------------------------------------------------------------- // // Member: CAMCView::ScExecuteResultItemVerb // // Synopsis: Get the currently selected context and pass it on to // nodemgr to execute given verb. // // Arguments: [verb] - Verb to execute // [bstrNewName] - valid for Rename else NULL. // // Returns: SC // //-------------------------------------------------------------------- SC CAMCView::ScExecuteResultItemVerb (MMC_CONSOLE_VERB verb, BSTR bstrNewName) { DECLARE_SC(sc, _T("CAMCView::ScExecuteResultItemVerb")); if (!HasList()) // not a list. Return error return (sc = ScFromMMC(MMC_E_NOLIST)); LPARAM lvData = LVDATA_ERROR; sc = ScGetSelectedLVItem(lvData); if (sc) return sc; if (lvData == LVDATA_ERROR) return (sc = E_UNEXPECTED); HNODE hNode = GetSelectedNode(); sc = ScCheckPointers(hNode, E_UNEXPECTED); if (sc) return sc; INodeCallback* pNodeCallback = GetNodeCallback(); sc = ScCheckPointers(pNodeCallback, E_UNEXPECTED); if(sc) return sc.ToHr(); sc = pNodeCallback->ExecuteResultItemVerb( verb, hNode, lvData, bstrNewName); if (sc) return sc; return (sc); } /*+-------------------------------------------------------------------------* * * CAMCView::ScDisplayScopeNodePropertySheet * * PURPOSE: Displays the property sheet for a scope node. * * PARAMETERS: * VARIANT varScopeNode : * * RETURNS: * SC * *+-------------------------------------------------------------------------*/ SC CAMCView::ScDisplayScopeNodePropertySheet(VARIANT& varScopeNode) { DECLARE_SC(sc, TEXT("CAMCView::ScDisplayPropertySheet")); sc = ScExecuteScopeItemVerb(MMC_VERB_PROPERTIES, varScopeNode, NULL); if (sc) return sc; return sc; } //+------------------------------------------------------------------- // // Member: CAMCView::ScDisplaySelectionPropertySheet // // Synopsis: Show the property sheet for selected result item(s). // // Arguments: None // // Returns: SC // //-------------------------------------------------------------------- SC CAMCView::ScDisplaySelectionPropertySheet () { DECLARE_SC(sc, _T("CAMCView::ScDisplaySelectionPropertySheet")); sc = ScExecuteResultItemVerb(MMC_VERB_PROPERTIES, NULL); if (sc) return sc; return (sc); } //+------------------------------------------------------------------- // // Member: CAMCView::ScCopyScopeNode // // Synopsis: Copy the specified scope node (if given) or currently // selected node to clipboard. // // Arguments: [varScopeNode] - given node. // // Returns: SC // //-------------------------------------------------------------------- SC CAMCView::ScCopyScopeNode (VARIANT& varScopeNode) { DECLARE_SC(sc, _T("CAMCView::ScCopyScopeNode")); sc = ScExecuteScopeItemVerb(MMC_VERB_COPY, varScopeNode, NULL); if (sc) return sc; return (sc); } //+------------------------------------------------------------------- // // Member: CAMCView::ScCopySelection // // Synopsis: Copy the selected result item(s) to clipboard. // // Arguments: // // Returns: SC // //-------------------------------------------------------------------- SC CAMCView::ScCopySelection () { DECLARE_SC(sc, _T("CAMCView::ScCopySelection")); sc = ScExecuteResultItemVerb(MMC_VERB_COPY, NULL); if (sc) return sc; return (sc); } //+------------------------------------------------------------------- // // Member: CAMCView::ScDeleteScopeNode // // Synopsis: Deletes the specified scope node (if given) or currently // selected node. // // Arguments: [varScopeNode] - node to delete // // Returns: SC // //-------------------------------------------------------------------- SC CAMCView::ScDeleteScopeNode (VARIANT& varScopeNode) { DECLARE_SC(sc, _T("CAMCView::ScDeleteScopeNode")); sc = ScExecuteScopeItemVerb(MMC_VERB_DELETE, varScopeNode, NULL); if (sc) return sc; return (sc); } //+------------------------------------------------------------------- // // Member: CAMCView::ScDeleteSelection // // Synopsis: Deletes the selected item(s) in result pane. // // Returns: SC // //-------------------------------------------------------------------- SC CAMCView::ScDeleteSelection () { DECLARE_SC(sc, _T("CAMCView::ScDeleteSelection")); sc = ScExecuteResultItemVerb(MMC_VERB_DELETE, NULL); if (sc) return sc; return (sc); } //+------------------------------------------------------------------- // // Member: CAMCView::ScRenameScopeNode // // Synopsis: Rename the specified scope node (if given) or currently // selected node with given new name. // // Arguments: [bstrNewName] - the new name // [varScopeNode] - given node. // // Returns: SC // //-------------------------------------------------------------------- SC CAMCView::ScRenameScopeNode (BSTR bstrNewName, VARIANT& varScopeNode) { DECLARE_SC(sc, _T("CAMCView::ScRenameScopeNode")); sc = ScExecuteScopeItemVerb(MMC_VERB_RENAME, varScopeNode, bstrNewName); if (sc) return sc; return (sc); } //+------------------------------------------------------------------- // // Member: CAMCView::ScRenameSelectedItem // // Synopsis: Rename the selected result item with given new name. // // Arguments: // // Returns: SC // //-------------------------------------------------------------------- SC CAMCView::ScRenameSelectedItem (BSTR bstrNewName) { DECLARE_SC(sc, _T("CAMCView::ScRenameSelectedItem")); sc = ScExecuteResultItemVerb(MMC_VERB_RENAME, bstrNewName); if (sc) return sc; return (sc); } //+------------------------------------------------------------------- // // Member: CAMCView::ScRefreshScopeNode // // Synopsis: Refresh the specified scope node (if given) or currently // selected node. // // Arguments: [varScopeNode] - given node. // // Returns: SC // //-------------------------------------------------------------------- SC CAMCView::ScRefreshScopeNode (VARIANT& varScopeNode) { DECLARE_SC(sc, _T("CAMCView::ScRefreshScopeNode")); sc = ScExecuteScopeItemVerb(MMC_VERB_REFRESH, varScopeNode, NULL); if (sc) return sc; return (sc); } //+------------------------------------------------------------------- // // Member: CAMCView::ScRefreshSelection // // Synopsis: Refresh the selected result item(s). // // Arguments: // // Returns: SC // //-------------------------------------------------------------------- SC CAMCView::ScRefreshSelection () { DECLARE_SC(sc, _T("CAMCView::ScRefreshSelection")); sc = ScExecuteResultItemVerb(MMC_VERB_REFRESH, NULL); if (sc) return sc; return (sc); } /*+-------------------------------------------------------------------------* * * CAMCView::Scget_ScopeNodeContextMenu * * PURPOSE: Creates a context menu for a scope node and returns it. * * PARAMETERS: * VARIANT varScopeNode : * PPCONTEXTMENU ppContextMenu : * * RETURNS: * SC * *+-------------------------------------------------------------------------*/ SC CAMCView::Scget_ScopeNodeContextMenu(VARIANT& varScopeNode, PPCONTEXTMENU ppContextMenu, bool bMatchGivenNode /* = false*/) { DECLARE_SC(sc, TEXT("CAMCView::Scget_ContextMenu")); NodePtr spNode; // See if context menu for exactly the given node is asked for. bool bMatchedGivenNode = false; sc = ScGetOptionalScopeNodeParameter(varScopeNode, &spNode, bMatchedGivenNode); if (sc) return sc; if ( (bMatchGivenNode) && (!bMatchedGivenNode) ) return ScFromMMC(IDS_NODE_NOT_FOUND); if(sc) return sc; INodeCallback* spNodeCallback = GetNodeCallback(); sc = ScCheckPointers(spNode, ppContextMenu, spNodeCallback, GetTreeCtrl()); if(sc) return sc.ToHr(); *ppContextMenu = NULL; // initialize output. HNODE hNode = NULL; sc = ScGetHNodeFromPNode(spNode, hNode); if (sc) return sc; // tell the node callback to add menu items for the scope node. sc = spNodeCallback->CreateContextMenu(spNode, hNode, ppContextMenu); return sc; } /*+-------------------------------------------------------------------------* * * CAMCView::Scget_SelectionContextMenu * * PURPOSE: Creates a context menu for the current selection and returns it. * * PARAMETERS: * PPCONTEXTMENU ppContextMenu : [OUT]: The context menu object * * RETURNS: * SC : error if no list exists, or there is nothing selected. * *+-------------------------------------------------------------------------*/ SC CAMCView::Scget_SelectionContextMenu( PPCONTEXTMENU ppContextMenu) { DECLARE_SC(sc, TEXT("CAMCView::Scget_SelectionContextMenu")); sc = ScCheckPointers(ppContextMenu); if(sc) return sc; if (!HasListOrListPad()) // not a list. Return error return (sc = ScFromMMC(MMC_E_NOLIST)); INodeCallback* pNodeCallback = GetNodeCallback(); sc = ScCheckPointers(pNodeCallback); if(sc) return sc.ToHr(); CContextMenuInfo contextInfo; // the structure to pass to nodemgr // common entries contextInfo.m_pConsoleView = this; // always use the temp verbs - cannot depend on what the active pane is contextInfo.m_dwFlags = CMINFO_USE_TEMP_VERB; int iIndex = -1; HNODE hNode = GetSelectedNode(); ASSERT(hNode != NULL); int cSel = m_pListCtrl->GetSelectedCount(); if(0 == cSel) { // no items selected, bail return (sc = ScFromMMC(MMC_E_NO_SELECTED_ITEMS)); } else if(1 == cSel) { // single selection LPARAM lvData = LVDATA_ERROR; iIndex = _GetLVSelectedItemData(&lvData); ASSERT(iIndex != -1); ASSERT(lvData != LVDATA_ERROR); if (IsVirtualList()) { // virtual list item in the result pane contextInfo.m_eDataObjectType = CCT_RESULT; contextInfo.m_eContextMenuType = MMC_CONTEXT_MENU_DEFAULT; contextInfo.m_bBackground = false; contextInfo.m_bMultiSelect = false; contextInfo.m_resultItemParam = iIndex; contextInfo.m_iListItemIndex = iIndex; } else { CResultItem* pri = CResultItem::FromHandle (lvData); if(!pri) return (sc = E_UNEXPECTED); if (pri->IsScopeItem()) { // scope item in the result pane contextInfo.m_eDataObjectType = CCT_SCOPE; contextInfo.m_eContextMenuType = MMC_CONTEXT_MENU_DEFAULT; contextInfo.m_bBackground = FALSE; contextInfo.m_hSelectedScopeNode = GetSelectedNode(); contextInfo.m_resultItemParam = NULL; contextInfo.m_bMultiSelect = FALSE; contextInfo.m_bScopeAllowed = TRUE; // change the scope node on which the menu is to be displayed hNode = pri->GetScopeNode(); } else { // single result item in the result pane contextInfo.m_eDataObjectType = CCT_RESULT; contextInfo.m_eContextMenuType = MMC_CONTEXT_MENU_DEFAULT; contextInfo.m_bBackground = false; contextInfo.m_bMultiSelect = false; contextInfo.m_resultItemParam = lvData; contextInfo.m_iListItemIndex = iIndex; } } } else { // multiselection iIndex = INDEX_MULTISELECTION; // => MultiSelect contextInfo.m_eDataObjectType = CCT_RESULT; contextInfo.m_eContextMenuType = MMC_CONTEXT_MENU_DEFAULT; contextInfo.m_bBackground = false; contextInfo.m_bMultiSelect = true; contextInfo.m_resultItemParam = LVDATA_MULTISELECT; contextInfo.m_iListItemIndex = iIndex; } sc = pNodeCallback->CreateSelectionContextMenu(hNode, &contextInfo, ppContextMenu); return sc; } /*+-------------------------------------------------------------------------* * * CAMCView::ScExecuteMenuItem * * PURPOSE: Executes the specified context menu item on the specified context menu * * PARAMETERS: * PCONTEXTMENU pContextMenu : * BSTR MenuItemPath : Either the language-independent path or the * language-dependent path. * * RETURNS: * SC * *+-------------------------------------------------------------------------*/ SC CAMCView::ScExecuteMenuItem(PCONTEXTMENU pContextMenu, BSTR MenuItemPath) { DECLARE_SC(sc, TEXT("CAMCView::ScExecuteMenuItem")); sc = ScCheckPointers(MenuItemPath); if(sc) return sc; sc = ScCheckPointers(pContextMenu, E_UNEXPECTED); if(sc) return sc; // execute the menu item, if found. MenuItemPtr spMenuItem; sc = pContextMenu->get_Item(CComVariant(MenuItemPath), &spMenuItem); if(sc.IsError() || sc == SC(S_FALSE)) // error or no item return (sc = E_INVALIDARG); // did not find the menu item. // recheck the pointer sc = ScCheckPointers(spMenuItem, E_UNEXPECTED); if (sc) return sc; // found - execute it sc = spMenuItem->Execute(); return sc; } /*+-------------------------------------------------------------------------* * * CAMCView::ScExecuteSelectionMenuItem * * PURPOSE: Executes a context menu item on the selection. * * PARAMETERS: * BSTR MenuItemPath : Either the language-independent path or the * language-dependent path of the menu item. * * NOTE: This is an aggregate or utility function - it only uses other * object model functions * * RETURNS: * SC * *+-------------------------------------------------------------------------*/ SC CAMCView::ScExecuteSelectionMenuItem(BSTR MenuItemPath) { DECLARE_SC(sc, TEXT("CAMCView::ScExecuteSelectionMenuItem")); // get the context menu object ContextMenuPtr spContextMenu; sc = Scget_SelectionContextMenu(&spContextMenu); if(sc) return sc; sc = ScExecuteMenuItem(spContextMenu, MenuItemPath); return sc; } /*+-------------------------------------------------------------------------* * * CAMCView::ScExecuteScopeNodeMenuItem * * PURPOSE: Executes a context menu item on the specified scope node. The parameter * is the language independent path of the menu item * * PARAMETERS: * BSTR MenuItemLanguageIndependentPath : * * NOTE: This is an aggregate or utility function - it only uses other * object model functions * * RETURNS: * SC * *+-------------------------------------------------------------------------*/ SC CAMCView::ScExecuteScopeNodeMenuItem(BSTR MenuItemPath, VARIANT &varScopeNode /* = ActiveScopeNode */) { DECLARE_SC(sc, TEXT("CAMCView::ScExecuteScopeNodeMenuItem")); // get the context menu object for exactly the given node. ContextMenuPtr spContextMenu; sc = Scget_ScopeNodeContextMenu(varScopeNode, &spContextMenu, /*bMatchGivenNode = */ true); if (sc == ScFromMMC(IDS_NODE_NOT_FOUND)) { sc = ScFromMMC(IDS_ACTION_COULD_NOTBE_COMPLETED); return sc; } if(sc) return sc; sc = ScExecuteMenuItem(spContextMenu, MenuItemPath); return sc; } /*+-------------------------------------------------------------------------* * * CAMCView::ScExecuteShellCommand * * PURPOSE: Executes a shell command with the specified parameters in the * specified directory with the correct window size * * PARAMETERS: * BSTR Command : * BSTR Directory : * BSTR Parameters : * BSTR WindowState : * * RETURNS: * SC * *+-------------------------------------------------------------------------*/ SC CAMCView::ScExecuteShellCommand(BSTR Command, BSTR Directory, BSTR Parameters, BSTR WindowState) { DECLARE_SC(sc, TEXT("CAMCView::ScExecuteShellCommand")); sc = ScCheckPointers(Command, Directory, Parameters, WindowState); if(sc) return sc; INodeCallback *pNodeCallback = GetNodeCallback(); HNODE hNodeSel = GetSelectedNode(); sc = ScCheckPointers(pNodeCallback, hNodeSel, E_UNEXPECTED); if(sc) return sc; sc = pNodeCallback->ExecuteShellCommand(hNodeSel, Command, Directory, Parameters, WindowState); return sc; } /*+-------------------------------------------------------------------------* * * CAMCView::Scget_ListViewMode * * PURPOSE: Returns the list view mode, if available. * * PARAMETERS: * ListViewMode * pMode : * * RETURNS: * STDMETHODIMP * *+-------------------------------------------------------------------------*/ SC CAMCView::Scget_ListViewMode(PLISTVIEWMODE pMode) { DECLARE_SC(sc, TEXT("CAMCView::Scget_ListViewMode")); // check parameter if(!pMode) { sc = E_INVALIDARG; return sc; } if (!HasList()) return (ScFromMMC(MMC_E_NOLIST)); int mode = 0; // translate it into an automation friendly enum switch(GetViewMode()) { default: ASSERT( 0 && "Should not come here"); // fall thru. case LVS_LIST: *pMode = ListMode_List; break; case LVS_ICON: *pMode = ListMode_Large_Icons; break; case LVS_SMALLICON: *pMode = ListMode_Small_Icons; break; case LVS_REPORT: *pMode = ListMode_Detail; break; case MMCLV_VIEWSTYLE_FILTERED: *pMode = ListMode_Filtered; break; } return sc; } /*+-------------------------------------------------------------------------* * * CAMCView::Scput_ListViewMode * * PURPOSE: Sets the list mode to the specified mode. * * PARAMETERS: * ListViewMode mode : * * RETURNS: * STDMETHODIMP * *+-------------------------------------------------------------------------*/ SC CAMCView::Scput_ListViewMode(ListViewMode mode) { DECLARE_SC(sc, TEXT("CAMCView::Scput_ListViewMode")); int nMode; if (!HasList()) return (ScFromMMC(MMC_E_NOLIST)); switch (mode) { default: sc = E_INVALIDARG; return sc; case ListMode_List: nMode = LVS_LIST; break; case ListMode_Detail: nMode = LVS_REPORT; break; case ListMode_Large_Icons: nMode = LVS_ICON; break; case ListMode_Small_Icons: nMode = LVS_SMALLICON; break; case ListMode_Filtered: nMode = MMCLV_VIEWSTYLE_FILTERED; break; } sc = ScChangeViewMode(nMode); return sc; } /*+-------------------------------------------------------------------------* * * CAMCView::ScBack * * PURPOSE: Invokes the Back command on the view. * * RETURNS: * SC * *+-------------------------------------------------------------------------*/ SC CAMCView::ScBack() { DECLARE_SC(sc, TEXT("CAMCView::ScBack")); sc = ScWebCommand(CConsoleView::eWeb_Back); return sc; } /*+-------------------------------------------------------------------------* * * CAMCView::ScForward * * PURPOSE: Invokes the Forward command on the view. * * RETURNS: * SC * *+-------------------------------------------------------------------------*/ SC CAMCView::ScForward() { DECLARE_SC(sc, TEXT("CAMCView::ScForward")); sc = ScWebCommand(CConsoleView::eWeb_Forward); return sc; } /*+-------------------------------------------------------------------------* * * CAMCView::Scput_StatusBarText * * PURPOSE: Sets the status bar text for the view * * PARAMETERS: * BSTR StatusBarText : * * RETURNS: * SC * *+-------------------------------------------------------------------------*/ SC CAMCView::Scput_StatusBarText(BSTR StatusBarText) { DECLARE_SC(sc, TEXT("CAMCView::Scput_StatusBarText")); // check the in parameter sc = ScCheckPointers(StatusBarText); if(sc) return sc; CConsoleStatusBar *pStatusBar = m_ViewData.GetStatusBar(); sc = ScCheckPointers(pStatusBar, E_UNEXPECTED); if(sc) return sc; USES_CONVERSION; // set the status text sc = pStatusBar->ScSetStatusText(OLE2T(StatusBarText)); return sc; } /*+-------------------------------------------------------------------------* * * CAMCView::Scget_Memento * * PURPOSE: Returns the XML version of the memento for the current view. * * PARAMETERS: * PBSTR Memento : [out]: The memento * * RETURNS: * SC * *+-------------------------------------------------------------------------*/ SC CAMCView::Scget_Memento(PBSTR Memento) { DECLARE_SC(sc, TEXT("CAMCView::Scget_Memento")); sc = ScCheckPointers(Memento); if(sc) return sc; // initialize the out parameter *Memento = NULL; CMemento memento; sc = ScInitializeMemento(memento); if(sc) return sc; std::wstring xml_contents; sc = memento.ScSaveToString(&xml_contents); if(sc) return sc.ToHr(); // store the result CComBSTR bstrBuff(xml_contents.c_str()); *Memento = bstrBuff.Detach(); return sc; } /*+-------------------------------------------------------------------------* * * CAMCView::ScViewMemento * * PURPOSE: Sets the view from the specified XML memento. * * PARAMETERS: * BSTR Memento : * * RETURNS: * SC * *+-------------------------------------------------------------------------*/ SC CAMCView::ScViewMemento(BSTR Memento) { DECLARE_SC(sc, TEXT("CAMCView::ScViewMemento")); sc = ScCheckPointers(Memento); if(sc) return sc; CMemento memento; sc = memento.ScLoadFromString(Memento); if(sc) return sc; sc = ScViewMemento(&memento); if (sc == ScFromMMC(IDS_NODE_NOT_FOUND)) return (sc = ScFromMMC(IDS_ACTION_COULD_NOTBE_COMPLETED)); return sc; } //+------------------------------------------------------------------- // // Member: CAMCView::Scget_CellContents // // Synopsis: Given row & column, get the text. // // Arguments: Node: - the row // [Column] - 1 based column index // [pbstrCellContents] - return value, contents of cell. // // Returns: SC // //-------------------------------------------------------------------- SC CAMCView::Scget_CellContents (PNODE Node, long Column, PBSTR pbstrCellContents) { DECLARE_SC(sc, _T("CAMCView::Scget_CellContents")); sc = ScCheckPointers(Node, pbstrCellContents); if (sc) return sc; *pbstrCellContents = NULL; if (!HasList()) return (ScFromMMC(MMC_E_NOLIST)); sc = ScCheckPointers(m_pListCtrl, E_UNEXPECTED); if (sc) return sc; // No need to check if we are in REPORT mode as columns exist // even in other modes (small icon....). int iItem = -1; sc = m_pListCtrl->ScFindResultItem( Node, iItem ); if (sc) return sc; // Script uses 1- based index for columns & rows. // ColCount are total # of cols. if (m_pListCtrl->GetColCount() < Column) return (sc = E_INVALIDARG); CListCtrl& ctlList = m_pListCtrl->GetListCtrl(); CString strData = ctlList.GetItemText(iItem, Column-1 /*convert to zero-based*/); *pbstrCellContents = strData.AllocSysString(); return (sc); } //+------------------------------------------------------------------- // // Member: CAMCView::ScExportList // // Synopsis: Export the list view data to given file with given options. // // Arguments: [bstrFile] - File to save to. // [exportoptions] - (Unicode, tab/comma delimited & selected rows only). // // Returns: SC // //-------------------------------------------------------------------- SC CAMCView::ScExportList (BSTR bstrFile, ExportListOptions exportoptions) { DECLARE_SC(sc, _T("CAMCView::ScExportList")); if (SysStringLen(bstrFile) < 1) return (sc = E_INVALIDARG); if (!HasList()) return (ScFromMMC(MMC_E_NOLIST)); sc = ScCheckPointers(m_pListCtrl, E_UNEXPECTED); if (sc) return sc; bool bUnicode = (exportoptions & ExportListOptions_Unicode); bool bTabDelimited = (exportoptions & ExportListOptions_TabDelimited); bool bSelectedRowsOnly = (exportoptions & ExportListOptions_SelectedItemsOnly); USES_CONVERSION; LPCTSTR lpszFileName = OLE2T(bstrFile); sc = ScWriteExportListData(lpszFileName, bUnicode, bTabDelimited, bSelectedRowsOnly, false /*bShowErrorDialogs*/); if (sc) return (sc); return (sc); } /*+-------------------------------------------------------------------------* * * CAMCView::ScClose * * PURPOSE: Implements Wiew.Close method * * PARAMETERS: * * RETURNS: * SC * *+-------------------------------------------------------------------------*/ SC CAMCView::ScClose() { DECLARE_SC(sc, TEXT("CAMCView::ScClose")); // get the frame and the document CChildFrame* pFrame = GetParentFrame(); CAMCDoc* pDoc = CAMCDoc::GetDocument(); sc= ScCheckPointers(pDoc, pFrame, E_FAIL); if (sc) return sc; // count the views int cViews = 0; CAMCViewPosition pos = pDoc->GetFirstAMCViewPosition(); while (pos != NULL) { CAMCView* pView = pDoc->GetNextAMCView(pos); if ((pView != NULL) && ++cViews >= 2) break; } // prevent closing the document this way !!! if (cViews == 1) { sc.FromMMC(IDS_CloseDocNotLastView); return sc; } // if not closing last view, then give it // a chance to clean up first. // (if whole doc is closing CAMCDoc will handle // closing all the views.) /* * Don't allow the user to close the last persisted view. */ if (IsPersisted() && (pDoc->GetNumberOfPersistedViews() == 1)) { sc.FromMMC(IDS_CantCloseLastPersistableView); return sc; } // checkings done, do close // do it indirectly so that it won't hurt the view extension it it // tries to close itself pFrame->PostMessage(WM_CLOSE); return sc; } /*+-------------------------------------------------------------------------* * * CAMCView::Scget_ScopeTreeVisible * * PURPOSE: Implements get method for Wiew.ScopeTreeVisible property * * PARAMETERS: * * RETURNS: * SC * *+-------------------------------------------------------------------------*/ SC CAMCView::Scget_ScopeTreeVisible( PBOOL pbVisible ) { DECLARE_SC(sc, TEXT("CAMCView::Scget_ScopeTreeVisible")); // parameter check... sc = ScCheckPointers(pbVisible); if (sc) return sc; *pbVisible = IsScopePaneVisible(); return sc; } /*+-------------------------------------------------------------------------* * * CAMCView::Scput_ScopeTreeVisible * * PURPOSE: Implements set method for Wiew.ScopeTreeVisible property * * PARAMETERS: * * RETURNS: * SC * *+-------------------------------------------------------------------------*/ SC CAMCView::Scput_ScopeTreeVisible( BOOL bVisible ) { DECLARE_SC(sc, TEXT("CAMCView::Scput_ScopeTreeVisible")); // show/hide the scope pane sc = ScShowScopePane (bVisible); if (sc) return (sc); return sc; } /***************************************************************************\ * * METHOD: CAMCView::ScFindResultItemForScopeNode * * PURPOSE: - Calculates result item representing the scope node in the list * * PARAMETERS: * PNODE pNode - node to search * HRESULTITEM &itm - resulting item * * RETURNS: * SC - result code * \***************************************************************************/ SC CAMCView::ScFindResultItemForScopeNode( PNODE pNode, HRESULTITEM &itm ) { DECLARE_SC(sc, TEXT("CAMCView::ScFindResultItemForScopeNode")); // initialization itm = NULL; // parameter check sc = ScCheckPointers(pNode); if (sc) return sc; // get/check for list view and tree controls and callback IScopeTree* const pScopeTree = GetScopeTreePtr(); sc = ScCheckPointers( pScopeTree, m_pTreeCtrl, m_spNodeCallback, E_UNEXPECTED); if (sc) return sc; // retrieve MTNode HMTNODE hMTNode = NULL; sc = pScopeTree->GetHMTNode(pNode, &hMTNode); if (sc) return sc; // get the pointer to the map CTreeViewMap *pTreeMap = m_pTreeCtrl->GetTreeViewMap(); sc = ScCheckPointers(pTreeMap, E_UNEXPECTED); if (sc) return sc; // find the tree item for the node HTREEITEM htiNode = NULL; sc = pTreeMap->ScGetHTreeItemFromHMTNode(hMTNode, &htiNode); if (sc) return sc = ScFromMMC(MMC_E_RESULT_ITEM_NOT_FOUND); // try to match the node to the child of selected one HTREEITEM htiParent = m_pTreeCtrl->GetParentItem(htiNode); if (htiParent == NULL || htiParent != m_pTreeCtrl->GetSelectedItem()) return sc = ScFromMMC(MMC_E_RESULT_ITEM_NOT_FOUND); // the node shold be in the ListView, lets find if! HNODE hNode = (HNODE)m_pTreeCtrl->GetItemData(htiNode); // get result item id sc = m_spNodeCallback->GetResultItem (hNode, &itm); if (sc) return sc; return sc; } /***************************************************************************\ * * METHOD: CAMCView::ScGetScopeNodeForItem * * PURPOSE: Returns Node (Scope Node) for specified item index * * PARAMETERS: * int nItem - node index to retrieve * PPNODE ppNode - result storage * * RETURNS: * SC - result code * \***************************************************************************/ SC CAMCView::ScGetScopeNode( HNODE hNode, PPNODE ppNode ) { DECLARE_SC(sc, TEXT("CCCListViewCtrl::ScGetScopeNodeForItem")); // check the parameters sc = ScCheckPointers(ppNode); if (sc) return sc; // initialize the result *ppNode = NULL; // get/check required pointers IScopeTree* const pScopeTree = GetScopeTreePtr(); sc = ScCheckPointers(pScopeTree, m_spNodeCallback, E_UNEXPECTED); if (sc) return sc; // find MTNode HMTNODE hmtNode; sc = m_spNodeCallback->GetMTNode(hNode, &hmtNode); if (sc) return sc; // request the object! sc = pScopeTree->GetMMCNode(hmtNode, ppNode); if (sc) return sc; return sc; } /***************************************************************************\ * * METHOD: CAMCView::Scget_Columns * * PURPOSE: create new or return pointer to existing Columns object * * PARAMETERS: * PPCOLUMNS ppColumns - resulting (AddRef'ed) pointer * * RETURNS: * SC - result code * \***************************************************************************/ SC CAMCView::Scget_Columns(PPCOLUMNS ppColumns) { DECLARE_SC(sc, TEXT("CAMCView::Scget_Columns")); // Check received parameters sc = ScCheckPointers(ppColumns); if (sc) return sc; // initialize *ppColumns = NULL; // Check the pointer to LV sc = ScCheckPointers(m_pListCtrl, E_UNEXPECTED); if (sc) return sc; // forward the request to LV sc = m_pListCtrl->Scget_Columns(ppColumns); if (sc) return sc; return sc; } //+------------------------------------------------------------------- // // Member: CAMCView::ScGetSelectedLVItem // // Synopsis: Return the LVItem cookie. // // Arguments: LPARAM - the LVDATA retval. // // Returns: SC - Fails if no selected item in LV. // //-------------------------------------------------------------------- SC CAMCView::ScGetSelectedLVItem(LPARAM& lvData) { DECLARE_SC(sc, _T("CAMCView::ScGetSelectedLVItem")); lvData = LVDATA_ERROR; int cSel = m_pListCtrl->GetSelectedCount(); if(0 == cSel) { // no items selected, bail return (sc = ScFromMMC(MMC_E_NO_SELECTED_ITEMS)); } else if(1 == cSel) { // single selection int iIndex = _GetLVSelectedItemData(&lvData); if (iIndex == -1 || lvData == LVDATA_ERROR) return (sc = E_UNEXPECTED); if (IsVirtualList()) { // virtual list item in the result pane lvData = iIndex; } } else if (cSel > 1) { // multiselection lvData = LVDATA_MULTISELECT; } return (sc); } //+------------------------------------------------------------------- // // Member: CAMCView::ScGetHNodeFromPNode // // Synopsis: Takes in PNODE and returns corresponding hNode // // Arguments: [PNODE] - Given pnode. // [HNODE] - ret val. // // Returns: SC // //-------------------------------------------------------------------- SC CAMCView::ScGetHNodeFromPNode (const PNODE& pNode, HNODE& hNode) { DECLARE_SC(sc, _T("CAMCView::ScGetHNodeFromPNode")); hNode = NULL; CAMCTreeView* pAMCTreeView = GetTreeCtrl(); sc = ScCheckPointers(pAMCTreeView, E_UNEXPECTED); if (sc) return sc; CTreeViewMap *pTreeMap = pAMCTreeView->GetTreeViewMap(); IScopeTree *pScopeTree = GetScopeTree(); sc = ScCheckPointers(pTreeMap, pScopeTree, E_UNEXPECTED); if(sc) return sc; HMTNODE hMTNode = NULL; sc = pScopeTree->GetHMTNode(pNode, &hMTNode); if(sc) return sc; sc = pTreeMap->ScGetHNodeFromHMTNode(hMTNode, &hNode); if(sc) return sc; return (sc); } /*+-------------------------------------------------------------------------* * * CAMCView::ScGetMMCView * * PURPOSE: Creates, AddRef's, and returns a pointer to the tied COM object. * * PARAMETERS: * View ** ppView : * * RETURNS: * SC * *+-------------------------------------------------------------------------*/ SC CAMCView::ScGetMMCView(View **ppView) { DECLARE_SC(sc, TEXT("CAMCView::ScGetMMCView")); sc = ScCheckPointers(ppView); if (sc) return sc; // init out parameter *ppView = NULL; // create a CMMCView if needed. sc = CTiedComObjectCreator::ScCreateAndConnect(*this, m_spView); if(sc) return sc; if(m_spView == NULL) { sc = E_UNEXPECTED; return sc; } // addref the pointer for the client. m_spView->AddRef(); *ppView = m_spView; return sc; } /*+-------------------------------------------------------------------------* * * CAMCView::IsDirty * * PURPOSE: Determines whether or not CAMCView is in a dirty state * * RETURNS: * bool * *+-------------------------------------------------------------------------*/ bool CAMCView::IsDirty() { bool bRet = m_bDirty; if (!m_bDirty && !m_fRootedAtNonPersistedDynamicNode) bRet = HasNodeSelChanged(); TraceDirtyFlag(TEXT("CAMCView"), bRet); return (bRet); } ///////////////////////////////////////////////////////////////////////////// // CAMCView drawing void CAMCView::OnDraw(CDC* pDC) { if (IsScopePaneVisible()) { pDC->FillRect (m_rectVSplitter, AMCGetSysColorBrush (COLOR_3DFACE)); } } ///////////////////////////////////////////////////////////////////////////// // CAMCView printing BOOL CAMCView::OnPreparePrinting(CPrintInfo* pInfo) { TRACE_METHOD(CAMCView, OnPreparePrinting); // default preparation return DoPreparePrinting(pInfo); } void CAMCView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/) { TRACE_METHOD(CAMCView, OnBeginPrinting); } void CAMCView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/) { TRACE_METHOD(CAMCView, OnEndPrinting); } ///////////////////////////////////////////////////////////////////////////// // CAMCView diagnostics #ifdef _DEBUG void CAMCView::AssertValid() const { CView::AssertValid(); } void CAMCView::Dump(CDumpContext& dc) const { CView::Dump(dc); } CAMCDoc* CAMCView::GetDocument() // non-debug version is inline { ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CAMCDoc))); return (CAMCDoc*)m_pDocument; } #endif //_DEBUG ///////////////////////////////////////////////////////////////////////////// // CAMCView message handlers //+------------------------------------------------------------------------- // // Function: PreCreateWindow // // Synopsis: Create new window class (CAMCView) - WS_EX_CLIENTEDGE // //-------------------------------------------------------------------------- BOOL CAMCView::PreCreateWindow(CREATESTRUCT& cs) { cs.style |= WS_CLIPCHILDREN; cs.style &= ~WS_BORDER; // give base class a chance to do own job BOOL bOK = (CView::PreCreateWindow(cs)); // register view class LPCTSTR pszViewClassName = g_szAMCViewWndClassName; // try to register window class which does not cause the repaint // on resizing (do it only once) static bool bClassRegistered = false; if ( !bClassRegistered ) { WNDCLASS wc; if (::GetClassInfo(AfxGetInstanceHandle(), cs.lpszClass, &wc)) { // Clear the H and V REDRAW flags wc.style &= ~(CS_HREDRAW | CS_VREDRAW); wc.lpszClassName = pszViewClassName; // Register this new class; bClassRegistered = AfxRegisterClass(&wc); } } // change window class to one which does not cause the repaint // on resizing if we successfully registered such if ( bClassRegistered ) cs.lpszClass = pszViewClassName; return bOK; } //+------------------------------------------------------------------------- // // Function: OnCreate // // Synopsis: Create Window, and Tree control / Default List control // //-------------------------------------------------------------------------- int CAMCView::OnCreate(LPCREATESTRUCT lpCreateStruct) { DECLARE_SC(sc, _T("CAMCView::OnCreate")); if (CView::OnCreate(lpCreateStruct) == -1) { sc = E_FAIL; return -1; } CChildFrame* pFrame = GetParentFrame(); ASSERT(NULL != pFrame); if (pFrame) pFrame->SetAMCView(this); m_ViewData.SetStatusBar (dynamic_cast(pFrame)); m_ViewData.SetConsoleView (this); m_RightDescCtrl.Create (NULL, WS_CHILD, g_rectEmpty, this, IDC_RightDescBar); ASSERT (m_pDocument != NULL); ASSERT (m_pDocument == CAMCDoc::GetDocument()); ASSERT_KINDOF (CAMCDoc, m_pDocument); CAMCDoc* pAMCDoc = reinterpret_cast(m_pDocument); CCreateContext* pContext = (CCreateContext*) lpCreateStruct->lpCreateParams; ASSERT (pContext != NULL); // Set window options m_ViewData.m_lWindowOptions = pAMCDoc->GetNewWindowOptions(); /* * If the scope pane is suppressed, clear the scope-visible flag. * It's not necessary to call ScShowScopePane here because none of * the windows have been created yet. We just need to keep our * interal accounting correct. */ if (m_ViewData.m_lWindowOptions & MMC_NW_OPTION_NOSCOPEPANE) SetScopePaneVisible (false); // Create tree ctrl. if (!CreateView (IDC_TreeView) || (!m_pTreeCtrl) ) { sc = E_FAIL; return -1; } SetPane(ePane_ScopeTree, m_pTreeCtrl, uiClientEdge); if (!AreStdToolbarsAllowed()) m_ViewData.m_dwToolbarsDisplayed &= ~(STD_MENUS | STD_BUTTONS); // Create default list control if (!CreateListCtrl (IDC_ListView, pContext)) { sc = E_FAIL; return -1; } // Create the folder tab control if (!CreateFolderCtrls ()) { sc = E_FAIL; return -1; } // initialize the result pane to the list view { CResultViewType rvt; sc = ScSetResultPane(NULL /*HNODE*/, rvt, MMCLV_VIEWSTYLE_REPORT /*viewMode*/, false /*bUsingHistory*/); if(sc) return -1; } sc = ScCreateToolbarObjects(); if (sc) return -1; // // Set m_ViewData. // m_ViewData.m_nViewID = 0;// Set in OnInitialUpdate VERIFY ((m_ViewData.m_spNodeManager = m_pTreeCtrl->m_spNodeManager) != NULL); VERIFY ((m_ViewData.m_spResultData = m_pTreeCtrl->m_spResultData) != NULL); VERIFY ((m_ViewData.m_spRsltImageList = m_pTreeCtrl->m_spRsltImageList) != NULL); VERIFY ( m_ViewData.m_hwndView = m_hWnd); VERIFY ( m_ViewData.m_hwndListCtrl = m_pListCtrl->GetListViewHWND()); VERIFY ( m_ViewData.m_pConsoleData = GetDocument()->GetConsoleData()); m_ViewData.m_pMultiSelection = NULL; if(pFrame) { // add the MDIClient window's taskbar as an observer CMDIFrameWnd * pFrameWnd = pFrame->GetMDIFrame(); CWnd *pWnd = NULL; if(pFrameWnd) pWnd = pFrameWnd->GetWindow(GW_CHILD); // get the first child of the frame. } // add AMCDoc as an observer for this source (object) CAMCApp *pCAMCApp = AMCGetApp(); if ( pCAMCApp ) AddObserver(*static_cast(pCAMCApp)); // fire the view creation event to all observers. sc = ScFireEvent(CAMCViewObserver::ScOnViewCreated, this); if(sc) sc.TraceAndClear(); return 0; } /*+-------------------------------------------------------------------------* * * CAMCView::CreateFolderCtrls * * PURPOSE: Creates the tabbed folder controls for the scope and result panes. * * RETURNS: * bool * *+-------------------------------------------------------------------------*/ bool CAMCView::CreateFolderCtrls() { if (!m_pResultFolderTabView->Create (WS_CHILD|WS_VISIBLE, g_rectEmpty, this, IDC_ResultTabCtrl)) return false; // add the views to the framework GetDocument()->AddView(m_pResultFolderTabView); return true; } /*+-------------------------------------------------------------------------* * CAMCView::CreateView * * This was copied largely from CFrameWnd::CreateView. We need to duplicate * it here so common control-based views are initially created with the * correct parent. A common control caches its original parent, so * using CFrameWnd::CreateView (which will create the view with the frame * as its parent) then reparenting to CAMCView will result in the common * control caching the wrong parent. *--------------------------------------------------------------------------*/ CView* CAMCView::CreateView (CCreateContext* pContext, int nID, DWORD dwStyle) { ASSERT(m_hWnd != NULL); ASSERT(::IsWindow(m_hWnd)); ASSERT(pContext != NULL); ASSERT(pContext->m_pNewViewClass != NULL); CView* pView = (CView*)pContext->m_pNewViewClass->CreateObject(); if (pView == NULL) { TRACE1("Warning: Dynamic create of view type %hs failed.\n", pContext->m_pNewViewClass->m_lpszClassName); return NULL; } ASSERT_KINDOF(CView, pView); // views are always created with a border! if (!pView->Create (NULL, NULL, AFX_WS_DEFAULT_VIEW | dwStyle, g_rectEmpty, this, nID, pContext)) { TRACE0("Warning: could not create view for frame.\n"); return NULL; // can't continue without a view } return pView; } /*+-------------------------------------------------------------------------* * CAMCView::CreateView * * *--------------------------------------------------------------------------*/ bool CAMCView::CreateView (int nID) { struct CreateViewData { int nID; CRuntimeClass* pClass; CView** ppView; DWORD dwStyle; }; CreateViewData rgCreateViewData[] = { { IDC_TreeView, RUNTIME_CLASS(CAMCTreeView), (CView**)&m_pTreeCtrl, 0 }, { IDC_OCXHostView, RUNTIME_CLASS(COCXHostView), (CView**)&m_pOCXHostView, 0 }, { IDC_WebViewCtrl, RUNTIME_CLASS(CAMCWebViewCtrl), (CView**)&m_pWebViewCtrl, CAMCWebViewCtrl::WS_HISTORY | CAMCWebViewCtrl::WS_SINKEVENTS}, { IDC_ViewExtensionView, RUNTIME_CLASS(CAMCWebViewCtrl), (CView**)&m_pViewExtensionCtrl, WS_CLIPSIBLINGS }, }; for (int i = 0; i < countof (rgCreateViewData); i++) { if (rgCreateViewData[i].nID == nID) { CCreateContext ctxt; ZeroMemory (&ctxt, sizeof (ctxt)); ctxt.m_pCurrentDoc = GetDocument(); ctxt.m_pNewViewClass = rgCreateViewData[i].pClass; CView*& pView = *rgCreateViewData[i].ppView; ASSERT (pView == NULL); pView = CreateView (&ctxt, nID, rgCreateViewData[i].dwStyle); ASSERT ((pView != NULL) && "Check the debug output window"); // Add observers only to tree, ocx and web hosts. Do not add to view extension host // as we do not care about its activation/deactivations. switch (nID) { case IDC_TreeView: // set the view and the description bar as observers of the tree view control m_pTreeCtrl->AddObserver(static_cast(*this)); m_pTreeCtrl->AddObserver(static_cast(m_RightDescCtrl)); break; case IDC_OCXHostView: m_pOCXHostView->AddObserver(static_cast(*this)); break; case IDC_WebViewCtrl: m_pWebViewCtrl->AddObserver(static_cast(*this)); break; } return (pView != NULL); } } ASSERT (false && "Missing an entry in rgCreateViewData"); return (false); } /*+-------------------------------------------------------------------------* * CAMCView::GetActiveView * * *--------------------------------------------------------------------------*/ CAMCView* CAMCView::GetActiveView() { return NULL; } /*+-------------------------------------------------------------------------* * CAMCView::ScChangeViewMode * * *--------------------------------------------------------------------------*/ SC CAMCView::ScChangeViewMode (int nNewMode) { AFX_MANAGE_STATE (AfxGetAppModuleState()); DECLARE_SC (sc, _T("CAMCView::OnViewModeChange")); // if switching from a custom view, force a reselect if (!HasListOrListPad()) { NavState state = m_pHistoryList->GetNavigateState(); m_pHistoryList->SetNavigateState (MMC_HISTORY_BUSY); PrivateChangeListViewMode(nNewMode); m_pHistoryList->SetNavigateState (state); sc = m_pTreeCtrl->ScReselect(); if (sc) return sc; } else { int nCurMode = m_pListCtrl->GetViewMode(); if ( (nNewMode == MMCLV_VIEWSTYLE_FILTERED) && (!(GetListOptions() & RVTI_LIST_OPTIONS_FILTERED)) ) return (sc = E_INVALIDARG); PrivateChangeListViewMode(nNewMode); // if filter state change, notify the snap-in if ( ((nCurMode == MMCLV_VIEWSTYLE_FILTERED) != (nNewMode == MMCLV_VIEWSTYLE_FILTERED)) && (GetListOptions() & RVTI_LIST_OPTIONS_FILTERED)) { HNODE hNodeSel = GetSelectedNode(); ASSERT(hNodeSel != NULL); m_spNodeCallback->Notify(hNodeSel, NCLBK_FILTER_CHANGE, (nNewMode == MMCLV_VIEWSTYLE_FILTERED) ? MFCC_ENABLE : MFCC_DISABLE, 0); } } return (sc); } /*+-------------------------------------------------------------------------* * CAMCView::ViewMmento * * *--------------------------------------------------------------------------*/ SC CAMCView::ScViewMemento(CMemento* pMemento) { DECLARE_SC (sc, TEXT("CAMCView::ScViewMemento")); sc = ScCheckPointers(pMemento); if (sc) return sc; AFX_MANAGE_STATE (AfxGetAppModuleState()); IScopeTree* const pScopeTree = GetScopeTreePtr(); sc = ScCheckPointers(pScopeTree, E_UNEXPECTED); if (sc) return sc; MTNODEID NodeId = 0; CBookmark& bm = pMemento->GetBookmark(); ASSERT(bm.IsValid()); // We want to display message if exact favorite item cannot be selected. bool bExactMatchFound = false; // out value from GetNodeIDFromBookmark. sc = pScopeTree->GetNodeIDFromBookmark( bm, &NodeId, bExactMatchFound); if(sc) return sc; if (! bExactMatchFound) return ScFromMMC(IDS_NODE_NOT_FOUND); // do not trace INodeCallback *pNodeCallback = GetNodeCallback(); sc = ScCheckPointers(pNodeCallback, E_UNEXPECTED); if (sc) return sc; // set the persisted information to the saved settings. sc = pNodeCallback->SetViewSettings(GetViewID(), reinterpret_cast(&bm), reinterpret_cast(&pMemento->GetViewSettings())); if (sc) return sc; sc = ScSelectNode(NodeId, /*bSelectExactNode*/ true); if (sc == ScFromMMC(IDS_NODE_NOT_FOUND)) { SC scNoTrace = sc; sc.Clear(); return scNoTrace; } if (sc) return sc; return sc; } /*+-------------------------------------------------------------------------* * CAMCView::OnSetFocus * * WM_SETFOCUS handler for CAMCView. *--------------------------------------------------------------------------*/ void CAMCView::OnSetFocus(CWnd* pOldWnd) { /* * try to deflect the activation to a child view; if we couldn't just punt */ if (!DeflectActivation (true, NULL)) CView::OnSetFocus(pOldWnd); } /*+-------------------------------------------------------------------------* * CAMCView::OnActivateView * * *--------------------------------------------------------------------------*/ void CAMCView::OnActivateView(BOOL bActivate, CView* pActivateView, CView* pDeactiveView) { /* * try to deflect the activation to a child view; if we couldn't just punt */ if (!DeflectActivation (bActivate, pDeactiveView)) CView::OnActivateView (bActivate, pActivateView, pDeactiveView); } /*+-------------------------------------------------------------------------* * CAMCView::DeflectActivation * * *--------------------------------------------------------------------------*/ bool CAMCView::DeflectActivation (BOOL fActivate, CView* pDeactivatingView) { if (fActivate) { CFrameWnd* pFrame = GetParentFrame(); if (pFrame == NULL) return (false); /* * first try to put the focus back on the deactivating view */ if (pDeactivatingView == NULL) pDeactivatingView = pFrame->GetActiveView(); if ((pDeactivatingView != NULL) && (pDeactivatingView != this)) { pFrame->SetActiveView (pDeactivatingView); return true; } /* * otherwise, deflect the activation to the scope view, if it's there */ CView* pScopeView = NULL; if (IsScopePaneVisible() && ((pScopeView = GetPaneView(ePane_ScopeTree)) != NULL)) { if (IsWindow (pScopeView->GetSafeHwnd())) { pFrame->SetActiveView (pScopeView); return (true); } } /* * finally, no scope view, try the result view */ CView* pResultView = GetResultView(); if (pResultView != NULL) { pFrame->SetActiveView(pResultView); return (true); } } return (false); } //+------------------------------------------------------------------------- // // Function: OnLButtonDown // // Synopsis: If mouse down in splitter area initiate view tracker to move // the splitter. (TrackerCallback function handles completion) //-------------------------------------------------------------------------- void CAMCView::OnLButtonDown(UINT nFlags, CPoint pt) { TRACE_METHOD(CAMCView, OnLButtonDown); // click in splitter bar? if (!m_rectVSplitter.PtInRect(pt)) return; // setup tracker information TRACKER_INFO trkinfo; // range is client area GetClientRect(trkinfo.rectArea); // bound by min size of panes trkinfo.rectBounds = trkinfo.rectArea; trkinfo.rectBounds.left += m_PaneInfo[ePane_ScopeTree].cxMin; trkinfo.rectBounds.right -= m_PaneInfo[ePane_Results].cxMin; // Current tracker is splitter rect trkinfo.rectTracker = trkinfo.rectArea; trkinfo.rectTracker.left = m_PaneInfo[ePane_ScopeTree].cx; trkinfo.rectTracker.right = trkinfo.rectTracker.left + m_cxSplitter; // Don't allow either pane to be hidden by dragging the splitter trkinfo.bAllowLeftHide = FALSE; trkinfo.bAllowRightHide = FALSE; // back ptr and completion callback trkinfo.pView = this; trkinfo.pCallback = TrackerCallback; // initiate tracking CViewTracker::StartTracking (&trkinfo); } void CAMCView::AdjustTracker (int cx, int cy) { // if user resizes window so that splitter becomes hidden, // move it like Explorer does. if (!IsScopePaneVisible()) return; // extra adjustment cx -= BORDERPADDING + 1; if (cx <= m_PaneInfo[ePane_ScopeTree].cx + m_cxSplitter) { int offset = m_PaneInfo[ePane_ScopeTree].cx + m_cxSplitter - cx; m_PaneInfo[ePane_ScopeTree].cx -= offset; m_PaneInfo[ePane_Results].cx -= offset; RedrawWindow(NULL, NULL, RDW_ALLCHILDREN | RDW_UPDATENOW); } } /*+-------------------------------------------------------------------------* * * CAMCView::ScAddDefaultColumns * * PURPOSE: * * RETURNS: * SC * *+-------------------------------------------------------------------------*/ SC CAMCView::ScAddDefaultColumns() { DECLARE_SC(sc, TEXT("CAMCView::ScAddDefaultColumns")); IHeaderCtrlPtr spHeaderCtrl = m_ViewData.m_spNodeManager; sc = ScCheckPointers(spHeaderCtrl, E_UNEXPECTED); if(sc) return sc; SetUsingDefColumns(TRUE); const int INDEX_MAX = 2; CString str[INDEX_MAX]; LoadString(str[0], IDS_NAME); LoadString(str[1], IDS_TYPE); int iMax = 0; int nMax = str[0].GetLength(); int nTemp = 0; for (int i=1; i < INDEX_MAX; i++) { nTemp = str[i].GetLength(); if (nTemp > nMax) { nMax = nTemp; iMax = i; } } LPOLESTR psz = new OLECHAR[nMax + 1]; int alWidths[INDEX_MAX] = {0, 0}; GetDefaultColumnWidths(alWidths); for (i=0; i < INDEX_MAX; i++) { // Bug 157408: remove the "Type" column for static nodes if (i == 1) continue; USES_CONVERSION; wcscpy(psz, T2COLE( (LPCTSTR) str[i] )); sc = spHeaderCtrl->InsertColumn(i, psz, LVCFMT_LEFT, alWidths[i]); if(sc) return sc; } delete [] psz; return sc; } SC CAMCView::ScInitDefListView(LPUNKNOWN pUnkResultsPane) { DECLARE_SC(sc, TEXT("CAMCView::ScInitDefListView")); if (!HasList()) return (sc = E_UNEXPECTED); sc = ScCheckPointers(pUnkResultsPane, m_ViewData.m_spResultData, E_UNEXPECTED); if(sc) return sc; m_ViewData.m_spResultData->ResetResultData(); return sc; } /*+-------------------------------------------------------------------------* * * CAMCView::ScOnSelectNode * * Most of this code was moved out of CAMCTreeView::OnSelectNode, as it is * more appropriate that this is executed by CAMCView. * * PURPOSE: Called when an item in the tree is selected. Does the following: * 1) Sets up the result pane to either a list, and OCX, or a web page. * 2) Sets the view options * 3) Sends a selection notification to the node. * 3) Adds a history entry if needed. * * PARAMETERS: * HNODE hNode : [IN]: The node that got selected. * BOOL & bAddSubFolders : [OUT]: Whether subfolders should be added to the list * * RETURNS: * SC * *+-------------------------------------------------------------------------*/ SC CAMCView::ScOnSelectNode(HNODE hNode, BOOL &bAddSubFolders) { DECLARE_SC(sc, TEXT("CAMCView::ScOnSelectNode")); USES_CONVERSION; // // Set the result pane // LPOLESTR pszResultPane = NULL; GUID guidTaskpad = GUID_NULL; int lViewMode = MMCLV_VIEWSTYLE_REPORT; // the default view mode //long lViewOptions = MMC_VIEW_OPTIONS_NONE; bool bUsingHistory = false; bool bRestoredView = false; INodeCallback* spNodeCallBack = GetNodeCallback(); sc = ScCheckPointers(spNodeCallBack, E_UNEXPECTED); if (sc) return sc; CHistoryList* pHistoryList = GetHistoryList(); sc = ScCheckPointers(pHistoryList, E_UNEXPECTED); if (sc) return sc; CResultViewType rvt; if (pHistoryList->GetNavigateState() == MMC_HISTORY_NAVIGATING) { // we're going "back" or "forward": // get Result pane stuff from history bUsingHistory = true; sc = pHistoryList->ScGetCurrentResultViewType(rvt, lViewMode, guidTaskpad); if (sc) return sc; sc = spNodeCallBack->RestoreResultView(hNode, rvt); if (sc) { TraceError(_T("Snapin failed on NCLBK_RESTORE_VIEW\n"), sc); sc.Clear(); // Compatible with 1.2 dont need this error. } if (sc.ToHr() == S_OK) bRestoredView = true; else rvt = CResultViewType(); // this restores rvt back to a nascent state. see Bug 176058. } // The view is not restored by history so ask snapin for view settings. if (! bRestoredView) { // get Result pane stuff from snapin GUID guid = GUID_NULL; sc = spNodeCallBack->GetResultPane(hNode, rvt, &guid); if (sc) return sc; // we cannot pass the guidTaskpad to GetResultPane directly, since // when it is navigation what causes the change, view settings are // not yet updated and thus the guid returned will not reflect the // current situation if (!bUsingHistory) guidTaskpad = guid; } // make sure we have a taskpad set (this will change the value of guidTaskpad if required) // This is required when pages referred from history are no longer available when returning // to the view (taskpad being deleted/default page being replaced/etc.) if (bUsingHistory) spNodeCallBack->SetTaskpad(hNode, &guidTaskpad); //SetViewOptions(lViewOptions); // at this stage, rvt contains all the result view information (excluding, as always the list view mode.) if (rvt.HasList()) { SetListViewMultiSelect( (rvt.GetListOptions() & RVTI_LIST_OPTIONS_MULTISELECT) == RVTI_LIST_OPTIONS_MULTISELECT); } sc = ScSetResultPane(hNode, rvt, lViewMode, bUsingHistory); if(sc) return sc; ::CoTaskMemFree(pszResultPane); // // Initialize default list view. // LPUNKNOWN pUnkResultsPane = GetPaneUnknown(CConsoleView::ePane_Results); if (rvt.HasList()) { sc = ScInitDefListView(pUnkResultsPane); if(sc) return sc; sc = ScCheckPointers(m_ViewData.m_spResultData, E_UNEXPECTED); if (sc) return sc; // this turns off list view redrawing. Should have some sort of smart object that automatically // turns redrawing on in its destructor. m_ViewData.m_spResultData->SetLoadMode(TRUE); // SetLoadMode(FALSE) is called by the caller, CAMCTreeView::OnSelectNode } // // Notify the new node that it is selected. // SELECTIONINFO selInfo; ZeroMemory(&selInfo, sizeof(selInfo)); selInfo.m_bScope = TRUE; selInfo.m_pView = pUnkResultsPane; if (rvt.HasWebBrowser()) { selInfo.m_bResultPaneIsWeb = TRUE; selInfo.m_lCookie = LVDATA_CUSTOMWEB; } else if (rvt.HasOCX()) { selInfo.m_bResultPaneIsOCX = TRUE; selInfo.m_lCookie = LVDATA_CUSTOMOCX; } // Increment and save local copy of nesting level counter. This counter serves // two purposes. First, it allows AMCView to inhibit inserting scope items in // the result pane during a select by checking the IsSelectingNode method. // Without this test the scope items would appear twice because all the scope // items are added to the result pane at the end of this method. // Second, during the following ScNotifySelect call the snap-in could do another // select which would re-enter this method. In that case, only the innermost // call to this method should do the post-notify processing. The outer calls // should just exit, returning S_FALSE instead of S_OK. int nMyNestLevel = ++m_nSelectNestLevel; // collect / manage view tabs sc = ScAddFolderTabs( hNode, guidTaskpad ); if (sc) return sc; try { sc = ScNotifySelect ( spNodeCallBack, hNode, false /*fMultiSelect*/, true, &selInfo); if (sc) sc.TraceAndClear(); // ignore & continue; } catch(...) { // if first call to Select, reset level to zero before leaving if (nMyNestLevel == 1) m_nSelectNestLevel = 0; throw; } // if the local call level does not match the shared call level then this // method was reentered during the ScNotifySelect. In that case don't finish // the processing because the node and/or view may have changed. // Be sure to reset the call level to zero if this is the outermost call. ASSERT(nMyNestLevel <= m_nSelectNestLevel); BOOL bDoProcessing = (nMyNestLevel == m_nSelectNestLevel); if (nMyNestLevel == 1) m_nSelectNestLevel = 0; if (!bDoProcessing) return S_FALSE; // // If the result pane is the def-LV, ensure that there are headers. // If not add the default ones // if (rvt.HasList()) { SetUsingDefColumns(FALSE); // Get ptr to ResultPane. IMMCListViewPtr pMMCLV = pUnkResultsPane; sc = ScCheckPointers(pMMCLV, E_UNEXPECTED); if (sc) return sc; int nCols = 0; sc = pMMCLV->GetColumnCount(&nCols); if (sc) return sc; if(0 == nCols) { sc = ScAddDefaultColumns(); if(sc) return sc; IResultDataPrivatePtr& pResultDataPrivate = m_ViewData.m_spResultData; sc = ScCheckPointers(pResultDataPrivate, E_UNEXPECTED); if (sc) return sc; long lViewMode = GetViewMode(); // If default mode is filtered and new node doesn't // support that, use report mode instead if (lViewMode == MMCLV_VIEWSTYLE_FILTERED && !(rvt.GetListOptions() & RVTI_LIST_OPTIONS_FILTERED)) lViewMode = LVS_REPORT; // you've got to change the mode before you change the // style: style doesn't contain the "quickfilter" bit. pResultDataPrivate->SetViewMode (lViewMode); long style = GetDefaultListViewStyle(); if (style != 0) { sc = pResultDataPrivate->SetListStyle(style); if (sc) return sc; } } } // // Show the static scope items in the result pane, // but not for a virtual list view, or views specifically // marked that they don't want scope items in the result view // if (rvt.HasList() && !(rvt.GetListOptions() & RVTI_LIST_OPTIONS_OWNERDATALIST) && !(rvt.GetListOptions() & RVTI_LIST_OPTIONS_EXCLUDE_SCOPE_ITEMS_FROM_LIST)) { bAddSubFolders = TRUE; } // Update window title. sc = ScUpdateWindowTitle(); if(sc) return sc; // fire event to script sc = ScFireEvent(CAMCViewObserver::ScOnViewChange, this, hNode); if (sc) return sc; return sc; } /*+-------------------------------------------------------------------------* * * CAMCView::ScSetResultPane * * PURPOSE: Sets the result pane to the specified configuration. * * PARAMETERS: * HNODE hNode : * CResultViewType rvt : * long lViewOptions : * bool bUsingHistory : * * RETURNS: * SC * *+-------------------------------------------------------------------------*/ SC CAMCView::ScSetResultPane(HNODE hNode, CResultViewType rvt, int viewMode, bool bUsingHistory) { DECLARE_SC(sc, TEXT("CAMCView::SetResultPane")); m_ViewData.SetResultViewType(rvt); if(rvt.HasList()) { sc = ScAttachListViewAsResultPane(); if(sc) return sc; } else if(rvt.HasWebBrowser()) { sc = ScAttachWebViewAsResultPane(); if(sc) return sc; } else if(rvt.HasOCX()) { sc = ScAttachOCXAsResultPane(hNode); if(sc) return sc; } else { ASSERT(0 && "Should not come here!!"); return (sc = E_UNEXPECTED); } // show the toolbars if(GetStdToolbar() != NULL) // may be NULL at startup. { sc = GetStdToolbar()->ScShowStdBar(true); if(sc) return sc; } // if we haven't gotten here using history, add a history entry. if(!bUsingHistory) { GUID guidTaskpad = GUID_NULL; GetTaskpadID(guidTaskpad); sc = m_pHistoryList->ScAddEntry(rvt, m_nViewMode, guidTaskpad); if(sc) return sc; } // if we have a node manager, tell it what the result pane is. if(m_ViewData.m_spNodeManager) { LPUNKNOWN pUnkResultsPane = GetPaneUnknown(CConsoleView::ePane_Results); m_ViewData.m_spNodeManager->SetResultView(pUnkResultsPane); } return sc; } BOOL CAMCView::CreateListCtrl(int nID, CCreateContext* pContext) { TRACE_METHOD(CAMCView, CreateListCtrl); ASSERT(m_pListCtrl == NULL); CComObject *pLV = NULL; CComObject::CreateInstance( &pLV ); if (pLV == NULL) { ASSERT(0 && "Unable to create list control"); return FALSE; } // we assign directly - implicit cast works, since we have a type derived from the one we need m_pListCtrl = pLV; // we intend to hold a reference, so do addref here (CreateInstance creates w/ 0 reffs) m_pListCtrl->AddRef(); if (!m_pListCtrl->Create (WS_VISIBLE | WS_CHILD, g_rectEmpty, this, nID, pContext)) { ASSERT(0 && "Unable to create list control"); return FALSE; } m_pListCtrl->SetViewMode (m_nViewMode); SC SC = m_pListCtrl->ScInitialize(); // intialize the list control return TRUE; } void CAMCView::SetListViewOptions(DWORD dwListOptions) { TRACE_METHOD(CAMCView, SetListViewOptions); bool bVirtual = (dwListOptions & RVTI_LIST_OPTIONS_OWNERDATALIST) ? true : false; ASSERT(m_pListCtrl != NULL); CDocument* pDoc = GetDocument(); ASSERT(pDoc != NULL); // If change to/from virtual list, change list mode if (IsVirtualList() != bVirtual) { m_ViewData.SetVirtualList (bVirtual); pDoc->RemoveView(m_pListCtrl->GetListViewPtr()); m_pListCtrl->SetVirtualMode(bVirtual); pDoc->AddView(m_pListCtrl->GetListViewPtr()); m_ViewData.m_hwndListCtrl = m_pListCtrl->GetListViewHWND(); } // if snapin doesn't support filtering make sure it's off if (!(GetListOptions() & RVTI_LIST_OPTIONS_FILTERED) && m_pListCtrl->GetViewMode() == MMCLV_VIEWSTYLE_FILTERED) { m_pListCtrl->SetViewMode(LVS_REPORT); } } /*+-------------------------------------------------------------------------* * * CAMCView::ScAttachListViewAsResultPane * * PURPOSE: Sets up the list view as the result pane. * * PARAMETERS: NONE * * RETURNS: * SC * *+-------------------------------------------------------------------------*/ SC CAMCView::ScAttachListViewAsResultPane() { DECLARE_SC(sc, TEXT("CAMCView::ScAttachListViewAsResultPane")); bool bVirtual = (GetListOptions() & RVTI_LIST_OPTIONS_OWNERDATALIST) ? true : false; GUID guidTaskpad; GetTaskpadID(guidTaskpad); sc = ScCheckPointers(m_pListCtrl, E_UNEXPECTED); if(sc) return sc; CDocument* pDoc = GetDocument(); ASSERT(pDoc != NULL); // If change to/from virtual list, change list mode if (IsVirtualList() != bVirtual) { m_ViewData.SetVirtualList (bVirtual); pDoc->RemoveView(m_pListCtrl->GetListViewPtr()); m_pListCtrl->SetVirtualMode(bVirtual); pDoc->AddView(m_pListCtrl->GetListViewPtr()); m_ViewData.m_hwndListCtrl = m_pListCtrl->GetListViewHWND(); } // if snapin doesn't support filtering make sure it's off if (!(GetListOptions() & RVTI_LIST_OPTIONS_FILTERED) && m_pListCtrl->GetViewMode() == MMCLV_VIEWSTYLE_FILTERED) { m_pListCtrl->SetViewMode(LVS_REPORT); } ShowResultPane(m_pListCtrl->GetListViewPtr(), uiClientEdge); return sc; } /*+-------------------------------------------------------------------------* * * CAMCView::ScAttachWebViewAsResultPane * * PURPOSE: * * PARAMETERS: NONE * * RETURNS: * void * *+-------------------------------------------------------------------------*/ SC CAMCView::ScAttachWebViewAsResultPane() { DECLARE_SC(sc, TEXT("CAMCView::ScAttachWebViewAsResultPane")); // if we were in ListPad-mode, undo that. if (m_pListCtrl->IsListPad()) { sc = m_pListCtrl->ScAttachToListPad (NULL, NULL); if(sc) return sc; } // The control is created on demand. This prevents IE from loading when unnecessary // and reduces startup time. if (m_pWebViewCtrl == NULL) CreateView (IDC_WebViewCtrl); sc = ScCheckPointers(m_pWebViewCtrl, E_UNEXPECTED); if(sc) return sc; // Force web control to update its palette SendMessage(WM_QUERYNEWPALETTE); ShowResultPane(m_pWebViewCtrl, uiNoClientEdge); return sc; } /*+-------------------------------------------------------------------------* * * CAMCView::ScAttachOCXAsResultPane * * PURPOSE: * * PARAMETERS: * LPCTSTR pszResultPane : * * RETURNS: * SC * *+-------------------------------------------------------------------------*/ SC CAMCView::ScAttachOCXAsResultPane(HNODE hNode) { DECLARE_SC(sc, TEXT("CAMCView::ScAttachOCXAsResultPane")); USES_CONVERSION; ASSERT(m_pListCtrl != NULL); if (m_pOCXHostView == NULL) CreateView (IDC_OCXHostView); sc = ScCheckPointers(m_pOCXHostView); if(sc) return sc; sc = m_pOCXHostView->ScSetControl(hNode, m_ViewData.m_rvt, GetNodeCallback()); if(sc) return sc; ShowResultPane(m_pOCXHostView, uiClientEdge); return sc; } /*+-------------------------------------------------------------------------* * CAMCView::ScApplyViewExtension * * Applies a view extension to the current view. pszURL specifies the * URL of the HTML to load as the view extension. If pszURL is NULL or * empty, the view extension is removed. * * This method will force a layout of the view if it is required. *--------------------------------------------------------------------------*/ SC CAMCView::ScApplyViewExtension ( LPCTSTR pszURL) /* I:URL to use, NULL to remove */ { DECLARE_SC (sc, _T("CAMCView::ScApplyViewExtension")); /* * assume no view extension */ bool fViewWasExtended = m_fViewExtended; m_fViewExtended = false; /* * if we're given a URL with which to extend the view, turn on the extension */ if ((pszURL != NULL) && (*pszURL != 0)) { /* * if we don't have a web control for the view extension yet, create one */ if (m_pViewExtensionCtrl == NULL) CreateView (IDC_ViewExtensionView); sc = ScCheckPointers (m_pViewExtensionCtrl, E_FAIL); if (sc) return (sc); m_fViewExtended = true; // hide the hosted window initially CWnd *pwndHosted = GetPaneView(ePane_Results); sc = ScCheckPointers(pwndHosted); if(sc) return sc; pwndHosted->ShowWindow(SW_HIDE); RecalcLayout(); // do this BEFORE calling Navigate, which may resize the above rectangle via the mmcview behavior // navigate to the requested URL m_pViewExtensionCtrl->Navigate (pszURL, NULL); } else if (fViewWasExtended && (m_pViewExtensionCtrl != NULL)) { /* * Bug 96948: If we've got an extension and we're currently extending * the view, navigate the view extension's web browser to an empty page * so the behavior that resizes the hosted result frame is disabled */ CStr strEmptyPage; sc = ScGetPageBreakURL (strEmptyPage); if (sc) return (sc); m_pViewExtensionCtrl->Navigate (strEmptyPage, NULL); if(fViewWasExtended) DeferRecalcLayout(); } return (sc); } /*+-------------------------------------------------------------------------* * * CAMCView::ShowResultPane * * PURPOSE: * * PARAMETERS: * CView* pNewView : * EUIStyleType nStyle : * * RETURNS: * void * *+-------------------------------------------------------------------------*/ void CAMCView::ShowResultPane(CView* pNewView, EUIStyleType nStyle) { TRACE_METHOD(CAMCView, ShowResultPane); ASSERT(pNewView != NULL); CView* pCurrentView = GetPaneView(ePane_Results); bool bActive = (GetParentFrame()->GetActiveView() == pCurrentView); // Check to see if we need to swap the CWnd control in the result pane if (pNewView != pCurrentView) { HWND hwndCurrentView = pCurrentView->GetSafeHwnd(); if (IsWindow (hwndCurrentView)) { pCurrentView->ShowWindow(SW_HIDE); // Note: We are directly hiding the window for cases that controls // don't hide during a DoVerb(OLEIVERB_HIDE). Actually, this does a // hide on all windows. It's too hard at this point to optimize the code // for doing this with an OLE control only. ::ShowWindow(hwndCurrentView, SW_HIDE); } SetPane(ePane_Results, pNewView, nStyle); RecalcLayout(); // if other pane was active, make the new one active if ((pCurrentView != NULL) && bActive) { // make sure the new window is visible pNewView->ShowWindow(SW_SHOW); GetParentFrame()->SetActiveView(pNewView); } } } //+------------------------------------------------------------------------- // // Function: GetPaneInfo // // Synopsis: Get information about a particular pane // //-------------------------------------------------------------------------- void CAMCView::GetPaneInfo(ViewPane ePane, int* pcxCur, int* pcxMin) { TRACE_METHOD(CAMCView, GetPaneInfo); ASSERT_VALID(this); if (!IsValidPane (ePane)) { ASSERT (false && "CAMCView::GetPaneInfo: Invalid pane specifier"); return; } if ((pcxCur==NULL) || (pcxMin==NULL)) { ASSERT(FALSE); // One or more of the args is wrong return; } // REVIEW fix enum *pcxCur = m_PaneInfo[ePane].cx; *pcxMin = m_PaneInfo[ePane].cxMin; } //+------------------------------------------------------------------------- // // Function: SetPaneInfo // // Synopsis: Set information about a particular pane // //-------------------------------------------------------------------------- void CAMCView::SetPaneInfo(ViewPane ePane, int cxCur, int cxMin) { TRACE_METHOD(CAMCView, SetPaneInfo); ASSERT_VALID(this); if (!IsValidPane (ePane)) { ASSERT (false && "CAMCView::SetPaneInfo: Invalid pane specifier"); return; } if (cxCur < 0 || cxMin < 0) { ASSERT(FALSE); // One or more of the args is wrong return; } m_PaneInfo[ePane].cx = cxCur; m_PaneInfo[ePane].cxMin = cxMin; } //+------------------------------------------------------------------------- // // Function: GetPaneView // // Synopsis: Returns a pointer to CView for a particular pane // //-------------------------------------------------------------------------- CView* CAMCView::GetPaneView(ViewPane ePane) { TRACE_METHOD(CAMCView, GetPaneView); ASSERT_VALID(this); if (!IsValidPane (ePane)) { ASSERT (false && "CAMCView::GetPaneView: Invalid pane specifier"); return (NULL); } return (m_PaneInfo[ePane].pView); } /*+-------------------------------------------------------------------------* * CAMCView::GetResultView * * *--------------------------------------------------------------------------*/ CView* CAMCView::GetResultView() const { CView* pView = NULL; // may need changes here - assumes the different types are independent. if(HasWebBrowser()) pView = m_pWebViewCtrl; else if(HasList()) pView = m_pListCtrl->GetListViewPtr(); else if(HasOCX()) pView = m_pOCXHostView; ASSERT (pView != NULL); return (pView); } //+------------------------------------------------------------------------- // // Function: GetPaneUnknown // // Synopsis: Returns a pointer to the Unknown // //-------------------------------------------------------------------------- LPUNKNOWN CAMCView::GetPaneUnknown(ViewPane ePane) { TRACE_METHOD(CAMCView, GetPaneUnknown); ASSERT_VALID(this); if (!IsValidPane (ePane)) { ASSERT (false && "CAMCView::GetPaneUnknown: Invalid pane specifier"); return (NULL); } if (!IsWindow (GetPaneView(ePane)->GetSafeHwnd())) { ASSERT(FALSE); // Invalid pane element return NULL; } if (HasWebBrowser() && m_pWebViewCtrl != NULL) { return m_pWebViewCtrl->GetIUnknown(); } else if( HasList() && m_pListCtrl != NULL ) { IUnknownPtr spUnk = m_pListCtrl; LPUNKNOWN pUnk = spUnk; return pUnk; } else if (HasOCX() && m_pOCXHostView != NULL) { ASSERT(GetPaneView (ePane)); return m_pOCXHostView->GetIUnknown(); } else { // result pane not initialized yet. This is usually because we are in between a deselect and a // subsequent reselect. return NULL; } } //+------------------------------------------------------------------------- // // Function: SetPane // // Synopsis: Set a CWnd pointer for a particular pane and other information // //-------------------------------------------------------------------------- void CAMCView::SetPane(ViewPane ePane, CView* pView, EUIStyleType nStyle) { TRACE_METHOD(CAMCView, SetPane); ASSERT_VALID(this); if (!IsValidPane (ePane)) { ASSERT (false && "CAMCView::SetPane: Invalid pane specifier"); return; } if (pView==NULL || !IsWindow(*pView)) { ASSERT(FALSE); // Invalid arg return; } m_PaneInfo[ePane].pView = pView; // Ensure that the window is visible & at the top of the Z-order. pView->SetWindowPos(&wndTop, 0, 0, 0, 0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE); // Note: We are directly showing the window for cases that controls // don't show during a DoVerb(OLEIVERB_SHOW). Actually, this does a // show on all windows. It's too hard at this point to optimize the code // for doing this with an OLE control only. ::ShowWindow(pView->m_hWnd, SW_SHOW); } // // Other Methods // /*+-------------------------------------------------------------------------* * CAMCView::ScShowScopePane * * Shows or hides the scope pane in the current view. If fForce is true, * we'll go through the motions of showing the scope pane even if we think * its visibility state wouldn't change. *--------------------------------------------------------------------------*/ SC CAMCView::ScShowScopePane (bool fShow, bool fForce /* =false */) { DECLARE_SC (sc, _T("CAMCView::ScShowScopePane")); /* * if the current visibility state doesn't match the requested state, * change the current state to match the requested state */ if (fForce || (IsScopePaneVisible() != fShow)) { /* * If MMC_NW_OPTION_NOSCOPEPANE was specified when this view was * created, we can't display a scope pane. If we're asked to, fail. */ if (fShow && !IsScopePaneAllowed()) return (sc = E_FAIL); /* * if the scope pane is being hidden and it contained the active * view, activate the result pane */ if (!fShow && (GetFocusedPane() == ePane_ScopeTree)) ScSetFocusToResultPane (); // ignore errors here /* * remember the new state */ SetScopePaneVisible (fShow); /* * Don't defer this layout. This may be called by the Customize View * dialog which wants to see its updates in real time. It will be * sitting in a modal message loop so we won't get a chance to precess * our idle task. */ RecalcLayout(); /* * the console has changed */ SetDirty(); } /* * put the scope pane toolbar button in the right state */ CStandardToolbar* pStdToolbar = GetStdToolbar(); sc = ScCheckPointers(pStdToolbar, E_UNEXPECTED); if (sc) return (sc); CAMCDoc *pDoc = GetDocument(); sc = ScCheckPointers(pDoc, E_UNEXPECTED); if (sc) return sc; bool bEnableScopePaneButton = (IsScopePaneAllowed() && pDoc->AllowViewCustomization()); // IF view customization is not allowed then "Show/Hide Consolte tree" button should be hidden. if (bEnableScopePaneButton) { /* * the scope pane is permitted; show and check the toolbar * button if the scope pane is visible, show and uncheck the * toolbar button if the scope pane is hidden */ sc = pStdToolbar->ScCheckScopePaneBtn (fShow); if (sc) return (sc); } else { /* * no scope pane permitted, hide the scope pane button */ sc = pStdToolbar->ScEnableScopePaneBtn (bEnableScopePaneButton); if (sc) return (sc); } /* * if we get to this point, the current state should match the requested state */ ASSERT (IsScopePaneVisible() == fShow); return (sc); } /*+-------------------------------------------------------------------------* * CAMCView::CDeferredLayout::CDeferredLayout * * Constructs a CAMCView::CDeferredLayout::CDeferredLayout. Note that if * an error occurs during construction, an SC exception will be thrown. *--------------------------------------------------------------------------*/ CAMCView::CDeferredLayout::CDeferredLayout (CAMCView* pAMCView) : m_atomTask (AddAtom (_T("CAMCView::CDeferredLayout"))) { DECLARE_SC (sc, _T("CAMCView::CDeferredLayout::CDeferredLayout")); if (!Attach (pAMCView)) (sc = E_INVALIDARG).Throw(); } /*+-------------------------------------------------------------------------* * CAMCView::CDeferredLayout::~CDeferredLayout * * *--------------------------------------------------------------------------*/ CAMCView::CDeferredLayout::~CDeferredLayout() { DeleteAtom (m_atomTask); } /*+-------------------------------------------------------------------------* * CAMCView::CDeferredLayout::ScDoWork * * *--------------------------------------------------------------------------*/ SC CAMCView::CDeferredLayout::ScDoWork() { WindowCollection::iterator it; WindowCollection::iterator itEnd = m_WindowsToLayout.end(); for (it = m_WindowsToLayout.begin(); it != itEnd; ++it) { CWnd* pwnd = CWnd::FromHandlePermanent (*it); CAMCView* pAMCView = dynamic_cast(pwnd); if (pAMCView != NULL) { pAMCView->RecalcLayout(); pAMCView->Invalidate(); pAMCView->UpdateWindow(); } } return (S_OK); } /*+-------------------------------------------------------------------------* * CAMCView::CDeferredLayout::ScGetTaskID * * *--------------------------------------------------------------------------*/ SC CAMCView::CDeferredLayout::ScGetTaskID(ATOM* pID) { *pID = m_atomTask; return (S_OK); } /*+-------------------------------------------------------------------------* * CAMCView::CDeferredLayout::ScMerge * * *--------------------------------------------------------------------------*/ SC CAMCView::CDeferredLayout::ScMerge(CIdleTask* pitMergeFrom) { CDeferredLayout* pdlMergeFrom = dynamic_cast(pitMergeFrom); ASSERT (pdlMergeFrom != NULL); /* * copy the windows from the merge-from task into the merge-to task */ WindowCollection::iterator it; WindowCollection::iterator itEnd = pdlMergeFrom->m_WindowsToLayout.end(); for (it = pdlMergeFrom->m_WindowsToLayout.begin(); it != itEnd; ++it) { m_WindowsToLayout.insert (*it); } return (S_OK); } /*+-------------------------------------------------------------------------* * CAMCView::CDeferredLayout::Attach * * *--------------------------------------------------------------------------*/ bool CAMCView::CDeferredLayout::Attach (CAMCView* pAMCView) { ASSERT (pAMCView != NULL); HWND hwndAMCView = pAMCView->GetSafeHwnd(); if (hwndAMCView != NULL) m_WindowsToLayout.insert (hwndAMCView); return (hwndAMCView != NULL); } /*+-------------------------------------------------------------------------* * CAMCView::DeferRecalcLayout * * *--------------------------------------------------------------------------*/ void CAMCView::DeferRecalcLayout (bool fUseIdleTaskQueue /* =true */, bool bArrangeIcons /* = false*/) { DECLARE_SC (sc, _T("CAMCView::DeferRecalcLayout")); if (fUseIdleTaskQueue) { Trace (tagLayout, _T("CAMCView::DeferRecalcLayout (idle task)")); try { /* * get the idle task manager */ CIdleTaskQueue* pIdleTaskQueue = AMCGetIdleTaskQueue(); if (pIdleTaskQueue == NULL) (sc = E_UNEXPECTED).Throw(); /* * create the deferred layout task */ CAutoPtr spDeferredLayout (new CDeferredLayout (this)); if (spDeferredLayout == NULL) (sc = E_OUTOFMEMORY).Throw(); /* * put the task in the queue, which will take ownership of it */ sc = pIdleTaskQueue->ScPushTask (spDeferredLayout, ePriority_Normal); if (sc) sc.Throw(); /* * if we get here, the idle task queue owns the idle task, so * we can detach it from our smart pointer */ spDeferredLayout.Detach(); /* * jiggle the message pump so that it wakes up and checks idle tasks */ PostMessage (WM_NULL); } catch (SC& scCaught) { /* * if we failed to enqueue our deferred layout task, do the layout now */ RecalcLayout(); } } /* * post a message instead of using the idle task queue */ else { /* * we only need to post a message if there's not one in the queue * already */ MSG msg; if (!PeekMessage (&msg, GetSafeHwnd(), m_nDeferRecalcLayoutMsg, m_nDeferRecalcLayoutMsg, PM_NOREMOVE)) { PostMessage (m_nDeferRecalcLayoutMsg, bArrangeIcons); Trace (tagLayout, _T("CAMCView::DeferRecalcLayout (posted message)")); } else { Trace (tagLayout, _T("CAMCView::DeferRecalcLayout (skipping redundant posted message)")); } } } //+------------------------------------------------------------------------- // // Function: RecalcLayout // // Synopsis: Calls methods to layout control and paint borders and splitters. // //-------------------------------------------------------------------------- void CAMCView::RecalcLayout(void) { TRACE_METHOD(CAMCView, RecalcLayout); ASSERT_VALID(this); Trace (tagLayout, _T("CAMCView::RecalcLayout")); /* * short out if the client rect is empty */ CRect rectClient; GetClientRect (rectClient); if (rectClient.IsRectEmpty()) return; CDeferWindowPos dwp (10); LayoutScopePane (dwp, rectClient); LayoutResultPane (dwp, rectClient); /* * CDeferWindowPos dtor will position the windows */ } /*+-------------------------------------------------------------------------* * CAMCView::LayoutScopePane * * *--------------------------------------------------------------------------*/ void CAMCView::LayoutScopePane (CDeferWindowPos& dwp, CRect& rectRemaining) { int cxScope = 0; // If a scope pane is visible if (IsScopePaneVisible()) { int cxTotal = rectRemaining.Width(); // get the current width cxScope = m_PaneInfo[ePane_ScopeTree].cx; // if not determined yet, set scope pane width to 1/4 of window if (cxScope == -1) cxScope = cxTotal / 3; /* * Bug 86718: Make sure we leave at least the minimum width * for the result pane, which is always visible */ cxScope = std::_MIN (cxScope, cxTotal - m_PaneInfo[ePane_Results].cxMin - m_cxSplitter); /* * remember the scope pane width */ m_PaneInfo[ePane_ScopeTree].cx = cxScope; } CRect rectScope = rectRemaining; rectScope.right = rectScope.left + cxScope; /* * remove space used by the scope pane * (and splitter) from the remaining area */ if (IsScopePaneVisible()) { m_rectVSplitter.left = rectScope.right; m_rectVSplitter.top = rectScope.top; m_rectVSplitter.right = rectScope.right + m_cxSplitter; m_rectVSplitter.bottom = rectScope.bottom; rectRemaining.left = m_rectVSplitter.right; /* * Inflate the splitter rect to give a little bigger hot area. * We need to do this logically instead of physically (i.e. instead * of increasing m_cxSplitter) to keep the visuals right. */ m_rectVSplitter.InflateRect (GetSystemMetrics (SM_CXEDGE), 0); } else m_rectVSplitter = g_rectEmpty; /* * scope pane */ dwp.AddWindow (GetPaneView(ePane_ScopeTree), rectScope, SWP_NOZORDER | SWP_NOACTIVATE | (IsScopePaneVisible() ? SWP_SHOWWINDOW : SWP_HIDEWINDOW)); } /*+-------------------------------------------------------------------------* * CAMCView::LayoutResultPane * * Lays out the children of the result pane. *--------------------------------------------------------------------------*/ void CAMCView::LayoutResultPane (CDeferWindowPos& dwp, CRect& rectRemaining) { /* * Note: the order of these calls to LayoutXxx is *critical*. */ LayoutResultDescriptionBar (dwp, rectRemaining); LayoutResultFolderTabView (dwp, rectRemaining); m_rectResultFrame = rectRemaining; LayoutResultView (dwp, rectRemaining); /* * remember the final width of the result pane in m_PaneInfo[ePane_Results].cx */ m_PaneInfo[ePane_Results].cx = m_rectResultFrame.Width(); } /*+-------------------------------------------------------------------------* * CAMCView::LayoutResultFolderTabView * * *--------------------------------------------------------------------------*/ void CAMCView::LayoutResultFolderTabView (CDeferWindowPos& dwp, CRect& rectRemaining) { DECLARE_SC(sc, TEXT("CAMCView::LayoutResultFolderTabView")); sc = ScCheckPointers(m_pResultFolderTabView, E_UNEXPECTED); if (sc) return; // layout the folder tab control - always on top. bool bVisible = AreTaskpadTabsAllowed() && m_pResultFolderTabView->IsVisible(); CRect rectFolder; if (bVisible) m_pResultFolderTabView->Layout(rectRemaining, rectFolder); else rectFolder = g_rectEmpty; DWORD dwPosFlags = SWP_NOZORDER | SWP_NOACTIVATE | (bVisible ? SWP_SHOWWINDOW : SWP_HIDEWINDOW); dwp.AddWindow (m_pResultFolderTabView, rectFolder, dwPosFlags); } /*+-------------------------------------------------------------------------* * CAMCView::LayoutResultDescriptionBar * * *--------------------------------------------------------------------------*/ void CAMCView::LayoutResultDescriptionBar (CDeferWindowPos& dwp, CRect& rectRemaining) { DWORD dwPosFlags = SWP_NOZORDER | SWP_NOACTIVATE; CRect rectT = rectRemaining; if (IsDescBarVisible() && !rectT.IsRectEmpty()) { rectT.bottom = rectT.top + m_RightDescCtrl.GetHeight(); rectRemaining.top = rectT.bottom; dwPosFlags |= SWP_SHOWWINDOW; } else { dwPosFlags |= SWP_HIDEWINDOW; } dwp.AddWindow (&m_RightDescCtrl, rectT, dwPosFlags); } /*+-------------------------------------------------------------------------* * CAMCView::LayoutResultView * * *--------------------------------------------------------------------------*/ void CAMCView::LayoutResultView (CDeferWindowPos& dwp, const CRect& rectRemaining) { DECLARE_SC (sc, _T("CAMCView::LayoutResultView")); Trace (tagLayout, _T("CAMCView::LayoutResultView")); CWnd* pwndResult = GetPaneView(ePane_Results); /* * we should never think the view is extended if we don't also have * a view extension web host control */ ASSERT (!(m_fViewExtended && (m_pViewExtensionCtrl == NULL))); /* * if it exists, the view extension control is always at the bottom of * the Z-order, and visible if the view is being extended */ if(m_pViewExtensionCtrl != NULL) { /* * note no SWP_NOZORDER */ DWORD dwPosFlags = SWP_NOACTIVATE | ((m_fViewExtended) ? SWP_SHOWWINDOW : SWP_HIDEWINDOW); dwp.AddWindow (m_pViewExtensionCtrl, rectRemaining, dwPosFlags, &CWnd::wndBottom); } /* * If the view's not extended, show or hide the result window based on * whether there's any room left in the positioning rectangle. (If the * view is extended, the result window will have been hidden when the * view extension was applied (in ScApplyViewExtension), and possibly * redisplayed by the extension in ScSetViewExtensionFrame.) */ if (!m_fViewExtended) { DWORD dwFlags = SWP_NOZORDER | SWP_NOACTIVATE | (rectRemaining.IsRectEmpty() ? SWP_HIDEWINDOW : SWP_SHOWWINDOW); dwp.AddWindow (pwndResult, rectRemaining, dwFlags); } /* * lists in extended views and listpads don't get a border, all others do */ if (HasListOrListPad()) { if (HasListPad()) { sc = ScCheckPointers (m_pListCtrl, E_UNEXPECTED); if (sc) return; CWnd* pwndListCtrl = m_pListCtrl->GetListViewPtr(); sc = ScCheckPointers (pwndListCtrl, E_UNEXPECTED); if (sc) return; pwndListCtrl->ModifyStyleEx (WS_EX_CLIENTEDGE, 0, SWP_FRAMECHANGED); // remove border } else if (m_fViewExtended) pwndResult->ModifyStyleEx (WS_EX_CLIENTEDGE, 0, SWP_FRAMECHANGED); // remove border else pwndResult->ModifyStyleEx (0, WS_EX_CLIENTEDGE, SWP_FRAMECHANGED); // add border } } // // Tracking and and hit testing methods // //+------------------------------------------------------------------------- // // Function: HitTestPane // // Synopsis: Test which pane contains the point arg, or ePane_None for // the splitter bar // //-------------------------------------------------------------------------- int CAMCView::HitTestPane(CPoint& point) { TRACE_METHOD(CAMCView, HitTestPane); if (PtInWindow(m_pTreeCtrl, point)) return ePane_ScopeTree; if (m_PaneInfo[ePane_Results].pView && PtInWindow(m_PaneInfo[ePane_Results].pView, point)) return ePane_Results; return ePane_None; } HNODE CAMCView::GetSelectedNode(void) { AFX_MANAGE_STATE (AfxGetAppModuleState()); TRACE_METHOD(CAMCView, GetSelectedNode); // When the tree is empty we don't want to AV HTREEITEM hti = m_pTreeCtrl->GetSelectedItem(); if (hti == NULL) return NULL; HNODE hNode = m_pTreeCtrl->GetItemNode(hti); return hNode; } HNODE CAMCView::GetRootNode(void) { TRACE_METHOD(CAMCView, GetSelectedNode); // When the tree is empty we don't want to AV HTREEITEM hti = m_pTreeCtrl->GetRootItem(); if (hti == NULL) return NULL; HNODE hNode = m_pTreeCtrl->GetItemNode(hti); return hNode; } /*+-------------------------------------------------------------------------* * * CAMCView::ScUpdateWindowTitle * * PURPOSE: Updates the window title and informs observers about the change. * * RETURNS: * SC * *+-------------------------------------------------------------------------*/ SC CAMCView::ScUpdateWindowTitle() { DECLARE_SC(sc, TEXT("CAMCView::ScUpdateWindowTitle")); CChildFrame* pFrame = GetParentFrame(); sc = ScCheckPointers(pFrame); if(sc) return sc; if (pFrame) pFrame->OnUpdateFrameTitle(TRUE); sc = ScFireEvent(CAMCViewObserver::ScOnViewTitleChanged, this); return sc; } BOOL CAMCView::RenameItem(HNODE hNode, BOOL bScopeItem, MMC_COOKIE lResultItemCookie, LPWSTR pszText, LRESULT* pResult) { DECLARE_SC(sc, TEXT("CAMCView::RenameItem")); sc = S_FALSE; SELECTIONINFO selInfo; ZeroMemory(&selInfo, sizeof(selInfo)); selInfo.m_bScope = bScopeItem; selInfo.m_lCookie = lResultItemCookie; if (pszText != NULL) { USES_CONVERSION; /* * Bug 322184: The snap-in may throw up some UI on this notification. * The list or tree may have captured the mouse to look for a drag, * which will interfere with the snap-in's UI. Release the capture * during the callback and put it back when we're done. */ HWND hwndCapture = ::SetCapture (NULL); sc = m_spNodeCallback->Notify(hNode, NCLBK_RENAME, reinterpret_cast(&selInfo), reinterpret_cast(pszText)); /* * put the capture back */ ::SetCapture (hwndCapture); } *pResult = (sc == SC(S_OK)); if (*pResult) { sc = ScUpdateWindowTitle(); if(sc) sc.TraceAndClear(); } return TRUE; } BOOL CAMCView::DispatchListCtrlNotificationMsg(LPARAM lParam, LRESULT* pResult) { DECLARE_SC(sc, TEXT("CAMCView::DispatchListCtrlNotificationMsg")); TRACE_METHOD(CAMCView, DispatchListCtrlNotificationMsg); NM_LISTVIEW *pNm = reinterpret_cast(lParam); BOOL bReturn = TRUE; switch (pNm->hdr.code) { case NM_RCLICK: bReturn = FALSE; // In case of right click send the select notification to the snapin // but return FALSE so that message is further processed to display // context menu. // Fall thro into NM_CLICK case NM_CLICK: { sc = ScOnLeftOrRightMouseClickInListView(); if (sc) return bReturn; } break; case NM_DBLCLK: OnListCtrlItemDblClk(); break; case NM_CUSTOMDRAW: *pResult = m_pListCtrl->OnCustomDraw ( reinterpret_cast(lParam)); break; case LVN_BEGINLABELEDITA: case LVN_BEGINLABELEDITW: { CMainFrame* pFrame = AMCGetMainWnd(); if ((pFrame != NULL) && (IsVerbEnabled(MMC_VERB_RENAME) || m_bRenameListPadItem == true)) { pFrame->SetInRenameMode(true); return FALSE; } else { return TRUE; } break; } case LVN_ENDLABELEDITW: case LVN_ENDLABELEDITA: { CMainFrame* pFrame = AMCGetMainWnd(); if (pFrame != NULL) pFrame->SetInRenameMode(false); LPARAM lResultParam = 0; long index = -1; LPWSTR pszText = NULL; if (pNm->hdr.code == LVN_ENDLABELEDITW) { LV_DISPINFOW* pdi = (LV_DISPINFOW*) lParam; index = pdi->item.iItem; pszText = pdi->item.pszText; lResultParam = pdi->item.lParam; } else // if (pNm->hdr.code == LVN_ENDLABELEDIT) { LV_DISPINFO* pdi = (LV_DISPINFO*) lParam; index = pdi->item.iItem; USES_CONVERSION; pszText = T2W(pdi->item.pszText); lResultParam = pdi->item.lParam; } if (IsVirtualList()) { // for virtual list pass the item index rather than the lparam HNODE hNodeSel = GetSelectedNode(); RenameItem(hNodeSel, FALSE, index, pszText, pResult); } else { CResultItem* pri = CResultItem::FromHandle (lResultParam); if (pri != NULL) { if (pri->IsScopeItem()) RenameItem(pri->GetScopeNode(), TRUE, 0, pszText, pResult); else RenameItem(GetSelectedNode(), FALSE, pri->GetSnapinData(), pszText, pResult); } } break; } case LVN_GETDISPINFOW: { LV_DISPINFOW *pDispInfo = reinterpret_cast(lParam); // If column is hidden do not forward the call to snapin. if (m_pListCtrl && m_pListCtrl->IsColumnHidden(pDispInfo->item.iSubItem)) break; m_spNodeCallback->GetDispInfo (GetSelectedNode(), &pDispInfo->item); break; } case LVN_GETDISPINFOA: { LV_DISPINFOA *pDispInfo = reinterpret_cast(lParam); ASSERT (pDispInfo != NULL); // If column is hidden do not forward the call to snapin. if (m_pListCtrl && m_pListCtrl->IsColumnHidden(pDispInfo->item.iSubItem)) break; /* * put the data in the UNICODE structure for the query */ LV_ITEMW lviW; lviW.mask = pDispInfo->item.mask; lviW.iItem = pDispInfo->item.iItem; lviW.iSubItem = pDispInfo->item.iSubItem; lviW.state = pDispInfo->item.state; lviW.stateMask = pDispInfo->item.stateMask; lviW.cchTextMax = pDispInfo->item.cchTextMax; lviW.iImage = pDispInfo->item.iImage; lviW.lParam = pDispInfo->item.lParam; lviW.iIndent = pDispInfo->item.iIndent; if (pDispInfo->item.mask & LVIF_TEXT) lviW.pszText = new WCHAR[pDispInfo->item.cchTextMax]; /* * convert to ANSI */ if (SUCCEEDED (m_spNodeCallback->GetDispInfo (GetSelectedNode(), &lviW)) && (pDispInfo->item.mask & LVIF_TEXT)) { WideCharToMultiByte (CP_ACP, 0, lviW.pszText, -1, pDispInfo->item.pszText, pDispInfo->item.cchTextMax, NULL, NULL); } if (pDispInfo->item.mask & LVIF_TEXT) delete [] lviW.pszText; /* * copy the results back to the ANSI structure */ pDispInfo->item.mask = lviW.mask; pDispInfo->item.iItem = lviW.iItem; pDispInfo->item.iSubItem = lviW.iSubItem; pDispInfo->item.state = lviW.state; pDispInfo->item.stateMask = lviW.stateMask; pDispInfo->item.cchTextMax = lviW.cchTextMax; pDispInfo->item.iImage = lviW.iImage; pDispInfo->item.lParam = lviW.lParam; pDispInfo->item.iIndent = lviW.iIndent; break; } case LVN_DELETEALLITEMS: // return TRUE to prevent notification for each item return TRUE; case LVN_ITEMCHANGED: bReturn = OnListItemChanged (pNm); break; case LVN_ODSTATECHANGED: // The state of an item or range of items has changed in virtual list. return OnVirtualListItemsStateChanged(reinterpret_cast(lParam)); break; case LVN_ODFINDITEMA: case LVN_ODFINDITEMW: { USES_CONVERSION; NM_FINDITEM *pNmFind = reinterpret_cast(lParam); ASSERT(IsVirtualList() && (pNmFind->lvfi.flags & LVFI_STRING)); LPOLESTR polestr = NULL; if (pNm->hdr.code == LVN_ODFINDITEMW) { LVFINDINFOW* pfiw = reinterpret_cast(&pNmFind->lvfi); polestr = const_cast(pfiw->psz); } else { LVFINDINFOA* pfi = reinterpret_cast(&pNmFind->lvfi); polestr = A2W(const_cast(pfi->psz)); } Dbg(DEB_USER1, _T("\n********************** polestr = %ws\n"), polestr); RESULTFINDINFO findInfo; findInfo.psz = polestr; findInfo.nStart = pNmFind->iStart; findInfo.dwOptions = 0; // Listview bug: LVFI_SUBSTRING is not defined in the SDK headers and the // listview sets it instead of LVFI_PARTIAL when it wants a // partial match. So for now, define it here and test for both. #define LVFI_SUBSTRING 0x0004 if (pNmFind->lvfi.flags & (LVFI_PARTIAL | LVFI_SUBSTRING)) findInfo.dwOptions |= RFI_PARTIAL; if (pNmFind->lvfi.flags & LVFI_WRAP) findInfo.dwOptions |= RFI_WRAP; HNODE hNodeSel = GetSelectedNode(); INodeCallback* pNC = GetNodeCallback(); ASSERT(pNC != NULL); pNC->Notify(hNodeSel, NCLBK_FINDITEM, reinterpret_cast(&findInfo), reinterpret_cast(pResult)); } break; case LVN_ODCACHEHINT: { NM_CACHEHINT *pNmHint = reinterpret_cast(lParam); ASSERT(IsVirtualList()); HNODE hNodeSel = GetSelectedNode(); INodeCallback* pNC = GetNodeCallback(); ASSERT(pNC != NULL); pNC->Notify(hNodeSel, NCLBK_CACHEHINT, pNmHint->iFrom, pNmHint->iTo); } break; case LVN_KEYDOWN: { NMLVKEYDOWN *pNmKeyDown = reinterpret_cast(lParam); switch (pNmKeyDown->wVKey) { case VK_DELETE: { if (!IsVerbEnabled(MMC_VERB_DELETE)) break; INodeCallback* pCallback = GetNodeCallback(); ASSERT(pCallback != NULL); if (pCallback == NULL) break; HNODE hNode = GetSelectedNode(); if (hNode == 0) break; int cSel = m_pListCtrl->GetSelectedCount(); ASSERT(cSel >= 0); LPARAM lvData; if (cSel == 0) { break; } else if (cSel == 1) { if (_GetLVSelectedItemData(&lvData) == -1) break; } else if (cSel > 1) { lvData = LVDATA_MULTISELECT; } else { break; } pCallback->Notify(hNode, NCLBK_DELETE, FALSE, lvData); break; } break; case VK_TAB: GetParentFrame()->SetActiveView (m_pTreeCtrl); break; case VK_BACK: ScUpOneLevel(); break; case VK_RETURN: if(GetKeyState(VK_MENU)<0) // has the ALT key been pressed? { // Process if (! IsVerbEnabled(MMC_VERB_PROPERTIES)) break; LPARAM lvData = 0; if (HasList()) { ASSERT (m_pListCtrl != NULL); ASSERT (GetParentFrame()->GetActiveView() == m_pListCtrl->GetListViewPtr()); int cSel = m_pListCtrl->GetSelectedCount(); ASSERT(cSel >= 0); lvData = LVDATA_ERROR; if (cSel == 0) lvData = LVDATA_BACKGROUND; else if (cSel == 1) _GetLVSelectedItemData(&lvData); else if (cSel > 1) lvData = LVDATA_MULTISELECT; ASSERT(lvData != LVDATA_ERROR); if (lvData == LVDATA_ERROR) break; if (lvData == LVDATA_BACKGROUND) break; } else if (HasOCX()) { lvData = LVDATA_CUSTOMOCX; } else { ASSERT(HasWebBrowser()); lvData = LVDATA_CUSTOMWEB; } INodeCallback* pNC = GetNodeCallback(); ASSERT(pNC != NULL); if (pNC == NULL) break; HNODE hNodeSel = GetSelectedNode(); ASSERT(hNodeSel != NULL); if (hNodeSel == NULL) break; pNC->Notify(hNodeSel, NCLBK_PROPERTIES, FALSE, lvData); break; } else // nope, the ALT key has not been pressed. { // do the default verb. OnListCtrlItemDblClk(); } break; default: bReturn = OnSharedKeyDown(pNmKeyDown->wVKey); break; } } break; default: bReturn = FALSE; break; } return bReturn; } //+------------------------------------------------------------------- // // Member: CAMCView::ScOnLeftOrRightMouseClickInListView // // Synopsis: Left or right mouse button is clicked on the list view, see // if it is clicked on list-view background. If so send a select. // // Click on list view background is treated as scope owner item selected. // // Arguments: None // // Returns: SC // //-------------------------------------------------------------------- SC CAMCView::ScOnLeftOrRightMouseClickInListView() { DECLARE_SC(sc, TEXT("CAMCView::ScOnLeftOrRightMouseClickInListView")); sc = ScCheckPointers(m_pListCtrl, E_UNEXPECTED); if (sc) return sc; CAMCListView *pAMCListView = m_pListCtrl->GetListViewPtr(); sc = ScCheckPointers(pAMCListView, E_UNEXPECTED); if (sc) return sc; CPoint pt; GetCursorPos(&pt); pAMCListView->ScreenToClient(&pt); UINT uFlags = 0; int iItem = pAMCListView->GetListCtrl().HitTest(pt, &uFlags); Dbg(DEB_USER1, _T("----- HitTest > %d \n"), iItem); // Make sure mouse click is in the ListView and there are // no items selected in the list view. if ( (iItem == -1) && !(uFlags & (LVHT_ABOVE | LVHT_BELOW | LVHT_TOLEFT | LVHT_TORIGHT) ) && (m_pListCtrl->GetSelectedCount() == 0) ) { INodeCallback* pNC = GetNodeCallback(); sc = ScCheckPointers(pNC, E_UNEXPECTED); if (sc) return sc; HNODE hNodeSel = GetSelectedNode(); SELECTIONINFO selInfo; ZeroMemory(&selInfo, sizeof(selInfo)); selInfo.m_bScope = TRUE; selInfo.m_bDueToFocusChange = TRUE; selInfo.m_bBackground = TRUE; selInfo.m_lCookie = LVDATA_BACKGROUND; sc = ScNotifySelect (pNC, hNodeSel, false /*fMultiSelect*/, true, &selInfo); if (sc) sc.TraceAndClear(); // ignore & continue; } return (sc); } /*+-------------------------------------------------------------------------* * CAMCView::OnListItemChanged * * WM_NOTIFY (LVN_ITEMCHANGED) handler for CAMCView. * * return true as message is handled here. *--------------------------------------------------------------------------*/ bool CAMCView::OnListItemChanged (NM_LISTVIEW* pnmlv) { DECLARE_SC (sc, _T("CAMCView::OnListItemChanged")); bool bOldState = (pnmlv->uOldState & LVIS_SELECTED); bool bNewState = (pnmlv->uNewState & LVIS_SELECTED); // is this a selection change? if ( (pnmlv->uChanged & LVIF_STATE) && (bOldState != bNewState) ) { const int cSelectedItems = m_pListCtrl->GetSelectedCount(); #ifdef DBG Trace (tagListSelection, _T("Item %d %sselected, %d total items selected"), pnmlv->iItem, (pnmlv->uOldState & LVIS_SELECTED) ? _T("de") : _T(" "), cSelectedItems); #endif SELECTIONINFO selInfo; ZeroMemory(&selInfo, sizeof(selInfo)); selInfo.m_bScope = FALSE; selInfo.m_pView = NULL; selInfo.m_lCookie = IsVirtualList() ? pnmlv->iItem : pnmlv->lParam; /* * If user is (de)selecting multiple items using control and/or shift keys * then defer the multi-select notification until we're quiescent * with the exception of only one item being (de)selected. */ if ((IsKeyPressed(VK_SHIFT) || IsKeyPressed(VK_CONTROL)) && (GetParentFrame()->GetActiveView() == m_pListCtrl->GetListViewPtr()) && (cSelectedItems > 1) ) { // See ScPostMultiSelectionChangesMessage (this handles both selection // and de-selection of multiple items). sc = ScPostMultiSelectionChangesMessage(); if (sc) sc.TraceAndClear(); return (true); } else { m_bProcessMultiSelectionChanges = false; } HNODE hNodeSel = GetSelectedNode(); INodeCallback* pNC = GetNodeCallback(); sc = ScCheckPointers(pNC, (void*) hNodeSel, E_UNEXPECTED); if (sc) return (true); // item = -1 is only expected for deselect in virtual list ASSERT( pnmlv->iItem != -1 || (IsVirtualList() && (pnmlv->uOldState & LVIS_SELECTED))); if (pnmlv->uOldState & LVIS_SELECTED) { if (cSelectedItems == 0) { if (!m_bLastSelWasMultiSel) { sc = ScNotifySelect (pNC, hNodeSel, false /*fMultiSelect*/, false, &selInfo); if (sc) sc.TraceAndClear(); // ignore & continue; } else { m_bLastSelWasMultiSel = false; sc = ScNotifySelect (pNC, hNodeSel, true /*fMultiSelect*/, false, 0); if (sc) sc.TraceAndClear(); // ignore & continue; } } else if (m_bLastSelWasMultiSel) { // may need to cancel multiselect and send single select notify. // if another change comes in, it will cancel the delayed message // This fixes a problem that is caused by large icon mode not // sending as many noifications as the other modes. // See ScPostMultiSelectionChangesMessage (this handles both selection // and de-selection of multiple items). sc = ScPostMultiSelectionChangesMessage(); if (sc) sc.TraceAndClear(); } } else if (pnmlv->uNewState & LVIS_SELECTED) { ASSERT(cSelectedItems >= 1); if (cSelectedItems == 1) { sc = ScNotifySelect (pNC, hNodeSel, false /*fMultiSelect*/, true, &selInfo); if (sc) sc.TraceAndClear(); // ignore & continue; } else { sc = ScNotifySelect (pNC, hNodeSel, true /*fMultiSelect*/, true, 0); if (sc) sc.TraceAndClear(); // ignore & continue; m_bLastSelWasMultiSel = true; } } } return (true); } //+------------------------------------------------------------------- // // Member: CAMCView::OnVirtualListItemsStateChanged // // Synopsis: The state of an item or range of items has changed in virtual list. // // Arguments: lpStateChange - // // Returns: should return 0 according to docs. // //-------------------------------------------------------------------- int CAMCView::OnVirtualListItemsStateChanged(LPNMLVODSTATECHANGE lpStateChange ) { DECLARE_SC(sc, TEXT("CAMCView::OnVirtualListItemsStateChanged")); sc = ScCheckPointers(lpStateChange); if (sc) { sc.TraceAndClear(); return 0; } bool bOldState = (lpStateChange->uOldState & LVIS_SELECTED); bool bNewState = (lpStateChange->uNewState & LVIS_SELECTED); int cItems = (lpStateChange->iTo - lpStateChange->iFrom) + 1; #ifdef DBG Trace (tagListSelection, _T("Items %d to %d were %sselected, %d total items selected"), lpStateChange->iFrom, lpStateChange->iTo, bOldState ? _T("de") : _T(" "), cItems ); #endif if (bOldState != bNewState) { sc = ScPostMultiSelectionChangesMessage(); if (sc) sc.TraceAndClear(); } return (0); } //+------------------------------------------------------------------- // // Member: CAMCView::ScPostMultiSelectionChangesMessage // // Synopsis: Post selection change message (need to post because multi-sel // may not be over, wait till it is quiet.) // // This method posts message telling selection states of multiple // items are changed but not if they are selected or de-selected. // The m_bLastSelWasMultiSel is used to determine if it is // selection or de-selection. // // Arguments: // // Returns: SC // //-------------------------------------------------------------------- SC CAMCView::ScPostMultiSelectionChangesMessage () { DECLARE_SC(sc, _T("CAMCView::ScPostMultiSelectionChangesMessage")); /* * This is a multi-selection, defer notification until we're quiescent */ m_bProcessMultiSelectionChanges = true; PostMessage (m_nProcessMultiSelectionChangesMsg); // We need to disable all the toolbars, menubuttons // during multiselect. Above PostMessage enables // stdbar and MMC menubuttons. CAMCViewToolbarsMgr* pAMCViewToolbarsMgr = m_ViewData.GetAMCViewToolbarsMgr(); CMenuButtonsMgr* pMenuBtnsMgr = m_ViewData.GetMenuButtonsMgr(); sc = ScCheckPointers(pAMCViewToolbarsMgr, pMenuBtnsMgr, E_UNEXPECTED); if (sc) return 0; pAMCViewToolbarsMgr->ScDisableToolbars(); pMenuBtnsMgr->ScDisableMenuButtons(); return (sc); } void CAMCView::OpenResultItem(HNODE hNode) { /* * Bug 139695: Make certain this function doesn't need to change the * active view. We should only get here as a result of double- clicking * or pressing Enter on a scope node in the result pane, in which case * the result pane should already be the active view. If it is, we don't * need to change the active view, which can cause the problems listed in * the bug. */ ASSERT (m_pListCtrl != NULL); ASSERT (GetParentFrame() != NULL); ASSERT (GetParentFrame()->GetActiveView() == m_pListCtrl->GetListViewPtr()); ASSERT(m_pTreeCtrl); HTREEITEM htiParent = m_pTreeCtrl->GetSelectedItem(); ASSERT(htiParent != NULL); m_pTreeCtrl->ExpandNode(htiParent); m_pTreeCtrl->Expand(htiParent, TVE_EXPAND); HTREEITEM hti = m_pTreeCtrl->GetChildItem(htiParent); if (hti == NULL) return; while (hti) { if (m_pTreeCtrl->GetItemNode(hti) == hNode) break; hti = m_pTreeCtrl->GetNextItem(hti, TVGN_NEXT); } if (hti != 0) { m_pTreeCtrl->Expand(htiParent, TVE_EXPAND); m_pTreeCtrl->SelectItem(hti); } } BOOL CAMCView::OnListCtrlItemDblClk(void) { TRACE_METHOD(CAMCView, OnListCtrlItemDblClk); LPARAM lvData = -1; if (_GetLVSelectedItemData(&lvData) == -1) lvData = LVDATA_BACKGROUND; HNODE hNodeSel = GetSelectedNode(); INodeCallback* pNC = GetNodeCallback(); ASSERT(pNC != NULL); if (!pNC) return FALSE; HRESULT hr = pNC->Notify(hNodeSel, NCLBK_DBLCLICK, lvData, 0); if (hr == S_FALSE) { ASSERT(lvData != LVDATA_BACKGROUND); if (!IsVirtualList()) { CResultItem* pri = CResultItem::FromHandle (lvData); if ((pri != NULL) && pri->IsScopeItem()) OpenResultItem (pri->GetScopeNode()); } } return TRUE; } BOOL CAMCView::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult) { DECLARE_SC(sc, TEXT("CAMCView::OnNotify")); NMHDR *pNmHdr = reinterpret_cast(lParam); sc = ScCheckPointers(pNmHdr, pResult); if (sc) { sc.TraceAndClear(); return CView::OnNotify(wParam, lParam, pResult); } *pResult = TRUE; // init switch(pNmHdr->code) { case HDN_ENDTRACKA: // Save the column width changes. case HDN_ENDTRACKW: // HDN_BEGINTRACK handles dis-allowing hidden column dragging. { NMHEADER* nmh = (NMHEADER*)lParam; CAMCListView *pAMCListView = m_pListCtrl->GetListViewPtr(); SC sc = ScCheckPointers(pAMCListView, E_UNEXPECTED); if (sc) { sc.TraceAndClear(); return FALSE; } sc = pAMCListView->ScOnColumnsAttributeChanged(nmh, HDN_ENDTRACK); if (sc) { sc.TraceAndClear(); return FALSE; } // S_FALSE : dont allow the change if (sc == SC(S_FALSE)) return TRUE; return CView::OnNotify(wParam, lParam, pResult); } break; case HDN_ENDDRAG: // Column order changes. { NMHEADER* nmh = (NMHEADER*)lParam; if (nmh->pitem->mask & HDI_ORDER) { CAMCListView *pAMCListView = m_pListCtrl->GetListViewPtr(); SC sc = ScCheckPointers(pAMCListView, E_UNEXPECTED); if (sc) { sc.TraceAndClear(); return FALSE; } sc = pAMCListView->ScOnColumnsAttributeChanged(nmh, HDN_ENDDRAG); if (sc) { sc.TraceAndClear(); return FALSE; } // S_FALSE : dont allow the change if (sc = SC(S_FALSE)) return TRUE; } return CView::OnNotify(wParam, lParam, pResult); } break; case TVN_BEGINLABELEDIT: { TV_DISPINFO* ptvdi = (TV_DISPINFO*)lParam; if ((ptvdi->item.lParam == CAMCTreeView::LParamFromNode (GetSelectedNode())) && (IsVerbEnabled(MMC_VERB_RENAME) == FALSE)) { return TRUE; } CMainFrame* pFrame = AMCGetMainWnd(); if (pFrame != NULL) pFrame->SetInRenameMode(true); return FALSE; } case TVN_ENDLABELEDIT: { TV_DISPINFO* ptvdi = (TV_DISPINFO*)lParam; CMainFrame* pFrame = AMCGetMainWnd(); if (pFrame != NULL) pFrame->SetInRenameMode(false); USES_CONVERSION; return RenameItem(CAMCTreeView::NodeFromLParam (ptvdi->item.lParam), TRUE, 0, T2W(ptvdi->item.pszText), pResult); } case TVN_KEYDOWN: { TV_KEYDOWN* ptvkd = reinterpret_cast(lParam); if (ptvkd->wVKey == VK_TAB) { ScSetFocusToResultPane(); return TRUE; } else { return OnSharedKeyDown(ptvkd->wVKey); } } } if (UsingDefColumns() && (pNmHdr->code == HDN_ENDTRACKA || pNmHdr->code == HDN_ENDTRACKW)) { // WARNING: If HD_NOTIFY::pitem::pszText needs to be used you should cast // lParam to either HD_NOTIFYA or HD_NOTIFYW depending on the pNmHdr->code HD_NOTIFY* phdn = reinterpret_cast(lParam); ASSERT(phdn != NULL); if (phdn->pitem->mask & HDI_WIDTH) { int alWidths[2] = {0, 0}; GetDefaultColumnWidths(alWidths); alWidths[phdn->iItem] = phdn->pitem->cxy; SetDefaultColumnWidths(alWidths, FALSE); return TRUE; } } #ifdef DBG if (m_pTreeCtrl && m_pTreeCtrl->m_hWnd == pNmHdr->hwndFrom) { switch (pNmHdr->code) { case NM_CLICK: Dbg(DEB_USER2, "\t Tree item clicked\n"); break; case NM_DBLCLK: Dbg(DEB_USER2, "\t Tree item dbl-clicked\n"); break; case NM_RCLICK: Dbg(DEB_USER2, "\t Tree item R-clicked\n"); break; default: break; } } #endif // HasList() is added to prevent dispatching notifications, when AMCView thinks // it does not have a list. This lead to wrong assumptions about the list type // and as a result - AV handling messages like GetDisplayInfo // See BUG 451896 if (m_pListCtrl && HasListOrListPad()) { if (m_pListCtrl->GetListViewHWND() == pNmHdr->hwndFrom) { if (DispatchListCtrlNotificationMsg(lParam, pResult) == TRUE) return TRUE; } else if (m_pListCtrl->GetHeaderCtrl() && m_pListCtrl->GetHeaderCtrl()->m_hWnd == pNmHdr->hwndFrom) { switch(pNmHdr->code) { case HDN_ITEMCLICKA: case HDN_ITEMCLICKW: { HNODE hNodeSel = GetSelectedNode(); HD_NOTIFY* phdn = reinterpret_cast(lParam); ASSERT(phdn != NULL); int nCol = phdn->iItem; sc = m_spNodeCallback->Notify(hNodeSel, NCLBK_COLUMN_CLICKED, 0, nCol); if (sc) sc.TraceAndClear(); return TRUE; } // filter related code case HDN_FILTERCHANGE: { HNODE hNodeSel = GetSelectedNode(); int nCol = ((NMHEADER*)lParam)->iItem; sc = m_spNodeCallback->Notify(hNodeSel, NCLBK_FILTER_CHANGE, MFCC_VALUE_CHANGE, nCol); if (sc) sc.TraceAndClear(); return TRUE; } case HDN_FILTERBTNCLICK: { HNODE hNodeSel = GetSelectedNode(); int nCol = ((NMHDFILTERBTNCLICK*)lParam)->iItem; RECT rc = ((NMHDFILTERBTNCLICK*)lParam)->rc; // rect is relative to owning list box, convert to screen ::MapWindowPoints(m_pListCtrl->GetListViewHWND(), NULL, (LPPOINT)&rc, 2); sc = m_spNodeCallback->Notify(hNodeSel, NCLBK_FILTERBTN_CLICK, nCol, (LPARAM)&rc); *pResult = (sc == SC(S_OK)); if (sc) sc.TraceAndClear(); return TRUE; } } } } return CView::OnNotify(wParam, lParam, pResult); } /*+-------------------------------------------------------------------------* * * CAMCView::ScOnMinimize * * PURPOSE: Send the NCLBK_MINIMIZED notification to the node manager. * * PARAMETERS: * bool fMinimized : TRUE if the window is being minimized, false if maximized. * * RETURNS: * SC * *+-------------------------------------------------------------------------*/ SC CAMCView::ScOnMinimize(bool fMinimized) { DECLARE_SC(sc, TEXT("CAMCView::ScOnMinimize")); HNODE hNode = GetSelectedNode(); if (hNode == NULL) return (sc = E_FAIL); INodeCallback* pNodeCallback = GetNodeCallback(); if (pNodeCallback == NULL) return (sc = E_FAIL); sc = pNodeCallback->Notify (hNode, NCLBK_MINIMIZED, fMinimized, 0); return sc; } /*+-------------------------------------------------------------------------* * * CAMCView::ScOnSize * * PURPOSE: Send the size notification to all * * PARAMETERS: * UINT nType : * int cx : * int cy : * * RETURNS: * SC * *+-------------------------------------------------------------------------*/ SC CAMCView::ScOnSize(UINT nType, int cx, int cy) { DECLARE_SC(sc, TEXT("CAMCView::ScOnSize")); if (IsPersisted() && GetDocument()) GetDocument()->SetFrameModifiedFlag(true); sc = ScFireEvent(CAMCViewObserver::ScOnViewResized, this, nType, cx, cy); return sc; } /*+-------------------------------------------------------------------------* * * CAMCView::ScActivate * * PURPOSE: Sets the view as the active view. * * RETURNS: * SC * *+-------------------------------------------------------------------------*/ SC CAMCView::ScActivate() { DECLARE_SC(sc, TEXT("CAMCView::ScActivate")); // get the child frame. CChildFrame * pChildFrame = GetParentFrame(); sc = ScCheckPointers(pChildFrame); if(sc) return sc; if (pChildFrame->IsIconic()) pChildFrame->MDIRestore(); else pChildFrame->MDIActivate(); // activate the child frame. return sc; } void CAMCView::OnContextMenu(CWnd* pWnd, CPoint point) { TRACE_METHOD(CAMCView, OnContextMenu); /* * make sure this child frame is active */ GetParentFrame()->MDIActivate(); if (NULL == m_pTreeCtrl) { TRACE(_T("CAMCView::OnContextMenu: tree control not ready\n" )); return; } // (-1,-1) => came from context menu key or Shift-F10 // Pop-up context for whatever has focus if (point.x == -1 && point.y == -1) { OnShiftF10(); return; } switch (HitTestPane(point)) { case ePane_Results: { CPoint pointListCtrlCoord = point; CListView* pListView = m_pListCtrl->GetListViewPtr(); pListView->ScreenToClient(&pointListCtrlCoord); CWnd* pwndHit = pListView->ChildWindowFromPoint (pointListCtrlCoord, CWP_SKIPINVISIBLE); /* * if the hit window isn't the list view, it must be the list's * header window; ignore the context menu request */ if (pwndHit != pListView) { TRACE (_T("CAMCView::OnContextMenu: ignore right-click on result pane header\n")); break; } if (NULL != m_pListCtrl && pWnd->m_hWnd == m_pListCtrl->GetListViewHWND()) OnListContextMenu(point); else TRACE(_T("CAMCView::OnContextMenu: result control not ready\n")); // CODEWORK should do something here break; } case ePane_ScopeTree: { TRACE(_T("CAMCView::OnContextMenu: handle right-click on scope pane\n")); CPoint pointTreeCtrlCoord = point; m_pTreeCtrl->ScreenToClient(&pointTreeCtrlCoord); OnTreeContextMenu( point, pointTreeCtrlCoord, NULL ); break; } case ePane_Tasks: // TO BE ADDED - put up taskpad context menu break; case ePane_None: TRACE(_T("CAMCView::OnContextMenu: ignore right-click on splitter\n")); break; default: TRACE(_T("CAMCView::OnContextMenu: unexpected return value from HitTestPane()\n")); ASSERT(FALSE); } } void CAMCView::OnTreeContextMenu(CPoint& point, CPoint& pointClientCoord, HTREEITEM htiRClicked) { TRACE_METHOD(CAMCView, OnTreeContextMenu); if (NULL == m_pTreeCtrl) { TRACE(_T("CAMCTreeView::OnTreeContextMenu: IFrame not ready\n")); return; } UINT fHitTestFlags = TVHT_ONITEM; if (htiRClicked == NULL) htiRClicked = m_pTreeCtrl->HitTest(pointClientCoord, &fHitTestFlags); switch(fHitTestFlags) { case TVHT_ABOVE: case TVHT_BELOW: case TVHT_TOLEFT: case TVHT_TORIGHT: // Outside the tree view area so return without doing anything. return; default: break; } if (NULL == htiRClicked || !(fHitTestFlags & TVHT_ONITEM)) { OnContextMenuForTreeBackground(point); } else { HNODE hNode = (HNODE)m_pTreeCtrl->GetItemData(htiRClicked); ASSERT(hNode != 0); OnContextMenuForTreeItem(INDEX_INVALID, hNode, point, CCT_SCOPE, htiRClicked); } } void CAMCView::OnContextMenuForTreeItem(int iIndex, HNODE hNode, CPoint& point, DATA_OBJECT_TYPES type_of_pane, HTREEITEM htiRClicked, MMC_CONTEXT_MENU_TYPES eMenuType, LPCRECT prcExclude, bool bAllowDefaultItem) { TRACE_METHOD(CAMCView, OnContextMenuForTreeItem); DECLARE_SC (sc, _T("CAMCView::OnContextMenuForTreeItem")); ASSERT(hNode != 0); CContextMenuInfo contextInfo; contextInfo.m_displayPoint.x = point.x; contextInfo.m_displayPoint.y = point.y; contextInfo.m_eContextMenuType = eMenuType; contextInfo.m_eDataObjectType = CCT_SCOPE; contextInfo.m_bBackground = FALSE; contextInfo.m_bScopeAllowed = IsScopePaneAllowed(); contextInfo.m_hWnd = m_hWnd; contextInfo.m_pConsoleView = this; contextInfo.m_bAllowDefaultItem = bAllowDefaultItem; contextInfo.m_hSelectedScopeNode = GetSelectedNode(); contextInfo.m_htiRClicked = htiRClicked; contextInfo.m_iListItemIndex = iIndex; /* * if given, initialize the rectangle not to obscure */ if (prcExclude != NULL) contextInfo.m_rectExclude = *prcExclude; // If selected scope node is same as node for which context menu is // needed, then add savelist, view menus if (contextInfo.m_hSelectedScopeNode == hNode) { // Show view owner items contextInfo.m_dwFlags |= CMINFO_SHOW_VIEWOWNER_ITEMS; // Don't need to remove temporary selection, since none was applied contextInfo.m_pConsoleTree = NULL; if (eMenuType == MMC_CONTEXT_MENU_DEFAULT) contextInfo.m_dwFlags |= CMINFO_SHOW_VIEW_ITEMS; if (HasListOrListPad()) contextInfo.m_dwFlags |= CMINFO_SHOW_SAVE_LIST; } else if (htiRClicked) // htiRClicked is NULL for tree items in list view. { // TempNodeSelect == TRUE -> menu is not for the node that owns the result pane sc = m_pTreeCtrl->ScSetTempSelection (htiRClicked); if (sc) return; contextInfo.m_pConsoleTree = m_pTreeCtrl; contextInfo.m_dwFlags |= CMINFO_USE_TEMP_VERB; } if (htiRClicked) contextInfo.m_dwFlags |= CMINFO_DO_SCOPEPANE_MENU; else contextInfo.m_dwFlags |= CMINFO_SCOPEITEM_IN_RES_PANE; if (HasListOrListPad()) contextInfo.m_spListView = m_pListCtrl; INodeCallback* spNodeCallback = GetNodeCallback(); ASSERT(spNodeCallback != NULL); HRESULT hr = spNodeCallback->Notify(hNode, NCLBK_CONTEXTMENU, 0, reinterpret_cast(&contextInfo)); } /*+-------------------------------------------------------------------------* * * CAMCView::GetTaskpadID * * PURPOSE: returns the GUID id of the currently selected taskpad. * * RETURNS: * GUID : the taskpad, if any, else GUID_NULL. * *+-------------------------------------------------------------------------*/ void CAMCView::GetTaskpadID(GUID &guidID) { ITaskCallback * pTaskCallback = m_ViewData.m_spTaskCallback; if(pTaskCallback != NULL) { pTaskCallback->GetTaskpadID(&guidID); } else { guidID = GUID_NULL; } } /*+-------------------------------------------------------------------------* * * CAMCView::ScInitializeMemento * * PURPOSE: Initializes the memento from the current view. * * PARAMETERS: * CMemento & memento : * * RETURNS: * SC * *+-------------------------------------------------------------------------*/ SC CAMCView::ScInitializeMemento(CMemento &memento) { DECLARE_SC(sc, TEXT("CAMCView::ScInitializeMemento")); sc = GetSelectedNodePath(&memento.GetBookmark()); if (sc) return sc; GUID guidTaskpad = GUID_NULL; HNODE hNode = GetSelectedNode(); // get Result pane stuff from snapin CResultViewType rvt; sc = GetNodeCallback()->GetResultPane(hNode, rvt, &guidTaskpad /*this is not used*/); if (sc) return sc; CViewSettings& viewSettings = memento.GetViewSettings(); // Initialize the CViewSettings. sc = viewSettings.ScSetResultViewType(rvt); if (sc) return sc; GUID guid; GetTaskpadID(guid); // we use this guid instead of guidTaskpad because // the memento should contain the taskpad that is currently being displayed. sc = viewSettings.ScSetTaskpadID(guid); return sc; } /*+-------------------------------------------------------------------------* * * CAMCView::OnAddToFavorites * * PURPOSE: Creates a memento from the currently configured view. Saves it into a * shortcut. * * RETURNS: * void * *+-------------------------------------------------------------------------*/ void CAMCView::OnAddToFavorites() { DECLARE_SC(sc , _T("CAMCView::OnAddToFavorites")); USES_CONVERSION; CAMCDoc* pDoc = GetDocument(); sc = ScCheckPointers(pDoc, E_UNEXPECTED); if (sc) return; IScopeTree* const pScopeTree = GetScopeTreePtr(); sc = ScCheckPointers(pScopeTree, E_UNEXPECTED); if (sc) return; CMemento memento; sc = ScInitializeMemento(memento); // init the memento with the current view settings. if(sc) return; HNODE hNode = GetSelectedNode(); tstring strName; sc = GetNodeCallback()->GetDisplayName(hNode, strName); if (sc) return; HMTNODE hmtNode; sc = m_spNodeCallback->GetMTNode(hNode, &hmtNode); if (sc) return; CCoTaskMemPtr spszPath; sc = pScopeTree->GetPathString(NULL, hmtNode, &spszPath); if (sc) return; sc = ScCheckPointers(pDoc->GetFavorites(), E_UNEXPECTED); if (sc) return; sc = pDoc->GetFavorites()->AddToFavorites(strName.data(), W2CT(spszPath), memento, this); if (sc) return; pDoc->SetModifiedFlag(); } void CAMCView::OnContextMenuForTreeBackground(CPoint& point, LPCRECT prcExclude, bool bAllowDefaultItem) { TRACE_METHOD(CAMCView, OnContextMenuForTreeBackground); HNODE hNode = NULL; CContextMenuInfo contextInfo; contextInfo.m_displayPoint.x = point.x; contextInfo.m_displayPoint.y = point.y; contextInfo.m_eDataObjectType = CCT_SCOPE; contextInfo.m_bBackground = TRUE; contextInfo.m_bScopeAllowed = IsScopePaneAllowed(); contextInfo.m_hWnd = m_hWnd; contextInfo.m_pConsoleView = this; contextInfo.m_bAllowDefaultItem = bAllowDefaultItem; /* * if given, initialize the rectangle not to obscure */ if (prcExclude != NULL) contextInfo.m_rectExclude = *prcExclude; INodeCallback* spNodeCallback = GetNodeCallback(); ASSERT(spNodeCallback != NULL); HRESULT hr = spNodeCallback->Notify(hNode, NCLBK_CONTEXTMENU, 0, reinterpret_cast(&contextInfo)); } SC CAMCView::ScWebCommand (WebCommand eCommand) { AFX_MANAGE_STATE (AfxGetAppModuleState()); if (m_pWebViewCtrl == NULL) { ASSERT (m_pHistoryList); if (!m_pHistoryList) return FALSE; // this is the case when we don't have a web control yet.... bool bHandled = false; switch (eCommand) { case eWeb_Back: m_pHistoryList->Back (bHandled); ASSERT(bHandled); break; case eWeb_Forward: m_pHistoryList->Forward (bHandled); ASSERT(bHandled); break; default: return FALSE; } return TRUE; } switch (eCommand) { case eWeb_Back: m_pWebViewCtrl->Back(); break; case eWeb_Forward: m_pWebViewCtrl->Forward(); break; case eWeb_Home: ASSERT(0 && "Should not come here! - remove all code related to Web_Home"); break; case eWeb_Refresh: m_pWebViewCtrl->Refresh(); break; case eWeb_Stop: m_pWebViewCtrl->Stop(); break; default: ASSERT(0); return FALSE; } return TRUE; } /*+-------------------------------------------------------------------------* * * CAMCView::ScCreateTaskpadHost * * PURPOSE: Creates a legacy (snapin taskpad) host interface pointer * * NOTE: When a view containing a taskpad is navigated away from, the amcview * forgets about the taskpad host pointer, but the html window does not. * When the same view is re-navigated to using History, the amcview needs * a taskpad host pointer, so a new instance is created. Thus at this point * the amcview and the HTML have pointers to different taskpad host * objects. This is OK, because both objects are initialized to the same * amcview, and contain no other state * * RETURNS: * SC * *+-------------------------------------------------------------------------*/ SC CAMCView::ScCreateTaskpadHost() { DECLARE_SC(sc , _T("CAMCView::ScCreateTaskpadHost")); if(m_spTaskPadHost != NULL) return sc; CComObject* pTaskPadHost = NULL; sc = CComObject::CreateInstance(&pTaskPadHost); if (sc) return sc; sc = ScCheckPointers (pTaskPadHost, E_UNEXPECTED); if (sc) return sc; pTaskPadHost->Init (this); m_spTaskPadHost = pTaskPadHost; return sc; } LRESULT CAMCView::OnConnectToCIC (WPARAM wParam, LPARAM lParam) { DECLARE_SC (sc, _T("CAMCView::OnConnectToCIC")); // fill out wparam, which is an IUnknown ** (alloc'd by CIC) ASSERT (wParam != NULL); IUnknown ** ppunk = (IUnknown **)wParam; ASSERT (!IsBadReadPtr (ppunk, sizeof(IUnknown *))); ASSERT (!IsBadWritePtr (ppunk, sizeof(IUnknown *))); sc = ScCheckPointers (ppunk); if (sc) return (sc.ToHr()); // lParam holds MMCCtrl's IUnknown: we can hang onto this if we // need it. Presently not saved or used. sc = ScCreateTaskpadHost(); if(sc) return sc.ToHr(); sc = ScCheckPointers(m_spTaskPadHost, E_UNEXPECTED); if(sc) return sc.ToHr();; sc = m_spTaskPadHost->QueryInterface(IID_IUnknown, (void **)ppunk); if (sc) return (sc.ToHr()); return (sc.ToHr()); } //+------------------------------------------------------------------- // // Member: CAMCView::OnGetIconInfoForSelectedNode // // Synopsis: Icon control sends this message to get the small icon // for currently the selected node. // // Arguments: [wParam] - Out param, ptr to HICON handle. // [lParam] - Unused // // Returns: LRESULT // //-------------------------------------------------------------------- LRESULT CAMCView::OnGetIconInfoForSelectedNode(WPARAM wParam, LPARAM lParam) { AFX_MANAGE_STATE (AfxGetAppModuleState()); DECLARE_SC(sc, _T("CAMCView::OnGetIconInfoForSelectedNode")); HICON *phIcon = (HICON*)wParam; sc = ScCheckPointers(phIcon); if (sc) return sc.ToHr(); *phIcon = NULL; sc = ScCheckPointers(m_pTreeCtrl, m_spNodeCallback, E_UNEXPECTED); if (sc) return sc.ToHr(); sc = m_pTreeCtrl->ScGetTreeItemIconInfo(GetSelectedNode(), phIcon); return sc.ToHr(); } HRESULT CAMCView::NotifyListPad (BOOL b) { if (b == TRUE) // attaching: save current node m_ListPadNode = GetSelectedNode(); else if (m_ListPadNode == NULL) // detaching, but no hnode return E_UNEXPECTED; // send notify to snapin INodeCallback* pNC = GetNodeCallback(); HRESULT hr = pNC->Notify (m_ListPadNode, NCLBK_LISTPAD, (long)b, (long)0); if (b == FALSE) // if detaching, ensure that we do this only once m_ListPadNode = NULL; return hr; } /*+-------------------------------------------------------------------------* * * CAMCView::ScOnConnectToTPLV * * PURPOSE: Connects the listpad to the HTML frame * * PARAMETERS: * WPARAM wParam : parent window * LPARAM lParam : [OUT]: pointer to window to be created and filled out * * RETURNS: * SC * *+-------------------------------------------------------------------------*/ SC CAMCView::ScOnConnectToTPLV(WPARAM wParam, LPARAM lParam) { DECLARE_SC(sc, _T("CAMCView::ScOnConnectToTPLV")); HWND hwnd = (HWND )wParam; if(!IsWindow (hwnd)) return (sc = S_FALSE); if (lParam == NULL) // detaching { SC sc = m_pListCtrl->ScAttachToListPad (hwnd, NULL); if(sc) return sc; } else { // attaching sc = ScCreateTaskpadHost(); if(sc) return sc; HWND* phwnd = (HWND*)lParam; if (IsBadWritePtr (phwnd, sizeof(HWND *))) return (sc = E_UNEXPECTED); // Attach TaskPad's ListView to the NodeMgr sc = ScCheckPointers(m_pListCtrl, E_UNEXPECTED); if(sc) return sc; sc = m_pTreeCtrl->m_spNodeManager->SetTaskPadList(m_pListCtrl); if(sc) return sc; // Attach TaskPad's ListView to the curr selected node INodeCallback* pNC = GetNodeCallback(); sc = ScCheckPointers(pNC, E_UNEXPECTED); if(sc) return sc; HNODE hNodeSel = GetSelectedNode(); sc = pNC->SetTaskPadList(hNodeSel, m_pListCtrl); if(sc) // this test was commented out earlier. Uncommented it so we can figure out why. return sc; // // Attach the listctrl to the list pad. // // First set the list view options. SetListViewOptions(GetListOptions()); sc = m_pListCtrl->ScAttachToListPad (hwnd, phwnd); if(sc) return sc; } RecalcLayout(); return sc; } SC CAMCView::ScShowWebContextMenu () { AFX_MANAGE_STATE (AfxGetAppModuleState()); PostMessage (m_nShowWebContextMenuMsg); return (S_OK); } LRESULT CAMCView::OnShowWebContextMenu (WPARAM /*wParam*/, LPARAM /*lParam*/) { INodeCallback* pNC = GetNodeCallback(); ASSERT(pNC != NULL); if (pNC) pNC->Notify (GetSelectedNode(), NCLBK_WEBCONTEXTMENU, 0, 0); return (0); } SC CAMCView::ScSetDescriptionBarText (LPCTSTR pszDescriptionText) { AFX_MANAGE_STATE (AfxGetAppModuleState()); GetRightDescCtrl().SetSnapinText (pszDescriptionText); return (S_OK); } HWND CAMCView::CreateFavoriteObserver (HWND hwndParent, int nID) { DECLARE_SC (sc, _T("CAMCView::CreateFavoriteObserver")); AFX_MANAGE_STATE (AfxGetAppModuleState()); CFavTreeCtrl* pFavCtrl = CFavTreeCtrl::CreateInstance(); if (pFavCtrl != NULL) { pFavCtrl->Create (NULL, TEXT(""), WS_CHILD|WS_TABSTOP|WS_VISIBLE, g_rectEmpty, CWnd::FromHandle(hwndParent), nID); pFavCtrl->ModifyStyleEx (0, WS_EX_CLIENTEDGE, 0); CAMCDoc* pDoc = GetDocument(); ASSERT(pDoc != NULL && pDoc->GetFavorites() != NULL); sc = pFavCtrl->ScInitialize(pDoc->GetFavorites(), TOBSRV_HIDEROOT); if (sc) { pFavCtrl->DestroyWindow(); // CFavTreeCtrl::PostNcDestroy will "delete this" pFavCtrl = NULL; } } return (pFavCtrl->GetSafeHwnd()); } int CAMCView::GetListSize () { AFX_MANAGE_STATE (AfxGetAppModuleState()); return (m_pListCtrl->GetItemCount() * m_pListCtrl->GetColCount()); } long CAMCView::GetListViewStyle() { DECLARE_SC(sc, _T("CAMCView::GetListViewStyle")); sc = ScCheckPointers(m_pTreeCtrl, m_pTreeCtrl->m_spResultData, E_UNEXPECTED); if (sc) return 0; if (HasList()) return 0; long style = 0; // First findout if the result view is properly // set in the nodemgr by asking IFramePrivate. IFramePrivatePtr spFrame = m_pTreeCtrl->m_spResultData; sc = ScCheckPointers(spFrame, E_UNEXPECTED); if (sc) return 0; BOOL bIsResultViewSet = FALSE; sc = spFrame->IsResultViewSet(&bIsResultViewSet); // The result view is set, clean it up. if (bIsResultViewSet) { sc = m_pTreeCtrl->m_spResultData->GetListStyle(&style); if (sc) return 0; } return style; } void CAMCView::OnListContextMenu(CPoint& point) { DECLARE_SC(sc, TEXT("CAMCView::OnListContextMenu")); ASSERT(m_pTreeCtrl != NULL); ASSERT(m_pTreeCtrl->m_spResultData != NULL); // Determine which item is affected UINT fHitTestFlags = 0; HRESULTITEM hHitTestItem = 0; COMPONENTID componentID = 0; int iIndex = -1; do // not a loop { if (!HasList()) break; int cSel = m_pListCtrl->GetSelectedCount(); ASSERT(cSel >= 0); if (cSel == 0) { OnContextMenuForListItem(INDEX_BACKGROUND, NULL, point); return; } else if (cSel > 1) { if (IsKeyPressed(VK_SHIFT) || IsKeyPressed(VK_CONTROL)) { HNODE hNodeSel = GetSelectedNode(); ASSERT(hNodeSel != 0); INodeCallback* pNC = GetNodeCallback(); ASSERT(pNC != NULL); if (pNC != NULL) { sc = ScNotifySelect (pNC, hNodeSel, true /*fMultiSelect*/, true, 0); if (sc) sc.TraceAndClear(); // ignore & continue; m_bLastSelWasMultiSel = true; } } iIndex = INDEX_MULTISELECTION; // => MultiSelect break; } else { LPARAM lvData = LVDATA_ERROR; iIndex = _GetLVSelectedItemData(&lvData); ASSERT(iIndex != -1); ASSERT(lvData != LVDATA_ERROR); if (IsVirtualList()) { // for virtual list pass the item index rather than the lparam OnContextMenuForListItem(iIndex, iIndex, point); return; } else { CResultItem* pri = CResultItem::FromHandle (lvData); if (pri != NULL) { if (pri->IsScopeItem()) OnContextMenuForTreeItem(iIndex, pri->GetScopeNode(), point, CCT_SCOPE); else OnContextMenuForListItem(iIndex, lvData, point); } return; } } } while (0); OnContextMenuForListItem(iIndex, hHitTestItem, point); } void CAMCView::OnContextMenuForListItem(int iIndex, HRESULTITEM hHitTestItem, CPoint& point, MMC_CONTEXT_MENU_TYPES eMenuType, LPCRECT prcExclude, bool bAllowDefaultItem) { CContextMenuInfo contextInfo; contextInfo.m_displayPoint.x = point.x; contextInfo.m_displayPoint.y = point.y; contextInfo.m_eContextMenuType = eMenuType; contextInfo.m_eDataObjectType = CCT_RESULT; contextInfo.m_bBackground = (iIndex == INDEX_BACKGROUND); contextInfo.m_bMultiSelect = (iIndex == INDEX_MULTISELECTION); contextInfo.m_bAllowDefaultItem = bAllowDefaultItem; if (iIndex >= 0) contextInfo.m_resultItemParam = IsVirtualList() ? iIndex : hHitTestItem; else if (contextInfo.m_bMultiSelect) contextInfo.m_resultItemParam = LVDATA_MULTISELECT; contextInfo.m_bScopeAllowed = IsScopePaneAllowed(); contextInfo.m_hWnd = m_hWnd; contextInfo.m_pConsoleView = this; contextInfo.m_hSelectedScopeNode = GetSelectedNode(); contextInfo.m_iListItemIndex = iIndex; if (HasListOrListPad()) contextInfo.m_spListView = m_pListCtrl; if ((INDEX_OCXPANE == iIndex) && HasOCX()) { contextInfo.m_resultItemParam = LVDATA_CUSTOMOCX; } else if ((INDEX_WEBPANE == iIndex) && HasWebBrowser()) { contextInfo.m_resultItemParam = LVDATA_CUSTOMWEB; } /* * if given, initialize the rectangle not to obscure */ if (prcExclude != NULL) contextInfo.m_rectExclude = *prcExclude; HNODE hNode = GetSelectedNode(); ASSERT(hNode != NULL); INodeCallback* pNodeCallback = GetNodeCallback(); ASSERT(pNodeCallback != NULL); HRESULT hr = pNodeCallback->Notify(hNode, NCLBK_CONTEXTMENU, 0, reinterpret_cast(&contextInfo)); } HTREEITEM CAMCView::FindChildNode(HTREEITEM hti, DWORD dwItemDataKey) { hti = m_pTreeCtrl->GetChildItem(hti); while (hti && (dwItemDataKey != m_pTreeCtrl->GetItemData(hti))) { hti = m_pTreeCtrl->GetNextItem(hti, TVGN_NEXT); } return hti; } /////////////////////////////////////////////////////////////////////////////// /// Context Menu Handlers for Result View Item and Background void CAMCView::ArrangeIcon(long style) { #ifdef OLD_STUFF ASSERT(m_pTreeCtrl && m_pTreeCtrl->m_pNodeInstCurr); if (!m_pTreeCtrl || !m_pTreeCtrl->m_pNodeInstCurr) return; IFrame* const pFrame = m_pTreeCtrl->m_pNodeInstCurr->GetIFrame(); ASSERT(pFrame); if (!pFrame) return; IResultDataPrivatePtr pResult = pFrame; ASSERT(static_cast(pResult)); if (pResult == NULL) return ; HRESULT hr = pResult->Arrange(style); ASSERT(SUCCEEDED(style)); #endif // OLD_STUFF } /////////////////////////////////////////////////////////////////////////////// /// Menu handlers CAMCView::ViewPane CAMCView::GetFocusedPane () { AFX_MANAGE_STATE (AfxGetAppModuleState()); ASSERT_VALID (this); CView* pActiveView = GetParentFrame()->GetActiveView(); for (ViewPane ePane = ePane_First; ePane <= ePane_Last; ePane = (ViewPane)(ePane+1)) { if (GetPaneView (ePane) == pActiveView) return (ePane); } return (ePane_None); } /*+-------------------------------------------------------------------------* * CDeferredResultPaneActivation * * * PURPOSE: If the result pane has the focus before and after the node was * selected, then the last event snapin receives is scope selected which * is incorrect. So we first set scope pane as active view but do not * send notifications. Then we set result pane as active view which * sends scope de-select and result pane select. * But when we try to set result pane as active view, the listview may * not be visible yet (if there is view extension, the behavior hides * and then shows the listview). * So we need to wait till listview is setup. We cannot use PostMessage * as the resizing of listview happens using PostMessage which is sent * later (race condition). Therefore we use the idle timer as shown below * so that activation will occur after resizing occurs. * *+-------------------------------------------------------------------------*/ class CDeferredResultPaneActivation : public CIdleTask { public: CDeferredResultPaneActivation(HWND hWndAMCView) : m_atomTask (AddAtom (_T("CDeferredResultPaneActivation"))), m_hWndAMCView(hWndAMCView) { } ~CDeferredResultPaneActivation() {} // IIdleTask methods SC ScDoWork() { DECLARE_SC (sc, TEXT("CDeferredResultPaneActivation::ScDoWork")); sc = ScCheckPointers((void*)m_hWndAMCView, E_UNEXPECTED); if (sc) return (sc); CWnd *pWnd = CWnd::FromHandle(m_hWndAMCView); sc = ScCheckPointers(pWnd, E_UNEXPECTED); if (sc) return sc; CAMCView *pAMCView = dynamic_cast(pWnd); // Since this method is called by IdleQueue, the target // CAMCView may have gone by now, if it does not exist // it is not an error (see bug 175737 related to SQL). if (! pAMCView) return sc; sc = pAMCView->ScSetFocusToResultPane(); if (sc) return sc; return sc; } SC ScGetTaskID(ATOM* pID) { DECLARE_SC (sc, TEXT("CDeferredResultPaneActivation::ScGetTaskID")); sc = ScCheckPointers(pID); if(sc) return sc; *pID = m_atomTask; return sc; } SC ScMerge(CIdleTask* pitMergeFrom) {return S_FALSE /*do not merge*/;} private: const ATOM m_atomTask; HWND m_hWndAMCView; }; /*+-------------------------------------------------------------------------* * CAMCView::ScDeferSettingFocusToResultPane * * Synopsis: If the result pane has the focus before and after the node was * selected, then the last event snapin receives is scope selected which * is incorrect. So we first set scope pane as active view but do not * send notifications. Then we set result pane as active view which * sends scope de-select and result pane select. * But when we try to set result pane as active view, the listview may * not be visible yet (if there is view extension, the behavior hides * and then shows the listview). * So we need to wait till listview is setup. We cannot use PostMessage * as the resizing of listview happens using PostMessage which is sent * later (race condition). Therefore we use the idle timer as shown below * so that activation will occur after resizing occurs. * * Returns: SC * *--------------------------------------------------------------------------*/ SC CAMCView::ScDeferSettingFocusToResultPane () { AFX_MANAGE_STATE (AfxGetAppModuleState()); // not sure if we need this, but doesn't hurt to have it in here. DECLARE_SC (sc, TEXT("CAMCView::ScDeferSettingFocusToResultPane")); CIdleTaskQueue* pIdleTaskQueue = AMCGetIdleTaskQueue(); sc = ScCheckPointers(pIdleTaskQueue, E_UNEXPECTED); if(sc) return sc; /* * create the deferred page break task */ CAutoPtr spDeferredResultPaneActivation(new CDeferredResultPaneActivation (GetSafeHwnd())); sc = ScCheckPointers(spDeferredResultPaneActivation, E_OUTOFMEMORY); if(sc) return sc; /* * put the task in the queue, which will take ownership of it * Activation should happen at lower priority than layout. */ sc = pIdleTaskQueue->ScPushTask (spDeferredResultPaneActivation, ePriority_Low); if (sc) return sc; /* * if we get here, the idle task queue owns the idle task, so * we can detach it from our smart pointer */ spDeferredResultPaneActivation.Detach(); /* * jiggle the message pump so that it wakes up and checks idle tasks */ PostMessage (WM_NULL); return (S_OK); } //+------------------------------------------------------------------- // // Member: ScSetFocusToResultPane // // Synopsis: Set focus to result pane (list or ocx or web). If result // is hidden then set to folder tab else set to tasks pane. // // Arguments: // // Returns: SC // //-------------------------------------------------------------------- SC CAMCView::ScSetFocusToResultPane () { DECLARE_SC(sc, TEXT("CAMCView::ScSetFocusToResultPane")); AFX_MANAGE_STATE (AfxGetAppModuleState()); if (GetFocusedPane() == ePane_Results) return (sc); // Make active // 1. ListView/OCX/Web if it exists else // 2. Folder tab if it exists. // 3. Tasks in console taskpad. CView* rgActivationOrderEntry[] = { GetPaneView(ePane_Results), // results m_pResultFolderTabView, // result tab control m_pViewExtensionCtrl, // view extension web page }; const int INDEX_RESULTS_PANE = 0; ASSERT (rgActivationOrderEntry[INDEX_RESULTS_PANE] == GetPaneView(ePane_Results)); int cEntries = (sizeof(rgActivationOrderEntry) / sizeof(rgActivationOrderEntry[0])); // get the currently active entry. for(int i = 0; i< cEntries; i++) { CView *pView = rgActivationOrderEntry[i]; sc = ScCheckPointers(pView, E_UNEXPECTED); if (sc) continue; if (IsWindow (pView->GetSafeHwnd()) && pView->IsWindowVisible() && pView->IsWindowEnabled()) { GetParentFrame()->SetActiveView (pView); return (sc); } } return (sc); } //+------------------------------------------------------------------- // // Member: ScSetFocusToPane // // Synopsis: Call this member to set focus to any pane. // // Arguments: // // Returns: // //-------------------------------------------------------------------- SC CAMCView::ScSetFocusToPane (ViewPane ePane) { DECLARE_SC(sc, TEXT("CAMCView::ScSetFocusToPane")); AFX_MANAGE_STATE (AfxGetAppModuleState()); if (!IsValidPane (ePane)) { ASSERT (false && "CAMCView::ScSetFocusToPane: Invalid pane specifier"); return (sc = E_FAIL); } if (GetFocusedPane() == ePane) return (sc); if (ePane == ePane_Results) return (sc = ScSetFocusToResultPane()); CView* pView = GetPaneView(ePane); if (!IsWindow (pView->GetSafeHwnd()) || !pView->IsWindowVisible() || !pView->IsWindowEnabled()) { return (sc = E_FAIL); } GetParentFrame()->SetActiveView (pView); return (sc); } //+------------------------------------------------------------------- // // Member: CAMCView::ScGetFocusedItem // // Synopsis: Get the currently selected item's context. // // Arguments: [hNode] - [out] The owner of result pane. // [lCookie] - [out] If result pane selected the LVDATA. // [fScope] - [out] scope or result // // Returns: SC // //-------------------------------------------------------------------- SC CAMCView::ScGetFocusedItem (HNODE& hNode, LPARAM& lCookie, bool& fScope) { DECLARE_SC(sc, TEXT("CAMCView::ScGetFocusedItem")); AFX_MANAGE_STATE (AfxGetAppModuleState()); ASSERT_VALID (this); lCookie = LVDATA_ERROR; hNode = GetSelectedNode(); if (hNode == NULL) return (sc = E_UNEXPECTED); switch (m_eCurrentActivePane) { case eActivePaneScope: fScope = true; break; case eActivePaneResult: { fScope = false; // Calculate the LPARAM for result item. if (HasOCX()) lCookie = LVDATA_CUSTOMOCX; else if (HasWebBrowser()) lCookie = LVDATA_CUSTOMWEB; else if (HasListOrListPad()) { int cSel = m_pListCtrl->GetSelectedCount(); ASSERT(cSel >= 0); if (cSel == 0) lCookie = LVDATA_BACKGROUND; else if (cSel == 1) _GetLVSelectedItemData (&lCookie); else if (cSel > 1) lCookie = LVDATA_MULTISELECT; } else { return (sc = E_FAIL); // dont know who has the focus??? } } break; case eActivePaneNone: default: sc = E_UNEXPECTED; break; } return (sc); } //+------------------------------------------------------------------- // // Member: CAMCView::PrivateChangeListViewMode // // Synopsis: Private function to change view mode. Consider using // ScChangeViewMode instead of this function. // // Arguments: [nMode] - view mode to be set. // //-------------------------------------------------------------------- void CAMCView::PrivateChangeListViewMode(int nMode) { DECLARE_SC(sc, TEXT("CAMCView::PrivateChangeListViewMode")); if ((nMode < 0) || (nMode > MMCLV_VIEWSTYLE_FILTERED) ) { sc = E_INVALIDARG; return; } // Add a history entry which will be same as current // one except for view mode change. sc = ScCheckPointers(m_pHistoryList, m_pListCtrl, E_UNEXPECTED); if (sc) return; // change the current history list entry's view mode sc = m_pHistoryList->ScChangeViewMode(nMode); if(sc) return; // set the list control's view mode sc = m_pListCtrl->SetViewMode(nMode); if (!sc) { m_nViewMode = nMode; SetDirty(); SetDefaultListViewStyle(GetListViewStyle()); } } //+------------------------------------------------------------------- // // Member: CAMCView::OnProcessMultiSelectionChanges // // Synopsis: message handler for m_nProcessMultiSelectionChangesMsg // messages that are posted. // // Handles multi-item de-selection for list view and then // send selection for list view items. // // This method knows that selection states of multiple items // are changed but not if they are selected or de-selected. // The m_bLastSelWasMultiSel is used to determine if it is // selection or de-selection. // // Arguments: none used. // // Returns: LRESULT // //-------------------------------------------------------------------- LRESULT CAMCView::OnProcessMultiSelectionChanges (WPARAM, LPARAM) { DECLARE_SC(sc, _T("CAMCView::OnProcessMultiSelectionChanges")); // Selection change so appropriately enable std-toolbar buttons // back, forward, export-list, up-one-level, show/hide-scope, help sc = ScUpdateStandardbarMMCButtons(); if (sc) return (0); if (! m_bProcessMultiSelectionChanges) return (0); m_bProcessMultiSelectionChanges = false; INodeCallback* pNC = GetNodeCallback(); HNODE hNodeSel = GetSelectedNode(); sc = ScCheckPointers((void*) hNodeSel, pNC, m_pListCtrl, E_UNEXPECTED); if (sc) return (0); // If some thing was selected previously send a deselection // message before sending a selection message (single item de-select // is already handled in OnListItemChanged so just handle multi item // deselect here). if (m_bLastSelWasMultiSel) { sc = ScNotifySelect (pNC, hNodeSel, true /*fMultiSelect*/, false, 0); if (sc) sc.TraceAndClear(); // ignore & continue; m_bLastSelWasMultiSel = false; } // Now send a selection message UINT cSel = m_pListCtrl->GetSelectedCount (); if (cSel == 1) { SELECTIONINFO selInfo; ZeroMemory(&selInfo, sizeof(selInfo)); selInfo.m_bScope = FALSE; int iItem = _GetLVSelectedItemData(&selInfo.m_lCookie); ASSERT(iItem != -1); sc = ScNotifySelect (pNC, hNodeSel, false /*fMultiSelect*/, true, &selInfo); if (sc) sc.TraceAndClear(); // ignore & continue; } else if (cSel > 1) { Dbg(DEB_USER1, _T(" 5. LVN_SELCHANGE <0, 1>\n")); sc = ScNotifySelect (pNC, hNodeSel, true /*fMultiSelect*/, true, 0); if (sc) sc.TraceAndClear(); // ignore & continue; m_bLastSelWasMultiSel = true; } return (0); } SC CAMCView::ScRenameListPadItem() // obsolete? { DECLARE_SC (sc, _T("CAMCView::ScRenameListPadItem")); AFX_MANAGE_STATE (AfxGetAppModuleState()); ASSERT(m_pListCtrl != NULL); ASSERT(m_pListCtrl->GetListViewPtr() != NULL); int cSel = m_pListCtrl->GetSelectedCount(); if (cSel != 1) return (sc = E_FAIL); LPARAM lParam; int iItem = _GetLVSelectedItemData(&lParam); ASSERT(iItem >= 0); if (iItem >= 0) { m_bRenameListPadItem = true; m_pListCtrl->GetListViewPtr()->SetFocus(); m_pListCtrl->GetListViewPtr()->GetListCtrl().EditLabel(iItem); m_bRenameListPadItem = false; } return (sc); } /*+-------------------------------------------------------------------------* * * CAMCView::ScOrganizeFavorites * * PURPOSE: Display the "organize favorites" dialog. * * RETURNS: * SC * *+-------------------------------------------------------------------------*/ SC CAMCView::ScOrganizeFavorites() { DECLARE_SC (sc, TEXT("CAMCView::ScOrganizeFavorites")); CAMCDoc* pDoc = GetDocument(); sc = ScCheckPointers(pDoc, E_UNEXPECTED); if(sc) return sc; CFavorites *pFavorites = pDoc->GetFavorites(); sc = ScCheckPointers(pFavorites); if(sc) return sc; pFavorites->OrganizeFavorites(this); return sc; } /*+-------------------------------------------------------------------------* * * CAMCView::ScLineUpIcons * * PURPOSE: line up the icons in the list * * RETURNS: * SC * *+-------------------------------------------------------------------------*/ SC CAMCView::ScLineUpIcons() { DECLARE_SC (sc, TEXT("CAMCView::ScLineUpIcons")); ArrangeIcon(LVA_SNAPTOGRID); return sc; } /*+-------------------------------------------------------------------------* * * CAMCView::ScAutoArrangeIcons * * PURPOSE: auto arrange the icons in the list * * RETURNS: * SC * *+-------------------------------------------------------------------------*/ SC CAMCView::ScAutoArrangeIcons() { DECLARE_SC(sc, TEXT("CAMCView::ScAutoArrangeIcons")); sc = ScCheckPointers(m_pListCtrl, E_UNEXPECTED); if(sc) return sc; m_pListCtrl->SetListStyle(m_pListCtrl->GetListStyle() ^ LVS_AUTOARRANGE); return sc; } /*+-------------------------------------------------------------------------* * * CAMCView::ScOnRefresh * * PURPOSE: Refreshes the view. * * RETURNS: * SC * *+-------------------------------------------------------------------------*/ SC CAMCView::ScOnRefresh(HNODE hNode, bool bScope, LPARAM lResultItemParam) { DECLARE_SC(sc, TEXT("CAMCView::ScOnRefresh")); sc = ScCheckPointers((void*)hNode); if (sc) return sc; HWND hwnd = ::GetFocus(); sc = ScProcessConsoleVerb(hNode, bScope, lResultItemParam, evRefresh); ::SetFocus(hwnd); if (sc) return sc; return sc; } /***************************************************************************\ * * CLASS: CDeferredRenameListItem * * PURPOSE: This class encapsulates means to put a list control in the rename mode * asynchronously. This is needed to assure all mesages are processed before * and no-one will steel the focus ending unexpectidly the edit mode. * * USAGE: * use CDeferredRenameListItem::ScDoRenameAsIdleTask() to invoke the operation * asyncronously * \***************************************************************************/ class CDeferredRenameListItem : public CIdleTask { // constructor - used internally only CDeferredRenameListItem( HWND hwndListCtrl, int iItemIndex ) : m_atomTask (AddAtom (_T("CDeferredRenameListItem"))), m_hwndListCtrl(hwndListCtrl), m_iItemIndex(iItemIndex) { } protected: // IIdleTask methods SC ScDoWork() { DECLARE_SC (sc, TEXT("CDeferredRenameListItem::ScDoWork")); // get the ListCtrl pointer CListCtrl *pListCtrl = (CListCtrl *)CWnd::FromHandlePermanent(m_hwndListCtrl); sc = ScCheckPointers( pListCtrl ); if (sc) return sc; // do what you are asked for - put LV in the rename mode pListCtrl->SetFocus(); // set the focus first. Don't need to do a SetActiveView here, I believe (vivekj) pListCtrl->EditLabel( m_iItemIndex ); return sc; } SC ScGetTaskID(ATOM* pID) { DECLARE_SC (sc, TEXT("CDeferredPageBreak::ScGetTaskID")); sc = ScCheckPointers(pID); if(sc) return sc; *pID = m_atomTask; return sc; } SC ScMerge(CIdleTask* pitMergeFrom) { return S_FALSE /*do not merge*/; } public: // this method is called to invoke rename asyncronously. // it constructs the idle task and puts it into the queue static SC ScDoRenameAsIdleTask( HWND hwndListCtrl, int iItemIndex ) { DECLARE_SC(sc, TEXT("CDeferredPageBreak::ScDoRenameAsIdleTask")); CIdleTaskQueue* pIdleTaskQueue = AMCGetIdleTaskQueue(); sc = ScCheckPointers(pIdleTaskQueue, E_UNEXPECTED); if(sc) return sc; // create the deferred task CAutoPtr spTask(new CDeferredRenameListItem (hwndListCtrl, iItemIndex)); sc = ScCheckPointers( spTask, E_OUTOFMEMORY); if(sc) return sc; // put the task in the queue, which will take ownership of it sc = pIdleTaskQueue->ScPushTask (spTask, ePriority_Normal); if (sc) return sc; // ownership tranfered to the queue, get rid of control over the pointer spTask.Detach(); return sc; } private: const ATOM m_atomTask; HWND m_hwndListCtrl; int m_iItemIndex; }; /*+-------------------------------------------------------------------------* * * CAMCView::ScOnRename * * PURPOSE: Allows the user to renames the scope or result item specified by pContextInfo * * PARAMETERS: * CContextMenuInfo * pContextInfo : * * RETURNS: * SC * *+-------------------------------------------------------------------------*/ SC CAMCView::ScOnRename(CContextMenuInfo *pContextInfo) { DECLARE_SC(sc, TEXT("CAMCView::ScOnRename")); sc = ScCheckPointers(pContextInfo, m_pTreeCtrl, m_pListCtrl); if(sc) return sc; if (pContextInfo->m_htiRClicked != NULL) { m_pTreeCtrl->EditLabel(pContextInfo->m_htiRClicked); } else { ASSERT(pContextInfo->m_iListItemIndex >= 0); sc = ScCheckPointers(m_pListCtrl->GetListCtrl()); if(sc) return sc; // Do this on idle - or else we'll suffer from someone steeling focus // Syncronous operation fails in console task case. sc = CDeferredRenameListItem::ScDoRenameAsIdleTask( m_pListCtrl->GetListCtrl().m_hWnd, pContextInfo->m_iListItemIndex ); if(sc) return sc; } return sc; } /*+-------------------------------------------------------------------------* * * CAMCView::ScRenameScopeNode * * PURPOSE: put the specified scope node into rename mode. * * PARAMETERS: * HMTNODE hMTNode : The scope node * * RETURNS: * SC * *+-------------------------------------------------------------------------*/ SC CAMCView::ScRenameScopeNode(HMTNODE hMTNode) { DECLARE_SC(sc, TEXT("CAMCView::ScRenameScopeNode")); sc = ScCheckPointers(m_pTreeCtrl, E_FAIL); if(sc) return sc; sc = m_pTreeCtrl->ScRenameScopeNode(hMTNode); return sc; } /*+-------------------------------------------------------------------------* * * CAMCView::ScGetStatusBar * * PURPOSE: Returns the status bar * * PARAMETERS: * CConsoleStatusBar ** ppStatusBar : * * RETURNS: * SC * *+-------------------------------------------------------------------------*/ SC CAMCView::ScGetStatusBar(CConsoleStatusBar **ppStatusBar) { DECLARE_SC(sc, TEXT("CAMCView::ScGetStatusBar")); sc = ScCheckPointers(ppStatusBar); if(sc) return sc; *ppStatusBar = m_ViewData.GetStatusBar(); return sc; } /*+-------------------------------------------------------------------------* * * CAMCView::ScGetProperty * * PURPOSE: Gets the property for a result item * * PARAMETERS: * int m_iIndex : The index of the item in the list. * BSTR bstrPropertyName : * PBSTR pbstrPropertyValue : * * RETURNS: * SC * *+-------------------------------------------------------------------------*/ SC CAMCView::ScGetProperty(int iIndex, BSTR bstrPropertyName, PBSTR pbstrPropertyValue) { DECLARE_SC(sc, TEXT("CAMCView::ScGetProperty")); sc = ScCheckPointers(GetNodeCallback(), m_pListCtrl, E_UNEXPECTED); if(sc) return sc; LPARAM resultItemParam = iIndex; // the virtual list case bool bScopeItem = false; // the virtual list case if(!IsVirtualList()) { CResultItem *pri = NULL; sc = m_pListCtrl->GetLParam(iIndex, pri); if(sc) return sc; resultItemParam = CResultItem::ToHandle(pri); sc = ScCheckPointers(pri); if(sc) return sc; bScopeItem = pri->IsScopeItem(); } sc = GetNodeCallback()->GetProperty(GetSelectedNode(), bScopeItem, resultItemParam, bstrPropertyName, pbstrPropertyValue); return sc; } /*+-------------------------------------------------------------------------* * * CAMCView::ScGetNodetype * * PURPOSE: Returns the nodetype for a list item * * PARAMETERS: * int iIndex : * PBSTR Nodetype : * * RETURNS: * SC * *+-------------------------------------------------------------------------*/ SC CAMCView::ScGetNodetype(int iIndex, PBSTR Nodetype) { DECLARE_SC(sc, TEXT("CAMCView::ScGetProperty")); sc = ScCheckPointers(GetNodeCallback(), m_pListCtrl, E_UNEXPECTED); if(sc) return sc; LPARAM resultItemParam = iIndex; // the virtual list case bool bScopeItem = false; // the virtual list case if(!IsVirtualList()) { CResultItem *pri = NULL; sc = m_pListCtrl->GetLParam(iIndex, pri); if(sc) return sc; resultItemParam = CResultItem::ToHandle(pri); sc = ScCheckPointers(pri); if(sc) return sc; bScopeItem = pri->IsScopeItem(); } sc = GetNodeCallback()->GetNodetypeForListItem(GetSelectedNode(), bScopeItem, resultItemParam, Nodetype); return sc; } /*+-------------------------------------------------------------------------* * CAMCView::ScAddViewExtension * * *--------------------------------------------------------------------------*/ SC CAMCView::ScAddViewExtension (const CViewExtensionData& ved) { DECLARE_SC (sc, _T("CAMCView::ScAddViewExtension")); return (sc); } void CAMCView::OnChangedResultTab(NMHDR *nmhdr, LRESULT *pRes) { DECLARE_SC(sc, TEXT("CAMCView::OnChangedResultTab")); NMFOLDERTAB* nmtab = static_cast(nmhdr); int iTab = nmtab->iItem; CFolderTab &tab = m_pResultFolderTabView->GetItem(iTab); GUID guidTaskpad = tab.GetClsid(); // check if we're moving to the same taskpad. GUID guidCurrentTaskpad; GetTaskpadID(guidCurrentTaskpad); if(guidTaskpad == guidCurrentTaskpad) return; // lookup view extension URL CViewExtensionURLs::iterator itVE = m_ViewExtensionURLs.find(guidTaskpad); LPCTSTR url = (itVE != m_ViewExtensionURLs.end()) ? itVE->second.c_str() : NULL; // apply URL sc = ScApplyViewExtension(url); if (sc) sc.TraceAndClear(); GetNodeCallback()->SetTaskpad(GetSelectedNode(), &guidTaskpad); // if not found, guidTaskpad is set to GUID_NULL. // After setting the taskpad enable/disable save list button CStandardToolbar* pStdToolbar = GetStdToolbar(); ASSERT(NULL != pStdToolbar); if (NULL != pStdToolbar) { pStdToolbar->ScEnableExportList(GetListSize() > 0 /*Enable only if LV has items*/); } // the taskpad changed. Create a new entry in the history list. sc = m_pHistoryList->ScModifyViewTab( guidTaskpad ); if(sc) sc.TraceAndClear(); } HRESULT CAMCView::GetRootNodePath( CBookmark* pbm) { HTREEITEM htiRoot = m_pTreeCtrl->GetRootItem(); return GetNodePath(htiRoot, htiRoot, pbm); } HRESULT CAMCView::GetSelectedNodePath( CBookmark* pbm) { return GetNodePath(m_pTreeCtrl->GetSelectedItem(), m_pTreeCtrl->GetRootItem(), pbm); } HRESULT CAMCView::GetNodePath( HTREEITEM hti, HTREEITEM htiRoot, CBookmark* pbm) { TRACE_METHOD(CAMCView, GetRootNodeID); if (hti == NULL) return E_FAIL; if (htiRoot == NULL) return E_FAIL; ASSERT(hti != NULL); ASSERT(htiRoot != NULL); HNODE hNode = (HNODE)m_pTreeCtrl->GetItemData(hti); HNODE hRootNode = (HNODE)m_pTreeCtrl->GetItemData(htiRoot); HRESULT hr = m_spNodeCallback->GetPath(hNode, hRootNode, (LPBYTE) pbm); return hr; } inline HMTNODE CAMCView::GetHMTNode(HTREEITEM hti) { TRACE_METHOD(CAMCView, GetHMTNode); HNODE hNode = (HNODE)m_pTreeCtrl->GetItemData(hti); HMTNODE hMTNodeTemp; HRESULT hr = m_spNodeCallback->GetMTNode(hNode, &hMTNodeTemp); CHECK_HRESULT(hr); return hMTNodeTemp; } HTREEITEM CAMCView::FindHTreeItem(HMTNODE hMTNode, HTREEITEM hti) { TRACE_METHOD(CAMCView, FindHTreeItem); while (hti) { if (hMTNode == GetHMTNode(hti)) break; hti = m_pTreeCtrl->GetNextItem(hti, TVGN_NEXT); } return hti; } UINT CAMCView::ClipPath(CHMTNODEList* pNodeList, POSITION& rpos, HNODE hNode) { TRACE_METHOD(CAMCView, ClipPath); UINT uiReturn = ITEM_IS_IN_VIEW; CCoTaskMemPtr sphMTNode; long lLength = 0; HRESULT hr = m_spNodeCallback->GetMTNodePath(hNode, &sphMTNode, &lLength); CHECK_HRESULT(hr); if (FAILED(hr)) return hr; ASSERT(lLength == 0 || sphMTNode != NULL); for (long i=0; rpos != 0 && i < lLength; i++) { HMTNODE hMTNode = pNodeList->GetNext(rpos); if (hMTNode != sphMTNode[i]) { uiReturn = ITEM_NOT_IN_VIEW; break; } } if (uiReturn == ITEM_NOT_IN_VIEW) return ITEM_NOT_IN_VIEW; return (rpos == 0 && lLength >= i) ? ITEM_IS_PARENT_OF_ROOT : ITEM_IS_IN_VIEW; } // // GetTreeItem returns TRUE if it can find the htreeitem of the item // whose HMTNode is equal to the last element in pNodeList. It returns // FALSE if the node does not appear in the view name space or if the // the node has not yet been created. // // "pNodeList" is a list of HMTNODEs such that pNodeList[n] is the parent // of pNodeList[n+1]. // UINT CAMCView::GetTreeItem(CHMTNODEList* pNodeList, HTREEITEM* phItem) { TRACE_METHOD(CAMCView, GetTreeItem); ASSERT(pNodeList->IsEmpty() == FALSE); HTREEITEM hti = NULL; HMTNODE hMTNodeTemp = 0; hti = m_pTreeCtrl->GetRootItem(); if (hti == NULL) return ITEM_NOT_IN_VIEW; HNODE hNode = (HNODE)m_pTreeCtrl->GetItemData(hti); POSITION pos = pNodeList->GetHeadPosition(); UINT uiReturn = ClipPath(pNodeList, pos, hNode); if (uiReturn != ITEM_IS_IN_VIEW) return uiReturn; HTREEITEM htiTemp = NULL; while (pos && hti) { hMTNodeTemp = (HMTNODE)pNodeList->GetNext(pos); hti = FindHTreeItem(hMTNodeTemp, hti); ASSERT(hti == NULL || hMTNodeTemp == GetHMTNode(hti)); htiTemp = hti; if (hti != NULL) hti = m_pTreeCtrl->GetChildItem(hti); } if (pos == 0 && htiTemp != NULL) { // Found the node. ASSERT(hMTNodeTemp == pNodeList->GetTail()); ASSERT(hMTNodeTemp == GetHMTNode(htiTemp)); *phItem = htiTemp; return ITEM_IS_IN_VIEW; } else { // The node has not yet been created. *phItem = NULL; return ITEM_NOT_IN_VIEW; } return ITEM_IS_IN_VIEW; } #define HMTNODE_FIRST reinterpret_cast(TVI_FIRST) #define HMTNODE_LAST reinterpret_cast(TVI_LAST) void CAMCView::OnAdd(SViewUpdateInfo *pvui) { TRACE_METHOD(CAMCView, OnAdd); ASSERT(pvui->path.IsEmpty() == FALSE); HTREEITEM htiParent; if (GetTreeItem(&pvui->path, &htiParent) != ITEM_IS_IN_VIEW || htiParent == NULL) return; bool bFirstChild = (m_pTreeCtrl->GetChildItem(htiParent) == NULL); HNODE hNodeParent = (HNODE)m_pTreeCtrl->GetItemData(htiParent); if (m_spNodeCallback->Notify(hNodeParent, NCLBK_EXPAND, 0, 0) == S_FALSE) { m_pTreeCtrl->SetCountOfChildren(htiParent, 1); return; // Don't add if it is not expanded. } // If the hNode was already expanded add the item. IScopeTree* const pScopeTree = GetScopeTree(); ASSERT(pScopeTree != NULL); HNODE hNodeNew = 0; HRESULT hr = pScopeTree->CreateNode(pvui->newNode, reinterpret_cast(GetViewData()), FALSE, &hNodeNew); CHECK_HRESULT(hr); if (FAILED(hr)) return; HTREEITEM hInsertAfter = TVI_LAST; int iInsertIndex = -1; if (pvui->insertAfter != NULL) { hInsertAfter = reinterpret_cast(pvui->insertAfter); if (pvui->insertAfter == HMTNODE_LAST) { } else if (pvui->insertAfter == HMTNODE_FIRST) { iInsertIndex = 0; } else { HTREEITEM hti = m_pTreeCtrl->GetChildItem(htiParent); ASSERT(hti != NULL); iInsertIndex = 1; while (hti != NULL) { if (GetHMTNode(hti) == pvui->insertAfter) break; hti = m_pTreeCtrl->GetNextSiblingItem(hti); iInsertIndex++; } if (hti) { hInsertAfter = hti; } else { hInsertAfter = TVI_LAST; iInsertIndex = -1; } } } if (m_pTreeCtrl->InsertNode(htiParent, hNodeNew, hInsertAfter) == NULL) return; // if parent of the inserted item currently owns a non-virtual result list, // add the item to result list too. Don't add the item if a node select is in // progress because the tree control will automatically add all scope items // as part of the select procedure. if (OwnsResultList(htiParent) && CanInsertScopeItemInResultPane() ) { // Ensure the node is enumerated m_pTreeCtrl->ExpandNode(htiParent); // Add to result pane. RESULTDATAITEM tRDI; ::ZeroMemory(&tRDI, sizeof(tRDI)); tRDI.mask = RDI_STR | RDI_IMAGE | RDI_PARAM; tRDI.nCol = 0; tRDI.str = MMC_TEXTCALLBACK; tRDI.nIndex = iInsertIndex; int nImage; int nSelectedImage; hr = m_spNodeCallback->GetImages(hNodeNew, &nImage, &nSelectedImage); ASSERT(hr == S_OK || nImage == 0); tRDI.nImage = nImage; tRDI.lParam = CAMCTreeView::LParamFromNode (hNodeNew); LPRESULTDATA pResultData = m_pTreeCtrl->GetResultData(); ASSERT(pResultData != NULL); hr = pResultData->InsertItem(&tRDI); CHECK_HRESULT(hr); if (SUCCEEDED(hr)) hr = m_spNodeCallback->SetResultItem(hNodeNew, tRDI.itemID); } if ((m_pTreeCtrl->GetRootItem() == htiParent) || ((bFirstChild == true) && (m_spNodeCallback->Notify(hNodeParent, NCLBK_GETEXPANDEDVISUALLY, 0, 0) == S_OK))) { m_pTreeCtrl->Expand(htiParent, TVE_EXPAND); } } void CAMCView::OnDeleteEmptyView() { if (m_pTreeCtrl->GetRootItem() == NULL) { ++m_nReleaseViews; if (m_nReleaseViews == 3) { // Ensure that there is at least one *persistable* view CAMCDoc* pDoc = dynamic_cast(GetDocument()); ASSERT(pDoc != NULL); int cViews = pDoc->GetNumberOfPersistedViews(); ASSERT(cViews >= 1); if ((cViews == 1) && IsPersisted()) { CMainFrame* pMain = dynamic_cast(AfxGetMainWnd()); ASSERT(pMain != NULL); if ( pMain != NULL ) pMain->SendMessage(WM_COMMAND, ID_WINDOW_NEW, 0); } DeleteView(); } } } void CAMCView::OnDelete(SViewUpdateInfo *pvui) { TRACE_METHOD(CAMCView, OnDelete); ASSERT(pvui->path.IsEmpty() == FALSE); HTREEITEM hti; UINT uiReturn = GetTreeItem(&pvui->path, &hti); if (uiReturn == ITEM_NOT_IN_VIEW) return; ASSERT(uiReturn != ITEM_IS_IN_VIEW || pvui->path.GetTail() == GetHMTNode(hti)); HTREEITEM htiSel = m_pTreeCtrl->GetSelectedItem(); BOOL fDeleteThis = (pvui->flag & VUI_DELETE_THIS) ? TRUE : FALSE; BOOL fExpandable = (pvui->flag & VUI_DELETE_SETAS_EXPANDABLE) ? TRUE : FALSE; if (uiReturn == ITEM_IS_PARENT_OF_ROOT || NULL == hti) { hti = m_pTreeCtrl->GetRootItem(); fDeleteThis = TRUE; fExpandable = FALSE; } ASSERT(hti != NULL); // If deleted scope item is also shown in the result pane // delete it there too. Can't happen with a virtual list. // Don't try deleting item if selection is in progress because // the scope items haven't been added yet. if (fDeleteThis == TRUE && OwnsResultList(m_pTreeCtrl->GetParentItem(hti)) && CanInsertScopeItemInResultPane()) { INodeCallback* pNC = GetNodeCallback(); HRESULTITEM itemID; HNODE hNode = (HNODE)m_pTreeCtrl->GetItemData(hti); HRESULT hr = pNC->GetResultItem(hNode, &itemID); if (SUCCEEDED(hr) && itemID != 0) { IResultData* pIRD = m_pTreeCtrl->GetResultData(); pIRD->DeleteItem(itemID, 0); } } m_pTreeCtrl->DeleteNode(hti, fDeleteThis); if (fDeleteThis == FALSE && fExpandable == TRUE) m_pTreeCtrl->SetItemState(hti, 0, TVIS_EXPANDEDONCE | TVIS_EXPANDED); } /*+-------------------------------------------------------------------------* * * CAMCView::OnUpdateSelectionForDelete * * PURPOSE: Called when a scope node is deleted. If the node is an ancestor * of the currently selected node, the selection is changed to the closest * node of the deleted node. This is either the next sibling of the node that is being deleted, * or, if there is no next sibling, the previous sibling, or, if there is none, * the parent. * * PARAMETERS: * SViewUpdateInfo* pvui : * * RETURNS: * void * *+-------------------------------------------------------------------------*/ void CAMCView::OnUpdateSelectionForDelete(SViewUpdateInfo* pvui) { DECLARE_SC(sc, TEXT("CAMCView::OnUpdateSelectionForDelete")); // make sure we have a path to the deleted node. if(pvui->path.IsEmpty()) { sc = E_UNEXPECTED; return; } HTREEITEM htiToDelete; UINT uiReturn = GetTreeItem(&pvui->path, &htiToDelete); if (uiReturn == ITEM_IS_IN_VIEW && NULL != htiToDelete) { HTREEITEM htiSel = m_pTreeCtrl->GetSelectedItem(); BOOL fDeleteThis = (pvui->flag & VUI_DELETE_THIS); // Determine whether the selected node is a descendant of the // node bring deleted. HTREEITEM htiTemp = htiSel; while (htiTemp != NULL && htiTemp != htiToDelete) { htiTemp = m_pTreeCtrl->GetParentItem(htiTemp); } if (htiToDelete == htiTemp) { // The selected node is a descendant of the // node being deleted. if (fDeleteThis == TRUE) htiTemp = m_pTreeCtrl->GetParentItem(htiToDelete); if (!htiTemp) htiTemp = htiToDelete; if (htiTemp != htiSel) { HNODE hNode = m_pTreeCtrl->GetItemNode(htiSel); m_pTreeCtrl->OnDeSelectNode(hNode); ASSERT(htiTemp != NULL); if (htiTemp != NULL) m_pTreeCtrl->SelectItem(htiTemp); } } } } /*+-------------------------------------------------------------------------* * CAMCView::OnUpdateTaskpadNavigation * * PURPOSE: * * PARAMETERS: * SViewUpdateInfo * pvui: * * RETURNS: * void /*+-------------------------------------------------------------------------*/ void CAMCView::OnUpdateTaskpadNavigation(SViewUpdateInfo *pvui) { TRACE_METHOD(CAMCView, OnupdateTaskpadNavigation); ASSERT(pvui->newNode != NULL); //m_spNodeCallback->UpdateTaskpadNavigation(GetSelectedNode(), pvui->newNode); } /*+-------------------------------------------------------------------------* * CAMCView::OnModify * * PURPOSE: * * PARAMETERS: * SViewUpdateInfo * pvui: * * RETURNS: * void /*+-------------------------------------------------------------------------*/ void CAMCView::OnModify(SViewUpdateInfo *pvui) { TRACE_METHOD(CAMCView, OnModify); ASSERT(pvui->path.IsEmpty() == FALSE); HNODE hNode = 0; HTREEITEM hti; if (GetTreeItem(&pvui->path, &hti) == ITEM_IS_IN_VIEW && hti != NULL) { ASSERT(m_pTreeCtrl != NULL); m_pTreeCtrl->ResetNode(hti); /* * The name of the selected node and all of its ancestors are * displayed in the frame title. If the modified item is an * ancestor of the selected node, we need to update the frame title. */ HTREEITEM htiAncesctor; for (htiAncesctor = m_pTreeCtrl->GetSelectedItem(); htiAncesctor != NULL; htiAncesctor = m_pTreeCtrl->GetParentItem (htiAncesctor)) { if (htiAncesctor == hti) { CChildFrame* pFrame = GetParentFrame(); if (pFrame) pFrame->OnUpdateFrameTitle(TRUE); break; } } ASSERT(hti != NULL); if (hti != NULL && OwnsResultList(m_pTreeCtrl->GetParentItem(hti)) && !IsVirtualList()) { // Continue only if the currently selected item is the parent // of the modified node. In this case we need to update the // result view. Can't happen with a virtual list. if (hNode == 0) hNode = (HNODE)m_pTreeCtrl->GetItemData(hti); ASSERT(hNode != NULL); HRESULTITEM hri; HRESULT hr = m_spNodeCallback->GetResultItem(hNode, &hri); CHECK_HRESULT(hr); // NOTE: the test for itemID != NULL below is related to bug 372242: // MMC asserts on index server root node. // What happens is that the snapin adds scope nodes on a SHOW event. // These items have not yet been added to the result pane and so itemID // comes back NULL. if (SUCCEEDED(hr) && hri != NULL) m_pListCtrl->OnModifyItem(CResultItem::FromHandle(hri)); } } } void CAMCView::OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint) { Dbg(DEB_USER1, _T("CAMCView::OnUpdate<0x%08x, 0x%08x, 0x%08x>\n"), pSender, lHint, pHint); SViewUpdateInfo *pvui = reinterpret_cast(pHint); switch (lHint) { case 0: // Sent by CView::OnInitialUpdate() break; case VIEW_UPDATE_ADD: OnAdd(pvui); break; case VIEW_UPDATE_SELFORDELETE: OnUpdateSelectionForDelete(pvui); break; case VIEW_UPDATE_DELETE: OnDelete(pvui); break; case VIEW_UPDATE_DELETE_EMPTY_VIEW: OnDeleteEmptyView(); break; case VIEW_UPDATE_MODIFY: OnModify(pvui); break; case VIEW_RESELECT: if (m_ViewData.m_spControlbarsCache != NULL) m_ViewData.m_spControlbarsCache->DetachControlbars(); m_pTreeCtrl->ScReselect(); break; case VIEW_UPDATE_TASKPAD_NAVIGATION: OnUpdateTaskpadNavigation(pvui); break; default: ASSERT(0); } } static int static_nViewID = 1; UINT CAMCView::GetViewID(void) { if (m_nViewID) return m_nViewID; SetViewID(static_nViewID); ++static_nViewID; return m_nViewID; //UINT const id = m_nViewID ? m_nViewID : m_nViewID = static_nViewID++; //return id; } /*+-------------------------------------------------------------------------* * CAMCView::ScCompleteInitialization * * This function completes the initialization process for CAMCView. It * is called from OnInitialUpdate. *--------------------------------------------------------------------------*/ SC CAMCView::ScCompleteInitialization() { DECLARE_SC (sc, _T("CAMCView::ScCompleteInitialization")); IScopeTree* const pScopeTree = GetScopeTree(); sc = ScCheckPointers (pScopeTree, E_UNEXPECTED); if (sc) return (sc); pScopeTree->QueryIterator(&m_spScopeTreeIter); pScopeTree->QueryNodeCallback(&m_spNodeCallback); m_ViewData.m_spNodeCallback = GetNodeCallback(); sc = ScCheckPointers (m_ViewData.m_spNodeCallback, E_UNEXPECTED); if (sc) return (sc); CAMCDoc* const pDoc = GetDocument(); sc = ScCheckPointers (pDoc, E_UNEXPECTED); if (sc) return (sc); if (m_hMTNode == NULL) { MTNODEID const nodeID = pDoc->GetMTNodeIDForNewView(); HRESULT hr = pScopeTree->Find(nodeID, &m_hMTNode); if (FAILED(hr) || m_hMTNode == 0) { sc.FromMMC (IDS_ExploredWindowFailed); return (sc); } } sc = m_spStandardToolbar->ScInitializeStdToolbar(this); if (sc) return (sc); // Set the iterator to the correct node m_spScopeTreeIter->SetCurrent(m_hMTNode); bool fShowScopePane = IsScopePaneAllowed(); // Intialize the iterator and the callback interface SetViewID(pDoc->GetViewIDForNewView()); GetViewID(); // initialized the view id if GetViewIDForNewView returned 0 // Insert the root node for this view HNODE hNode = 0; sc = pScopeTree->CreateNode (m_hMTNode, reinterpret_cast(GetViewData()), TRUE, &hNode); if (sc) return (sc); sc = ScCheckPointers (hNode, E_UNEXPECTED); if (sc) return (sc); HTREEITEM hti = m_pTreeCtrl->InsertNode(TVI_ROOT, hNode); m_htiStartingSelectedNode = hti; // If the persisted state is expanded, call INodeCallback::Expand m_pTreeCtrl->Expand(hti, TVE_EXPAND); /* * If a scope pane is permitted in this window, set the scope * pane visible, and modify the scope pane & favorites toolbar * buttons to the proper checked state. */ sc = ScShowScopePane (fShowScopePane, true); if (sc) return (sc); LPUNKNOWN pUnkResultsPane = NULL; pUnkResultsPane = GetPaneUnknown(ePane_Results); m_pTreeCtrl->m_spNodeManager->SetResultView(pUnkResultsPane); DeferRecalcLayout(); m_pHistoryList->Clear(); IdentifyRootNode (); // Select the root item hti = m_pTreeCtrl->GetRootItem(); m_pTreeCtrl->SelectItem(hti); /* * if the document has a custom icon, use it on this window */ if (pDoc->HasCustomIcon()) { GetParentFrame()->SetIcon (pDoc->GetCustomIcon(true), true); GetParentFrame()->SetIcon (pDoc->GetCustomIcon(false), false); } /* * we just initialized, so the view isn't dirty */ SetDirty (false); return (sc); } void CAMCView::OnInitialUpdate() { DECLARE_SC (sc, _T("CAMCView::OnInitialUpdate")); CView::OnInitialUpdate(); sc = ScCompleteInitialization (); if (sc) return; } //+------------------------------------------------------------------- // // Member: CAMCView::ScDocumentLoadCompleted // // Synopsis: The document is completely loaded so all the objects // that initialize themself from document are in valid // state. Any initialization performed earlier using invalid // data can be now re-initialized with proper data. // // The above CAMCView::ScCompleteInitialization is called // during the loading of views, thus the document is not // completely loaded yet. // // Arguments: [pDoc] - [in] the CAMCDoc object // // Returns: SC // //-------------------------------------------------------------------- SC CAMCView::ScDocumentLoadCompleted (CAMCDoc *pDoc) { DECLARE_SC(sc, _T("CAMCView::ScDocumentLoadCompleted")); sc = ScCheckPointers(pDoc); if (sc) return sc; // 1. Need to hide toolbutton "Show/Hide scopetree". // The FrameState is loaded after views when CAMCDoc loads document. And it contains // whether the "View Customization" is enabled or not. If "View customization" is // disabled then we need to disable "Show ScopeTree" button. if (! pDoc->AllowViewCustomization()) { CStandardToolbar* pStdToolbar = GetStdToolbar(); sc = ScCheckPointers(pStdToolbar, E_UNEXPECTED); if (sc) return (sc); sc = pStdToolbar->ScEnableScopePaneBtn (false); if (sc) return (sc); } return (sc); } /*--------------------------------------------------------------------------* * CAMCView::IdentifyRootNode * * This functions determines if this view is rooted at a non-persistent * dynamic node. If so, we won't persist this view at save time. *--------------------------------------------------------------------------*/ void CAMCView::IdentifyRootNode () { // In order to get results from GetRootNodePath that are meaningful // in this context, there needs to be a root item in the tree. ASSERT (m_pTreeCtrl->GetRootItem() != NULL); CBookmark bm; HRESULT hr = GetRootNodePath (&bm); ASSERT (SUCCEEDED (hr) == bm.IsValid()); m_fRootedAtNonPersistedDynamicNode = (hr != S_OK); } void GetFullPath(CAMCTreeView &ctc, HTREEITEM hti, CString &strPath) { TRACE_FUNCTION(GetFullPath); if (hti == NULL) { strPath = _T(""); return; } GetFullPath(ctc, ctc.GetParentItem(hti), strPath); if (strPath.GetLength() > 0) strPath += _T('\\'); HNODE hNode = ctc.GetItemNode(hti); INodeCallback* spCallback = ctc.GetNodeCallback(); ASSERT(spCallback != NULL); tstring strName; HRESULT const hr = spCallback->GetDisplayName(hNode, strName); strPath += strName.data(); } LPCTSTR CAMCView::GetWindowTitle(void) { TRACE_METHOD(CAMCView, GetWindowTitle); if (HasCustomTitle() && (m_spNodeCallback != NULL)) { HNODE hNode = GetSelectedNode(); if (hNode != NULL) { tstring strWindowTitle; if (SUCCEEDED(m_spNodeCallback->GetWindowTitle(hNode, strWindowTitle))) { m_strWindowTitle = strWindowTitle.data(); return m_strWindowTitle; } } } if (m_pTreeCtrl == NULL) { m_strWindowTitle.Empty(); } else { GetFullPath(*m_pTreeCtrl, m_pTreeCtrl->GetSelectedItem(), m_strWindowTitle); } return m_strWindowTitle; } void CAMCView::SelectNode(MTNODEID ID, GUID &guidTaskpad) { ScSelectNode(ID); // After setting the taskpad enable/disable save list button CStandardToolbar* pStdToolbar = GetStdToolbar(); ASSERT(NULL != pStdToolbar); if (NULL != pStdToolbar) { pStdToolbar->ScEnableExportList(GetListSize() > 0 /*Enable only if LV has items*/); } } //+------------------------------------------------------------------- // // Member: CAMCView::ScSelectNode // // Synopsis: Select the given node. Normally if the node is not available // then we select nearest parent or child. But if bSelectExactNode // is true then have to select the exact node else do not select any node. // // Arguments: [ID] - [in] node that needs to be selected. // [bSelectExactNode] - [in] select exact node or not? // // Returns: SC // //-------------------------------------------------------------------- SC CAMCView::ScSelectNode (MTNODEID ID, bool bSelectExactNode) { AFX_MANAGE_STATE (AfxGetAppModuleState()); DECLARE_SC (sc, _T("CAMCView::ScSelectNode")); IScopeTree* pIST = GetScopeTreePtr(); sc = ScCheckPointers(pIST, m_pTreeCtrl, E_UNEXPECTED); if (sc) return sc; long length = 0; CCoTaskMemPtr spIDs; sc = pIST->GetIDPath(ID, &spIDs, &length); if (sc) return (sc); if ( (length < 1) || (spIDs == NULL) ) return (sc = E_FAIL); sc = m_pTreeCtrl->ScSelectNode(spIDs, length, bSelectExactNode); // If select exact node is specified and the node could not be // selected then return error without tracing it. if (bSelectExactNode && (sc == ScFromMMC(IDS_NODE_NOT_FOUND)) ) { SC scNoTrace = sc; sc.Clear(); return scNoTrace; } if (sc) return sc; SetDirty(); return (sc); } /*+-------------------------------------------------------------------------* * * CAMCView::ScExpandNode * * PURPOSE: Expands the tree up to the specified node. The expansion can occur * either visually, where the user sees the expansion, or nonvisually, * where all the child items are added but there is no visual effect. * * PARAMETERS: * MTNODEID id : id of node to expand * bool bExpand : true to expand the node, false to collapse * bool bExpandVisually : true to show the changes, else false. * * RETURNS: * SC * *+-------------------------------------------------------------------------*/ SC CAMCView::ScExpandNode ( MTNODEID id, bool fExpand, bool fExpandVisually) { AFX_MANAGE_STATE (AfxGetAppModuleState()); DECLARE_SC (sc, _T("CAMCView::ScExpandNode")); IScopeTree* pIST = GetScopeTreePtr(); ASSERT(pIST != NULL); if (!pIST) return (sc = E_NOINTERFACE); long length = 0; CCoTaskMemPtr spIDs; sc = pIST->GetIDPath(id, &spIDs, &length); if (sc) return (sc); ASSERT(length); ASSERT(spIDs); ASSERT(m_pTreeCtrl != NULL); if (m_pTreeCtrl) m_pTreeCtrl->ExpandNode(spIDs, length, fExpand, fExpandVisually); return (sc); } ViewSettings::ViewSettings(CAMCView* v) : m_nViewID(v->m_nViewID), m_bDescriptionbarVisible(v->IsDescBarVisible()), m_nViewMode(v->m_nViewMode), m_nListViewStyle(v->GetDefaultListViewStyle()), m_DefaultLVStyle(v->m_DefaultLVStyle), m_bScopePaneVisible(v->IsScopePaneVisible()) { ASSERT(v != NULL); v->GetPaneInfo (CConsoleView::ePane_ScopeTree, &m_Scope.cxWidth, &m_Scope.cxMin); v->GetDefaultColumnWidths(m_DefaultColumnWidths); } /* * The location and hidden fields of the scope structure were redundant and are * no longer used. Both fields were used to indicate when the scope pane was * hidden, which is also determined by the FLAG1_SCOPE_VISIBLE flag. The space * has been retained to avoid changing the persisted structure. */ struct PersistedViewData { WINDOWPLACEMENT windowPlacement; struct { int location; // not used, but kept for compatibility int min; int ideal; BOOL hidden; // not used, but kept for compatibility } scope; int viewMode; long listViewStyle; ULONG ulFlag1; int viewID; BOOL descriptionBarVisible; int defaultColumnWidth[2]; }; /* * The sense of the FLAG1_NO_xxx flags is negative. That is, when a * FLAG1_NO_xxx flag is set, its corresponding UI element is *not* * displayed. This is to maintain compatibility with console files * created before the existence of the FLAG1_NO_xxx flags. These * consoles always had all UI elements displayed, and the then-unused * bits in their flags field were defaulted to 0. To maintain * compatibility, we have to maintain that (0 == on). */ #define FLAG1_SCOPE_PANE_VISIBLE 0x00000001 #define FLAG1_NO_STD_MENUS 0x00000002 #define FLAG1_NO_STD_BUTTONS 0x00000004 #define FLAG1_NO_SNAPIN_MENUS 0x00000008 #define FLAG1_NO_SNAPIN_BUTTONS 0x00000010 #define FLAG1_DISABLE_SCOPEPANE 0x00000020 #define FLAG1_DISABLE_STD_TOOLBARS 0x00000040 #define FLAG1_CUSTOM_TITLE 0x00000080 #define FLAG1_NO_STATUS_BAR 0x00000100 #define FLAG1_CREATED_IN_USER_MODE 0x00000200 // used to be named FLAG1_NO_AUTHOR_MODE //#define FLAG1_FAVORITES_SELECTED 0x00000400 // unused, but don't recycle (for compatibility) #define FLAG1_NO_TREE_ALLOWED 0x00000800 // used for compatibility with MMC1.2 in CAMCView::Load. // Do not use for any other purposes. #define FLAG1_NO_TASKPAD_TABS 0x00001000 /***************************************************************************\ * * ARRAY: mappedViewModes * * PURPOSE: provides map to be used when persisting ViewMode enumeration * \***************************************************************************/ static const EnumLiteral mappedViewModes[] = { { MMCLV_VIEWSTYLE_ICON, XML_ENUM_LV_STYLE_ICON }, { MMCLV_VIEWSTYLE_REPORT, XML_ENUM_LV_STYLE_REPORT }, { MMCLV_VIEWSTYLE_SMALLICON, XML_ENUM_LV_STYLE_SMALLICON }, { MMCLV_VIEWSTYLE_LIST, XML_ENUM_LV_STYLE_LIST }, { MMCLV_VIEWSTYLE_FILTERED, XML_ENUM_LV_STYLE_FILTERED}, }; /***************************************************************************\ * * ARRAY: mappedListStyles * * PURPOSE: provides map to be used when persisting ListView style flag * \***************************************************************************/ static const EnumLiteral mappedListStyles[] = { { LVS_SINGLESEL, XML_BITFLAG_LV_STYLE_SINGLESEL }, { LVS_SHOWSELALWAYS, XML_BITFLAG_LV_STYLE_SHOWSELALWAYS }, { LVS_SORTASCENDING, XML_BITFLAG_LV_STYLE_SORTASCENDING }, { LVS_SORTDESCENDING, XML_BITFLAG_LV_STYLE_SORTDESCENDING }, { LVS_SHAREIMAGELISTS, XML_BITFLAG_LV_STYLE_SHAREIMAGELISTS }, { LVS_NOLABELWRAP, XML_BITFLAG_LV_STYLE_NOLABELWRAP }, { LVS_AUTOARRANGE, XML_BITFLAG_LV_STYLE_AUTOARRANGE }, { LVS_EDITLABELS, XML_BITFLAG_LV_STYLE_EDITLABELS }, { LVS_OWNERDATA, XML_BITFLAG_LV_STYLE_OWNERDATA }, { LVS_NOSCROLL, XML_BITFLAG_LV_STYLE_NOSCROLL }, { LVS_ALIGNLEFT, XML_BITFLAG_LV_STYLE_ALIGNLEFT }, { LVS_OWNERDRAWFIXED, XML_BITFLAG_LV_STYLE_OWNERDRAWFIXED }, { LVS_NOCOLUMNHEADER, XML_BITFLAG_LV_STYLE_NOCOLUMNHEADER }, { LVS_NOSORTHEADER, XML_BITFLAG_LV_STYLE_NOSORTHEADER }, }; /***************************************************************************\ * * ARRAY: mappedViewFlags * * PURPOSE: provides map to be used when persisting View flags * \***************************************************************************/ static const EnumLiteral mappedViewFlags[] = { { FLAG1_SCOPE_PANE_VISIBLE, XML_BITFLAG_VIEW_SCOPE_PANE_VISIBLE }, { FLAG1_NO_STD_MENUS, XML_BITFLAG_VIEW_NO_STD_MENUS }, { FLAG1_NO_STD_BUTTONS, XML_BITFLAG_VIEW_NO_STD_BUTTONS }, { FLAG1_NO_SNAPIN_MENUS, XML_BITFLAG_VIEW_NO_SNAPIN_MENUS }, { FLAG1_NO_SNAPIN_BUTTONS, XML_BITFLAG_VIEW_NO_SNAPIN_BUTTONS }, { FLAG1_DISABLE_SCOPEPANE, XML_BITFLAG_VIEW_DISABLE_SCOPEPANE }, { FLAG1_DISABLE_STD_TOOLBARS, XML_BITFLAG_VIEW_DISABLE_STD_TOOLBARS }, { FLAG1_CUSTOM_TITLE, XML_BITFLAG_VIEW_CUSTOM_TITLE }, { FLAG1_NO_STATUS_BAR, XML_BITFLAG_VIEW_NO_STATUS_BAR }, { FLAG1_CREATED_IN_USER_MODE, XML_BITFLAG_VIEW_CREATED_IN_USER_MODE }, { FLAG1_NO_TASKPAD_TABS, XML_BITFLAG_VIEW_NO_TASKPAD_TABS }, }; /***************************************************************************\ * * ARRAY: mappedSWCommands * * PURPOSE: provides mapping to persist show commands as literals * \***************************************************************************/ static const EnumLiteral mappedSWCommands[] = { { SW_HIDE, XML_ENUM_SHOW_CMD_HIDE }, { SW_SHOWNORMAL, XML_ENUM_SHOW_CMD_SHOWNORMAL }, { SW_SHOWMINIMIZED, XML_ENUM_SHOW_CMD_SHOWMINIMIZED }, { SW_SHOWMAXIMIZED, XML_ENUM_SHOW_CMD_SHOWMAXIMIZED }, { SW_SHOWNOACTIVATE, XML_ENUM_SHOW_CMD_SHOWNOACTIVATE }, { SW_SHOW, XML_ENUM_SHOW_CMD_SHOW }, { SW_MINIMIZE, XML_ENUM_SHOW_CMD_MINIMIZE }, { SW_SHOWMINNOACTIVE, XML_ENUM_SHOW_CMD_SHOWMINNOACTIVE }, { SW_SHOWNA, XML_ENUM_SHOW_CMD_SHOWNA }, { SW_RESTORE, XML_ENUM_SHOW_CMD_RESTORE }, { SW_SHOWDEFAULT, XML_ENUM_SHOW_CMD_SHOWDEFAULT }, { SW_FORCEMINIMIZE, XML_ENUM_SHOW_CMD_FORCEMINIMIZE }, }; /***************************************************************************\ * * ARRAY: mappedWPFlags * * PURPOSE: provides mapping to persist WP flags * \***************************************************************************/ static const EnumLiteral mappedWPFlags[] = { { WPF_SETMINPOSITION, XML_ENUM_WIN_PLACE_SETMINPOSITION }, { WPF_RESTORETOMAXIMIZED, XML_ENUM_WIN_PLACE_RESTORETOMAXIMIZED }, #ifdef WPF_ASYNCWINDOWPLACEMENT { WPF_ASYNCWINDOWPLACEMENT, XML_ENUM_WIN_PLACE_ASYNCWINDOWPLACEMENT }, #else { 4, XML_ENUM_WIN_PLACE_ASYNCWINDOWPLACEMENT }, #endif }; /*+-------------------------------------------------------------------------* * PersistViewData(CPersistor &persistor, PersistedViewData viewData) * * * PURPOSE: Persists a PersistedViewData object to the specified persistor. * *+-------------------------------------------------------------------------*/ void PersistViewData(CPersistor &persistor, PersistedViewData& viewData) { persistor.PersistAttribute(XML_ATTR_VIEW_ID, viewData.viewID); // write out the windowPlacement structure. persistor.Persist(CXMLWindowPlacement(viewData.windowPlacement)); // write out the scope structure persistor.PersistAttribute(XML_ATTR_VIEW_SCOPE_WIDTH, viewData.scope.ideal); if (persistor.IsLoading()) { // initialize for compatibility; viewData.scope.hidden = true; viewData.scope.location = 0; viewData.scope.min = 50; } // write out the remaining fields CPersistor persistorSettings(persistor, XML_TAG_VIEW_SETTINGS_2); // create wrapper to persist enumeration values as strings CXMLEnumeration viewModePersistor(viewData.viewMode, mappedViewModes, countof(mappedViewModes)); // persist the wrapper persistorSettings.PersistAttribute(XML_ATTR_VIEW_SETNGS_VIEW_MODE, viewModePersistor); // create wrapper to persist flag values as strings CXMLBitFlags viewStylePersistor(viewData.listViewStyle, mappedListStyles, countof(mappedListStyles)); // persist the wrapper persistorSettings.PersistAttribute(XML_ATTR_VIEW_SETNGS_LIST_STYLE, viewStylePersistor); // create wrapper to persist flag values as strings CXMLBitFlags flagPersistor(viewData.ulFlag1, mappedViewFlags, countof(mappedViewFlags)); // persist the wrapper persistorSettings.PersistAttribute(XML_ATTR_VIEW_SETNGS_FLAG, flagPersistor); persistorSettings.PersistAttribute(XML_ATTR_VIEW_SETNGS_DB_VISIBLE, CXMLBoolean(viewData.descriptionBarVisible)); persistorSettings.PersistAttribute(XML_ATTR_VIEW_SETNGS_DEF_COL_W0, viewData.defaultColumnWidth[0]); persistorSettings.PersistAttribute(XML_ATTR_VIEW_SETNGS_DEF_COL_W1, viewData.defaultColumnWidth[1]); } /*+-------------------------------------------------------------------------* * * CAMCView::Persist * * PURPOSE: Persists the CAMCView object to the specified persistor. Based * on CAMCView::Save. * * PARAMETERS: * CPersistor& persistor : * * RETURNS: * void * *+-------------------------------------------------------------------------*/ void CAMCView::Persist(CPersistor& persistor) { DECLARE_SC(sc, TEXT("CAMCView::Persist")); HRESULT hr; CBookmark bmr; CBookmark bms; if (persistor.IsStoring()) { sc = GetRootNodePath(&bmr); if (sc) sc.Throw(); persistor.Persist(bmr, XML_NAME_ROOT_NODE); // ... its too late for root node when loading sc = GetSelectedNodePath(&bms); if (sc) sc.Throw(); } persistor.Persist(bms, XML_NAME_SELECTED_NODE); // mostly copied from CAMCView::Save // Get the parent frame CWnd* const pParent = GetParent(); sc = ScCheckPointers(pParent,E_POINTER); if (sc) sc.Throw(); // Get the frames state data PersistedViewData vd; vd.windowPlacement.length = sizeof(vd.windowPlacement); const BOOL bGotPlacement = pParent->GetWindowPlacement(&vd.windowPlacement); if (!bGotPlacement) sc.Throw(E_FAIL); if (persistor.IsStoring()) { /* * If this window is minimized, make sure we set things up so the * WINDOWPLACEMENT.ptMinPosition will be restored by SetWindowPlacement * when we load. If we don't do this, it'll get some random min * position, likely not what we want. */ if (vd.windowPlacement.showCmd == SW_SHOWMINIMIZED) vd.windowPlacement.flags |= WPF_SETMINPOSITION; GetPaneInfo(ePane_ScopeTree, &vd.scope.ideal, &vd.scope.min); vd.viewMode = m_nViewMode; vd.listViewStyle = GetDefaultListViewStyle(); vd.ulFlag1 = 0; if (IsScopePaneVisible()) vd.ulFlag1 |= FLAG1_SCOPE_PANE_VISIBLE; if (!IsAuthorModeView()) vd.ulFlag1 |= FLAG1_CREATED_IN_USER_MODE; if (!(m_ViewData.m_dwToolbarsDisplayed & STD_MENUS)) vd.ulFlag1 |= FLAG1_NO_STD_MENUS; if (!(m_ViewData.m_dwToolbarsDisplayed & STD_BUTTONS)) vd.ulFlag1 |= FLAG1_NO_STD_BUTTONS; if (!(m_ViewData.m_dwToolbarsDisplayed & SNAPIN_MENUS)) vd.ulFlag1 |= FLAG1_NO_SNAPIN_MENUS; if (!(m_ViewData.m_dwToolbarsDisplayed & SNAPIN_BUTTONS)) vd.ulFlag1 |= FLAG1_NO_SNAPIN_BUTTONS; if (!(m_ViewData.m_dwToolbarsDisplayed & STATUS_BAR)) vd.ulFlag1 |= FLAG1_NO_STATUS_BAR; if (!AreStdToolbarsAllowed ()) vd.ulFlag1 |= FLAG1_DISABLE_STD_TOOLBARS; if (!IsScopePaneAllowed ()) vd.ulFlag1 |= FLAG1_DISABLE_SCOPEPANE; if (HasCustomTitle ()) vd.ulFlag1 |= FLAG1_CUSTOM_TITLE; if (!AreTaskpadTabsAllowed()) (vd.ulFlag1 |= FLAG1_NO_TASKPAD_TABS); vd.viewID = GetViewID(); vd.descriptionBarVisible = IsDescBarVisible(); GetDefaultColumnWidths(vd.defaultColumnWidth); } PersistViewData(persistor,vd); if (persistor.IsLoading()) { ASSERT(int(m_nViewID) == vd.viewID); m_ViewData.m_nViewID = m_nViewID = vd.viewID; if (int(m_nViewID) >= static_nViewID) static_nViewID = m_nViewID + 1; //SetDefaultColumnWidths(vd.defaultColumnWidth); SetDescBarVisible(vd.descriptionBarVisible); // we shouldn't restore maximized window position // since it may not be proper one for the current resolution // related to bug #404118 WINDOWPLACEMENT orgPlacement; ZeroMemory(&orgPlacement,sizeof(orgPlacement)); orgPlacement.length = sizeof(orgPlacement); if (pParent->GetWindowPlacement(&orgPlacement)) { vd.windowPlacement.ptMaxPosition = orgPlacement.ptMaxPosition; } m_ViewData.SetScopePaneVisible( 0 != (vd.ulFlag1 & FLAG1_SCOPE_PANE_VISIBLE) ); // Set the location and size of the frame const BOOL bPlaced = pParent->SetWindowPlacement(&vd.windowPlacement); if (!bPlaced) sc.Throw(E_FAIL); // Restore window settings if (vd.ulFlag1 & FLAG1_DISABLE_SCOPEPANE) m_ViewData.m_lWindowOptions |= MMC_NW_OPTION_NOSCOPEPANE; if (vd.ulFlag1 & FLAG1_DISABLE_STD_TOOLBARS) m_ViewData.m_lWindowOptions |= MMC_NW_OPTION_NOTOOLBARS; if (vd.ulFlag1 & FLAG1_CUSTOM_TITLE) m_ViewData.m_lWindowOptions |= MMC_NW_OPTION_CUSTOMTITLE; SetAuthorModeView (!(vd.ulFlag1 & FLAG1_CREATED_IN_USER_MODE)); if ((vd.ulFlag1 & FLAG1_NO_TASKPAD_TABS)) SetTaskpadTabsAllowed(FALSE); // Apply run time restrictions // if at least one type of scope pane allowed then if the selected // one is not allowed, switch to the other. If neither is allowed // then keep the selection and hide the scope pane. if (IsScopePaneAllowed()) { // Restore scope pane settings SetPaneInfo(ePane_ScopeTree, vd.scope.ideal, vd.scope.min); sc = ScShowScopePane ( m_ViewData.IsScopePaneVisible() ); } else sc = ScShowScopePane (false); if (sc) sc.Throw(); // Force layout re-calculation DeferRecalcLayout(); // Restore view style & view mode if persisted will be set by nodemgr. SetDefaultListViewStyle(vd.listViewStyle); DWORD dwToolbars = 0; if (!(vd.ulFlag1 & FLAG1_NO_STD_MENUS)) dwToolbars |= STD_MENUS; if (!(vd.ulFlag1 & FLAG1_NO_STD_BUTTONS)) dwToolbars |= STD_BUTTONS; if (!(vd.ulFlag1 & FLAG1_NO_SNAPIN_MENUS)) dwToolbars |= SNAPIN_MENUS; if (!(vd.ulFlag1 & FLAG1_NO_SNAPIN_BUTTONS)) dwToolbars |= SNAPIN_BUTTONS; if (!(vd.ulFlag1 & FLAG1_NO_STATUS_BAR)) dwToolbars |= STATUS_BAR; // display the status bar appropriately if (StatusBarOf (m_ViewData.m_dwToolbarsDisplayed) != StatusBarOf (dwToolbars)) { CChildFrame* pFrame = GetParentFrame (); if (pFrame != NULL) { pFrame->ToggleStatusBar(); SetStatusBarVisible(!IsStatusBarVisible()); ASSERT (StatusBarOf (m_ViewData.m_dwToolbarsDisplayed) == StatusBarOf (dwToolbars)); } } // display the appropriate toolbars if (ToolbarsOf (m_ViewData.m_dwToolbarsDisplayed) != ToolbarsOf (dwToolbars)) { m_spNodeCallback->UpdateWindowLayout( reinterpret_cast(&m_ViewData), dwToolbars); ASSERT (ToolbarsOf (m_ViewData.m_dwToolbarsDisplayed) == ToolbarsOf (dwToolbars)); } // Update the status of MMC menus. sc = ScUpdateMMCMenus(); if (sc) sc.Throw(); SetDirty (false); m_pHistoryList->Clear(); } SaveStartingSelectedNode(); if (persistor.IsLoading()) { SC sc; IScopeTree* const pScopeTree = GetScopeTreePtr(); if(!pScopeTree) { sc = E_UNEXPECTED; return; } MTNODEID idTemp = 0; bool bExactMatchFound = false; // out value from GetNodeIDFromBookmark, unused sc = pScopeTree->GetNodeIDFromBookmark(bms, &idTemp, bExactMatchFound); if(sc) return; sc = ScSelectNode(idTemp); if(sc) return; } // if we've stored everything -we're clean if (persistor.IsStoring()) SetDirty (false); } bool CAMCView::Load(IStream& stream) // Caller is responsible for notifying user if false is returned { TRACE_METHOD(CAMCView, Load); SetDirty (false); // Read the view data from the stream. ASSERT(&stream); if (!&stream) return false; PersistedViewData pvd; unsigned long bytesRead; HRESULT hr = stream.Read(&pvd, sizeof(pvd), &bytesRead); ASSERT(SUCCEEDED(hr) && bytesRead == sizeof(pvd)); if (FAILED(hr)) return false; ASSERT(int(m_nViewID) == pvd.viewID); m_ViewData.m_nViewID = m_nViewID = pvd.viewID; if (int(m_nViewID) >= static_nViewID) static_nViewID = m_nViewID + 1; //SetDefaultColumnWidths(pvd.defaultColumnWidth); SetDescBarVisible(pvd.descriptionBarVisible); // Get the parent frame CWnd* const pParent = GetParent(); ASSERT(pParent != NULL); if (pParent == NULL) return false; // we shouldn't restore maximized window position // since it may not be proper one for the current resolution // related to bug #404118 WINDOWPLACEMENT orgPlacement; ZeroMemory(&orgPlacement,sizeof(orgPlacement)); orgPlacement.length = sizeof(orgPlacement); if (pParent->GetWindowPlacement(&orgPlacement)) { pvd.windowPlacement.ptMaxPosition = orgPlacement.ptMaxPosition; } // Set the location and size of the frame const BOOL bPlaced = pParent->SetWindowPlacement(&pvd.windowPlacement); ASSERT(bPlaced != FALSE); if (bPlaced == FALSE) return false; // Restore window settings if (pvd.ulFlag1 & FLAG1_DISABLE_SCOPEPANE) m_ViewData.m_lWindowOptions |= MMC_NW_OPTION_NOSCOPEPANE; if (pvd.ulFlag1 & FLAG1_DISABLE_STD_TOOLBARS) m_ViewData.m_lWindowOptions |= MMC_NW_OPTION_NOTOOLBARS; if (pvd.ulFlag1 & FLAG1_CUSTOM_TITLE) m_ViewData.m_lWindowOptions |= MMC_NW_OPTION_CUSTOMTITLE; SetAuthorModeView (!(pvd.ulFlag1 & FLAG1_CREATED_IN_USER_MODE)); if ((pvd.ulFlag1 & FLAG1_NO_TASKPAD_TABS)) SetTaskpadTabsAllowed(FALSE); // Restore scope pane settings SetPaneInfo(ePane_ScopeTree, pvd.scope.ideal, pvd.scope.min); // The FLAG1_NO_TREE_ALLOWED is used only for compatibility with MMC1.2 console files // It is a relic from old console files that does not exist in MMC2.0 console files. bool bScopeTreeNotAllowed = (pvd.ulFlag1 & FLAG1_NO_TREE_ALLOWED); SC sc; if ( (IsScopePaneAllowed()) && (! bScopeTreeNotAllowed) ) sc = ScShowScopePane ((pvd.ulFlag1 & FLAG1_SCOPE_PANE_VISIBLE) != 0); else sc = ScShowScopePane (false); if (sc) return (false); // Force layout re-calculation DeferRecalcLayout(); // Restore view style & view mode if persisted will be set by nodemgr. SetDefaultListViewStyle(pvd.listViewStyle); DWORD dwToolbars = 0; if (!(pvd.ulFlag1 & FLAG1_NO_STD_MENUS)) dwToolbars |= STD_MENUS; if (!(pvd.ulFlag1 & FLAG1_NO_STD_BUTTONS)) dwToolbars |= STD_BUTTONS; if (!(pvd.ulFlag1 & FLAG1_NO_SNAPIN_MENUS)) dwToolbars |= SNAPIN_MENUS; if (!(pvd.ulFlag1 & FLAG1_NO_SNAPIN_BUTTONS)) dwToolbars |= SNAPIN_BUTTONS; if (!(pvd.ulFlag1 & FLAG1_NO_STATUS_BAR)) dwToolbars |= STATUS_BAR; // display the status bar appropriately if (StatusBarOf (m_ViewData.m_dwToolbarsDisplayed) != StatusBarOf (dwToolbars)) { CChildFrame* pFrame = GetParentFrame (); if (pFrame != NULL) { pFrame->ToggleStatusBar(); SetStatusBarVisible(!IsStatusBarVisible()); ASSERT (StatusBarOf (m_ViewData.m_dwToolbarsDisplayed) == StatusBarOf (dwToolbars)); } } // display the appropriate toolbars if (ToolbarsOf (m_ViewData.m_dwToolbarsDisplayed) != ToolbarsOf (dwToolbars)) { m_spNodeCallback->UpdateWindowLayout( reinterpret_cast(&m_ViewData), dwToolbars); ASSERT (ToolbarsOf (m_ViewData.m_dwToolbarsDisplayed) == ToolbarsOf (dwToolbars)); } // Update the status of MMC menus. sc = ScUpdateMMCMenus(); if (sc) return false; SetDirty (false); m_pHistoryList->Clear(); return true; } //+------------------------------------------------------------------- // // Member: ScSpecialResultpaneSelectionActivate // // Synopsis: Only the list(/Web/OCX) or the tree can be "active" from the point // of view of selected items and MMCN_SELECT. This is not // the same as the MFC concept of "active view". There are a couple // of views that cannot be active in this sense, such as the taskpad // and tab views. // When the active view (according to this definition) changes, this // function is called. Thus, ScTreeViewSelectionActivate and // ScListViewSelectionActivate/ScSpecialResultpaneSelectionActivate // are always called in pairs when the activation changes, one to handle // deactivation, and one to handle activation. // // Consider the following scenario // 1) The tree view has (MFC/windows style) focus. // 2) The user clicks on the taskpad view // Result - selection activation does not change from the tree. All verbs // still correspond to the selected tree item. // 3) The user clicks on the folder view // Result - once again, selection activation does not chang // 4) The user clicks on one of the result views eg the list // Result - ScTreeViewSelectionActivate(false) and ScListViewSelectionActivate(true) // Thus verbs and the toolbar now correspond to the selected list item(s). // 5) The user clicks on the taskpad view. // Result - as in step 2, nothing happens // 6) The user clicks on the result view // Result - because the active view has not changed, nothing happens. // // Arguments: [bActivate] - special result pane is selected/de-selected. // // Returns: SC // //-------------------------------------------------------------------- SC CAMCView::ScSpecialResultpaneSelectionActivate(bool bActivate) { DECLARE_SC(sc, TEXT("CAMCView::ScSpecialResultpaneSelectionActivate")); /* * Bug 331904: prevent recursion */ if (m_fActivatingSpecialResultPane) { TRACE (_T("CAMCView:ScSpecialResultpaneSelectionActivate: shorting out of recursion\n")); return sc; } do { m_fActivatingSpecialResultPane = true; HNODE hNode = GetSelectedNode(); SELECTIONINFO selInfo; ZeroMemory(&selInfo, sizeof(selInfo)); selInfo.m_bScope = FALSE; selInfo.m_bDueToFocusChange = TRUE; selInfo.m_bBackground = FALSE; INodeCallback* pNodeCallBack = GetNodeCallback(); if (HasOCX()) { selInfo.m_bResultPaneIsOCX = TRUE; selInfo.m_lCookie = LVDATA_CUSTOMOCX; } else if (HasWebBrowser()) { selInfo.m_bResultPaneIsWeb = TRUE; selInfo.m_lCookie = LVDATA_CUSTOMWEB; } else { // Dont do anything. Just return. m_fActivatingSpecialResultPane = false; return sc; } sc = ScNotifySelect (pNodeCallBack, hNode, false /*fMultiSelect*/, bActivate, &selInfo); if (sc) sc.TraceAndClear(); // ignore & continue; } while ( FALSE ); m_fActivatingSpecialResultPane = false; return sc; } void CAMCView::CloseView() { DECLARE_SC(sc, TEXT("CAMCView::CloseView")); TRACE_METHOD(CAMCView, CloseView); // fire event to script // this needs to be done while view is still 'alive' sc = ScFireEvent(CAMCViewObserver::ScOnCloseView, this); if (sc) sc.TraceAndClear(); IScopeTree* const pScopeTree = GetScopeTreePtr(); ASSERT(pScopeTree != NULL); if (pScopeTree != NULL) { HRESULT hr = pScopeTree->CloseView(m_nViewID); ASSERT(hr == S_OK); } } void CAMCView::OnDestroy() { TRACE_METHOD(CAMCView, OnDestroy); // send the view destroy notification to all observers. SC sc; sc = ScFireEvent(CAMCViewObserver::ScOnViewDestroyed, this); if(sc) sc.TraceAndClear(); if (IsPersisted()) { if(m_pDocument != NULL) m_pDocument->SetModifiedFlag(TRUE); SetDirty(); } CDocument* pDoc = GetDocument(); ASSERT(pDoc != NULL); // if we were in ListPad-mode.... // this must be detached before destroying the Scopetree, // because we need to send a notify to the snapin, // which we get from the hnode. if (m_pListCtrl->IsListPad()) { sc = m_pListCtrl->ScAttachToListPad (NULL, NULL); if(sc) sc.TraceAndClear(); } // make sure to stop running scripts if we have a web browser if( HasWebBrowser() ) { ASSERT( m_pWebViewCtrl != NULL ); if ( m_pWebViewCtrl != NULL ) { m_pWebViewCtrl->DestroyWindow(); m_pWebViewCtrl = NULL; } } // make sure to stop running scripts if we have a view extension if ( m_fViewExtended ) { ASSERT( m_pViewExtensionCtrl != NULL ); if ( m_pViewExtensionCtrl != NULL ) { m_pViewExtensionCtrl->DestroyWindow(); m_pViewExtensionCtrl = NULL; } } if (m_pTreeCtrl != NULL) { HNODE hNode = GetSelectedNode(); if (hNode) m_pTreeCtrl->OnDeSelectNode(hNode); m_pTreeCtrl->DeleteScopeTree(); } IScopeTree* const pScopeTree = GetScopeTreePtr(); ASSERT(pScopeTree != NULL); if (pScopeTree != NULL) { HRESULT hr = pScopeTree->DeleteView(m_nViewID); ASSERT(hr == S_OK); } CView::OnDestroy(); } void CAMCView::OnUpdateFileSnapinmanager(CCmdUI* pCmdUI) { pCmdUI->Enable (); } void CAMCView::OnSize(UINT nType, int cx, int cy) { TRACE_METHOD(CAMCView, OnSize); CView::OnSize(nType, cx, cy); if (nType != SIZE_MINIMIZED) RecalcLayout(); } SC CAMCView::ScToggleDescriptionBar() { TRACE_METHOD(CAMCView, ScToggleDescriptionBar); AFX_MANAGE_STATE (AfxGetAppModuleState()); SetDescBarVisible (!IsDescBarVisible()); SetDirty(); /* * Don't defer this layout. This may be called by the Customize View * dialog which wants to see its updates in real time. It will be * sitting in a modal message loop so we won't get a chance to precess * our idle task. */ RecalcLayout(); return (S_OK); } SC CAMCView::ScToggleStatusBar() { TRACE_METHOD(CAMCView, ScToggleStatusBar); AFX_MANAGE_STATE (AfxGetAppModuleState()); DECLARE_SC (sc, _T("CAMCView::ScToggleStatusBar")); CChildFrame* pFrame = GetParentFrame(); sc = ScCheckPointers (pFrame, E_UNEXPECTED); if (sc) return (sc); pFrame->ToggleStatusBar(); SetStatusBarVisible (!IsStatusBarVisible()); SetDirty(); return (sc); } SC CAMCView::ScToggleTaskpadTabs() { TRACE_METHOD(CAMCView, ScToggleTaskpadTabs); AFX_MANAGE_STATE (AfxGetAppModuleState()); SetTaskpadTabsAllowed (!AreTaskpadTabsAllowed()); SetDirty(); /* * Don't defer this layout. This message will be sent by the * Customize View dialog which wants to see its updates in * real time. It will be sitting in a modal message loop so * we won't get a chance to precess our idle task. */ RecalcLayout(); return (S_OK); } SC CAMCView::ScToggleScopePane() { AFX_MANAGE_STATE (AfxGetAppModuleState()); DECLARE_SC (sc, _T("CAMCView::ScToggleScopePane")); sc = ScShowScopePane (!IsScopePaneVisible()); if (sc) return (sc); return (sc); } void CAMCView::OnActionMenu(CPoint point, LPCRECT prcExclude) { TRACE_METHOD(CAMCView, OnActionMenu); UINT fHitTestFlags = 0; HTREEITEM hTreeItem = m_pTreeCtrl->GetSelectedItem( ); ASSERT_VALID (this); /* * BUG: 99643 * Right now there is inconsistency between what you get by action menu & right click * on a location in taskpad. The action menu always assumes it is tree or if result * pane it is list or ocx or web or background. So if a taskpad is selected it assumes * the corresponding list item is selected or tree item is selected or background. * But right click on taskpad calls CAMCView::OnContextMenu which determines nothing * is selected and does nothing. This needs to be addressed. */ ASSERT(eActivePaneNone != m_eCurrentActivePane); if (eActivePaneScope == m_eCurrentActivePane) { if (hTreeItem != NULL) { HNODE hNode = (HNODE)m_pTreeCtrl->GetItemData(hTreeItem); OnContextMenuForTreeItem(INDEX_INVALID, hNode, point, CCT_SCOPE, hTreeItem, MMC_CONTEXT_MENU_ACTION, prcExclude, false/*bAllowDefaultItem*/); } else { OnContextMenuForTreeBackground(point, prcExclude, false/*bAllowDefaultItem*/); } } else { if (HasListOrListPad()) { int cSel = m_pListCtrl->GetSelectedCount(); int nIndex = -1; LPARAM lvData = LVDATA_ERROR; if (cSel == 0) lvData = LVDATA_BACKGROUND; else if (cSel == 1) nIndex = _GetLVSelectedItemData(&lvData); else if (cSel > 1) lvData = LVDATA_MULTISELECT; ASSERT(lvData != LVDATA_ERROR); if (lvData == LVDATA_ERROR) return; if (lvData == LVDATA_BACKGROUND) { // Find out which pane has focus to set the CMINFO_DO_SCOPEPANE_MENU flag. HNODE hNode = GetSelectedNode(); DATA_OBJECT_TYPES ePaneType = (GetParentFrame()->GetActiveView() == m_pTreeCtrl) ? CCT_SCOPE : CCT_RESULT; OnContextMenuForTreeItem(INDEX_BACKGROUND, hNode, point, ePaneType, hTreeItem, MMC_CONTEXT_MENU_ACTION, prcExclude, false/*bAllowDefaultItem*/); return; } else if (lvData == LVDATA_MULTISELECT) { OnContextMenuForListItem(INDEX_MULTISELECTION, NULL, point, MMC_CONTEXT_MENU_ACTION, prcExclude, false/*bAllowDefaultItem*/); } else { if (IsVirtualList()) { OnContextMenuForListItem(nIndex, (HRESULTITEM)NULL, point, MMC_CONTEXT_MENU_ACTION, prcExclude, false/*bAllowDefaultItem*/); } else { CResultItem* pri = CResultItem::FromHandle (lvData); if (pri != NULL) { if (pri->IsScopeItem()) OnContextMenuForTreeItem(nIndex, pri->GetScopeNode(), point, CCT_RESULT, NULL, MMC_CONTEXT_MENU_ACTION, prcExclude, false/*bAllowDefaultItem*/); else OnContextMenuForListItem(nIndex, lvData, point, MMC_CONTEXT_MENU_ACTION, prcExclude, false/*bAllowDefaultItem*/); } } } } else { // The active window may be a web page or task pad or ocx. LPARAM lvData = LVDATA_ERROR; if (HasOCX()) { lvData = LVDATA_CUSTOMOCX; OnContextMenuForListItem(INDEX_OCXPANE, (HRESULTITEM)lvData, point, MMC_CONTEXT_MENU_ACTION, prcExclude, false/*bAllowDefaultItem*/); } else if (HasWebBrowser()) { lvData = LVDATA_CUSTOMWEB; OnContextMenuForListItem(INDEX_WEBPANE, (HRESULTITEM)lvData, point, MMC_CONTEXT_MENU_ACTION, prcExclude, false/*bAllowDefaultItem*/); } else { // Some unknown window has the focus. ASSERT(FALSE && "Unknown window has the focus"); } } } } SC CAMCView::ScUpOneLevel() { AFX_MANAGE_STATE (AfxGetAppModuleState()); TRACE_METHOD(CAMCView, ScUpOneLevel); DECLARE_SC (sc, _T("CAMCView::ScUpOneLevel")); sc = E_FAIL; if (m_pTreeCtrl) { HTREEITEM htiParent = m_pTreeCtrl->GetParentItem (m_pTreeCtrl->GetSelectedItem()); if (htiParent) { m_pTreeCtrl->SelectItem(htiParent); m_pTreeCtrl->EnsureVisible(htiParent); sc = S_OK; } } return (sc); } void CAMCView::OnViewMenu(CPoint point, LPCRECT prcExclude) { TRACE_METHOD(CAMCView, OnViewMenu); OnContextMenuForListItem (INDEX_BACKGROUND, NULL, point, MMC_CONTEXT_MENU_VIEW, prcExclude, false /*bAllowDefaultItem*/); } void CAMCView::OnDrawClipboard() { if (m_htiCut) { m_pTreeCtrl->SetItemState(m_htiCut, 0, TVIS_CUT); } else { m_pListCtrl->CutSelectedItems(FALSE); } } /*+-------------------------------------------------------------------------* * * CAMCView::OnSettingChange * * PURPOSE: Handles WM_SETTINGCHANGE. Recalculates the layout. The * result folder tab control needs this, for instance. * * PARAMETERS: * UINT uFlags : * LPCTSTR lpszSection : * * RETURNS: * void * *+-------------------------------------------------------------------------*/ void CAMCView::OnSettingChange(UINT uFlags, LPCTSTR lpszSection) { DeferRecalcLayout(); } void CAMCView::OnUpdatePasteBtn() { DECLARE_SC(sc, TEXT("CAMCView::OnUpdatePasteBtn")); HNODE hNode = NULL; LPARAM lvData = NULL; bool bScope = FALSE; sc = ScGetFocusedItem(hNode, lvData, bScope); if (sc) return; INodeCallback* pNC = GetNodeCallback(); sc = ScCheckPointers(hNode, pNC, E_UNEXPECTED); if (sc) return; sc = pNC->UpdatePasteButton(hNode, bScope, lvData); if (sc) return; return; } void CAMCView::OnContextHelp() { ScContextHelp(); } SC CAMCView::ScContextHelp () { AFX_MANAGE_STATE (AfxGetAppModuleState()); m_fSnapinDisplayedHelp = false; SC sc = SendGenericNotify(NCLBK_CONTEXTHELP); // if snap-in hasn't called us to display a topic // and it has not handled the notification then // display MMC topic by default if (!m_fSnapinDisplayedHelp && (sc.ToHr() != S_OK)) sc = ScHelpTopics (); if (sc) TraceError (_T("CAMCView::ScContextHelp"), sc); return (sc); } void CAMCView::OnSnapInHelp() { SendGenericNotify(NCLBK_SNAPINHELP); } void CAMCView::OnSnapinAbout() { DECLARE_SC(sc, TEXT("CAMCView::OnSnapinAbout")); HNODE hNode = GetSelectedNode(); sc = ScCheckPointers((void*) hNode, E_UNEXPECTED); if (sc) return; INodeCallback *pNC = GetNodeCallback(); sc = ScCheckPointers(pNC, E_UNEXPECTED); if (sc) return; sc = pNC->ShowAboutInformation(hNode); if (sc) return; return; } void CAMCView::OnHelpTopics() { ScHelpTopics(); } SC CAMCView::ScHelpWorker (LPCTSTR pszHelpTopic) { DECLARE_SC (sc, _T("CAMCView::ScShowSnapinHelpTopic")); USES_CONVERSION; /* * generation of the help collection might take a while, so display * a wait cursor */ CWaitCursor wait; INodeCallback* pNC = GetNodeCallback(); ASSERT(pNC != NULL); CAMCDoc* pdoc = GetDocument(); // Point helpdoc info to current console file path if (pdoc->GetPathName().IsEmpty()) pdoc->GetHelpDocInfo()->m_pszFileName = NULL; else pdoc->GetHelpDocInfo()->m_pszFileName = T2COLE(pdoc->GetPathName()); /* * smart pointer for automatic deletion of the help file name */ CCoTaskMemPtr spszHelpFile; sc = pNC->Notify (0, NCLBK_GETHELPDOC, reinterpret_cast(pdoc->GetHelpDocInfo()), reinterpret_cast(&spszHelpFile)); if (sc) return (sc); CAMCApp* pAMCApp = AMCGetApp(); if (NULL == pAMCApp) return (sc = E_UNEXPECTED); sc = pAMCApp->ScShowHtmlHelp(W2T(spszHelpFile), (DWORD_PTR) pszHelpTopic); return (sc); } SC CAMCView::ScHelpTopics () { AFX_MANAGE_STATE (AfxGetAppModuleState()); return (ScHelpWorker (NULL)); } SC CAMCView::ScShowSnapinHelpTopic (LPCTSTR pszHelpTopic) { AFX_MANAGE_STATE (AfxGetAppModuleState()); CString strTopicPath; // Add protocol prefix to topic string if (pszHelpTopic != NULL) { strTopicPath = _T("ms-its:"); strTopicPath += pszHelpTopic; } SC sc = ScHelpWorker (strTopicPath); if (!sc) m_fSnapinDisplayedHelp = true; return (sc); } //+------------------------------------------------------------------- // // Member: CAMCView::UpdateSnapInHelpMenus // // Synopsis: Update the following Help menu items // a) Help on (if snapin does not support HTML help) // b) About (if snapin supports about object) // // Arguments: [pMenu] - The help popup menu. // //-------------------------------------------------------------------- void CAMCView::UpdateSnapInHelpMenus(CMenu* pMenu) { DECLARE_SC(sc, TEXT("CAMCView::UpdateSnapInHelpMenus")); sc = ScCheckPointers(pMenu); if (sc) return; ASSERT_VALID (this); HNODE hNode = GetSelectedNode(); INodeCallback* pNC = GetNodeCallback(); sc = ScCheckPointers(hNode, pNC, E_UNEXPECTED); if (sc) goto Error; // Empty block for goto's { // First Make sure this is not a dummy substitute snapin. bool bDummySnapin = false; sc = pNC->IsDummySnapin (hNode, bDummySnapin); if (sc) goto Error; if (bDummySnapin) goto Error; // Get the snapin name for "Help on " or "About " menus CCoTaskMemPtr spszName; CString strMenu; // Try to get name of snap-in for custom menu item bool bSnapinNameValid = false; sc = pNC->GetSnapinName(hNode, &spszName, bSnapinNameValid); if (sc) goto Error; ASSERT( spszName != NULL || bSnapinNameValid ); USES_CONVERSION; // if snapin supports html help, don't give it it's own help command bool bStandardHelpExists = false; sc = pNC->DoesStandardSnapinHelpExist(hNode, bStandardHelpExists); if (sc) goto Error; if (bStandardHelpExists) { pMenu->DeleteMenu(ID_HELP_SNAPINHELP, MF_BYCOMMAND); } else { if (bSnapinNameValid) { // "Help on " LoadString(strMenu, IDS_HELP_ON); AfxFormatString1(strMenu, IDS_HELP_ON, OLE2T(spszName)); } else { // ""Help on Snap-in" LoadString(strMenu, IDS_HELP_ON_SNAPIN); } // Either add or modify the custom help menu item if (pMenu->GetMenuState(ID_HELP_SNAPINHELP, MF_BYCOMMAND) == (UINT)-1) { pMenu->InsertMenu(ID_HELP_HELPTOPICS, MF_BYCOMMAND|MF_ENABLED, ID_HELP_SNAPINHELP, strMenu); } else { pMenu->ModifyMenu(ID_HELP_SNAPINHELP, MF_BYCOMMAND|MF_ENABLED, ID_HELP_SNAPINHELP, strMenu); } } /* Now add the About menu*/ bool bAboutExists = false; SC scNoTrace = pNC->DoesAboutExist(hNode, &bAboutExists); if ( (scNoTrace.IsError()) || (!bAboutExists) ) { pMenu->DeleteMenu(ID_SNAPIN_ABOUT, MF_BYCOMMAND); return; } if (bSnapinNameValid) { // "About on " AfxFormatString1(strMenu, IDS_ABOUT_ON, OLE2T(spszName)); } else { // Cant get name just delete & return pMenu->DeleteMenu(ID_SNAPIN_ABOUT, MF_BYCOMMAND); return; } if (pMenu->GetMenuState(ID_SNAPIN_ABOUT, MF_BYCOMMAND) == (UINT)-1) { pMenu->InsertMenu(-1, MF_BYPOSITION|MF_ENABLED, ID_SNAPIN_ABOUT, strMenu); } else { pMenu->ModifyMenu(ID_SNAPIN_ABOUT, MF_BYCOMMAND|MF_ENABLED, ID_SNAPIN_ABOUT, strMenu); } } Cleanup: return; Error: pMenu->DeleteMenu(ID_HELP_SNAPINHELP, MF_BYCOMMAND); pMenu->DeleteMenu(ID_SNAPIN_ABOUT, MF_BYCOMMAND); goto Cleanup; } #ifdef IMPLEMENT_LIST_SAVE // See nodemgr.idl (t-dmarm) /* * Displays errors from the list save function and cleans up the file if necessary */ void CAMCView::ListSaveErrorMes(EListSaveErrorType etype, HANDLE hfile, LPCTSTR lpFileName) { CString strMessage; switch (etype) { case LSaveCantCreate: //"ERROR: Unable to create file." FormatString1 (strMessage, IDS_LISTSAVE_ER1, lpFileName); break; case LSaveCantWrite: // ERROR: Created file but encountered an error while writing to it FormatString1 (strMessage, IDS_LISTSAVE_ER2, lpFileName); break; case LSaveReadOnly: //"ERROR: File to be overwritten is read only." FormatString1 (strMessage, IDS_LISTSAVE_ER3, lpFileName); break; default: // Should not make it here ASSERT(0); } MMCMessageBox (strMessage); } // Saves a list and performs necessary dialog boxes and error checking SC CAMCView::ScSaveList() { DECLARE_SC(sc, _T("ScSaveList")); AFX_MANAGE_STATE (AfxGetAppModuleState()); sc = ScExportListWorker(); return (sc); } //+------------------------------------------------------------------- // // Member: CAMCView::ScGetExportListFile // // Synopsis: Get the filename, flags for save list. // // Arguments: [strFileName] - File Name retval. // [bUnicode] - Unicode or ansi. // [bTabDelimited] - Tab or Comma delimited. // [bSelectedRowsOnly] - selected items only or all items. // // Returns: SC, S_FALSE if user cancels dialog. // //-------------------------------------------------------------------- SC CAMCView::ScGetExportListFile (CString& strFileName, bool& bUnicode, bool& bTabDelimited, bool& bSelectedRowsOnly) { DECLARE_SC(sc, _T("CAMCView::ScGetExportListFile")); CString strFilter; LoadString(strFilter, IDS_ANSI_FILE_TYPE); #ifdef UNICODE { // limit the lifetime of strUniFilter CString strUniFilter; LoadString(strUniFilter, IDS_UNICODE_FILE_TYPE); strFilter += strUniFilter; } #endif // End of Filter char strFilter += "|"; sc = ScCheckPointers(m_pListCtrl, E_UNEXPECTED); if (sc) return sc; // See if there are any items selected else disable the "Selected items only" check-box. CListCtrl& ctlList = m_pListCtrl->GetListCtrl(); int iItem = ctlList.GetNextItem( -1,LVNI_SELECTED); bool bSomeRowSelected = (-1 != iItem); // Create the dialog. File extensions are not localized. CSaveFileDialog dlgFile(false, _T("txt"), NULL, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT | OFN_ENABLESIZING, strFilter, bSomeRowSelected); // Display the dialog if (dlgFile.DoModal() == IDCANCEL) return S_FALSE; // S_FALSE if user cancels dialog. // Create a wait cursor and redraw the screen (necessary in saving big files) CWaitCursor wait; AfxGetMainWnd()->RedrawWindow(NULL, NULL, RDW_ALLCHILDREN | RDW_UPDATENOW ); // Retrieve the filename strFileName = dlgFile.GetPathName(); bSelectedRowsOnly = (dlgFile.Getflags() & SELECTED); switch (dlgFile.GetFileType()) { case FILE_ANSI_TEXT: bTabDelimited = true; // Tab delimited. bUnicode = false; break; case FILE_ANSI_CSV: bTabDelimited = false; // Comma delimited. bUnicode = false; break; #ifdef UNICODE case FILE_UNICODE_TEXT: bTabDelimited = true; // tab delimited. bUnicode = true; break; case FILE_UNICODE_CSV: bTabDelimited = false; // comma delimited. bUnicode = true; break; #endif default: sc = E_UNEXPECTED; break; } return (sc); } //+------------------------------------------------------------------- // // Member: CAMCView::ScCreateExportListFile // // Synopsis: Create a file with given name & path. Write unicode marker if needed. // // Arguments: [strFileName] - file to create. // [bUnicode] - unicode or ansi file. // [bShowErrorDialogs] - Show error dialogs or not. // [hFile] - Retval, handle to file. // // Returns: SC // //-------------------------------------------------------------------- SC CAMCView::ScCreateExportListFile(const CString& strFileName, bool bUnicode, bool bShowErrorDialogs, HANDLE& hFile) { DECLARE_SC(sc, _T("CAMCView::ScCreateExportListFile")); // Create a file according to specs hFile = CreateFile(strFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); DWORD dwAttrib = GetFileAttributes(strFileName); // If it did not fail and the file is read-only // Not required. Used to determine if the file being overwritten is read only and display appropriate message if ((dwAttrib != 0xFFFFFFFF) && (dwAttrib & FILE_ATTRIBUTE_READONLY)) { if (bShowErrorDialogs) ListSaveErrorMes(LSaveReadOnly, hFile, strFileName); return (sc = E_FAIL); } // Creation failed if (hFile == INVALID_HANDLE_VALUE) { if (bShowErrorDialogs) ListSaveErrorMes(LSaveCantCreate, NULL, strFileName); sc.FromWin32(::GetLastError()); return sc; } /* * for Unicode files, write the Unicode prefix */ if (bUnicode) { const WCHAR chPrefix = 0xFEFF; const DWORD cbToWrite = sizeof (chPrefix); DWORD cbWritten; if (!WriteFile (hFile, &chPrefix, cbToWrite, &cbWritten, NULL) || (cbToWrite != cbWritten)) { CloseHandle(hFile); DeleteFile( strFileName ); if (bShowErrorDialogs) ListSaveErrorMes(LSaveCantWrite, hFile, strFileName); return (sc = E_FAIL); } } return (sc); } //+------------------------------------------------------------------- // // Member: CAMCView::ScExportListWorker // // Synopsis: Prompt for a file name & write the ListView data to it. // // Returns: SC // //-------------------------------------------------------------------- SC CAMCView::ScExportListWorker() { DECLARE_SC(sc, _T("CAMCView::ScExportListWorker")); CString strFileName; bool bUnicode = false; bool bTabDelimited = false; bool bSelectedRowsOnly = false; sc = ScGetExportListFile(strFileName, bUnicode, bTabDelimited, bSelectedRowsOnly); if (sc.ToHr() == S_FALSE) // if user cancels dialog. return sc; sc = ScWriteExportListData(strFileName, bUnicode, bTabDelimited, bSelectedRowsOnly); if (sc) return sc; return sc; } //+------------------------------------------------------------------- // // Member: CAMCView::ScWriteExportListData // // Synopsis: Write ListView data to given file. // // Arguments: [strFileName] - File to create & write to. // [bUnicode] - Unicode or ansi. // [bTabDelimited] - Tab or Comma separated values. // [bSelectedRowsOnly] - like Selected rows only. // [bShowErrorDialogs] - Show error dialogs or not. // // Returns: SC // //-------------------------------------------------------------------- SC CAMCView::ScWriteExportListData (const CString& strFileName, bool bUnicode, bool bTabDelimited, bool bSelectedRowsOnly, bool bShowErrorDialogs /*true*/) { DECLARE_SC(sc, _T("CAMCView::ScWriteExportListData")); // Get number of rows and columns const int cRows = m_pListCtrl->GetItemCount(); const int cCols = m_pListCtrl->GetColCount(); // If there are no columns inserted then there cannot be any // items inserted into the listview. So error out. if (cCols <= 0) return (sc = E_UNEXPECTED); HANDLE hFile = NULL; sc = ScCreateExportListFile(strFileName, bUnicode, bShowErrorDialogs, hFile); if (sc) return sc; // Retrieve the flags CString strEol( _T("\r\n") ); LPCTSTR pszSeparator = _T("\t"); if (!bTabDelimited) pszSeparator = _T(","); // Determine how many columns must be printed int printcols = 1; struct ColInfo { CString strColName; BOOL bHidden; }; ColInfo* rgColumns = NULL; int* pnColOrder = NULL; // If it is LVS_REPORT, get the list of column names, order // and hidden or not flag. if ( (m_pListCtrl->GetViewMode() == LVS_REPORT) || (m_pListCtrl->GetViewMode() == MMCLV_VIEWSTYLE_FILTERED) ) { printcols = cCols; // Allocate mem to store col names, order, hidden states rgColumns = new ColInfo[printcols]; if (! rgColumns) { sc = E_OUTOFMEMORY; goto Error; } pnColOrder = new int[printcols]; if (! pnColOrder) { sc = E_OUTOFMEMORY; goto Error; } CHeaderCtrl* pHeader = m_pListCtrl->GetHeaderCtrl(); sc = ScCheckPointers(pHeader, E_UNEXPECTED); if (sc) goto Error; // Get the order if (!Header_GetOrderArray(pHeader->GetSafeHwnd(), printcols, pnColOrder)) { goto Error; } // Get the name and hidden state of cols for (int i = 0; i < printcols ; i++) { TCHAR szColName[MAX_PATH * 2]; HDITEM hdItem; hdItem.mask = HDI_TEXT | HDI_LPARAM; hdItem.pszText = szColName; hdItem.cchTextMax = countof (szColName); if (pHeader->GetItem (i, &hdItem)) { CHiddenColumnInfo hci (hdItem.lParam); rgColumns[i].strColName = hdItem.pszText; rgColumns[i].bHidden = hci.fHidden; } else { goto Error; } } for (int i = 0; i < printcols ; i++) { // Print the column name according to the order if (rgColumns[pnColOrder[i]].bHidden) continue; if ( (!Write2File(hFile, rgColumns[pnColOrder[i]].strColName, bUnicode)) || ((i < printcols - 1) && (!Write2File(hFile, pszSeparator, bUnicode)))) { goto CantWriteError; } } // Write an EOL character if necessary if (!Write2File(hFile, strEol, bUnicode)) { goto CantWriteError; } } { // Data for use in the writing stage CString strData; CListCtrl& ctlList = m_pListCtrl->GetListCtrl(); // Set iNextType to 0 if all items will be saved or LVNI_SELECTED if only selected ones will be saved int iNextType = 0; if (bSelectedRowsOnly) iNextType = LVNI_SELECTED; // Find the first item in the list int iItem = ctlList.GetNextItem( -1,iNextType); // Iterate until there are no more items to save while (iItem != -1) { for(int ind2 = 0; ind2 < printcols ; ind2++) { if (rgColumns) { // If not hidden get the item if (rgColumns[pnColOrder[ind2]].bHidden) continue; else strData = ctlList.GetItemText( iItem, pnColOrder[ind2]); } else strData = ctlList.GetItemText( iItem, ind2); // Write the text and if necessary a comma // If either one fails, then delete the file and return if ( (!Write2File(hFile, strData, bUnicode)) || ((ind2 < printcols - 1) && (!Write2File(hFile, pszSeparator, bUnicode)))) { goto CantWriteError; } } // Write an EOL character if necessary if (!Write2File(hFile, strEol, bUnicode)) { goto CantWriteError; } // Find the next item to save iItem = ctlList.GetNextItem( iItem, iNextType); } } Cleanup: if (rgColumns) delete[] rgColumns; if (pnColOrder) delete[] pnColOrder; CloseHandle(hFile); return (sc); CantWriteError: if (bShowErrorDialogs) ListSaveErrorMes(LSaveCantWrite, hFile, strFileName); Error: DeleteFile( strFileName ); goto Cleanup; } // Write out a string to the given file // Used as a separate function to preserve memory // Returns true if successful, false otherwise bool CAMCView::Write2File(HANDLE hfile, LPCTSTR strwrite, BOOL fUnicode) { DECLARE_SC(sc, TEXT("CAMCView::Write2File")); // parameter check; sc = ScCheckPointers( strwrite ); if (sc) return false; // Initializes Macro USES_CONVERSION; // The number of bytes written DWORD cbWritten; DWORD cbToWrite; if (fUnicode) { // Convert the string to Unicode and write it to hfile LPCWSTR Ustring = T2CW( strwrite ); cbToWrite = wcslen (Ustring) * sizeof (WCHAR); WriteFile(hfile, Ustring, cbToWrite, &cbWritten, NULL); } else { // Convert the string to ANSI and write it to hfile const unsigned char* Astring = (const unsigned char*) T2CA( strwrite ); cbToWrite = _mbsnbcnt (Astring, _mbslen (Astring)); WriteFile(hfile, Astring, cbToWrite, &cbWritten, NULL); } // Make sure that the correct number of bytes were written return (cbWritten == cbToWrite); } #endif // IMPLEMENT_LIST_SAVE See nodemgr.idl (t-dmarm) // Refreshes all panes and HTML void CAMCView::OnRefresh() { HWND hwnd = ::GetFocus(); if (IsVerbEnabled(MMC_VERB_REFRESH)) { ScConsoleVerb(evRefresh); } else if (HasWebBrowser()) { ScWebCommand(eWeb_Refresh); } ::SetFocus(hwnd); } void CAMCView::OnVerbAccelKey(UINT nID) { DECLARE_SC(sc, TEXT("CAMCView::OnVerbAccelKey")); switch (nID) { case ID_MMC_CUT: if (IsVerbEnabled(MMC_VERB_CUT)) sc = ScConsoleVerb(evCut); break; case ID_MMC_COPY: if (IsVerbEnabled(MMC_VERB_COPY)) sc = ScConsoleVerb(evCopy); break; case ID_MMC_PASTE: if (IsVerbEnabled(MMC_VERB_PASTE)) { // Check if the dataobject in clipboard can be // pasted into the selected node. // Then only we send MMCN_PASTE notification to snapin. HNODE hNode = NULL; LPARAM lvData = NULL; bool bScope = FALSE; sc = ScGetFocusedItem(hNode, lvData, bScope); if (sc) break; INodeCallback* pNC = GetNodeCallback(); sc = ScCheckPointers(pNC, hNode, E_UNEXPECTED); if (sc) break; bool bPasteAllowed = false; sc = pNC->QueryPasteFromClipboard(hNode, bScope, lvData, bPasteAllowed); if (sc) break; if (bPasteAllowed) sc = ScConsoleVerb(evPaste); } break; case ID_MMC_PRINT: if (IsVerbEnabled(MMC_VERB_PRINT)) sc = ScConsoleVerb(evPrint); break; case ID_MMC_RENAME: if (IsVerbEnabled(MMC_VERB_RENAME)) sc = ScConsoleVerb(evRename); break; case ID_MMC_REFRESH: OnRefresh(); break; default: ASSERT(FALSE); } if (sc) return; } // // Handle accelerator keys shared by result and scope panes // BOOL CAMCView::OnSharedKeyDown(WORD wVKey) { BOOL bReturn = TRUE; if (::GetKeyState(VK_CONTROL) < 0) { switch (wVKey) { case 'C': case 'c': case VK_INSERT: OnVerbAccelKey(ID_MMC_COPY); // Ctrl-C, Ctrl-Insert break; case 'V': case 'v': OnVerbAccelKey(ID_MMC_PASTE); // Ctrl-V break; case 'X': case 'x': OnVerbAccelKey(ID_MMC_CUT); // Ctrl-X break; default: bReturn = FALSE; } } else if (::GetKeyState(VK_SHIFT) < 0) { switch (wVKey) { case VK_DELETE: OnVerbAccelKey(ID_MMC_CUT); // Shift-Delete break; case VK_INSERT: OnVerbAccelKey(ID_MMC_PASTE); // Shift -Insert break; default: bReturn = FALSE; } } else { switch (wVKey) { case VK_F2: OnVerbAccelKey(ID_MMC_RENAME); // F2 break; default: bReturn = FALSE; } } return bReturn; } //+------------------------------------------------------------------- // // Member: ScConsoleVerb // // Synopsis: Execute the Console verb. // // Arguments: [nVerb] - The verb to be executed. // // Note: The verb is executed in the context of // currently focused item (scope or result). // // Returns: SC // //-------------------------------------------------------------------- SC CAMCView::ScConsoleVerb (int nVerb) { AFX_MANAGE_STATE (AfxGetAppModuleState()); ASSERT_VALID (this); DECLARE_SC (sc, _T("CAMCView::ScConsoleVerb")); HNODE hNode = NULL; LPARAM lvData = 0; bool bScope = false; // Get the focused item to process the console verb. sc = ScGetFocusedItem(hNode, lvData, bScope); if (sc) return sc; sc = ScProcessConsoleVerb(hNode, bScope, lvData, nVerb); return (sc); } //+------------------------------------------------------------------- // // Member: ScProcessConsoleVerb // // Synopsis: Execute the Console verb with given context. // // Arguments: [hNode] - The tree node context. // [bScope] - Scope or Result pane. // [lvData] - LPARAM of result item (if result pane has focus). // [nVerb] - The verb to be executed. // // Returns: SC // //-------------------------------------------------------------------- SC CAMCView::ScProcessConsoleVerb(HNODE hNode, bool bScope, LPARAM lvData, int nVerb) { DECLARE_SC (sc, _T("CAMCView::ScProcessConsoleVerb")); AFX_MANAGE_STATE (AfxGetAppModuleState()); ASSERT_VALID (this); // To maintain compatibility with MMC1.2 (This is init to LVERROR which // nodemgr process differently). if (bScope) lvData = 0; if (lvData == LVDATA_BACKGROUND) { switch (nVerb) { case evCut: case evCopy: case evDelete: case evRename: sc = E_UNEXPECTED; return sc; } } NCLBK_NOTIFY_TYPE nclbk = NCLBK_NONE; switch (nVerb) { case evCut: nclbk = NCLBK_CUT; break; case evCopy: nclbk = NCLBK_COPY; break; case evDelete: nclbk = NCLBK_DELETE; break; case evProperties: nclbk = NCLBK_PROPERTIES; break; case evPrint: nclbk = NCLBK_PRINT; break; case evPaste: { INodeCallback* pNC = GetNodeCallback(); sc = ScCheckPointers(pNC, E_UNEXPECTED); if (sc) return sc; sc = pNC->Paste(hNode, bScope, lvData); if (sc) return sc; sc = ScPaste (); if (sc) return sc; break; } case evRefresh: // if web page on view, send it a refresh first if (HasWebBrowser()) sc = ScWebCommand(eWeb_Refresh); if (sc) return sc; nclbk = NCLBK_REFRESH; break; case evRename: // Enable edit for the item. if (bScope == TRUE) { if (sc = ScCheckPointers(m_pTreeCtrl, E_UNEXPECTED)) return sc; HTREEITEM hti = m_pTreeCtrl->GetSelectedItem(); if (sc = ScCheckPointers(hti, E_UNEXPECTED)) return sc; m_pTreeCtrl->EditLabel(hti); } else { if ( sc = ScCheckPointers(m_pListCtrl, E_UNEXPECTED)) return sc; CAMCListView* pListView = m_pListCtrl->GetListViewPtr(); if (NULL == pListView) { sc = E_UNEXPECTED; return sc; } int iItem = _GetLVSelectedItemData(&lvData); ASSERT(iItem >= 0); CListCtrl& listCtrl = pListView->GetListCtrl(); listCtrl.EditLabel(iItem); } break; default: sc = E_UNEXPECTED; return sc; } if (nclbk != NCLBK_NONE) { // Ask the nodemgr to process the verb. INodeCallback* pNC = GetNodeCallback(); if (pNC == NULL) { sc = E_UNEXPECTED; return sc; } sc = pNC->Notify(hNode, nclbk, bScope, lvData); if (sc) return sc; } if (nclbk == NCLBK_CUT) sc = ScCut (bScope ? m_pTreeCtrl->GetSelectedItem() : 0); if (sc) return sc; return (sc); } //+------------------------------------------------------------------- // // Member: CAMCView::ScListViewSelectionActivate // // Synopsis: Only the list(/Web/OCX) or the tree can be "active" from the point // of view of selected items and MMCN_SELECT. This is not // the same as the MFC concept of "active view". There are a couple // of views that cannot be active in this sense, such as the taskpad // and tab views. // When the active view (according to this definition) changes, this // function is called. Thus, ScTreeViewSelectionActivate and // ScListViewSelectionActivate/ScSpecialResultpaneSelectionActivate // are always called in pairs when the activation changes, one to handle // deactivation, and one to handle activation. // // Consider the following scenario // 1) The tree view has (MFC/windows style) focus. // 2) The user clicks on the taskpad view // Result - selection activation does not change from the tree. All verbs // still correspond to the selected tree item. // 3) The user clicks on the folder view // Result - once again, selection activation does not chang // 4) The user clicks on one of the result views eg the list // Result - ScTreeViewSelectionActivate(false) and ScListViewSelectionActivate(true) // Thus verbs and the toolbar now correspond to the selected list item(s). // 5) The user clicks on the taskpad view. // Result - as in step 2, nothing happens // 6) The user clicks on the result view // Result - because the active view has not changed, nothing happens. // // Arguments: [bActivate] - [in] // // Returns: SC // //-------------------------------------------------------------------- SC CAMCView::ScListViewSelectionActivate(bool bActivate) { DECLARE_SC(sc, TEXT("CAMCView::ScListViewSelectionActivate")); if (m_pListCtrl == NULL) return sc; INodeCallback* pNC = GetNodeCallback(); sc = ScCheckPointers(pNC, E_UNEXPECTED); if (sc) { sc.TraceAndClear(); return sc; } HNODE hNodeSel = GetSelectedNode(); SELECTIONINFO selInfo; ZeroMemory(&selInfo, sizeof(selInfo)); selInfo.m_bScope = FALSE; selInfo.m_bDueToFocusChange = TRUE; #ifdef DBG if (bActivate == TRUE) { ASSERT(m_bProcessMultiSelectionChanges == false); } #endif // DBG /* * The below block can never execute. When m_bProcessMultiSelectionChanges is * set to true messages are posted to handle multiselection changes. So the * handler OnProcessMultiSelectionChanges should have processed the message and the * m_bProcessMultiSelectionChanges should have been reset by now. If there is * some unknown way to make de-activate the listview before processing the message * then below block will be executed that will send de-select notification. * * The below block sends a de-select multi-select items. */ if (m_bProcessMultiSelectionChanges) { ASSERT(false); // Would like to know when this block is hit. ASSERT(bActivate == false); m_bProcessMultiSelectionChanges = false; sc = ScNotifySelect (pNC, hNodeSel, true /*fMultiSelect*/, false, 0); if (sc) sc.TraceAndClear(); // ignore & continue; // Focus change so appropriately enable std-toolbar buttons // back, forward, export-list, up-one-level, show/hide-scope, help sc = ScUpdateStandardbarMMCButtons(); if (sc) sc.TraceAndClear(); } bool bSelect = bActivate; do { // // Multi select // int cSelected = m_pListCtrl->GetSelectedCount(); if (cSelected > 1) { sc = ScNotifySelect (pNC, hNodeSel, true /*fMultiSelect*/, bSelect, 0); if (sc) sc.TraceAndClear(); // ignore & continue; m_bLastSelWasMultiSel = bSelect; break; } // // Zero or Single select // if (cSelected == 0) { selInfo.m_bBackground = TRUE; selInfo.m_lCookie = LVDATA_BACKGROUND; } else { #include "pushwarn.h" #pragma warning(disable: 4552) // ">=" operator has no effect VERIFY(_GetLVSelectedItemData(&selInfo.m_lCookie) >= 0); #include "popwarn.h" } ASSERT(cSelected >= 0); ASSERT(cSelected <= 1); sc = ScNotifySelect (pNC, hNodeSel, false /*fMultiSelect*/, bSelect, &selInfo); if (sc) sc.TraceAndClear(); // ignore & continue; } while (0); return sc; } void CAMCView::OnShowWindow(BOOL bShow, UINT nStatus) { CView::OnShowWindow(bShow, nStatus); } int CAMCView::_GetLVItemData(LPARAM *plParam, UINT flags) { HWND hwnd = m_pListCtrl->GetListViewHWND(); int iItem = ::SendMessage(hwnd, LVM_GETNEXTITEM, (WPARAM) (int) -1, MAKELPARAM(flags, 0)); if (iItem >= 0) { if (IsVirtualList()) { *plParam = iItem; } else { LV_ITEM lvi; ZeroMemory(&lvi, sizeof(lvi)); lvi.iItem = iItem; lvi.mask = LVIF_PARAM; #include "pushwarn.h" #pragma warning(disable: 4553) // "==" operator has no effect VERIFY(::SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM)&lvi) == TRUE); #include "popwarn.h" *plParam = lvi.lParam; } } return iItem; } int CAMCView::_GetLVFocusedItemData(LPARAM *plParam) { return (_GetLVItemData (plParam, LVNI_FOCUSED)); } int CAMCView::_GetLVSelectedItemData(LPARAM *plParam) { return (_GetLVItemData (plParam, LVNI_SELECTED)); } void CAMCView::SetListViewMultiSelect(BOOL bMultiSelect) { long lStyle = m_pListCtrl->GetListStyle(); if (bMultiSelect == FALSE) lStyle |= LVS_SINGLESEL; else lStyle &= ~LVS_SINGLESEL; m_pListCtrl->SetListStyle(lStyle); } /*+-------------------------------------------------------------------------* * * CAMCView::ScOnItemDeselected * * PURPOSE: Tree observer method. Called when a tree item is deselected. * * PARAMETERS: * HNODE hNode : The node that was deselected. * * NOTE: This function can be merged with the next. * * RETURNS: * SC * *+-------------------------------------------------------------------------*/ SC CAMCView::ScOnItemDeselected(HNODE hNode) { DECLARE_SC (sc, TEXT("CAMCView::ScOnItemDeselected")); DeSelectResultPane(hNode); if (!hNode) return sc; SELECTIONINFO selInfo; ZeroMemory(&selInfo, sizeof(selInfo)); // Ask the SnapIn to cleanup any items it has inserted. INodeCallback* spNodeCallBack = GetNodeCallback(); ASSERT(spNodeCallBack != NULL); selInfo.m_bScope = TRUE; selInfo.m_pView = NULL; Dbg(DEB_USER6, _T("T1. CAMCTreeView::OnDeSelectNode<1, 0>\n")); sc = ScNotifySelect (spNodeCallBack, hNode, false /*fMultiSelect*/, false, &selInfo); if (sc) sc.TraceAndClear(); // ignore & continue; return sc; } /*+-------------------------------------------------------------------------* * * CAMCView::DeSelectResultPane * * PURPOSE: Deselects the result pane and sets the view type to invalid. * * PARAMETERS: * HNODE hNodeSel : * * RETURNS: * void * *+-------------------------------------------------------------------------*/ void CAMCView::DeSelectResultPane(HNODE hNodeSel) { DECLARE_SC(sc, TEXT("CAMCView::DeSelectResultPane")); if (m_spTaskPadHost.GetInterfacePtr() != NULL) { CTaskPadHost *pTaskPadHost = dynamic_cast(m_spTaskPadHost.GetInterfacePtr()); m_spTaskPadHost = NULL; } INodeCallback* pNC = GetNodeCallback(); ASSERT(pNC != NULL); if (hNodeSel == 0) return; // If there was no list view being displayed return. if (HasListOrListPad()) { // if we were in ListPad-mode, undo that. if (m_pListCtrl->IsListPad()) { sc = m_pListCtrl->ScAttachToListPad (NULL, NULL); if(sc) sc.TraceAndClear(); //ignore } // If we are in edit mode cancel it. m_pListCtrl->GetListCtrl().EditLabel(-1); SELECTIONINFO selInfo; ZeroMemory(&selInfo, sizeof(selInfo)); selInfo.m_bScope = FALSE; /* * The below block can never execute. When m_bProcessMultiSelectionChanges is * set to true messages are posted to handle multiselection changes. So the * handler OnProcessMultiSelectionChanges should have processed the message and the * m_bProcessMultiSelectionChanges should have been reset by now. If there is * some unknown way to make select different node (to deselect result pane) * before processing the message then below block will be executed that will * send de-select notification. * * The below block sends a de-select multi-select items. */ if (m_bProcessMultiSelectionChanges) { ASSERT(false); // Would like to know when this block is hit. m_bProcessMultiSelectionChanges = false; sc = ScNotifySelect (pNC, hNodeSel, true /*fMultiSelect*/, false, 0); if (sc) sc.TraceAndClear(); // ignore & continue; } else { UINT cSel = m_pListCtrl->GetSelectedCount(); if (cSel == 1) { if (cSel) { int iItem = _GetLVSelectedItemData(&selInfo.m_lCookie); ASSERT(iItem != -1); sc = ScNotifySelect (pNC, hNodeSel, false /*fMultiSelect*/, false, &selInfo); if (sc) sc.TraceAndClear(); // ignore & continue; } } else if (cSel > 1) { sc = ScNotifySelect (pNC, hNodeSel, true /*fMultiSelect*/, false, 0); if (sc) sc.TraceAndClear(); // ignore & continue; m_bLastSelWasMultiSel = false; } } } else { // If it is OCX or Web send de-select notifications. sc = ScSpecialResultpaneSelectionActivate(FALSE); } } LRESULT CAMCView::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { // NATHAN case WM_NOTIFYFORMAT: { int id = ::GetDlgCtrlID ((HWND)wParam); //if (m_pTreeCtrl == NULL || ((HWND)wParam != m_pTreeCtrl->m_hWnd)) if (id == IDC_ListView) return NFR_UNICODE; } break; #ifdef DBG case WM_KEYUP: { switch (wParam) { case VK_SHIFT: case VK_CONTROL: // We removed some code that will work if m_bProcessMultiSelectionChanges // is true. I dont see any way the bool being true. Still let us have below // assert. If this gets fired then we should call OnProcessMultiSelectionChanges. ASSERT(m_bProcessMultiSelectionChanges == false); break; } break; } break; #endif } return CView::WindowProc(message, wParam, lParam); } /*+-------------------------------------------------------------------------* * CAMCView::ChangePane * * Moves the activation from pane to pane. The (forward) tab order is * * Scope pane (either tree or favorites) * Result pane * Task view (if visible) *--------------------------------------------------------------------------*/ class CTabOrderEntry { public: CView* const m_pView; const bool m_bValid; // is this entry valid CTabOrderEntry(CView *pView) : m_pView (pView), m_bValid ((pView != NULL) && IsWindowVisible (pView->m_hWnd)) {} }; void CAMCView::ChangePane(AMCNavDir eDir) { ASSERT_VALID (this); CFrameWnd* pFrame = GetParentFrame(); CView* pActiveView = pFrame->GetActiveView(); HWND hWndActive = ::GetFocus(); CTabOrderEntry rgOrderEntry[] = { CTabOrderEntry(GetPaneView(ePane_ScopeTree)), // tree has focus CTabOrderEntry(GetPaneView(ePane_Results)), // results has focus - note the value of INDEX_RESULTS_PANE below. CTabOrderEntry(m_pViewExtensionCtrl), // view extension web page has focus CTabOrderEntry(m_pResultFolderTabView), // result tab control has focus }; /* * this is the index of the result pane entry in rgOrderEntry, * used for default focus placement if something unexpected happens */ const int INDEX_RESULTS_PANE = 1; ASSERT (rgOrderEntry[INDEX_RESULTS_PANE].m_pView == GetPaneView(ePane_Results)); // Get the navigator if one exists. If so, use it and bail. CAMCNavigator* pNav = dynamic_cast(pActiveView); if (pNav && pNav->ChangePane(eDir)) return; int cEntries = (sizeof(rgOrderEntry) / sizeof(rgOrderEntry[0])); // get the currently active entry. for(int i = 0; i< cEntries; i++) { if( (rgOrderEntry[i].m_pView == pActiveView) ) break; } ASSERT(i < cEntries); if(i>= cEntries) { // if we don't know where we are, a bit of defensive coding puts the focus back // on the results pane, ie into a known state. i = INDEX_RESULTS_PANE; } int iPrev = i; // at this point we've found the right entry. int increment = (eDir==AMCNAV_PREV) ? -1 : 1; int sanityCount = 0; while(true) { i = (i+increment+cEntries) % cEntries; if(rgOrderEntry[i].m_bValid) break; sanityCount++; if(sanityCount == cEntries) { ASSERT(0 && "Something's seriously messed up!!"); return; } } // update the active view if (i != iPrev) pFrame->SetActiveView(rgOrderEntry[i].m_pView); else { // if view retains focus and has a navigator, // tell navigator to take the focus if (pNav) pNav->TakeFocus(eDir); } // if there is a special focus handler, call it. CFocusHandler *pFocusHandler = dynamic_cast(rgOrderEntry[i].m_pView); if(pFocusHandler != NULL) { pFocusHandler->OnKeyboardFocus (LVIS_FOCUSED | LVIS_SELECTED, LVIS_FOCUSED | LVIS_SELECTED); } } void CAMCView::OnNextPane() { ChangePane(AMCNAV_NEXT); } void CAMCView::OnPrevPane() { ChangePane(AMCNAV_PREV); } void CAMCView::OnUpdateNextPane(CCmdUI* pCmdUI) { pCmdUI->Enable(TRUE); } void CAMCView::OnUpdatePrevPane(CCmdUI* pCmdUI) { pCmdUI->Enable(TRUE); } void RestrictPointToWindow (CWnd* pwnd, CPoint* ppt) { CRect rectWnd; pwnd->GetClientRect (rectWnd); if (ppt->x < rectWnd.left) ppt->x = rectWnd.left; else if (ppt->x > rectWnd.right) ppt->x = rectWnd.right; if (ppt->y < rectWnd.top) ppt->y = rectWnd.top; else if (ppt->y > rectWnd.bottom) ppt->y = rectWnd.bottom; } void CAMCView::OnShiftF10() { CRect rect; CWnd* pwndFocus = GetFocus(); CListCtrl& lc = m_pListCtrl->GetListCtrl(); ASSERT_VALID (this); if (pwndFocus == &lc) { int iItem = lc.GetNextItem (-1, LVNI_SELECTED); CPoint pt = 0; if (iItem != -1) { VERIFY (lc.GetItemRect (iItem, rect, LVIR_ICON)); pt = rect.CenterPoint (); } else { CHeaderCtrl* pHeader = m_pListCtrl->GetHeaderCtrl(); if (pHeader != NULL && pHeader->IsWindowVisible()) { pHeader->GetClientRect(&rect); pt.y = rect.Height(); ASSERT (pt.y >= 0); } } /* * make sure the context menu doesn't show up outside the window */ RestrictPointToWindow (&lc, &pt); m_pListCtrl->GetListViewPtr()->ClientToScreen(&pt); OnListContextMenu(pt); } else if (pwndFocus == m_pTreeCtrl) { HTREEITEM hTreeItem = m_pTreeCtrl->GetSelectedItem(); if (hTreeItem == NULL) return; m_pTreeCtrl->GetItemRect (hTreeItem, rect, TRUE); CPoint ptClient (rect.left, rect.bottom-1); /* * make sure the context menu doesn't show up outside the window */ RestrictPointToWindow (m_pTreeCtrl, &ptClient); CPoint ptScreen = ptClient; m_pTreeCtrl->ClientToScreen(&ptScreen); OnTreeContextMenu(ptScreen, ptClient, hTreeItem); } } void CAMCView::OnUpdateShiftF10(CCmdUI* pCmdUI) { pCmdUI->Enable(TRUE); } BOOL CAMCView::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message) { if (nHitTest == HTCLIENT && pWnd == this && !IsTracking()) { CPoint pt (GetMessagePos()); ScreenToClient (&pt); if (m_rectVSplitter.PtInRect (pt)) { SetCursor(AfxGetApp()->LoadStandardCursor(IDC_SIZEWE)); return TRUE; } } return CWnd::OnSetCursor(pWnd, nHitTest, message); } SC CAMCView::ScCut (HTREEITEM htiCut) { AFX_MANAGE_STATE (AfxGetAppModuleState()); DECLARE_SC (sc, _T("CAMCView::ScCut")); CMainFrame* pMain = AMCGetMainWnd(); sc = ScCheckPointers (pMain, E_UNEXPECTED); if (sc) return (sc); pMain->SetWindowToNotifyCBChange(m_hWnd); if (htiCut) m_pTreeCtrl->SetItemState (htiCut, TVIS_CUT, TVIS_CUT); else m_pListCtrl->CutSelectedItems (TRUE); m_htiCut = htiCut; return (S_OK); } SC CAMCView::ScPaste () { AFX_MANAGE_STATE (AfxGetAppModuleState()); DECLARE_SC (sc, _T("CAMCView::ScPaste")); if (!m_htiCut) m_pListCtrl->CutSelectedItems(FALSE); CMainFrame* pMain = AMCGetMainWnd(); sc = ScCheckPointers (pMain, E_UNEXPECTED); if (sc) return (sc); pMain->SetWindowToNotifyCBChange(NULL); return (S_OK); } HRESULT CAMCView::SendGenericNotify(NCLBK_NOTIFY_TYPE nclbk) { BOOL bScope = TRUE; MMC_COOKIE lCookie = 0; int iItem = -1; ASSERT_VALID (this); if (m_pListCtrl && m_pListCtrl->GetListViewHWND() == ::GetFocus()) { iItem = _GetLVSelectedItemData(&lCookie); if (iItem != -1) bScope = FALSE; } INodeCallback* pNC = GetNodeCallback(); ASSERT(pNC != NULL); if (pNC == NULL) return E_FAIL; HNODE hNodeSel = GetSelectedNode(); ASSERT(hNodeSel != NULL); if (hNodeSel == NULL) return E_FAIL; // selection notifications should use ScNotifySelect() ASSERT ((nclbk != NCLBK_SELECT) && (nclbk != NCLBK_MULTI_SELECT)); return pNC->Notify(hNodeSel, nclbk, bScope, lCookie); } void CAMCView::SaveStartingSelectedNode() { m_htiStartingSelectedNode = m_pTreeCtrl->GetSelectedItem(); } bool CAMCView::HasNodeSelChanged() { return (m_pTreeCtrl->GetSelectedItem() != m_htiStartingSelectedNode); } //+--------------------------------------------------------------------------- // // Function: OnSysKeyDown // // Synopsis: Handles WM_SYSKEYDOWN message. // CAMCTreeView::OnSysKeyDown handles the Tree view so // here we handle only the list view (or Result pane) // // Returns: none // //+--------------------------------------------------------------------------- void CAMCView::OnSysKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) { switch (nChar) { case VK_LEFT: ScWebCommand(eWeb_Back); break; case VK_RIGHT: ScWebCommand(eWeb_Forward); break; } } /*+-------------------------------------------------------------------------* * CAMCView::OnAppCommand * * WM_APPCOMMAND handler for CAMCView. This is used to handle to forward * and backward buttons on the IntelliMouse Explorer and the Microsoft * Natural Keyboards *--------------------------------------------------------------------------*/ LRESULT CAMCView::OnAppCommand(WPARAM wParam, LPARAM lParam) { DECLARE_SC (sc, _T("CAMCView::OnAppCommand")); switch (GET_APPCOMMAND_LPARAM (lParam)) { case APPCOMMAND_BROWSER_BACKWARD: sc = ScWebCommand (eWeb_Back); if (sc) break; return (TRUE); // handled here case APPCOMMAND_BROWSER_FORWARD: sc = ScWebCommand (eWeb_Forward); if (sc) break; return (TRUE); // handled here case APPCOMMAND_BROWSER_REFRESH: OnRefresh (); return (TRUE); // handled here } return (Default()); } void CAMCView::OnPaletteChanged(CWnd* pwndFocus) { // if displaying a web page, forward the palette change to the shell if (HasWebBrowser() && m_pWebViewCtrl != NULL) { if (m_pWebViewCtrl->m_hWnd != NULL) { HWND hwndShell = ::GetWindow(m_pWebViewCtrl->m_hWnd, GW_CHILD); if (hwndShell != NULL) ::SendMessage(hwndShell, WM_PALETTECHANGED, (WPARAM)pwndFocus->m_hWnd, (LPARAM)0); } } } BOOL CAMCView::OnQueryNewPalette() { // if displaying a web page, forward the palette query to the shell if (HasWebBrowser() && m_pWebViewCtrl != NULL) { if (m_pWebViewCtrl->m_hWnd != NULL) { HWND hwndShell = ::GetWindow(m_pWebViewCtrl->m_hWnd, GW_CHILD); if (hwndShell != NULL) return ::SendMessage(hwndShell, WM_QUERYNEWPALETTE, (WPARAM)0, (LPARAM)0); } } return 0; } BOOL CAMCView::OwnsResultList(HTREEITEM hti) { if (hti == NULL) return (false); // if result list is active if (HasListOrListPad()) { // Get selected node and query node HNODE hnodeSelected = GetSelectedNode(); HNODE hnode = m_pTreeCtrl ? m_pTreeCtrl->GetItemNode(hti) : NULL; if (hnodeSelected && hnode) { INodeCallback* pNC = GetNodeCallback(); ASSERT(pNC != NULL); // See if the selected node uses the query node as a target // S_OK - yes // S_FALSE - uses a different target node // E_FAIL - doesn't use a target node HRESULT hr = pNC->IsTargetNodeOf(hnodeSelected, hnode); if (hr == S_OK) return TRUE; else if (hr == S_FALSE) return FALSE; else return (hnodeSelected == hnode); } } return FALSE; } /*+-------------------------------------------------------------------------* * CAMCView::OnSysColorChange * * WM_SYSCOLORCHANGE handler for CAMCView. *--------------------------------------------------------------------------*/ void CAMCView::OnSysColorChange() { CView::OnSysColorChange(); /* * the list control isn't a window but rather a wrapper on a window, * so we need to manually forward on the WM_SYSCOLORCHANGE */ m_pListCtrl->OnSysColorChange(); } /*+-------------------------------------------------------------------------* * TrackerCallback function * * Called by CViewTracker when tracking of splitter bar is completed. This * function applies the changes if the AcceptChange flag is set. *--------------------------------------------------------------------------*/ void CALLBACK TrackerCallback( TRACKER_INFO* pInfo, bool bAcceptChange, bool bSyncLayout) { DECLARE_SC (sc, _T("TrackerCallback")); if (bAcceptChange) { CAMCView* pView = dynamic_cast(pInfo->pView); sc = ScCheckPointers (pView, E_UNEXPECTED); if (sc) return; // Set new width and recompute layout pView->m_PaneInfo[CConsoleView::ePane_ScopeTree].cx = pInfo->rectTracker.left; pView->SetDirty(); if (bSyncLayout) { Trace (tagSplitterTracking, _T("Synchronous layout")); pView->RecalcLayout(); pView->UpdateWindow(); } else { Trace (tagSplitterTracking, _T("Deferred layout")); pView->DeferRecalcLayout(); } } } /*+-------------------------------------------------------------------------* * PtInWindow * * Test if point is in a window (pt is in screen coordinates) *--------------------------------------------------------------------------*/ BOOL PtInWindow(CWnd* pWnd, CPoint pt) { if (!pWnd->IsWindowVisible()) return FALSE; CRect rect; pWnd->GetWindowRect(&rect); return rect.PtInRect(pt); } /*+-------------------------------------------------------------------------* * CAMCView::ScJiggleListViewFocus * * Bug 345402: Make sure the focus rect is on the list control (if it * actually has the focus) to wake up any accessibility tools that might * be watching for input and focus changes. * * We post a message here rather than doing it synchronously so we can * allow any other processing in the list (like sorting) to happen * before we put the focus on the 1st item. If we didn't wait until after * the sort, the item we put the focus on might not be the first item * in the list. *--------------------------------------------------------------------------*/ SC CAMCView::ScJiggleListViewFocus () { AFX_MANAGE_STATE (AfxGetAppModuleState()); PostMessage (m_nJiggleListViewFocusMsg); return (S_OK); } LRESULT CAMCView::OnJiggleListViewFocus (WPARAM, LPARAM) { CAMCListView* pListView = m_pListCtrl->GetListViewPtr(); /* * If the focus is on the list control, make sure that at least one item * has the focus rect. Doing this will wake up any accessibility tools * that might be watching (Bug 345402). */ if ((GetFocusedPane() == ePane_Results) && (GetResultView() == pListView)) { pListView->OnKeyboardFocus (LVIS_FOCUSED, LVIS_FOCUSED); } return (0); } /*+-------------------------------------------------------------------------* * CAMCView::OnDeferRecalcLayout * * CAMCView::m_nDeferRecalcLayoutMsg registered message handler for CAMCView. * * Parameters: * bDoArrange - if non-zero need to call Arrange on list-view so that * common-control can layout items properly. * *--------------------------------------------------------------------------*/ LRESULT CAMCView::OnDeferRecalcLayout (WPARAM bDoArrange, LPARAM) { Trace (tagLayout, _T("CAMCView::OnDeferRecalcLayout")); RecalcLayout(); if (bDoArrange && m_pListCtrl) { int nViewMode = m_pListCtrl->GetViewMode(); // Arrange is only for large & small icon modes. if ( (nViewMode == MMCLV_VIEWSTYLE_ICON) || (nViewMode == MMCLV_VIEWSTYLE_SMALLICON) ) m_pListCtrl->Arrange(LVA_DEFAULT); } return (0); } /*+-------------------------------------------------------------------------* * CDeferredPageBreak * * * PURPOSE: Used to delay sending a web page break until an idle timeout. * This used to be sent via PostMessage, but resulted in multiple * ScDoPageBreak calls on the same stack, since the latter has * its own message loop. By using the idle timer, we guarantee that * there are no reentrant problems. * *+-------------------------------------------------------------------------*/ class CDeferredPageBreak : public CIdleTask { public: CDeferredPageBreak(UINT nAddPageBreakAndNavigateMsg, HWND hWnd, WPARAM wParam, LPCTSTR szURL) : m_atomTask (AddAtom (_T("CDeferredPageBreak"))), m_nAddPageBreakAndNavigateMsg(nAddPageBreakAndNavigateMsg), m_hWnd(hWnd), m_wParam(wParam), m_strURL(szURL ? szURL : _T("")) { } ~CDeferredPageBreak() {} // IIdleTask methods SC ScDoWork() { DECLARE_SC (sc, TEXT("CDeferredPageBreak::ScDoWork")); ::SendMessage(m_hWnd, m_nAddPageBreakAndNavigateMsg, m_wParam, reinterpret_cast( m_strURL.data() )); // do this synchronously return sc; } SC ScGetTaskID(ATOM* pID) { DECLARE_SC (sc, TEXT("CDeferredPageBreak::ScGetTaskID")); sc = ScCheckPointers(pID); if(sc) return sc; *pID = m_atomTask; return sc; } SC ScMerge(CIdleTask* pitMergeFrom) {return S_FALSE /*do not merge*/;} private: const ATOM m_atomTask; const UINT m_nAddPageBreakAndNavigateMsg; const HWND m_hWnd; const WPARAM m_wParam; const tstring m_strURL; }; /*+-------------------------------------------------------------------------* * CAMCView::ScAddPageBreakAndNavigate * * Adds a page break to the history list. This needs to occur asynchronously, * so we post a private message to ourselves and return. *--------------------------------------------------------------------------*/ SC CAMCView::ScAddPageBreakAndNavigate (bool fAddPageBreak, bool fNavigate, LPCTSTR szURL) { AFX_MANAGE_STATE (AfxGetAppModuleState()); // not sure if we need this, but doesn't hurt to have it in here. DECLARE_SC (sc, TEXT("CAMCView::ScAddPageBreakAndNavigate")); CIdleTaskQueue* pIdleTaskQueue = AMCGetIdleTaskQueue(); sc = ScCheckPointers(pIdleTaskQueue, E_UNEXPECTED); if(sc) return sc; if ( fNavigate && szURL == NULL ) return sc = E_INVALIDARG; /* * create the deferred page break task */ CAutoPtr spDeferredPageBreak (new CDeferredPageBreak (m_nAddPageBreakAndNavigateMsg, m_hWnd, MAKEWPARAM(fAddPageBreak, fNavigate), szURL)); sc = ScCheckPointers(spDeferredPageBreak, E_OUTOFMEMORY); if(sc) return sc; /* * put the task in the queue, which will take ownership of it */ sc = pIdleTaskQueue->ScPushTask (spDeferredPageBreak, ePriority_Normal); if (sc) return sc; /* * if we get here, the idle task queue owns the idle task, so * we can detach it from our smart pointer */ spDeferredPageBreak.Detach(); /* * jiggle the message pump so that it wakes up and checks idle tasks */ PostMessage (WM_NULL); return (S_OK); } /***************************************************************************\ * * METHOD: CAMCView::OnAddPageBreakAndNavigate * * PURPOSE: Puts a page break and/or navigates to a new webapge * This method will be called to perfor 3 kinds of the jobs: * 1. Add a pagebreak (used when selection changes from the web page to list view) * 2. Add a pagebreak and navigate * (a. when selection changes from web page to another web page) * (b. when selection changes from list view to the webpage * and it is the first web page in the history) * 3. Navigate only. ( when navigating from list view to the webpage - * if pagebreak had to be added when leaving the previos web page) * * PARAMETERS: * LOWORD(wParam) - nonzero if page break needs to be added * HIWORD(wParam) - nonzero if navigation should take place * LPARAM lParam - not used * * RETURNS: * SC - result code * \***************************************************************************/ LRESULT CAMCView::OnAddPageBreakAndNavigate (WPARAM wParam, LPARAM lParam) { DECLARE_SC(sc, TEXT("CAMCView::OnAddPageBreakAndNavigate")); BOOL bAddPageBreak = (BOOL)LOWORD(wParam); BOOL bNavigate = (BOOL)HIWORD(wParam); // check the pointer we will need here CHistoryList* pHistoryList = GetHistoryList(); sc = ScCheckPointers( pHistoryList, m_pWebViewCtrl, E_UNEXPECTED); if (sc) return 0; if (bAddPageBreak) { sc = pHistoryList->ScDoPageBreak(); if (sc) return 0; } if (bNavigate) { LPCTSTR szURL = reinterpret_cast(lParam); sc = ScCheckPointers( szURL ); if (sc) return 0; m_pWebViewCtrl->Navigate( szURL, NULL ); } return 0; } //############################################################################ //############################################################################ // // Implementation of class CViewTemplate // //############################################################################ //############################################################################ /***************************************************************************\ * * METHOD: CViewTemplateList::Persist * * PURPOSE: Used when loading XML. Persist enough information to create a view * The rest of view peristence is dome by CAMCView * * PARAMETERS: * CPersistor& persistor - persistor to load from * * RETURNS: * SC - result code * \***************************************************************************/ void CViewTemplateList::Persist(CPersistor& persistor) { // the view should be stored instead ASSERT (persistor.IsLoading()); // delegate to the base class XMLListCollectionBase::Persist(persistor); } /***************************************************************************\ * * METHOD: CViewTemplateList::OnNewElement * * PURPOSE: Called by XMLListCollectionBase to request persisting of new element * Each new element is created and persisted in this function. * * PARAMETERS: * CPersistor& persistor - persisto from which the element should be loaded * * RETURNS: * SC - result code * \***************************************************************************/ void CViewTemplateList::OnNewElement(CPersistor& persistor) { CBookmark bm; int iViewId = -1; // load information byte for new view CPersistor persistorView(persistor, CAMCView::_GetXMLType()); persistorView.Persist(bm, XML_NAME_ROOT_NODE); persistorView.PersistAttribute(XML_ATTR_VIEW_ID, iViewId); // store information to the list m_ViewsList.push_back(ViewTempl_Type(iViewId, ViewTemplB_Type(bm, persistorView))); } //+------------------------------------------------------------------- // // Member: ScUpdateStandardbarMMCButtons // // Synopsis: Appropriately enable/disable std-toolbar buttons // that are owned by MMC (not verb buttons that snapins own) like // back, forward, export-list, up-one-level, show/hide-scope, help. // // Arguments: None. // //-------------------------------------------------------------------- SC CAMCView::ScUpdateStandardbarMMCButtons() { DECLARE_SC (sc, _T("CAMCView::ScUpdateStandardbarMMCButtons")); // Get the standard toolbar and change the states. CStandardToolbar* pStdToolbar = GetStdToolbar(); if (NULL == pStdToolbar) return (sc = E_UNEXPECTED); CAMCDoc *pDoc = GetDocument(); sc = ScCheckPointers(pDoc, E_UNEXPECTED); if (sc) return sc; // If view is not customizable then hide the "Show/Hide scope tree" button. sc = pStdToolbar->ScEnableScopePaneBtn(IsScopePaneAllowed() && pDoc->AllowViewCustomization()); if (sc) sc.TraceAndClear(); sc = pStdToolbar->ScEnableContextHelpBtn(true); if (sc) sc.TraceAndClear(); sc = pStdToolbar->ScEnableExportList(GetListSize() > 0 /*Enable only if LV has items*/); if (sc) sc.TraceAndClear(); // Enable/Disable Up-One Level button. BOOL bEnableUpOneLevel = !m_pTreeCtrl->IsRootItemSel(); sc = pStdToolbar->ScEnableUpOneLevel(bEnableUpOneLevel); if (sc) sc.TraceAndClear(); // Now update history related buttons. sc = ScCheckPointers(m_pHistoryList, E_UNEXPECTED); if (sc) return sc; m_pHistoryList->MaintainWebBar(); return sc; } //+------------------------------------------------------------------- // // Member: CAMCView::ScUpdateMMCMenus // // Synopsis: Show or Hide MMC menus depending on if they are allowed // or not. Should do this only if our view owns the menus // that is we are the active view. (Action/View/Favs) // // Arguments: // // Returns: SC // //-------------------------------------------------------------------- SC CAMCView::ScUpdateMMCMenus () { DECLARE_SC(sc, _T("CAMCView::ScUpdateMMCMenus")); CMainFrame* pMainFrame = AMCGetMainWnd(); sc = ScCheckPointers(pMainFrame, E_UNEXPECTED); if (sc) return sc; if (this != pMainFrame->GetActiveAMCView()) return (sc = S_OK); // we are not active view so it is ok. // We are active view so tell mainframe to update the menus. sc = pMainFrame->ScShowMMCMenus(m_ViewData.IsStandardMenusAllowed()); if (sc) return sc; return (sc); } //+------------------------------------------------------------------- // // Member: CAMCView::ScCreateToolbarObjects // // Synopsis: Create the CAMCViewToolbars that manages all toolbar data // for this view & CStandardToolbar objects. // // Arguments: None. // // Returns: SC // //-------------------------------------------------------------------- SC CAMCView::ScCreateToolbarObjects () { DECLARE_SC(sc, _T("CAMCView::ScCreateToolbarObjects")); CMainFrame *pMainFrame = AMCGetMainWnd(); sc = ScCheckPointers(pMainFrame, E_UNEXPECTED); if (sc) return sc; // Create the toolbars for this view. CMMCToolBar *pMainToolbar = pMainFrame->GetMainToolbar(); sc = ScCheckPointers(pMainToolbar, E_OUTOFMEMORY); if (sc) return sc; m_spAMCViewToolbars = std::auto_ptr(new CAMCViewToolbars(pMainToolbar, this)); sc = ScCheckPointers(m_spAMCViewToolbars.get(), E_FAIL); if (sc) return sc; m_ViewData.SetAMCViewToolbarsMgr(m_spAMCViewToolbars.get() ); sc = m_spAMCViewToolbars->ScInit(); if (sc) return sc; // This CAMCViewToolbars is interested in view activation/de-activation/destruction events. AddObserver( (CAMCViewObserver&) (*m_spAMCViewToolbars) ); // Main toolbar UI is interested in the active CAMCViewToolbars. m_spAMCViewToolbars->AddObserver( *static_cast(pMainToolbar) ); // MMC application is interested in the toolbar event, since it needs to inform the script CAMCApp *pCAMCApp = AMCGetApp(); if ( pCAMCApp ) m_spAMCViewToolbars->AddObserver( *static_cast(pCAMCApp) ); // Create standard toolbar. m_spStandardToolbar = std::auto_ptr(new CStandardToolbar()); sc = ScCheckPointers(m_spStandardToolbar.get(), E_OUTOFMEMORY); if (sc) return sc; m_ViewData.SetStdVerbButtons(m_spStandardToolbar.get()); return (sc); } /*+-------------------------------------------------------------------------* * class CMMCViewFrame * * * PURPOSE: The COM 0bject that exposes the Frame interface off the View object. * *+-------------------------------------------------------------------------*/ class CMMCViewFrame : public CMMCIDispatchImpl, public CTiedComObject { typedef CAMCView CMyTiedObject; typedef CMMCViewFrame ThisClass; public: BEGIN_MMC_COM_MAP(ThisClass) END_MMC_COM_MAP() //Frame interface public: MMC_METHOD0( Maximize ); MMC_METHOD0( Minimize ); MMC_METHOD0( Restore ); MMC_METHOD1( get_Left, LPINT ); MMC_METHOD1( put_Left, INT ); MMC_METHOD1( get_Right, LPINT ); MMC_METHOD1( put_Right, INT ); MMC_METHOD1( get_Top, LPINT ); MMC_METHOD1( put_Top, INT ); MMC_METHOD1( get_Bottom, LPINT ); MMC_METHOD1( put_Bottom, INT ); }; /*+-------------------------------------------------------------------------* * * CAMCView::ScGetFrame * * PURPOSE: Returns a pointer to the COM object that implements the * Frame interface. * * PARAMETERS: * Frame **ppFrame : * * RETURNS: * SC * *+-------------------------------------------------------------------------*/ SC CAMCView::Scget_Frame(Frame **ppFrame) { DECLARE_SC(sc, TEXT("CAMCView::ScGetFrame") ); if(!ppFrame) { sc = E_POINTER; return sc; } // init out parameter *ppFrame = NULL; // create a CMMCApplicationFrame if not already done so. sc = CTiedComObjectCreator::ScCreateAndConnect(*this, m_spFrame); if(sc) return sc; if(m_spFrame == NULL) { sc = E_UNEXPECTED; return sc; } // addref the pointer for the client. m_spFrame->AddRef(); *ppFrame = m_spFrame; return sc; } /***************************************************************************\ | Frame interface | \***************************************************************************/ /*+-------------------------------------------------------------------------* * * CAMCView::ScMaximize * * PURPOSE: Maximizes frame window of the view * * PARAMETERS: * * RETURNS: * SC * *+-------------------------------------------------------------------------*/ SC CAMCView::ScMaximize () { DECLARE_SC(sc, TEXT("CAMCView::ScMaximize")); CChildFrame *pFrame = GetParentFrame(); sc = ScCheckPointers(pFrame, E_FAIL); if (sc) return sc; pFrame->ShowWindow(SW_MAXIMIZE); return sc; } /*+-------------------------------------------------------------------------* * * CAMCView::ScMinimize * * PURPOSE: Minimizes frame window of the view * * PARAMETERS: * * RETURNS: * SC * *+-------------------------------------------------------------------------*/ SC CAMCView::ScMinimize () { DECLARE_SC(sc, TEXT("CAMCView::ScMinimize")); CChildFrame *pFrame = GetParentFrame(); sc = ScCheckPointers(pFrame, E_FAIL); if (sc) return sc; pFrame->ShowWindow(SW_MINIMIZE); return sc; } /*+-------------------------------------------------------------------------* * * CAMCView::ScRestore * * PURPOSE: Restores frame window of the view * * PARAMETERS: * * RETURNS: * SC * *+-------------------------------------------------------------------------*/ SC CAMCView::ScRestore () { DECLARE_SC(sc, TEXT("CAMCView::ScRestore")); CChildFrame *pFrame = GetParentFrame(); sc = ScCheckPointers(pFrame, E_FAIL); if (sc) return sc; pFrame->ShowWindow(SW_RESTORE); return sc; } /*+-------------------------------------------------------------------------* * * CAMCView::ScGetFrameCoord * * PURPOSE: Helper method. Returns specified coordinate of the parent frame * * PARAMETERS: * LPINT pCoord - storage for return value * coord_t eCoord - which coordinate to return (LEFT, TOP, etc) * * RETURNS: * SC * *+-------------------------------------------------------------------------*/ SC CAMCView::ScGetFrameCoord ( LPINT pCoord, coord_t eCoord ) { DECLARE_SC(sc, TEXT("CAMCView::ScGetFrameCoord")); // get & check frame ptr CChildFrame *pFrame = GetParentFrame(); sc = ScCheckPointers(pFrame, E_FAIL); if (sc) return sc; CWnd *pParent = pFrame->GetParent(); sc = ScCheckPointers (pParent, E_FAIL); if (sc) return (sc); // get coordinates of frame window relative to its parent CWindowRect rcFrame (pFrame); pParent->ScreenToClient(rcFrame); // assign to result sc = ScGetRectCoord (rcFrame, pCoord, eCoord); if (sc) return (sc); return sc; } /*+-------------------------------------------------------------------------* * * CAMCView::ScSetFrameCoord * * PURPOSE: Helper method. Sets specified coordinate of the parent frame * * PARAMETERS: * INT coord - new value to set * coord_t eCoord - which coordinate to modify (LEFT, TOP, etc) * * RETURNS: * SC * *+-------------------------------------------------------------------------*/ SC CAMCView::ScSetFrameCoord ( INT coord, coord_t eCoord ) { DECLARE_SC(sc, TEXT("CAMCView::ScSetFrameCoord")); CChildFrame *pFrame = GetParentFrame(); sc = ScCheckPointers(pFrame, E_FAIL); if (sc) return sc; CWnd *pParent = pFrame->GetParent(); sc = ScCheckPointers (pParent, E_FAIL); if (sc) return (sc); // get coordinates of frame window relative to its parent CWindowRect rcFrame (pFrame); pParent->ScreenToClient(rcFrame); // change the rectangle's specified coordinate sc = ScSetRectCoord (rcFrame, coord, eCoord); if (sc) return (sc); // move the window pFrame->MoveWindow (rcFrame); return sc; } /*+-------------------------------------------------------------------------* * * CAMCView::ScGetRectCoord * * PURPOSE: Helper method. Returns specified coordinate of the given rectangle * * PARAMETERS: * const RECT& rect - rectangle to query * LPINT pCoord - storage for return value * coord_t eCoord - which coordinate to return (LEFT, TOP, etc) * * RETURNS: * SC * *+-------------------------------------------------------------------------*/ SC CAMCView::ScGetRectCoord ( const RECT& rect, LPINT pCoord, coord_t eCoord ) { DECLARE_SC(sc, TEXT("CAMCView::ScGetRectCoord")); // check parameters sc = ScCheckPointers(pCoord); if (sc) return sc; // assign to result switch (eCoord) { case LEFT: *pCoord = rect.left; break; case RIGHT: *pCoord = rect.right; break; case TOP: *pCoord = rect.top; break; case BOTTOM: *pCoord = rect.bottom; break; default: *pCoord = 0; sc = E_INVALIDARG; break; } return sc; } /*+-------------------------------------------------------------------------* * * CAMCView::ScSetRectCoord * * PURPOSE: Helper method. Sets specified coordinate of the given rectangle * * PARAMETERS: * RECT& rect - rectangle to modify * INT coord - new value to set * coord_t eCoord - which coordinate to modify (LEFT, TOP, etc) * * RETURNS: * SC * *+-------------------------------------------------------------------------*/ SC CAMCView::ScSetRectCoord ( RECT& rect, INT coord, coord_t eCoord ) { DECLARE_SC(sc, TEXT("CAMCView::ScSetRectCoord")); // assign coordinate switch (eCoord) { case LEFT: rect.left = coord; break; case RIGHT: rect.right = coord; break; case TOP: rect.top = coord; break; case BOTTOM: rect.bottom = coord; break; default: sc = E_INVALIDARG; break; } return sc; } /*+-------------------------------------------------------------------------* * * CAMCView::Scget_Left * * PURPOSE: Implements Frame.Left property's Get method for view * * PARAMETERS: * LPINT pCoord - storage for return value * * RETURNS: * SC * *+-------------------------------------------------------------------------*/ SC CAMCView::Scget_Left ( LPINT pCoord ) { DECLARE_SC(sc, TEXT("CAMCView::Scget_Left")); sc = ScGetFrameCoord( pCoord, LEFT ); if (sc) return sc; return sc; } /*+-------------------------------------------------------------------------* * * CAMCView::Scput_Left * * PURPOSE: Implements Frame.Left property's Put method for view * * PARAMETERS: * INT coord - value to set * * RETURNS: * SC * *+-------------------------------------------------------------------------*/ SC CAMCView::Scput_Left ( INT coord ) { DECLARE_SC(sc, TEXT("CAMCView::Scput_Left")); sc = ScSetFrameCoord( coord, LEFT ); if (sc) return sc; return sc; } /*+-------------------------------------------------------------------------* * * CAMCView::Scget_Right * * PURPOSE: Implements Frame.Right property's Get method for view * * PARAMETERS: * LPINT pCoord - storage for return value * * RETURNS: * SC * *+-------------------------------------------------------------------------*/ SC CAMCView::Scget_Right ( LPINT pCoord) { DECLARE_SC(sc, TEXT("CAMCView::Scget_Right")); sc = ScGetFrameCoord( pCoord, RIGHT ); if (sc) return sc; return sc; } /*+-------------------------------------------------------------------------* * * CAMCView::Scput_Right * * PURPOSE: Implements Frame.Right property's Put method for view * * PARAMETERS: * INT coord - value to set * * RETURNS: * SC * *+-------------------------------------------------------------------------*/ SC CAMCView::Scput_Right ( INT coord ) { DECLARE_SC(sc, TEXT("CAMCView::Scput_Right")); sc = ScSetFrameCoord( coord, RIGHT ); if (sc) return sc; return sc; } /*+-------------------------------------------------------------------------* * * CAMCView::Scget_Top * * PURPOSE: Implements Frame.Top property's Get method for view * * PARAMETERS: * LPINT pCoord - storage for return value * * RETURNS: * SC * *+-------------------------------------------------------------------------*/ SC CAMCView::Scget_Top ( LPINT pCoord) { DECLARE_SC(sc, TEXT("CAMCView::Scget_Top")); sc = ScGetFrameCoord( pCoord, TOP ); if (sc) return sc; return sc; } /*+-------------------------------------------------------------------------* * * CAMCView::Scput_Top * * PURPOSE: Implements Frame.Top property's Put method for view * * PARAMETERS: * INT coord - value to set * * RETURNS: * SC * *+-------------------------------------------------------------------------*/ SC CAMCView::Scput_Top ( INT coord ) { DECLARE_SC(sc, TEXT("CAMCView::Scput_Top")); sc = ScSetFrameCoord( coord, TOP ); if (sc) return sc; return sc; } /*+-------------------------------------------------------------------------* * * CAMCView::Scget_Bottom * * PURPOSE: Implements Frame.Bottom property's Get method for view * * PARAMETERS: * LPINT pCoord - storage for return value * * RETURNS: * SC * *+-------------------------------------------------------------------------*/ SC CAMCView::Scget_Bottom ( LPINT pCoord) { DECLARE_SC(sc, TEXT("CAMCView::Scget_Bottom")); sc = ScGetFrameCoord( pCoord, BOTTOM ); if (sc) return sc; return sc; } /*+-------------------------------------------------------------------------* * * CAMCView::Scput_Bottom * * PURPOSE: Implements Frame.Bottom property's Put method for view * * PARAMETERS: * INT coord - value to set * * RETURNS: * SC * *+-------------------------------------------------------------------------*/ SC CAMCView::Scput_Bottom ( INT coord ) { DECLARE_SC(sc, TEXT("CAMCView::Scput_Bottom")); sc = ScSetFrameCoord( coord, BOTTOM ); if (sc) return sc; return sc; } /*+-------------------------------------------------------------------------* * * CAMCView::ScSetViewExtensionFrame * * PURPOSE: * * PARAMETERS: * INT top : * INT left : * INT bottom : * INT right : * * RETURNS: * SC * *+-------------------------------------------------------------------------*/ SC CAMCView::ScSetViewExtensionFrame(bool bShowListView, INT top, INT left, INT bottom, INT right) { DECLARE_SC(sc, TEXT("CAMCView::ScSetViewExtensionFrame")) /* * this method is only available while a view extension is active */ if (!m_fViewExtended) return sc; // return silently. NOTE: This method will be removed shortly, as will the view extension hosted frame object, // once mmc moves the mmcview behavior into the web host's element factory. /* * figure out the maximum bounding rectangle for the hosted view, * mapped to view extension-relative coordinates */ CRect rectBound; CalcMaxHostedFrameRect (rectBound); #ifdef DBG CString strDebugMsg; strDebugMsg.Format (_T("CAMCView::ScSetViewExtFrameCoord bound=(l=%d,t=%d,r=%d,b=%d), new = (l=%d,t=%d,r=%d,b=%d)"), rectBound.left, rectBound.top, rectBound.right, rectBound.bottom, left, top, right, bottom ); #endif /* * make sure the requested coordinate is withing the permitted area */ if (left < rectBound.left) left = rectBound.left; if (right > rectBound.right) right = rectBound.right; if (top < rectBound.top) top = rectBound.top; if (bottom > rectBound.bottom) bottom = rectBound.bottom; /* * if we get here, the view extension-relative coordinate supplied * is within the acceptable range, now we need to convert it to * CAMCView-relative coordinates */ CPoint pointTopLeft(left, top); CPoint pointBottomRight(right, bottom); if ( GetExStyle() & WS_EX_LAYOUTRTL ) { // IE does not change left/right order on the RTL locales // thus we need to mirror it's coordinates // see windows bug #195094 ntbugs9 11/30/00 pointTopLeft.x = rectBound.left + (rectBound.right - right); pointBottomRight.x = rectBound.left + (rectBound.right - left); } MapHostedFramePtToViewPt (pointTopLeft); MapHostedFramePtToViewPt (pointBottomRight); /* * set the coordinates */ CRect rectViewExtHostedFrame; rectViewExtHostedFrame.left = pointTopLeft.x; rectViewExtHostedFrame.right = pointBottomRight.x; rectViewExtHostedFrame.top = pointTopLeft.y; rectViewExtHostedFrame.bottom = pointBottomRight.y; // move the window to the correct location CWnd* pwndResult = GetPaneView(ePane_Results); sc = ScCheckPointers(pwndResult); if(sc) return sc; if (bShowListView) pwndResult->ShowWindow(SW_SHOW); ::MoveWindow(*pwndResult, rectViewExtHostedFrame.left, rectViewExtHostedFrame.top, rectViewExtHostedFrame.right - rectViewExtHostedFrame.left, rectViewExtHostedFrame.bottom - rectViewExtHostedFrame.top, TRUE /*bRepaint*/); return (sc); } /*+-------------------------------------------------------------------------* * CAMCView::CalcMaxHostedFrameRect * * Returns the maximum rectangle that can be occupied by a view extension's * hosted frame, normalized around (0,0). *--------------------------------------------------------------------------*/ void CAMCView::CalcMaxHostedFrameRect (CRect& rect) { /* * start with the result frame rectangle and inset it a little so * we'll see the client edge provided by the view extension's web * host view */ rect = m_rectResultFrame; rect.DeflateRect (m_sizEdge); /* * now normalize around (0,0) */ rect.OffsetRect (-rect.TopLeft()); } /*+-------------------------------------------------------------------------* * CAMCView::MapViewPtToHostedFramePt * * *--------------------------------------------------------------------------*/ void CAMCView::MapViewPtToHostedFramePt (CPoint& pt) { PointMapperWorker (pt, true); } /*+-------------------------------------------------------------------------* * CAMCView::MapHostedFramePtToViewPt * * *--------------------------------------------------------------------------*/ void CAMCView::MapHostedFramePtToViewPt (CPoint& pt) { PointMapperWorker (pt, false); } /*+-------------------------------------------------------------------------* * CAMCView::MapHostedFramePtToViewPt * * *--------------------------------------------------------------------------*/ void CAMCView::PointMapperWorker (CPoint& pt, bool fViewToHostedFrame) { int nMultiplier = (fViewToHostedFrame) ? -1 : 1; /* * adjust to the origin of the result frame rectangle and for the * web host view's client edge */ pt.Offset (nMultiplier * (m_rectResultFrame.left + m_sizEdge.cx), nMultiplier * (m_rectResultFrame.top + m_sizEdge.cy)); } /***************************************************************************\ * * METHOD: CXMLWindowPlacement::Persist * * PURPOSE: Persists window placement settings * * PARAMETERS: * CPersistor &persistor * * RETURNS: * void * \***************************************************************************/ void CXMLWindowPlacement::Persist(CPersistor &persistor) { // create wrapper to persist flag values as strings CXMLBitFlags wpFlagsPersistor(m_rData.flags, mappedWPFlags, countof(mappedWPFlags)); // persist the wrapper persistor.PersistAttribute( XML_ATTR_WIN_PLACEMENT_FLAGS, wpFlagsPersistor ); // persist show command as literal // create wrapper to persist enumeration values as strings CXMLEnumeration showCmdPersistor(m_rData.showCmd, mappedSWCommands, countof(mappedSWCommands)); // persist the wrapper persistor.PersistAttribute( XML_ATTR_SHOW_COMMAND, showCmdPersistor ); persistor.Persist( XMLPoint( XML_NAME_MIN_POSITION, m_rData.ptMinPosition ) ); persistor.Persist( XMLPoint( XML_NAME_MAX_POSITION, m_rData.ptMaxPosition ) ); persistor.Persist( XMLRect( XML_NAME_NORMAL_POSITION, m_rData.rcNormalPosition ) ); } /***************************************************************************\ * * METHOD: CAMCView::Scget_Document * * PURPOSE: implements View.Document property in object model * * PARAMETERS: * PPDOCUMENT ppDocument [out] document to which the view belongs * * RETURNS: * SC - result code * \***************************************************************************/ SC CAMCView::Scget_Document( PPDOCUMENT ppDocument ) { DECLARE_SC(sc, TEXT("CAMCView::Scget_Document")); // parameter check sc = ScCheckPointers(ppDocument); if (sc) return sc; // get the document CAMCDoc* pDoc = GetDocument(); sc = ScCheckPointers(pDoc, E_UNEXPECTED); if (sc) return sc; // construct com object sc = pDoc->ScGetMMCDocument(ppDocument); if (sc) return sc; return (sc); } /*******************************************************\ | helper function to avoid too many stack allocations \*******************************************************/ static tstring W2T_ForLoop(const std::wstring& str) { #if defined(_UNICODE) return str; #else USES_CONVERSION; return W2CA(str.c_str()); #endif } /***************************************************************************\ * * METHOD: CAMCView::ScAddFolderTabs * * PURPOSE: Collects view extensions and taskpads and displays them as tabs * * PARAMETERS: * HNODE hNode - selected scope node * const CLSID &guidTabToSelect - tab to select * * RETURNS: * SC - result code * \***************************************************************************/ SC CAMCView::ScAddFolderTabs( HNODE hNode, const CLSID& guidTabToSelect ) { DECLARE_SC(sc, TEXT("CAMCView::ScAddFolderTabs")); sc = ScCheckPointers(m_pResultFolderTabView, E_UNEXPECTED); if (sc) return sc; // cleanup urls m_ViewExtensionURLs.clear(); // cleanup view tabs before we do anything else m_pResultFolderTabView->DeleteAllItems(); // get the callback INodeCallback* pNodeCallBack = GetNodeCallback(); sc = ScCheckPointers(pNodeCallBack, m_pResultFolderTabView, E_UNEXPECTED); if (sc) return sc; // collect view extensions CViewExtCollection vecExtensions; CViewExtInsertIterator itExtensions(vecExtensions, vecExtensions.begin()); sc = pNodeCallBack->GetNodeViewExtensions(hNode, itExtensions); if (sc) { sc.TraceAndClear(); vecExtensions.clear(); // continue anyway } // check if there is something to show if(vecExtensions.size() == 0) // no tabs to show. { m_pResultFolderTabView->SetVisible(false); } else { bool bAddDefaultTab = true; // add extensions CViewExtCollection::iterator iterVE; for(iterVE = vecExtensions.begin(); iterVE != vecExtensions.end(); ++iterVE) { tstring strName( W2T_ForLoop(iterVE->strName) ); m_pResultFolderTabView->AddItem(strName.c_str(), iterVE->viewID); m_ViewExtensionURLs[iterVE->viewID] = W2T_ForLoop(iterVE->strURL); // do not add the "normal" tab if we have a valid replacement for it if (iterVE->bReplacesDefaultView) bAddDefaultTab = false; } // add the default item. if (bAddDefaultTab) { CStr strNormal; strNormal.LoadString(GetStringModule(), IDS_NORMAL); m_pResultFolderTabView->AddItem(strNormal, GUID_NULL); } // select required item and show tabs int iIndex = m_pResultFolderTabView->SelectItemByClsid(guidTabToSelect); if (iIndex < 0) TraceError(_T("CAMCView::ScAddFolderTabs - failed to select requested folder"), SC(E_FAIL)); // no need for cotrol if we only have one tab bool bMoreThanOneTab = (m_pResultFolderTabView->GetItemCount() > 1); m_pResultFolderTabView->SetVisible(bMoreThanOneTab); } // lookup view extension URL CViewExtensionURLs::iterator itVE = m_ViewExtensionURLs.find(guidTabToSelect); LPCTSTR url = (itVE != m_ViewExtensionURLs.end()) ? itVE->second.c_str() : NULL; // apply URL sc = ScApplyViewExtension(url); if (sc) sc.TraceAndClear(); RecalcLayout(); return sc; } /***************************************************************************\ * * METHOD: CAMCView::Scget_ControlObject * * PURPOSE: returns IDispatch of embeded OCX control * implements View.ControlObject property * * PARAMETERS: * PPDISPATCH ppControl [out] control's interface * * RETURNS: * SC - result code * \***************************************************************************/ SC CAMCView::Scget_ControlObject( PPDISPATCH ppControl) { DECLARE_SC(sc, TEXT("CAMCView::Scget_ControlObject")); // parameter check sc = ScCheckPointers(ppControl); if (sc) return sc; // init out param *ppControl = NULL; // have a OCX view? if ( (! HasOCX()) || (m_pOCXHostView == NULL)) return sc.FromMMC( MMC_E_NO_OCX_IN_VIEW ); // get the control's interface CComQIPtr spDispatch = m_pOCXHostView->GetIUnknown(); if (spDispatch == NULL) return sc = E_NOINTERFACE; // return the pointer *ppControl = spDispatch.Detach(); return sc; } //+------------------------------------------------------------------- // // Member: CAMCView::ScTreeViewSelectionActivate // // Synopsis: Only the list(/Web/OCX) or the tree can be "active" from the point // of view of selected items and MMCN_SELECT. This is not // the same as the MFC concept of "active view". There are a couple // of views that cannot be active in this sense, such as the taskpad // and tab views. // When the active view (according to this definition) changes, this // function is called. Thus, ScTreeViewSelectionActivate and // ScListViewSelectionActivate/ScSpecialResultpaneSelectionActivate // are always called in pairs when the activation changes, one to handle // deactivation, and one to handle activation. // // Consider the following scenario // 1) The tree view has (MFC/windows style) focus. // 2) The user clicks on the taskpad view // Result - selection activation does not change from the tree. All verbs // still correspond to the selected tree item. // 3) The user clicks on the folder view // Result - once again, selection activation does not chang // 4) The user clicks on one of the result views eg the list // Result - ScTreeViewSelectionActivate(false) and ScListViewSelectionActivate(true) // Thus verbs and the toolbar now correspond to the selected list item(s). // 5) The user clicks on the taskpad view. // Result - as in step 2, nothing happens // 6) The user clicks on the result view // Result - because the active view has not changed, nothing happens. // // Arguments: [bActivate] - [in] // // Returns: SC // //-------------------------------------------------------------------- SC CAMCView::ScTreeViewSelectionActivate (bool bActivate) { DECLARE_SC(sc, _T("CAMCView::ScTreeViewSelectionActivate")); sc = ScCheckPointers(m_pTreeCtrl, E_UNEXPECTED); if (sc) return sc; // 1. Setup the SELECTINFO SELECTIONINFO selInfo; ZeroMemory(&selInfo, sizeof(selInfo)); selInfo.m_bScope = TRUE; selInfo.m_pView = NULL; selInfo.m_bDueToFocusChange = TRUE; if (HasOCX()) { selInfo.m_bResultPaneIsOCX = true; selInfo.m_lCookie = LVDATA_CUSTOMOCX; } else if (HasWebBrowser()) { selInfo.m_bResultPaneIsWeb = TRUE; selInfo.m_lCookie = LVDATA_CUSTOMWEB; } HTREEITEM htiSelected = m_pTreeCtrl->GetSelectedItem(); HNODE hSelectedNode = (htiSelected != NULL) ? m_pTreeCtrl->GetItemNode (htiSelected) : NULL; // insure that this is the active view when we have the focus ASSERT ( ( (bActivate) && (GetParentFrame()->GetActiveView () == m_pTreeCtrl) ) || ( (!bActivate) && (GetParentFrame()->GetActiveView () != m_pTreeCtrl) ) ); if (hSelectedNode != NULL) { // Send select notification. sc = ScNotifySelect ( GetNodeCallback(), hSelectedNode, false /*fMultiSelect*/, bActivate, &selInfo); if (sc) return sc; } else if ( (htiSelected == NULL) && (bActivate) ) { m_pTreeCtrl->SelectItem (m_pTreeCtrl->GetRootItem()); } return (sc); } //+------------------------------------------------------------------- // // Member: CAMCView::ScOnTreeViewActivated // // Synopsis: Observer implementation for tree-view activation. // // Arguments: // // Returns: SC // //-------------------------------------------------------------------- SC CAMCView::ScOnTreeViewActivated () { DECLARE_SC(sc, _T("CAMCView::ScOnTreeViewActivated")); if (m_eCurrentActivePane == eActivePaneScope) // Scope pane is already active so return. return sc; #ifdef DBG Trace (tagViewActivation, _T("Deactivate %s in result pane Activate Scope pane\n"), HasListOrListPad() ? _T("ListView") : (HasOCX() ? _T("OCX") : _T("WebBrowser"))); #endif if (m_eCurrentActivePane == eActivePaneResult) { // Send deactivate to result. if (HasListOrListPad()) sc = ScListViewSelectionActivate (false); else if (HasOCX() || HasWebBrowser()) sc = ScSpecialResultpaneSelectionActivate(false); else return (sc = E_UNEXPECTED); if (sc) sc.TraceAndClear(); } // Send select to scope. m_eCurrentActivePane = eActivePaneScope; sc = ScTreeViewSelectionActivate(true); if (sc) return sc; return (sc); } //+------------------------------------------------------------------- // // Member: CAMCView::ScOnListViewActivated // // Synopsis: Observer implementation for list-view activation. // // Arguments: // // Returns: SC // //-------------------------------------------------------------------- SC CAMCView::ScOnListViewActivated () { DECLARE_SC(sc, _T("CAMCView::ScOnListViewActivated")); if (m_eCurrentActivePane == eActivePaneResult) // Result pane is already active so return. return sc; #ifdef DBG Trace (tagViewActivation, _T("Deactivate Scope pane Activate ListView in Result pane\n")); #endif if (m_eCurrentActivePane == eActivePaneScope) { // Send deactivate to scope. sc = ScTreeViewSelectionActivate(false); if (sc) sc.TraceAndClear(); } // Send activate to list. m_eCurrentActivePane = eActivePaneResult; ASSERT(HasListOrListPad()); sc = ScListViewSelectionActivate (true); if (sc) sc.TraceAndClear(); return (sc); } /*+-------------------------------------------------------------------------* * * CAMCView::ScOnListViewItemUpdated * * PURPOSE: called when an item is updated. This method fires an event to all COM observers. * * PARAMETERS: * int nIndex : * * RETURNS: * SC * *+-------------------------------------------------------------------------*/ SC CAMCView::ScOnListViewItemUpdated (int nIndex) { DECLARE_SC(sc, _T("CAMCView::ScOnListViewItemUpdated")); // fire event sc = ScFireEvent(CAMCViewObserver::ScOnListViewItemUpdated, this, nIndex); if (sc) return sc; return sc; } //+------------------------------------------------------------------- // // Member: CAMCView::ScOnOCXHostActivated // // Synopsis: Observer implementation for ocx or web view activation. // // Arguments: // // Returns: SC // //-------------------------------------------------------------------- SC CAMCView::ScOnOCXHostActivated () { DECLARE_SC(sc, _T("CAMCView::ScOnOCXHostActivated")); if (m_eCurrentActivePane == eActivePaneResult) // Result pane is already active so return. return sc; #ifdef DBG Trace (tagViewActivation, _T("Deactivate Scope pane Activate %s in Result pane\n"), HasOCX() ? _T("OCX") : _T("WebBrowser")); #endif if (m_eCurrentActivePane == eActivePaneScope) { // Send deactivate to scope. sc = ScTreeViewSelectionActivate(false); if (sc) sc.TraceAndClear(); } // Send select to ocx or web view. m_eCurrentActivePane = eActivePaneResult; ASSERT(HasOCX() || HasWebBrowser()); sc = ScSpecialResultpaneSelectionActivate(true); if (sc) sc.TraceAndClear(); return (sc); }