/***************************************************************************** Collapses all levels of a branch -- not just 1 level. Using this in conjunction with TreeDataExpandOneLevel will get a tree grid that performs like VC++ watch window. Windows explorer tree differs: it "remembers" last expansion. Note that it doesn't check whether adjacent nodes are properply represented, it just does the collapse. *****************************************************************************/ void CTreeColumn::TreeDataCollapseAllSubLevels( int aiGridRow) { ASSERT( m_iColumnWithTree >= 0); ASSERT( m_pGrid != NULL); ASSERT( aiGridRow >= m_iFixedRowCount && aiGridRow < m_iRowCount); // display desired node and save its level and make visible CGridTreeCell* pGridTreeCell = (CGridTreeCell*)m_pGrid->GetCell( aiGridRow, m_iColumnWithTree); if( pGridTreeCell == NULL) return; unsigned char ucLevelCurrent = pGridTreeCell->GetLevel(); if( ucLevelCurrent <= 0) return; // don't expand or collapse items not part of the tree pGridTreeCell->SetViewable( TRUE); unsigned char ucLevel; int i1; for( i1 = aiGridRow + 1; i1 < m_iRowCount; i1++) { CGridTreeCell* pGridTreeCell = (CGridTreeCell*)m_pGrid->GetCell( i1, m_iColumnWithTree); if( pGridTreeCell == NULL) return; ucLevel = pGridTreeCell->GetLevel(); if( ucLevel <= ucLevelCurrent) break; pGridTreeCell->SetViewable( FALSE); } }
CString CVariablesGrid::GetFullName( int row ) { // Get the full name. CString fullName = GetItemText( row, 0 ); CGridTreeCell* treeCell = (CGridTreeCell*)GetCell( row, 0 ); int curLevel = treeCell->GetLevel(); if (curLevel > 1) { for (int i = row - 1; i >= 1; --i) { if (curLevel <= 1) break; CGridTreeCell* treeCell = (CGridTreeCell*)GetCell(i, 0); int level = treeCell->GetLevel(); if (level == curLevel - 1) { // Found a new part to tack on. fullName = GetItemText(i, 0) + "." + fullName; curLevel--; } } } return fullName; }
/***************************************************************************** Toggles tree expansion and collapsing. Intended to be connected to a user event *****************************************************************************/ void CTreeColumn::TreeExpandCollapseToggle( int aiGridRow) // Grid row of node to toggle { ASSERT( m_pGrid != NULL); m_pGrid->m_bLMouseButtonDown = FALSE; ASSERT( aiGridRow >= m_iFixedRowCount && aiGridRow < m_iRowCount); ASSERT( m_bAllowDraw); ASSERT( m_iColumnWithTree >= 0); if( m_iColumnWithTree < 0) return; // if last element, forget it if( aiGridRow + 1 >= m_iRowCount) return; // see if it needs to be expanded by looking at hide/show state of first neighbor. // If first neighbor is hidden, should expand CGridTreeCell* pGridTreeCell = (CGridTreeCell*)m_pGrid->GetCell( aiGridRow + 1, m_iColumnWithTree); if( pGridTreeCell == NULL) return; if( pGridTreeCell->IsViewable() ) { TreeDataCollapseAllSubLevels( aiGridRow); TreeRefreshRows(); } else { TreeDataExpandOneLevel( aiGridRow); TreeRefreshRows(); // Make sure bottom expanded row is visible (or as many of the expanded rows as possible) CGridTreeCell* pGridTreeCell = (CGridTreeCell*)m_pGrid->GetCell(aiGridRow, m_iColumnWithTree); if( pGridTreeCell == NULL) return; UCHAR lev = pGridTreeCell->GetLevel(); int ii; for (ii = aiGridRow + 1; ii < m_iRowCount; ii++) { pGridTreeCell = (CGridTreeCell*)m_pGrid->GetCell(ii, m_iColumnWithTree); if (pGridTreeCell == NULL || pGridTreeCell->GetLevel() <= lev) break; } m_pGrid->EnsureVisible(ii-1, m_iColumnWithTree); m_pGrid->EnsureVisible(aiGridRow, m_iColumnWithTree); } }
int CVariablesGrid::FindWatchActualIndex( int row ) { CString name = GetItemText( row, 0 ); int actualIndex = -1; int lastCheckRow = row; if (!name.IsEmpty() && row == GetRowCount() - 1) { actualIndex++; lastCheckRow--; } // Determine the true index. for (int i = 1; i <= lastCheckRow; ++i) { CGridTreeCell* treeCell = (CGridTreeCell*)GetCell(i, 0); if (treeCell->IsKindOf(RUNTIME_CLASS(CGridTreeCell))) { int level = treeCell->GetLevel(); if (level == 1) actualIndex++; } else actualIndex++; } return actualIndex; }
void CVariablesGrid::SaveExpandInfo(bool extraRow) { m_expandInfo.RemoveAll(); // Get the full name. CString fullName; int numRows = GetRowCount(); if (extraRow) numRows--; for (int i = 1; i < numRows; ++i) { CGridTreeCell* treeCell = (CGridTreeCell*)GetCell(i, 0); int level = treeCell->GetLevel(); if (level == 1) { fullName = GetItemText(i, 0); } else { fullName += "." + GetItemText(i, 0); } if (treeCell->IsViewable()) { ExpandInfo info; info.m_fullName = fullName; m_expandInfo.Add(info); } } }
void CVariablesGrid::FixupRows(bool readOnly) { // Nothing here... // if (m_titleList.GetSize() == 0) // return; int numRows = GetRowCount(); if (readOnly && numRows == 1) return; GV_ITEM Item; m_treeColumn.TreeSetup( this, NAME_COL, readOnly ? numRows - 1 : numRows, 1, m_treeLevelArray.GetData(), TRUE, FALSE); m_treeColumn.SetTreeLineColor( RGB( 0, 0, 0xFF) ); // m_treeColumn.SetDefTreeIndent( 8 ); // m_treeColumn.TreeDisplayOutline(100); int curWatchIndex = -1; for (int i = 1; i < numRows; i++) { CGridTreeCell* treeCell = (CGridTreeCell*)GetCell(i, 0); treeCell->SetForcePlus( m_treeForcePlusArray[ i - 1 ] ); int curLevel = treeCell->GetLevel(); if (curLevel == 1) { curWatchIndex++; } Item.mask = GVIF_TEXT|GVIF_FORMAT|GVIF_FONT|GVIF_PARAM; Item.row = i; Item.col = NAME_COL; Item.mask = GVIF_TEXT|GVIF_FORMAT|GVIF_STATE; Item.nFormat = DT_LEFT|DT_VCENTER|DT_SINGLELINE|DT_END_ELLIPSIS; Item.nState = (readOnly || curLevel > 1) ? GVIS_READONLY : 0; m_titleFont.GetLogFont(&Item.lfFont); Item.lParam = curWatchIndex; SetItem(&Item); } for (int i = 1; i <= m_titleList.GetSize(); ++i) { // SetFont(&m_titleFont); SetItemText(i, NAME_COL, m_titleList[i - 1]); } // for (i = 0; i < numRows; ++i) // m_treeColumn.TreeDataCollapseAllSubLevels(i); }
unsigned char CTreeColumn::GetTreeLevel( int aiRow) // row // returns: tree level, =0 if invalid input { ASSERT( m_pGrid != NULL); ASSERT( aiRow >= 0 && aiRow < m_iRowCount ); ASSERT( m_iColumnWithTree >= 0); CGridTreeCell* pGridTreeCell = (CGridTreeCell*)m_pGrid->GetCell( aiRow, m_iColumnWithTree); if( pGridTreeCell != NULL) return pGridTreeCell->GetLevel(); return 0; }
/***************************************************************************** Callable by class consumer to prepare one's own data array of tree info to display something reasonable. High order Bits of the tree display data are modified. *****************************************************************************/ void CTreeColumn::TreeDataPrepOutline(unsigned char aucLevel, // level to display >= 0x80 displays all int aiIndex, // Index to tree display data to modify int aiNbrElements) // nbr of elements in tree display data { ASSERT( aucLevel > 0); ASSERT( m_iColumnWithTree >= 0); ASSERT( aiIndex >= 0 ); ASSERT( aiNbrElements > 0); ASSERT( m_pGrid != NULL); ASSERT( aiIndex + aiNbrElements <= m_iRowCount - m_iFixedRowCount ); int i1; if( aucLevel >= 0x80) { for( i1=0; i1 < aiNbrElements; i1++) { int iCellRow = m_iFixedRowCount + aiIndex + i1; CGridTreeCell* pGridTreeCell = (CGridTreeCell*)m_pGrid->GetCell( iCellRow, m_iColumnWithTree); if( pGridTreeCell == NULL) return; pGridTreeCell->SetViewable( TRUE); } } else { for( i1=0; i1 < aiNbrElements; i1++) { int iCellRow = m_iFixedRowCount + aiIndex + i1; CGridTreeCell* pGridTreeCell = (CGridTreeCell*)m_pGrid->GetCell( iCellRow, m_iColumnWithTree); if( pGridTreeCell == NULL) return; if( pGridTreeCell->GetLevel() <= aucLevel) pGridTreeCell->SetViewable( TRUE); else pGridTreeCell->SetViewable( FALSE); } } }
void CVariablesGrid::RestoreExpandInfo(bool extraRow) { if (m_expandInfo.GetSize() == 0) return; // Get the full name. CString fullName; int curExpandPos = 0; int numRows = GetRowCount(); if (extraRow) numRows--; for (int i = 1; i < numRows; ++i) { CGridTreeCell* treeCell = (CGridTreeCell*)GetCell(i, 0); int level = treeCell->GetLevel(); if (level == 1) { fullName = GetItemText(i, 0); } else { fullName += "." + GetItemText(i, 0); } if (m_expandInfo[curExpandPos].m_fullName == fullName) { // m_treeColumn.TreeDataExpandOneLevel(i); treeCell->SetViewable(TRUE); curExpandPos++; if (curExpandPos == m_expandInfo.GetSize()) { m_treeColumn.TreeRefreshRows(); return; } } } m_treeColumn.TreeRefreshRows(); }
/***************************************************************************** Should the cell identified by the row have a "+" or "-" graphic? *****************************************************************************/ BOOL CTreeColumn::TreeCellHasPlusMinus( int aiRow, // row of Cell to check BOOL* apbIsPlus, // returns: T=Is a plus BOOL* apbIsMinus, // returns: T=Is a minus BOOL* apbIsLastLeaf)// returns: T=Is Last Leaf // returns: T=cell has a plus or minus; F=not { ASSERT( m_pGrid != NULL); ASSERT( aiRow >= m_iFixedRowCount && aiRow < m_iRowCount); ASSERT( m_iColumnWithTree >= 0); ASSERT( apbIsPlus != NULL); ASSERT( apbIsMinus != NULL); ASSERT( apbIsLastLeaf != NULL); *apbIsPlus = FALSE; *apbIsMinus = FALSE; *apbIsLastLeaf = FALSE; int iStartPt = aiRow + 1; int i1; // get current level CGridTreeCell* pGridTreeCell = (CGridTreeCell*)m_pGrid->GetCell( aiRow, m_iColumnWithTree); if( pGridTreeCell == NULL) return FALSE; unsigned char ucLevelCurrent = pGridTreeCell->GetLevel(); if( ucLevelCurrent <= 0) return FALSE; // no tree BOOL bIsNextShowing = FALSE; unsigned char ucLevelNext = 0; for( i1=iStartPt; i1 < m_iRowCount; i1++) { pGridTreeCell = (CGridTreeCell*)m_pGrid->GetCell( i1, m_iColumnWithTree); if( pGridTreeCell == NULL) return FALSE; bIsNextShowing = pGridTreeCell->IsViewable(); ucLevelNext = pGridTreeCell->GetLevel(); if( ucLevelCurrent >= ucLevelNext ) { break; } if( !bIsNextShowing && ucLevelNext == ucLevelCurrent + 1) { *apbIsPlus = TRUE; } } // final attribute setting now that enough data has been examined if( i1 > iStartPt && !*apbIsPlus) { *apbIsMinus = TRUE; } if( !bIsNextShowing || ucLevelCurrent > ucLevelNext || i1 >= m_iRowCount ) // hit last element *apbIsLastLeaf = TRUE; return *apbIsMinus || *apbIsPlus; }
/***************************************************************************** This may delete one or more rows depending on the makeup of the tree branch. It's analagous to deleting a file directory with all files and sub-directories deleted, too. *****************************************************************************/ int CTreeColumn::DeleteTreeBranch( int aiRow, // Row that the tree branch begins on BOOL abRedraw) // T=redraw; F=don't // returns: nbr of rows deleted { ASSERT( aiRow >= -1); ASSERT( m_pGrid != NULL); // Must call TreeSetup(), first if( aiRow < m_iFixedRowCount || aiRow >= m_iRowCount) return 0; int iRowDeleteCount = 0; m_bAllowDraw = FALSE; // prevents crash during reset // get level of initial row to delete from tree CGridTreeCell* pGridTreeCell = (CGridTreeCell*)m_pGrid->GetCell( aiRow, m_iColumnWithTree); unsigned char ucLevelCurrent = CHAR_MAX; if( pGridTreeCell != NULL) { // delete just the parent ucLevelCurrent = pGridTreeCell->GetLevel(); if( m_pGrid->DeleteRow( aiRow) ) { iRowDeleteCount++; m_iRowCount--; } } // see if any children need to be deleted, too unsigned char ucLevel; while( aiRow < m_iRowCount) { pGridTreeCell = (CGridTreeCell*)m_pGrid->GetCell( aiRow, m_iColumnWithTree); if( pGridTreeCell == NULL) break; ucLevel = pGridTreeCell->GetLevel(); if( ucLevel <= ucLevelCurrent) break; if( !m_pGrid->DeleteRow( aiRow) ) break; iRowDeleteCount++; m_iRowCount--; } ASSERT( m_iRowCount == m_pGrid->GetRowCount() ); // have to re-number all cells below deletion point if( iRowDeleteCount > 0) { int iRow; int iColumnCount = m_pGrid->GetColumnCount(); for( iRow=aiRow; iRow < m_iRowCount; iRow++) { int iCol; for (iCol = 0; iCol < iColumnCount; iCol++) { CGridCellBase* pGridCellBase = m_pGrid->GetCell( iRow, iCol); if( pGridCellBase != NULL) { pGridCellBase->SetCoords( iRow, iCol); } } } } m_bAllowDraw = TRUE; TreeRefreshRows(); if( abRedraw) m_pGrid->Invalidate(); return iRowDeleteCount; }