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