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