Professional UI Solutions
Site Map   /  Register
 
 

Forum

Please Log In to post a new message or reply to an existing one. If you are not registered, please register.

NOTE: Some forums may be read-only if you are not currently subscribed to our technical support services.

Forums » Prof-UIS Tech Support » Sorting in tree grid Collapse All
Subject Author Date
Rado Manzela May 23, 2007 - 10:22 AM

I’ve made recursive function for sorting tree grid items based on the ItemSortChildren() function.
The problem is that ItemSortChildren() function expands the sorted items. How can I avoid this? (I’m sorting all items including their children by selected column but need to preserve expand status of tree).
It seems to be inefficient to remember expand state of sorted node and restore it after sort.
Is it necessary to expand the node in prof-uis library while sorting?
Thank you.

Technical Support May 24, 2007 - 4:31 AM

Thank you for reporting us this issue. The following updated method fixes the problem.

CExtTreeGridCellNode * CExtTreeGridDataProvider::_Tree_NodeCopyMove(
      CExtTreeGridCellNode * pNodeCopyMove,
      CExtTreeGridCellNode * pNodeNewParent, // if NULL - root
      ULONG nIdxInsertBefore, // = (ULONG(-1)) // if (ULONG(-1)) - insert to end
      bool bMove, // = true
      bool bCloneOnMove, // = true
      bool bCloneCellObjects, // = true
      INT nExpandAction, // = TVE_TOGGLE // TVE_TOGGLE in this case - keep expanded state
      bool bEnableCopyingIntoInnerBranch, // = true
      bool * p_bCopyingIntoInnerBranch // = NULL
      )
{
      ASSERT_VALID( this );
      if( bMove )
            bEnableCopyingIntoInnerBranch = false;
bool bCopyingIntoInnerBranch = false;
bool bCopyMoveTestRetVal =
            _Tree_NodeCopyMoveTest(
                  pNodeCopyMove,
                  pNodeNewParent,
                  nIdxInsertBefore,
                  bEnableCopyingIntoInnerBranch,
                  &bCopyingIntoInnerBranch
                  );
      if( p_bCopyingIntoInnerBranch != NULL )
            (*p_bCopyingIntoInnerBranch) = bCopyingIntoInnerBranch;
      if( ! bCopyMoveTestRetVal )
            return NULL;
      ASSERT_VALID( pNodeCopyMove );
CExtTreeGridCellNode * pNodeRoot = _Tree_NodeGetRoot();
      ASSERT_VALID( pNodeRoot );
      if( pNodeNewParent == NULL )
            pNodeNewParent = pNodeRoot;
      ASSERT_VALID( pNodeNewParent );
ULONG nTargetParentSiblingCount = pNodeNewParent->TreeNodeGetChildCount();
      if(         nIdxInsertBefore == ULONG(-1L)
            ||    nIdxInsertBefore > nTargetParentSiblingCount
            )
            nIdxInsertBefore = nTargetParentSiblingCount;
CExtTreeGridCellNode * pNodeRetVal = NULL;
      if( bMove && ( ! bCloneOnMove ) )
      {
            bool b1 = pNodeCopyMove->TreeNodeIsExpanded();
            bool b2 = pNodeNewParent->TreeNodeIsExpanded();
            if( ! b1 )
                  _Tree_NodeExpand( pNodeCopyMove, TVE_EXPAND );
            if( ! b2 )
                  _Tree_NodeExpand( pNodeNewParent, TVE_EXPAND );
            if(   _Tree_NodeMoveImpl(
                        pNodeCopyMove,
                        pNodeNewParent,
                        nIdxInsertBefore,
                        nExpandAction
                        )
                  )
                  pNodeRetVal = pNodeCopyMove;
            if( ! b1 )
                  _Tree_NodeExpand( pNodeCopyMove, TVE_COLLAPSE );
            if( ! b2 )
                  _Tree_NodeExpand( pNodeNewParent, TVE_COLLAPSE );
      }
      else
            pNodeRetVal =
                  _Tree_NodeCopyImpl(
                        pNodeCopyMove,
                        pNodeNewParent,
                        NULL,
                        nIdxInsertBefore,
                        nExpandAction,
                        bCloneCellObjects
                        );
      if( pNodeRetVal == NULL )
            return NULL;
      ASSERT_VALID( pNodeRetVal );
      if( bMove && bCloneOnMove )
            _Tree_NodeRemove( pNodeCopyMove );
      return pNodeRetVal;
}
We used this project for testing.

Rado Manzela May 24, 2007 - 5:52 AM

Now it is better but still not perfect ;)
Try to setup the tree like this and then sort. Item 000 still expands.
http://rrrado.szm.sk/tree.png

Technical Support May 26, 2007 - 10:25 AM

We have just improved the code to perform deep sorting without losing expanded row states and without expanding/collapsing while sorting. Please update the source code for the following two methods:

CExtTreeGridCellNode * CExtTreeGridDataProvider::_Tree_NodeCopyMove(
      CExtTreeGridCellNode * pNodeCopyMove,
      CExtTreeGridCellNode * pNodeNewParent, // if NULL - root
      ULONG nIdxInsertBefore, // = (ULONG(-1)) // if (ULONG(-1)) - insert to end
      bool bMove, // = true
      bool bCloneOnMove, // = true
      bool bCloneCellObjects, // = true
      INT nExpandAction, // = TVE_TOGGLE // TVE_TOGGLE in this case - keep expanded state
      bool bEnableCopyingIntoInnerBranch, // = true
      bool * p_bCopyingIntoInnerBranch // = NULL
      )
{
      ASSERT_VALID( this );
      if( bMove )
            bEnableCopyingIntoInnerBranch = false;
bool bCopyingIntoInnerBranch = false;
bool bCopyMoveTestRetVal =
            _Tree_NodeCopyMoveTest(
                  pNodeCopyMove,
                  pNodeNewParent,
                  nIdxInsertBefore,
                  bEnableCopyingIntoInnerBranch,
                  &bCopyingIntoInnerBranch
                  );
      if( p_bCopyingIntoInnerBranch != NULL )
            (*p_bCopyingIntoInnerBranch) = bCopyingIntoInnerBranch;
      if( ! bCopyMoveTestRetVal )
            return NULL;
      ASSERT_VALID( pNodeCopyMove );
CExtTreeGridCellNode * pNodeRoot = _Tree_NodeGetRoot();
      ASSERT_VALID( pNodeRoot );
      if( pNodeNewParent == NULL )
            pNodeNewParent = pNodeRoot;
      ASSERT_VALID( pNodeNewParent );
ULONG nTargetParentSiblingCount = pNodeNewParent->TreeNodeGetChildCount();
      if(         nIdxInsertBefore == ULONG(-1L)
            ||    nIdxInsertBefore > nTargetParentSiblingCount
            )
            nIdxInsertBefore = nTargetParentSiblingCount;
CExtTreeGridCellNode * pNodeRetVal = NULL;
      if( bMove && ( ! bCloneOnMove ) )
      {
            if(   _Tree_NodeMoveImpl(
                        pNodeCopyMove,
                        pNodeNewParent,
                        nIdxInsertBefore,
                        nExpandAction
                        )
                  )
                  pNodeRetVal = pNodeCopyMove;
      }
      else
            pNodeRetVal =
                  _Tree_NodeCopyImpl(
                        pNodeCopyMove,
                        pNodeNewParent,
                        NULL,
                        nIdxInsertBefore,
                        nExpandAction,
                        bCloneCellObjects
                        );
      if( pNodeRetVal == NULL )
            return NULL;
      ASSERT_VALID( pNodeRetVal );
      if( bMove && bCloneOnMove )
            _Tree_NodeRemove( pNodeCopyMove );
      return pNodeRetVal;
}

bool CExtTreeGridDataProvider::_Tree_NodeMoveImpl(
      CExtTreeGridCellNode * pNodeCopyMove,
      CExtTreeGridCellNode * pNodeNewParent,
      ULONG nIdxInsertBefore,
      INT nExpandAction
      )
{
      ASSERT_VALID( this );
      ASSERT_VALID( pNodeCopyMove );
      ASSERT_VALID( pNodeNewParent );
      nExpandAction;
ULONG nIndex;
CExtTreeGridCellNode * pNode = NULL;
bool b3 = pNodeCopyMove->TreeNodeIsDisplayed();
bool b4 = pNodeNewParent->TreeNodeIsDisplayed() && pNodeNewParent->TreeNodeIsExpanded();
      if( ! ( ( b3 && b4 ) || ( (!b3) && (!b4) ) ) )
      {
            ASSERT( FALSE );
            return false;
      }
      if( b3 )
      {
            CExtTreeGridCellNode * pNodeRoot = TreeNodeGetRoot();
            ASSERT_VALID( pNodeRoot );
            ASSERT( pNodeCopyMove != pNodeRoot );
            pNode = pNodeCopyMove->TreeNodeGetParent();
            ASSERT_VALID( pNode );
            for( ; LPCVOID(pNodeRoot) != LPCVOID(pNode); )
            {
                  TreeNodeExpand( pNode, TVE_EXPAND );
                  pNode = pNode->TreeNodeGetParent();
                  ASSERT_VALID( pNode );
            } // for( ; LPCVOID(pNodeRoot) == LPCVOID(pNode); )
            pNode = pNodeNewParent;
            for( ; LPCVOID(pNodeRoot) != LPCVOID(pNode); )
            {
                  TreeNodeExpand( pNode, TVE_EXPAND );
                  pNode = pNode->TreeNodeGetParent();
                  ASSERT_VALID( pNode );
            } // for( ; LPCVOID(pNodeRoot) == LPCVOID(pNode); )
      }

CExtTreeGridCellNode * pNodeOldParent = pNodeCopyMove->m_pNodeParent;
      ASSERT_VALID( pNodeOldParent );
ULONG nOldOptIndex = pNodeCopyMove->TreeNodeGetSiblingIndex();

ULONG nTargetChildrenCount = pNodeNewParent->TreeNodeGetChildCount();
      ASSERT( nIdxInsertBefore <= nTargetChildrenCount );
CExtTreeGridCellNode * pNodeTargetCalc = NULL;
      if( nIdxInsertBefore == nTargetChildrenCount )
            pNodeTargetCalc = pNodeNewParent;
      else
            pNodeTargetCalc = pNodeNewParent->TreeNodeGetChildAt( nIdxInsertBefore );
ULONG nExpandedOffsetSrc = pNodeCopyMove->TreeNodeCalcOffset( true );
ULONG nPhysicalOffsetSrc = pNodeCopyMove->TreeNodeCalcOffset( false );
ULONG nExpandedOffsetDst = pNodeTargetCalc->TreeNodeCalcOffset( true );
ULONG nPhysicalOffsetDst = pNodeTargetCalc->TreeNodeCalcOffset( false );
ULONG nMoveWeightExpanded = pNodeCopyMove->_ContentWeight_Get( true ) + 1;
ULONG nMoveWeightPhysical = pNodeCopyMove->_ContentWeight_Get( false ) + 1;
      if( nIdxInsertBefore == nTargetChildrenCount )
      {
            nExpandedOffsetDst += pNodeTargetCalc->_ContentWeight_Get( true ) + 1;
            nPhysicalOffsetDst += pNodeTargetCalc->_ContentWeight_Get( false ) + 1;
      }
CExtTreeGridCellNode::NodeArr_t _arrNodes;
      if( b3 )
      {
            _arrNodes.SetSize( nMoveWeightExpanded );
            for( nIndex = 0; nIndex < nMoveWeightExpanded; nIndex ++ )
            {
                  pNode = m_arrGridVis[ nExpandedOffsetSrc + nIndex ];
                  ASSERT_VALID( pNode );
                  _arrNodes.SetAt( nIndex, pNode );
            }
            m_arrGridVis.RemoveAt( nExpandedOffsetSrc, nMoveWeightExpanded );
            ULONG _nExpandedOffsetDst = nExpandedOffsetDst;
            if( _nExpandedOffsetDst > nExpandedOffsetSrc )
                  _nExpandedOffsetDst -= nMoveWeightExpanded;
            m_arrGridVis.InsertAt( _nExpandedOffsetDst, &_arrNodes );
      }

      _arrNodes.SetSize( nMoveWeightPhysical );
      for( nIndex = 0; nIndex < nMoveWeightPhysical; nIndex ++ )
      {
            pNode = m_arrGridRef[ nPhysicalOffsetSrc + nIndex ];
            ASSERT_VALID( pNode );
            _arrNodes.SetAt( nIndex, pNode );
      }
      m_arrGridRef.RemoveAt( nPhysicalOffsetSrc, nMoveWeightPhysical );
ULONG _nPhysicalOffsetDst = nPhysicalOffsetDst;
      if( _nPhysicalOffsetDst > nPhysicalOffsetSrc )
            _nPhysicalOffsetDst -= nMoveWeightPhysical;
      m_arrGridRef.InsertAt( _nPhysicalOffsetDst, &_arrNodes );

ULONG nReservedRowCount = 0L;
      m_DP.CacheReservedCountsGet( NULL, &nReservedRowCount );
      nPhysicalOffsetSrc += nReservedRowCount;
      nPhysicalOffsetDst += nReservedRowCount;
LONG nTmp = 0;
      for( nIndex = 0; nIndex < nMoveWeightPhysical; nIndex ++ )
      {
            if( nPhysicalOffsetSrc < nPhysicalOffsetDst )
            {
                  ULONG nOffsetSrc = nPhysicalOffsetSrc + nMoveWeightPhysical - 1 - nIndex;
                  ULONG nOffsetDst = nPhysicalOffsetDst + nMoveWeightPhysical - 1 - nIndex;
                  for( ; nOffsetSrc != nOffsetDst; )
                  {
                        m_DP._SortSwapSeries(
                              nOffsetSrc,
                              nOffsetSrc + 1,
                              nTmp,
                              NULL,
                              false
                              );
                        nOffsetSrc ++;
                  }
            }
            else
            {
                  ULONG nOffsetSrc = nPhysicalOffsetSrc + nIndex;
                  ULONG nOffsetDst = nPhysicalOffsetDst + nIndex;
                  for( ; nOffsetSrc != nOffsetDst; )
                  {
                        m_DP._SortSwapSeries(
                              nOffsetSrc,
                              nOffsetSrc - 1,
                              nTmp,
                              NULL,
                              false
                              );
                        nOffsetSrc --;
                  }
            }
      }

CExtTreeGridCellNode * pNodePrev = pNodeCopyMove->m_pNodePrev;
CExtTreeGridCellNode * pNodeNext = pNodeCopyMove->m_pNodeNext;
      if( pNodePrev != NULL )
      {
            ASSERT_VALID( pNodePrev );
            pNodePrev->m_pNodeNext = pNodeNext;
      }
      if( pNodeNext != NULL )
      {
            ASSERT_VALID( pNodeNext );
            pNodeNext->m_pNodePrev = pNodePrev;
      }
      pNodeCopyMove->m_pNodePrev = pNodeCopyMove->m_pNodeNext = NULL;
      if( nIdxInsertBefore == nTargetChildrenCount )
      {
            if( nTargetChildrenCount > 0 )
            {
                  pNode = pNodeNewParent->TreeNodeGetLastChild();
                  ASSERT_VALID( pNode );
                  ASSERT( pNode->m_pNodeNext == NULL );
                  pNode->m_pNodeNext = pNodeCopyMove;
                  pNodeCopyMove->m_pNodePrev = pNode;
            }
      }
      else
      {
            pNodeCopyMove->m_pNodeNext = pNodeTargetCalc;
            pNodeCopyMove->m_pNodePrev = pNodeTargetCalc->m_pNodePrev;
            if( pNodeCopyMove->m_pNodePrev != NULL )
            {
                  ASSERT_VALID( pNodeCopyMove->m_pNodePrev );
                  pNodeCopyMove->m_pNodePrev->m_pNodeNext = pNodeCopyMove;
            }
            if( pNodeCopyMove->m_pNodeNext != NULL )
            {
                  ASSERT_VALID( pNodeCopyMove->m_pNodeNext );
                  pNodeCopyMove->m_pNodeNext->m_pNodePrev = pNodeCopyMove;
            }
      }

      if( LPVOID(pNodeNewParent) != LPVOID(pNodeOldParent) )
      {
            pNodeOldParent->m_arrChildren.RemoveAt( nOldOptIndex, 1 );
            ULONG nStartIndex = nOldOptIndex;
            ULONG nEndIndex = ULONG( pNodeOldParent->m_arrChildren.GetSize() );
            for( nIndex = nStartIndex; nIndex < nEndIndex; nIndex ++ )
            {
                  pNode = pNodeOldParent->m_arrChildren[ nIndex ];
                  ASSERT_VALID( pNode );
                  pNode->m_nOptIndex = nIndex;
            }
            pNodeNewParent->m_arrChildren.InsertAt( nIdxInsertBefore, pNodeCopyMove, 1 );
            nStartIndex = nIdxInsertBefore;
            nEndIndex = ULONG( pNodeNewParent->m_arrChildren.GetSize() );
            for( nIndex = nStartIndex; nIndex < nEndIndex; nIndex ++ )
            {
                  pNode = pNodeNewParent->m_arrChildren[ nIndex ];
                  ASSERT_VALID( pNode );
                  pNode->m_nOptIndex = nIndex;
            }
            
            for( pNode = pNodeOldParent; pNode != NULL && pNode->TreeNodeIsExpanded(); pNode = pNode->m_pNodeParent )
            {
                  pNode->m_nContentWeightAll -= nMoveWeightPhysical;
                  pNode->m_nContentWeightExpanded -= nMoveWeightExpanded;
            }
            for( pNode = pNodeNewParent; pNode != NULL && pNode->TreeNodeIsExpanded(); pNode = pNode->m_pNodeParent )
            {
                  pNode->m_nContentWeightAll += nMoveWeightPhysical;
                  pNode->m_nContentWeightExpanded += nMoveWeightExpanded;
            }
      }
      else
      {
            pNodeOldParent->m_arrChildren.RemoveAt( nOldOptIndex, 1 );
            ULONG _nIdxInsertBefore = nIdxInsertBefore;
            if( _nIdxInsertBefore  >= nOldOptIndex )
                  _nIdxInsertBefore --;
            pNodeOldParent->m_arrChildren.InsertAt( _nIdxInsertBefore , pNodeCopyMove, 1 );
            ULONG nStartIndex = min( nOldOptIndex, nIdxInsertBefore );
            ULONG nEndIndex = ( max( nOldOptIndex, nIdxInsertBefore ) ) + 1;
            if( nEndIndex >= ULONG(pNodeOldParent->m_arrChildren.GetSize()) )
                  nEndIndex = ULONG(pNodeOldParent->m_arrChildren.GetSize()) - 1;
            for( nIndex = nStartIndex; nIndex <= nEndIndex; nIndex ++ )
            {
                  pNode = pNodeOldParent->m_arrChildren[ nIndex ];
                  ASSERT_VALID( pNode );
                  pNode->m_nOptIndex = nIndex;
            }
      }

      return true;
}