//+--------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1997. // // File: C H K L I S T . C P P // // Contents: Implements bindings checkbox related utility functions // and classes. // // Notes: // // Created: tongl 20 Nov 1997 // //---------------------------------------------------------------------------- #include "pch.h" #pragma hdrstop #include "ncnetcfg.h" #include "ncui.h" #include "ncstl.h" #include "lanuiobj.h" #include "lanui.h" #include "util.h" #include "chklist.h" #include "ncperms.h" //+--------------------------------------------------------------------------- // // Member: HrRebuildBindingPathObjCollection // // Purpose: Build or rebuild a list of BindingPathObjects, // establish the links between sub-paths and super-paths, // as well as between ComponentObjects in the list view // and elements of the BindingPathObject collection // // Arguments: // [IN] pnccAdapter // [IN] hList // [INOUT] pListObj // // Returns: TRUE // // Author: tongl 20 Nov 1997 // // Notes: // HRESULT HrRebuildBindingPathObjCollection(INetCfgComponent * pnccAdapter, ListBPObj * pListBPObj) { HRESULT hr = S_OK; // now, add new BindingPathObjects to our list CIterNetCfgUpperBindingPath ncbpIter(pnccAdapter); INetCfgBindingPath * pncbp; TraceTag(ttidLanUi, "*** List of binding paths: begin ***"); // Go through all upper binding paths starting from the current LAN // adapter, and add to our list of BindingPathObjects: while(SUCCEEDED(hr) && (hr = ncbpIter.HrNext(&pncbp)) == S_OK) { PrintBindingPath(ttidLanUi, pncbp, NULL); // create a new BindingPathObj CBindingPathObj * pBPObj = new CBindingPathObj(pncbp); // insert to our list, sorted by the length of the path // and establish super/sub path lists with existing items in // the list hr = HrInsertBindingPathObj(pListBPObj, pBPObj); ReleaseObj(pncbp); } TraceTag(ttidLanUi, "*** List of binding paths: end ***"); #if DBG TraceTag(ttidLanUi, "%%% Begin dump the subpath list %%%"); for (ListBPObj_ITER iter = pListBPObj->begin(); iter != pListBPObj->end(); iter++) { (*iter)->DumpSubPathList(); } TraceTag(ttidLanUi, "%%% End dump the subpath list %%%"); #endif if (hr == S_FALSE) // We just got to the end of the loop hr = S_OK; TraceError("HrRebuildBindingPathObjCollection", hr); return hr; } //+--------------------------------------------------------------------------- // // Member: HrInsertBindingPathObj // // Purpose: Insert a BindingPathObj to a list of BindingPathObj's, // keep the list sorted by the length of paths. // Also establishs super/sub path lists with existing items // in the list. // // Arguments: // [INOUT] pListBPObj // [IN] pBPObj // // Returns: S_OK if succeeded, // otherwise return a failure code // // Author: tongl 20 Nov 1997 // // Notes: // HRESULT HrInsertBindingPathObj(ListBPObj * pListBPObj, CBindingPathObj * pBPObj) { HRESULT hr = S_OK; HRESULT hrTmp = S_OK; ListBPObj_ITER iter; // insert the new element for (iter = pListBPObj->begin();iter != pListBPObj->end(); iter++) { if ((*iter)->GetDepth() > pBPObj->GetDepth()) break; } // insert at the current position ListBPObj_ITER iterNewItem = pListBPObj->insert(iter, pBPObj); // set subpaths and superpaths // Because of the change in the new binding engine for paths for DONT_EXPOSE_LOWER // components, we have to compare with every item in the list because the length // no longer garantees which one is the subpath.. for (iter = pListBPObj->begin(); iter != pListBPObj->end(); iter++) { // Is this a sub-path ? hrTmp = ((*iter)->m_pncbp)->IsSubPathOf((*iterNewItem)->m_pncbp); if (S_OK == hrTmp) { hrTmp = (*iter)->HrInsertSuperPath(*iterNewItem); if SUCCEEDED(hr) hr = hrTmp; hrTmp = (*iterNewItem)->HrInsertSubPath(*iter); if SUCCEEDED(hr) hr = hrTmp; } // Is this a super-path ? hrTmp = ((*iterNewItem)->m_pncbp)->IsSubPathOf((*iter)->m_pncbp); if (S_OK == hrTmp) { hrTmp = (*iter)->HrInsertSubPath(*iterNewItem); if SUCCEEDED(hr) hr = hrTmp; hrTmp = (*iterNewItem)->HrInsertSuperPath(*iter); if SUCCEEDED(hr) hr = hrTmp; } } TraceError("HrInsertBindingPathObj", hr); return hr; } //+--------------------------------------------------------------------------- // // Member: HrRefreshBindingPathObjCollectionState // // Purpose: Refresh the binding state of all items in the collection // of BindingPathObjects // // Arguments: // [INOUT] pListBPObj // // Returns: S_OK if succeeded, // otherwise return a failure code // // Author: tongl 20 Nov 1997 // // Notes: // HRESULT HrRefreshBindingPathObjCollectionState(ListBPObj * plistBPObj) { HRESULT hr = S_OK; ListBPObj_ITER iter; // first, clearup any existing state for (iter = plistBPObj->begin();iter != plistBPObj->end(); iter++) { (*iter)->SetBindingState(BPOBJ_UNSET); } // now set the new states TraceTag(ttidLanUi, "*** List of binding paths: begin ***"); for (iter = plistBPObj->begin();iter != plistBPObj->end(); iter++) { Assert((*iter)->GetBindingState() != BPOBJ_ENABLED); #if DBG PrintBindingPath (ttidLanUi, (*iter)->m_pncbp, NULL); #endif if (BPOBJ_UNSET != (*iter)->GetBindingState()) { continue; } // if it's not disabled yet, i.e. all of its sub paths // are enabled. hr = ((*iter)->m_pncbp)->IsEnabled(); if (S_OK == hr) // enabled { (*iter)->SetBindingState(BPOBJ_ENABLED); continue; } else if (S_FALSE == hr) // disabled { // normal disabled case (*iter)->SetBindingState(BPOBJ_DISABLED); // special cases: // if the check state of the corresponding component is intent_check or mixed or checked if ((*iter)->m_pCompObj != NULL) { // if user is not intentionally unchecking this component if ((*iter)->m_pCompObj->m_ExpCheckState != UNCHECKED) { // if the component should be checked or if it's hidden if ((((*iter)->m_pCompObj)->m_CheckState == INTENT_CHECKED) || (((*iter)->m_pCompObj)->m_CheckState == MIXED) || (((*iter)->m_pCompObj)->m_CheckState == CHECKED)) { // (#297772) We should only do this if one of the subpaths has just // been re-enabled by user BOOL fSubPathEnabled = FALSE; ListBPObj_ITER iterSub; for (iterSub = (*iter)->m_listSubPaths.begin(); iterSub != (*iter)->m_listSubPaths.end(); iterSub++) { // is the top component just enabled ? INetCfgComponent * pncc; hr = (*iterSub)->m_pncbp->GetOwner(&pncc); if (SUCCEEDED(hr)) { if (((*iterSub)->m_pCompObj != NULL) && (CHECKED == (*iterSub)->m_pCompObj->m_ExpCheckState)) { fSubPathEnabled = TRUE; } ReleaseObj(pncc); if (fSubPathEnabled) break; } } if (fSubPathEnabled) { // Special case: enable the following binding path because // 1) it's check state is intent or mixed, and // 2) one of it's sub-paths is newly enabled #if DBG TraceTag(ttidLanUi, "Special case, enable the following path:"); PrintBindingPath(ttidLanUi, (*iter)->m_pncbp, "\n"); #endif hr = HrEnableBindingPath((*iter)->m_pncbp, TRUE); if (S_OK == hr) { (*iter)->SetBindingState(BPOBJ_ENABLED); continue; } } } } } } } TraceTag(ttidLanUi, "*** List of binding paths: end ***"); TraceError("HrRefreshBindingPathObjCollectionState", hr); return hr; } //+--------------------------------------------------------------------------- // // Member: HrRefreshCheckListState // // Purpose: Refresh the check state of all components in the list view // // Arguments: // hwndList[in]: Handle of the list view // pChangedCompObj[in]: Component object which state has // changed and has induced this refresh call. // This is used to keep a corresponding "undo" flag // for the changed component in case other components // are dependend on this component and the user decides // not to go through with the change. // Set to NULL if not applicable. // // Returns: S_OK if succeeded, // otherwise return a failure code // // Author: tongl 20 Nov 1997 // // Notes: // HRESULT HrRefreshCheckListState(HWND hListView, CComponentObj *pChangedCompObj) { HRESULT hr = S_OK; TraceTag(ttidLanUi, "<<<<(lvItem.lParam); if (pnid) { // get the component object associated with this item CComponentObj * pCompObj = pnid->pCompObj; // assume the current component is not dependend on the // supplied changed component BOOL fDependedOnChangedComponent = FALSE; // get counts for enabled & disabled paths int iEnabled = 0; int iDisabled =0; // for each ComponentObject on the list ListBPObj_ITER iter; for (iter = (pCompObj->m_listBPObj).begin(); iter != (pCompObj->m_listBPObj).end(); iter++) { // the state should not be unset Assert((*iter)->m_BindingState != BPOBJ_UNSET); // if enabled switch ((*iter)->m_BindingState) { case BPOBJ_ENABLED: PrintBindingPath(ttidLanUi, (*iter)->m_pncbp, "is enabled"); iEnabled++; break; case BPOBJ_DISABLED: PrintBindingPath(ttidLanUi, (*iter)->m_pncbp, "is disabled"); // $REVIEW(tongl 1/19/98): According to SteveFal, // for paths with length>1, we only count "disabled" if // the sub paths are all enabled but the main path is disabled. // Bug #304606, can't use length any more with IPX special case { // Is all the subpaths enabled ? BOOL fAllSubPathsEnabled = TRUE; ListBPObj_ITER iterSubPath; for (iterSubPath = ((*iter)->m_listSubPaths).begin(); iterSubPath != ((*iter)->m_listSubPaths).end(); iterSubPath++) { if ((*iterSubPath)->m_BindingState == BPOBJ_DISABLED) { fAllSubPathsEnabled = FALSE; // Is the changed component part of this // component's sub paths? if (pChangedCompObj) { ListBPObj_ITER changedIter; for (changedIter = (pChangedCompObj->m_listBPObj).begin(); changedIter != (pChangedCompObj->m_listBPObj).end(); changedIter++) { // Don't need to compare sub path to itself if (pCompObj != pChangedCompObj) { hr = (*changedIter)->m_pncbp->IsSubPathOf((*iterSubPath)->m_pncbp); if (S_OK == hr) { fDependedOnChangedComponent = TRUE; break; } } } } break; } } if (fAllSubPathsEnabled) { // Is the binding path itself enabled ? hr = ((*iter)->m_pncbp)->IsEnabled(); if (S_FALSE == hr) { iDisabled++; hr = S_OK; } } } break; default: PrintBindingPath(ttidLanUi, (*iter)->m_pncbp, "*** has an invalid binding state ***"); break; } } UINT iChkIndex = 0; BOOL fHasPermission = FHasPermission(NCPERM_ChangeBindState); if (pnid->dwFlags & NCF_FIXED_BINDING) { // Don't change the checked state, we just want to prevent // the user from changing it. iChkIndex = SELS_FIXEDBINDING_ENABLED; } else if ((iEnabled >0) && (iDisabled == 0)) { if (!fHasPermission) { iChkIndex = SELS_FIXEDBINDING_ENABLED; } else { // if we enabled the changed component, // it should not have any dependable // components anymore to "undo" if (pCompObj == pChangedCompObj) { pCompObj->m_DepStateChanged = FALSE; } // current state is "checked" pCompObj->m_CheckState = CHECKED; iChkIndex = SELS_CHECKED; } } else if ((iEnabled >0) && (iDisabled > 0)) { if (!fHasPermission) { iChkIndex = SELS_FIXEDBINDING_ENABLED; } else { // current state is "mixed" pCompObj->m_CheckState = MIXED; iChkIndex = SELS_INTERMEDIATE; } } else //iEnabled ==0 { if (!fHasPermission) { iChkIndex = SELS_FIXEDBINDING_DISABLED; } else { if (pCompObj->m_ExpCheckState == CHECKED) { // mark the component who caused this state // in order to be able to "undo" it later if ((pChangedCompObj) && (fDependedOnChangedComponent)) { pChangedCompObj->m_DepStateChanged = TRUE; } // change current state to "intent checked" pCompObj->m_CheckState = INTENT_CHECKED; // $REVIEW(tongl 1/19/98): SteveFal wants to show the // intent state as checked in the display // iChkIndex = SELS_INTENTCHECKED; iChkIndex = SELS_CHECKED; } else if (pCompObj->m_ExpCheckState == UNSET) { // we are not changing this component if ((pCompObj->m_CheckState == CHECKED) || (pCompObj->m_CheckState == MIXED) || (pCompObj->m_CheckState == INTENT_CHECKED)) { // mark the component who caused this state // in order to be able to "undo" it later if ((pChangedCompObj) && (fDependedOnChangedComponent)) { pChangedCompObj->m_DepStateChanged = TRUE; } // set current state to "intent checked" pCompObj->m_CheckState = INTENT_CHECKED; // $REVIEW(tongl 1/19/98): SteveFal wants to show the // intent state as checked in the display // iChkIndex = SELS_INTENTCHECKED; iChkIndex = SELS_CHECKED; } else { // set current state to "unchecked" pCompObj->m_CheckState = UNCHECKED; iChkIndex = SELS_UNCHECKED; } } else { // current state is "unchecked" pCompObj->m_CheckState = UNCHECKED; iChkIndex = SELS_UNCHECKED; } } } // clear up expected check state pCompObj->m_ExpCheckState = UNSET; // update the checkmark AssertSz(iChkIndex, "What's the new check state ??"); lvItem.mask = LVIF_STATE; lvItem.stateMask = LVIS_STATEIMAGEMASK; lvItem.state = INDEXTOSTATEIMAGEMASK(iChkIndex); BOOL ret = ListView_SetItem(hListView, &lvItem); } } } TraceError("HrRefreshCheckListState", hr); TraceTag(ttidLanUi, ">>>>>Leaving HrRefreshCheckListState"); return hr; } //+--------------------------------------------------------------------------- // // Member: HrEnableBindingPath // // Purpose: Wraps the INetCfgBindingPath->Enable method with the following // flags: if enabling, it applies to all hidden super paths, if // disabling, it applies to all super paths. // // // Arguments: // [IN] pncbp : the binding path to enable or disable // [IN] fEnable : Enable = TRUE; disable = FALSE // // Returns: S_OK if succeeded, // otherwise return a failure code // // Author: tongl 5 Dec 1997 // // Notes: // HRESULT HrEnableBindingPath(INetCfgBindingPath * pncbpThis, BOOL fEnable) { HRESULT hr; hr = pncbpThis->Enable(fEnable); return hr; } //+--------------------------------------------------------------------------- // // Member: CBindingPathObj implementation // // Author: tongl 20 Nov 1997 // // Notes: // CBindingPathObj::CBindingPathObj(INetCfgBindingPath * pncbp) { Assert(pncbp); m_pncbp = pncbp; m_pncbp->AddRef(); // Initialize other members m_pCompObj = NULL; m_BindingState = BPOBJ_UNSET; HRESULT hr = pncbp->GetDepth(&m_ulPathLen); TraceError("CBindingPathObj::CBindingPathObj failed on GetDepth", hr); } CBindingPathObj::~CBindingPathObj() { ReleaseObj(m_pncbp); m_listSubPaths.erase (m_listSubPaths.begin(), m_listSubPaths.end()); m_listSuperPaths.erase (m_listSuperPaths.begin(), m_listSuperPaths.end()); } HRESULT CBindingPathObj::HrInsertSuperPath(CBindingPathObj * pbpobjSuperPath) { HRESULT hr = S_OK; ListBPObj_ITER iter; // insert the new super path into the list, in increasing order of length for (iter = m_listSuperPaths.begin(); iter != m_listSuperPaths.end(); iter++) { if ((*iter)->GetDepth() > pbpobjSuperPath->GetDepth()) break; } // insert at the current position ListBPObj_ITER iterNewItem = m_listSuperPaths.insert(iter, pbpobjSuperPath); TraceError("CBindingPathObj::HrInsertSuperPath", hr); return hr; } HRESULT CBindingPathObj::HrInsertSubPath(CBindingPathObj * pbpobjSubPath) { HRESULT hr = S_OK; ListBPObj_ITER iter; // insert the new sub path into the list, in decreasing order of length for (iter = m_listSubPaths.begin(); iter != m_listSubPaths.end(); iter++) { if ((*iter)->GetDepth() < pbpobjSubPath->GetDepth()) break; } // insert at the current position ListBPObj_ITER iterNewItem = m_listSubPaths.insert(iter, pbpobjSubPath); TraceError("CBindingPathObj::HrInsertSubPath", hr); return hr; } HRESULT CBindingPathObj::HrEnable(ListBPObj * plistBPObj) { HRESULT hr = S_OK; #if DBG if (m_BindingState == BPOBJ_ENABLED) { TraceTag(ttidError, "Why trying to enable a path that is already enabled ?"); } #endif AssertSz(m_ulPathLen > 1, "binding path length must be > 1"); if (m_ulPathLen == 2) { // enable the current path hr = HrEnableBindingPath(m_pncbp, TRUE); } else { if (m_listSubPaths.size() <= 0) { PrintBindingPath(ttidLanUi, m_pncbp, "m_ulPathLen > 1, but no subpaths"); AssertSz(FALSE, "if pathLen>1, there must be subpaths"); } else { // check if the sub-path object is enabled, if not then we can't // enable this path .. if (m_listSubPaths.back()->m_BindingState == BPOBJ_ENABLED) { hr = HrEnableBindingPath(m_pncbp, TRUE); } } } // now refresh the BindingPathObjectList ::HrRefreshBindingPathObjCollectionState(plistBPObj); TraceError("CBindingPathObj::HrEnable", hr); return hr; } HRESULT CBindingPathObj::HrDisable(ListBPObj * plistBPObj) { HRESULT hr = S_OK; // Disable the current path hr = ::HrEnableBindingPath(m_pncbp, FALSE); if (S_OK == hr) { hr = ::HrRefreshBindingPathObjCollectionState(plistBPObj); } TraceError("CBindingPathObj::HrDisable", hr); return hr; } #if DBG VOID CBindingPathObj::DumpSubPathList() { TraceTag(ttidLanUi, " +++ Path: +++"); PrintBindingPath(ttidLanUi, m_pncbp, NULL); if (m_listSubPaths.size()) { TraceTag(ttidLanUi, "=== Subpaths: ==="); for (ListBPObj_ITER iter = m_listSubPaths.begin(); iter != m_listSubPaths.end(); iter++) { (*iter)->DumpPath(); } } } VOID CBindingPathObj::DumpPath() { PrintBindingPath(ttidLanUi, m_pncbp, NULL); } #endif //+--------------------------------------------------------------------------- // // Member: CComponentObj implementation // // Author: tongl 20 Nov 1997 // // Notes: // CComponentObj::CComponentObj(INetCfgComponent * pncc) { Assert(pncc); m_pncc = pncc; m_pncc->AddRef(); // Initialize other members m_CheckState = UNSET; m_ExpCheckState = UNSET; m_DepStateChanged = FALSE; } CComponentObj::~CComponentObj() { ReleaseObj(m_pncc); m_listBPObj.erase (m_listBPObj.begin(), m_listBPObj.end()); } HRESULT CComponentObj::HrInit(ListBPObj * plistBindingPaths) { PWSTR pszwThisId; HRESULT hr = m_pncc->GetId(&pszwThisId); if (SUCCEEDED(hr)) { // builds the connection between a component object and a list of // binding path objects ListBPObj_ITER iter; for (iter = plistBindingPaths->begin(); iter != plistBindingPaths->end(); iter ++) { INetCfgComponent * pncc; hr = (*iter)->m_pncbp->GetOwner(&pncc); if SUCCEEDED(hr) { // check if the top component of the binding path is the // same component by comparing INF id PWSTR pszwId; hr = pncc->GetId (&pszwId); if (SUCCEEDED(hr)) { if (FEqualComponentId (pszwId, pszwThisId)) { // Add the BindingPathObj to the end of m_listBPObj m_listBPObj.push_back((*iter)); // Make m_pCompObj of the BindingPathObj point to this ComponentObj Assert(NULL == (*iter)->m_pCompObj); (*iter)->m_pCompObj = this; } CoTaskMemFree(pszwId); } ReleaseObj(pncc); } } CoTaskMemFree(pszwThisId); } TraceError ("CComponentObj::HrInit", hr); return hr; } HRESULT CComponentObj::HrCheck(ListBPObj * plistBPObj) { HRESULT hr = S_OK; HRESULT hrTmp = S_OK; Assert(m_CheckState == UNCHECKED); // remember that user wanted to check (enable) this component m_ExpCheckState = CHECKED; ListBPObj_ITER iter; for (iter = m_listBPObj.begin();iter != m_listBPObj.end(); iter++) { // enable each binding path with enabled subpath hrTmp = (*iter)->HrEnable(plistBPObj); if SUCCEEDED(hr) hr = hrTmp; } TraceError("CComponentObj::HrCheck", hr); return hr; } HRESULT CComponentObj::HrUncheck(ListBPObj * plistBPObj) { HRESULT hr = S_OK; HRESULT hrTmp = S_OK; Assert(m_CheckState != UNCHECKED); // remember that user wanted to uncheck (disable) this component m_ExpCheckState = UNCHECKED; if (INTENT_CHECKED == m_CheckState) { m_CheckState = UNCHECKED; } else { ListBPObj_ITER iter; for (iter = m_listBPObj.begin();iter != m_listBPObj.end(); iter++) { // disable each binding path with enabled subpath hrTmp = (*iter)->HrDisable(plistBPObj); if SUCCEEDED(hr) hr = hrTmp; } } TraceError("CComponentObj::HrUnCheck", hr); return hr; }