text: /////////////////////////////////////////////////////////////////////////////
  // Name:        src/propgrid/manager.cpp
  // Purpose:     wxPropertyGridManager
  // Author:      Jaakko Salli
  // Modified by:
  // Created:     2005-01-14
  // Copyright:   (c) Jaakko Salli
  // Licence:     wxWindows licence
  /////////////////////////////////////////////////////////////////////////////
  
  // For compilers that support precompilation, includes "wx/wx.h".
  #include "wx/wxprec.h"
  
  
  #if wxUSE_PROPGRID
  
  #ifndef WX_PRECOMP
      #include "wx/settings.h"
      #include "wx/stattext.h"
      #include "wx/textctrl.h"
      #include "wx/toolbar.h"
  #endif
  
  #include "wx/dcbuffer.h" // for wxALWAYS_NATIVE_DOUBLE_BUFFER
  #include "wx/headerctrl.h" // for wxPGHeaderCtrl
  
  // This define is necessary to prevent macro clearing
  #define __wxPG_SOURCE_FILE__
  
  #include "wx/propgrid/manager.h"
  
  
  #define wxPG_MAN_ALTERNATE_BASE_ID          11249 // Needed for wxID_ANY madness
  
  
  // -----------------------------------------------------------------------
  
  // For wxMSW cursor consistency, we must do mouse capturing even
  // when using custom controls
  
  #define BEGIN_MOUSE_CAPTURE \
      if ( !(m_iFlags & wxPG_FL_MOUSE_CAPTURED) ) \
      { \
          CaptureMouse(); \
          m_iFlags |= wxPG_FL_MOUSE_CAPTURED; \
      }
  
  #define END_MOUSE_CAPTURE \
      if ( m_iFlags & wxPG_FL_MOUSE_CAPTURED ) \
      { \
          ReleaseMouse(); \
          m_iFlags &= ~(wxPG_FL_MOUSE_CAPTURED); \
      }
  
  // -----------------------------------------------------------------------
  // wxPropertyGridManager
  // -----------------------------------------------------------------------
  
  const char wxPropertyGridManagerNameStr[] = "wxPropertyGridManager";
  
  
  // Categoric Mode Icon
  static const char* const gs_xpm_catmode[] = {
  "16 16 5 1",
  ". c none",
  "B c black",
  "D c #868686",
  "L c #CACACA",
  "W c #FFFFFF",
  ".DDD............",
  ".DLD.BBBBBB.....",
  ".DDD............",
  ".....DDDDD.DDD..",
  "................",
  ".....DDDDD.DDD..",
  "................",
  ".....DDDDD.DDD..",
  "................",
  ".....DDDDD.DDD..",
  "................",
  ".DDD............",
  ".DLD.BBBBBB.....",
  ".DDD............",
  ".....DDDDD.DDD..",
  "................"
  };
  
  // Alphabetic Mode Icon
  static const char* const gs_xpm_noncatmode[] = {
  "16 16 5 1",
  ". c none",
  "B c black",
  "D c #868686",
  "L c #000080",
  "W c #FFFFFF",
  "..DBD...DDD.DDD.",
  ".DB.BD..........",
  ".BBBBB..DDD.DDD.",
  ".B...B..........",
  "...L....DDD.DDD.",
  "...L............",
  ".L.L.L..DDD.DDD.",
  "..LLL...........",
  "...L....DDD.DDD.",
  "................",
  ".BBBBB..DDD.DDD.",
  "....BD..........",
  "...BD...DDD.DDD.",
  "..BD............",
  ".BBBBB..DDD.DDD.",
  "................"
  };
  
  // Default Page Icon.
  static const char* const gs_xpm_defpage[] = {
  "16 16 5 1",
  ". c none",
  "B c black",
  "D c #868686",
  "L c #000080",
  "W c #FFFFFF",
  "................",
  "................",
  "..BBBBBBBBBBBB..",
  "..B..........B..",
  "..B.BB.LLLLL.B..",
  "..B..........B..",
  "..B.BB.LLLLL.B..",
  "..B..........B..",
  "..B.BB.LLLLL.B..",
  "..B..........B..",
  "..B.BB.LLLLL.B..",
  "..B..........B..",
  "..BBBBBBBBBBBB..",
  "................",
  "................",
  "................"
  };
  
  // -----------------------------------------------------------------------
  // wxPropertyGridPage
  // -----------------------------------------------------------------------
  
  
  wxIMPLEMENT_CLASS(wxPropertyGridPage, wxEvtHandler);
  
  
  wxBEGIN_EVENT_TABLE(wxPropertyGridPage, wxEvtHandler)
  wxEND_EVENT_TABLE()
  
  
  wxPropertyGridPage::wxPropertyGridPage()
      : wxEvtHandler(), wxPropertyGridInterface(), wxPropertyGridPageState()
  {
      m_pState = this; // wxPropertyGridInterface to point to State
      m_manager = NULL;
      m_isDefault = false;
  }
  
  wxPropertyGridPage::~wxPropertyGridPage()
  {
  }
  
  void wxPropertyGridPage::Clear()
  {
      GetStatePtr()->DoClear();
  }
  
  wxSize wxPropertyGridPage::FitColumns()
  {
      wxSize sz = DoFitColumns();
      return sz;
  }
  
  void wxPropertyGridPage::RefreshProperty( wxPGProperty* p )
  {
      if ( m_manager )
          m_manager->RefreshProperty(p);
  }
  
  void wxPropertyGridPage::OnShow()
  {
  }
  
  void wxPropertyGridPage::SetSplitterPosition( int splitterPos, int col )
  {
      wxPropertyGrid* pg = GetGrid();
      if ( pg->GetState() == this )
          pg->SetSplitterPosition(splitterPos);
      else
          DoSetSplitterPosition(splitterPos, col, false);
  }
  
  void wxPropertyGridPage::DoSetSplitterPosition( int pos,
                                                  int splitterColumn,
                                                  int flags )
  {
      if ( (flags & wxPG_SPLITTER_ALL_PAGES) && m_manager->GetPageCount() )
          m_manager->SetSplitterPosition( pos, splitterColumn );
      else
          wxPropertyGridPageState::DoSetSplitterPosition( pos,
                                                          splitterColumn,
                                                          flags );
  }
  
  // -----------------------------------------------------------------------
  // wxPGHeaderCtrl
  // -----------------------------------------------------------------------
  
  #if wxUSE_HEADERCTRL
  
  class wxPGHeaderCtrl : public wxHeaderCtrl
  {
  public:
      wxPGHeaderCtrl(wxPropertyGridManager* manager, wxWindowID id, const wxPoint& pos,
                     const wxSize& size, long style) :
          wxHeaderCtrl(manager, id, pos, size, style)
      {
          m_manager = manager;
          EnsureColumnCount(2);
  
          // Seed titles with defaults
          m_columns[0]->SetTitle(_("Property"));
          m_columns[1]->SetTitle(_("Value"));
  
          Bind(wxEVT_HEADER_RESIZING, &wxPGHeaderCtrl::OnResizing, this);
          Bind(wxEVT_HEADER_BEGIN_RESIZE, &wxPGHeaderCtrl::OnBeginResize, this);
          Bind(wxEVT_HEADER_END_RESIZE, &wxPGHeaderCtrl::OnEndResize, this);
      }
  
      virtual ~wxPGHeaderCtrl()
      {
          for (wxVector<wxHeaderColumnSimple*>::const_iterator it = m_columns.begin();
               it != m_columns.end(); ++it)
          {
              delete *it;
          }
      }
  
      virtual void OnColumnCountChanging(unsigned int count) wxOVERRIDE
      {
          EnsureColumnCount(count);
      }
  
      void OnPageChanged(const wxPropertyGridPage* page)
      {
          m_page = page;
          SetColumnCount(m_page->GetColumnCount());
          DetermineAllColumnWidths();
          UpdateAllColumns();
      }
  
      void OnColumWidthsChanged()
      {
          DetermineAllColumnWidths();
          UpdateAllColumns();
      }
  
      virtual const wxHeaderColumn& GetColumn(unsigned int idx) const wxOVERRIDE
      {
          return *m_columns[idx];
      }
  
      void SetColumnTitle(unsigned int idx, const wxString& title)
      {
          EnsureColumnCount(idx+1);
          m_columns[idx]->SetTitle(title);
      }
  
  private:
      void UpdateAllColumns()
      {
          unsigned int colCount = GetColumnCount();
          for ( unsigned int i = 0; i < colCount; i++ )
          {
              UpdateColumn(i);
          }
      }
  
      void EnsureColumnCount(unsigned int count)
      {
          while ( m_columns.size() < count )
          {
              wxHeaderColumnSimple* colInfo = new wxHeaderColumnSimple(wxEmptyString);
              m_columns.push_back(colInfo);
          }
      }
  
      void DetermineAllColumnWidths() const
      {
          wxPropertyGrid* pg = m_manager->GetGrid();
  
          // Internal border width
          int borderWidth = pg->DoGetBorderSize().x / 2;
  
          const unsigned int colCount = m_page->GetColumnCount();
          for ( unsigned int i = 0; i < colCount; i++ )
          {
              wxHeaderColumnSimple* colInfo = m_columns[i];
  
              int colWidth = m_page->GetColumnWidth(i);
              int colMinWidth = m_page->GetColumnMinWidth(i);
              if ( i == 0 )
              {
                  // Compensate for the internal border
                  int margin = pg->GetMarginWidth() + borderWidth;
  
                  colWidth += margin;
                  colMinWidth += margin;
              }
              else if ( i == colCount-1 )
              {
                  // Compensate for the internal border and scrollbar
                  int margin = borderWidth;
  
                  colWidth += margin;
                  colMinWidth += margin;
              }
  
              colInfo->SetWidth(colWidth);
              colInfo->SetMinWidth(colMinWidth);
          }
      }
  
      void OnSetColumnWidth(int col, int colWidth)
      {
          wxPropertyGrid* pg = m_manager->GetGrid();
  
          // Internal border width
          int borderWidth = pg->DoGetBorderSize().x / 2;
  
          // Compensate for the internal border
          int x = -borderWidth;
  
          for ( int i=0; i<col; i++ )
              x += m_columns[i]->GetWidth();
  
          x += colWidth;
  
          pg->DoSetSplitterPosition(x, col,
                                    wxPG_SPLITTER_REFRESH |
                                    wxPG_SPLITTER_FROM_EVENT);
      }
  
      void OnResizing(wxHeaderCtrlEvent& evt)
      {
          int col = evt.GetColumn();
          int colWidth = evt.GetWidth();
  
          OnSetColumnWidth(col, colWidth);
          OnColumWidthsChanged();
  
          wxPropertyGrid* pg = m_manager->GetGrid();
          pg->SendEvent(wxEVT_PG_COL_DRAGGING, NULL, NULL, 0,
                        (unsigned int)col);
      }
  
      void OnBeginResize(wxHeaderCtrlEvent& evt)
      {
          int col = evt.GetColumn();
          wxPropertyGrid* pg = m_manager->GetGrid();
  
          // Don't allow resizing the rightmost column
          // (like it's not allowed for the rightmost wxPropertyGrid splitter)
          if ( col == (int)m_page->GetColumnCount() - 1 )
              evt.Veto();
          // Never allow column resize if layout is static
          else if ( m_manager->HasFlag(wxPG_STATIC_SPLITTER) )
              evt.Veto();
          // Allow application to veto dragging
          else if ( pg->SendEvent(wxEVT_PG_COL_BEGIN_DRAG,
                                  NULL, NULL, 0,
                                  (unsigned int)col) )
              evt.Veto();
      }
  
      void OnEndResize(wxHeaderCtrlEvent& evt)
      {
          int col = evt.GetColumn();
          wxPropertyGrid* pg = m_manager->GetGrid();
          pg->SendEvent(wxEVT_PG_COL_END_DRAG,
                        NULL, NULL, 0,
                        (unsigned int)col);
      }
  
      wxPropertyGridManager*          m_manager;
      const wxPropertyGridPage*       m_page;
      wxVector<wxHeaderColumnSimple*> m_columns;
  };
  
  #endif // wxUSE_HEADERCTRL
  
  // -----------------------------------------------------------------------
  // wxPropertyGridManager
  // -----------------------------------------------------------------------
  
  // Final default splitter y is client height minus this.
  #define wxPGMAN_DEFAULT_NEGATIVE_SPLITTER_Y         100
  
  // -----------------------------------------------------------------------
  
  wxIMPLEMENT_CLASS(wxPropertyGridManager, wxPanel);
  
  // -----------------------------------------------------------------------
  
  wxBEGIN_EVENT_TABLE(wxPropertyGridManager, wxPanel)
    EVT_MOTION(wxPropertyGridManager::OnMouseMove)
    EVT_SIZE(wxPropertyGridManager::OnResize)
    EVT_PAINT(wxPropertyGridManager::OnPaint)
    EVT_LEFT_DOWN(wxPropertyGridManager::OnMouseClick)
    EVT_LEFT_UP(wxPropertyGridManager::OnMouseUp)
    EVT_LEAVE_WINDOW(wxPropertyGridManager::OnMouseEntry)
    //EVT_ENTER_WINDOW(wxPropertyGridManager::OnMouseEntry)
  wxEND_EVENT_TABLE()
  
  // -----------------------------------------------------------------------
  
  wxPropertyGridManager::wxPropertyGridManager()
      : wxPanel()
  {
      Init1();
  }
  
  // -----------------------------------------------------------------------
  
  wxPropertyGridManager::wxPropertyGridManager( wxWindow *parent,
                                                wxWindowID id,
                                                const wxPoint& pos,
                                                const wxSize& size,
                                                long style,
                                                const wxString& name )
      : wxPanel()
  {
      Init1();
      Create(parent,id,pos,size,style,name);
  }
  
  // -----------------------------------------------------------------------
  
  bool wxPropertyGridManager::Create( wxWindow *parent,
                                      wxWindowID id,
                                      const wxPoint& pos,
                                      const wxSize& size,
                                      long style,
                                      const wxString& name )
  {
      if ( !m_pPropGrid )
          m_pPropGrid = CreatePropertyGrid();
  
      bool res = wxPanel::Create( parent, id, pos, size,
                                  (style & wxWINDOW_STYLE_MASK)|wxWANTS_CHARS,
                                  name );
      Init2(style);
  
      SetInitialSize(size);
  
      return res;
  }
  
  // -----------------------------------------------------------------------
  
  //
  // Initialize values to defaults
  //
  void wxPropertyGridManager::Init1()
  {
  
      m_pPropGrid = NULL;
  
  #if wxUSE_TOOLBAR
      m_pToolbar = NULL;
  #endif
  #if wxUSE_HEADERCTRL
      m_pHeaderCtrl = NULL;
      m_showHeader = false;
  #endif
      m_pTxtHelpCaption = NULL;
      m_pTxtHelpContent = NULL;
  
      m_emptyPage = NULL;
  
      m_selPage = -1;
  
      m_width = m_height = 0;
  
      m_splitterHeight = 5;
  
      m_splitterY = -1; // -1 causes default to be set.
  
      m_nextDescBoxSize = -1;
  
      m_categorizedModeToolId = -1;
      m_alphabeticModeToolId = -1;
  
      m_extraHeight = 0;
      m_dragStatus = 0;
      m_onSplitter = false;
      m_iFlags = 0;
  }
  
  // -----------------------------------------------------------------------
  
  // These flags are always used in wxPropertyGrid integrated in wxPropertyGridManager.
  #define wxPG_MAN_PROPGRID_FORCED_FLAGS (  wxBORDER_THEME | \
                                            wxCLIP_CHILDREN)
  
  // Which flags can be passed to underlying wxPropertyGrid.
  #define wxPG_MAN_PASS_FLAGS_MASK       (wxPG_WINDOW_STYLE_MASK|wxTAB_TRAVERSAL)
  
  //
  // Initialize after parent etc. set
  //
  void wxPropertyGridManager::Init2( int style )
  {
  
      if ( m_iFlags & wxPG_FL_INITIALIZED )
          return;
  
      m_windowStyle |= (style & wxPG_WINDOW_STYLE_MASK);
  
      wxSize csz = GetClientSize();
  
      m_cursorSizeNS = wxCursor(wxCURSOR_SIZENS);
  
      // Prepare the first page
      // NB: But just prepare - you still need to call Add/InsertPage
      //     to actually add properties on it.
      wxPropertyGridPage* pd = new wxPropertyGridPage();
      pd->m_isDefault = true;
      pd->m_manager = this;
      wxPropertyGridPageState* state = pd->GetStatePtr();
      state->m_pPropGrid = m_pPropGrid;
      m_arrPages.push_back( pd );
      m_pPropGrid->m_pState = state;
  
      wxWindowID baseId = GetId();
      wxWindowID useId = baseId;
      if ( baseId < 0 )
          baseId = wxPG_MAN_ALTERNATE_BASE_ID;
  
  #ifdef __WXMAC__
     // Smaller controls on Mac
     SetWindowVariant(wxWINDOW_VARIANT_SMALL);
  #endif
  
     long propGridFlags = (m_windowStyle&wxPG_MAN_PASS_FLAGS_MASK)
                          |wxPG_MAN_PROPGRID_FORCED_FLAGS;
  
     propGridFlags &= ~wxBORDER_MASK;
  
     long pgManExStyle = 0;
     if ((style & wxPG_NO_INTERNAL_BORDER) == 0)
     {
         propGridFlags |= wxBORDER_THEME;
     }
     else
     {
         propGridFlags |= wxBORDER_NONE;
         pgManExStyle |= wxPG_EX_TOOLBAR_SEPARATOR;
     }
  
      // Create propertygrid.
      m_pPropGrid->Create(this,baseId,wxPoint(0,0),csz, propGridFlags);
  
      m_pPropGrid->m_eventObject = this;
  
      m_pPropGrid->SetId(useId);
  
      m_pPropGrid->SetInternalFlag(wxPG_FL_IN_MANAGER);
  
      m_pState = m_pPropGrid->m_pState;
  
      // Rely on native double-buffering by default.
      long pgExStyle = wxPG_EX_INIT_NOCAT;
  #if wxALWAYS_NATIVE_DOUBLE_BUFFER
      pgExStyle |= wxPG_EX_NATIVE_DOUBLE_BUFFERING;
  #endif // wxALWAYS_NATIVE_DOUBLE_BUFFER
      m_pPropGrid->SetExtraStyle(pgExStyle);
      wxWindow::SetExtraStyle(pgManExStyle | pgExStyle);
  
      // Connect to property grid onselect event.
      // NB: Even if wxID_ANY is used, this doesn't connect properly in wxPython
      //     (see wxPropertyGridManager::ProcessEvent).
      ReconnectEventHandlers(wxID_NONE, m_pPropGrid->GetId());
  
      // Optional initial controls.
      m_width = -12345;
  
      m_iFlags |= wxPG_FL_INITIALIZED;
  
  }
  
  // -----------------------------------------------------------------------
  
  wxPropertyGridManager::~wxPropertyGridManager()
  {
      END_MOUSE_CAPTURE
  
      //m_pPropGrid->ClearSelection();
      wxDELETE(m_pPropGrid);
  
      for ( size_t i = 0; i < m_arrPages.size(); i++ )
      {
          delete m_arrPages[i];
      }
  
      delete m_emptyPage;
  }
  
  // -----------------------------------------------------------------------
  
  wxPropertyGrid* wxPropertyGridManager::CreatePropertyGrid() const
  {
      return new wxPropertyGrid();
  }
  
  // -----------------------------------------------------------------------
  
  void wxPropertyGridManager::SetId( wxWindowID winid )
  {
      wxWindow::SetId(winid);
  
      // Reconnect propgrid event handlers.
      ReconnectEventHandlers(m_pPropGrid->GetId(), winid);
  
      m_pPropGrid->SetId(winid);
  }
  
  // -----------------------------------------------------------------------
  
  wxSize wxPropertyGridManager::DoGetBestSize() const
  {
      // Width: margin=15 + columns=2*40 + scroll bar
      return wxSize(15+2*40+wxSystemSettings::GetMetric(wxSYS_VSCROLL_X, m_pPropGrid), 150);
  }
  
  // -----------------------------------------------------------------------
  
  bool wxPropertyGridManager::SetFont( const wxFont& font )
  {
      bool res = wxWindow::SetFont(font);
      m_pPropGrid->SetFont(font);
  
      // TODO: Need to do caption recalculations for other pages as well.
      for ( unsigned int i = 0; i < m_arrPages.size(); i++ )
      {
          wxPropertyGridPage* page = GetPage(i);
  
          if ( page != m_pPropGrid->GetState() )
              page->CalculateFontAndBitmapStuff(-1);
      }
  
      return res;
  }
  
  // -----------------------------------------------------------------------
  
  // Which flags can affect the toolbar
  #define wxPG_EX_WINDOW_TOOLBAR_STYLE_MASK  (wxPG_EX_NO_FLAT_TOOLBAR|wxPG_EX_MODE_BUTTONS|wxPG_EX_NO_TOOLBAR_DIVIDER)
  
  void wxPropertyGridManager::SetExtraStyle( long exStyle )
  {
      // Pass only relevant flags to wxPropertyGrid.
      m_pPropGrid->SetExtraStyle(exStyle & wxPG_EX_WINDOW_PG_STYLE_MASK);
      // Because it can happen that not all flags are actually changed
      // by call to SetExtraStyle() (e.g. wxPG_EX_NATIVE_DOUBLE_BUFFERING),
      // we have to get the actual style flags prior to storing them.
      exStyle &= ~wxPG_EX_WINDOW_PG_STYLE_MASK;
      exStyle |= m_pPropGrid->GetExtraStyle() & wxPG_EX_WINDOW_PG_STYLE_MASK;
  
  #if wxUSE_TOOLBAR
      bool toolbarStyleChanged =
          (GetExtraStyle() & wxPG_EX_WINDOW_TOOLBAR_STYLE_MASK) != (exStyle & wxPG_EX_WINDOW_TOOLBAR_STYLE_MASK);
  #endif // wxUSE_TOOLBAR
  
      wxWindow::SetExtraStyle( exStyle );
  #if wxUSE_TOOLBAR
      if ( toolbarStyleChanged && m_pToolbar )
          RecreateControls();
  #endif
  }
  
  // -----------------------------------------------------------------------
  
  void wxPropertyGridManager::DoFreeze()
  {
      m_pPropGrid->Freeze();
      wxWindow::DoFreeze();
  }
  
  // -----------------------------------------------------------------------
  
  void wxPropertyGridManager::DoThaw()
  {
      wxWindow::DoThaw();
      m_pPropGrid->Thaw();
  }
  
  // -----------------------------------------------------------------------
  
  void wxPropertyGridManager::SetWindowStyleFlag( long style )
  {
      long oldWindowStyle = GetWindowStyleFlag();
  
      wxWindow::SetWindowStyleFlag( style );
      m_pPropGrid->SetWindowStyleFlag( (m_pPropGrid->GetWindowStyleFlag()&~(wxPG_MAN_PASS_FLAGS_MASK)) |
                                     (style&wxPG_MAN_PASS_FLAGS_MASK) );
  
      // Need to re-position windows?
      if ( (oldWindowStyle & (wxPG_TOOLBAR|wxPG_DESCRIPTION)) !=
           (style & (wxPG_TOOLBAR|wxPG_DESCRIPTION)) )
      {
          RecreateControls();
      }
  }
  
  // -----------------------------------------------------------------------
  
  bool wxPropertyGridManager::Reparent( wxWindowBase *newParent )
  {
      if ( m_pPropGrid )
          m_pPropGrid->OnTLPChanging((wxWindow*)newParent);
  
      bool res = wxPanel::Reparent(newParent);
  
      return res;
  }
  
  // -----------------------------------------------------------------------
  
  // Actually shows given page.
  bool wxPropertyGridManager::DoSelectPage( int index )
  {
      // -1 means no page was selected
      //wxASSERT( m_selPage >= 0 );
  
      wxCHECK_MSG( index >= -1 && index < (int)GetPageCount(),
                   false,
                   wxS("invalid page index") );
  
      if ( m_selPage == index )
          return true;
  
      if ( m_pPropGrid->GetSelection() )
      {
          if ( !m_pPropGrid->ClearSelection() )
              return false;
      }
  
  #if wxUSE_TOOLBAR
      wxPropertyGridPage* prevPage;
  
      if ( m_selPage >= 0 )
          prevPage = GetPage(m_selPage);
      else
          prevPage = m_emptyPage;
  #endif
  
      wxPropertyGridPage* nextPage;
  
      if ( index >= 0 )
      {
          nextPage = m_arrPages[index];
  
          nextPage->OnShow();
      }
      else
      {
          if ( !m_emptyPage )
          {
              m_emptyPage = new wxPropertyGridPage();
              m_emptyPage->m_pPropGrid = m_pPropGrid;
          }
  
          nextPage = m_emptyPage;
      }
  
      m_iFlags |= wxPG_FL_DESC_REFRESH_REQUIRED;
  
      m_pPropGrid->SwitchState( nextPage->GetStatePtr() );
  
      m_pState = m_pPropGrid->m_pState;
  
      m_selPage = index;
  
  #if wxUSE_TOOLBAR
      if ( m_pToolbar )
      {
          if ( index >= 0 )
              m_pToolbar->ToggleTool( nextPage->GetToolId(), true );
          else
              m_pToolbar->ToggleTool( prevPage->GetToolId(), false );
      }
  #endif
  
  #if wxUSE_HEADERCTRL
      if ( m_pHeaderCtrl && m_pHeaderCtrl->IsShown() )
          m_pHeaderCtrl->OnPageChanged(nextPage);
  #endif
  
      return true;
  }
  
  // -----------------------------------------------------------------------
  
  // Changes page *and* set the target page for insertion operations.
  void wxPropertyGridManager::SelectPage( int index )
  {
      DoSelectPage(index);
  }
  
  // -----------------------------------------------------------------------
  
  int wxPropertyGridManager::GetPageByName( const wxString& name ) const
  {
      for ( size_t i = 0; i < GetPageCount(); i++ )
      {
          if ( m_arrPages[i]->m_label == name )
              return i;
      }
      return wxNOT_FOUND;
  }
  
  // -----------------------------------------------------------------------
  
  int wxPropertyGridManager::GetPageByState( const wxPropertyGridPageState* pState ) const
  {
      wxASSERT( pState );
  
      for ( size_t i = 0; i < GetPageCount(); i++ )
      {
          if ( pState == m_arrPages[i]->GetStatePtr() )
              return i;
      }
  
      return wxNOT_FOUND;
  }
  
  // -----------------------------------------------------------------------
  
  const wxString& wxPropertyGridManager::GetPageName( int index ) const
  {
      wxASSERT( index >= 0 && index < (int)GetPageCount() );
      return m_arrPages[index]->m_label;
  }
  
  // -----------------------------------------------------------------------
  
  wxPropertyGridPageState* wxPropertyGridManager::GetPageState( int page ) const
  {
      // Do not change this into wxCHECK because returning NULL is important
      // for wxPropertyGridInterface page enumeration mechanics.
      if ( page >= (int)GetPageCount() )
          return NULL;
  
      if ( page == -1 )
          return m_pState;
      return m_arrPages[page];
  }
  
  // -----------------------------------------------------------------------
  
  void wxPropertyGridManager::Clear()
  {
      m_pPropGrid->ClearSelection(false);
  
      m_pPropGrid->Freeze();
  
      for ( int i=(int)GetPageCount()-1; i>=0; i-- )
          RemovePage(i);
  
      m_pPropGrid->Thaw();
  }
  
  // -----------------------------------------------------------------------
  
  void wxPropertyGridManager::ClearPage( int page )
  {
      wxASSERT( page >= 0 );
      wxASSERT( page < (int)GetPageCount() );
  
      if ( page >= 0 && page < (int)GetPageCount() )
      {
          wxPropertyGridPageState* state = m_arrPages[page];
  
          if ( state == m_pPropGrid->GetState() )
              m_pPropGrid->Clear();
          else
              state->DoClear();
      }
  }
  
  // -----------------------------------------------------------------------
  
  int wxPropertyGridManager::GetColumnCount( int page ) const
  {
      wxASSERT( page >= -1 );
      wxASSERT( page < (int)GetPageCount() );
  
      return GetPageState(page)->GetColumnCount();
  }
  
  // -----------------------------------------------------------------------
  
  void wxPropertyGridManager::SetColumnCount( int colCount, int page )
  {
      wxASSERT( page >= -1 );
      wxASSERT( page < (int)GetPageCount() );
  
      wxPropertyGridPageState* state = GetPageState(page);
  #if wxUSE_HEADERCTRL
      // Update header only if column count is set for the currently visible page
      if ( m_pHeaderCtrl && m_pHeaderCtrl->IsShown() && state == m_pState )
      {
          m_pHeaderCtrl->SetColumnCount(colCount);
      }
  #endif // wxUSE_HEADERCTRL
      state->SetColumnCount( colCount );
      GetGrid()->Refresh();
  #if wxUSE_HEADERCTRL
      // Update header only if column count is set for the currently visible page
      if ( m_pHeaderCtrl && m_pHeaderCtrl->IsShown() && state == m_pState )
      {
          m_pHeaderCtrl->OnColumWidthsChanged();
      }
  #endif // wxUSE_HEADERCTRL
  }
  // -----------------------------------------------------------------------
  
  size_t wxPropertyGridManager::GetPageCount() const
  {
      if ( !(m_iFlags & wxPG_MAN_FL_PAGE_INSERTED) )
          return 0;
  
      return m_arrPages.size();
  }
  
  // -----------------------------------------------------------------------
  
  wxPropertyGridPage* wxPropertyGridManager::InsertPage( int index,
                                                         const wxString& label,
                                                         const wxBitmap& bmp,
                                                         wxPropertyGridPage* pageObj )
  {
      if ( index < 0 )
          index = GetPageCount();
  
      wxCHECK_MSG( (size_t)index == GetPageCount(), NULL,
          wxS("wxPropertyGridManager currently only supports appending pages (due to wxToolBar limitation)."));
  
      bool needInit = true;
      bool isPageInserted = m_iFlags & wxPG_MAN_FL_PAGE_INSERTED ? true : false;
  
      wxASSERT( index == 0 || isPageInserted );
  
      if ( !pageObj )
      {
          // No custom page object was given, so we will either re-use the default base
          // page (if index==0), or create a new default page object.
          if ( !isPageInserted )
          {
              pageObj = GetPage(0);
              // Of course, if the base page was custom, we need to delete and
              // re-create it.
              if ( !pageObj->m_isDefault )
              {
                  delete pageObj;
                  pageObj = new wxPropertyGridPage();
                  m_arrPages[0] = pageObj;
              }
              needInit = false;
          }
          else
          {
              pageObj = new wxPropertyGridPage();
          }
          pageObj->m_isDefault = true;
      }
      else
      {
          if ( !isPageInserted )
          {
              // Initial page needs to be deleted and replaced
              delete GetPage(0);
              m_arrPages[0] = pageObj;
              m_pPropGrid->m_pState = pageObj->GetStatePtr();
          }
      }
  
      wxPropertyGridPageState* state = pageObj->GetStatePtr();
  
      pageObj->m_manager = this;
  
      if ( needInit )
      {
          state->m_pPropGrid = m_pPropGrid;
          state->InitNonCatMode();
      }
  
      if ( !label.empty() )
      {
          wxASSERT_MSG( pageObj->m_label.empty(),
                        wxS("If page label is given in constructor, empty label must be given in AddPage"));
          pageObj->m_label = label;
      }
  
      pageObj->m_toolId = -1;
  
      if ( !HasFlag(wxPG_SPLITTER_AUTO_CENTER) )
          pageObj->m_dontCenterSplitter = true;
  
      if ( isPageInserted )
          m_arrPages.push_back( pageObj );
  
  #if wxUSE_TOOLBAR
      if ( m_windowStyle & wxPG_TOOLBAR )
      {
          if ( !m_pToolbar )
              RecreateControls();
  
          if ( !HasExtraStyle(wxPG_EX_HIDE_PAGE_BUTTONS) )
          {
              wxASSERT( m_pToolbar );
  
              // Add separator before first page.
              if ( GetPageCount() < 2 && HasExtraStyle(wxPG_EX_MODE_BUTTONS) &&
                   m_pToolbar->GetToolsCount() < 3 )
                  m_pToolbar->AddSeparator();
  
              wxToolBarToolBase* tool;
  
              if ( bmp.IsOk() )
                  tool = m_pToolbar->AddTool(wxID_ANY, label, bmp,
                                             label, wxITEM_RADIO);
              else
                  tool = m_pToolbar->AddTool(wxID_ANY, label,
                                             wxBitmap(gs_xpm_defpage),
                                             label, wxITEM_RADIO);
  
              pageObj->m_toolId = tool->GetId();
  
              // Connect to toolbar button events.
              Bind(wxEVT_TOOL, &wxPropertyGridManager::OnToolbarClick, this,
                   pageObj->GetToolId());
  
              m_pToolbar->Realize();
          }
      }
  #else
      wxUnusedVar(bmp);
  #endif
  
      // If selected page was above the point of insertion, fix the current page index
      if ( isPageInserted )
      {
          if ( m_selPage >= index )
          {
              m_selPage += 1;
          }
      }
      else
      {
          // Set this value only when adding the first page
          m_selPage = 0;
      }
  
      pageObj->Init();
  
      m_iFlags |= wxPG_MAN_FL_PAGE_INSERTED;
  
      wxASSERT( pageObj->GetGrid() );
  
      return pageObj;
  }
  
  // -----------------------------------------------------------------------
  
  bool wxPropertyGridManager::IsAnyModified() const
  {
      for ( size_t i = 0; i < GetPageCount(); i++ )
      {
          if ( m_arrPages[i]->GetStatePtr()->m_anyModified )
              return true;
      }
      return false;
  }
  
  // -----------------------------------------------------------------------
  
  bool wxPropertyGridManager::IsPageModified( size_t index ) const
  {
      wxCHECK_MSG( index < GetPageCount(), false, wxS("Invalid page index") );
  
  #if WXWIN_COMPATIBILITY_3_0
      return m_arrPages[index]->GetStatePtr()->m_anyModified != (unsigned char)false;
  #else
      return m_arrPages[index]->GetStatePtr()->m_anyModified;
  #endif
  }
  
  // -----------------------------------------------------------------------
  
  #if wxUSE_HEADERCTRL
  void wxPropertyGridManager::ShowHeader(bool show)
  {
      if ( show != m_showHeader)
      {
          m_showHeader = show;
          RecreateControls();
      }
  }
  #endif
  
  // -----------------------------------------------------------------------
  
  #if wxUSE_HEADERCTRL
  void wxPropertyGridManager::SetColumnTitle( int idx, const wxString& title )
  {
      if ( !m_pHeaderCtrl )
          ShowHeader();
  
      m_pHeaderCtrl->SetColumnTitle(idx, title);
  }
  #endif
  
  // -----------------------------------------------------------------------
  
  bool wxPropertyGridManager::IsPropertySelected( wxPGPropArg id ) const
  {
      wxPG_PROP_ARG_CALL_PROLOG_RETVAL(false)
      for ( unsigned int i=0; i<GetPageCount(); i++ )
      {
          if ( GetPageState(i)->DoIsPropertySelected(p) )
              return true;
      }
      return false;
  }
  
  // -----------------------------------------------------------------------
  
  wxPGProperty* wxPropertyGridManager::GetPageRoot( int index ) const
  {
      wxCHECK_MSG( (index >= 0) && (index < (int)m_arrPages.size()),
                   NULL,
                   wxS("invalid page index") );
  
      return m_arrPages[index]->GetRoot();
  }
  
  // -----------------------------------------------------------------------
  
  bool wxPropertyGridManager::RemovePage( int page )
  {
      wxCHECK_MSG( (page >= 0) && (page < (int)GetPageCount()),
                   false,
                   wxS("invalid page index") );
  
      wxPropertyGridPage* pd = m_arrPages[page];
  
      if ( m_arrPages.size() == 1 )
      {
          // Last page: do not remove page entry
          m_pPropGrid->Clear();
          m_selPage = -1;
          m_iFlags &= ~wxPG_MAN_FL_PAGE_INSERTED;
          pd->m_label.clear();
      }
  
      // Change selection if current is page
      else if ( page == m_selPage )
      {
          if ( !m_pPropGrid->ClearSelection() )
                  return false;
  
          // Substitute page to select
          int substitute = page - 1;
          if ( substitute < 0 )
              substitute = page + 1;
  
          SelectPage(substitute);
      }
  
      // Remove toolbar icon
  #if wxUSE_TOOLBAR
      if ( HasFlag(wxPG_TOOLBAR) )
      {
          wxASSERT( m_pToolbar );
  
          int toolPos = HasExtraStyle(wxPG_EX_MODE_BUTTONS) ? 3 : 0;
          toolPos += page;
  
          // Delete separator as well, for consistency
          if ( HasExtraStyle(wxPG_EX_MODE_BUTTONS) &&
               GetPageCount() == 1 )
              m_pToolbar->DeleteToolByPos(2);
  
          m_pToolbar->DeleteToolByPos(toolPos);
      }
  #endif
  
      if ( m_arrPages.size() > 1 )
      {
          m_arrPages.erase(m_arrPages.begin() + page);
          delete pd;
      }
  
      // Adjust indexes that were above removed
      if ( m_selPage > page )
          m_selPage--;
  
      return true;
  }
  
  // -----------------------------------------------------------------------
  
  bool wxPropertyGridManager::ProcessEvent( wxEvent& event )
  {
      const wxEventType evtType = event.GetEventType();
  
      // NB: For some reason, under wxPython, Connect in Init doesn't work properly,
      //     so we'll need to call OnPropertyGridSelect manually. Multiple calls
      //     don't really matter.
      if ( evtType == wxEVT_PG_SELECTED )
          OnPropertyGridSelect((wxPropertyGridEvent&)event);
  
      // Property grid events get special attention
      if ( evtType >= wxPG_BASE_EVT_TYPE &&
           evtType < (wxPG_MAX_EVT_TYPE) &&
           m_selPage >= 0 )
      {
          wxPropertyGridPage* page = GetPage(m_selPage);
          wxPropertyGridEvent* pgEvent = wxDynamicCast(&event, wxPropertyGridEvent);
  
          // Add property grid events to appropriate custom pages
          // but stop propagating to parent if page says it is
          // handling everything.
          if ( pgEvent && !page->m_isDefault )
          {
              /*if ( pgEvent->IsPending() )
                  page->AddPendingEvent(event);
              else*/
                  page->ProcessEvent(event);
  
              if ( page->IsHandlingAllEvents() )
                  event.StopPropagation();
          }
      }
  
      return wxPanel::ProcessEvent(event);
  }
  
  // -----------------------------------------------------------------------
  
  void wxPropertyGridManager::RepaintDescBoxDecorations( wxDC& dc,
                                                         int newSplitterY,
                                                         int newWidth,
                                                         int newHeight )
  {
      // Draw background
      wxColour bgcol = GetBackgroundColour();
      dc.SetBrush(bgcol);
      dc.SetPen(bgcol);
      int rectHeight = m_splitterHeight;
      dc.DrawRectangle(0, newSplitterY, newWidth, rectHeight);
      dc.SetPen( wxSystemSettings::GetColour(wxSYS_COLOUR_3DDKSHADOW) );
      int splitterBottom = newSplitterY + m_splitterHeight - 1;
      int boxHeight = newHeight - splitterBottom;
      if ( boxHeight > 1 )
          dc.DrawRectangle(0, splitterBottom, newWidth, boxHeight);
      else
          dc.DrawLine(0, splitterBottom, newWidth, splitterBottom);
  }
  
  // -----------------------------------------------------------------------
  
  void wxPropertyGridManager::UpdateDescriptionBox( int new_splittery, int new_width, int new_height )
  {
      int use_hei = new_height-1;
      int use_width = new_width-6;
  
      // Fix help control positions.
      int cap_y = new_splittery+m_splitterHeight+5;
      m_pTxtHelpCaption->SetSize(3, cap_y, use_width, wxDefaultCoord, wxSIZE_AUTO_HEIGHT);
      int cap_hei = m_pTxtHelpCaption->GetSize().GetHeight();
      int cnt_y = cap_y+cap_hei+3;
      int sub_cap_hei = cap_y+cap_hei-use_hei;
      int cnt_hei = use_hei-cnt_y;
      if ( sub_cap_hei > 0 )
      {
          cap_hei -= sub_cap_hei;
          cnt_hei = 0;
      }
      if ( cap_hei <= 2 )
      {
          m_pTxtHelpCaption->Show( false );
          m_pTxtHelpContent->Show( false );
      }
      else
      {
          m_pTxtHelpCaption->Wrap(-1);
          m_pTxtHelpCaption->Show( true );
          if ( cnt_hei <= 2 )
          {
              m_pTxtHelpContent->Show( false );
          }
          else
          {
              m_pTxtHelpContent->SetSize(3,cnt_y,use_width,cnt_hei);
              m_pTxtHelpContent->Wrap(use_width);
              m_pTxtHelpContent->Show( true );
          }
      }
  
      wxRect r(0, new_splittery, new_width, new_height-new_splittery);
      RefreshRect(r);
  
      m_splitterY = new_splittery;
  
      m_iFlags &= ~(wxPG_FL_DESC_REFRESH_REQUIRED);
  }
  
  // -----------------------------------------------------------------------
  
  void wxPropertyGridManager::RecalculatePositions( int width, int height )
  {
      int propgridY = 0;
      int propgridBottomY = height;
  
      // Toolbar at the top.
  #if wxUSE_TOOLBAR
      if ( m_pToolbar )
      {
          m_pToolbar->SetSize(0, 0, width, wxDefaultCoord);
          propgridY += m_pToolbar->GetSize().y;
  
          if ( HasExtraStyle(wxPG_EX_TOOLBAR_SEPARATOR) )
              propgridY += 1;
      }
  #endif
  
      // Header comes after the tool bar
  #if wxUSE_HEADERCTRL
      if ( m_pHeaderCtrl && m_pHeaderCtrl->IsShown() )
      {
          m_pHeaderCtrl->SetSize(0, propgridY, width, wxDefaultCoord);
          // Sync horizontal scroll position with grid
          int x;
          m_pPropGrid->CalcScrolledPosition(0, 0, &x, NULL);
          m_pHeaderCtrl->ScrollWindow(x, 0);
          propgridY += m_pHeaderCtrl->GetSize().y;
      }
  #endif
  
      // Help box.
      if ( m_pTxtHelpCaption )
      {
          int new_splittery = m_splitterY;
  
          // Move m_splitterY
          if ( ( m_splitterY >= 0 || m_nextDescBoxSize ) && m_height > 32 )
          {
              if ( m_nextDescBoxSize >= 0 )
              {
                  new_splittery = m_height - m_nextDescBoxSize - m_splitterHeight;
                  m_nextDescBoxSize = -1;
              }
              new_splittery += (height-m_height);
          }
          else
          {
              new_splittery = height - wxPGMAN_DEFAULT_NEGATIVE_SPLITTER_Y;
              if ( new_splittery < 32 )
                  new_splittery = 32;
          }
  
          // Check if beyond minimum.
          int nspy_min = propgridY + m_pPropGrid->GetRowHeight();
          if ( new_splittery < nspy_min )
              new_splittery = nspy_min;
  
          propgridBottomY = new_splittery;
  
          UpdateDescriptionBox( new_splittery, width, height );
      }
  
      if ( m_iFlags & wxPG_FL_INITIALIZED )
      {
          int pgh = propgridBottomY - propgridY;
          if ( pgh < 0 )
              pgh = 0;
          m_pPropGrid->SetSize( 0, propgridY, width, pgh );
  
          m_extraHeight = height - pgh;
  
          m_width = width;
          m_height = height;
      }
  }
  
  // -----------------------------------------------------------------------
  
  void wxPropertyGridManager::SetDescBoxHeight( int ht, bool refresh )
  {
      if ( m_windowStyle & wxPG_DESCRIPTION )
      {
          if ( ht != GetDescBoxHeight() )
          {
              m_nextDescBoxSize = ht;
              if ( refresh )
                  RecalculatePositions(m_width, m_height);
          }
      }
  }
  
  // -----------------------------------------------------------------------
  
  int wxPropertyGridManager::GetDescBoxHeight() const
  {
      return GetClientSize().y - m_splitterY - m_splitterHeight;
  }
  
  // -----------------------------------------------------------------------
  
  void wxPropertyGridManager::OnPaint( wxPaintEvent& WXUNUSED(event) )
  {
      wxPaintDC dc(this);
  
      // Update everything inside the box
      wxRect r = GetUpdateRegion().GetBox();
  
      if ( HasExtraStyle(wxPG_EX_TOOLBAR_SEPARATOR) )
      {
  #if wxUSE_TOOLBAR
          if (m_pToolbar && m_pPropGrid)
          {
              wxPen marginPen(m_pPropGrid->GetMarginColour());
              dc.SetPen(marginPen);
  
              int y = m_pPropGrid->GetPosition().y-1;
              dc.DrawLine(0, y, GetClientSize().x, y);
          }
  #endif // wxUSE_TOOLBAR
      }
  
      // Repaint splitter and any other description box decorations
      if ( (r.y + r.height) >= m_splitterY && m_splitterY != -1)
          RepaintDescBoxDecorations( dc, m_splitterY, m_width, m_height );
  }
  
  // -----------------------------------------------------------------------
  
  void wxPropertyGridManager::Refresh(bool eraseBackground, const wxRect* rect )
  {
      wxPanel::Refresh(eraseBackground, rect);
  }
  
  // -----------------------------------------------------------------------
  
  void wxPropertyGridManager::RefreshProperty( wxPGProperty* p )
  {
      wxASSERT( p->IsRoot() ||
                p->GetParentState() == p->GetParent()->GetParentState() );
  
      if ( GetPage(m_selPage)->GetStatePtr() == p->GetParentState() )
      {
          wxPropertyGrid* grid = p->GetGrid();
          grid->RefreshProperty(p);
      }
  }
  
  // -----------------------------------------------------------------------
  
  void wxPropertyGridManager::RecreateControls()
  {
      bool was_shown = IsShown();
      if ( was_shown )
          Show ( false );
  
  #if wxUSE_TOOLBAR
      if ( m_windowStyle & wxPG_TOOLBAR )
      {
          bool tbModified = false;
  
          long toolBarFlags = HasExtraStyle(wxPG_EX_NO_FLAT_TOOLBAR) ? 0 : wxTB_FLAT;
          if ( HasExtraStyle(wxPG_EX_NO_TOOLBAR_DIVIDER) )
              toolBarFlags |= wxTB_NODIVIDER;
          // Has toolbar.
          if ( !m_pToolbar )
          {
              m_pToolbar = new wxToolBar(this, wxID_ANY,
                                         wxDefaultPosition,
                                         wxDefaultSize,
                                         toolBarFlags);
              m_pToolbar->SetToolBitmapSize(wxSize(16, 15));
  
          #if defined(__WXMSW__)
              // Eliminate toolbar flicker on XP
              // NOTE: Not enabled since it corrupts drawing somewhat.
  
              /*
              #ifndef WS_EX_COMPOSITED
                  #define WS_EX_COMPOSITED        0x02000000L
              #endif
  
              wxMSWWinExStyleUpdater(GetHwndOf(m_pToolbar))
                  .TurnOn(WS_EX_COMPOSITED);
              */
  
          #endif
  
              m_pToolbar->SetCursor ( *wxSTANDARD_CURSOR );
              tbModified = true;
              m_categorizedModeToolId = -1;
              m_alphabeticModeToolId = -1;
          }
          else
          {
              m_pToolbar->SetWindowStyle(toolBarFlags);
              tbModified = true;
          }
  
          if ( HasExtraStyle(wxPG_EX_MODE_BUTTONS) )
          {
              // Add buttons if they don't already exist.
              if (m_categorizedModeToolId == -1)
              {
                  wxString desc(_("Categorized Mode"));
                  wxToolBarToolBase* tool = m_pToolbar->InsertTool(0,
                                              wxID_ANY,
                                              desc,
                                              wxBitmap(gs_xpm_catmode),
                                              wxNullBitmap,
                                              wxITEM_RADIO,
                                              desc);
                  m_categorizedModeToolId = tool->GetId();
                  tbModified = true;
  
                  Bind(wxEVT_TOOL, &wxPropertyGridManager::OnToolbarClick, this,
                       m_categorizedModeToolId);
              }
  
              if (m_alphabeticModeToolId == -1)
              {
                  wxString desc(_("Alphabetic Mode"));
                  wxToolBarToolBase* tool = m_pToolbar->InsertTool(1,
                                              wxID_ANY,
                                              desc,
                                              wxBitmap(gs_xpm_noncatmode),
                                              wxNullBitmap,
                                              wxITEM_RADIO,
                                              desc);
                  m_alphabeticModeToolId = tool->GetId();
                  tbModified = true;
  
                  Bind(wxEVT_TOOL, &wxPropertyGridManager::OnToolbarClick, this,
                       m_alphabeticModeToolId);
              }
  
              // Both buttons should exist here.
              wxASSERT( m_categorizedModeToolId != -1 && m_alphabeticModeToolId != -1);
          }
          else
          {
              // Remove buttons if they exist.
              if (m_categorizedModeToolId != -1)
              {
                  Unbind(wxEVT_TOOL, &wxPropertyGridManager::OnToolbarClick, this,
                         m_categorizedModeToolId);
  
                  m_pToolbar->DeleteTool(m_categorizedModeToolId);
                  m_categorizedModeToolId = -1;
                  tbModified = true;
              }
  
              if (m_alphabeticModeToolId != -1)
              {
                  Unbind(wxEVT_TOOL, &wxPropertyGridManager::OnToolbarClick, this,
                         m_alphabeticModeToolId);
  
                  m_pToolbar->DeleteTool(m_alphabeticModeToolId);
                  m_alphabeticModeToolId = -1;
                  tbModified = true;
              }
  
              // No button should exist here.
              wxASSERT( m_categorizedModeToolId == -1 && m_alphabeticModeToolId == -1);
          }
  
          // Rebuild toolbar if any changes were applied.
          if (tbModified)
          {
              m_pToolbar->Realize();
          }
  
          if ( HasExtraStyle(wxPG_EX_MODE_BUTTONS) )
          {
              // Toggle correct mode button.
              // TODO: This doesn't work in wxMSW (when changing,
              // both items will get toggled).
              int toggle_but_on_ind;
              int toggle_but_off_ind;
              if ( m_pPropGrid->m_pState->IsInNonCatMode() )
              {
                  toggle_but_on_ind = m_alphabeticModeToolId;
                  toggle_but_off_ind = m_categorizedModeToolId;
              }
              else
              {
                  toggle_but_on_ind = m_categorizedModeToolId;
                  toggle_but_off_ind = m_alphabeticModeToolId;
              }
  
              m_pToolbar->ToggleTool(toggle_but_on_ind, true);
              m_pToolbar->ToggleTool(toggle_but_off_ind, false);
          }
      }
      else
      {
          // No toolbar.
          if ( m_pToolbar )
              m_pToolbar->Destroy();
          m_pToolbar = NULL;
      }
  #endif
  
  #if wxUSE_HEADERCTRL
      if ( m_showHeader )
      {
          if ( !m_pHeaderCtrl )
          {
              m_pHeaderCtrl = new wxPGHeaderCtrl(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0);
          }
          else
          {
              m_pHeaderCtrl->Show();
          }
  
          m_pHeaderCtrl->OnPageChanged(GetCurrentPage());
      }
      else
      {
          if ( m_pHeaderCtrl )
              m_pHeaderCtrl->Hide();
      }
  #endif
  
      if ( m_windowStyle & wxPG_DESCRIPTION )
      {
          // Has help box.
          m_pPropGrid->SetInternalFlag(wxPG_FL_NOSTATUSBARHELP);
  
          if ( !m_pTxtHelpCaption )
          {
              m_pTxtHelpCaption = new wxStaticText(this,
                                                   wxID_ANY,
                                                   wxEmptyString,
                                                   wxDefaultPosition,
                                                   wxDefaultSize,
                                                   wxALIGN_LEFT|wxST_NO_AUTORESIZE);
              m_pTxtHelpCaption->SetFont(m_pPropGrid->GetCaptionFont());
              m_pTxtHelpCaption->SetCursor( *wxSTANDARD_CURSOR );
          }
          if ( !m_pTxtHelpContent )
          {
              m_pTxtHelpContent = new wxStaticText(this,
                                                   wxID_ANY,
                                                   wxEmptyString,
                                                   wxDefaultPosition,
                                                   wxDefaultSize,
                                                   wxALIGN_LEFT|wxST_NO_AUTORESIZE);
              m_pTxtHelpContent->SetCursor( *wxSTANDARD_CURSOR );
          }
  
          SetDescribedProperty(GetSelection());
      }
      else
      {
          // No help box.
          m_pPropGrid->ClearInternalFlag(wxPG_FL_NOSTATUSBARHELP);
  
          if ( m_pTxtHelpCaption )
              m_pTxtHelpCaption->Destroy();
  
          m_pTxtHelpCaption = NULL;
  
          if ( m_pTxtHelpContent )
              m_pTxtHelpContent->Destroy();
  
          m_pTxtHelpContent = NULL;
      }
  
      int width, height;
  
      GetClientSize(&width,&height);
  
      RecalculatePositions(width,height);
  
      if ( was_shown )
          Show ( true );
  }
  
  // -----------------------------------------------------------------------
  
  wxPGProperty* wxPropertyGridManager::DoGetPropertyByName( const wxString& name ) const
  {
      for ( size_t i = 0; i < GetPageCount(); i++ )
      {
          wxPropertyGridPageState* pState = m_arrPages[i]->GetStatePtr();
          wxPGProperty* p = pState->BaseGetPropertyByName(name);
          if ( p )
          {
              return p;
          }
      }
      return NULL;
  }
  
  // -----------------------------------------------------------------------
  
  bool wxPropertyGridManager::EnsureVisible( wxPGPropArg id )
  {
      wxPG_PROP_ARG_CALL_PROLOG_RETVAL(false)
  
      wxPropertyGridPageState* parentState = p->GetParentState();
  
      // Select correct page.
      if ( m_pPropGrid->m_pState != parentState )
          DoSelectPage( GetPageByState(parentState) );
  
      return m_pPropGrid->EnsureVisible(id);
  }
  
  // -----------------------------------------------------------------------
  
  #if wxUSE_TOOLBAR
  void wxPropertyGridManager::OnToolbarClick( wxCommandEvent &event )
  {
      int id = event.GetId();
  
      if ( id == m_categorizedModeToolId )
      {
          // Categorized mode.
          if ( m_pPropGrid->HasFlag(wxPG_HIDE_CATEGORIES) )
          {
              if ( !m_pPropGrid->HasInternalFlag(wxPG_FL_CATMODE_AUTO_SORT) )
                  m_pPropGrid->m_windowStyle &= ~wxPG_AUTO_SORT;
              m_pPropGrid->EnableCategories( true );
          }
      }
      else if ( id == m_alphabeticModeToolId )
      {
          // Alphabetic mode.
          if ( !m_pPropGrid->HasFlag(wxPG_HIDE_CATEGORIES) )
          {
              if ( m_pPropGrid->HasFlag(wxPG_AUTO_SORT) )
                  m_pPropGrid->SetInternalFlag(wxPG_FL_CATMODE_AUTO_SORT);
              else
                  m_pPropGrid->ClearInternalFlag(wxPG_FL_CATMODE_AUTO_SORT);
  
              m_pPropGrid->m_windowStyle |= wxPG_AUTO_SORT;
              m_pPropGrid->EnableCategories( false );
          }
      }
      else
      {
          // Page Switching.
  
          int index = -1;
  
          // Find page with given id.
          for ( size_t i = 0; i < GetPageCount(); i++ )
          {
              wxPropertyGridPage* pdc = m_arrPages[i];
              if ( pdc->GetToolId() == id )
              {
                  index = i;
                  break;
              }
          }
  
          wxASSERT( index >= 0 );
  
          if ( DoSelectPage(index) )
          {
              // Event dispatching must be last.
              m_pPropGrid->SendEvent( wxEVT_PG_PAGE_CHANGED, (wxPGProperty*)NULL );
          }
          else
          {
              // Restore button state on toolbar.
              wxToolBar* tb = wxDynamicCast(event.GetEventObject(), wxToolBar);
              wxASSERT( tb );
  
              // Release the current button.
              tb->ToggleTool(id, false);
              // Depress the old button.
              if ( m_selPage >= 0 )
              {
                  wxPropertyGridPage* prevPage = m_arrPages[m_selPage];
                  tb->ToggleTool(prevPage->GetToolId(), true);
              }
          }
      }
  }
  #endif
  
  // -----------------------------------------------------------------------
  
  bool wxPropertyGridManager::SetEditableStateItem( const wxString& name, wxVariant value )
  {
      if ( name == wxS("descboxheight") )
      {
          SetDescBoxHeight(value.GetLong(), true);
          return true;
      }
      return false;
  }
  
  // -----------------------------------------------------------------------
  
  wxVariant wxPropertyGridManager::GetEditableStateItem( const wxString& name ) const
  {
      if ( name == wxS("descboxheight") )
      {
          return (long) GetDescBoxHeight();
      }
      return wxNullVariant;
  }
  
  // -----------------------------------------------------------------------
  
  void wxPropertyGridManager::SetDescription( const wxString& label, const wxString& content )
  {
      if ( m_pTxtHelpCaption )
      {
          wxSize osz1 = m_pTxtHelpCaption->GetSize();
          wxSize osz2 = m_pTxtHelpContent->GetSize();
  
          m_pTxtHelpCaption->SetLabel(label);
          m_pTxtHelpContent->SetLabel(content);
  
          m_pTxtHelpCaption->SetSize(wxDefaultCoord, osz1.y);
          m_pTxtHelpContent->SetSize(wxDefaultCoord, osz2.y);
  
          UpdateDescriptionBox( m_splitterY, m_width, m_height );
      }
  }
  
  // -----------------------------------------------------------------------
  
  void wxPropertyGridManager::SetDescribedProperty( wxPGProperty* p )
  {
      if ( m_pTxtHelpCaption )
      {
          if ( p )
          {
              SetDescription( p->GetLabel(), p->GetHelpString() );
          }
          else
          {
              SetDescription( wxEmptyString, wxEmptyString );
          }
      }
  }
  
  // -----------------------------------------------------------------------
  
  void wxPropertyGridManager::SetSplitterLeft( bool subProps, bool allPages )
  {
      if ( !allPages )
      {
          m_pPropGrid->SetSplitterLeft(subProps);
      }
      else
      {
          wxClientDC dc(this);
          dc.SetFont(m_pPropGrid->GetFont());
  
          int highest = 0;
  
          for ( size_t i = 0; i < GetPageCount(); i++ )
          {
              int maxW = m_pState->GetColumnFitWidth(dc, m_arrPages[i]->DoGetRoot(), 0, subProps );
              maxW += m_pPropGrid->GetMarginWidth();
              if ( maxW > highest )
                  highest = maxW;
              m_pState->m_dontCenterSplitter = true;
          }
  
          if ( highest > 0 )
              SetSplitterPosition( highest );
      }
  
  #if wxUSE_HEADERCTRL
      if ( m_pHeaderCtrl && m_pHeaderCtrl->IsShown() )
          m_pHeaderCtrl->OnColumWidthsChanged();
  #endif
  }
  
  void wxPropertyGridManager::SetPageSplitterLeft(int page, bool subProps)
  {
      wxASSERT_MSG( (page < (int) GetPageCount()),
                    wxS("SetPageSplitterLeft() has no effect until pages have been added") );
  
      if (page < (int) GetPageCount())
      {
          wxClientDC dc(this);
          dc.SetFont(m_pPropGrid->GetFont());
  
          int maxW = m_pState->GetColumnFitWidth(dc, m_arrPages[page]->DoGetRoot(), 0, subProps );
          maxW += m_pPropGrid->GetMarginWidth();
          SetPageSplitterPosition( page, maxW );
  
  #if wxUSE_HEADERCTRL
          if ( m_pHeaderCtrl && m_pHeaderCtrl->IsShown() )
              m_pHeaderCtrl->OnColumWidthsChanged();
  #endif
      }
  }
  
  void wxPropertyGridManager::ReconnectEventHandlers(wxWindowID oldId, wxWindowID newId)
  {
      wxCHECK_RET( oldId != newId,
                   wxS("Attempting to reconnect event handlers to the same window"));
  
      if (oldId != wxID_NONE)
      {
          Unbind(wxEVT_PG_SELECTED, &wxPropertyGridManager::OnPropertyGridSelect, this,
                 oldId);
          Unbind(wxEVT_PG_HSCROLL, &wxPropertyGridManager::OnPGScrollH, this, oldId);
          Unbind(wxEVT_PG_COLS_RESIZED, &wxPropertyGridManager::OnColWidthsChanged, this, oldId);
      }
  
      if (newId != wxID_NONE)
      {
          Bind(wxEVT_PG_SELECTED, &wxPropertyGridManager::OnPropertyGridSelect, this,
               newId);
          Bind(wxEVT_PG_HSCROLL, &wxPropertyGridManager::OnPGScrollH, this, newId);
          Bind(wxEVT_PG_COLS_RESIZED, &wxPropertyGridManager::OnColWidthsChanged, this, newId);
      }
  }
  
  // -----------------------------------------------------------------------
  
  void wxPropertyGridManager::OnPropertyGridSelect( wxPropertyGridEvent& event )
  {
      // Check id.
      wxASSERT_MSG( GetId() == m_pPropGrid->GetId(),
          wxS("wxPropertyGridManager id must be set with wxPropertyGridManager::SetId (not wxWindow::SetId).") );
  
      SetDescribedProperty(event.GetProperty());
      event.Skip();
  }
  
  // -----------------------------------------------------------------------
  
  void wxPropertyGridManager::OnPGScrollH(wxPropertyGridEvent& evt)
  {
  #if wxUSE_HEADERCTRL
      if ( m_pHeaderCtrl )
      {
          m_pHeaderCtrl->ScrollWindow(evt.GetInt(), 0);
      }
  #endif // wxUSE_HEADERCTRL
  }
  
  void wxPropertyGridManager::OnColWidthsChanged(wxPropertyGridEvent& WXUNUSED(evt))
  {
  #if wxUSE_HEADERCTRL
      if ( m_pHeaderCtrl )
          m_pHeaderCtrl->OnColumWidthsChanged();
  #endif
  }
  
  // -----------------------------------------------------------------------
  
  void wxPropertyGridManager::OnResize( wxSizeEvent& WXUNUSED(event) )
  {
      int width, height;
  
      GetClientSize(&width, &height);
  
      if ( m_width == -12345 )
          RecreateControls();
  
      RecalculatePositions(width, height);
  
      if ( m_pPropGrid && m_pPropGrid->GetParent() )
      {
          int pgWidth, pgHeight;
          m_pPropGrid->GetClientSize(&pgWidth, &pgHeight);
  
          // Regenerate splitter positions for non-current pages
          for ( unsigned int i=0; i<GetPageCount(); i++ )
          {
              wxPropertyGridPage* page = GetPage(i);
              if ( page != m_pPropGrid->GetState() )
              {
                  page->OnClientWidthChange(pgWidth,
                                            pgWidth - page->GetVirtualWidth(),
                                            true);
              }
          }
      }
  
  #if wxUSE_HEADERCTRL
      if ( m_pHeaderCtrl && m_pHeaderCtrl->IsShown() )
          m_pHeaderCtrl->OnColumWidthsChanged();
  #endif
  }
  
  // -----------------------------------------------------------------------
  
  void wxPropertyGridManager::OnMouseEntry( wxMouseEvent& WXUNUSED(event) )
  {
      // Correct cursor. This is required at least for wxGTK, for which
      // setting button's cursor to *wxSTANDARD_CURSOR does not work.
      SetCursor( wxNullCursor );
      m_onSplitter = false;
  }
  
  // -----------------------------------------------------------------------
  
  void wxPropertyGridManager::OnMouseMove( wxMouseEvent &event )
  {
      if ( !m_pTxtHelpCaption )
          return;
  
      int y = event.m_y;
  
      if ( m_dragStatus > 0 )
      {
          int sy = y - m_dragOffset;
  
          // Calculate drag limits
          int bottom_limit = m_height - m_splitterHeight + 1;
          int top_limit = m_pPropGrid->GetRowHeight();
  #if wxUSE_TOOLBAR
          if ( m_pToolbar ) top_limit += m_pToolbar->GetSize().y;
  #endif
  
          if ( sy >= top_limit && sy < bottom_limit )
          {
  
              int change = sy - m_splitterY;
              if ( change )
              {
                  m_splitterY = sy;
  
                  m_pPropGrid->SetSize( m_width, m_splitterY - m_pPropGrid->GetPosition().y );
                  UpdateDescriptionBox( m_splitterY, m_width, m_height );
  
                  m_extraHeight -= change;
                  InvalidateBestSize();
              }
  
          }
  
      }
      else
      {
          if ( y >= m_splitterY && y < (m_splitterY+m_splitterHeight+2) )
          {
              SetCursor ( m_cursorSizeNS );
              m_onSplitter = true;
          }
          else
          {
              if ( m_onSplitter )
              {
                  SetCursor ( wxNullCursor );
              }
              m_onSplitter = false;
          }
      }
  }
  
  // -----------------------------------------------------------------------
  
  void wxPropertyGridManager::OnMouseClick( wxMouseEvent &event )
  {
      int y = event.m_y;
  
      // Click on splitter.
      if ( y >= m_splitterY && y < (m_splitterY+m_splitterHeight+2) )
      {
          if ( m_dragStatus == 0 )
          {
              //
              // Begin dragging the splitter
              //
  
              BEGIN_MOUSE_CAPTURE
  
              m_dragStatus = 1;
  
              m_dragOffset = y - m_splitterY;
  
          }
      }
  }
  
  // -----------------------------------------------------------------------
  
  void wxPropertyGridManager::OnMouseUp( wxMouseEvent &event )
  {
      // No event type check - basically calling this method should
      // just stop dragging.
  
      if ( m_dragStatus >= 1 )
      {
          //
          // End Splitter Dragging
          //
  
          int y = event.m_y;
  
          // DO NOT ENABLE FOLLOWING LINE!
          // (it is only here as a reminder to not to do it)
          //m_splitterY = y;
  
          // This is necessary to return cursor
          END_MOUSE_CAPTURE
  
          // Set back the default cursor, if necessary
          if ( y < m_splitterY || y >= (m_splitterY+m_splitterHeight+2) )
          {
              SetCursor ( wxNullCursor );
          }
  
          m_dragStatus = 0;
      }
  }
  
  // -----------------------------------------------------------------------
  
  void wxPropertyGridManager::SetSplitterPosition( int pos, int splitterColumn )
  {
      wxASSERT_MSG( GetPageCount(),
                    wxS("SetSplitterPosition() has no effect until pages have been added") );
  
      for ( size_t i = 0; i < GetPageCount(); i++ )
      {
          wxPropertyGridPage* page = GetPage(i);
          page->DoSetSplitterPosition( pos, splitterColumn,
                                       wxPG_SPLITTER_REFRESH );
      }
  
  #if wxUSE_HEADERCTRL
      if ( m_pHeaderCtrl && m_pHeaderCtrl->IsShown() )
          m_pHeaderCtrl->OnColumWidthsChanged();
  #endif
  }
  
  // -----------------------------------------------------------------------
  
  void wxPropertyGridManager::SetPageSplitterPosition( int page,
                                                       int pos,
                                                       int column )
  {
      GetPage(page)->DoSetSplitterPosition( pos, column );
  
  #if wxUSE_HEADERCTRL
      if ( m_pHeaderCtrl && m_pHeaderCtrl->IsShown() )
          m_pHeaderCtrl->OnColumWidthsChanged();
  #endif
  }
  
  // -----------------------------------------------------------------------
  // wxPGVIterator_Manager
  // -----------------------------------------------------------------------
  
  // Default returned by wxPropertyGridInterface::CreateVIterator().
  class wxPGVIteratorBase_Manager : public wxPGVIteratorBase
  {
  public:
      wxPGVIteratorBase_Manager( wxPropertyGridManager* manager, int flags )
          : m_manager(manager), m_flags(flags), m_curPage(0)
      {
          m_it.Init(manager->GetPage(0), flags);
      }
      virtual ~wxPGVIteratorBase_Manager() { }
      virtual void Next() wxOVERRIDE
      {
          m_it.Next();
  
          // Next page?
          if ( m_it.AtEnd() )
          {
              m_curPage++;
              if ( m_curPage < m_manager->GetPageCount() )
                  m_it.Init( m_manager->GetPage(m_curPage), m_flags );
          }
      }
  private:
      wxPropertyGridManager*  m_manager;
      int                     m_flags;
      unsigned int            m_curPage;
  };
  
  wxPGVIterator wxPropertyGridManager::GetVIterator( int flags ) const
  {
      return wxPGVIterator(new wxPGVIteratorBase_Manager(const_cast<wxPropertyGridManager*>(this), flags));
  }
  
  #endif  // wxUSE_PROPGRID
  