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