wxHtmlHelpWindow: Fix contents panel syncing with view.
[wxWidgets.git] / src / html / helpwnd.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/html/helpwnd.cpp
3 // Purpose: wxHtmlHelpWindow
4 // Notes: Based on htmlhelp.cpp, implementing a monolithic
5 // HTML Help controller class, by Vaclav Slavik
6 // Author: Harm van der Heijden and Vaclav Slavik
7 // RCS-ID: $Id$
8 // Copyright: (c) Harm van der Heijden and Vaclav Slavik
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // For compilers that support precompilation, includes "wx.h"
13
14 #include "wx/wxprec.h"
15
16 #ifdef __BORLANDC__
17 #pragma hdrstop
18 #endif
19
20 #if wxUSE_WXHTML_HELP
21
22 #ifndef WX_PRECOMP
23 #include "wx/object.h"
24 #include "wx/dynarray.h"
25 #include "wx/intl.h"
26 #include "wx/log.h"
27 #if wxUSE_STREAMS
28 #include "wx/stream.h"
29 #endif
30
31 #include "wx/sizer.h"
32
33 #include "wx/bmpbuttn.h"
34 #include "wx/statbox.h"
35 #include "wx/radiobox.h"
36 #include "wx/menu.h"
37 #include "wx/settings.h"
38 #include "wx/msgdlg.h"
39 #include "wx/textctrl.h"
40 #include "wx/toolbar.h"
41 #include "wx/choicdlg.h"
42 #include "wx/filedlg.h"
43 #endif // WX_PRECOMP
44
45 #include "wx/html/helpfrm.h"
46 #include "wx/html/helpdlg.h"
47 #include "wx/html/helpctrl.h"
48 #include "wx/notebook.h"
49 #include "wx/imaglist.h"
50 #include "wx/treectrl.h"
51 #include "wx/tokenzr.h"
52 #include "wx/wfstream.h"
53 #include "wx/html/htmlwin.h"
54 #include "wx/busyinfo.h"
55 #include "wx/progdlg.h"
56 #include "wx/fontenum.h"
57 #include "wx/artprov.h"
58 #include "wx/spinctrl.h"
59
60 // what is considered "small index"?
61 #define INDEX_IS_SMALL 1000
62
63 // minimum width for content tree and index
64 // (we cannot let minimum size be determined from content, else long titles
65 // make the help frame unusable)
66 const wxCoord CONTENT_TREE_INDEX_MIN_WIDTH = 150;
67
68 /* Motif defines this as a macro */
69 #ifdef Below
70 #undef Below
71 #endif
72
73 //--------------------------------------------------------------------------
74 // wxHtmlHelpTreeItemData (private)
75 //--------------------------------------------------------------------------
76
77 class wxHtmlHelpTreeItemData : public wxTreeItemData
78 {
79 public:
80 #if defined(__VISAGECPP__)
81 // VA needs a default ctor for some reason....
82 wxHtmlHelpTreeItemData() : wxTreeItemData()
83 { m_Id = 0; }
84 #endif
85 wxHtmlHelpTreeItemData(int id) : wxTreeItemData()
86 { m_Id = id;}
87
88 int m_Id;
89 };
90
91
92 //--------------------------------------------------------------------------
93 // wxHtmlHelpHashData (private)
94 //--------------------------------------------------------------------------
95
96 class wxHtmlHelpHashData : public wxObject
97 {
98 public:
99 wxHtmlHelpHashData(int index, wxTreeItemId id) : wxObject()
100 { m_Index = index; m_Id = id;}
101 virtual ~wxHtmlHelpHashData() {}
102
103 int m_Index;
104 wxTreeItemId m_Id;
105 };
106
107
108 //--------------------------------------------------------------------------
109 // wxHtmlHelpHtmlWindow (private)
110 //--------------------------------------------------------------------------
111
112
113 class wxHtmlHelpHtmlWindow : public wxHtmlWindow
114 {
115 public:
116 wxHtmlHelpHtmlWindow(wxHtmlHelpWindow *win, wxWindow *parent, wxWindowID id = wxID_ANY,
117 const wxPoint& pos = wxDefaultPosition, const wxSize& sz = wxDefaultSize, long style = wxHW_DEFAULT_STYLE)
118 : wxHtmlWindow(parent, id, pos, sz, style), m_Window(win)
119 {
120 SetStandardFonts();
121 }
122
123 virtual bool LoadPage(const wxString& location)
124 {
125 if ( !wxHtmlWindow::LoadPage(location) )
126 return false;
127
128 m_Window->NotifyPageChanged();
129 return true;
130 }
131
132 // Returns full location with anchor (helper)
133 static wxString GetOpenedPageWithAnchor(wxHtmlWindow *win)
134 {
135 if(!win)
136 return wxEmptyString;
137
138 wxString an = win->GetOpenedAnchor();
139 wxString pg = win->GetOpenedPage();
140 if(!an.empty())
141 {
142 pg << wxT("#") << an;
143 }
144 return pg;
145 }
146
147 private:
148 wxHtmlHelpWindow *m_Window;
149
150 wxDECLARE_NO_COPY_CLASS(wxHtmlHelpHtmlWindow);
151 };
152
153
154 //---------------------------------------------------------------------------
155 // wxHtmlHelpWindow::m_mergedIndex
156 //---------------------------------------------------------------------------
157
158 WX_DEFINE_ARRAY_PTR(const wxHtmlHelpDataItem*, wxHtmlHelpDataItemPtrArray);
159
160 struct wxHtmlHelpMergedIndexItem
161 {
162 wxHtmlHelpMergedIndexItem *parent;
163 wxString name;
164 wxHtmlHelpDataItemPtrArray items;
165 };
166
167 WX_DECLARE_OBJARRAY(wxHtmlHelpMergedIndexItem, wxHtmlHelpMergedIndex);
168 #include "wx/arrimpl.cpp"
169 WX_DEFINE_OBJARRAY(wxHtmlHelpMergedIndex)
170
171 void wxHtmlHelpWindow::UpdateMergedIndex()
172 {
173 delete m_mergedIndex;
174 m_mergedIndex = new wxHtmlHelpMergedIndex;
175 wxHtmlHelpMergedIndex& merged = *m_mergedIndex;
176
177 const wxHtmlHelpDataItems& items = m_Data->GetIndexArray();
178 size_t len = items.size();
179
180 wxHtmlHelpMergedIndexItem *history[128] = {NULL};
181
182 for (size_t i = 0; i < len; i++)
183 {
184 const wxHtmlHelpDataItem& item = items[i];
185 wxASSERT_MSG( item.level < 128, wxT("nested index entries too deep") );
186
187 if (history[item.level] &&
188 history[item.level]->items[0]->name == item.name)
189 {
190 // same index entry as previous one, update list of items
191 history[item.level]->items.Add(&item);
192 }
193 else
194 {
195 // new index entry
196 wxHtmlHelpMergedIndexItem *mi = new wxHtmlHelpMergedIndexItem();
197 mi->name = item.GetIndentedName();
198 mi->items.Add(&item);
199 mi->parent = (item.level == 0) ? NULL : history[item.level - 1];
200 history[item.level] = mi;
201 merged.Add(mi);
202 }
203 }
204 }
205
206 //---------------------------------------------------------------------------
207 // wxHtmlHelpWindow
208 //---------------------------------------------------------------------------
209
210 IMPLEMENT_DYNAMIC_CLASS(wxHtmlHelpWindow, wxWindow)
211
212 BEGIN_EVENT_TABLE(wxHtmlHelpWindow, wxWindow)
213 EVT_TOOL_RANGE(wxID_HTML_PANEL, wxID_HTML_OPTIONS, wxHtmlHelpWindow::OnToolbar)
214 EVT_BUTTON(wxID_HTML_BOOKMARKSREMOVE, wxHtmlHelpWindow::OnToolbar)
215 EVT_BUTTON(wxID_HTML_BOOKMARKSADD, wxHtmlHelpWindow::OnToolbar)
216 EVT_TREE_SEL_CHANGED(wxID_HTML_TREECTRL, wxHtmlHelpWindow::OnContentsSel)
217 EVT_LISTBOX(wxID_HTML_INDEXLIST, wxHtmlHelpWindow::OnIndexSel)
218 EVT_LISTBOX(wxID_HTML_SEARCHLIST, wxHtmlHelpWindow::OnSearchSel)
219 EVT_BUTTON(wxID_HTML_SEARCHBUTTON, wxHtmlHelpWindow::OnSearch)
220 EVT_TEXT_ENTER(wxID_HTML_SEARCHTEXT, wxHtmlHelpWindow::OnSearch)
221 EVT_BUTTON(wxID_HTML_INDEXBUTTON, wxHtmlHelpWindow::OnIndexFind)
222 EVT_TEXT_ENTER(wxID_HTML_INDEXTEXT, wxHtmlHelpWindow::OnIndexFind)
223 EVT_BUTTON(wxID_HTML_INDEXBUTTONALL, wxHtmlHelpWindow::OnIndexAll)
224 EVT_COMBOBOX(wxID_HTML_BOOKMARKSLIST, wxHtmlHelpWindow::OnBookmarksSel)
225 EVT_SIZE(wxHtmlHelpWindow::OnSize)
226 END_EVENT_TABLE()
227
228 wxHtmlHelpWindow::wxHtmlHelpWindow(wxWindow* parent, wxWindowID id,
229 const wxPoint& pos,
230 const wxSize& size,
231 int style, int helpStyle, wxHtmlHelpData* data)
232 {
233 Init(data);
234 Create(parent, id, pos, size, style, helpStyle);
235 }
236
237 void wxHtmlHelpWindow::Init(wxHtmlHelpData* data)
238 {
239 if (data)
240 {
241 m_Data = data;
242 m_DataCreated = false;
243 }
244 else
245 {
246 m_Data = new wxHtmlHelpData();
247 m_DataCreated = true;
248 }
249
250 m_ContentsPage = 0;
251 m_IndexPage = 0;
252 m_SearchPage = 0;
253
254 m_ContentsBox = NULL;
255 m_IndexList = NULL;
256 m_IndexButton = NULL;
257 m_IndexButtonAll = NULL;
258 m_IndexText = NULL;
259 m_SearchList = NULL;
260 m_SearchButton = NULL;
261 m_SearchText = NULL;
262 m_SearchChoice = NULL;
263 m_IndexCountInfo = NULL;
264 m_Splitter = NULL;
265 m_NavigPan = NULL;
266 m_NavigNotebook = NULL;
267 m_HtmlWin = NULL;
268 m_Bookmarks = NULL;
269 m_SearchCaseSensitive = NULL;
270 m_SearchWholeWords = NULL;
271
272 m_mergedIndex = NULL;
273
274 #if wxUSE_CONFIG
275 m_Config = NULL;
276 m_ConfigRoot = wxEmptyString;
277 #endif // wxUSE_CONFIG
278
279 m_Cfg.x = m_Cfg.y = wxDefaultCoord;
280 m_Cfg.w = 700;
281 m_Cfg.h = 480;
282 m_Cfg.sashpos = 240;
283 m_Cfg.navig_on = true;
284
285 m_NormalFonts = m_FixedFonts = NULL;
286 m_NormalFace = m_FixedFace = wxEmptyString;
287 #ifdef __WXMSW__
288 m_FontSize = 10;
289 #else
290 m_FontSize = 14;
291 #endif
292
293 #if wxUSE_PRINTING_ARCHITECTURE
294 m_Printer = NULL;
295 #endif
296
297 m_PagesHash = NULL;
298 m_UpdateContents = true;
299 m_toolBar = NULL;
300 m_helpController = NULL;
301 }
302
303 // Create: builds the GUI components.
304 // with the style flag it's possible to toggle the toolbar, contents, index and search
305 // controls.
306 // m_HtmlWin will *always* be created, but it's important to realize that
307 // m_ContentsBox, m_IndexList, m_SearchList, m_SearchButton, m_SearchText and
308 // m_SearchButton may be NULL.
309 // moreover, if no contents, index or searchpage is needed, m_Splitter and
310 // m_NavigPan will be NULL too (with m_HtmlWin directly connected to the frame)
311
312 bool wxHtmlHelpWindow::Create(wxWindow* parent, wxWindowID id,
313 const wxPoint& pos, const wxSize& size,
314 int style, int helpStyle)
315 {
316 m_hfStyle = helpStyle;
317
318 #if wxUSE_CONFIG
319 // Do the config in two steps. We read the HtmlWindow customization after we
320 // create the window.
321 if (m_Config)
322 ReadCustomization(m_Config, m_ConfigRoot);
323 #endif // wxUSE_CONFIG
324
325 wxWindow::Create(parent, id, pos, size, style, wxT("wxHtmlHelp"));
326
327 SetHelpText(_("Displays help as you browse the books on the left."));
328
329 GetPosition(&m_Cfg.x, &m_Cfg.y);
330
331 int notebook_page = 0;
332
333 // The sizer for the whole top-level window.
334 wxSizer *topWindowSizer = new wxBoxSizer(wxVERTICAL);
335 SetSizer(topWindowSizer);
336 SetAutoLayout(true);
337
338 #if wxUSE_TOOLBAR
339 // toolbar?
340 if (helpStyle & (wxHF_TOOLBAR | wxHF_FLAT_TOOLBAR))
341 {
342 wxToolBar *toolBar = new wxToolBar(this, wxID_ANY, wxDefaultPosition, wxDefaultSize,
343 wxNO_BORDER | wxTB_HORIZONTAL |
344 wxTB_DOCKABLE | wxTB_NODIVIDER |
345 (helpStyle & wxHF_FLAT_TOOLBAR ? wxTB_FLAT : 0));
346 toolBar->SetMargins( 2, 2 );
347 toolBar->SetToolBitmapSize( wxSize(22,22) );
348 AddToolbarButtons(toolBar, helpStyle);
349 toolBar->Realize();
350 topWindowSizer->Add(toolBar, 0, wxEXPAND);
351 m_toolBar = toolBar;
352 }
353 #endif //wxUSE_TOOLBAR
354
355 wxSizer *navigSizer = NULL;
356
357 #ifdef __WXMSW__
358 wxBorder htmlWindowBorder = GetDefaultBorder();
359 htmlWindowBorder = wxBORDER_THEME;
360 #else
361 wxBorder htmlWindowBorder = wxBORDER_SUNKEN;
362 #endif
363
364 if (helpStyle & (wxHF_CONTENTS | wxHF_INDEX | wxHF_SEARCH))
365 {
366 // traditional help controller; splitter window with html page on the
367 // right and a notebook containing various pages on the left
368 long splitterStyle = wxSP_3D;
369 // Drawing moving sash can cause problems on wxMac
370 #ifdef __WXMAC__
371 splitterStyle |= wxSP_LIVE_UPDATE;
372 #endif
373 m_Splitter = new wxSplitterWindow(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, splitterStyle);
374
375 topWindowSizer->Add(m_Splitter, 1, wxEXPAND);
376
377 m_HtmlWin = new wxHtmlHelpHtmlWindow(this, m_Splitter, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxHW_DEFAULT_STYLE|htmlWindowBorder);
378 m_NavigPan = new wxPanel(m_Splitter, wxID_ANY);
379 m_NavigNotebook = new wxNotebook(m_NavigPan, wxID_HTML_NOTEBOOK,
380 wxDefaultPosition, wxDefaultSize);
381 #ifdef __WXMAC__
382 m_NavigNotebook->SetWindowVariant(wxWINDOW_VARIANT_SMALL);
383 #endif
384
385 navigSizer = new wxBoxSizer(wxVERTICAL);
386 navigSizer->Add(m_NavigNotebook, 1, wxEXPAND);
387
388 m_NavigPan->SetSizer(navigSizer);
389 }
390 else
391 {
392 // only html window, no notebook with index,contents etc
393 m_HtmlWin = new wxHtmlWindow(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxHW_DEFAULT_STYLE|htmlWindowBorder);
394 topWindowSizer->Add(m_HtmlWin, 1, wxEXPAND);
395 }
396
397 #if wxUSE_CONFIG
398 if ( m_Config )
399 m_HtmlWin->ReadCustomization(m_Config, m_ConfigRoot);
400 #endif // wxUSE_CONFIG
401
402 // contents tree panel?
403 if ( helpStyle & wxHF_CONTENTS )
404 {
405 wxWindow *dummy = new wxPanel(m_NavigNotebook, wxID_HTML_INDEXPAGE);
406 #ifdef __WXMAC__
407 dummy->SetWindowVariant(wxWINDOW_VARIANT_NORMAL);
408 #endif
409 wxSizer *topsizer = new wxBoxSizer(wxVERTICAL);
410
411 topsizer->Add(0, 10);
412
413 dummy->SetSizer(topsizer);
414
415 if ( helpStyle & wxHF_BOOKMARKS )
416 {
417 long comboStyle = wxCB_READONLY;
418 #ifndef __WXMAC__
419 // Not supported on OSX/Cocoa presently
420 comboStyle |= wxCB_SORT;
421
422 #endif
423 m_Bookmarks = new wxComboBox(dummy, wxID_HTML_BOOKMARKSLIST,
424 wxEmptyString,
425 wxDefaultPosition, wxDefaultSize,
426 0, NULL, comboStyle);
427 m_Bookmarks->Append(_("(bookmarks)"));
428 for (unsigned i = 0; i < m_BookmarksNames.GetCount(); i++)
429 m_Bookmarks->Append(m_BookmarksNames[i]);
430 m_Bookmarks->SetSelection(0);
431
432 wxBitmapButton *bmpbt1, *bmpbt2;
433 bmpbt1 = new wxBitmapButton(dummy, wxID_HTML_BOOKMARKSADD,
434 wxArtProvider::GetBitmap(wxART_ADD_BOOKMARK,
435 wxART_BUTTON));
436 bmpbt2 = new wxBitmapButton(dummy, wxID_HTML_BOOKMARKSREMOVE,
437 wxArtProvider::GetBitmap(wxART_DEL_BOOKMARK,
438 wxART_BUTTON));
439 #if wxUSE_TOOLTIPS
440 bmpbt1->SetToolTip(_("Add current page to bookmarks"));
441 bmpbt2->SetToolTip(_("Remove current page from bookmarks"));
442 #endif // wxUSE_TOOLTIPS
443
444 wxSizer *sizer = new wxBoxSizer(wxHORIZONTAL);
445
446 sizer->Add(m_Bookmarks, 1, wxALIGN_CENTRE_VERTICAL | wxRIGHT, 5);
447 sizer->Add(bmpbt1, 0, wxALIGN_CENTRE_VERTICAL | wxRIGHT, 2);
448 sizer->Add(bmpbt2, 0, wxALIGN_CENTRE_VERTICAL, 0);
449
450 topsizer->Add(sizer, 0, wxEXPAND | wxLEFT | wxBOTTOM | wxRIGHT, 10);
451 }
452
453 m_ContentsBox = new wxTreeCtrl(dummy, wxID_HTML_TREECTRL,
454 wxDefaultPosition, wxDefaultSize,
455 #if defined(__WXGTK20__) || defined(__WXMAC__)
456 wxSUNKEN_BORDER |
457 wxTR_HAS_BUTTONS | wxTR_HIDE_ROOT |
458 wxTR_NO_LINES
459 #else
460 wxSUNKEN_BORDER |
461 wxTR_HAS_BUTTONS | wxTR_HIDE_ROOT |
462 wxTR_LINES_AT_ROOT
463 #endif
464 );
465
466 wxImageList *ContentsImageList = new wxImageList(16, 16);
467 ContentsImageList->Add(wxArtProvider::GetIcon(wxART_HELP_BOOK,
468 wxART_HELP_BROWSER,
469 wxSize(16, 16)));
470 ContentsImageList->Add(wxArtProvider::GetIcon(wxART_HELP_FOLDER,
471 wxART_HELP_BROWSER,
472 wxSize(16, 16)));
473 ContentsImageList->Add(wxArtProvider::GetIcon(wxART_HELP_PAGE,
474 wxART_HELP_BROWSER,
475 wxSize(16, 16)));
476
477 m_ContentsBox->AssignImageList(ContentsImageList);
478
479 topsizer->Add(m_ContentsBox, 1,
480 wxEXPAND | wxLEFT | wxBOTTOM | wxRIGHT,
481 2);
482
483 m_NavigNotebook->AddPage(dummy, _("Contents"));
484 m_ContentsPage = notebook_page++;
485 }
486
487 // index listbox panel?
488 if ( helpStyle & wxHF_INDEX )
489 {
490 wxWindow *dummy = new wxPanel(m_NavigNotebook, wxID_HTML_INDEXPAGE);
491 #ifdef __WXMAC__
492 dummy->SetWindowVariant(wxWINDOW_VARIANT_NORMAL);
493 #endif
494 wxSizer *topsizer = new wxBoxSizer(wxVERTICAL);
495
496 dummy->SetSizer(topsizer);
497
498 m_IndexText = new wxTextCtrl(dummy, wxID_HTML_INDEXTEXT, wxEmptyString,
499 wxDefaultPosition, wxDefaultSize,
500 wxTE_PROCESS_ENTER);
501 m_IndexButton = new wxButton(dummy, wxID_HTML_INDEXBUTTON, _("Find"));
502 m_IndexButtonAll = new wxButton(dummy, wxID_HTML_INDEXBUTTONALL,
503 _("Show all"));
504 m_IndexCountInfo = new wxStaticText(dummy, wxID_HTML_COUNTINFO,
505 wxEmptyString, wxDefaultPosition,
506 wxDefaultSize,
507 wxALIGN_RIGHT | wxST_NO_AUTORESIZE);
508 m_IndexList = new wxListBox(dummy, wxID_HTML_INDEXLIST,
509 wxDefaultPosition, wxDefaultSize,
510 0, NULL, wxLB_SINGLE);
511
512 #if wxUSE_TOOLTIPS
513 m_IndexButton->SetToolTip(_("Display all index items that contain given substring. Search is case insensitive."));
514 m_IndexButtonAll->SetToolTip(_("Show all items in index"));
515 #endif //wxUSE_TOOLTIPS
516
517 topsizer->Add(m_IndexText, 0, wxEXPAND | wxALL, 10);
518 wxSizer *btsizer = new wxBoxSizer(wxHORIZONTAL);
519 btsizer->Add(m_IndexButton, 0, wxRIGHT, 2);
520 btsizer->Add(m_IndexButtonAll);
521 topsizer->Add(btsizer, 0,
522 wxALIGN_RIGHT | wxLEFT | wxRIGHT | wxBOTTOM, 10);
523 topsizer->Add(m_IndexCountInfo, 0, wxEXPAND | wxLEFT | wxRIGHT, 2);
524 topsizer->Add(m_IndexList, 1, wxEXPAND | wxALL, 2);
525
526 m_NavigNotebook->AddPage(dummy, _("Index"));
527 m_IndexPage = notebook_page++;
528 }
529
530 // search list panel?
531 if ( helpStyle & wxHF_SEARCH )
532 {
533 wxWindow *dummy = new wxPanel(m_NavigNotebook, wxID_HTML_INDEXPAGE);
534 #ifdef __WXMAC__
535 dummy->SetWindowVariant(wxWINDOW_VARIANT_NORMAL);
536 #endif
537 wxSizer *sizer = new wxBoxSizer(wxVERTICAL);
538
539 dummy->SetSizer(sizer);
540
541 m_SearchText = new wxTextCtrl(dummy, wxID_HTML_SEARCHTEXT,
542 wxEmptyString,
543 wxDefaultPosition, wxDefaultSize,
544 wxTE_PROCESS_ENTER);
545 m_SearchChoice = new wxChoice(dummy, wxID_HTML_SEARCHCHOICE,
546 wxDefaultPosition, wxSize(125,wxDefaultCoord));
547 m_SearchCaseSensitive = new wxCheckBox(dummy, wxID_ANY, _("Case sensitive"));
548 m_SearchWholeWords = new wxCheckBox(dummy, wxID_ANY, _("Whole words only"));
549 m_SearchButton = new wxButton(dummy, wxID_HTML_SEARCHBUTTON, _("Search"));
550 #if wxUSE_TOOLTIPS
551 m_SearchButton->SetToolTip(_("Search contents of help book(s) for all occurrences of the text you typed above"));
552 #endif //wxUSE_TOOLTIPS
553 m_SearchList = new wxListBox(dummy, wxID_HTML_SEARCHLIST,
554 wxDefaultPosition, wxDefaultSize,
555 0, NULL, wxLB_SINGLE);
556
557 sizer->Add(m_SearchText, 0, wxEXPAND | wxALL, 10);
558 sizer->Add(m_SearchChoice, 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 10);
559 sizer->Add(m_SearchCaseSensitive, 0, wxLEFT | wxRIGHT, 10);
560 sizer->Add(m_SearchWholeWords, 0, wxLEFT | wxRIGHT, 10);
561 sizer->Add(m_SearchButton, 0, wxALL | wxALIGN_RIGHT, 8);
562 sizer->Add(m_SearchList, 1, wxALL | wxEXPAND, 2);
563
564 m_NavigNotebook->AddPage(dummy, _("Search"));
565 m_SearchPage = notebook_page;
566 }
567
568 m_HtmlWin->Show();
569
570 RefreshLists();
571
572 if ( navigSizer )
573 {
574 navigSizer->SetSizeHints(m_NavigPan);
575 m_NavigPan->Layout();
576 }
577
578 // showtime
579 if ( m_NavigPan && m_Splitter )
580 {
581 // The panel will have its own min size which the splitter
582 // should respect
583 //if (m_NavigPan)
584 // m_Splitter->SetMinimumPaneSize(m_NavigPan->GetBestSize().x);
585 //else
586 m_Splitter->SetMinimumPaneSize(20);
587
588 if ( m_Cfg.navig_on )
589 {
590 m_NavigPan->Show();
591 m_Splitter->SplitVertically(m_NavigPan, m_HtmlWin, m_Cfg.sashpos);
592 }
593 else
594 {
595 m_NavigPan->Show(false);
596 m_Splitter->Initialize(m_HtmlWin);
597 }
598 }
599
600 // Reduce flicker by updating the splitter pane sizes before the
601 // frame is shown
602 wxSizeEvent sizeEvent(GetSize(), GetId());
603 GetEventHandler()->ProcessEvent(sizeEvent);
604
605 if (m_Splitter)
606 m_Splitter->UpdateSize();
607
608 return true;
609 }
610
611 wxHtmlHelpWindow::~wxHtmlHelpWindow()
612 {
613 if ( m_helpController )
614 m_helpController->SetHelpWindow(NULL);
615
616 delete m_mergedIndex;
617
618 // PopEventHandler(); // wxhtmlhelpcontroller (not any more!)
619 if (m_DataCreated)
620 delete m_Data;
621 if (m_NormalFonts) delete m_NormalFonts;
622 if (m_FixedFonts) delete m_FixedFonts;
623 if (m_PagesHash)
624 {
625 WX_CLEAR_HASH_TABLE(*m_PagesHash);
626 delete m_PagesHash;
627 }
628 #if wxUSE_PRINTING_ARCHITECTURE
629 if (m_Printer) delete m_Printer;
630 #endif
631 }
632
633 void wxHtmlHelpWindow::SetController(wxHtmlHelpController* controller)
634 {
635 if (m_DataCreated)
636 delete m_Data;
637 m_helpController = controller;
638 m_Data = controller->GetHelpData();
639 m_DataCreated = false;
640 }
641
642 #if wxUSE_TOOLBAR
643 void wxHtmlHelpWindow::AddToolbarButtons(wxToolBar *toolBar, int style)
644 {
645 wxBitmap wpanelBitmap =
646 wxArtProvider::GetBitmap(wxART_HELP_SIDE_PANEL, wxART_TOOLBAR);
647 wxBitmap wbackBitmap =
648 wxArtProvider::GetBitmap(wxART_GO_BACK, wxART_TOOLBAR);
649 wxBitmap wforwardBitmap =
650 wxArtProvider::GetBitmap(wxART_GO_FORWARD, wxART_TOOLBAR);
651 wxBitmap wupnodeBitmap =
652 wxArtProvider::GetBitmap(wxART_GO_TO_PARENT, wxART_TOOLBAR);
653 wxBitmap wupBitmap =
654 wxArtProvider::GetBitmap(wxART_GO_UP, wxART_TOOLBAR);
655 wxBitmap wdownBitmap =
656 wxArtProvider::GetBitmap(wxART_GO_DOWN, wxART_TOOLBAR);
657 wxBitmap wopenBitmap =
658 wxArtProvider::GetBitmap(wxART_FILE_OPEN, wxART_TOOLBAR);
659 wxBitmap wprintBitmap =
660 wxArtProvider::GetBitmap(wxART_PRINT, wxART_TOOLBAR);
661 wxBitmap woptionsBitmap =
662 wxArtProvider::GetBitmap(wxART_HELP_SETTINGS, wxART_TOOLBAR);
663
664 wxASSERT_MSG( (wpanelBitmap.IsOk() && wbackBitmap.IsOk() &&
665 wforwardBitmap.IsOk() && wupnodeBitmap.IsOk() &&
666 wupBitmap.IsOk() && wdownBitmap.IsOk() &&
667 wopenBitmap.IsOk() && wprintBitmap.IsOk() &&
668 woptionsBitmap.IsOk()),
669 wxT("One or more HTML help frame toolbar bitmap could not be loaded.")) ;
670
671
672 toolBar->AddTool(wxID_HTML_PANEL, wxEmptyString, wpanelBitmap, _("Show/hide navigation panel"));
673 toolBar->AddSeparator();
674 toolBar->AddTool(wxID_HTML_BACK, wxEmptyString, wbackBitmap, _("Go back"));
675 toolBar->AddTool(wxID_HTML_FORWARD, wxEmptyString, wforwardBitmap, _("Go forward"));
676 toolBar->AddSeparator();
677 toolBar->AddTool(wxID_HTML_UPNODE, wxEmptyString, wupnodeBitmap, _("Go one level up in document hierarchy"));
678 toolBar->AddTool(wxID_HTML_UP, wxEmptyString, wupBitmap, _("Previous page"));
679 toolBar->AddTool(wxID_HTML_DOWN, wxEmptyString, wdownBitmap, _("Next page"));
680
681 if ((style & wxHF_PRINT) || (style & wxHF_OPEN_FILES))
682 toolBar->AddSeparator();
683
684 if (style & wxHF_OPEN_FILES)
685 toolBar->AddTool(wxID_HTML_OPENFILE, wxEmptyString, wopenBitmap, _("Open HTML document"));
686
687 #if wxUSE_PRINTING_ARCHITECTURE
688 if (style & wxHF_PRINT)
689 toolBar->AddTool(wxID_HTML_PRINT, wxEmptyString, wprintBitmap, _("Print this page"));
690 #endif
691
692 toolBar->AddSeparator();
693 toolBar->AddTool(wxID_HTML_OPTIONS, wxEmptyString, woptionsBitmap, _("Display options dialog"));
694
695 // Allow application to add custom buttons
696 wxHtmlHelpFrame* parentFrame = wxDynamicCast(GetParent(), wxHtmlHelpFrame);
697 wxHtmlHelpDialog* parentDialog = wxDynamicCast(GetParent(), wxHtmlHelpDialog);
698 if (parentFrame)
699 parentFrame->AddToolbarButtons(toolBar, style);
700 if (parentDialog)
701 parentDialog->AddToolbarButtons(toolBar, style);
702 }
703 #endif //wxUSE_TOOLBAR
704
705
706 bool wxHtmlHelpWindow::Display(const wxString& x)
707 {
708 wxString url = m_Data->FindPageByName(x);
709 if (!url.empty())
710 {
711 m_HtmlWin->LoadPage(url);
712 return true;
713 }
714
715 return false;
716 }
717
718 bool wxHtmlHelpWindow::Display(const int id)
719 {
720 wxString url = m_Data->FindPageById(id);
721 if (!url.empty())
722 {
723 m_HtmlWin->LoadPage(url);
724 return true;
725 }
726
727 return false;
728 }
729
730 bool wxHtmlHelpWindow::DisplayContents()
731 {
732 if (! m_ContentsBox)
733 return false;
734
735 if (!m_Splitter->IsSplit())
736 {
737 m_NavigPan->Show();
738 m_HtmlWin->Show();
739 m_Splitter->SplitVertically(m_NavigPan, m_HtmlWin, m_Cfg.sashpos);
740 m_Cfg.navig_on = true;
741 }
742
743 m_NavigNotebook->SetSelection(m_ContentsPage);
744
745 if (m_Data->GetBookRecArray().GetCount() > 0)
746 {
747 wxHtmlBookRecord& book = m_Data->GetBookRecArray()[0];
748 if (!book.GetStart().empty())
749 m_HtmlWin->LoadPage(book.GetFullPath(book.GetStart()));
750 }
751
752 return true;
753 }
754
755 bool wxHtmlHelpWindow::DisplayIndex()
756 {
757 if (! m_IndexList)
758 return false;
759
760 if (!m_Splitter->IsSplit())
761 {
762 m_NavigPan->Show();
763 m_HtmlWin->Show();
764 m_Splitter->SplitVertically(m_NavigPan, m_HtmlWin, m_Cfg.sashpos);
765 }
766
767 m_NavigNotebook->SetSelection(m_IndexPage);
768
769 if (m_Data->GetBookRecArray().GetCount() > 0)
770 {
771 wxHtmlBookRecord& book = m_Data->GetBookRecArray()[0];
772 if (!book.GetStart().empty())
773 m_HtmlWin->LoadPage(book.GetFullPath(book.GetStart()));
774 }
775
776 return true;
777 }
778
779 void wxHtmlHelpWindow::DisplayIndexItem(const wxHtmlHelpMergedIndexItem *it)
780 {
781 if (it->items.size() == 1)
782 {
783 if (!it->items[0]->page.empty())
784 {
785 m_HtmlWin->LoadPage(it->items[0]->GetFullPath());
786 }
787 }
788 else
789 {
790 wxBusyCursor busy_cursor;
791
792 // more pages associated with this index item -- let the user choose
793 // which one she/he wants from a list:
794 wxArrayString arr;
795 size_t len = it->items.size();
796 for (size_t i = 0; i < len; i++)
797 {
798 wxString page = it->items[i]->page;
799 // try to find page's title in contents:
800 const wxHtmlHelpDataItems& contents = m_Data->GetContentsArray();
801 size_t clen = contents.size();
802 for (size_t j = 0; j < clen; j++)
803 {
804 if (contents[j].page == page)
805 {
806 page = contents[j].name;
807 break;
808 }
809 }
810 arr.push_back(page);
811 }
812
813 wxSingleChoiceDialog dlg(this,
814 _("Please choose the page to display:"),
815 _("Help Topics"),
816 arr,
817 (void**)NULL, // No client data
818 wxCHOICEDLG_STYLE & ~wxCENTRE);
819 if (dlg.ShowModal() == wxID_OK)
820 {
821 m_HtmlWin->LoadPage(it->items[dlg.GetSelection()]->GetFullPath());
822 }
823 }
824 }
825
826 bool wxHtmlHelpWindow::KeywordSearch(const wxString& keyword,
827 wxHelpSearchMode mode)
828 {
829 wxCHECK_MSG( !keyword.empty(), false, "must have a non empty keyword" );
830
831 if (mode == wxHELP_SEARCH_ALL)
832 {
833 if ( !(m_SearchList &&
834 m_SearchButton && m_SearchText && m_SearchChoice) )
835 return false;
836 }
837 else if (mode == wxHELP_SEARCH_INDEX)
838 {
839 if ( !(m_IndexList &&
840 m_IndexButton && m_IndexButtonAll && m_IndexText) )
841 return false;
842 }
843
844 int foundcnt = 0;
845 wxString foundstr;
846 wxString book = wxEmptyString;
847
848 if (!m_Splitter->IsSplit())
849 {
850 m_NavigPan->Show();
851 m_HtmlWin->Show();
852 m_Splitter->SplitVertically(m_NavigPan, m_HtmlWin, m_Cfg.sashpos);
853 }
854
855 if (mode == wxHELP_SEARCH_ALL)
856 {
857 m_NavigNotebook->SetSelection(m_SearchPage);
858 m_SearchList->Clear();
859 m_SearchText->SetValue(keyword);
860 m_SearchButton->Disable();
861
862 if (m_SearchChoice->GetSelection() != 0)
863 book = m_SearchChoice->GetStringSelection();
864
865 wxHtmlSearchStatus status(m_Data, keyword,
866 m_SearchCaseSensitive->GetValue(),
867 m_SearchWholeWords->GetValue(),
868 book);
869
870 #if wxUSE_PROGRESSDLG
871 wxProgressDialog progress(_("Searching..."),
872 _("No matching page found yet"),
873 status.GetMaxIndex(), this,
874 wxPD_APP_MODAL | wxPD_CAN_ABORT | wxPD_AUTO_HIDE);
875 #endif
876
877 int curi;
878 while (status.IsActive())
879 {
880 curi = status.GetCurIndex();
881 if (curi % 32 == 0
882 #if wxUSE_PROGRESSDLG
883 && !progress.Update(curi)
884 #endif
885 )
886 break;
887 if (status.Search())
888 {
889 foundstr.Printf(_("Found %i matches"), ++foundcnt);
890 #if wxUSE_PROGRESSDLG
891 progress.Update(status.GetCurIndex(), foundstr);
892 #endif
893 m_SearchList->Append(status.GetName(), (void*)status.GetCurItem());
894 }
895 }
896
897 m_SearchButton->Enable();
898 m_SearchText->SetSelection(0, keyword.length());
899 m_SearchText->SetFocus();
900 }
901 else if (mode == wxHELP_SEARCH_INDEX)
902 {
903 m_NavigNotebook->SetSelection(m_IndexPage);
904 m_IndexList->Clear();
905 m_IndexButton->Disable();
906 m_IndexButtonAll->Disable();
907 m_IndexText->SetValue(keyword);
908
909 DoIndexFind();
910 m_IndexButton->Enable();
911 m_IndexButtonAll->Enable();
912 foundcnt = m_IndexList->GetCount();
913 }
914
915 if (foundcnt)
916 {
917 switch ( mode )
918 {
919 default:
920 wxFAIL_MSG( wxT("unknown help search mode") );
921 // fall back
922
923 case wxHELP_SEARCH_ALL:
924 {
925 wxHtmlHelpDataItem *it =
926 (wxHtmlHelpDataItem*) m_SearchList->GetClientData(0);
927 if (it)
928 {
929 m_HtmlWin->LoadPage(it->GetFullPath());
930 }
931 break;
932 }
933
934 case wxHELP_SEARCH_INDEX:
935 {
936 wxHtmlHelpMergedIndexItem* it =
937 (wxHtmlHelpMergedIndexItem*) m_IndexList->GetClientData(0);
938 if (it)
939 DisplayIndexItem(it);
940 break;
941 }
942 }
943
944 }
945
946 return foundcnt > 0;
947 }
948
949 void wxHtmlHelpWindow::CreateContents()
950 {
951 if (! m_ContentsBox)
952 return ;
953
954 if (m_PagesHash)
955 {
956 WX_CLEAR_HASH_TABLE(*m_PagesHash);
957 delete m_PagesHash;
958 }
959
960 const wxHtmlHelpDataItems& contents = m_Data->GetContentsArray();
961
962 size_t cnt = contents.size();
963
964 m_PagesHash = new wxHashTable(wxKEY_STRING, 2 * cnt);
965
966 const int MAX_ROOTS = 64;
967 wxTreeItemId roots[MAX_ROOTS];
968 // VS: this array holds information about whether we've set item icon at
969 // given level. This is necessary because m_Data has a flat structure
970 // and there's no way of recognizing if some item has subitems or not.
971 // We set the icon later: when we find an item with level=n, we know
972 // that the last item with level=n-1 was afolder with subitems, so we
973 // set its icon accordingly
974 bool imaged[MAX_ROOTS];
975 m_ContentsBox->DeleteAllItems();
976
977 roots[0] = m_ContentsBox->AddRoot(_("(Help)"));
978 imaged[0] = true;
979
980 for (size_t i = 0; i < cnt; i++)
981 {
982 wxHtmlHelpDataItem *it = &contents[i];
983 // Handle books:
984 if (it->level == 0)
985 {
986 if (m_hfStyle & wxHF_MERGE_BOOKS)
987 // VS: we don't want book nodes, books' content should
988 // appear under tree's root. This line will create a "fake"
989 // record about book node so that the rest of this look
990 // will believe there really _is_ a book node and will
991 // behave correctly.
992 roots[1] = roots[0];
993 else
994 {
995 roots[1] = m_ContentsBox->AppendItem(roots[0],
996 it->name, IMG_Book, -1,
997 new wxHtmlHelpTreeItemData(i));
998 m_ContentsBox->SetItemBold(roots[1], true);
999 }
1000 imaged[1] = true;
1001 }
1002 // ...and their contents:
1003 else
1004 {
1005 roots[it->level + 1] = m_ContentsBox->AppendItem(
1006 roots[it->level], it->name, IMG_Page,
1007 -1, new wxHtmlHelpTreeItemData(i));
1008 imaged[it->level + 1] = false;
1009 }
1010
1011 m_PagesHash->Put(it->GetFullPath(),
1012 new wxHtmlHelpHashData(i, roots[it->level + 1]));
1013
1014 // Set the icon for the node one level up in the hierarchy,
1015 // unless already done (see comment above imaged[] declaration)
1016 if (!imaged[it->level])
1017 {
1018 int image = IMG_Folder;
1019 if (m_hfStyle & wxHF_ICONS_BOOK)
1020 image = IMG_Book;
1021 else if (m_hfStyle & wxHF_ICONS_BOOK_CHAPTER)
1022 image = (it->level == 1) ? IMG_Book : IMG_Folder;
1023 m_ContentsBox->SetItemImage(roots[it->level], image);
1024 m_ContentsBox->SetItemImage(roots[it->level], image,
1025 wxTreeItemIcon_Selected);
1026 imaged[it->level] = true;
1027 }
1028 }
1029
1030 m_ContentsBox->SetMinSize(wxSize(CONTENT_TREE_INDEX_MIN_WIDTH,
1031 m_ContentsBox->GetMinHeight()));
1032 }
1033
1034 void wxHtmlHelpWindow::CreateIndex()
1035 {
1036 if (! m_IndexList)
1037 return ;
1038
1039 m_IndexList->Clear();
1040
1041 unsigned long cnt = m_mergedIndex->size();
1042
1043 wxString cnttext;
1044 if (cnt > INDEX_IS_SMALL)
1045 cnttext.Printf(_("%d of %lu"), 0, cnt);
1046 else
1047 cnttext.Printf(_("%lu of %lu"), cnt, cnt);
1048 m_IndexCountInfo->SetLabel(cnttext);
1049 if (cnt > INDEX_IS_SMALL)
1050 return;
1051
1052 for (size_t i = 0; i < cnt; i++)
1053 m_IndexList->Append((*m_mergedIndex)[i].name,
1054 (char*)(&(*m_mergedIndex)[i]));
1055
1056 m_IndexList->SetMinSize(wxSize(CONTENT_TREE_INDEX_MIN_WIDTH,
1057 m_IndexList->GetMinHeight()));
1058 }
1059
1060 void wxHtmlHelpWindow::CreateSearch()
1061 {
1062 if (! (m_SearchList && m_SearchChoice))
1063 return ;
1064 m_SearchList->Clear();
1065 m_SearchChoice->Clear();
1066 m_SearchChoice->Append(_("Search in all books"));
1067 const wxHtmlBookRecArray& bookrec = m_Data->GetBookRecArray();
1068 int i, cnt = bookrec.GetCount();
1069 for (i = 0; i < cnt; i++)
1070 m_SearchChoice->Append(bookrec[i].GetTitle());
1071 m_SearchChoice->SetSelection(0);
1072 }
1073
1074 void wxHtmlHelpWindow::RefreshLists()
1075 {
1076 // Update m_mergedIndex:
1077 UpdateMergedIndex();
1078 // Update the controls
1079 CreateContents();
1080 CreateIndex();
1081 CreateSearch();
1082 }
1083
1084 #if wxUSE_CONFIG
1085 void wxHtmlHelpWindow::ReadCustomization(wxConfigBase *cfg, const wxString& path)
1086 {
1087 wxString oldpath;
1088 wxString tmp;
1089
1090 if (path != wxEmptyString)
1091 {
1092 oldpath = cfg->GetPath();
1093 cfg->SetPath(wxT("/") + path);
1094 }
1095
1096 m_Cfg.navig_on = cfg->Read(wxT("hcNavigPanel"), m_Cfg.navig_on) != 0;
1097 m_Cfg.sashpos = cfg->Read(wxT("hcSashPos"), m_Cfg.sashpos);
1098 m_Cfg.x = cfg->Read(wxT("hcX"), m_Cfg.x);
1099 m_Cfg.y = cfg->Read(wxT("hcY"), m_Cfg.y);
1100 m_Cfg.w = cfg->Read(wxT("hcW"), m_Cfg.w);
1101 m_Cfg.h = cfg->Read(wxT("hcH"), m_Cfg.h);
1102
1103 m_FixedFace = cfg->Read(wxT("hcFixedFace"), m_FixedFace);
1104 m_NormalFace = cfg->Read(wxT("hcNormalFace"), m_NormalFace);
1105 m_FontSize = cfg->Read(wxT("hcBaseFontSize"), m_FontSize);
1106
1107 {
1108 int i;
1109 int cnt;
1110 wxString val, s;
1111
1112 cnt = cfg->Read(wxT("hcBookmarksCnt"), 0L);
1113 if (cnt != 0)
1114 {
1115 m_BookmarksNames.Clear();
1116 m_BookmarksPages.Clear();
1117 if (m_Bookmarks)
1118 {
1119 m_Bookmarks->Clear();
1120 m_Bookmarks->Append(_("(bookmarks)"));
1121 }
1122
1123 for (i = 0; i < cnt; i++)
1124 {
1125 val.Printf(wxT("hcBookmark_%i"), i);
1126 s = cfg->Read(val);
1127 m_BookmarksNames.Add(s);
1128 if (m_Bookmarks) m_Bookmarks->Append(s);
1129 val.Printf(wxT("hcBookmark_%i_url"), i);
1130 s = cfg->Read(val);
1131 m_BookmarksPages.Add(s);
1132 }
1133 }
1134 }
1135
1136 if (m_HtmlWin)
1137 m_HtmlWin->ReadCustomization(cfg);
1138
1139 if (path != wxEmptyString)
1140 cfg->SetPath(oldpath);
1141 }
1142
1143 void wxHtmlHelpWindow::WriteCustomization(wxConfigBase *cfg, const wxString& path)
1144 {
1145 wxString oldpath;
1146 wxString tmp;
1147
1148 if (path != wxEmptyString)
1149 {
1150 oldpath = cfg->GetPath();
1151 cfg->SetPath(wxT("/") + path);
1152 }
1153
1154 cfg->Write(wxT("hcNavigPanel"), m_Cfg.navig_on);
1155 cfg->Write(wxT("hcSashPos"), (long)m_Cfg.sashpos);
1156
1157 // Don't write if iconized as this would make the window
1158 // disappear next time it is shown!
1159 cfg->Write(wxT("hcX"), (long)m_Cfg.x);
1160 cfg->Write(wxT("hcY"), (long)m_Cfg.y);
1161 cfg->Write(wxT("hcW"), (long)m_Cfg.w);
1162 cfg->Write(wxT("hcH"), (long)m_Cfg.h);
1163
1164 cfg->Write(wxT("hcFixedFace"), m_FixedFace);
1165 cfg->Write(wxT("hcNormalFace"), m_NormalFace);
1166 cfg->Write(wxT("hcBaseFontSize"), (long)m_FontSize);
1167
1168 if (m_Bookmarks)
1169 {
1170 int i;
1171 int cnt = m_BookmarksNames.GetCount();
1172 wxString val;
1173
1174 cfg->Write(wxT("hcBookmarksCnt"), (long)cnt);
1175 for (i = 0; i < cnt; i++)
1176 {
1177 val.Printf(wxT("hcBookmark_%i"), i);
1178 cfg->Write(val, m_BookmarksNames[i]);
1179 val.Printf(wxT("hcBookmark_%i_url"), i);
1180 cfg->Write(val, m_BookmarksPages[i]);
1181 }
1182 }
1183
1184 if (m_HtmlWin)
1185 m_HtmlWin->WriteCustomization(cfg);
1186
1187 if (path != wxEmptyString)
1188 cfg->SetPath(oldpath);
1189 }
1190 #endif // wxUSE_CONFIG
1191
1192 static void SetFontsToHtmlWin(wxHtmlWindow *win, const wxString& scalf, const wxString& fixf, int size)
1193 {
1194 int f_sizes[7];
1195 f_sizes[0] = int(size * 0.6);
1196 f_sizes[1] = int(size * 0.8);
1197 f_sizes[2] = size;
1198 f_sizes[3] = int(size * 1.2);
1199 f_sizes[4] = int(size * 1.4);
1200 f_sizes[5] = int(size * 1.6);
1201 f_sizes[6] = int(size * 1.8);
1202
1203 win->SetFonts(scalf, fixf, f_sizes);
1204 }
1205
1206 class wxHtmlHelpWindowOptionsDialog : public wxDialog
1207 {
1208 public:
1209 wxComboBox *NormalFont, *FixedFont;
1210 wxSpinCtrl *FontSize;
1211 wxHtmlWindow *TestWin;
1212
1213 wxHtmlHelpWindowOptionsDialog(wxWindow *parent)
1214 : wxDialog(parent, wxID_ANY, wxString(_("Help Browser Options")))
1215 {
1216 wxBoxSizer *topsizer = new wxBoxSizer(wxVERTICAL);
1217 wxFlexGridSizer *sizer = new wxFlexGridSizer(2, 3, 2, 5);
1218
1219 sizer->Add(new wxStaticText(this, wxID_ANY, _("Normal font:")));
1220 sizer->Add(new wxStaticText(this, wxID_ANY, _("Fixed font:")));
1221 sizer->Add(new wxStaticText(this, wxID_ANY, _("Font size:")));
1222
1223 sizer->Add(NormalFont = new wxComboBox(this, wxID_ANY, wxEmptyString, wxDefaultPosition,
1224 wxSize(200, wxDefaultCoord),
1225 0, NULL, wxCB_DROPDOWN | wxCB_READONLY));
1226
1227 sizer->Add(FixedFont = new wxComboBox(this, wxID_ANY, wxEmptyString, wxDefaultPosition,
1228 wxSize(200, wxDefaultCoord),
1229 0, NULL, wxCB_DROPDOWN | wxCB_READONLY));
1230
1231 sizer->Add(FontSize = new wxSpinCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition,
1232 wxDefaultSize, wxSP_ARROW_KEYS, 2, 100, 2, wxT("wxSpinCtrl")));
1233
1234 topsizer->Add(sizer, 0, wxLEFT|wxRIGHT|wxTOP, 10);
1235
1236 topsizer->Add(new wxStaticText(this, wxID_ANY, _("Preview:")),
1237 0, wxLEFT | wxTOP, 10);
1238
1239 topsizer->AddSpacer(5);
1240
1241 topsizer->Add(TestWin = new wxHtmlWindow(this, wxID_ANY, wxDefaultPosition, wxSize(20, 150),
1242 wxHW_SCROLLBAR_AUTO|wxBORDER_THEME),
1243 1, wxEXPAND | wxLEFT | wxRIGHT, 10);
1244
1245 wxBoxSizer *sizer2 = new wxBoxSizer(wxHORIZONTAL);
1246 wxButton *ok;
1247 sizer2->Add(ok = new wxButton(this, wxID_OK), 0, wxALL, 10);
1248 ok->SetDefault();
1249 sizer2->Add(new wxButton(this, wxID_CANCEL), 0, wxALL, 10);
1250 topsizer->Add(sizer2, 0, wxALIGN_RIGHT);
1251
1252 SetSizer(topsizer);
1253 topsizer->Fit(this);
1254 Centre(wxBOTH);
1255 }
1256
1257
1258 void UpdateTestWin()
1259 {
1260 wxBusyCursor bcur;
1261 SetFontsToHtmlWin(TestWin,
1262 NormalFont->GetStringSelection(),
1263 FixedFont->GetStringSelection(),
1264 FontSize->GetValue());
1265
1266 wxString content(_("font size"));
1267
1268 content = wxT("<font size=-2>") + content + wxT(" -2</font><br>")
1269 wxT("<font size=-1>") + content + wxT(" -1</font><br>")
1270 wxT("<font size=+0>") + content + wxT(" +0</font><br>")
1271 wxT("<font size=+1>") + content + wxT(" +1</font><br>")
1272 wxT("<font size=+2>") + content + wxT(" +2</font><br>")
1273 wxT("<font size=+3>") + content + wxT(" +3</font><br>")
1274 wxT("<font size=+4>") + content + wxT(" +4</font><br>") ;
1275
1276 content = wxString( wxT("<html><body><table><tr><td>") ) +
1277 _("Normal face<br>and <u>underlined</u>. ") +
1278 _("<i>Italic face.</i> ") +
1279 _("<b>Bold face.</b> ") +
1280 _("<b><i>Bold italic face.</i></b><br>") +
1281 content +
1282 wxString( wxT("</td><td><tt>") ) +
1283 _("Fixed size face.<br> <b>bold</b> <i>italic</i> ") +
1284 _("<b><i>bold italic <u>underlined</u></i></b><br>") +
1285 content +
1286 wxT("</tt></td></tr></table></body></html>");
1287
1288 TestWin->SetPage( content );
1289 }
1290
1291 void OnUpdate(wxCommandEvent& WXUNUSED(event))
1292 {
1293 UpdateTestWin();
1294 }
1295 void OnUpdateSpin(wxSpinEvent& WXUNUSED(event))
1296 {
1297 UpdateTestWin();
1298 }
1299
1300 DECLARE_EVENT_TABLE()
1301 wxDECLARE_NO_COPY_CLASS(wxHtmlHelpWindowOptionsDialog);
1302 };
1303
1304 BEGIN_EVENT_TABLE(wxHtmlHelpWindowOptionsDialog, wxDialog)
1305 EVT_COMBOBOX(wxID_ANY, wxHtmlHelpWindowOptionsDialog::OnUpdate)
1306 EVT_SPINCTRL(wxID_ANY, wxHtmlHelpWindowOptionsDialog::OnUpdateSpin)
1307 END_EVENT_TABLE()
1308
1309 void wxHtmlHelpWindow::OptionsDialog()
1310 {
1311 wxHtmlHelpWindowOptionsDialog dlg(this);
1312 unsigned i;
1313
1314 if (m_NormalFonts == NULL)
1315 {
1316 m_NormalFonts = new wxArrayString(wxFontEnumerator::GetFacenames());
1317 m_NormalFonts->Sort(); // ascending sort
1318 }
1319 if (m_FixedFonts == NULL)
1320 {
1321 m_FixedFonts = new wxArrayString(
1322 wxFontEnumerator::GetFacenames(wxFONTENCODING_SYSTEM,
1323 true /*enum fixed width only*/));
1324 m_FixedFonts->Sort(); // ascending sort
1325 }
1326
1327 // VS: We want to show the font that is actually used by wxHtmlWindow.
1328 // If customization dialog wasn't used yet, facenames are empty and
1329 // wxHtmlWindow uses default fonts -- let's find out what they
1330 // are so that we can pass them to the dialog:
1331 if (m_NormalFace.empty())
1332 {
1333 wxFont fnt(m_FontSize, wxSWISS, wxNORMAL, wxNORMAL, false);
1334 m_NormalFace = fnt.GetFaceName();
1335 }
1336 if (m_FixedFace.empty())
1337 {
1338 wxFont fnt(m_FontSize, wxMODERN, wxNORMAL, wxNORMAL, false);
1339 m_FixedFace = fnt.GetFaceName();
1340 }
1341
1342 for (i = 0; i < m_NormalFonts->GetCount(); i++)
1343 dlg.NormalFont->Append((*m_NormalFonts)[i]);
1344 for (i = 0; i < m_FixedFonts->GetCount(); i++)
1345 dlg.FixedFont->Append((*m_FixedFonts)[i]);
1346 if (!m_NormalFace.empty())
1347 dlg.NormalFont->SetStringSelection(m_NormalFace);
1348 else
1349 dlg.NormalFont->SetSelection(0);
1350 if (!m_FixedFace.empty())
1351 dlg.FixedFont->SetStringSelection(m_FixedFace);
1352 else
1353 dlg.FixedFont->SetSelection(0);
1354 dlg.FontSize->SetValue(m_FontSize);
1355 dlg.UpdateTestWin();
1356
1357 if (dlg.ShowModal() == wxID_OK)
1358 {
1359 m_NormalFace = dlg.NormalFont->GetStringSelection();
1360 m_FixedFace = dlg.FixedFont->GetStringSelection();
1361 m_FontSize = dlg.FontSize->GetValue();
1362 SetFontsToHtmlWin(m_HtmlWin, m_NormalFace, m_FixedFace, m_FontSize);
1363 }
1364 }
1365
1366 void wxHtmlHelpWindow::NotifyPageChanged()
1367 {
1368 if (m_UpdateContents && m_PagesHash)
1369 {
1370 wxString page = wxHtmlHelpHtmlWindow::GetOpenedPageWithAnchor(m_HtmlWin);
1371 wxHtmlHelpHashData *ha = NULL;
1372 if (!page.empty())
1373 ha = (wxHtmlHelpHashData*) m_PagesHash->Get(page);
1374
1375 if (ha)
1376 {
1377 bool olduc = m_UpdateContents;
1378 m_UpdateContents = false;
1379 m_ContentsBox->SelectItem(ha->m_Id);
1380 m_ContentsBox->EnsureVisible(ha->m_Id);
1381 m_UpdateContents = olduc;
1382 }
1383 }
1384 }
1385
1386 /*
1387 EVENT HANDLING :
1388 */
1389
1390
1391 void wxHtmlHelpWindow::OnToolbar(wxCommandEvent& event)
1392 {
1393 switch (event.GetId())
1394 {
1395 case wxID_HTML_BACK :
1396 m_HtmlWin->HistoryBack();
1397 break;
1398
1399 case wxID_HTML_FORWARD :
1400 m_HtmlWin->HistoryForward();
1401 break;
1402
1403 case wxID_HTML_UP :
1404 if (m_PagesHash)
1405 {
1406 wxString page = wxHtmlHelpHtmlWindow::GetOpenedPageWithAnchor(m_HtmlWin);
1407 wxHtmlHelpHashData *ha = NULL;
1408 if (!page.empty())
1409 ha = (wxHtmlHelpHashData*) m_PagesHash->Get(page);
1410 if (ha && ha->m_Index > 0)
1411 {
1412 const wxHtmlHelpDataItem& it = m_Data->GetContentsArray()[ha->m_Index - 1];
1413 if (!it.page.empty())
1414 {
1415 m_HtmlWin->LoadPage(it.GetFullPath());
1416 }
1417 }
1418 }
1419 break;
1420
1421 case wxID_HTML_UPNODE :
1422 if (m_PagesHash)
1423 {
1424 wxString page = wxHtmlHelpHtmlWindow::GetOpenedPageWithAnchor(m_HtmlWin);
1425 wxHtmlHelpHashData *ha = NULL;
1426 if (!page.empty())
1427 ha = (wxHtmlHelpHashData*) m_PagesHash->Get(page);
1428 if (ha && ha->m_Index > 0)
1429 {
1430 int level =
1431 m_Data->GetContentsArray()[ha->m_Index].level - 1;
1432 int ind = ha->m_Index - 1;
1433
1434 const wxHtmlHelpDataItem *it =
1435 &m_Data->GetContentsArray()[ind];
1436 while (ind >= 0 && it->level != level)
1437 {
1438 ind--;
1439 it = &m_Data->GetContentsArray()[ind];
1440 }
1441 if (ind >= 0)
1442 {
1443 if (!it->page.empty())
1444 m_HtmlWin->LoadPage(it->GetFullPath());
1445 }
1446 }
1447 }
1448 break;
1449
1450 case wxID_HTML_DOWN :
1451 if (m_PagesHash)
1452 {
1453 wxString page = wxHtmlHelpHtmlWindow::GetOpenedPageWithAnchor(m_HtmlWin);
1454 wxHtmlHelpHashData *ha = NULL;
1455 if (!page.empty())
1456 ha = (wxHtmlHelpHashData*) m_PagesHash->Get(page);
1457
1458 const wxHtmlHelpDataItems& contents = m_Data->GetContentsArray();
1459 if (ha && ha->m_Index < (int)contents.size() - 1)
1460 {
1461 size_t idx = ha->m_Index + 1;
1462
1463 while (contents[idx].GetFullPath() == page) idx++;
1464
1465 if (!contents[idx].page.empty())
1466 m_HtmlWin->LoadPage(contents[idx].GetFullPath());
1467 }
1468 }
1469 break;
1470
1471 case wxID_HTML_PANEL :
1472 {
1473 if (! (m_Splitter && m_NavigPan))
1474 return ;
1475 if (m_Splitter->IsSplit())
1476 {
1477 m_Cfg.sashpos = m_Splitter->GetSashPosition();
1478 m_Splitter->Unsplit(m_NavigPan);
1479 m_Cfg.navig_on = false;
1480 }
1481 else
1482 {
1483 m_NavigPan->Show();
1484 m_HtmlWin->Show();
1485 m_Splitter->SplitVertically(m_NavigPan, m_HtmlWin, m_Cfg.sashpos);
1486 m_Cfg.navig_on = true;
1487 }
1488 }
1489 break;
1490
1491 case wxID_HTML_OPTIONS :
1492 OptionsDialog();
1493 break;
1494
1495 case wxID_HTML_BOOKMARKSADD :
1496 {
1497 wxString item;
1498 wxString url;
1499
1500 item = m_HtmlWin->GetOpenedPageTitle();
1501 url = m_HtmlWin->GetOpenedPage();
1502 if (item == wxEmptyString)
1503 item = url.AfterLast(wxT('/'));
1504 if (m_BookmarksPages.Index(url) == wxNOT_FOUND)
1505 {
1506 m_Bookmarks->Append(item);
1507 m_BookmarksNames.Add(item);
1508 m_BookmarksPages.Add(url);
1509 }
1510 }
1511 break;
1512
1513 case wxID_HTML_BOOKMARKSREMOVE :
1514 {
1515 wxString item;
1516 int pos;
1517
1518 item = m_Bookmarks->GetStringSelection();
1519 pos = m_BookmarksNames.Index(item);
1520 if (pos != wxNOT_FOUND)
1521 {
1522 m_BookmarksNames.RemoveAt(pos);
1523 m_BookmarksPages.RemoveAt(pos);
1524 pos = m_Bookmarks->GetSelection();
1525 wxASSERT_MSG( pos != wxNOT_FOUND , wxT("Unknown bookmark position") ) ;
1526 m_Bookmarks->Delete((unsigned int)pos);
1527 }
1528 }
1529 break;
1530
1531 #if wxUSE_PRINTING_ARCHITECTURE
1532 case wxID_HTML_PRINT :
1533 {
1534 if (m_Printer == NULL)
1535 m_Printer = new wxHtmlEasyPrinting(_("Help Printing"), this);
1536 if (!m_HtmlWin->GetOpenedPage())
1537 {
1538 wxLogWarning(_("Cannot print empty page."));
1539 }
1540 else
1541 {
1542 m_Printer->PrintFile(m_HtmlWin->GetOpenedPage());
1543 }
1544 }
1545 break;
1546 #endif
1547
1548 case wxID_HTML_OPENFILE :
1549 {
1550 wxString filemask = wxString(
1551 _("HTML files (*.html;*.htm)|*.html;*.htm|")) +
1552 _("Help books (*.htb)|*.htb|Help books (*.zip)|*.zip|") +
1553 _("HTML Help Project (*.hhp)|*.hhp|") +
1554 #if wxUSE_LIBMSPACK
1555 _("Compressed HTML Help file (*.chm)|*.chm|") +
1556 #endif
1557 wxALL_FILES;
1558 wxString s = wxFileSelector(_("Open HTML document"),
1559 wxEmptyString,
1560 wxEmptyString,
1561 wxEmptyString,
1562 filemask,
1563 wxFD_OPEN | wxFD_FILE_MUST_EXIST,
1564 this);
1565 if (!s.empty())
1566 {
1567 wxString ext = s.Right(4).Lower();
1568 if (ext == wxT(".zip") || ext == wxT(".htb") ||
1569 #if wxUSE_LIBMSPACK
1570 ext == wxT(".chm") ||
1571 #endif
1572 ext == wxT(".hhp"))
1573 {
1574 wxBusyCursor bcur;
1575 m_Data->AddBook(s);
1576 RefreshLists();
1577 }
1578 else
1579 m_HtmlWin->LoadPage(s);
1580 }
1581 }
1582 break;
1583 }
1584 }
1585
1586 void wxHtmlHelpWindow::OnContentsSel(wxTreeEvent& event)
1587 {
1588 wxHtmlHelpTreeItemData *pg;
1589
1590 pg = (wxHtmlHelpTreeItemData*) m_ContentsBox->GetItemData(event.GetItem());
1591
1592 if (pg && m_UpdateContents)
1593 {
1594 const wxHtmlHelpDataItems& contents = m_Data->GetContentsArray();
1595 m_UpdateContents = false;
1596 if (!contents[pg->m_Id].page.empty())
1597 m_HtmlWin->LoadPage(contents[pg->m_Id].GetFullPath());
1598 m_UpdateContents = true;
1599 }
1600 }
1601
1602 void wxHtmlHelpWindow::OnIndexSel(wxCommandEvent& WXUNUSED(event))
1603 {
1604 wxHtmlHelpMergedIndexItem *it = (wxHtmlHelpMergedIndexItem*)
1605 m_IndexList->GetClientData(m_IndexList->GetSelection());
1606 if (it)
1607 DisplayIndexItem(it);
1608 }
1609
1610 void wxHtmlHelpWindow::OnIndexFind(wxCommandEvent& WXUNUSED(event))
1611 {
1612 DoIndexFind();
1613 }
1614
1615 void wxHtmlHelpWindow::DoIndexFind()
1616 {
1617 wxString sr = m_IndexText->GetLineText(0);
1618 sr.MakeLower();
1619 if (sr == wxEmptyString)
1620 {
1621 DoIndexAll();
1622 }
1623 else
1624 {
1625 wxBusyCursor bcur;
1626
1627 m_IndexList->Clear();
1628 const wxHtmlHelpMergedIndex& index = *m_mergedIndex;
1629 size_t cnt = index.size();
1630
1631 int displ = 0;
1632 for (size_t i = 0; i < cnt; i++)
1633 {
1634 if (index[i].name.Lower().find(sr) != wxString::npos)
1635 {
1636 int pos = m_IndexList->Append(index[i].name,
1637 (char*)(&index[i]));
1638
1639 if (displ++ == 0)
1640 {
1641 // don't automatically show topic selector if this
1642 // item points to multiple pages:
1643 if (index[i].items.size() == 1)
1644 {
1645 m_IndexList->SetSelection(0);
1646 DisplayIndexItem(&index[i]);
1647 }
1648 }
1649
1650 // if this is nested item of the index, show its parent(s)
1651 // as well, otherwise it would not be clear what entry is
1652 // shown:
1653 wxHtmlHelpMergedIndexItem *parent = index[i].parent;
1654 while (parent)
1655 {
1656 if (pos == 0 ||
1657 (index.Index(*(wxHtmlHelpMergedIndexItem*)m_IndexList->GetClientData(pos-1))) < index.Index(*parent))
1658 {
1659 m_IndexList->Insert(parent->name,
1660 pos, (char*)parent);
1661 parent = parent->parent;
1662 }
1663 else break;
1664 }
1665
1666 // finally, it the item we just added is itself a parent for
1667 // other items, show them as well, because they are refinements
1668 // of the displayed index entry (i.e. it is implicitly contained
1669 // in them: "foo" with parent "bar" reads as "bar, foo"):
1670 int level = index[i].items[0]->level;
1671 i++;
1672 while (i < cnt && index[i].items[0]->level > level)
1673 {
1674 m_IndexList->Append(index[i].name, (char*)(&index[i]));
1675 i++;
1676 }
1677 i--;
1678 }
1679 }
1680
1681 wxString cnttext;
1682 cnttext.Printf(_("%i of %i"), displ, cnt);
1683 m_IndexCountInfo->SetLabel(cnttext);
1684
1685 m_IndexText->SetSelection(0, sr.length());
1686 m_IndexText->SetFocus();
1687 }
1688 }
1689
1690 void wxHtmlHelpWindow::OnIndexAll(wxCommandEvent& WXUNUSED(event))
1691 {
1692 DoIndexAll();
1693 }
1694
1695 void wxHtmlHelpWindow::DoIndexAll()
1696 {
1697 wxBusyCursor bcur;
1698
1699 m_IndexList->Clear();
1700 const wxHtmlHelpMergedIndex& index = *m_mergedIndex;
1701 size_t cnt = index.size();
1702 bool first = true;
1703
1704 for (size_t i = 0; i < cnt; i++)
1705 {
1706 m_IndexList->Append(index[i].name, (char*)(&index[i]));
1707 if (first)
1708 {
1709 // don't automatically show topic selector if this
1710 // item points to multiple pages:
1711 if (index[i].items.size() == 1)
1712 {
1713 DisplayIndexItem(&index[i]);
1714 }
1715 first = false;
1716 }
1717 }
1718
1719 wxString cnttext;
1720 cnttext.Printf(_("%i of %i"), cnt, cnt);
1721 m_IndexCountInfo->SetLabel(cnttext);
1722 }
1723
1724 void wxHtmlHelpWindow::OnSearchSel(wxCommandEvent& WXUNUSED(event))
1725 {
1726 wxHtmlHelpDataItem *it = (wxHtmlHelpDataItem*) m_SearchList->GetClientData(m_SearchList->GetSelection());
1727 if (it)
1728 {
1729 if (!it->page.empty())
1730 m_HtmlWin->LoadPage(it->GetFullPath());
1731 }
1732 }
1733
1734 void wxHtmlHelpWindow::OnSearch(wxCommandEvent& WXUNUSED(event))
1735 {
1736 wxString sr = m_SearchText->GetLineText(0);
1737
1738 if (!sr.empty())
1739 KeywordSearch(sr, wxHELP_SEARCH_ALL);
1740 }
1741
1742 void wxHtmlHelpWindow::OnBookmarksSel(wxCommandEvent& WXUNUSED(event))
1743 {
1744 wxString str = m_Bookmarks->GetStringSelection();
1745 int idx = m_BookmarksNames.Index(str);
1746 if (!str.empty() && str != _("(bookmarks)") && idx != wxNOT_FOUND)
1747 {
1748 m_HtmlWin->LoadPage(m_BookmarksPages[(size_t)idx]);
1749 }
1750 }
1751
1752 void wxHtmlHelpWindow::OnSize(wxSizeEvent& WXUNUSED(event))
1753 {
1754 Layout();
1755 }
1756
1757 #endif // wxUSE_WXHTML_HELP