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