]> git.saurik.com Git - wxWidgets.git/blob - src/common/treebase.cpp
fix off by 1 error in GetTextRaw() (#4317)
[wxWidgets.git] / src / common / treebase.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: treebase.cpp
3 // Purpose: Base wxTreeCtrl classes
4 // Author: Julian Smart
5 // Created: 01/02/97
6 // Modified:
7 // Id: $Id$
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
36 DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_BEGIN_DRAG)
37 DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_BEGIN_RDRAG)
38 DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_BEGIN_LABEL_EDIT)
39 DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_END_LABEL_EDIT)
40 DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_DELETE_ITEM)
41 DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_GET_INFO)
42 DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_SET_INFO)
43 DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_EXPANDED)
44 DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_EXPANDING)
45 DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_COLLAPSED)
46 DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_COLLAPSING)
47 DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_SEL_CHANGED)
48 DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_SEL_CHANGING)
49 DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_KEY_DOWN)
50 DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_ACTIVATED)
51 DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_RIGHT_CLICK)
52 DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_MIDDLE_CLICK)
53 DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_END_DRAG)
54 DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_STATE_IMAGE_CLICK)
55 DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_GETTOOLTIP)
56 DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_MENU)
57
58 // ----------------------------------------------------------------------------
59 // Tree event
60 // ----------------------------------------------------------------------------
61
62 IMPLEMENT_ABSTRACT_CLASS(wxTreeEvent, wxNotifyEvent)
63
64
65 wxTreeEvent::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
79 wxTreeEvent::wxTreeEvent(wxEventType commandType, int id)
80 : wxNotifyEvent(commandType, id)
81 {
82 m_itemOld = 0l;
83 m_editCancelled = false;
84 }
85
86 wxTreeEvent::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
101 wxTreeCtrlBase::~wxTreeCtrlBase()
102 {
103 if (m_ownsImageListNormal)
104 delete m_imageListNormal;
105 if (m_ownsImageListState)
106 delete m_imageListState;
107 }
108
109 static void
110 wxGetBestTreeSize(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
134 wxSize 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
184 void wxTreeCtrlBase::ExpandAll()
185 {
186 if ( IsEmpty() )
187 return;
188
189 ExpandAllChildren(GetRootItem());
190 }
191
192 void wxTreeCtrlBase::ExpandAllChildren(const wxTreeItemId& item)
193 {
194 Freeze();
195 // expand this item first, this might result in its children being added on
196 // the fly
197 if ( item != GetRootItem() || !HasFlag(wxTR_HIDE_ROOT) )
198 Expand(item);
199 //else: expanding hidden root item is unsupported and unnecessary
200
201 // then (recursively) expand all the children
202 wxTreeItemIdValue cookie;
203 for ( wxTreeItemId idCurr = GetFirstChild(item, cookie);
204 idCurr.IsOk();
205 idCurr = GetNextChild(item, cookie) )
206 {
207 ExpandAllChildren(idCurr);
208 }
209 Thaw();
210 }
211
212 void wxTreeCtrlBase::CollapseAll()
213 {
214 if ( IsEmpty() )
215 return;
216
217 CollapseAllChildren(GetRootItem());
218 }
219
220 void wxTreeCtrlBase::CollapseAllChildren(const wxTreeItemId& item)
221 {
222 Freeze();
223 // first (recursively) collapse all the children
224 wxTreeItemIdValue cookie;
225 for ( wxTreeItemId idCurr = GetFirstChild(item, cookie);
226 idCurr.IsOk();
227 idCurr = GetNextChild(item, cookie) )
228 {
229 CollapseAllChildren(idCurr);
230 }
231
232 // then collapse this element too
233 Collapse(item);
234 Thaw();
235 }
236
237 bool wxTreeCtrlBase::IsEmpty() const
238 {
239 return !GetRootItem().IsOk();
240 }
241
242 #endif // wxUSE_TREECTRL
243