]> git.saurik.com Git - wxWidgets.git/blobdiff - src/html/helpfrm.cpp
merged MapBitmap() from 2.2 branch
[wxWidgets.git] / src / html / helpfrm.cpp
index 9bdb9311261c7cbdc4c7c35bab2923683ebc33d7..78ca55abb0251f3c9aeb855391e015032e8d9836 100644 (file)
 #pragma hdrstop
 #endif
 
 #pragma hdrstop
 #endif
 
-#include "wx/defs.h"
+#if wxUSE_WXHTML_HELP
 
 
-#if wxUSE_HTML && wxUSE_STREAMS
 #ifndef WXPRECOMP
 #ifndef WXPRECOMP
-#include "wx/wx.h"
-#endif
+    #include "wx/intl.h"
+    #include "wx/log.h"
+
+    #include "wx/object.h"
+    #include "wx/layout.h"
+    #include "wx/sizer.h"
+
+    #include "wx/bmpbuttn.h"
+    #include "wx/statbox.h"
+    #include "wx/radiobox.h"
+#endif // WXPRECOMP
 
 #include "wx/html/helpfrm.h"
 #include "wx/html/helpctrl.h"
 
 #include "wx/html/helpfrm.h"
 #include "wx/html/helpctrl.h"
 // what is considered "small index"?
 #define INDEX_IS_SMALL 100
 
 // what is considered "small index"?
 #define INDEX_IS_SMALL 100
 
+/* Motif defines this as a macro */
+#ifdef Below
+#undef Below
+#endif
 
 //--------------------------------------------------------------------------
 // wxHtmlHelpTreeItemData (private)
 
 //--------------------------------------------------------------------------
 // wxHtmlHelpTreeItemData (private)
 class wxHtmlHelpTreeItemData : public wxTreeItemData
 {
     public:
 class wxHtmlHelpTreeItemData : public wxTreeItemData
 {
     public:
+#if defined(__VISAGECPP__)
+//  VA needs a default ctor for some reason....
+        wxHtmlHelpTreeItemData() : wxTreeItemData()
+            { m_Id = 0; }
+#endif
         wxHtmlHelpTreeItemData(int id) : wxTreeItemData()
             { m_Id = id;}
 
         wxHtmlHelpTreeItemData(int id) : wxTreeItemData()
             { m_Id = id;}
 
@@ -124,6 +141,38 @@ class wxHtmlHelpHtmlWindow : public wxHtmlWindow
 // wxHtmlHelpFrame
 //---------------------------------------------------------------------------
 
 // wxHtmlHelpFrame
 //---------------------------------------------------------------------------
 
+// Command IDs :
+enum
+{
+    //wxID_HTML_HELPFRAME = wxID_HIGHEST + 1,
+    wxID_HTML_PANEL = wxID_HIGHEST + 2,
+    wxID_HTML_BACK,
+    wxID_HTML_FORWARD,
+    wxID_HTML_UPNODE,
+    wxID_HTML_UP,
+    wxID_HTML_DOWN,
+    wxID_HTML_PRINT,
+    wxID_HTML_OPENFILE,
+    wxID_HTML_OPTIONS,
+    wxID_HTML_BOOKMARKSLIST,
+    wxID_HTML_BOOKMARKSADD,
+    wxID_HTML_BOOKMARKSREMOVE,
+    wxID_HTML_TREECTRL,
+    wxID_HTML_INDEXPAGE,
+    wxID_HTML_INDEXLIST,
+    wxID_HTML_INDEXTEXT,
+    wxID_HTML_INDEXBUTTON,
+    wxID_HTML_INDEXBUTTONALL,
+    wxID_HTML_NOTEBOOK,
+    wxID_HTML_SEARCHPAGE,
+    wxID_HTML_SEARCHTEXT,
+    wxID_HTML_SEARCHLIST,
+    wxID_HTML_SEARCHBUTTON,
+    wxID_HTML_SEARCHCHOICE,
+    wxID_HTML_COUNTINFO
+};
+
+
 IMPLEMENT_DYNAMIC_CLASS(wxHtmlHelpFrame, wxFrame)
 
 wxHtmlHelpFrame::wxHtmlHelpFrame(wxWindow* parent, wxWindowID id, const wxString& title,
 IMPLEMENT_DYNAMIC_CLASS(wxHtmlHelpFrame, wxFrame)
 
 wxHtmlHelpFrame::wxHtmlHelpFrame(wxWindow* parent, wxWindowID id, const wxString& title,
@@ -135,11 +184,11 @@ wxHtmlHelpFrame::wxHtmlHelpFrame(wxWindow* parent, wxWindowID id, const wxString
 
 void wxHtmlHelpFrame::Init(wxHtmlHelpData* data)
 {
 
 void wxHtmlHelpFrame::Init(wxHtmlHelpData* data)
 {
-    if (data) 
+    if (data)
     {
         m_Data = data;
         m_DataCreated = FALSE;
     {
         m_Data = data;
         m_DataCreated = FALSE;
-    } else 
+    } else
     {
         m_Data = new wxHtmlHelpData();
         m_DataCreated = TRUE;
     {
         m_Data = new wxHtmlHelpData();
         m_DataCreated = TRUE;
@@ -193,9 +242,11 @@ void wxHtmlHelpFrame::Init(wxHtmlHelpData* data)
 // moreover, if no contents, index or searchpage is needed, m_Splitter and
 // m_NavigPan will be NULL too (with m_HtmlWin directly connected to the frame)
 
 // moreover, if no contents, index or searchpage is needed, m_Splitter and
 // m_NavigPan will be NULL too (with m_HtmlWin directly connected to the frame)
 
-bool wxHtmlHelpFrame::Create(wxWindow* parent, wxWindowID id, const wxString& title,
-                             int style)
+bool wxHtmlHelpFrame::Create(wxWindow* parent, wxWindowID id,
+                             const wxString& WXUNUSED(title), int style)
 {
 {
+    m_hfStyle = style;
+
     wxImageList *ContentsImageList = new wxImageList(16, 16);
     ContentsImageList->Add(wxICON(wbook));
     ContentsImageList->Add(wxICON(wfolder));
     wxImageList *ContentsImageList = new wxImageList(16, 16);
     ContentsImageList->Add(wxICON(wbook));
     ContentsImageList->Add(wxICON(wfolder));
@@ -218,17 +269,17 @@ bool wxHtmlHelpFrame::Create(wxWindow* parent, wxWindowID id, const wxString& ti
     CreateStatusBar();
 
     // toolbar?
     CreateStatusBar();
 
     // toolbar?
-    if (style & (wxHF_TOOLBAR | wxHF_FLATTOOLBAR)) 
+    if (style & (wxHF_TOOLBAR | wxHF_FLAT_TOOLBAR))
     {
         wxToolBar *toolBar = CreateToolBar(wxNO_BORDER | wxTB_HORIZONTAL |
                                            wxTB_DOCKABLE |
     {
         wxToolBar *toolBar = CreateToolBar(wxNO_BORDER | wxTB_HORIZONTAL |
                                            wxTB_DOCKABLE |
-                                           (style & wxHF_FLATTOOLBAR ? wxTB_FLAT : 0));
+                                           (style & wxHF_FLAT_TOOLBAR ? wxTB_FLAT : 0));
         toolBar->SetMargins( 2, 2 );
         AddToolbarButtons(toolBar, style);
         toolBar->Realize();
     }
 
         toolBar->SetMargins( 2, 2 );
         AddToolbarButtons(toolBar, style);
         toolBar->Realize();
     }
 
-    if (style & (wxHF_CONTENTS | wxHF_INDEX | wxHF_SEARCH)) 
+    if (style & (wxHF_CONTENTS | wxHF_INDEX | wxHF_SEARCH))
     {
         // traditional help controller; splitter window with html page on the
         // right and a notebook containing various pages on the left
     {
         // traditional help controller; splitter window with html page on the
         // right and a notebook containing various pages on the left
@@ -237,8 +288,8 @@ bool wxHtmlHelpFrame::Create(wxWindow* parent, wxWindowID id, const wxString& ti
         m_HtmlWin = new wxHtmlHelpHtmlWindow(this, m_Splitter);
         m_NavigPan = new wxNotebook(m_Splitter, wxID_HTML_NOTEBOOK,
                                     wxDefaultPosition, wxDefaultSize);
         m_HtmlWin = new wxHtmlHelpHtmlWindow(this, m_Splitter);
         m_NavigPan = new wxNotebook(m_Splitter, wxID_HTML_NOTEBOOK,
                                     wxDefaultPosition, wxDefaultSize);
-    } 
-    else 
+    }
+    else
     { // only html window, no notebook with index,contents etc
         m_HtmlWin = new wxHtmlWindow(this);
     }
     { // only html window, no notebook with index,contents etc
         m_HtmlWin = new wxHtmlWindow(this);
     }
@@ -249,12 +300,12 @@ bool wxHtmlHelpFrame::Create(wxWindow* parent, wxWindowID id, const wxString& ti
         m_HtmlWin->ReadCustomization(m_Config, m_ConfigRoot);
 
     // contents tree panel?
         m_HtmlWin->ReadCustomization(m_Config, m_ConfigRoot);
 
     // contents tree panel?
-    if (style & wxHF_CONTENTS) 
+    if (style & wxHF_CONTENTS)
     {
         wxWindow *dummy = new wxPanel(m_NavigPan, wxID_HTML_INDEXPAGE);
 
     {
         wxWindow *dummy = new wxPanel(m_NavigPan, wxID_HTML_INDEXPAGE);
 
-        if (style & wxHF_BOOKMARKS) 
-           {
+        if (style & wxHF_BOOKMARKS)
+        {
             wxLayoutConstraints *b1 = new wxLayoutConstraints;
             wxBitmapButton *bmpbt = new wxBitmapButton(dummy, wxID_HTML_BOOKMARKSREMOVE, wxBITMAP(wbkdel), wxDefaultPosition, wxSize(20,20));
 
             wxLayoutConstraints *b1 = new wxLayoutConstraints;
             wxBitmapButton *bmpbt = new wxBitmapButton(dummy, wxID_HTML_BOOKMARKSREMOVE, wxBITMAP(wbkdel), wxDefaultPosition, wxSize(20,20));
 
@@ -296,7 +347,11 @@ bool wxHtmlHelpFrame::Create(wxWindow* parent, wxWindowID id, const wxString& ti
             wxLayoutConstraints *b4 = new wxLayoutConstraints;
             m_ContentsBox = new wxTreeCtrl(dummy, wxID_HTML_TREECTRL,
                                            wxDefaultPosition, wxDefaultSize,
             wxLayoutConstraints *b4 = new wxLayoutConstraints;
             m_ContentsBox = new wxTreeCtrl(dummy, wxID_HTML_TREECTRL,
                                            wxDefaultPosition, wxDefaultSize,
-                                           wxTR_HAS_BUTTONS | wxSUNKEN_BORDER);
+#ifdef __WXMAC__
+       wxSUNKEN_BORDER|wxTR_MAC_BUTTONS|wxTR_NO_LINES|wxTR_ROW_LINES );
+#else
+       wxSUNKEN_BORDER|wxTR_HAS_BUTTONS );
+#endif
             m_ContentsBox->AssignImageList(ContentsImageList);
 
             b4->top.Below (m_Bookmarks, 10);
             m_ContentsBox->AssignImageList(ContentsImageList);
 
             b4->top.Below (m_Bookmarks, 10);
@@ -324,7 +379,7 @@ bool wxHtmlHelpFrame::Create(wxWindow* parent, wxWindowID id, const wxString& ti
     }
 
     // index listbox panel?
     }
 
     // index listbox panel?
-    if (style & wxHF_INDEX) 
+    if (style & wxHF_INDEX)
     {
         wxWindow *dummy = new wxPanel(m_NavigPan, wxID_HTML_INDEXPAGE);
 
     {
         wxWindow *dummy = new wxPanel(m_NavigPan, wxID_HTML_INDEXPAGE);
 
@@ -383,7 +438,7 @@ bool wxHtmlHelpFrame::Create(wxWindow* parent, wxWindowID id, const wxString& ti
     }
 
     // search list panel?
     }
 
     // search list panel?
-    if (style & wxHF_SEARCH) 
+    if (style & wxHF_SEARCH)
     {
         wxWindow *dummy = new wxPanel(m_NavigPan, wxID_HTML_SEARCHPAGE);
 
     {
         wxWindow *dummy = new wxPanel(m_NavigPan, wxID_HTML_SEARCHPAGE);
 
@@ -449,24 +504,24 @@ bool wxHtmlHelpFrame::Create(wxWindow* parent, wxWindowID id, const wxString& ti
     RefreshLists();
 
     // showtime
     RefreshLists();
 
     // showtime
-    if (m_NavigPan && m_Splitter) 
+    if (m_NavigPan && m_Splitter)
     {
         m_Splitter->SetMinimumPaneSize(20);
         if (m_Cfg.navig_on)
             m_Splitter->SplitVertically(m_NavigPan, m_HtmlWin, m_Cfg.sashpos);
     {
         m_Splitter->SetMinimumPaneSize(20);
         if (m_Cfg.navig_on)
             m_Splitter->SplitVertically(m_NavigPan, m_HtmlWin, m_Cfg.sashpos);
-        else 
-           {
+        else
+        {
             m_Splitter->SplitVertically(m_NavigPan, m_HtmlWin, m_Cfg.sashpos);
             m_Splitter->Unsplit();
         }
 
             m_Splitter->SplitVertically(m_NavigPan, m_HtmlWin, m_Cfg.sashpos);
             m_Splitter->Unsplit();
         }
 
-           if (m_Cfg.navig_on) 
-           {
+        if (m_Cfg.navig_on)
+        {
             m_NavigPan->Show(TRUE);
             m_Splitter->SplitVertically(m_NavigPan, m_HtmlWin, m_Cfg.sashpos);
         }
             m_NavigPan->Show(TRUE);
             m_Splitter->SplitVertically(m_NavigPan, m_HtmlWin, m_Cfg.sashpos);
         }
-        else 
-           {
+        else
+        {
             m_NavigPan->Show(FALSE);
             m_Splitter->Initialize(m_HtmlWin);
         }
             m_NavigPan->Show(FALSE);
             m_Splitter->Initialize(m_HtmlWin);
         }
@@ -528,10 +583,10 @@ void wxHtmlHelpFrame::AddToolbarButtons(wxToolBar *toolBar, int style)
                        FALSE, -1, -1, (wxObject *) NULL,
                        _("Next page"));
 
                        FALSE, -1, -1, (wxObject *) NULL,
                        _("Next page"));
 
-    if ((style & wxHF_PRINT) || (style & wxHF_OPENFILES))
+    if ((style & wxHF_PRINT) || (style & wxHF_OPEN_FILES))
         toolBar->AddSeparator();
 
         toolBar->AddSeparator();
 
-    if (style & wxHF_OPENFILES)
+    if (style & wxHF_OPEN_FILES)
         toolBar->AddTool(wxID_HTML_OPENFILE, wopenBitmap, wxNullBitmap,
                            FALSE, -1, -1, (wxObject *) NULL,
                            _("Open HTML document"));
         toolBar->AddTool(wxID_HTML_OPENFILE, wopenBitmap, wxNullBitmap,
                            FALSE, -1, -1, (wxObject *) NULL,
                            _("Open HTML document"));
@@ -561,7 +616,7 @@ void wxHtmlHelpFrame::SetTitleFormat(const wxString& format)
 bool wxHtmlHelpFrame::Display(const wxString& x)
 {
     wxString url = m_Data->FindPageByName(x);
 bool wxHtmlHelpFrame::Display(const wxString& x)
 {
     wxString url = m_Data->FindPageByName(x);
-    if (!url.IsEmpty()) 
+    if (!url.IsEmpty())
     {
         m_HtmlWin->LoadPage(url);
         NotifyPageChanged();
     {
         m_HtmlWin->LoadPage(url);
         NotifyPageChanged();
@@ -573,7 +628,7 @@ bool wxHtmlHelpFrame::Display(const wxString& x)
 bool wxHtmlHelpFrame::Display(const int id)
 {
     wxString url = m_Data->FindPageById(id);
 bool wxHtmlHelpFrame::Display(const int id)
 {
     wxString url = m_Data->FindPageById(id);
-    if (!url.IsEmpty()) 
+    if (!url.IsEmpty())
     {
         m_HtmlWin->LoadPage(url);
         NotifyPageChanged();
     {
         m_HtmlWin->LoadPage(url);
         NotifyPageChanged();
@@ -588,7 +643,7 @@ bool wxHtmlHelpFrame::DisplayContents()
 {
     if (! m_ContentsBox)
         return FALSE;
 {
     if (! m_ContentsBox)
         return FALSE;
-    if (!m_Splitter->IsSplit()) 
+    if (!m_Splitter->IsSplit())
     {
         m_NavigPan->Show(TRUE);
         m_HtmlWin->Show(TRUE);
     {
         m_NavigPan->Show(TRUE);
         m_HtmlWin->Show(TRUE);
@@ -596,6 +651,12 @@ bool wxHtmlHelpFrame::DisplayContents()
         m_Cfg.navig_on = TRUE;
     }
     m_NavigPan->SetSelection(0);
         m_Cfg.navig_on = TRUE;
     }
     m_NavigPan->SetSelection(0);
+    if (m_Data->GetBookRecArray().GetCount() > 0)
+    {
+        wxHtmlBookRecord& book = m_Data->GetBookRecArray()[0];
+        if (!book.GetStart().IsEmpty())
+            m_HtmlWin->LoadPage(book.GetFullPath(book.GetStart()));
+    }
     return TRUE;
 }
 
     return TRUE;
 }
 
@@ -605,13 +666,19 @@ bool wxHtmlHelpFrame::DisplayIndex()
 {
     if (! m_IndexList)
         return FALSE;
 {
     if (! m_IndexList)
         return FALSE;
-    if (!m_Splitter->IsSplit()) 
+    if (!m_Splitter->IsSplit())
     {
         m_NavigPan->Show(TRUE);
         m_HtmlWin->Show(TRUE);
         m_Splitter->SplitVertically(m_NavigPan, m_HtmlWin, m_Cfg.sashpos);
     }
     m_NavigPan->SetSelection(1);
     {
         m_NavigPan->Show(TRUE);
         m_HtmlWin->Show(TRUE);
         m_Splitter->SplitVertically(m_NavigPan, m_HtmlWin, m_Cfg.sashpos);
     }
     m_NavigPan->SetSelection(1);
+    if (m_Data->GetBookRecArray().GetCount() > 0)
+    {
+        wxHtmlBookRecord& book = m_Data->GetBookRecArray()[0];
+        if (!book.GetStart().IsEmpty())
+            m_HtmlWin->LoadPage(book.GetFullPath(book.GetStart()));
+    }
     return TRUE;
 }
 
     return TRUE;
 }
 
@@ -626,7 +693,7 @@ bool wxHtmlHelpFrame::KeywordSearch(const wxString& keyword)
     wxString foundstr;
     wxString book = wxEmptyString;
 
     wxString foundstr;
     wxString book = wxEmptyString;
 
-    if (!m_Splitter->IsSplit()) 
+    if (!m_Splitter->IsSplit())
     {
         m_NavigPan->Show(TRUE);
         m_HtmlWin->Show(TRUE);
     {
         m_NavigPan->Show(TRUE);
         m_HtmlWin->Show(TRUE);
@@ -648,13 +715,13 @@ bool wxHtmlHelpFrame::KeywordSearch(const wxString& keyword)
                               status.GetMaxIndex(), this,
                               wxPD_APP_MODAL | wxPD_CAN_ABORT | wxPD_AUTO_HIDE);
 
                               status.GetMaxIndex(), this,
                               wxPD_APP_MODAL | wxPD_CAN_ABORT | wxPD_AUTO_HIDE);
 
-    while (status.IsActive()) 
+    while (status.IsActive())
     {
         curi = status.GetCurIndex();
         if (curi % 32 == 0 && progress.Update(curi) == FALSE)
             break;
     {
         curi = status.GetCurIndex();
         if (curi % 32 == 0 && progress.Update(curi) == FALSE)
             break;
-        if (status.Search()) 
-           {
+        if (status.Search())
+        {
             foundstr.Printf(_("Found %i matches"), ++foundcnt);
             progress.Update(status.GetCurIndex(), foundstr);
             m_SearchList->Append(status.GetName(), status.GetContentsItem());
             foundstr.Printf(_("Found %i matches"), ++foundcnt);
             progress.Update(status.GetCurIndex(), foundstr);
             m_SearchList->Append(status.GetName(), status.GetContentsItem());
@@ -664,20 +731,18 @@ bool wxHtmlHelpFrame::KeywordSearch(const wxString& keyword)
     m_SearchButton->Enable(TRUE);
     m_SearchText->SetSelection(0, keyword.Length());
     m_SearchText->SetFocus();
     m_SearchButton->Enable(TRUE);
     m_SearchText->SetSelection(0, keyword.Length());
     m_SearchText->SetFocus();
-    if (foundcnt) 
+    if (foundcnt)
     {
         wxHtmlContentsItem *it = (wxHtmlContentsItem*) m_SearchList->GetClientData(0);
         if (it)
         {
     {
         wxHtmlContentsItem *it = (wxHtmlContentsItem*) m_SearchList->GetClientData(0);
         if (it)
         {
-            m_HtmlWin->LoadPage(it->m_Book->GetBasePath() + it->m_Page);
+            m_HtmlWin->LoadPage(it->GetFullPath());
             NotifyPageChanged();
         }
     }
     return (foundcnt > 0);
 }
 
             NotifyPageChanged();
         }
     }
     return (foundcnt > 0);
 }
 
-#define MAX_ROOTS 64
-
 void wxHtmlHelpFrame::CreateContents()
 {
     if (! m_ContentsBox)
 void wxHtmlHelpFrame::CreateContents()
 {
     if (! m_ContentsBox)
@@ -691,43 +756,91 @@ void wxHtmlHelpFrame::CreateContents()
 
     int cnt = m_Data->GetContentsCnt();
     int i;
 
     int cnt = m_Data->GetContentsCnt();
     int i;
+    size_t booksCnt = m_Data->GetBookRecArray().GetCount();
 
     wxHtmlContentsItem *it;
 
 
     wxHtmlContentsItem *it;
 
+    const int MAX_ROOTS = 64;
     wxTreeItemId roots[MAX_ROOTS];
     wxTreeItemId roots[MAX_ROOTS];
+    // VS: this array holds information about whether we've set item icon at
+    //     given level. This is neccessary because m_Data has flat structure
+    //     and there's no way of recognizing if some item has subitems or not.
+    //     We set the icon later: when we find an item with level=n, we know
+    //     that the last item with level=n-1 was folder with subitems, so we
+    //     set its icon accordingly
     bool imaged[MAX_ROOTS];
     bool imaged[MAX_ROOTS];
-
     m_ContentsBox->DeleteAllItems();
     m_ContentsBox->DeleteAllItems();
-    roots[0] = m_ContentsBox->AddRoot(_("(Help)"));
-    m_ContentsBox->SetItemImage(roots[0], IMG_RootFolder);
-    m_ContentsBox->SetItemSelectedImage(roots[0], IMG_RootFolder);
-    imaged[0] = TRUE;
 
 
-    for (it = m_Data->GetContents(), i = 0; i < cnt; i++, it++) 
+    // Don't show (Help) root if there's only one boook
+    if (booksCnt > 1)
     {
     {
-        roots[it->m_Level + 1] =  m_ContentsBox->AppendItem(
-                                       roots[it->m_Level], it->m_Name, IMG_Page, -1,
-                                       new wxHtmlHelpTreeItemData(i));
-        m_PagesHash->Put(it->m_Book->GetBasePath() + it->m_Page,
-                           new wxHtmlHelpHashData(i, roots[it->m_Level + 1]));
+        roots[0] = m_ContentsBox->AddRoot(_("(Help)"));
+        m_ContentsBox->SetItemImage(roots[0], IMG_RootFolder);
+        m_ContentsBox->SetItemSelectedImage(roots[0], IMG_RootFolder);
+        imaged[0] = TRUE;
+    }
 
 
-        if (it->m_Level == 0) 
-           {
-            m_ContentsBox->SetItemBold(roots[1], TRUE);
-            m_ContentsBox->SetItemImage(roots[1], IMG_Book);
-            m_ContentsBox->SetItemSelectedImage(roots[1], IMG_Book);
-            imaged[1] = TRUE;
+    for (it = m_Data->GetContents(), i = 0; i < cnt; i++, it++)
+    {
+        // Handle books:
+        if (it->m_Level == 0)
+        {
+            // special case, only one book, make it tree's root:
+            if (booksCnt == 1)
+            {
+                roots[0] = roots[1] = m_ContentsBox->AddRoot(
+                                         it->m_Name, IMG_Book, -1,
+                                         new wxHtmlHelpTreeItemData(i));
+                imaged[0] = imaged[1] = TRUE;
+                m_ContentsBox->SetItemBold(roots[1], TRUE);
+            }
+            // multiple books:
+            else
+            {
+                if (m_hfStyle & wxHF_MERGE_BOOKS)
+                    // VS: we don't want book nodes, books' content should
+                    //    appear under tree's root. This line will create "fake"
+                    //    record about book node so that the rest of this look
+                    //    will believe there really _is_ book node and will
+                    //    behave correctly.
+                    roots[1] = roots[0];
+                else
+                {
+                    roots[1] = m_ContentsBox->AppendItem(roots[0],
+                                             it->m_Name, IMG_Book, -1,
+                                             new wxHtmlHelpTreeItemData(i));
+                    m_ContentsBox->SetItemBold(roots[1], TRUE);
+                }
+                imaged[1] = TRUE;
+            }
+        }
+        // ...and their contents:
+        else
+        {
+            roots[it->m_Level + 1] = m_ContentsBox->AppendItem(
+                                     roots[it->m_Level], it->m_Name, IMG_Page,
+                                     -1, new wxHtmlHelpTreeItemData(i));
+            imaged[it->m_Level + 1] = FALSE;
         }
         }
-           else 
-               imaged[it->m_Level + 1] = FALSE;
 
 
-        if (!imaged[it->m_Level]) 
-           {
-            m_ContentsBox->SetItemImage(roots[it->m_Level], IMG_Folder);
-            m_ContentsBox->SetItemSelectedImage(roots[it->m_Level], IMG_Folder);
+        m_PagesHash->Put(it->GetFullPath(),
+                           new wxHtmlHelpHashData(i, roots[it->m_Level + 1]));
+
+        // Set the icon for the node one level up in the hiearachy,
+        // unless already done (see comment above imaged[] declaration)
+        if (!imaged[it->m_Level])
+        {
+            int image = IMG_Folder;
+            if (m_hfStyle & wxHF_ICONS_BOOK)
+                image = IMG_Book;
+            else if (m_hfStyle & wxHF_ICONS_BOOK_CHAPTER)
+                image = (it->m_Level == 1) ? IMG_Book : IMG_Folder;
+            m_ContentsBox->SetItemImage(roots[it->m_Level], image);
+            m_ContentsBox->SetItemSelectedImage(roots[it->m_Level], image);
             imaged[it->m_Level] = TRUE;
         }
     }
             imaged[it->m_Level] = TRUE;
         }
     }
+
     m_ContentsBox->Expand(roots[0]);
 }
 
     m_ContentsBox->Expand(roots[0]);
 }
 
@@ -780,7 +893,7 @@ void wxHtmlHelpFrame::ReadCustomization(wxConfigBase *cfg, const wxString& path)
     wxString oldpath;
     wxString tmp;
 
     wxString oldpath;
     wxString tmp;
 
-    if (path != wxEmptyString) 
+    if (path != wxEmptyString)
     {
         oldpath = cfg->GetPath();
         cfg->SetPath(_T("/") + path);
     {
         oldpath = cfg->GetPath();
         cfg->SetPath(_T("/") + path);
@@ -803,18 +916,18 @@ void wxHtmlHelpFrame::ReadCustomization(wxConfigBase *cfg, const wxString& path)
         wxString val, s;
 
         cnt = cfg->Read(wxT("hcBookmarksCnt"), 0L);
         wxString val, s;
 
         cnt = cfg->Read(wxT("hcBookmarksCnt"), 0L);
-        if (cnt != 0) 
-           {
+        if (cnt != 0)
+        {
             m_BookmarksNames.Clear();
             m_BookmarksPages.Clear();
             m_BookmarksNames.Clear();
             m_BookmarksPages.Clear();
-            if (m_Bookmarks) 
-               {
+            if (m_Bookmarks)
+            {
                 m_Bookmarks->Clear();
                 m_Bookmarks->Append(_("(bookmarks)"));
             }
 
                 m_Bookmarks->Clear();
                 m_Bookmarks->Append(_("(bookmarks)"));
             }
 
-            for (i = 0; i < cnt; i++) 
-               {
+            for (i = 0; i < cnt; i++)
+            {
                 val.Printf(wxT("hcBookmark_%i"), i);
                 s = cfg->Read(val);
                 m_BookmarksNames.Add(s);
                 val.Printf(wxT("hcBookmark_%i"), i);
                 s = cfg->Read(val);
                 m_BookmarksNames.Add(s);
@@ -838,7 +951,7 @@ void wxHtmlHelpFrame::WriteCustomization(wxConfigBase *cfg, const wxString& path
     wxString oldpath;
     wxString tmp;
 
     wxString oldpath;
     wxString tmp;
 
-    if (path != wxEmptyString) 
+    if (path != wxEmptyString)
     {
         oldpath = cfg->GetPath();
         cfg->SetPath(_T("/") + path);
     {
         oldpath = cfg->GetPath();
         cfg->SetPath(_T("/") + path);
@@ -854,15 +967,15 @@ void wxHtmlHelpFrame::WriteCustomization(wxConfigBase *cfg, const wxString& path
     cfg->Write(wxT("hcNormalFace"), m_NormalFace);
     cfg->Write(wxT("hcFontSize"), (long)m_FontSize);
 
     cfg->Write(wxT("hcNormalFace"), m_NormalFace);
     cfg->Write(wxT("hcFontSize"), (long)m_FontSize);
 
-    if (m_Bookmarks) 
+    if (m_Bookmarks)
     {
         int i;
         int cnt = m_BookmarksNames.GetCount();
         wxString val;
 
         cfg->Write(wxT("hcBookmarksCnt"), (long)cnt);
     {
         int i;
         int cnt = m_BookmarksNames.GetCount();
         wxString val;
 
         cfg->Write(wxT("hcBookmarksCnt"), (long)cnt);
-        for (i = 0; i < cnt; i++) 
-           {
+        for (i = 0; i < cnt; i++)
+        {
             val.Printf(wxT("hcBookmark_%i"), i);
             cfg->Write(val, m_BookmarksNames[i]);
             val.Printf(wxT("hcBookmark_%i_url"), i);
             val.Printf(wxT("hcBookmark_%i"), i);
             cfg->Write(val, m_BookmarksNames[i]);
             val.Printf(wxT("hcBookmark_%i_url"), i);
@@ -983,7 +1096,7 @@ Normal face<br>(and <u>underlined</u>. <i>Italic face.</i> \
                                   ));
             }
 
                                   ));
             }
 
-        void OnUpdate(wxCommandEvent& event)
+        void OnUpdate(wxCommandEvent& WXUNUSED(event))
             {
                 UpdateTestWin();
             }
             {
                 UpdateTestWin();
             }
@@ -1002,7 +1115,7 @@ void wxHtmlHelpFrame::OptionsDialog()
     wxHtmlHelpFrameOptionsDialog dlg(this);
     unsigned i;
 
     wxHtmlHelpFrameOptionsDialog dlg(this);
     unsigned i;
 
-    if (m_NormalFonts == NULL) 
+    if (m_NormalFonts == NULL)
     {
         wxFontEnumerator enu;
         enu.EnumerateFacenames();
     {
         wxFontEnumerator enu;
         enu.EnumerateFacenames();
@@ -1010,7 +1123,7 @@ void wxHtmlHelpFrame::OptionsDialog()
         *m_NormalFonts = *enu.GetFacenames();
         m_NormalFonts->Sort();
     }
         *m_NormalFonts = *enu.GetFacenames();
         m_NormalFonts->Sort();
     }
-    if (m_FixedFonts == NULL) 
+    if (m_FixedFonts == NULL)
     {
         wxFontEnumerator enu;
         enu.EnumerateFacenames(wxFONTENCODING_SYSTEM, TRUE);
     {
         wxFontEnumerator enu;
         enu.EnumerateFacenames(wxFONTENCODING_SYSTEM, TRUE);
@@ -1030,7 +1143,7 @@ void wxHtmlHelpFrame::OptionsDialog()
     dlg.RadioBox->SetSelection(m_FontSize);
     dlg.UpdateTestWin();
 
     dlg.RadioBox->SetSelection(m_FontSize);
     dlg.UpdateTestWin();
 
-    if (dlg.ShowModal() == wxID_OK) 
+    if (dlg.ShowModal() == wxID_OK)
     {
         m_NormalFace = dlg.NormalFont->GetStringSelection();
         m_FixedFace = dlg.FixedFont->GetStringSelection();
     {
         m_NormalFace = dlg.NormalFont->GetStringSelection();
         m_FixedFace = dlg.FixedFont->GetStringSelection();
@@ -1071,7 +1184,7 @@ EVENT HANDLING :
 
 void wxHtmlHelpFrame::OnToolbar(wxCommandEvent& event)
 {
 
 void wxHtmlHelpFrame::OnToolbar(wxCommandEvent& event)
 {
-    switch (event.GetId()) 
+    switch (event.GetId())
     {
         case wxID_HTML_BACK :
             m_HtmlWin->HistoryBack();
     {
         case wxID_HTML_BACK :
             m_HtmlWin->HistoryBack();
@@ -1095,8 +1208,11 @@ void wxHtmlHelpFrame::OnToolbar(wxCommandEvent& event)
                 if (ha && ha->m_Index > 0)
                 {
                     wxHtmlContentsItem *it = m_Data->GetContents() + (ha->m_Index - 1);
                 if (ha && ha->m_Index > 0)
                 {
                     wxHtmlContentsItem *it = m_Data->GetContents() + (ha->m_Index - 1);
-                    m_HtmlWin->LoadPage(it->m_Book->GetBasePath() + it->m_Page);
-                    NotifyPageChanged();
+                    if (it->m_Page[0] != 0)
+                    {
+                        m_HtmlWin->LoadPage(it->GetFullPath());
+                        NotifyPageChanged();
+                    }
                 }
             }
             break;
                 }
             }
             break;
@@ -1120,8 +1236,11 @@ void wxHtmlHelpFrame::OnToolbar(wxCommandEvent& event)
                     while (ind >= 0 && it->m_Level != level) ind--, it--;
                     if (ind >= 0)
                     {
                     while (ind >= 0 && it->m_Level != level) ind--, it--;
                     if (ind >= 0)
                     {
-                        m_HtmlWin->LoadPage(it->m_Book->GetBasePath() + it->m_Page);
-                        NotifyPageChanged();
+                        if (it->m_Page[0] != 0)
+                        {
+                            m_HtmlWin->LoadPage(it->GetFullPath());
+                            NotifyPageChanged();
+                        }
                     }
                 }
             }
                     }
                 }
             }
@@ -1143,9 +1262,13 @@ void wxHtmlHelpFrame::OnToolbar(wxCommandEvent& event)
                 {
                     wxHtmlContentsItem *it = m_Data->GetContents() + (ha->m_Index + 1);
 
                 {
                     wxHtmlContentsItem *it = m_Data->GetContents() + (ha->m_Index + 1);
 
-                    while (it->m_Book->GetBasePath() + it->m_Page == adr) it++;
-                    m_HtmlWin->LoadPage(it->m_Book->GetBasePath() + it->m_Page);
-                    NotifyPageChanged();
+                    while (it->GetFullPath() == adr) it++;
+
+                    if (it->m_Page[0] != 0)
+                    {
+                        m_HtmlWin->LoadPage(it->GetFullPath());
+                        NotifyPageChanged();
+                    }
                 }
             }
             break;
                 }
             }
             break;
@@ -1154,14 +1277,14 @@ void wxHtmlHelpFrame::OnToolbar(wxCommandEvent& event)
             {
                 if (! (m_Splitter && m_NavigPan))
                     return ;
             {
                 if (! (m_Splitter && m_NavigPan))
                     return ;
-                if (m_Splitter->IsSplit()) 
-                       {
+                if (m_Splitter->IsSplit())
+                {
                     m_Cfg.sashpos = m_Splitter->GetSashPosition();
                     m_Splitter->Unsplit(m_NavigPan);
                     m_Cfg.navig_on = FALSE;
                     m_Cfg.sashpos = m_Splitter->GetSashPosition();
                     m_Splitter->Unsplit(m_NavigPan);
                     m_Cfg.navig_on = FALSE;
-                } 
-                       else 
-                       {
+                }
+                else
+                {
                     m_NavigPan->Show(TRUE);
                     m_HtmlWin->Show(TRUE);
                     m_Splitter->SplitVertically(m_NavigPan, m_HtmlWin, m_Cfg.sashpos);
                     m_NavigPan->Show(TRUE);
                     m_HtmlWin->Show(TRUE);
                     m_Splitter->SplitVertically(m_NavigPan, m_HtmlWin, m_Cfg.sashpos);
@@ -1181,10 +1304,10 @@ void wxHtmlHelpFrame::OnToolbar(wxCommandEvent& event)
 
                 item = m_HtmlWin->GetOpenedPageTitle();
                 url = m_HtmlWin->GetOpenedPage();
 
                 item = m_HtmlWin->GetOpenedPageTitle();
                 url = m_HtmlWin->GetOpenedPage();
-                if (item == wxEmptyString) 
-                           item = url.AfterLast(wxT('/'));
-                if (m_BookmarksPages.Index(url) == wxNOT_FOUND) 
-                       {
+                if (item == wxEmptyString)
+                    item = url.AfterLast(wxT('/'));
+                if (m_BookmarksPages.Index(url) == wxNOT_FOUND)
+                {
                     m_Bookmarks->Append(item);
                     m_BookmarksNames.Add(item);
                     m_BookmarksPages.Add(url);
                     m_Bookmarks->Append(item);
                     m_BookmarksNames.Add(item);
                     m_BookmarksPages.Add(url);
@@ -1199,8 +1322,8 @@ void wxHtmlHelpFrame::OnToolbar(wxCommandEvent& event)
 
                 item = m_Bookmarks->GetStringSelection();
                 pos = m_BookmarksNames.Index(item);
 
                 item = m_Bookmarks->GetStringSelection();
                 pos = m_BookmarksNames.Index(item);
-                if (pos != wxNOT_FOUND) 
-                       {
+                if (pos != wxNOT_FOUND)
+                {
                     m_BookmarksNames.Remove(pos);
                     m_BookmarksPages.Remove(pos);
                     m_Bookmarks->Delete(m_Bookmarks->GetSelection());
                     m_BookmarksNames.Remove(pos);
                     m_BookmarksPages.Remove(pos);
                     m_Bookmarks->Delete(m_Bookmarks->GetSelection());
@@ -1265,7 +1388,8 @@ void wxHtmlHelpFrame::OnContentsSel(wxTreeEvent& event)
     {
         it = m_Data->GetContents() + (pg->m_Id);
         m_UpdateContents = FALSE;
     {
         it = m_Data->GetContents() + (pg->m_Id);
         m_UpdateContents = FALSE;
-        m_HtmlWin->LoadPage(it->m_Book->GetBasePath() + it->m_Page);
+        if (it->m_Page[0] != 0)
+            m_HtmlWin->LoadPage(it->GetFullPath());
         m_UpdateContents = TRUE;
     }
 }
         m_UpdateContents = TRUE;
     }
 }
@@ -1275,7 +1399,8 @@ void wxHtmlHelpFrame::OnContentsSel(wxTreeEvent& event)
 void wxHtmlHelpFrame::OnIndexSel(wxCommandEvent& WXUNUSED(event))
 {
     wxHtmlContentsItem *it = (wxHtmlContentsItem*) m_IndexList->GetClientData(m_IndexList->GetSelection());
 void wxHtmlHelpFrame::OnIndexSel(wxCommandEvent& WXUNUSED(event))
 {
     wxHtmlContentsItem *it = (wxHtmlContentsItem*) m_IndexList->GetClientData(m_IndexList->GetSelection());
-    m_HtmlWin->LoadPage(it->m_Book->GetBasePath() + it->m_Page);
+    if (it->m_Page[0] != 0)
+        m_HtmlWin->LoadPage(it->GetFullPath());
     NotifyPageChanged();
 }
 
     NotifyPageChanged();
 }
 
@@ -1288,11 +1413,12 @@ void wxHtmlHelpFrame::OnIndexFind(wxCommandEvent& event)
     {
         OnIndexAll(event);
     }
     {
         OnIndexAll(event);
     }
-    else 
+    else
     {
         wxBusyCursor bcur;
         const wxChar *cstr = sr.c_str();
     {
         wxBusyCursor bcur;
         const wxChar *cstr = sr.c_str();
-        wxChar mybuff[512], *ptr;
+        wxChar mybuff[512];
+        wxChar *ptr;
         bool first = TRUE;
 
         m_IndexList->Clear();
         bool first = TRUE;
 
         m_IndexList->Clear();
@@ -1307,13 +1433,14 @@ void wxHtmlHelpFrame::OnIndexFind(wxCommandEvent& event)
             for (ptr = mybuff; *ptr != 0; ptr++)
                 if (*ptr >= _T('A') && *ptr <= _T('Z'))
                     *ptr -= (wxChar)(_T('A') - _T('a'));
             for (ptr = mybuff; *ptr != 0; ptr++)
                 if (*ptr >= _T('A') && *ptr <= _T('Z'))
                     *ptr -= (wxChar)(_T('A') - _T('a'));
-            if (wxStrstr(mybuff, cstr) != NULL) 
-               {
+            if (wxStrstr(mybuff, cstr) != NULL)
+            {
                 m_IndexList->Append(index[i].m_Name, (char*)(index + i));
                 displ++;
                 m_IndexList->Append(index[i].m_Name, (char*)(index + i));
                 displ++;
-                if (first) 
-                       {
-                    m_HtmlWin->LoadPage(index[i].m_Book->GetBasePath() + index[i].m_Page);
+                if (first)
+                {
+                    if (index[i].m_Page[0] != 0)
+                        m_HtmlWin->LoadPage(index[i].GetFullPath());
                     NotifyPageChanged();
                     first = FALSE;
                 }
                     NotifyPageChanged();
                     first = FALSE;
                 }
@@ -1338,12 +1465,13 @@ void wxHtmlHelpFrame::OnIndexAll(wxCommandEvent& WXUNUSED(event))
     bool first = TRUE;
     wxHtmlContentsItem* index = m_Data->GetIndex();
 
     bool first = TRUE;
     wxHtmlContentsItem* index = m_Data->GetIndex();
 
-    for (int i = 0; i < cnt; i++) 
+    for (int i = 0; i < cnt; i++)
     {
         m_IndexList->Append(index[i].m_Name, (char*)(index + i));
     {
         m_IndexList->Append(index[i].m_Name, (char*)(index + i));
-        if (first) 
-           {
-            m_HtmlWin->LoadPage(index[i].m_Book->GetBasePath() + index[i].m_Page);
+        if (first)
+        {
+            if (index[i].m_Page[0] != 0)
+                m_HtmlWin->LoadPage(index[i].GetFullPath());
             NotifyPageChanged();
             first = FALSE;
         }
             NotifyPageChanged();
             first = FALSE;
         }
@@ -1360,7 +1488,8 @@ void wxHtmlHelpFrame::OnSearchSel(wxCommandEvent& WXUNUSED(event))
     wxHtmlContentsItem *it = (wxHtmlContentsItem*) m_SearchList->GetClientData(m_SearchList->GetSelection());
     if (it)
     {
     wxHtmlContentsItem *it = (wxHtmlContentsItem*) m_SearchList->GetClientData(m_SearchList->GetSelection());
     if (it)
     {
-        m_HtmlWin->LoadPage(it->m_Book->GetBasePath() + it->m_Page);
+        if (it->m_Page[0] != 0)
+            m_HtmlWin->LoadPage(it->GetFullPath());
         NotifyPageChanged();
     }
 }
         NotifyPageChanged();
     }
 }
@@ -1417,4 +1546,5 @@ BEGIN_EVENT_TABLE(wxHtmlHelpFrame, wxFrame)
     EVT_CLOSE(wxHtmlHelpFrame::OnCloseWindow)
 END_EVENT_TABLE()
 
     EVT_CLOSE(wxHtmlHelpFrame::OnCloseWindow)
 END_EVENT_TABLE()
 
-#endif
+#endif // wxUSE_WXHTML_HELP
+