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