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 » CExtTreeCtrl and TVN_BEGINLABELEDIT Collapse All
Subject Author Date
Jeroen Walter Nov 18, 2009 - 5:41 AM

Hi


using profuis 2.85:


 


I want to be able to selectively allow or prohibit the editing of a label in the CExtTreeCtrl.


For this I thought the notification TVN_BEGINLABELEDIT should be used.


However, the CExtTreeCtrl doesn’t use TVN_BEGINLABELEDIT and TVN_ENDLABELEDIT notifications.


Instead it breaks the notification mechanism by calling EditLabel somewhere in its message spy hook thingy.


For the TVN_ENDLABELEDIT this is fixed by calling the virtual method OnInplaceControlComplete.


However, for the TVN_BEGINLABELEDIT there is no such callback.


CExtTreeCtrl::OnInplaceControlCreate would seem the logical counterpart, but is not called for label editing, only for the additional control.


Could you please fix CExtCtrl so we can have the behavior back that is available in a normal tree ctrl?


It’s nice to have a tree ctrl with extended functionality and skinning, but it’s nicer to have one that actually functions like the default CTreeCtrl from which it is derived....


For instance, call OnInplaceControlCreate with an additional parameter pEditingLabel like in OnInplaceControlComplete.


 


Kind regards


 


Jeroen Walter


Ellips B.V.


 


 


 


 

Technical Support Nov 23, 2009 - 9:36 AM

We added the TVN_BEGINLABELEDIT / TVN_ENDLABELEDIT notifications. Please update the source code for the following methods:

 LRESULT CExtTreeCtrl::WindowProc( UINT message, WPARAM wParam, LPARAM lParam )
{
            switch( message )
            {
            case TVM_EDITLABEL:
                        {
                                    KillTimer( m_nDelayedEditingTimerID );
                                    m_wndContentExpand.Deactivate();
                                    HTREEITEM hti = (HTREEITEM)lParam; //GetFocusedItem();
                                    if(                     hti == NULL
                                                ||           (! HasItem( hti ) )
                                                )
                                                return LRESULT(NULL);
                                    SendMessage( WM_CANCELMODE );
                                    EnsureVisible( hti );

                                    HWND hWndParent = ::GetParent( m_hWnd );
                                    UINT nOwnID = GetDlgCtrlID();
                                    CExtSafeString strItemText;
                                    TV_DISPINFO _data;
                                    ::memset( &_data, 0, sizeof(TV_DISPINFO) );
                                    _data.hdr.hwndFrom = m_hWnd;
                                    _data.hdr.idFrom = nOwnID;
                                    _data.hdr.code = TVN_BEGINLABELEDIT;
                                    _data.item.mask = TVIF_CHILDREN|TVIF_HANDLE|TVIF_PARAM|TVIF_STATE;
                                    _data.item.hItem = hti;
                                    GetItem( &_data.item );
                                    strItemText = GetItemText( hti );
                                    _data.item.cchTextMax = INT(strItemText.GetLength());
                                    _data.item.pszText = strItemText.IsEmpty() ? _T("") : LPTSTR(LPCTSTR(strItemText));
                                    _data.item.mask |= TVIF_TEXT;
                                    if( ::SendMessage( hWndParent, WM_NOTIFY, WPARAM(nOwnID), LPARAM(&_data) ) != 0 )
                                                return TRUE;

                                    CRect rcLabel;
                                    if( ! TreeItemRectGet( hti, rcLabel, e_tirt_label ) )
                                                return LRESULT(NULL);
                                    rcLabel.right += 6;
                                    CExtSafeString s;
                                    const TREEITEMINFO_t & _TII = TreeItemInfoGet( hti );
                                    CInplaceEdit * pEdit = new CInplaceEdit( true );
                                    if( ! pEdit->Create(
                                                            WS_CHILD | WS_VISIBLE
                                                                        | WS_CLIPSIBLINGS | ES_AUTOHSCROLL | ES_WANTRETURN
                                                                        | ( ReadOnlyLabelsGet() ? ES_READONLY : 0 )
                                                                        | _TII.m_dwAdditionalLabelEditorStyles
                                                                        ,
                                                            rcLabel,
                                                            this,
                                                            UINT(IDC_STATIC)
                                                            )
                                                )
                                                return LRESULT(NULL);

                                    CFont * pFont = NULL;
                                    pFont = OnQueryItemFont( hti );
                                    if( pFont == NULL )
                                                pFont = GetFont();
                                    pEdit->SetFont( pFont );
                                    s = GetItemText( hti );
                                    pEdit->SetWindowText( s );
                                    pEdit->SetSel(0, -1);
                                    pEdit->SetFocus();
                                    m_hWndChildControl = pEdit->m_hWnd;
                                    if( m_hWndChildControl != NULL )
                                                m_htiInplaceEdited = hti;
                        }
                        // continue falling:
            case TVM_GETEDITCONTROL:
                        return LRESULT(m_hWndChildControl);
            case WM_NCLBUTTONDOWN:
            case WM_NCMBUTTONDOWN:
            case WM_NCRBUTTONDOWN:
                        SendMessage( WM_CANCELMODE );
                        if( ::GetFocus() != m_hWnd )
                                    SetFocus();
            break;
            case TVM_SETINSERTMARK:
            {
                        m_bInsertMarkAfter = ( wParam != 0 ) ? true : false;
                        HTREEITEM htiInsertMarkOld = m_htiInsertMark;
                        m_htiInsertMark = (HTREEITEM) lParam;
                        if( ! HasItem( m_htiInsertMark ) )
                                    m_htiInsertMark = NULL;
                        if( htiInsertMarkOld != m_htiInsertMark && IsWindowVisible() )
                                    Invalidate();
            }
            break;
            case TVM_SETINSERTMARKCOLOR:
                        if( IsWindowVisible() )
                                    Invalidate();
            break;
            } // switch( message )
LRESULT lResult = CTreeCtrl::WindowProc( message, wParam, lParam );
            switch( message )
            {
            case WM_COMMAND:
                        m_wndContentExpand.Deactivate();
                        if(                     HIWORD(wParam) == CBN_KILLFOCUS
                                    &&        m_hWndChildControl == ((HWND)lParam)
                                    )
                        {
                                    SendMessage( WM_CANCELMODE );
                        }
            break;
            case TVM_INSERTITEM:
            {
                        m_wndContentExpand.Deactivate();
                        if( m_hWndChildControl != NULL )
                                    SendMessage( WM_CANCELMODE );
                        HTREEITEM hti = (HTREEITEM)lResult;
                        if( hti != NULL )
                                    m_mapItemInfo.SetAt( hti, new TREEITEMINFO_t );
            }
            break;
            case TVM_DELETEITEM:
            {
                        HTREEITEM hti = (HTREEITEM)lParam;
                        if( m_htiDelayedFocus == hti )
                        {
                                    m_htiDelayedFocus = NULL;
                                    KillTimer( m_nDelayedFocusTimerID );
                                    KillTimer( m_nDelayedEditingTimerID );
                        }
                        m_wndContentExpand.Deactivate();
                        if( m_hWndChildControl != NULL )
                                    SendMessage( WM_CANCELMODE );
                        _UnregisterItemsFromMap( hti );
#ifdef _DEBUG
                        if( hti == NULL || hti == TVI_ROOT )
                        {
                                    ASSERT( m_mapItemInfo.GetCount() == 0 );
                        }
#endif // _DEBUG
            }
            break;
            case TVM_EXPAND:
                        m_wndContentExpand.Deactivate();
            break;
            } // switch( message )
            return lResult;
}

void CExtTreeCtrl::OnInplaceControlComplete(
            __EXT_MFC_SAFE_LPCTSTR strEditedText,
            bool bEditingLabel
            )
{
            ASSERT_VALID( this );
HTREEITEM hti = GetInPlaceEditedItem();
            if( hti == NULL )
                        return;
            if( ! bEditingLabel )
            {
                        TREEITEMINFO_t & _TII = TreeItemInfoGet( hti );
                        _TII.m_strEditText = LPCTSTR(strEditedText);
            } // if( ! bEditingLabel )
            else
            {
                        HWND hWndParent = ::GetParent( m_hWnd );
                        UINT nOwnID = GetDlgCtrlID();
                        CExtSafeString strItemText;
                        TV_DISPINFO _data;
                        ::memset( &_data, 0, sizeof(TV_DISPINFO) );
                        _data.hdr.hwndFrom = m_hWnd;
                        _data.hdr.idFrom = nOwnID;
                        _data.hdr.code = TVN_ENDLABELEDIT;
                        _data.item.mask = TVIF_CHILDREN|TVIF_HANDLE|TVIF_PARAM|TVIF_STATE;
                        _data.item.hItem = hti;
                        GetItem( &_data.item );
                        strItemText = GetItemText( hti );
                        if( strItemText == LPCTSTR(strEditedText) )
                        {
                                    _data.item.cchTextMax = 0;
                                    _data.item.pszText = 0;
                        }
                        else
                        {
                                    _data.item.cchTextMax = INT(strItemText.GetLength());
                                    _data.item.pszText = strItemText.IsEmpty() ? _T("") : LPTSTR(LPCTSTR(strItemText));
                                    _data.item.mask |= TVIF_TEXT;
                        }
                        if( ::SendMessage( hWndParent, WM_NOTIFY, WPARAM(nOwnID), LPARAM(&_data) ) != 0 )
                                    return;

                        SetItemText( hti, LPCTSTR(strEditedText) );
            } // else from if( ! bEditingLabel )
}

Jeroen Walter Nov 24, 2009 - 3:19 AM

Thanks.


It’s almost correct, as the msdn documentation of TVN_ENDLABELEDIT states:


"Return Value


If the pszText member is non-NULL, return TRUE to set the item’s label to the edited text. Return FALSE to reject the edited text and revert to the original label."

So the if-statement around the SendMessage for TVN_ENDLABELEDIT is incorrect, it should return if SendMessage returns FALSE instead of TRUE.


 


 

Technical Support Nov 24, 2009 - 2:07 PM

Yes, you are right. Here is the correct version:

void CExtTreeCtrl::OnInplaceControlComplete(
            __EXT_MFC_SAFE_LPCTSTR strEditedText,
            bool bEditingLabel
            )
{
            ASSERT_VALID( this );
HTREEITEM hti = GetInPlaceEditedItem();
            if( hti == NULL )
                        return;
            if( ! bEditingLabel )
            {
                        TREEITEMINFO_t & _TII = TreeItemInfoGet( hti );
                        _TII.m_strEditText = LPCTSTR(strEditedText);
            } // if( ! bEditingLabel )
            else
            {
                        HWND hWndParent = ::GetParent( m_hWnd );
                        UINT nOwnID = GetDlgCtrlID();
                        CExtSafeString strItemText;
                        TV_DISPINFO _data;
                        ::memset( &_data, 0, sizeof(TV_DISPINFO) );
                        _data.hdr.hwndFrom = m_hWnd;
                        _data.hdr.idFrom = nOwnID;
                        _data.hdr.code = TVN_ENDLABELEDIT;
                        _data.item.mask = TVIF_CHILDREN|TVIF_HANDLE|TVIF_PARAM|TVIF_STATE;
                        _data.item.hItem = hti;
                        GetItem( &_data.item );
                        strItemText = GetItemText( hti );
                        bool bModeNotNULL = true;
                        if( strItemText == LPCTSTR(strEditedText) )
                        {
                                    bModeNotNULL = false;
                                    _data.item.cchTextMax = 0;
                                    _data.item.pszText = 0;
                        }
                        else
                        {
                                    _data.item.cchTextMax = INT(strItemText.GetLength());
                                    _data.item.pszText = strItemText.IsEmpty() ? _T("") : LPTSTR(LPCTSTR(strItemText));
                                    _data.item.mask |= TVIF_TEXT;
                        }
                        if( ! ::SendMessage( hWndParent, WM_NOTIFY, WPARAM(nOwnID), LPARAM(&_data) ) != 0 )
                        {
                                    if( bModeNotNULL )
                                                return;
                        }

                        SetItemText( hti, LPCTSTR(strEditedText) );
            } // else from if( ! bEditingLabel )
}



Jeroen Walter Nov 26, 2009 - 2:07 AM

Thanks.

Technical Support Nov 18, 2009 - 12:34 PM

The CExtTreeCtrl control is completely re-painted version of tree view common control with a set of unique features. We had to handle all the mouse/keyboard input in it for implementing its extended features. As result, we also had to implement emulations for standard TVN_*** notifications. The best approach to implement selective item editing is to enable editing of all the item labels and override the CExtTreeCtrl::OnInplaceControlCreate() virtual method. Your method should return NULL for non-editable tree items and invoke parent class method in other case.


Lars Mohr Nov 19, 2009 - 5:00 AM

The CExtTreeCtrl::OnInplaceControlCreate virtual methode will call only if you want to editing the lable of the control not of the item themselfes.



            if( ( dwHitTestFlags & __EXT_TVHT_ONCONTROL ) != 0 )
            {
                CRect rcControl;
                VERIFY( TreeItemRectGet( hti, rcControl, e_tirt_control ) );
                ASSERT( ! rcControl.IsRectEmpty() );
                if( m_hWndChildControl != NULL )
                {
                    CRect rc;
                    ::GetWindowRect( m_hWndChildControl, &rc );
                    if( rc == rcControl )
                        return true;
                    SendMessage( WM_CANCELMODE );
                }
                m_hWndChildControl = OnInplaceControlCreate( hti, rcControl );
                if( m_hWndChildControl != NULL )
                    m_htiInplaceEdited = hti;
                return true;
            }


 

Technical Support Nov 19, 2009 - 1:52 PM

Yes, you are right. The CExtTreeCtrl::WindowProc() virtual method and handles the TVM_EDITLABEL message and runs the in-place activate label editor window. You should override this virtual method in your CExtTreeCtrl-derived class, catch the TVM_EDITLABEL message and not invoke the parent class method for non-editable labels. The LPARAM parameter is the HTREEITEM handle for label editing.

Jeroen Walter Nov 23, 2009 - 3:55 AM

Thanks, I already saw that option in the code, but again, it relies on knowing the implementation of the CExtTreeCtrl, which may change in next releases of profuis, so for me it’s a bad idea.


"As result, we also had to implement emulations for standard TVN_*** notifications."


Clearly the emulation is not complete.


I will try your suggestion though, but I still think that you should’ve emulated the default tree ctrl behaviour better.

Lars Mohr Nov 18, 2009 - 6:21 AM

Hi,


I solved the problem with the OnTimer function and the nIDEvent == m_nDelayedEditingTimerID Event ID.


Best regards

Jeroen Walter Nov 18, 2009 - 6:39 AM

Not an option. It implies knowledge about the internal working of the CExtTreeCtrl, which may be different in a next release.


For me, clearly, the interface of CExtTreeCtrl is lacking features and default CTreeCtrl behavior is broken.