Include wx/msgdlg.h according to precompiled headers of wx/wx.h (with other minor...
[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 #endif // WXPRECOMP
40
41 #include "wx/html/helpfrm.h"
42 #include "wx/html/helpdlg.h"
43 #include "wx/html/helpctrl.h"
44 #include "wx/textctrl.h"
45 #include "wx/notebook.h"
46 #include "wx/imaglist.h"
47 #include "wx/treectrl.h"
48 #include "wx/tokenzr.h"
49 #include "wx/wfstream.h"
50 #include "wx/html/htmlwin.h"
51 #include "wx/busyinfo.h"
52 #include "wx/progdlg.h"
53 #include "wx/toolbar.h"
54 #include "wx/fontenum.h"
55 #include "wx/filedlg.h"
56 #include "wx/artprov.h"
57 #include "wx/spinctrl.h"
58 #include "wx/choicdlg.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 ~wxHtmlHelpHashData() {}
97
98 int m_Index;
99 wxTreeItemId m_Id;
100 };
101
102
103 //--------------------------------------------------------------------------
104 // wxHtmlHelpHtmlWindow (private)
105 //--------------------------------------------------------------------------
106
107 DEFINE_EVENT_TYPE(wxEVT_COMMAND_HTMLWINDOW_URL_CLICKED)
108 IMPLEMENT_DYNAMIC_CLASS(wxHtmlWindowEvent, wxNotifyEvent)
109
110 class wxHtmlHelpHtmlWindow : public wxHtmlWindow
111 {
112 public:
113 wxHtmlHelpHtmlWindow(wxHtmlHelpWindow *win, wxWindow *parent)
114 : wxHtmlWindow(parent), m_Window(win)
115 {
116 SetStandardFonts();
117 }
118
119 virtual void OnLinkClicked(const wxHtmlLinkInfo& link)
120 {
121 wxHtmlWindowEvent event(wxEVT_COMMAND_HTMLWINDOW_URL_CLICKED, GetId());
122 event.SetURL(link.GetHref());
123 if (!ProcessEvent(event))
124 {
125 wxHtmlWindow::OnLinkClicked(link);
126 }
127 const wxMouseEvent *e = link.GetEvent();
128 if (e == NULL || e->LeftUp())
129 m_Window->NotifyPageChanged();
130 }
131
132 // Returns full location with anchor (helper)
133 static wxString GetOpenedPageWithAnchor(wxHtmlWindow *win)
134 {
135 if(!win)
136 return wxEmptyString;
137
138 wxString an = win->GetOpenedAnchor();
139 wxString pg = win->GetOpenedPage();
140 if(!an.empty())
141 {
142 pg << wxT("#");
143 pg << an;
144 }
145 return pg;
146 }
147
148 private:
149 wxHtmlHelpWindow *m_Window;
150
151 DECLARE_NO_COPY_CLASS(wxHtmlHelpHtmlWindow)
152 };
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 wxFontEnumerator enu;
1285 enu.EnumerateFacenames();
1286 m_NormalFonts = new wxArrayString;
1287 *m_NormalFonts = *enu.GetFacenames();
1288 m_NormalFonts->Sort(); // ascending sort
1289 }
1290 if (m_FixedFonts == NULL)
1291 {
1292 wxFontEnumerator enu;
1293 enu.EnumerateFacenames(wxFONTENCODING_SYSTEM, true /*enum fixed width only*/);
1294 m_FixedFonts = new wxArrayString;
1295 *m_FixedFonts = *enu.GetFacenames();
1296 m_FixedFonts->Sort(); // ascending sort
1297 }
1298
1299 // VS: We want to show the font that is actually used by wxHtmlWindow.
1300 // If customization dialog wasn't used yet, facenames are empty and
1301 // wxHtmlWindow uses default fonts -- let's find out what they
1302 // are so that we can pass them to the dialog:
1303 if (m_NormalFace.empty())
1304 {
1305 wxFont fnt(m_FontSize, wxSWISS, wxNORMAL, wxNORMAL, false);
1306 m_NormalFace = fnt.GetFaceName();
1307 }
1308 if (m_FixedFace.empty())
1309 {
1310 wxFont fnt(m_FontSize, wxMODERN, wxNORMAL, wxNORMAL, false);
1311 m_FixedFace = fnt.GetFaceName();
1312 }
1313
1314 for (i = 0; i < m_NormalFonts->GetCount(); i++)
1315 dlg.NormalFont->Append((*m_NormalFonts)[i]);
1316 for (i = 0; i < m_FixedFonts->GetCount(); i++)
1317 dlg.FixedFont->Append((*m_FixedFonts)[i]);
1318 if (!m_NormalFace.empty())
1319 dlg.NormalFont->SetStringSelection(m_NormalFace);
1320 else
1321 dlg.NormalFont->SetSelection(0);
1322 if (!m_FixedFace.empty())
1323 dlg.FixedFont->SetStringSelection(m_FixedFace);
1324 else
1325 dlg.FixedFont->SetSelection(0);
1326 dlg.FontSize->SetValue(m_FontSize);
1327 dlg.UpdateTestWin();
1328
1329 if (dlg.ShowModal() == wxID_OK)
1330 {
1331 m_NormalFace = dlg.NormalFont->GetStringSelection();
1332 m_FixedFace = dlg.FixedFont->GetStringSelection();
1333 m_FontSize = dlg.FontSize->GetValue();
1334 SetFontsToHtmlWin(m_HtmlWin, m_NormalFace, m_FixedFace, m_FontSize);
1335 }
1336 }
1337
1338 void wxHtmlHelpWindow::NotifyPageChanged()
1339 {
1340 if (m_UpdateContents && m_PagesHash)
1341 {
1342 wxString page = wxHtmlHelpHtmlWindow::GetOpenedPageWithAnchor(m_HtmlWin);
1343 wxHtmlHelpHashData *ha = NULL;
1344 if (!page.empty())
1345 ha = (wxHtmlHelpHashData*) m_PagesHash->Get(page);
1346
1347 if (ha)
1348 {
1349 bool olduc = m_UpdateContents;
1350 m_UpdateContents = false;
1351 m_ContentsBox->SelectItem(ha->m_Id);
1352 m_ContentsBox->EnsureVisible(ha->m_Id);
1353 m_UpdateContents = olduc;
1354 }
1355 }
1356 }
1357
1358 /*
1359 EVENT HANDLING :
1360 */
1361
1362
1363 void wxHtmlHelpWindow::OnToolbar(wxCommandEvent& event)
1364 {
1365 switch (event.GetId())
1366 {
1367 case wxID_HTML_BACK :
1368 m_HtmlWin->HistoryBack();
1369 NotifyPageChanged();
1370 break;
1371
1372 case wxID_HTML_FORWARD :
1373 m_HtmlWin->HistoryForward();
1374 NotifyPageChanged();
1375 break;
1376
1377 case wxID_HTML_UP :
1378 if (m_PagesHash)
1379 {
1380 wxString page = wxHtmlHelpHtmlWindow::GetOpenedPageWithAnchor(m_HtmlWin);
1381 wxHtmlHelpHashData *ha = NULL;
1382 if (!page.empty())
1383 ha = (wxHtmlHelpHashData*) m_PagesHash->Get(page);
1384 if (ha && ha->m_Index > 0)
1385 {
1386 const wxHtmlHelpDataItem& it = m_Data->GetContentsArray()[ha->m_Index - 1];
1387 if (!it.page.empty())
1388 {
1389 m_HtmlWin->LoadPage(it.GetFullPath());
1390 NotifyPageChanged();
1391 }
1392 }
1393 }
1394 break;
1395
1396 case wxID_HTML_UPNODE :
1397 if (m_PagesHash)
1398 {
1399 wxString page = wxHtmlHelpHtmlWindow::GetOpenedPageWithAnchor(m_HtmlWin);
1400 wxHtmlHelpHashData *ha = NULL;
1401 if (!page.empty())
1402 ha = (wxHtmlHelpHashData*) m_PagesHash->Get(page);
1403 if (ha && ha->m_Index > 0)
1404 {
1405 int level =
1406 m_Data->GetContentsArray()[ha->m_Index].level - 1;
1407 int ind = ha->m_Index - 1;
1408
1409 const wxHtmlHelpDataItem *it =
1410 &m_Data->GetContentsArray()[ind];
1411 while (ind >= 0 && it->level != level)
1412 {
1413 ind--;
1414 it = &m_Data->GetContentsArray()[ind];
1415 }
1416 if (ind >= 0)
1417 {
1418 if (!it->page.empty())
1419 {
1420 m_HtmlWin->LoadPage(it->GetFullPath());
1421 NotifyPageChanged();
1422 }
1423 }
1424 }
1425 }
1426 break;
1427
1428 case wxID_HTML_DOWN :
1429 if (m_PagesHash)
1430 {
1431 wxString page = wxHtmlHelpHtmlWindow::GetOpenedPageWithAnchor(m_HtmlWin);
1432 wxHtmlHelpHashData *ha = NULL;
1433 if (!page.empty())
1434 ha = (wxHtmlHelpHashData*) m_PagesHash->Get(page);
1435
1436 const wxHtmlHelpDataItems& contents = m_Data->GetContentsArray();
1437 if (ha && ha->m_Index < (int)contents.size() - 1)
1438 {
1439 size_t idx = ha->m_Index + 1;
1440
1441 while (contents[idx].GetFullPath() == page) idx++;
1442
1443 if (!contents[idx].page.empty())
1444 {
1445 m_HtmlWin->LoadPage(contents[idx].GetFullPath());
1446 NotifyPageChanged();
1447 }
1448 }
1449 }
1450 break;
1451
1452 case wxID_HTML_PANEL :
1453 {
1454 if (! (m_Splitter && m_NavigPan))
1455 return ;
1456 if (m_Splitter->IsSplit())
1457 {
1458 m_Cfg.sashpos = m_Splitter->GetSashPosition();
1459 m_Splitter->Unsplit(m_NavigPan);
1460 m_Cfg.navig_on = false;
1461 }
1462 else
1463 {
1464 m_NavigPan->Show();
1465 m_HtmlWin->Show();
1466 m_Splitter->SplitVertically(m_NavigPan, m_HtmlWin, m_Cfg.sashpos);
1467 m_Cfg.navig_on = true;
1468 }
1469 }
1470 break;
1471
1472 case wxID_HTML_OPTIONS :
1473 OptionsDialog();
1474 break;
1475
1476 case wxID_HTML_BOOKMARKSADD :
1477 {
1478 wxString item;
1479 wxString url;
1480
1481 item = m_HtmlWin->GetOpenedPageTitle();
1482 url = m_HtmlWin->GetOpenedPage();
1483 if (item == wxEmptyString)
1484 item = url.AfterLast(wxT('/'));
1485 if (m_BookmarksPages.Index(url) == wxNOT_FOUND)
1486 {
1487 m_Bookmarks->Append(item);
1488 m_BookmarksNames.Add(item);
1489 m_BookmarksPages.Add(url);
1490 }
1491 }
1492 break;
1493
1494 case wxID_HTML_BOOKMARKSREMOVE :
1495 {
1496 wxString item;
1497 int pos;
1498
1499 item = m_Bookmarks->GetStringSelection();
1500 pos = m_BookmarksNames.Index(item);
1501 if (pos != wxNOT_FOUND)
1502 {
1503 m_BookmarksNames.RemoveAt(pos);
1504 m_BookmarksPages.RemoveAt(pos);
1505 pos = m_Bookmarks->GetSelection();
1506 wxASSERT_MSG( pos != wxNOT_FOUND , wxT("Unknown bookmark position") ) ;
1507 m_Bookmarks->Delete((unsigned int)pos);
1508 }
1509 }
1510 break;
1511
1512 #if wxUSE_PRINTING_ARCHITECTURE
1513 case wxID_HTML_PRINT :
1514 {
1515 if (m_Printer == NULL)
1516 m_Printer = new wxHtmlEasyPrinting(_("Help Printing"), this);
1517 if (!m_HtmlWin->GetOpenedPage())
1518 wxLogWarning(_("Cannot print empty page."));
1519 else
1520 m_Printer->PrintFile(m_HtmlWin->GetOpenedPage());
1521 }
1522 break;
1523 #endif
1524
1525 case wxID_HTML_OPENFILE :
1526 {
1527 wxString filemask = wxString(
1528 _("HTML files (*.html;*.htm)|*.html;*.htm|")) +
1529 _("Help books (*.htb)|*.htb|Help books (*.zip)|*.zip|") +
1530 _("HTML Help Project (*.hhp)|*.hhp|") +
1531 #if wxUSE_LIBMSPACK
1532 _("Compressed HTML Help file (*.chm)|*.chm|") +
1533 #endif
1534 _("All files (*.*)|*");
1535 wxString s = wxFileSelector(_("Open HTML document"),
1536 wxEmptyString,
1537 wxEmptyString,
1538 wxEmptyString,
1539 filemask,
1540 wxOPEN | wxFILE_MUST_EXIST,
1541 this);
1542 if (!s.empty())
1543 {
1544 wxString ext = s.Right(4).Lower();
1545 if (ext == _T(".zip") || ext == _T(".htb") ||
1546 #if wxUSE_LIBMSPACK
1547 ext == _T(".chm") ||
1548 #endif
1549 ext == _T(".hhp"))
1550 {
1551 wxBusyCursor bcur;
1552 m_Data->AddBook(s);
1553 RefreshLists();
1554 }
1555 else
1556 m_HtmlWin->LoadPage(s);
1557 }
1558 }
1559 break;
1560 }
1561 }
1562
1563 void wxHtmlHelpWindow::OnContentsSel(wxTreeEvent& event)
1564 {
1565 wxHtmlHelpTreeItemData *pg;
1566
1567 pg = (wxHtmlHelpTreeItemData*) m_ContentsBox->GetItemData(event.GetItem());
1568
1569 if (pg && m_UpdateContents)
1570 {
1571 const wxHtmlHelpDataItems& contents = m_Data->GetContentsArray();
1572 m_UpdateContents = false;
1573 if (!contents[pg->m_Id].page.empty())
1574 m_HtmlWin->LoadPage(contents[pg->m_Id].GetFullPath());
1575 m_UpdateContents = true;
1576 }
1577 }
1578
1579 void wxHtmlHelpWindow::OnIndexSel(wxCommandEvent& WXUNUSED(event))
1580 {
1581 wxHtmlHelpMergedIndexItem *it = (wxHtmlHelpMergedIndexItem*)
1582 m_IndexList->GetClientData(m_IndexList->GetSelection());
1583 if (it)
1584 DisplayIndexItem(it);
1585 }
1586
1587 void wxHtmlHelpWindow::OnIndexFind(wxCommandEvent& WXUNUSED(event))
1588 {
1589 DoIndexFind();
1590 }
1591
1592 void wxHtmlHelpWindow::DoIndexFind()
1593 {
1594 wxString sr = m_IndexText->GetLineText(0);
1595 sr.MakeLower();
1596 if (sr == wxEmptyString)
1597 {
1598 DoIndexAll();
1599 }
1600 else
1601 {
1602 wxBusyCursor bcur;
1603
1604 m_IndexList->Clear();
1605 const wxHtmlHelpMergedIndex& index = *m_mergedIndex;
1606 size_t cnt = index.size();
1607
1608 int displ = 0;
1609 for (size_t i = 0; i < cnt; i++)
1610 {
1611 if (index[i].name.Lower().find(sr) != wxString::npos)
1612 {
1613 int pos = m_IndexList->Append(index[i].name,
1614 (char*)(&index[i]));
1615
1616 if (displ++ == 0)
1617 {
1618 // don't automatically show topic selector if this
1619 // item points to multiple pages:
1620 if (index[i].items.size() == 1)
1621 {
1622 m_IndexList->SetSelection(0);
1623 DisplayIndexItem(&index[i]);
1624 }
1625 }
1626
1627 // if this is nested item of the index, show its parent(s)
1628 // as well, otherwise it would not be clear what entry is
1629 // shown:
1630 wxHtmlHelpMergedIndexItem *parent = index[i].parent;
1631 while (parent)
1632 {
1633 if (pos == 0 ||
1634 (index.Index(*(wxHtmlHelpMergedIndexItem*)m_IndexList->GetClientData(pos-1))) < index.Index(*parent))
1635 {
1636 m_IndexList->Insert(parent->name,
1637 pos, (char*)parent);
1638 parent = parent->parent;
1639 }
1640 else break;
1641 }
1642
1643 // finally, it the item we just added is itself a parent for
1644 // other items, show them as well, because they are refinements
1645 // of the displayed index entry (i.e. it is implicitly contained
1646 // in them: "foo" with parent "bar" reads as "bar, foo"):
1647 int level = index[i].items[0]->level;
1648 i++;
1649 while (i < cnt && index[i].items[0]->level > level)
1650 {
1651 m_IndexList->Append(index[i].name, (char*)(&index[i]));
1652 i++;
1653 }
1654 i--;
1655 }
1656 }
1657
1658 wxString cnttext;
1659 cnttext.Printf(_("%i of %i"), displ, cnt);
1660 m_IndexCountInfo->SetLabel(cnttext);
1661
1662 m_IndexText->SetSelection(0, sr.length());
1663 m_IndexText->SetFocus();
1664 }
1665 }
1666
1667 void wxHtmlHelpWindow::OnIndexAll(wxCommandEvent& WXUNUSED(event))
1668 {
1669 DoIndexAll();
1670 }
1671
1672 void wxHtmlHelpWindow::DoIndexAll()
1673 {
1674 wxBusyCursor bcur;
1675
1676 m_IndexList->Clear();
1677 const wxHtmlHelpMergedIndex& index = *m_mergedIndex;
1678 size_t cnt = index.size();
1679 bool first = true;
1680
1681 for (size_t i = 0; i < cnt; i++)
1682 {
1683 m_IndexList->Append(index[i].name, (char*)(&index[i]));
1684 if (first)
1685 {
1686 // don't automatically show topic selector if this
1687 // item points to multiple pages:
1688 if (index[i].items.size() == 1)
1689 {
1690 DisplayIndexItem(&index[i]);
1691 }
1692 first = false;
1693 }
1694 }
1695
1696 wxString cnttext;
1697 cnttext.Printf(_("%i of %i"), cnt, cnt);
1698 m_IndexCountInfo->SetLabel(cnttext);
1699 }
1700
1701 void wxHtmlHelpWindow::OnSearchSel(wxCommandEvent& WXUNUSED(event))
1702 {
1703 wxHtmlHelpDataItem *it = (wxHtmlHelpDataItem*) m_SearchList->GetClientData(m_SearchList->GetSelection());
1704 if (it)
1705 {
1706 if (!it->page.empty())
1707 m_HtmlWin->LoadPage(it->GetFullPath());
1708 NotifyPageChanged();
1709 }
1710 }
1711
1712 void wxHtmlHelpWindow::OnSearch(wxCommandEvent& WXUNUSED(event))
1713 {
1714 wxString sr = m_SearchText->GetLineText(0);
1715
1716 if (!sr.empty())
1717 KeywordSearch(sr, wxHELP_SEARCH_ALL);
1718 }
1719
1720 void wxHtmlHelpWindow::OnBookmarksSel(wxCommandEvent& WXUNUSED(event))
1721 {
1722 wxString str = m_Bookmarks->GetStringSelection();
1723 int idx = m_BookmarksNames.Index(str);
1724 if (!str.empty() && str != _("(bookmarks)") && idx != wxNOT_FOUND)
1725 {
1726 m_HtmlWin->LoadPage(m_BookmarksPages[(size_t)idx]);
1727 NotifyPageChanged();
1728 }
1729 }
1730
1731 void wxHtmlHelpWindow::OnSize(wxSizeEvent& WXUNUSED(event))
1732 {
1733 Layout();
1734 }
1735
1736 #endif // wxUSE_WXHTML_HELP