Hide

SftTree/DLL 7.5 - Tree Control

Display
Print

CellEditing Sample (C++)

This sample illustrates cell editing using an edit control and a combo box, with cell navigation and restricted cells.

The source code is located at C:\Program Files (x86)\Softelvdm\SftTree DLL 7.5\Samples\MFC\CellEditing\SamplVw.cpp or C:\Program Files\Softelvdm\SftTree DLL 7.5\Samples\MFC\CellEditing\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 "CellEditing.h"
#include "sampldoc.h"
#include "samplvw.h"

/////////////////////////////////////////////////////////////////////////////
// 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_LBUTTONDOWN_TEXT(IDC_TREE, OnStartEdit)
    ON_SFTTREEN_QUITEDIT(IDC_TREE, OnQuitEdit)
    ON_SFTTREEN_VALIDATEEDIT(IDC_TREE, OnValidateEdit)
    ON_SFTTREEN_KEYINTERCEPTED(IDC_TREE, OnKeyIntercepted)
END_MESSAGE_MAP()

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

CSampleView::CSampleView()
{
    m_pEdit = NULL;                      /* No cell editing */
    m_pCombo = NULL;
}

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_LEFTBUTTONONLY |    /* Only respond to left mouse button */
        SFTTREESTYLE_SCROLL |            /* Honor WS_H/VSCROLL */
        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_AUTOMATIC0);/* Dotted or invisible tree lines (incl. level 0) */
    m_Tree.SetShowButtons(FALSE);        /* Expand/collapse buttons (level 1..n) */
    m_Tree.SetShowButton0(TRUE);         /* Show expand/collapse buttons (level 0) */
    m_Tree.SetButtons(SFTTREE_BUTTON_AUTOMATIC3);/* Automatic button style 3 */
    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.SetSelectionStyle(SFTTREE_SELECTION_CELL1 | SFTTREE_SELECTION_OUTLINE);/* Select first cell only using outline */
    m_Tree.SetSelectionArea(SFTTREE_SELECTIONAREA_ALLCELLS);/* Selection changes by clicking on an item's cells */
    m_Tree.SetFlyby(TRUE);               /* Flyby highlighting */
    m_Tree.SetUpdateCaretExpandCollapse(FALSE);/* don't update caret location when expand/collapse button clicked */
    m_Tree.SetScrollTips(TRUE);          /* Show Scrolltips */
    m_Tree.SetInheritBgColor(TRUE);      /* Inherit background color of first cell */
    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[3] = {
          { 0, 0,                        /* Reserved */
            221,                         /* 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) */
            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) */
            0,                           /* Column flag */
            0,                           /* Minimum column width */
          },                             
          { 0, 0,                        /* Reserved */
            100,                         /* Width (in pixels) */
            ES_LEFT | SFTTREE_TOOLTIP,   /* Cell alignment */
            ES_LEFT | SFTTREE_HEADER_UP, /* Title style */
            _T("Third 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) */
            2,                           /* Display column number (display position) */
            0,                           /* Column flag */
            0,                           /* Minimum column width */
          }                              
        };
        m_Tree.SetColumns(3, 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 */
    m_RowColBitmap.LoadBitmap(IDB_SMILE);/* Cell picture */
    Sft_SetPictureBitmap(&Pic, m_RowColBitmap);
    m_Tree.SetRowColHeaderPicture(&Pic);       /* Row/column picture */
    m_Tree.SetRowColHeaderPictureStyle(SFTTREE_BMP_RIGHT);/* Row/column picture alignment */
    m_Tree.SetCharSearchMode(SFTTREE_CHARSEARCH_ALLCHARSWRAP2, -1);/* Consider all characters typed, find next item, wrap around, don't expand */
    /* Change the default colors */
    {
        SFTTREE_COLORS Colors;
        m_Tree.GetCtlColors(&Colors);    /* Get current color settings */
        Colors.colorTreeLines = COLOR_3DDKSHADOW | 0x80000000L;/* Tree line color */
        Colors.colorSelBgNoFocus = COLOR_BTNFACE | 0x80000000L;/* Selection background color (no input focus) */
        Colors.colorSelFgNoFocus = COLOR_BTNTEXT | 0x80000000L;/* Selection foreground color (no input focus) */
        m_Tree.SetCtlColors(&Colors);    /* Set new colors */
    }

    /*------------------------------------------------------------------------------*/
    /* Add a few items.                                                             */
    /*------------------------------------------------------------------------------*/
    
    {
        int index;
        index = m_Tree.AddString(TEXT("Click on a cell to edit"));/* Add an item */
        m_Tree.SetText(index, 1, TEXT("Use Tab/Return keys"));/* Set text in next column */
        m_Tree.SetText(index, 2, TEXT("Use arrow keys"));/* Set text in next column */
        index = m_Tree.AddString(TEXT("This sample supports cell navigation"));/* Add an item */
        m_Tree.SetText(index, 1, TEXT("Ctrl+Home and Ctrl+End"));/* Set text in next column */
    }

    for (int i = 0 ; i < 50 ; ++i) {
        int index;

        index = m_Tree.AddString(_T("An item"));/* Add an item */
        m_Tree.SetText(index, 1, _T("2nd Column"));/* Set text in next column */
        m_Tree.SetText(index, 2, _T("3rd Column"));/* Set text in next column */

        index = m_Tree.AddString(_T("Another item"));/* Add another item */
        m_Tree.SetText(index, 1, _T("2nd Column"));/* Set text in next column */
        m_Tree.SetText(index, 2, _T("3rd Column"));/* Set text in next column */
        m_Tree.SetItemLevel(index, 1);/* change level */

        index = m_Tree.AddString(_T("This item can't be edited"));/* Add another item */
        m_Tree.SetItemEditIgnore(index, TRUE);
        m_Tree.SetItemLevel(index, 2);/* change level */
        m_Tree.SetText(index, 1, _T("2nd Column (can't edit this item)"));/* Set text in next column */
        m_Tree.SetText(index, 2, _T("3rd Column (can't edit this item)"));/* Set text in next column */

        index = m_Tree.AddString(_T("A fourth item"));/* Add another item */
        m_Tree.SetItemLevel(index, 1);/* change level */
        m_Tree.SetText(index, 1, _T("This cell can't be edited"));/* Set text in next column */

        SFTTREE_CELLINFOPARM CellInfo;
        CellInfo.version = 7;
        CellInfo.index = index;
        CellInfo.iCol = 1;
        m_Tree.GetCellInfo(&CellInfo);
        CellInfo.Cell.flag2 |= SFTTREECELL_EDITIGNORE; // can't edit this column
        m_Tree.SetCellInfo(&CellInfo);

        m_Tree.SetText(index, 2, _T("3rd Column"));/* Set text in next column */

        /* Set a cell bitmap */
        CellInfo.version = 7;
        CellInfo.index = index;
        CellInfo.iCol = 1;
        m_Tree.GetCellInfo(&CellInfo);
        Sft_SetPictureBitmap(&CellInfo.Cell.CellPicture1, m_CellBitmap);
        m_Tree.SetCellInfo(&CellInfo);
    }

    /*------------------------------------------------------------------------------*/
    /* 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 */

    m_Tree.SetCurSel(0); // select the first item
    m_Tree.SetCaretIndex(0); // and make it current

    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 */
    }
}

/* These routines handle item data editing. In this        */
/* example, an edit control is used. Any Windows control   */
/* can be used, even custom controls.                      */

void CSampleView::OnLButtonDownText()
{
    int index, col;
    index = m_Tree.GetCaretIndex();/* Get item index */
    col = m_Tree.GetCaretColumn();/* Get column number */
    StartEdit(index, col);
}

/* Start editing in response to a                          */
/* SFTTREEN_LBUTTONDOWN_TEXT notification.                 */

void CSampleView::StartEdit(int index, int col)
{
    CRect rect;

    /* Make the cell completely visible */
    m_Tree.MakeCellVisible(index, col);
    /* get the item location */
    if (!m_Tree.GetDisplayCellRect(index, col, TRUE, &rect, NULL))
        return;                          /* No column active */

    if (m_Tree.GetItemEditIgnore(index))
        return; // this item can't be edited
    SFTTREE_CELLINFOPARM CellInfo;
    CellInfo.version = 7;
    CellInfo.index = index;
    CellInfo.iCol = col;
    m_Tree.GetCellInfo(&CellInfo);
    if (CellInfo.Cell.flag2 & SFTTREECELL_EDITIGNORE)
        return; // this item can't be edited

    m_editIndex = index; /* save position */
    m_editCol = col;

    m_Tree.SetCurSel(index); // <<<< added:  selection follows item being edited
    m_Tree.SetCaretIndex(index); // <<<< added:  selection follows item being edited

    /* Change selection style to not shown anything */
    m_Tree.SetNoFocusStyle(SFTTREE_NOFOCUS_NOTHING);

    /* Copy the text found in the tree control */
    CString str;
    m_Tree.GetText(m_editIndex, m_editCol, str);

    m_Tree.AdjustCellEditRect(m_editIndex, m_editCol, &rect);
    CWnd* pEditParent = m_Tree.GetCellEditWindow(m_editIndex, m_editCol);

    // based on font height, get best height for the control used for cell editing
    CFont* pFont = m_Tree.GetFont();

    int diff;
    TEXTMETRIC tm;
    CDC* pDC = GetDC();    
    CFont* pFontOld = (CFont*) pDC->SelectObject(pFont);
    pDC->GetTextMetrics(&tm); // Get Font Information
    pDC->SelectObject(pFontOld);
    ReleaseDC(pDC);

    diff = (tm.tmHeight + 5) - (rect.bottom-rect.top);
    rect.InflateRect(0, (diff+1)/2);
    int height;
    height = rect.bottom-rect.top;

    if (col != 1) {
        /* Create the edit control.*/
        /* Based on the tree control attributes and your preference, you may */
        /* have to adjust the rectangle used for the edit control. */

        m_pEdit = new CEdit;
        m_pEdit->Create(
                WS_CHILD|WS_BORDER|ES_LEFT|ES_AUTOHSCROLL, /* Styles */
                rect,                        /* Coordinates */
                pEditParent,                 /* Parent window */
                IDC_EDIT);                  /* <-- provide unique ID */

        /* Set some edit control attributes */
        m_pEdit->SetWindowText(str);
        /* Set the font defined for cell editing */
        m_pEdit->SetFont(pFont, FALSE);
        /* Select all text in the edit control and display it */
        m_pEdit->LimitText(80);
        m_pEdit->SetSel(0, -1, TRUE);
        m_pEdit->ShowWindow(SW_SHOW);
        m_pEdit->SetFocus();                /* Set input focus to the control */
    } else {
        /* Create the combo box */
        RECT comboRect;
        comboRect = rect;
        comboRect.bottom = comboRect.top + (comboRect.bottom-comboRect.top)*8;
        m_pCombo = new CComboBox;
        m_pCombo->Create(WS_CHILD|WS_BORDER|WS_VSCROLL|CBS_DROPDOWN|CBS_AUTOHSCROLL, /* Styles */
                comboRect,
                pEditParent,                 /* Tree control */
                IDC_COMBO);                  /* <-- provide unique ID */

        /* Set the font defined for cell editing */
        m_pCombo->SetFont(pFont, FALSE);

        // Add possible selections
        m_pCombo->AddString(_T("Selection 1"));
        m_pCombo->AddString(_T("Selection 2"));
        m_pCombo->AddString(_T("Selection 3"));
        m_pCombo->SetWindowText(str);

        m_pCombo->LimitText(80);
        m_pCombo->SetItemHeight(-1, rect.bottom-rect.top-5);

        m_pCombo->ShowWindow(SW_SHOW);
        m_pCombo->SetFocus();                /* Set input focus to the control */
        m_pCombo->ShowDropDown();
    }

    // The following has been added to support key handling while cell editing
    // It is used to define keys to be intercepted
    {
        BYTE KeyTable[256];
        m_Tree.GetKeyHandling(KeyTable, NULL, NULL);
        KeyTable[VK_TAB] = (SFTTREE_HANDLEPURE|SFTTREE_HANDLESHIFT|SFTTREE_HANDLECTRL);// handle Tab key
        KeyTable[VK_RETURN] = (SFTTREE_HANDLEPURE|SFTTREE_HANDLESHIFT|SFTTREE_HANDLECTRL);// handle Return key
        KeyTable[VK_HOME] = (SFTTREE_HANDLECTRL);// handle Control+Home key
        KeyTable[VK_END] = (SFTTREE_HANDLECTRL);// handle Control+End key
        if (m_pCombo) {
            KeyTable[VK_UP] = 0;                // don't handle Up arrow key
            KeyTable[VK_DOWN] = 0;              // don't handle Down arrow key
        } else {
            KeyTable[VK_UP] = (SFTTREE_HANDLEPURE);// handle Up arrow key
            KeyTable[VK_DOWN] = (SFTTREE_HANDLEPURE);// handle Down arrow key
        }
        m_Tree.SetKeyHandling(KeyTable);
    }

    m_Tree.UpdateWindow();
}

void CSampleView::OnStartEdit()
{
    /* Get cell to edit (honors cell merging) */
    int index, col;
    index = m_Tree.GetCaretIndex();      /* Get item index */
    col = m_Tree.GetCaretColumn();       /* Get column number */
    StartEdit(index, col);
}

void CSampleView::CellNavigation(TCHAR vKey, BYTE vMask)
{
    // Here we handle special keys to implement cell editing with 
    // cell navigation. Cell navigation is not automatic, but using this 
    // sample code, a sophisticated editing scheme can be easily implemented, 
    // even with skipped columns, hidden columns, collapsed items, etc. 
    // Keep in mind that col is a REAL column number, but we have 
    // to deal in DISPLAY columns as the user may have reordered the 
    // columns. When using cell navigation, we want to move through the 
    // displayed columns 

    // Please note that cell merging is not supported.

    int index = m_editIndex, col = m_editCol;
    int dispCol, firstDispCol, lastDispCol;
    LPSFTTREE_COLUMN_EX lpCol;
    int nCols; 
    int lastShown = m_Tree.GetPrevShown(-1);

    // get general information about tree control and columns
    nCols = m_Tree.GetColumns(&lpCol);/* Get column attributes */ 
    dispCol = m_Tree.GetDisplayColumn(col);
    firstDispCol = m_Tree.GetFirstDisplayColumn();
    lastDispCol = m_Tree.GetLastDisplayColumn();

    if (vKey == VK_HOME && (vMask & SFTTREE_HANDLECTRL)) {  // Control+Home
        index = 0;
        dispCol = firstDispCol;
        vKey = VK_RIGHT; // if index/dispCol can't be edited, search a cell in this direction:
    } else if (vKey == VK_END && (vMask & SFTTREE_HANDLECTRL)) {  // Control+End
        index = m_Tree.GetPrevShown(-1);
        dispCol = lastDispCol;
        vKey = VK_LEFT; // if index/dispCol can't be edited, search a cell in this direction:
    } else if ((vKey == VK_LEFT && (vMask & SFTTREE_HANDLEPURE)) || (vKey == VK_TAB && (vMask & SFTTREE_HANDLESHIFT))) { // Left Arrow or Shift+Tab
        dispCol--;
        vKey = VK_LEFT; // if index/dispCol can't be edited, search a cell in this direction:
    } else if ((vKey == VK_RIGHT || vKey == VK_TAB) && (vMask & SFTTREE_HANDLEPURE)) { // Right Arrow or Tab
        dispCol++;
        vKey = VK_RIGHT; // if index/dispCol can't be edited, search a cell in this direction:
    } else if (vKey == VK_RETURN && (vMask & SFTTREE_HANDLEPURE)) { // Return
        dispCol++;
        vKey = VK_RIGHT; // if index/dispCol can't be edited, search a cell in this direction:
    } else if (vKey == VK_UP && (vMask & SFTTREE_HANDLEPURE)) { // Up arrow
        index--;
    } else if (vKey == VK_DOWN && (vMask & SFTTREE_HANDLEPURE)) { // Down arrow
        index++;
    } else 
        return; // this key is not handled

    // index, dispCol has possible cell coordinates.  If this cell can't be
    // edited, proceed in vKey direction (VK_UP,VK_LEFT,VK_DOWN,VK_RIGHT only)
    // until a suitable cell is found or until we hit m_editIndex, m_editCol.

    for ( ; ; ) {
        // position to a valid cell
        if (dispCol < firstDispCol) {
            index = m_Tree.GetPrevShown(index);// try previous item 
            dispCol = lastDispCol;
        }
        if (dispCol > lastDispCol) {
            index = m_Tree.GetNextShown(index);// try next item 
            if (index < 0)
                index = 0;
            dispCol = firstDispCol;
        }
        if (index < 0)
            index = lastShown;
        if (index > lastShown)
            index = 0;

        col = m_Tree.GetRealColumn(dispCol);

        // make sure the item is shown
        if (m_Tree.GetItemShown(index)) {
            // make sure the column is really displayed 
            if (lpCol[col].width > 0) {

                // back at m_editIndex, m_editCol?
                if (m_editIndex == index && m_editCol == col) {
                    StartEdit(index, col);
                    return;
                }

                // check if item ignored
                if (!m_Tree.GetItemEditIgnore(index)) {
                    // item not ignored
                    // check if cell ignored
                    SFTTREE_CELLINFOPARM CellInfo;
                    CellInfo.version = 7;
                    CellInfo.index = index; 
                    CellInfo.iCol = col; 
                    m_Tree.GetCellInfo(&CellInfo);
                    if ((CellInfo.Cell.flag2 & SFTTREECELL_EDITIGNORE) == 0) {
                        // cell not ignored
                        StartEdit(index, col);
                        return;
                    }
                }
            }
        }

        // next cell
        if (vKey == VK_LEFT) {
            --dispCol;
        } else if (vKey == VK_RIGHT) {
            ++dispCol;
        } else if (vKey == VK_UP) {
            --index;
        } else if (vKey == VK_DOWN) {
            ++index;
        }
    }
}

/* Quit editing in response to a SFTTREEN_QUITEDIT         */
/* notification.                                           */

void CSampleView::OnQuitEdit()
{
    /* If the control has the focus, set the focus back to the */
    /* tree control after destroying the control */
    BOOL fHadFocus = (GetFocus() == m_pEdit || GetFocus() == m_pCombo);

    if (m_pEdit) {
        m_pEdit->DestroyWindow();
        delete m_pEdit;
        m_pEdit = NULL;
    } else if (m_pCombo) {
        m_pCombo->DestroyWindow();
        delete m_pCombo;
        m_pCombo = NULL;
    }
    /* Restore nofocus display method */
    m_Tree.SetNoFocusStyle(SFTTREE_NOFOCUS_KEEPSEL);
    if (fHadFocus)
        m_Tree.SetFocus();
}

/* Validate edit data in response to a                     */
/* SFTTREEN_VALIDATEEDIT notification.                     */

void CSampleView::OnValidateEdit()
{
    CString str;

    if (m_pEdit) {
        /* Get the text from the edit control */
        m_pEdit->GetWindowText(str);

        /* Validate the data */
        if (str == _T("")) {
            AfxMessageBox(_T("Just to demonstrate data input validation, this example rejects empty cells.  Please enter some data."));
            m_pEdit->SetFocus();
            return;
        } else {
            m_pEdit->DestroyWindow();
            delete m_pEdit;
            m_pEdit = NULL;
        }
    } else {
        /* Get the text from the combo control */
        m_pCombo->GetWindowText(str);
        m_pCombo->GetWindowText(str);

        /* Validate the data */
        if (str == _T("")) {
            AfxMessageBox(_T("Just to demonstrate data input validation, this example rejects empty cells.  Please enter some data."));
            m_pEdit->SetFocus();
            return;
        } else {
            m_pCombo->DestroyWindow();
            delete m_pCombo;
            m_pCombo = NULL;
        }
    }
    /* Save the data in the tree control */
    m_Tree.SetText(m_editIndex, m_editCol, str);
    /* Restore nofocus display method */
    m_Tree.SetNoFocusStyle(SFTTREE_NOFOCUS_KEEPSEL);
}

// The following has been added to support key handling while cell editing

void CSampleView::OnKeyIntercepted()
{
    TCHAR vKey;
    BYTE vMask;
    m_Tree.GetKeyHandling(NULL, &vKey, &vMask);
    switch (vKey) {
    case VK_TAB:            // Tab key
    case VK_RETURN:         // Return key
    case VK_UP:             // Up arrow key
    case VK_DOWN:           // Down arrow key
    case VK_HOME:           // Home key
    case VK_END:            // End key
        OnValidateEdit();   // validate the contents
        if (CellEditing())  // we're still editing (validation failed)
            break;
        CellNavigation(vKey, vMask);
        break;
    }
}