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