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