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