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