Hide

SftTree/DLL 7.5 - Tree Control

Display
Print

OLEDrag Sample (C++)

This sample illustrates drag & drop (using OLE mechanisms) within a tree control and with Windows Explorer.

The source code is located at C:\Program Files (x86)\Softelvdm\SftTree DLL 7.5\Samples\MFC\OLEDrag\SamplVw.cpp or C:\Program Files\Softelvdm\SftTree DLL 7.5\Samples\MFC\OLEDrag\SamplVw.cpp (on 32-bit Windows versions).

/****************************************************************************/
/* SftTree/DLL 7.5 - Tree Control for C/C++                                 */
/* Copyright (C) 1995, 2016  Softel vdm, Inc. All Rights Reserved.          */
/****************************************************************************/

#include "stdafx.h"
#include "OLEDrag.h"

#include "sampldoc.h"
#include "samplvw.h"

#ifdef _DEBUG
#undef THIS_FILE
static char BASED_CODE THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CSampleView

IMPLEMENT_DYNCREATE(CSampleView, CView)

BEGIN_MESSAGE_MAP(CSampleView, CView)
    //{{AFX_MSG_MAP(CSampleView)
    ON_WM_CREATE()
    ON_WM_SIZE()
    //}}AFX_MSG_MAP
    ON_SFTTREEN_LBUTTONDBLCLK_TEXT(IDC_TREE, OnLButtonExpandCollapse)
    ON_SFTTREEN_LBUTTONDOWN_BUTTON(IDC_TREE, OnLButtonExpandCollapse)
    ON_SFTTREEN_LBUTTONDBLCLK_BUTTON(IDC_TREE, OnLButtonExpandCollapse)
    ON_SFTTREEN_EXPANDALL(IDC_TREE, OnExpandAll)
    ON_SFTTREEN_LBUTTONDBLCLK_COLUMNRES(IDC_TREE, OnLButtonDblClkColumnResize)
    ON_SFTTREEN_LBUTTONDBLCLK_PLUSMIN(IDC_TREE, OnLButtonExpandCollapse)
    ON_SFTTREEN_LBUTTONDOWN_PLUSMIN(IDC_TREE, OnLButtonExpandCollapse)
    ON_SFTTREEN_BEGINDRAG(IDC_TREE, OnBeginDrag)
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CSampleView construction/destruction

CSampleView::CSampleView()
{
}

CSampleView::~CSampleView()
{
}

/////////////////////////////////////////////////////////////////////////////
// CSampleView drawing

void CSampleView::OnDraw(CDC* pDC)
{
    CSampleDoc* pDoc = GetDocument();
    ASSERT_VALID(pDoc);
}

/////////////////////////////////////////////////////////////////////////////
// CSampleView diagnostics

#ifdef _DEBUG
void CSampleView::AssertValid() const
{
    CView::AssertValid();
}

void CSampleView::Dump(CDumpContext& dc) const
{
    CView::Dump(dc);
}

CSampleDoc* CSampleView::GetDocument() // non-debug version is inline
{
    ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CSampleDoc)));
    return (CSampleDoc*)m_pDocument;
}
#endif //_DEBUG

/////////////////////////////////////////////////////////////////////////////
// CSampleView message handlers

int CSampleView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
    if (CView::OnCreate(lpCreateStruct) == -1)
        return -1;

    if (!m_Tree.CreateEx(
        WS_EX_CLIENTEDGE,
        SFTTREESTYLE_NOTIFY |            /* Notify parent window */
        SFTTREESTYLE_DRAGDROP |          /* Drag & drop enabled */
        SFTTREESTYLE_LEFTBUTTONONLY |    /* Only respond to left mouse button */
        SFTTREESTYLE_SCROLL |            /* Honor WS_H/VSCROLL */
        SFTTREESTYLE_DISABLENOSCROLL |   /* Disable scrollbars instead of hiding */
        WS_HSCROLL | WS_VSCROLL |        /* Vertical and horizontal scrollbars */
        WS_VISIBLE | WS_CHILD,           /* Visible, child window */
        CRect(0,0,0,0),                  /* Location */
        this,                            /* Parent window */
        IDC_TREE))                       /* Tree control ID */
            return -1;

    m_Tree.SetShowHeader(TRUE);          /* Show column headers */

    SFT_PICTURE Pic;                     /* Used for certain pictures */

    /* Register the item pictures.  These pictures are used    */
    /* for all items in the tree control. All three pictures   */
    /* must be the same size.                                  */
    {
        SFT_PICTURE aPic[3];
        Sft_InitPicture(&aPic[0]);
        Sft_InitPicture(&aPic[1]);
        Sft_InitPicture(&aPic[2]);
        m_aThreeItemBitmaps[0].LoadBitmap(IDB_EXPANDABLE);/* Expandable bitmap */
        Sft_SetPictureBitmap(&aPic[0], m_aThreeItemBitmaps[0]);/* Assign bitmap */
        m_aThreeItemBitmaps[1].LoadBitmap(IDB_EXPANDED);/* Expanded bitmap */
        Sft_SetPictureBitmap(&aPic[1], m_aThreeItemBitmaps[1]);/* Assign bitmap */
        m_aThreeItemBitmaps[2].LoadBitmap(IDB_LEAF);/* Leaf bitmap */
        Sft_SetPictureBitmap(&aPic[2], m_aThreeItemBitmaps[2]);/* Assign bitmap */
        m_Tree.SetPictures(aPic);        /* Use item pictures */
    }
    m_Tree.SetItemBitmapAlign(TRUE);     /* Align item bitmaps */
    /* Register the cell picture size.  All cell pictures used */
    /* must be the same size.  Only one picture needs to be    */
    /* registered, even if several are used.                   */
    {
        SFTTREE_CELLINFOPARM CellInfo;
        CellInfo.version = 7;
        CellInfo.index = -1;             /* Registering picture size */
        m_CellBitmap.LoadBitmap(IDB_SMILE);/* Cell picture */
        Sft_InitPicture(&CellInfo.Cell.CellPicture1);
        Sft_SetPictureBitmap(&CellInfo.Cell.CellPicture1, m_CellBitmap);/* Assign bitmap */
        m_Tree.SetCellInfo(&CellInfo);   /* Register use of cell pictures */
    }
    m_Tree.SetTreeLineStyle(SFTTREE_TREELINE_DOT);/* Dotted tree lines */
    m_Tree.SetShowButtons(FALSE);        /* Expand/collapse buttons (level 1..n) */
    m_Tree.SetShowGrid(TRUE);            /* Show grid */
    m_Tree.SetGridStyle(SFTTREE_GRID_BOTH_DOT);/* Dotted grid lines */
    m_Tree.SetShowTruncated(TRUE);       /* Show ... if truncated */
    m_Tree.SetNoFocusStyle(SFTTREE_NOFOCUS_FRAME);/* No focus, show frame */
    m_Tree.SetSelectionStyle(SFTTREE_SELECTION_CELL1 | SFTTREE_SELECTION_OUTLINE);/* Select first cell only using outline */
    m_Tree.SetSelectionArea(SFTTREE_SELECTIONAREA_ALL);/* Selection changes by clicking anywhere on an item */
    m_Tree.SetFlyby(TRUE);               /* Flyby highlighting */
    m_Tree.SetCrossColumnResize(TRUE);   /* Resize multiple columns */
    m_Tree.SetReorderColumns(TRUE);      /* Column reordering */
    m_Tree.SetOpenEnded(TRUE);           /* Last column width */
    m_Tree.SetShowHeaderButtons(TRUE);   /* Show column header as buttons */
    /* Define columns */
    {
        SFTTREE_COLUMN_EX aCol[2] = {
          { 0, 0,                        /* Reserved */
            100,                         /* Width (in pixels) */
            ES_LEFT | SFTTREE_TOOLTIP,   /* Cell alignment */
            ES_LEFT | SFTTREE_HEADER_UP, /* Title style */
            _T("First Column"),          /* Column header title */
            NULL, NULL,                  /* Reserved field and bitmap handle */
            SFTTREE_BMP_RIGHT,           /* Picture alignment */
            0, 0, 0,                     /* Reserved fields */
            SFTTREE_NOCOLOR,             /* Cell background color */
            SFTTREE_NOCOLOR,             /* Cell foreground color */
            SFTTREE_NOCOLOR,             /* Selected cell background color */
            SFTTREE_NOCOLOR,             /* Selected cell foreground color */
            0,                           /* Real column position (set by SetColumns call) */
            0,                           /* Display column number (display position) */
            SFTTREE_COL_MERGE |          /* Column can merge with next */
            SFTTREE_COL_MERGEINTO |      /* Previous column can merge into this column */
            0,                           /* Column flag */
            0,                           /* Minimum column width */
          },
          { 0, 0,                        /* Reserved */
            253,                         /* Width (in pixels) */
            ES_LEFT | SFTTREE_TOOLTIP,   /* Cell alignment */
            ES_LEFT | SFTTREE_HEADER_UP, /* Title style */
            _T("Second Column"),         /* Column header title */
            NULL, NULL,                  /* Reserved field and bitmap handle */
            SFTTREE_BMP_RIGHT,           /* Picture alignment */
            0, 0, 0,                     /* Reserved fields */
            SFTTREE_NOCOLOR,             /* Cell background color */
            SFTTREE_NOCOLOR,             /* Cell foreground color */
            SFTTREE_NOCOLOR,             /* Selected cell background color */
            SFTTREE_NOCOLOR,             /* Selected cell foreground color */
            0,                           /* Real column position (set by SetColumns call) */
            1,                           /* Display column number (display position) */
            SFTTREE_COL_MERGE |          /* Column can merge with next */
            SFTTREE_COL_MERGEINTO |      /* Previous column can merge into this column */
            0,                           /* Column flag */
            0,                           /* Minimum column width */
          }
        };
        m_Tree.SetColumns(2, aCol);      /* Set column attributes */
    }
    m_Tree.SetShowRowHeader(SFTTREE_ROWSTYLE_BUTTONCOUNT1);/* Row style */
    m_Tree.SetRowColHeaderText(_T("?"));       /* Row/column header text */
    m_Tree.SetRowColHeaderStyle(ES_LEFT | SFTTREE_HEADER_UP);/* Row/column header style */
    Sft_InitPicture(&Pic);               /* Initialize */
    Sft_SetPictureBitmap(&Pic, m_RowColBitmap);
    m_Tree.SetRowColHeaderPicture(&Pic);       /* Row/column picture */
    m_Tree.SetRowColHeaderPictureStyle(SFTTREE_BMP_RIGHT);/* Row/column picture alignment */
    m_Tree.SetDragBitmaps(TRUE);         /* Allow drag & drop from item, label pictures */
    m_Tree.SetDragType(SFTTREE_DRAG_PIXELIMM);/* Select and move by a number of pixels to start drag */
    m_Tree.SetDropHighlightStyle(SFTTREE_DROPHIGHLIGHT_ONTOP);/* Highlight drop target */

    /*------------------------------------------------------------------------------*/
    /* Add a few items.                                                             */
    /*------------------------------------------------------------------------------*/

    int i, index;

    index = m_Tree.AddString(_T("Items can be copied within this tree control."));      /* Add an item */
    index = m_Tree.AddString(_T("Item text can be copied to other applications."));      /* Add an item */
    index = m_Tree.AddString(_T("Files/folders can be dropped here (from Windows Explorer) and their names are added to the tree control."));      /* Add an item */

    for (i = 0 ; i < 30 ; ) {
        CString str;
        str.Format(_T("Item %d"), i);
        index = m_Tree.AddString(str);      /* Add an item */
        ++i;

        str.Format(_T("Item %d"), i);
        index = m_Tree.AddString(str);      /* Add another item */
        m_Tree.SetText(index, 1, _T("2nd Column"));/* Set text in next column */
        /* Set an item's row header text using: */
        m_Tree.SetRowText(index, _T(">"));   /* Row header text */
        ++i;

        str.Format(_T("Item %d"), i);
        index = m_Tree.AddString(str);      /* Add another item */
        m_Tree.SetText(index, 1, _T("2nd Column"));/* Set text in next column */
        ++i;

        str.Format(_T("Item %d"), i);
        index = m_Tree.AddString(str);      /* Add another item */
        m_Tree.SetText(index, 1, _T("2nd Column"));/* Set text in next column */
        /* Set a cell bitmap */
        SFTTREE_CELLINFOPARM CellInfo;
        CellInfo.version = 7;
        CellInfo.index = index;
        CellInfo.iCol = 1;
        m_Tree.GetCellInfo(&CellInfo);
        Sft_SetPictureBitmap(&CellInfo.Cell.CellPicture1, m_CellBitmap);
        m_Tree.SetCellInfo(&CellInfo);
        ++i;
    }

    /*------------------------------------------------------------------------------*/
    /* Once ALL TREE CONTROL ITEMS HAVE BEEN ADDED, you can set additional tree     */
    /* control attributes.                                                          */
    /*------------------------------------------------------------------------------*/

    /* Make all column widths optimal, so text and bitmaps are */
    /* not clipped horizontally.                               */
    m_Tree.MakeColumnOptimal(-1, 0, FALSE);/* Make column widths optimal */
    /* Make row header width optimal, so text and bitmaps are  */
    /* not clipped horizontally.                               */
    m_Tree.MakeRowHeaderOptimal(0, FALSE);/* Make row header width optimal */
    m_Tree.RecalcHorizontalExtent(0, FALSE);/* Update horizontal scroll bar */



    // Register this tree control as a possible drop target
    m_dropTarget.Register(&m_Tree);


    return 0;
}

void CSampleView::OnSize(UINT nType, int cx, int cy)
{
    CView::OnSize(nType, cx, cy);
    m_Tree.MoveWindow(0, 0, cx, cy);
}

/* Respond to expand/collapse requests as the user clicks  */
/* on different tree components.  The events handled here  */
/* can be changed to suit your application.                */

void CSampleView::OnLButtonExpandCollapse()
{
    /* get index of item to expand/collapse */
    int index = m_Tree.GetExpandCollapseIndex();
    /* get current expand/collapsed status */
    BOOL fExpanded = m_Tree.GetItemExpand(index);
    /* if control key is used we'll expand all dependents */
    BOOL fDepth = (::GetKeyState(VK_CONTROL)&0x8000);

    if (fExpanded)
        m_Tree.Collapse(index, TRUE);
    else
        m_Tree.Expand(index, TRUE, fDepth);
}

/* Respond to numeric keypad multiply key.                 */

void CSampleView::OnExpandAll()
{
    /* get index of item to expand/collapse */
    int index = m_Tree.GetExpandCollapseIndex();

   m_Tree.Expand(index, TRUE, TRUE);
}

void CSampleView::OnLButtonDblClkColumnResize()
{
    /* Resize column optimally */
    int realCol = m_Tree.GetResizeColumn();
    if (realCol >= 0) {
        m_Tree.MakeColumnOptimal(realCol);/* Make column width optimal */
        m_Tree.RecalcHorizontalExtent(0, FALSE);/* Update horizontal scroll bar */
    }
}

// Drag & drop support

void CSampleView::OnBeginDrag()
{
    /* Drag & drop started */

    // determine what item is being dragged
    int index = m_Tree.GetCaretIndex();
    CString str;
    m_Tree.GetText(index, 0, str);// get the item's text

    // turn off the tree's built-in drag & drop, we'll use OLE drag & drop instead
    m_Tree.SendMessage(WM_CANCELMODE);

    // use CacheData or CacheGlobalData to define the data to be moved/copied
    // In this example, the cell text of the source item is copied into a global
    // storage area
    m_dataSource.Empty();
    HGLOBAL hGlobal = ::GlobalAlloc(GHND, (str.GetLength()+1)*sizeof(TCHAR));
    if (!hGlobal)
        return;
    LPTSTR lpStr = (LPTSTR) GlobalLock(hGlobal);
    lstrcpy(lpStr, (LPCTSTR) str);// copy the cell text into the global area
    GlobalUnlock(hGlobal);
    m_dataSource.CacheGlobalData(CF_TEXT, hGlobal);

    // Initiate the OLE drag & drop, OLE mechanisms now take over (using COleDropSource
    // and COleDataSource classes defined here) and COleDropTarget in the target control/window
    m_dataSource.DoDragDrop( DROPEFFECT_COPY|DROPEFFECT_MOVE, NULL, &m_dropSource);
}


// The COleDropTarget class needs a little help so target highlighting works
// correctly.  Anytime a drag&drop ends up above the tree control, the
// COleDropTarget class handles the events.

DROPEFFECT CTreeDropTarget::OnDragEnter( CWnd* pWnd, COleDataObject* pDataObject, DWORD dwKeyState, CPoint point )
{
    if (!pWnd->IsKindOf(RUNTIME_CLASS(CSftTree)))
        return DROPEFFECT_NONE;
    CSftTree* pTree = (CSftTree*) pWnd;

    // clear drop highlight
    pTree->SetDropHighlight(-1);

    return DROPEFFECT_NONE;
}

DROPEFFECT CTreeDropTarget::OnDragOver( CWnd* pWnd, COleDataObject* pDataObject, DWORD dwKeyState, CPoint point )
{
    if (!pWnd->IsKindOf(RUNTIME_CLASS(CSftTree)))
        return DROPEFFECT_NONE;
    CSftTree* pTree = (CSftTree*) pWnd;

    // find the index of the item at the cursor position
    int index = pTree->CalcIndexFromPointEx(&point);
    if (index < 0) {
        pTree->SetDropHighlight(-1);
        return DROPEFFECT_NONE;
    }

    // if the data being dragged into the control isn't in the proper format,
    // dropping isn't possible
    if (!pDataObject->IsDataAvailable(CF_TEXT) && !pDataObject->IsDataAvailable(CF_HDROP)
                                                            )
        return DROPEFFECT_NONE;

    // determine the desired "drop" effect
    // DROPEFFECT_NONE   The data object cannot be dropped in this window.
    // DROPEFFECT_LINK for MK_CONTROL | MK_SHIFT   Creates a linkage between the object and its server.
    //  not used in this example
    // DROPEFFECT_COPY for MK_CONTROL   Creates a copy of the dropped object.
    // DROPEFFECT_MOVE for MK_ALT   Creates a copy of the dropped object and delete the original object.
    //                              This is typically the default drop effect, when the view can accept the data object.
    //  not used in this example (as it might be too destructive for illustration purposes)
    DROPEFFECT effect = DROPEFFECT_COPY;

    // set the item's drop highlight indicator (start scrolling if it's
    // an item at the top or bottom of the control
    pTree->SetDropHighlight(index, TRUE);

    return effect;
}

void CTreeDropTarget::OnDragLeave( CWnd* pWnd )
{
    if (!pWnd->IsKindOf(RUNTIME_CLASS(CSftTree)))
        return;
    CSftTree* pTree = (CSftTree*) pWnd;

    // clear drop highlight
    pTree->SetDropHighlight(-1);

    return;
}

DROPEFFECT CTreeDropTarget::OnDropEx( CWnd* pWnd, COleDataObject* pDataObject, DROPEFFECT dropDefault, DROPEFFECT dropList, CPoint point )
{
    if (!pWnd->IsKindOf(RUNTIME_CLASS(CSftTree)))
        return DROPEFFECT_NONE;
    CSftTree* pTree = (CSftTree*) pWnd;

    // determine the drop-target item
    int dropIndex = pTree->GetDropHighlight();
    // make sure InsertString adds AFTER the drop-target
    if (dropIndex >= 0)
        ++dropIndex;
    // clear drop highlight
    pTree->SetDropHighlight(-1);

    // extract the data that arrived here.  This is just a sample
    // and is very application specific.
    STGMEDIUM StgMedium;
    CFile*pFile = pDataObject->GetFileData(CF_TEXT, NULL);
    if (pFile) {
        // the data is in CF_TEXT format, just add the text as a new item at
        // the insertion point
        TCHAR szBuffer[256];
        pFile->Read(szBuffer, sizeof(szBuffer)/sizeof(TCHAR));

        int index = pTree->InsertString(dropIndex, szBuffer);
        pTree->SetCaretIndex(index);
        pTree->SetCurSel(index);
        ++dropIndex;

        delete pFile;
    } else if (pDataObject->GetData(CF_HDROP, &StgMedium, NULL) && StgMedium.tymed == TYMED_HGLOBAL) {
        // the data is in CF_HDROP format (a list of files from Windows Explorer),
        // just add each new item at the insertion point
        TCHAR szBuffer[_MAX_PATH];
        int nFiles = DragQueryFile((HDROP)StgMedium.hGlobal, -1, NULL, 0); // get # of files
        for (int i = 0 ; i < nFiles ; ++i) {
            // extract one file
            DragQueryFile((HDROP)StgMedium.hGlobal, i, szBuffer, sizeof(szBuffer)/sizeof(TCHAR)); // get file name
            // insert it as a new item in the tree control
            int index = pTree->InsertString(dropIndex, szBuffer);
            pTree->SetCaretIndex(index);
            pTree->SetCurSel(index);
            ++dropIndex;
        }
    }

    return DROPEFFECT_COPY;
}

// The COleDropSource default implementation works just fine.
// The COleDropSource class can be used to control the
// drag & drop behaviour when the tree control is the
// origin of a drag & drop

SCODE CTreeDropSource::GiveFeedback(DROPEFFECT dropEffect)
{
    return COleDropSource::GiveFeedback(dropEffect);
}

BOOL CTreeDropSource::OnBeginDrag(CWnd* pWnd)
{
    return COleDropSource::OnBeginDrag(pWnd);
}

SCODE CTreeDropSource::QueryContinueDrag(BOOL bEscapePressed, DWORD dwKeyState)
{
    return COleDropSource::QueryContinueDrag(bEscapePressed, dwKeyState);
}