No changes, just move wxTreeCtrlBase ctor to the source file.
[wxWidgets.git] / src / common / treebase.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/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 extern WXDLLEXPORT_DATA(const char) wxTreeCtrlNameStr[] = "treeCtrl";
33
34 // ----------------------------------------------------------------------------
35 // events
36 // ----------------------------------------------------------------------------
37
38 wxDEFINE_EVENT( wxEVT_COMMAND_TREE_BEGIN_DRAG, wxTreeEvent );
39 wxDEFINE_EVENT( wxEVT_COMMAND_TREE_BEGIN_RDRAG, wxTreeEvent );
40 wxDEFINE_EVENT( wxEVT_COMMAND_TREE_BEGIN_LABEL_EDIT, wxTreeEvent );
41 wxDEFINE_EVENT( wxEVT_COMMAND_TREE_END_LABEL_EDIT, wxTreeEvent );
42 wxDEFINE_EVENT( wxEVT_COMMAND_TREE_DELETE_ITEM, wxTreeEvent );
43 wxDEFINE_EVENT( wxEVT_COMMAND_TREE_GET_INFO, wxTreeEvent );
44 wxDEFINE_EVENT( wxEVT_COMMAND_TREE_SET_INFO, wxTreeEvent );
45 wxDEFINE_EVENT( wxEVT_COMMAND_TREE_ITEM_EXPANDED, wxTreeEvent );
46 wxDEFINE_EVENT( wxEVT_COMMAND_TREE_ITEM_EXPANDING, wxTreeEvent );
47 wxDEFINE_EVENT( wxEVT_COMMAND_TREE_ITEM_COLLAPSED, wxTreeEvent );
48 wxDEFINE_EVENT( wxEVT_COMMAND_TREE_ITEM_COLLAPSING, wxTreeEvent );
49 wxDEFINE_EVENT( wxEVT_COMMAND_TREE_SEL_CHANGED, wxTreeEvent );
50 wxDEFINE_EVENT( wxEVT_COMMAND_TREE_SEL_CHANGING, wxTreeEvent );
51 wxDEFINE_EVENT( wxEVT_COMMAND_TREE_KEY_DOWN, wxTreeEvent );
52 wxDEFINE_EVENT( wxEVT_COMMAND_TREE_ITEM_ACTIVATED, wxTreeEvent );
53 wxDEFINE_EVENT( wxEVT_COMMAND_TREE_ITEM_RIGHT_CLICK, wxTreeEvent );
54 wxDEFINE_EVENT( wxEVT_COMMAND_TREE_ITEM_MIDDLE_CLICK, wxTreeEvent );
55 wxDEFINE_EVENT( wxEVT_COMMAND_TREE_END_DRAG, wxTreeEvent );
56 wxDEFINE_EVENT( wxEVT_COMMAND_TREE_STATE_IMAGE_CLICK, wxTreeEvent );
57 wxDEFINE_EVENT( wxEVT_COMMAND_TREE_ITEM_GETTOOLTIP, wxTreeEvent );
58 wxDEFINE_EVENT( wxEVT_COMMAND_TREE_ITEM_MENU, wxTreeEvent );
59
60 // ----------------------------------------------------------------------------
61 // XTI
62 // ----------------------------------------------------------------------------
63
64 wxDEFINE_FLAGS( wxTreeCtrlStyle )
65 wxBEGIN_FLAGS( wxTreeCtrlStyle )
66 // new style border flags, we put them first to
67 // use them for streaming out
68 wxFLAGS_MEMBER(wxBORDER_SIMPLE)
69 wxFLAGS_MEMBER(wxBORDER_SUNKEN)
70 wxFLAGS_MEMBER(wxBORDER_DOUBLE)
71 wxFLAGS_MEMBER(wxBORDER_RAISED)
72 wxFLAGS_MEMBER(wxBORDER_STATIC)
73 wxFLAGS_MEMBER(wxBORDER_NONE)
74
75 // old style border flags
76 wxFLAGS_MEMBER(wxSIMPLE_BORDER)
77 wxFLAGS_MEMBER(wxSUNKEN_BORDER)
78 wxFLAGS_MEMBER(wxDOUBLE_BORDER)
79 wxFLAGS_MEMBER(wxRAISED_BORDER)
80 wxFLAGS_MEMBER(wxSTATIC_BORDER)
81 wxFLAGS_MEMBER(wxBORDER)
82
83 // standard window styles
84 wxFLAGS_MEMBER(wxTAB_TRAVERSAL)
85 wxFLAGS_MEMBER(wxCLIP_CHILDREN)
86 wxFLAGS_MEMBER(wxTRANSPARENT_WINDOW)
87 wxFLAGS_MEMBER(wxWANTS_CHARS)
88 wxFLAGS_MEMBER(wxFULL_REPAINT_ON_RESIZE)
89 wxFLAGS_MEMBER(wxALWAYS_SHOW_SB )
90 wxFLAGS_MEMBER(wxVSCROLL)
91 wxFLAGS_MEMBER(wxHSCROLL)
92
93 wxFLAGS_MEMBER(wxTR_EDIT_LABELS)
94 wxFLAGS_MEMBER(wxTR_NO_BUTTONS)
95 wxFLAGS_MEMBER(wxTR_HAS_BUTTONS)
96 wxFLAGS_MEMBER(wxTR_TWIST_BUTTONS)
97 wxFLAGS_MEMBER(wxTR_NO_LINES)
98 wxFLAGS_MEMBER(wxTR_FULL_ROW_HIGHLIGHT)
99 wxFLAGS_MEMBER(wxTR_LINES_AT_ROOT)
100 wxFLAGS_MEMBER(wxTR_HIDE_ROOT)
101 wxFLAGS_MEMBER(wxTR_ROW_LINES)
102 wxFLAGS_MEMBER(wxTR_HAS_VARIABLE_ROW_HEIGHT)
103 wxFLAGS_MEMBER(wxTR_SINGLE)
104 wxFLAGS_MEMBER(wxTR_MULTIPLE)
105 #if WXWIN_COMPATIBILITY_2_8
106 wxFLAGS_MEMBER(wxTR_EXTENDED)
107 #endif
108 wxFLAGS_MEMBER(wxTR_DEFAULT_STYLE)
109 wxEND_FLAGS( wxTreeCtrlStyle )
110
111 wxIMPLEMENT_DYNAMIC_CLASS_XTI(wxTreeCtrl, wxControl, "wx/treectrl.h")
112
113 wxBEGIN_PROPERTIES_TABLE(wxTreeCtrl)
114 wxEVENT_PROPERTY( TextUpdated, wxEVT_COMMAND_TEXT_UPDATED, wxCommandEvent )
115 wxEVENT_RANGE_PROPERTY( TreeEvent, wxEVT_COMMAND_TREE_BEGIN_DRAG, \
116 wxEVT_COMMAND_TREE_STATE_IMAGE_CLICK, wxTreeEvent )
117
118 wxPROPERTY_FLAGS( WindowStyle, wxTreeCtrlStyle, long, SetWindowStyleFlag, \
119 GetWindowStyleFlag, wxEMPTY_PARAMETER_VALUE, 0 /*flags*/, \
120 wxT("Helpstring"), wxT("group")) // style
121 wxEND_PROPERTIES_TABLE()
122
123 wxEMPTY_HANDLERS_TABLE(wxTreeCtrl)
124
125 wxCONSTRUCTOR_5( wxTreeCtrl, wxWindow*, Parent, wxWindowID, Id, \
126 wxPoint, Position, wxSize, Size, long, WindowStyle )
127
128 // ----------------------------------------------------------------------------
129 // Tree event
130 // ----------------------------------------------------------------------------
131
132 IMPLEMENT_DYNAMIC_CLASS(wxTreeEvent, wxNotifyEvent)
133
134 wxTreeEvent::wxTreeEvent(wxEventType commandType,
135 wxTreeCtrlBase *tree,
136 const wxTreeItemId& item)
137 : wxNotifyEvent(commandType, tree->GetId()),
138 m_item(item)
139 {
140 m_editCancelled = false;
141
142 SetEventObject(tree);
143
144 if ( item.IsOk() )
145 SetClientObject(tree->GetItemData(item));
146 }
147
148 wxTreeEvent::wxTreeEvent(wxEventType commandType, int id)
149 : wxNotifyEvent(commandType, id)
150 {
151 m_itemOld = 0l;
152 m_editCancelled = false;
153 }
154
155 wxTreeEvent::wxTreeEvent(const wxTreeEvent & event)
156 : wxNotifyEvent(event)
157 {
158 m_evtKey = event.m_evtKey;
159 m_item = event.m_item;
160 m_itemOld = event.m_itemOld;
161 m_pointDrag = event.m_pointDrag;
162 m_label = event.m_label;
163 m_editCancelled = event.m_editCancelled;
164 }
165
166 // ----------------------------------------------------------------------------
167 // wxTreeCtrlBase
168 // ----------------------------------------------------------------------------
169
170 wxTreeCtrlBase::wxTreeCtrlBase()
171 {
172 m_imageListNormal =
173 m_imageListState = NULL;
174 m_ownsImageListNormal =
175 m_ownsImageListState = false;
176
177 // arbitrary default
178 m_spacing = 18;
179
180 // quick DoGetBestSize calculation
181 m_quickBestSize = true;
182 }
183
184 wxTreeCtrlBase::~wxTreeCtrlBase()
185 {
186 if (m_ownsImageListNormal)
187 delete m_imageListNormal;
188 if (m_ownsImageListState)
189 delete m_imageListState;
190 }
191
192 void wxTreeCtrlBase::SetItemState(const wxTreeItemId& item, int state)
193 {
194 if ( state == wxTREE_ITEMSTATE_NEXT )
195 {
196 int current = GetItemState(item);
197 if ( current == wxTREE_ITEMSTATE_NONE )
198 return;
199 state = current + 1;
200 if ( m_imageListState && state >= m_imageListState->GetImageCount() )
201 state = 0;
202 }
203 else if ( state == wxTREE_ITEMSTATE_PREV )
204 {
205 int current = GetItemState(item);
206 if ( current == wxTREE_ITEMSTATE_NONE )
207 return;
208 state = current - 1;
209 if ( state == -1 )
210 state = m_imageListState ? m_imageListState->GetImageCount() - 1 : 0;
211 }
212 // else: wxTREE_ITEMSTATE_NONE depending on platform
213
214 DoSetItemState(item, state);
215 }
216
217 static void
218 wxGetBestTreeSize(const wxTreeCtrlBase* treeCtrl, wxTreeItemId id, wxSize& size)
219 {
220 wxRect rect;
221
222 if ( treeCtrl->GetBoundingRect(id, rect, true /* just the item */) )
223 {
224 // Translate to logical position so we get the full extent
225 #if defined(__WXMSW__) && !defined(__WXUNIVERSAL__)
226 rect.x += treeCtrl->GetScrollPos(wxHORIZONTAL);
227 rect.y += treeCtrl->GetScrollPos(wxVERTICAL);
228 #endif
229
230 size.IncTo(wxSize(rect.GetRight(), rect.GetBottom()));
231 }
232
233 wxTreeItemIdValue cookie;
234 for ( wxTreeItemId item = treeCtrl->GetFirstChild(id, cookie);
235 item.IsOk();
236 item = treeCtrl->GetNextChild(id, cookie) )
237 {
238 wxGetBestTreeSize(treeCtrl, item, size);
239 }
240 }
241
242 wxSize wxTreeCtrlBase::DoGetBestSize() const
243 {
244 wxSize size;
245
246 // this doesn't really compute the total bounding rectangle of all items
247 // but a not too bad guess of it which has the advantage of not having to
248 // examine all (potentially hundreds or thousands) items in the control
249
250 if (GetQuickBestSize())
251 {
252 for ( wxTreeItemId item = GetRootItem();
253 item.IsOk();
254 item = GetLastChild(item) )
255 {
256 wxRect rect;
257
258 // last parameter is "true" to get only the dimensions of the text
259 // label, we don't want to get the entire item width as it's determined
260 // by the current size
261 if ( GetBoundingRect(item, rect, true) )
262 {
263 if ( size.x < rect.x + rect.width )
264 size.x = rect.x + rect.width;
265 if ( size.y < rect.y + rect.height )
266 size.y = rect.y + rect.height;
267 }
268 }
269 }
270 else // use precise, if potentially slow, size computation method
271 {
272 // iterate over all items recursively
273 wxTreeItemId idRoot = GetRootItem();
274 if ( idRoot.IsOk() )
275 wxGetBestTreeSize(this, idRoot, size);
276 }
277
278 // need some minimal size even for empty tree
279 if ( !size.x || !size.y )
280 size = wxControl::DoGetBestSize();
281 else
282 {
283 // Add border size
284 size += GetWindowBorderSize();
285
286 CacheBestSize(size);
287 }
288
289 return size;
290 }
291
292 void wxTreeCtrlBase::ExpandAll()
293 {
294 if ( IsEmpty() )
295 return;
296
297 ExpandAllChildren(GetRootItem());
298 }
299
300 void wxTreeCtrlBase::ExpandAllChildren(const wxTreeItemId& item)
301 {
302 Freeze();
303 // expand this item first, this might result in its children being added on
304 // the fly
305 if ( item != GetRootItem() || !HasFlag(wxTR_HIDE_ROOT) )
306 Expand(item);
307 //else: expanding hidden root item is unsupported and unnecessary
308
309 // then (recursively) expand all the children
310 wxTreeItemIdValue cookie;
311 for ( wxTreeItemId idCurr = GetFirstChild(item, cookie);
312 idCurr.IsOk();
313 idCurr = GetNextChild(item, cookie) )
314 {
315 ExpandAllChildren(idCurr);
316 }
317 Thaw();
318 }
319
320 void wxTreeCtrlBase::CollapseAll()
321 {
322 if ( IsEmpty() )
323 return;
324
325 CollapseAllChildren(GetRootItem());
326 }
327
328 void wxTreeCtrlBase::CollapseAllChildren(const wxTreeItemId& item)
329 {
330 Freeze();
331 // first (recursively) collapse all the children
332 wxTreeItemIdValue cookie;
333 for ( wxTreeItemId idCurr = GetFirstChild(item, cookie);
334 idCurr.IsOk();
335 idCurr = GetNextChild(item, cookie) )
336 {
337 CollapseAllChildren(idCurr);
338 }
339
340 // then collapse this element too unless it's the hidden root which can't
341 // be collapsed
342 if ( item != GetRootItem() || !HasFlag(wxTR_HIDE_ROOT) )
343 Collapse(item);
344 Thaw();
345 }
346
347 bool wxTreeCtrlBase::IsEmpty() const
348 {
349 return !GetRootItem().IsOk();
350 }
351
352 #endif // wxUSE_TREECTRL