1/////////////////////////////////////////////////////////////////////////////
2// Name:        treebase.cpp
3// Purpose:     Base wxTreeCtrl classes
4// Author:      Julian Smart
5// Created:     01/02/97
6// Modified:
7// Id:          $Id: treebase.cpp 51356 2008-01-24 11:23:30Z VZ $
8// Copyright:   (c) 1998 Robert Roebling, Julian Smart et al
9// Licence:     wxWindows licence
10/////////////////////////////////////////////////////////////////////////////
11
12// =============================================================================
13// declarations
14// =============================================================================
15
16// -----------------------------------------------------------------------------
17// headers
18// -----------------------------------------------------------------------------
19
20// For compilers that support precompilation, includes "wx.h".
21#include "wx/wxprec.h"
22
23#ifdef __BORLANDC__
24    #pragma hdrstop
25#endif
26
27#if wxUSE_TREECTRL
28
29#include "wx/treectrl.h"
30#include "wx/imaglist.h"
31
32// ----------------------------------------------------------------------------
33// events
34// ----------------------------------------------------------------------------
35
36DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_BEGIN_DRAG)
37DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_BEGIN_RDRAG)
38DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_BEGIN_LABEL_EDIT)
39DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_END_LABEL_EDIT)
40DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_DELETE_ITEM)
41DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_GET_INFO)
42DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_SET_INFO)
43DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_EXPANDED)
44DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_EXPANDING)
45DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_COLLAPSED)
46DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_COLLAPSING)
47DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_SEL_CHANGED)
48DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_SEL_CHANGING)
49DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_KEY_DOWN)
50DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_ACTIVATED)
51DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_RIGHT_CLICK)
52DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_MIDDLE_CLICK)
53DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_END_DRAG)
54DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_STATE_IMAGE_CLICK)
55DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_GETTOOLTIP)
56DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_MENU)
57
58// ----------------------------------------------------------------------------
59// Tree event
60// ----------------------------------------------------------------------------
61
62IMPLEMENT_ABSTRACT_CLASS(wxTreeEvent, wxNotifyEvent)
63
64
65wxTreeEvent::wxTreeEvent(wxEventType commandType,
66                         wxTreeCtrlBase *tree,
67                         const wxTreeItemId& item)
68           : wxNotifyEvent(commandType, tree->GetId()),
69             m_item(item)
70{
71    m_editCancelled = false;
72
73    SetEventObject(tree);
74
75    if ( item.IsOk() )
76        SetClientObject(tree->GetItemData(item));
77}
78
79wxTreeEvent::wxTreeEvent(wxEventType commandType, int id)
80           : wxNotifyEvent(commandType, id)
81{
82    m_itemOld = 0l;
83    m_editCancelled = false;
84}
85
86wxTreeEvent::wxTreeEvent(const wxTreeEvent & event)
87           : wxNotifyEvent(event)
88{
89    m_evtKey = event.m_evtKey;
90    m_item = event.m_item;
91    m_itemOld = event.m_itemOld;
92    m_pointDrag = event.m_pointDrag;
93    m_label = event.m_label;
94    m_editCancelled = event.m_editCancelled;
95}
96
97// ----------------------------------------------------------------------------
98// wxTreeCtrlBase
99// ----------------------------------------------------------------------------
100
101wxTreeCtrlBase::~wxTreeCtrlBase()
102{
103    if (m_ownsImageListNormal)
104        delete m_imageListNormal;
105    if (m_ownsImageListState)
106        delete m_imageListState;
107}
108
109static void
110wxGetBestTreeSize(const wxTreeCtrlBase* treeCtrl, wxTreeItemId id, wxSize& size)
111{
112    wxRect rect;
113
114    if ( treeCtrl->GetBoundingRect(id, rect, true /* just the item */) )
115    {
116        // Translate to logical position so we get the full extent
117#if defined(__WXMSW__) && !defined(__WXUNIVERSAL__)
118        rect.x += treeCtrl->GetScrollPos(wxHORIZONTAL);
119        rect.y += treeCtrl->GetScrollPos(wxVERTICAL);
120#endif
121
122        size.IncTo(wxSize(rect.GetRight(), rect.GetBottom()));
123    }
124
125    wxTreeItemIdValue cookie;
126    for ( wxTreeItemId item = treeCtrl->GetFirstChild(id, cookie);
127          item.IsOk();
128          item = treeCtrl->GetNextChild(id, cookie) )
129    {
130        wxGetBestTreeSize(treeCtrl, item, size);
131    }
132}
133
134wxSize wxTreeCtrlBase::DoGetBestSize() const
135{
136    wxSize size;
137
138    // this doesn't really compute the total bounding rectangle of all items
139    // but a not too bad guess of it which has the advantage of not having to
140    // examine all (potentially hundreds or thousands) items in the control
141
142    if (GetQuickBestSize())
143    {
144        for ( wxTreeItemId item = GetRootItem();
145              item.IsOk();
146              item = GetLastChild(item) )
147        {
148            wxRect rect;
149
150            // last parameter is "true" to get only the dimensions of the text
151            // label, we don't want to get the entire item width as it's determined
152            // by the current size
153            if ( GetBoundingRect(item, rect, true) )
154            {
155                if ( size.x < rect.x + rect.width )
156                    size.x = rect.x + rect.width;
157                if ( size.y < rect.y + rect.height )
158                    size.y = rect.y + rect.height;
159            }
160        }
161    }
162    else // use precise, if potentially slow, size computation method
163    {
164        // iterate over all items recursively
165        wxTreeItemId idRoot = GetRootItem();
166        if ( idRoot.IsOk() )
167            wxGetBestTreeSize(this, idRoot, size);
168    }
169
170    // need some minimal size even for empty tree
171    if ( !size.x || !size.y )
172        size = wxControl::DoGetBestSize();
173    else
174    {
175        // Add border size
176        size += GetWindowBorderSize();
177
178        CacheBestSize(size);
179    }
180
181    return size;
182}
183
184void wxTreeCtrlBase::ExpandAll()
185{
186    if ( IsEmpty() )
187        return;
188
189    ExpandAllChildren(GetRootItem());
190}
191
192void wxTreeCtrlBase::ExpandAllChildren(const wxTreeItemId& item)
193{
194    // expand this item first, this might result in its children being added on
195    // the fly
196    if ( item != GetRootItem() || !HasFlag(wxTR_HIDE_ROOT) )
197        Expand(item);
198    //else: expanding hidden root item is unsupported and unnecessary
199
200    // then (recursively) expand all the children
201    wxTreeItemIdValue cookie;
202    for ( wxTreeItemId idCurr = GetFirstChild(item, cookie);
203          idCurr.IsOk();
204          idCurr = GetNextChild(item, cookie) )
205    {
206        ExpandAllChildren(idCurr);
207    }
208}
209
210void wxTreeCtrlBase::CollapseAll()
211{
212    if ( IsEmpty() )
213        return;
214
215    CollapseAllChildren(GetRootItem());
216}
217
218void wxTreeCtrlBase::CollapseAllChildren(const wxTreeItemId& item)
219{
220    // first (recursively) collapse all the children
221    wxTreeItemIdValue cookie;
222    for ( wxTreeItemId idCurr = GetFirstChild(item, cookie);
223          idCurr.IsOk();
224          idCurr = GetNextChild(item, cookie) )
225    {
226        CollapseAllChildren(idCurr);
227    }
228
229    // then collapse this element too
230    Collapse(item);
231}
232
233bool wxTreeCtrlBase::IsEmpty() const
234{
235    return !GetRootItem().IsOk();
236}
237
238#endif // wxUSE_TREECTRL
239
240