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