Added support for sub-object virtual attributes (temporary attributes for characters...
[wxWidgets.git] / samples / xti / classlist.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: classlist.cpp
3 // Purpose: ClassListDialog implementation
4 // Author: Francesco Montorsi
5 // Modified by:
6 // Created: 03/06/2007 14:49:55
7 // RCS-ID: $Id$
8 // Copyright: (c) 2007 Francesco Montorsi
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12
13 // ----------------------------------------------------------------------------
14 // headers
15 // ----------------------------------------------------------------------------
16
17 // For compilers that support precompilation, includes "wx/wx.h".
18 #include "wx/wxprec.h"
19
20 #ifdef __BORLANDC__
21 #pragma hdrstop
22 #endif
23
24 #ifndef WX_PRECOMP
25 #include "wx/wx.h"
26 #endif
27
28 #include "classlist.h"
29
30 #if !wxUSE_EXTENDED_RTTI
31 #error This sample requires XTI (eXtended RTTI) enabled
32 #endif
33
34 // IMPLEMENT_DYNAMIC_CLASS( ClassListDialog, wxDialog ) -- see the header
35 BEGIN_EVENT_TABLE( ClassListDialog, wxDialog )
36 EVT_LISTBOX( ID_LISTBOX, ClassListDialog::OnListboxSelected )
37 EVT_TREE_SEL_CHANGED( ID_TREECTRL, ClassListDialog::OnTreectrlSelChanged )
38 EVT_CHOICEBOOK_PAGE_CHANGED( ID_LISTMODE, ClassListDialog::OnChoiceBookPageChange )
39
40 EVT_CHECKBOX( ID_SHOW_ONLY_XTI, ClassListDialog::OnShowOnlyXTICheckbox )
41 EVT_CHECKBOX( ID_SHOW_PROPERTIES_RECURSIVELY, ClassListDialog::OnShowRecursiveInfoCheckbox )
42 END_EVENT_TABLE()
43
44 // defined later
45 wxString DumpClassInfo(const wxClassInfo*, bool recursive);
46
47
48 // ----------------------------------------------------------------------------
49 // ClassListDialog
50 // ----------------------------------------------------------------------------
51
52 ClassListDialog::ClassListDialog()
53 {
54 Init();
55 }
56
57 ClassListDialog::ClassListDialog( wxWindow* parent, wxWindowID id,
58 const wxString& caption, const wxPoint& pos,
59 const wxSize& size, long style )
60 {
61 Init();
62 Create(parent, id, caption, pos, size, style);
63 }
64
65 bool ClassListDialog::Create( wxWindow* parent, wxWindowID id, const wxString& caption,
66 const wxPoint& pos, const wxSize& size, long style )
67 {
68 SetExtraStyle(wxWS_EX_BLOCK_EVENTS);
69 wxDialog::Create( parent, id, caption, pos, size, style );
70
71 CreateControls();
72 if (GetSizer())
73 {
74 GetSizer()->SetSizeHints(this);
75 }
76 Centre();
77
78 return true;
79 }
80
81 ClassListDialog::~ClassListDialog()
82 {
83 }
84
85 void ClassListDialog::Init()
86 {
87 m_pClassCountText = NULL;
88 m_pRawListBox = NULL;
89 m_pParentTreeCtrl = NULL;
90 m_pSizeListBox = NULL;
91 m_pTextCtrl = NULL;
92 }
93
94 void ClassListDialog::CreateControls()
95 {
96 wxBoxSizer* itemBoxSizer2 = new wxBoxSizer(wxVERTICAL);
97 this->SetSizer(itemBoxSizer2);
98
99 wxStaticText* itemStaticText3 = new wxStaticText( this, wxID_STATIC, _("This is the list of wxWidgets classes registered in the XTI system.\nNote that not all wxWidgets classes are registered nor all registered classes are completely _described_ using XTI metadata."), wxDefaultPosition, wxDefaultSize, 0 );
100 itemBoxSizer2->Add(itemStaticText3, 0, wxALIGN_LEFT|wxALL, 5);
101
102 // filters
103 wxBoxSizer* filters = new wxBoxSizer(wxHORIZONTAL);
104 itemBoxSizer2->Add(filters, 0, wxGROW|wxLEFT|wxRIGHT|wxBOTTOM, 5);
105 filters->Add(new wxCheckBox(this, ID_SHOW_ONLY_XTI,
106 wxT("Show only classes with eXtended infos")));
107 filters->AddSpacer(10);
108 filters->Add(new wxCheckBox(this, ID_SHOW_PROPERTIES_RECURSIVELY,
109 wxT("Show properties of parent classes")));
110
111 // show how many have we filtered out
112 m_pClassCountText = new wxStaticText( this, wxID_STATIC,
113 wxT("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"),
114 wxDefaultPosition, wxDefaultSize, 0 );
115 m_pClassCountText->SetFont(wxFont(8, wxSWISS, wxNORMAL, wxBOLD, false, wxT("Tahoma")));
116 itemBoxSizer2->Add(m_pClassCountText, 0, wxALIGN_LEFT|wxLEFT|wxRIGHT|wxBOTTOM, 5);
117
118 wxBoxSizer* itemBoxSizer5 = new wxBoxSizer(wxHORIZONTAL);
119 itemBoxSizer2->Add(itemBoxSizer5, 1, wxGROW, 5);
120
121 m_pChoiceBook = new wxChoicebook( this, ID_LISTMODE, wxDefaultPosition, wxDefaultSize, wxCHB_DEFAULT );
122
123 // raw-list page
124 wxPanel* itemPanel7 = new wxPanel( m_pChoiceBook, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
125 wxBoxSizer* itemBoxSizer8 = new wxBoxSizer(wxHORIZONTAL);
126 itemPanel7->SetSizer(itemBoxSizer8);
127
128 wxArrayString m_pRawListBoxStrings;
129 m_pRawListBox = new wxListBox( itemPanel7, ID_LISTBOX, wxDefaultPosition, wxDefaultSize, m_pRawListBoxStrings, wxLB_SINGLE );
130 itemBoxSizer8->Add(m_pRawListBox, 1, wxGROW, 5);
131
132 m_pChoiceBook->AddPage(itemPanel7, _("Raw list"));
133
134 // by-size page
135 wxPanel* itemPanel13 = new wxPanel( m_pChoiceBook, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER|wxTAB_TRAVERSAL );
136 wxBoxSizer* itemBoxSizer14 = new wxBoxSizer(wxHORIZONTAL);
137 itemPanel13->SetSizer(itemBoxSizer14);
138
139 wxArrayString m_pSizeListBoxStrings;
140 m_pSizeListBox = new wxListBox( itemPanel13, ID_LISTBOX, wxDefaultPosition, wxDefaultSize, m_pSizeListBoxStrings, wxLB_SINGLE );
141 itemBoxSizer14->Add(m_pSizeListBox, 1, wxGROW, 5);
142
143 m_pChoiceBook->AddPage(itemPanel13, _("Classes by size"));
144
145 // tree page
146 wxPanel* itemPanel10 = new wxPanel( m_pChoiceBook, ID_PANEL, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
147 wxBoxSizer* itemBoxSizer11 = new wxBoxSizer(wxVERTICAL);
148 itemPanel10->SetSizer(itemBoxSizer11);
149
150 m_pParentTreeCtrl = new wxTreeCtrl( itemPanel10, ID_TREECTRL, wxDefaultPosition, wxSize(100, 100), wxTR_HAS_BUTTONS |wxTR_SINGLE );
151 itemBoxSizer11->Add(m_pParentTreeCtrl, 1, wxGROW, 5);
152
153 m_pChoiceBook->AddPage(itemPanel10, _("Classes by parent"));
154
155
156 itemBoxSizer5->Add(m_pChoiceBook, 0, wxGROW|wxALL, 5);
157
158 m_pTextCtrl = new wxTextCtrl( this, ID_TEXTCTRL, wxT(""), wxDefaultPosition, wxSize(500, -1), wxTE_MULTILINE|wxTE_READONLY );
159 itemBoxSizer5->Add(m_pTextCtrl, 3, wxGROW|wxALL, 5);
160
161 wxStdDialogButtonSizer* itemStdDialogButtonSizer17 = new wxStdDialogButtonSizer;
162
163 itemBoxSizer2->Add(itemStdDialogButtonSizer17, 0, wxGROW|wxALL, 5);
164 wxButton* itemButton18 = new wxButton( this, wxID_OK, _("&OK"), wxDefaultPosition, wxDefaultSize, 0 );
165 itemStdDialogButtonSizer17->AddButton(itemButton18);
166
167 wxButton* itemButton19 = new wxButton( this, wxID_CANCEL, _("&Cancel"), wxDefaultPosition, wxDefaultSize, 0 );
168 itemStdDialogButtonSizer17->AddButton(itemButton19);
169
170 itemStdDialogButtonSizer17->Realize();
171
172 InitControls();
173 }
174
175 int ClassListDialog::AddClassesWithParent(const wxClassInfo *parent, const wxTreeItemId &id)
176 {
177 const wxClassInfo *ci = wxClassInfo::GetFirst();
178 int count = 0;
179 while (ci)
180 {
181 // is this class derived from the given parent?
182 if (wxString(ci->GetBaseClassName1()) == parent->GetClassName() ||
183 wxString(ci->GetBaseClassName2()) == parent->GetClassName())
184 {
185 wxTreeItemId child = m_pParentTreeCtrl->AppendItem(id, ci->GetClassName());
186
187 // update the name of this child with the count of the children classes
188 int ret = AddClassesWithParent(ci, child);
189 m_pParentTreeCtrl->SetItemText(child,
190 m_pParentTreeCtrl->GetItemText(child) +
191 wxString::Format(wxT(" [%d]"), ret));
192 count += ret+1;
193 }
194
195 ci = ci->GetNext();
196 }
197
198 // reorder all the children we've just added
199 m_pParentTreeCtrl->SortChildren(id);
200
201 return count;
202 }
203
204 int GetSizeOfClass(const wxString &cn)
205 {
206 const wxClassInfo *ci = wxClassInfo::FindClass(cn);
207 if (ci)
208 return ci->GetSize();
209 return 0;
210 }
211
212 int CompareClassSizes(const wxString &class1, const wxString &class2)
213 {
214 return GetSizeOfClass(class1) - GetSizeOfClass(class2);
215 }
216
217 void ClassListDialog::InitControls()
218 {
219 // create a wxArrayString with the names of all classes:
220 const wxClassInfo *ci = wxClassInfo::GetFirst();
221 wxArrayString arr;
222 while (ci)
223 {
224 arr.Add(ci->GetClassName());
225 ci = ci->GetNext();
226 }
227
228 arr.Sort(); // sort alphabetically
229
230 // now add it to the raw-mode listbox
231 for (unsigned int i=0; i<arr.GetCount(); i++)
232 if (!IsToDiscard(arr[i]))
233 m_pRawListBox->Append(arr[i]);
234 m_nCount = m_pRawListBox->GetCount();
235
236 // sort again using size as sortkey
237 arr.Sort((wxArrayString::CompareFunction)CompareClassSizes);
238
239 // now add it to the size-mode listbox
240 for (unsigned int i=0; i<arr.GetCount(); i++)
241 if (!IsToDiscard(arr[i]))
242 m_pSizeListBox->Append(arr[i]);
243
244 // add root item to parent-mode treectrl
245 wxTreeItemId id = m_pParentTreeCtrl->AddRoot(wxT("wxObject"));
246
247 // recursively add all leaves to the treectrl
248 int count = AddClassesWithParent(CLASSINFO(wxObject), id);
249 m_pParentTreeCtrl->SetItemText(id, m_pParentTreeCtrl->GetItemText(id) +
250 wxString::Format(wxT(" [%d]"), count));
251
252 // initially expand the root item
253 m_pParentTreeCtrl->Expand(id);
254
255 m_nTotalCount = arr.GetCount();
256 UpdateFilterText();
257
258 // don't leave blank the XTI info display
259 m_pChoiceBook->ChangeSelection(0);
260 m_pRawListBox->Select(0);
261 UpdateClassInfo(m_pRawListBox->GetStringSelection());
262 }
263
264 bool ClassListDialog::IsToDiscard(const wxString &classname) const
265 {
266 wxCheckBox *cb = wx_static_cast(wxCheckBox*, FindWindow(ID_SHOW_ONLY_XTI));
267 if (!cb || !cb->IsChecked())
268 return false;
269
270 // check if this class has XTI infos
271 wxClassInfo *info = wxClassInfo::FindClass(classname);
272 if (!info)
273 return false;
274 if (info->GetFirstProperty() != NULL || info->GetFirstHandler() != NULL)
275 return false; // has XTI info
276 return true; // no XTI info
277 }
278
279 void ClassListDialog::UpdateFilterText()
280 {
281 // tell the user how many registered classes are present and
282 // how many are we showing
283 m_pClassCountText->SetLabel(
284 wxString::Format(
285 wxT("Showing %d classes on a total of %d registered classes in wxXTI."),
286 m_nCount, m_nTotalCount));
287 }
288
289 void ClassListDialog::UpdateClassInfo(const wxString &itemName)
290 {
291 wxString classname = itemName.BeforeFirst(wxT(' '));
292 wxCheckBox *cb = wx_static_cast(wxCheckBox*, FindWindow(ID_SHOW_PROPERTIES_RECURSIVELY));
293
294 m_pTextCtrl->SetValue(
295 DumpClassInfo(wxClassInfo::FindClass(classname), cb->IsChecked()));
296 }
297
298
299 // ----------------------------------------------------------------------------
300 // ClassListDialog - event handlers
301 // ----------------------------------------------------------------------------
302
303 void ClassListDialog::OnShowOnlyXTICheckbox( wxCommandEvent& WXUNUSED(event) )
304 {
305 m_pRawListBox->Clear();
306 m_pParentTreeCtrl->DeleteAllItems();
307 m_pSizeListBox->Clear();
308
309 InitControls();
310 }
311
312 void ClassListDialog::OnShowRecursiveInfoCheckbox( wxCommandEvent& WXUNUSED(event) )
313 {
314 m_pRawListBox->Clear();
315 m_pParentTreeCtrl->DeleteAllItems();
316 m_pSizeListBox->Clear();
317
318 InitControls();
319 }
320
321 void ClassListDialog::OnListboxSelected( wxCommandEvent& event )
322 {
323 UpdateClassInfo(event.GetString());
324 }
325
326 void ClassListDialog::OnTreectrlSelChanged( wxTreeEvent& event )
327 {
328 UpdateClassInfo(m_pParentTreeCtrl->GetItemText(event.GetItem()));
329 }
330
331 void ClassListDialog::OnChoiceBookPageChange( wxChoicebookEvent& event )
332 {
333 switch (event.GetSelection())
334 {
335 case 0:
336 if (m_pRawListBox->GetCount())
337 {
338 m_pRawListBox->Select(0);
339 UpdateClassInfo(m_pRawListBox->GetStringSelection());
340 }
341 break;
342 case 1:
343 if (m_pSizeListBox->GetCount())
344 {
345 m_pSizeListBox->Select(0);
346 UpdateClassInfo(m_pSizeListBox->GetStringSelection());
347 }
348 break;
349 case 2:
350 {
351 wxTreeItemId root = m_pParentTreeCtrl->GetRootItem();
352 if (root.IsOk())
353 {
354 m_pParentTreeCtrl->SelectItem(root);
355 UpdateClassInfo(m_pParentTreeCtrl->GetItemText(root));
356 }
357 }
358 break;
359 }
360 }
361
362
363
364 // ----------------------------------------------------------------------------
365 // dump functions
366 // ----------------------------------------------------------------------------
367
368 wxString DumpStr(const wxString &str)
369 {
370 if (str.empty())
371 return wxT("none");
372 return str;
373 }
374
375 wxString DumpTypeInfo(const wxTypeInfo *ti)
376 {
377 if (!ti)
378 return wxT("none");
379
380 return DumpStr(ti->GetTypeName());
381 }
382
383 wxString DumpPropertyAccessor(const wxPropertyAccessor *acc, int indent)
384 {
385 wxString ind = wxT("\n") + wxString(indent, wxT(' '));
386 wxString infostr;
387
388 if (!acc)
389 return ind + wxT("no property accessors");
390
391 if (acc->HasSetter())
392 infostr << ind << wxT("setter name: ") << acc->GetSetterName();
393 if (acc->HasCollectionGetter())
394 infostr << ind << wxT("collection getter name: ") << acc->GetCollectionGetterName();
395 if (acc->HasGetter())
396 infostr << ind << wxT("getter name: ") << acc->GetGetterName();
397 if (acc->HasAdder())
398 infostr << ind << wxT("adder name: ") << acc->GetAdderName();
399
400 return infostr;
401 }
402
403 wxString DumpPropertyInfo(const wxPropertyInfo *prop, int indent)
404 {
405 wxString ind = wxT("\n") + wxString(indent, wxT(' '));
406 wxString infostr;
407
408 if (!prop)
409 return ind + wxT("none");
410
411 infostr << ind << wxT("flags: ");
412 if (prop->GetFlags() & wxPROP_DEPRECATED)
413 infostr << wxT("wxPROP_DEPRECATED,");
414 if (prop->GetFlags() & wxPROP_OBJECT_GRAPH)
415 infostr << wxT("wxPROP_OBJECT_GRAPH,");
416 if (prop->GetFlags() & wxPROP_ENUM_STORE_LONG)
417 infostr << wxT("wxPROP_ENUM_STORE_LONG,");
418 if (prop->GetFlags() & wxPROP_DONT_STREAM)
419 infostr << wxT("wxPROP_DONT_STREAM,");
420
421 if (prop->GetFlags() == 0)
422 infostr << wxT("none");
423 else
424 infostr.RemoveLast(); // remove last comma
425
426 infostr << ind << wxT("help string: ") << DumpStr(prop->GetHelpString());
427 infostr << ind << wxT("group string: ") << DumpStr(prop->GetGroupString());
428
429 infostr << ind << wxT("collection element type: ") << DumpTypeInfo(prop->GetCollectionElementTypeInfo());
430 infostr << ind << wxT("type: ") << DumpTypeInfo(prop->GetTypeInfo());
431
432 infostr << ind << wxT("default value: ") << DumpStr(wxAnyGetAsString(prop->GetDefaultValue()));
433 infostr << DumpPropertyAccessor(prop->GetAccessor(), indent+1);
434
435 return infostr;
436 }
437
438 wxString DumpHandlerInfo(const wxHandlerInfo *phdlr, int indent)
439 {
440 wxString ind = wxT("\n") + wxString(indent, wxT(' '));
441 wxString infostr;
442
443 if (!phdlr)
444 return ind + wxT("none");
445
446 infostr << ind << wxT("event class: ") <<
447 (phdlr->GetEventClassInfo() ? phdlr->GetEventClassInfo()->GetClassName() : wxT("none"));
448
449 return infostr;
450 }
451
452 int DumpProperties(const wxClassInfo *info, wxString& infostr, bool recursive)
453 {
454 const wxPropertyInfo *prop;
455 int pcount;
456 for (prop = info->GetFirstProperty(), pcount = 0;
457 prop;
458 prop = prop->GetNext(), pcount++)
459 {
460 infostr << wxT("\n\n [") << pcount+1 << wxT("] Property: ") << prop->GetName();
461 infostr << DumpPropertyInfo(prop, 4);
462 }
463
464 if (pcount == 0)
465 infostr << wxT("\n None");
466
467 if (recursive)
468 {
469 const wxClassInfo **parent = info->GetParents();
470 wxString str;
471
472 for (int i=0; parent[i] != NULL; i++)
473 {
474 int ppcount = DumpProperties(parent[i], str, recursive);
475 if (ppcount)
476 {
477 pcount += ppcount;
478 infostr << wxT("\n\n ") << parent[i]->GetClassName() << wxT(" PARENT'S PROPERTIES:");
479 infostr << str;
480 }
481 }
482 }
483
484 return pcount;
485 }
486
487 int DumpHandlers(const wxClassInfo *info, wxString& infostr, bool recursive)
488 {
489 const wxHandlerInfo *h;
490 int hcount;
491 for (h = info->GetFirstHandler(), hcount = 0;
492 h;
493 h = h->GetNext(), hcount++)
494 {
495 infostr << wxT("\n\n [") << hcount+1 << wxT("] Handler: ") << h->GetName();
496 infostr << DumpHandlerInfo(h, 4);
497 }
498
499 if (hcount == 0)
500 infostr << wxT("\n None");
501
502 if (recursive)
503 {
504 const wxClassInfo **parent = info->GetParents();
505 wxString str;
506
507 for (int i=0; parent[i] != NULL; i++)
508 {
509 int hhcount = DumpHandlers(parent[i], str, recursive);
510 if (hhcount)
511 {
512 hcount += hhcount;
513 infostr << wxT("\n\n ") << parent[i]->GetClassName() << wxT(" PARENT'S HANDLERS:");
514 infostr << str;
515 }
516 }
517 }
518
519 return hcount;
520 }
521
522 wxString DumpClassInfo(const wxClassInfo *info, bool recursive)
523 {
524 wxString infostr;
525
526 if (!info)
527 return wxEmptyString;
528
529 // basic stuff:
530
531 infostr << wxT("\n BASIC RTTI INFO ABOUT ") << info->GetClassName();
532 infostr << wxT("\n =================================================");
533 infostr << wxT("\n Base class #1: ") << DumpStr(info->GetBaseClassName1());
534 infostr << wxT("\n Base class #2: ") << DumpStr(info->GetBaseClassName2());
535 infostr << wxT("\n Include file: ") << DumpStr(info->GetIncludeName());
536 infostr << wxT("\n Size: ") << info->GetSize();
537 infostr << wxT("\n Dynamic: ") << (info->IsDynamic() ? wxT("true") : wxT("false"));
538
539
540 // advanced stuff:
541
542 infostr << wxT("\n\n\n ADVANCED RTTI INFO ABOUT ") << info->GetClassName();
543 infostr << wxT("\n =================================================\n");
544 infostr << wxT("\n PROPERTIES");
545 infostr << wxT("\n -----------------------------------------");
546 int pcount = DumpProperties(info, infostr, recursive);
547 infostr << wxT("\n\n HANDLERS");
548 infostr << wxT("\n -----------------------------------------");
549 int hcount = DumpHandlers(info, infostr, recursive);
550
551 if (pcount+hcount == 0)
552 infostr << wxT("\n\n no advanced info\n");
553 else
554 {
555 infostr << wxT("\n\n Total count of properties: ") << pcount;
556 infostr << wxT("\n Total count of handlers: ") << hcount << wxT("\n");
557 }
558
559 return infostr;
560 }