1 /*
2
3 Copyright (C) 2003 - 2013 Razvan Cojocaru <rzvncj@gmail.com>
4 XML-RPC/Context ID code contributed by Eamon Millman / PCI Geomatics
5 <millman@pcigeomatics.com>
6 Tree control icons code (and the icons) contributed by Fritz Elfert
7 <felfert@users.sourceforge.net>.
8
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
22 MA 02110-1301, USA.
23
24 */
25
26
27 #include <chmframe.h>
28 #include <chminputstream.h>
29 #include <chmhtmlwindow.h>
30 #include <chmfontdialog.h>
31 #include <chmsearchpanel.h>
32 #include <chmindexpanel.h>
33 #include <chmlistctrl.h>
34 #include <chmhtmlnotebook.h>
35 #include <hhcparser.h>
36 #include <wx/fontenum.h>
37 #include <wx/statbox.h>
38 #include <wx/accel.h>
39 #include <wx/filesys.h>
40 #include <wx/mimetype.h>
41 #include <wx/imaglist.h>
42 #include <wx/bitmap.h>
43 #include <wx/fs_mem.h>
44 #include <wx/utils.h>
45
46 #include <wx/busyinfo.h>
47
48
49 #define OPEN_HELP _("Open a CHM book.")
50 #define FONTS_HELP _("Change fonts.")
51 #define PRINT_HELP _("Print the page currently displayed.")
52 #define CONTENTS_HELP _("Toggle table of contents.")
53 #define HOME_HELP _("Go to the book's start page.")
54 #define FORWARD_HELP _("Go forward in history. Per book.")
55 #define BACK_HELP _("Back to the last visited page. Per book.")
56 #define ABOUT_HELP _("About the program.")
57 #define COPY_HELP _("Copy selection.")
58 #define FIND_HELP _("Find word in page.")
59 #define FULLSCREEN_HELP _("Toggle fullscreen mode.")
60 #define CLOSETAB_HELP _("Close the current tab")
61 #define NEWTAB_HELP _("Open a new tab")
62 #define REGISTER_EXTENSION_HELP _("Associate the .chm file extension with xCHM.")
63
64
65 namespace {
66
67 const wxChar *greeting = wxT("<html><head><title>About</title></head>")
68 wxT("<body><table border=0><tr><td align=\"left\">")
69 wxT("<img src=\"memory:logo.xpm\"></td><td align=\"left\">")
70 wxT("Hello, and welcome to <B>xCHM</B>, the UNIX CHM viewer.")
71 wxT("<br><br><B>xCHM</B> has been written by Razvan Cojocaru ")
72 wxT("(rzvncj@gmail.com). It is licensed under the <TT>GPL</TT>.<br>")
73 wxT("<B>xCHM</B> is based on Jed Wing's <a href=\"http://www.jedrea.com/")
74 wxT("chmlib/\">CHMLIB</a> and <a href=\"http://www.")
75 wxT("wxwidgets.org\">wxWidgets</a>.</td></tr></table>")
76 wxT("<br>If you'd like to know more about CHM, go to")
77 wxT(" <a href=\"http://www.nongnu.org/chmspec/latest/\">Pabs' CHM")
78 wxT(" Specification page</a>.<br>Pabs has contributed time and knowledge")
79 wxT(" to the development of <B>xCHM</B>, and features such as the fast")
80 wxT(" index search would not have been implemented without his help.")
81 wxT(" Portions of the fast index search are modified versions of")
82 wxT(" Pabs' <TT>GPL</TT>d <TT>chmdeco</TT> code.<br><br>If")
83 wxT(" you'd like to use the code in your own stuff please figure")
84 wxT(" <TT>GPL</TT> out first.")
85 #if !defined(wxUSE_UNICODE) || !wxUSE_UNICODE
86 wxT("<br><br><B>WARNING</B>: your <B>xCHM</B> binary is linked")
87 wxT(" against a non-Unicode version of wxWidgets! While it will")
88 wxT(" work with most CHMs, it might not properly display")
89 wxT(" special character languages.")
90 #endif
91 wxT("<br><br>Tips:<br><ul><li>")
92 wxT("The global search is an \'AND\' search, i.e. searching for")
93 wxT(" \'word1 word2\' (quotes not included) will find all the pages")
94 wxT(" that contain both word1 and word2, in whatever order.</li>")
95 wxT("<li>Allowing partial matches will find pages that contain")
96 wxT(" words that only start with the typed strings, i.e. searching")
97 wxT(" for \'ans 4\' (quotes not included) will find pages that")
98 wxT(" contain the sentence \'The answer is 42.\'.</li><li>Right")
99 wxT(" clicking on the displayed page brings out a popup menu with")
100 wxT(" common options.</li></ul><br><br>Ctrl(cmd)-C is copy,")
101 wxT(" Ctrl(cmd)-F is find in page.<br><br>Enjoy.</body></html>");
102
103
104 const wxChar *error_page =
105 wxT("<html><body>Error loading CHM file!</body></html>");
106
107
108 const wxChar *about_txt = wxT("xCHM v. ") wxT(VERSION)
109 wxT("\nby Razvan Cojocaru <rzvncj@gmail.com>\n\n")
110 wxT("With thanks to Pabs (http://bonedaddy.net/pabs3/hhm/).\n")
111 wxT("Based on Jed Wing's CHMLIB (http://66.93.236.84/~jedwin/projects/).\n")
112 wxT("XMLRPC code for context sensitive help contributed by\n")
113 wxT("Eamon Millman <millman@pcigeomatics.com>.\n")
114 wxT("<SPAN> tag support and contents tree icons contributed by\n")
115 wxT("Fritz Elfert <felfert@users.sourceforge.net>.\n")
116 wxT("Tabbed browsing support contributed by Cedric Boudinet")
117 wxT(" <bouced@gmx.fr>.\n")
118 wxT("Written with wxWidgets (http://www.wxwidgets.org).\n\n")
119 wxT("This program is (proudly) under the GPL.");
120
121 #include <xchm-32.xpm>
122 #include <logo.xpm>
123
124 } // namespace
125
126
CHMFrame(const wxString & title,const wxString & booksDir,const wxPoint & pos,const wxSize & size,const wxString & normalFont,const wxString & fixedFont,const int fontSize,const int sashPosition,const wxString & fullAppPath,bool loadTopics,bool loadIndex)127 CHMFrame::CHMFrame(const wxString& title, const wxString& booksDir,
128 const wxPoint& pos, const wxSize& size,
129 const wxString& normalFont, const wxString& fixedFont,
130 const int fontSize, const int sashPosition,
131 const wxString& fullAppPath, bool loadTopics,
132 bool loadIndex)
133 : wxFrame(NULL, -1, title, pos, size),
134 _tcl(NULL), _sw(NULL), _menuFile(NULL), _tb(NULL), _ep(NULL),
135 _nb(NULL), _cb(NULL), _csp(NULL), _cip(NULL), _openPath(booksDir),
136 _normalFonts(NULL), _fixedFonts(NULL), _normalFont(normalFont),
137 _fixedFont(fixedFont), _fontSize(fontSize), _bookmarkSel(true),
138 _bookmarksDeleted(false), _sashPos(sashPosition),
139 _fullAppPath(fullAppPath), _loadTopics(loadTopics),
140 _loadIndex(loadIndex), _fullScreen(false)
141 {
142 # if wxUSE_ACCEL
143 const int NO_ACCELERATOR_ENTRIES = 6;
144 wxAcceleratorEntry entries[NO_ACCELERATOR_ENTRIES];
145
146 entries[0].Set(wxACCEL_CTRL, (int) 'F', ID_FindInPage);
147 entries[1].Set(wxACCEL_CTRL, (int) 'C', ID_CopySelection);
148 entries[2].Set(wxACCEL_CTRL, (int) ']', ID_Forward);
149 entries[3].Set(wxACCEL_CTRL, (int) '[', ID_Back);
150 entries[4].Set(wxACCEL_CTRL, WXK_F4, ID_CloseTab);
151 entries[5].Set(wxACCEL_CTRL, 'Q', ID_Quit);
152
153 wxAcceleratorTable accel(NO_ACCELERATOR_ENTRIES, entries);
154 SetAcceleratorTable(accel);
155 # endif
156
157 #ifdef __WXMAC__
158 wxApp::s_macAboutMenuItemId = ID_About;
159 #endif
160
161 wxLogNull wln;
162 int sizes[7];
163 for(int i = -3; i <= 3; ++i)
164 sizes[i+3] = _fontSize + i * 2;
165
166 SetIcon(wxIcon(xchm_32_xpm));
167 SetMenuBar(CreateMenu());
168
169 _tb = CreateToolBar(wxTB_HORIZONTAL | wxTB_TEXT
170 #if defined __WXMSW__ || defined __WXGTK__
171 | wxTB_FLAT | wxTB_DOCKABLE
172 #endif
173 );
174 InitToolBar(_tb);
175
176 CreateStatusBar();
177 SetStatusText(_("Ready."));
178
179 wxBitmap bitmap(logo_xpm);
180 wxMemoryFSHandler::AddFile(wxT("logo.xpm"), bitmap, //wxBITMAP(logo),
181 wxBITMAP_TYPE_XPM);
182 wxMemoryFSHandler::AddFile(wxT("about.html"), greeting);
183 wxMemoryFSHandler::AddFile(wxT("error.html"), error_page);
184
185 _ep = new wxHtmlEasyPrinting(wxT("Printing"), this);
186
187 _sw = new wxSplitterWindow(this);
188 _sw->SetMinimumPaneSize(CONTENTS_MARGIN);
189
190 _nb = new wxNotebook(_sw, ID_Notebook);
191 _nb->Show(FALSE);
192
193 wxPanel* temp = CreateContentsPanel();
194 _nbhtml = new CHMHtmlNotebook(_sw, _tcl, _normalFont, _fixedFont,
195 fontSize, this);
196 _nbhtml->SetChildrenFonts(_normalFont, _fixedFont, sizes);
197
198 _csp = new CHMSearchPanel(_nb, _tcl, _nbhtml);
199 _font = _tcl->GetFont();
200
201 _cip = new CHMIndexPanel(_nb, _nbhtml);
202
203 _nb->AddPage(temp, _("Contents"));
204 _nb->AddPage(_cip, _("Index"));
205 _nb->AddPage(_csp, _("Search"));
206
207 _sw->Initialize(_nbhtml);
208 _nbhtml->GetCurrentPage()->SetFocusFromKbd();
209 }
210
211
~CHMFrame()212 CHMFrame::~CHMFrame()
213 {
214 if(_tcl) // Supposedly, workaround for wxWin
215 _tcl->Unselect();
216
217 delete _ep;
218 delete _fixedFonts;
219 delete _normalFonts;
220 }
221
222
OnQuit(wxCommandEvent & WXUNUSED (event))223 void CHMFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
224 {
225 Close(TRUE);
226 }
227
228
OnAbout(wxCommandEvent & WXUNUSED (event))229 void CHMFrame::OnAbout(wxCommandEvent& WXUNUSED(event))
230 {
231 ::wxMessageBox(about_txt, _("About xCHM"),
232 wxOK | wxICON_INFORMATION, this );
233 }
234
235
OnOpen(wxCommandEvent & WXUNUSED (event))236 void CHMFrame::OnOpen(wxCommandEvent& WXUNUSED(event))
237 {
238 wxString selection =
239 ::wxFileSelector(_("Choose a file.."), _openPath,
240 wxEmptyString, wxT("chm"),
241 #ifndef __WXMOTIF__
242 // they say Motif can't handle the following.
243 wxT("CHM files (*.chm)|*.chm;*.CHM|")
244 wxT("All files (*.*)|*.*"),
245 #else
246 wxT("All files (*.*)|*.*"),
247 #endif
248 wxFD_OPEN | wxFD_FILE_MUST_EXIST, this);
249
250 if(selection.IsEmpty() || !_tcl)
251 return;
252
253 _openPath = selection.BeforeLast(wxT('/'));
254 LoadCHM(selection);
255 }
256
257
OnChangeFonts(wxCommandEvent & WXUNUSED (event))258 void CHMFrame::OnChangeFonts(wxCommandEvent& WXUNUSED(event))
259 {
260 wxLogNull wln;
261
262 // First time initialization only.
263 if(_normalFonts == NULL) {
264 wxFontEnumerator enu;
265 enu.EnumerateFacenames();
266 _normalFonts = new wxArrayString;
267
268 #if wxMAJOR_VERSION == 2 && wxMINOR_VERSION >= 7
269 *_normalFonts = enu.GetFacenames();
270 #else
271 *_normalFonts = *enu.GetFacenames();
272 #endif
273 _normalFonts->Sort();
274 }
275
276 if(_fixedFonts == NULL) {
277 wxFontEnumerator enu;
278 enu.EnumerateFacenames(wxFONTENCODING_SYSTEM, TRUE);
279 _fixedFonts = new wxArrayString;
280
281 #if wxMAJOR_VERSION == 2 && wxMINOR_VERSION >= 7
282 *_fixedFonts = enu.GetFacenames();
283 #else
284 *_fixedFonts = *enu.GetFacenames();
285 #endif
286 _fixedFonts->Sort();
287 }
288
289
290 assert(_normalFonts != NULL);
291 assert(_fixedFonts != NULL);
292
293 CHMFontDialog cfd(this, _normalFonts, _fixedFonts, _normalFont,
294 _fixedFont, _fontSize);
295
296 if(cfd.ShowModal() == wxID_OK) {
297
298 wxBusyCursor bc;
299
300 _nbhtml->SetChildrenFonts(_normalFont = cfd.NormalFont(),
301 _fixedFont = cfd.FixedFont(),
302 cfd.Sizes());
303
304 _fontSize = *(cfd.Sizes() + 3);
305
306 wxString page = _nbhtml->GetCurrentPage()->GetOpenedPage();
307
308 if(page.IsEmpty())
309 _nbhtml->GetCurrentPage()
310 ->LoadPage(wxT("memory:about.html"));
311 }
312 }
313
314
OnHome(wxCommandEvent & WXUNUSED (event))315 void CHMFrame::OnHome(wxCommandEvent& WXUNUSED(event))
316 {
317 CHMFile *chmf = CHMInputStream::GetCache();
318
319 if(!chmf)
320 return;
321
322 _nbhtml->LoadPageInCurrentView(wxString(wxT("file:")) +
323 chmf->ArchiveName()
324 + wxT("#xchm:") + chmf->HomePage());
325 }
326
327
OnHistoryForward(wxCommandEvent & WXUNUSED (event))328 void CHMFrame::OnHistoryForward(wxCommandEvent& WXUNUSED(event))
329 {
330 _nbhtml->GetCurrentPage()->HistoryForward();
331 }
332
333
OnHistoryBack(wxCommandEvent & WXUNUSED (event))334 void CHMFrame::OnHistoryBack(wxCommandEvent& WXUNUSED(event))
335 {
336 if(_nbhtml->GetCurrentPage()->HistoryCanBack())
337 _nbhtml->GetCurrentPage()->HistoryBack();
338 else {
339 if(CHMInputStream::GetCache())
340 return;
341 }
342 }
343
344
OnShowContents(wxCommandEvent & WXUNUSED (event))345 void CHMFrame::OnShowContents(wxCommandEvent& WXUNUSED(event))
346 {
347 if(_sw->IsSplit()) {
348 _tb->ToggleTool(ID_Contents, FALSE);
349 _menuFile->Check(ID_Contents, FALSE);
350 _sashPos = _sw->GetSashPosition();
351
352 _sw->Unsplit(_nb);
353 _nb->Show(FALSE);
354 } else {
355
356 //if(_tcl->GetCount() >= 1) {
357
358 _tb->ToggleTool(ID_Contents, TRUE);
359 _menuFile->Check(ID_Contents, TRUE);
360
361 _nb->Show(TRUE);
362 _sw->SplitVertically(_nb, _nbhtml, _sashPos);
363
364 /*} else {
365 _tb->ToggleTool(ID_Contents, FALSE);
366 _menuFile->Check(ID_Contents, FALSE);
367
368 ::wxMessageBox(_("Couldn't extract the book"
369 " contents tree."),
370 _("No contents.."),
371 wxOK | wxICON_WARNING, this );
372 }*/
373 }
374 }
375
376
377 #if defined(__WXMSW__) || defined(__WXMAC__)
378
379 # define EC_WARNING_MSG "This is experimental code, and \
380 doing this will overwrite any previously registered CHM viewer \
381 associations.\n\nAre you sure you know what you're doing?"
382
OnRegisterExtension(wxCommandEvent & WXUNUSED (event))383 void CHMFrame::OnRegisterExtension(wxCommandEvent& WXUNUSED(event))
384 {
385 int answer = wxMessageBox(_(EC_WARNING_MSG), _("Confirm"),
386 wxOK | wxCANCEL, this);
387
388 if(answer == wxOK) {
389 wxFileTypeInfo fti(wxT("application/x-chm"), _fullAppPath,
390 wxEmptyString, wxT("Compiled HTML help"),
391 wxT("chm"), NULL);
392
393 wxFileType *ft = wxTheMimeTypesManager->Associate(fti);
394
395 if(ft) {
396 ft->SetDefaultIcon(_fullAppPath);
397 wxMessageBox(_("Registration successful!"),
398 _("Done"), wxOK, this);
399 }
400 }
401 }
402 #endif// __WXMSW__
403
404
OnPrint(wxCommandEvent & WXUNUSED (event))405 void CHMFrame::OnPrint(wxCommandEvent& WXUNUSED(event))
406 {
407 wxLogNull wln;
408
409 int sizes[7];
410 for(int i = -3; i <= 3; ++i)
411 sizes[i+3] = _fontSize + i * 2;
412
413 _ep->SetFonts(_normalFont, _fixedFont, sizes);
414 _ep->PrintFile(_nbhtml->GetCurrentPage()->GetOpenedPage());
415 }
416
417
OnHistFile(wxCommandEvent & event)418 void CHMFrame::OnHistFile(wxCommandEvent& event)
419 {
420 wxString f(_fh.GetHistoryFile(event.GetId() - wxID_FILE1));
421 if (!f.IsEmpty())
422 LoadCHM(f);
423 }
424
425
OnFind(wxCommandEvent & event)426 void CHMFrame::OnFind(wxCommandEvent& event)
427 {
428 _nbhtml->GetCurrentPage()->OnFind(event);
429 }
430
431
OnCloseTab(wxCommandEvent & event)432 void CHMFrame::OnCloseTab(wxCommandEvent& event)
433 {
434 _nbhtml->OnCloseTab(event);
435 }
436
437
OnNewTab(wxCommandEvent & event)438 void CHMFrame::OnNewTab(wxCommandEvent& event)
439 {
440 _nbhtml->OnNewTab(event);
441 }
442
443
OnCopySelection(wxCommandEvent & event)444 void CHMFrame::OnCopySelection(wxCommandEvent& event)
445 {
446 _nbhtml->GetCurrentPage()->OnCopy(event);
447 }
448
449
OnFullScreen(wxCommandEvent & WXUNUSED (event))450 void CHMFrame::OnFullScreen(wxCommandEvent& WXUNUSED(event))
451 {
452 _fullScreen = !_fullScreen;
453 ShowFullScreen(_fullScreen, wxFULLSCREEN_ALL);
454 }
455
456
OnAddBookmark(wxCommandEvent & WXUNUSED (event))457 void CHMFrame::OnAddBookmark(wxCommandEvent& WXUNUSED(event))
458 {
459 wxTreeItemId id = _tcl->GetSelection();
460
461 if(!id.IsOk())
462 return;
463
464 wxString title = _tcl->GetItemText(id);
465
466 if(title.IsEmpty())
467 return;
468
469 URLTreeItem *data = reinterpret_cast<URLTreeItem *>(
470 _tcl->GetItemData(id));
471
472 if(!data || (data->_url).IsEmpty())
473 return;
474
475 _cb->Append(title, new wxString(data->_url));
476
477 _bookmarkSel = false;
478 _cb->SetSelection(_cb->GetCount() - 1);
479 _bookmarkSel = true;
480 }
481
482
OnRemoveBookmark(wxCommandEvent & WXUNUSED (event))483 void CHMFrame::OnRemoveBookmark(wxCommandEvent& WXUNUSED(event))
484 {
485 if(!_cb->GetCount())
486 return;
487
488 _cb->Delete(_cb->GetSelection());
489 _bookmarksDeleted = true;
490
491 if(_cb->GetCount()) {
492 _bookmarkSel = false;
493 _cb->SetSelection(0);
494 _bookmarkSel = true;
495 } else {
496 _cb->SetValue(wxEmptyString);
497 }
498 }
499
500
OnBookmarkSel(wxCommandEvent & event)501 void CHMFrame::OnBookmarkSel(wxCommandEvent& event)
502 {
503 if(!_bookmarkSel)
504 return;
505
506 wxString *url = reinterpret_cast<wxString *>(
507 #ifdef __WXGTK__
508 _cb->GetClientData(event.GetSelection()));
509 #else
510 _cb->wxItemContainer::GetClientData(event.GetSelection()));
511 #endif
512
513 if(!url || url->IsEmpty())
514 return;
515
516 CHMFile *chmf = CHMInputStream::GetCache();
517
518 if(!chmf)
519 return;
520
521 _nbhtml->LoadPageInCurrentView(wxString(wxT("file:")) +
522 chmf->ArchiveName() +
523 wxT("#xchm:/") + *url);
524 }
525
526
OnSelectionChanged(wxTreeEvent & event)527 void CHMFrame::OnSelectionChanged(wxTreeEvent& event)
528 {
529 wxTreeItemId id = event.GetItem();
530 CHMFile *chmf = CHMInputStream::GetCache();
531
532 if(id == _tcl->GetRootItem() || !chmf)
533 return;
534
535 if(!id.IsOk())
536 return;
537
538 URLTreeItem *data = reinterpret_cast<URLTreeItem *>(
539 _tcl->GetItemData(id));
540
541 if(!data || data->_url.IsEmpty())
542 return;
543
544 if(!_nbhtml->GetCurrentPage()->IsCaller()) {
545 _nbhtml->GetCurrentPage()->SetSync(false);
546 _nbhtml->LoadPageInCurrentView(wxString(wxT("file:")) +
547 chmf->ArchiveName() +
548 wxT("#xchm:/") + data->_url);
549 _nbhtml->GetCurrentPage()->SetSync(true);
550 }
551 }
552
553
OnCloseWindow(wxCloseEvent & WXUNUSED (event))554 void CHMFrame::OnCloseWindow(wxCloseEvent& WXUNUSED(event))
555 {
556 SaveExitInfo();
557 SaveBookmarks();
558 Destroy();
559 }
560
561
OnChar(wxKeyEvent & event)562 void CHMFrame::OnChar(wxKeyEvent& event)
563 {
564 if(event.GetKeyCode() == WXK_F9) {
565 wxCommandEvent dummy;
566 OnShowContents(dummy);
567 }
568
569 event.Skip();
570 }
571
572
LoadCHM(const wxString & archive)573 bool CHMFrame::LoadCHM(const wxString& archive)
574 {
575 wxBusyCursor bc;
576 wxLogNull wln;
577
578 bool rtn = false;
579 SaveBookmarks();
580 _nb->SetSelection(0);
581 _nbhtml->CloseAllPagesExceptFirst();
582 if(!archive.StartsWith(wxT("file:")) ||
583 !archive.Contains(wxT("#xchm:"))) {
584
585 wxFileSystem wfs;
586 std::auto_ptr<wxFSFile> p(wfs.OpenFile(wxString(wxT("file:")) + archive +
587 wxT("#xchm:/")));
588
589 CHMFile *chmf = CHMInputStream::GetCache();
590
591 if(!chmf)
592 return false;
593
594 rtn = _nbhtml->LoadPageInCurrentView(wxString(wxT("file:"))
595 + chmf->ArchiveName()
596 + wxT("#xchm:")
597 + chmf->HomePage());
598 } else {
599 rtn = _nbhtml->LoadPageInCurrentView(archive);
600 }
601
602 if(!rtn) { // Error, could not load CHM file
603 if(_tcl->GetCount())
604 _tcl->Unselect();
605 _tcl->DeleteChildren(_tcl->GetRootItem());
606 if(_sw->IsSplit()) {
607 _sw->Unsplit(_nb);
608 _nb->Show(FALSE);
609 }
610 _menuFile->Check(ID_Contents, FALSE);
611 _tb->ToggleTool(ID_Contents, FALSE);
612 _cip->Reset();
613 _csp->Reset();
614 _nbhtml->LoadPageInCurrentView(wxT("memory:error.html"));
615
616 } else {
617 UpdateCHMInfo();
618 LoadBookmarks();
619 }
620
621 return rtn;
622 }
623
624
LoadContextID(const int contextID)625 bool CHMFrame::LoadContextID( const int contextID )
626 {
627 wxBusyCursor bc;
628
629 CHMFile *chmf = CHMInputStream::GetCache();
630
631 if(!chmf)
632 return FALSE;
633
634 if( !chmf->IsValidCID( contextID ) )
635 return FALSE;
636
637 return _nbhtml->LoadPageInCurrentView(wxString(wxT("file:")) +
638 chmf->ArchiveName()
639 + wxT("#xchm:") +
640 chmf->GetPageByCID(contextID));
641 }
642
UpdateCHMInfo()643 void CHMFrame::UpdateCHMInfo()
644 {
645 #if !wxUSE_UNICODE
646 static bool noSpecialFont = true;
647 static wxFontEncoding enc = wxFont::GetDefaultEncoding();
648 #endif
649 CHMFile *chmf = CHMInputStream::GetCache();
650
651 if(!chmf)
652 return;
653
654 wxWindowDisabler wwd;
655 wxBusyInfo wait(_("Loading, please wait.."), this);
656
657 wxString filename = chmf->ArchiveName();
658 if(!filename.IsEmpty()) {
659 _fh.AddFileToHistory(filename);
660
661 if(!_menuFile->IsEnabled(ID_Recent))
662 _menuFile->Enable(ID_Recent, TRUE);
663 }
664
665 _nbhtml->GetCurrentPage()->HistoryClear();
666 _csp->Reset();
667 _cip->Reset();
668
669 wxString title = chmf->Title();
670
671 if(_tcl->GetCount()) {
672 _tcl->Unselect();
673 _tcl->DeleteChildren(_tcl->GetRootItem());
674 }
675
676 #if !wxUSE_UNICODE
677 wxString fontFace = chmf->DefaultFont();
678
679 if(!fontFace.IsEmpty()) {
680
681 long fs = -1;
682 fontFace.BeforeLast(wxT(',')).AfterLast(wxT(',')).ToLong(&fs);
683
684 if(fs < 10)
685 fs = 10;
686
687 wxFont font((int)fs, wxDEFAULT, wxNORMAL, wxNORMAL,
688 FALSE, fontFace.BeforeFirst(wxT(',')),
689 chmf->DesiredEncoding());
690
691 if(font.Ok()) {
692
693 int sizes[7];
694 for(int i = -3; i <= 3; ++i)
695 sizes[i+3] = _fontSize + i * 2;
696
697 _tcl->SetFont(font);
698 _csp->SetNewFont(font);
699 _cip->SetNewFont(font);
700 _cb->SetFont(font);
701 _nbhtml->SetChildrenFonts(font.GetFaceName(),
702 font.GetFaceName(),
703 sizes);
704 noSpecialFont = false;
705 }
706
707 } else if(noSpecialFont == false) {
708
709 int sizes[7];
710 for(int i = -3; i <= 3; ++i)
711 sizes[i+3] = _fontSize + i * 2;
712
713 _tcl->SetFont(_font);
714
715 wxFont tmp(_font.GetPointSize(),
716 _font.GetFamily(),
717 _font.GetStyle(), _font.GetWeight(),
718 _font.GetUnderlined(), _font.GetFaceName(),
719 enc);
720
721 if(tmp.Ok()) {
722 _cb->SetFont(tmp);
723 _csp->SetNewFont(tmp);
724 _cip->SetNewFont(tmp);
725 }
726
727 _nbhtml->SetChildrenFonts(_normalFont, _fixedFont, sizes);
728 noSpecialFont = true;
729 }
730 #endif
731 if(_loadTopics)
732 chmf->GetTopicsTree(_tcl);
733
734 if(_loadIndex)
735 chmf->GetIndex(_cip->GetResultsList());
736
737 if(!title.IsEmpty()) {
738 wxString titleBarText =
739 wxString(wxT("xCHM v. " wxT(VERSION) wxT(": ")))
740 + title;
741
742 SetTitle(titleBarText);
743 } else {
744 SetTitle(wxT("xCHM v. ") wxT(VERSION));
745 }
746
747 // if we have contents..
748 if(_tcl->GetCount() >= 1) {
749 if(!_sw->IsSplit()) {
750 _nb->Show(TRUE);
751 _sw->SplitVertically(_nb, _nbhtml, _sashPos);
752 _menuFile->Check(ID_Contents, TRUE);
753 _tb->ToggleTool(ID_Contents, TRUE);
754 }
755 } else {
756
757 if(_sw->IsSplit()) {
758 _sw->Unsplit(_nb);
759 _nb->Show(FALSE);
760 }
761 _menuFile->Check(ID_Contents, FALSE);
762 _tb->ToggleTool(ID_Contents, FALSE);
763 }
764
765 // select Contents
766 _nb->SetSelection(0);
767 }
768
769
CreateMenu()770 wxMenuBar* CHMFrame::CreateMenu()
771 {
772 _menuFile = new wxMenu;
773
774 _menuFile->Append(ID_Open, _("&Open..\tCtrl-O"), OPEN_HELP);
775 _menuFile->Append(ID_Print, _("&Print page..\tCtrl-P"), PRINT_HELP);
776 _menuFile->Append(ID_Fonts, _("Fon&ts.."), FONTS_HELP);
777 _menuFile->AppendSeparator();
778 _menuFile->AppendCheckItem(ID_Contents,
779 _("&Show contents tree\tCtrl-S"),
780 CONTENTS_HELP);
781 _menuFile->AppendSeparator();
782
783 #if defined(__WXMSW__) || defined(__WXMAC__)
784 _menuFile->Append(ID_RegisterExtension,
785 _("&Make xCHM the default CHM viewer"),
786 REGISTER_EXTENSION_HELP);
787 _menuFile->AppendSeparator();
788 #endif
789
790 wxMenu *recent = new wxMenu;
791 _menuFile->Append(ID_Recent, _("&Recent files"), recent);
792 _fh.UseMenu(recent);
793
794 // Fill the file history menu.
795 wxConfig config(wxT("xchm"));
796 config.SetPath(wxT("/Recent"));
797 _fh.Load(config);
798
799 if(_fh.GetCount() == 0)
800 _menuFile->Enable(ID_Recent, FALSE);
801
802 _menuFile->AppendSeparator();
803 _menuFile->Append(ID_Quit, _("E&xit\tCtrl-X"),
804 _("Quit the application."));
805
806 wxMenu *menuHistory = new wxMenu;
807
808 menuHistory->Append(ID_Home, _("&Home\tCtrl-H"), HOME_HELP);
809 menuHistory->Append(ID_Forward, _("For&ward\tAlt-RIGHT"),
810 FORWARD_HELP);
811 menuHistory->Append(ID_Back, _("&Back\tAlt-LEFT"), BACK_HELP);
812
813 wxMenu *menuHelp = new wxMenu;
814 menuHelp->Append(ID_About, _("&About..\tF1"), ABOUT_HELP);
815
816 wxMenu *menuEdit = new wxMenu;
817 menuEdit->Append(ID_CopySelection, _("&Copy\tCtrl-C"), COPY_HELP);
818 menuEdit->Append(ID_FindInPage, _("&Find..\tCtrl-F"), FIND_HELP);
819 menuEdit->AppendSeparator();
820 menuEdit->Append(ID_CloseTab, _("&Close tab\tCtrl-W"), CLOSETAB_HELP);
821 menuEdit->Append(ID_NewTab, _("&New tab\tCtrl-T"), NEWTAB_HELP);
822
823 wxMenu *menuView = new wxMenu;
824 menuView->Append(ID_FullScreen, _("Toggle &fullscreen\tF11"),
825 FULLSCREEN_HELP);
826
827 wxMenuBar *menuBar = new wxMenuBar;
828 menuBar->Append(_menuFile, _("&File"));
829 menuBar->Append(menuView, _("&View"));
830 menuBar->Append(menuEdit, _("&Edit"));
831 menuBar->Append(menuHistory, _("Hi&story"));
832 menuBar->Append(menuHelp, _("&Help"));
833
834 return menuBar;
835 }
836
837 //#ifndef __WXMSW__
838 namespace {
839
840 #include <hbook_open.xpm>
841 #include <hbook_closed.xpm>
842 #include <hpage.xpm>
843
844 } // namespace
845 //#endif
846
847
CreateContentsPanel()848 wxPanel* CHMFrame::CreateContentsPanel()
849 {
850 wxPanel *temp = new wxPanel(_nb);
851 wxSizer *sizer = new wxBoxSizer(wxVERTICAL);
852 wxSizer *bmarks = new wxStaticBoxSizer(
853 new wxStaticBox(temp, -1, _("Bookmarks")), wxVERTICAL);
854 wxSizer *inner = new wxBoxSizer(wxHORIZONTAL);
855
856 temp->SetAutoLayout(TRUE);
857 temp->SetSizer(sizer);
858
859 wxImageList *il = new wxImageList(16, 16);
860 il->Add(wxIcon(hbook_closed_xpm));
861 il->Add(wxIcon(hbook_open_xpm));
862 il->Add(wxIcon(hpage_xpm));
863
864 _tcl = new wxTreeCtrl(temp, ID_TreeCtrl, wxDefaultPosition,
865 wxDefaultSize,
866 wxSUNKEN_BORDER | wxTR_HIDE_ROOT
867 | wxTR_LINES_AT_ROOT);
868
869 _tcl->AssignImageList(il);
870 _tcl->AddRoot(_("Topics"));
871
872 _cb = new wxComboBox(temp, ID_Bookmarks, wxT(""), wxDefaultPosition,
873 wxDefaultSize, 0, NULL, wxCB_DROPDOWN
874 | wxCB_READONLY);
875 sizer->Add(_tcl, 1, wxEXPAND, 0);
876 sizer->Add(bmarks, 0, wxEXPAND | wxALL, 0);
877
878 bmarks->Add(_cb, 0, wxEXPAND | wxBOTTOM, 5);
879 bmarks->Add(inner, 1, wxEXPAND, 0);
880
881 wxButton *badd = new wxButton(temp, ID_Add, _("Add"));
882 wxButton *bremove = new wxButton(temp, ID_Remove, _("Remove"));
883
884 #if wxUSE_TOOLTIPS
885 badd->SetToolTip(_("Add displayed page to bookmarks."));
886 bremove->SetToolTip(_("Remove selected bookmark."));
887 #endif
888
889 inner->Add(badd, 1, wxEXPAND | wxRIGHT, 2);
890 inner->Add(bremove, 1, wxEXPAND | wxLEFT, 2);
891
892 return temp;
893 }
894
895
LoadBookmarks()896 void CHMFrame::LoadBookmarks()
897 {
898 _cb->Clear();
899 _cb->SetValue(wxEmptyString);
900
901 CHMFile *chmf = CHMInputStream::GetCache();
902
903 if(!chmf)
904 return;
905
906 wxConfig config(wxT("xchm"));
907 wxString bookname = chmf->ArchiveName();
908 bookname.Replace(wxT("/"), wxT("."), TRUE);
909
910 bookname = wxString(wxT("/Bookmarks/")) + bookname;
911 long noEntries;
912
913 config.SetPath(bookname);
914 wxString title, url;
915
916 if(config.Read(wxT("noEntries"), &noEntries)) {
917
918 const wxChar* format1 = wxT("bookmark_%ld_title");
919 const wxChar* format2 = wxT("bookmark_%ld_url");
920
921 for(long i = 0; i < noEntries; ++i) {
922 config.Read(wxString::Format(format1, i), &title);
923 config.Read(wxString::Format(format2, i), &url);
924
925 _cb->Append(title, new wxString(url));
926 }
927 }
928 }
929
930
SaveBookmarks()931 void CHMFrame::SaveBookmarks()
932 {
933 long noEntries = _cb->GetCount();
934
935 if(!_bookmarksDeleted && noEntries == 0)
936 return;
937
938 CHMFile *chmf = CHMInputStream::GetCache();
939
940 if(!chmf)
941 return;
942
943 wxConfig config(wxT("xchm"));
944 wxString bookname = chmf->ArchiveName();
945 bookname.Replace(wxT("/"), wxT("."), TRUE);
946 bookname = wxString(wxT("/Bookmarks/")) + bookname;
947
948 if(_bookmarksDeleted)
949 config.DeleteGroup(bookname);
950
951 if(noEntries == 0)
952 return;
953
954 config.SetPath(bookname);
955 config.Write(wxT("noEntries"), noEntries);
956
957 const wxChar* format1 = wxT("bookmark_%ld_title");
958 const wxChar* format2 = wxT("bookmark_%ld_url");
959
960 for(int i = 0; i < noEntries; ++i) {
961 wxString *url = reinterpret_cast<wxString *>(
962 #ifdef __WXGTK__
963 _cb->GetClientData(i));
964 #else
965 _cb->wxItemContainer::GetClientData(i));
966 #endif
967
968 config.Write(wxString::Format(format1, i),
969 _cb->GetString(i));
970
971 if(url)
972 config.Write(wxString::Format(format2, i), *url);
973 }
974 }
975
976
SaveExitInfo()977 void CHMFrame::SaveExitInfo()
978 {
979 int xorig, yorig, width, height;
980 int sashPos = _sw->IsSplit() ? _sw->GetSashPosition() : _sashPos;
981
982 GetPosition(&xorig, &yorig);
983 GetSize(&width, &height);
984
985 wxConfig config(wxT("xchm"));
986
987 config.Write(wxT("/Position/xOrig"), xorig);
988 config.Write(wxT("/Position/yOrig"), yorig);
989 config.Write(wxT("/Position/width"), width);
990 config.Write(wxT("/Position/height"), height);
991 config.Write(wxT("/Paths/lastOpenedDir"), _openPath);
992 config.Write(wxT("/Fonts/normalFontFace"), _normalFont);
993 config.Write(wxT("/Fonts/fixedFontFace"), _fixedFont);
994 config.Write(wxT("/Fonts/size"), _fontSize);
995 config.Write(wxT("/Sash/leftMargin"), sashPos);
996
997 config.SetPath(wxT("/Recent"));
998 _fh.Save(config);
999 }
1000
1001
1002 namespace {
1003
1004 #include <fileopen.xpm>
1005 #include <print.xpm>
1006 #include <back.xpm>
1007 #include <forward.xpm>
1008 #include <home.xpm>
1009 #include <helpicon.xpm>
1010 #include <htmsidep.xpm>
1011 #include <htmoptns.xpm>
1012 #include <copy.xpm>
1013 #include <find.xpm>
1014 #include <fullscreen.xpm>
1015
1016 } // namespace
1017
1018
InitToolBar(wxToolBar * toolbar)1019 bool CHMFrame::InitToolBar(wxToolBar *toolbar)
1020 {
1021 toolbar->AddTool(ID_Open, _("Open .."), wxBitmap(fileopen_xpm),
1022 OPEN_HELP);
1023 toolbar->AddTool(ID_Print, _("Print .."), wxBitmap(print_xpm),
1024 PRINT_HELP);
1025 toolbar->AddTool(ID_Fonts, _("Fonts .."), wxBitmap(htmoptns_xpm),
1026 FONTS_HELP);
1027 toolbar->AddCheckTool(ID_Contents, _("Contents"),
1028 wxBitmap(htmsidep_xpm),
1029 wxBitmap(htmsidep_xpm), CONTENTS_HELP);
1030
1031 toolbar->AddSeparator();
1032 toolbar->AddTool(ID_CopySelection, _("Copy"),
1033 wxBitmap(copy_xpm), COPY_HELP);
1034 toolbar->AddTool(ID_FindInPage, _("Find"),
1035 wxBitmap(find_xpm), FIND_HELP);
1036
1037 toolbar->AddSeparator();
1038
1039 toolbar->AddTool(ID_FullScreen, _("Fullscreen"),
1040 wxBitmap(fullscreen_xpm), FULLSCREEN_HELP);
1041
1042 toolbar->AddSeparator();
1043
1044 toolbar->AddTool(ID_Back, _("Back"), wxBitmap(back_xpm), BACK_HELP);
1045 toolbar->AddTool(ID_Forward, _("Forward"), wxBitmap(forward_xpm),
1046 FORWARD_HELP);
1047 toolbar->AddTool(ID_Home, _("Home"), wxBitmap(home_xpm),
1048 HOME_HELP);
1049 toolbar->AddSeparator();
1050 toolbar->AddTool(ID_About, _("About"), wxBitmap(helpicon_xpm),
1051 ABOUT_HELP);
1052
1053 toolbar->Realize();
1054
1055 return TRUE;
1056 }
1057
1058
AddHtmlView(const wxString & path,const wxString & link)1059 void CHMFrame::AddHtmlView(const wxString& path, const wxString& link)
1060 {
1061 _nbhtml->AddHtmlView(path, link);
1062 }
1063
1064
ToggleFullScreen(bool onlyIfFullScreenOn)1065 void CHMFrame::ToggleFullScreen(bool onlyIfFullScreenOn)
1066 {
1067 if(onlyIfFullScreenOn && !_fullScreen)
1068 return;
1069
1070 wxCommandEvent dummy;
1071 OnFullScreen(dummy);
1072 }
1073
1074
1075 BEGIN_EVENT_TABLE(CHMFrame, wxFrame)
1076 EVT_MENU(ID_Quit, CHMFrame::OnQuit)
1077 EVT_MENU(ID_About, CHMFrame::OnAbout)
1078 EVT_MENU(ID_Open, CHMFrame::OnOpen)
1079 EVT_MENU(ID_Fonts, CHMFrame::OnChangeFonts)
1080 EVT_MENU(ID_Home, CHMFrame::OnHome)
1081 EVT_MENU(ID_Forward, CHMFrame::OnHistoryForward)
1082 EVT_MENU(ID_Back, CHMFrame::OnHistoryBack)
1083 EVT_MENU(ID_Contents, CHMFrame::OnShowContents)
1084 #if defined(__WXMSW__) || defined(__WXMAC__)
1085 EVT_MENU(ID_RegisterExtension, CHMFrame::OnRegisterExtension)
1086 #endif
1087 EVT_MENU(ID_Print, CHMFrame::OnPrint)
1088 EVT_MENU_RANGE(wxID_FILE1, wxID_FILE9, CHMFrame::OnHistFile)
1089 EVT_MENU(ID_FindInPage, CHMFrame::OnFind)
1090 EVT_MENU(ID_CloseTab, CHMFrame::OnCloseTab)
1091 EVT_MENU(ID_NewTab, CHMFrame::OnNewTab)
1092 EVT_MENU(ID_CopySelection, CHMFrame::OnCopySelection)
1093 EVT_MENU(ID_FullScreen, CHMFrame::OnFullScreen)
1094 EVT_BUTTON(ID_Add, CHMFrame::OnAddBookmark)
1095 EVT_BUTTON(ID_Remove, CHMFrame::OnRemoveBookmark)
1096 EVT_TREE_SEL_CHANGED(ID_TreeCtrl, CHMFrame::OnSelectionChanged)
1097 EVT_COMBOBOX(ID_Bookmarks, CHMFrame::OnBookmarkSel)
1098 EVT_TEXT_ENTER(ID_Bookmarks, CHMFrame::OnBookmarkSel)
1099 EVT_CLOSE(CHMFrame::OnCloseWindow)
1100 EVT_CHAR(CHMFrame::OnChar)
1101 END_EVENT_TABLE()
1102
1103
1104 /*
1105 Local Variables:
1106 mode: c++
1107 c-basic-offset: 8
1108 tab-width: 8
1109 c-indent-comments-syntactically-p: t
1110 c-tab-always-indent: t
1111 indent-tabs-mode: t
1112 End:
1113 */
1114
1115 // vim:shiftwidth=8:autoindent:tabstop=8:noexpandtab:softtabstop=8
1116
1117