//
//  Copyright(c) Ivyware Pty Ltd  2002
//               MELBOURNE, VICTORIA, AUSTRALIA, 3130
//
//  Description: MfcExtensions
//

#include "StdAfx.h"

#include "CTreeCtrl_ext.h"

//
//  Moves CTreeCtrl and associated childern to alternative location
//
//
//  Parameters:  CTreeCtrl *pCTreeCtrl
//               Tree control containing item to be copied
//
//               BOOL bCopyOnly
//               Full window copy flag
//
//  Returns:     HTREEITEM
//               Moved item as a copy of hItem
HTREEITEM
CTreeCtrl_MoveItem_ ( CTreeCtrl& oTreeCtrl, HTREEITEM hItem, HTREEITEM hItemTo
		               , BOOL bCopyOnly, PFNMTICOPYDATA pfnCopyData
		               , HTREEITEM hItemPos )
{
    // To be sure, to be sure
    if ( hItem   == NULL ||
         hItemTo == NULL    )
      return NULL;
    if ( hItem   == hItemTo                        ||
         hItemTo == oTreeCtrl.GetParentItem(hItem)    )
      return hItem;
    // Block descendant movement
    HTREEITEM hItemParent = hItemTo;
    while ( hItemParent != TVI_ROOT                                     &&
           (hItemParent = oTreeCtrl.GetParentItem(hItemParent)) != NULL    )
    {
      if ( hItemParent == hItem )
        return NULL;
    }

    // Recursively copy items to new location and optionally remove original
    CString sText = oTreeCtrl.GetItemText(hItem);
    TVINSERTSTRUCT tvis;
    tvis.item.mask = TVIF_HANDLE | TVIF_IMAGE | TVIF_PARAM
	                 | TVIF_SELECTEDIMAGE | TVIF_STATE;
    tvis.item.hItem = hItem;
  
    // Negate expanded and selected states
    tvis.item.stateMask = (UINT)-1 & ~(TVIS_DROPHILITED | TVIS_EXPANDED
		                    | TVIS_EXPANDEDONCE | TVIS_EXPANDPARTIAL | TVIS_SELECTED);
    oTreeCtrl.GetItem(&tvis.item);
    tvis.hParent = hItemTo;
    tvis.hInsertAfter = hItemPos;

    // Data item not transferred for copy only
    if ( bCopyOnly           && 
         pfnCopyData != NULL     )
      tvis.item.lParam = pfnCopyData ( oTreeCtrl, hItem, tvis.item.lParam );
    HTREEITEM hItemNew = oTreeCtrl.InsertItem(&tvis);
    oTreeCtrl.SetItemText(hItemNew, sText);

    // Recursively move children under new item
    HTREEITEM hItemChild = oTreeCtrl.GetChildItem(hItem);
    while (hItemChild != NULL)
    {
      HTREEITEM hItemNextChild = oTreeCtrl.GetNextSiblingItem(hItemChild);
      CTreeCtrl_MoveItem_(oTreeCtrl, hItemChild, hItemNew, bCopyOnly, pfnCopyData);
      hItemChild = hItemNextChild;
    }

    // Tidy up reminants
    // NOTES: Negate data field prior to removal
    if ( !bCopyOnly )
    {
      oTreeCtrl.SetItemData ( hItem, 0 );
      oTreeCtrl.DeleteItem  ( hItem );
    } 
    return hItemNew;
}

HTREEITEM
CTreeCtrl_MoveItem ( CTreeCtrl *pCTreeCtrl
                   , HTREEITEM hItem, HTREEITEM hItemParent, HTREEITEM hItemAfter
                   , fptrCTreeCtrl_MoveItem fptrMoveItemCB )
{
    // To be sure, to be sure
    if ( hItem       == NULL ||
         hItemParent == NULL    )
      return NULL;
    //if ( hItem == hItemTo || hItemTo == tree.GetParentItem(hItem))
    //  return hItem;

    // Block movement to a descendant
    HTREEITEM hItemCheck = hItemParent;
    while ( hItemCheck != TVI_ROOT &&
           (hItemCheck = pCTreeCtrl->GetParentItem(hItemCheck)) != NULL)
    {
      if (hItemCheck == hItem)
        return NULL;
    }

    // copy items to new location, recursively, then delete old heirarchy
    // get text, and other info
    CString sText = pCTreeCtrl->GetItemText(hItem);
    TVINSERTSTRUCT tvis;
    tvis.item.mask  = TVIF_HANDLE | TVIF_IMAGE | TVIF_PARAM | 
	        TVIF_SELECTEDIMAGE | TVIF_STATE;
    tvis.item.hItem = hItem;
    // we don't want to copy selection/expanded state etc
    tvis.item.stateMask = (UINT)-1 & ~(TVIS_DROPHILITED | TVIS_EXPANDED | 
	  		TVIS_EXPANDEDONCE | TVIS_EXPANDPARTIAL | TVIS_SELECTED);
    pCTreeCtrl -> GetItem ( &tvis.item );
    tvis.hParent      = hItemParent;
    tvis.hInsertAfter = hItemAfter;
    // if we're only copying, then ask for new data
    //if (bCopyOnly && pfnCopyData != NULL)
    tvis.item.lParam   = 0;//pfnCopyData(pCTreeCtrl, hItem, tvis.item.lParam);
    HTREEITEM hItemNew = pCTreeCtrl->InsertItem(&tvis);
    pCTreeCtrl->SetItemText(hItemNew, sText);
    if ( fptrMoveItemCB )
      (*fptrMoveItemCB) ( pCTreeCtrl, hItem, hItemNew );

    // now move children to under new item
    HTREEITEM hItemChild = pCTreeCtrl->GetChildItem(hItem);
    while ( hItemChild != NULL )
    {
      HTREEITEM hItemNextChild = pCTreeCtrl->GetNextSiblingItem(hItemChild);
      CTreeCtrl_MoveItem ( pCTreeCtrl, hItemChild, hItemNew, TVI_LAST 
                         , fptrMoveItemCB );
      hItemChild = hItemNextChild;
    }

    //if (! bCopyOnly)
    {
      // clear item data, so nothing tries to delete stuff based on lParam
      pCTreeCtrl->SetItemData(hItem, 0);
      // no (more) children, so we can safely delete top item
      pCTreeCtrl->DeleteItem(hItem);
    }

    // Tidy up, and
    return hItemNew;
}

