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