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