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