From a236aa2058ccf3d36e9cafc20fa7375080c4be50 Mon Sep 17 00:00:00 2001
From: Vadim Zeitlin <vadim@wxwidgets.org>
Date: Thu, 26 Jul 2007 13:54:14 +0000
Subject: [PATCH] many wxItemContainer-related changes:

1. the main function for item insertion is now DoInsertItems() which allows
   for much more efficient addition of many new items at once
2. the items client data management is done entirely in wxItemContainer
   itself, the derived classes don't have to distinguish between void and
   object client data
3. many fixes for sorted controls, in particular implemented wxCB_SORT support
   in wxGTK combobox


git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@47730 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
---
 build/bakefiles/files.bkl         |   4 +
 docs/changes.txt                  |   1 +
 docs/latex/wx/ctrlsub.tex         |  86 +++++-
 include/wx/arrstr.h               |  77 +++++
 include/wx/choice.h               |   3 +
 include/wx/clntdata.h             | 104 -------
 include/wx/cocoa/choice.h         |  12 +-
 include/wx/cocoa/combobox.h       |  12 +-
 include/wx/cocoa/listbox.h        |  12 +-
 include/wx/ctrlsub.h              | 303 +++++++++++++++++---
 include/wx/generic/bmpcbox.h      |  39 +--
 include/wx/generic/ctrlsub.h      | 123 ++++++++
 include/wx/gtk/choice.h           |  15 +-
 include/wx/gtk/combobox.h         |  26 +-
 include/wx/gtk/listbox.h          |  16 +-
 include/wx/gtk1/choice.h          |  13 +-
 include/wx/gtk1/combobox.h        |  11 +-
 include/wx/gtk1/listbox.h         |  12 +-
 include/wx/htmllbox.h             |  26 +-
 include/wx/listbox.h              |  24 +-
 include/wx/mac/carbon/choice.h    |  15 +-
 include/wx/mac/carbon/combobox.h  |  13 +-
 include/wx/mac/carbon/listbox.h   |  13 +-
 include/wx/mac/carbon/private.h   |   6 +-
 include/wx/motif/checklst.h       |   6 +-
 include/wx/motif/choice.h         |  19 +-
 include/wx/motif/combobox.h       |   9 +-
 include/wx/motif/ctrlsub.h        |  40 +++
 include/wx/motif/listbox.h        |  20 +-
 include/wx/msw/choice.h           |  12 +-
 include/wx/msw/ctrlsub.h          |  43 +++
 include/wx/msw/listbox.h          |  14 +-
 include/wx/msw/wince/checklst.h   |  14 +-
 include/wx/msw/wince/choicece.h   |  17 +-
 include/wx/odcombo.h              |  13 +-
 include/wx/os2/checklst.h         |   4 +-
 include/wx/os2/choice.h           |  13 +-
 include/wx/os2/listbox.h          |  21 +-
 include/wx/palmos/choice.h        |  11 +-
 include/wx/palmos/listbox.h       |  12 +-
 include/wx/univ/checklst.h        |   9 +-
 include/wx/univ/combobox.h        |  12 +-
 include/wx/univ/listbox.h         |  26 +-
 samples/widgets/Makefile.in       |  16 +-
 samples/widgets/bmpcombobox.cpp   |  13 +-
 samples/widgets/choice.cpp        | 453 ++++++++++++++++++++++++++++++
 samples/widgets/combobox.cpp      |  13 +-
 samples/widgets/icons/choice.xpm  |  27 ++
 samples/widgets/itemcontainer.cpp | 288 +++++++++++++++++++
 samples/widgets/itemcontainer.h   |  53 ++++
 samples/widgets/listbox.cpp       |  13 +-
 samples/widgets/makefile.bcc      |  17 +-
 samples/widgets/makefile.gcc      |  17 +-
 samples/widgets/makefile.unx      |  38 ++-
 samples/widgets/makefile.vc       |  16 +-
 samples/widgets/makefile.wat      |  17 +-
 samples/widgets/odcombobox.cpp    |  13 +-
 samples/widgets/widgets.bkl       |   2 +
 samples/widgets/widgets.dsp       |   8 +
 src/cocoa/choice.mm               |  78 ++---
 src/cocoa/combobox.mm             |  43 ++-
 src/cocoa/listbox.mm              |  49 +---
 src/common/ctrlsub.cpp            | 139 +++++++--
 src/common/lboxcmn.cpp            |  27 --
 src/generic/bmpcboxg.cpp          | 145 +++++-----
 src/generic/htmllbox.cpp          |  70 +++--
 src/generic/odcombo.cpp           |  42 +--
 src/gtk/choice.cpp                | 187 +++---------
 src/gtk/combobox.cpp              | 229 ++++-----------
 src/gtk/listbox.cpp               |  90 ++----
 src/gtk1/choice.cpp               | 123 ++------
 src/gtk1/combobox.cpp             | 140 +++------
 src/gtk1/listbox.cpp              | 167 ++---------
 src/mac/carbon/choice.cpp         | 110 +++-----
 src/mac/carbon/combobox.cpp       |  77 ++---
 src/mac/carbon/combobxc.cpp       |  81 ++----
 src/mac/carbon/listbox.cpp        |  52 +---
 src/mac/carbon/utils.cpp          |  33 +--
 src/motif/checklst.cpp            |  30 +-
 src/motif/choice.cpp              | 104 +++----
 src/motif/combobox.cpp            |  50 ++--
 src/motif/combobox_native.cpp     |  44 ++-
 src/motif/listbox.cpp             | 119 ++------
 src/msw/choice.cpp                |  93 ++----
 src/msw/control.cpp               |  36 +++
 src/msw/datectrl.cpp              |   2 +
 src/msw/dir.cpp                   |   2 +-
 src/msw/listbox.cpp               | 146 +++-------
 src/msw/wince/checklst.cpp        |  62 ++--
 src/msw/wince/choicece.cpp        |  68 ++---
 src/os2/checklst.cpp              |  10 +-
 src/os2/choice.cpp                | 100 +++----
 src/os2/listbox.cpp               | 157 +++--------
 src/palmos/choice.cpp             |  23 +-
 src/palmos/listbox.cpp            |  30 +-
 src/univ/checklst.cpp             |  36 +--
 src/univ/combobox.cpp             |  32 +--
 src/univ/listbox.cpp              | 126 ++-------
 98 files changed, 2792 insertions(+), 2645 deletions(-)
 create mode 100644 include/wx/generic/ctrlsub.h
 create mode 100644 include/wx/motif/ctrlsub.h
 create mode 100644 include/wx/msw/ctrlsub.h
 create mode 100644 samples/widgets/choice.cpp
 create mode 100644 samples/widgets/icons/choice.xpm
 create mode 100644 samples/widgets/itemcontainer.cpp
 create mode 100644 samples/widgets/itemcontainer.h

diff --git a/build/bakefiles/files.bkl b/build/bakefiles/files.bkl
index c2d4f7884a..d17fe62995 100644
--- a/build/bakefiles/files.bkl
+++ b/build/bakefiles/files.bkl
@@ -1369,6 +1369,7 @@ IMPORTANT: please read docs/tech/tn0016.txt before modifying this file!
 </set>
 <set var="MOTIF_HDR" hints="files">
     wx/generic/colrdlgg.h
+    wx/generic/ctrlsub.h
     wx/generic/dirdlgg.h
     wx/generic/fdrepdlg.h
     wx/generic/fontdlgg.h
@@ -1391,6 +1392,7 @@ IMPORTANT: please read docs/tech/tn0016.txt before modifying this file!
     wx/motif/colour.h
     wx/motif/combobox.h
     wx/motif/control.h
+    wx/motif/ctrlsub.h
     wx/motif/cursor.h
     wx/motif/dataform.h
     wx/motif/dataobj.h
@@ -1642,6 +1644,7 @@ IMPORTANT: please read docs/tech/tn0016.txt before modifying this file!
     wx/msw/combo.h
     wx/msw/combobox.h
     wx/msw/control.h
+    wx/msw/ctrlsub.h
     wx/msw/cursor.h
     wx/msw/dc.h
     wx/msw/dcclient.h
@@ -2634,6 +2637,7 @@ IMPORTANT: please read docs/tech/tn0016.txt before modifying this file!
 </set>
 <set var="UNIV_HDR" hints="files">
     wx/generic/accel.h
+    wx/generic/ctrlsub.h
     wx/generic/dirdlgg.h
     wx/generic/fdrepdlg.h
     wx/generic/fontdlgg.h
diff --git a/docs/changes.txt b/docs/changes.txt
index 75824c0085..bd7acde67a 100644
--- a/docs/changes.txt
+++ b/docs/changes.txt
@@ -155,6 +155,7 @@ wxGTK:
 - Support for markup and ellipsization in wxStaticText (Francesco Montorsi)
 - Native implementation for wxHyperlinkCtrl (Francesco Montorsi)
 - Native keyboard navigation implementation
+- Added wxCB_SORT support to wxComboBox (Evgeniy Tarassov)
 - Don't overwrite primary selection with clipboard and vice versa
 - Implemented support for underlined fonts in wxStaticText.
 - wxTopLevelWindow::SetSizeHints size increments now work.
diff --git a/docs/latex/wx/ctrlsub.tex b/docs/latex/wx/ctrlsub.tex
index afb99c037b..1a430cd202 100644
--- a/docs/latex/wx/ctrlsub.tex
+++ b/docs/latex/wx/ctrlsub.tex
@@ -61,15 +61,27 @@ untyped, client data pointer with the item.
 
 \func{void}{Append}{\param{const wxArrayString\& }{strings}}
 
+\func{void}{Append}{\param{unsigned int }{n},\param{const wxString* }{strings}}
+
+\func{void}{Append}{\param{unsigned int }{n},\param{const wxString* }{strings}, \param{void **}{clientData}}
+
+\func{void}{Append}{\param{unsigned int }{n},\param{const wxString* }{strings}, \param{wxClientData **}{clientData}}
+
 Appends several items at once to the control. Notice that calling this method
-may be much faster than appending the items one by one if you need to add a lot
+is usually much faster than appending them one by one if you need to add a lot
 of items.
 
 \wxheading{Parameters}
 
 \docparam{item}{String to add.}
 
-\docparam{clientData}{Client data to associate with the item.}
+\docparam{stringsArray}{Contains items to append to the control.}
+
+\docparam{strings}{Array of strings of size \arg{n}.}
+
+\docparam{n}{Number of items in the \arg{strings} array.}
+
+\docparam{clientData}{Array of client data pointers of size \arg{n} to associate with the new items.}
 
 \wxheading{Return value}
 
@@ -242,13 +254,34 @@ Inserts the item into the list before pos, associating the given, typed or
 untyped, client data pointer with the item.
 Not valid for {\tt wxLB\_SORT} or {\tt wxCB\_SORT} styles, use Append instead.
 
+\func{void}{Insert}{\param{const wxArrayString\& }{strings}, \param{unsigned int }{pos}}
+
+\func{void}{Insert}{\param{const wxArrayString\& }{strings}, \param{unsigned int }{pos}}
+
+\func{void}{Insert}{\param{unsigned int }{n},\param{const wxString* }{strings}, \param{unsigned int }{pos}}
+
+\func{void}{Insert}{\param{unsigned int }{n},\param{const wxString* }{strings}, \param{unsigned int }{pos}, \param{void **}{clientData}}
+
+\func{void}{Insert}{\param{unsigned int }{n},\param{const wxString* }{strings}, \param{unsigned int }{pos}, \param{wxClientData **}{clientData}}
+
+Inserts several items at once into the control. Notice that calling this method
+is usually much faster than inserting them one by one if you need to insert a lot
+of items.
+
+
 \wxheading{Parameters}
 
 \docparam{item}{String to add.}
 
 \docparam{pos}{Position to insert item before, zero based.}
 
-\docparam{clientData}{Client data to associate with the item.}
+\docparam{stringsArray}{Contains items to insert into the control content}
+
+\docparam{strings}{Array of strings of size \arg{n}.}
+
+\docparam{n}{Number of items in the \arg{strings} array.}
+
+\docparam{clientData}{Array of client data pointers of size \arg{n} to associate with the new items.}
 
 \wxheading{Return value}
 
@@ -276,6 +309,53 @@ exists only because it is slightly more natural for controls which support
 multiple selection.
 
 
+\membersection{wxControlWithItems::Set}\label{wxcontrolwithitemsset}
+
+\func{int}{Set}{\param{const wxString\& }{ item}}
+
+\func{int}{Set}{\param{const wxString\& }{ item}, \param{void *}{clientData}}
+
+\func{int}{Set}{\param{const wxString\& }{ item}, \param{wxClientData *}{clientData}}
+
+Replace control items with the (only) item specified, associating the typed or
+untyped client data pointer with it if given.
+
+\func{void}{Set}{\param{const wxArrayString\& }{stringsArray}}
+
+\func{void}{Set}{\param{unsigned int }{n},\param{const wxString* }{strings}}
+
+\func{void}{Set}{\param{unsigned int }{n},\param{const wxString* }{strings}, \param{void **}{clientData}}
+
+\func{void}{Set}{\param{unsigned int }{n},\param{const wxString* }{strings}, \param{wxClientData **}{clientData}}
+
+Replaces the current control contents with the given items. Notice that calling
+this method is much faster than appending the items one by one if you need to
+append a lot of them.
+
+\wxheading{Parameters}
+
+\docparam{item}{The single item to insert into the control.}
+
+\docparam{stringsArray}{Contains items to set as control content.}
+
+\docparam{strings}{Raw C++ array of strings. Only used in conjunction with 'n'.}
+
+\docparam{n}{Number of items passed in 'strings'. Only used in conjunction with 'strings'.}
+
+\docparam{clientData}{Client data to associate with the item(s).}
+
+\wxheading{Return value}
+
+When the control is sorted (e.g. has {\tt wxLB\_SORT} or {\tt wxCB\_SORT} style)
+the return value could be different from (GetCount() - 1).
+When setting a single item to the container, the return value is the index of the
+newly added item which may be different from the last one if the control is sorted
+(e.g. has {\tt wxLB\_SORT} or {\tt wxCB\_SORT} style).
+
+By default this method subsequently calls \helpref{Clear}{wxcontrolwithitemsclear}
+and \helpref{Append}{wxcontrolwithitemsappend}.
+
+
 \membersection{wxControlWithItems::SetClientData}\label{wxcontrolwithitemssetclientdata}
 
 \func{void}{SetClientData}{\param{unsigned int}{ n}, \param{void *}{data}}
diff --git a/include/wx/arrstr.h b/include/wx/arrstr.h
index ac59ff6483..a78d09e9dd 100644
--- a/include/wx/arrstr.h
+++ b/include/wx/arrstr.h
@@ -362,4 +362,81 @@ WXDLLIMPEXP_BASE wxArrayString wxSplit(const wxString& str,
                                        const wxChar sep,
                                        const wxChar escape = wxT('\\'));
 
+
+// ----------------------------------------------------------------------------
+// This helper class allows to pass both C array of wxStrings or wxArrayString
+// using the same interface.
+//
+// Use it when you have two methods taking wxArrayString or (int, wxString[]),
+// that do the same thing. This class lets you iterate over input data in the
+// same way whether it is a raw array of strings or wxArrayString.
+//
+// The object does not take ownership of the data -- internally it keeps
+// pointers to the data, therefore the data must be disposed of by user
+// and only after this object is destroyed. Usually it is not a problem as
+// only temporary objects of this class are used.
+// ----------------------------------------------------------------------------
+
+class wxArrayStringsAdapter
+{
+public:
+    // construct an adapter from a wxArrayString
+    wxArrayStringsAdapter(const wxArrayString& strings)
+        : m_type(wxSTRING_ARRAY), m_size(strings.size())
+    {
+        m_data.array = &strings;
+    }
+
+    // construct an adapter from a wxString[]
+    wxArrayStringsAdapter(unsigned int n, const wxString *strings)
+        : m_type(wxSTRING_POINTER), m_size(n)
+    {
+        m_data.ptr = strings;
+    }
+
+    // construct an adapter from a single wxString
+    wxArrayStringsAdapter(const wxString& s)
+        : m_type(wxSTRING_POINTER), m_size(1)
+    {
+        m_data.ptr = &s;
+    }
+
+    // default copy constructor is ok
+
+    // iteration interface
+    unsigned int GetCount() const { return m_size; }
+    bool IsEmpty() const { return GetCount() == 0; }
+    const wxString& operator[] (unsigned int i) const
+    {
+        wxASSERT_MSG( i < GetCount(), wxT("index out of bounds") );
+        if(m_type == wxSTRING_POINTER)
+            return m_data.ptr[i];
+        return m_data.array->Item(i);
+    }
+    wxArrayString AsArrayString() const
+    {
+        if(m_type == wxSTRING_ARRAY)
+            return *m_data.array;
+        return wxArrayString(GetCount(), m_data.ptr);
+    }
+
+private:
+    // type of the data being held
+    enum wxStringContainerType
+    {
+        wxSTRING_ARRAY,  // wxArrayString
+        wxSTRING_POINTER // wxString[]
+    };
+
+    wxStringContainerType m_type;
+    unsigned int m_size;
+    union
+    {
+        const wxString *      ptr;
+        const wxArrayString * array;
+    } m_data;
+
+    DECLARE_NO_ASSIGN_CLASS(wxArrayStringsAdapter)
+};
+
 #endif // _WX_ARRSTR_H
diff --git a/include/wx/choice.h b/include/wx/choice.h
index 16017f87ec..164aac07a5 100644
--- a/include/wx/choice.h
+++ b/include/wx/choice.h
@@ -55,6 +55,9 @@ public:
     // emulate selecting the item event.GetInt()
     void Command(wxCommandEvent& event);
 
+    // override wxItemContainer::IsSorted
+    virtual bool IsSorted() const { return HasFlag(wxCB_SORT); }
+
 private:
     DECLARE_NO_COPY_CLASS(wxChoiceBase)
 };
diff --git a/include/wx/clntdata.h b/include/wx/clntdata.h
index aba1cf71ef..c0f33dbb38 100644
--- a/include/wx/clntdata.h
+++ b/include/wx/clntdata.h
@@ -159,109 +159,5 @@ protected:
 
 };
 
-#include "wx/vector.h"
-
-struct WXDLLIMPEXP_BASE wxClientDataDictionaryPair
-{
-    wxClientDataDictionaryPair( size_t idx ) : index( idx ), data( 0 ) { }
-
-    size_t index;
-    wxClientData* data;
-};
-
-// this class is used internally to maintain the association between items
-// of (some subclasses of) wxControlWithItems and their client data
-// NOTE: this class does not keep track of whether it contains
-// wxClientData or void*. The client must ensure that
-// it does not contain a mix of the two, and that
-// DestroyData is called if it contains wxClientData
-class WXDLLIMPEXP_BASE wxClientDataDictionary
-{
-public:
-    wxClientDataDictionary() {}
-
-    // deletes all the data
-    void DestroyData()
-    {
-        for( size_t i = 0, end = m_vec.size(); i != end; ++i )
-            delete m_vec[i].data;
-        m_vec.clear();
-    }
-
-    // if data for the given index is not present, add it,
-    // if it is present, delete the old data and replace it with
-    // the new one
-    void Set( size_t index, wxClientData* data, bool doDelete )
-    {
-        size_t ptr = Find( index );
-
-        if( !data )
-        {
-            if( ptr == m_vec.size() ) return;
-            if( doDelete )
-                delete m_vec[ptr].data;
-            m_vec.erase( m_vec.begin() + ptr );
-        }
-        else
-        {
-            if( ptr == m_vec.size() )
-            {
-                m_vec.push_back( wxClientDataDictionaryPair( index ) );
-                ptr = m_vec.size() - 1;
-            }
-
-            if( doDelete )
-                delete m_vec[ptr].data;
-            m_vec[ptr].data = data;
-        }
-    }
-
-    // get the data associated with the given index,
-    // return 0 if not found
-    wxClientData* Get( size_t index ) const
-    {
-        size_t it = Find( index );
-        if( it == m_vec.size() ) return 0;
-        return (wxClientData*)m_vec[it].data; // const cast
-    }
-
-    // delete the data associated with the given index
-    // it also decreases by one the indices of all the elements
-    // with an index greater than the given index
-    void Delete( size_t index, bool doDelete )
-    {
-        size_t todel = m_vec.size();
-
-        for( size_t i = 0, end = m_vec.size(); i != end; ++i )
-        {
-            if( m_vec[i].index == index )
-                todel = i;
-            else if( m_vec[i].index > index )
-                --(m_vec[i].index);
-        }
-
-        if( todel != m_vec.size() )
-        {
-            if( doDelete )
-                delete m_vec[todel].data;
-            m_vec.erase( m_vec.begin() + todel );
-        }
-    }
-private:
-    // returns MyVec.size() if not found
-    size_t Find( size_t index ) const
-    {
-        for( size_t i = 0, end = m_vec.size(); i != end; ++i )
-        {
-            if( m_vec[i].index == index )
-                return i;
-        }
-
-        return m_vec.size();
-    }
-
-    wxVector<wxClientDataDictionaryPair> m_vec;
-};
-
 #endif // _WX_CLNTDATAH__
 
diff --git a/include/wx/cocoa/choice.h b/include/wx/cocoa/choice.h
index 1057527bae..e0ad953c9a 100644
--- a/include/wx/cocoa/choice.h
+++ b/include/wx/cocoa/choice.h
@@ -80,19 +80,19 @@ protected:
 // Implementation
 // ------------------------------------------------------------------------
 public:
-    virtual void Clear();
-    virtual void Delete(unsigned int n);
+    virtual void DoClear();
+    virtual void DoDelete(unsigned int n);
     virtual unsigned int GetCount() const;
     virtual wxString GetString(unsigned int) const;
     virtual void SetString(unsigned int pos, const wxString&);
     virtual int FindString(const wxString& s, bool bCase = false) const;
     virtual int GetSelection() const;
-    virtual int DoAppend(const wxString&);
-    virtual int DoInsert(const wxString&, unsigned int pos);
+    virtual int DoInsertItems(const wxArrayStringsAdapter& items,
+                              unsigned int pos,
+                              void **clientData, wxClientDataType type);
+    virtual void DoDeleteOneItem(unsigned int pos);
     virtual void DoSetItemClientData(unsigned int, void*);
     virtual void* DoGetItemClientData(unsigned int) const;
-    virtual void DoSetItemClientObject(unsigned int, wxClientData*);
-    virtual wxClientData* DoGetItemClientObject(unsigned int) const;
     virtual void SetSelection(int pos);
 protected:
     wxSortedArrayString *m_sortedStrings;
diff --git a/include/wx/cocoa/combobox.h b/include/wx/cocoa/combobox.h
index cc262de82d..9423b28d94 100644
--- a/include/wx/cocoa/combobox.h
+++ b/include/wx/cocoa/combobox.h
@@ -106,19 +106,19 @@ public:
     // Overlapping methods
     virtual wxString GetStringSelection();
     // wxItemContainer
-    virtual void Clear();
-    virtual void Delete(unsigned int n);
+    virtual void DoClear();
+    virtual void DoDeleteOneItem(unsigned int n);
     virtual unsigned int GetCount() const;
     virtual wxString GetString(unsigned int) const;
     virtual void SetString(unsigned int pos, const wxString&);
     virtual int FindString(const wxString& s, bool bCase = false) const;
     virtual int GetSelection() const;
-    virtual int DoAppend(const wxString&);
-    virtual int DoInsert(const wxString&, unsigned int pos);
+    virtual int DoInsertItems(const wxArrayStringsAdapter& items,
+                              unsigned int pos,
+                              void **clientData, wxClientDataType type);
     virtual void DoSetItemClientData(unsigned int, void*);
     virtual void* DoGetItemClientData(unsigned int) const;
-    virtual void DoSetItemClientObject(unsigned int, wxClientData*);
-    virtual wxClientData* DoGetItemClientObject(unsigned int) const;
+    virtual bool IsSorted() const { return HasFlag(wxCB_SORT); }
     // wxComboBoxBase pure virtuals
     virtual wxString GetValue() const
     {   return wxTextCtrl::GetValue(); }
diff --git a/include/wx/cocoa/listbox.h b/include/wx/cocoa/listbox.h
index 0002435bbc..e21a39c3e1 100644
--- a/include/wx/cocoa/listbox.h
+++ b/include/wx/cocoa/listbox.h
@@ -84,16 +84,14 @@ public:
     virtual bool IsSelected(int n) const;
     virtual int GetSelections(wxArrayInt& aSelections) const;
 protected:
-    virtual void DoInsertItems(const wxArrayString& items, unsigned int pos);
-    virtual void DoSetItems(const wxArrayString& items, void **clientData);
     virtual void DoSetFirstItem(int n);
     virtual void DoSetSelection(int n, bool select);
 
 // pure virtuals from wxItemContainer
 public:
     // deleting items
-    virtual void Clear();
-    virtual void Delete(unsigned int n);
+    virtual void DoClear();
+    virtual void DoDeleteOneItem(unsigned int n);
     // accessing strings
     virtual unsigned int GetCount() const;
     virtual wxString GetString(unsigned int n) const;
@@ -102,11 +100,11 @@ public:
     // selection
     virtual int GetSelection() const;
 protected:
-    virtual int DoAppend(const wxString& item);
+    virtual int DoInsertItems(const wxArrayStringsAdapter& items,
+                              unsigned int pos,
+                              void **clientData, wxClientDataType type);
     virtual void DoSetItemClientData(unsigned int n, void* clientData);
     virtual void* DoGetItemClientData(unsigned int n) const;
-    virtual void DoSetItemClientObject(unsigned int n, wxClientData* clientData);
-    virtual wxClientData* DoGetItemClientObject(unsigned int n) const;
 };
 
 #endif // __WX_COCOA_LISTBOX_H__
diff --git a/include/wx/ctrlsub.h b/include/wx/ctrlsub.h
index 9939f9a7df..901f52c45d 100644
--- a/include/wx/ctrlsub.h
+++ b/include/wx/ctrlsub.h
@@ -16,6 +16,7 @@
 
 #if wxUSE_CONTROLS
 
+#include "wx/arrstr.h"
 #include "wx/control.h"      // base class
 
 // ----------------------------------------------------------------------------
@@ -80,14 +81,109 @@ public:
 
 
 protected:
-
     // check that the index is valid
-    inline bool IsValid(unsigned int n) const { return n < GetCount(); }
-    inline bool IsValidInsert(unsigned int n) const { return n <= GetCount(); }
+    bool IsValid(unsigned int n) const { return n < GetCount(); }
+    bool IsValidInsert(unsigned int n) const { return n <= GetCount(); }
 };
 
+// ----------------------------------------------------------------------------
+// wxItemContainer extends wxItemContainerImmutable interface with methods
+// for adding/removing items.
+//
+// Classes deriving from this one must override DoInsertItems() to implement
+// adding items to the control. This can often be implemented more efficiently
+// than simply looping over the elements and inserting them but if this is not
+// the case, the generic DoInsertItemsInLoop can be used in implementation, but
+// in this case DoInsertItem() needs to be overridden.
+// ----------------------------------------------------------------------------
+
 class WXDLLEXPORT wxItemContainer : public wxItemContainerImmutable
 {
+private:
+    // AppendItems() and InsertItems() helpers just call DoAppend/InsertItems()
+    // after doing some checks
+    //
+    // NB: they're defined here so that they're inlined when used in public part
+    int AppendItems(const wxArrayStringsAdapter& items,
+                    void **clientData,
+                    wxClientDataType type)
+    {
+        if ( items.IsEmpty() )
+            return wxNOT_FOUND;
+
+        return DoAppendItems(items, clientData, type);
+    }
+
+    int AppendItems(const wxArrayStringsAdapter& items)
+    {
+        return AppendItems(items, NULL, wxClientData_None);
+    }
+
+    int AppendItems(const wxArrayStringsAdapter& items, void **clientData)
+    {
+        wxASSERT_MSG( m_clientDataItemsType != wxClientData_Object,
+                      _T("can't mix different types of client data") );
+
+        return AppendItems(items, clientData, wxClientData_Void);
+    }
+
+    int AppendItems(const wxArrayStringsAdapter& items,
+                    wxClientData **clientData)
+    {
+        wxASSERT_MSG( m_clientDataItemsType != wxClientData_Void,
+                      _T("can't mix different types of client data") );
+
+        return AppendItems(items, wx_reinterpret_cast(void **, clientData),
+                           wxClientData_Object);
+    }
+
+    int InsertItems(const wxArrayStringsAdapter& items,
+                    unsigned int pos,
+                    void **clientData,
+                    wxClientDataType type)
+    {
+        wxASSERT_MSG( !IsSorted(), _T("can't insert items in sorted control") );
+
+        wxCHECK_MSG( pos <= GetCount(), wxNOT_FOUND,
+                     _T("position out of range") );
+
+        // not all derived classes handle empty arrays correctly in
+        // DoInsertItems() and besides it really doesn't make much sense to do
+        // this (for append it could correspond to creating an initially empty
+        // control but why would anybody need to insert 0 items?)
+        wxCHECK_MSG( !items.IsEmpty(), wxNOT_FOUND,
+                     _T("need something to insert") );
+
+        return DoInsertItems(items, pos, clientData, type);
+    }
+
+    int InsertItems(const wxArrayStringsAdapter& items, unsigned int pos)
+    {
+        return InsertItems(items, pos, NULL, wxClientData_None);
+    }
+
+    int InsertItems(const wxArrayStringsAdapter& items,
+                     unsigned int pos,
+                     void **clientData)
+    {
+        wxASSERT_MSG( m_clientDataItemsType != wxClientData_Object,
+                      _T("can't mix different types of client data") );
+
+        return InsertItems(items, pos, clientData, wxClientData_Void);
+    }
+
+    int InsertItems(const wxArrayStringsAdapter& items,
+                     unsigned int pos,
+                     wxClientData **clientData)
+    {
+        wxASSERT_MSG( m_clientDataItemsType != wxClientData_Void,
+                      _T("can't mix different types of client data") );
+
+        return InsertItems(items, pos,
+                           wx_reinterpret_cast(void **, clientData),
+                           wxClientData_Object);
+    }
+
 public:
     wxItemContainer() { m_clientDataItemsType = wxClientData_None; }
     virtual ~wxItemContainer();
@@ -95,54 +191,178 @@ public:
     // adding items
     // ------------
 
+    // append single item, return its position in the control (which can be
+    // different from the last one if the control is sorted)
     int Append(const wxString& item)
-        { return DoAppend(item); }
+        { return AppendItems(item); }
     int Append(const wxString& item, void *clientData)
-        { int n = DoAppend(item); SetClientData(n, clientData); return n; }
+        { return AppendItems(item, &clientData); }
     int Append(const wxString& item, wxClientData *clientData)
-        { int n = DoAppend(item); SetClientObject(n, clientData); return n; }
-
-    // only for rtti needs (separate name)
-    void AppendString( const wxString& item)
-        { Append( item ); }
-
-    // append several items at once to the control
-    void Append(const wxArrayString& strings);
-
+        { return AppendItems(item, &clientData); }
+
+    // append several items at once to the control, return the position of the
+    // last item appended
+    int Append(const wxArrayString& items)
+        { return AppendItems(items); }
+    int Append(const wxArrayString& items, void **clientData)
+        { return AppendItems(items, clientData); }
+    int Append(const wxArrayString& items, wxClientData **clientData)
+        { return AppendItems(items, clientData); }
+    int Append(unsigned int n, const wxString *items)
+        { return AppendItems(wxArrayStringsAdapter(n, items)); }
+    int Append(unsigned int n, const wxString *items, void **clientData)
+        { return AppendItems(wxArrayStringsAdapter(n, items), clientData); }
+    int Append(unsigned int n,
+               const wxString *items,
+               wxClientData **clientData)
+        { return AppendItems(wxArrayStringsAdapter(n, items), clientData); }
+
+    // only for RTTI needs (separate name)
+    void AppendString(const wxString& item)
+        { Append(item); }
+
+
+    // inserting items: not for sorted controls!
+    // -----------------------------------------
+
+    // insert single item at the given position, return its effective position
     int Insert(const wxString& item, unsigned int pos)
-        { return DoInsert(item, pos); }
-    int Insert(const wxString& item, unsigned int pos, void *clientData);
-    int Insert(const wxString& item, unsigned int pos, wxClientData *clientData);
+        { return InsertItems(item, pos); }
+    int Insert(const wxString& item, unsigned int pos, void *clientData)
+        { return InsertItems(item, pos, &clientData); }
+    int Insert(const wxString& item, unsigned int pos, wxClientData *clientData)
+        { return InsertItems(item, pos, &clientData); }
+
+    // insert several items at once into the control, return the index of the
+    // last item inserted
+    int Insert(const wxArrayString& items, unsigned int pos)
+        { return InsertItems(items, pos); }
+    int Insert(const wxArrayString& items, unsigned int pos, void **clientData)
+        { return InsertItems(items, pos, clientData); }
+    int Insert(const wxArrayString& items,
+               unsigned int pos,
+               wxClientData **clientData)
+        { return InsertItems(items, pos, clientData); }
+    int Insert(unsigned int n, const wxString *items, unsigned int pos)
+        { return InsertItems(wxArrayStringsAdapter(n, items), pos); }
+    int Insert(unsigned int n,
+               const wxString *items,
+               unsigned int pos,
+               void **clientData)
+        { return InsertItems(wxArrayStringsAdapter(n, items), pos, clientData); }
+    int Insert(unsigned int n,
+               const wxString *items,
+               unsigned int pos,
+               wxClientData **clientData)
+        { return InsertItems(wxArrayStringsAdapter(n, items), pos, clientData); }
+
+
+    // replacing items
+    // ---------------
+
+    void Set(const wxArrayString& items)
+        { Clear(); Append(items); }
+    void Set(const wxArrayString& items, void **clientData)
+        { Clear(); Append(items, clientData); }
+    void Set(const wxArrayString& items, wxClientData **clientData)
+        { Clear(); Append(items, clientData); }
+    void Set(unsigned int n, const wxString *items)
+        { Clear(); Append(n, items); }
+    void Set(unsigned int n, const wxString *items, void **clientData)
+        { Clear(); Append(n, items, clientData); }
+    void Set(unsigned int n, const wxString *items, wxClientData **clientData)
+        { Clear(); Append(n, items, clientData); }
 
     // deleting items
     // --------------
 
-    virtual void Clear() = 0;
-    virtual void Delete(unsigned int n) = 0;
+    void Clear();
+    void Delete(unsigned int pos);
 
-    // misc
-    // ----
 
     // client data stuff
+    // -----------------
+
     void SetClientData(unsigned int n, void* clientData);
     void* GetClientData(unsigned int n) const;
 
     void SetClientObject(unsigned int n, wxClientData* clientData);
     wxClientData* GetClientObject(unsigned int n) const;
 
+    bool HasClientData() const
+        { return m_clientDataItemsType != wxClientData_None; }
     bool HasClientObjectData() const
         { return m_clientDataItemsType == wxClientData_Object; }
     bool HasClientUntypedData() const
         { return m_clientDataItemsType == wxClientData_Void; }
 
+
+    // The control may maintain its items in a sorted order in which case
+    // items are automatically inserted at the right position when they are
+    // inserted or appended. Derived classes have to override this method if
+    // they implement sorting, typically by returning HasFlag(wxXX_SORT)
+    virtual bool IsSorted() const { return false; }
+
 protected:
-    virtual int DoAppend(const wxString& item) = 0;
-    virtual int DoInsert(const wxString& item, unsigned int pos) = 0;
+    // there is usually no need to override this method but you can do it if it
+    // is more convenient to only do "real" insertions in DoInsertItems() and
+    // to implement items appending here (in which case DoInsertItems() should
+    // call this method if pos == GetCount() as it can still be called in this
+    // case if public Insert() is called with such position)
+    virtual int DoAppendItems(const wxArrayStringsAdapter& items,
+                              void **clientData,
+                              wxClientDataType type)
+    {
+        return DoInsertItems(items, GetCount(), clientData, type);
+    }
 
-    virtual void DoSetItemClientData(unsigned int n, void* clientData) = 0;
-    virtual void* DoGetItemClientData(unsigned int n) const = 0;
-    virtual void DoSetItemClientObject(unsigned int n, wxClientData* clientData) = 0;
-    virtual wxClientData* DoGetItemClientObject(unsigned int n) const = 0;
+    // this method must be implemented to insert the items into the control at
+    // position pos which can be GetCount() meaning that the items should be
+    // appended; for the sorted controls the position can be ignored
+    //
+    // the derived classes typically use AssignNewItemClientData() to
+    // associate the data with the items as they're being inserted
+    //
+    // the method should return the index of the position the last item was
+    // inserted into or wxNOT_FOUND if an error occurred
+    virtual int DoInsertItems(const wxArrayStringsAdapter & items,
+                              unsigned int pos,
+                              void **clientData,
+                              wxClientDataType type) = 0;
+
+    // before the client data is set for the first time for the control which
+    // hadn't had it before, DoInitItemClientData() is called which gives the
+    // derived class the possibility to initialize its client data storage only
+    // when client data is really used
+    virtual void DoInitItemClientData() { }
+    virtual void DoSetItemClientData(unsigned int n, void *clientData) = 0;
+    virtual void *DoGetItemClientData(unsigned int n) const = 0;
+
+    virtual void DoClear() = 0;
+    virtual void DoDeleteOneItem(unsigned int pos) = 0;
+
+
+    // methods useful for the derived classes which don't have any better way
+    // of adding multiple items to the control than doing it one by one: such
+    // classes should call DoInsertItemsInLoop() from their DoInsert() and
+    // override DoInsertOneItem() to perform the real insertion
+    virtual int DoInsertOneItem(const wxString& item, unsigned int pos);
+    int DoInsertItemsInLoop(const wxArrayStringsAdapter& items,
+                            unsigned int pos,
+                            void **clientData,
+                            wxClientDataType type);
+
+
+    // helper for DoInsertItems(): n is the index into clientData, pos is the
+    // position of the item in the control
+    void AssignNewItemClientData(unsigned int pos,
+                                 void **clientData,
+                                 unsigned int n,
+                                 wxClientDataType type);
+
+    // free the client object associated with the item at given position and
+    // set it to NULL (must only be called if HasClientObjectData())
+    void ResetItemClientObject(unsigned int n);
 
 
     // the type of the client data for the items
@@ -171,11 +391,11 @@ protected:
     wxClientData* GetClientObject(unsigned int n) const                    \
         { return wxItemContainer::GetClientObject(n); }
 
-class WXDLLEXPORT wxControlWithItems : public wxControl, public wxItemContainer
+class WXDLLEXPORT wxControlWithItemsBase : public wxControl,
+                                           public wxItemContainer
 {
 public:
-    wxControlWithItems() { }
-    virtual ~wxControlWithItems();
+    wxControlWithItemsBase() { }
 
     // we have to redefine these functions here to avoid ambiguities in classes
     // deriving from us which would arise otherwise because both base classses
@@ -196,14 +416,25 @@ protected:
     void InitCommandEventWithItems(wxCommandEvent& event, int n);
 
 private:
-    DECLARE_ABSTRACT_CLASS(wxControlWithItems)
-    DECLARE_NO_COPY_CLASS(wxControlWithItems)
+    DECLARE_NO_COPY_CLASS(wxControlWithItemsBase)
 };
 
-
-// ----------------------------------------------------------------------------
-// inline functions
-// ----------------------------------------------------------------------------
+// define the platform-specific wxControlWithItems class
+#if defined(__WXMSW__)
+    #include "wx/msw/ctrlsub.h"
+#elif defined(__WXMOTIF__)
+    #include "wx/motif/ctrlsub.h"
+#else
+    class wxControlWithItems : public wxControlWithItemsBase
+    {
+    public:
+        wxControlWithItems() { }
+
+    private:
+        DECLARE_ABSTRACT_CLASS(wxControlWithItems)
+        DECLARE_NO_COPY_CLASS(wxControlWithItems)
+    };
+#endif
 
 #endif // wxUSE_CONTROLS
 
diff --git a/include/wx/generic/bmpcbox.h b/include/wx/generic/bmpcbox.h
index 58f53627de..e192470c4e 100644
--- a/include/wx/generic/bmpcbox.h
+++ b/include/wx/generic/bmpcbox.h
@@ -86,13 +86,17 @@ public:
     virtual ~wxBitmapComboBox();
 
     // Adds item with image to the end of the combo box.
-    int Append(const wxString& item, const wxBitmap& bitmap = wxNullBitmap)
-        { return DoAppendWithImage(item, bitmap); }
+    int Append(const wxString& item, const wxBitmap& bitmap = wxNullBitmap);
+    int Append(const wxString& item, const wxBitmap& bitmap, void *clientData);
+    int Append(const wxString& item, const wxBitmap& bitmap, wxClientData *clientData);
 
-    int Append(const wxString& item, const wxBitmap& bitmap, void *clientData)
-        { int n = DoAppendWithImage(item, bitmap); SetClientData(n, clientData); return n; }
-    int Append(const wxString& item, const wxBitmap& bitmap, wxClientData *clientData)
-        { int n = DoAppendWithImage(item, bitmap); SetClientObject(n, clientData); return n; }
+    // Inserts item with image into the list before pos. Not valid for wxCB_SORT
+    // styles, use Append instead.
+    int Insert(const wxString& item, const wxBitmap& bitmap, unsigned int pos);
+    int Insert(const wxString& item, const wxBitmap& bitmap,
+               unsigned int pos, void *clientData);
+    int Insert(const wxString& item, const wxBitmap& bitmap,
+               unsigned int pos, wxClientData *clientData);
 
     // Returns size of image used in list.
     virtual wxSize GetBitmapSize() const
@@ -103,21 +107,11 @@ public:
     // Returns the image of the item with the given index.
     virtual wxBitmap GetItemBitmap(unsigned int n) const;
 
-    // Inserts item with image into the list before pos. Not valid for wxCB_SORT or wxCB_SORT
-    // styles, use Append instead.
-    int Insert(const wxString& item, const wxBitmap& bitmap, unsigned int pos)
-        { return DoInsertWithImage(item, bitmap, pos); }
-
-    int Insert(const wxString& item, const wxBitmap& bitmap,
-               unsigned int pos, void *clientData);
-    int Insert(const wxString& item, const wxBitmap& bitmap,
-               unsigned int pos, wxClientData *clientData);
-
     // Sets the image for the given item.
     virtual void SetItemBitmap(unsigned int n, const wxBitmap& bitmap);
 
-    virtual void Clear();
-    virtual void Delete(unsigned int n);
+    virtual void DoClear();
+    virtual void DoDeleteOneItem(unsigned int n);
 
 protected:
 
@@ -126,12 +120,9 @@ protected:
     virtual wxCoord OnMeasureItem(size_t item) const;
     virtual wxCoord OnMeasureItemWidth(size_t item) const;
 
-    virtual int DoAppendWithImage(const wxString& item, const wxBitmap& bitmap);
-    virtual int DoInsertWithImage(const wxString& item, const wxBitmap& bitmap,
-                                  unsigned int pos);
-
-    virtual int DoAppend(const wxString& item);
-    virtual int DoInsert(const wxString& item, unsigned int pos);
+    virtual int DoInsertItems(const wxArrayStringsAdapter & items,
+                              unsigned int pos,
+                              void **clientData, wxClientDataType type);
 
     virtual bool SetFont(const wxFont& font);
 
diff --git a/include/wx/generic/ctrlsub.h b/include/wx/generic/ctrlsub.h
new file mode 100644
index 0000000000..425380d602
--- /dev/null
+++ b/include/wx/generic/ctrlsub.h
@@ -0,0 +1,123 @@
+///////////////////////////////////////////////////////////////////////////////
+// Name:        wx/generic/ctrlsub.h
+// Purpose:     common functionality of wxItemContainer-derived controls
+// Author:      Vadim Zeitlin
+// Created:     2007-07-25
+// RCS-ID:      $Id$
+// Copyright:   (c) 2007 Vadim Zeitlin <vadim@wxwindows.org>
+// Licence:     wxWindows licence
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef _WX_GENERIC_CTRLSUB_H_
+#define _WX_GENERIC_CTRLSUB_H_
+
+#include "wx/dynarray.h"
+
+// ----------------------------------------------------------------------------
+// wxControlWithItemsGeneric: generic implementation of item client data
+// ----------------------------------------------------------------------------
+
+class wxControlWithItemsGeneric : public wxControlWithItemsBase
+{
+public:
+    wxControlWithItemsGeneric() { }
+
+    virtual void DoInitItemClientData()
+    {
+        m_itemsClientData.resize(GetCount(), NULL);
+    }
+
+    virtual void DoSetItemClientData(unsigned int n, void *clientData)
+    {
+        m_itemsClientData[n] = clientData;
+    }
+
+    virtual void *DoGetItemClientData(unsigned int n) const
+    {
+        return m_itemsClientData[n];
+    }
+
+    virtual void DoClear() { m_itemsClientData.clear(); }
+    virtual void DoDeleteOneItem(unsigned int pos)
+    {
+        if ( HasClientData() )
+            m_itemsClientData.RemoveAt(pos);
+    }
+
+protected:
+    // preallocate memory for numItems new items: this should be called from
+    // the derived classes DoInsertItems() to speed up appending big numbers of
+    // items with client data; it is safe to call even if we don't use client
+    // data at all and does nothing in this case
+    void AllocClientData(unsigned int numItems)
+    {
+        if ( HasClientData() )
+            m_itemsClientData.reserve(m_itemsClientData.size() + numItems);
+    }
+
+    // this must be called by derived classes when a new item is added to the
+    // control to add storage for the corresponding client data pointer (before
+    // inserting many items, call AllocClientData())
+    void InsertNewItemClientData(unsigned int pos,
+                                 void **clientData,
+                                 unsigned int n,
+                                 wxClientDataType type)
+    {
+        if ( InitClientDataIfNeeded(type) )
+            m_itemsClientData.Insert(clientData[n], pos);
+    }
+
+    // the same as InsertNewItemClientData() but for numItems consecutive items
+    // (this can only be used if the control doesn't support sorting as
+    // otherwise the items positions wouldn't be consecutive any more)
+    void InsertNewItemsClientData(unsigned int pos,
+                                  unsigned int numItems,
+                                  void **clientData,
+                                  wxClientDataType type)
+    {
+        if ( InitClientDataIfNeeded(type) )
+        {
+            // it's more efficient to insert everything at once and then update
+            // for big number of items to avoid moving the array contents
+            // around (which would result in O(N^2) algorithm)
+            m_itemsClientData.Insert(NULL, pos, numItems);
+
+            for ( unsigned int n = 0; n < numItems; ++n, ++pos )
+                m_itemsClientData[pos] = clientData[n];
+        }
+    }
+
+
+    // vector containing the client data pointers: it is either empty (if
+    // client data is not used) or has the same number of elements as the
+    // control
+    wxArrayPtrVoid m_itemsClientData;
+
+private:
+    // initialize client data if needed, return false if we don't have any
+    // client data and true otherwise
+    bool InitClientDataIfNeeded(wxClientDataType type)
+    {
+        if ( !HasClientData() )
+        {
+            if ( type == wxClientData_None )
+            {
+                // we didn't have the client data before and are not asked to
+                // store it now neither
+                return false;
+            }
+
+            // this is the first time client data is used with this control
+            DoInitItemClientData();
+            m_clientDataItemsType = type;
+        }
+        //else: we already have client data
+
+        return true;
+    }
+
+    DECLARE_NO_COPY_CLASS(wxControlWithItemsGeneric)
+};
+
+#endif // _WX_GENERIC_CTRLSUB_H_
+
diff --git a/include/wx/gtk/choice.h b/include/wx/gtk/choice.h
index 96830c5847..1606120b09 100644
--- a/include/wx/gtk/choice.h
+++ b/include/wx/gtk/choice.h
@@ -62,8 +62,8 @@ public:
             const wxString& name = wxChoiceNameStr );
 
     // implement base class pure virtuals
-    void Delete(unsigned int n);
-    void Clear();
+    void DoDeleteOneItem(unsigned int n);
+    void DoClear();
 
     int GetSelection() const;
     void SetSelection(int n);
@@ -77,22 +77,21 @@ public:
     GetClassDefaultAttributes(wxWindowVariant variant = wxWINDOW_VARIANT_NORMAL);
 
 protected:
-    wxList m_clientList;    // contains the client data for the items
+    wxArrayPtrVoid m_clientData; // contains the client data for the items
 
     virtual wxSize DoGetBestSize() const;
     virtual void DoApplyWidgetStyle(GtkRcStyle *style);
     virtual GdkWindow *GTKGetWindow(wxArrayGdkWindows& windows) const;
 
-    virtual int DoAppend(const wxString& item);
-    virtual int DoInsert(const wxString& item, unsigned int pos);
+    virtual int DoInsertItems(const wxArrayStringsAdapter& items,
+                              unsigned int pos,
+                              void **clientData, wxClientDataType type);
 
     virtual void DoSetItemClientData(unsigned int n, void* clientData);
     virtual void* DoGetItemClientData(unsigned int n) const;
-    virtual void DoSetItemClientObject(unsigned int n, wxClientData* clientData);
-    virtual wxClientData* DoGetItemClientObject(unsigned int n) const;
 
 private:
-    // common part of Create() and DoAppend()
+    // DoInsertItems() helper
     int GtkAddHelper(GtkWidget *menu, unsigned int pos, const wxString& item);
 
     // this array is only used for controls with wxCB_SORT style, so only
diff --git a/include/wx/gtk/combobox.h b/include/wx/gtk/combobox.h
index f8540a2bd8..f77165b975 100644
--- a/include/wx/gtk/combobox.h
+++ b/include/wx/gtk/combobox.h
@@ -18,7 +18,7 @@
 class WXDLLIMPEXP_CORE wxComboBox : public wxControl, public wxComboBoxBase
 {
 public:
-    inline wxComboBox() {}
+    inline wxComboBox() { m_strings = NULL; }
     inline wxComboBox(wxWindow *parent, wxWindowID id,
            const wxString& value = wxEmptyString,
            const wxPoint& pos = wxDefaultPosition,
@@ -71,8 +71,8 @@ public:
     wxString GetStringSelection() const; // not a virtual in parent class
 
     // From wxItemContainer:
-    virtual void Clear();
-    virtual void Delete(unsigned int n);
+    virtual void DoClear();
+    virtual void DoDeleteOneItem(unsigned int n);
 
     // From wxBomboBoxBase:
     virtual wxString GetValue() const;
@@ -125,10 +125,9 @@ public:
     void OnUpdateDelete(wxUpdateUIEvent& event);
     void OnUpdateSelectAll(wxUpdateUIEvent& event);
 
-    bool     m_ignoreNextUpdate:1;
-    wxList   m_clientDataList;
-    wxList   m_clientObjectList;
-    int      m_prevSelection;
+    bool           m_ignoreNextUpdate:1;
+    wxArrayPtrVoid m_clientData;
+    int            m_prevSelection;
 
     void DisableEvents();
     void EnableEvents();
@@ -145,13 +144,12 @@ protected:
     virtual GdkWindow *GTKGetWindow(wxArrayGdkWindows& windows) const;
 
     // From wxItemContainer:
-    virtual int DoAppend(const wxString& item);
-    virtual int DoInsert(const wxString& item, unsigned int pos);
-
+    virtual int DoInsertItems(const wxArrayStringsAdapter& items,
+                              unsigned int pos,
+                              void **clientData, wxClientDataType type);
     virtual void DoSetItemClientData(unsigned int n, void* clientData);
     virtual void* DoGetItemClientData(unsigned int n) const;
-    virtual void DoSetItemClientObject(unsigned int n, wxClientData* clientData);
-    virtual wxClientData* DoGetItemClientObject(unsigned int n) const;
+    virtual bool IsSorted() const { return HasFlag(wxCB_SORT); }
 
     // From wxControl:
     virtual wxSize DoGetBestSize() const;
@@ -161,6 +159,10 @@ protected:
     virtual bool UseGTKStyleBase() const { return true; }
 
 private:
+    // this array is only used for controls with wxCB_SORT style, so only
+    // allocate it if it's needed (hence using pointer)
+    wxSortedArrayString *m_strings;
+
     DECLARE_DYNAMIC_CLASS_NO_COPY(wxComboBox)
     DECLARE_EVENT_TABLE()
 };
diff --git a/include/wx/gtk/listbox.h b/include/wx/gtk/listbox.h
index c855e3d688..aa38ecd895 100644
--- a/include/wx/gtk/listbox.h
+++ b/include/wx/gtk/listbox.h
@@ -65,8 +65,8 @@ public:
                 const wxString& name = wxListBoxNameStr);
 
     // implement base class pure virtuals
-    virtual void Clear();
-    virtual void Delete(unsigned int n);
+    virtual void DoClear();
+    virtual void DoDeleteOneItem(unsigned int n);
 
     virtual unsigned int GetCount() const;
     virtual wxString GetString(unsigned int n) const;
@@ -98,8 +98,6 @@ public:
     bool       m_blockEvent;
 
     struct _GtkTreeEntry* GtkGetEntry(unsigned pos) const;
-    void GtkInsertItems(const wxArrayString& items,
-                        void** clientData, unsigned int pos);
     void GtkDeselectAll();
     void GtkSetSelection(int n, const bool select, const bool blockEvent);
 
@@ -109,14 +107,14 @@ protected:
     virtual GdkWindow *GTKGetWindow(wxArrayGdkWindows& windows) const;
 
     virtual void DoSetSelection(int n, bool select);
-    virtual int DoAppend(const wxString& item);
-    virtual void DoInsertItems(const wxArrayString& items, unsigned int pos);
-    virtual void DoSetItems(const wxArrayString& items, void **clientData);
+
+    virtual int DoInsertItems(const wxArrayStringsAdapter& items,
+                              unsigned int pos,
+                              void **clientData, wxClientDataType type);
+
     virtual void DoSetFirstItem(int n);
     virtual void DoSetItemClientData(unsigned int n, void* clientData);
     virtual void* DoGetItemClientData(unsigned int n) const;
-    virtual void DoSetItemClientObject(unsigned int n, wxClientData* clientData);
-    virtual wxClientData* DoGetItemClientObject(unsigned int n) const;
     virtual int DoListHitTest(const wxPoint& point) const;
 
     // get the iterator for the given index, returns false if invalid
diff --git a/include/wx/gtk1/choice.h b/include/wx/gtk1/choice.h
index 5d8579b731..c78e8308fe 100644
--- a/include/wx/gtk1/choice.h
+++ b/include/wx/gtk1/choice.h
@@ -62,8 +62,8 @@ public:
             const wxString& name = wxChoiceNameStr );
 
     // implement base class pure virtuals
-    void Delete(unsigned int n);
-    void Clear();
+    void DoDeleteOneItem(unsigned int n);
+    void DoClear();
 
     int GetSelection() const;
     virtual void SetSelection(int n);
@@ -80,20 +80,19 @@ protected:
     wxList m_clientList;    // contains the client data for the items
 
     void DoApplyWidgetStyle(GtkRcStyle *style);
-    virtual int DoAppend(const wxString& item);
-    virtual int DoInsert(const wxString& item, unsigned int pos);
+    virtual int DoInsertItems(const wxArrayStringsAdapter& items,
+                              unsigned int pos,
+                              void **clientData, wxClientDataType type);
 
     virtual void DoSetItemClientData(unsigned int n, void* clientData);
     virtual void* DoGetItemClientData(unsigned int n) const;
-    virtual void DoSetItemClientObject(unsigned int n, wxClientData* clientData);
-    virtual wxClientData* DoGetItemClientObject(unsigned int n) const;
 
     virtual wxSize DoGetBestSize() const;
 
     virtual bool IsOwnGtkWindow( GdkWindow *window );
 
 private:
-    // common part of Create() and DoAppend()
+    // DoInsertItems() helper
     int GtkAddHelper(GtkWidget *menu, unsigned int pos, const wxString& item);
 
     // this array is only used for controls with wxCB_SORT style, so only
diff --git a/include/wx/gtk1/combobox.h b/include/wx/gtk1/combobox.h
index fd046fc073..e46402b839 100644
--- a/include/wx/gtk1/combobox.h
+++ b/include/wx/gtk1/combobox.h
@@ -80,8 +80,8 @@ public:
            const wxValidator& validator = wxDefaultValidator,
            const wxString& name = wxComboBoxNameStr);
 
-    void Clear();
-    void Delete(unsigned int n);
+    void DoClear();
+    void DoDeleteOneItem(unsigned int n);
 
     virtual int FindString(const wxString& s, bool bCase = false) const;
     int GetSelection() const;
@@ -159,13 +159,12 @@ public:
     GetClassDefaultAttributes(wxWindowVariant variant = wxWINDOW_VARIANT_NORMAL);
 
 protected:
-    virtual int DoAppend(const wxString& item);
-    virtual int DoInsert(const wxString& item, unsigned int pos);
+    virtual int DoInsertItems(const wxArrayStringsAdapter& items,
+                              unsigned int pos,
+                              void **clientData, wxClientDataType type);
 
     virtual void DoSetItemClientData(unsigned int n, void* clientData);
     virtual void* DoGetItemClientData(unsigned int n) const;
-    virtual void DoSetItemClientObject(unsigned int n, wxClientData* clientData);
-    virtual wxClientData* DoGetItemClientObject(unsigned int n) const;
 
     virtual wxSize DoGetBestSize() const;
 
diff --git a/include/wx/gtk1/listbox.h b/include/wx/gtk1/listbox.h
index 42cd90f1e9..be62c96846 100644
--- a/include/wx/gtk1/listbox.h
+++ b/include/wx/gtk1/listbox.h
@@ -67,8 +67,8 @@ public:
                 const wxString& name = wxListBoxNameStr);
 
     // implement base class pure virtuals
-    virtual void Clear();
-    virtual void Delete(unsigned int n);
+    virtual void DoClear();
+    virtual void DoDeleteOneItem(unsigned int n);
 
     virtual unsigned int GetCount() const;
     virtual wxString GetString(unsigned int n) const;
@@ -80,16 +80,14 @@ public:
     virtual int GetSelection() const;
     virtual int GetSelections(wxArrayInt& aSelections) const;
 
-    virtual int DoAppend(const wxString& item);
-    virtual void DoInsertItems(const wxArrayString& items, unsigned int pos);
-    virtual void DoSetItems(const wxArrayString& items, void **clientData);
+    virtual int DoInsertItems(const wxArrayStringsAdapter& items,
+                              unsigned int pos,
+                              void **clientData, wxClientDataType type);
 
     virtual void DoSetFirstItem(int n);
 
     virtual void DoSetItemClientData(unsigned int n, void* clientData);
     virtual void* DoGetItemClientData(unsigned int n) const;
-    virtual void DoSetItemClientObject(unsigned int n, wxClientData* clientData);
-    virtual wxClientData* DoGetItemClientObject(unsigned int n) const;
 
     static wxVisualAttributes
     GetClassDefaultAttributes(wxWindowVariant variant = wxWINDOW_VARIANT_NORMAL);
diff --git a/include/wx/htmllbox.h b/include/wx/htmllbox.h
index 0cc43ef289..89c06d29dc 100644
--- a/include/wx/htmllbox.h
+++ b/include/wx/htmllbox.h
@@ -268,35 +268,19 @@ public:
 
     virtual void SetString(unsigned int n, const wxString& s);
 
-    virtual void Clear();
-    virtual void Delete(unsigned int n);
-
-    // override default unoptimized wxItemContainer::Append() function
-    void Append(const wxArrayString& strings);
-
-    // since we override one Append() overload, we need to overload all others too
-    int Append(const wxString& item)
-        { return wxItemContainer::Append(item); }
-    int Append(const wxString& item, void *clientData)
-        { return wxItemContainer::Append(item, clientData); }
-    int Append(const wxString& item, wxClientData *clientData)
-        { return wxItemContainer::Append(item, clientData); }
-
+    virtual void DoClear();
+    virtual void DoDeleteOneItem(unsigned int n);
 
 protected:
-
-    virtual int DoAppend(const wxString& item);
-    virtual int DoInsert(const wxString& item, unsigned int pos);
+    virtual int DoInsertItems(const wxArrayStringsAdapter & items,
+                              unsigned int pos,
+                              void **clientData, wxClientDataType type);
 
     virtual void DoSetItemClientData(unsigned int n, void *clientData)
         { m_HTMLclientData[n] = clientData; }
 
     virtual void *DoGetItemClientData(unsigned int n) const
         { return m_HTMLclientData[n]; }
-    virtual void DoSetItemClientObject(unsigned int n, wxClientData *clientData)
-        { m_HTMLclientData[n] = (void *)clientData; }
-    virtual wxClientData *DoGetItemClientObject(unsigned int n) const
-        { return (wxClientData *)m_HTMLclientData[n]; }
 
     // calls wxHtmlListBox::SetItemCount() and RefreshAll()
     void UpdateCount();
diff --git a/include/wx/listbox.h b/include/wx/listbox.h
index 89a61df202..01604e47f6 100644
--- a/include/wx/listbox.h
+++ b/include/wx/listbox.h
@@ -42,13 +42,10 @@ public:
     wxListBoxBase() { }
     virtual ~wxListBoxBase();
 
-    void InsertItems(unsigned int nItems, const wxString *items, unsigned int pos);
+    void InsertItems(unsigned int nItems, const wxString *items, unsigned int pos)
+        { Insert(nItems, items, pos); }
     void InsertItems(const wxArrayString& items, unsigned int pos)
-        { DoInsertItems(items, pos); }
-
-    void Set(int n, const wxString* items, void **clientData = NULL);
-    void Set(const wxArrayString& items, void **clientData = NULL)
-        { DoSetItems(items, clientData); }
+        { Insert(items, pos); }
 
     // multiple selection logic
     virtual bool IsSelected(int n) const = 0;
@@ -87,8 +84,8 @@ public:
                (m_windowStyle & wxLB_EXTENDED);
     }
 
-    // return true if this listbox is sorted
-    bool IsSorted() const { return (m_windowStyle & wxLB_SORT) != 0; }
+    // override wxItemContainer::IsSorted
+    virtual bool IsSorted() const { return HasFlag( wxLB_SORT ); }
 
     // emulate selecting or deselecting the item event.GetInt() (depending on
     // event.GetExtraLong())
@@ -104,15 +101,6 @@ public:
 #endif // WXWIN_COMPATIBILITY_2_6
 
 protected:
-    // NB: due to wxGTK implementation details, DoInsert() is implemented
-    //     using DoInsertItems() and not the other way round
-    virtual int DoInsert(const wxString& item, unsigned int pos)
-        { InsertItems(1, &item, pos); return pos; }
-
-    // to be implemented in derived classes
-    virtual void DoInsertItems(const wxArrayString& items, unsigned int pos) = 0;
-    virtual void DoSetItems(const wxArrayString& items, void **clientData) = 0;
-
     virtual void DoSetFirstItem(int n) = 0;
 
     virtual void DoSetSelection(int n, bool select) = 0;
@@ -121,7 +109,7 @@ protected:
     virtual int DoListHitTest(const wxPoint& WXUNUSED(point)) const
         { return wxNOT_FOUND; }
 
-
+private:
     DECLARE_NO_COPY_CLASS(wxListBoxBase)
 };
 
diff --git a/include/wx/mac/carbon/choice.h b/include/wx/mac/carbon/choice.h
index 57f765da1b..838da21dc0 100644
--- a/include/wx/mac/carbon/choice.h
+++ b/include/wx/mac/carbon/choice.h
@@ -69,8 +69,8 @@ public:
                 const wxValidator& validator = wxDefaultValidator,
                 const wxString& name = wxChoiceNameStr);
 
-    virtual void Delete(unsigned int n);
-    virtual void Clear();
+    virtual void DoDeleteOneItem(unsigned int n);
+    virtual void DoClear();
 
     virtual unsigned int GetCount() const ;
     virtual int GetSelection() const ;
@@ -83,17 +83,12 @@ public:
 
 protected:
     virtual wxSize DoGetBestSize() const ;
-    virtual int DoAppend(const wxString& item);
-    virtual int DoInsert(const wxString& item, unsigned int pos);
+    virtual int DoInsertItems(const wxArrayStringsAdapter& items,
+                              unsigned int pos,
+                              void **clientData, wxClientDataType type);
 
     virtual void DoSetItemClientData(unsigned int n, void* clientData);
     virtual void* DoGetItemClientData(unsigned int n) const;
-    virtual void DoSetItemClientObject(unsigned int n, wxClientData* clientData);
-    virtual wxClientData* DoGetItemClientObject(unsigned int n) const;
-
-    // free all memory we have (used by Clear() and dtor)
-    // prevent collision with some BSD definitions of macro Free()
-    void FreeData();
 
     wxArrayString m_strings;
     wxChoiceDataArray m_datas ;
diff --git a/include/wx/mac/carbon/combobox.h b/include/wx/mac/carbon/combobox.h
index 446b4b14a5..737f7b4423 100644
--- a/include/wx/mac/carbon/combobox.h
+++ b/include/wx/mac/carbon/combobox.h
@@ -85,8 +85,8 @@ class WXDLLEXPORT wxComboBox : public wxControl, public wxComboBoxBase
            const wxString& name = wxComboBoxNameStr);
 
     // List functions
-    virtual void Delete(unsigned int n);
-    virtual void Clear();
+    virtual void DoDeleteOneItem(unsigned int n);
+    virtual void DoClear();
 
     virtual int GetSelection() const;
     virtual void SetSelection(int n);
@@ -135,19 +135,16 @@ protected:
     // common part of all ctors
     void Init();
 
-    void FreeData();
-
     // override the base class virtuals involved in geometry calculations
     virtual wxSize DoGetBestSize() const;
     virtual void DoMoveWindow(int x, int y, int width, int height);
 
-    virtual int DoAppend(const wxString& item);
-    virtual int DoInsert(const wxString& item, unsigned int pos);
+    virtual int DoInsertItems(const wxArrayStringsAdapter& items,
+                              unsigned int pos,
+                              void **clientData, wxClientDataType type);
 
     virtual void DoSetItemClientData(unsigned int n, void* clientData);
     virtual void * DoGetItemClientData(unsigned int n) const;
-    virtual void DoSetItemClientObject(unsigned int n, wxClientData* clientData);
-    virtual wxClientData * DoGetItemClientObject(unsigned int n) const;
 
     // the subcontrols
     wxComboBoxText*     m_text;
diff --git a/include/wx/mac/carbon/listbox.h b/include/wx/mac/carbon/listbox.h
index 69e45871ef..91214b05b6 100644
--- a/include/wx/mac/carbon/listbox.h
+++ b/include/wx/mac/carbon/listbox.h
@@ -89,8 +89,8 @@ public:
 
     // implement base class pure virtuals
     virtual void Refresh(bool eraseBack = true, const wxRect *rect = NULL);
-    virtual void Clear();
-    virtual void Delete(unsigned int n);
+    virtual void DoClear();
+    virtual void DoDeleteOneItem(unsigned int n);
 
     virtual unsigned int GetCount() const;
     virtual wxString GetString(unsigned int n) const;
@@ -111,16 +111,15 @@ public:
 
 protected:
     // from wxItemContainer
-    virtual int DoAppend(const wxString& item);
+    virtual int DoInsertItems(const wxArrayStringsAdapter& items,
+                              unsigned int pos,
+                              void **clientData, wxClientDataType type);
+
     virtual void DoSetItemClientData(unsigned int n, void* clientData);
     virtual void* DoGetItemClientData(unsigned int n) const;
-    virtual void DoSetItemClientObject(unsigned int n, wxClientData* clientData);
-    virtual wxClientData* DoGetItemClientObject(unsigned int n) const;
 
     // from wxListBoxBase
     virtual void DoSetSelection(int n, bool select);
-    virtual void DoInsertItems(const wxArrayString& items, unsigned int pos);
-    virtual void DoSetItems(const wxArrayString& items, void **clientData);
     virtual void DoSetFirstItem(int n);
     virtual int DoListHitTest(const wxPoint& point) const;
 
diff --git a/include/wx/mac/carbon/private.h b/include/wx/mac/carbon/private.h
index ecc66ddd19..6fc913dd2c 100644
--- a/include/wx/mac/carbon/private.h
+++ b/include/wx/mac/carbon/private.h
@@ -824,8 +824,7 @@ class wxMacListControl
 {
 public:
     virtual void            MacDelete( unsigned int n ) = 0;
-    virtual void            MacInsert( unsigned int n, const wxString& item, int column = -1 ) = 0;
-    virtual void            MacInsert( unsigned int n, const wxArrayString& items, int column = -1 ) = 0;
+    virtual void            MacInsert( unsigned int n, const wxArrayStringsAdapter& items, int column = -1 ) = 0;
     // returns index of newly created line
     virtual int             MacAppend( const wxString& item ) = 0;
     virtual void            MacSetString( unsigned int n, const wxString& item ) = 0;
@@ -975,8 +974,7 @@ public :
     // add and remove
 
     virtual void            MacDelete( unsigned int n );
-    virtual void            MacInsert( unsigned int n, const wxString& item, int column = -1 );
-    virtual void            MacInsert( unsigned int n, const wxArrayString& items, int column = -1 );
+    virtual void            MacInsert( unsigned int n, const wxArrayStringsAdapter& items, int column = -1 );
     virtual int             MacAppend( const wxString& item );
     virtual void            MacClear();
 
diff --git a/include/wx/motif/checklst.h b/include/wx/motif/checklst.h
index 78bb982180..7ec30059eb 100644
--- a/include/wx/motif/checklst.h
+++ b/include/wx/motif/checklst.h
@@ -60,13 +60,13 @@ public:
     void Check(unsigned int uiIndex, bool bCheck = true);
 
     // override base class functions
-    virtual int DoAppend(const wxString& item);
+    virtual int DoInsertItems(const wxArrayStringsAdapter& items,
+                              unsigned int pos,
+                              void **clientData, wxClientDataType type);
     virtual int FindString(const wxString& s, bool bCase = false) const;
     virtual void SetString(unsigned int n, const wxString& s);
     virtual wxString GetString(unsigned int n) const;
 
-    virtual void DoInsertItems(const wxArrayString& items, unsigned int pos);
-    virtual void DoSetItems(const wxArrayString& items, void **clientData);
 private:
     void DoToggleItem( int item, int x );
 private:
diff --git a/include/wx/motif/choice.h b/include/wx/motif/choice.h
index bc8f39cf7d..7532c50ba2 100644
--- a/include/wx/motif/choice.h
+++ b/include/wx/motif/choice.h
@@ -72,15 +72,9 @@ public:
 
     // implementation of wxControlWithItems
     virtual unsigned int GetCount() const;
-    virtual int DoAppend(const wxString& item);
-    virtual int DoInsert(const wxString& item, unsigned int pos);
-    virtual void DoSetItemClientData(unsigned int n, void* clientData);
-    virtual void* DoGetItemClientData(unsigned int n) const;
-    virtual void DoSetItemClientObject(unsigned int n, wxClientData* clientData);
-    virtual wxClientData* DoGetItemClientObject(unsigned int n) const;
     virtual int GetSelection() const;
-    virtual void Delete(unsigned int n);
-    virtual void Clear();
+    virtual void DoDeleteOneItem(unsigned int n);
+    virtual void DoClear();
     virtual void SetString(unsigned int n, const wxString& s);
     virtual wxString GetString(unsigned int n) const;
 
@@ -118,12 +112,15 @@ protected:
     wxWidgetArray m_widgetArray;
     WXWidget      m_formWidget;
     wxStringList  m_stringList;
-    wxClientDataDictionary m_clientDataDict;
 
     virtual void DoSetSize(int x, int y,
         int width, int height,
         int sizeFlags = wxSIZE_AUTO);
+
+    // implementation of wxControlWithItems
+    virtual int DoInsertItems(const wxArrayStringsAdapter& items,
+                              unsigned int pos,
+                              void **clientData, wxClientDataType type);
 };
 
-#endif
-// _WX_CHOICE_H_
+#endif // _WX_CHOICE_H_
diff --git a/include/wx/motif/combobox.h b/include/wx/motif/combobox.h
index e47a4e8b64..d63326ba22 100644
--- a/include/wx/motif/combobox.h
+++ b/include/wx/motif/combobox.h
@@ -70,10 +70,11 @@ public:
         const wxString& name = wxComboBoxNameStr);
 
     // implementation of wxControlWithItems
-    virtual int DoAppend(const wxString& item);
-    virtual int DoInsert(const wxString& item, unsigned int pos);
-    virtual void Delete(unsigned int n);
-    virtual void Clear();
+    virtual int DoInsertItems(const wxArrayStringsAdapter& items,
+                              unsigned int pos,
+                              void **clientData, wxClientDataType type);
+    virtual void DoDeleteOneItem(unsigned int n);
+    virtual void DoClear();
     virtual int GetSelection() const ;
     virtual void SetSelection(int n);
     virtual int FindString(const wxString& s, bool bCase = false) const;
diff --git a/include/wx/motif/ctrlsub.h b/include/wx/motif/ctrlsub.h
new file mode 100644
index 0000000000..dfa0915e6b
--- /dev/null
+++ b/include/wx/motif/ctrlsub.h
@@ -0,0 +1,40 @@
+///////////////////////////////////////////////////////////////////////////////
+// Name:        wx/motif/ctrlsub.h
+// Purpose:     common functionality of wxItemContainer-derived controls
+// Author:      Vadim Zeitlin
+// Created:     2007-07-25
+// RCS-ID:      $Id$
+// Copyright:   (c) 2007 Vadim Zeitlin <vadim@wxwindows.org>
+// Licence:     wxWindows licence
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef _WX_MOTIF_CTRLSUB_H_
+#define _WX_MOTIF_CTRLSUB_H_
+
+#include "wx/dynarray.h"
+#include "wx/generic/ctrlsub.h"
+
+// ----------------------------------------------------------------------------
+// wxControlWithItems
+// ----------------------------------------------------------------------------
+
+class wxControlWithItems : public wxControlWithItemsGeneric
+{
+public:
+    wxControlWithItems() { }
+
+protected:
+    // Motif functions inserting items in the control interpret positions
+    // differently from wx: they're 1-based and 0 means to append
+    unsigned int GetMotifPosition(unsigned int pos) const
+    {
+        return pos == GetCount() ? 0 : pos + 1;
+    }
+
+private:
+    DECLARE_ABSTRACT_CLASS(wxControlWithItems)
+    DECLARE_NO_COPY_CLASS(wxControlWithItems)
+};
+
+#endif // _WX_MOTIF_CTRLSUB_H_
+
diff --git a/include/wx/motif/listbox.h b/include/wx/motif/listbox.h
index 29faf7d6dc..c743a98add 100644
--- a/include/wx/motif/listbox.h
+++ b/include/wx/motif/listbox.h
@@ -63,26 +63,20 @@ public:
         const wxValidator& validator = wxDefaultValidator,
         const wxString& name = wxListBoxNameStr);
 
-    virtual ~wxListBox();
-
     // implementation of wxControlWithItems
     virtual unsigned int GetCount() const;
-    virtual int DoAppend(const wxString& item);
-    virtual void DoSetItemClientData(unsigned int n, void* clientData);
-    virtual void* DoGetItemClientData(unsigned int n) const;
-    virtual void DoSetItemClientObject(unsigned int n, wxClientData* clientData);
-    virtual wxClientData* DoGetItemClientObject(unsigned int n) const;
+    virtual int DoInsertItems(const wxArrayStringsAdapter& items,
+                              unsigned int pos,
+                              void **clientData, wxClientDataType type);
     virtual int GetSelection() const;
-    virtual void Delete(unsigned int n);
+    virtual void DoDeleteOneItem(unsigned int n);
     virtual int FindString(const wxString& s, bool bCase = false) const;
-    virtual void Clear();
+    virtual void DoClear();
     virtual void SetString(unsigned int n, const wxString& s);
     virtual wxString GetString(unsigned int n) const;
 
     // implementation of wxListBoxbase
     virtual void DoSetSelection(int n, bool select);
-    virtual void DoInsertItems(const wxArrayString& items, unsigned int pos);
-    virtual void DoSetItems(const wxArrayString& items, void **clientData);
     virtual void DoSetFirstItem(int n);
     virtual int GetSelections(wxArrayInt& aSelections) const;
     virtual bool IsSelected(int n) const;
@@ -96,15 +90,13 @@ public:
     WXWidget GetTopWidget() const;
 
 #if wxUSE_CHECKLISTBOX
-    virtual void DoToggleItem(int WXUNUSED(item), int WXUNUSED(x)) {};
+    virtual void DoToggleItem(int WXUNUSED(item), int WXUNUSED(x)) {}
 #endif
 protected:
     virtual wxSize DoGetBestSize() const;
 
     unsigned int m_noItems;
 
-    // List mapping positions->client data
-    wxClientDataDictionary m_clientDataDict;
 private:
     void SetSelectionPolicy();
 };
diff --git a/include/wx/msw/choice.h b/include/wx/msw/choice.h
index a2ca016367..3d004d2ab6 100644
--- a/include/wx/msw/choice.h
+++ b/include/wx/msw/choice.h
@@ -66,8 +66,8 @@ public:
                 const wxValidator& validator = wxDefaultValidator,
                 const wxString& name = wxChoiceNameStr);
 
-    virtual void Delete(unsigned int n);
-    virtual void Clear();
+    virtual void DoDeleteOneItem(unsigned int n);
+    virtual void DoClear();
 
     virtual unsigned int GetCount() const;
     virtual int GetSelection() const;
@@ -89,13 +89,13 @@ protected:
     // common part of all ctors
     void Init() { m_lastAcceptedSelection = wxID_NONE; }
 
-    virtual int DoAppend(const wxString& item);
-    virtual int DoInsert(const wxString& item, unsigned int pos);
+    virtual int DoInsertItems(const wxArrayStringsAdapter& items,
+                              unsigned int pos,
+                              void **clientData, wxClientDataType type);
+
     virtual void DoMoveWindow(int x, int y, int width, int height);
     virtual void DoSetItemClientData(unsigned int n, void* clientData);
     virtual void* DoGetItemClientData(unsigned int n) const;
-    virtual void DoSetItemClientObject(unsigned int n, wxClientData* clientData);
-    virtual wxClientData* DoGetItemClientObject(unsigned int n) const;
 
     // MSW implementation
     virtual wxSize DoGetBestSize() const;
diff --git a/include/wx/msw/ctrlsub.h b/include/wx/msw/ctrlsub.h
new file mode 100644
index 0000000000..d197bb1b01
--- /dev/null
+++ b/include/wx/msw/ctrlsub.h
@@ -0,0 +1,43 @@
+///////////////////////////////////////////////////////////////////////////////
+// Name:        wx/msw/ctrlsub.h
+// Purpose:     common functionality of wxItemContainer-derived controls
+// Author:      Vadim Zeitlin
+// Created:     2007-07-25
+// RCS-ID:      $Id$
+// Copyright:   (c) 2007 Vadim Zeitlin <vadim@wxwindows.org>
+// Licence:     wxWindows licence
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef _WX_MSW_CTRLSUB_H_
+#define _WX_MSW_CTRLSUB_H_
+
+// ----------------------------------------------------------------------------
+// wxControlWithItems
+// ----------------------------------------------------------------------------
+
+class WXDLLEXPORT wxControlWithItems : public wxControlWithItemsBase
+{
+public:
+    wxControlWithItems() { }
+
+protected:
+    // preallocate memory for inserting the given new items into the control
+    // using the wm message (normally either LB_INITSTORAGE or CB_INITSTORAGE)
+    void MSWAllocStorage(const wxArrayStringsAdapter& items, unsigned wm);
+
+    // insert or append a string to the controls using the given message
+    // (one of {CB,LB}_{ADD,INSERT}STRING, pos must be 0 when appending)
+    int MSWInsertOrAppendItem(unsigned pos, const wxString& item, unsigned wm);
+
+    // normally the control containing the items is this window itself but if
+    // the derived control is composed of several windows, this method can be
+    // overridden to return the real list/combobox control
+    virtual WXHWND MSWGetItemsHWND() const { return GetHWND(); }
+
+private:
+    DECLARE_ABSTRACT_CLASS(wxControlWithItems)
+    DECLARE_NO_COPY_CLASS(wxControlWithItems)
+};
+
+#endif // _WX_MSW_CTRLSUB_H_
+
diff --git a/include/wx/msw/listbox.h b/include/wx/msw/listbox.h
index d4eb27141c..13daa8a232 100644
--- a/include/wx/msw/listbox.h
+++ b/include/wx/msw/listbox.h
@@ -78,8 +78,8 @@ public:
     virtual ~wxListBox();
 
     // implement base class pure virtuals
-    virtual void Clear();
-    virtual void Delete(unsigned int n);
+    virtual void DoClear();
+    virtual void DoDeleteOneItem(unsigned int n);
 
     virtual unsigned int GetCount() const;
     virtual wxString GetString(unsigned int n) const;
@@ -135,14 +135,14 @@ public:
 
 protected:
     virtual void DoSetSelection(int n, bool select);
-    virtual int DoAppend(const wxString& item);
-    virtual void DoInsertItems(const wxArrayString& items, unsigned int pos);
-    virtual void DoSetItems(const wxArrayString& items, void **clientData);
+
+    virtual int DoInsertItems(const wxArrayStringsAdapter& items,
+                              unsigned int pos,
+                              void **clientData, wxClientDataType type);
+
     virtual void DoSetFirstItem(int n);
     virtual void DoSetItemClientData(unsigned int n, void* clientData);
     virtual void* DoGetItemClientData(unsigned int n) const;
-    virtual void DoSetItemClientObject(unsigned int n, wxClientData* clientData);
-    virtual wxClientData* DoGetItemClientObject(unsigned int n) const;
     virtual int DoListHitTest(const wxPoint& point) const;
 
     // free memory (common part of Clear() and dtor)
diff --git a/include/wx/msw/wince/checklst.h b/include/wx/msw/wince/checklst.h
index 01f0c23319..42cc6475db 100644
--- a/include/wx/msw/wince/checklst.h
+++ b/include/wx/msw/wince/checklst.h
@@ -50,7 +50,7 @@ public:
                 const wxString& name = wxListBoxNameStr);
 
     // override base class virtuals
-    virtual void Delete(unsigned int n);
+    virtual void DoDeleteOneItem(unsigned int n);
 
     // items may be checked
     virtual bool IsChecked(unsigned int uiIndex) const;
@@ -72,20 +72,18 @@ protected:
     void OnSize(wxSizeEvent& event);
 
     // protected interface derived from wxListBox and lower classes
-    virtual int DoAppend(const wxString& item);
+    virtual int DoInsertItems(const wxArrayStringsAdapter& items,
+                              unsigned int pos,
+                              void **clientData, wxClientDataType type);
+
     virtual void* DoGetItemClientData(unsigned int n) const;
-    virtual wxClientData* DoGetItemClientObject(unsigned int n) const;
-    virtual void DoInsertItems(const wxArrayString& items, unsigned int pos);
-    virtual void DoSetFirstItem(int n);
     virtual void DoSetItemClientData(unsigned int n, void* clientData);
-    virtual void DoSetItemClientObject(unsigned int n, wxClientData* clientData);
-    virtual void DoSetItems(const wxArrayString& items, void **clientData);
+    virtual void DoSetFirstItem(int n);
     virtual void DoSetSelection(int n, bool select);
     // convert our styles to Windows
     virtual WXDWORD MSWGetStyle(long style, WXDWORD *exstyle) const;
 
 private:
-
     wxArrayPtrVoid m_itemsClientData;
 
     DECLARE_EVENT_TABLE()
diff --git a/include/wx/msw/wince/choicece.h b/include/wx/msw/wince/choicece.h
index 3b827e73a4..5f4e3302d5 100644
--- a/include/wx/msw/wince/choicece.h
+++ b/include/wx/msw/wince/choicece.h
@@ -78,10 +78,8 @@ public:
                 const wxString& name = wxChoiceNameStr);
 
     // implement base class pure virtuals
-    virtual int DoAppend(const wxString& item);
-    virtual int DoInsert(const wxString& item, unsigned int pos);
-    virtual void Delete(unsigned int n);
-    virtual void Clear() ;
+    virtual void DoDeleteOneItem(unsigned int n);
+    virtual void DoClear();
 
     virtual unsigned int GetCount() const;
     virtual int GetSelection() const;
@@ -100,10 +98,14 @@ public:
     virtual bool MSWCommand(WXUINT param, WXWORD id);
 
 protected:
+    virtual int DoInsertItems(const wxArrayStringsAdapter& items,
+                              unsigned int pos,
+                              void **clientData, wxClientDataType type);
+
     virtual void DoSetItemClientData(unsigned int n, void* clientData);
     virtual void* DoGetItemClientData(unsigned int n) const;
-    virtual void DoSetItemClientObject(unsigned int n, wxClientData* clientData);
-    virtual wxClientData* DoGetItemClientObject(unsigned int n) const;
+
+    virtual WXHWND MSWGetItemsHWND() const { return m_hwndBuddy; }
 
     // MSW implementation
     virtual void DoGetPosition(int *x, int *y) const;
@@ -122,9 +124,6 @@ protected:
                        const wxValidator& validator,
                        const wxString& name);
 
-    // free all memory we have (used by Clear() and dtor)
-    void Free();
-
     // the data for the "buddy" list
     WXHWND     m_hwndBuddy;
     WXFARPROC  m_wndProcBuddy;
diff --git a/include/wx/odcombo.h b/include/wx/odcombo.h
index 334d725410..7efe58f9e4 100644
--- a/include/wx/odcombo.h
+++ b/include/wx/odcombo.h
@@ -304,8 +304,8 @@ public:
     }
 
     // wxControlWithItems methods
-    virtual void Clear();
-    virtual void Delete(unsigned int n);
+    virtual void DoClear();
+    virtual void DoDeleteOneItem(unsigned int n);
     virtual unsigned int GetCount() const;
     virtual wxString GetString(unsigned int n) const;
     virtual void SetString(unsigned int n, const wxString& s);
@@ -327,6 +327,8 @@ public:
     // Return the index of the widest item (recalculating it if necessary)
     virtual int GetWidestItem() { EnsurePopupControl(); return GetVListBoxComboPopup()->GetWidestItem(); }
 
+    virtual bool IsSorted() const { return HasFlag(wxCB_SORT); }
+
     wxCONTROL_ITEMCONTAINER_CLIENTDATAOBJECT_RECAST
 
 protected:
@@ -359,12 +361,11 @@ protected:
         return (wxVListBoxComboPopup*) m_popupInterface;
     }
 
-    virtual int DoAppend(const wxString& item);
-    virtual int DoInsert(const wxString& item, unsigned int pos);
+    virtual int DoInsertItems(const wxArrayStringsAdapter& items,
+                              unsigned int pos,
+                              void **clientData, wxClientDataType type);
     virtual void DoSetItemClientData(unsigned int n, void* clientData);
     virtual void* DoGetItemClientData(unsigned int n) const;
-    virtual void DoSetItemClientObject(unsigned int n, wxClientData* clientData);
-    virtual wxClientData* DoGetItemClientObject(unsigned int n) const;
 
     // temporary storage for the initial choices
     //const wxString*         m_baseChoices;
diff --git a/include/wx/os2/checklst.h b/include/wx/os2/checklst.h
index 2a23c9645d..db4f841bc6 100644
--- a/include/wx/os2/checklst.h
+++ b/include/wx/os2/checklst.h
@@ -72,7 +72,9 @@ protected:
     virtual wxOwnerDrawn* CreateItem(size_t n);
     virtual long          OS2OnMeasure(WXMEASUREITEMSTRUCT* pItem);
 
-    virtual void DoInsertItems(const wxArrayString& items, unsigned int pos);
+    virtual int DoInsertItems(const wxArrayStringsAdapter & items,
+                              unsigned int pos,
+                              void **clientData, wxClientDataType type);
 
     //
     // Pressing space or clicking the check box toggles the item
diff --git a/include/wx/os2/choice.h b/include/wx/os2/choice.h
index 8054f22344..5acbbf3d31 100644
--- a/include/wx/os2/choice.h
+++ b/include/wx/os2/choice.h
@@ -93,8 +93,8 @@ public:
     //
     // Implement base class virtuals
     //
-    virtual void     Delete(unsigned int n);
-    virtual void     Clear(void);
+    virtual void     DoDeleteOneItem(unsigned int n);
+    virtual void     DoClear(void);
 
     virtual unsigned int GetCount() const;
     virtual int      GetSelection(void) const;
@@ -115,12 +115,13 @@ public:
                                   );
 
 protected:
-    virtual int           DoAppend(const wxString& rsItem);
-    virtual int           DoInsert(const wxString& rsItem, unsigned int pos);
+    virtual int           DoInsertItems(const wxArrayStringsAdapter& items,
+                                        unsigned int pos,
+                                        void **clientData,
+                                        wxClientDataType type);
+
     virtual void          DoSetItemClientData(unsigned int n, void* pClientData);
     virtual void*         DoGetItemClientData(unsigned int n) const;
-    virtual void          DoSetItemClientObject(unsigned int n, wxClientData* pClientData);
-    virtual wxClientData* DoGetItemClientObject(unsigned int n) const;
     virtual wxSize        DoGetBestSize(void) const;
     virtual void          DoSetSize( int nX
                                     ,int nY
diff --git a/include/wx/os2/listbox.h b/include/wx/os2/listbox.h
index 012d913b09..6b42cdc9f2 100644
--- a/include/wx/os2/listbox.h
+++ b/include/wx/os2/listbox.h
@@ -103,8 +103,8 @@ public:
     //
     // Implement base class pure virtuals
     //
-    virtual void          Clear(void);
-    virtual void          Delete(unsigned int n);
+    virtual void          DoClear(void);
+    virtual void          DoDeleteOneItem(unsigned int n);
 
     virtual unsigned int  GetCount() const;
     virtual wxString      GetString(unsigned int n) const;
@@ -115,18 +115,10 @@ public:
     virtual int           GetSelection(void) const;
     virtual int           GetSelections(wxArrayInt& raSelections) const;
 
-    virtual int           DoAppend(const wxString& rsItem);
-    virtual void          DoInsertItems( const wxArrayString& raItems, unsigned int rPos );
-    virtual void          DoSetItems( const wxArrayString& raItems
-                                     ,void **              ppClientData
-                                    );
-
     virtual void          DoSetFirstItem(int n);
 
     virtual void          DoSetItemClientData(unsigned int n, void* pClientData);
     virtual void*         DoGetItemClientData(unsigned int n) const;
-    virtual void          DoSetItemClientObject(unsigned int n, wxClientData* pClientData);
-    virtual wxClientData* DoGetItemClientObject(unsigned int n) const;
 
     //
     // wxCheckListBox support
@@ -160,7 +152,14 @@ protected:
     wxListBoxItemsArray             m_aItems;
 #endif
 
-private:
+    //
+    // Implement base wxItemContainer virtuals
+    //
+    virtual int           DoInsertItems(const wxArrayStringsAdapter& items,
+                                        unsigned int pos,
+                                        void **clientData,
+                                        wxClientDataType type);
+
     DECLARE_DYNAMIC_CLASS(wxListBox)
 }; // end of wxListBox
 
diff --git a/include/wx/palmos/choice.h b/include/wx/palmos/choice.h
index e978c2d869..1cffe80f7b 100644
--- a/include/wx/palmos/choice.h
+++ b/include/wx/palmos/choice.h
@@ -64,10 +64,11 @@ public:
                 const wxString& name = wxChoiceNameStr);
 
     // implement base class pure virtuals
-    virtual int DoAppend(const wxString& item);
-    virtual int DoInsert(const wxString& item, unsigned int pos);
-    virtual void Delete(unsigned int n);
-    virtual void Clear();
+    virtual int DoInsertItems(const wxArrayStringsAdapter& items,
+                              unsigned int pos,
+                              void **clientData, wxClientDataType type);
+    virtual void DoDeleteOneItem(unsigned int n);
+    virtual void DoClear();
 
     virtual unsigned int GetCount() const;
     virtual int GetSelection() const;
@@ -84,8 +85,6 @@ protected:
     virtual void DoMoveWindow(int x, int y, int width, int height);
     virtual void DoSetItemClientData(unsigned int n, void* clientData);
     virtual void* DoGetItemClientData(unsigned int n) const;
-    virtual void DoSetItemClientObject(unsigned int n, wxClientData* clientData);
-    virtual wxClientData* DoGetItemClientObject(unsigned int n) const;
 
     // MSW implementation
     virtual wxSize DoGetBestSize() const;
diff --git a/include/wx/palmos/listbox.h b/include/wx/palmos/listbox.h
index 0f6e6e7578..1bf96f567a 100644
--- a/include/wx/palmos/listbox.h
+++ b/include/wx/palmos/listbox.h
@@ -78,8 +78,8 @@ public:
     virtual ~wxListBox();
 
     // implement base class pure virtuals
-    virtual void Clear();
-    virtual void Delete(unsigned int n);
+    virtual void DoClear();
+    virtual void DoDeleteOneItem(unsigned int n);
 
     virtual unsigned int GetCount() const;
     virtual wxString GetString(unsigned int n) const;
@@ -90,16 +90,14 @@ public:
     virtual int GetSelection() const;
     virtual int GetSelections(wxArrayInt& aSelections) const;
 
-    virtual int DoAppend(const wxString& item);
-    virtual void DoInsertItems(const wxArrayString& items, unsigned int pos);
-    virtual void DoSetItems(const wxArrayString& items, void **clientData);
+    virtual int DoInsertItems(const wxArrayStringsAdapter& items,
+                              unsigned int pos,
+                              void **clientData, wxClientDataType type);
 
     virtual void DoSetFirstItem(int n);
 
     virtual void DoSetItemClientData(unsigned int n, void* clientData);
     virtual void* DoGetItemClientData(unsigned int n) const;
-    virtual void DoSetItemClientObject(unsigned int n, wxClientData* clientData);
-    virtual wxClientData* DoGetItemClientObject(unsigned int n) const;
 
     // wxCheckListBox support
 #if wxUSE_OWNER_DRAWN
diff --git a/include/wx/univ/checklst.h b/include/wx/univ/checklst.h
index e6afd10a16..3df4668770 100644
--- a/include/wx/univ/checklst.h
+++ b/include/wx/univ/checklst.h
@@ -84,14 +84,11 @@ public:
         return GetStdInputHandler(handlerDef);
     }
 
+protected:
     // override all methods which add/delete items to update m_checks array as
     // well
-    virtual void Delete(unsigned int n);
-
-protected:
-    virtual int DoAppend(const wxString& item);
-    virtual void DoInsertItems(const wxArrayString& items, unsigned int pos);
-    virtual void DoSetItems(const wxArrayString& items, void **clientData);
+    virtual void OnItemInserted(unsigned int pos);
+    virtual void DoDeleteOneItem(unsigned int n);
     virtual void DoClear();
 
     // draw the check items instead of the usual ones
diff --git a/include/wx/univ/combobox.h b/include/wx/univ/combobox.h
index 830f3e2ef5..48fc4225f4 100644
--- a/include/wx/univ/combobox.h
+++ b/include/wx/univ/combobox.h
@@ -117,8 +117,8 @@ public:
     virtual bool CanRedo() const;
 
     // wxControlWithItems methods
-    virtual void Clear();
-    virtual void Delete(unsigned int n);
+    virtual void DoClear();
+    virtual void DoDeleteOneItem(unsigned int n);
     virtual unsigned int GetCount() const;
     virtual wxString GetString(unsigned int n) const;
     virtual void SetString(unsigned int n, const wxString& s);
@@ -143,12 +143,12 @@ public:
     }
 
 protected:
-    virtual int DoAppend(const wxString& item);
-    virtual int DoInsert(const wxString& item, unsigned int pos);
+    virtual int DoInsertItems(const wxArrayStringsAdapter& items,
+                              unsigned int pos,
+                              void **clientData, wxClientDataType type);
+
     virtual void DoSetItemClientData(unsigned int n, void* clientData);
     virtual void* DoGetItemClientData(unsigned int n) const;
-    virtual void DoSetItemClientObject(unsigned int n, wxClientData* clientData);
-    virtual wxClientData* DoGetItemClientObject(unsigned int n) const;
 
     // common part of all ctors
     void Init();
diff --git a/include/wx/univ/listbox.h b/include/wx/univ/listbox.h
index 2edbdc1003..a5ef8d0d87 100644
--- a/include/wx/univ/listbox.h
+++ b/include/wx/univ/listbox.h
@@ -96,8 +96,8 @@ public:
                 const wxString& name = wxListBoxNameStr);
 
     // implement the listbox interface defined by wxListBoxBase
-    virtual void Clear();
-    virtual void Delete(unsigned int n);
+    virtual void DoClear();
+    virtual void DoDeleteOneItem(unsigned int n);
 
     virtual unsigned int GetCount() const
         { return (unsigned int)m_strings->GetCount(); }
@@ -114,17 +114,19 @@ public:
 
 protected:
     virtual void DoSetSelection(int n, bool select);
-    virtual int DoAppendOnly(const wxString& item);
-    virtual int DoAppend(const wxString& item);
-    virtual void DoInsertItems(const wxArrayString& items, unsigned int pos);
-    virtual void DoSetItems(const wxArrayString& items, void **clientData);
+
+    virtual int DoInsertItems(const wxArrayStringsAdapter& items,
+                              unsigned int pos,
+                              void **clientData,
+                              wxClientDataType type);
+
+    // universal wxComboBox implementation internally uses wxListBox
+    friend class WXDLLEXPORT wxComboBox;
 
     virtual void DoSetFirstItem(int n);
 
     virtual void DoSetItemClientData(unsigned int n, void* clientData);
     virtual void* DoGetItemClientData(unsigned int n) const;
-    virtual void DoSetItemClientObject(unsigned int n, wxClientData* clientData);
-    virtual wxClientData* DoGetItemClientObject(unsigned int n) const;
 
 public:
     // override some more base class methods
@@ -202,15 +204,17 @@ protected:
     virtual void DoDraw(wxControlRenderer *renderer);
     virtual wxBorder GetDefaultBorder() const;
 
+    // special hook for wxCheckListBox which allows it to update its internal
+    // data when a new item is inserted into the listbox
+    virtual void OnItemInserted(unsigned int WXUNUSED(pos)) { }
+
+
     // common part of all ctors
     void Init();
 
     // event handlers
     void OnSize(wxSizeEvent& event);
 
-    // common part of Clear() and DoSetItems(): clears everything
-    virtual void DoClear();
-
     // refresh the given item(s) or everything
     void RefreshItems(int from, int count);
     void RefreshItem(int n);
diff --git a/samples/widgets/Makefile.in b/samples/widgets/Makefile.in
index 43923e57ec..06a21cf635 100644
--- a/samples/widgets/Makefile.in
+++ b/samples/widgets/Makefile.in
@@ -1,6 +1,6 @@
 # =========================================================================
 #     This makefile was generated by
-#     Bakefile 0.2.1 (http://bakefile.sourceforge.net)
+#     Bakefile 0.2.2 (http://bakefile.sourceforge.net)
 #     Do not modify, all changes will be overwritten!
 # =========================================================================
 
@@ -34,6 +34,7 @@ EXTRALIBS_XML = @EXTRALIBS_XML@
 EXTRALIBS_HTML = @EXTRALIBS_HTML@
 EXTRALIBS_GUI = @EXTRALIBS_GUI@
 EXTRALIBS_SDL = @EXTRALIBS_SDL@
+CXXWARNINGS = @CXXWARNINGS@
 HOST_SUFFIX = @HOST_SUFFIX@
 SAMPLES_RPATH_FLAG = @SAMPLES_RPATH_FLAG@
 SAMPLES_RPATH_POSTLINK = @SAMPLES_RPATH_POSTLINK@
@@ -47,12 +48,14 @@ WX_VERSION = $(WX_RELEASE).0
 LIBDIRNAME = $(wx_top_builddir)/lib
 WIDGETS_CXXFLAGS = -D__WX$(TOOLKIT)__ $(__WXUNIV_DEFINE_p) \
 	$(__EXCEPTIONS_DEFINE_p) $(__RTTI_DEFINE_p) $(__THREAD_DEFINE_p) \
-	-I$(srcdir) $(__DLLFLAG_p) -I$(srcdir)/../../samples $(CPPFLAGS) $(CXXFLAGS)
+	-I$(srcdir) $(__DLLFLAG_p) -I$(srcdir)/../../samples $(CXXWARNINGS) \
+	$(CPPFLAGS) $(CXXFLAGS)
 WIDGETS_OBJECTS =  \
 	$(__widgets_os2_lib_res) \
 	widgets_bmpcombobox.o \
 	widgets_button.o \
 	widgets_checkbox.o \
+	widgets_choice.o \
 	widgets_clrpicker.o \
 	widgets_combobox.o \
 	widgets_datepick.o \
@@ -62,6 +65,7 @@ WIDGETS_OBJECTS =  \
 	widgets_fontpicker.o \
 	widgets_gauge.o \
 	widgets_hyperlnk.o \
+	widgets_itemcontainer.o \
 	widgets_listbox.o \
 	widgets_notebook.o \
 	widgets_odcombobox.o \
@@ -224,6 +228,9 @@ widgets_button.o: $(srcdir)/button.cpp
 widgets_checkbox.o: $(srcdir)/checkbox.cpp
 	$(CXXC) -c -o $@ $(WIDGETS_CXXFLAGS) $(srcdir)/checkbox.cpp
 
+widgets_choice.o: $(srcdir)/choice.cpp
+	$(CXXC) -c -o $@ $(WIDGETS_CXXFLAGS) $(srcdir)/choice.cpp
+
 widgets_clrpicker.o: $(srcdir)/clrpicker.cpp
 	$(CXXC) -c -o $@ $(WIDGETS_CXXFLAGS) $(srcdir)/clrpicker.cpp
 
@@ -251,6 +258,9 @@ widgets_gauge.o: $(srcdir)/gauge.cpp
 widgets_hyperlnk.o: $(srcdir)/hyperlnk.cpp
 	$(CXXC) -c -o $@ $(WIDGETS_CXXFLAGS) $(srcdir)/hyperlnk.cpp
 
+widgets_itemcontainer.o: $(srcdir)/itemcontainer.cpp
+	$(CXXC) -c -o $@ $(WIDGETS_CXXFLAGS) $(srcdir)/itemcontainer.cpp
+
 widgets_listbox.o: $(srcdir)/listbox.cpp
 	$(CXXC) -c -o $@ $(WIDGETS_CXXFLAGS) $(srcdir)/listbox.cpp
 
@@ -285,7 +295,7 @@ widgets_widgets.o: $(srcdir)/widgets.cpp
 	$(CXXC) -c -o $@ $(WIDGETS_CXXFLAGS) $(srcdir)/widgets.cpp
 
 widgets_sample_rc.o: $(srcdir)/../sample.rc
-	$(WINDRES) -i$< -o$@   --define __WX$(TOOLKIT)__ $(__WXUNIV_DEFINE_p_2)  $(__EXCEPTIONS_DEFINE_p_2) $(__RTTI_DEFINE_p_2) $(__THREAD_DEFINE_p_2)   --include-dir $(srcdir) $(__DLLFLAG_p_2) --include-dir $(srcdir)/../../samples $(__RCDEFDIR_p_1) --include-dir $(top_srcdir)/include
+	$(WINDRES) -i$< -o$@    --define __WX$(TOOLKIT)__ $(__WXUNIV_DEFINE_p_2)  $(__EXCEPTIONS_DEFINE_p_2) $(__RTTI_DEFINE_p_2) $(__THREAD_DEFINE_p_2)   --include-dir $(srcdir) $(__DLLFLAG_p_2) --include-dir $(srcdir)/../../samples $(__RCDEFDIR_p_1) --include-dir $(top_srcdir)/include
 
 
 # Include dependency info, if present:
diff --git a/samples/widgets/bmpcombobox.cpp b/samples/widgets/bmpcombobox.cpp
index 5cd72b3e28..7f9388545f 100644
--- a/samples/widgets/bmpcombobox.cpp
+++ b/samples/widgets/bmpcombobox.cpp
@@ -52,6 +52,7 @@
 #include "wx/imaglist.h"
 #include "wx/bmpcbox.h"
 
+#include "itemcontainer.h"
 #include "widgets.h"
 
 #include "icons/bmpcombobox.xpm"
@@ -82,7 +83,8 @@ enum
     BitmapComboBoxPage_Delete,
     BitmapComboBoxPage_DeleteText,
     BitmapComboBoxPage_DeleteSel,
-    BitmapComboBoxPage_Combo
+    BitmapComboBoxPage_Combo,
+    BitmapComboBoxPage_ContainerTests
 };
 
 
@@ -90,12 +92,13 @@ enum
 // BitmapComboBoxWidgetsPage
 // ----------------------------------------------------------------------------
 
-class BitmapComboBoxWidgetsPage : public WidgetsPage
+class BitmapComboBoxWidgetsPage : public ItemContainerWidgetsPage
 {
 public:
     BitmapComboBoxWidgetsPage(WidgetsBookCtrl *book, wxImageList *imaglist);
 
     virtual wxControl *GetWidget() const { return m_combobox; }
+    virtual wxItemContainer* GetContainer() const { return m_combobox; }
     virtual void RecreateWidget() { CreateCombo(); }
 
     // lazy creation of the content
@@ -195,6 +198,7 @@ BEGIN_EVENT_TABLE(BitmapComboBoxWidgetsPage, WidgetsPage)
     EVT_BUTTON(BitmapComboBoxPage_AddMany, BitmapComboBoxWidgetsPage::OnButtonAddMany)
     EVT_BUTTON(BitmapComboBoxPage_LoadFromFile, BitmapComboBoxWidgetsPage::OnButtonLoadFromFile)
     EVT_BUTTON(BitmapComboBoxPage_SetFromFile, BitmapComboBoxWidgetsPage::OnButtonSetFromFile)
+    EVT_BUTTON(BitmapComboBoxPage_ContainerTests, ItemContainerWidgetsPage::OnButtonTestItemContainer)
 
     EVT_TEXT_ENTER(BitmapComboBoxPage_InsertText, BitmapComboBoxWidgetsPage::OnButtonInsert)
     EVT_TEXT(BitmapComboBoxPage_ChangeHeight, BitmapComboBoxWidgetsPage::OnTextChangeHeight)
@@ -233,7 +237,7 @@ IMPLEMENT_WIDGETS_PAGE(BitmapComboBoxWidgetsPage, _T("BitmapCombobox"),
 
 BitmapComboBoxWidgetsPage::BitmapComboBoxWidgetsPage(WidgetsBookCtrl *book,
                                              wxImageList *imaglist)
-                  : WidgetsPage(book, imaglist, bmpcombobox_xpm)
+                  : ItemContainerWidgetsPage(book, imaglist, bmpcombobox_xpm)
 {
     // init everything
     m_chkSort =
@@ -308,6 +312,9 @@ void BitmapComboBoxWidgetsPage::CreateContent()
         _T("&Change wxBitmapComboBox contents"));
     wxSizer *sizerMiddle = new wxStaticBoxSizer(box2, wxVERTICAL);
 
+    btn = new wxButton(this, BitmapComboBoxPage_ContainerTests, _T("Run &tests"));
+    sizerMiddle->Add(btn, 0, wxALL | wxGROW, 5);
+
 #if wxUSE_IMAGE
     btn = new wxButton(this, BitmapComboBoxPage_AddWidgetIcons, _T("Add &widget icons"));
     sizerMiddle->Add(btn, 0, wxALL | wxGROW, 5);
diff --git a/samples/widgets/choice.cpp b/samples/widgets/choice.cpp
new file mode 100644
index 0000000000..872c91a741
--- /dev/null
+++ b/samples/widgets/choice.cpp
@@ -0,0 +1,453 @@
+/////////////////////////////////////////////////////////////////////////////
+// Program:     wxWidgets Widgets Sample
+// Name:        choice.cpp
+// Purpose:     Part of the widgets sample showing wxChoice
+// Created:     23.07.07
+// Id:          $Id$
+// License:     wxWindows license
+/////////////////////////////////////////////////////////////////////////////
+
+// ============================================================================
+// declarations
+// ============================================================================
+
+// ----------------------------------------------------------------------------
+// headers
+// ----------------------------------------------------------------------------
+
+// for compilers that support precompilation, includes "wx/wx.h".
+#include "wx/wxprec.h"
+
+#ifdef __BORLANDC__
+    #pragma hdrstop
+#endif
+
+#if wxUSE_CHOICE
+
+// for all others, include the necessary headers
+#ifndef WX_PRECOMP
+    #include "wx/log.h"
+
+    #include "wx/bitmap.h"
+    #include "wx/button.h"
+    #include "wx/checkbox.h"
+    #include "wx/choice.h"
+    #include "wx/combobox.h"
+    #include "wx/radiobox.h"
+    #include "wx/statbox.h"
+    #include "wx/textctrl.h"
+#endif
+
+#include "wx/sizer.h"
+
+#include "wx/checklst.h"
+
+#include "itemcontainer.h"
+#include "widgets.h"
+
+#include "icons/choice.xpm"
+
+// ----------------------------------------------------------------------------
+// constants
+// ----------------------------------------------------------------------------
+
+// control ids
+enum
+{
+    ChoicePage_Reset = wxID_HIGHEST,
+    ChoicePage_Add,
+    ChoicePage_AddText,
+    ChoicePage_AddSeveral,
+    ChoicePage_AddMany,
+    ChoicePage_Clear,
+    ChoicePage_Change,
+    ChoicePage_ChangeText,
+    ChoicePage_Delete,
+    ChoicePage_DeleteText,
+    ChoicePage_DeleteSel,
+    ChoicePage_Choice,
+    ChoicePage_ContainerTests
+};
+
+// ----------------------------------------------------------------------------
+// ChoiceWidgetsPage
+// ----------------------------------------------------------------------------
+
+class ChoiceWidgetsPage : public ItemContainerWidgetsPage
+{
+public:
+    ChoiceWidgetsPage(WidgetsBookCtrl *book, wxImageList *imaglist);
+
+    virtual wxControl *GetWidget() const { return m_choice; }
+    virtual wxItemContainer* GetContainer() const { return m_choice; }
+    virtual void RecreateWidget() { CreateChoice(); }
+
+    // lazy creation of the content
+    virtual void CreateContent();
+
+protected:
+    // event handlers
+    void OnButtonReset(wxCommandEvent& event);
+    void OnButtonChange(wxCommandEvent& event);
+    void OnButtonDelete(wxCommandEvent& event);
+    void OnButtonDeleteSel(wxCommandEvent& event);
+    void OnButtonClear(wxCommandEvent& event);
+    void OnButtonAdd(wxCommandEvent& event);
+    void OnButtonAddSeveral(wxCommandEvent& event);
+    void OnButtonAddMany(wxCommandEvent& event);
+
+    void OnChoice(wxCommandEvent& event);
+
+    void OnCheckOrRadioBox(wxCommandEvent& event);
+
+    void OnUpdateUIAddSeveral(wxUpdateUIEvent& event);
+    void OnUpdateUIClearButton(wxUpdateUIEvent& event);
+    void OnUpdateUIDeleteButton(wxUpdateUIEvent& event);
+    void OnUpdateUIDeleteSelButton(wxUpdateUIEvent& event);
+    void OnUpdateUIResetButton(wxUpdateUIEvent& event);
+
+    // reset the choice parameters
+    void Reset();
+
+    // (re)create the choice
+    void CreateChoice();
+
+    // should it be sorted?
+    bool m_sorted;
+
+    // the controls
+    // ------------
+
+    // the checkboxes
+    wxCheckBox *m_chkSort;
+
+    // the choice itself and the sizer it is in
+#ifdef __WXWINCE__
+    wxChoiceBase
+#else
+    wxChoice
+#endif
+                  *m_choice;
+
+    wxSizer *m_sizerChoice;
+
+    // the text entries for "Add/change string" and "Delete" buttons
+    wxTextCtrl *m_textAdd,
+               *m_textChange,
+               *m_textDelete;
+
+private:
+    DECLARE_EVENT_TABLE()
+    DECLARE_WIDGETS_PAGE(ChoiceWidgetsPage)
+};
+
+// ----------------------------------------------------------------------------
+// event tables
+// ----------------------------------------------------------------------------
+
+BEGIN_EVENT_TABLE(ChoiceWidgetsPage, WidgetsPage)
+    EVT_BUTTON(ChoicePage_Reset, ChoiceWidgetsPage::OnButtonReset)
+    EVT_BUTTON(ChoicePage_Change, ChoiceWidgetsPage::OnButtonChange)
+    EVT_BUTTON(ChoicePage_Delete, ChoiceWidgetsPage::OnButtonDelete)
+    EVT_BUTTON(ChoicePage_DeleteSel, ChoiceWidgetsPage::OnButtonDeleteSel)
+    EVT_BUTTON(ChoicePage_Clear, ChoiceWidgetsPage::OnButtonClear)
+    EVT_BUTTON(ChoicePage_Add, ChoiceWidgetsPage::OnButtonAdd)
+    EVT_BUTTON(ChoicePage_AddSeveral, ChoiceWidgetsPage::OnButtonAddSeveral)
+    EVT_BUTTON(ChoicePage_AddMany, ChoiceWidgetsPage::OnButtonAddMany)
+    EVT_BUTTON(ChoicePage_ContainerTests, ItemContainerWidgetsPage::OnButtonTestItemContainer)
+
+    EVT_TEXT_ENTER(ChoicePage_AddText, ChoiceWidgetsPage::OnButtonAdd)
+    EVT_TEXT_ENTER(ChoicePage_DeleteText, ChoiceWidgetsPage::OnButtonDelete)
+
+    EVT_UPDATE_UI(ChoicePage_Reset, ChoiceWidgetsPage::OnUpdateUIResetButton)
+    EVT_UPDATE_UI(ChoicePage_AddSeveral, ChoiceWidgetsPage::OnUpdateUIAddSeveral)
+    EVT_UPDATE_UI(ChoicePage_Clear, ChoiceWidgetsPage::OnUpdateUIClearButton)
+    EVT_UPDATE_UI(ChoicePage_DeleteText, ChoiceWidgetsPage::OnUpdateUIClearButton)
+    EVT_UPDATE_UI(ChoicePage_Delete, ChoiceWidgetsPage::OnUpdateUIDeleteButton)
+    EVT_UPDATE_UI(ChoicePage_Change, ChoiceWidgetsPage::OnUpdateUIDeleteSelButton)
+    EVT_UPDATE_UI(ChoicePage_ChangeText, ChoiceWidgetsPage::OnUpdateUIDeleteSelButton)
+    EVT_UPDATE_UI(ChoicePage_DeleteSel, ChoiceWidgetsPage::OnUpdateUIDeleteSelButton)
+
+    EVT_CHOICE(ChoicePage_Choice, ChoiceWidgetsPage::OnChoice)
+
+    EVT_CHECKBOX(wxID_ANY, ChoiceWidgetsPage::OnCheckOrRadioBox)
+    EVT_RADIOBOX(wxID_ANY, ChoiceWidgetsPage::OnCheckOrRadioBox)
+END_EVENT_TABLE()
+
+// ============================================================================
+// implementation
+// ============================================================================
+
+#if defined(__WXUNIVERSAL__)
+    #define FAMILY_CTRLS UNIVERSAL_CTRLS
+#else
+    #define FAMILY_CTRLS NATIVE_CTRLS
+#endif
+
+IMPLEMENT_WIDGETS_PAGE(ChoiceWidgetsPage, _T("Choice"),
+                       FAMILY_CTRLS | WITH_ITEMS_CTRLS
+                       );
+
+ChoiceWidgetsPage::ChoiceWidgetsPage(WidgetsBookCtrl *book,
+                                     wxImageList *imaglist)
+                  : ItemContainerWidgetsPage(book, imaglist, choice_xpm)
+{
+    // init everything
+
+    m_chkSort = (wxCheckBox *)NULL;
+
+    m_choice = NULL;
+    m_sizerChoice = (wxSizer *)NULL;
+
+}
+
+void ChoiceWidgetsPage::CreateContent()
+{
+    /*
+       What we create here is a frame having 3 panes: style pane is the
+       leftmost one, in the middle the pane with buttons allowing to perform
+       miscellaneous choice operations and the pane containing the choice
+       itself to the right
+    */
+    wxSizer *sizerTop = new wxBoxSizer(wxHORIZONTAL);
+
+    // left pane
+    wxStaticBox *box = new wxStaticBox(this, wxID_ANY,
+        _T("&Set choice parameters"));
+    wxSizer *sizerLeft = new wxStaticBoxSizer(box, wxVERTICAL);
+
+    static const wxString modes[] =
+    {
+        _T("single"),
+        _T("extended"),
+        _T("multiple"),
+    };
+
+    m_chkSort = CreateCheckBoxAndAddToSizer(sizerLeft, _T("&Sort items"));
+
+    wxButton *btn = new wxButton(this, ChoicePage_Reset, _T("&Reset"));
+    sizerLeft->Add(btn, 0, wxALIGN_CENTRE_HORIZONTAL | wxALL, 15);
+
+    // middle pane
+    wxStaticBox *box2 = new wxStaticBox(this, wxID_ANY,
+        _T("&Change choice contents"));
+    wxSizer *sizerMiddle = new wxStaticBoxSizer(box2, wxVERTICAL);
+
+    wxSizer *sizerRow = new wxBoxSizer(wxHORIZONTAL);
+    btn = new wxButton(this, ChoicePage_Add, _T("&Add this string"));
+    m_textAdd = new wxTextCtrl(this, ChoicePage_AddText, _T("test item 0"));
+    sizerRow->Add(btn, 0, wxRIGHT, 5);
+    sizerRow->Add(m_textAdd, 1, wxLEFT, 5);
+    sizerMiddle->Add(sizerRow, 0, wxALL | wxGROW, 5);
+
+    btn = new wxButton(this, ChoicePage_AddSeveral, _T("&Insert a few strings"));
+    sizerMiddle->Add(btn, 0, wxALL | wxGROW, 5);
+
+    btn = new wxButton(this, ChoicePage_AddMany, _T("Add &many strings"));
+    sizerMiddle->Add(btn, 0, wxALL | wxGROW, 5);
+
+    sizerRow = new wxBoxSizer(wxHORIZONTAL);
+    btn = new wxButton(this, ChoicePage_Change, _T("C&hange current"));
+    m_textChange = new wxTextCtrl(this, ChoicePage_ChangeText, wxEmptyString);
+    sizerRow->Add(btn, 0, wxRIGHT, 5);
+    sizerRow->Add(m_textChange, 1, wxLEFT, 5);
+    sizerMiddle->Add(sizerRow, 0, wxALL | wxGROW, 5);
+
+    sizerRow = new wxBoxSizer(wxHORIZONTAL);
+    btn = new wxButton(this, ChoicePage_Delete, _T("&Delete this item"));
+    m_textDelete = new wxTextCtrl(this, ChoicePage_DeleteText, wxEmptyString);
+    sizerRow->Add(btn, 0, wxRIGHT, 5);
+    sizerRow->Add(m_textDelete, 1, wxLEFT, 5);
+    sizerMiddle->Add(sizerRow, 0, wxALL | wxGROW, 5);
+
+    btn = new wxButton(this, ChoicePage_DeleteSel, _T("Delete &selection"));
+    sizerMiddle->Add(btn, 0, wxALL | wxGROW, 5);
+
+    btn = new wxButton(this, ChoicePage_Clear, _T("&Clear"));
+    sizerMiddle->Add(btn, 0, wxALL | wxGROW, 5);
+
+    btn = new wxButton(this, ChoicePage_ContainerTests, _T("Run &tests"));
+    sizerMiddle->Add(btn, 0, wxALL | wxGROW, 5);
+
+    // right pane
+    wxSizer *sizerRight = new wxBoxSizer(wxVERTICAL);
+    m_choice = new wxChoice(this, ChoicePage_Choice);
+    sizerRight->Add(m_choice, 1, wxGROW | wxALL, 5);
+    sizerRight->SetMinSize(150, 0);
+    m_sizerChoice = sizerRight; // save it to modify it later
+
+    // the 3 panes panes compose the window
+    sizerTop->Add(sizerLeft, 0, wxGROW | (wxALL & ~wxLEFT), 10);
+    sizerTop->Add(sizerMiddle, 1, wxGROW | wxALL, 10);
+    sizerTop->Add(sizerRight, 1, wxGROW | (wxALL & ~wxRIGHT), 10);
+
+    // final initializations
+    Reset();
+
+    SetSizer(sizerTop);
+}
+
+// ----------------------------------------------------------------------------
+// operations
+// ----------------------------------------------------------------------------
+
+void ChoiceWidgetsPage::Reset()
+{
+    m_chkSort->SetValue(false);
+}
+
+void ChoiceWidgetsPage::CreateChoice()
+{
+    int flags = ms_defaultFlags;
+
+    if ( m_chkSort->GetValue() )
+        flags |= wxCB_SORT;
+
+    wxArrayString items;
+    if ( m_choice )
+    {
+        int count = m_choice->GetCount();
+        for ( int n = 0; n < count; n++ )
+        {
+            items.Add(m_choice->GetString(n));
+        }
+
+        m_sizerChoice->Detach( m_choice );
+        delete m_choice;
+    }
+
+    m_choice = new wxChoice(this, ChoicePage_Choice,
+                            wxDefaultPosition, wxDefaultSize,
+                            0, NULL,
+                            flags);
+
+    m_choice->Set(items);
+    m_sizerChoice->Add(m_choice, 1, wxGROW | wxALL, 5);
+    m_sizerChoice->Layout();
+}
+
+// ----------------------------------------------------------------------------
+// event handlers
+// ----------------------------------------------------------------------------
+
+void ChoiceWidgetsPage::OnButtonReset(wxCommandEvent& WXUNUSED(event))
+{
+    Reset();
+
+    CreateChoice();
+}
+
+void ChoiceWidgetsPage::OnButtonChange(wxCommandEvent& WXUNUSED(event))
+{
+    int selection = m_choice->GetSelection();
+    if(selection != wxNOT_FOUND)
+    {
+        m_choice->SetString(selection, m_textChange->GetValue());
+    }
+}
+
+void ChoiceWidgetsPage::OnButtonDelete(wxCommandEvent& WXUNUSED(event))
+{
+    unsigned long n;
+    if ( !m_textDelete->GetValue().ToULong(&n) ||
+            (n >= (unsigned)m_choice->GetCount()) )
+    {
+        return;
+    }
+
+    m_choice->Delete(n);
+}
+
+void ChoiceWidgetsPage::OnButtonDeleteSel(wxCommandEvent& WXUNUSED(event))
+{
+    int selection = m_choice->GetSelection();
+    if(selection != wxNOT_FOUND)
+    {
+        m_choice->Delete(selection);
+    }
+}
+
+void ChoiceWidgetsPage::OnButtonClear(wxCommandEvent& WXUNUSED(event))
+{
+    m_choice->Clear();
+}
+
+void ChoiceWidgetsPage::OnButtonAdd(wxCommandEvent& WXUNUSED(event))
+{
+    static unsigned int s_item = 0;
+
+    wxString s = m_textAdd->GetValue();
+    if ( !m_textAdd->IsModified() )
+    {
+        // update the default string
+        m_textAdd->SetValue(wxString::Format(_T("test item %u"), ++s_item));
+    }
+
+    m_choice->Append(s);
+}
+
+void ChoiceWidgetsPage::OnButtonAddMany(wxCommandEvent& WXUNUSED(event))
+{
+    // "many" means 1000 here
+    wxArrayString strings;
+    for ( unsigned int n = 0; n < 1000; n++ )
+    {
+        strings.Add(wxString::Format(_T("item #%u"), n));
+    }
+    m_choice->Append(strings);
+}
+
+void ChoiceWidgetsPage::OnButtonAddSeveral(wxCommandEvent& WXUNUSED(event))
+{
+    wxArrayString items;
+    items.Add(_T("First"));
+    items.Add(_T("another one"));
+    items.Add(_T("and the last (very very very very very very very very very very long) one"));
+    m_choice->Insert(items, 0);
+}
+
+void ChoiceWidgetsPage::OnUpdateUIResetButton(wxUpdateUIEvent& event)
+{
+    event.Enable( m_chkSort->GetValue() );
+}
+
+void ChoiceWidgetsPage::OnUpdateUIDeleteButton(wxUpdateUIEvent& event)
+{
+    unsigned long n;
+    event.Enable(m_textDelete->GetValue().ToULong(&n) &&
+                    (n < (unsigned)m_choice->GetCount()));
+}
+
+void ChoiceWidgetsPage::OnUpdateUIDeleteSelButton(wxUpdateUIEvent& event)
+{
+    wxArrayInt selections;
+    event.Enable(m_choice->GetSelection() != wxNOT_FOUND);
+}
+
+void ChoiceWidgetsPage::OnUpdateUIClearButton(wxUpdateUIEvent& event)
+{
+    event.Enable(m_choice->GetCount() != 0);
+}
+
+void ChoiceWidgetsPage::OnUpdateUIAddSeveral(wxUpdateUIEvent& event)
+{
+    event.Enable(!m_choice->HasFlag(wxCB_SORT));
+}
+
+void ChoiceWidgetsPage::OnChoice(wxCommandEvent& event)
+{
+    long sel = event.GetSelection();
+    m_textDelete->SetValue(wxString::Format(_T("%ld"), sel));
+
+    if (event.IsSelection())
+        wxLogMessage(_T("Choice item %ld selected"), sel);
+    else
+        wxLogMessage(_T("Choice item %ld deselected"), sel);
+}
+
+void ChoiceWidgetsPage::OnCheckOrRadioBox(wxCommandEvent& WXUNUSED(event))
+{
+    CreateChoice();
+}
+
+#endif // wxUSE_CHOICE
diff --git a/samples/widgets/combobox.cpp b/samples/widgets/combobox.cpp
index bb565684bc..6518ddd09f 100644
--- a/samples/widgets/combobox.cpp
+++ b/samples/widgets/combobox.cpp
@@ -41,6 +41,7 @@
 
 #include "wx/sizer.h"
 
+#include "itemcontainer.h"
 #include "widgets.h"
 #if 1
 #include "icons/combobox.xpm"
@@ -70,7 +71,8 @@ enum
     ComboPage_DeleteSel,
     ComboPage_SetValue,
     ComboPage_SetValueText,
-    ComboPage_Combo
+    ComboPage_Combo,
+    ComboPage_ContainerTests
 };
 
 // kinds of comboboxes
@@ -85,12 +87,13 @@ enum
 // ComboboxWidgetsPage
 // ----------------------------------------------------------------------------
 
-class ComboboxWidgetsPage : public WidgetsPage
+class ComboboxWidgetsPage : public ItemContainerWidgetsPage
 {
 public:
     ComboboxWidgetsPage(WidgetsBookCtrl *book, wxImageList *imaglist);
 
     virtual wxControl *GetWidget() const { return m_combobox; }
+    virtual wxItemContainer* GetContainer() const { return m_combobox; }
     virtual void RecreateWidget() { CreateCombo(); }
 
     // lazy creation of the content
@@ -175,6 +178,7 @@ BEGIN_EVENT_TABLE(ComboboxWidgetsPage, WidgetsPage)
     EVT_BUTTON(ComboPage_AddMany, ComboboxWidgetsPage::OnButtonAddMany)
     EVT_BUTTON(ComboPage_SetValue, ComboboxWidgetsPage::OnButtonSetValue)
     EVT_BUTTON(ComboPage_SetCurrent, ComboboxWidgetsPage::OnButtonSetCurrent)
+    EVT_BUTTON(ComboPage_ContainerTests, ItemContainerWidgetsPage::OnButtonTestItemContainer)
 
     EVT_TEXT_ENTER(ComboPage_InsertText, ComboboxWidgetsPage::OnButtonInsert)
     EVT_TEXT_ENTER(ComboPage_AddText, ComboboxWidgetsPage::OnButtonAdd)
@@ -217,7 +221,7 @@ IMPLEMENT_WIDGETS_PAGE(ComboboxWidgetsPage, _T("Combobox"),
 
 ComboboxWidgetsPage::ComboboxWidgetsPage(WidgetsBookCtrl *book,
                                          wxImageList *imaglist)
-                  : WidgetsPage(book, imaglist, combobox_xpm)
+                  : ItemContainerWidgetsPage(book, imaglist, combobox_xpm)
 {
     // init everything
     m_chkSort =
@@ -331,6 +335,9 @@ void ComboboxWidgetsPage::CreateContent()
                                             &m_textSetValue);
     sizerMiddle->Add(sizerRow, 0, wxALL | wxGROW, 5);
 
+    btn = new wxButton(this, ComboPage_ContainerTests, _T("Run &tests"));
+    sizerMiddle->Add(btn, 0, wxALL | wxGROW, 5);
+
 
 
     // right pane
diff --git a/samples/widgets/icons/choice.xpm b/samples/widgets/icons/choice.xpm
new file mode 100644
index 0000000000..c46aaf5dba
--- /dev/null
+++ b/samples/widgets/icons/choice.xpm
@@ -0,0 +1,27 @@
+/* XPM */
+static char * choice_xpm[] = {
+/* width height ncolors chars_per_pixel */
+"16 16 5 1",
+/* colors */
+" 	s None	c None",
+".	c #000000",
+"+	c #c0c0c0",
+"@	c #808080",
+"#	c #ffffff",
+/* pixels */
+"@@@@@@@@@@@@@@@@",
+"@..............@",
+"@.########+++++@",
+"@.########.....@",
+"@.########+...+@",
+"@.########++.++@",
+"@.+++++++++++++@",
+"@@@@@@@@@@@@@@@@",
+"  ##############",
+"  ..............",
+"  .#########+.+.",
+"  .#########....",
+"  .#########+++.",
+"  .#########....",
+"  .#########+.+.",
+"  .............."};
diff --git a/samples/widgets/itemcontainer.cpp b/samples/widgets/itemcontainer.cpp
new file mode 100644
index 0000000000..c46a738d08
--- /dev/null
+++ b/samples/widgets/itemcontainer.cpp
@@ -0,0 +1,288 @@
+/////////////////////////////////////////////////////////////////////////////
+// Program:     wxWidgets Widgets Sample
+// Name:        itemcontainer.cpp
+// Purpose:     Part of the widgets sample showing wxComboBox
+// Created:     20.07.07
+// Id:          $Id$
+// License:     wxWindows license
+/////////////////////////////////////////////////////////////////////////////
+
+// ============================================================================
+// declarations
+// ============================================================================
+
+// ----------------------------------------------------------------------------
+// headers
+// ----------------------------------------------------------------------------
+
+// for compilers that support precompilation, includes "wx/wx.h".
+#include "wx/wxprec.h"
+
+#ifdef __BORLANDC__
+    #pragma hdrstop
+#endif
+
+// for all others, include the necessary headers
+#ifndef WX_PRECOMP
+    #include "wx/log.h"
+
+    #include "wx/event.h"
+#endif
+
+#include "wx/ctrlsub.h"
+#include "itemcontainer.h"
+
+
+// Help track client data objects in wxItemContainer instances.
+class TrackedClientData : public wxClientData
+{
+public:
+
+    TrackedClientData(ItemContainerWidgetsPage* tracker, int value)
+        : m_tracker(tracker),
+          m_value(value)
+    {
+        m_tracker->StartTrackingData();
+    }
+
+    virtual ~TrackedClientData()
+    {
+        m_tracker->StopTrackingData();
+    }
+
+    int GetValue() const
+    {
+        return m_value;
+    }
+
+private:
+    ItemContainerWidgetsPage *m_tracker;
+    int m_value;
+
+    DECLARE_NO_COPY_CLASS(TrackedClientData)
+};
+
+// ============================================================================
+// implementation
+// ============================================================================
+
+ItemContainerWidgetsPage::ItemContainerWidgetsPage(WidgetsBookCtrl *book,
+                                                   wxImageList *image_list,
+                                                   char* icon[])
+: WidgetsPage(book, image_list, icon), m_trackedDataObjects(0)
+{
+    m_items.Add(_T("This"));
+    m_items.Add(_T("is"));
+    m_items.Add(_T("a"));
+    m_items.Add(_T("List"));
+    m_items.Add(_T("of"));
+    m_items.Add(_T("strings"));
+    m_itemsSorted = m_items;
+}
+
+ItemContainerWidgetsPage::~ItemContainerWidgetsPage()
+{
+}
+
+wxClientData* ItemContainerWidgetsPage::CreateClientData(int value)
+{
+    return new TrackedClientData(this, value);
+}
+
+void ItemContainerWidgetsPage::StartTrackingData()
+{
+    ++m_trackedDataObjects;
+}
+
+void ItemContainerWidgetsPage::StopTrackingData()
+{
+    --m_trackedDataObjects;
+}
+
+bool ItemContainerWidgetsPage::VerifyAllClientDataDestroyed()
+{
+    if ( m_trackedDataObjects )
+    {
+        wxString message = _T("Bug in managing wxClientData: ");
+        if ( m_trackedDataObjects > 0 )
+            message << m_trackedDataObjects << _T(" lost objects");
+        else
+            message << (-m_trackedDataObjects) << _T(" extra deletes");
+        wxFAIL_MSG(message);
+        return false;
+    }
+
+    return true;
+}
+
+void ItemContainerWidgetsPage::StartTest(const wxString& label)
+{
+    m_container->Clear();
+    wxLogMessage(_T("Test - %s:"), label.c_str());
+}
+
+void ItemContainerWidgetsPage::EndTest(const wxArrayString& items)
+{
+    const unsigned count = m_container->GetCount();
+
+    bool ok = count == items.GetCount();
+    if ( !ok )
+    {
+        wxFAIL_MSG(_T("Item count does not match."));
+    }
+    else
+    {
+        for ( unsigned i = 0; i < count; ++i )
+        {
+            wxString str = m_container->GetString(i);
+            if ( str != items[i] )
+            {
+                wxFAIL_MSG(wxString::Format(
+                            _T("Wrong string \"%s\" at position %d (expected \"%s\")"),
+                           str.c_str(), i, items[i].c_str()));
+                ok = false;
+                break;
+            }
+
+            if ( m_container->HasClientUntypedData() )
+            {
+                void *data = m_container->GetClientData(i);
+                if ( data && !VerifyClientData((wxUIntPtr)data, str) )
+                {
+                    ok = false;
+                    break;
+                }
+            }
+            else if ( m_container->HasClientObjectData() )
+            {
+                TrackedClientData* obj = (TrackedClientData*)m_container->GetClientObject(i);
+                if ( obj && !VerifyClientData(obj->GetValue(), str) )
+                {
+                    ok = false;
+                    break;
+                }
+            }
+        }
+
+        if ( !ok )
+        {
+            wxLogMessage(DumpContainerData(items));
+        }
+    }
+
+    m_container->Clear();
+    ok &= VerifyAllClientDataDestroyed();
+
+    wxLogMessage(_T("...%s"), ok ? _T("passed") : _T("failed"));
+}
+
+wxString
+ItemContainerWidgetsPage::DumpContainerData(const wxArrayString& expected) const
+{
+    wxString str;
+    str << _T("Current content:\n");
+
+    unsigned i;
+    for ( i = 0; i < m_container->GetCount(); ++i )
+    {
+        str << _T(" - ") << m_container->GetString(i) << _T(" [");
+        if ( m_container->HasClientObjectData() )
+        {
+            TrackedClientData *
+                obj = (TrackedClientData*)m_container->GetClientObject(i);
+            if ( obj )
+                str << obj->GetValue();
+        }
+        else if ( m_container->HasClientUntypedData() )
+        {
+            void *data = m_container->GetClientData(i);
+            if ( data )
+                str << (wxUIntPtr)data;
+        }
+        str << _T("]\n");
+    }
+
+    str << _T("Expected content:\n");
+    for ( i = 0; i < expected.GetCount(); ++i )
+    {
+        const wxString& item = expected[i];
+        str << _T(" - ") << item << _T("[");
+        for( unsigned j = 0; j < m_items.GetCount(); ++j )
+        {
+            if ( m_items[j] == item )
+                str << j;
+        }
+        str << _T("]\n");
+    }
+
+    return str;
+}
+
+bool ItemContainerWidgetsPage::VerifyClientData(wxUIntPtr i, const wxString& str)
+{
+    if ( i > m_items.GetCount() || m_items[i] != str )
+    {
+        wxLogMessage(_T("Client data for '%s' does not match."), str.c_str());
+        return false;
+    }
+
+    return true;
+}
+
+void ItemContainerWidgetsPage::OnButtonTestItemContainer(wxCommandEvent&)
+{
+    m_container = GetContainer();
+    wxASSERT_MSG(m_container, _T("Widget must have a test widget"));
+
+    wxLogMessage(_T("wxItemContainer test for %s, %s:"),
+                 GetWidget()->GetClassInfo()->GetClassName(),
+                 (m_container->IsSorted() ? "Sorted" : "Unsorted"));
+
+    const wxArrayString
+        & expected_result = m_container->IsSorted() ? m_itemsSorted
+                                                    : m_items;
+
+    StartTest(_T("Append one item"));
+    wxString item = m_items[0];
+    m_container->Append(item);
+    EndTest(wxArrayString(1, &item));
+
+    StartTest(_T("Append some items"));
+    m_container->Append(m_items);
+    EndTest(expected_result);
+
+    StartTest(_T("Append some items with data objects"));
+    wxClientData **objects = new wxClientData *[m_items.GetCount()];
+    for ( unsigned i = 0; i < m_items.GetCount(); ++i )
+        objects[i] = CreateClientData(i);
+    m_container->Append(m_items, objects);
+    EndTest(expected_result);
+    delete[] objects;
+
+    StartTest(_T("Append some items with data"));
+    void **data = new void *[m_items.GetCount()];
+    for ( unsigned i = 0; i < m_items.GetCount(); ++i )
+        data[i] = (void*)i;
+    m_container->Append(m_items, data);
+    EndTest(expected_result);
+    delete[] data;
+
+    StartTest(_T("Append some items with data, one by one"));
+    for ( unsigned i = 0; i < m_items.GetCount(); ++i )
+        m_container->Append(m_items[i], (void*)i);
+    EndTest(expected_result);
+
+    StartTest(_T("Append some items with data objects, one by one"));
+    for ( unsigned i = 0; i < m_items.GetCount(); ++i )
+        m_container->Append(m_items[i], CreateClientData(i));
+    EndTest(expected_result);
+
+    if ( !m_container->IsSorted() )
+    {
+        StartTest(_T("Insert in reverse order with data, one by one"));
+        for ( unsigned i = m_items.GetCount(); i; --i )
+            m_container->Insert(m_items[i - 1], 0, (void*)(i - 1));
+        EndTest(expected_result);
+    }
+}
+
diff --git a/samples/widgets/itemcontainer.h b/samples/widgets/itemcontainer.h
new file mode 100644
index 0000000000..30d79ec558
--- /dev/null
+++ b/samples/widgets/itemcontainer.h
@@ -0,0 +1,53 @@
+/////////////////////////////////////////////////////////////////////////////
+// Program:     wxWidgets Widgets Sample
+// Name:        itemcontainer.h
+// Purpose:     Part of the widgets sample showing wxComboBox
+// Created:     20.07.07
+// Id:          $Id$
+// License:     wxWindows license
+/////////////////////////////////////////////////////////////////////////////
+
+#ifndef _WX_SAMPLE_WIDGETS_ITEMCONTAINER_H_
+#define _WX_SAMPLE_WIDGETS_ITEMCONTAINER_H_
+
+// for compilers that support precompilation, includes "wx/wx.h".
+#include "wx/wxprec.h"
+
+#include "widgets.h"
+
+class ItemContainerWidgetsPage : public WidgetsPage
+{
+public:
+    ItemContainerWidgetsPage(WidgetsBookCtrl *book,
+                             wxImageList *image_list,
+                             char* icon[]);
+    virtual ~ItemContainerWidgetsPage();
+
+    void OnButtonTestItemContainer(wxCommandEvent& event);
+
+    virtual wxItemContainer* GetContainer() const = 0;
+
+private:
+    void StartTest(const wxString& label);
+    void EndTest(const wxArrayString& result);
+
+    // Track client data in wxItemContainer instances
+    wxClientData* CreateClientData(int value);
+    void StartTrackingData();
+    void StopTrackingData();
+    friend class TrackedClientData;
+
+    bool VerifyAllClientDataDestroyed();
+    bool VerifyClientData(wxUIntPtr i, const wxString& str);
+
+    wxString DumpContainerData(const wxArrayString& expected) const;
+
+    wxArrayString       m_items;
+    wxSortedArrayString m_itemsSorted;
+    int m_trackedDataObjects;
+
+    // holds pointer to the widget being tested
+    wxItemContainer *m_container;
+};
+
+#endif // _WX_SAMPLE_WIDGETS_ITEMCONTAINER_H_
diff --git a/samples/widgets/listbox.cpp b/samples/widgets/listbox.cpp
index a766ef441f..b92ae08e7d 100644
--- a/samples/widgets/listbox.cpp
+++ b/samples/widgets/listbox.cpp
@@ -44,6 +44,7 @@
 
 #include "wx/checklst.h"
 
+#include "itemcontainer.h"
 #include "widgets.h"
 
 #include "icons/listbox.xpm"
@@ -66,19 +67,21 @@ enum
     ListboxPage_Delete,
     ListboxPage_DeleteText,
     ListboxPage_DeleteSel,
-    ListboxPage_Listbox
+    ListboxPage_Listbox,
+    ListboxPage_ContainerTests
 };
 
 // ----------------------------------------------------------------------------
 // ListboxWidgetsPage
 // ----------------------------------------------------------------------------
 
-class ListboxWidgetsPage : public WidgetsPage
+class ListboxWidgetsPage : public ItemContainerWidgetsPage
 {
 public:
     ListboxWidgetsPage(WidgetsBookCtrl *book, wxImageList *imaglist);
 
     virtual wxControl *GetWidget() const { return m_lbox; }
+    virtual wxItemContainer* GetContainer() const { return m_lbox; }
     virtual void RecreateWidget() { CreateLbox(); }
 
     // lazy creation of the content
@@ -177,6 +180,7 @@ BEGIN_EVENT_TABLE(ListboxWidgetsPage, WidgetsPage)
     EVT_BUTTON(ListboxPage_Add, ListboxWidgetsPage::OnButtonAdd)
     EVT_BUTTON(ListboxPage_AddSeveral, ListboxWidgetsPage::OnButtonAddSeveral)
     EVT_BUTTON(ListboxPage_AddMany, ListboxWidgetsPage::OnButtonAddMany)
+    EVT_BUTTON(ListboxPage_ContainerTests, ItemContainerWidgetsPage::OnButtonTestItemContainer)
 
     EVT_TEXT_ENTER(ListboxPage_AddText, ListboxWidgetsPage::OnButtonAdd)
     EVT_TEXT_ENTER(ListboxPage_DeleteText, ListboxWidgetsPage::OnButtonDelete)
@@ -214,7 +218,7 @@ IMPLEMENT_WIDGETS_PAGE(ListboxWidgetsPage, _T("Listbox"),
 
 ListboxWidgetsPage::ListboxWidgetsPage(WidgetsBookCtrl *book,
                                        wxImageList *imaglist)
-                  : WidgetsPage(book, imaglist, listbox_xpm)
+                  : ItemContainerWidgetsPage(book, imaglist, listbox_xpm)
 {
     // init everything
     m_radioSelMode = (wxRadioBox *)NULL;
@@ -315,6 +319,9 @@ void ListboxWidgetsPage::CreateContent()
     btn = new wxButton(this, ListboxPage_Clear, _T("&Clear"));
     sizerMiddle->Add(btn, 0, wxALL | wxGROW, 5);
 
+    btn = new wxButton(this, ListboxPage_ContainerTests, _T("Run &tests"));
+    sizerMiddle->Add(btn, 0, wxALL | wxGROW, 5);
+
     // right pane
     wxSizer *sizerRight = new wxBoxSizer(wxVERTICAL);
     m_lbox = new wxListBox(this, ListboxPage_Listbox,
diff --git a/samples/widgets/makefile.bcc b/samples/widgets/makefile.bcc
index 84c9e650f1..66a930a6ec 100644
--- a/samples/widgets/makefile.bcc
+++ b/samples/widgets/makefile.bcc
@@ -1,6 +1,6 @@
 # =========================================================================
 #     This makefile was generated by
-#     Bakefile 0.2.1 (http://bakefile.sourceforge.net)
+#     Bakefile 0.2.2 (http://bakefile.sourceforge.net)
 #     Do not modify, all changes will be overwritten!
 # =========================================================================
 
@@ -22,9 +22,10 @@ BCCDIR = $(MAKEDIR)\..
 ### Variables: ###
 
 WX_RELEASE_NODOT = 29
+COMPILER_PREFIX = bcc
 OBJS = \
-	bcc_$(PORTNAME)$(WXUNIVNAME)$(WXUNICODEFLAG)$(WXDEBUGFLAG)$(WXDLLFLAG)$(CFG)
-LIBDIRNAME = .\..\..\lib\bcc_$(LIBTYPE_SUFFIX)$(CFG)
+	$(COMPILER_PREFIX)_$(PORTNAME)$(WXUNIVNAME)$(WXUNICODEFLAG)$(WXDEBUGFLAG)$(WXDLLFLAG)$(CFG)
+LIBDIRNAME = .\..\..\lib\$(COMPILER_PREFIX)_$(LIBTYPE_SUFFIX)$(CFG)
 SETUPHDIR = \
 	$(LIBDIRNAME)\$(PORTNAME)$(WXUNIVNAME)$(WXUNICODEFLAG)$(WXDEBUGFLAG)
 WIDGETS_CXXFLAGS = $(__RUNTIME_LIBS_7) -I$(BCCDIR)\include $(__DEBUGINFO) \
@@ -37,6 +38,7 @@ WIDGETS_OBJECTS =  \
 	$(OBJS)\widgets_bmpcombobox.obj \
 	$(OBJS)\widgets_button.obj \
 	$(OBJS)\widgets_checkbox.obj \
+	$(OBJS)\widgets_choice.obj \
 	$(OBJS)\widgets_clrpicker.obj \
 	$(OBJS)\widgets_combobox.obj \
 	$(OBJS)\widgets_datepick.obj \
@@ -46,6 +48,7 @@ WIDGETS_OBJECTS =  \
 	$(OBJS)\widgets_fontpicker.obj \
 	$(OBJS)\widgets_gauge.obj \
 	$(OBJS)\widgets_hyperlnk.obj \
+	$(OBJS)\widgets_itemcontainer.obj \
 	$(OBJS)\widgets_listbox.obj \
 	$(OBJS)\widgets_notebook.obj \
 	$(OBJS)\widgets_odcombobox.obj \
@@ -269,6 +272,9 @@ $(OBJS)\widgets_button.obj: .\button.cpp
 $(OBJS)\widgets_checkbox.obj: .\checkbox.cpp
 	$(CXX) -q -c -P -o$@ $(WIDGETS_CXXFLAGS) $**
 
+$(OBJS)\widgets_choice.obj: .\choice.cpp
+	$(CXX) -q -c -P -o$@ $(WIDGETS_CXXFLAGS) $**
+
 $(OBJS)\widgets_clrpicker.obj: .\clrpicker.cpp
 	$(CXX) -q -c -P -o$@ $(WIDGETS_CXXFLAGS) $**
 
@@ -296,6 +302,9 @@ $(OBJS)\widgets_gauge.obj: .\gauge.cpp
 $(OBJS)\widgets_hyperlnk.obj: .\hyperlnk.cpp
 	$(CXX) -q -c -P -o$@ $(WIDGETS_CXXFLAGS) $**
 
+$(OBJS)\widgets_itemcontainer.obj: .\itemcontainer.cpp
+	$(CXX) -q -c -P -o$@ $(WIDGETS_CXXFLAGS) $**
+
 $(OBJS)\widgets_listbox.obj: .\listbox.cpp
 	$(CXX) -q -c -P -o$@ $(WIDGETS_CXXFLAGS) $**
 
@@ -330,5 +339,5 @@ $(OBJS)\widgets_widgets.obj: .\widgets.cpp
 	$(CXX) -q -c -P -o$@ $(WIDGETS_CXXFLAGS) $**
 
 $(OBJS)\widgets_sample.res: .\..\sample.rc
-	brcc32 -32 -r -fo$@ -i$(BCCDIR)\include   -d__WXMSW__ $(__WXUNIV_DEFINE_p_1) $(__DEBUG_DEFINE_p_1) $(__EXCEPTIONS_DEFINE_p_1) $(__RTTI_DEFINE_p_1) $(__THREAD_DEFINE_p_1) $(__UNICODE_DEFINE_p_1) $(__MSLU_DEFINE_p_1) $(__GFXCTX_DEFINE_p_1) -i$(SETUPHDIR) -i.\..\..\include -i. $(__DLLFLAG_p_1) -i.\..\..\samples -dNOPCH $**
+	brcc32 -32 -r -fo$@ -i$(BCCDIR)\include    -d__WXMSW__ $(__WXUNIV_DEFINE_p_1) $(__DEBUG_DEFINE_p_1) $(__EXCEPTIONS_DEFINE_p_1) $(__RTTI_DEFINE_p_1) $(__THREAD_DEFINE_p_1) $(__UNICODE_DEFINE_p_1) $(__MSLU_DEFINE_p_1) $(__GFXCTX_DEFINE_p_1) -i$(SETUPHDIR) -i.\..\..\include -i. $(__DLLFLAG_p_1) -i.\..\..\samples -dNOPCH $**
 
diff --git a/samples/widgets/makefile.gcc b/samples/widgets/makefile.gcc
index 53aba1b639..9401c9c275 100644
--- a/samples/widgets/makefile.gcc
+++ b/samples/widgets/makefile.gcc
@@ -1,6 +1,6 @@
 # =========================================================================
 #     This makefile was generated by
-#     Bakefile 0.2.1 (http://bakefile.sourceforge.net)
+#     Bakefile 0.2.2 (http://bakefile.sourceforge.net)
 #     Do not modify, all changes will be overwritten!
 # =========================================================================
 
@@ -14,9 +14,10 @@ include ../../build/msw/config.gcc
 
 CPPDEPS = -MT$@ -MF$@.d -MD
 WX_RELEASE_NODOT = 29
+COMPILER_PREFIX = gcc
 OBJS = \
-	gcc_$(PORTNAME)$(WXUNIVNAME)$(WXUNICODEFLAG)$(WXDEBUGFLAG)$(WXDLLFLAG)$(CFG)
-LIBDIRNAME = .\..\..\lib\gcc_$(LIBTYPE_SUFFIX)$(CFG)
+	$(COMPILER_PREFIX)_$(PORTNAME)$(WXUNIVNAME)$(WXUNICODEFLAG)$(WXDEBUGFLAG)$(WXDLLFLAG)$(CFG)
+LIBDIRNAME = .\..\..\lib\$(COMPILER_PREFIX)_$(LIBTYPE_SUFFIX)$(CFG)
 SETUPHDIR = \
 	$(LIBDIRNAME)\$(PORTNAME)$(WXUNIVNAME)$(WXUNICODEFLAG)$(WXDEBUGFLAG)
 WIDGETS_CXXFLAGS = $(__DEBUGINFO) $(__OPTIMIZEFLAG_2) $(__THREADSFLAG) \
@@ -30,6 +31,7 @@ WIDGETS_OBJECTS =  \
 	$(OBJS)\widgets_bmpcombobox.o \
 	$(OBJS)\widgets_button.o \
 	$(OBJS)\widgets_checkbox.o \
+	$(OBJS)\widgets_choice.o \
 	$(OBJS)\widgets_clrpicker.o \
 	$(OBJS)\widgets_combobox.o \
 	$(OBJS)\widgets_datepick.o \
@@ -39,6 +41,7 @@ WIDGETS_OBJECTS =  \
 	$(OBJS)\widgets_fontpicker.o \
 	$(OBJS)\widgets_gauge.o \
 	$(OBJS)\widgets_hyperlnk.o \
+	$(OBJS)\widgets_itemcontainer.o \
 	$(OBJS)\widgets_listbox.o \
 	$(OBJS)\widgets_notebook.o \
 	$(OBJS)\widgets_odcombobox.o \
@@ -262,6 +265,9 @@ $(OBJS)\widgets_button.o: ./button.cpp
 $(OBJS)\widgets_checkbox.o: ./checkbox.cpp
 	$(CXX) -c -o $@ $(WIDGETS_CXXFLAGS) $(CPPDEPS) $<
 
+$(OBJS)\widgets_choice.o: ./choice.cpp
+	$(CXX) -c -o $@ $(WIDGETS_CXXFLAGS) $(CPPDEPS) $<
+
 $(OBJS)\widgets_clrpicker.o: ./clrpicker.cpp
 	$(CXX) -c -o $@ $(WIDGETS_CXXFLAGS) $(CPPDEPS) $<
 
@@ -289,6 +295,9 @@ $(OBJS)\widgets_gauge.o: ./gauge.cpp
 $(OBJS)\widgets_hyperlnk.o: ./hyperlnk.cpp
 	$(CXX) -c -o $@ $(WIDGETS_CXXFLAGS) $(CPPDEPS) $<
 
+$(OBJS)\widgets_itemcontainer.o: ./itemcontainer.cpp
+	$(CXX) -c -o $@ $(WIDGETS_CXXFLAGS) $(CPPDEPS) $<
+
 $(OBJS)\widgets_listbox.o: ./listbox.cpp
 	$(CXX) -c -o $@ $(WIDGETS_CXXFLAGS) $(CPPDEPS) $<
 
@@ -323,7 +332,7 @@ $(OBJS)\widgets_widgets.o: ./widgets.cpp
 	$(CXX) -c -o $@ $(WIDGETS_CXXFLAGS) $(CPPDEPS) $<
 
 $(OBJS)\widgets_sample_rc.o: ./../sample.rc
-	windres --use-temp-file -i$< -o$@   --define __WXMSW__ $(__WXUNIV_DEFINE_p_1) $(__DEBUG_DEFINE_p_1) $(__EXCEPTIONS_DEFINE_p_1) $(__RTTI_DEFINE_p_1) $(__THREAD_DEFINE_p_1) $(__UNICODE_DEFINE_p_1) $(__MSLU_DEFINE_p_1) $(__GFXCTX_DEFINE_p_1) --include-dir $(SETUPHDIR) --include-dir ./../../include --include-dir . $(__DLLFLAG_p_1) --include-dir ./../../samples --define NOPCH
+	windres --use-temp-file -i$< -o$@    --define __WXMSW__ $(__WXUNIV_DEFINE_p_1) $(__DEBUG_DEFINE_p_1) $(__EXCEPTIONS_DEFINE_p_1) $(__RTTI_DEFINE_p_1) $(__THREAD_DEFINE_p_1) $(__UNICODE_DEFINE_p_1) $(__MSLU_DEFINE_p_1) $(__GFXCTX_DEFINE_p_1) --include-dir $(SETUPHDIR) --include-dir ./../../include --include-dir . $(__DLLFLAG_p_1) --include-dir ./../../samples --define NOPCH
 
 .PHONY: all clean
 
diff --git a/samples/widgets/makefile.unx b/samples/widgets/makefile.unx
index 5d1572e1b2..5a2096c8d0 100644
--- a/samples/widgets/makefile.unx
+++ b/samples/widgets/makefile.unx
@@ -1,6 +1,6 @@
 # =========================================================================
 #     This makefile was generated by
-#     Bakefile 0.2.1 (http://bakefile.sourceforge.net)
+#     Bakefile 0.2.2 (http://bakefile.sourceforge.net)
 #     Do not modify, all changes will be overwritten!
 # =========================================================================
 
@@ -11,34 +11,34 @@
 # -------------------------------------------------------------------------
 
 # C++ compiler 
-CXX = g++
+CXX := g++
 
 # Standard flags for C++ 
-CXXFLAGS = 
+CXXFLAGS := 
 
 # Standard preprocessor flags (common for CC and CXX) 
-CPPFLAGS = 
+CPPFLAGS := 
 
 # Standard linker flags 
-LDFLAGS = 
+LDFLAGS := 
 
 # Location and arguments of wx-config script 
-WX_CONFIG = wx-config
+WX_CONFIG := wx-config
 
-# Port of the wx library to build against [gtk1,gtk2,msw,x11,motif,mgl,mac,$(shell $(WX_CONFIG) --selected-config | cut -d '-' -f 1)]
-WX_PORT = $(shell $(WX_CONFIG) --selected-config | cut -d '-' -f 1)
+# Port of the wx library to build against [gtk1,gtk2,msw,x11,motif,mgl,mac,dfb]
+WX_PORT := $(shell $(WX_CONFIG) --selected-config | cut -d '-' -f 1)
 
-# Use DLL build of wx library to use? [0,1,$(shell if test -z `$(WX_CONFIG) --selected-config | cut -d '-' -f 5`; then echo 1; else echo 0; fi)]
-WX_SHARED = $(shell if test -z `$(WX_CONFIG) --selected-config | cut -d '-' -f 5`; then echo 1; else echo 0; fi)
+# Use DLL build of wx library to use? [0,1]
+WX_SHARED := $(shell if test -z `$(WX_CONFIG) --selected-config | cut -d '-' -f 5`; then echo 1; else echo 0; fi)
 
-# Compile Unicode build of wxWidgets? [0,1,$(shell $(WX_CONFIG) --selected-config | cut -d '-' -f 2 | sed 's/unicode/1/;s/ansi/0/')]
-WX_UNICODE = $(shell $(WX_CONFIG) --selected-config | cut -d '-' -f 2 | sed 's/unicode/1/;s/ansi/0/')
+# Compile Unicode build of wxWidgets? [0,1]
+WX_UNICODE := $(shell $(WX_CONFIG) --selected-config | cut -d '-' -f 2 | sed 's/unicode/1/;s/ansi/0/')
 
-# Use debug build of wxWidgets (define __WXDEBUG__)? [0,1,$(shell $(WX_CONFIG) --selected-config | cut -d '-' -f 3 | sed 's/debug/1/;s/release/0/')]
-WX_DEBUG = $(shell $(WX_CONFIG) --selected-config | cut -d '-' -f 3 | sed 's/debug/1/;s/release/0/')
+# Use debug build of wxWidgets (define __WXDEBUG__)? [0,1]
+WX_DEBUG := $(shell $(WX_CONFIG) --selected-config | cut -d '-' -f 3 | sed 's/debug/1/;s/release/0/')
 
 # Version of the wx library to build against. 
-WX_VERSION = $(shell $(WX_CONFIG) --selected-config | sed -e 's/.*-\([0-9]*\)\.\([0-9]*\)$$/\1\2/')
+WX_VERSION := $(shell $(WX_CONFIG) --selected-config | sed -e 's/.*-\([0-9]*\)\.\([0-9]*\)$$/\1\2/')
 
 
 
@@ -60,6 +60,7 @@ WIDGETS_OBJECTS =  \
 	widgets_bmpcombobox.o \
 	widgets_button.o \
 	widgets_checkbox.o \
+	widgets_choice.o \
 	widgets_clrpicker.o \
 	widgets_combobox.o \
 	widgets_datepick.o \
@@ -69,6 +70,7 @@ WIDGETS_OBJECTS =  \
 	widgets_fontpicker.o \
 	widgets_gauge.o \
 	widgets_hyperlnk.o \
+	widgets_itemcontainer.o \
 	widgets_listbox.o \
 	widgets_notebook.o \
 	widgets_odcombobox.o \
@@ -131,6 +133,9 @@ widgets_button.o: ./button.cpp
 widgets_checkbox.o: ./checkbox.cpp
 	$(CXX) -c -o $@ $(WIDGETS_CXXFLAGS) $(CPPDEPS) $<
 
+widgets_choice.o: ./choice.cpp
+	$(CXX) -c -o $@ $(WIDGETS_CXXFLAGS) $(CPPDEPS) $<
+
 widgets_clrpicker.o: ./clrpicker.cpp
 	$(CXX) -c -o $@ $(WIDGETS_CXXFLAGS) $(CPPDEPS) $<
 
@@ -158,6 +163,9 @@ widgets_gauge.o: ./gauge.cpp
 widgets_hyperlnk.o: ./hyperlnk.cpp
 	$(CXX) -c -o $@ $(WIDGETS_CXXFLAGS) $(CPPDEPS) $<
 
+widgets_itemcontainer.o: ./itemcontainer.cpp
+	$(CXX) -c -o $@ $(WIDGETS_CXXFLAGS) $(CPPDEPS) $<
+
 widgets_listbox.o: ./listbox.cpp
 	$(CXX) -c -o $@ $(WIDGETS_CXXFLAGS) $(CPPDEPS) $<
 
diff --git a/samples/widgets/makefile.vc b/samples/widgets/makefile.vc
index c16d810af5..bebfdcf199 100644
--- a/samples/widgets/makefile.vc
+++ b/samples/widgets/makefile.vc
@@ -1,6 +1,6 @@
 # =========================================================================
 #     This makefile was generated by
-#     Bakefile 0.2.1 (http://bakefile.sourceforge.net)
+#     Bakefile 0.2.2 (http://bakefile.sourceforge.net)
 #     Do not modify, all changes will be overwritten!
 # =========================================================================
 
@@ -13,9 +13,11 @@
 ### Variables: ###
 
 WX_RELEASE_NODOT = 29
+COMPILER_PREFIX = vc
 OBJS = \
-	vc_$(PORTNAME)$(WXUNIVNAME)$(WXUNICODEFLAG)$(WXDEBUGFLAG)$(WXDLLFLAG)$(CFG)$(DIR_SUFFIX_CPU)
-LIBDIRNAME = .\..\..\lib\vc$(DIR_SUFFIX_CPU)_$(LIBTYPE_SUFFIX)$(CFG)
+	$(COMPILER_PREFIX)_$(PORTNAME)$(WXUNIVNAME)$(WXUNICODEFLAG)$(WXDEBUGFLAG)$(WXDLLFLAG)$(CFG)$(DIR_SUFFIX_CPU)
+LIBDIRNAME = \
+	.\..\..\lib\$(COMPILER_PREFIX)$(DIR_SUFFIX_CPU)_$(LIBTYPE_SUFFIX)$(CFG)
 SETUPHDIR = \
 	$(LIBDIRNAME)\$(PORTNAME)$(WXUNIVNAME)$(WXUNICODEFLAG)$(WXDEBUGFLAG)
 WIDGETS_CXXFLAGS = /M$(__RUNTIME_LIBS_8)$(__DEBUGRUNTIME_3) /DWIN32 \
@@ -30,6 +32,7 @@ WIDGETS_OBJECTS =  \
 	$(OBJS)\widgets_bmpcombobox.obj \
 	$(OBJS)\widgets_button.obj \
 	$(OBJS)\widgets_checkbox.obj \
+	$(OBJS)\widgets_choice.obj \
 	$(OBJS)\widgets_clrpicker.obj \
 	$(OBJS)\widgets_combobox.obj \
 	$(OBJS)\widgets_datepick.obj \
@@ -39,6 +42,7 @@ WIDGETS_OBJECTS =  \
 	$(OBJS)\widgets_fontpicker.obj \
 	$(OBJS)\widgets_gauge.obj \
 	$(OBJS)\widgets_hyperlnk.obj \
+	$(OBJS)\widgets_itemcontainer.obj \
 	$(OBJS)\widgets_listbox.obj \
 	$(OBJS)\widgets_notebook.obj \
 	$(OBJS)\widgets_odcombobox.obj \
@@ -344,6 +348,9 @@ $(OBJS)\widgets_button.obj: .\button.cpp
 $(OBJS)\widgets_checkbox.obj: .\checkbox.cpp
 	$(CXX) /c /nologo /TP /Fo$@ $(WIDGETS_CXXFLAGS) $**
 
+$(OBJS)\widgets_choice.obj: .\choice.cpp
+	$(CXX) /c /nologo /TP /Fo$@ $(WIDGETS_CXXFLAGS) $**
+
 $(OBJS)\widgets_clrpicker.obj: .\clrpicker.cpp
 	$(CXX) /c /nologo /TP /Fo$@ $(WIDGETS_CXXFLAGS) $**
 
@@ -371,6 +378,9 @@ $(OBJS)\widgets_gauge.obj: .\gauge.cpp
 $(OBJS)\widgets_hyperlnk.obj: .\hyperlnk.cpp
 	$(CXX) /c /nologo /TP /Fo$@ $(WIDGETS_CXXFLAGS) $**
 
+$(OBJS)\widgets_itemcontainer.obj: .\itemcontainer.cpp
+	$(CXX) /c /nologo /TP /Fo$@ $(WIDGETS_CXXFLAGS) $**
+
 $(OBJS)\widgets_listbox.obj: .\listbox.cpp
 	$(CXX) /c /nologo /TP /Fo$@ $(WIDGETS_CXXFLAGS) $**
 
diff --git a/samples/widgets/makefile.wat b/samples/widgets/makefile.wat
index 1c54cf7930..189195cd06 100644
--- a/samples/widgets/makefile.wat
+++ b/samples/widgets/makefile.wat
@@ -1,6 +1,6 @@
 # =========================================================================
 #     This makefile was generated by
-#     Bakefile 0.2.1 (http://bakefile.sourceforge.net)
+#     Bakefile 0.2.2 (http://bakefile.sourceforge.net)
 #     Do not modify, all changes will be overwritten!
 # =========================================================================
 
@@ -225,9 +225,10 @@ __DLLFLAG_p = -dWXUSINGDLL
 ### Variables: ###
 
 WX_RELEASE_NODOT = 29
+COMPILER_PREFIX = wat
 OBJS = &
-	wat_$(PORTNAME)$(WXUNIVNAME)$(WXUNICODEFLAG)$(WXDEBUGFLAG)$(WXDLLFLAG)$(CFG)
-LIBDIRNAME = .\..\..\lib\wat_$(LIBTYPE_SUFFIX)$(CFG)
+	$(COMPILER_PREFIX)_$(PORTNAME)$(WXUNIVNAME)$(WXUNICODEFLAG)$(WXDEBUGFLAG)$(WXDLLFLAG)$(CFG)
+LIBDIRNAME = .\..\..\lib\$(COMPILER_PREFIX)_$(LIBTYPE_SUFFIX)$(CFG)
 SETUPHDIR = &
 	$(LIBDIRNAME)\$(PORTNAME)$(WXUNIVNAME)$(WXUNICODEFLAG)$(WXDEBUGFLAG)
 WIDGETS_CXXFLAGS = $(__DEBUGINFO_0) $(__OPTIMIZEFLAG_2) $(__THREADSFLAG_5) &
@@ -241,6 +242,7 @@ WIDGETS_OBJECTS =  &
 	$(OBJS)\widgets_bmpcombobox.obj &
 	$(OBJS)\widgets_button.obj &
 	$(OBJS)\widgets_checkbox.obj &
+	$(OBJS)\widgets_choice.obj &
 	$(OBJS)\widgets_clrpicker.obj &
 	$(OBJS)\widgets_combobox.obj &
 	$(OBJS)\widgets_datepick.obj &
@@ -250,6 +252,7 @@ WIDGETS_OBJECTS =  &
 	$(OBJS)\widgets_fontpicker.obj &
 	$(OBJS)\widgets_gauge.obj &
 	$(OBJS)\widgets_hyperlnk.obj &
+	$(OBJS)\widgets_itemcontainer.obj &
 	$(OBJS)\widgets_listbox.obj &
 	$(OBJS)\widgets_notebook.obj &
 	$(OBJS)\widgets_odcombobox.obj &
@@ -300,6 +303,9 @@ $(OBJS)\widgets_button.obj :  .AUTODEPEND .\button.cpp
 $(OBJS)\widgets_checkbox.obj :  .AUTODEPEND .\checkbox.cpp
 	$(CXX) -bt=nt -zq -fo=$^@ $(WIDGETS_CXXFLAGS) $<
 
+$(OBJS)\widgets_choice.obj :  .AUTODEPEND .\choice.cpp
+	$(CXX) -bt=nt -zq -fo=$^@ $(WIDGETS_CXXFLAGS) $<
+
 $(OBJS)\widgets_clrpicker.obj :  .AUTODEPEND .\clrpicker.cpp
 	$(CXX) -bt=nt -zq -fo=$^@ $(WIDGETS_CXXFLAGS) $<
 
@@ -327,6 +333,9 @@ $(OBJS)\widgets_gauge.obj :  .AUTODEPEND .\gauge.cpp
 $(OBJS)\widgets_hyperlnk.obj :  .AUTODEPEND .\hyperlnk.cpp
 	$(CXX) -bt=nt -zq -fo=$^@ $(WIDGETS_CXXFLAGS) $<
 
+$(OBJS)\widgets_itemcontainer.obj :  .AUTODEPEND .\itemcontainer.cpp
+	$(CXX) -bt=nt -zq -fo=$^@ $(WIDGETS_CXXFLAGS) $<
+
 $(OBJS)\widgets_listbox.obj :  .AUTODEPEND .\listbox.cpp
 	$(CXX) -bt=nt -zq -fo=$^@ $(WIDGETS_CXXFLAGS) $<
 
@@ -361,5 +370,5 @@ $(OBJS)\widgets_widgets.obj :  .AUTODEPEND .\widgets.cpp
 	$(CXX) -bt=nt -zq -fo=$^@ $(WIDGETS_CXXFLAGS) $<
 
 $(OBJS)\widgets_sample.res :  .AUTODEPEND .\..\sample.rc
-	wrc -q -ad -bt=nt -r -fo=$^@   -d__WXMSW__ $(__WXUNIV_DEFINE_p) $(__DEBUG_DEFINE_p) $(__EXCEPTIONS_DEFINE_p) $(__RTTI_DEFINE_p) $(__THREAD_DEFINE_p) $(__UNICODE_DEFINE_p)  $(__GFXCTX_DEFINE_p) -i=$(SETUPHDIR) -i=.\..\..\include -i=. $(__DLLFLAG_p) -i=.\..\..\samples -dNOPCH $<
+	wrc -q -ad -bt=nt -r -fo=$^@    -d__WXMSW__ $(__WXUNIV_DEFINE_p) $(__DEBUG_DEFINE_p) $(__EXCEPTIONS_DEFINE_p) $(__RTTI_DEFINE_p) $(__THREAD_DEFINE_p) $(__UNICODE_DEFINE_p)  $(__GFXCTX_DEFINE_p) -i=$(SETUPHDIR) -i=.\..\..\include -i=. $(__DLLFLAG_p) -i=.\..\..\samples -dNOPCH $<
 
diff --git a/samples/widgets/odcombobox.cpp b/samples/widgets/odcombobox.cpp
index a20d439a43..b5201e3e3f 100644
--- a/samples/widgets/odcombobox.cpp
+++ b/samples/widgets/odcombobox.cpp
@@ -45,6 +45,7 @@
 #include "wx/odcombo.h"
 
 
+#include "itemcontainer.h"
 #include "widgets.h"
 
 #include "icons/odcombobox.xpm"
@@ -76,7 +77,8 @@ enum
     ODComboPage_Delete,
     ODComboPage_DeleteText,
     ODComboPage_DeleteSel,
-    ODComboPage_Combo
+    ODComboPage_Combo,
+    ODComboPage_ContainerTests
 };
 
 
@@ -84,12 +86,13 @@ enum
 // ODComboboxWidgetsPage
 // ----------------------------------------------------------------------------
 
-class ODComboboxWidgetsPage : public WidgetsPage
+class ODComboboxWidgetsPage : public ItemContainerWidgetsPage
 {
 public:
     ODComboboxWidgetsPage(WidgetsBookCtrl *book, wxImageList *imaglist);
 
     virtual wxControl *GetWidget() const { return m_combobox; }
+    virtual wxItemContainer* GetContainer() const { return m_combobox; }
     virtual void RecreateWidget() { CreateCombo(); }
 
     // lazy creation of the content
@@ -188,6 +191,7 @@ BEGIN_EVENT_TABLE(ODComboboxWidgetsPage, WidgetsPage)
     EVT_BUTTON(ODComboPage_Add, ODComboboxWidgetsPage::OnButtonAdd)
     EVT_BUTTON(ODComboPage_AddSeveral, ODComboboxWidgetsPage::OnButtonAddSeveral)
     EVT_BUTTON(ODComboPage_AddMany, ODComboboxWidgetsPage::OnButtonAddMany)
+    EVT_BUTTON(ODComboPage_ContainerTests, ItemContainerWidgetsPage::OnButtonTestItemContainer)
 
     EVT_TEXT_ENTER(ODComboPage_InsertText, ODComboboxWidgetsPage::OnButtonInsert)
     EVT_TEXT_ENTER(ODComboPage_AddText, ODComboboxWidgetsPage::OnButtonAdd)
@@ -296,7 +300,7 @@ IMPLEMENT_WIDGETS_PAGE(ODComboboxWidgetsPage, _T("OwnerDrawnCombobox"),
 
 ODComboboxWidgetsPage::ODComboboxWidgetsPage(WidgetsBookCtrl *book,
                                              wxImageList *imaglist)
-                  : WidgetsPage(book, imaglist, odcombobox_xpm)
+                  : ItemContainerWidgetsPage(book, imaglist, odcombobox_xpm)
 {
     // init everything
     m_chkSort =
@@ -394,6 +398,9 @@ void ODComboboxWidgetsPage::CreateContent()
         _T("&Change combobox contents"));
     wxSizer *sizerMiddle = new wxStaticBoxSizer(box2, wxVERTICAL);
 
+    btn = new wxButton(this, ODComboPage_ContainerTests, _T("Run &tests"));
+    sizerMiddle->Add(btn, 0, wxALL | wxGROW, 5);
+
     sizerRow = CreateSizerWithTextAndLabel(_T("Current selection"),
                                            ODComboPage_CurText,
                                            &text);
diff --git a/samples/widgets/widgets.bkl b/samples/widgets/widgets.bkl
index 2d1768b779..229fa20740 100644
--- a/samples/widgets/widgets.bkl
+++ b/samples/widgets/widgets.bkl
@@ -9,6 +9,7 @@
             bmpcombobox.cpp
             button.cpp
             checkbox.cpp
+            choice.cpp
             clrpicker.cpp
             combobox.cpp
             datepick.cpp
@@ -18,6 +19,7 @@
             fontpicker.cpp
             gauge.cpp
             hyperlnk.cpp
+            itemcontainer.cpp
             listbox.cpp
             notebook.cpp
             odcombobox.cpp
diff --git a/samples/widgets/widgets.dsp b/samples/widgets/widgets.dsp
index 3d309eb1e3..77a805177c 100644
--- a/samples/widgets/widgets.dsp
+++ b/samples/widgets/widgets.dsp
@@ -480,6 +480,10 @@ SOURCE=.\checkbox.cpp
 # End Source File
 # Begin Source File
 
+SOURCE=.\choice.cpp
+# End Source File
+# Begin Source File
+
 SOURCE=.\clrpicker.cpp
 # End Source File
 # Begin Source File
@@ -516,6 +520,10 @@ SOURCE=.\hyperlnk.cpp
 # End Source File
 # Begin Source File
 
+SOURCE=.\itemcontainer.cpp
+# End Source File
+# Begin Source File
+
 SOURCE=.\listbox.cpp
 # End Source File
 # Begin Source File
diff --git a/src/cocoa/choice.mm b/src/cocoa/choice.mm
index 0da0563835..dbc2ce597f 100644
--- a/src/cocoa/choice.mm
+++ b/src/cocoa/choice.mm
@@ -108,16 +108,7 @@ wxChoice::~wxChoice()
 {
     DisassociateNSMenu([(NSPopUpButton*)m_cocoaNSView menu]);
 
-    if(m_sortedStrings)
-        m_sortedStrings->Clear();
-    delete m_sortedStrings;
-
-    if(HasClientObjectData())
-    {
-        for(unsigned int i=0; i < m_itemsClientData.GetCount(); i++)
-            delete (wxClientData*)m_itemsClientData.Item(i);
-    }
-    m_itemsClientData.Clear();
+    Clear();
 }
 
 void wxChoice::CocoaNotification_menuDidSendAction(WX_NSNotification notification)
@@ -134,25 +125,18 @@ void wxChoice::CocoaNotification_menuDidSendAction(WX_NSNotification notificatio
     GetEventHandler()->ProcessEvent(event);
 }
 
-void wxChoice::Clear()
+void wxChoice::DoClear()
 {
     if(m_sortedStrings)
         m_sortedStrings->Clear();
-    if(HasClientObjectData())
-    {
-        for(unsigned int i=0; i < m_itemsClientData.GetCount(); i++)
-            delete (wxClientData*)m_itemsClientData.Item(i);
-    }
     m_itemsClientData.Clear();
     [(NSPopUpButton*)m_cocoaNSView removeAllItems];
 }
 
-void wxChoice::Delete(unsigned int n)
+void wxChoice::DoDeleteOneItem(unsigned int n)
 {
     if(m_sortedStrings)
         m_sortedStrings->RemoveAt(n);
-    if(HasClientObjectData())
-        delete (wxClientData*)m_itemsClientData.Item(n);
     m_itemsClientData.RemoveAt(n);
     [(NSPopUpButton*)m_cocoaNSView removeItemAtIndex:n];
 }
@@ -186,57 +170,35 @@ int wxChoice::GetSelection() const
     return [(NSPopUpButton*)m_cocoaNSView indexOfSelectedItem];
 }
 
-int wxChoice::DoAppend(const wxString& title)
+int wxChoice::DoInsertItems(const wxArrayStringsAdapter & items,
+                            unsigned int pos,
+                            void **clientData, wxClientDataType type)
 {
-    wxAutoNSAutoreleasePool pool;
     NSMenu *nsmenu = [(NSPopUpButton*)m_cocoaNSView menu];
-    NSMenuItem *item;
-    if(m_sortedStrings)
-    {
-        int sortedIndex = m_sortedStrings->Add(title);
-        item = [nsmenu insertItemWithTitle:
-                wxNSStringWithWxString(title)
-            action: nil keyEquivalent:@"" atIndex:sortedIndex];
-        m_itemsClientData.Insert(NULL, sortedIndex);
-    }
-    else
+    NSMenuItem *item = NULL;
+
+    unsigned int numItems = items.GetCount();
+    for ( unsigned int i = 0; i < numItems; ++i, ++pos )
     {
-        item = [nsmenu addItemWithTitle:wxNSStringWithWxString(title)
-            action: nil keyEquivalent:@""];
-        m_itemsClientData.Add(NULL);
-    }
-    return [nsmenu indexOfItem:item];
-}
+        const wxString& str = items[i];
+        int idx = m_sortedStrings ? m_sortedStrings->Add(str) : pos;
 
-int wxChoice::DoInsert(const wxString& title, unsigned int pos)
-{
-    if(m_sortedStrings)
-        return DoAppend(title);
-    NSMenu *nsmenu = [(NSPopUpButton*)m_cocoaNSView menu];
-    NSMenuItem *item = [nsmenu insertItemWithTitle:wxNSStringWithWxString(title)
-        action: nil keyEquivalent:@"" atIndex:pos];
-    m_itemsClientData.Insert(NULL, pos);
+        item = [nsmenu insertItemWithTitle:wxNSStringWithWxString(str)
+            action: nil keyEquivalent:@"" atIndex:idx];
+        m_itemsClientData.Insert(NULL, idx);
+        AssignNewItemClientData(idx, clientData, i, type);
+    }
     return [nsmenu indexOfItem:item];
 }
 
 void wxChoice::DoSetItemClientData(unsigned int n, void *data)
 {
-    m_itemsClientData.Item(n) = data;
+    m_itemsClientData[n] = data;
 }
 
 void* wxChoice::DoGetItemClientData(unsigned int n) const
 {
-    return m_itemsClientData.Item(n);
-}
-
-void wxChoice::DoSetItemClientObject(unsigned int n, wxClientData *data)
-{
-    m_itemsClientData.Item(n) = data;
-}
-
-wxClientData* wxChoice::DoGetItemClientObject(unsigned int n) const
-{
-    return (wxClientData*)m_itemsClientData.Item(n);
+    return m_itemsClientData[n];
 }
 
 void wxChoice::SetSelection(int n)
@@ -245,4 +207,4 @@ void wxChoice::SetSelection(int n)
     [(NSPopUpButton*)m_cocoaNSView selectItemAtIndex:n];
 }
 
-#endif
+#endif // wxUSE_CHOICE
diff --git a/src/cocoa/combobox.mm b/src/cocoa/combobox.mm
index 4e016fb200..041fd382c5 100644
--- a/src/cocoa/combobox.mm
+++ b/src/cocoa/combobox.mm
@@ -206,8 +206,7 @@ bool wxComboBox::Create(wxWindow *parent, wxWindowID winid,
         m_parent->CocoaAddChild(this);
     SetInitialFrameRect(pos,size);
 
-    for(int i = 0; i < n; ++i)
-        wxComboBox::DoAppend(choices[i]);
+    wxComboBox::Append(n, choices);
 
     [GetNSComboBox() setCompletes:true]; //autocomplete :)
 
@@ -246,13 +245,13 @@ wxString wxComboBox::GetStringSelection()
     return wxStringWithNSString([GetNSComboBox() objectValueOfSelectedItem]);
 }
 
-void wxComboBox::Clear()
+void wxComboBox::DoClear()
 {
     [GetNSComboBox() removeAllItems];
     m_Datas.Clear();
 }
 
-void wxComboBox::Delete(unsigned int n)
+void wxComboBox::DoDeleteOneItem(unsigned int n)
 {
     [GetNSComboBox() removeItemAtIndex:n];
     m_Datas.RemoveAt(n);
@@ -288,20 +287,20 @@ int wxComboBox::GetSelection() const
     return [GetNSComboBox() indexOfSelectedItem];
 }
 
-int wxComboBox::DoAppend(const wxString& szItem)
+int wxComboBox::DoInsertItems(const wxArrayStringsAdapter& items,
+                              unsigned int pos,
+                              void **clientData,
+                              wxClientDataType type)
 {
-    m_Datas.Add(NULL);
     wxAutoNSAutoreleasePool pool;
-    [GetNSComboBox() addItemWithObjectValue:wxNSStringWithWxString(szItem)];
-    return [GetNSComboBox() numberOfItems];
-}
-
-int wxComboBox::DoInsert(const wxString& szItem, unsigned int nIndex)
-{
-    m_Datas.Insert(NULL, nIndex);
-    wxAutoNSAutoreleasePool pool;
-    [GetNSComboBox() insertItemWithObjectValue:wxNSStringWithWxString(szItem) atIndex:nIndex];
-    return (int)nIndex;
+    const unsigned int numITems = items.GetCount();
+    for ( unsigned int i = 0; i < numITems; ++i, ++pos )
+    {
+        [GetNSComboBox() insertItemWithObjectValue:wxNSStringWithWxString(items[i]) atIndex:(pos)];
+        m_Datas.Insert(NULL, pos);
+        AssignNewItemClientData(pos, clientData, i, type);
+    }
+    return pos - 1;
 }
 
 void wxComboBox::DoSetItemClientData(unsigned int nIndex, void* pData)
@@ -314,14 +313,4 @@ void* wxComboBox::DoGetItemClientData(unsigned int nIndex) const
     return m_Datas[nIndex];
 }
 
-void wxComboBox::DoSetItemClientObject(unsigned int nIndex, wxClientData* pClientData)
-{
-    m_Datas[nIndex] = (void*) pClientData;
-}
-
-wxClientData* wxComboBox::DoGetItemClientObject(unsigned int nIndex) const
-{
-    return (wxClientData*) m_Datas[nIndex];
-}
-
-#endif //wxUSE_COMBOBOX
+#endif // wxUSE_COMBOBOX
diff --git a/src/cocoa/listbox.mm b/src/cocoa/listbox.mm
index c24e9b9439..1b9a228a34 100644
--- a/src/cocoa/listbox.mm
+++ b/src/cocoa/listbox.mm
@@ -169,33 +169,21 @@ int wxListBox::GetSelections(wxArrayInt& aSelections) const
     return [GetNSTableView() numberOfSelectedRows];
 }
 
-void wxListBox::DoInsertItems(const wxArrayString& items, unsigned int pos)
+int wxListBox::DoInsertItems(const wxArrayStringsAdapter & items, unsigned int pos, void **clientData, wxClientDataType type)
 {
     wxAutoNSAutoreleasePool pool;
 
-    for(int i=int(items.GetCount())-1; i >= 0; i--)
+    const unsigned int numItems = items.GetCount();
+    for ( unsigned int i = 0; i < numItems; ++i, ++pos )
     {
         [m_cocoaItems insertObject: wxNSStringWithWxString(items[i])
             atIndex: pos];
-        m_itemClientData.Insert(NULL,pos);
+        m_itemClientData.Insert(NULL, pos);
+        AssignNewItemClientData(pos, clientData, i, type);
     }
-    [GetNSTableView() reloadData];
-}
-
-void wxListBox::DoSetItems(const wxArrayString& items, void **clientData)
-{
-    wxAutoNSAutoreleasePool pool;
 
-    // Remove everything
-    [m_cocoaItems removeAllObjects];
-    m_itemClientData.Clear();
-    // Provide the data
-    for(unsigned int i=0; i < items.GetCount(); i++)
-    {
-        [m_cocoaItems addObject: wxNSStringWithWxString(items[i])];
-        m_itemClientData.Add(clientData[i]);
-    }
     [GetNSTableView() reloadData];
+    return pos - 1;
 }
 
 void wxListBox::DoSetFirstItem(int n)
@@ -210,14 +198,14 @@ void wxListBox::DoSetFirstItem(int n)
 
 // pure virtuals from wxItemContainer
     // deleting items
-void wxListBox::Clear()
+void wxListBox::DoClear()
 {
     [m_cocoaItems removeAllObjects];
     m_itemClientData.Clear();
     [GetNSTableView() reloadData];
 }
 
-void wxListBox::Delete(unsigned int n)
+void wxListBox::DoDeleteOneItem(unsigned int n)
 {
     [m_cocoaItems removeObjectAtIndex:n];
     m_itemClientData.RemoveAt(n);
@@ -256,15 +244,6 @@ int wxListBox::GetSelection() const
     return [GetNSTableView() selectedRow];
 }
 
-int wxListBox::DoAppend(const wxString& item)
-{
-    wxAutoNSAutoreleasePool pool;
-    [m_cocoaItems addObject:wxNSStringWithWxString(item)];
-    [GetNSTableView() reloadData];
-    m_itemClientData.Add(NULL);
-    return [m_cocoaItems count];
-}
-
 void wxListBox::DoSetItemClientData(unsigned int n, void* clientData)
 {
     m_itemClientData[n] = clientData;
@@ -275,14 +254,4 @@ void* wxListBox::DoGetItemClientData(unsigned int n) const
     return m_itemClientData[n];
 }
 
-void wxListBox::DoSetItemClientObject(unsigned int n, wxClientData* clientData)
-{
-    m_itemClientData[n] = (void*) clientData;
-}
-
-wxClientData* wxListBox::DoGetItemClientObject(unsigned int n) const
-{
-    return (wxClientData*) m_itemClientData[n];
-}
-
-#endif
+#endif // wxUSE_LISTBOX
diff --git a/src/common/ctrlsub.cpp b/src/common/ctrlsub.cpp
index c94e8f2ca3..ec05cae146 100644
--- a/src/common/ctrlsub.cpp
+++ b/src/common/ctrlsub.cpp
@@ -90,93 +90,175 @@ wxItemContainer::~wxItemContainer()
 }
 
 // ----------------------------------------------------------------------------
-// appending items
+// deleting items
 // ----------------------------------------------------------------------------
 
-void wxItemContainer::Append(const wxArrayString& strings)
+void wxItemContainer::Clear()
 {
-    const size_t count = strings.GetCount();
-    for ( size_t n = 0; n < count; n++ )
+    if ( HasClientObjectData() )
     {
-        Append(strings[n]);
+        const unsigned count = GetCount();
+        for ( unsigned i = 0; i < count; ++i )
+            ResetItemClientObject(i);
     }
+
+    m_clientDataItemsType = wxClientData_None;
+
+    DoClear();
 }
 
-int wxItemContainer::Insert(const wxString& item, unsigned int pos, void *clientData)
+void wxItemContainer::Delete(unsigned int pos)
 {
-    int n = DoInsert(item, pos);
-    if ( n != wxNOT_FOUND )
-        SetClientData(n, clientData);
+    wxCHECK_RET( pos < GetCount(), _T("invalid index") );
 
-    return n;
+    if ( HasClientObjectData() )
+        ResetItemClientObject(pos);
+
+    DoDeleteOneItem(pos);
+
+    if ( IsEmpty() )
+    {
+        m_clientDataItemsType = wxClientData_None;
+    }
 }
 
-int wxItemContainer::Insert(const wxString& item, unsigned int pos, wxClientData *clientData)
+// ----------------------------------------------------------------------------
+// 
+// ----------------------------------------------------------------------------
+
+int wxItemContainer::DoInsertItemsInLoop(const wxArrayStringsAdapter& items,
+                                         unsigned int pos,
+                                         void **clientData,
+                                         wxClientDataType type)
 {
-    int n = DoInsert(item, pos);
-    if ( n != wxNOT_FOUND )
-        SetClientObject(n, clientData);
+    int n = wxNOT_FOUND;
+
+    const unsigned int count = items.GetCount();
+    for ( unsigned int i = 0; i < count; ++i )
+    {
+        n = DoInsertOneItem(items[i], pos++);
+        if ( n == wxNOT_FOUND )
+            break;
+
+        AssignNewItemClientData(n, clientData, i, type);
+    }
 
     return n;
 }
 
+int
+wxItemContainer::DoInsertOneItem(const wxString& WXUNUSED(item),
+                                 unsigned int WXUNUSED(pos))
+{
+    wxFAIL_MSG( _T("Must be overridden if DoInsertItemsInLoop() is used") );
+
+    return wxNOT_FOUND;
+}
+
+
 // ----------------------------------------------------------------------------
 // client data
 // ----------------------------------------------------------------------------
 
 void wxItemContainer::SetClientObject(unsigned int n, wxClientData *data)
 {
-    wxASSERT_MSG( m_clientDataItemsType != wxClientData_Void,
+    wxASSERT_MSG( m_clientDataItemsType == wxClientData_Object ||
+                    m_clientDataItemsType == wxClientData_None,
                   wxT("can't have both object and void client data") );
 
-    // when we call SetClientObject() for the first time, m_clientDataItemsType
-    // is still wxClientData_None and so calling DoGetItemClientObject() would
-    // fail (in addition to being useless) - don't do it
     if ( m_clientDataItemsType == wxClientData_Object )
     {
-        wxClientData *clientDataOld = DoGetItemClientObject(n);
+        wxClientData * clientDataOld
+            = wx_static_cast(wxClientData *, DoGetItemClientData(n));
         if ( clientDataOld )
             delete clientDataOld;
     }
     else // m_clientDataItemsType == wxClientData_None
     {
         // now we have object client data
+        DoInitItemClientData();
+
         m_clientDataItemsType = wxClientData_Object;
     }
 
-    DoSetItemClientObject(n, data);
+    DoSetItemClientData(n, data);
 }
 
 wxClientData *wxItemContainer::GetClientObject(unsigned int n) const
 {
-    wxASSERT_MSG( m_clientDataItemsType == wxClientData_Object,
+    wxCHECK_MSG( m_clientDataItemsType == wxClientData_Object, NULL,
                   wxT("this window doesn't have object client data") );
 
-    return DoGetItemClientObject(n);
+    return wx_static_cast(wxClientData *, DoGetItemClientData(n));
 }
 
 void wxItemContainer::SetClientData(unsigned int n, void *data)
 {
-    wxASSERT_MSG( m_clientDataItemsType != wxClientData_Object,
+    if ( m_clientDataItemsType == wxClientData_None )
+    {
+        DoInitItemClientData();
+        m_clientDataItemsType = wxClientData_Void;
+    }
+
+    wxASSERT_MSG( m_clientDataItemsType == wxClientData_Void,
                   wxT("can't have both object and void client data") );
 
     DoSetItemClientData(n, data);
-    m_clientDataItemsType = wxClientData_Void;
 }
 
 void *wxItemContainer::GetClientData(unsigned int n) const
 {
-    wxASSERT_MSG( m_clientDataItemsType == wxClientData_Void,
+    wxCHECK_MSG( m_clientDataItemsType == wxClientData_Void, NULL,
                   wxT("this window doesn't have void client data") );
 
     return DoGetItemClientData(n);
 }
 
+void wxItemContainer::AssignNewItemClientData(unsigned int pos,
+                                              void **clientData,
+                                              unsigned int n,
+                                              wxClientDataType type)
+{
+    switch ( type )
+    {
+        case wxClientData_Object:
+            SetClientObject
+            (
+                pos,
+                (wx_reinterpret_cast(wxClientData **, clientData))[n]
+            );
+            break;
+
+        case wxClientData_Void:
+            SetClientData(pos, clientData[n]);
+            break;
+
+        default:
+            wxFAIL_MSG( _T("unknown client data type") );
+            // fall through
+
+        case wxClientData_None:
+            // nothing to do
+            break;
+    }
+}
+
+void wxItemContainer::ResetItemClientObject(unsigned int n)
+{
+    wxClientData * const data = GetClientObject(n);
+    if ( data )
+    {
+        delete data;
+        DoSetItemClientData(n, NULL);
+    }
+}
+
 // ============================================================================
 // wxControlWithItems implementation
 // ============================================================================
 
-void wxControlWithItems::InitCommandEventWithItems(wxCommandEvent& event, int n)
+void
+wxControlWithItemsBase::InitCommandEventWithItems(wxCommandEvent& event, int n)
 {
     InitCommandEvent(event);
 
@@ -189,9 +271,4 @@ void wxControlWithItems::InitCommandEventWithItems(wxCommandEvent& event, int n)
     }
 }
 
-wxControlWithItems::~wxControlWithItems()
-{
-    // this destructor is required for Darwin
-}
-
 #endif // wxUSE_CONTROLS
diff --git a/src/common/lboxcmn.cpp b/src/common/lboxcmn.cpp
index 218ba8a71a..2d764f33bf 100644
--- a/src/common/lboxcmn.cpp
+++ b/src/common/lboxcmn.cpp
@@ -42,33 +42,6 @@ wxListBoxBase::~wxListBoxBase()
     // this destructor is required for Darwin
 }
 
-// ----------------------------------------------------------------------------
-// adding items
-// ----------------------------------------------------------------------------
-
-void wxListBoxBase::InsertItems(unsigned int nItems, const wxString *items, unsigned int pos)
-{
-    wxArrayString aItems;
-    for ( unsigned int n = 0; n < nItems; n++ )
-    {
-        aItems.Add(items[n]);
-    }
-
-    DoInsertItems(aItems, pos);
-}
-
-
-void wxListBoxBase::Set(int nItems, const wxString* items, void **clientData)
-{
-    wxArrayString aItems;
-    for ( int n = 0; n < nItems; n++ )
-    {
-        aItems.Add(items[n]);
-    }
-
-    DoSetItems(aItems, clientData);
-}
-
 // ----------------------------------------------------------------------------
 // selection
 // ----------------------------------------------------------------------------
diff --git a/src/generic/bmpcboxg.cpp b/src/generic/bmpcboxg.cpp
index 6aec2b629e..a9b1eb0a3e 100644
--- a/src/generic/bmpcboxg.cpp
+++ b/src/generic/bmpcboxg.cpp
@@ -176,23 +176,86 @@ wxBitmap wxBitmapComboBox::GetItemBitmap(unsigned int n) const
     return *GetBitmapPtr(n);
 }
 
+int wxBitmapComboBox::DoInsertItems(const wxArrayStringsAdapter & items,
+                                    unsigned int pos,
+                                    void **clientData, wxClientDataType type)
+{
+    const unsigned int numItems = items.GetCount();
+    const unsigned int countNew = GetCount() + numItems;
+
+    m_bitmaps.Alloc(countNew);
+
+    for ( unsigned int i = 0; i < numItems; ++i )
+    {
+        m_bitmaps.Insert(new wxBitmap(wxNullBitmap), pos + i);
+    }
+
+    const int index = wxOwnerDrawnComboBox::DoInsertItems(items, pos,
+                                                          clientData, type);
+
+    if ( index == wxNOT_FOUND )
+    {
+        for ( int i = countNew - GetCount(); i > 0; --i )
+        {
+            wxBitmap *bmp = GetBitmapPtr(pos);
+            m_bitmaps.RemoveAt(pos);
+            delete bmp;
+        }
+    }
+    return index;
+}
+
+int wxBitmapComboBox::Append(const wxString& item, const wxBitmap& bitmap)
+{
+    const int n = wxOwnerDrawnComboBox::Append(item);
+    if(n != wxNOT_FOUND)
+        SetItemBitmap(n, bitmap);
+    return n;
+}
+
+int wxBitmapComboBox::Append(const wxString& item, const wxBitmap& bitmap,
+                             void *clientData)
+{
+    const int n = wxOwnerDrawnComboBox::Append(item, clientData);
+    if(n != wxNOT_FOUND)
+        SetItemBitmap(n, bitmap);
+    return n;
+}
+
+int wxBitmapComboBox::Append(const wxString& item, const wxBitmap& bitmap,
+                             wxClientData *clientData)
+{
+    const int n = wxOwnerDrawnComboBox::Append(item, clientData);
+    if(n != wxNOT_FOUND)
+        SetItemBitmap(n, bitmap);
+    return n;
+}
+
+int wxBitmapComboBox::Insert(const wxString& item,
+                             const wxBitmap& bitmap,
+                             unsigned int pos)
+{
+    const int n = wxOwnerDrawnComboBox::Insert(item, pos);
+    if(n != wxNOT_FOUND)
+        SetItemBitmap(n, bitmap);
+    return n;
+}
+
 int wxBitmapComboBox::Insert(const wxString& item, const wxBitmap& bitmap,
                              unsigned int pos, void *clientData)
 {
-    int n = DoInsertWithImage(item, bitmap, pos);
-    if ( n != wxNOT_FOUND )
-        SetClientData(n, clientData);
-
+    const int n = wxOwnerDrawnComboBox::Insert(item, pos, clientData);
+    if(n != wxNOT_FOUND)
+        SetItemBitmap(n, bitmap);
     return n;
 }
 
 int wxBitmapComboBox::Insert(const wxString& item, const wxBitmap& bitmap,
                              unsigned int pos, wxClientData *clientData)
 {
-    int n = DoInsertWithImage(item, bitmap, pos);
-    if ( n != wxNOT_FOUND )
-        SetClientObject(n, clientData);
-
+    const int n = wxOwnerDrawnComboBox::Insert(item, pos, clientData);
+    if(n != wxNOT_FOUND)
+        SetItemBitmap(n, bitmap);
     return n;
 }
 
@@ -227,67 +290,9 @@ bool wxBitmapComboBox::OnAddBitmap(const wxBitmap& bitmap)
     return true;
 }
 
-bool wxBitmapComboBox::DoInsertBitmap(const wxBitmap& bitmap, unsigned int pos)
-{
-    if ( !OnAddBitmap(bitmap) )
-        return false;
-
-    // NB: We must try to set the image before DoInsert or
-    //     DoAppend because OnMeasureItem might be called
-    //     before it returns.
-    m_bitmaps.Insert( new wxBitmap(bitmap), pos);
-
-    return true;
-}
-
-int wxBitmapComboBox::DoAppendWithImage(const wxString& item, const wxBitmap& image)
-{
-    unsigned int pos = m_bitmaps.size();
-
-    if ( !DoInsertBitmap(image, pos) )
-        return wxNOT_FOUND;
-
-    int index = wxOwnerDrawnComboBox::DoAppend(item);
-
-    if ( index < 0 )
-        index = m_bitmaps.size();
-
-    // Need to re-check the index incase DoAppend sorted
-    if ( (unsigned int) index != pos )
-    {
-        wxBitmap* bmp = GetBitmapPtr(pos);
-        m_bitmaps.RemoveAt(pos);
-        m_bitmaps.Insert(bmp, index);
-    }
-
-    return index;
-}
-
-int wxBitmapComboBox::DoInsertWithImage(const wxString& item,
-                                        const wxBitmap& image,
-                                        unsigned int pos)
-{
-    wxCHECK_MSG( IsValidInsert(pos), wxNOT_FOUND, wxT("invalid item index") );
-
-    if ( !DoInsertBitmap(image, pos) )
-        return wxNOT_FOUND;
-
-    return wxOwnerDrawnComboBox::DoInsert(item, pos);
-}
-
-int wxBitmapComboBox::DoAppend(const wxString& item)
-{
-    return DoAppendWithImage(item, wxNullBitmap);
-}
-
-int wxBitmapComboBox::DoInsert(const wxString& item, unsigned int pos)
-{
-    return DoInsertWithImage(item, wxNullBitmap, pos);
-}
-
-void wxBitmapComboBox::Clear()
+void wxBitmapComboBox::DoClear()
 {
-    wxOwnerDrawnComboBox::Clear();
+    wxOwnerDrawnComboBox::DoClear();
 
     unsigned int i;
 
@@ -302,9 +307,9 @@ void wxBitmapComboBox::Clear()
     DetermineIndent();
 }
 
-void wxBitmapComboBox::Delete(unsigned int n)
+void wxBitmapComboBox::DoDeleteOneItem(unsigned int n)
 {
-    wxOwnerDrawnComboBox::Delete(n);
+    wxOwnerDrawnComboBox::DoDeleteOneItem(n);
     delete GetBitmapPtr(n);
     m_bitmaps.RemoveAt(n);
 }
diff --git a/src/generic/htmllbox.cpp b/src/generic/htmllbox.cpp
index 22e2722cec..fb819ab3e6 100644
--- a/src/generic/htmllbox.cpp
+++ b/src/generic/htmllbox.cpp
@@ -562,19 +562,19 @@ bool wxSimpleHtmlListBox::Create(wxWindow *parent, wxWindowID id,
 #if wxUSE_VALIDATORS
     SetValidator(validator);
 #endif
-    for (int i=0; i<n; i++)
-        Append(choices[i]);
+
+    Append(n, choices);
 
     return true;
 }
 
 bool wxSimpleHtmlListBox::Create(wxWindow *parent, wxWindowID id,
-                                    const wxPoint& pos,
-                                    const wxSize& size,
-                                    const wxArrayString& choices,
-                                    long style,
-                                    const wxValidator& validator,
-                                    const wxString& name)
+                                 const wxPoint& pos,
+                                 const wxSize& size,
+                                 const wxArrayString& choices,
+                                 long style,
+                                 const wxValidator& validator,
+                                 const wxString& name)
 {
     if (!wxHtmlListBox::Create(parent, id, pos, size, style, name))
         return false;
@@ -582,6 +582,7 @@ bool wxSimpleHtmlListBox::Create(wxWindow *parent, wxWindowID id,
 #if wxUSE_VALIDATORS
     SetValidator(validator);
 #endif
+
     Append(choices);
 
     return true;
@@ -589,53 +590,46 @@ bool wxSimpleHtmlListBox::Create(wxWindow *parent, wxWindowID id,
 
 wxSimpleHtmlListBox::~wxSimpleHtmlListBox()
 {
-    wxASSERT(m_items.GetCount() == m_HTMLclientData.GetCount());
-    if (HasClientObjectData())
-    {
-        // clear the array of client data objects
-        for (size_t i=0; i<m_items.GetCount(); i++)
-            delete DoGetItemClientObject(i);
-    }
-
-    m_items.Clear();
-    m_HTMLclientData.Clear();
+    wxItemContainer::Clear();
 }
 
-void wxSimpleHtmlListBox::Clear()
+void wxSimpleHtmlListBox::DoClear()
 {
+    wxASSERT(m_items.GetCount() == m_HTMLclientData.GetCount());
+
     m_items.Clear();
     m_HTMLclientData.Clear();
+
     UpdateCount();
 }
 
-void wxSimpleHtmlListBox::Delete(unsigned int n)
+void wxSimpleHtmlListBox::DoDeleteOneItem(unsigned int n)
 {
     m_items.RemoveAt(n);
+
     m_HTMLclientData.RemoveAt(n);
-    UpdateCount();
-}
 
-void wxSimpleHtmlListBox::Append(const wxArrayString& strings)
-{
-    // append all given items at once
-    WX_APPEND_ARRAY(m_items, strings);
-    m_HTMLclientData.Add(NULL, strings.GetCount());
     UpdateCount();
 }
 
-int wxSimpleHtmlListBox::DoAppend(const wxString& item)
+int wxSimpleHtmlListBox::DoInsertItems(const wxArrayStringsAdapter& items,
+                                       unsigned int pos,
+                                       void **clientData,
+                                       wxClientDataType type)
 {
-    m_items.Add(item);
-    m_HTMLclientData.Add(NULL);
-    UpdateCount();
-    return GetCount()-1;
-}
+    const unsigned int count = items.GetCount();
+
+    m_items.Insert(wxEmptyString, pos, count);
+    m_HTMLclientData.Insert(NULL, pos, count);
+
+    for ( unsigned int i = 0; i < count; ++i, ++pos )
+    {
+        m_items[pos] = items[i];
+        AssignNewItemClientData(pos, clientData, i, type);
+    }
 
-int wxSimpleHtmlListBox::DoInsert(const wxString& item, unsigned int pos)
-{
-    m_items.Insert(item, pos);
-    m_HTMLclientData.Insert(NULL, pos);
     UpdateCount();
+
     return pos;
 }
 
@@ -644,7 +638,7 @@ void wxSimpleHtmlListBox::SetString(unsigned int n, const wxString& s)
     wxCHECK_RET( IsValid(n),
                  wxT("invalid index in wxSimpleHtmlListBox::SetString") );
 
-    m_items[n]=s; 
+    m_items[n]=s;
     RefreshRow(n);
 }
 
diff --git a/src/generic/odcombo.cpp b/src/generic/odcombo.cpp
index 3e62b8349d..cecfb1ff2d 100644
--- a/src/generic/odcombo.cpp
+++ b/src/generic/odcombo.cpp
@@ -471,6 +471,8 @@ void wxVListBoxComboPopup::Insert( const wxString& item, int pos )
     }
 
     m_strings.Insert(item,pos);
+    m_clientDatas.Insert(NULL, pos);
+
     m_widths.Insert(-1,pos);
     m_widthsDirty = true;
 
@@ -541,7 +543,6 @@ void wxVListBoxComboPopup::SetItemClientData( unsigned int n,
     // It should be sufficient to update this variable only here
     m_clientDataItemsType = clientDataItemsType;
 
-    m_clientDatas.SetCount(n+1,NULL);
     m_clientDatas[n] = clientData;
 
     ItemWidthChanged(n);
@@ -923,7 +924,7 @@ void wxOwnerDrawnComboBox::DoSetPopupControl(wxComboPopup* popup)
 // wxOwnerDrawnComboBox item manipulation methods
 // ----------------------------------------------------------------------------
 
-void wxOwnerDrawnComboBox::Clear()
+void wxOwnerDrawnComboBox::DoClear()
 {
     EnsurePopupControl();
 
@@ -932,7 +933,7 @@ void wxOwnerDrawnComboBox::Clear()
     SetValue(wxEmptyString);
 }
 
-void wxOwnerDrawnComboBox::Delete(unsigned int n)
+void wxOwnerDrawnComboBox::DoDeleteOneItem(unsigned int n)
 {
     wxCHECK_RET( IsValid(n), _T("invalid index in wxOwnerDrawnComboBox::Delete") );
 
@@ -1006,24 +1007,21 @@ int wxOwnerDrawnComboBox::GetSelection() const
     return GetVListBoxComboPopup()->GetSelection();
 }
 
-int wxOwnerDrawnComboBox::DoAppend(const wxString& item)
-{
-    EnsurePopupControl();
-    wxASSERT(m_popupInterface);
-
-    return GetVListBoxComboPopup()->Append(item);
-}
-
-int wxOwnerDrawnComboBox::DoInsert(const wxString& item, unsigned int pos)
+int wxOwnerDrawnComboBox::DoInsertItems(const wxArrayStringsAdapter& items,
+                                        unsigned int pos,
+                                        void **clientData,
+                                        wxClientDataType type)
 {
     EnsurePopupControl();
 
-    wxCHECK_MSG(!(GetWindowStyle() & wxCB_SORT), -1, wxT("can't insert into sorted list"));
-    wxCHECK_MSG(IsValidInsert(pos), -1, wxT("invalid index"));
-
-    GetVListBoxComboPopup()->Insert(item,pos);
+    const unsigned int count = items.GetCount();
+    for( unsigned int i = 0; i < count; ++i, ++pos )
+    {
+        GetVListBoxComboPopup()->Insert(items[i], pos);
+        AssignNewItemClientData(pos, clientData, i, type);
+    }
 
-    return pos;
+    return pos - 1;
 }
 
 void wxOwnerDrawnComboBox::DoSetItemClientData(unsigned int n, void* clientData)
@@ -1041,16 +1039,6 @@ void* wxOwnerDrawnComboBox::DoGetItemClientData(unsigned int n) const
     return GetVListBoxComboPopup()->GetItemClientData(n);
 }
 
-void wxOwnerDrawnComboBox::DoSetItemClientObject(unsigned int n, wxClientData* clientData)
-{
-    DoSetItemClientData(n, (void*) clientData);
-}
-
-wxClientData* wxOwnerDrawnComboBox::DoGetItemClientObject(unsigned int n) const
-{
-    return (wxClientData*) DoGetItemClientData(n);
-}
-
 // ----------------------------------------------------------------------------
 // wxOwnerDrawnComboBox item drawing and measuring default implementations
 // ----------------------------------------------------------------------------
diff --git a/src/gtk/choice.cpp b/src/gtk/choice.cpp
index 69ca481174..7dfecca77a 100644
--- a/src/gtk/choice.cpp
+++ b/src/gtk/choice.cpp
@@ -103,9 +103,9 @@ bool wxChoice::Create( wxWindow *parent, wxWindowID id,
 
     m_widget = gtk_option_menu_new();
 
-    if ( style & wxCB_SORT )
+    if ( IsSorted() )
     {
-        // if our m_strings != NULL, DoAppend() will check for it and insert
+        // if our m_strings != NULL, Append() will check for it and insert
         // items in the correct order
         m_strings = new wxSortedArrayString;
     }
@@ -137,79 +137,46 @@ wxChoice::~wxChoice()
     delete m_strings;
 }
 
-int wxChoice::DoAppend( const wxString &item )
+int wxChoice::DoInsertItems(const wxArrayStringsAdapter & items,
+                            unsigned int pos,
+                            void **clientData, wxClientDataType type)
 {
     wxCHECK_MSG( m_widget != NULL, -1, wxT("invalid choice control") );
 
-    GtkWidget *menu = gtk_option_menu_get_menu( GTK_OPTION_MENU(m_widget) );
-
-    return GtkAddHelper(menu, GetCount(), item);
-}
+    const unsigned int count = items.GetCount();
 
-int wxChoice::DoInsert(const wxString &item, unsigned int pos)
-{
-    wxCHECK_MSG( m_widget != NULL, -1, wxT("invalid choice control") );
-    wxCHECK_MSG( IsValidInsert(pos), -1, wxT("invalid index"));
+    GtkWidget *menu = gtk_option_menu_get_menu( GTK_OPTION_MENU(m_widget) );
 
-    if (pos == GetCount())
-        return DoAppend(item);
+    for ( unsigned int i = 0; i < count; ++i, ++pos )
+    {
+        int n = GtkAddHelper(menu, pos, items[i]);
+        if ( n == wxNOT_FOUND )
+            return n;
 
-    GtkWidget *menu = gtk_option_menu_get_menu( GTK_OPTION_MENU(m_widget) );
+        AssignNewItemClientData(n, clientData, i, type);
+    }
 
     // if the item to insert is at or before the selection, and the selection is valid
     if (((int)pos <= m_selection_hack) && (m_selection_hack != wxNOT_FOUND))
     {
-        // move the selection forward one
-        m_selection_hack++;
+        // move the selection forward
+        m_selection_hack += count;
     }
 
-    return GtkAddHelper(menu, pos, item);
+    return pos - 1;
 }
 
 void wxChoice::DoSetItemClientData(unsigned int n, void* clientData)
 {
-    wxCHECK_RET( m_widget != NULL, wxT("invalid choice control") );
-
-    wxList::compatibility_iterator node = m_clientList.Item( n );
-    wxCHECK_RET( node, wxT("invalid index in wxChoice::DoSetItemClientData") );
-
-    node->SetData( (wxObject*) clientData );
+    m_clientData[n] = clientData;
 }
 
 void* wxChoice::DoGetItemClientData(unsigned int n) const
 {
-    wxCHECK_MSG( m_widget != NULL, NULL, wxT("invalid choice control") );
-
-    wxList::compatibility_iterator node = m_clientList.Item( n );
-    wxCHECK_MSG( node, NULL, wxT("invalid index in wxChoice::DoGetItemClientData") );
-
-    return node->GetData();
-}
-
-void wxChoice::DoSetItemClientObject(unsigned int n, wxClientData* clientData)
-{
-    wxCHECK_RET( m_widget != NULL, wxT("invalid choice control") );
-
-    wxList::compatibility_iterator node = m_clientList.Item( n );
-    wxCHECK_RET( node, wxT("invalid index in wxChoice::DoSetItemClientObject") );
-
-    // wxItemContainer already deletes data for us
-
-    node->SetData( (wxObject*) clientData );
-}
-
-wxClientData* wxChoice::DoGetItemClientObject(unsigned int n) const
-{
-    wxCHECK_MSG( m_widget != NULL, (wxClientData*) NULL, wxT("invalid choice control") );
-
-    wxList::compatibility_iterator node = m_clientList.Item( n );
-    wxCHECK_MSG( node, (wxClientData *)NULL,
-                 wxT("invalid index in wxChoice::DoGetItemClientObject") );
-
-    return (wxClientData*) node->GetData();
+    return m_clientData[n];
 }
 
-void wxChoice::Clear()
+void wxChoice::DoClear()
 {
     wxCHECK_RET( m_widget != NULL, wxT("invalid choice") );
 
@@ -217,19 +184,7 @@ void wxChoice::Clear()
     GtkWidget *menu = gtk_menu_new();
     gtk_option_menu_set_menu( GTK_OPTION_MENU(m_widget), menu );
 
-    if ( HasClientObjectData() )
-    {
-        // destroy the data (due to Robert's idea of using wxList<wxObject>
-        // and not wxList<wxClientData> we can't just say
-        // m_clientList.DeleteContents(true) - this would crash!
-        wxList::compatibility_iterator node = m_clientList.GetFirst();
-        while ( node )
-        {
-            delete (wxClientData *)node->GetData();
-            node = node->GetNext();
-        }
-    }
-    m_clientList.Clear();
+    m_clientData.Clear();
 
     if ( m_strings )
         m_strings->Clear();
@@ -238,16 +193,11 @@ void wxChoice::Clear()
     m_selection_hack = wxNOT_FOUND;
 }
 
-void wxChoice::Delete(unsigned int n)
+void wxChoice::DoDeleteOneItem(unsigned int n)
 {
     wxCHECK_RET( m_widget != NULL, wxT("invalid choice") );
     wxCHECK_RET( IsValid(n), _T("invalid index in wxChoice::Delete") );
 
-    // VZ: apparently GTK+ doesn't have a built-in function to do it (not even
-    //     in 2.0), hence this dumb implementation -- still better than nothing
-    unsigned int i;
-    const unsigned int count = GetCount();
-
     // if the item to delete is before the selection, and the selection is valid
     if (((int)n < m_selection_hack) && (m_selection_hack != wxNOT_FOUND))
     {
@@ -260,56 +210,30 @@ void wxChoice::Delete(unsigned int n)
         m_selection_hack = wxNOT_FOUND;
     }
 
-    const bool hasClientData = m_clientDataItemsType != wxClientData_None;
-    const bool hasObjectData = m_clientDataItemsType == wxClientData_Object;
-
-    wxList::compatibility_iterator node = m_clientList.GetFirst();
+    // VZ: apparently GTK+ doesn't have a built-in function to do it (not even
+    //     in 2.0), hence this dumb implementation -- still better than nothing
+    const unsigned int count = GetCount();
 
     wxArrayString items;
     wxArrayPtrVoid itemsData;
     items.Alloc(count);
-    for ( i = 0; i < count; i++ )
+    itemsData.Alloc(count);
+    for ( unsigned i = 0; i < count; i++ )
     {
         if ( i != n )
         {
             items.Add(GetString(i));
-            if ( hasClientData )
-            {
-                // also save the client data
-                itemsData.Add(node->GetData());
-            }
-        }
-        else // need to delete the client object too
-        {
-            if ( hasObjectData )
-            {
-                delete (wxClientData *)node->GetData();
-            }
-        }
-
-        if ( hasClientData )
-        {
-            node = node->GetNext();
+            itemsData.Add(m_clientData[i]);
         }
     }
 
-    if ( hasObjectData )
-    {
-        // prevent Clear() from destroying all client data
-        m_clientDataItemsType = wxClientData_None;
-    }
-
-    Clear();
-
-    for ( i = 0; i < count - 1; i++ )
-    {
-        Append(items[i]);
+    wxChoice::DoClear();
 
-        if ( hasObjectData )
-            SetClientObject(i, (wxClientData *)itemsData[i]);
-        else if ( hasClientData )
-            SetClientData(i, itemsData[i]);
-    }
+    void ** const data = &itemsData[0];
+    if ( HasClientObjectData() )
+        Append(items, wx_reinterpret_cast(wxClientData **, data));
+    else
+        Append(items, data);
 }
 
 int wxChoice::FindString( const wxString &string, bool bCase ) const
@@ -482,47 +406,24 @@ void wxChoice::DoApplyWidgetStyle(GtkRcStyle *style)
 
 int wxChoice::GtkAddHelper(GtkWidget *menu, unsigned int pos, const wxString& item)
 {
-    wxCHECK_MSG(pos<=m_clientList.GetCount(), -1, wxT("invalid index"));
+    wxCHECK_MSG(pos<=m_clientData.GetCount(), -1, wxT("invalid index"));
 
     GtkWidget *menu_item = gtk_menu_item_new_with_label( wxGTK_CONV( item ) );
 
-    unsigned int index;
     if ( m_strings )
     {
         // sorted control, need to insert at the correct index
-        index = m_strings->Add(item);
-
-        gtk_menu_shell_insert( GTK_MENU_SHELL(menu), menu_item, index );
-
-        if ( index )
-        {
-            m_clientList.Insert( m_clientList.Item(index - 1),
-                                 (wxObject*) NULL );
-        }
-        else
-        {
-            m_clientList.Insert( (wxObject*) NULL );
-        }
+        pos = m_strings->Add(item);
     }
+
+    // don't call wxChoice::GetCount() from here because it doesn't work
+    // if we're called from ctor (and GtkMenuShell is still NULL)
+    if (pos == m_clientData.GetCount())
+        gtk_menu_shell_append( GTK_MENU_SHELL(menu), menu_item );
     else
-    {
-        // don't call wxChoice::GetCount() from here because it doesn't work
-        // if we're called from ctor (and GtkMenuShell is still NULL)
+        gtk_menu_shell_insert( GTK_MENU_SHELL(menu), menu_item, pos );
 
-        // normal control, just append
-        if (pos == m_clientList.GetCount())
-        {
-            gtk_menu_shell_append( GTK_MENU_SHELL(menu), menu_item );
-            m_clientList.Append( (wxObject*) NULL );
-            index = m_clientList.GetCount() - 1;
-        }
-        else
-        {
-            gtk_menu_shell_insert( GTK_MENU_SHELL(menu), menu_item, pos );
-            m_clientList.Insert( pos, (wxObject*) NULL );
-            index = pos;
-        }
-    }
+    m_clientData.Insert( NULL, pos );
 
     if (GTK_WIDGET_REALIZED(m_widget))
     {
@@ -545,7 +446,7 @@ int wxChoice::GtkAddHelper(GtkWidget *menu, unsigned int pos, const wxString& it
     gtk_widget_show( menu_item );
 
     // return the index of the item in the control
-    return index;
+    return pos;
 }
 
 wxSize wxChoice::DoGetBestSize() const
diff --git a/src/gtk/combobox.cpp b/src/gtk/combobox.cpp
index 56acb50640..91207fc70a 100644
--- a/src/gtk/combobox.cpp
+++ b/src/gtk/combobox.cpp
@@ -241,6 +241,7 @@ bool wxComboBox::Create( wxWindow *parent, wxWindowID id, const wxString& value,
                          long style, const wxValidator& validator,
                          const wxString& name )
 {
+    m_strings = NULL;
     m_ignoreNextUpdate = false;
     m_prevSelection = 0;
 
@@ -251,21 +252,15 @@ bool wxComboBox::Create( wxWindow *parent, wxWindowID id, const wxString& value,
         return false;
     }
 
+    if(HasFlag(wxCB_SORT))
+        m_strings = new wxSortedArrayString();
+
 #ifdef __WXGTK24__
     if (!gtk_check_version(2,4,0))
     {
         m_widget = gtk_combo_box_entry_new_text();
-        GtkComboBox* combobox = GTK_COMBO_BOX( m_widget );
 
         gtk_entry_set_editable( GTK_ENTRY( GTK_BIN(m_widget)->child ), TRUE );
-
-        for (int i = 0; i < n; i++)
-        {
-            gtk_combo_box_append_text( combobox,  wxGTK_CONV( choices[i] ) );
-
-            m_clientDataList.Append( (wxObject*)NULL );
-            m_clientObjectList.Append( (wxObject*)NULL );
-        }
     }
     else
 #endif
@@ -288,22 +283,9 @@ bool wxComboBox::Create( wxWindow *parent, wxWindowID id, const wxString& value,
 
         if (style & wxNO_BORDER)
             g_object_set (combo->entry, "has-frame", FALSE, NULL );
-
-        GtkWidget *list = combo->list;
-
-        for (int i = 0; i < n; i++)
-        {
-            GtkWidget *list_item = gtk_list_item_new_with_label( wxGTK_CONV( choices[i] ) );
-
-            m_clientDataList.Append( (wxObject*)NULL );
-            m_clientObjectList.Append( (wxObject*)NULL );
-
-            gtk_container_add( GTK_CONTAINER(list), list_item );
-
-            gtk_widget_show( list_item );
-        }
     }
 
+    Append(n, choices);
 
     m_parent->DoAddChild( this );
 
@@ -372,16 +354,9 @@ bool wxComboBox::Create( wxWindow *parent, wxWindowID id, const wxString& value,
 
 wxComboBox::~wxComboBox()
 {
-    wxList::compatibility_iterator node = m_clientObjectList.GetFirst();
-    while (node)
-    {
-        wxClientData *cd = (wxClientData*)node->GetData();
-        if (cd) delete cd;
-        node = node->GetNext();
-    }
-    m_clientObjectList.Clear();
+    Clear();
 
-    m_clientDataList.Clear();
+    delete m_strings;
 }
 
 void wxComboBox::SetFocus()
@@ -395,15 +370,36 @@ void wxComboBox::SetFocus()
     gtk_widget_grab_focus( m_focusWidget );
 }
 
-int wxComboBox::DoAppend( const wxString &item )
+int wxComboBox::DoInsertItems(const wxArrayStringsAdapter & items,
+                              unsigned int pos,
+                              void **clientData, wxClientDataType type)
 {
     wxCHECK_MSG( m_widget != NULL, -1, wxT("invalid combobox") );
 
+    wxASSERT_MSG( !IsSorted() || (pos == GetCount()),
+                 _T("In a sorted combobox data could only be appended"));
+
+    const int count = items.GetCount();
+
+    int n = wxNOT_FOUND;
+
 #ifdef __WXGTK24__
     if (!gtk_check_version(2,4,0))
     {
         GtkComboBox* combobox = GTK_COMBO_BOX( m_widget );
-        gtk_combo_box_append_text( combobox,  wxGTK_CONV( item ) );
+        for( int i = 0; i < count; ++i )
+        {
+            n = pos + i;
+            // If sorted, use this wxSortedArrayStrings to determine
+            // the right insertion point
+            if(m_strings)
+                n = m_strings->Add(items[i]);
+
+            gtk_combo_box_insert_text( combobox, n, wxGTK_CONV( items[i] ) );
+
+            m_clientData.Insert( NULL, n );
+            AssignNewItemClientData(n, clientData, i, type);
+        }
     }
     else
 #endif
@@ -411,141 +407,54 @@ int wxComboBox::DoAppend( const wxString &item )
         DisableEvents();
 
         GtkWidget *list = GTK_COMBO(m_widget)->list;
-        GtkWidget *list_item = gtk_list_item_new_with_label( wxGTK_CONV( item ) );
-
-        gtk_container_add( GTK_CONTAINER(list), list_item );
-
-        if (GTK_WIDGET_REALIZED(m_widget))
+        for( int i = 0; i < count; ++i )
         {
-            gtk_widget_realize( list_item );
-            gtk_widget_realize( GTK_BIN(list_item)->child );
-        }
-
-        // Apply current widget style to the new list_item
-        GtkRcStyle *style = CreateWidgetStyle();
-        if (style)
-        {
-            gtk_widget_modify_style(list_item, style);
-            GtkBin *bin = GTK_BIN( list_item );
-            GtkWidget *label = bin->child;
-            gtk_widget_modify_style( label, style );
-            gtk_rc_style_unref( style );
-        }
-
-        gtk_widget_show( list_item );
-
-        EnableEvents();
-    }
-
-    const unsigned int count = GetCount();
-
-    if ( m_clientDataList.GetCount() < count )
-        m_clientDataList.Append( (wxObject*) NULL );
-    if ( m_clientObjectList.GetCount() < count )
-        m_clientObjectList.Append( (wxObject*) NULL );
-
-    InvalidateBestSize();
-
-    return count - 1;
-}
-
-int wxComboBox::DoInsert(const wxString &item, unsigned int pos)
-{
-    wxCHECK_MSG( !(GetWindowStyle() & wxCB_SORT), -1,
-                    wxT("can't insert into sorted list"));
-
-    wxCHECK_MSG( m_widget != NULL, -1, wxT("invalid combobox") );
-    wxCHECK_MSG( IsValidInsert(pos), -1, wxT("invalid index") );
+            n = pos + i;
+            // If sorted, use this wxSortedArrayStrings to determine
+            // the right insertion point
+            if(m_strings)
+                n = m_strings->Add(items[i]);
 
-    unsigned int count = GetCount();
+            GtkWidget *list_item = gtk_list_item_new_with_label( wxGTK_CONV( items[i] ) );
 
-    if (pos == count)
-        return Append(item);
+            // TODO construct a list with all items and call gtk_list_insert_items once?
+            GList *gitem_list = g_list_alloc ();
+            gitem_list->data = list_item;
+            gtk_list_insert_items( GTK_LIST (list), gitem_list, n );
 
-#ifdef __WXGTK24__
-    if (!gtk_check_version(2,4,0))
-    {
-        GtkComboBox* combobox = GTK_COMBO_BOX( m_widget );
-        gtk_combo_box_insert_text( combobox, pos, wxGTK_CONV( item ) );
-    }
-    else
-#endif
-    {
-        DisableEvents();
+            m_clientData.Insert( NULL, n );
+            AssignNewItemClientData(n, clientData, i, type);
 
-        GtkWidget *list = GTK_COMBO(m_widget)->list;
-        GtkWidget *list_item = gtk_list_item_new_with_label( wxGTK_CONV( item ) );
-
-        GList *gitem_list = g_list_alloc ();
-        gitem_list->data = list_item;
-        gtk_list_insert_items( GTK_LIST (list), gitem_list, pos );
+            if (GTK_WIDGET_REALIZED(m_widget))
+            {
+                gtk_widget_realize( list_item );
+                gtk_widget_realize( GTK_BIN(list_item)->child );
 
-        if (GTK_WIDGET_REALIZED(m_widget))
-        {
-            gtk_widget_realize( list_item );
-            gtk_widget_realize( GTK_BIN(list_item)->child );
+                ApplyWidgetStyle();
+            }
 
-            ApplyWidgetStyle();
+            gtk_widget_show( list_item );
         }
 
-        gtk_widget_show( list_item );
-
         EnableEvents();
     }
 
-    count = GetCount();
-
-    if ( m_clientDataList.GetCount() < count )
-        m_clientDataList.Insert( pos, (wxObject*) NULL );
-    if ( m_clientObjectList.GetCount() < count )
-        m_clientObjectList.Insert( pos, (wxObject*) NULL );
-
     InvalidateBestSize();
 
-    return pos;
+    return n;
 }
 
 void wxComboBox::DoSetItemClientData(unsigned int n, void* clientData)
 {
-    wxCHECK_RET( m_widget != NULL, wxT("invalid combobox") );
-
-    wxList::compatibility_iterator node = m_clientDataList.Item( n );
-    if (!node) return;
-
-    node->SetData( (wxObject*) clientData );
+    m_clientData[n] = clientData;
 }
 
 void* wxComboBox::DoGetItemClientData(unsigned int n) const
 {
-    wxCHECK_MSG( m_widget != NULL, NULL, wxT("invalid combobox") );
-
-    wxList::compatibility_iterator node = m_clientDataList.Item( n );
-
-    return node ? node->GetData() : NULL;
+    return m_clientData[n];
 }
 
-void wxComboBox::DoSetItemClientObject(unsigned int n, wxClientData* clientData)
-{
-    wxCHECK_RET( m_widget != NULL, wxT("invalid combobox") );
-
-    wxList::compatibility_iterator node = m_clientObjectList.Item( n );
-    if (!node) return;
-
-    // wxItemContainer already deletes data for us
-
-    node->SetData( (wxObject*) clientData );
-}
-
-wxClientData* wxComboBox::DoGetItemClientObject(unsigned int n) const
-{
-    wxCHECK_MSG( m_widget != NULL, (wxClientData*)NULL, wxT("invalid combobox") );
-
-    wxList::compatibility_iterator node = m_clientObjectList.Item( n );
-
-    return node ? (wxClientData*) node->GetData() : NULL;
-}
-
-void wxComboBox::Clear()
+void wxComboBox::DoClear()
 {
     wxCHECK_RET( m_widget != NULL, wxT("invalid combobox") );
 
@@ -566,23 +475,17 @@ void wxComboBox::Clear()
         gtk_list_clear_items( GTK_LIST(list), 0, GetCount() );
     }
 
-    wxList::compatibility_iterator node = m_clientObjectList.GetFirst();
-    while (node)
-    {
-        wxClientData *cd = (wxClientData*)node->GetData();
-        delete cd;
-        node = node->GetNext();
-    }
-    m_clientObjectList.Clear();
+    m_clientData.Clear();
 
-    m_clientDataList.Clear();
+    if(m_strings)
+        m_strings->Clear();
 
     EnableEvents();
 
     InvalidateBestSize();
 }
 
-void wxComboBox::Delete(unsigned int n)
+void wxComboBox::DoDeleteOneItem(unsigned int n)
 {
     wxCHECK_RET( m_widget != NULL, wxT("invalid combobox") );
 
@@ -616,17 +519,9 @@ void wxComboBox::Delete(unsigned int n)
         EnableEvents();
     }
 
-    wxList::compatibility_iterator node = m_clientObjectList.Item( n );
-    if (node)
-    {
-        wxClientData *cd = (wxClientData*)node->GetData();
-        if (cd) delete cd;
-        m_clientObjectList.Erase( node );
-    }
-
-    node = m_clientDataList.Item( n );
-    if (node)
-        m_clientDataList.Erase( node );
+    m_clientData.RemoveAt( n );
+    if(m_strings)
+        m_strings->RemoveAt( n );
 
     InvalidateBestSize();
 }
@@ -946,7 +841,7 @@ void wxComboBox::SetValue( const wxString& value )
 
     wxString tmp;
     if (!value.IsNull()) tmp = value;
-    
+
     DisableEvents();
     gtk_entry_set_text( entry, wxGTK_CONV( tmp ) );
     EnableEvents();
diff --git a/src/gtk/listbox.cpp b/src/gtk/listbox.cpp
index 15c70a351d..3517dd9f71 100644
--- a/src/gtk/listbox.cpp
+++ b/src/gtk/listbox.cpp
@@ -205,6 +205,7 @@ static void gtk_tree_entry_destroy_cb(GtkTreeEntry* entry,
 //-----------------------------------------------------------------------------
 // Sorting callback (standard CmpNoCase return value)
 //-----------------------------------------------------------------------------
+#include <iostream>
 
 extern "C" {
 static gint gtk_listbox_sort_callback(GtkTreeModel *model,
@@ -228,8 +229,8 @@ static gint gtk_listbox_sort_callback(GtkTreeModel *model,
 
     //We compare collate keys here instead of calling g_utf8_collate
     //as it is rather slow (and even the docs reccommend this)
-    int ret = strcasecmp(gtk_tree_entry_get_collate_key(entry),
-                         gtk_tree_entry_get_collate_key(entry2));
+    int ret = strcmp(gtk_tree_entry_get_collate_key(entry),
+                     gtk_tree_entry_get_collate_key(entry2));
 
     g_object_unref (entry);
     g_object_unref (entry2);
@@ -258,8 +259,8 @@ static gboolean gtk_listbox_searchequal_callback(GtkTreeModel* model,
     wxCHECK_MSG(entry, 0, wxT("Could not get entry"));
     wxGtkString keycollatekey(g_utf8_collate_key(key, -1));
 
-    int ret = strcasecmp(keycollatekey,
-                         gtk_tree_entry_get_collate_key(entry));
+    int ret = strcmp(keycollatekey,
+                     gtk_tree_entry_get_collate_key(entry));
 
     g_object_unref (entry);
 
@@ -396,7 +397,7 @@ bool wxListBox::Create( wxWindow *parent, wxWindowID id,
     gtk_tree_selection_set_mode( selection, mode );
 
     // Handle sortable stuff
-    if(style & wxLB_SORT)
+    if(HasFlag(wxLB_SORT))
     {
         // Setup sorting in ascending (wx) order
         gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(m_liststore),
@@ -418,7 +419,7 @@ bool wxListBox::Create( wxWindow *parent, wxWindowID id,
     gtk_widget_show( GTK_WIDGET(m_treeview) );
     m_focusWidget = GTK_WIDGET(m_treeview);
 
-    wxListBox::DoInsertItems(wxArrayString(n, choices), 0); // insert initial items
+    Append(n, choices); // insert initial items
 
     // generate dclick events
     g_signal_connect_after(m_treeview, "row-activated",
@@ -443,35 +444,30 @@ wxListBox::~wxListBox()
 // adding items
 // ----------------------------------------------------------------------------
 
-void wxListBox::GtkInsertItems(const wxArrayString& items,
-                               void** clientData, unsigned int pos)
+int wxListBox::DoInsertItems(const wxArrayStringsAdapter& items,
+                             unsigned int pos,
+                             void **clientData,
+                             wxClientDataType type)
 {
-    wxCHECK_RET( m_treeview != NULL, wxT("invalid listbox") );
+    wxCHECK_MSG( m_treeview != NULL, wxNOT_FOUND, wxT("invalid listbox") );
 
     InvalidateBestSize();
 
-    // Create and set column ids and GValues
-
-    unsigned int nNum = items.GetCount();
-    unsigned int nCurCount = wxListBox::GetCount();
-    wxASSERT_MSG(pos <= nCurCount, wxT("Invalid index passed to wxListBox"));
-
     GtkTreeIter* pIter = NULL; // append by default
     GtkTreeIter iter;
-    if (pos != nCurCount)
+    if ( pos != GetCount() )
     {
-        wxCHECK_RET( GtkGetIteratorFor(pos, &iter),
+        wxCHECK_MSG( GtkGetIteratorFor(pos, &iter), wxNOT_FOUND,
                      wxT("internal wxListBox error in insertion") );
 
         pIter = &iter;
     }
 
-    for (unsigned int i = 0; i < nNum; ++i)
+    const unsigned int numItems = items.GetCount();
+    for ( unsigned int i = 0; i < numItems; ++i )
     {
-        wxString label = items[i];
-
         GtkTreeEntry* entry = gtk_tree_entry_new();
-        gtk_tree_entry_set_label(entry, wxGTK_CONV(label));
+        gtk_tree_entry_set_label(entry, wxGTK_CONV(items[i]));
         gtk_tree_entry_set_destroy_func(entry,
                 (GtkTreeEntryDestroy)gtk_tree_entry_destroy_cb,
                             this);
@@ -486,49 +482,18 @@ void wxListBox::GtkInsertItems(const wxArrayString& items,
 
         g_object_unref (entry);
     }
-}
-
-void wxListBox::DoInsertItems(const wxArrayString& items, unsigned int pos)
-{
-    wxCHECK_RET( IsValidInsert(pos), wxT("invalid index in wxListBox::InsertItems") );
-
-    GtkInsertItems(items, NULL, pos);
-}
-
-int wxListBox::DoAppend( const wxString& item )
-{
-    wxCHECK_MSG( m_treeview != NULL, -1, wxT("invalid listbox") );
-
-    InvalidateBestSize();
-
-    GtkTreeEntry* entry = gtk_tree_entry_new();
-    gtk_tree_entry_set_label( entry, wxGTK_CONV(item) );
-    gtk_tree_entry_set_destroy_func(entry,
-                (GtkTreeEntryDestroy)gtk_tree_entry_destroy_cb,
-                            this);
-
-    GtkTreeIter itercur;
-    gtk_list_store_insert_before( m_liststore, &itercur, NULL );
-
-    GtkSetItem(itercur, entry);
 
-    g_object_unref (entry);
+    if ( !HasClientData() )
+        m_clientDataItemsType = type;
 
-    return GtkGetIndexFor(itercur);
-}
-
-void wxListBox::DoSetItems( const wxArrayString& items,
-                            void **clientData)
-{
-    Clear();
-    GtkInsertItems(items, clientData, 0);
+    return pos + numItems - 1;
 }
 
 // ----------------------------------------------------------------------------
 // deleting items
 // ----------------------------------------------------------------------------
 
-void wxListBox::Clear()
+void wxListBox::DoClear()
 {
     wxCHECK_RET( m_treeview != NULL, wxT("invalid listbox") );
 
@@ -537,7 +502,7 @@ void wxListBox::Clear()
     gtk_list_store_clear( m_liststore ); /* well, THAT was easy :) */
 }
 
-void wxListBox::Delete(unsigned int n)
+void wxListBox::DoDeleteOneItem(unsigned int n)
 {
     wxCHECK_RET( m_treeview != NULL, wxT("invalid listbox") );
 
@@ -632,11 +597,6 @@ void* wxListBox::DoGetItemClientData(unsigned int n) const
     return userdata;
 }
 
-wxClientData* wxListBox::DoGetItemClientObject(unsigned int n) const
-{
-    return (wxClientData*) wxListBox::DoGetItemClientData(n);
-}
-
 void wxListBox::DoSetItemClientData(unsigned int n, void* clientData)
 {
     wxCHECK_RET( IsValid(n),
@@ -649,12 +609,6 @@ void wxListBox::DoSetItemClientData(unsigned int n, void* clientData)
     g_object_unref (entry);
 }
 
-void wxListBox::DoSetItemClientObject(unsigned int n, wxClientData* clientData)
-{
-    // wxItemContainer already deletes data for us
-    wxListBox::DoSetItemClientData(n, (void*) clientData);
-}
-
 // ----------------------------------------------------------------------------
 // string list access
 // ----------------------------------------------------------------------------
diff --git a/src/gtk1/choice.cpp b/src/gtk1/choice.cpp
index 9b03f45cfe..adf1d04101 100644
--- a/src/gtk1/choice.cpp
+++ b/src/gtk1/choice.cpp
@@ -126,7 +126,7 @@ bool wxChoice::Create( wxWindow *parent, wxWindowID id,
 
     if ( style & wxCB_SORT )
     {
-        // if our m_strings != NULL, DoAppend() will check for it and insert
+        // if our m_strings != NULL, Append() will check for it and insert
         // items in the correct order
         m_strings = new wxSortedArrayString;
     }
@@ -158,33 +158,33 @@ wxChoice::~wxChoice()
     delete m_strings;
 }
 
-int wxChoice::DoAppend( const wxString &item )
+int wxChoice::DoInsertItems(const wxArrayStringsAdapter & items,
+                            unsigned int pos,
+                            void **clientData, wxClientDataType type)
 {
     wxCHECK_MSG( m_widget != NULL, -1, wxT("invalid choice control") );
 
-    GtkWidget *menu = gtk_option_menu_get_menu( GTK_OPTION_MENU(m_widget) );
-
-    return GtkAddHelper(menu, GetCount(), item);
-}
+    const unsigned int count = items.GetCount();
 
-int wxChoice::DoInsert( const wxString &item, unsigned int pos )
-{
-    wxCHECK_MSG( m_widget != NULL, -1, wxT("invalid choice control") );
-    wxCHECK_MSG( IsValidInsert(pos), -1, wxT("invalid index"));
+    GtkWidget *menu = gtk_option_menu_get_menu( GTK_OPTION_MENU(m_widget) );
 
-    if (pos == GetCount())
-        return DoAppend(item);
+    for ( unsigned int i = 0; i < count; ++i, ++pos )
+    {
+        int n = GtkAddHelper(menu, pos, items[i]);
+        if ( n == wxNOT_FOUND )
+            return n;
 
-    GtkWidget *menu = gtk_option_menu_get_menu( GTK_OPTION_MENU(m_widget) );
+        AssignNewItemClientData(n, clientData, i, type);
+    }
 
     // if the item to insert is at or before the selection, and the selection is valid
     if (((int)pos <= m_selection_hack) && (m_selection_hack != wxNOT_FOUND))
     {
-        // move the selection forward one
-        m_selection_hack++;
+        // move the selection forward
+        m_selection_hack += count;
     }
 
-    return GtkAddHelper(menu, pos, item);
+    return pos - 1;
 }
 
 void wxChoice::DoSetItemClientData(unsigned int n, void* clientData)
@@ -207,30 +207,7 @@ void* wxChoice::DoGetItemClientData(unsigned int n) const
     return node->GetData();
 }
 
-void wxChoice::DoSetItemClientObject(unsigned int n, wxClientData* clientData)
-{
-    wxCHECK_RET( m_widget != NULL, wxT("invalid choice control") );
-
-    wxList::compatibility_iterator node = m_clientList.Item( n );
-    wxCHECK_RET( node, wxT("invalid index in wxChoice::DoSetItemClientObject") );
-
-    // wxItemContainer already deletes data for us
-
-    node->SetData( (wxObject*) clientData );
-}
-
-wxClientData* wxChoice::DoGetItemClientObject(unsigned int n) const
-{
-    wxCHECK_MSG( m_widget != NULL, (wxClientData*) NULL, wxT("invalid choice control") );
-
-    wxList::compatibility_iterator node = m_clientList.Item( n );
-    wxCHECK_MSG( node, (wxClientData *)NULL,
-                 wxT("invalid index in wxChoice::DoGetItemClientObject") );
-
-    return (wxClientData*) node->GetData();
-}
-
-void wxChoice::Clear()
+void wxChoice::DoClear()
 {
     wxCHECK_RET( m_widget != NULL, wxT("invalid choice") );
 
@@ -238,18 +215,6 @@ void wxChoice::Clear()
     GtkWidget *menu = gtk_menu_new();
     gtk_option_menu_set_menu( GTK_OPTION_MENU(m_widget), menu );
 
-    if ( HasClientObjectData() )
-    {
-        // destroy the data (due to Robert's idea of using wxList<wxObject>
-        // and not wxList<wxClientData> we can't just say
-        // m_clientList.DeleteContents(true) - this would crash!
-        wxList::compatibility_iterator node = m_clientList.GetFirst();
-        while ( node )
-        {
-            delete (wxClientData *)node->GetData();
-            node = node->GetNext();
-        }
-    }
     m_clientList.Clear();
 
     if ( m_strings )
@@ -259,15 +224,10 @@ void wxChoice::Clear()
     m_selection_hack = wxNOT_FOUND;
 }
 
-void wxChoice::Delete(unsigned int n)
+void wxChoice::DoDeleteOneItem(unsigned int n)
 {
     wxCHECK_RET( m_widget != NULL, wxT("invalid choice") );
 
-    // VZ: apparently GTK+ doesn't have a built-in function to do it (not even
-    //     in 2.0), hence this dumb implementation -- still better than nothing
-    unsigned int i;
-    unsigned int count = GetCount();
-
     wxCHECK_RET( IsValid(n), _T("invalid index in wxChoice::Delete") );
 
     // if the item to delete is before the selection, and the selection is valid
@@ -282,56 +242,31 @@ void wxChoice::Delete(unsigned int n)
         m_selection_hack = wxNOT_FOUND;
     }
 
-    const bool hasClientData = m_clientDataItemsType != wxClientData_None;
-    const bool hasObjectData = m_clientDataItemsType == wxClientData_Object;
+    // VZ: apparently GTK+ doesn't have a built-in function to do it (not even
+    //     in 2.0), hence this dumb implementation -- still better than nothing
+    const unsigned int count = GetCount();
 
     wxList::compatibility_iterator node = m_clientList.GetFirst();
 
     wxArrayString items;
     wxArrayPtrVoid itemsData;
     items.Alloc(count);
-    for ( i = 0; i < count; i++ )
+    for ( unsigned i = 0; i < count; i++, node = node->GetNext() )
     {
         if ( i != n )
         {
             items.Add(GetString(i));
-            if ( hasClientData )
-            {
-                // also save the client data
-                itemsData.Add(node->GetData());
-            }
-        }
-        else // need to delete the client object too
-        {
-            if ( hasObjectData )
-            {
-                delete (wxClientData *)node->GetData();
-            }
+            itemsData.Add(node->GetData());
         }
-
-        if ( hasClientData )
-        {
-            node = node->GetNext();
-        }
-    }
-
-    if ( hasObjectData )
-    {
-        // prevent Clear() from destroying all client data
-        m_clientDataItemsType = wxClientData_None;
     }
 
-    Clear();
-
-    for ( i = 0; i < count - 1; i++ )
-    {
-        Append(items[i]);
+    wxChoice::DoClear();
 
-        if ( hasObjectData )
-            SetClientObject(i, (wxClientData *)itemsData[i]);
-        else if ( hasClientData )
-            SetClientData(i, itemsData[i]);
-    }
+    void ** const data = &itemsData[0];
+    if ( HasClientObjectData() )
+        Append(items, wx_reinterpret_cast(wxClientData **, data));
+    else
+        Append(items, data);
 }
 
 int wxChoice::FindString( const wxString &string, bool bCase ) const
diff --git a/src/gtk1/combobox.cpp b/src/gtk1/combobox.cpp
index 3e519a1bc0..d6f65e2af7 100644
--- a/src/gtk1/combobox.cpp
+++ b/src/gtk1/combobox.cpp
@@ -317,7 +317,10 @@ void wxComboBox::SetFocus()
     gtk_widget_grab_focus( m_focusWidget );
 }
 
-int wxComboBox::DoAppend( const wxString &item )
+int wxComboBox::DoInsertItems(const wxArrayStringsAdapter& items,
+                              unsigned int pos,
+                              void **clientData,
+                              wxClientDataType type)
 {
     wxCHECK_MSG( m_widget != NULL, -1, wxT("invalid combobox") );
 
@@ -325,87 +328,58 @@ int wxComboBox::DoAppend( const wxString &item )
 
     GtkWidget *list = GTK_COMBO(m_widget)->list;
 
-    GtkWidget *list_item = gtk_list_item_new_with_label( wxGTK_CONV( item ) );
-
-    gtk_container_add( GTK_CONTAINER(list), list_item );
-
-    if (GTK_WIDGET_REALIZED(m_widget))
-    {
-        gtk_widget_realize( list_item );
-        gtk_widget_realize( GTK_BIN(list_item)->child );
-    }
-
-    // Apply current widget style to the new list_item
     GtkRcStyle *style = CreateWidgetStyle();
-    if (style)
-    {
-        gtk_widget_modify_style( GTK_WIDGET( list_item ), style );
-        GtkBin *bin = GTK_BIN( list_item );
-        GtkWidget *label = GTK_WIDGET( bin->child );
-        gtk_widget_modify_style( label, style );
-        gtk_rc_style_unref( style );
-    }
 
-    gtk_widget_show( list_item );
-
-    const unsigned int count = GetCount();
-
-    if ( m_clientDataList.GetCount() < count )
-        m_clientDataList.Append( (wxObject*) NULL );
-    if ( m_clientObjectList.GetCount() < count )
-        m_clientObjectList.Append( (wxObject*) NULL );
-
-    EnableEvents();
-
-    InvalidateBestSize();
-
-    return count - 1;
-}
-
-int wxComboBox::DoInsert( const wxString &item, unsigned int pos )
-{
-    wxCHECK_MSG( !(GetWindowStyle() & wxCB_SORT), -1,
-                    wxT("can't insert into sorted list"));
-
-    wxCHECK_MSG( m_widget != NULL, -1, wxT("invalid combobox") );
-
-    wxCHECK_MSG( IsValidInsert(pos), -1, wxT("invalid index") );
+    const unsigned int count = items.GetCount();
+    for( unsigned int i = 0; i < count; ++i, ++pos )
+    {
+        GtkWidget *
+            list_item = gtk_list_item_new_with_label( wxGTK_CONV( items[i] ) );
 
-    if (pos == GetCount())
-        return Append(item);
+        if ( pos == GetCount() )
+        {
+            gtk_container_add( GTK_CONTAINER(list), list_item );
+        }
+        else // insert, not append
+        {
+            GList *gitem_list = g_list_alloc ();
+            gitem_list->data = list_item;
+            gtk_list_insert_items( GTK_LIST (list), gitem_list, pos );
+        }
 
-    DisableEvents();
+        if (GTK_WIDGET_REALIZED(m_widget))
+        {
+            gtk_widget_realize( list_item );
+            gtk_widget_realize( GTK_BIN(list_item)->child );
 
-    GtkWidget *list = GTK_COMBO(m_widget)->list;
+            if (style)
+            {
+                gtk_widget_modify_style( GTK_WIDGET( list_item ), style );
+                GtkBin *bin = GTK_BIN( list_item );
+                GtkWidget *label = GTK_WIDGET( bin->child );
+                gtk_widget_modify_style( label, style );
+            }
 
-    GtkWidget *list_item = gtk_list_item_new_with_label( wxGTK_CONV( item ) );
+        }
 
-    GList *gitem_list = g_list_alloc ();
-    gitem_list->data = list_item;
-    gtk_list_insert_items( GTK_LIST (list), gitem_list, pos );
+        gtk_widget_show( list_item );
 
-    if (GTK_WIDGET_REALIZED(m_widget))
-    {
-        gtk_widget_realize( list_item );
-        gtk_widget_realize( GTK_BIN(list_item)->child );
+        if ( m_clientDataList.GetCount() < GetCount() )
+            m_clientDataList.Insert( pos, (wxObject*) NULL );
+        if ( m_clientObjectList.GetCount() < GetCount() )
+            m_clientObjectList.Insert( pos, (wxObject*) NULL );
 
-        ApplyWidgetStyle();
+        AssignNewItemClientData(pos, clientData, i, type);
     }
 
-    gtk_widget_show( list_item );
-
-    const unsigned int count = GetCount();
-
-    if ( m_clientDataList.GetCount() < count )
-        m_clientDataList.Insert( pos, (wxObject*) NULL );
-    if ( m_clientObjectList.GetCount() < count )
-        m_clientObjectList.Insert( pos, (wxObject*) NULL );
+    if ( style )
+        gtk_rc_style_unref( style );
 
     EnableEvents();
 
     InvalidateBestSize();
 
-    return pos;
+    return pos - 1;
 }
 
 void wxComboBox::DoSetItemClientData(unsigned int n, void* clientData)
@@ -427,28 +401,7 @@ void* wxComboBox::DoGetItemClientData(unsigned int n) const
     return node ? node->GetData() : NULL;
 }
 
-void wxComboBox::DoSetItemClientObject(unsigned int n, wxClientData* clientData)
-{
-    wxCHECK_RET( m_widget != NULL, wxT("invalid combobox") );
-
-    wxList::compatibility_iterator node = m_clientObjectList.Item( n );
-    if (!node) return;
-
-    // wxItemContainer already deletes data for us
-
-    node->SetData( (wxObject*) clientData );
-}
-
-wxClientData* wxComboBox::DoGetItemClientObject(unsigned int n) const
-{
-    wxCHECK_MSG( m_widget != NULL, (wxClientData*)NULL, wxT("invalid combobox") );
-
-    wxList::compatibility_iterator node = m_clientObjectList.Item( n );
-
-    return node ? (wxClientData*) node->GetData() : NULL;
-}
-
-void wxComboBox::Clear()
+void wxComboBox::DoClear()
 {
     wxCHECK_RET( m_widget != NULL, wxT("invalid combobox") );
 
@@ -457,13 +410,6 @@ void wxComboBox::Clear()
     GtkWidget *list = GTK_COMBO(m_widget)->list;
     gtk_list_clear_items( GTK_LIST(list), 0, (int)GetCount() );
 
-    wxList::compatibility_iterator node = m_clientObjectList.GetFirst();
-    while (node)
-    {
-        wxClientData *cd = (wxClientData*)node->GetData();
-        if (cd) delete cd;
-        node = node->GetNext();
-    }
     m_clientObjectList.Clear();
 
     m_clientDataList.Clear();
@@ -473,7 +419,7 @@ void wxComboBox::Clear()
     InvalidateBestSize();
 }
 
-void wxComboBox::Delete(unsigned int n)
+void wxComboBox::DoDeleteOneItem(unsigned int n)
 {
     wxCHECK_RET( m_widget != NULL, wxT("invalid combobox") );
 
@@ -496,8 +442,6 @@ void wxComboBox::Delete(unsigned int n)
     wxList::compatibility_iterator node = m_clientObjectList.Item( n );
     if (node)
     {
-        wxClientData *cd = (wxClientData*)node->GetData();
-        if (cd) delete cd;
         m_clientObjectList.Erase( node );
     }
 
diff --git a/src/gtk1/listbox.cpp b/src/gtk1/listbox.cpp
index 2cf833d0ac..93815ed498 100644
--- a/src/gtk1/listbox.cpp
+++ b/src/gtk1/listbox.cpp
@@ -541,7 +541,7 @@ bool wxListBox::Create( wxWindow *parent, wxWindowID id,
 
     if ( style & wxLB_SORT )
     {
-        // this will change DoAppend() behaviour
+        // this will change Append() behaviour
         m_strings = new wxSortedArrayString;
     }
     else
@@ -549,11 +549,7 @@ bool wxListBox::Create( wxWindow *parent, wxWindowID id,
         m_strings = (wxSortedArrayString *)NULL;
     }
 
-    for (int i = 0; i < n; i++)
-    {
-        // add one by one
-        DoAppend(choices[i]);
-    }
+    Append(n, choices);
 
     m_parent->DoAddChild( this );
 
@@ -577,101 +573,44 @@ wxListBox::~wxListBox()
 // adding items
 // ----------------------------------------------------------------------------
 
-void wxListBox::DoInsertItems(const wxArrayString& items, unsigned int pos)
+int wxListBox::DoInsertItems(const wxArrayStringsAdapter& items,
+                             unsigned int pos,
+                             void **clientData,
+                             wxClientDataType type)
 {
-    wxCHECK_RET( m_list != NULL, wxT("invalid listbox") );
+    wxCHECK_MSG( m_list != NULL, wxNOT_FOUND, wxT("invalid listbox") );
 
-    // VZ: notice that InsertItems knows nothing about sorting, so calling it
-    //     from outside (and not from our own Append) is likely to break
-    //     everything
+    const unsigned count = GetCount();
+    wxCHECK_MSG( pos <= count, wxNOT_FOUND,
+                    wxT("invalid index in wxListBox::InsertItems") );
 
     // code elsewhere supposes we have as many items in m_clientList as items
     // in the listbox
-    wxASSERT_MSG( m_clientList.GetCount() == GetCount(),
-                  wxT("bug in client data management") );
+    wxASSERT_MSG( m_clientList.GetCount() == count,
+                      wxT("bug in client data management") );
 
     InvalidateBestSize();
 
-    GList *children = m_list->children;
-    unsigned int length = g_list_length(children);
-
-    wxCHECK_RET( pos <= length, wxT("invalid index in wxListBox::InsertItems") );
+    const unsigned numItems = items.GetCount();
 
-    unsigned int nItems = items.GetCount();
-    int index;
-
-    if (m_strings)
+    for ( unsigned int n = 0; n < numItems; ++n, ++pos )
     {
-        for (unsigned int n = 0; n < nItems; n++)
-        {
-            index = m_strings->Add( items[n] );
+        const wxString& item = items[n];
 
-            if (index != (int)GetCount())
-            {
-                GtkAddItem( items[n], index );
-                wxList::compatibility_iterator node = m_clientList.Item( index );
-                m_clientList.Insert( node, (wxObject*) NULL );
-            }
-            else
-            {
-                GtkAddItem( items[n] );
-                m_clientList.Append( (wxObject*) NULL );
-            }
-        }
-    }
-    else
-    {
-        if (pos == length)
-        {
-            for ( unsigned int n = 0; n < nItems; n++ )
-            {
-                GtkAddItem( items[n] );
+        const unsigned idx = m_strings ? m_strings->Add(item)
+                                       : pos;
 
-                m_clientList.Append((wxObject *)NULL);
-            }
-        }
-        else
-        {
-            wxList::compatibility_iterator node = m_clientList.Item( pos );
-            for ( unsigned int n = 0; n < nItems; n++ )
-            {
-                GtkAddItem( items[n], pos+n );
+        GtkAddItem(item, idx == GetCount() ? -1 : idx);
 
-                m_clientList.Insert( node, (wxObject *)NULL );
-            }
-        }
+        m_clientList.Insert(idx, NULL);
+
+        AssignNewItemClientData(idx, clientData, n, type);
     }
 
     wxASSERT_MSG( m_clientList.GetCount() == GetCount(),
                       wxT("bug in client data management") );
-}
-
-int wxListBox::DoAppend( const wxString& item )
-{
-    InvalidateBestSize();
-
-    if (m_strings)
-    {
-        // need to determine the index
-        int index = m_strings->Add( item );
-
-        // only if not at the end anyway
-        if (index != (int)GetCount())
-        {
-           GtkAddItem( item, index );
 
-           wxList::compatibility_iterator node = m_clientList.Item( index );
-           m_clientList.Insert( node, (wxObject *)NULL );
-
-           return index;
-        }
-    }
-
-    GtkAddItem(item);
-
-    m_clientList.Append((wxObject *)NULL);
-
-    return GetCount() - 1;
+    return pos - 1;
 }
 
 void wxListBox::GtkAddItem( const wxString &item, int pos )
@@ -752,28 +691,11 @@ void wxListBox::GtkAddItem( const wxString &item, int pos )
     }
 }
 
-void wxListBox::DoSetItems( const wxArrayString& items,
-                            void **clientData)
-{
-    Clear();
-
-    DoInsertItems(items, 0);
-
-    if ( clientData )
-    {
-        unsigned int count = items.GetCount();
-        for ( unsigned int n = 0; n < count; n++ )
-        {
-            SetClientData(n, clientData[n]);
-        }
-    }
-}
-
 // ----------------------------------------------------------------------------
 // deleting items
 // ----------------------------------------------------------------------------
 
-void wxListBox::Clear()
+void wxListBox::DoClear()
 {
     wxCHECK_RET( m_list != NULL, wxT("invalid listbox") );
 
@@ -785,25 +707,13 @@ void wxListBox::Clear()
         GTK_LIST(m_list)->last_focus_child = NULL;
     }
 
-    if ( HasClientObjectData() )
-    {
-        // destroy the data (due to Robert's idea of using wxList<wxObject>
-        // and not wxList<wxClientData> we can't just say
-        // m_clientList.DeleteContents(true) - this would crash!
-        wxList::compatibility_iterator node = m_clientList.GetFirst();
-        while ( node )
-        {
-            delete (wxClientData *)node->GetData();
-            node = node->GetNext();
-        }
-    }
     m_clientList.Clear();
 
     if ( m_strings )
         m_strings->Clear();
 }
 
-void wxListBox::Delete(unsigned int n)
+void wxListBox::DoDeleteOneItem(unsigned int n)
 {
     wxCHECK_RET( m_list != NULL, wxT("invalid listbox") );
 
@@ -818,12 +728,6 @@ void wxListBox::Delete(unsigned int n)
     wxList::compatibility_iterator node = m_clientList.Item( n );
     if ( node )
     {
-        if ( m_clientDataItemsType == wxClientData_Object )
-        {
-            wxClientData *cd = (wxClientData*)node->GetData();
-            delete cd;
-        }
-
         m_clientList.Erase( node );
     }
 
@@ -855,29 +759,6 @@ void* wxListBox::DoGetItemClientData(unsigned int n) const
     return node->GetData();
 }
 
-void wxListBox::DoSetItemClientObject(unsigned int n, wxClientData* clientData)
-{
-    wxCHECK_RET( m_widget != NULL, wxT("invalid listbox control") );
-
-    wxList::compatibility_iterator node = m_clientList.Item( n );
-    wxCHECK_RET( node, wxT("invalid index in wxListBox::DoSetItemClientObject") );
-
-    // wxItemContainer already deletes data for us
-
-    node->SetData( (wxObject*) clientData );
-}
-
-wxClientData* wxListBox::DoGetItemClientObject(unsigned int n) const
-{
-    wxCHECK_MSG( m_widget != NULL, (wxClientData*) NULL, wxT("invalid listbox control") );
-
-    wxList::compatibility_iterator node = m_clientList.Item( n );
-    wxCHECK_MSG( node, (wxClientData *)NULL,
-                 wxT("invalid index in wxListBox::DoGetItemClientObject") );
-
-    return (wxClientData*) node->GetData();
-}
-
 // ----------------------------------------------------------------------------
 // string list access
 // ----------------------------------------------------------------------------
diff --git a/src/mac/carbon/choice.cpp b/src/mac/carbon/choice.cpp
index b0ba01d97d..13a5f77c37 100644
--- a/src/mac/carbon/choice.cpp
+++ b/src/mac/carbon/choice.cpp
@@ -50,11 +50,14 @@ bool wxChoice::Create(wxWindow *parent,
     const wxValidator& validator,
     const wxString& name )
 {
-    wxCArrayString chs( choices );
-
     return Create(
-        parent, id, pos, size, chs.GetCount(), chs.GetStrings(),
+        parent, id, pos, size, 0, NULL,
         style, validator, name );
+
+    Append( choices );
+
+    if ( !choices.empty() )
+        SetSelection( 0 );
 }
 
 bool wxChoice::Create(wxWindow *parent,
@@ -91,10 +94,7 @@ bool wxChoice::Create(wxWindow *parent,
         m_strings = wxArrayString( 1 );
 #endif
 
-    for ( int i = 0; i < n; i++ )
-    {
-        Append( choices[i] );
-    }
+    Append(n, choices);
 
     // Set the first item as being selected
     if (n > 0)
@@ -109,54 +109,45 @@ bool wxChoice::Create(wxWindow *parent,
 // ----------------------------------------------------------------------------
 // adding/deleting items to/from the list
 // ----------------------------------------------------------------------------
-int wxChoice::DoAppend( const wxString& item )
-{
-#if wxUSE_STL
-    wxArrayString::iterator insertPoint;
-    unsigned int index;
 
-    if (GetWindowStyle() & wxCB_SORT)
-    {
-        insertPoint = std::lower_bound( m_strings.begin(), m_strings.end(), item );
-        index = insertPoint - m_strings.begin();
-    }
-    else
+int wxChoice::DoInsertItems(const wxArrayStringsAdapter & items,
+                            unsigned int pos,
+                            void **clientData, wxClientDataType type)
+{
+    const unsigned int numItems = items.GetCount();
+    for( unsigned int i = 0; i < numItems; ++i, ++pos )
     {
-        insertPoint = m_strings.end();
-        index = m_strings.size();
-    }
-
-    m_strings.insert( insertPoint, item );
-#else
-    unsigned int index = m_strings.Add( item );
-#endif
-
-    m_datas.Insert( NULL , index );
-    UMAInsertMenuItem( MAC_WXHMENU( m_macPopUpMenuHandle ), item, m_font.GetEncoding(), index );
-    DoSetItemClientData( index, NULL );
-    m_peer->SetMaximum( GetCount() );
-
-    return index;
-}
+        unsigned int idx;
 
-int wxChoice::DoInsert( const wxString& item, unsigned int pos )
-{
-    wxCHECK_MSG( !(GetWindowStyle() & wxCB_SORT), -1, wxT("wxChoice::DoInsert: can't insert into sorted list") );
-    wxCHECK_MSG( IsValidInsert(pos), -1, wxT("wxChoice::DoInsert: invalid index") );
+#if wxUSE_STL
+        if ( IsSorted() )
+        {
+            wxArrayString::iterator
+                insertPoint = std::lower_bound( m_strings.begin(), m_strings.end(), items[i] );
+            idx = insertPoint - m_strings.begin();
+            m_strings.insert( insertPoint, items[i] );
+        }
+        else
+#endif // wxUSE_STL
+        {
+            idx = pos;
+            m_strings.Insert( items[i], idx );
+        }
 
-    if (pos == GetCount())
-        return DoAppend( item );
+        UMAInsertMenuItem(MAC_WXHMENU( m_macPopUpMenuHandle ),
+                          items[i],
+                          m_font.GetEncoding(),
+                          idx);
+        m_datas.Insert( NULL, idx );
+        AssignNewItemClientData(idx, clientData, i, type);
+    }
 
-    UMAInsertMenuItem( MAC_WXHMENU( m_macPopUpMenuHandle ), item, m_font.GetEncoding(), pos );
-    m_strings.Insert( item, pos );
-    m_datas.Insert( NULL, pos );
-    DoSetItemClientData( pos, NULL );
     m_peer->SetMaximum( GetCount() );
 
-    return pos;
+    return pos - 1;
 }
 
-void wxChoice::Delete(unsigned int n)
+void wxChoice::DoDeleteOneItem(unsigned int n)
 {
     wxCHECK_RET( IsValid(n) , wxT("wxChoice::Delete: invalid index") );
 
@@ -169,9 +160,8 @@ void wxChoice::Delete(unsigned int n)
     m_peer->SetMaximum( GetCount() ) ;
 }
 
-void wxChoice::Clear()
+void wxChoice::DoClear()
 {
-    FreeData();
     for ( unsigned int i = 0 ; i < GetCount() ; i++ )
     {
         ::DeleteMenuItem( MAC_WXHMENU(m_macPopUpMenuHandle) , 1 ) ;
@@ -182,18 +172,6 @@ void wxChoice::Clear()
     m_peer->SetMaximum( 0 ) ;
 }
 
-void wxChoice::FreeData()
-{
-    if ( HasClientObjectData() )
-    {
-        unsigned int count = GetCount();
-        for ( unsigned int n = 0; n < count; n++ )
-        {
-            delete GetClientObject( n );
-        }
-    }
-}
-
 // ----------------------------------------------------------------------------
 // selection
 // ----------------------------------------------------------------------------
@@ -220,7 +198,7 @@ int wxChoice::FindString( const wxString& s, bool bCase ) const
 {
 #if !wxUSE_STL
     // Avoid assert for non-default args passed to sorted array Index
-    if ( HasFlag(wxCB_SORT) )
+    if ( IsSorted() )
         bCase = true;
 #endif
 
@@ -261,16 +239,6 @@ void * wxChoice::DoGetItemClientData(unsigned int n) const
     return (void *)m_datas[n];
 }
 
-void wxChoice::DoSetItemClientObject(unsigned int n, wxClientData* clientData)
-{
-    DoSetItemClientData(n, clientData);
-}
-
-wxClientData* wxChoice::DoGetItemClientObject(unsigned int n) const
-{
-    return (wxClientData*)DoGetItemClientData( n ) ;
-}
-
 wxInt32 wxChoice::MacControlHit( WXEVENTHANDLERREF WXUNUSED(handler) , WXEVENTREF WXUNUSED(event) )
 {
     wxCommandEvent event( wxEVT_COMMAND_CHOICE_SELECTED, m_windowId );
diff --git a/src/mac/carbon/combobox.cpp b/src/mac/carbon/combobox.cpp
index eaf09763e2..1241f98b12 100644
--- a/src/mac/carbon/combobox.cpp
+++ b/src/mac/carbon/combobox.cpp
@@ -230,9 +230,6 @@ END_EVENT_TABLE()
 
 wxComboBox::~wxComboBox()
 {
-    // delete client objects
-    FreeData();
-
     // delete the controls now, don't leave them alive even though they would
     // still be eventually deleted by our parent - but it will be too late, the
     // user code expects them to be gone now
@@ -347,10 +344,8 @@ bool wxComboBox::Create(wxWindow *parent,
     const wxValidator& validator,
     const wxString& name)
 {
-    wxCArrayString chs( choices );
-
-    return Create( parent, id, value, pos, size, chs.GetCount(),
-                   chs.GetStrings(), style, validator, name );
+    return Create( parent, id, value, pos, size, 0, NULL,
+                   style, validator, name );
 }
 
 bool wxComboBox::Create(wxWindow *parent,
@@ -388,10 +383,7 @@ bool wxComboBox::Create(wxWindow *parent,
 
     DoSetSize(pos.x, pos.y, csize.x, csize.y);
 
-    for ( int i = 0 ; i < n ; i++ )
-    {
-        m_choice->DoAppend( choices[ i ] );
-    }
+    Append( n, choices );
 
     // Needed because it is a wxControlWithItems
     SetInitialSize(size);
@@ -510,59 +502,48 @@ void wxComboBox::SetSelection(long from, long to)
         m_text->SetSelection(from,to);
 }
 
-int wxComboBox::DoAppend(const wxString& item)
-{
-    return m_choice->DoAppend( item ) ;
-}
+int wxComboBox::DoInsertItems(const wxArrayStringsAdapter& items,
+                              unsigned int pos,
+                              void **clientData,
+                              wxClientDataType type)
+{
+    // wxItemContainer should probably be doing it itself but usually this is
+    // not necessary as the derived class DoInsertItems() calls
+    // AssignNewItemClientData() which initializes m_clientDataItemsType
+    // correctly; however as we just forward everything to wxChoice, we need to
+    // do it ourselves
+    //
+    // also notice that we never use wxClientData_Object with wxChoice as we
+    // don't want it to delete the data -- we will
+    int rc = m_choice->DoInsertItems(items, pos, clientData,
+                                     clientData ? wxClientData_Void
+                                                : wxClientData_None) ;
+    if ( rc != wxNOT_FOUND )
+    {
+        if ( !HasClientData() && type != wxClientData_None )
+            m_clientDataItemsType = type;
+    }
 
-int wxComboBox::DoInsert(const wxString& item, unsigned int pos)
-{
-    return m_choice->DoInsert( item , pos ) ;
+    return rc;
 }
 
 void wxComboBox::DoSetItemClientData(unsigned int n, void* clientData)
 {
-    return m_choice->DoSetItemClientData( n , clientData ) ;
+    return m_choice->SetClientData( n , clientData ) ;
 }
 
 void* wxComboBox::DoGetItemClientData(unsigned int n) const
 {
-    return m_choice->DoGetItemClientData( n ) ;
-}
-
-void wxComboBox::DoSetItemClientObject(unsigned int n, wxClientData* clientData)
-{
-    return m_choice->DoSetItemClientObject(n, clientData);
-}
-
-wxClientData* wxComboBox::DoGetItemClientObject(unsigned int n) const
-{
-    return m_choice->DoGetItemClientObject( n ) ;
-}
-
-void wxComboBox::FreeData()
-{
-    if ( HasClientObjectData() )
-    {
-        unsigned int count = GetCount();
-        for ( unsigned int n = 0; n < count; n++ )
-        {
-            SetClientObject( n, NULL );
-        }
-    }
+    return m_choice->GetClientData( n ) ;
 }
 
-void wxComboBox::Delete(unsigned int n)
+void wxComboBox::DoDeleteOneItem(unsigned int n)
 {
-    // force client object deletion
-    if( HasClientObjectData() )
-        SetClientObject( n, NULL );
     m_choice->Delete( n );
 }
 
-void wxComboBox::Clear()
+void wxComboBox::DoClear()
 {
-    FreeData();
     m_choice->Clear();
 }
 
diff --git a/src/mac/carbon/combobxc.cpp b/src/mac/carbon/combobxc.cpp
index 9a63c93e70..670cbf7b6d 100644
--- a/src/mac/carbon/combobxc.cpp
+++ b/src/mac/carbon/combobxc.cpp
@@ -216,9 +216,6 @@ END_EVENT_TABLE()
 
 wxComboBox::~wxComboBox()
 {
-    // delete client objects
-    FreeData();
-
     // delete the controls now, don't leave them alive even though they would
     // still be eventually deleted by our parent - but it will be too late, the
     // user code expects them to be gone now
@@ -386,10 +383,7 @@ bool wxComboBox::Create(wxWindow *parent, wxWindowID id,
 
     MacPostControlCreate(pos,size);
 
-    for ( int i = 0; i < n; i++ )
-    {
-        DoAppend( choices[ i ] );
-    }
+    Append( choices[ i ] );
 
     HIViewSetVisible( m_peer->GetControlRef(), true );
     SetSelection(0);
@@ -416,10 +410,7 @@ bool wxComboBox::Create(wxWindow *parent, wxWindowID id,
 
     DoSetSize(pos.x, pos.y, csize.x, csize.y);
 
-    for ( int i = 0; i < n; i++ )
-    {
-        m_choice->DoAppend( choices[ i ] );
-    }
+    m_choice->Append( n, choices );
     SetInitialSize(csize);   // Needed because it is a wxControlWithItems
 #endif
 
@@ -545,28 +536,26 @@ void wxComboBox::SetSelection(long from, long to)
     // TODO
 }
 
-int wxComboBox::DoAppend(const wxString& item)
+int wxComboBox::DoInsertItems(const wxArrayStringsAdapter& items,
+                              unsigned int pos,
+                              void **clientData, wxClientDataType type)
 {
 #if USE_HICOMBOBOX
-    CFIndex outIndex;
-    HIComboBoxAppendTextItem( m_peer->GetControlRef(), wxMacCFStringHolder( item, m_font.GetEncoding() ), &outIndex );
-    //SetControl32BitMaximum( m_peer->GetControlRef(), GetCount() );
-    return (int) outIndex;
-#else
-    return m_choice->DoAppend( item );
-#endif
-}
-
-int wxComboBox::DoInsert(const wxString& item, unsigned int pos)
-{
-#if USE_HICOMBOBOX
-    HIComboBoxInsertTextItemAtIndex( m_peer->GetControlRef(), (CFIndex)pos, wxMacCFStringHolder(item, m_font.GetEncoding()) );
+    const unsigned int count = items.GetCount();
+    for ( unsigned int i = 0; i < count; ++i, ++pos )
+    {
+        HIComboBoxInsertTextItemAtIndex(m_peer->GetControlRef(),
+                                        (CFIndex)pos,
+                                        wxMacCFStringHolder(items[i],
+                                                            m_font.GetEncoding()));
+        AssignNewItemClientData(pos, clientData, i, type);
+    }
 
     //SetControl32BitMaximum( m_peer->GetControlRef(), GetCount() );
 
-    return pos;
+    return pos - 1;
 #else
-    return m_choice->DoInsert( item , pos );
+    return m_choice->DoInsertItems( items, pos, clientData, type );
 #endif
 }
 
@@ -588,36 +577,6 @@ void* wxComboBox::DoGetItemClientData(unsigned int n) const
 #endif
 }
 
-void wxComboBox::DoSetItemClientObject(unsigned int n, wxClientData* clientData)
-{
-#if USE_HICOMBOBOX
-    return; //TODO
-#else
-    return m_choice->DoSetItemClientObject( n , clientData );
-#endif
-}
-
-wxClientData* wxComboBox::DoGetItemClientObject(unsigned int n) const
-{
-#if USE_HICOMBOBOX
-    return NULL;
-#else
-    return m_choice->DoGetItemClientObject( n );
-#endif
-}
-
-void wxComboBox::FreeData()
-{
-    if (HasClientObjectData())
-    {
-        unsigned int count = GetCount();
-        for ( unsigned int n = 0; n < count; n++ )
-        {
-            SetClientObject( n, NULL );
-        }
-    }
-}
-
 unsigned int wxComboBox::GetCount() const {
 #if USE_HICOMBOBOX
     return (unsigned int) HIComboBoxGetItemCount( m_peer->GetControlRef() );
@@ -626,21 +585,17 @@ unsigned int wxComboBox::GetCount() const {
 #endif
 }
 
-void wxComboBox::Delete(unsigned int n)
+void wxComboBox::DoDeleteOneItem(unsigned int n)
 {
 #if USE_HICOMBOBOX
     HIComboBoxRemoveItemAtIndex( m_peer->GetControlRef(), (CFIndex)n );
 #else
-    // force client object deletion
-    if( HasClientObjectData() )
-        SetClientObject( n, NULL );
     m_choice->Delete( n );
 #endif
 }
 
-void wxComboBox::Clear()
+void wxComboBox::DoClear()
 {
-    FreeData();
 #if USE_HICOMBOBOX
     for ( CFIndex i = GetCount() - 1; i >= 0; ++ i )
         verify_noerr( HIComboBoxRemoveItemAtIndex( m_peer->GetControlRef(), i ) );
diff --git a/src/mac/carbon/listbox.cpp b/src/mac/carbon/listbox.cpp
index 54717cfb18..74efe70511 100644
--- a/src/mac/carbon/listbox.cpp
+++ b/src/mac/carbon/listbox.cpp
@@ -87,7 +87,7 @@ bool wxListBox::Create(
 
     MacPostControlCreate( pos, size );
 
-    InsertItems( n, choices, 0 );
+    Append(n, choices);
 
    // Needed because it is a wxControlWithItems
     SetInitialSize( size );
@@ -116,36 +116,29 @@ void wxListBox::EnsureVisible(int n)
     GetPeer()->MacScrollTo( n );
 }
 
-void wxListBox::Delete(unsigned int n)
+void wxListBox::DoDeleteOneItem(unsigned int n)
 {
     wxCHECK_RET( IsValid(n), wxT("invalid index in wxListBox::Delete") );
 
     GetPeer()->MacDelete( n );
 }
 
-int wxListBox::DoAppend(const wxString& item)
+int wxListBox::DoInsertItems(const wxArrayStringsAdapter& items,
+                             unsigned int pos,
+                             void **clientData,
+                             wxClientDataType type)
 {
     InvalidateBestSize();
 
-    return GetPeer()->MacAppend( item );
-}
-
-void wxListBox::DoSetItems(const wxArrayString& choices, void** clientData)
-{
-    Clear();
-
-    unsigned int n = choices.GetCount();
-
-    for ( size_t i = 0; i < n; ++i )
+    GetPeer()->MacInsert( pos, items );
+    const unsigned int count = items.GetCount();
+    if ( clientData )
     {
-        if ( clientData )
-        {
-            Append( choices[i], clientData[i] );
-        }
-        else
-            Append( choices[i] );
+        for (unsigned int i = 0; i < count; ++i)
+            AssignNewItemClientData( pos + i, clientData, i, type );
     }
 
+    return pos + count - 1;
 }
 
 int wxListBox::FindString(const wxString& s, bool bCase) const
@@ -159,7 +152,7 @@ int wxListBox::FindString(const wxString& s, bool bCase) const
     return wxNOT_FOUND;
 }
 
-void wxListBox::Clear()
+void wxListBox::DoClear()
 {
     FreeData();
 }
@@ -188,22 +181,12 @@ void *wxListBox::DoGetItemClientData(unsigned int n) const
     return GetPeer()->MacGetClientData( n );
 }
 
-wxClientData *wxListBox::DoGetItemClientObject(unsigned int n) const
-{
-    return (wxClientData*)DoGetItemClientData( n );
-}
-
 void wxListBox::DoSetItemClientData(unsigned int n, void *clientData)
 {
     wxCHECK_RET( IsValid(n), wxT("invalid index in wxListBox::SetClientData") );
     GetPeer()->MacSetClientData( n , clientData);
 }
 
-void wxListBox::DoSetItemClientObject(unsigned int n, wxClientData* clientData)
-{
-    DoSetItemClientData(n, clientData);
-}
-
 // Return number of selections and an array of selected integers
 int wxListBox::GetSelections(wxArrayInt& aSelections) const
 {
@@ -223,15 +206,6 @@ wxString wxListBox::GetString(unsigned int n) const
     return GetPeer()->MacGetString(n);
 }
 
-void wxListBox::DoInsertItems(const wxArrayString& items, unsigned int pos)
-{
-    wxCHECK_RET( IsValidInsert(pos), wxT("invalid index in wxListBox::InsertItems") );
-
-    InvalidateBestSize();
-
-    GetPeer()->MacInsert( pos, items );
-}
-
 void wxListBox::SetString(unsigned int n, const wxString& s)
 {
     GetPeer()->MacSetString( n, s );
diff --git a/src/mac/carbon/utils.cpp b/src/mac/carbon/utils.cpp
index 9afe0b6d5b..55848f5799 100644
--- a/src/mac/carbon/utils.cpp
+++ b/src/mac/carbon/utils.cpp
@@ -2020,36 +2020,9 @@ void wxMacDataItemBrowserControl::MacDelete( unsigned int n )
     RemoveItem( wxMacDataBrowserRootContainer, item );
 }
 
-void wxMacDataItemBrowserControl::MacInsert( unsigned int n, const wxString& text, int column )
-{
-    wxMacDataItem* newItem = CreateItem();
-    newItem->SetLabel( text );
-    if ( column != -1 )
-        newItem->SetColumn( kMinColumnId + column );
-
-    if ( m_sortOrder == SortOrder_None )
-    {
-        // increase the order of the lines to be shifted
-        unsigned int lines = MacGetCount();
-        for ( unsigned int i = n; i < lines; ++i)
-        {
-            wxMacDataItem* iter = (wxMacDataItem*) GetItemFromLine(i);
-            iter->SetOrder( iter->GetOrder() + 1 );
-        }
-
-        SInt32 frontLineOrder = 0;
-        if ( n > 0 )
-        {
-            wxMacDataItem* iter = (wxMacDataItem*) GetItemFromLine(n-1);
-            frontLineOrder = iter->GetOrder();
-        }
-        newItem->SetOrder( frontLineOrder + 1 );
-    }
-
-    AddItem( wxMacDataBrowserRootContainer, newItem );
-}
-
-void wxMacDataItemBrowserControl::MacInsert( unsigned int n, const wxArrayString& items, int column )
+void wxMacDataItemBrowserControl::MacInsert( unsigned int n,
+                                             const wxArrayStringsAdapter& items,
+                                             int column )
 {
     size_t itemsCount = items.GetCount();
     if ( itemsCount == 0 )
diff --git a/src/motif/checklst.cpp b/src/motif/checklst.cpp
index 0205216a2b..b0e22aaefe 100644
--- a/src/motif/checklst.cpp
+++ b/src/motif/checklst.cpp
@@ -51,15 +51,6 @@ static inline const wxString& Prefix(bool checked)
 static inline bool IsChecked(const wxString& s)
     { wxASSERT(s.length() >=4); return s[1] == checkChar; }
 
-static void CopyStringsAddingPrefix(const wxArrayString& orig,
-                                    wxArrayString& copy)
-{
-    copy.Clear();
-
-    for(size_t i = 0; i < orig.GetCount(); ++i )
-        copy.Add( Prefix(false) + orig[i] );
-}
-
 // def ctor: use Create() to really create the control
 wxCheckListBox::wxCheckListBox() : wxCheckListBoxBase()
 {
@@ -154,11 +145,6 @@ void wxCheckListBox::DoToggleItem( int n, int x )
     }
 }
 
-int wxCheckListBox::DoAppend(const wxString& item)
-{
-    return wxListBox::DoAppend( Prefix(false) + item );
-}
-
 int wxCheckListBox::FindString(const wxString& s, bool bCase) const
 {
     int n1 = wxListBox::FindString(Prefix(false) + s, bCase);
@@ -183,18 +169,16 @@ wxString wxCheckListBox::GetString(unsigned int n) const
     return wxListBox::GetString(n).substr(4);
 }
 
-void wxCheckListBox::DoInsertItems(const wxArrayString& items, unsigned int pos)
+int wxCheckListBox::DoInsertItems(const wxArrayStringsAdapter& items,
+                                  unsigned int pos,
+                                  void **clientData, wxClientDataType type)
 {
     wxArrayString copy;
-    CopyStringsAddingPrefix(items, copy);
-    wxListBox::DoInsertItems(copy, pos);
-}
+    copy.reserve(pos);
+    for ( size_t i = 0; i < items.GetCount(); ++i )
+        copy.push_back( Prefix(false) + items[i] );
 
-void wxCheckListBox::DoSetItems(const wxArrayString& items, void **clientData)
-{
-    wxArrayString copy;
-    CopyStringsAddingPrefix(items, copy);
-    wxListBox::DoSetItems(copy, clientData);
+    return wxListBox::DoInsertItems(copy, pos, clientData, type);
 }
 
 #endif // wxUSE_CHECKLISTBOX
diff --git a/src/motif/choice.cpp b/src/motif/choice.cpp
index 6c7edaa117..bb1181f4fd 100644
--- a/src/motif/choice.cpp
+++ b/src/motif/choice.cpp
@@ -179,8 +179,6 @@ wxChoice::~wxChoice()
         m_mainWidget = (WXWidget) 0;
         m_buttonWidget = (WXWidget) 0;
     }
-    if ( HasClientObjectData() )
-        m_clientDataDict.DestroyData();
 }
 
 static inline wxChar* MYcopystring(const wxChar* s)
@@ -189,72 +187,78 @@ static inline wxChar* MYcopystring(const wxChar* s)
     return wxStrcpy(copy, s);
 }
 
-int wxChoice::DoInsert(const wxString& item, unsigned int pos)
+// TODO auto-sorting is not supported by the code
+int wxChoice::DoInsertItems(const wxArrayStringsAdapter& items,
+                            unsigned int pos,
+                            void **clientData, wxClientDataType type)
 {
 #ifndef XmNpositionIndex
     wxCHECK_MSG( pos == GetCount(), -1, wxT("insert not implemented"));
 #endif
-    Widget w = XtVaCreateManagedWidget (GetLabelText(item),
+
+    const unsigned int numItems = items.GetCount();
+    AllocClientData(numItems);
+    for( unsigned int i = 0; i < numItems; ++i, ++pos )
+    {
+        Widget w = XtVaCreateManagedWidget (GetLabelText(items[i]),
 #if wxUSE_GADGETS
-        xmPushButtonGadgetClass, (Widget) m_menuWidget,
+            xmPushButtonGadgetClass, (Widget) m_menuWidget,
 #else
-        xmPushButtonWidgetClass, (Widget) m_menuWidget,
+            xmPushButtonWidgetClass, (Widget) m_menuWidget,
 #endif
 #ifdef XmNpositionIndex
-        XmNpositionIndex, pos,
+            XmNpositionIndex, pos,
 #endif
-        NULL);
+            NULL);
 
-    wxDoChangeBackgroundColour((WXWidget) w, m_backgroundColour);
+        wxDoChangeBackgroundColour((WXWidget) w, m_backgroundColour);
 
-    if( m_font.Ok() )
-        wxDoChangeFont( w, m_font );
+        if( m_font.Ok() )
+            wxDoChangeFont( w, m_font );
 
-    m_widgetArray.Insert(w, pos);
+        m_widgetArray.Insert(w, pos);
 
-    char mnem = wxFindMnemonic (item);
-    if (mnem != 0)
-        XtVaSetValues (w, XmNmnemonic, mnem, NULL);
+        char mnem = wxFindMnemonic (items[i]);
+        if (mnem != 0)
+            XtVaSetValues (w, XmNmnemonic, mnem, NULL);
 
-    XtAddCallback (w, XmNactivateCallback,
-                   (XtCallbackProc) wxChoiceCallback,
-                   (XtPointer) this);
+        XtAddCallback (w, XmNactivateCallback,
+                       (XtCallbackProc) wxChoiceCallback,
+                       (XtPointer) this);
 
-    if (m_noStrings == 0 && m_buttonWidget)
-    {
-        XtVaSetValues ((Widget) m_buttonWidget, XmNmenuHistory, w, NULL);
-        Widget label = XmOptionButtonGadget ((Widget) m_buttonWidget);
-        wxXmString text( item );
-        XtVaSetValues (label,
-            XmNlabelString, text(),
-            NULL);
+        if (m_noStrings == 0 && m_buttonWidget)
+        {
+            XtVaSetValues ((Widget) m_buttonWidget, XmNmenuHistory, w, NULL);
+            Widget label = XmOptionButtonGadget ((Widget) m_buttonWidget);
+            wxXmString text( items[i] );
+            XtVaSetValues (label,
+                XmNlabelString, text(),
+                NULL);
+        }
+        // need to ditch wxStringList for wxArrayString
+        m_stringList.Insert(pos, MYcopystring(items[i]));
+        m_noStrings ++;
+
+        InsertNewItemClientData(pos, clientData, i, type);
     }
-    // need to ditch wxStringList for wxArrayString
-    m_stringList.Insert(pos, MYcopystring(item));
-    m_noStrings ++;
 
-    return pos;
+    return pos - 1;
 }
 
-int wxChoice::DoAppend(const wxString& item)
-{
-    return DoInsert(item, GetCount());
-}
-
-void wxChoice::Delete(unsigned int n)
+void wxChoice::DoDeleteOneItem(unsigned int n)
 {
     Widget w = (Widget)m_widgetArray[n];
     XtRemoveCallback(w, XmNactivateCallback, (XtCallbackProc)wxChoiceCallback,
                      (XtPointer)this);
     m_stringList.Erase(m_stringList.Item(n));
     m_widgetArray.RemoveAt(size_t(n));
-    m_clientDataDict.Delete(n, HasClientObjectData());
+    wxChoiceBase::DoDeleteOneItem(n);
 
     XtDestroyWidget(w);
     m_noStrings--;
 }
 
-void wxChoice::Clear()
+void wxChoice::DoClear()
 {
     m_stringList.Clear ();
     unsigned int i;
@@ -272,8 +276,7 @@ void wxChoice::Clear()
                        XmNmenuHistory, (Widget) NULL,
                        NULL);
 
-    if ( HasClientObjectData() )
-        m_clientDataDict.DestroyData();
+    wxChoiceBase::DoClear();
 
     m_noStrings = 0;
 }
@@ -502,27 +505,6 @@ unsigned int wxChoice::GetCount() const
     return m_noStrings;
 }
 
-void wxChoice::DoSetItemClientData(unsigned int n, void* clientData)
-{
-    m_clientDataDict.Set(n, (wxClientData*)clientData, false);
-}
-
-void* wxChoice::DoGetItemClientData(unsigned int n) const
-{
-    return (void*)m_clientDataDict.Get(n);
-}
-
-void wxChoice::DoSetItemClientObject(unsigned int n, wxClientData* clientData)
-{
-    // don't delete, wxItemContainer does that for us
-    m_clientDataDict.Set(n, clientData, false);
-}
-
-wxClientData* wxChoice::DoGetItemClientObject(unsigned int n) const
-{
-    return m_clientDataDict.Get(n);
-}
-
 void wxChoice::SetString(unsigned int WXUNUSED(n), const wxString& WXUNUSED(s))
 {
     wxFAIL_MSG( wxT("wxChoice::SetString not implemented") );
diff --git a/src/motif/combobox.cpp b/src/motif/combobox.cpp
index 313dde7628..4083a88ebd 100644
--- a/src/motif/combobox.cpp
+++ b/src/motif/combobox.cpp
@@ -111,8 +111,6 @@ wxComboBox::~wxComboBox()
     DetachWidget((Widget) m_mainWidget); // Removes event handlers
     XtDestroyWidget((Widget) m_mainWidget);
     m_mainWidget = (WXWidget) 0;
-    if ( HasClientObjectData() )
-        m_clientDataDict.DestroyData();
 }
 
 void wxComboBox::DoSetSize(int x, int y,
@@ -151,34 +149,29 @@ void wxComboBox::SetString(unsigned int WXUNUSED(n), const wxString& WXUNUSED(s)
     wxFAIL_MSG( wxT("wxComboBox::SetString only implemented for Motif 2.0") );
 }
 
-int wxComboBox::DoAppend(const wxString& item)
+// TODO auto-sorting is not supported by the code
+int wxComboBox::DoInsertItems(const wxArrayStringsAdapter& items,
+                              unsigned int pos,
+                              void **clientData,
+                              wxClientDataType type)
 {
-    wxXmString str( item.c_str() );
-    XmComboBoxAddItem((Widget) m_mainWidget, str(), 0);
-    m_stringList.Add(item);
-    m_noStrings ++;
+    const unsigned int numItems = items.GetCount();
 
-    return GetCount() - 1;
-}
-
-int wxComboBox::DoInsert(const wxString& item, unsigned int pos)
-{
-    wxCHECK_MSG(!(GetWindowStyle() & wxCB_SORT), -1, wxT("can't insert into sorted list"));
-    wxCHECK_MSG(IsValidInsert(pos), -1, wxT("invalid index"));
-
-    if (pos == GetCount())
-        return DoAppend(item);
-
-    wxXmString str( item.c_str() );
-    XmComboBoxAddItem((Widget) m_mainWidget, str(), pos+1);
-    wxChar* copy = wxStrcpy(new wxChar[item.length() + 1], item.c_str());
-    m_stringList.Insert(pos, copy);
-    m_noStrings ++;
+    AllocClientData(numItems);
+    for( unsigned int i = 0; i < numItems; ++i, ++pos )
+    {
+        wxXmString str( items[i].c_str() );
+        XmComboBoxAddItem((Widget) m_mainWidget, str(), GetMotifPosition(pos));
+        wxChar* copy = wxStrcpy(new wxChar[items[i].length() + 1], items[i].c_str());
+        m_stringList.Insert(pos, copy);
+        m_noStrings ++;
+        InsertNewItemClientData(pos, clientData, i, type);
+    }
 
-    return pos;
+    return pos - 1;
 }
 
-void wxComboBox::Delete(unsigned int n)
+void wxComboBox::DoDeleteOneItem(unsigned int n)
 {
     XmComboBoxDeletePos((Widget) m_mainWidget, n+1);
     wxStringList::Node *node = m_stringList.Item(n);
@@ -187,17 +180,16 @@ void wxComboBox::Delete(unsigned int n)
         delete[] node->GetData();
         delete node;
     }
-    m_clientDataDict.Delete(n, HasClientObjectData());
+    wxControlWithItems::DoDeleteOneItem(n);
     m_noStrings--;
 }
 
-void wxComboBox::Clear()
+void wxComboBox::DoClear()
 {
     XmComboBoxDeleteAllItems((Widget) m_mainWidget);
     m_stringList.Clear();
 
-    if ( HasClientObjectData() )
-        m_clientDataDict.DestroyData();
+    wxControlWithItems::DoClear();
     m_noStrings = 0;
 }
 
diff --git a/src/motif/combobox_native.cpp b/src/motif/combobox_native.cpp
index 0caced91fd..959b1581ae 100644
--- a/src/motif/combobox_native.cpp
+++ b/src/motif/combobox_native.cpp
@@ -161,8 +161,6 @@ wxComboBox::~wxComboBox()
     DetachWidget((Widget) m_mainWidget); // Removes event handlers
     XtDestroyWidget((Widget) m_mainWidget);
     m_mainWidget = (WXWidget) 0;
-    if ( HasClientObjectData() )
-        m_clientDataDict.DestroyData();
 }
 
 void wxComboBox::DoSetSize(int x, int y, int width, int WXUNUSED(height), int sizeFlags)
@@ -202,33 +200,28 @@ void wxComboBox::SetValue(const wxString& value)
     m_inSetValue = false;
 }
 
-int wxComboBox::DoAppend(const wxString& item)
+int wxComboBox::DoInsertItems(const wxArrayStringsAdapter & items,
+                              unsigned int pos,
+                              void **clientData, wxClientDataType type)
 {
-    wxXmString str( item.c_str() );
-    XmComboBoxAddItem((Widget) m_mainWidget, str(), 0, False);
-    m_noStrings ++;
-    AdjustDropDownListSize();
-
-    return GetCount() - 1;
-}
+    const unsigned int numItems = items.GetCount();
 
-int wxComboBox::DoInsert(const wxString& item, unsigned int pos)
-{
-    wxCHECK_MSG(!(GetWindowStyle() & wxCB_SORT), -1, wxT("can't insert into sorted list"));
-    wxCHECK_MSG(IsValidInsert(pos), -1, wxT("invalid index"));
-
-    if (pos == GetCount())
-        return DoAppend(item);
+    AllocClientData(numItems);
+    for ( unsigned int i = 0; i < numItems; ++i, ++pos )
+    {
+        wxXmString str( items[i].c_str() );
+        XmComboBoxAddItem((Widget) m_mainWidget, str(),
+                          GetMotifPosition(pos), False);
+        m_noStrings ++;
+        InsertNewItemClientData(pos, clientData, i, type);
+    }
 
-    wxXmString str( item.c_str() );
-    XmComboBoxAddItem((Widget) m_mainWidget, str(), pos+1, False);
-    m_noStrings ++;
     AdjustDropDownListSize();
 
-    return GetCount() - 1;
+    return pos - 1;
 }
 
-void wxComboBox::Delete(unsigned int n)
+void wxComboBox::DoDeleteOneItem(unsigned int n)
 {
 #ifdef LESSTIF_VERSION
     XmListDeletePos (GetXmList(this), n + 1);
@@ -236,13 +229,13 @@ void wxComboBox::Delete(unsigned int n)
     XmComboBoxDeletePos((Widget) m_mainWidget, n+1);
 #endif
 
-    m_clientDataDict.Delete(n, HasClientObjectData());
+    wxControlWithItems::DoDeleteOneItem(n);
     m_noStrings--;
 
     AdjustDropDownListSize();
 }
 
-void wxComboBox::Clear()
+void wxComboBox::DoClear()
 {
 #ifdef LESSTIF_VERSION
     XmListDeleteAllItems (GetXmList(this));
@@ -253,8 +246,7 @@ void wxComboBox::Clear()
     }
 #endif
 
-    if ( HasClientObjectData() )
-        m_clientDataDict.DestroyData();
+    wxControlWithItems::DoClear();
     m_noStrings = 0;
     AdjustDropDownListSize();
 }
diff --git a/src/motif/listbox.cpp b/src/motif/listbox.cpp
index fc729fba27..d20f37dfcb 100644
--- a/src/motif/listbox.cpp
+++ b/src/motif/listbox.cpp
@@ -171,12 +171,6 @@ bool wxListBox::Create(wxWindow *parent, wxWindowID id,
                   style, validator, name);
 }
 
-wxListBox::~wxListBox()
-{
-    if( HasClientObjectData() )
-        m_clientDataDict.DestroyData();
-}
-
 void wxListBox::SetSelectionPolicy()
 {
     Widget listBox = (Widget)m_mainWidget;
@@ -208,63 +202,16 @@ void wxListBox::DoSetFirstItem( int N )
     XmListSetPos ((Widget) m_mainWidget, N + 1);
 }
 
-void wxListBox::Delete(unsigned int n)
+void wxListBox::DoDeleteOneItem(unsigned int n)
 {
     Widget listBox = (Widget) m_mainWidget;
 
     XmListDeletePos (listBox, n + 1);
 
-    m_clientDataDict.Delete(n, HasClientObjectData());
+    wxListBoxBase::DoDeleteOneItem(n);
     m_noItems --;
 }
 
-int wxListBox::DoAppend(const wxString& item)
-{
-    Widget listBox = (Widget) m_mainWidget;
-
-    int n;
-    XtVaGetValues (listBox, XmNitemCount, &n, NULL);
-    wxXmString text( item );
-    //  XmListAddItem(listBox, text, n + 1);
-    XmListAddItemUnselected (listBox, text(), 0);
-
-    // It seems that if the list is cleared, we must re-ask for
-    // selection policy!!
-    SetSelectionPolicy();
-
-    m_noItems ++;
-
-    return GetCount() - 1;
-}
-
-void wxListBox::DoSetItems(const wxArrayString& items, void** clientData)
-{
-    Widget listBox = (Widget) m_mainWidget;
-
-    if( HasClientObjectData() )
-        m_clientDataDict.DestroyData();
-
-    XmString *text = new XmString[items.GetCount()];
-    unsigned int i;
-    for (i = 0; i < items.GetCount(); ++i)
-        text[i] = wxStringToXmString (items[i]);
-
-    if ( clientData )
-        for (i = 0; i < items.GetCount(); ++i)
-            m_clientDataDict.Set(i, (wxClientData*)clientData[i], false);
-
-    XmListAddItems (listBox, text, items.GetCount(), 0);
-    for (i = 0; i < items.GetCount(); i++)
-        XmStringFree (text[i]);
-    delete[] text;
-
-    // It seems that if the list is cleared, we must re-ask for
-    // selection policy!!
-    SetSelectionPolicy();
-
-    m_noItems = items.GetCount();
-}
-
 int wxDoFindStringInList(Widget w, const wxString& s)
 {
     wxXmString str( s );
@@ -290,20 +237,19 @@ int wxListBox::FindString(const wxString& s, bool WXUNUSED(bCase)) const
     return wxDoFindStringInList( (Widget)m_mainWidget, s );
 }
 
-void wxListBox::Clear()
+void wxListBox::DoClear()
 {
-    if (m_noItems <= 0)
+    if (!m_noItems)
         return;
 
     wxSizeKeeper sk( this );
     Widget listBox = (Widget) m_mainWidget;
 
     XmListDeleteAllItems (listBox);
-    if( HasClientObjectData() )
-        m_clientDataDict.DestroyData();
 
     sk.Restore();
 
+    wxListBoxBase::DoClear();
     m_noItems = 0;
 }
 
@@ -364,26 +310,6 @@ bool wxListBox::IsSelected(int N) const
     return false;
 }
 
-void wxListBox::DoSetItemClientObject(unsigned int n, wxClientData* clientData)
-{
-    m_clientDataDict.Set(n, clientData, false);
-}
-
-wxClientData* wxListBox::DoGetItemClientObject(unsigned int n) const
-{
-    return m_clientDataDict.Get(n);
-}
-
-void *wxListBox::DoGetItemClientData(unsigned int n) const
-{
-    return (void*)m_clientDataDict.Get(n);
-}
-
-void wxListBox::DoSetItemClientData(unsigned int n, void *Client_data)
-{
-    m_clientDataDict.Set(n, (wxClientData*)Client_data, false);
-}
-
 // Return number of selections and an array of selected integers
 int wxListBox::GetSelections(wxArrayInt& aSelections) const
 {
@@ -456,36 +382,43 @@ wxString wxListBox::GetString(unsigned int n) const
     return wxDoGetStringInList( (Widget)m_mainWidget, n );
 }
 
-void wxListBox::DoInsertItems(const wxArrayString& items, unsigned int pos)
+int wxListBox::DoInsertItems(const wxArrayStringsAdapter & items,
+                             unsigned int pos,
+                             void **clientData, wxClientDataType type)
 {
     Widget listBox = (Widget) m_mainWidget;
 
-    XmString *text = new XmString[items.GetCount()];
+    const unsigned int numItems = items.GetCount();
+
+    XmString *text = new XmString[numItems];
     unsigned int i;
-    // Steve Hammes: Motif 1.1 compatibility
-    // #if XmVersion > 1100
-    // Corrected by Sergey Krasnov from Steve Hammes' code
 #if XmVersion > 1001
-    for (i = 0; i < items.GetCount(); i++)
+    for (i = 0; i < numItems; i++)
+    {
         text[i] = wxStringToXmString(items[i]);
-    XmListAddItemsUnselected(listBox, text, items.GetCount(), pos+1);
+    }
+    XmListAddItemsUnselected(listBox, text, numItems, GetMotifPosition(pos));
+    InsertNewItemsClientData(pos, numItems, clientData, type);
 #else
-    for (i = 0; i < items.GetCount(); i++)
+    AllocClientData(numItems);
+
+    unsigned int idx = pos;
+    for ( i = 0; i < numItems; i++, idx++ )
     {
         text[i] = wxStringToXmString(items[i]);
-        // Another Sergey correction
-        XmListAddItemUnselected(listBox, text[i], pos+i+1);
+        XmListAddItemUnselected(listBox, text[i], GetMotifPosition(idx));
+        InsertNewItemClientData(idx, clientData, i, type);
     }
 #endif
-    for (i = 0; i < items.GetCount(); i++)
+    for (i = 0; i < numItems; i++)
         XmStringFree(text[i]);
     delete[] text;
 
-    // It seems that if the list is cleared, we must re-ask for
-    // selection policy!!
+    m_noItems += numItems;
+
     SetSelectionPolicy();
 
-    m_noItems += items.GetCount();
+    return pos + numItems - 1;
 }
 
 void wxListBox::SetString(unsigned int n, const wxString& s)
diff --git a/src/msw/choice.cpp b/src/msw/choice.cpp
index 4af53089a6..4d834267cd 100644
--- a/src/msw/choice.cpp
+++ b/src/msw/choice.cpp
@@ -211,63 +211,56 @@ WXDWORD wxChoice::MSWGetStyle(long style, WXDWORD *exstyle) const
 
 wxChoice::~wxChoice()
 {
-    Free();
+    Clear();
 }
 
 // ----------------------------------------------------------------------------
 // adding/deleting items to/from the list
 // ----------------------------------------------------------------------------
 
-int wxChoice::DoAppend(const wxString& item)
+int wxChoice::DoInsertItems(const wxArrayStringsAdapter& items,
+                            unsigned int pos,
+                            void **clientData, wxClientDataType type)
 {
-    int n = (int)SendMessage(GetHwnd(), CB_ADDSTRING, 0,
-                             (LPARAM)item.wx_str());
-    if ( n == CB_ERR )
-    {
-        wxLogLastError(wxT("SendMessage(CB_ADDSTRING)"));
-    }
-    else // ok
-    {
-        // we need to refresh our size in order to have enough space for the
-        // newly added items
-        if ( !IsFrozen() )
-            UpdateVisibleHeight();
-    }
+    MSWAllocStorage(items, CB_INITSTORAGE);
 
-    InvalidateBestSize();
-    return n;
-}
+    const bool append = pos == GetCount();
 
-int wxChoice::DoInsert(const wxString& item, unsigned int pos)
-{
-    wxCHECK_MSG(!(GetWindowStyle() & wxCB_SORT), -1, wxT("can't insert into sorted list"));
-    wxCHECK_MSG(IsValidInsert(pos), -1, wxT("invalid index"));
+    // use CB_ADDSTRING when appending at the end to make sure the control is
+    // resorted if it has wxCB_SORT style
+    const unsigned msg = append ? CB_ADDSTRING : CB_INSERTSTRING;
 
-    int n = (int)SendMessage(GetHwnd(), CB_INSERTSTRING, pos,
-                             (LPARAM)item.wx_str());
-    if ( n == CB_ERR )
-    {
-        wxLogLastError(wxT("SendMessage(CB_INSERTSTRING)"));
-    }
-    else // ok
+    if ( append )
+        pos = 0;
+
+    int n = wxNOT_FOUND;
+    const unsigned numItems = items.GetCount();
+    for ( unsigned i = 0; i < numItems; ++i )
     {
-        if ( !IsFrozen() )
-            UpdateVisibleHeight();
+        n = MSWInsertOrAppendItem(pos, items[i], msg);
+        if ( n == wxNOT_FOUND )
+            return n;
+
+        if ( !append )
+            pos++;
+
+        AssignNewItemClientData(n, clientData, i, type);
     }
 
+    // we need to refresh our size in order to have enough space for the
+    // newly added items
+    if ( !IsFrozen() )
+        UpdateVisibleHeight();
+
     InvalidateBestSize();
+
     return n;
 }
 
-void wxChoice::Delete(unsigned int n)
+void wxChoice::DoDeleteOneItem(unsigned int n)
 {
     wxCHECK_RET( IsValid(n), wxT("invalid item index in wxChoice::Delete") );
 
-    if ( HasClientObjectData() )
-    {
-        delete GetClientObject(n);
-    }
-
     SendMessage(GetHwnd(), CB_DELETESTRING, n, 0);
 
     if ( !IsFrozen() )
@@ -276,10 +269,8 @@ void wxChoice::Delete(unsigned int n)
     InvalidateBestSize();
 }
 
-void wxChoice::Clear()
+void wxChoice::DoClear()
 {
-    Free();
-
     SendMessage(GetHwnd(), CB_RESETCONTENT, 0, 0);
 
     if ( !IsFrozen() )
@@ -288,18 +279,6 @@ void wxChoice::Clear()
     InvalidateBestSize();
 }
 
-void wxChoice::Free()
-{
-    if ( HasClientObjectData() )
-    {
-        unsigned int count = GetCount();
-        for ( unsigned int n = 0; n < count; n++ )
-        {
-            delete GetClientObject(n);
-        }
-    }
-}
-
 // ----------------------------------------------------------------------------
 // selection
 // ----------------------------------------------------------------------------
@@ -456,16 +435,6 @@ void* wxChoice::DoGetItemClientData(unsigned int n) const
     return (void *)rc;
 }
 
-void wxChoice::DoSetItemClientObject(unsigned int n, wxClientData* clientData)
-{
-    DoSetItemClientData(n, clientData);
-}
-
-wxClientData* wxChoice::DoGetItemClientObject(unsigned int n) const
-{
-    return (wxClientData *)DoGetItemClientData(n);
-}
-
 // ----------------------------------------------------------------------------
 // wxMSW specific helpers
 // ----------------------------------------------------------------------------
diff --git a/src/msw/control.cpp b/src/msw/control.cpp
index 030a55f704..2b4eb28cd8 100644
--- a/src/msw/control.cpp
+++ b/src/msw/control.cpp
@@ -35,6 +35,7 @@
     #include "wx/dcclient.h"
     #include "wx/log.h"
     #include "wx/settings.h"
+    #include "wx/ctrlsub.h"
 #endif
 
 #if wxUSE_LISTCTRL
@@ -433,6 +434,41 @@ WXHBRUSH wxControl::MSWControlColorDisabled(WXHDC pDC)
                              GetHWND());
 }
 
+// ----------------------------------------------------------------------------
+// wxControlWithItems
+// ----------------------------------------------------------------------------
+
+void wxControlWithItems::MSWAllocStorage(const wxArrayStringsAdapter& items,
+                                         unsigned wm)
+{
+    const unsigned numItems = items.GetCount();
+    unsigned long totalTextLength = numItems; // for trailing '\0' characters
+    for ( unsigned i = 0; i < numItems; ++i )
+    {
+        totalTextLength += items[i].length();
+    }
+
+    if ( SendMessage(MSWGetItemsHWND(), wm, numItems,
+                     (LPARAM)totalTextLength*sizeof(wxChar)) == LB_ERRSPACE )
+    {
+        wxLogLastError(wxT("SendMessage(XX_INITSTORAGE)"));
+    }
+}
+
+int wxControlWithItems::MSWInsertOrAppendItem(unsigned pos,
+                                              const wxString& item,
+                                              unsigned wm)
+{
+    LRESULT n = SendMessage(MSWGetItemsHWND(), wm, pos, (LPARAM)item.wx_str());
+    if ( n == CB_ERR || n == CB_ERRSPACE )
+    {
+        wxLogLastError(wxT("SendMessage(XX_ADD/INSERTSTRING)"));
+        return wxNOT_FOUND;
+    }
+
+    return n;
+}
+
 // ---------------------------------------------------------------------------
 // global functions
 // ---------------------------------------------------------------------------
diff --git a/src/msw/datectrl.cpp b/src/msw/datectrl.cpp
index d6a4315352..58a3b435c2 100644
--- a/src/msw/datectrl.cpp
+++ b/src/msw/datectrl.cpp
@@ -263,6 +263,8 @@ void wxDatePickerCtrl::SetValue(const wxDateTime& dt)
         m_date.ResetTime();
 }
 
+#include <iostream>
+
 wxDateTime wxDatePickerCtrl::GetValue() const
 {
 #ifdef __WXDEBUG__
diff --git a/src/msw/dir.cpp b/src/msw/dir.cpp
index ae9d7ddb9b..5525d72a61 100644
--- a/src/msw/dir.cpp
+++ b/src/msw/dir.cpp
@@ -201,7 +201,7 @@ bool wxDirData::Read(wxString *filename)
 
         if ( err != ERROR_FILE_NOT_FOUND && err != ERROR_NO_MORE_FILES )
         {
-            wxLogSysError(err, wxString(_("Can not enumerate files in directory '%s'")),
+            wxLogSysError(err, _("Can not enumerate files in directory '%s'"),
                           m_dirname.c_str());
         }
 #endif // __WIN32__
diff --git a/src/msw/listbox.cpp b/src/msw/listbox.cpp
index 698d03d610..3f85f6bbb7 100644
--- a/src/msw/listbox.cpp
+++ b/src/msw/listbox.cpp
@@ -256,93 +256,17 @@ void wxListBox::DoSetFirstItem(int N)
     SendMessage(GetHwnd(), LB_SETTOPINDEX, (WPARAM)N, (LPARAM)0);
 }
 
-void wxListBox::Delete(unsigned int n)
+void wxListBox::DoDeleteOneItem(unsigned int n)
 {
     wxCHECK_RET( IsValid(n),
                  wxT("invalid index in wxListBox::Delete") );
 
-    // for owner drawn objects, the data is used for storing wxOwnerDrawn
-    // pointers and we shouldn't touch it
-#if !wxUSE_OWNER_DRAWN
-    if ( !(m_windowStyle & wxLB_OWNERDRAW) )
-#endif // !wxUSE_OWNER_DRAWN
-        if ( HasClientObjectData() )
-        {
-            delete GetClientObject(n);
-        }
-
     SendMessage(GetHwnd(), LB_DELETESTRING, n, 0);
     m_noItems--;
 
     SetHorizontalExtent(wxEmptyString);
 }
 
-int wxListBox::DoAppend(const wxString& item)
-{
-    int index = ListBox_AddString(GetHwnd(), item.wx_str());
-    m_noItems++;
-
-#if wxUSE_OWNER_DRAWN
-    if ( m_windowStyle & wxLB_OWNERDRAW ) {
-        wxOwnerDrawn *pNewItem = CreateLboxItem(index); // dummy argument
-        pNewItem->SetName(item);
-        m_aItems.Insert(pNewItem, index);
-        ListBox_SetItemData(GetHwnd(), index, pNewItem);
-        pNewItem->SetFont(GetFont());
-    }
-#endif // wxUSE_OWNER_DRAWN
-
-    SetHorizontalExtent(item);
-
-    return index;
-}
-
-void wxListBox::DoSetItems(const wxArrayString& choices, void** clientData)
-{
-    // avoid flicker - but don't need to do this for a hidden listbox
-    bool hideAndShow = IsShown();
-    if ( hideAndShow )
-    {
-        ShowWindow(GetHwnd(), SW_HIDE);
-    }
-
-    ListBox_ResetContent(GetHwnd());
-
-    m_noItems = choices.GetCount();
-    unsigned int i;
-    for (i = 0; i < m_noItems; i++)
-    {
-        ListBox_AddString(GetHwnd(), choices[i].wx_str());
-        if ( clientData )
-        {
-            SetClientData(i, clientData[i]);
-        }
-    }
-
-#if wxUSE_OWNER_DRAWN
-    if ( m_windowStyle & wxLB_OWNERDRAW ) {
-        // first delete old items
-        WX_CLEAR_ARRAY(m_aItems);
-
-        // then create new ones
-        for ( unsigned int ui = 0; ui < m_noItems; ui++ ) {
-            wxOwnerDrawn *pNewItem = CreateLboxItem(ui);
-            pNewItem->SetName(choices[ui]);
-            m_aItems.Add(pNewItem);
-            ListBox_SetItemData(GetHwnd(), ui, pNewItem);
-        }
-    }
-#endif // wxUSE_OWNER_DRAWN
-
-    SetHorizontalExtent();
-
-    if ( hideAndShow )
-    {
-        // show the listbox back if we hid it
-        ShowWindow(GetHwnd(), SW_SHOW);
-    }
-}
-
 int wxListBox::FindString(const wxString& s, bool bCase) const
 {
     // back to base class search for not native search type
@@ -356,7 +280,7 @@ int wxListBox::FindString(const wxString& s, bool bCase) const
         return pos;
 }
 
-void wxListBox::Clear()
+void wxListBox::DoClear()
 {
     Free();
 
@@ -373,15 +297,7 @@ void wxListBox::Free()
     {
         WX_CLEAR_ARRAY(m_aItems);
     }
-    else
 #endif // wxUSE_OWNER_DRAWN
-    if ( HasClientObjectData() )
-    {
-        for ( unsigned int n = 0; n < m_noItems; n++ )
-        {
-            delete GetClientObject(n);
-        }
-    }
 }
 
 void wxListBox::DoSetSelection(int N, bool select)
@@ -407,11 +323,6 @@ bool wxListBox::IsSelected(int N) const
     return SendMessage(GetHwnd(), LB_GETSEL, N, 0) == 0 ? false : true;
 }
 
-wxClientData* wxListBox::DoGetItemClientObject(unsigned int n) const
-{
-    return (wxClientData *)DoGetItemClientData(n);
-}
-
 void *wxListBox::DoGetItemClientData(unsigned int n) const
 {
     wxCHECK_MSG( IsValid(n), NULL,
@@ -420,11 +331,6 @@ void *wxListBox::DoGetItemClientData(unsigned int n) const
     return (void *)SendMessage(GetHwnd(), LB_GETITEMDATA, n, 0);
 }
 
-void wxListBox::DoSetItemClientObject(unsigned int n, wxClientData* clientData)
-{
-    DoSetItemClientData(n, clientData);
-}
-
 void wxListBox::DoSetItemClientData(unsigned int n, void *clientData)
 {
     wxCHECK_RET( IsValid(n),
@@ -511,35 +417,53 @@ wxString wxListBox::GetString(unsigned int n) const
     return result;
 }
 
-void
-wxListBox::DoInsertItems(const wxArrayString& items, unsigned int pos)
+int wxListBox::DoInsertItems(const wxArrayStringsAdapter & items,
+                             unsigned int pos,
+                             void **clientData,
+                             wxClientDataType type)
 {
-    wxCHECK_RET( IsValidInsert(pos),
-                 wxT("invalid index in wxListBox::InsertItems") );
+    MSWAllocStorage(items, LB_INITSTORAGE);
+
+    const bool append = pos == GetCount();
+
+    // we must use CB_ADDSTRING when appending as only it works correctly for
+    // the sorted controls
+    const unsigned msg = append ? LB_ADDSTRING : LB_INSERTSTRING;
 
-    unsigned int nItems = items.GetCount();
-    for ( unsigned int i = 0; i < nItems; i++ )
+    if ( append )
+        pos = 0;
+
+    int n = wxNOT_FOUND;
+
+    const unsigned int numItems = items.GetCount();
+    for ( unsigned int i = 0; i < numItems; i++ )
     {
-        int idx = ListBox_InsertString(GetHwnd(), i + pos, items[i].wx_str());
+        n = MSWInsertOrAppendItem(pos, items[i], msg);
+        if ( n == wxNOT_FOUND )
+            return n;
+
+        if ( !append )
+            pos++;
+
+        ++m_noItems;
 
 #if wxUSE_OWNER_DRAWN
-        if ( m_windowStyle & wxLB_OWNERDRAW )
+        if ( HasFlag(wxLB_OWNERDRAW) )
         {
-            wxOwnerDrawn *pNewItem = CreateLboxItem(idx);
+            wxOwnerDrawn *pNewItem = CreateLboxItem(n);
             pNewItem->SetName(items[i]);
             pNewItem->SetFont(GetFont());
-            m_aItems.Insert(pNewItem, idx);
+            m_aItems.Insert(pNewItem, n);
 
-            ListBox_SetItemData(GetHwnd(), idx, pNewItem);
+            ListBox_SetItemData(GetHwnd(), n, pNewItem);
         }
-#else
-        wxUnusedVar(idx);
 #endif // wxUSE_OWNER_DRAWN
+        AssignNewItemClientData(n, clientData, i, type);
     }
 
-    m_noItems += nItems;
-
     SetHorizontalExtent();
+
+    return n;
 }
 
 int wxListBox::DoListHitTest(const wxPoint& point) const
diff --git a/src/msw/wince/checklst.cpp b/src/msw/wince/checklst.cpp
index 7f14ed6c63..d5f5274921 100644
--- a/src/msw/wince/checklst.cpp
+++ b/src/msw/wince/checklst.cpp
@@ -152,7 +152,7 @@ void wxCheckListBox::OnSize(wxSizeEvent& event)
 // misc overloaded methods
 // -----------------------
 
-void wxCheckListBox::Delete(unsigned int n)
+void wxCheckListBox::DoDeleteOneItem(unsigned int n)
 {
     wxCHECK_RET( IsValid( n ), _T("invalid index in wxCheckListBox::Delete") );
 
@@ -258,44 +258,35 @@ void wxCheckListBox::SetString(unsigned int n, const wxString& s)
     delete [] buf;
 }
 
-int wxCheckListBox::DoAppend(const wxString& item)
-{
-    int n = (int)GetCount();
-    LVITEM newItem;
-    wxZeroMemory(newItem);
-    newItem.iItem = n;
-    int ret = ListView_InsertItem( (HWND)GetHWND(), & newItem );
-    wxCHECK_MSG( n == ret , -1, _T("Item not added") );
-    SetString( ret , item );
-    m_itemsClientData.Insert(NULL, ret);
-    return ret;
-}
-
 void* wxCheckListBox::DoGetItemClientData(unsigned int n) const
 {
     return m_itemsClientData.Item(n);
 }
 
-wxClientData* wxCheckListBox::DoGetItemClientObject(unsigned int n) const
+int wxCheckListBox::DoInsertItems(const wxArrayStringsAdapter & items,
+                                  unsigned int pos,
+                                  void **clientData, wxClientDataType type)
 {
-    return (wxClientData *)DoGetItemClientData(n);
-}
+    ListView_SetItemCount( GetHwnd(), GetCount() + count );
 
-void wxCheckListBox::DoInsertItems(const wxArrayString& items, unsigned int pos)
-{
-    wxCHECK_RET( IsValidInsert( pos ),
-                 wxT("invalid index in wxListBox::InsertItems") );
+    const unsigned int count = items.GetCount();
 
-    for( unsigned int i = 0; i < items.GetCount(); i++ )
+    int n = wxNOT_FOUND;
+
+    for( unsigned int i = 0; i < count; i++ )
     {
         LVITEM newItem;
         wxZeroMemory(newItem);
-        newItem.iItem = i+pos;
-        int ret = ListView_InsertItem( (HWND)GetHWND(), & newItem );
-        wxASSERT_MSG( int(i+pos) == ret , _T("Item not added") );
-        SetString( ret , items[i] );
-        m_itemsClientData.Insert(NULL, ret);
+        newItem.iItem = pos + i;
+        n = ListView_InsertItem( (HWND)GetHWND(), & newItem );
+        wxCHECK_MSG( n != -1, -1, _T("Item not added") );
+        SetString( n, items[i] );
+        m_itemsClientData.Insert(NULL, n);
+
+        AssignNewItemClientData(n, clientData, i, type);
     }
+
+    return n;
 }
 
 void wxCheckListBox::DoSetFirstItem(int n)
@@ -314,23 +305,6 @@ void wxCheckListBox::DoSetItemClientData(unsigned int n, void* clientData)
     m_itemsClientData.Item(n) = clientData;
 }
 
-void wxCheckListBox::DoSetItemClientObject(unsigned int n, wxClientData* clientData)
-{
-    DoSetItemClientData(n, clientData);
-}
-
-void wxCheckListBox::DoSetItems(const wxArrayString& items, void **clientData)
-{
-    ListView_SetItemCount( GetHwnd(), GetCount() + items.GetCount() );
-
-    for( unsigned int i = 0; i < items.GetCount(); i++ )
-    {
-        int pos = Append(items[i]);
-        if( pos >= 0 && clientData )
-            DoSetItemClientData(pos, clientData[i]);
-    }
-}
-
 void wxCheckListBox::DoSetSelection(int n, bool select)
 {
     ListView_SetItemState(GetHwnd(), n, select ? LVIS_SELECTED : 0, LVIS_SELECTED);
diff --git a/src/msw/wince/choicece.cpp b/src/msw/wince/choicece.cpp
index 40f7dc8120..0966c4276a 100644
--- a/src/msw/wince/choicece.cpp
+++ b/src/msw/wince/choicece.cpp
@@ -325,70 +325,52 @@ bool wxChoice::MSWCommand(WXUINT param, WXWORD WXUNUSED(id))
 
 wxChoice::~wxChoice()
 {
-    Free();
+    Clear();
 }
 
 // ----------------------------------------------------------------------------
 // adding/deleting items to/from the list
 // ----------------------------------------------------------------------------
 
-int wxChoice::DoAppend(const wxString& item)
+int wxChoice::DoInsertItems(const wxArrayStringsAdapter& items,
+                            unsigned int pos,
+                            void **clientData,
+                            wxClientDataType type)
 {
-    int n = (int)::SendMessage(GetBuddyHwnd(), LB_ADDSTRING, 0, (LPARAM)item.c_str());
+    MSWAllocStorage(items, LB_INITSTORAGE);
 
-    if ( n == LB_ERR )
-    {
-        wxLogLastError(wxT("SendMessage(LB_ADDSTRING)"));
-    }
-
-    return n;
-}
+    const bool append = pos == GetCount();
+    const unsigned msg = append ? LB_ADDSTRING : LB_INSERTSTRING;
+    if ( append )
+        pos = 0;
 
-int wxChoice::DoInsert(const wxString& item, unsigned int pos)
-{
-    wxCHECK_MSG(!(GetWindowStyle() & wxCB_SORT), -1, wxT("can't insert into choice"));
-    wxCHECK_MSG(IsValidInsert(pos), -1, wxT("invalid index"));
+    int n = wxNOT_FOUND;
 
-    int n = (int)::SendMessage(GetBuddyHwnd(), LB_INSERTSTRING, pos, (LPARAM)item.c_str());
-    if ( n == LB_ERR )
+    const unsigned int numItems = items.GetCount();
+    for ( unsigned int i = 0; i < numItems; ++i )
     {
-        wxLogLastError(wxT("SendMessage(LB_INSERTSTRING)"));
+        n = MSWInsertOrAppendItem(pos, items[i], msg);
+        if ( !append )
+            pos++;
+
+        AssignNewItemClientData(n, clientData, i, type);
     }
 
     return n;
 }
 
-void wxChoice::Delete(unsigned int n)
+void wxChoice::DoDeleteOneItem(unsigned int n)
 {
     wxCHECK_RET( IsValid(n), wxT("invalid item index in wxChoice::Delete") );
 
-    if ( HasClientObjectData() )
-    {
-        delete GetClientObject(n);
-    }
-
     ::SendMessage(GetBuddyHwnd(), LB_DELETESTRING, n, 0);
 }
 
-void wxChoice::Clear()
+void wxChoice::DoClear()
 {
-    Free();
-
     ::SendMessage(GetBuddyHwnd(), LB_RESETCONTENT, 0, 0);
 }
 
-void wxChoice::Free()
-{
-    if ( HasClientObjectData() )
-    {
-        unsigned int count = GetCount();
-        for ( unsigned int n = 0; n < count; n++ )
-        {
-            delete GetClientObject(n);
-        }
-    }
-}
-
 // ----------------------------------------------------------------------------
 // selection
 // ----------------------------------------------------------------------------
@@ -502,16 +484,6 @@ void* wxChoice::DoGetItemClientData(unsigned int n) const
     return (void *)rc;
 }
 
-void wxChoice::DoSetItemClientObject(unsigned int n, wxClientData* clientData)
-{
-    DoSetItemClientData(n, clientData);
-}
-
-wxClientData* wxChoice::DoGetItemClientObject(unsigned int n) const
-{
-    return (wxClientData *)DoGetItemClientData(n);
-}
-
 // ----------------------------------------------------------------------------
 // size calculations
 // ----------------------------------------------------------------------------
diff --git a/src/os2/checklst.cpp b/src/os2/checklst.cpp
index 8491b44200..c32fc84787 100644
--- a/src/os2/checklst.cpp
+++ b/src/os2/checklst.cpp
@@ -284,10 +284,13 @@ void wxCheckListBox::Delete(unsigned int n)
     m_aItems.RemoveAt(n);
 } // end of wxCheckListBox::Delete
 
-void wxCheckListBox::DoInsertItems(const wxArrayString& items, unsigned int pos)
+int wxCheckListBox::DoInsertItems(const wxArrayStringsAdapter& items,
+                                  unsigned int pos,
+                                  void **clientData,
+                                  wxClientDataType type)
 {
     // pos is validated in wxListBox
-    wxListBox::DoInsertItems( items, pos );
+    int result = wxListBox::DoInsertItems( items, pos, clientData, type );
     unsigned int n = items.GetCount();
     for (unsigned int i = 0; i < n; i++)
     {
@@ -301,7 +304,8 @@ void wxCheckListBox::DoInsertItems(const wxArrayString& items, unsigned int pos)
                       MPFROMP(pNewItem)
                     );
     }
-} // end of wxCheckListBox::InsertItems
+    return result;
+} // end of wxCheckListBox::DoInsertItems
 
 bool wxCheckListBox::SetFont ( const wxFont& rFont )
 {
diff --git a/src/os2/choice.cpp b/src/os2/choice.cpp
index 59e63f9275..e91486c6d7 100644
--- a/src/os2/choice.cpp
+++ b/src/os2/choice.cpp
@@ -114,69 +114,62 @@ bool wxChoice::Create(
 
 wxChoice::~wxChoice()
 {
-    Free();
+    Clear();
 }
 
 // ----------------------------------------------------------------------------
 // adding/deleting items to/from the list
 // ----------------------------------------------------------------------------
 
-int wxChoice::DoAppend(
-  const wxString&                   rsItem
-)
+int wxChoice::DoInsertItems(const wxArrayStringsAdapter& items
+                           , unsigned int pos
+                           , void **clientData
+                           , wxClientDataType type
+                           )
 {
-    int                             nIndex;
+    int                             nIndex = wxNOT_FOUND;
     LONG                            nIndexType = 0;
-    if (m_windowStyle & wxCB_SORT)
+    bool                            incrementPos = false;
+    if ( IsSorted() )
         nIndexType = LIT_SORTASCENDING;
-    else
+    else if (pos == GetCount())
         nIndexType = LIT_END;
-    nIndex = (int)::WinSendMsg( GetHwnd()
-                               ,LM_INSERTITEM
-                               ,(MPARAM)nIndexType
-                               ,(MPARAM)rsItem.wx_str()
-                              );
-    return nIndex;
-} // end of wxChoice::DoAppend
-
-int wxChoice::DoInsert( const wxString& rsItem, unsigned int pos )
-{
-    wxCHECK_MSG(!(GetWindowStyle() & wxCB_SORT), -1, wxT("can't insert into sorted list"));
-    wxCHECK_MSG(IsValidInsert(pos), -1, wxT("invalid index"));
-
-    if (pos == GetCount())
-        return DoAppend(rsItem);
-
-    int  nIndex;
-    LONG nIndexType = 0;
-
-    if (m_windowStyle & wxCB_SORT)
-        nIndexType = LIT_SORTASCENDING;
     else
+    {
         nIndexType = pos;
-    nIndex = (int)::WinSendMsg( GetHwnd()
-                               ,LM_INSERTITEM
-                               ,(MPARAM)nIndexType
-                               ,(MPARAM)rsItem.wx_str()
-                              );
+        incrementPos = true;
+    }
+
+    const unsigned int count = items.GetCount();
+    for( unsigned int i = 0; i < count; ++i )
+    {
+        nIndex = (int)::WinSendMsg( GetHwnd()
+                                   ,LM_INSERTITEM
+                                   ,(MPARAM)nIndexType
+                                   ,(MPARAM)items[i].wx_str()
+                                  );
+        if (nIndex < 0)
+        {
+            nIndex = wxNOT_FOUND;
+            break;
+        }
+        AssignNewItemClientData(nIndex, clientData, i, type);
+
+        if (incrementPos)
+            ++nIndexType;
+    }
     return nIndex;
-} // end of wxChoice::DoInsert
+} // end of wxChoice::DoInsertAppendItemsWithData
 
-void wxChoice::Delete(unsigned int n)
+void wxChoice::DoDeleteOneItem(unsigned int n)
 {
     wxCHECK_RET( IsValid(n), wxT("invalid item index in wxChoice::Delete") );
 
-    if ( HasClientObjectData() )
-    {
-        delete GetClientObject(n);
-    }
-
     ::WinSendMsg(GetHwnd(), LM_DELETEITEM, (MPARAM)n, (MPARAM)0);
 } // end of wxChoice::Delete
 
-void wxChoice::Clear()
+void wxChoice::DoClear()
 {
-    Free();
     ::WinSendMsg(GetHwnd(), LM_DELETEALL, (MPARAM)0, (MPARAM)0);
 } // end of wxChoice::Clear
 
@@ -277,16 +270,6 @@ void* wxChoice::DoGetItemClientData(unsigned int n) const
     return((void*)rc);
 } // end of wxChoice::DoGetItemClientData
 
-void wxChoice::DoSetItemClientObject(unsigned int n, wxClientData* pClientData)
-{
-    DoSetItemClientData(n, pClientData);
-} // end of wxChoice::DoSetItemClientObject
-
-wxClientData* wxChoice::DoGetItemClientObject(unsigned int n) const
-{
-    return (wxClientData *)DoGetItemClientData(n);
-} // end of wxChoice::DoGetItemClientObject
-
 // ----------------------------------------------------------------------------
 // wxOS2 specific helpers
 // ----------------------------------------------------------------------------
@@ -399,17 +382,4 @@ bool wxChoice::OS2Command(
     return true;
 } // end of wxChoice::OS2Command
 
-void wxChoice::Free()
-{
-    if (HasClientObjectData())
-    {
-        const unsigned int nCount = GetCount();
-
-        for (unsigned int n = 0; n < nCount; n++)
-        {
-            delete GetClientObject(n);
-        }
-    }
-} // end of wxChoice::Free
-
 #endif // wxUSE_CHOICE
diff --git a/src/os2/listbox.cpp b/src/os2/listbox.cpp
index aaca7eabcb..3755c4109e 100644
--- a/src/os2/listbox.cpp
+++ b/src/os2/listbox.cpp
@@ -252,7 +252,7 @@ void wxListBox::DoSetFirstItem(int N)
     ::WinSendMsg(GetHwnd(), LM_SETTOPINDEX, MPFROMLONG(N), (MPARAM)0);
 } // end of wxListBox::DoSetFirstItem
 
-void wxListBox::Delete(unsigned int n)
+void wxListBox::DoDeleteOneItem(unsigned int n)
 {
     wxCHECK_RET( IsValid(n),
                  wxT("invalid index in wxListBox::Delete") );
@@ -260,102 +260,67 @@ void wxListBox::Delete(unsigned int n)
 #if wxUSE_OWNER_DRAWN
     delete m_aItems[n];
     m_aItems.RemoveAt(n);
-#else // !wxUSE_OWNER_DRAWN
-    if (HasClientObjectData())
-    {
-        delete GetClientObject(n);
-    }
 #endif // wxUSE_OWNER_DRAWN/!wxUSE_OWNER_DRAWN
 
     ::WinSendMsg(GetHwnd(), LM_DELETEITEM, (MPARAM)n, (MPARAM)0);
     m_nNumItems--;
 } // end of wxListBox::DoSetFirstItem
 
-int wxListBox::DoAppend(const wxString& rsItem)
+int wxListBox::DoInsertItems(const wxArrayStringsAdapter & items,
+                             unsigned int pos,
+                             void **clientData,
+                             wxClientDataType type)
 {
     long lIndex = 0;
     LONG lIndexType = 0;
+    bool incrementPos = false;
 
-    if (m_windowStyle & wxLB_SORT)
+    if (IsSorted())
         lIndexType = LIT_SORTASCENDING;
-    else
+    else if (pos == GetCount())
         lIndexType = LIT_END;
-
-    lIndex = (long)::WinSendMsg(GetHwnd(), LM_INSERTITEM, (MPARAM)lIndexType, (MPARAM)rsItem.wx_str());
-    m_nNumItems++;
-
-#if wxUSE_OWNER_DRAWN
-    if (m_windowStyle & wxLB_OWNERDRAW)
+    else
     {
-        wxOwnerDrawn*               pNewItem = CreateItem(lIndex); // dummy argument
-        wxScreenDC                  vDc;
-
-
-        pNewItem->SetName(rsItem);
-        m_aItems.Insert(pNewItem, lIndex);
-        ::WinSendMsg(GetHwnd(), LM_SETITEMHANDLE, (MPARAM)lIndex, MPFROMP(pNewItem));
-        pNewItem->SetFont(GetFont());
+        lIndexType = (LONG)pos;
+        incrementPos = true;
     }
-#endif
-    return (int)lIndex;
-} // end of wxListBox::DoAppend
 
-void wxListBox::DoSetItems( const wxArrayString& raChoices,
-                            void** ppClientData )
-{
-    BOOL bHideAndShow = IsShown();
-    LONG lIndexType = 0;
+    int n = wxNOT_FOUND;
 
-    if (bHideAndShow)
+    unsigned int count = items.GetCount();
+    for (unsigned int i = 0; i < count; i++)
     {
-        ::WinShowWindow(GetHwnd(), FALSE);
-    }
-    ::WinSendMsg(GetHwnd(), LM_DELETEALL, (MPARAM)0, (MPARAM)0);
-    m_nNumItems = raChoices.GetCount();
-    for (unsigned int i = 0; i < m_nNumItems; i++)
-    {
-        if (m_windowStyle & wxLB_SORT)
-            lIndexType = LIT_SORTASCENDING;
-        else
-            lIndexType = LIT_END;
-        ::WinSendMsg(GetHwnd(), LM_INSERTITEM, (MPARAM)lIndexType, (MPARAM)raChoices[i].wx_str());
-
-        if (ppClientData)
+        n = (int)::WinSendMsg(GetHwnd(), LM_INSERTITEM, (MPARAM)lIndexType, (MPARAM)items[i].wx_str());
+        if (n < 0)
         {
-#if wxUSE_OWNER_DRAWN
-            wxASSERT_MSG(ppClientData[i] == NULL,
-                         wxT("Can't use client data with owner-drawn listboxes"));
-#else // !wxUSE_OWNER_DRAWN
-            ::WinSendMsg(WinUtil_GetHwnd(), LM_SETITEMHANDLE, MPFROMLONG(lCount), MPFROMP(ppClientData[i]));
-#endif // wxUSE_OWNER_DRAWN/!wxUSE_OWNER_DRAWN
+            wxLogLastError(_T("WinSendMsg(LM_INSERTITEM)"));
+            n = wxNOT_FOUND;
+            break;
         }
-    }
+        ++m_nNumItems;
 
 #if wxUSE_OWNER_DRAWN
-    if ( m_windowStyle & wxLB_OWNERDRAW )
-    {
-        //
-        // First delete old items
-        //
-        WX_CLEAR_ARRAY(m_aItems);
-
-        //
-        // Then create new ones
-        //
-        for (unsigned int ui = 0; ui < m_nNumItems; ui++)
+        if (HasFlag(wxLB_OWNERDRAW))
         {
-            wxOwnerDrawn* pNewItem = CreateItem(ui);
-
-            pNewItem->SetName(raChoices[ui]);
-            m_aItems.Add(pNewItem);
-            ::WinSendMsg(GetHwnd(), LM_SETITEMHANDLE, MPFROMLONG(ui), MPFROMP(pNewItem));
+            wxOwnerDrawn*               pNewItem = CreateItem(n); // dummy argument
+            wxScreenDC                  vDc; // FIXME: is it really needed here?
+    
+            pNewItem->SetName(items[i]);
+            m_aItems.Insert(pNewItem, n);
+            ::WinSendMsg(GetHwnd(), LM_SETITEMHANDLE, (MPARAM)n, MPFROMP(pNewItem));
+            pNewItem->SetFont(GetFont());
         }
+#endif
+        AssignNewItemClientData(n, clientData, i, type);
+
+        if (incrementPos)
+            ++lIndexType;
     }
-#endif // wxUSE_OWNER_DRAWN
-    ::WinShowWindow(GetHwnd(), TRUE);
-} // end of wxListBox::DoSetItems
 
-void wxListBox::Clear()
+    return n;
+} // end of wxListBox::DoInsertAppendItemsWithData
+
+void wxListBox::DoClear()
 {
 #if wxUSE_OWNER_DRAWN
     unsigned int lUiCount = m_aItems.Count();
@@ -366,15 +331,7 @@ void wxListBox::Clear()
     }
 
     m_aItems.Clear();
-#else // !wxUSE_OWNER_DRAWN
-    if (HasClientObjectData())
-    {
-        for (unsigned int n = 0; n < m_lNumItems; n++)
-        {
-            delete GetClientObject(n);
-        }
-    }
-#endif // wxUSE_OWNER_DRAWN/!wxUSE_OWNER_DRAWN
+#endif // wxUSE_OWNER_DRAWN
     ::WinSendMsg(GetHwnd(), LM_DELETEALL, (MPARAM)0, (MPARAM)0);
 
     m_nNumItems = 0;
@@ -414,11 +371,6 @@ bool wxListBox::IsSelected( int N ) const
     return (lItem == (LONG)N && lItem != LIT_NONE);
 } // end of wxListBox::IsSelected
 
-wxClientData* wxListBox::DoGetItemClientObject(unsigned int n) const
-{
-    return (wxClientData *)DoGetItemClientData(n);
-}
-
 void* wxListBox::DoGetItemClientData(unsigned int n) const
 {
     wxCHECK_MSG( IsValid(n), NULL,
@@ -427,11 +379,6 @@ void* wxListBox::DoGetItemClientData(unsigned int n) const
     return((void *)::WinSendMsg(GetHwnd(), LM_QUERYITEMHANDLE, MPFROMLONG(n), (MPARAM)0));
 } // end of wxListBox::DoGetItemClientData
 
-void wxListBox::DoSetItemClientObject(unsigned int n, wxClientData* pClientData)
-{
-    DoSetItemClientData(n, pClientData);
-} // end of wxListBox::DoSetItemClientObject
-
 void wxListBox::DoSetItemClientData(unsigned int n, void* pClientData)
 {
     wxCHECK_RET( IsValid(n),
@@ -551,34 +498,6 @@ wxString wxListBox::GetString(unsigned int n) const
     return sResult;
 } // end of wxListBox::GetString
 
-void wxListBox::DoInsertItems(const wxArrayString& asItems, unsigned int nPos)
-{
-    wxCHECK_RET( IsValidInsert(nPos),
-                 wxT("invalid index in wxListBox::InsertItems") );
-
-    unsigned int nItems = asItems.GetCount();
-
-    for (unsigned int i = 0; i < nItems; i++)
-    {
-        int nIndex = (int)::WinSendMsg( GetHwnd(),
-                                        LM_INSERTITEM,
-                                        MPFROMLONG((LONG)(i + nPos)),
-                                        (MPARAM)asItems[i].wx_str() );
-
-        wxOwnerDrawn* pNewItem = CreateItem(nIndex);
-
-        pNewItem->SetName(asItems[i]);
-        pNewItem->SetFont(GetFont());
-        m_aItems.Insert(pNewItem, nIndex);
-        ::WinSendMsg( GetHwnd()
-                     ,LM_SETITEMHANDLE
-                     ,(MPARAM)((LONG)nIndex)
-                     ,MPFROMP(pNewItem)
-                    );
-        m_nNumItems += nItems;
-    }
-} // end of wxListBox::DoInsertItems
-
 void wxListBox::SetString(unsigned int n, const wxString& rsString)
 {
     wxCHECK_RET( IsValid(n),
diff --git a/src/palmos/choice.cpp b/src/palmos/choice.cpp
index d9ba679dd6..c6c100fc0a 100644
--- a/src/palmos/choice.cpp
+++ b/src/palmos/choice.cpp
@@ -150,21 +150,19 @@ wxChoice::~wxChoice()
 // adding/deleting items to/from the list
 // ----------------------------------------------------------------------------
 
-int wxChoice::DoAppend(const wxString& item)
+int wxChoice::DoInsertItems(const wxArrayStringsAdapter& items,
+                            unsigned int pos,
+                            void **clientData,
+                            wxClientDataType type)
 {
     return 0;
 }
 
-int wxChoice::DoInsert(const wxString& item, unsigned int pos)
+void wxChoice::DoDeleteOneItem(unsigned int n)
 {
-    return 0;
 }
 
-void wxChoice::Delete(unsigned int n)
-{
-}
-
-void wxChoice::Clear()
+void wxChoice::DoClear()
 {
 }
 
@@ -216,15 +214,6 @@ void* wxChoice::DoGetItemClientData(unsigned int n) const
     return (void *)NULL;
 }
 
-void wxChoice::DoSetItemClientObject(unsigned int n, wxClientData* clientData )
-{
-}
-
-wxClientData* wxChoice::DoGetItemClientObject(unsigned int n) const
-{
-    return (wxClientData *)DoGetItemClientData(n);
-}
-
 // ----------------------------------------------------------------------------
 // wxMSW specific helpers
 // ----------------------------------------------------------------------------
diff --git a/src/palmos/listbox.cpp b/src/palmos/listbox.cpp
index eb61926a48..de22719ab6 100644
--- a/src/palmos/listbox.cpp
+++ b/src/palmos/listbox.cpp
@@ -177,20 +177,11 @@ void wxListBox::DoSetFirstItem(int N)
 {
 }
 
-void wxListBox::Delete(unsigned int n)
+void wxListBox::DoDeleteOneItem(unsigned int n)
 {
 }
 
-int wxListBox::DoAppend(const wxString& item)
-{
-    return 0;
-}
-
-void wxListBox::DoSetItems(const wxArrayString& choices, void** clientData)
-{
-}
-
-void wxListBox::Clear()
+void wxListBox::DoClear()
 {
 }
 
@@ -207,20 +198,11 @@ bool wxListBox::IsSelected(int N) const
     return false;
 }
 
-wxClientData* wxListBox::DoGetItemClientObject(unsigned int n) const
-{
-    return (wxClientData *)DoGetItemClientData(n);
-}
-
 void *wxListBox::DoGetItemClientData(unsigned int n) const
 {
     return (void *)NULL;
 }
 
-void wxListBox::DoSetItemClientObject(unsigned int n, wxClientData* clientData)
-{
-}
-
 void wxListBox::DoSetItemClientData(unsigned int n, void *clientData)
 {
 }
@@ -243,11 +225,13 @@ wxString wxListBox::GetString(unsigned int n) const
     return wxEmptyString;
 }
 
-void
-wxListBox::DoInsertItems(const wxArrayString& items, unsigned int pos)
+int wxListBox::DoInsertItems(const wxArrayStringsAdapter& items,
+                             unsigned int pos,
+                             void **clientData,
+                             wxClientDataType type)
 {
+    return 0;
 }
-
 void wxListBox::SetString(unsigned int n, const wxString& s)
 {
 }
diff --git a/src/univ/checklst.cpp b/src/univ/checklst.cpp
index 95e1af791d..3a85960386 100644
--- a/src/univ/checklst.cpp
+++ b/src/univ/checklst.cpp
@@ -146,46 +146,16 @@ void wxCheckListBox::Check(unsigned int item, bool check)
 // methods forwarded to wxListBox
 // ----------------------------------------------------------------------------
 
-void wxCheckListBox::Delete(unsigned int n)
+void wxCheckListBox::DoDeleteOneItem(unsigned int n)
 {
-    wxCHECK_RET( IsValid(n), _T("invalid index in wxListBox::Delete") );
-
-    wxListBox::Delete(n);
+    wxListBox::DoDeleteOneItem(n);
 
     m_checks.RemoveAt(n);
 }
 
-int wxCheckListBox::DoAppend(const wxString& item)
+void wxCheckListBox::OnItemInserted(unsigned int pos)
 {
-    int pos = wxListBox::DoAppend(item);
-
-    // the item is initially unchecked
     m_checks.Insert(false, pos);
-
-    return pos;
-}
-
-void wxCheckListBox::DoInsertItems(const wxArrayString& items, unsigned int pos)
-{
-    wxListBox::DoInsertItems(items, pos);
-
-    unsigned int count = items.GetCount();
-    for ( unsigned int n = 0; n < count; n++ )
-    {
-        m_checks.Insert(false, pos + n);
-    }
-}
-
-void wxCheckListBox::DoSetItems(const wxArrayString& items, void **clientData)
-{
-    // call it first as it does DoClear()
-    wxListBox::DoSetItems(items, clientData);
-
-    unsigned int count = items.GetCount();
-    for ( unsigned int n = 0; n < count; n++ )
-    {
-        m_checks.Add(false);
-    }
 }
 
 void wxCheckListBox::DoClear()
diff --git a/src/univ/combobox.cpp b/src/univ/combobox.cpp
index f347cfe1b9..1ca6ffd795 100644
--- a/src/univ/combobox.cpp
+++ b/src/univ/combobox.cpp
@@ -344,13 +344,13 @@ void wxComboBox::SetEditable(bool editable)
 // wxComboBox methods forwarded to wxListBox
 // ----------------------------------------------------------------------------
 
-void wxComboBox::Clear()
+void wxComboBox::DoClear()
 {
     GetLBox()->Clear();
     if ( GetTextCtrl() ) GetTextCtrl()->SetValue(wxEmptyString);
 }
 
-void wxComboBox::Delete(unsigned int n)
+void wxComboBox::DoDeleteOneItem(unsigned int n)
 {
     wxCHECK_RET( IsValid(n), _T("invalid index in wxComboBox::Delete") );
 
@@ -410,21 +410,11 @@ int wxComboBox::GetSelection() const
 #endif
 }
 
-int wxComboBox::DoAppend(const wxString& item)
+int wxComboBox::DoInsertItems(const wxArrayStringsAdapter & items,
+                              unsigned int pos,
+                              void **clientData, wxClientDataType type)
 {
-    return GetLBox()->Append(item);
-}
-
-int wxComboBox::DoInsert(const wxString& item, unsigned int pos)
-{
-    wxCHECK_MSG(!(GetWindowStyle() & wxCB_SORT), -1, wxT("can't insert into sorted list"));
-    wxCHECK_MSG(IsValidInsert(pos), -1, wxT("invalid index"));
-
-    if (pos == GetCount())
-        return DoAppend(item);
-
-    GetLBox()->Insert(item, pos);
-    return pos;
+    return GetLBox()->DoInsertItems(items, pos, clientData, type);
 }
 
 void wxComboBox::DoSetItemClientData(unsigned int n, void* clientData)
@@ -437,16 +427,6 @@ void *wxComboBox::DoGetItemClientData(unsigned int n) const
     return GetLBox()->GetClientData(n);
 }
 
-void wxComboBox::DoSetItemClientObject(unsigned int n, wxClientData* clientData)
-{
-    GetLBox()->SetClientObject(n, clientData);
-}
-
-wxClientData* wxComboBox::DoGetItemClientObject(unsigned int n) const
-{
-    return GetLBox()->GetClientObject(n);
-}
-
 bool wxComboBox::IsEditable() const
 {
     return GetTextCtrl() != NULL && (!HasFlag(wxCB_READONLY) || GetTextCtrl()->IsEditable() );
diff --git a/src/univ/listbox.cpp b/src/univ/listbox.cpp
index 7aaa9953f3..7c1ca6dcca 100644
--- a/src/univ/listbox.cpp
+++ b/src/univ/listbox.cpp
@@ -192,7 +192,7 @@ bool wxListBox::Create(wxWindow *parent,
                             validator, name) )
         return false;
 
-    m_strings = new wxArrayString;
+    m_strings = IsSorted() ? new wxArrayString : new wxSortedArrayString;
 
     Set(n, choices);
 
@@ -217,67 +217,25 @@ wxListBox::~wxListBox()
 // adding/inserting strings
 // ----------------------------------------------------------------------------
 
-int wxCMPFUNC_CONV wxListBoxSortNoCase(wxString* s1, wxString* s2)
+int wxListBox::DoInsertItems(const wxArrayStringsAdapter& items,
+                             unsigned int pos,
+                             void **clientData,
+                             wxClientDataType type)
 {
-    return  s1->CmpNoCase(*s2);
-}
-
-int wxListBox::DoAppendOnly(const wxString& item)
-{
-    unsigned int index;
+    int idx = wxNOT_FOUND;
 
-    if ( IsSorted() )
+    const unsigned int numItems = items.GetCount();
+    for ( unsigned int i = 0; i < numItems; ++i )
     {
-        m_strings->Add(item);
-        m_strings->Sort(wxListBoxSortNoCase);
-        index = m_strings->Index(item);
-    }
-    else
-    {
-        index = m_strings->GetCount();
-        m_strings->Add(item);
-    }
+        const wxString& item = items[i];
+        idx = IsSorted() ? m_strings->Add(item)
+                         : (m_strings->Insert(item, pos), pos++);
 
-    return index;
-}
+        m_itemsClientData.Insert(NULL, idx);
+        AssignNewItemClientData(idx, clientData, i, type);
 
-int wxListBox::DoAppend(const wxString& item)
-{
-    size_t index = DoAppendOnly( item );
-
-    m_itemsClientData.Insert(NULL, index);
-
-    m_updateScrollbarY = true;
-
-    if ( HasHorzScrollbar() )
-    {
-        // has the max width increased?
-        wxCoord width;
-        GetTextExtent(item, &width, NULL);
-        if ( width > m_maxWidth )
-        {
-            m_maxWidth = width;
-            m_maxWidthItem = index;
-            m_updateScrollbarX = true;
-        }
-    }
-
-    RefreshFromItemToEnd(index);
-
-    return index;
-}
-
-void wxListBox::DoInsertItems(const wxArrayString& items, unsigned int pos)
-{
-    // the position of the item being added to a sorted listbox can't be
-    // specified
-    wxCHECK_RET( !IsSorted(), _T("can't insert items into sorted listbox") );
-
-    unsigned int count = items.GetCount();
-    for ( unsigned int n = 0; n < count; n++ )
-    {
-        m_strings->Insert(items[n], pos + n);
-        m_itemsClientData.Insert(NULL, pos + n);
+        // call the wxCheckListBox hook
+        OnItemInserted(idx);
     }
 
     // the number of items has changed so we might have to show the scrollbar
@@ -291,29 +249,8 @@ void wxListBox::DoInsertItems(const wxArrayString& items, unsigned int pos)
     // note that we have to refresh all the items after the ones we inserted,
     // not just these items
     RefreshFromItemToEnd(pos);
-}
 
-void wxListBox::DoSetItems(const wxArrayString& items, void **clientData)
-{
-    DoClear();
-
-    unsigned int count = items.GetCount();
-    if ( !count )
-        return;
-
-    m_strings->Alloc(count);
-
-    m_itemsClientData.Alloc(count);
-    for ( unsigned int n = 0; n < count; n++ )
-    {
-        unsigned int index = DoAppendOnly(items[n]);
-
-        m_itemsClientData.Insert(clientData ? clientData[n] : NULL, index);
-    }
-
-    m_updateScrollbarY = true;
-
-    RefreshAll();
+    return idx;
 }
 
 void wxListBox::SetString(unsigned int n, const wxString& s)
@@ -355,24 +292,10 @@ void wxListBox::DoClear()
 {
     m_strings->Clear();
 
-    if ( HasClientObjectData() )
-    {
-        unsigned int count = m_itemsClientData.GetCount();
-        for ( unsigned int n = 0; n < count; n++ )
-        {
-            delete (wxClientData *) m_itemsClientData[n];
-        }
-    }
-
     m_itemsClientData.Clear();
     m_selections.Clear();
 
     m_current = -1;
-}
-
-void wxListBox::Clear()
-{
-    DoClear();
 
     m_updateScrollbarY = true;
 
@@ -381,7 +304,7 @@ void wxListBox::Clear()
     RefreshAll();
 }
 
-void wxListBox::Delete(unsigned int n)
+void wxListBox::DoDeleteOneItem(unsigned int n)
 {
     wxCHECK_RET( IsValid(n),
                  _T("invalid index in wxListBox::Delete") );
@@ -392,11 +315,6 @@ void wxListBox::Delete(unsigned int n)
 
     m_strings->RemoveAt(n);
 
-    if ( HasClientObjectData() )
-    {
-        delete (wxClientData *)m_itemsClientData[n];
-    }
-
     m_itemsClientData.RemoveAt(n);
 
     // when the item disappears we must not keep using its index
@@ -458,16 +376,6 @@ void *wxListBox::DoGetItemClientData(unsigned int n) const
     return m_itemsClientData[n];
 }
 
-void wxListBox::DoSetItemClientObject(unsigned int n, wxClientData* clientData)
-{
-    m_itemsClientData[n] = clientData;
-}
-
-wxClientData* wxListBox::DoGetItemClientObject(unsigned int n) const
-{
-    return (wxClientData *)m_itemsClientData[n];
-}
-
 // ----------------------------------------------------------------------------
 // selection
 // ----------------------------------------------------------------------------
-- 
2.50.0

