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