///////////////////////////////////////////////////////////////////////////// // Name: classlist.cpp // Purpose: ClassListDialog implementation // Author: Francesco Montorsi // Modified by: // Created: 03/06/2007 14:49:55 // RCS-ID: $Id$ // Copyright: (c) 2007 Francesco Montorsi // Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// // ---------------------------------------------------------------------------- // headers // ---------------------------------------------------------------------------- // For compilers that support precompilation, includes "wx/wx.h". #include "wx/wxprec.h" #ifdef __BORLANDC__ #pragma hdrstop #endif #ifndef WX_PRECOMP #include "wx/wx.h" #endif #include "classlist.h" #if !wxUSE_EXTENDED_RTTI #error This sample requires XTI (eXtended RTTI) enabled #endif // IMPLEMENT_DYNAMIC_CLASS( ClassListDialog, wxDialog ) -- see the header BEGIN_EVENT_TABLE( ClassListDialog, wxDialog ) EVT_LISTBOX( ID_LISTBOX, ClassListDialog::OnListboxSelected ) EVT_TREE_SEL_CHANGED( ID_TREECTRL, ClassListDialog::OnTreectrlSelChanged ) EVT_CHOICEBOOK_PAGE_CHANGED( ID_LISTMODE, ClassListDialog::OnChoiceBookPageChange ) EVT_CHECKBOX( ID_SHOW_ONLY_XTI, ClassListDialog::OnShowOnlyXTICheckbox ) EVT_CHECKBOX( ID_SHOW_PROPERTIES_RECURSIVELY, ClassListDialog::OnShowRecursiveInfoCheckbox ) END_EVENT_TABLE() // defined later wxString DumpClassInfo(const wxClassInfo*, bool recursive); // ---------------------------------------------------------------------------- // ClassListDialog // ---------------------------------------------------------------------------- ClassListDialog::ClassListDialog() { Init(); } ClassListDialog::ClassListDialog( wxWindow* parent, wxWindowID id, const wxString& caption, const wxPoint& pos, const wxSize& size, long style ) { Init(); Create(parent, id, caption, pos, size, style); } bool ClassListDialog::Create( wxWindow* parent, wxWindowID id, const wxString& caption, const wxPoint& pos, const wxSize& size, long style ) { SetExtraStyle(wxWS_EX_BLOCK_EVENTS); wxDialog::Create( parent, id, caption, pos, size, style ); CreateControls(); if (GetSizer()) { GetSizer()->SetSizeHints(this); } Centre(); return true; } ClassListDialog::~ClassListDialog() { } void ClassListDialog::Init() { m_pClassCountText = NULL; m_pRawListBox = NULL; m_pParentTreeCtrl = NULL; m_pSizeListBox = NULL; m_pTextCtrl = NULL; } void ClassListDialog::CreateControls() { wxBoxSizer* itemBoxSizer2 = new wxBoxSizer(wxVERTICAL); this->SetSizer(itemBoxSizer2); 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 ); itemBoxSizer2->Add(itemStaticText3, 0, wxALIGN_LEFT|wxALL, 5); // filters wxBoxSizer* filters = new wxBoxSizer(wxHORIZONTAL); itemBoxSizer2->Add(filters, 0, wxGROW|wxLEFT|wxRIGHT|wxBOTTOM, 5); filters->Add(new wxCheckBox(this, ID_SHOW_ONLY_XTI, wxT("Show only classes with eXtended infos"))); filters->AddSpacer(10); filters->Add(new wxCheckBox(this, ID_SHOW_PROPERTIES_RECURSIVELY, wxT("Show properties of parent classes"))); // show how many have we filtered out m_pClassCountText = new wxStaticText( this, wxID_STATIC, wxT("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"), wxDefaultPosition, wxDefaultSize, 0 ); m_pClassCountText->SetFont(wxFont(8, wxSWISS, wxNORMAL, wxBOLD, false, wxT("Tahoma"))); itemBoxSizer2->Add(m_pClassCountText, 0, wxALIGN_LEFT|wxLEFT|wxRIGHT|wxBOTTOM, 5); wxBoxSizer* itemBoxSizer5 = new wxBoxSizer(wxHORIZONTAL); itemBoxSizer2->Add(itemBoxSizer5, 1, wxGROW, 5); m_pChoiceBook = new wxChoicebook( this, ID_LISTMODE, wxDefaultPosition, wxDefaultSize, wxCHB_DEFAULT ); // raw-list page wxPanel* itemPanel7 = new wxPanel( m_pChoiceBook, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL ); wxBoxSizer* itemBoxSizer8 = new wxBoxSizer(wxHORIZONTAL); itemPanel7->SetSizer(itemBoxSizer8); wxArrayString m_pRawListBoxStrings; m_pRawListBox = new wxListBox( itemPanel7, ID_LISTBOX, wxDefaultPosition, wxDefaultSize, m_pRawListBoxStrings, wxLB_SINGLE ); itemBoxSizer8->Add(m_pRawListBox, 1, wxGROW, 5); m_pChoiceBook->AddPage(itemPanel7, _("Raw list")); // by-size page wxPanel* itemPanel13 = new wxPanel( m_pChoiceBook, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER|wxTAB_TRAVERSAL ); wxBoxSizer* itemBoxSizer14 = new wxBoxSizer(wxHORIZONTAL); itemPanel13->SetSizer(itemBoxSizer14); wxArrayString m_pSizeListBoxStrings; m_pSizeListBox = new wxListBox( itemPanel13, ID_LISTBOX, wxDefaultPosition, wxDefaultSize, m_pSizeListBoxStrings, wxLB_SINGLE ); itemBoxSizer14->Add(m_pSizeListBox, 1, wxGROW, 5); m_pChoiceBook->AddPage(itemPanel13, _("Classes by size")); // tree page wxPanel* itemPanel10 = new wxPanel( m_pChoiceBook, ID_PANEL, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL ); wxBoxSizer* itemBoxSizer11 = new wxBoxSizer(wxVERTICAL); itemPanel10->SetSizer(itemBoxSizer11); m_pParentTreeCtrl = new wxTreeCtrl( itemPanel10, ID_TREECTRL, wxDefaultPosition, wxSize(100, 100), wxTR_HAS_BUTTONS |wxTR_SINGLE ); itemBoxSizer11->Add(m_pParentTreeCtrl, 1, wxGROW, 5); m_pChoiceBook->AddPage(itemPanel10, _("Classes by parent")); itemBoxSizer5->Add(m_pChoiceBook, 0, wxGROW|wxALL, 5); m_pTextCtrl = new wxTextCtrl( this, ID_TEXTCTRL, wxT(""), wxDefaultPosition, wxSize(500, -1), wxTE_MULTILINE|wxTE_READONLY ); itemBoxSizer5->Add(m_pTextCtrl, 3, wxGROW|wxALL, 5); wxStdDialogButtonSizer* itemStdDialogButtonSizer17 = new wxStdDialogButtonSizer; itemBoxSizer2->Add(itemStdDialogButtonSizer17, 0, wxGROW|wxALL, 5); wxButton* itemButton18 = new wxButton( this, wxID_OK, _("&OK"), wxDefaultPosition, wxDefaultSize, 0 ); itemStdDialogButtonSizer17->AddButton(itemButton18); wxButton* itemButton19 = new wxButton( this, wxID_CANCEL, _("&Cancel"), wxDefaultPosition, wxDefaultSize, 0 ); itemStdDialogButtonSizer17->AddButton(itemButton19); itemStdDialogButtonSizer17->Realize(); InitControls(); } int ClassListDialog::AddClassesWithParent(const wxClassInfo *parent, const wxTreeItemId &id) { const wxClassInfo *ci = wxClassInfo::GetFirst(); int count = 0; while (ci) { // is this class derived from the given parent? if (wxString(ci->GetBaseClassName1()) == parent->GetClassName() || wxString(ci->GetBaseClassName2()) == parent->GetClassName()) { wxTreeItemId child = m_pParentTreeCtrl->AppendItem(id, ci->GetClassName()); // update the name of this child with the count of the children classes int ret = AddClassesWithParent(ci, child); m_pParentTreeCtrl->SetItemText(child, m_pParentTreeCtrl->GetItemText(child) + wxString::Format(wxT(" [%d]"), ret)); count += ret+1; } ci = ci->GetNext(); } // reorder all the children we've just added m_pParentTreeCtrl->SortChildren(id); return count; } int GetSizeOfClass(const wxString &cn) { const wxClassInfo *ci = wxClassInfo::FindClass(cn); if (ci) return ci->GetSize(); return 0; } int CompareClassSizes(const wxString &class1, const wxString &class2) { return GetSizeOfClass(class1) - GetSizeOfClass(class2); } void ClassListDialog::InitControls() { // create a wxArrayString with the names of all classes: const wxClassInfo *ci = wxClassInfo::GetFirst(); wxArrayString arr; while (ci) { arr.Add(ci->GetClassName()); ci = ci->GetNext(); } arr.Sort(); // sort alphabetically // now add it to the raw-mode listbox for (unsigned int i=0; iAppend(arr[i]); m_nCount = m_pRawListBox->GetCount(); // sort again using size as sortkey arr.Sort((wxArrayString::CompareFunction)CompareClassSizes); // now add it to the size-mode listbox for (unsigned int i=0; iAppend(arr[i]); // add root item to parent-mode treectrl wxTreeItemId id = m_pParentTreeCtrl->AddRoot(wxT("wxObject")); // recursively add all leaves to the treectrl int count = AddClassesWithParent(CLASSINFO(wxObject), id); m_pParentTreeCtrl->SetItemText(id, m_pParentTreeCtrl->GetItemText(id) + wxString::Format(wxT(" [%d]"), count)); // initially expand the root item m_pParentTreeCtrl->Expand(id); m_nTotalCount = arr.GetCount(); UpdateFilterText(); // don't leave blank the XTI info display m_pChoiceBook->ChangeSelection(0); m_pRawListBox->Select(0); UpdateClassInfo(m_pRawListBox->GetStringSelection()); } bool ClassListDialog::IsToDiscard(const wxString &classname) const { wxCheckBox *cb = wx_static_cast(wxCheckBox*, FindWindow(ID_SHOW_ONLY_XTI)); if (!cb || !cb->IsChecked()) return false; // check if this class has XTI infos wxClassInfo *info = wxClassInfo::FindClass(classname); if (!info) return false; if (info->GetFirstProperty() != NULL || info->GetFirstHandler() != NULL) return false; // has XTI info return true; // no XTI info } void ClassListDialog::UpdateFilterText() { // tell the user how many registered classes are present and // how many are we showing m_pClassCountText->SetLabel( wxString::Format( wxT("Showing %d classes on a total of %d registered classes in wxXTI."), m_nCount, m_nTotalCount)); } void ClassListDialog::UpdateClassInfo(const wxString &itemName) { wxString classname = itemName.BeforeFirst(wxT(' ')); wxCheckBox *cb = wx_static_cast(wxCheckBox*, FindWindow(ID_SHOW_PROPERTIES_RECURSIVELY)); m_pTextCtrl->SetValue( DumpClassInfo(wxClassInfo::FindClass(classname), cb->IsChecked())); } // ---------------------------------------------------------------------------- // ClassListDialog - event handlers // ---------------------------------------------------------------------------- void ClassListDialog::OnShowOnlyXTICheckbox( wxCommandEvent& WXUNUSED(event) ) { m_pRawListBox->Clear(); m_pParentTreeCtrl->DeleteAllItems(); m_pSizeListBox->Clear(); InitControls(); } void ClassListDialog::OnShowRecursiveInfoCheckbox( wxCommandEvent& WXUNUSED(event) ) { m_pRawListBox->Clear(); m_pParentTreeCtrl->DeleteAllItems(); m_pSizeListBox->Clear(); InitControls(); } void ClassListDialog::OnListboxSelected( wxCommandEvent& event ) { UpdateClassInfo(event.GetString()); } void ClassListDialog::OnTreectrlSelChanged( wxTreeEvent& event ) { UpdateClassInfo(m_pParentTreeCtrl->GetItemText(event.GetItem())); } void ClassListDialog::OnChoiceBookPageChange( wxChoicebookEvent& event ) { switch (event.GetSelection()) { case 0: if (m_pRawListBox->GetCount()) { m_pRawListBox->Select(0); UpdateClassInfo(m_pRawListBox->GetStringSelection()); } break; case 1: if (m_pSizeListBox->GetCount()) { m_pSizeListBox->Select(0); UpdateClassInfo(m_pSizeListBox->GetStringSelection()); } break; case 2: { wxTreeItemId root = m_pParentTreeCtrl->GetRootItem(); if (root.IsOk()) { m_pParentTreeCtrl->SelectItem(root); UpdateClassInfo(m_pParentTreeCtrl->GetItemText(root)); } } break; } } // ---------------------------------------------------------------------------- // dump functions // ---------------------------------------------------------------------------- wxString DumpStr(const wxString &str) { if (str.empty()) return wxT("none"); return str; } wxString DumpTypeInfo(const wxTypeInfo *ti) { if (!ti) return wxT("none"); return DumpStr(ti->GetTypeName()); } wxString DumpPropertyAccessor(const wxPropertyAccessor *acc, int indent) { wxString ind = wxT("\n") + wxString(indent, wxT(' ')); wxString infostr; if (!acc) return ind + wxT("no property accessors"); if (acc->HasSetter()) infostr << ind << wxT("setter name: ") << acc->GetSetterName(); if (acc->HasCollectionGetter()) infostr << ind << wxT("collection getter name: ") << acc->GetCollectionGetterName(); if (acc->HasGetter()) infostr << ind << wxT("getter name: ") << acc->GetGetterName(); if (acc->HasAdder()) infostr << ind << wxT("adder name: ") << acc->GetAdderName(); return infostr; } wxString DumpPropertyInfo(const wxPropertyInfo *prop, int indent) { wxString ind = wxT("\n") + wxString(indent, wxT(' ')); wxString infostr; if (!prop) return ind + wxT("none"); infostr << ind << wxT("flags: "); if (prop->GetFlags() & wxPROP_DEPRECATED) infostr << wxT("wxPROP_DEPRECATED,"); if (prop->GetFlags() & wxPROP_OBJECT_GRAPH) infostr << wxT("wxPROP_OBJECT_GRAPH,"); if (prop->GetFlags() & wxPROP_ENUM_STORE_LONG) infostr << wxT("wxPROP_ENUM_STORE_LONG,"); if (prop->GetFlags() & wxPROP_DONT_STREAM) infostr << wxT("wxPROP_DONT_STREAM,"); if (prop->GetFlags() == 0) infostr << wxT("none"); else infostr.RemoveLast(); // remove last comma infostr << ind << wxT("help string: ") << DumpStr(prop->GetHelpString()); infostr << ind << wxT("group string: ") << DumpStr(prop->GetGroupString()); infostr << ind << wxT("collection element type: ") << DumpTypeInfo(prop->GetCollectionElementTypeInfo()); infostr << ind << wxT("type: ") << DumpTypeInfo(prop->GetTypeInfo()); infostr << ind << wxT("default value: ") << DumpStr(wxAnyGetAsString(prop->GetDefaultValue())); infostr << DumpPropertyAccessor(prop->GetAccessor(), indent+1); return infostr; } wxString DumpHandlerInfo(const wxHandlerInfo *phdlr, int indent) { wxString ind = wxT("\n") + wxString(indent, wxT(' ')); wxString infostr; if (!phdlr) return ind + wxT("none"); infostr << ind << wxT("event class: ") << (phdlr->GetEventClassInfo() ? phdlr->GetEventClassInfo()->GetClassName() : wxT("none")); return infostr; } int DumpProperties(const wxClassInfo *info, wxString& infostr, bool recursive) { const wxPropertyInfo *prop; int pcount; for (prop = info->GetFirstProperty(), pcount = 0; prop; prop = prop->GetNext(), pcount++) { infostr << wxT("\n\n [") << pcount+1 << wxT("] Property: ") << prop->GetName(); infostr << DumpPropertyInfo(prop, 4); } if (pcount == 0) infostr << wxT("\n None"); if (recursive) { const wxClassInfo **parent = info->GetParents(); wxString str; for (int i=0; parent[i] != NULL; i++) { int ppcount = DumpProperties(parent[i], str, recursive); if (ppcount) { pcount += ppcount; infostr << wxT("\n\n ") << parent[i]->GetClassName() << wxT(" PARENT'S PROPERTIES:"); infostr << str; } } } return pcount; } int DumpHandlers(const wxClassInfo *info, wxString& infostr, bool recursive) { const wxHandlerInfo *h; int hcount; for (h = info->GetFirstHandler(), hcount = 0; h; h = h->GetNext(), hcount++) { infostr << wxT("\n\n [") << hcount+1 << wxT("] Handler: ") << h->GetName(); infostr << DumpHandlerInfo(h, 4); } if (hcount == 0) infostr << wxT("\n None"); if (recursive) { const wxClassInfo **parent = info->GetParents(); wxString str; for (int i=0; parent[i] != NULL; i++) { int hhcount = DumpHandlers(parent[i], str, recursive); if (hhcount) { hcount += hhcount; infostr << wxT("\n\n ") << parent[i]->GetClassName() << wxT(" PARENT'S HANDLERS:"); infostr << str; } } } return hcount; } wxString DumpClassInfo(const wxClassInfo *info, bool recursive) { wxString infostr; if (!info) return wxEmptyString; // basic stuff: infostr << wxT("\n BASIC RTTI INFO ABOUT ") << info->GetClassName(); infostr << wxT("\n ================================================="); infostr << wxT("\n Base class #1: ") << DumpStr(info->GetBaseClassName1()); infostr << wxT("\n Base class #2: ") << DumpStr(info->GetBaseClassName2()); infostr << wxT("\n Include file: ") << DumpStr(info->GetIncludeName()); infostr << wxT("\n Size: ") << info->GetSize(); infostr << wxT("\n Dynamic: ") << (info->IsDynamic() ? wxT("true") : wxT("false")); // advanced stuff: infostr << wxT("\n\n\n ADVANCED RTTI INFO ABOUT ") << info->GetClassName(); infostr << wxT("\n =================================================\n"); infostr << wxT("\n PROPERTIES"); infostr << wxT("\n -----------------------------------------"); int pcount = DumpProperties(info, infostr, recursive); infostr << wxT("\n\n HANDLERS"); infostr << wxT("\n -----------------------------------------"); int hcount = DumpHandlers(info, infostr, recursive); if (pcount+hcount == 0) infostr << wxT("\n\n no advanced info\n"); else { infostr << wxT("\n\n Total count of properties: ") << pcount; infostr << wxT("\n Total count of handlers: ") << hcount << wxT("\n"); } return infostr; }