From eca15c0d5497309e402d4bb91f8e479b4fb70fa9 Mon Sep 17 00:00:00 2001
From: Vadim Zeitlin <vadim@wxwidgets.org>
Date: Sun, 9 Oct 2005 18:40:36 +0000
Subject: [PATCH] Added wxTreebook: - added the control itself - added
 protected wxBookCtrlBase::AllowNullPage() to accommodate it - big changes to
 the sample to get rid of (most) ugly macros - added XRC handler for the
 control - added docs - and wxUSE_TREEBOOK everywhere

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@35862 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
---
 build/bakefiles/files.bkl       |   3 +
 configure.in                    |  10 +
 docs/changes.txt                |   1 +
 docs/latex/wx/category.tex      |   2 +
 docs/latex/wx/classes.tex       |   2 +
 docs/latex/wx/treebook.tex      | 269 +++++++++++
 docs/latex/wx/treebookevent.tex |  80 ++++
 docs/latex/wx/treebookevt.inc   |  12 +
 docs/latex/wx/tsamples.tex      |   6 +-
 include/wx/bookctrl.h           |   7 +
 include/wx/mac/setup0.h         |   8 +
 include/wx/msw/setup0.h         |   8 +
 include/wx/msw/wince/setup.h    |   8 +
 include/wx/setup_inc.h          |   8 +
 include/wx/treebook.h           | 298 ++++++++++++
 include/wx/univ/setup0.h        |   8 +
 include/wx/xrc/xh_all.h         |   1 +
 include/wx/xrc/xh_treebk.h      |  81 ++++
 samples/notebook/notebook.cpp   | 690 +++++++++++++++------------
 samples/notebook/notebook.h     |  63 ++-
 samples/xrc/rc/controls.xrc     |  37 ++
 setup.h.in                      |   2 +
 setup.h_vms                     |   2 +
 src/common/bookctrl.cpp         |  20 +-
 src/generic/treebkg.cpp         | 807 ++++++++++++++++++++++++++++++++
 src/xrc/xh_treebk.cpp           | 134 ++++++
 src/xrc/xmlrsall.cpp            |   3 +
 27 files changed, 2244 insertions(+), 326 deletions(-)
 create mode 100644 docs/latex/wx/treebook.tex
 create mode 100644 docs/latex/wx/treebookevent.tex
 create mode 100644 docs/latex/wx/treebookevt.inc
 create mode 100644 include/wx/treebook.h
 create mode 100644 include/wx/xrc/xh_treebk.h
 create mode 100644 src/generic/treebkg.cpp
 create mode 100644 src/xrc/xh_treebk.cpp

diff --git a/build/bakefiles/files.bkl b/build/bakefiles/files.bkl
index f720c8d2ad..f56d135978 100644
--- a/build/bakefiles/files.bkl
+++ b/build/bakefiles/files.bkl
@@ -627,6 +627,7 @@ IMPORTANT: please read docs/tech/tn0016.txt before modifying this file!
     src/generic/textdlgg.cpp
     src/generic/tipwin.cpp
     src/generic/treectlg.cpp
+    src/generic/treebkg.cpp
     src/generic/vlbox.cpp
     src/generic/vscroll.cpp
 </set>
@@ -793,6 +794,7 @@ IMPORTANT: please read docs/tech/tn0016.txt before modifying this file!
     wx/tooltip.h
     wx/toplevel.h
     wx/treebase.h
+    wx/treebook.h
     wx/treectrl.h
     wx/valgen.h
     wx/vidmode.h
@@ -2610,6 +2612,7 @@ IMPORTANT: please read docs/tech/tn0016.txt before modifying this file!
     src/xrc/xh_tglbtn.cpp
     src/xrc/xh_toolb.cpp
     src/xrc/xh_tree.cpp
+    src/xrc/xh_treebk.cpp
     src/xrc/xh_unkwn.cpp
     src/xrc/xh_wizrd.cpp
     src/xrc/xmlres.cpp
diff --git a/configure.in b/configure.in
index 6fec5fa511..2b85a555a1 100644
--- a/configure.in
+++ b/configure.in
@@ -527,6 +527,7 @@ if test $DEBUG_CONFIGURE = 1; then
   DEFAULT_wxUSE_TOOLBAR=no
   DEFAULT_wxUSE_TOOLBAR_NATIVE=no
   DEFAULT_wxUSE_TOOLBAR_SIMPLE=no
+  DEFAULT_wxUSE_TREEBOOK=no
   DEFAULT_wxUSE_TREECTRL=no
   DEFAULT_wxUSE_POPUPWIN=no
   DEFAULT_wxUSE_TIPWINDOW=no
@@ -723,6 +724,7 @@ else
   DEFAULT_wxUSE_TOOLBAR=yes
   DEFAULT_wxUSE_TOOLBAR_NATIVE=yes
   DEFAULT_wxUSE_TOOLBAR_SIMPLE=yes
+  DEFAULT_wxUSE_TREEBOOK=yes
   DEFAULT_wxUSE_TREECTRL=yes
   DEFAULT_wxUSE_POPUPWIN=yes
   DEFAULT_wxUSE_TIPWINDOW=yes
@@ -1025,6 +1027,7 @@ if test "$wxUSE_CONTROLS" = "yes"; then
   DEFAULT_wxUSE_TOOLBAR_NATIVE=yes
   DEFAULT_wxUSE_TOOLBAR_SIMPLE=yes
   DEFAULT_wxUSE_TOOLTIPS=yes
+  DEFAULT_wxUSE_TREEBOOK=yes
   DEFAULT_wxUSE_TREECTRL=yes
   DEFAULT_wxUSE_POPUPWIN=yes
   DEFAULT_wxUSE_TIPWINDOW=yes
@@ -1065,6 +1068,7 @@ elif test "$wxUSE_CONTROLS" = "no"; then
   DEFAULT_wxUSE_TOOLBAR_NATIVE=no
   DEFAULT_wxUSE_TOOLBAR_SIMPLE=no
   DEFAULT_wxUSE_TOOLTIPS=no
+  DEFAULT_wxUSE_TREEBOOK=no
   DEFAULT_wxUSE_TREECTRL=no
   DEFAULT_wxUSE_POPUPWIN=no
   DEFAULT_wxUSE_TIPWINDOW=no
@@ -1108,6 +1112,7 @@ WX_ARG_ENABLE(togglebtn,   [  --enable-togglebtn      use wxToggleButton class],
 WX_ARG_ENABLE(toolbar,     [  --enable-toolbar        use wxToolBar class], wxUSE_TOOLBAR)
 WX_ARG_ENABLE(tbarnative,  [  --enable-tbarnative     use native wxToolBar class], wxUSE_TOOLBAR_NATIVE)
 WX_ARG_ENABLE(tbarsmpl,    [  --enable-tbarsmpl       use wxToolBarSimple class], wxUSE_TOOLBAR_SIMPLE)
+WX_ARG_ENABLE(treebook,    [  --enable-treebook       use wxTreebook class], wxUSE_TREEBOOK)
 WX_ARG_ENABLE(treectrl,    [  --enable-treectrl       use wxTreeCtrl class], wxUSE_TREECTRL)
 WX_ARG_ENABLE(tipwindow,   [  --enable-tipwindow      use wxTipWindow class], wxUSE_TIPWINDOW)
 WX_ARG_ENABLE(popupwin,    [  --enable-popupwin       use wxPopUpWindow class], wxUSE_POPUPWIN)
@@ -6393,6 +6398,11 @@ if test "$wxUSE_TOOLTIPS" = "yes"; then
     fi
 fi
 
+if test "$wxUSE_TREEBOOK" = "yes"; then
+    AC_DEFINE(wxUSE_TREEBOOK)
+    USES_CONTROLS=1
+fi
+
 if test "$wxUSE_TREECTRL" = "yes"; then
     if test "$wxUSE_IMAGLIST" = "yes"; then
         AC_DEFINE(wxUSE_TREECTRL)
diff --git a/docs/changes.txt b/docs/changes.txt
index d8a0460092..1c5fc8e5f3 100644
--- a/docs/changes.txt
+++ b/docs/changes.txt
@@ -11,6 +11,7 @@ All:
 
 All (GUI):
 
+- added wxTreeBook
 - added wxDialog::SetEscapeId()
 - wxItemContainerImmutable::FindString unified (affects wxRadioBox, wxListBox,
   wxComboBox and wxChoice)
diff --git a/docs/latex/wx/category.tex b/docs/latex/wx/category.tex
index 31a4d13114..f1ae1587ba 100644
--- a/docs/latex/wx/category.tex
+++ b/docs/latex/wx/category.tex
@@ -44,6 +44,7 @@ The following are a variety of classes that are derived from wxWindow.
 \twocolitem{\helpref{wxNotebook}{wxnotebook}}{Notebook class}
 \twocolitem{\helpref{wxListbook}{wxlistbook}}{Similar to notebook but using list control}
 \twocolitem{\helpref{wxChoicebook}{wxchoicebook}}{Similar to notebook but using choice control}
+\twocolitem{\helpref{wxTreebook}{wxtreebook}}{Similar to notebook but using tree control}
 \twocolitem{\helpref{wxSashWindow}{wxsashwindow}}{Window with four optional sashes that can be dragged}
 \twocolitem{\helpref{wxSashLayoutWindow}{wxsashlayoutwindow}}{Window that can be involved in an IDE-like layout arrangement}
 \twocolitem{\helpref{wxVScrolledWindow}{wxvscrolledwindow}}{As wxScrolledWindow but supports lines of variable height}
@@ -252,6 +253,7 @@ An event object contains information about a specific event. Event handlers
 \twocolitem{\helpref{wxSplitterEvent}{wxsplitterevent}}{An event from \helpref{wxSplitterWindow}{wxsplitterwindow}}
 \twocolitem{\helpref{wxSysColourChangedEvent}{wxsyscolourchangedevent}}{A system colour change event}
 \twocolitem{\helpref{wxTimerEvent}{wxtimerevent}}{A timer expiration event}
+\twocolitem{\helpref{wxTreebookEvent}{wxtreebookevent}}{A treebook control event}
 \twocolitem{\helpref{wxTreeEvent}{wxtreeevent}}{A tree control event}
 \twocolitem{\helpref{wxUpdateUIEvent}{wxupdateuievent}}{A user interface update event}
 \twocolitem{\helpref{wxWindowCreateEvent}{wxwindowcreateevent}}{A window creation event}
diff --git a/docs/latex/wx/classes.tex b/docs/latex/wx/classes.tex
index 6c55698d6d..ffbe9e6dcc 100644
--- a/docs/latex/wx/classes.tex
+++ b/docs/latex/wx/classes.tex
@@ -348,6 +348,8 @@
 \input toolbar.tex
 \input tooltip.tex
 \input tlw.tex
+\input treebook.tex
+\input treebookevent.tex
 \input treectrl.tex
 \input treeevt.tex
 \input treedata.tex
diff --git a/docs/latex/wx/treebook.tex b/docs/latex/wx/treebook.tex
new file mode 100644
index 0000000000..5fb0b255f8
--- /dev/null
+++ b/docs/latex/wx/treebook.tex
@@ -0,0 +1,269 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Name:        treebook.tex
+%% Purpose:     wxTreebook documentation
+%% Author:      Evgeniy Tarassov
+%% Modified by:
+%% Created:     2005-10-04
+%% RCS-ID:      $Id$
+%% Copyright:   (c) 2005 Vadim Zeitlin <vadim@wxwindows.org>
+%% License:     wxWindows license
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\section{\class{wxTreebook}}\label{wxtreebook}
+
+This class is an extension of the Notebook class that allows a tree structured
+set of pages to be shown in a control.
+A classic example is a netscape preferences dialog that shows a tree
+of preference sections on the left and select section page on the right.
+
+To use the class simply create it and populate with pages using
+\helpref{InsertPage}{wxtreebookinsertpage},
+\helpref{AddPage}{wxtreebookaddpage},
+\helpref{AddSubPage}{wxtreebookaddsubpage}.
+
+If your tree is no more than 1 level in depth then you could
+simply use \helpref{AddPage}{wxtreebookaddpage} and 
+\helpref{AddSubPage}{wxtreebookaddsubpage} to sequentially populate your tree
+by adding at every step a page or a subpage to the end of the tree.
+
+
+\wxheading{Derived from}
+
+wxBookCtrlBase\\
+\helpref{wxControl}{wxcontrol}\\
+\helpref{wxWindow}{wxwindow}\\
+\helpref{wxEvtHandler}{wxevthandler}\\
+\helpref{wxObject}{wxobject}
+
+
+\wxheading{Include files}
+
+<wx/treebook.h>
+
+\input treebookevt.inc
+
+
+\wxheading{See also}
+
+\helpref{wxNotebook}{wxnotebook}, \helpref{wxTreebookEvent}{wxtreebookevent}, \helpref{wxImageList}{wximagelist}, \helpref{notebook sample}{samplenotebook}
+
+
+
+\latexignore{\rtfignore{\wxheading{Members}}}
+
+
+\membersection{wxTreebook::wxTreebook}\label{wxtreebookwxtreebook}
+
+\func{}{wxTreebook}{\void}
+
+Default constructor.
+
+
+\func{}{wxTreebook}{
+    \param{wxWindow* }{parent},
+    \param{wxWindowID }{id},
+    \param{const wxPoint\& }{pos = wxDefaultPosition},
+    \param{const wxSize\& }{size = wxDefaultSize},
+    \param{long }{style = wxTBK\_DEFAULT},
+    \param{const wxString\& }{name = wxEmptyString}}
+
+Creates an empty TreeBook control.
+
+\wxheading{Parameters}
+
+\docparam{parent}{The parent window. Must be non-NULL.}
+
+\docparam{id}{The window identifier.}
+
+\docparam{pos}{The window position.}
+
+\docparam{size}{The window size.}
+
+\docparam{style}{The window style. See \helpref{wxNotebook}{wxnotebook}.}
+
+\docparam{name}{The name of the control (used only under Motif).}
+
+
+
+\membersection{wxTreebook::\destruct{wxTreebook}}\label{wxtreebookdtor}
+
+\func{}{\destruct{wxTreebook}}{\void}
+
+Destroys the wxTreebook object.
+
+Also deletes all the pages owned by the control (inserted previously into it).
+
+
+
+\membersection{wxTreebook::AddPage}\label{wxtreebookaddpage}
+
+\func{bool}{AddPage}{
+    \param{wxWindow* }{page},
+    \param{const wxString\& }{text},
+    \param{bool }{bSelect = false},
+    \param{int }{imageId = wxNOT\_FOUND}}
+
+Adds a new page. The page is placed at the topmost level after all other pages.
+NULL could be specified for page to create an empty page.
+
+
+
+\membersection{wxTreebook::AddSubPage}\label{wxtreebookaddsubpage}
+
+\func{bool}{AddSubPage}{\param{wxWindow* }{page}, \param{const wxString\& }{text}, \param{bool }{bSelect = false}, \param{int }{imageId = wxNOT\_FOUND}}
+
+\func{bool}{AddSubPage}{\param{size\_t }{pagePos}, \param{wxWindow* }{page}, \param{const wxString\& }{text}, \param{bool }{bSelect = false}, \param{int }{imageId = wxNOT\_FOUND}}
+
+Adds a new child-page to either the last or the specified top-level.
+NULL could be specified for page to create an empty page.
+
+
+
+\membersection{wxTreebook::AssignImageList}\label{wxtreebookassignimagelist}
+
+\func{void}{AssignImageList}{\param{wxImageList* }{imageList}}
+
+Sets the image list for the page control and takes ownership of the list.
+
+\wxheading{See also}
+
+\helpref{wxImageList}{wximagelist}, \helpref{SetImageList}{wxtreebooksetimagelist}
+
+
+
+\membersection{wxTreebook::CollapseNode}\label{wxtreebookcollapsenode}
+
+\func{bool}{CollapseNode}{\param{size\_t }{pageId}}
+
+Shortcut for \helpref{ExpandNode}{wxtreebookexpandnode}(pageId, false).
+
+
+
+\membersection{wxTreebook::Create}\label{wxtreebookcreate}
+
+\func{bool}{Create}{\param{wxWindow* }{parent}, \param{wxWindowID }{id}, \param{const wxPoint\& }{pos = wxDefaultPosition}, \param{const wxSize\& }{size = wxDefaultSize}, \param{long }{style = wxTBK\_DEFAULT}, \param{const wxString\& }{name = wxEmptyString}}
+
+Creates a treebook control. See \helpref{wxTreebook::wxTreebook}{wxtreebookwxtreebook} for the description of the parameters.
+
+
+
+\membersection{wxTreebook::DeleteAllPages}\label{wxtreebookdeleteallpages}
+
+\func{bool}{DeleteAllPages}{\void}
+
+Deletes all pages inserted into the treebook. No event is generated.
+
+
+
+\membersection{wxTreebook::DeletePage}\label{wxtreebookdeletepage}
+
+\func{bool}{DeletePage}{\param{size\_t }{pagePos}}
+
+Deletes the page at the specified position and all its children. Could trigger page selection change
+in a case when selected page is removed. In that case its parent is selected
+(or the next page if no parent).
+
+
+
+\membersection{wxTreebook::ExpandNode}\label{wxtreebookexpandnode}
+
+\func{bool}{ExpandNode}{\param{size\_t }{pageId}, \param{bool }{expand = true}}
+
+Expands (collapses) the pageId node. Returns the previous state.
+May generate page changing events (if selected page
+is under the collapsed branch, then its parent is autoselected).
+
+
+\membersection{wxTreebook::GetPageImage}\label{wxtreebookgetpageimage}
+
+\constfunc{int}{GetPageImage}{\param{size\_t }{n}}
+
+Returns the image index for the given page.
+
+
+\membersection{wxTreebook::GetPageParent}\label{wxtreebookgetpageparent}
+
+\constfunc{int}{GetPageParent}{\param{size\_t }{page}}
+
+Returns the parent page of the given one or \texttt{wxNOT\_FOUND} if this is a
+top-level page.
+
+
+\membersection{wxTreebook::GetPageText}\label{wxtreebookgetpagetext}
+
+\constfunc{wxString}{GetPageText}{\param{size\_t }{n}}
+
+Returns the string for the given page.
+
+
+
+\membersection{wxTreebook::GetSelection}\label{wxtreebookgetselection}
+
+\constfunc{int}{GetSelection}{\void}
+
+Returns the currently selected page, or wxNOT\_FOUND if none was selected.
+
+Note that this method may return either the previously or newly selected page
+when called from the EVT\_TREEBOOK\_PAGE\_CHANGED handler
+depending on the platform and so wxTreebookEvent::GetSelection should be used instead in this case.
+
+
+
+\membersection{wxTreebook::InsertPage}\label{wxtreebookinsertpage}
+
+\func{bool}{InsertPage}{\param{size\_t }{pagePos}, \param{wxWindow* }{page}, \param{const wxString\& }{text}, \param{bool }{bSelect = false}, \param{int }{imageId = wxNOT\_FOUND}}
+
+Inserts a new page just before the page indicated by pagePos.
+The new page is placed before pagePos page and on the same level.
+NULL could be specified for page to create an empty page.
+
+
+\membersection{wxTreebook::IsNodeExpanded}\label{wxtreebookisnodeexpanded}
+
+\constfunc{bool}{IsNodeExpanded}{\param{size\_t }{pageId}}
+
+Gets the pagePos page state -- whether it is expanded or collapsed
+
+
+
+\membersection{wxTreebook::SetImageList}\label{wxtreebooksetimagelist}
+
+\func{void}{SetImageList}{\param{wxImageList* }{imageList}}
+
+Sets the image list for the page control. It does not take ownership of the image list, you must delete it yourself.
+
+\wxheading{See also}
+
+\helpref{wxImageList}{wximagelist}, \helpref{AssignImageList}{wxtreebookassignimagelist}
+
+
+
+\membersection{wxTreebook::SetPageImage}\label{wxtreebooksetpageimage}
+
+\func{bool}{SetPageImage}{\param{size\_t }{page}, \param{int }{imageId}}
+
+Sets the image index for the given page. ImageId is an index into the image list
+which was set with \helpref{SetImageList}{wxtreebooksetimagelist}.
+
+
+
+\membersection{wxTreebook::SetPageText}\label{wxtreebooksetpagetext}
+
+\func{bool}{SetPageText}{\param{size\_t }{page}, \param{const wxString\& }{text}}
+
+Sets the text for the given page.
+
+
+
+\membersection{wxTreebook::SetSelection}\label{wxtreebooksetselection}
+
+\func{int}{SetSelection}{\param{size\_t }{n}}
+
+Sets the selection for the given page, returning the previous selection.
+
+The call to this function generates the page changing events.
+
+\wxheading{See also}
+
+\helpref{wxTreebook::GetSelection}{wxtreebookgetselection}
+
diff --git a/docs/latex/wx/treebookevent.tex b/docs/latex/wx/treebookevent.tex
new file mode 100644
index 0000000000..289e9a52ed
--- /dev/null
+++ b/docs/latex/wx/treebookevent.tex
@@ -0,0 +1,80 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Name:        treebookevent.tex
+%% Purpose:     wxTreebookEvent documentation
+%% Author:      Evgeniy Tarassov
+%% Modified by:
+%% Created:     2005-10-04
+%% RCS-ID:      $Id$
+%% Copyright:   (c) 2005 Vadim Zeitlin <vadim@wxwindows.org>
+%% License:     wxWindows license
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\section{\class{wxTreebookEvent}}\label{wxtreebookevent}
+
+This class represents the events generated by a treebook control: currently,
+there are four of them. The PAGE\_CHANGING and PAGE\_CHANGED - have exactly the same
+behaviour as \helpref{wxNotebookEvent}{wxnotebookevent}.
+
+The other two NODE\_COLLAPSED and NODE\_EXPANDED are triggered when page node in the tree control
+is collapsed/expanded. The page index could be retreived by calling
+\helpref{wxTreebookEvent::GetSelection}{wxtreebookeventgetselection}.
+
+
+
+\wxheading{Derived from}
+
+wxBookCtrlBaseEvent\\
+\helpref{wxNotifyEvent}{wxnotifyevent}\\
+\helpref{wxCommandEvent}{wxcommandevent}\\
+\helpref{wxEvent}{wxevent}\\
+\helpref{wxObject}{wxobject}
+
+
+
+\wxheading{Include files}
+
+<treebook.h>
+
+
+
+\input treebookevt.inc
+
+
+
+\wxheading{See also}
+
+\helpref{wxNotebookEvent}{wxnotebookevent}, \helpref{wxTreebook}{wxtreebook}
+
+
+
+\latexignore{\rtfignore{\wxheading{Members}}}
+
+
+\membersection{wxTreebookEvent::wxTreebookEvent}\label{wxtreebookeventwxtreebookevent}
+
+\func{}{wxTreebookEvent}{\param{wxEventType }{commandType = wxEVT\_NULL}, \param{int }{id = 0}, \param{int }{nSel = wxNOT\_FOUND}, \param{int }{nOldSel = wxNOT\_FOUND}}
+
+\wxheading{See also}
+
+\helpref{wxNotebookEvent}{wxnotebookevent}
+
+
+
+\membersection{wxTreebookEvent::GetOldSelection}\label{wxtreebookeventgetoldselection}
+
+\constfunc{int}{GetOldSelection}{\void}
+
+Returns the page that was selected before the change, wxNOT\_FOUND if none was selected.
+
+
+
+\membersection{wxTreebookEvent::GetSelection}\label{wxtreebookeventgetselection}
+
+\constfunc{int}{GetSelection}{\void}
+
+Returns the currently selected page, or wxNOT\_FOUND if none was selected.
+
+\wxheading{See also}
+
+\helpref{wxNotebookEvent::GetSelection}{wxnotebookeventgetselection}
+
diff --git a/docs/latex/wx/treebookevt.inc b/docs/latex/wx/treebookevt.inc
new file mode 100644
index 0000000000..5c3e3d8668
--- /dev/null
+++ b/docs/latex/wx/treebookevt.inc
@@ -0,0 +1,12 @@
+\wxheading{Event handling}
+
+To process input from a treebook control, use the following event handler macros
+to direct input to member functions that take a \helpref{wxTreebookEvent}{wxtreebookevent} argument.
+
+\twocolwidtha{10cm}
+\begin{twocollist}\itemsep=0pt
+\twocolitem{{\bf EVT\_TREEBOOK\_PAGE\_CHANGED(id, func)}}{The page selection was changed. Processes a wxEVT\_COMMAND\_TREEBOOK\_PAGE\_CHANGED event.}
+\twocolitem{{\bf EVT\_TREEBOOK\_PAGE\_CHANGING(id, func)}}{The page selection is about to be changed. Processes a wxEVT\_COMMAND\_TREEBOOK\_PAGE\_CHANGING event. This event can be \helpref{vetoed}{wxnotifyeventveto}.}
+\twocolitem{{\bf EVT\_TREEBOOK\_NODE\_COLLAPSED(id, func)}}{The page node is going to be collapsed. Processes a wxEVT\_COMMAND\_TREEBOOK\_NODE\_COLLAPSED event.}
+\twocolitem{{\bf EVT\_TREEBOOK\_NODE\_EXPANDED(id, func)}}{The page node is going to be expanded. Processes a wxEVT\_COMMAND\_TREEBOOK\_NODE\_EXPANDED event.}
+\end{twocollist}
diff --git a/docs/latex/wx/tsamples.tex b/docs/latex/wx/tsamples.tex
index 08ef75068d..347dbb5ee0 100644
--- a/docs/latex/wx/tsamples.tex
+++ b/docs/latex/wx/tsamples.tex
@@ -369,9 +369,9 @@ It replaces the old dynamic sample.
 
 This samples shows \helpref{wxBookCtrl}{wxbookctrloverview} family of controls.
 Although initially it was written to demonstrate \helpref{wxNotebook}{wxnotebook}
-only, it can now be also used to see \helpref{wxListbook}{wxlistbook} and
-\helpref{wxChoicebook}{wxchoicebook} in action. Test each of the controls, their
-orientation, images and pages using commands through menu.
+only, it can now be also used to see \helpref{wxListbook}{wxlistbook},
+\helpref{wxChoicebook}{wxchoicebook} and \helpref{wxTreebook}{wxtreebook} in action.
+Test each of the controls, their orientation, images and pages using commands through menu.
 
 
 
diff --git a/include/wx/bookctrl.h b/include/wx/bookctrl.h
index 95e79de2ab..347dc6ba0c 100644
--- a/include/wx/bookctrl.h
+++ b/include/wx/bookctrl.h
@@ -176,6 +176,13 @@ public:
     }
 
 protected:
+    // Should we accept NULL page pointers in Add/InsertPage()?
+    //
+    // Default is no but derived classes may override it if they can treat NULL
+    // pages in some sensible way (e.g. wxTreebook overrides this to allow
+    // having nodes without any associated page)
+    virtual bool AllowNullPage() const { return false; }
+
     // remove the page and return a pointer to it
     virtual wxWindow *DoRemovePage(size_t page) = 0;
 
diff --git a/include/wx/mac/setup0.h b/include/wx/mac/setup0.h
index 3af04ca034..dc853edc9f 100644
--- a/include/wx/mac/setup0.h
+++ b/include/wx/mac/setup0.h
@@ -614,6 +614,14 @@
 // Recommended setting: 1
 #define wxUSE_CHOICEBOOK 1
 
+// wxTreebook control is similar to wxNotebook but uses wxTreeCtrl instead of
+// the tabs
+//
+// Default is 1.
+//
+// Recommended setting: 1
+#define wxUSE_TREEBOOK 1
+
 // wxTabDialog is a generic version of wxNotebook but it is incompatible with
 // the new class. It shouldn't be used in new code.
 //
diff --git a/include/wx/msw/setup0.h b/include/wx/msw/setup0.h
index 1f53738b08..7e34e7e226 100644
--- a/include/wx/msw/setup0.h
+++ b/include/wx/msw/setup0.h
@@ -613,6 +613,14 @@
 // Recommended setting: 1
 #define wxUSE_CHOICEBOOK 1
 
+// wxTreebook control is similar to wxNotebook but uses wxTreeCtrl instead of
+// the tabs
+//
+// Default is 1.
+//
+// Recommended setting: 1
+#define wxUSE_TREEBOOK 1
+
 // wxTabDialog is a generic version of wxNotebook but it is incompatible with
 // the new class. It shouldn't be used in new code.
 //
diff --git a/include/wx/msw/wince/setup.h b/include/wx/msw/wince/setup.h
index 03451f486e..8cd7baf9d1 100644
--- a/include/wx/msw/wince/setup.h
+++ b/include/wx/msw/wince/setup.h
@@ -613,6 +613,14 @@
 // Recommended setting: 1
 #define wxUSE_CHOICEBOOK 1
 
+// wxTreebook control is similar to wxNotebook but uses wxTreeCtrl instead of
+// the tabs
+//
+// Default is 1.
+//
+// Recommended setting: 1
+#define wxUSE_TREEBOOK 1
+
 // wxTabDialog is a generic version of wxNotebook but it is incompatible with
 // the new class. It shouldn't be used in new code.
 //
diff --git a/include/wx/setup_inc.h b/include/wx/setup_inc.h
index 9f955e23b4..c8e48f7d7d 100644
--- a/include/wx/setup_inc.h
+++ b/include/wx/setup_inc.h
@@ -609,6 +609,14 @@
 // Recommended setting: 1
 #define wxUSE_CHOICEBOOK 1
 
+// wxTreebook control is similar to wxNotebook but uses wxTreeCtrl instead of
+// the tabs
+//
+// Default is 1.
+//
+// Recommended setting: 1
+#define wxUSE_TREEBOOK 1
+
 // wxTabDialog is a generic version of wxNotebook but it is incompatible with
 // the new class. It shouldn't be used in new code.
 //
diff --git a/include/wx/treebook.h b/include/wx/treebook.h
new file mode 100644
index 0000000000..34f0090f89
--- /dev/null
+++ b/include/wx/treebook.h
@@ -0,0 +1,298 @@
+///////////////////////////////////////////////////////////////////////////////
+// Name:        wx/treebook.h
+// Purpose:     wxTreebook: wxNotebook-like control presenting pages in a tree
+// Author:      Evgeniy Tarassov, Vadim Zeitlin
+// Modified by:
+// Created:     2005-09-15
+// RCS-ID:      $Id$
+// Copyright:   (c) 2005 Vadim Zeitlin <vadim@wxwidgets.org>
+// Licence:     wxWindows licence
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef _WX_TREEBOOK_H_
+#define _WX_TREEBOOK_H_
+
+#include "wx/defs.h"
+
+#if wxUSE_TREEBOOK
+
+#include "wx/bookctrl.h"
+#include "wx/treectrl.h"        // for wxArrayTreeItemIds
+
+typedef wxWindow wxTreebookPage;
+
+class WXDLLEXPORT wxTreeEvent;
+
+// ----------------------------------------------------------------------------
+// style flags
+// ----------------------------------------------------------------------------
+
+// This is a set of synonyms of wxNB_XXX, which still could be used directly
+// for styling the control. Defined for consistency with wxListbook and
+// wxChoicebook only.
+#define wxTBK_LEFT      wxNB_LEFT
+#define wxTBK_RIGHT     wxNB_RIGHT
+
+// we don't support TOP/BOTTOM orientations but still define the flags (again,
+// for consistency with others)
+#define wxTBK_TOP       wxTBK_LEFT
+#define wxTBK_BOTTOM    wxTBK_RIGHT
+
+#define wxTBK_ALIGN_MASK (wxTBK_LEFT | wxTBK_RIGHT)
+#define wxTBK_DEFAULT   wxTBK_LEFT
+
+// ----------------------------------------------------------------------------
+// wxTreebook
+// ----------------------------------------------------------------------------
+
+class WXDLLEXPORT wxTreebook : public wxBookCtrlBase
+{
+public:
+    // Constructors and such
+    // ---------------------
+
+    // Default ctor doesn't create the control, use Create() afterwards
+    wxTreebook()
+    {
+        Init();
+    }
+
+    // This ctor creates the tree book control
+    wxTreebook(wxWindow *parent,
+               wxWindowID id,
+               const wxPoint& pos = wxDefaultPosition,
+               const wxSize& size = wxDefaultSize,
+               long style = wxTBK_DEFAULT,
+               const wxString& name = wxEmptyString)
+    {
+        Init();
+
+        (void)Create(parent, id, pos, size, style, name);
+    }
+
+    // Really creates the control
+    bool Create(wxWindow *parent,
+                wxWindowID id,
+                const wxPoint& pos = wxDefaultPosition,
+                const wxSize& size = wxDefaultSize,
+                long style = wxTBK_DEFAULT,
+                const wxString& name = wxEmptyString);
+
+
+    // Page insertion operations
+    // -------------------------
+
+    // Notice that page pointer may be NULL in which case the next non NULL
+    // page (usually the first child page of a node) is shown when this page is
+    // selected
+
+    // Inserts a new page just before the page indicated by page.
+    // The new page is placed on the same level as page.
+    virtual bool InsertPage(size_t pos,
+                            wxWindow *page,
+                            const wxString& text,
+                            bool bSelect = false,
+                            int imageId = wxNOT_FOUND);
+
+    // Inserts a new sub-page to the end of children of the page at given pos.
+    virtual bool AddSubPage(size_t pos,
+                            wxWindow *page,
+                            const wxString& text,
+                            bool bSelect = false,
+                            int imageId = wxNOT_FOUND);
+
+    // Adds a new page at top level after all other pages.
+    virtual bool AddPage(wxWindow *page,
+                         const wxString& text,
+                         bool bSelect = false,
+                         int imageId = wxNOT_FOUND);
+
+    // Adds a new child-page to the last top-level page inserted.
+    // Useful when constructing 1 level tree structure.
+    virtual bool AddSubPage(wxWindow *page,
+                            const wxString& text,
+                            bool bSelect = false,
+                            int imageId = wxNOT_FOUND);
+
+    // Deletes the page and ALL its children. Could trigger page selection
+    // change in a case when selected page is removed. In that case its parent
+    // is selected (or the next page if no parent).
+    virtual bool DeletePage(size_t pos);
+
+
+    // Tree operations
+    // ---------------
+
+    // Gets the page node state -- node is expanded or collapsed
+    virtual bool IsNodeExpanded(size_t pos) const;
+
+    // Expands or collapses the page node. Returns the previous state.
+    // May generate page changing events (if selected page
+    // is under the collapsed branch, then parent is autoselected).
+    virtual bool ExpandNode(size_t pos, bool expand = true);
+
+    // shortcut for ExpandNode(pos, false)
+    bool CollapseNode(size_t pos) { return ExpandNode(pos, false); }
+
+    // get the parent page or wxNOT_FOUND if this is a top level page
+    int GetPageParent(size_t pos) const;
+
+
+    // Standard operations inherited from wxBookCtrlBase
+    // -------------------------------------------------
+
+    virtual int GetSelection() const;
+    virtual bool SetPageText(size_t n, const wxString& strText);
+    virtual wxString GetPageText(size_t n) const;
+    virtual int GetPageImage(size_t n) const;
+    virtual bool SetPageImage(size_t n, int imageId);
+    virtual wxSize CalcSizeFromPage(const wxSize& sizePage) const;
+    virtual int SetSelection(size_t n);
+    virtual void SetImageList(wxImageList *imageList);
+    virtual void AssignImageList(wxImageList *imageList);
+    virtual bool DeleteAllPages();
+
+protected:
+    // This subclass of wxBookCtrlBase accepts NULL page pointers (empty pages)
+    virtual bool AllowNullPage() const { return true; }
+
+    // get the size which the tree control should have
+    wxSize GetTreeSize() const;
+
+    // get the page area
+    wxRect GetPageRect() const;
+
+    // event handlers
+    void OnSize(wxSizeEvent& event);
+    void OnTreeSelectionChange(wxTreeEvent& event);
+    void OnTreeNodeExpandedCollapsed(wxTreeEvent& event);
+
+
+    // the tree control we use for showing the pages index tree
+    wxTreeCtrl *m_tree;
+
+    // array of page ids and page windows
+    wxArrayTreeItemIds m_treeIds;
+
+    // the currently selected page or wxNOT_FOUND if none
+    int m_selection;
+
+    // in the situation when m_selection page is not wxNOT_FOUND but page is
+    // NULL this is the first (sub)child that has a non-NULL page
+    int m_actualSelection;
+
+private:
+    // common part of all constructors
+    void Init();
+
+    // The real implementations of page insertion functions
+    // ------------------------------------------------------
+    // All DoInsert/Add(Sub)Page functions add the page into :
+    // - the base class
+    // - the tree control
+    // - update the index/TreeItemId corespondance array
+    bool DoInsertPage(size_t pos,
+                      wxWindow *page,
+                      const wxString& text,
+                      bool bSelect = false,
+                      int imageId = wxNOT_FOUND);
+    bool DoInsertSubPage(size_t pos,
+                         wxWindow *page,
+                         const wxString& text,
+                         bool bSelect = false,
+                         int imageId = wxNOT_FOUND);
+    bool DoAddSubPage(wxWindow *page,
+                         const wxString& text,
+                         bool bSelect = false,
+                         int imageId = wxNOT_FOUND);
+
+    // Implementation of a page removal. See DeletPage for comments.
+    wxTreebookPage *DoRemovePage(size_t pos);
+
+    // Sets selection in the tree control and updates the page being shown.
+    int DoSetSelection(size_t pos);
+
+    // Returns currently shown page. In a case when selected the node
+    // has empty (NULL) page finds first (sub)child with not-empty page.
+    wxTreebookPage *DoGetCurrentPage() const;
+
+    // Does the selection update. Called from page insertion functions
+    // to update selection if the selected page was pushed by the newly inserted
+    void DoUpdateSelection(bool bSelect, int page);
+
+
+    // Operations on the internal private members of the class
+    // -------------------------------------------------------
+    // Returns the page TreeItemId for the page.
+    // Or, if the page index is incorrect, a fake one (fakePage.IsOk() == false)
+    wxTreeItemId DoInternalGetPage(size_t pos) const;
+
+    // Linear search for a page with the id specified. If no page
+    // found wxNOT_FOUND is returned. The function is used when we catch an event
+    // from m_tree (wxTreeCtrl) component.
+    int DoInternalFindPageById(wxTreeItemId page) const;
+
+    // Updates page and wxTreeItemId correspondance.
+    void DoInternalAddPage(size_t newPos, wxWindow *page, wxTreeItemId pageId);
+
+    // Removes the page from internal structure.
+    void DoInternalRemovePage(size_t pos)
+        { DoInternalRemovePageRange(pos, 0); }
+
+    // Removes the page and all its children designated by subCount
+    // from internal structures of the control.
+    void DoInternalRemovePageRange(size_t pos, size_t subCount);
+
+    // Returns internal number of pages which can be different from
+    // GetPageCount() while performing a page insertion or removal.
+    size_t DoInternalGetPageCount() const { return m_treeIds.Count(); }
+
+
+    DECLARE_EVENT_TABLE()
+    DECLARE_DYNAMIC_CLASS_NO_COPY(wxTreebook)
+};
+
+
+// ----------------------------------------------------------------------------
+// treebook event class and related stuff
+// ----------------------------------------------------------------------------
+
+class WXDLLEXPORT wxTreebookEvent : public wxBookCtrlBaseEvent
+{
+public:
+    wxTreebookEvent(wxEventType commandType = wxEVT_NULL, int id = 0,
+                    int nSel = wxNOT_FOUND, int nOldSel = wxNOT_FOUND)
+        : wxBookCtrlBaseEvent(commandType, id, nSel, nOldSel)
+    {
+    }
+
+private:
+    DECLARE_DYNAMIC_CLASS_NO_COPY(wxTreebookEvent)
+};
+
+extern WXDLLIMPEXP_CORE const wxEventType wxEVT_COMMAND_TREEBOOK_PAGE_CHANGED;
+extern WXDLLIMPEXP_CORE const wxEventType wxEVT_COMMAND_TREEBOOK_PAGE_CHANGING;
+extern WXDLLIMPEXP_CORE const wxEventType wxEVT_COMMAND_TREEBOOK_NODE_COLLAPSED;
+extern WXDLLIMPEXP_CORE const wxEventType wxEVT_COMMAND_TREEBOOK_NODE_EXPANDED;
+
+typedef void (wxEvtHandler::*wxTreebookEventFunction)(wxTreebookEvent&);
+
+#define wxTreebookEventHandler(func) \
+    (wxObjectEventFunction)(wxEventFunction)wxStaticCastEvent(wxTreebookEventFunction, &func)
+
+#define EVT_TREEBOOK_PAGE_CHANGED(winid, fn) \
+    wx__DECLARE_EVT1(wxEVT_COMMAND_TREEBOOK_PAGE_CHANGED, winid, wxTreebookEventHandler(fn))
+
+#define EVT_TREEBOOK_PAGE_CHANGING(winid, fn) \
+    wx__DECLARE_EVT1(wxEVT_COMMAND_TREEBOOK_PAGE_CHANGING, winid, wxTreebookEventHandler(fn))
+
+#define EVT_TREEBOOK_NODE_COLLAPSED(winid, fn) \
+    wx__DECLARE_EVT1(wxEVT_COMMAND_TREEBOOK_NODE_COLLAPSED, winid, wxTreebookEventHandler(fn))
+
+#define EVT_TREEBOOK_NODE_EXPANDED(winid, fn) \
+    wx__DECLARE_EVT1(wxEVT_COMMAND_TREEBOOK_NODE_EXPANDED, winid, wxTreebookEventHandler(fn))
+
+
+#endif // wxUSE_TREEBOOK
+
+#endif // _WX_TREEBOOK_H_
diff --git a/include/wx/univ/setup0.h b/include/wx/univ/setup0.h
index 1c2f618990..b22c5318d9 100644
--- a/include/wx/univ/setup0.h
+++ b/include/wx/univ/setup0.h
@@ -649,6 +649,14 @@
 // Recommended setting: 1
 #define wxUSE_CHOICEBOOK 1
 
+// wxTreebook control is similar to wxNotebook but uses wxTreeCtrl instead of
+// the tabs
+//
+// Default is 1.
+//
+// Recommended setting: 1
+#define wxUSE_TREEBOOK 1
+
 // wxTabDialog is a generic version of wxNotebook but it is incompatible with
 // the new class. It shouldn't be used in new code.
 //
diff --git a/include/wx/xrc/xh_all.h b/include/wx/xrc/xh_all.h
index 41baf0cbb1..b3f42aa180 100644
--- a/include/wx/xrc/xh_all.h
+++ b/include/wx/xrc/xh_all.h
@@ -36,6 +36,7 @@
 #include "wx/xrc/xh_notbk.h"
 #include "wx/xrc/xh_listbk.h"
 #include "wx/xrc/xh_choicbk.h"
+#include "wx/xrc/xh_treebk.h"
 #include "wx/xrc/xh_text.h"
 #include "wx/xrc/xh_listb.h"
 #include "wx/xrc/xh_toolb.h"
diff --git a/include/wx/xrc/xh_treebk.h b/include/wx/xrc/xh_treebk.h
new file mode 100644
index 0000000000..cc2cd4d479
--- /dev/null
+++ b/include/wx/xrc/xh_treebk.h
@@ -0,0 +1,81 @@
+/////////////////////////////////////////////////////////////////////////////
+// Name:        xh_treebk.h
+// Purpose:     XML resource handler for wxTreebook
+// Author:      Evgeniy Tarassov
+// Created:     2005/09/28
+// Copyright:   (c) 2005 TT-Solutions <vadim@tt-solutions.com>
+// Licence:     wxWindows licence
+/////////////////////////////////////////////////////////////////////////////
+
+#ifndef _WX_XH_TREEBK_H_
+#define _WX_XH_TREEBK_H_
+
+#include "wx/xrc/xmlres.h"
+
+#if wxUSE_TREEBOOK
+
+#include "wx/treebook.h"
+
+WX_DEFINE_ARRAY_INT(size_t, wxArrayTbkPageIndexes);
+
+// ---------------------------------------------------------------------
+// wxTreebookXmlHandler class
+// ---------------------------------------------------------------------
+// Resource xml structure have to be almost the "same" as for wxNotebook
+// except the additional (size_t)depth parameter for treebookpage nodes
+// which indicates the depth of the page in the tree.
+// There is only one logical constraint on this parameter :
+// it cannot be greater than the previous page depth plus one
+class WXDLLIMPEXP_XRC wxTreebookXmlHandler : public wxXmlResourceHandler
+{
+DECLARE_DYNAMIC_CLASS(wxTreebookXmlHandler)
+public:
+    wxTreebookXmlHandler();
+    virtual wxObject *DoCreateResource();
+    virtual bool CanHandle(wxXmlNode *node);
+
+private:
+    bool m_isInside;
+    wxTreebook * m_tbk;
+    wxArrayTbkPageIndexes m_treeContext;
+};
+
+
+// Example:
+// -------
+// Label
+// \--First
+// |  \--Second
+// \--Third
+//
+//<resource>
+//  ...
+//  <object class="wxTreebook">
+//    <object class="treebookpage">
+//      <object class="wxWindow" />
+//      <label>My first page</label>
+//      <depth>0</depth>
+//    </object>
+//    <object class="treebookpage">
+//      <object class="wxWindow" />
+//      <label>First</label>
+//      <depth>1</depth>
+//    </object>
+//    <object class="treebookpage">
+//      <object class="wxWindow" />
+//      <label>Second</label>
+//      <depth>2</depth>
+//    </object>
+//    <object class="treebookpage">
+//      <object class="wxWindow" />
+//      <label>Third</label>
+//      <depth>1</depth>
+//    </object>
+//  </object>
+//  ...
+//</resource>
+
+#endif
+
+#endif // _WX_XH_TREEBK_H_
+
diff --git a/samples/notebook/notebook.cpp b/samples/notebook/notebook.cpp
index ad083b352e..c9e3cb44ca 100644
--- a/samples/notebook/notebook.cpp
+++ b/samples/notebook/notebook.cpp
@@ -33,7 +33,7 @@ IMPLEMENT_APP(MyApp)
 bool MyApp::OnInit()
 {
     // Create the main window
-    MyFrame *frame = new MyFrame( wxT("Notebook sample") );
+    MyFrame *frame = new MyFrame();
 
     // Problem with generic wxNotebook implementation whereby it doesn't size
     // properly unless you set the size again
@@ -153,51 +153,40 @@ void CreateInitialPages(wxBookCtrlBase *parent)
 
 wxPanel *CreatePage(wxBookCtrlBase *parent, const wxString&pageName)
 {
-    if
-    (
-        pageName.Contains(INSERTED_PAGE_NAME)
-        || pageName.Contains(ADDED_PAGE_NAME)
-    )
-    {
+    if ( pageName.Contains(INSERTED_PAGE_NAME) ||
+            pageName.Contains(ADDED_PAGE_NAME) ||
+                pageName.Contains(ADDED_SUB_PAGE_NAME) ||
+                    pageName.Contains(ADDED_PAGE_NAME_BEFORE) )
         return CreateUserCreatedPage(parent);
-    }
 
-    if (pageName == I_WAS_INSERTED_PAGE_NAME)
-    {
+    if ( pageName == I_WAS_INSERTED_PAGE_NAME )
         return CreateInsertPage(parent);
-    }
 
-    if (pageName == VETO_PAGE_NAME)
-    {
+    if ( pageName == VETO_PAGE_NAME )
         return CreateVetoPage(parent);
-    }
 
-    if (pageName == RADIOBUTTONS_PAGE_NAME)
-    {
+    if ( pageName == RADIOBUTTONS_PAGE_NAME )
         return CreateRadioButtonsPage(parent);
-    }
 
-
-    if (pageName == MAXIMIZED_BUTTON_PAGE_NAME)
-    {
+    if ( pageName == MAXIMIZED_BUTTON_PAGE_NAME )
         return CreateBigButtonPage(parent);
-    }
 
-    wxFAIL;
+    wxFAIL_MSG( _T("unknown page name") );
 
-    return (wxPanel *) NULL;
+    return NULL;
 }
 
-MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size,
-                 long style)
-    : wxFrame((wxWindow *) NULL, wxID_ANY, title, pos, size, style)
+MyFrame::MyFrame()
+       : wxFrame(NULL, wxID_ANY,  wxString(wxT("wxWidgets book controls sample")))
 {
 #if wxUSE_NOTEBOOK
-    m_type = ID_BOOK_NOTEBOOK;
+    m_type = Type_Notebook;
 #elif wxUSE_CHOICEBOOK
-    m_type = ID_BOOK_CHOICEBOOK;
+    m_type = Type_Choicebook;
 #elif wxUSE_LISTBOOK
-    m_type = ID_BOOK_LISTBOOK;
+    m_type = Type_Listbook;
+#elif wxUSE_TREEBOOK
+    m_type = Type_Treebook;
 #elif
     #error "Don't use Notebook sample without any book enabled in wxWidgets build!"
 #endif
@@ -219,21 +208,30 @@ MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size,
 #if wxUSE_CHOICEBOOK
     menuType->AppendRadioItem(ID_BOOK_CHOICEBOOK, wxT("&Choicebook\tCtrl-3"));
 #endif
-    menuType->Check(m_type, true);
+#if wxUSE_TREEBOOK
+    menuType->AppendRadioItem(ID_BOOK_TREEBOOK,   wxT("&Treebook\tCtrl-4"));
+#endif
+
+    menuType->Check(ID_BOOK_NOTEBOOK + m_type, true);
 
     wxMenu *menuOrient = new wxMenu;
-    menuOrient->AppendRadioItem(ID_ORIENT_DEFAULT, wxT("&Default\tCtrl-4"));
-    menuOrient->AppendRadioItem(ID_ORIENT_TOP,     wxT("&Top\tCtrl-5"));
-    menuOrient->AppendRadioItem(ID_ORIENT_BOTTOM,  wxT("&Bottom\tCtrl-6"));
-    menuOrient->AppendRadioItem(ID_ORIENT_LEFT,    wxT("&Left\tCtrl-7"));
-    menuOrient->AppendRadioItem(ID_ORIENT_RIGHT,   wxT("&Right\tCtrl-8"));
-
-    wxMenu *menuDo = new wxMenu;
-    menuDo->Append(ID_ADD_PAGE, wxT("&Add page\tAlt-A"));
-    menuDo->Append(ID_INSERT_PAGE, wxT("&Insert page\tAlt-I"));
-    menuDo->Append(ID_DELETE_CUR_PAGE, wxT("&Delete current page\tAlt-D"));
-    menuDo->Append(ID_DELETE_LAST_PAGE, wxT("D&elete last page\tAlt-L"));
-    menuDo->Append(ID_NEXT_PAGE, wxT("&Next page\tAlt-N"));
+    menuOrient->AppendRadioItem(ID_ORIENT_DEFAULT, wxT("&Default\tCtrl-5"));
+    menuOrient->AppendRadioItem(ID_ORIENT_TOP,     wxT("&Top\tCtrl-6"));
+    menuOrient->AppendRadioItem(ID_ORIENT_BOTTOM,  wxT("&Bottom\tCtrl-7"));
+    menuOrient->AppendRadioItem(ID_ORIENT_LEFT,    wxT("&Left\tCtrl-8"));
+    menuOrient->AppendRadioItem(ID_ORIENT_RIGHT,   wxT("&Right\tCtrl-9"));
+
+    wxMenu *menuOperations = new wxMenu;
+    menuOperations->Append(ID_ADD_PAGE, wxT("&Add page\tAlt-A"));
+    menuOperations->Append(ID_INSERT_PAGE, wxT("&Insert page\tAlt-I"));
+    menuOperations->Append(ID_DELETE_CUR_PAGE, wxT("&Delete current page\tAlt-D"));
+    menuOperations->Append(ID_DELETE_LAST_PAGE, wxT("D&elete last page\tAlt-L"));
+    menuOperations->Append(ID_NEXT_PAGE, wxT("&Next page\tAlt-N"));
+#if wxUSE_TREEBOOK
+    menuOperations->AppendSeparator();
+    menuOperations->Append(ID_ADD_PAGE_BEFORE, wxT("Insert page &before\tAlt-B"));
+    menuOperations->Append(ID_ADD_SUB_PAGE, wxT("Add s&ub page\tAlt-U"));
+#endif
 
     wxMenu *menuFile = new wxMenu;
     menuFile->Append(wxID_ANY, wxT("&Type"), menuType, wxT("Type of control"));
@@ -247,54 +245,32 @@ MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size,
 
     wxMenuBar *menuBar = new wxMenuBar;
     menuBar->Append(menuFile, wxT("&File"));
-    menuBar->Append(menuDo, wxT("&Operations"));
+    menuBar->Append(menuOperations, wxT("&Operations"));
     SetMenuBar(menuBar);
 
     // books creation
-
-    m_panel      = (wxPanel *)      NULL;
-#if wxUSE_NOTEBOOK
-    m_notebook   = (wxNotebook *)   NULL;
-#endif
-#if wxUSE_CHOICEBOOK
-    m_choicebook = (wxChoicebook *) NULL;
-#endif
-#if wxUSE_LISTBOOK
-    m_listbook   = (wxListbook *)   NULL;
-#endif
+    m_panel    = NULL;
+    m_bookCtrl = NULL;
 
     // create a dummy image list with a few icons
-    wxSize imageSize(32, 32);
-
-    m_imageList
-        = new wxImageList( imageSize.GetWidth(), imageSize.GetHeight() );
-
-    m_imageList->Add
-        (
-            wxArtProvider::GetIcon(wxART_INFORMATION, wxART_OTHER, imageSize)
-        );
+    const wxSize imageSize(32, 32);
 
-    m_imageList->Add
-        (
-            wxArtProvider::GetIcon(wxART_QUESTION, wxART_OTHER, imageSize)
-        );
+    m_imageList = new wxImageList(imageSize.GetWidth(), imageSize.GetHeight());
+    m_imageList->
+        Add(wxArtProvider::GetIcon(wxART_INFORMATION, wxART_OTHER, imageSize));
+    m_imageList->
+        Add(wxArtProvider::GetIcon(wxART_QUESTION, wxART_OTHER, imageSize));
+    m_imageList->
+        Add(wxArtProvider::GetIcon(wxART_WARNING, wxART_OTHER, imageSize));
+    m_imageList->
+        Add(wxArtProvider::GetIcon(wxART_ERROR, wxART_OTHER, imageSize));
 
-    m_imageList->Add
-        (
-            wxArtProvider::GetIcon(wxART_WARNING, wxART_OTHER, imageSize)
-        );
-
-    m_imageList->Add
-        (
-            wxArtProvider::GetIcon(wxART_ERROR, wxART_OTHER, imageSize)
-        );
-
-    m_panel = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxDefaultSize,
-        wxTAB_TRAVERSAL | wxCLIP_CHILDREN | wxNO_BORDER | wxNO_FULL_REPAINT_ON_RESIZE);
+    m_panel = new wxPanel(this);
 
 #if USE_LOG
     m_text = new wxTextCtrl(m_panel, wxID_ANY, wxEmptyString,
-        wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE | wxTE_READONLY);
+                            wxDefaultPosition, wxDefaultSize,
+                            wxTE_MULTILINE | wxTE_READONLY);
 
     m_logTargetOld = wxLog::SetActiveTarget( new wxLogTextCtrl(m_text) );
 #endif // USE_LOG
@@ -306,7 +282,7 @@ MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size,
     m_sizerFrame->Add(m_text, 1, wxEXPAND);
 #endif // USE_LOG
 
-    RecreateBooks();
+    RecreateBook();
 
     m_panel->SetSizer(m_sizerFrame);
 
@@ -322,160 +298,175 @@ MyFrame::~MyFrame()
     delete wxLog::SetActiveTarget(m_logTargetOld);
 #endif // USE_LOG
 
-    if (m_imageList)
-    {
-        delete m_imageList;
-        m_imageList = (wxImageList *) NULL;
-    }
+    delete m_imageList;
 }
 
-int MyFrame::SelectFlag(int id, int nb, int lb, int chb)
-{
-    switch (id)
-    {
-        case ID_NOTEBOOK:   return nb;
-        case ID_LISTBOOK:   return lb;
-        case ID_CHOICEBOOK: return chb;
-    }
-    return 0;
-}
-
-#ifdef __SMARTPHONE__
-    #define MARGIN 0
+// DISPATCH_ON_TYPE() macro is an ugly way to write the "same" code for
+// different wxBookCtrlBase-derived classes without duplicating code and
+// without using templates, it expands into "before <xxx> after" where "xxx"
+// part is control class-specific
+#if wxUSE_NOTEBOOK
+    #define CASE_NOTEBOOK(x) case Type_Notebook: x; break;
 #else
-    #define MARGIN 4
+    #define CASE_NOTEBOOK(x)
 #endif
 
-#define RECREATE( wxBookType , idBook, oldBook , newBook )                         \
-{                                                                                  \
-    int flags;                                                                     \
-                                                                                   \
-    switch ( m_orient )                                                            \
-    {                                                                              \
-        case ID_ORIENT_TOP:                                                        \
-            flags = SelectFlag(idBook, wxNB_TOP, wxLB_TOP, wxCHB_TOP);             \
-            break;                                                                 \
-                                                                                   \
-        case ID_ORIENT_BOTTOM:                                                     \
-            flags = SelectFlag(idBook, wxNB_BOTTOM, wxLB_BOTTOM, wxCHB_BOTTOM);    \
-            break;                                                                 \
-                                                                                   \
-        case ID_ORIENT_LEFT:                                                       \
-            flags = SelectFlag(idBook, wxNB_LEFT, wxLB_LEFT, wxCHB_LEFT);          \
-            break;                                                                 \
-                                                                                   \
-        case ID_ORIENT_RIGHT:                                                      \
-            flags = SelectFlag(idBook, wxNB_RIGHT, wxLB_RIGHT, wxCHB_RIGHT);       \
-            break;                                                                 \
-                                                                                   \
-        default:                                                                   \
-            flags = SelectFlag(idBook, wxNB_DEFAULT, wxLB_DEFAULT, wxCHB_DEFAULT); \
-    }                                                                              \
-                                                                                   \
-    if ( m_multi && ( idBook == ID_NOTEBOOK ) )                                    \
-        flags |= wxNB_MULTILINE;                                                   \
-                                                                                   \
-    wxBookType *oldBook = newBook;                                                 \
-                                                                                   \
-    newBook = new wxBookType(m_panel, idBook,                                      \
-                             wxDefaultPosition, wxDefaultSize,                     \
-                             flags);                                               \
-                                                                                   \
-    if ( m_chkShowImages )                                                         \
-    {                                                                              \
-        newBook->SetImageList(m_imageList);                                        \
-    }                                                                              \
-                                                                                   \
-    if (oldBook)                                                                   \
-    {                                                                              \
-        int sel = oldBook->GetSelection();                                         \
-                                                                                   \
-        int count = oldBook->GetPageCount();                                       \
-        for (int n = 0; n < count; n++)                                            \
-        {                                                                          \
-            wxString str = oldBook->GetPageText(n);                                \
-                                                                                   \
-            wxWindow *page = CreatePage(newBook, str);                             \
-            newBook->AddPage(page, str, false, GetIconIndex(newBook) );            \
-        }                                                                          \
-                                                                                   \
-        m_sizerFrame->Detach(oldBook);                                             \
-                                                                                   \
-        delete oldBook;                                                            \
-                                                                                   \
-        if (sel != wxNOT_FOUND)                                                    \
-        {                                                                          \
-            newBook->SetSelection(sel);                                            \
-        }                                                                          \
-                                                                                   \
-    }                                                                              \
-    else                                                                           \
-    {                                                                              \
-        CreateInitialPages(newBook);                                               \
-    }                                                                              \
-                                                                                   \
-    m_sizerFrame->Insert(0, newBook, 5, wxEXPAND | wxALL, MARGIN);                 \
-                                                                                   \
-    m_sizerFrame->Hide(newBook);                                                   \
-}
-
-void MyFrame::RecreateBooks()
-{
-#if wxUSE_NOTEBOOK
-    RECREATE( wxNotebook   , ID_NOTEBOOK   , notebook   , m_notebook );
+#if wxUSE_CHOICEBOOK
+    #define CASE_CHOICEBOOK(x) case Type_Choicebook: x; break;
+#else
+    #define CASE_CHOICEBOOK(x)
 #endif
+
 #if wxUSE_LISTBOOK
-    RECREATE( wxListbook   , ID_LISTBOOK   , listbook   , m_listbook );
+    #define CASE_LISTBOOK(x) case Type_Listbook: x; break;
+#else
+    #define CASE_LISTBOOK(x)
 #endif
-#if wxUSE_CHOICEBOOK
-    RECREATE( wxChoicebook , ID_CHOICEBOOK , choicebook , m_choicebook );
+
+#if wxUSE_TREEBOOK
+    #define CASE_TREEBOOK(x) case Type_Treebook: x; break;
+#else
+    #define CASE_TREEBOOK(x)
 #endif
 
-    ShowCurrentBook();
+#define DISPATCH_ON_TYPE(before, nb, lb, cb, tb, after)                       \
+    switch ( m_type )                                                         \
+    {                                                                         \
+        CASE_NOTEBOOK(before nb after)                                        \
+        CASE_CHOICEBOOK(before cb after)                                      \
+        CASE_LISTBOOK(before lb after)                                        \
+        CASE_TREEBOOK(before tb after)                                        \
+                                                                              \
+        default:                                                              \
+            wxFAIL_MSG( _T("unknown book control type") );                    \
+    }
+
+int MyFrame::TranslateBookFlag(int nb, int lb, int chb, int tbk) const
+{
+    int flag = 0;
+
+    DISPATCH_ON_TYPE(flag =, nb,  lb,  chb,  tbk, + 0);
+
+    return flag;
 }
 
-wxBookCtrlBase *MyFrame::GetCurrentBook()
+void MyFrame::RecreateBook()
 {
-    switch (m_type)
+#define SELECT_FLAG(flag) \
+    TranslateBookFlag(wxNB_##flag, wxCHB_##flag, wxLB_##flag, wxTBK_##flag)
+
+    int flags;
+    switch ( m_orient )
     {
-#if wxUSE_NOTEBOOK
-        case ID_BOOK_NOTEBOOK:   return m_notebook;
-#endif
-#if wxUSE_LISTBOOK
-        case ID_BOOK_LISTBOOK:   return m_listbook;
-#endif
-#if wxUSE_CHOICEBOOK
-        case ID_BOOK_CHOICEBOOK: return m_choicebook;
-#endif
+        case ID_ORIENT_TOP:
+            flags = SELECT_FLAG(TOP);
+            break;
+
+        case ID_ORIENT_BOTTOM:
+            flags = SELECT_FLAG(BOTTOM);
+            break;
+
+        case ID_ORIENT_LEFT:
+            flags = SELECT_FLAG(LEFT);
+            break;
+
+        case ID_ORIENT_RIGHT:
+            flags = SELECT_FLAG(RIGHT);
+            break;
+
+        default:
+            flags = SELECT_FLAG(DEFAULT);
     }
-    return NULL;
-}
 
-void MyFrame::ShowCurrentBook()
-{
-    switch(m_type)
+#undef SELECT_FLAG
+
+    if ( m_multi && m_type == Type_Notebook )
+        flags |= wxNB_MULTILINE;
+    flags |= wxDOUBLE_BORDER;
+
+    wxBookCtrlBase *oldBook = m_bookCtrl;
+
+    m_bookCtrl = NULL;
+
+    DISPATCH_ON_TYPE(m_bookCtrl = new,
+                         wxNotebook,
+                         wxChoicebook,
+                         wxListbook,
+                         wxTreebook,
+                     (m_panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, flags));
+
+    if ( !m_bookCtrl )
+        return;
+
+    m_bookCtrl->Hide();
+
+    if ( m_chkShowImages )
     {
-#if wxUSE_NOTEBOOK
-        case ID_BOOK_NOTEBOOK:   if(m_notebook)   m_sizerFrame->Show(m_notebook);   break;
-#endif
-#if wxUSE_LISTBOOK
-        case ID_BOOK_LISTBOOK:   if(m_listbook)   m_sizerFrame->Show(m_listbook);   break;
-#endif
-#if wxUSE_CHOICEBOOK
-        case ID_BOOK_CHOICEBOOK: if(m_choicebook) m_sizerFrame->Show(m_choicebook); break;
-#endif
+        m_bookCtrl->SetImageList(m_imageList);
     }
 
+    if ( oldBook )
+    {
+#if wxUSE_TREEBOOK
+        // we only need the old treebook if we're recreating another treebook
+        wxTreebook *tbkOld = m_type == Type_Treebook
+                                ? wxDynamicCast(oldBook, wxTreebook)
+                                : NULL;
+#endif // wxUSE_TREEBOOK
+
+        const int count = oldBook->GetPageCount();
+        for ( int n = 0; n < count; n++ )
+        {
+            const int image = GetIconIndex(m_bookCtrl);
+            const wxString str = oldBook->GetPageText(n);
+
+            wxWindow *page = CreatePage(m_bookCtrl, str);
+
+            // treebook complication: need to account for possible parent page
+#if wxUSE_TREEBOOK
+            if ( tbkOld )
+            {
+                const int parent = tbkOld->GetPageParent(n);
+                if ( parent != wxNOT_FOUND )
+                {
+                    wxStaticCast(m_bookCtrl, wxTreebook)->
+                        AddSubPage(parent, page, str, false, image);
+
+                    // skip adding it again below
+                    continue;
+                }
+            }
+#endif // wxUSE_TREEBOOK
+
+            m_bookCtrl->AddPage(page, str, false, image);
+        }
+
+        const int sel = oldBook->GetSelection();
+        if ( sel != wxNOT_FOUND )
+            m_bookCtrl->SetSelection(sel);
+
+
+        m_sizerFrame->Detach(oldBook);
+        delete oldBook;
+    }
+    else // no old book
+    {
+        CreateInitialPages(m_bookCtrl);
+    }
+
+    m_sizerFrame->Insert(0, m_bookCtrl, wxSizerFlags(5).Expand().Border());
+
+    m_sizerFrame->Show(m_bookCtrl);
     m_sizerFrame->Layout();
 }
 
 BEGIN_EVENT_TABLE(MyFrame, wxFrame)
     // File menu
-    EVT_MENU_RANGE(ID_BOOK_NOTEBOOK,ID_BOOK_MAX,MyFrame::OnType)
-    EVT_MENU_RANGE(ID_ORIENT_DEFAULT,ID_ORIENT_MAX,MyFrame::OnOrient)
+    EVT_MENU_RANGE(ID_BOOK_NOTEBOOK, ID_BOOK_MAX, MyFrame::OnType)
+    EVT_MENU_RANGE(ID_ORIENT_DEFAULT, ID_ORIENT_MAX, MyFrame::OnOrient)
     EVT_MENU(ID_SHOW_IMAGES, MyFrame::OnShowImages)
     EVT_MENU(ID_MULTI, MyFrame::OnMulti)
-    EVT_MENU(wxID_EXIT,MyFrame::OnExit)
+    EVT_MENU(wxID_EXIT, MyFrame::OnExit)
 
     // Operations menu
     EVT_MENU(ID_ADD_PAGE, MyFrame::OnAddPage)
@@ -483,55 +474,74 @@ BEGIN_EVENT_TABLE(MyFrame, wxFrame)
     EVT_MENU(ID_DELETE_CUR_PAGE, MyFrame::OnDeleteCurPage)
     EVT_MENU(ID_DELETE_LAST_PAGE, MyFrame::OnDeleteLastPage)
     EVT_MENU(ID_NEXT_PAGE, MyFrame::OnNextPage)
+    EVT_MENU(ID_ADD_SUB_PAGE, MyFrame::OnAddSubPage)
+    EVT_MENU(ID_ADD_PAGE_BEFORE, MyFrame::OnAddPageBefore)
 
     // Book controls
 #if wxUSE_NOTEBOOK
-    EVT_NOTEBOOK_PAGE_CHANGED(ID_NOTEBOOK, MyFrame::OnNotebook)
-    EVT_NOTEBOOK_PAGE_CHANGING(ID_NOTEBOOK, MyFrame::OnNotebook)
+    EVT_NOTEBOOK_PAGE_CHANGED(wxID_ANY, MyFrame::OnNotebook)
+    EVT_NOTEBOOK_PAGE_CHANGING(wxID_ANY, MyFrame::OnNotebook)
 #endif
 #if wxUSE_LISTBOOK
-    EVT_LISTBOOK_PAGE_CHANGED(ID_LISTBOOK, MyFrame::OnListbook)
-    EVT_LISTBOOK_PAGE_CHANGING(ID_LISTBOOK, MyFrame::OnListbook)
+    EVT_LISTBOOK_PAGE_CHANGED(wxID_ANY, MyFrame::OnListbook)
+    EVT_LISTBOOK_PAGE_CHANGING(wxID_ANY, MyFrame::OnListbook)
 #endif
 #if wxUSE_CHOICEBOOK
-    EVT_CHOICEBOOK_PAGE_CHANGED(ID_CHOICEBOOK, MyFrame::OnChoicebook)
-    EVT_CHOICEBOOK_PAGE_CHANGING(ID_CHOICEBOOK, MyFrame::OnChoicebook)
+    EVT_CHOICEBOOK_PAGE_CHANGED(wxID_ANY, MyFrame::OnChoicebook)
+    EVT_CHOICEBOOK_PAGE_CHANGING(wxID_ANY, MyFrame::OnChoicebook)
+#endif
+#if wxUSE_CHOICEBOOK
+    EVT_TREEBOOK_PAGE_CHANGED(wxID_ANY, MyFrame::OnTreebook)
+    EVT_TREEBOOK_PAGE_CHANGING(wxID_ANY, MyFrame::OnTreebook)
 #endif
 
     // Update title in idle time
     EVT_IDLE(MyFrame::OnIdle)
+
+#if wxUSE_TREEBOOK
+    EVT_UPDATE_UI_RANGE(ID_ADD_PAGE_BEFORE, ID_ADD_SUB_PAGE,
+                            MyFrame::OnUpdateTreeMenu)
+#endif // wxUSE_TREEBOOK
 END_EVENT_TABLE()
 
 void MyFrame::OnType(wxCommandEvent& event)
 {
-    wxBookCtrlBase *currBook = GetCurrentBook();
+    m_type = wx_static_cast(BookType, event.GetId() - ID_BOOK_NOTEBOOK);
+
+    if ( m_bookCtrl )
+        m_sizerFrame->Hide(m_bookCtrl);
 
-    m_type = event.GetId();
+    RecreateBook();
+}
 
-    if (currBook)
-        m_sizerFrame->Hide(currBook);
+#if wxUSE_TREEBOOK
 
-    ShowCurrentBook();
+void MyFrame::OnUpdateTreeMenu(wxUpdateUIEvent& event)
+{
+    event.Enable(m_type == Type_Treebook);
 }
 
+#endif // wxUSE_TREEBOOK
+
+
 void MyFrame::OnOrient(wxCommandEvent& event)
 {
     m_orient = event.GetId();
-    RecreateBooks();
+    RecreateBook();
     m_sizerFrame->Layout();
 }
 
 void MyFrame::OnShowImages(wxCommandEvent& event)
 {
     m_chkShowImages = event.IsChecked();
-    RecreateBooks();
+    RecreateBook();
     m_sizerFrame->Layout();
 }
 
 void MyFrame::OnMulti(wxCommandEvent& event)
 {
     m_multi = event.IsChecked();
-    RecreateBooks();
+    RecreateBook();
     m_sizerFrame->Layout();
     wxLogMessage(_T("Multiline setting works only in wxNotebook."));
 }
@@ -541,24 +551,84 @@ void MyFrame::OnExit(wxCommandEvent& WXUNUSED(event))
     Close();
 }
 
-void MyFrame::OnAddPage(wxCommandEvent& WXUNUSED(event))
+wxPanel *MyFrame::CreateNewPage() const
 {
-    static unsigned s_pageAdded = 0;
+    wxPanel *panel = new wxPanel(m_bookCtrl, wxID_ANY );
+    (void) new wxButton(panel, wxID_ANY, wxT("First button"), wxPoint(10, 10));
+    (void) new wxButton(panel, wxID_ANY, wxT("Second button"), wxPoint(50, 100));
+
+    return panel;
+}
 
+void MyFrame::OnAddPage(wxCommandEvent& WXUNUSED(event))
+{
     wxBookCtrlBase *currBook = GetCurrentBook();
 
     if ( currBook )
     {
-        wxPanel *panel = new wxPanel( currBook, wxID_ANY );
-        (void) new wxButton( panel, wxID_ANY, wxT("First button"),
-            wxPoint(10, 10), wxDefaultSize );
-        (void) new wxButton( panel, wxID_ANY, wxT("Second button"),
-            wxPoint(50, 100), wxDefaultSize );
-
-        currBook->AddPage(panel, wxString::Format(ADDED_PAGE_NAME wxT("%u"),
-            ++s_pageAdded), true, GetIconIndex(currBook) );
+        static unsigned s_pageAdded = 0;
+        currBook->AddPage(CreateNewPage(),
+                          wxString::Format
+                          (
+                            ADDED_PAGE_NAME wxT("%u"),
+                            ++s_pageAdded
+                          ),
+                          true,
+                          GetIconIndex(currBook));
+    }
+}
+
+#if wxUSE_TREEBOOK
+void MyFrame::OnAddSubPage(wxCommandEvent& WXUNUSED(event))
+{
+    wxTreebook *currBook = wxDynamicCast(GetCurrentBook(), wxTreebook);
+    if ( currBook )
+    {
+        const int selPos = currBook->GetSelection();
+        if ( selPos == wxNOT_FOUND )
+        {
+            wxLogError(_T("Select the parent page first!"));
+            return;
+        }
+
+        static unsigned s_subPageAdded = 0;
+        currBook->AddSubPage(selPos,
+                             CreateNewPage(),
+                             wxString::Format
+                             (
+                                ADDED_SUB_PAGE_NAME wxT("%u"),
+                                ++s_subPageAdded
+                             ),
+                             true,
+                             GetIconIndex(currBook));
+    }
+}
+
+void MyFrame::OnAddPageBefore(wxCommandEvent& WXUNUSED(event))
+{
+    wxBookCtrlBase *currBook = GetCurrentBook();
+    if ( currBook )
+    {
+        const int selPos = currBook->GetSelection();
+        if ( selPos == wxNOT_FOUND )
+        {
+            wxLogError(_T("Select the parent page first!"));
+            return;
+        }
+
+        static unsigned s_subPageAdded = 0;
+        currBook->InsertPage(selPos,
+                             CreateNewPage(),
+                             wxString::Format
+                             (
+                                ADDED_PAGE_NAME_BEFORE wxT("%u"),
+                                ++s_subPageAdded
+                             ),
+                             true,
+                             GetIconIndex(currBook));
     }
 }
+#endif // wxUSE_TREEBOOK
 
 void MyFrame::OnInsertPage(wxCommandEvent& WXUNUSED(event))
 {
@@ -648,65 +718,103 @@ void MyFrame::OnIdle( wxIdleEvent& WXUNUSED(event) )
     }
 }
 
-#if USE_LOG
-    #define BOOKEVENT_LOG m_text->SetInsertionPointEnd();
-#else
-    #define BOOKEVENT_LOG
-#endif
-
-#define BOOKEVENT(OnBook,wxBookEvent,bookStr,wxEVT_PAGE_CHANGED,wxEVT_PAGE_CHANGING,s_num) \
-void MyFrame::OnBook(wxBookEvent& event)                                                   \
-{                                                                                          \
-    wxString str = wxT("Unknown ");                                                        \
-    str << wxT(bookStr);                                                                   \
-    str << wxT(" event");                                                                  \
-                                                                                           \
-    wxEventType eventType = event.GetEventType();                                          \
-                                                                                           \
-    if (eventType == wxEVT_PAGE_CHANGED)                                                   \
-    {                                                                                      \
-        str = wxT("Changed");                                                              \
-    }                                                                                      \
-    else if (eventType == wxEVT_PAGE_CHANGING)                                             \
-    {                                                                                      \
-        int idx = event.GetOldSelection();                                                 \
-        wxBookCtrlBase *book = (wxBookCtrlBase *)event.GetEventObject();                   \
-        if ( idx != wxNOT_FOUND && book && book->GetPageText(idx) == VETO_PAGE_NAME )      \
-        {                                                                                  \
-            if                                                                             \
-            (                                                                              \
-                wxMessageBox(                                                              \
-                wxT("Are you sure you want to leave this page?\n")                         \
-                wxT("(This demonstrates veto-ing)"),                                       \
-                          wxT("Notebook sample"),                                          \
-                          wxICON_QUESTION | wxYES_NO, this) != wxYES )                     \
-            {                                                                              \
-                event.Veto();                                                              \
-            }                                                                              \
-                                                                                           \
-        }                                                                                  \
-                                                                                           \
-        str = wxT("Changing");                                                             \
-    }                                                                                      \
-                                                                                           \
-    static int s_num = 0;                                                                  \
-                                                                                           \
-    wxString logMsg;                                                                       \
-    logMsg.Printf(wxT("%s event #%d: %s (%d) Sel %d, OldSel %d"),                          \
-                  wxT(bookStr),s_num++, str.c_str(), eventType,                            \
-                  event.GetSelection(), event.GetOldSelection());                          \
-                                                                                           \
-    wxLogMessage(logMsg.c_str());                                                          \
-                                                                                           \
-    BOOKEVENT_LOG                                                                          \
-}
-
+void MyFrame::OnBookCtrl(wxBookCtrlBaseEvent& event)
+{
+    static const struct EventInfo
+    {
+        wxEventType typeChanged,
+                    typeChanging;
+        const wxChar *name;
+    } events[] =
+    {
 #if wxUSE_NOTEBOOK
-BOOKEVENT(OnNotebook,wxNotebookEvent,"wxNotebook",wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED,wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING,s_numNotebookEvents)
-#endif
+        {
+            wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED,
+            wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING,
+            _T("wxNotebook")
+        },
+#endif // wxUSE_NOTEBOOK
 #if wxUSE_CHOICEBOOK
-BOOKEVENT(OnChoicebook,wxChoicebookEvent,"wxChoicebook",wxEVT_COMMAND_CHOICEBOOK_PAGE_CHANGED,wxEVT_COMMAND_CHOICEBOOK_PAGE_CHANGING,s_numChoicebookEvents)
-#endif
+        {
+            wxEVT_COMMAND_CHOICEBOOK_PAGE_CHANGED,
+            wxEVT_COMMAND_CHOICEBOOK_PAGE_CHANGING,
+            _T("wxChoicebook")
+        },
+#endif // wxUSE_CHOICEBOOK
 #if wxUSE_LISTBOOK
-BOOKEVENT(OnListbook,wxListbookEvent,"wxListbook",wxEVT_COMMAND_LISTBOOK_PAGE_CHANGED,wxEVT_COMMAND_LISTBOOK_PAGE_CHANGING,s_numListbookEvents)
+        {
+            wxEVT_COMMAND_LISTBOOK_PAGE_CHANGED,
+            wxEVT_COMMAND_LISTBOOK_PAGE_CHANGING,
+            _T("wxListbook")
+        },
+#endif // wxUSE_LISTBOOK
+#if wxUSE_TREEBOOK
+        {
+            wxEVT_COMMAND_TREEBOOK_PAGE_CHANGED,
+            wxEVT_COMMAND_TREEBOOK_PAGE_CHANGING,
+            _T("wxTreebook")
+        },
+#endif // wxUSE_TREEBOOK
+    };
+
+
+    wxString nameEvent,
+             nameControl,
+             veto;
+    const wxEventType eventType = event.GetEventType();
+    for ( size_t n = 0; n < WXSIZEOF(events); n++ )
+    {
+        const EventInfo& ei = events[n];
+        if ( eventType == ei.typeChanged )
+        {
+            nameEvent = wxT("Changed");
+        }
+        else if ( eventType == ei.typeChanging )
+        {
+            const int idx = event.GetOldSelection();
+            const wxBookCtrlBase * const
+                book = wxStaticCast(event.GetEventObject(), wxBookCtrlBase);
+            if ( idx != wxNOT_FOUND &&
+                    book && book->GetPageText(idx) == VETO_PAGE_NAME )
+            {
+                if ( wxMessageBox
+                     (
+                      wxT("Are you sure you want to leave this page?\n")
+                      wxT("(This demonstrates veto-ing)"),
+                      wxT("Notebook sample"),
+                      wxICON_QUESTION | wxYES_NO,
+                      this
+                     ) != wxYES )
+                {
+                    event.Veto();
+                    veto = _T(" (vetoed)");
+                }
+            }
+
+            nameEvent = wxT("Changing");
+        }
+        else // skip end of the loop
+        {
+            continue;
+        }
+
+        nameControl = ei.name;
+        break;
+    }
+
+    static int s_num = 0;
+
+    wxLogMessage(wxT("Event #%d: %s: %s (%d) new sel %d, old %d%s"),
+                 ++s_num,
+                 nameControl.c_str(),
+                 nameEvent.c_str(),
+                 eventType,
+                 event.GetSelection(),
+                 event.GetOldSelection(),
+                 veto.c_str());
+
+#if USE_LOG
+    m_text->SetInsertionPointEnd();
 #endif
+}
+
diff --git a/samples/notebook/notebook.h b/samples/notebook/notebook.h
index 1eac27735d..42bd6088af 100644
--- a/samples/notebook/notebook.h
+++ b/samples/notebook/notebook.h
@@ -11,6 +11,7 @@
 
 #include "wx/choicebk.h"
 #include "wx/listbook.h"
+#include "wx/treebook.h"
 #include "wx/notebook.h"
 
 #if wxUSE_LOG && !defined( __SMARTPHONE__ )
@@ -28,12 +29,11 @@ public:
 
 DECLARE_APP(MyApp)
 
+
 class MyFrame : public wxFrame
 {
 public:
-    MyFrame(const wxString& title, const wxPoint& pos = wxDefaultPosition,
-        const wxSize& size = wxDefaultSize, long style = wxDEFAULT_FRAME_STYLE|wxCLIP_CHILDREN|wxNO_FULL_REPAINT_ON_RESIZE);
-
+    MyFrame();
     virtual ~MyFrame();
 
     void OnType(wxCommandEvent& event);
@@ -48,29 +48,47 @@ public:
     void OnDeleteLastPage(wxCommandEvent& event);
     void OnNextPage(wxCommandEvent& event);
 
+    void OnAddSubPage(wxCommandEvent& event);
+    void OnAddPageBefore(wxCommandEvent& event);
+
+    void OnBookCtrl(wxBookCtrlBaseEvent& event);
 #if wxUSE_NOTEBOOK
-    void OnNotebook(wxNotebookEvent& event);
+    void OnNotebook(wxNotebookEvent& event) { OnBookCtrl(event); }
 #endif
 #if wxUSE_CHOICEBOOK
-    void OnChoicebook(wxChoicebookEvent& event);
+    void OnChoicebook(wxChoicebookEvent& event) { OnBookCtrl(event); }
 #endif
 #if wxUSE_LISTBOOK
-    void OnListbook(wxListbookEvent& event);
+    void OnListbook(wxListbookEvent& event) { OnBookCtrl(event); }
+#endif
+#if wxUSE_TREEBOOK
+    void OnTreebook(wxTreebookEvent& event) { OnBookCtrl(event); }
 #endif
 
     void OnIdle(wxIdleEvent& event);
 
-    wxBookCtrlBase *GetCurrentBook();
+#if wxUSE_TREEBOOK
+    void OnUpdateTreeMenu(wxUpdateUIEvent& event);
+#endif // wxUSE_TREEBOOK
+
+    wxBookCtrlBase *GetCurrentBook() const { return m_bookCtrl; }
 
 private:
     wxLog *m_logTargetOld;
 
-    int SelectFlag(int id, int nb, int lb, int chb);
-    void ShowCurrentBook();
-    void RecreateBooks();
+    void RecreateBook();
+    wxPanel *CreateNewPage() const;
+    int TranslateBookFlag(int nb, int lb, int chb, int tbk) const;
 
     // Sample setup
-    int m_type;
+    enum BookType
+    {
+        Type_Notebook,
+        Type_Choicebook,
+        Type_Listbook,
+        Type_Treebook,
+        Type_Max
+    } m_type;
     int m_orient;
     bool m_chkShowImages;
     bool m_multi;
@@ -78,16 +96,7 @@ private:
     // Controls
 
     wxPanel *m_panel; // Panel containing notebook and other controls
-
-#if wxUSE_NOTEBOOK
-    wxNotebook   *m_notebook;
-#endif
-#if wxUSE_CHOICEBOOK
-    wxChoicebook *m_choicebook;
-#endif
-#if wxUSE_LISTBOOK
-    wxListbook   *m_listbook;
-#endif
+    wxBookCtrlBase *m_bookCtrl;
 
 #if USE_LOG
     // Log window
@@ -103,10 +112,13 @@ private:
 
 enum ID_COMMANDS
 {
+    // these should be in the same order as Type_XXX elements above
     ID_BOOK_NOTEBOOK = wxID_HIGHEST,
     ID_BOOK_LISTBOOK,
     ID_BOOK_CHOICEBOOK,
+    ID_BOOK_TREEBOOK,
     ID_BOOK_MAX,
+
     ID_ORIENT_DEFAULT,
     ID_ORIENT_TOP,
     ID_ORIENT_BOTTOM,
@@ -120,9 +132,8 @@ enum ID_COMMANDS
     ID_DELETE_CUR_PAGE,
     ID_DELETE_LAST_PAGE,
     ID_NEXT_PAGE,
-    ID_NOTEBOOK,
-    ID_LISTBOOK,
-    ID_CHOICEBOOK
+    ID_ADD_PAGE_BEFORE,
+    ID_ADD_SUB_PAGE
 };
 
 /*
@@ -139,3 +150,7 @@ to decide what type of page it is.
 // Pages that can be added by the user
 #define INSERTED_PAGE_NAME wxT("Inserted ")
 #define ADDED_PAGE_NAME wxT("Added ")
+#define ADDED_PAGE_NAME_BEFORE wxT(" Inserted before ")
+#define ADDED_SUB_PAGE_NAME wxT(" Inserted sub-page ")
+
+
diff --git a/samples/xrc/rc/controls.xrc b/samples/xrc/rc/controls.xrc
index 8826f43fde..9c71c14d5f 100644
--- a/samples/xrc/rc/controls.xrc
+++ b/samples/xrc/rc/controls.xrc
@@ -19,6 +19,43 @@
             <object class="wxNotebook" name="controls_notebook">
                 <usenotebooksizer>1</usenotebooksizer>
                 <size>550,200</size>
+                <object class="notebookpage">
+                    <label>wxTreebook</label>
+                                <object class="wxTreebook" name="controls_treebook">
+                                    <size>350,280</size>
+                                    <style>wxSUNKEN_BORDER</style>
+                                    <object class="treebookpage">
+                                        <label>Page 1</label>
+                                        <depth>0</depth>
+                                        <object class="wxButton" name="controls_treebook_button1">
+                                            <size>200,180</size>
+                                            <label>Button N1</label>
+                                        </object>
+                                    </object>
+                                    <object class="treebookpage">
+                                        <label>Empty Page 2</label>
+                                        <depth>1</depth>
+                                    </object>
+                                    <object class="treebookpage">
+                                        <label>Page 3</label>
+                                        <depth>2</depth>
+                                        <object class="wxButton" name="controls_treebook_button3">
+                                            <size>200,180</size>
+                                            <label>Button N3</label>
+                                        </object>
+                                    </object>
+                                    <object class="treebookpage">
+                                        <label>Page 4</label>
+                                        <depth>1</depth>
+                                        <object class="wxButton" name="controls_treebook_button4">
+                                            <size>200,180</size>
+                                            <label>Button N4</label>
+                                        </object>
+                                    </object>
+                                </object>
+                </object>
+
+                
                 <object class="notebookpage">
                     <label>wxBitmapButton</label>
                     <object class="wxPanel" name="bitmapbutton">
diff --git a/setup.h.in b/setup.h.in
index 089f1c568e..1b8e5a8d0a 100644
--- a/setup.h.in
+++ b/setup.h.in
@@ -329,6 +329,8 @@
 
 #define wxUSE_CHOICEBOOK 0
 
+#define wxUSE_TREEBOOK 0
+
 #define wxUSE_TAB_DIALOG    0
 
 #define wxUSE_GRID         0
diff --git a/setup.h_vms b/setup.h_vms
index 6eb38eeeaa..760f35b260 100644
--- a/setup.h_vms
+++ b/setup.h_vms
@@ -344,6 +344,8 @@
 
 #define wxUSE_CHOICEBOOK 1
 
+#define wxUSE_TREEBOOK 1
+
 #define wxUSE_TAB_DIALOG    1
 
 #define wxUSE_GRID         1
diff --git a/src/common/bookctrl.cpp b/src/common/bookctrl.cpp
index 2a995a9e51..eccc863d6a 100644
--- a/src/common/bookctrl.cpp
+++ b/src/common/bookctrl.cpp
@@ -114,14 +114,17 @@ wxSize wxBookCtrlBase::DoGetBestSize() const
     const size_t nCount = m_pages.size();
     for ( size_t nPage = 0; nPage < nCount; nPage++ )
     {
-        wxWindow *pPage = m_pages[nPage];
-        wxSize childBestSize(pPage->GetBestSize());
+        const wxWindow * const pPage = m_pages[nPage];
+        if( pPage )
+        {
+            wxSize childBestSize(pPage->GetBestSize());
 
-        if ( childBestSize.x > bestSize.x )
-            bestSize.x = childBestSize.x;
+            if ( childBestSize.x > bestSize.x )
+                bestSize.x = childBestSize.x;
 
-        if ( childBestSize.y > bestSize.y )
-            bestSize.y = childBestSize.y;
+            if ( childBestSize.y > bestSize.y )
+                bestSize.y = childBestSize.y;
+        }
     }
 
     // convert display area to window area, adding the size necessary for the
@@ -142,7 +145,7 @@ wxBookCtrlBase::InsertPage(size_t nPage,
                            bool WXUNUSED(bSelect),
                            int WXUNUSED(imageId))
 {
-    wxCHECK_MSG( page, false, _T("NULL page in wxBookCtrlBase::InsertPage()") );
+    wxCHECK_MSG( page || AllowNullPage(), false, _T("NULL page in wxBookCtrlBase::InsertPage()") );
     wxCHECK_MSG( nPage <= m_pages.size(), false,
                  _T("invalid page index in wxBookCtrlBase::InsertPage()") );
 
@@ -155,9 +158,10 @@ wxBookCtrlBase::InsertPage(size_t nPage,
 bool wxBookCtrlBase::DeletePage(size_t nPage)
 {
     wxWindow *page = DoRemovePage(nPage);
-    if ( !page )
+    if ( !(page || AllowNullPage()) )
         return false;
 
+    // delete NULL is harmless
     delete page;
 
     return true;
diff --git a/src/generic/treebkg.cpp b/src/generic/treebkg.cpp
new file mode 100644
index 0000000000..3b085c01b5
--- /dev/null
+++ b/src/generic/treebkg.cpp
@@ -0,0 +1,807 @@
+///////////////////////////////////////////////////////////////////////////////
+// Name:        src/generic/treebkg.cpp
+// Purpose:     generic implementation of wxTreebook
+// Author:      Evgeniy Tarassov, Vadim Zeitlin
+// Modified by:
+// Created:     2005-09-15
+// RCS-ID:      $Id$
+// Copyright:   (c) 2005 Vadim Zeitlin <vadim@wxwidgets.org>
+// Licence:     wxWindows licence
+///////////////////////////////////////////////////////////////////////////////
+
+// ============================================================================
+// declarations
+// ============================================================================
+
+// ----------------------------------------------------------------------------
+// headers
+// ----------------------------------------------------------------------------
+
+// For compilers that support precompilation, includes "wx.h".
+#include "wx/wxprec.h"
+
+#ifdef __BORLANDC__
+    #pragma hdrstop
+#endif
+
+#if wxUSE_TREEBOOK
+
+#include "wx/treebook.h"
+#include "wx/imaglist.h"
+#include "wx/settings.h"
+
+// ----------------------------------------------------------------------------
+// various wxWidgets macros
+// ----------------------------------------------------------------------------
+
+// check that the page index is valid
+#define IS_VALID_PAGE(nPage) ((nPage) < DoInternalGetPageCount())
+
+// ----------------------------------------------------------------------------
+// event table
+// ----------------------------------------------------------------------------
+
+IMPLEMENT_DYNAMIC_CLASS(wxTreebook, wxControl)
+IMPLEMENT_DYNAMIC_CLASS(wxTreebookEvent, wxNotifyEvent)
+
+const wxEventType wxEVT_COMMAND_TREEBOOK_PAGE_CHANGING = wxNewEventType();
+const wxEventType wxEVT_COMMAND_TREEBOOK_PAGE_CHANGED = wxNewEventType();
+const wxEventType wxEVT_COMMAND_TREEBOOK_NODE_COLLAPSED = wxNewEventType();
+const wxEventType wxEVT_COMMAND_TREEBOOK_NODE_EXPANDED = wxNewEventType();
+const int wxID_TREEBOOKTREEVIEW = wxNewId();
+
+BEGIN_EVENT_TABLE(wxTreebook, wxBookCtrlBase)
+    EVT_SIZE(wxTreebook::OnSize)
+    EVT_TREE_SEL_CHANGED   (wxID_TREEBOOKTREEVIEW, wxTreebook::OnTreeSelectionChange)
+    EVT_TREE_ITEM_EXPANDED (wxID_TREEBOOKTREEVIEW, wxTreebook::OnTreeNodeExpandedCollapsed)
+    EVT_TREE_ITEM_COLLAPSED(wxID_TREEBOOKTREEVIEW, wxTreebook::OnTreeNodeExpandedCollapsed)
+END_EVENT_TABLE()
+
+// ============================================================================
+// wxTreebook implementation
+// ============================================================================
+
+// ----------------------------------------------------------------------------
+// wxTreebook creation
+// ----------------------------------------------------------------------------
+
+void wxTreebook::Init()
+{
+    m_tree = NULL;
+    m_selection =
+    m_actualSelection = wxNOT_FOUND;
+}
+
+bool
+wxTreebook::Create(wxWindow *parent,
+                   wxWindowID id,
+                   const wxPoint& pos,
+                   const wxSize& size,
+                   long style,
+                   const wxString& name)
+{
+    // Check the style flag to have either wxTBK_RIGHT or wxTBK_LEFT
+    if ( style & wxTBK_RIGHT )
+    {
+        wxASSERT_MSG( !(style & wxTBK_LEFT),
+                            _T("RIGHT and LEFT can't be used together") );
+    }
+    else
+    {
+        style |= wxTBK_LEFT;
+    }
+
+    // no border for this control, it doesn't look nice together with the tree
+    style &= ~wxBORDER_MASK;
+    style |= wxBORDER_NONE;
+
+    if ( !wxControl::Create(parent, id, pos, size,
+                            style, wxDefaultValidator, name) )
+        return false;
+
+    m_tree = new wxTreeCtrl
+                 (
+                    this,
+                    wxID_TREEBOOKTREEVIEW,
+                    wxDefaultPosition,
+                    wxDefaultSize,
+                    wxBORDER_SIMPLE |
+                    wxTR_HAS_BUTTONS |
+                    wxTR_HIDE_ROOT |
+                    wxTR_LINES_AT_ROOT |
+                    wxTR_SINGLE
+                 );
+    m_tree->AddRoot(wxEmptyString); // label doesn't matter, it's hidden
+
+#ifdef __WXMSW__
+    // see listbook.h for origins of that
+    // On XP with themes enabled the GetViewRect used in GetListSize to
+    // determine the space needed for the list view will incorrectly return
+    // (0,0,0,0) the first time.  So send a pending event so OnSize will be
+    // called again after the window is ready to go.  Technically we don't
+    // need to do this on non-XP windows, but if things are already sized
+    // correctly then nothing changes and so there is no harm.
+    wxSizeEvent evt;
+    GetEventHandler()->AddPendingEvent(evt);
+#endif
+
+    return true;
+}
+
+
+// insert a new page just before the pagePos
+bool wxTreebook::InsertPage(size_t pagePos,
+                            wxWindow *page,
+                            const wxString& text,
+                            bool bSelect,
+                            int imageId)
+{
+    return DoInsertPage(pagePos, page, text, bSelect, imageId);
+}
+
+bool wxTreebook::AddSubPage(size_t pagePos,
+                            wxWindow *page,
+                            const wxString& text,
+                            bool bSelect,
+                            int imageId)
+{
+    return DoInsertSubPage(pagePos, page, text, bSelect, imageId);
+}
+
+bool wxTreebook::AddPage(wxWindow *page, const wxString& text, bool bSelect,
+                         int imageId)
+{
+    return DoInsertPage(m_treeIds.GetCount(), page, text, bSelect, imageId);
+}
+
+// insertion time is linear to the number of top-pages
+bool wxTreebook::AddSubPage(wxWindow *page, const wxString& text, bool bSelect, int imageId)
+{
+    return DoAddSubPage(page, text, bSelect, imageId);
+}
+
+
+bool wxTreebook::DoInsertPage(size_t pagePos,
+                              wxWindow *page,
+                              const wxString& text,
+                              bool bSelect,
+                              int imageId)
+{
+    wxCHECK_MSG( pagePos <= DoInternalGetPageCount(), false,
+                        wxT("Invalid treebook page position") );
+
+    if ( !wxBookCtrlBase::InsertPage(pagePos, page, text, bSelect, imageId) )
+        return false;
+
+    wxTreeItemId newId;
+    if ( pagePos == DoInternalGetPageCount() )
+    {
+        // append the page to the end
+        wxTreeItemId rootId = m_tree->GetRootItem();
+
+        newId = m_tree->AppendItem(rootId, text, imageId);
+    }
+    else // insert the new page before the given one
+    {
+        wxTreeItemId nodeId = m_treeIds[pagePos];
+
+        wxTreeItemId previousId = m_tree->GetPrevSibling(nodeId);
+        wxTreeItemId parentId = m_tree->GetItemParent(nodeId);
+
+        if ( previousId.IsOk() )
+        {
+            // insert before the sibling - previousId
+            newId = m_tree->InsertItem(parentId, previousId, text, imageId);
+        }
+        else // no prev siblings -- insert as a first child
+        {
+            wxASSERT_MSG( parentId.IsOk(), wxT( "Tree has no root node?" ) );
+
+            newId = m_tree->PrependItem(parentId, text, imageId);
+        }
+    }
+
+    if ( !newId.IsOk() )
+    {
+        //something wrong -> cleaning and returning with false
+        (void)wxBookCtrlBase::DoRemovePage(pagePos);
+
+        wxFAIL_MSG( wxT("Failed to insert treebook page") );
+        return false;
+    }
+
+    DoInternalAddPage(pagePos, page, newId);
+
+    DoUpdateSelection(bSelect, pagePos);
+
+    return true;
+}
+
+bool wxTreebook::DoAddSubPage(wxWindow *page, const wxString& text, bool bSelect, int imageId)
+{
+    wxTreeItemId rootId = m_tree->GetRootItem();
+
+    wxTreeItemId lastNodeId = m_tree->GetLastChild(rootId);
+
+    wxCHECK_MSG( lastNodeId.IsOk(), false,
+                        _T("Can't insert sub page when there are no pages") );
+
+    // now calculate its position (should we save/update it too?)
+    size_t newPos = m_tree->GetCount() -
+                        (m_tree->GetChildrenCount(lastNodeId, true) + 1);
+
+    return DoInsertSubPage(newPos, page, text, bSelect, imageId);
+}
+
+bool wxTreebook::DoInsertSubPage(size_t pagePos,
+                                 wxTreebookPage *page,
+                                 const wxString& text,
+                                 bool bSelect,
+                                 int imageId)
+{
+    wxTreeItemId parentId = DoInternalGetPage(pagePos);
+    wxCHECK_MSG( parentId.IsOk(), false, wxT("invalid tree item") );
+
+    size_t newPos = pagePos + m_tree->GetChildrenCount(parentId, true) + 1;
+    wxASSERT_MSG( newPos <= DoInternalGetPageCount(),
+                    wxT("Internal error in tree insert point calculation") );
+
+    if ( !wxBookCtrlBase::InsertPage(newPos, page, text, bSelect, imageId) )
+        return false;
+
+    wxTreeItemId newId = m_tree->AppendItem(parentId, text, imageId);
+
+    if ( !newId.IsOk() )
+    {
+        (void)wxBookCtrlBase::DoRemovePage(newPos);
+
+        wxFAIL_MSG( wxT("Failed to insert treebook page") );
+        return false;
+    }
+
+    DoInternalAddPage(newPos, page, newId);
+
+    DoUpdateSelection(bSelect, newPos);
+
+    return true;
+}
+
+bool wxTreebook::DeletePage(size_t pagePos)
+{
+    wxCHECK_MSG( IS_VALID_PAGE(pagePos), false, wxT("Invalid tree index") );
+
+    wxTreebookPage *oldPage = DoRemovePage(pagePos);
+    if ( !oldPage )
+        return false;
+
+    delete oldPage;
+
+    return true;
+}
+
+wxTreebookPage *wxTreebook::DoRemovePage(size_t pagePos)
+{
+    wxTreeItemId pageId = DoInternalGetPage(pagePos);
+    wxCHECK_MSG( pageId.IsOk(), NULL, wxT("Invalid tree index") );
+
+    wxTreebookPage * oldPage = GetPage(pagePos);
+
+    size_t subCount = m_tree->GetChildrenCount(pageId, true);
+    wxASSERT_MSG ( IS_VALID_PAGE(pagePos + subCount),
+                        wxT("Internal error in wxTreebook::DoRemovePage") );
+
+    // here we are going to delete ALL the pages in the range
+    // [pagePos, pagePos + subCount] -- the page and its children
+
+    // deleting all the pages from the base class
+    for ( size_t i = 0; i <= subCount; ++i )
+    {
+        wxTreebookPage *page = wxBookCtrlBase::DoRemovePage(pagePos);
+
+        // don't delete the page itself though -- it will be deleted in
+        // DeletePage() when we return
+        if ( i )
+        {
+            delete page;
+        }
+    }
+
+    DoInternalRemovePageRange(pagePos, subCount);
+
+    m_tree->DeleteChildren( pageId );
+    m_tree->Delete( pageId );
+
+    return oldPage;
+}
+
+bool wxTreebook::DeleteAllPages()
+{
+    wxBookCtrlBase::DeleteAllPages();
+    m_treeIds.Clear();
+    m_selection =
+    m_actualSelection = wxNOT_FOUND;
+
+    m_tree->DeleteChildren(m_tree->GetRootItem());
+
+    return true;
+}
+
+void wxTreebook::DoInternalAddPage(size_t newPos,
+                                   wxTreebookPage *page,
+                                   wxTreeItemId pageId)
+{
+    wxASSERT_MSG( newPos <= m_treeIds.GetCount(), wxT("Ivalid index passed to wxTreebook::DoInternalAddPage") );
+
+    // hide newly inserted page initially (it will be shown when selected)
+    if ( page )
+        page->Hide();
+
+    if ( newPos == m_treeIds.GetCount() )
+    {
+        // append
+        m_treeIds.Add(pageId);
+    }
+    else // insert
+    {
+        m_treeIds.Insert(pageId, newPos);
+
+        if ( m_selection != wxNOT_FOUND && newPos <= (size_t)m_selection )
+        {
+            // selection has been moved one unit toward the end
+            ++m_selection;
+            if ( m_actualSelection != wxNOT_FOUND )
+                ++m_actualSelection;
+        }
+        else if ( m_actualSelection != wxNOT_FOUND &&
+                    newPos <= (size_t)m_actualSelection )
+        {
+            DoSetSelection(m_selection);
+        }
+    }
+}
+
+void wxTreebook::DoInternalRemovePageRange(size_t pagePos, size_t subCount)
+{
+    // Attention: this function is only for a situation when we delete a node
+    // with all its children so pagePos is the node's index and subCount is the
+    // node children count
+    wxASSERT_MSG( pagePos + subCount < m_treeIds.GetCount(),
+                    wxT("Ivalid page index") );
+
+    wxTreeItemId pageId = m_treeIds[pagePos];
+
+    m_treeIds.RemoveAt(pagePos, subCount + 1);
+
+    if ( m_selection != wxNOT_FOUND )
+    {
+        if ( (size_t)m_selection > pagePos + subCount)
+        {
+            // selection is far after the deleted page, so just update the index and move on
+            m_selection -= 1 + subCount;
+            if ( m_actualSelection != wxNOT_FOUND)
+            {
+                m_actualSelection -= subCount + 1;
+            }
+        }
+        else if ( (size_t)m_selection >= pagePos )
+        {
+            // as selected page is going to be deleted, try to select the next
+            // sibling if exists, if not then the parent
+            wxTreeItemId nodeId = m_tree->GetNextSibling(pageId);
+
+            m_selection = wxNOT_FOUND;
+            m_actualSelection = wxNOT_FOUND;
+
+            if ( nodeId.IsOk() )
+            {
+                // selecting next siblings
+                m_tree->SelectItem(nodeId);
+            }
+            else // no next sibling, select the parent
+            {
+                wxTreeItemId parentId = m_tree->GetItemParent(pageId);
+
+                if ( parentId.IsOk() && parentId != m_tree->GetRootItem() )
+                {
+                    m_tree->SelectItem(parentId);
+                }
+                else // parent is root
+                {
+                    // we can't select it as it's hidden
+                    DoUpdateSelection(false, wxNOT_FOUND);
+                }
+            }
+        }
+        else if ( m_actualSelection != wxNOT_FOUND &&
+                    (size_t)m_actualSelection >= pagePos )
+        {
+            // nothing to do -- selection is before the deleted node, but
+            // actually shown page (the first (sub)child with page != NULL) is
+            // already deleted
+            m_actualSelection = m_selection;
+            DoSetSelection(m_selection);
+        }
+        //else: nothing to do -- selection is before the deleted node
+    }
+    else
+    {
+        DoUpdateSelection(false, wxNOT_FOUND);
+    }
+}
+
+
+void wxTreebook::DoUpdateSelection(bool bSelect, int newPos)
+{
+    int newSelPos;
+    if ( bSelect )
+    {
+        newSelPos = newPos;
+    }
+    else if ( m_selection == wxNOT_FOUND && DoInternalGetPageCount() > 0 )
+    {
+        newSelPos = 0;
+    }
+    else
+    {
+        newSelPos = wxNOT_FOUND;
+    }
+
+    if ( newSelPos != wxNOT_FOUND )
+    {
+        SetSelection((size_t)newSelPos);
+    }
+}
+
+wxTreeItemId wxTreebook::DoInternalGetPage(size_t pagePos) const
+{
+    if ( pagePos >= m_treeIds.GetCount() )
+    {
+        // invalid position but ok here, in this internal function, don't assert
+        // (the caller will do it)
+        return wxTreeItemId();
+    }
+
+    return m_treeIds[pagePos];
+}
+
+int wxTreebook::DoInternalFindPageById(wxTreeItemId pageId) const
+{
+    const size_t count = m_treeIds.GetCount();
+    for ( size_t i = 0; i < count; ++i )
+    {
+        if ( m_treeIds[i] == pageId )
+            return i;
+    }
+
+    return wxNOT_FOUND;
+}
+
+bool wxTreebook::IsNodeExpanded(size_t pagePos) const
+{
+    wxTreeItemId pageId = DoInternalGetPage(pagePos);
+
+    wxCHECK_MSG( pageId.IsOk(), false, wxT("invalid tree item") );
+
+    return m_tree->IsExpanded(pageId);
+}
+
+bool wxTreebook::ExpandNode(size_t pagePos, bool expand)
+{
+    wxTreeItemId pageId = DoInternalGetPage(pagePos);
+
+    wxCHECK_MSG( pageId.IsOk(), false, wxT("invalid tree item") );
+
+    if ( expand )
+    {
+        m_tree->Expand( pageId );
+    }
+    else // collapse
+    {
+        m_tree->Collapse( pageId );
+
+        // rely on the events generated by wxTreeCtrl to update selection
+    }
+
+    return true;
+}
+
+int wxTreebook::GetPageParent(size_t pagePos) const
+{
+    wxTreeItemId nodeId = DoInternalGetPage( pagePos );
+    wxCHECK_MSG( nodeId.IsOk(), wxNOT_FOUND, wxT("Invalid page index spacified!") );
+
+    const wxTreeItemId parent = m_tree->GetItemParent( nodeId );
+
+    return parent.IsOk() ? DoInternalFindPageById(parent) : wxNOT_FOUND;
+}
+
+bool wxTreebook::SetPageText(size_t n, const wxString& strText)
+{
+    wxTreeItemId pageId = DoInternalGetPage(n);
+
+    wxCHECK_MSG( pageId.IsOk(), false, wxT("invalid tree item") );
+
+    m_tree->SetItemText(pageId, strText);
+
+    return true;
+}
+
+wxString wxTreebook::GetPageText(size_t n) const
+{
+    wxTreeItemId pageId = DoInternalGetPage(n);
+
+    wxCHECK_MSG( pageId.IsOk(), wxString(), wxT("invalid tree item") );
+
+    return m_tree->GetItemText(pageId);
+}
+
+int wxTreebook::GetPageImage(size_t n) const
+{
+    wxTreeItemId pageId = DoInternalGetPage(n);
+
+    wxCHECK_MSG( pageId.IsOk(), wxNOT_FOUND, wxT("invalid tree item") );
+
+    return m_tree->GetItemImage(pageId);
+}
+
+bool wxTreebook::SetPageImage(size_t n, int imageId)
+{
+    wxTreeItemId pageId = DoInternalGetPage(n);
+
+    wxCHECK_MSG( pageId.IsOk(), false, wxT("invalid tree item") );
+
+    m_tree->SetItemImage(pageId, imageId);
+
+    return true;
+}
+
+wxSize wxTreebook::CalcSizeFromPage(const wxSize& sizePage) const
+{
+    const wxSize sizeTree = GetTreeSize();
+
+    wxSize size = sizePage;
+    size.x += sizeTree.x;
+
+    return size;
+}
+
+int wxTreebook::GetSelection() const
+{
+   return m_selection;
+}
+
+int wxTreebook::SetSelection(size_t pagePos)
+{
+   if ( (size_t)m_selection != pagePos )
+       return DoSetSelection(pagePos);
+
+   return m_selection;
+}
+
+int wxTreebook::DoSetSelection(size_t pagePos)
+{
+    wxCHECK_MSG( IS_VALID_PAGE(pagePos), wxNOT_FOUND,
+                 wxT("invalid page index in wxListbook::SetSelection()") );
+    wxASSERT_MSG( GetPageCount() == DoInternalGetPageCount(),
+                  wxT("wxTreebook logic error: m_treeIds and m_pages not in sync!"));
+
+    const int oldSel = m_selection;
+
+    wxTreebookEvent event(wxEVT_COMMAND_TREEBOOK_PAGE_CHANGING, m_windowId);
+    event.SetEventObject(this);
+    event.SetSelection(pagePos);
+    event.SetOldSelection(m_selection);
+
+    // don't send the event if the old and new pages are the same; do send it
+    // otherwise and be prepared for it to be vetoed
+    if ( (int)pagePos == m_selection ||
+            !GetEventHandler()->ProcessEvent(event) ||
+                event.IsAllowed() )
+    {
+        // hide the previously shown page
+        wxTreebookPage * const oldPage = DoGetCurrentPage();
+        if ( oldPage )
+            oldPage->Hide();
+
+        // then show the new one
+        m_selection = pagePos;
+        wxTreebookPage *page = wxBookCtrlBase::GetPage(m_selection);
+        if ( !page )
+        {
+            // find the next page suitable to be shown: the first (grand)child
+            // of this one with a non-NULL associated page
+            wxTreeItemId childId = m_treeIds[pagePos];
+            m_actualSelection = pagePos;
+            while ( !page && childId.IsOk() )
+            {
+                wxTreeItemIdValue cookie;
+                childId = m_tree->GetFirstChild( childId, cookie );
+                if ( childId.IsOk() )
+                {
+                    page = wxBookCtrlBase::GetPage(++m_actualSelection);
+                }
+            }
+
+            wxASSERT_MSG( page, wxT("no page to show found!") );
+        }
+
+        if ( page )
+        {
+            page->SetSize(GetPageRect());
+            page->Show();
+        }
+
+        m_tree->SelectItem(DoInternalGetPage(pagePos));
+
+        // notify about the (now completed) page change
+        event.SetEventType(wxEVT_COMMAND_TREEBOOK_PAGE_CHANGED);
+        (void)GetEventHandler()->ProcessEvent(event);
+    }
+    else // page change vetoed
+    {
+        // tree selection might have already had changed
+        m_tree->SelectItem(DoInternalGetPage(oldSel));
+    }
+
+    return oldSel;
+}
+
+void wxTreebook::SetImageList(wxImageList *imageList)
+{
+    wxBookCtrlBase::SetImageList(imageList);
+    m_tree->SetImageList(imageList);
+}
+
+void wxTreebook::AssignImageList(wxImageList *imageList)
+{
+    wxBookCtrlBase::AssignImageList(imageList);
+    m_tree->SetImageList(imageList);
+}
+
+// ----------------------------------------------------------------------------
+// event handlers
+// ----------------------------------------------------------------------------
+
+void wxTreebook::OnTreeSelectionChange(wxTreeEvent& event)
+{
+    wxTreeItemId newId = event.GetItem();
+
+    if ( (m_selection == wxNOT_FOUND &&
+                (!newId.IsOk() || newId == m_tree->GetRootItem())) ||
+            (m_selection != wxNOT_FOUND && newId == m_treeIds[m_selection]) )
+    {
+        // this event can only come when we modify the tree selection ourselves
+        // so we should simply ignore it
+        return;
+    }
+
+    int newPos = DoInternalFindPageById(newId);
+
+    if ( newPos != wxNOT_FOUND )
+        SetSelection( newPos );
+}
+
+void wxTreebook::OnTreeNodeExpandedCollapsed(wxTreeEvent & event)
+{
+    wxTreeItemId nodeId = event.GetItem();
+    if ( !nodeId.IsOk() || nodeId == m_tree->GetRootItem() )
+        return;
+    int pagePos = DoInternalFindPageById(nodeId);
+    wxCHECK_RET( pagePos != wxNOT_FOUND, wxT("Internal problem in wxTreebook!..") );
+
+    wxTreebookEvent ev(m_tree->IsExpanded(nodeId)
+            ? wxEVT_COMMAND_TREEBOOK_NODE_EXPANDED
+            : wxEVT_COMMAND_TREEBOOK_NODE_COLLAPSED,
+        m_windowId);
+
+    ev.SetSelection(pagePos);
+    ev.SetOldSelection(pagePos);
+    ev.SetEventObject(this);
+
+    GetEventHandler()->ProcessEvent(ev);
+}
+
+// ----------------------------------------------------------------------------
+// wxTreebook geometry management
+// ----------------------------------------------------------------------------
+
+wxSize wxTreebook::GetTreeSize() const
+{
+    const wxSize sizeClient = GetClientSize(),
+                 sizeBorder = m_tree->GetSize() - m_tree->GetClientSize(),
+                 sizeTree = m_tree->GetBestSize() + sizeBorder;
+
+    wxSize size;
+
+    size.x = sizeTree.x;
+    size.y = sizeClient.y;
+
+    return size;
+}
+
+wxRect wxTreebook::GetPageRect() const
+{
+    const wxSize sizeTree = m_tree->GetSize();
+
+    wxPoint pt;
+    wxRect rectPage(pt, GetClientSize());
+    switch ( GetWindowStyle() & wxTBK_ALIGN_MASK )
+    {
+        default:
+            wxFAIL_MSG( _T("unexpected wxTreebook alignment") );
+            // fall through
+
+        case wxTBK_LEFT:
+            rectPage.x = sizeTree.x; // + MARGIN;
+            // fall through
+
+        case wxTBK_RIGHT:
+            rectPage.width -= sizeTree.x; // + MARGIN;
+            break;
+    }
+
+    return rectPage;
+}
+
+void wxTreebook::OnSize(wxSizeEvent& event)
+{
+    event.Skip();
+
+    if ( !m_tree )
+    {
+        // we're not fully created yet
+        return;
+    }
+
+    // resize the list control and the page area to fit inside our new size
+    const wxSize sizeClient = GetClientSize(),
+                 sizeBorder = m_tree->GetSize() - m_tree->GetClientSize(),
+                 sizeTree = GetTreeSize();
+
+    m_tree->SetClientSize( sizeTree.x - sizeBorder.x, sizeTree.y - sizeBorder.y );
+
+    const wxSize sizeNew = m_tree->GetSize();
+    wxPoint posTree;
+    switch ( GetWindowStyle() & wxTBK_ALIGN_MASK )
+    {
+        default:
+            wxFAIL_MSG( _T("unexpected wxTreebook alignment") );
+            // fall through
+
+        case wxTBK_LEFT:
+            // posTree is already ok
+            break;
+
+        case wxTBK_RIGHT:
+            posTree.x = sizeClient.x - sizeNew.x;
+            break;
+    }
+
+    if ( m_tree->GetPosition() != posTree )
+        m_tree->Move(posTree);
+
+    // resize the currently shown page
+    wxTreebookPage *page = DoGetCurrentPage();
+    if ( page )
+    {
+        wxRect rectPage = GetPageRect();
+        page->SetSize(rectPage);
+    }
+}
+
+wxTreebookPage * wxTreebook::DoGetCurrentPage() const
+{
+    if ( m_selection == wxNOT_FOUND )
+        return NULL;
+
+    wxTreebookPage *page = wxBookCtrlBase::GetPage(m_selection);
+    if ( !page && m_actualSelection != wxNOT_FOUND )
+    {
+        page = wxBookCtrlBase::GetPage(m_actualSelection);
+    }
+
+    return page;
+}
+
+#endif // wxUSE_TREEBOOK
+
diff --git a/src/xrc/xh_treebk.cpp b/src/xrc/xh_treebk.cpp
new file mode 100644
index 0000000000..9b4513fdcc
--- /dev/null
+++ b/src/xrc/xh_treebk.cpp
@@ -0,0 +1,134 @@
+/////////////////////////////////////////////////////////////////////////////
+// Name:        xh_treebk.cpp
+// Purpose:     XRC resource handler for wxTreebook
+// Author:      Evgeniy Tarassov
+// Created:     2005/09/28
+// RCS-ID:      $Id$
+// Copyright:   (c) 2005 TT-Solutions <vadim@tt-solutions.com>
+// Licence:     wxWindows licence
+/////////////////////////////////////////////////////////////////////////////
+
+// For compilers that support precompilation, includes "wx.h".
+#include "wx/wxprec.h"
+
+#ifdef __BORLANDC__
+    #pragma hdrstop
+#endif
+
+#if wxUSE_XRC && wxUSE_TREEBOOK
+
+#include "wx/xrc/xh_treebk.h"
+
+#include "wx/treebook.h"
+#include "wx/imaglist.h"
+#include "wx/log.h"
+
+IMPLEMENT_DYNAMIC_CLASS(wxTreebookXmlHandler, wxXmlResourceHandler)
+
+wxTreebookXmlHandler::wxTreebookXmlHandler()
+: wxXmlResourceHandler(), m_isInside(false), m_tbk(NULL), m_treeContext()
+{
+    XRC_ADD_STYLE(wxTBK_DEFAULT);
+    XRC_ADD_STYLE(wxTBK_LEFT);
+    XRC_ADD_STYLE(wxTBK_RIGHT);
+
+    AddWindowStyles();
+}
+
+bool wxTreebookXmlHandler::CanHandle(wxXmlNode *node)
+{
+    return ((!m_isInside && IsOfClass(node, wxT("wxTreebook"))) ||
+            (m_isInside && IsOfClass(node, wxT("treebookpage"))));
+}
+
+
+wxObject *wxTreebookXmlHandler::DoCreateResource()
+{
+    if (m_class == wxT("wxTreebook"))
+    {
+        XRC_MAKE_INSTANCE(tbk, wxTreebook)
+
+        tbk->Create(m_parentAsWindow,
+                    GetID(),
+                    GetPosition(), GetSize(),
+                    GetStyle(wxT("style")),
+                    GetName());
+
+        wxTreebook * old_par = m_tbk;
+        m_tbk = tbk;
+
+        bool old_ins = m_isInside;
+        m_isInside = true;
+
+        wxArrayTbkPageIndexes old_treeContext = m_treeContext;
+        m_treeContext.Clear();
+
+        CreateChildren(m_tbk, true/*only this handler*/);
+
+        m_treeContext = old_treeContext;
+        m_isInside = old_ins;
+        m_tbk = old_par;
+
+        return tbk;
+    }
+
+//    else ( m_class == wxT("treebookpage") )
+    wxXmlNode *n = GetParamNode(wxT("object"));
+    wxWindow *wnd = NULL;
+
+    if ( !n )
+        n = GetParamNode(wxT("object_ref"));
+
+    if (n)
+    {
+        bool old_ins = m_isInside;
+        m_isInside = false;
+        wxObject *item = CreateResFromNode(n, m_tbk, NULL);
+        m_isInside = old_ins;
+        wnd = wxDynamicCast(item, wxWindow);
+
+        if (wnd == NULL && item != NULL)
+            wxLogError(wxT("Error in resource: control within treebook's <page> tag is not a window."));
+    }
+
+    size_t depth = GetLong( wxT("depth") );
+    
+    if( depth <= m_treeContext.Count() )
+    {
+        // first prepare the icon
+        int imgIndex = wxNOT_FOUND;
+        if ( HasParam(wxT("bitmap")) )
+        {
+            wxBitmap bmp = GetBitmap(wxT("bitmap"), wxART_OTHER);
+            wxImageList *imgList = m_tbk->GetImageList();
+            if ( imgList == NULL )
+            {
+                imgList = new wxImageList( bmp.GetWidth(), bmp.GetHeight() );
+                m_tbk->AssignImageList( imgList );
+            }
+            imgIndex = imgList->Add(bmp);
+        }
+
+        // then add the page to the corresponding parent
+        if( depth < m_treeContext.Count() )
+            m_treeContext.RemoveAt(depth, m_treeContext.Count() - depth );
+        if( depth == 0)
+        {
+            m_tbk->AddPage(wnd,
+                GetText(wxT("label")), GetBool(wxT("selected")), imgIndex);
+        }
+        else
+        {
+            m_tbk->AddSubPage(m_treeContext.Item(depth - 1), wnd,
+                GetText(wxT("label")), GetBool(wxT("selected")), imgIndex);
+        }
+        
+        m_treeContext.Add( m_tbk->GetPageCount() - 1);
+        
+    }
+    else
+        wxLogError(wxT("Error in resource. wxTreebookPage has an invalid depth."));
+    return wnd;
+}
+
+#endif // wxUSE_XRC && wxUSE_TREEBOOK
diff --git a/src/xrc/xmlrsall.cpp b/src/xrc/xmlrsall.cpp
index c4d5b04ba7..db1d0e9003 100644
--- a/src/xrc/xmlrsall.cpp
+++ b/src/xrc/xmlrsall.cpp
@@ -85,6 +85,9 @@ void wxXmlResource::InitAllHandlers()
 #endif
 #if wxUSE_CHOICEBOOK
     AddHandler(new wxChoicebookXmlHandler);
+#endif
+#if wxUSE_TREEBOOK
+    AddHandler(new wxTreebookXmlHandler);
 #endif
     AddHandler(new wxTextCtrlXmlHandler);
 #if wxUSE_LISTBOX
-- 
2.50.0

