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