Added customizable wxDocManager::OnMRUFileNotExist() virtual method.
[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 if (m_ownsImageListNormal)
173 delete m_imageListNormal;
174 if (m_ownsImageListState)
175 delete m_imageListState;
176 }
177
178 void wxTreeCtrlBase::SetItemState(const wxTreeItemId& item, int state)
179 {
180 if ( state == wxTREE_ITEMSTATE_NEXT )
181 {
182 int current = GetItemState(item);
183 if ( current == wxTREE_ITEMSTATE_NONE )
184 return;
185 state = current + 1;
186 if ( m_imageListState && state >= m_imageListState->GetImageCount() )
187 state = 0;
188 }
189 else if ( state == wxTREE_ITEMSTATE_PREV )
190 {
191 int current = GetItemState(item);
192 if ( current == wxTREE_ITEMSTATE_NONE )
193 return;
194 state = current - 1;
195 if ( state == -1 )
196 state = m_imageListState ? m_imageListState->GetImageCount() - 1 : 0;
197 }
198 // else: wxTREE_ITEMSTATE_NONE depending on platform
199
200 DoSetItemState(item, state);
201 }
202
203 static void
204 wxGetBestTreeSize(const wxTreeCtrlBase* treeCtrl, wxTreeItemId id, wxSize& size)
205 {
206 wxRect rect;
207
208 if ( treeCtrl->GetBoundingRect(id, rect, true /* just the item */) )
209 {
210 // Translate to logical position so we get the full extent
211 #if defined(__WXMSW__) && !defined(__WXUNIVERSAL__)
212 rect.x += treeCtrl->GetScrollPos(wxHORIZONTAL);
213 rect.y += treeCtrl->GetScrollPos(wxVERTICAL);
214 #endif
215
216 size.IncTo(wxSize(rect.GetRight(), rect.GetBottom()));
217 }
218
219 wxTreeItemIdValue cookie;
220 for ( wxTreeItemId item = treeCtrl->GetFirstChild(id, cookie);
221 item.IsOk();
222 item = treeCtrl->GetNextChild(id, cookie) )
223 {
224 wxGetBestTreeSize(treeCtrl, item, size);
225 }
226 }
227
228 wxSize wxTreeCtrlBase::DoGetBestSize() const
229 {
230 wxSize size;
231
232 // this doesn't really compute the total bounding rectangle of all items
233 // but a not too bad guess of it which has the advantage of not having to
234 // examine all (potentially hundreds or thousands) items in the control
235
236 if (GetQuickBestSize())
237 {
238 for ( wxTreeItemId item = GetRootItem();
239 item.IsOk();
240 item = GetLastChild(item) )
241 {
242 wxRect rect;
243
244 // last parameter is "true" to get only the dimensions of the text
245 // label, we don't want to get the entire item width as it's determined
246 // by the current size
247 if ( GetBoundingRect(item, rect, true) )
248 {
249 if ( size.x < rect.x + rect.width )
250 size.x = rect.x + rect.width;
251 if ( size.y < rect.y + rect.height )
252 size.y = rect.y + rect.height;
253 }
254 }
255 }
256 else // use precise, if potentially slow, size computation method
257 {
258 // iterate over all items recursively
259 wxTreeItemId idRoot = GetRootItem();
260 if ( idRoot.IsOk() )
261 wxGetBestTreeSize(this, idRoot, size);
262 }
263
264 // need some minimal size even for empty tree
265 if ( !size.x || !size.y )
266 size = wxControl::DoGetBestSize();
267 else
268 {
269 // Add border size
270 size += GetWindowBorderSize();
271
272 CacheBestSize(size);
273 }
274
275 return size;
276 }
277
278 void wxTreeCtrlBase::ExpandAll()
279 {
280 if ( IsEmpty() )
281 return;
282
283 ExpandAllChildren(GetRootItem());
284 }
285
286 void wxTreeCtrlBase::ExpandAllChildren(const wxTreeItemId& item)
287 {
288 Freeze();
289 // expand this item first, this might result in its children being added on
290 // the fly
291 if ( item != GetRootItem() || !HasFlag(wxTR_HIDE_ROOT) )
292 Expand(item);
293 //else: expanding hidden root item is unsupported and unnecessary
294
295 // then (recursively) expand all the children
296 wxTreeItemIdValue cookie;
297 for ( wxTreeItemId idCurr = GetFirstChild(item, cookie);
298 idCurr.IsOk();
299 idCurr = GetNextChild(item, cookie) )
300 {
301 ExpandAllChildren(idCurr);
302 }
303 Thaw();
304 }
305
306 void wxTreeCtrlBase::CollapseAll()
307 {
308 if ( IsEmpty() )
309 return;
310
311 CollapseAllChildren(GetRootItem());
312 }
313
314 void wxTreeCtrlBase::CollapseAllChildren(const wxTreeItemId& item)
315 {
316 Freeze();
317 // first (recursively) collapse all the children
318 wxTreeItemIdValue cookie;
319 for ( wxTreeItemId idCurr = GetFirstChild(item, cookie);
320 idCurr.IsOk();
321 idCurr = GetNextChild(item, cookie) )
322 {
323 CollapseAllChildren(idCurr);
324 }
325
326 // then collapse this element too unless it's the hidden root which can't
327 // be collapsed
328 if ( item != GetRootItem() || !HasFlag(wxTR_HIDE_ROOT) )
329 Collapse(item);
330 Thaw();
331 }
332
333 bool wxTreeCtrlBase::IsEmpty() const
334 {
335 return !GetRootItem().IsOk();
336 }
337
338 #endif // wxUSE_TREECTRL