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