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