added virtual listctrl support
authorVadim Zeitlin <vadim@wxwidgets.org>
Thu, 5 Jul 2001 01:27:38 +0000 (01:27 +0000)
committerVadim Zeitlin <vadim@wxwidgets.org>
Thu, 5 Jul 2001 01:27:38 +0000 (01:27 +0000)
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@10837 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

include/wx/defs.h
include/wx/listctrl.h
include/wx/msw/listctrl.h
samples/listctrl/listtest.cpp
samples/listctrl/listtest.h
src/common/resource.cpp
src/msw/listctrl.cpp

index 705efe38dfab4702b7892a84d6890849999fed57..ae282dcf5eb6ffd0d097ab17729ffc1f5e80f797 100644 (file)
@@ -1220,36 +1220,6 @@ enum wxBorder
 #define wxTR_MAC_BUTTONS     0x0200
 #define wxTR_ROW_LINES       0x0400
 
-/*
- * wxListCtrl flags
- */
-#define wxLC_VRULES          0x0001
-#define wxLC_HRULES          0x0002
-#define wxLC_ICON            0x0004
-#define wxLC_SMALL_ICON      0x0008
-#define wxLC_LIST            0x0010
-#define wxLC_REPORT          0x0020
-#define wxLC_ALIGN_TOP       0x0040
-#define wxLC_ALIGN_LEFT      0x0080
-#define wxLC_AUTOARRANGE     0x0100
-#define wxLC_USER_TEXT       0x0200
-#define wxLC_EDIT_LABELS     0x0400
-#define wxLC_NO_HEADER       0x0800
-#define wxLC_NO_SORT_HEADER  0x1000
-#define wxLC_SINGLE_SEL      0x2000
-#define wxLC_SORT_ASCENDING  0x4000
-#define wxLC_SORT_DESCENDING 0x8000
-
-#define wxLC_MASK_TYPE       (wxLC_ICON | wxLC_SMALL_ICON | wxLC_LIST | wxLC_REPORT)
-#define wxLC_MASK_ALIGN      (wxLC_ALIGN_TOP | wxLC_ALIGN_LEFT)
-#define wxLC_MASK_SORT       (wxLC_SORT_ASCENDING | wxLC_SORT_DESCENDING)
-
-// Omitted because (a) too much detail (b) not enough style flags
-// #define wxLC_NO_SCROLL
-// #define wxLC_NO_LABEL_WRAP
-// #define wxLC_OWNERDRAW_FIXED
-// #define wxLC_SHOW_SEL_ALWAYS
-
 /*
  * wxSpinButton flags.
  * Note that a wxSpinCtrl is sometimes defined as
index b8b1d6d3e8502e790ea8770584333e4fc1983e29..0fc15269f168473d943f91508da8df3c1ebaf852 100644 (file)
@@ -29,6 +29,41 @@ typedef int (wxCALLBACK *wxListCtrlCompare)(long item1, long item2, long sortDat
 // wxListCtrl constants
 // ----------------------------------------------------------------------------
 
+// style flags
+#define wxLC_VRULES          0x0001
+#define wxLC_HRULES          0x0002
+#define wxLC_ICON            0x0004
+#define wxLC_SMALL_ICON      0x0008
+#define wxLC_LIST            0x0010
+#define wxLC_REPORT          0x0020
+#define wxLC_ALIGN_TOP       0x0040
+#define wxLC_ALIGN_LEFT      0x0080
+#define wxLC_AUTOARRANGE     0x0100
+#define wxLC_VIRTUAL         0x0200
+#define wxLC_EDIT_LABELS     0x0400
+#define wxLC_NO_HEADER       0x0800
+#define wxLC_NO_SORT_HEADER  0x1000
+#define wxLC_SINGLE_SEL      0x2000
+#define wxLC_SORT_ASCENDING  0x4000
+#define wxLC_SORT_DESCENDING 0x8000
+
+#define wxLC_MASK_TYPE       (wxLC_ICON | wxLC_SMALL_ICON | wxLC_LIST | wxLC_REPORT)
+#define wxLC_MASK_ALIGN      (wxLC_ALIGN_TOP | wxLC_ALIGN_LEFT)
+#define wxLC_MASK_SORT       (wxLC_SORT_ASCENDING | wxLC_SORT_DESCENDING)
+
+// for compatibility only
+#define wxLC_USER_TEXT       wxLC_VIRTUAL
+
+// Omitted because
+//  (a) too much detail
+//  (b) not enough style flags
+//  (c) not implemented anyhow in the generic version
+//
+// #define wxLC_NO_SCROLL
+// #define wxLC_NO_LABEL_WRAP
+// #define wxLC_OWNERDRAW_FIXED
+// #define wxLC_SHOW_SEL_ALWAYS
+
 // Mask flags to tell app/GUI what fields of wxListItem are valid
 #define wxLIST_MASK_STATE           0x0001
 #define wxLIST_MASK_TEXT            0x0002
index 288c85b676fd81e7ad98fcce59dc42477452c08f..e11e89c67039ca4f00b165ca2a25c07d458a8aa0 100644 (file)
@@ -215,12 +215,6 @@ public:
     // Returns the item or -1 if unsuccessful.
     long GetNextItem(long item, int geometry = wxLIST_NEXT_ALL, int state = wxLIST_STATE_DONTCARE) const ;
 
-    // Implementation: converts wxWindows style to MSW style.
-    // Can be a single style flag or a bit list.
-    // oldStyle is 'normalised' so that it doesn't contain
-    // conflicting styles.
-    long ConvertToMSWStyle(long& oldStyle, long style) const;
-
     // Gets one of the three image lists
     wxImageList *GetImageList(int which) const ;
 
@@ -234,6 +228,9 @@ public:
     void SetImageList(wxImageList *imageList, int which) ;
     void AssignImageList(wxImageList *imageList, int which) ;
 
+    // returns true if it is a virtual list control
+    bool IsVirtual() const { return (GetWindowStyle() & wxLC_VIRTUAL) != 0; }
+
     // Operations
     ////////////////////////////////////////////////////////////////////////////
 
@@ -301,6 +298,9 @@ public:
                       int format = wxLIST_FORMAT_LEFT,
                       int width = -1);
 
+    // set the number of items in a virtual list control
+    void SetItemCount(long count);
+
     // Scrolls the list control. If in icon, small icon or report view mode,
     // x specifies the number of pixels to scroll. If in list view mode, x
     // specifies the number of columns to scroll.
@@ -328,9 +328,11 @@ public:
     // bring the control in sync with current m_windowStyle value
     void UpdateStyle();
 
-    // Add to pool: necessary because Windows needs to have a string
-    // still exist across 3 callbacks.
-    wxChar *AddPool(const wxString& str);
+    // Implementation: converts wxWindows style to MSW style.
+    // Can be a single style flag or a bit list.
+    // oldStyle is 'normalised' so that it doesn't contain
+    // conflicting styles.
+    long ConvertToMSWStyle(long& oldStyle, long style) const;
 
     // Event handlers
     ////////////////////////////////////////////////////////////////////////////
@@ -353,7 +355,6 @@ protected:
                       m_ownsImageListState;
 
     long              m_baseStyle;  // Basic Windows style flags, for recreation purposes
-    wxStringList      m_stringPool; // Pool of 3 strings to satisfy Windows callback requirements
     int               m_colCount;   // Windows doesn't have GetColumnCount so must
                                     // keep track of inserted/deleted columns
 
@@ -363,6 +364,15 @@ protected:
     // TRUE if we have any items with custom attributes
     bool m_hasAnyAttr;
 
+    // these functions are only used for virtual list view controls, i.e. the
+    // ones with wxLC_VIRTUAL style
+
+    // return the text for the given column of the given item
+    virtual wxString OnGetItemText(long item, long column) const;
+
+    // return the icon for the given item
+    virtual int OnGetItemImage(long item) const;
+
 private:
     bool DoCreateControl(int x, int y, int w, int h);
 
index 345620a545d23925cf882b2038d2ab46c43d311e..6363c9b2ddd7c0fd609047670da804b14a737a7a 100644 (file)
@@ -48,8 +48,8 @@
 #include "listtest.h"
 
 BEGIN_EVENT_TABLE(MyFrame, wxFrame)
-    EVT_MENU(BUSY_ON, MyFrame::BusyOn)
-    EVT_MENU(BUSY_OFF, MyFrame::BusyOff)
+    EVT_SIZE(MyFrame::OnSize)
+
     EVT_MENU(LIST_QUIT, MyFrame::OnQuit)
     EVT_MENU(LIST_ABOUT, MyFrame::OnAbout)
     EVT_MENU(LIST_LIST_VIEW, MyFrame::OnListView)
@@ -58,6 +58,8 @@ BEGIN_EVENT_TABLE(MyFrame, wxFrame)
     EVT_MENU(LIST_ICON_TEXT_VIEW, MyFrame::OnIconTextView)
     EVT_MENU(LIST_SMALL_ICON_VIEW, MyFrame::OnSmallIconView)
     EVT_MENU(LIST_SMALL_ICON_TEXT_VIEW, MyFrame::OnSmallIconTextView)
+    EVT_MENU(LIST_VIRTUAL_VIEW, MyFrame::OnVirtualView)
+
     EVT_MENU(LIST_TOGGLE_FIRST, MyFrame::OnToggleFirstSel)
     EVT_MENU(LIST_DESELECT_ALL, MyFrame::OnDeselectAll)
     EVT_MENU(LIST_SELECT_ALL, MyFrame::OnSelectAll)
@@ -68,6 +70,7 @@ BEGIN_EVENT_TABLE(MyFrame, wxFrame)
     EVT_MENU(LIST_SET_BG_COL, MyFrame::OnSetBgColour)
     EVT_MENU(LIST_TOGGLE_MULTI_SEL, MyFrame::OnToggleMultiSel)
     EVT_MENU(LIST_SHOW_COL_INFO, MyFrame::OnShowColInfo)
+
     EVT_UPDATE_UI(LIST_SHOW_COL_INFO, MyFrame::OnUpdateShowColInfo)
 END_EVENT_TABLE()
 
@@ -154,46 +157,42 @@ MyFrame::MyFrame(const wxChar *title, int x, int y, int w, int h)
 
     // Make a menubar
     wxMenu *menuFile = new wxMenu;
-    menuFile->Append(LIST_ABOUT, "&About");
+    menuFile->Append(LIST_ABOUT, _T("&About"));
     menuFile->AppendSeparator();
-#if 0 // what is this for? (VZ)
-    menuFile->Append(BUSY_ON,         "&Busy cursor on");
-    menuFile->Append(BUSY_OFF,         "&Busy cursor off");
-    menuFile->AppendSeparator();
-#endif
-    menuFile->Append(LIST_QUIT, "E&xit\tAlt-X");
+    menuFile->Append(LIST_QUIT, _T("E&xit\tAlt-X"));
 
     wxMenu *menuView = new wxMenu;
-    menuView->Append(LIST_LIST_VIEW,         "&List view\tF1");
-    menuView->Append(LIST_REPORT_VIEW,         "&Report view\tF2");
-    menuView->Append(LIST_ICON_VIEW,         "&Icon view\tF3");
-    menuView->Append(LIST_ICON_TEXT_VIEW,     "Icon view with &text\tF4");
-    menuView->Append(LIST_SMALL_ICON_VIEW,     "&Small icon view\tF5");
-    menuView->Append(LIST_SMALL_ICON_TEXT_VIEW,     "Small icon &view with text\tF6");
+    menuView->Append(LIST_LIST_VIEW, _T("&List view\tF1"));
+    menuView->Append(LIST_REPORT_VIEW, _T("&Report view\tF2"));
+    menuView->Append(LIST_ICON_VIEW, _T("&Icon view\tF3"));
+    menuView->Append(LIST_ICON_TEXT_VIEW, _T("Icon view with &text\tF4"));
+    menuView->Append(LIST_SMALL_ICON_VIEW, _T("&Small icon view\tF5"));
+    menuView->Append(LIST_SMALL_ICON_TEXT_VIEW, _T("Small icon &view with text\tF6"));
+    menuView->Append(LIST_VIRTUAL_VIEW, _T("Virtual view\tF7"));
 
     wxMenu *menuList = new wxMenu;
-    menuList->Append(LIST_TOGGLE_FIRST, "&Toggle first item\tCtrl-T");
-    menuList->Append(LIST_DESELECT_ALL, "&Deselect All\tCtrl-D");
-    menuList->Append(LIST_SELECT_ALL, "S&elect All\tCtrl-A");
-    menuList->Append(LIST_SHOW_COL_INFO, "Show &column info\tCtrl-C");
+    menuList->Append(LIST_TOGGLE_FIRST, _T("&Toggle first item\tCtrl-T"));
+    menuList->Append(LIST_DESELECT_ALL, _T("&Deselect All\tCtrl-D"));
+    menuList->Append(LIST_SELECT_ALL, _T("S&elect All\tCtrl-A"));
+    menuList->Append(LIST_SHOW_COL_INFO, _T("Show &column info\tCtrl-C"));
     menuList->AppendSeparator();
-    menuList->Append(LIST_SORT, "&Sort\tCtrl-S");
+    menuList->Append(LIST_SORT, _T("&Sort\tCtrl-S"));
     menuList->AppendSeparator();
-    menuList->Append(LIST_DELETE, "&Delete first item");
-    menuList->Append(LIST_DELETE_ALL, "Delete &all items");
+    menuList->Append(LIST_DELETE, _T("&Delete first item"));
+    menuList->Append(LIST_DELETE_ALL, _T("Delete &all items"));
     menuList->AppendSeparator();
-    menuList->Append(LIST_TOGGLE_MULTI_SEL, "&Multiple selection\tCtrl-M",
-            "Toggle multiple selection", TRUE);
+    menuList->Append(LIST_TOGGLE_MULTI_SEL, _T("&Multiple selection\tCtrl-M"),
+            _T("Toggle multiple selection"), TRUE);
 
     wxMenu *menuCol = new wxMenu;
-    menuCol->Append(LIST_SET_FG_COL, "&Foreground colour...");
-    menuCol->Append(LIST_SET_BG_COL, "&Background colour...");
+    menuCol->Append(LIST_SET_FG_COL, _T("&Foreground colour..."));
+    menuCol->Append(LIST_SET_BG_COL, _T("&Background colour..."));
 
     wxMenuBar *menubar = new wxMenuBar;
-    menubar->Append(menuFile, "&File");
-    menubar->Append(menuView, "&View");
-    menubar->Append(menuList, "&List");
-    menubar->Append(menuCol, "&Colour");
+    menubar->Append(menuFile, _T("&File"));
+    menubar->Append(menuView, _T("&View"));
+    menubar->Append(menuList, _T("&List"));
+    menubar->Append(menuCol, _T("&Colour"));
     SetMenuBar(menubar);
 
     m_listCtrl = new MyListCtrl(this, LIST_CTRL,
@@ -201,9 +200,6 @@ MyFrame::MyFrame(const wxChar *title, int x, int y, int w, int h)
                                 wxLC_LIST |
                                 wxSUNKEN_BORDER |
                                 wxLC_EDIT_LABELS |
-                                // wxLC_USER_TEXT requires app to supply all
-                                // text on demand
-                                //wxLC_USER_TEXT |
                                 wxLC_SINGLE_SEL
                                );
 
@@ -213,21 +209,6 @@ MyFrame::MyFrame(const wxChar *title, int x, int y, int w, int h)
 
     m_logOld = wxLog::SetActiveTarget(new wxLogTextCtrl(m_logWindow));
 
-    wxLayoutConstraints *c = new wxLayoutConstraints;
-    c->top.SameAs            (this, wxTop);
-    c->left.SameAs        (this, wxLeft);
-    c->right.SameAs        (this, wxRight);
-    c->height.PercentOf    (this, wxHeight, 66);
-    m_listCtrl->SetConstraints(c);
-
-    c = new wxLayoutConstraints;
-    c->top.Below            (m_listCtrl);
-    c->left.SameAs        (this, wxLeft);
-    c->right.SameAs        (this, wxRight);
-    c->bottom.SameAs        (this, wxBottom);
-    m_logWindow->SetConstraints(c);
-    SetAutoLayout(TRUE);
-
     for ( int i = 0; i < 30; i++ )
     {
         long idx = m_listCtrl->InsertItem(i, wxString::Format(_T("Item %d"), i));
@@ -245,19 +226,22 @@ MyFrame::~MyFrame()
     delete m_imageListSmall;
 }
 
-void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
+void MyFrame::OnSize(wxSizeEvent& event)
 {
-    Close(TRUE);
-}
+    if ( !m_logWindow )
+        return;
 
-void MyFrame::BusyOn(wxCommandEvent& WXUNUSED(event))
-{
-   wxBeginBusyCursor();
+    wxSize size = GetClientSize();
+    wxCoord y = (2*size.y)/3;
+    m_listCtrl->SetSize(0, 0, size.x, y);
+    m_logWindow->SetSize(0, y + 1, size.x, size.y - y);
+
+    event.Skip();
 }
 
-void MyFrame::BusyOff(wxCommandEvent& WXUNUSED(event))
+void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
 {
-   wxEndBusyCursor();
+    Close(TRUE);
 }
 
 void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event))
@@ -298,9 +282,7 @@ void MyFrame::OnListView(wxCommandEvent& WXUNUSED(event))
 
     for ( int i=0; i < 30; i++)
     {
-        wxChar buf[20];
-        wxSprintf(buf, _T("Item %d"), i);
-        m_listCtrl->InsertItem(i, buf);
+        m_listCtrl->InsertItem(i, wxString::Format(_T("Item %d"), i));
     }
 }
 
@@ -426,6 +408,35 @@ void MyFrame::OnSmallIconTextView(wxCommandEvent& WXUNUSED(event))
     }
 }
 
+void MyFrame::OnVirtualView(wxCommandEvent& WXUNUSED(event))
+{
+#ifdef __WXMSW__
+    m_logWindow->Clear();
+
+    // we really have to recreate it
+    delete m_listCtrl;
+
+    m_listCtrl = new MyListCtrl(this, LIST_CTRL,
+                                wxDefaultPosition, wxDefaultSize,
+                                wxLC_REPORT |
+                                wxSUNKEN_BORDER |
+                                wxLC_SINGLE_SEL |
+                                wxLC_VIRTUAL
+                               );
+
+    m_listCtrl->InsertColumn(0, "First Column");
+    m_listCtrl->InsertColumn(1, "Second Column");
+    m_listCtrl->SetColumnWidth(0, 150);
+    m_listCtrl->SetColumnWidth(1, 150);
+
+    m_listCtrl->SetItemCount(1000000);
+
+    SendSizeEvent();
+#else
+    wxLogError(_T("Sorry, not implemented"));
+#endif
+}
+
 void MyFrame::OnSort(wxCommandEvent& WXUNUSED(event))
 {
     wxStopWatch sw;
@@ -632,3 +643,13 @@ void MyListCtrl::LogEvent(const wxListEvent& event, const wxChar *eventName)
                  event.GetText().c_str(), event.GetData());
 }
 
+wxString MyListCtrl::OnGetItemText(long item, long column) const
+{
+    return wxString::Format(_T("Column %ld of item %ld"), column, item);
+}
+
+int MyListCtrl::OnGetItemImage(long item) const
+{
+    return 0;
+}
+
index 29e351e1ffa679db3ab698d805154a2e9a001165..8814cd59b6f18a4eed84adf8fd91c9b6eb2ce181 100644 (file)
@@ -44,6 +44,9 @@ public:
 private:
     void LogEvent(const wxListEvent& event, const wxChar *eventName);
 
+    virtual wxString OnGetItemText(long item, long column) const;
+    virtual int OnGetItemImage(long item) const;
+
     DECLARE_EVENT_TABLE()
 };
 
@@ -58,6 +61,8 @@ public:
     ~MyFrame();
 
 public:
+    void OnSize(wxSizeEvent& event);
+
     void OnQuit(wxCommandEvent& event);
     void OnAbout(wxCommandEvent& event);
     void OnListView(wxCommandEvent& event);
@@ -66,6 +71,8 @@ public:
     void OnIconTextView(wxCommandEvent& event);
     void OnSmallIconView(wxCommandEvent& event);
     void OnSmallIconTextView(wxCommandEvent& event);
+    void OnVirtualView(wxCommandEvent& event);
+
     void OnToggleFirstSel(wxCommandEvent& event);
     void OnDeselectAll(wxCommandEvent& event);
     void OnSelectAll(wxCommandEvent& event);
@@ -76,10 +83,8 @@ public:
     void OnSetBgColour(wxCommandEvent& event);
     void OnToggleMultiSel(wxCommandEvent& event);
     void OnShowColInfo(wxCommandEvent& event);
-    void OnUpdateShowColInfo(wxUpdateUIEvent& event);
 
-    void BusyOn(wxCommandEvent& event);
-    void BusyOff(wxCommandEvent& event);
+    void OnUpdateShowColInfo(wxUpdateUIEvent& event);
 
     wxImageList *m_imageListNormal;
     wxImageList *m_imageListSmall;
@@ -91,22 +96,22 @@ private:
 };
 
 
-// ID for the menu quit command
+// IDs for the menu commands
 enum
 {
-    LIST_QUIT                   = 1,
-    LIST_LIST_VIEW              = 2,
-    LIST_ICON_VIEW              = 3,
-    LIST_ICON_TEXT_VIEW         = 4,
-    LIST_SMALL_ICON_VIEW        = 5,
-    LIST_SMALL_ICON_TEXT_VIEW   = 6,
-    LIST_REPORT_VIEW            = 7,
-    LIST_DESELECT_ALL           = 8,
-    LIST_SELECT_ALL             = 9,
-    LIST_ABOUT                  = 102,
-    BUSY_ON                     = 10,
-    BUSY_OFF                    = 11,
-    LIST_DELETE_ALL             = 12,
+    LIST_QUIT,
+    LIST_LIST_VIEW,
+    LIST_ICON_VIEW,
+    LIST_ICON_TEXT_VIEW,
+    LIST_SMALL_ICON_VIEW,
+    LIST_SMALL_ICON_TEXT_VIEW,
+    LIST_VIRTUAL_VIEW,
+
+    LIST_REPORT_VIEW,
+    LIST_DESELECT_ALL,
+    LIST_SELECT_ALL,
+    LIST_ABOUT,
+    LIST_DELETE_ALL,
     LIST_DELETE,
     LIST_SORT,
     LIST_SET_FG_COL,
index c0ffa5a62e1073409984baaa9a8cf8e4ad0c7f0d..8f7a71f1d309ae1a191a1f3ffd35333eb260fba3 100644 (file)
@@ -53,6 +53,8 @@
 #include "wx/intl.h"
 #endif
 
+#include "wx/listctrl.h"
+
 #if wxUSE_RADIOBTN
 #include "wx/radiobut.h"
 #endif
index 3bd2d2cfa833e709e4c8454725d8347cfef19505..191b98c91a71827c5993e10fb7cdb7399e83c96e 100644 (file)
@@ -29,9 +29,7 @@
     #pragma hdrstop
 #endif
 
-#if wxUSE_LISTCTRL
-
-#ifdef __WIN95__
+#if wxUSE_LISTCTRL && defined(__WIN95__)
 
 #ifndef WX_PRECOMP
     #include "wx/app.h"
@@ -426,12 +424,6 @@ long wxListCtrl::ConvertToMSWStyle(long& oldStyle, long style) const
     if ( style & wxLC_AUTOARRANGE )
         wstyle |= LVS_AUTOARRANGE;
 
-    // Apparently, no such style (documentation wrong?)
-    /*
-       if ( style & wxLC_BUTTON )
-       wstyle |= LVS_BUTTON;
-     */
-
     if ( style & wxLC_NO_SORT_HEADER )
         wstyle |= LVS_NOSORTHEADER;
 
@@ -458,6 +450,11 @@ long wxListCtrl::ConvertToMSWStyle(long& oldStyle, long style) const
         wstyle |= LVS_SORTDESCENDING;
     }
 
+    if ( style & wxLC_VIRTUAL )
+    {
+        wstyle |= LVS_OWNERDATA;
+    }
+
     return wstyle;
 }
 
@@ -1191,6 +1188,8 @@ long wxListCtrl::HitTest(const wxPoint& point, int& flags)
 // -1 otherwise.
 long wxListCtrl::InsertItem(wxListItem& info)
 {
+    wxASSERT_MSG( !IsVirtual(), _T("can't be used with virtual controls") );
+
     LV_ITEM item;
     wxConvertToMSWListItem(this, info, item);
 
@@ -1454,24 +1453,6 @@ bool wxListCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
             }
             break;
 
-        case LVN_GETDISPINFO:
-                // this provokes stack overflow: indeed, wxConvertFromMSWListItem()
-                // sends us WM_NOTIFY! As it doesn't do anything for now, just leave
-                // it out.
-#if 0
-            {
-                // TODO: some text buffering here, I think
-                // TODO: API for getting Windows to retrieve values
-                // on demand.
-                eventType = wxEVT_COMMAND_LIST_GET_INFO;
-                LV_DISPINFO *info = (LV_DISPINFO *)lParam;
-                wxConvertFromMSWListItem(this, event.m_item, info->item, GetHwnd());
-                break;
-            }
-#endif // 0
-                return FALSE;
-
-
         case LVN_INSERTITEM:
             eventType = wxEVT_COMMAND_LIST_INSERT_ITEM;
             event.m_itemIndex = nmLV->iItem;
@@ -1687,6 +1668,34 @@ bool wxListCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
 //            break; // can never be reached
 #endif // _WIN32_IE >= 0x300
 
+        case LVN_GETDISPINFO:
+            if ( IsVirtual() )
+            {
+                LV_DISPINFO *info = (LV_DISPINFO *)lParam;
+
+                LV_ITEM& lvi = info->item;
+                long item = lvi.iItem;
+
+                if ( lvi.mask & LVIF_TEXT )
+                {
+                    wxString text = OnGetItemText(item, lvi.iSubItem);
+                    wxStrncpy(lvi.pszText, text, lvi.cchTextMax);
+                }
+
+                if ( lvi.mask & LVIF_IMAGE )
+                {
+                    lvi.iImage = OnGetItemImage(item);
+                }
+
+                // a little dose of healthy paranoia: as we never use
+                // LVM_SETCALLBACKMASK we're not supposed to get these ones
+                wxASSERT_MSG( !(lvi.mask & LVIF_STATE),
+                              _T("we don't support state callbacks yet!") );
+
+                return TRUE;
+            }
+            // fall through
+
         default:
             return wxControl::MSWOnNotify(idCtrl, lParam, result);
     }
@@ -1713,20 +1722,6 @@ bool wxListCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
 
             return TRUE;
 
-        case LVN_GETDISPINFO:
-            {
-                LV_DISPINFO *info = (LV_DISPINFO *)lParam;
-                if ( info->item.mask & LVIF_TEXT )
-                {
-                    if ( !event.m_item.m_text.IsNull() )
-                    {
-                        info->item.pszText = AddPool(event.m_item.m_text);
-                        info->item.cchTextMax = wxStrlen(info->item.pszText) + 1;
-                    }
-                }
-                //    wxConvertToMSWListItem(this, event.m_item, info->item);
-                break;
-            }
         case LVN_ENDLABELEDIT:
             {
                 *result = event.IsAllowed();
@@ -1739,19 +1734,6 @@ bool wxListCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
     return TRUE;
 }
 
-wxChar *wxListCtrl::AddPool(const wxString& str)
-{
-    // Remove the first element if 3 strings exist
-    if ( m_stringPool.Number() == 3 )
-    {
-        wxNode *node = m_stringPool.First();
-        delete[] (char *)node->Data();
-        delete node;
-    }
-    wxNode *node = m_stringPool.Add(WXSTRINGCAST str);
-    return (wxChar *)node->Data();
-}
-
 // Necessary for drawing hrules and vrules, if specified
 void wxListCtrl::OnPaint(wxPaintEvent& event)
 {
@@ -1817,6 +1799,37 @@ void wxListCtrl::OnPaint(wxPaintEvent& event)
     }
 }
 
+// ----------------------------------------------------------------------------
+// virtual list controls
+// ----------------------------------------------------------------------------
+
+wxString wxListCtrl::OnGetItemText(long item, long col) const
+{
+    // this is a pure virtual function, in fact - which is not really pure
+    // because the controls which are not virtual don't need to implement it
+    wxFAIL_MSG( _T("not supposed to be called") );
+
+    return wxEmptyString;
+}
+
+int wxListCtrl::OnGetItemImage(long item) const
+{
+    // same as above
+    wxFAIL_MSG( _T("not supposed to be called") );
+
+    return -1;
+}
+
+void wxListCtrl::SetItemCount(long count)
+{
+    wxASSERT_MSG( IsVirtual(), _T("this is for virtual controls only") );
+
+    if ( !::SendMessage(GetHwnd(), LVM_SETITEMCOUNT, (WPARAM)count, 0) )
+    {
+        wxLogLastError(_T("ListView_SetItemCount"));
+    }
+}
+
 // ----------------------------------------------------------------------------
 // wxListItem
 // ----------------------------------------------------------------------------
@@ -2022,6 +2035,4 @@ wxListEvent::wxListEvent(wxEventType commandType, int id)
     m_cancelled = FALSE;
 }
 
-#endif // __WIN95__
-
 #endif // wxUSE_LISTCTRL