wxlstack.cpp

Go to the documentation of this file.
00001 /////////////////////////////////////////////////////////////////////////////
00002 // Name:        StackTree.cpp
00003 // Purpose:     Display the Lua stack in a dialog.
00004 // Author:      J. Winwood, John Labenski
00005 // Created:     February 2002
00006 // Copyright:   (c) 2002 Lomtick Software. All rights reserved.
00007 // Licence:     wxWidgets licence
00008 /////////////////////////////////////////////////////////////////////////////
00009 
00010 #include "wx/wxprec.h"
00011 
00012 #ifdef __BORLANDC__
00013     #pragma hdrstop
00014 #endif
00015 
00016 #ifndef WX_PRECOMP
00017     #include "wx/wx.h"
00018 #endif
00019 
00020 #include "wx/imaglist.h"
00021 #include "wx/artprov.h"
00022 #include "wx/listctrl.h"
00023 #include "wx/splitter.h"
00024 #include "wx/progdlg.h"
00025 #include "wx/clipbrd.h"
00026 
00027 #include "wxluadebug/include/wxlstack.h"
00028 #include "wxlua/include/wxlua.h"
00029 #include "wxlua/include/wxlcallb.h"
00030 #include "wxluadebug/include/wxldebug.h"
00031 
00032 #if defined(__WXGTK__) || defined(__WXMAC__) || defined(__WXMOTIF__)
00033     #include "art/wxlua.xpm"
00034 #endif
00035 
00036 // Define our own flag to help track down where we've hacked thing to work
00037 // equally well with the treectrl for MSW
00038 #if defined(__WXMSW__)
00039     #define WXLUA_STACK_MSWTREE
00040 #endif //defined(__WXMSW__)
00041 
00042 #define DUMMY_TREEITEM wxT("  ")
00043 
00044 // ----------------------------------------------------------------------------
00045 // wxLuaStackListCtrl
00046 // ----------------------------------------------------------------------------
00047 
00048 class wxLuaStackListCtrl : public wxListCtrl
00049 {
00050 public:
00051     wxLuaStackListCtrl( wxLuaStackDialog* stkDialog,
00052                         wxWindow *parent,
00053                         wxWindowID winid = wxID_ANY,
00054                         const wxPoint& pos = wxDefaultPosition,
00055                         const wxSize& size = wxDefaultSize,
00056                         long style = wxLC_REPORT,
00057                         const wxValidator& validator = wxDefaultValidator,
00058                         const wxString &name = wxT("wxLuaStackListCtrl"))
00059         : wxListCtrl(parent, winid, pos, size, style, validator, name)
00060     {
00061         m_stkDlg = stkDialog;
00062     }
00063 
00064     virtual wxString OnGetItemText(long item, long column) const;
00065     virtual int OnGetItemImage(long item) const;
00066     virtual int OnGetItemColumnImage(long item, long column) const;
00067     virtual wxListItemAttr *OnGetItemAttr(long item) const;
00068 
00069     wxListItemAttr    m_itemAttr;
00070     wxLuaStackDialog* m_stkDlg;
00071 };
00072 
00073 
00074 wxString wxLuaStackListCtrl::OnGetItemText(long item, long column) const
00075 {
00076     return m_stkDlg->GetItemText(item, column);
00077 }
00078 int wxLuaStackListCtrl::OnGetItemImage(long item) const
00079 {
00080     return -1; // use OnGetItemColumnImage()
00081 }
00082 int wxLuaStackListCtrl::OnGetItemColumnImage(long item, long column) const
00083 {
00084     if ((column == wxLuaStackDialog::LIST_COL_KEY) ||
00085         (column == wxLuaStackDialog::LIST_COL_KEY_TYPE) ||
00086         (column == wxLuaStackDialog::LIST_COL_VALUE_TYPE))
00087     {
00088         wxLuaStackListData* stkListData = (wxLuaStackListData*)m_stkDlg->m_listData[item];
00089         wxCHECK_MSG(stkListData, -1, wxT("Invalid wxLuaStackListData item"));
00090         wxLuaDebugItem* debugItem = stkListData->GetDebugItem();
00091         wxCHECK_MSG(debugItem, -1, wxT("Invalid wxLuaDebugItem item"));
00092 
00093         if (column == wxLuaStackDialog::LIST_COL_KEY)
00094             return m_stkDlg->GetItemImage(debugItem);
00095         else if (column == wxLuaStackDialog::LIST_COL_KEY_TYPE)
00096         {
00097             if (debugItem->GetFlagBit(WXLUA_DEBUGITEM_KEY_REF))
00098             {
00099                 if (debugItem->GetFlagBit(WXLUA_DEBUGITEM_EXPANDED))
00100                     return wxLuaStackDialog::IMG_TABLE_OPEN;
00101                 else
00102                     return wxLuaStackDialog::IMG_TABLE;
00103             }
00104         }
00105         else if (column == wxLuaStackDialog::LIST_COL_VALUE_TYPE)
00106         {
00107             if (debugItem->GetFlagBit(WXLUA_DEBUGITEM_VALUE_REF))
00108             {
00109                 if (debugItem->GetFlagBit(WXLUA_DEBUGITEM_EXPANDED))
00110                     return wxLuaStackDialog::IMG_TABLE_OPEN;
00111                 else
00112                     return wxLuaStackDialog::IMG_TABLE;
00113             }
00114         }
00115     }
00116 
00117     return -1;
00118 }
00119 wxListItemAttr *wxLuaStackListCtrl::OnGetItemAttr(long item) const
00120 {
00121     wxLuaStackListData* stkListData = (wxLuaStackListData*)m_stkDlg->m_listData[item];
00122     wxCHECK_MSG(stkListData, NULL, wxT("Invalid wxLuaStackListData item"));
00123     wxLuaDebugItem* debugItem = stkListData->GetDebugItem();
00124     wxCHECK_MSG(debugItem, NULL, wxT("Invalid wxLuaDebugItem item"));
00125 
00126     int img = m_stkDlg->GetItemImage(debugItem);
00127 
00128     wxLuaStackListCtrl* stkCtrl = (wxLuaStackListCtrl*)this; // unconst
00129 
00130     stkCtrl->m_itemAttr.SetTextColour(m_stkDlg->m_typeColours[img]);
00131 
00132     //unsigned char c = 255 - (stkListData->m_level % 5)*22;
00133     //stkCtrl->m_itemAttr.SetBackgroundColour(wxColour(c,c,c));
00134 
00135     return &stkCtrl->m_itemAttr;
00136 }
00137 
00138 // ----------------------------------------------------------------------------
00139 // wxLuaStackDialog
00140 // ----------------------------------------------------------------------------
00141 IMPLEMENT_ABSTRACT_CLASS(wxLuaStackDialog, wxDialog)
00142 
00143 wxSize wxLuaStackDialog::m_defaultSize(500, 300);
00144 
00145 BEGIN_EVENT_TABLE(wxLuaStackDialog, wxDialog)
00146     EVT_CHOICE( ID_WXLUA_STACK_CHOICE, wxLuaStackDialog::OnSelectStack)
00147 
00148     EVT_BUTTON( ID_WXLUA_STACK_COLLAPSE_BUTTON, wxLuaStackDialog::OnExpandButton)
00149     EVT_BUTTON( ID_WXLUA_STACK_EXPAND_BUTTON,   wxLuaStackDialog::OnExpandButton)
00150 
00151     EVT_MENU( wxID_ANY, wxLuaStackDialog::OnMenu)
00152 
00153     EVT_TEXT_ENTER( ID_WXLUA_STACK_FIND_COMBO,  wxLuaStackDialog::OnFind)
00154     EVT_BUTTON( ID_WXLUA_STACK_FINDNEXT_BUTTON, wxLuaStackDialog::OnFind)
00155     EVT_BUTTON( ID_WXLUA_STACK_FINDPREV_BUTTON, wxLuaStackDialog::OnFind)
00156     EVT_BUTTON( ID_WXLUA_STACK_FINDMENU_BUTTON, wxLuaStackDialog::OnFind)
00157 
00158     EVT_TREE_ITEM_COLLAPSED(ID_WXLUA_STACK_TREECTRL, wxLuaStackDialog::OnTreeItem)
00159     EVT_TREE_ITEM_EXPANDED( ID_WXLUA_STACK_TREECTRL, wxLuaStackDialog::OnTreeItem)
00160     EVT_TREE_SEL_CHANGED(   ID_WXLUA_STACK_TREECTRL, wxLuaStackDialog::OnTreeItem)
00161 
00162     EVT_LIST_ITEM_SELECTED(    ID_WXLUA_STACK_LISTCTRL, wxLuaStackDialog::OnListItem)
00163     EVT_LIST_ITEM_ACTIVATED(   ID_WXLUA_STACK_LISTCTRL, wxLuaStackDialog::OnListItem)
00164     EVT_LIST_ITEM_RIGHT_CLICK( ID_WXLUA_STACK_LISTCTRL, wxLuaStackDialog::OnListRightClick)
00165 END_EVENT_TABLE()
00166 
00167 void wxLuaStackDialog::Init()
00168 {
00169     m_listCtrl          = NULL;
00170     m_treeCtrl          = NULL;
00171     m_listMenu          = NULL;
00172     m_stackChoice       = NULL;
00173     m_stack_sel         = -1;
00174     m_findComboBox      = NULL;
00175     m_findMenu          = NULL;
00176 
00177     m_imageList         = NULL;
00178     m_img_font_size     = 15;   // largest font size we'll use is 14
00179 
00180     m_show_dup_expand_msg = true;
00181     m_batch_count         = 0;
00182 }
00183 
00184 bool wxLuaStackDialog::Create(const wxLuaState& wxlState,
00185                               wxWindow* parent, wxWindowID id,
00186                               const wxString& title,
00187                               const wxPoint& pos, const wxSize& size_)
00188 {
00189     m_wxlState = wxlState;
00190 
00191     wxSize size(size_);
00192     if (size == wxDefaultSize) size = m_defaultSize;
00193 
00194     if (!wxDialog::Create(parent, id, title, pos, size,
00195             wxDEFAULT_DIALOG_STYLE | wxDIALOG_MODAL | wxMAXIMIZE_BOX | wxRESIZE_BORDER))
00196         return false;
00197 
00198     SetIcon(wxICON(LUA)); // set the frame icon
00199 
00200     // -----------------------------------------------------------------------
00201 
00202     m_imageList = new wxImageList(16, 16, true);
00203 
00204     wxBitmap bmp(wxArtProvider::GetIcon(wxART_NORMAL_FILE, wxART_TOOLBAR, wxSize(16,16)));
00205     m_imageList->Add(bmp); // IMG_NONE
00206     m_imageList->Add(bmp); // IMG_UNKNOWN
00207     m_imageList->Add(CreateBmpString(bmp, wxT("0"))); // IMG_NIL
00208     m_imageList->Add(CreateBmpString(bmp, wxT("b"))); // IMG_BOOLEAN
00209     m_imageList->Add(CreateBmpString(bmp, wxT("u"))); // IMG_LIGHTUSERDATA
00210     m_imageList->Add(CreateBmpString(bmp, wxT("1"))); // IMG_NUMBER
00211     m_imageList->Add(CreateBmpString(bmp, wxT("s"))); // IMG_STRING
00212     m_imageList->Add(wxArtProvider::GetIcon(wxART_FOLDER, wxART_TOOLBAR, wxSize(16,16))); // IMG_TABLE
00213     m_imageList->Add(CreateBmpString(bmp, wxT("f"))); // IMG_LUAFUNCTION
00214     m_imageList->Add(CreateBmpString(bmp, wxT("u"))); // IMG_USERDATA
00215     m_imageList->Add(CreateBmpString(bmp, wxT("t"))); // IMG_THREAD
00216     m_imageList->Add(CreateBmpString(bmp, wxT("1"))); // IMG_INTEGER
00217     m_imageList->Add(CreateBmpString(bmp, wxT("c"))); // IMG_CFUNCTION
00218     m_imageList->Add(wxArtProvider::GetIcon(wxART_NEW_DIR, wxART_TOOLBAR, wxSize(16,16))); // IMG_TABLE_OPEN
00219 
00220     // -----------------------------------------------------------------------
00221 
00222     m_typeColours[IMG_NONE]         = wxColour(wxT("DARK TURQUOISE"));
00223     m_typeColours[IMG_UNKNOWN]      = wxColour(wxT("DARK TURQUOISE"));
00224     m_typeColours[IMG_NIL]          = wxColour(wxT("BLACK"));
00225     m_typeColours[IMG_BOOLEAN]      = wxColour(wxT("FIREBRICK"));
00226     m_typeColours[IMG_LIGHTUSERDATA]= wxColour(wxT("CORNFLOWER BLUE"));
00227     m_typeColours[IMG_NUMBER]       = wxColour(wxT("DARK ORCHID"));
00228     m_typeColours[IMG_STRING]       = wxColour(wxT("RED"));
00229     m_typeColours[IMG_TABLE]        = wxColour(wxT("BLUE"));
00230     m_typeColours[IMG_LUAFUNCTION]  = wxColour(wxT("MEDIUM FOREST GREEN"));
00231     m_typeColours[IMG_USERDATA]     = wxColour(wxT("CORNFLOWER BLUE"));
00232     m_typeColours[IMG_THREAD]       = wxColour(wxT("BLACK"));
00233     m_typeColours[IMG_INTEGER]      = wxColour(wxT("DARK ORCHID"));
00234     m_typeColours[IMG_CFUNCTION]    = wxColour(wxT("FOREST GREEN"));
00235     m_typeColours[IMG_TABLE_OPEN]   = wxColour(wxT("BLUE"));
00236 
00237     // -----------------------------------------------------------------------
00238 
00239     wxPanel* panel = new wxPanel(this, wxID_ANY);
00240 
00241     // -----------------------------------------------------------------------
00242 
00243     wxStaticText* stackText = new wxStaticText( panel, wxID_ANY, wxT("Stack : "));
00244 
00245     m_stackChoice = new wxChoice( panel, ID_WXLUA_STACK_CHOICE,
00246                                   wxDefaultPosition, wxDefaultSize,
00247                                   0, NULL, 0, wxDefaultValidator ); // help GCC find which fn to call
00248     m_stackChoice->SetToolTip(wxT("Select Lua stack frame to display."));
00249 
00250     wxBitmapButton* expandButton = new wxBitmapButton(panel, ID_WXLUA_STACK_EXPAND_BUTTON,
00251                                           wxArtProvider::GetBitmap(wxART_ADD_BOOKMARK, wxART_BUTTON));
00252     expandButton->SetToolTip(wxT("Expand selected item's children (may take awhile)"));
00253 
00254     wxBitmapButton* collapseButton = new wxBitmapButton(panel, ID_WXLUA_STACK_COLLAPSE_BUTTON,
00255                                           wxArtProvider::GetBitmap(wxART_DEL_BOOKMARK, wxART_BUTTON));
00256     collapseButton->SetToolTip(wxT("Collapse selected item's children (may take awhile)"));
00257 
00258     // -----------------------------------------------------------------------
00259 
00260     wxStaticText* findText = new wxStaticText( panel, wxID_ANY, wxT("Find : "));
00261     m_findComboBox = new  wxComboBox( panel, ID_WXLUA_STACK_FIND_COMBO,
00262                                       wxEmptyString,
00263                                       wxDefaultPosition, wxDefaultSize,
00264                                       0, NULL, wxCB_DROPDOWN | wxTE_PROCESS_ENTER);
00265     m_findComboBox->SetToolTip(wxT("Enter string to find"));
00266 
00267     wxBitmapButton* findPrev = new wxBitmapButton( panel, ID_WXLUA_STACK_FINDPREV_BUTTON,
00268                                            wxArtProvider::GetBitmap(wxART_GO_BACK, wxART_BUTTON));
00269     wxBitmapButton* findNext = new wxBitmapButton( panel, ID_WXLUA_STACK_FINDNEXT_BUTTON,
00270                                            wxArtProvider::GetBitmap(wxART_GO_FORWARD, wxART_BUTTON));
00271     findPrev->SetToolTip(wxT("Find previous instance"));
00272     findNext->SetToolTip(wxT("Find next instance"));
00273 
00274     wxBitmapButton* findMenuButton = new wxBitmapButton(panel, ID_WXLUA_STACK_FINDMENU_BUTTON,
00275                                             wxArtProvider::GetBitmap(wxART_HELP_SETTINGS, wxART_BUTTON));
00276     findMenuButton->SetToolTip(wxT("Select find options"));
00277 
00278     m_findMenu = new wxMenu(wxT("Find Options"), 0);
00279     m_findMenu->Append(ID_WXLUA_STACK_FINDMENU_CASE,         wxT("&Case sensitive"),    wxT("Case sensitive searching"), wxITEM_CHECK);
00280     m_findMenu->Append(ID_WXLUA_STACK_FINDMENU_WHOLE_STRING, wxT("Match whole string"), wxT("Search for a string with an exact match"), wxITEM_CHECK);
00281     m_findMenu->AppendSeparator();
00282     m_findMenu->Append(ID_WXLUA_STACK_FINDMENU_ALL,       wxT("Search &everywhere"), wxT("Search in all columns"), wxITEM_CHECK);
00283     m_findMenu->Append(ID_WXLUA_STACK_FINDMENU_NAME,      wxT("Search &names"),      wxT("Search in name column"), wxITEM_CHECK);
00284     m_findMenu->Append(ID_WXLUA_STACK_FINDMENU_LEVEL,     wxT("Search &level"),      wxT("Search in level column"), wxITEM_CHECK);
00285     m_findMenu->Append(ID_WXLUA_STACK_FINDMENU_KEYTYPE,   wxT("Search &key type"),   wxT("Search in key type column"), wxITEM_CHECK);
00286     m_findMenu->Append(ID_WXLUA_STACK_FINDMENU_VALUETYPE, wxT("Search v&alue type"), wxT("Search in value type column"), wxITEM_CHECK);
00287     m_findMenu->Append(ID_WXLUA_STACK_FINDMENU_VALUE,     wxT("Search &values"),     wxT("Search in value column"), wxITEM_CHECK);
00288 
00289     m_findMenu->Check(ID_WXLUA_STACK_FINDMENU_NAME, true);
00290 
00291     // -----------------------------------------------------------------------
00292 
00293     wxFlexGridSizer* topSizer = new wxFlexGridSizer(2, 1);
00294     topSizer->AddGrowableCol(1);
00295 
00296     topSizer->Add(stackText, wxSizerFlags().Expand().Border().Align(wxALIGN_LEFT|wxALIGN_CENTER_VERTICAL));
00297 
00298     wxFlexGridSizer* stackSizer = new wxFlexGridSizer(3, 1);
00299     stackSizer->AddGrowableCol(0);
00300     stackSizer->Add(m_stackChoice, wxSizerFlags().Expand().Border());
00301     stackSizer->Add(collapseButton, wxSizerFlags().Border());
00302     stackSizer->Add(expandButton, wxSizerFlags().Border());
00303     topSizer->Add(stackSizer, wxSizerFlags().Expand());
00304 
00305     topSizer->Add(findText, wxSizerFlags().Expand().Border().Align(wxALIGN_LEFT|wxALIGN_CENTER_VERTICAL));
00306 
00307     wxFlexGridSizer* findSizer = new wxFlexGridSizer(4, 1);
00308     findSizer->AddGrowableCol(0);
00309     findSizer->Add(m_findComboBox, wxSizerFlags().Expand().Border());
00310     findSizer->Add(findPrev, wxSizerFlags().Expand().Border());
00311     findSizer->Add(findNext, wxSizerFlags().Expand().Border());
00312 
00313     findSizer->Add(findMenuButton, wxSizerFlags().Expand().Border());
00314 
00315     topSizer->Add(findSizer, wxSizerFlags().Expand());
00316 
00317     // -----------------------------------------------------------------------
00318 
00319     m_splitterWin = new wxSplitterWindow(panel, ID_WXLUA_STACK_SPLITTERWIN,
00320                                          wxDefaultPosition, wxDefaultSize,
00321                                          wxSP_3D);
00322     m_splitterWin->SetSashGravity(0.1);
00323     m_splitterWin->SetMinimumPaneSize(20);
00324 
00325     m_treeCtrl = new wxTreeCtrl(m_splitterWin, ID_WXLUA_STACK_TREECTRL,
00326                                 wxDefaultPosition, wxDefaultSize,
00327                                 wxTR_HAS_BUTTONS|wxTR_SINGLE|wxTR_HIDE_ROOT|wxTR_LINES_AT_ROOT);
00328 
00329     m_treeCtrl->SetImageList(m_imageList);
00330 
00331     m_listCtrl = new wxLuaStackListCtrl(this, m_splitterWin, ID_WXLUA_STACK_LISTCTRL,
00332                                 wxDefaultPosition, wxDefaultSize,
00333                                 wxLC_REPORT|wxLC_SINGLE_SEL|wxLC_HRULES|wxLC_VRULES|wxLC_VIRTUAL );
00334 
00335     m_listCtrl->SetImageList(m_imageList,          wxIMAGE_LIST_SMALL);
00336     m_listCtrl->InsertColumn(LIST_COL_KEY,        wxT("Name"),       wxLIST_FORMAT_LEFT, -1);
00337     m_listCtrl->InsertColumn(LIST_COL_LEVEL,      wxT("Level"),      wxLIST_FORMAT_LEFT, -1);
00338     m_listCtrl->InsertColumn(LIST_COL_KEY_TYPE,   wxT("Key Type"),   wxLIST_FORMAT_LEFT, -1);
00339     m_listCtrl->InsertColumn(LIST_COL_VALUE_TYPE, wxT("Value Type"), wxLIST_FORMAT_LEFT, -1);
00340     m_listCtrl->InsertColumn(LIST_COL_VALUE,      wxT("Value"),      wxLIST_FORMAT_LEFT, -1);
00341 
00342     int txt_width = 0, txt_height = 0;
00343 
00344     m_listCtrl->GetTextExtent(wxString(wxT('W'), 25), &txt_width, &txt_height);
00345 
00346 
00347     m_listCtrl->SetColumnWidth(0, txt_width);
00348     m_listCtrl->SetColumnWidth(4, 4*txt_width); // make it wide since it's the last
00349     m_listCtrl->GetTextExtent(wxT("555:5555"), &txt_width, &txt_height);
00350     m_listCtrl->SetColumnWidth(1, txt_width);
00351     m_listCtrl->GetTextExtent(wxT("Light User DataX"), &txt_width, &txt_height);
00352     m_listCtrl->SetColumnWidth(2, txt_width);
00353     m_listCtrl->SetColumnWidth(3, txt_width);
00354 
00355     m_listMenu = new wxMenu(wxEmptyString, 0);
00356     m_listMenu->Append(ID_WXLUA_STACK_LISTMENU_COPY0, wxT("Copy name"),       wxT("Copy name to clipboard"), wxITEM_NORMAL);
00357     m_listMenu->Append(ID_WXLUA_STACK_LISTMENU_COPY1, wxT("Copy level"),      wxT("Copy level to clipboard"), wxITEM_NORMAL);
00358     m_listMenu->Append(ID_WXLUA_STACK_LISTMENU_COPY2, wxT("Copy key type"),   wxT("Copy key type to clipboard"), wxITEM_NORMAL);
00359     m_listMenu->Append(ID_WXLUA_STACK_LISTMENU_COPY3, wxT("Copy value type"), wxT("Copy value type to clipboard"), wxITEM_NORMAL);
00360     m_listMenu->Append(ID_WXLUA_STACK_LISTMENU_COPY4, wxT("Copy value"),      wxT("Copy value to clipboard"), wxITEM_NORMAL);
00361 
00362     // -----------------------------------------------------------------------
00363 
00364     m_splitterWin->SplitVertically(m_treeCtrl, m_listCtrl, 160);
00365 
00366     // use sizers to layout the windows in the panel of the dialog
00367     wxBoxSizer* rootSizer = new wxBoxSizer(wxVERTICAL);
00368     rootSizer->Add(topSizer, 0, wxEXPAND|wxBOTTOM, 5);
00369     rootSizer->Add(m_splitterWin, 1, wxEXPAND);
00370     rootSizer->SetMinSize(200, 150);
00371     panel->SetSizer(rootSizer);
00372     rootSizer->SetSizeHints(this);
00373 
00374     SetSize(size); // force last good/known size
00375 
00376     EnumerateStack();
00377 
00378     return true;
00379 }
00380 
00381 wxLuaStackDialog::~wxLuaStackDialog()
00382 {
00383     if (!IsFullScreen() && !IsIconized() && !IsMaximized())
00384         m_defaultSize = GetSize();
00385 
00386     RemoveAllLuaReferences();
00387     DeleteAllListItemData();
00388 
00389     delete m_listMenu;
00390     delete m_findMenu;
00391 
00392     if (m_listCtrl) m_listCtrl->SetImageList(NULL, wxIMAGE_LIST_SMALL);
00393     if (m_treeCtrl) m_treeCtrl->SetImageList(NULL);
00394     delete m_imageList;
00395 }
00396 
00397 wxBitmap wxLuaStackDialog::CreateBmpString(const wxBitmap& bmp_, const wxString& s)
00398 {
00399     wxBitmap bmp(bmp_); // unconst it
00400     int bmp_w = bmp.GetWidth();
00401     int bmp_h = bmp.GetHeight();
00402 
00403     wxMemoryDC dc;
00404     dc.SelectObject(bmp);
00405 
00406     wxFont font(m_img_font_size, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
00407     wxCoord w = 0, h = 0;
00408 
00409     // after first time to find font size, run once to get the text extent
00410     for ( ; m_img_font_size > 3; --m_img_font_size)
00411     {
00412         dc.GetTextExtent(s, &w, &h, NULL, NULL, &font);
00413 
00414         if ((w < bmp_w) && (h < bmp_h))
00415             break;
00416 
00417         font.SetPointSize(m_img_font_size);
00418     }
00419 
00420     dc.SetFont(font);
00421     dc.DrawText(s, (bmp_w-w)/2, (bmp_h-h)/2);
00422     dc.SelectObject(wxNullBitmap);
00423 
00424     return bmp;
00425 }
00426 
00427 int wxLuaStackDialog::GetItemImage(const wxLuaDebugItem *dbgItem)
00428 {
00429     wxCHECK_MSG(dbgItem, IMG_UNKNOWN, wxT("Invalid wxLuaDebugItem"));
00430 
00431     int img = IMG_NONE;
00432 
00433     // Expanded nodes all use the open table icon
00434     if (dbgItem->GetFlagBit(WXLUA_DEBUGITEM_EXPANDED))
00435         img = IMG_TABLE_OPEN;
00436     else if (dbgItem->GetFlagBit(WXLUA_DEBUGITEM_LOCALS))
00437         img = IMG_TABLE;
00438     else
00439     {
00440         switch (dbgItem->GetValueType())
00441         {
00442             case WXLUA_TUNKNOWN        : img = IMG_UNKNOWN; break;
00443             case WXLUA_TNONE           : img = IMG_NONE; break;
00444             case WXLUA_TNIL            : img = IMG_NIL; break;
00445             case WXLUA_TBOOLEAN        : img = IMG_BOOLEAN; break;
00446             case WXLUA_TLIGHTUSERDATA  : img = IMG_LIGHTUSERDATA; break;
00447             case WXLUA_TNUMBER         : img = IMG_NUMBER; break;
00448             case WXLUA_TSTRING         : img = IMG_STRING; break;
00449             case WXLUA_TTABLE          : img = IMG_TABLE; break;
00450             case WXLUA_TFUNCTION       : img = IMG_LUAFUNCTION; break;
00451             case WXLUA_TUSERDATA       : img = IMG_USERDATA; break;
00452             case WXLUA_TTHREAD         : img = IMG_THREAD; break;
00453             case WXLUA_TINTEGER        : img = IMG_INTEGER; break;
00454             case WXLUA_TCFUNCTION      : img = IMG_CFUNCTION; break;
00455         }
00456     }
00457 
00458     return img;
00459 }
00460 
00461 wxString wxLuaStackDialog::GetItemText(long item, long column, bool exact_value)
00462 {
00463     wxLuaStackListData* stkListData = (wxLuaStackListData*)m_listData[item];
00464     wxCHECK_MSG(stkListData, wxEmptyString, wxT("Invalid wxLuaStackListData item"));
00465     wxLuaDebugItem* debugItem = stkListData->GetDebugItem();
00466     wxCHECK_MSG(debugItem, wxEmptyString, wxT("Invalid wxLuaDebugItem item"));
00467 
00468     switch (column)
00469     {
00470         case LIST_COL_KEY:
00471         {
00472             if (exact_value)
00473                 return debugItem->GetKey();
00474 
00475             if (stkListData->m_level > 0)
00476             {
00477                 //wxString s(wxT("-->"));
00478                 //for (int i = 1; i < stkListData->m_level; ++i) s += wxT("-->");
00479 
00480                 return wxString(wxT(' '), stkListData->m_level*4) + debugItem->GetKey();
00481             }
00482             else
00483                 return debugItem->GetKey();
00484         }
00485         case LIST_COL_LEVEL:
00486             return wxString::Format(wxT("%d:%d"), stkListData->m_level+1, stkListData->m_item_idx+1);
00487         case LIST_COL_KEY_TYPE:
00488             return debugItem->GetKeyTypeString();
00489         case LIST_COL_VALUE_TYPE:
00490             return debugItem->GetValueTypeString();
00491         case LIST_COL_VALUE:
00492         {
00493             if (exact_value)
00494                 return debugItem->GetValue();
00495 
00496             wxString value(debugItem->GetValue());
00497             if (value.Length() > 200) value = value.Mid(0, 200) + wxT("... <snip>");
00498             value.Replace(wxT("\n"), wxT("\\n"));
00499             value.Replace(wxT("\r"), wxT("\\r"));
00500             return value;
00501         }
00502     }
00503 
00504     return wxEmptyString;
00505 }
00506 
00507 void wxLuaStackDialog::EnumerateStack()
00508 {
00509     wxCHECK_RET(m_wxlState.Ok(), wxT("Invalid wxLuaState"));
00510     wxBusyCursor wait;
00511     wxLuaDebugData debugData(true);
00512     debugData.EnumerateStack(m_wxlState);
00513     FillStackCombobox(debugData);
00514 }
00515 void wxLuaStackDialog::EnumerateStackEntry(int nEntry)
00516 {
00517     wxCHECK_RET(m_wxlState.Ok(), wxT("Invalid wxLuaState"));
00518     wxBusyCursor wait;
00519     wxLuaDebugData debugData(true);
00520     debugData.EnumerateStackEntry(m_wxlState, nEntry, m_luaReferences);
00521     FillStackEntry(nEntry, debugData);
00522 }
00523 void wxLuaStackDialog::EnumerateTable(int nRef, int nEntry, long lc_item)
00524 {
00525     wxCHECK_RET(m_wxlState.Ok(), wxT("Invalid wxLuaState"));
00526     wxBusyCursor wait;
00527     wxLuaDebugData debugData(true);
00528     debugData.EnumerateTable(m_wxlState, nRef, nEntry, m_luaReferences);
00529     FillTableEntry(lc_item, debugData);
00530 }
00531 void wxLuaStackDialog::EnumerateGlobalData(long lc_item)
00532 {
00533     wxCHECK_RET(m_wxlState.Ok(), wxT("Invalid wxLuaState"));
00534     wxBusyCursor wait;
00535     wxLuaDebugData debugData(true);
00536     debugData.EnumerateTable(m_wxlState, -1, -1, m_luaReferences); // Get global table
00537     FillTableEntry(lc_item, debugData);
00538 }
00539 
00540 void wxLuaStackDialog::FillStackCombobox(const wxLuaDebugData& debugData)
00541 {
00542     wxCHECK_RET(debugData.Ok(), wxT("Invalid wxLuaDebugData in FillStackCombobox"));
00543 
00544     m_stackChoice->Clear();
00545     m_stackEntries.Clear();
00546 
00547     size_t n, count = debugData.GetCount();
00548     for (n = 0; n < count; ++n)
00549     {
00550         const wxLuaDebugItem *item = debugData.Item(n);
00551         m_stackEntries.Add(item->GetIndex());
00552         wxString name(item->GetKey());
00553         if (n == count - 1) name += wxT(" (Globals)");
00554         m_stackChoice->Append(name);
00555     }
00556 
00557     if (count > 0)
00558     {
00559         m_stackChoice->SetSelection(0);
00560         SelectStack(0);
00561     }
00562 }
00563 
00564 void wxLuaStackDialog::FillStackEntry(int WXUNUSED(nEntry), const wxLuaDebugData& debugData)
00565 {
00566     wxCHECK_RET(debugData.Ok(), wxT("Invalid wxLuaDebugData in FillStackEntry"));
00567 
00568     RemoveAllLuaReferences();
00569     DeleteAllListItemData();
00570     m_expandedItems.clear();
00571     m_listCtrl->SetItemCount(0);
00572 
00573     m_treeCtrl->DeleteAllItems();
00574     m_treeCtrl->AddRoot(wxT("wxLua Data"), -1, -1, NULL);
00575     m_treeCtrl->SetItemHasChildren(m_treeCtrl->GetRootItem());
00576 
00577     // Add the locals, fake a debug item to get it setup right
00578     wxLuaDebugItem* localItem  = new wxLuaDebugItem(_("Locals"), WXLUA_TNONE,
00579                     wxString::Format(wxT("%d Items"), (int)debugData.GetCount()), WXLUA_TNONE,
00580                     wxT(""), LUA_NOREF, 0, WXLUA_DEBUGITEM_EXPANDED|WXLUA_DEBUGITEM_LOCALS|WXLUA_DEBUGITEM_VALUE_REF);
00581     wxLuaDebugData localData(true); // this deletes the items
00582     localData.Add(localItem);
00583     FillTableEntry(m_listCtrl->GetItemCount(), localData);
00584 
00585     if (debugData.GetCount() > 0u)
00586         FillTableEntry(m_listCtrl->GetItemCount()-1, debugData);
00587 
00588     //  If at global scope, process globals
00589     if (m_stack_sel == (int)m_stackEntries.GetCount() - 1)
00590     {
00591         EnumerateGlobalData(m_listCtrl->GetItemCount()); // new item, put at end
00592 
00593         // for debugging also add the registry
00594         if (m_wxlState.Ok())
00595         {
00596             wxLuaDebugData regData(true);
00597             regData.EnumerateTable(m_wxlState, LUA_REGISTRYINDEX, -1, m_luaReferences); // Get global table
00598             FillTableEntry(m_listCtrl->GetItemCount(), regData);
00599         }
00600     }
00601 }
00602 
00603 void wxLuaStackDialog::FillTableEntry(long lc_item_, const wxLuaDebugData& debugData)
00604 {
00605     wxCHECK_RET(debugData.Ok(), wxT("Invalid wxLuaDebugData in FillTableEntry"));
00606 
00607     wxCHECK_RET(lc_item_ <= m_listCtrl->GetItemCount(), wxT("Attempting to add list item past end"));
00608 
00609     if (debugData.GetCount() > 0)
00610     {
00611         wxTreeItemId treeId;
00612         wxString levelStr;
00613         int level = 0;
00614 
00615         // If less than the count we're expanding a item, else adding a new root
00616         if (lc_item_ < (long)m_listData.GetCount())
00617         {
00618             // Set the children data for the parent
00619             wxLuaStackListData* stkListData = (wxLuaStackListData*)m_listData[lc_item_];
00620             wxCHECK_RET((stkListData != NULL), wxT("The wxLuaStackDialog does have stack data!"));
00621             // sanity check, either add new children data or we're expanding using the old data
00622             wxCHECK_RET(!stkListData->m_childrenDebugData.Ok() || (stkListData->m_childrenDebugData == debugData), wxT("Replacing the child data?"));
00623             if (!stkListData->m_childrenDebugData.Ok())
00624                 stkListData->m_childrenDebugData = debugData;
00625 
00626             treeId = stkListData->m_treeId;
00627             if (!treeId) treeId = m_treeCtrl->GetRootItem();
00628 
00629             level = stkListData->m_level+1;
00630         }
00631         else
00632         {
00633             treeId = m_treeCtrl->GetRootItem();
00634             lc_item_--;
00635         }
00636 
00637         m_treeCtrl->SetItemHasChildren(treeId);
00638 
00639         BeginBatch();
00640 
00641         bool removed_tree_dummy = false;
00642         size_t n, count = debugData.GetCount();
00643 
00644         long lc_item = lc_item_;
00645         for (n = 0; n < count; ++n)
00646         {
00647             wxLuaStackListData* stkListData = new wxLuaStackListData(n, level, debugData);
00648             m_listData.Insert(stkListData, lc_item+n+1);
00649 
00650             wxLuaDebugItem* debugItem = debugData.Item(n);
00651 
00652             int img = GetItemImage(debugItem);
00653 
00654             if ((debugItem->GetRef() != LUA_NOREF) ||
00655                  debugItem->GetFlagBit(WXLUA_DEBUGITEM_LOCALS))
00656             {
00657                 wxTreeItemId id = m_treeCtrl->AppendItem(treeId, debugItem->GetKey(), -1, -1, new wxLuaStackTreeData(stkListData));
00658                 m_treeCtrl->SetItemHasChildren(id);
00659                 stkListData->m_treeId = id;
00660 
00661                 // add dummy item for MSW to expand properly, also it shows that
00662                 // there's nothing in this level if they try to expand it and there
00663                 // aren't any real items (see below)
00664                 m_treeCtrl->AppendItem(id, DUMMY_TREEITEM);
00665 
00666                 // now that we've added something, remove the first dummy " " item from parent
00667                 if (!removed_tree_dummy)
00668                 {
00669                     removed_tree_dummy = true;
00670 
00671                     wxTreeItemIdValue dummyCookie;
00672                     wxTreeItemId dummyId = m_treeCtrl->GetFirstChild(treeId, dummyCookie);
00673                     if (m_treeCtrl->GetItemText(dummyId) == DUMMY_TREEITEM)
00674                         m_treeCtrl->Delete(dummyId);
00675                 }
00676             }
00677         }
00678 
00679         m_listCtrl->SetItemCount(m_listData.GetCount());
00680 
00681         EndBatch();
00682 
00683         // NOTE : The MSW treectrl will expand and immediately collapse a node if you call Expand()
00684         // from within a handler, don't do anything and it works...
00685 #if !defined(WXLUA_STACK_MSWTREE)
00686         // Cannot expand hidden root, nor can you check it
00687         if (treeId && !m_treeCtrl->IsExpanded(treeId) &&
00688             ((treeId != m_treeCtrl->GetRootItem()) || ((m_treeCtrl->GetWindowStyle() & wxTR_HIDE_ROOT) == 0)))
00689             m_treeCtrl->Expand(treeId);
00690 #endif //!defined(WXLUA_STACK_MSWTREE)
00691     }
00692 }
00693 
00694 void wxLuaStackDialog::BeginBatch()
00695 {
00696     if (m_batch_count == 0)
00697     {
00698         m_listCtrl->Freeze();
00699         m_treeCtrl->Freeze();
00700     }
00701 
00702     ++m_batch_count;
00703 }
00704 
00705 void wxLuaStackDialog::EndBatch()
00706 {
00707     if (m_batch_count == 1)
00708     {
00709         m_listCtrl->Thaw();
00710         m_treeCtrl->Thaw();
00711     }
00712 
00713     if (m_batch_count > 0)
00714         m_batch_count--;
00715 }
00716 
00717 long wxLuaStackDialog::FindListItem(wxLuaStackListData* stkListData, bool get_parent) const
00718 {
00719     long n, count = m_listCtrl->GetItemCount();
00720     wxLuaStackListData* stkListData_n = NULL;
00721 
00722     for (n = 0; n < count; ++n)
00723     {
00724         stkListData_n = (wxLuaStackListData*)m_listData[n];
00725 
00726         if (!get_parent && (stkListData_n == stkListData))
00727             return n;
00728         else if (get_parent && (stkListData_n->m_childrenDebugData == stkListData->m_parentDebugData))
00729             return n;
00730     }
00731 
00732     return wxNOT_FOUND;
00733 }
00734 
00735 void wxLuaStackDialog::OnExpandButton(wxCommandEvent &event)
00736 {
00737     long start_item = m_listCtrl->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
00738     // they must select an item
00739     if (start_item < 0) return;
00740 
00741     if (event.GetId() == ID_WXLUA_STACK_EXPAND_BUTTON)
00742         ExpandItemChildren(start_item);
00743     else
00744         CollapseItem(start_item);
00745 }
00746 
00747 // This code is copied from wxStEdit's function wxSTEPrependComboBoxString
00748 void wxLuaPrependComboBoxString(const wxString &str, int max_strings, wxComboBox *combo)
00749 {
00750     wxCHECK_RET(combo, wxT("Invalid combobox in wxLuaPrependComboBoxString"));
00751 
00752     int pos = combo->FindString(str);
00753     if (pos == 0)
00754         return;
00755     if (pos != wxNOT_FOUND)
00756         combo->Delete(pos);
00757 
00758     combo->Insert(str, 0);
00759     combo->SetSelection(0);
00760 
00761     while ((max_strings > 0) && ((int)combo->GetCount() > max_strings))
00762         combo->Delete(combo->GetCount()-1);
00763 }
00764 
00765 void wxLuaStackDialog::OnMenu(wxCommandEvent& event)
00766 {
00767     int id = event.GetId();
00768     bool checked = event.IsChecked();
00769 
00770     if (id == ID_WXLUA_STACK_FINDMENU_ALL)
00771     {
00772         m_findMenu->Check(ID_WXLUA_STACK_FINDMENU_NAME,      checked);
00773         m_findMenu->Check(ID_WXLUA_STACK_FINDMENU_LEVEL,     checked);
00774         m_findMenu->Check(ID_WXLUA_STACK_FINDMENU_KEYTYPE,   checked);
00775         m_findMenu->Check(ID_WXLUA_STACK_FINDMENU_VALUETYPE, checked);
00776         m_findMenu->Check(ID_WXLUA_STACK_FINDMENU_VALUE,     checked);
00777     }
00778     else if ((id >= ID_WXLUA_STACK_FINDMENU_NAME) && (id <= ID_WXLUA_STACK_FINDMENU_VALUE))
00779     {
00780         bool all_checked = m_findMenu->IsChecked(ID_WXLUA_STACK_FINDMENU_NAME) &&
00781                            m_findMenu->IsChecked(ID_WXLUA_STACK_FINDMENU_LEVEL) &&
00782                            m_findMenu->IsChecked(ID_WXLUA_STACK_FINDMENU_KEYTYPE) &&
00783                            m_findMenu->IsChecked(ID_WXLUA_STACK_FINDMENU_VALUETYPE) &&
00784                            m_findMenu->IsChecked(ID_WXLUA_STACK_FINDMENU_VALUE);
00785 
00786         if (m_findMenu->IsChecked(ID_WXLUA_STACK_FINDMENU_ALL) != checked)
00787             m_findMenu->Check(ID_WXLUA_STACK_FINDMENU_ALL, all_checked);
00788     }
00789     else if ((id >= ID_WXLUA_STACK_LISTMENU_COPY0) && (id <= ID_WXLUA_STACK_LISTMENU_COPY4))
00790     {
00791         long list_item = m_listCtrl->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
00792         // they must select an item
00793         if (list_item >= 0)
00794         {
00795             wxString s(GetItemText(list_item, id - ID_WXLUA_STACK_LISTMENU_COPY0, true));
00796 
00797             if (wxTheClipboard->Open())
00798             {
00799                 // These data objects are held by the clipboard,
00800                 // so do not delete them in the app.
00801                 wxTheClipboard->SetData( new wxTextDataObject(s) );
00802                 wxTheClipboard->Close();
00803             }
00804         }
00805     }
00806 }
00807 
00808 void wxLuaStackDialog::OnFind(wxCommandEvent &event)
00809 {
00810     if (event.GetId() == ID_WXLUA_STACK_FINDMENU_BUTTON)
00811     {
00812         wxWindow* button = ((wxWindow*)event.GetEventObject());
00813         wxSize s(button->GetSize());
00814         button->PopupMenu(m_findMenu, 0, s.GetHeight());
00815 
00816         return;
00817     }
00818 
00819     // Remaining events we handle are for finding
00820 
00821     bool find_col[5] = {
00822         m_findMenu->IsChecked(ID_WXLUA_STACK_FINDMENU_NAME),
00823         m_findMenu->IsChecked(ID_WXLUA_STACK_FINDMENU_LEVEL),
00824         m_findMenu->IsChecked(ID_WXLUA_STACK_FINDMENU_KEYTYPE),
00825         m_findMenu->IsChecked(ID_WXLUA_STACK_FINDMENU_VALUETYPE),
00826         m_findMenu->IsChecked(ID_WXLUA_STACK_FINDMENU_VALUE),
00827     };
00828 
00829     // Send warning instead of silently doing nothing
00830     if (!find_col[0] && !find_col[1] && !find_col[2] && !find_col[3] && !find_col[4])
00831     {
00832         wxMessageBox(wxT("Please select at least one column to search with the find options button"),
00833                      wxT("wxLua Stack Find Error"),
00834                      wxOK|wxICON_EXCLAMATION|wxCENTRE, this);
00835         return;
00836     }
00837 
00838     wxString findStr = m_findComboBox->GetValue();
00839     if (findStr.IsEmpty())
00840         return;
00841 
00842     wxBusyCursor busy;
00843     wxLuaPrependComboBoxString(findStr, 10, m_findComboBox);
00844 
00845     bool match_case = m_findMenu->IsChecked(ID_WXLUA_STACK_FINDMENU_CASE);
00846     if (!match_case) findStr = findStr.Lower();
00847 
00848     bool whole_string = m_findMenu->IsChecked(ID_WXLUA_STACK_FINDMENU_WHOLE_STRING);
00849 
00850     long direction = (event.GetId() == ID_WXLUA_STACK_FINDPREV_BUTTON) ? -1 : 1;
00851 
00852     long list_count = m_listCtrl->GetItemCount();
00853     long start_item = m_listCtrl->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
00854 
00855     int wrap_count = 0; // start at current item and wrap back around
00856 
00857     bool found = false;
00858     wxString txt;
00859 
00860     while ((wrap_count < 2) && !found)
00861     {
00862         long i = 0;
00863         found = false;
00864 
00865         if (wrap_count == 0)
00866         {
00867             i = start_item + direction;
00868 
00869             // tweak up the starting item
00870             if (start_item < 0)
00871             {
00872                 i = (direction > 0) ? 0 : list_count - 1;
00873                 ++wrap_count; // we're looking at all the elements
00874             }
00875             else if ((direction > 0) && (start_item == list_count - 1))
00876             {
00877                 i = 0;
00878                 ++wrap_count; // we're looking at all the elements
00879             }
00880         }
00881         else
00882         {
00883             i = (direction > 0) ? 0 : list_count - 1;
00884         }
00885 
00886         for ( ; (i >= 0) && (i < list_count) && !found; i = i + direction)
00887         {
00888             for (int col = 0; (col < 5) && !found; ++col)
00889             {
00890                 if (!find_col[col]) continue;
00891 
00892                 txt = GetItemText(i, col, true);
00893                 if (!match_case) txt.MakeLower();
00894 
00895                 if ((whole_string && (txt == findStr)) ||
00896                     (!whole_string && (txt.Find(findStr) != wxNOT_FOUND)))
00897                 {
00898                     m_listCtrl->SetItemState(i, wxLIST_STATE_FOCUSED, wxLIST_STATE_FOCUSED);
00899                     m_listCtrl->SetItemState(i, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED);
00900                     m_listCtrl->EnsureVisible(i);
00901                     found = true;
00902                     break;
00903                 }
00904             }
00905         }
00906 
00907         ++wrap_count;
00908     }
00909 }
00910 
00911 void wxLuaStackDialog::OnSelectStack(wxCommandEvent &event)
00912 {
00913     if (event.GetSelection() >= 0)
00914         SelectStack(event.GetSelection());
00915 }
00916 
00917 void wxLuaStackDialog::SelectStack(int stack_sel)
00918 {
00919     wxCHECK_RET((stack_sel >= 0) && (stack_sel < (int)m_stackEntries.GetCount()), wxT("Invalid stack index"));
00920     m_stack_sel = stack_sel;
00921     int n_entry = m_stackEntries[m_stack_sel];
00922     EnumerateStackEntry(n_entry);
00923 }
00924 
00925 void wxLuaStackDialog::OnTreeItem(wxTreeEvent &event)
00926 {
00927     if (m_batch_count > 0) return;
00928 
00929     wxTreeItemId id = event.GetItem();
00930     wxLuaStackTreeData* stkTreeData = (wxLuaStackTreeData*)m_treeCtrl->GetItemData(id);
00931     if (stkTreeData == NULL) return; // root has no data
00932 
00933     long list_item = FindListItem(stkTreeData->m_stkListData);
00934 
00935     if (list_item < 0) return; // not an item that we can do anything with
00936 
00937     int evt_type = event.GetEventType();
00938 
00939     if (evt_type == wxEVT_COMMAND_TREE_ITEM_EXPANDED)
00940     {
00941         wxBusyCursor busy;
00942         ExpandItem(list_item);
00943         m_listCtrl->RefreshItem(list_item);
00944     }
00945     else if (evt_type == wxEVT_COMMAND_TREE_ITEM_COLLAPSED)
00946     {
00947         wxBusyCursor busy;
00948         CollapseItem(list_item);
00949         m_listCtrl->RefreshItem(list_item);
00950     }
00951     else if (evt_type == wxEVT_COMMAND_TREE_SEL_CHANGED)
00952     {
00953         m_listCtrl->SetItemState(list_item, wxLIST_STATE_FOCUSED, wxLIST_STATE_FOCUSED);
00954         m_listCtrl->SetItemState(list_item, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED);
00955         m_listCtrl->EnsureVisible(list_item);
00956     }
00957 }
00958 
00959 void wxLuaStackDialog::OnListItem(wxListEvent &event)
00960 {
00961     long list_item = event.GetIndex();
00962 
00963     wxLuaStackListData* stkListData = (wxLuaStackListData*)m_listData[list_item];
00964     wxCHECK_RET(stkListData != NULL, wxT("Invalid wxLuaStack data"));
00965     wxLuaDebugItem* debugItem = stkListData->GetDebugItem();
00966     wxCHECK_RET(debugItem != NULL, wxT("Invalid debug item"));
00967 
00968     if (event.GetEventType() == wxEVT_COMMAND_LIST_ITEM_SELECTED)
00969     {
00970         if (stkListData->m_treeId)
00971         {
00972             m_treeCtrl->SelectItem(stkListData->m_treeId, true);
00973             m_treeCtrl->EnsureVisible(stkListData->m_treeId);
00974         }
00975     }
00976     else if (event.GetEventType() == wxEVT_COMMAND_LIST_ITEM_ACTIVATED)
00977     {
00978         if (!debugItem->GetFlagBit(WXLUA_DEBUGITEM_EXPANDED))
00979         {
00980             if (ExpandItem(list_item))
00981             {
00982                 // Hack for WXLUA_STACK_MSWTREE, need children to expand
00983                 if (stkListData->m_treeId && !m_treeCtrl->IsExpanded(stkListData->m_treeId))
00984                     m_treeCtrl->Expand(stkListData->m_treeId);
00985             }
00986         }
00987         else
00988         {
00989             // Hack for WXLUA_STACK_MSWTREE, need children to collapse
00990             if (stkListData->m_treeId && m_treeCtrl->IsExpanded(stkListData->m_treeId))
00991                 m_treeCtrl->Collapse(stkListData->m_treeId);
00992 
00993             CollapseItem(list_item);
00994         }
00995 
00996         // refresh here and not in Expand/CollapseItem() to make ExpandItemChildren() faster.
00997         m_listCtrl->RefreshItem(list_item);
00998     }
00999 }
01000 
01001 void wxLuaStackDialog::OnListRightClick(wxListEvent &event) // FIXME for easy debugging of mem addresses
01002 {
01003     event.Skip();
01004 
01005     if (event.GetIndex() >= 0)
01006         m_listCtrl->PopupMenu(m_listMenu);
01007 }
01008 
01009 bool wxLuaStackDialog::ExpandItem(long lc_item)
01010 {
01011     wxCHECK_MSG((lc_item >= 0) && (lc_item < (long)m_listData.GetCount()), false,
01012                 wxT("Invalid list item to expand"));
01013 
01014     bool expanded = false;
01015 
01016     wxLuaStackListData* stkListData = (wxLuaStackListData*)m_listData[lc_item];
01017     wxCHECK_MSG(stkListData != NULL, false, wxT("Invalid wxLuaStack data"));
01018     wxLuaDebugItem* debugItem = stkListData->GetDebugItem();
01019     wxCHECK_MSG(debugItem != NULL, false, wxT("Invalid debug item"));
01020 
01021     int nRef = debugItem->GetRef();
01022 
01023     if (!debugItem->GetFlagBit(WXLUA_DEBUGITEM_EXPANDED))
01024     {
01025         // re-expand the item that was previously collapsed
01026         if (stkListData->m_childrenDebugData.Ok())
01027         {
01028             debugItem->SetFlagBit(WXLUA_DEBUGITEM_EXPANDED, true);
01029 
01030             long long_key = 0;
01031             if (debugItem->GetRefPtr(long_key))
01032                 m_expandedItems[long_key] = (long)stkListData;
01033 
01034             FillTableEntry(lc_item, stkListData->m_childrenDebugData);
01035             expanded = true;
01036             return true;
01037         }
01038 
01039         // Check and block linked tables already shown, select it and return
01040         if (debugItem->GetRef() != LUA_NOREF)
01041         {
01042             long long_key = 0;
01043             wxCHECK_MSG(debugItem->GetRefPtr(long_key), false, wxT("Invalid table item"));
01044 
01045             if (m_expandedItems[long_key])
01046             {
01047                 if (m_show_dup_expand_msg)
01048                 {
01049                     wxMessageBox(wxT("Cannot expand linked tables,\nplease see the already expanded table."),
01050                         wxT("wxLua Stack"), wxOK | wxCENTRE, this);
01051 
01052                     int n = m_listData.Index((void*)m_expandedItems[long_key]);
01053                     wxCHECK_MSG(n != wxNOT_FOUND, false, wxT("Unable to find hash of expanded items."));
01054 
01055                     m_listCtrl->SetItemState(n, wxLIST_STATE_FOCUSED, wxLIST_STATE_FOCUSED);
01056                     m_listCtrl->SetItemState(n, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED);
01057                     m_listCtrl->EnsureVisible(n);
01058                 }
01059 
01060                 return false;
01061             }
01062         }
01063 
01064         if (nRef != LUA_NOREF)
01065         {
01066             debugItem->SetFlagBit(WXLUA_DEBUGITEM_EXPANDED, true);
01067 
01068             long long_key = 0;
01069             wxCHECK_MSG(debugItem->GetRefPtr(long_key), false, wxT("Invalid table item"));
01070             m_expandedItems[long_key] = (long)stkListData;
01071 
01072             int nIndex = debugItem->GetIndex() + 1;
01073             EnumerateTable(nRef, nIndex, lc_item);
01074             expanded = true;
01075         }
01076     }
01077 
01078     return expanded;
01079 }
01080 
01081 bool wxLuaStackDialog::ExpandItemChildren(long lc_item)
01082 {
01083     wxCHECK_MSG((lc_item >= 0) && (lc_item < (long)m_listData.GetCount()), false,
01084                 wxT("Invalid list item to expand"));
01085 
01086     bool expanded = false;
01087 
01088     wxProgressDialog* dlg =
01089         new wxProgressDialog(wxT("wxLua Stack Expanding node"), wxEmptyString, 100, this,
01090                              wxPD_AUTO_HIDE | wxPD_APP_MODAL | wxPD_CAN_ABORT);
01091 
01092     BeginBatch();
01093 
01094     // Note: Iterating through all of the listctrl items, even though most of
01095     // them are not expandable, is MUCH faster than using the far fewer
01096     // wxTreeCtrl items and calling Expand() on them.
01097 
01098     wxLuaStackListData* stkListData = (wxLuaStackListData*)m_listData[lc_item];
01099 
01100     int counter = 0;
01101     int n = lc_item, level = stkListData->m_level;
01102     while (n < (int)m_listData.GetCount())
01103     {
01104         // show message for first item only so it doesn't silently fail
01105         if (n > lc_item) m_show_dup_expand_msg = false;
01106 
01107         wxLuaStackListData* stkListData_n = (wxLuaStackListData*)m_listData[n];
01108 
01109         if ((n > lc_item) && (stkListData_n->m_level <= level)) break;
01110 
01111         if (counter % 20 == 0)
01112         {
01113             if (!dlg->Pulse(wxString::Format(wxT("Expanding nodes : %d"), counter)))
01114                 break;
01115         }
01116 
01117         if (!stkListData_n->GetDebugItem()->GetFlagBit(WXLUA_DEBUGITEM_EXPANDED))
01118             expanded |= ExpandItem(n);
01119 
01120         ++counter;
01121         ++n;
01122     }
01123 
01124     dlg->Destroy();
01125 
01126     EndBatch();
01127     m_show_dup_expand_msg = true;
01128 
01129     return expanded;
01130 }
01131 
01132 bool wxLuaStackDialog::CollapseItem(long lc_item)
01133 {
01134     wxCHECK_MSG((lc_item >= 0) && (lc_item < m_listCtrl->GetItemCount()), false,
01135                 wxT("Invalid list item to expand"));
01136 
01137     bool collapsed = false;
01138 
01139     wxLuaStackListData* stkListData = (wxLuaStackListData*)m_listData[lc_item];
01140     wxCHECK_MSG(stkListData != NULL, false, wxT("Invalid wxLuaStack data"));
01141     wxLuaDebugItem* debugItem = stkListData->GetDebugItem();
01142     wxCHECK_MSG((debugItem != NULL), false, wxT("Invalid debug item"));
01143     wxLuaDebugData childData = stkListData->m_childrenDebugData;
01144 
01145     BeginBatch();
01146 
01147     // Collapse the item, remove children
01148     if (debugItem->GetFlagBit(WXLUA_DEBUGITEM_EXPANDED))
01149     {
01150         if (childData.Ok())
01151         {
01152             long n, count = m_listCtrl->GetItemCount();
01153 
01154             for (n = lc_item+1; n < count; ++n)
01155             {
01156                 wxLuaStackListData* stkListData_n = (wxLuaStackListData*)m_listData[n];
01157                 wxCHECK_MSG(stkListData_n != NULL, false, wxT("Invalid wxLuaStack data"));
01158 
01159                 if (stkListData_n->m_parentDebugData == childData)
01160                 {
01161                     if (stkListData_n->m_childrenDebugData.Ok() &&
01162                         stkListData_n->GetDebugItem()->GetFlagBit(WXLUA_DEBUGITEM_EXPANDED))
01163                     {
01164                         long long_key = 0;
01165                         if (stkListData_n->GetDebugItem()->GetRefPtr(long_key))
01166                             m_expandedItems.erase(long_key);
01167 
01168                         CollapseItem(n);
01169 
01170                         n--; count = m_listData.GetCount();
01171                         continue;
01172                     }
01173 
01174                     collapsed = true; // only if we removed anything
01175 
01176                     if (stkListData_n->m_treeId)
01177                         m_treeCtrl->Delete(stkListData_n->m_treeId);
01178 
01179                     m_listData.RemoveAt(n);
01180 
01181                     if (stkListData_n != NULL)
01182                         delete stkListData_n;
01183 
01184                     n--; count = m_listData.GetCount();
01185                 }
01186             }
01187         }
01188 
01189         // don't call collapse here, let MSW do it if this is called from OnTreeItem
01190         // else we've already collapsed it in OnListActivated
01191         m_treeCtrl->DeleteChildren(stkListData->m_treeId);
01192         // Add back our dummy item for MSW to allow it to be reexpanded
01193         m_treeCtrl->AppendItem(stkListData->m_treeId, DUMMY_TREEITEM);
01194 
01195         debugItem->SetFlagBit(WXLUA_DEBUGITEM_EXPANDED, false);
01196 
01197         long long_key = 0;
01198         if (debugItem->GetRefPtr(long_key))
01199             m_expandedItems.erase(long_key);
01200     }
01201 
01202     EndBatch();
01203 
01204     m_listCtrl->SetItemCount(m_listData.GetCount());
01205 
01206     return collapsed;
01207 }
01208 
01209 void wxLuaStackDialog::DeleteAllListItemData()
01210 {
01211     m_expandedItems.clear();
01212 
01213     int i, count = m_listData.GetCount();
01214 
01215     for (i = 0; i < count; ++i)
01216     {
01217         wxLuaStackListData* stkListData = (wxLuaStackListData*)m_listData[i];
01218 
01219         if (stkListData != NULL)
01220             delete stkListData;
01221     }
01222 
01223     m_listData.Clear();
01224 }
01225 
01226 void wxLuaStackDialog::RemoveAllLuaReferences()
01227 {
01228     if (!m_wxlState.Ok()) return; // doesn't have to be ok
01229 
01230     int i;
01231 
01232 /*
01233     // try first to remove the refs in the listctrl (sanity check really)
01234     // make sure that we reset their data's ref to LUA_NOREF too.
01235 
01236       // Remove the references using the listctrl data itself
01237     for (i = 0; i < m_listCtrl->GetItemCount(); ++i)
01238     {
01239         wxLuaStackListData* stkListData = (wxLuaStackListData*)m_listCtrl->GetItemData(i);
01240         wxCHECK_RET(stkListData != NULL, wxT("Invalid wxLuaStack data"));
01241         wxLuaDebugItem* debugItem = stkListData->GetDebugItem();
01242 
01243         if (debugItem && (debugItem->GetRef() != LUA_NOREF) &&
01244             debugItem->GetFlagBit(WXLUA_DEBUGITEM_LUAREFED))
01245         {
01246             int lua_ref = debugItem->GetRef();
01247             int ok = m_wxlState.wxluaR_Unref(lua_ref);
01248             debugItem->SetReference(LUA_NOREF);
01249 
01250             int idx = m_luaReferences.Index(lua_ref);
01251             if (idx != wxNOT_FOUND)
01252                 m_luaReferences.RemoveAt(idx);
01253             else
01254                 wxPrintf(wxT("Missing Lua reference in listctrl #%d ok %d ref %d count %d idx %d\n"), i, ok, debugItem->GetRef(), m_luaReferences.GetCount(), idx);
01255         }
01256     }
01257 */
01258 
01259     lua_State* L = m_wxlState.GetLuaState();
01260 
01261     // remove the last to so we don't make any holes
01262     for (i = (int)m_luaReferences.GetCount()-1; i >= 0; --i)
01263     {
01264         bool ok = wxluaR_unref(L, m_luaReferences[i], &wxlua_lreg_debug_refs_key);
01265         wxCHECK_RET(ok, wxT("Unable to remove a reference in Lua"));
01266         //wxPrintf(wxT("Extra Lua reference in listctrl #%d ok %d ref %d count %d\n"), i, ok, m_luaReferences[i], m_luaReferences.GetCount());
01267     }
01268 
01269     m_luaReferences.Clear();
01270 
01271     // ----------------------------------------------------------------------
01272     // Sanity check to make sure that we've cleared all the references
01273     // There should be only one of us created at any time.
01274 
01275     //wxLuaCheckStack cs(L, wxT("wxLuaStackDialog::RemoveAllLuaReferences"));
01276     lua_pushlightuserdata(L, &wxlua_lreg_debug_refs_key); // push name of table to get as key
01277     lua_rawget(L, LUA_REGISTRYINDEX);   // pop key, push result (the refs table)
01278 
01279     lua_pushnil(L);
01280     while (lua_next(L, -2) != 0)      // ref table can have holes in it
01281     {
01282         // value = -1, key = -2, table = -3
01283         if (!lua_isnumber(L, -2))
01284             wxPrintf(wxT("wxLuaStackDialog::RemoveAllLuaReferences refs not empty key=%d value=%d\n"), lua_type(L, -2), lua_type(L, -1));
01285         else if ((lua_tonumber(L, -2) == 0) && (lua_tonumber(L, -1) != 1))
01286             wxPrintf(wxT("wxLuaStackDialog::RemoveAllLuaReferences refs not empty key=%lf value=%lg\n"), lua_tonumber(L, -2), lua_tonumber(L, -1));
01287 
01288         lua_pop(L, 1); // pop value, lua_next will pop key at end
01289     }
01290 
01291     lua_pop(L, 1); // pop ref table
01292 
01293     // Clear out the old numeric references since it should be "empty"
01294     // though full of dead table[idx]=next_idx, where table[0] = 1;
01295 
01296     wxlua_lreg_createtable(L, &wxlua_lreg_debug_refs_key);
01297 }
Generated on Tue Jul 13 10:30:39 2010 for wxLua by  doxygen 1.6.3