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