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