Remove all lines containing cvs/svn "$Id$" keyword.
[wxWidgets.git] / src / html / helpctrl.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/html/helpctrl.cpp
3 // Purpose: wxHtmlHelpController
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 // Copyright: (c) Harm van der Heijden and Vaclav Slavik
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
10
11 // For compilers that support precompilation, includes "wx.h".
12 #include "wx/wxprec.h"
13
14 #ifdef __BORLANDC__
15 #pragma hdrstop
16 #endif
17
18 #if wxUSE_WXHTML_HELP
19
20 #ifndef WX_PRECOMP
21 #include "wx/app.h"
22 #include "wx/intl.h"
23 #endif // WX_PRECOMP
24
25 #include "wx/busyinfo.h"
26 #include "wx/html/helpctrl.h"
27 #include "wx/html/helpwnd.h"
28 #include "wx/html/helpfrm.h"
29 #include "wx/html/helpdlg.h"
30
31 #if wxUSE_HELP
32 #include "wx/tipwin.h"
33 #endif
34
35 #if wxUSE_LIBMSPACK
36 #include "wx/html/forcelnk.h"
37 FORCE_LINK(wxhtml_chm_support)
38 #endif
39
40 IMPLEMENT_DYNAMIC_CLASS(wxHtmlHelpController, wxHelpControllerBase)
41
42 wxHtmlHelpController::wxHtmlHelpController(int style, wxWindow* parentWindow):
43 wxHelpControllerBase(parentWindow)
44 {
45 Init(style);
46 }
47
48 wxHtmlHelpController::wxHtmlHelpController(wxWindow* parentWindow, int style):
49 wxHelpControllerBase(parentWindow)
50 {
51 Init(style);
52 }
53
54 void wxHtmlHelpController::Init(int style)
55 {
56 m_helpWindow = NULL;
57 m_helpFrame = NULL;
58 m_helpDialog = NULL;
59 #if wxUSE_CONFIG
60 m_Config = NULL;
61 m_ConfigRoot = wxEmptyString;
62 #endif // wxUSE_CONFIG
63 m_titleFormat = _("Help: %s");
64 m_FrameStyle = style;
65 m_shouldPreventAppExit = false;
66 }
67
68
69 wxHtmlHelpController::~wxHtmlHelpController()
70 {
71 #if wxUSE_CONFIG
72 if (m_Config)
73 WriteCustomization(m_Config, m_ConfigRoot);
74 #endif // wxUSE_CONFIG
75 if (m_helpWindow)
76 DestroyHelpWindow();
77 }
78
79
80 void wxHtmlHelpController::DestroyHelpWindow()
81 {
82 if (m_FrameStyle & wxHF_EMBEDDED)
83 return;
84
85 // Find top-most parent window
86 // If a modal dialog
87 wxWindow* parent = FindTopLevelWindow();
88 if (parent)
89 {
90 wxDialog* dialog = wxDynamicCast(parent, wxDialog);
91 if (dialog && dialog->IsModal())
92 {
93 dialog->EndModal(wxID_OK);
94 }
95 parent->Destroy();
96 m_helpWindow = NULL;
97 }
98 m_helpDialog = NULL;
99 m_helpFrame = NULL;
100 }
101
102 void wxHtmlHelpController::OnCloseFrame(wxCloseEvent& evt)
103 {
104 #if wxUSE_CONFIG
105 if (m_Config)
106 WriteCustomization(m_Config, m_ConfigRoot);
107 #endif // wxUSE_CONFIG
108
109 evt.Skip();
110
111 OnQuit();
112
113 if ( m_helpWindow )
114 m_helpWindow->SetController(NULL);
115 m_helpWindow = NULL;
116 m_helpDialog = NULL;
117 m_helpFrame = NULL;
118 }
119
120 void wxHtmlHelpController::SetShouldPreventAppExit(bool enable)
121 {
122 m_shouldPreventAppExit = enable;
123 if ( m_helpFrame )
124 m_helpFrame->SetShouldPreventAppExit(enable);
125 }
126
127 void wxHtmlHelpController::SetTitleFormat(const wxString& title)
128 {
129 m_titleFormat = title;
130 wxHtmlHelpFrame* frame = wxDynamicCast(FindTopLevelWindow(), wxHtmlHelpFrame);
131 wxHtmlHelpDialog* dialog = wxDynamicCast(FindTopLevelWindow(), wxHtmlHelpDialog);
132 if (frame)
133 {
134 frame->SetTitleFormat(title);
135 }
136 else if (dialog)
137 dialog->SetTitleFormat(title);
138 }
139
140 // Find the top-most parent window
141 wxWindow* wxHtmlHelpController::FindTopLevelWindow()
142 {
143 return wxGetTopLevelParent(m_helpWindow);
144 }
145
146 bool wxHtmlHelpController::AddBook(const wxFileName& book_file, bool show_wait_msg)
147 {
148 return AddBook(wxFileSystem::FileNameToURL(book_file), show_wait_msg);
149 }
150
151 bool wxHtmlHelpController::AddBook(const wxString& book, bool show_wait_msg)
152 {
153 wxBusyCursor cur;
154 #if wxUSE_BUSYINFO
155 wxBusyInfo* busy = NULL;
156 wxString info;
157 if (show_wait_msg)
158 {
159 info.Printf(_("Adding book %s"), book.c_str());
160 busy = new wxBusyInfo(info);
161 }
162 #endif
163 bool retval = m_helpData.AddBook(book);
164 #if wxUSE_BUSYINFO
165 if (show_wait_msg)
166 delete busy;
167 #else
168 wxUnusedVar(show_wait_msg);
169 #endif
170 if (m_helpWindow)
171 m_helpWindow->RefreshLists();
172 return retval;
173 }
174
175 wxHtmlHelpFrame* wxHtmlHelpController::CreateHelpFrame(wxHtmlHelpData *data)
176 {
177 wxHtmlHelpFrame* frame = new wxHtmlHelpFrame(data);
178 frame->SetController(this);
179 frame->Create(m_parentWindow, -1, wxEmptyString, m_FrameStyle
180 #if wxUSE_CONFIG
181 , m_Config, m_ConfigRoot
182 #endif // wxUSE_CONFIG
183 );
184 frame->SetTitleFormat(m_titleFormat);
185 frame->SetShouldPreventAppExit(m_shouldPreventAppExit);
186 m_helpFrame = frame;
187 return frame;
188 }
189
190 wxHtmlHelpDialog* wxHtmlHelpController::CreateHelpDialog(wxHtmlHelpData *data)
191 {
192 wxHtmlHelpDialog* dialog = new wxHtmlHelpDialog(data);
193 dialog->SetController(this);
194 dialog->SetTitleFormat(m_titleFormat);
195 dialog->Create(m_parentWindow, -1, wxEmptyString, m_FrameStyle);
196 m_helpDialog = dialog;
197 return dialog;
198 }
199
200 wxWindow* wxHtmlHelpController::CreateHelpWindow()
201 {
202 if (m_helpWindow)
203 {
204 if (m_FrameStyle & wxHF_EMBEDDED)
205 return m_helpWindow;
206
207 wxWindow* topLevelWindow = FindTopLevelWindow();
208 if (topLevelWindow)
209 topLevelWindow->Raise();
210 return m_helpWindow;
211 }
212
213 #if wxUSE_CONFIG
214 if (m_Config == NULL)
215 {
216 m_Config = wxConfigBase::Get(false);
217 if (m_Config != NULL)
218 m_ConfigRoot = wxT("wxWindows/wxHtmlHelpController");
219 }
220 #endif // wxUSE_CONFIG
221
222 if (m_FrameStyle & wxHF_DIALOG)
223 {
224 wxHtmlHelpDialog* dialog = CreateHelpDialog(&m_helpData);
225 m_helpWindow = dialog->GetHelpWindow();
226 }
227 else if ((m_FrameStyle & wxHF_EMBEDDED) && m_parentWindow)
228 {
229 m_helpWindow = new wxHtmlHelpWindow(m_parentWindow, -1, wxDefaultPosition, wxDefaultSize,
230 wxTAB_TRAVERSAL|wxNO_BORDER, m_FrameStyle, &m_helpData);
231 }
232 else // wxHF_FRAME
233 {
234 wxHtmlHelpFrame* frame = CreateHelpFrame(&m_helpData);
235 m_helpWindow = frame->GetHelpWindow();
236 frame->Show(true);
237 }
238
239 return m_helpWindow;
240 }
241
242 #if wxUSE_CONFIG
243 void wxHtmlHelpController::ReadCustomization(wxConfigBase* cfg, const wxString& path)
244 {
245 /* should not be called by the user; call UseConfig, and the controller
246 * will do the rest */
247 if (m_helpWindow && cfg)
248 m_helpWindow->ReadCustomization(cfg, path);
249 }
250
251 void wxHtmlHelpController::WriteCustomization(wxConfigBase* cfg, const wxString& path)
252 {
253 /* typically called by the controllers OnCloseFrame handler */
254 if (m_helpWindow && cfg)
255 m_helpWindow->WriteCustomization(cfg, path);
256 }
257
258 void wxHtmlHelpController::UseConfig(wxConfigBase *config, const wxString& rootpath)
259 {
260 m_Config = config;
261 m_ConfigRoot = rootpath;
262 if (m_helpWindow) m_helpWindow->UseConfig(config, rootpath);
263 ReadCustomization(config, rootpath);
264 }
265 #endif // wxUSE_CONFIG
266
267 //// Backward compatibility with wxHelpController API
268
269 bool wxHtmlHelpController::Initialize(const wxString& file)
270 {
271 wxString dir, filename, ext;
272 wxFileName::SplitPath(file, & dir, & filename, & ext);
273
274 if (!dir.empty())
275 dir = dir + wxFILE_SEP_PATH;
276
277 // Try to find a suitable file
278 wxString actualFilename = dir + filename + wxString(wxT(".zip"));
279 if (!wxFileExists(actualFilename))
280 {
281 actualFilename = dir + filename + wxString(wxT(".htb"));
282 if (!wxFileExists(actualFilename))
283 {
284 actualFilename = dir + filename + wxString(wxT(".hhp"));
285 if (!wxFileExists(actualFilename))
286 {
287 #if wxUSE_LIBMSPACK
288 actualFilename = dir + filename + wxString(wxT(".chm"));
289 if (!wxFileExists(actualFilename))
290 #endif
291 return false;
292 }
293 }
294 }
295 return AddBook(wxFileName(actualFilename));
296 }
297
298 bool wxHtmlHelpController::LoadFile(const wxString& WXUNUSED(file))
299 {
300 // Don't reload the file or we'll have it appear again, presumably.
301 return true;
302 }
303
304 bool wxHtmlHelpController::DisplaySection(int sectionNo)
305 {
306 return Display(sectionNo);
307 }
308
309 bool wxHtmlHelpController::DisplayTextPopup(const wxString& text, const wxPoint& WXUNUSED(pos))
310 {
311 #if wxUSE_TIPWINDOW
312 static wxTipWindow* s_tipWindow = NULL;
313
314 if (s_tipWindow)
315 {
316 // Prevent s_tipWindow being nulled in OnIdle,
317 // thereby removing the chance for the window to be closed by ShowHelp
318 s_tipWindow->SetTipWindowPtr(NULL);
319 s_tipWindow->Close();
320 }
321 s_tipWindow = NULL;
322
323 if ( !text.empty() )
324 {
325 s_tipWindow = new wxTipWindow(wxTheApp->GetTopWindow(), text, 100, & s_tipWindow);
326
327 return true;
328 }
329 #else
330 wxUnusedVar(text);
331 #endif // wxUSE_TIPWINDOW
332
333 return false;
334 }
335
336 void wxHtmlHelpController::SetHelpWindow(wxHtmlHelpWindow* helpWindow)
337 {
338 m_helpWindow = helpWindow;
339 if (helpWindow)
340 helpWindow->SetController(this);
341 }
342
343 void wxHtmlHelpController::SetFrameParameters(const wxString& titleFormat,
344 const wxSize& size,
345 const wxPoint& pos,
346 bool WXUNUSED(newFrameEachTime))
347 {
348 SetTitleFormat(titleFormat);
349 wxHtmlHelpFrame* frame = wxDynamicCast(FindTopLevelWindow(), wxHtmlHelpFrame);
350 wxHtmlHelpDialog* dialog = wxDynamicCast(FindTopLevelWindow(), wxHtmlHelpDialog);
351 if (frame)
352 frame->SetSize(pos.x, pos.y, size.x, size.y);
353 else if (dialog)
354 dialog->SetSize(pos.x, pos.y, size.x, size.y);
355 }
356
357 wxFrame* wxHtmlHelpController::GetFrameParameters(wxSize *size,
358 wxPoint *pos,
359 bool *newFrameEachTime)
360 {
361 if (newFrameEachTime)
362 (* newFrameEachTime) = false;
363
364 wxHtmlHelpFrame* frame = wxDynamicCast(FindTopLevelWindow(), wxHtmlHelpFrame);
365 wxHtmlHelpDialog* dialog = wxDynamicCast(FindTopLevelWindow(), wxHtmlHelpDialog);
366 if (frame)
367 {
368 if (size)
369 (* size) = frame->GetSize();
370 if (pos)
371 (* pos) = frame->GetPosition();
372 return frame;
373 }
374 else if (dialog)
375 {
376 if (size)
377 (* size) = dialog->GetSize();
378 if (pos)
379 (* pos) = dialog->GetPosition();
380 return NULL;
381 }
382 return NULL;
383 }
384
385 bool wxHtmlHelpController::Quit()
386 {
387 DestroyHelpWindow();
388 return true;
389 }
390
391 // Make the help controller's frame 'modal' if
392 // needed
393 void wxHtmlHelpController::MakeModalIfNeeded()
394 {
395 if ((m_FrameStyle & wxHF_EMBEDDED) == 0)
396 {
397 wxHtmlHelpFrame* frame = wxDynamicCast(FindTopLevelWindow(), wxHtmlHelpFrame);
398 wxHtmlHelpDialog* dialog = wxDynamicCast(FindTopLevelWindow(), wxHtmlHelpDialog);
399 if (frame)
400 frame->AddGrabIfNeeded();
401 else if (dialog && (m_FrameStyle & wxHF_MODAL))
402 {
403 dialog->ShowModal();
404 }
405 }
406 }
407
408 bool wxHtmlHelpController::Display(const wxString& x)
409 {
410 CreateHelpWindow();
411 bool success = m_helpWindow->Display(x);
412 MakeModalIfNeeded();
413 return success;
414 }
415
416 bool wxHtmlHelpController::Display(int id)
417 {
418 CreateHelpWindow();
419 bool success = m_helpWindow->Display(id);
420 MakeModalIfNeeded();
421 return success;
422 }
423
424 bool wxHtmlHelpController::DisplayContents()
425 {
426 CreateHelpWindow();
427 bool success = m_helpWindow->DisplayContents();
428 MakeModalIfNeeded();
429 return success;
430 }
431
432 bool wxHtmlHelpController::DisplayIndex()
433 {
434 CreateHelpWindow();
435 bool success = m_helpWindow->DisplayIndex();
436 MakeModalIfNeeded();
437 return success;
438 }
439
440 bool wxHtmlHelpController::KeywordSearch(const wxString& keyword,
441 wxHelpSearchMode mode)
442 {
443 CreateHelpWindow();
444 bool success = m_helpWindow->KeywordSearch(keyword, mode);
445 MakeModalIfNeeded();
446 return success;
447 }
448
449 /*
450 * wxHtmlModalHelp
451 * A convenience class, to use like this:
452 *
453 * wxHtmlModalHelp help(parent, helpFile, topic);
454 */
455
456 wxHtmlModalHelp::wxHtmlModalHelp(wxWindow* parent, const wxString& helpFile, const wxString& topic, int style)
457 {
458 // Force some mandatory styles
459 style |= wxHF_DIALOG | wxHF_MODAL;
460
461 wxHtmlHelpController controller(style, parent);
462 controller.Initialize(helpFile);
463
464 if (topic.IsEmpty())
465 controller.DisplayContents();
466 else
467 controller.DisplaySection(topic);
468 }
469
470 #endif // wxUSE_WXHTML_HELP
471