Compilation fix for wxUSE_STL==1.
[wxWidgets.git] / src / common / cshelp.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/cshelp.cpp
3 // Purpose: Context sensitive help class implementation
4 // Author: Julian Smart, Vadim Zeitlin
5 // Modified by:
6 // Created: 08/09/2000
7 // RCS-ID: $Id$
8 // Copyright: (c) 2000 Julian Smart, Vadim Zeitlin
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
17 #pragma implementation "cshelp.h"
18 #endif
19
20 // ----------------------------------------------------------------------------
21 // headers
22 // ----------------------------------------------------------------------------
23
24 // For compilers that support precompilation, includes "wx.h".
25 #include "wx/wxprec.h"
26
27 #ifdef __BORLANDC__
28 #pragma hdrstop
29 #endif
30
31 #if wxUSE_HELP
32
33 #ifndef WX_PRECOMP
34 #endif
35
36 #include "wx/tipwin.h"
37 #include "wx/app.h"
38 #include "wx/module.h"
39 #include "wx/cshelp.h"
40
41 // ----------------------------------------------------------------------------
42 // wxContextHelpEvtHandler private class
43 // ----------------------------------------------------------------------------
44
45 // This class exists in order to eat events until the left mouse button is
46 // pressed
47 class wxContextHelpEvtHandler: public wxEvtHandler
48 {
49 public:
50 wxContextHelpEvtHandler(wxContextHelp* contextHelp)
51 {
52 m_contextHelp = contextHelp;
53 }
54
55 virtual bool ProcessEvent(wxEvent& event);
56
57 //// Data
58 wxContextHelp* m_contextHelp;
59
60 DECLARE_NO_COPY_CLASS(wxContextHelpEvtHandler)
61 };
62
63 // ============================================================================
64 // implementation
65 // ============================================================================
66
67 // ----------------------------------------------------------------------------
68 // wxContextHelp
69 // ----------------------------------------------------------------------------
70
71 /*
72 * Invokes context-sensitive help
73 */
74
75
76 IMPLEMENT_DYNAMIC_CLASS(wxContextHelp, wxObject)
77
78 wxContextHelp::wxContextHelp(wxWindow* win, bool beginHelp)
79 {
80 m_inHelp = FALSE;
81
82 if (beginHelp)
83 BeginContextHelp(win);
84 }
85
86 wxContextHelp::~wxContextHelp()
87 {
88 if (m_inHelp)
89 EndContextHelp();
90 }
91
92 // Not currently needed, but on some systems capture may not work as
93 // expected so we'll leave it here for now.
94 #ifdef __WXMOTIF__
95 static void wxPushOrPopEventHandlers(wxContextHelp* help, wxWindow* win, bool push)
96 {
97 if (push)
98 win->PushEventHandler(new wxContextHelpEvtHandler(help));
99 else
100 win->PopEventHandler(TRUE);
101
102 wxWindowList::compatibility_iterator node = win->GetChildren().GetFirst();
103 while (node)
104 {
105 wxWindow* child = node->GetData();
106 wxPushOrPopEventHandlers(help, child, push);
107
108 node = node->GetNext();
109 }
110 }
111 #endif
112
113 // Begin 'context help mode'
114 bool wxContextHelp::BeginContextHelp(wxWindow* win)
115 {
116 if (!win)
117 win = wxTheApp->GetTopWindow();
118 if (!win)
119 return FALSE;
120
121 wxCursor cursor(wxCURSOR_QUESTION_ARROW);
122 wxCursor oldCursor = win->GetCursor();
123 win->SetCursor(cursor);
124
125 #ifdef __WXMSW__
126 // wxSetCursor(cursor);
127 #endif
128
129 m_status = FALSE;
130
131 #ifdef __WXMOTIF__
132 wxPushOrPopEventHandlers(this, win, TRUE);
133 #else
134 win->PushEventHandler(new wxContextHelpEvtHandler(this));
135 #endif
136
137 win->CaptureMouse();
138
139 EventLoop();
140
141 win->ReleaseMouse();
142
143 #ifdef __WXMOTIF__
144 wxPushOrPopEventHandlers(this, win, FALSE);
145 #else
146 win->PopEventHandler(TRUE);
147 #endif
148
149 win->SetCursor(oldCursor);
150
151 if (m_status)
152 {
153 wxPoint pt;
154 wxWindow* winAtPtr = wxFindWindowAtPointer(pt);
155
156 #if 0
157 if (winAtPtr)
158 {
159 printf("Picked %s (%d)\n", winAtPtr->GetName().c_str(),
160 winAtPtr->GetId());
161 }
162 #endif
163
164 if (winAtPtr)
165 DispatchEvent(winAtPtr, pt);
166 }
167
168 return TRUE;
169 }
170
171 bool wxContextHelp::EndContextHelp()
172 {
173 m_inHelp = FALSE;
174
175 return TRUE;
176 }
177
178 bool wxContextHelp::EventLoop()
179 {
180 m_inHelp = TRUE;
181
182 while ( m_inHelp )
183 {
184 if (wxTheApp->Pending())
185 {
186 wxTheApp->Dispatch();
187 }
188 else
189 {
190 wxTheApp->ProcessIdle();
191 }
192 }
193
194 return TRUE;
195 }
196
197 bool wxContextHelpEvtHandler::ProcessEvent(wxEvent& event)
198 {
199 if (event.GetEventType() == wxEVT_LEFT_DOWN)
200 {
201 m_contextHelp->SetStatus(TRUE);
202 m_contextHelp->EndContextHelp();
203 return TRUE;
204 }
205
206 if ((event.GetEventType() == wxEVT_CHAR) ||
207 (event.GetEventType() == wxEVT_KEY_DOWN) ||
208 (event.GetEventType() == wxEVT_ACTIVATE) ||
209 (event.GetEventType() == wxEVT_MOUSE_CAPTURE_CHANGED))
210 {
211 // May have already been set to TRUE by a left-click
212 //m_contextHelp->SetStatus(FALSE);
213 m_contextHelp->EndContextHelp();
214 return TRUE;
215 }
216
217 if ((event.GetEventType() == wxEVT_PAINT) ||
218 (event.GetEventType() == wxEVT_ERASE_BACKGROUND))
219 {
220 event.Skip();
221 return FALSE;
222 }
223
224 return TRUE;
225 }
226
227 // Dispatch the help event to the relevant window
228 bool wxContextHelp::DispatchEvent(wxWindow* win, const wxPoint& pt)
229 {
230 wxWindow* subjectOfHelp = win;
231 bool eventProcessed = FALSE;
232 while (subjectOfHelp && !eventProcessed)
233 {
234 wxHelpEvent helpEvent(wxEVT_HELP, subjectOfHelp->GetId(), pt) ;
235 helpEvent.SetEventObject(this);
236
237 eventProcessed = win->GetEventHandler()->ProcessEvent(helpEvent);
238
239 // Go up the window hierarchy until the event is handled (or not).
240 // I.e. keep submitting ancestor windows until one is recognised
241 // by the app code that processes the ids and displays help.
242 subjectOfHelp = subjectOfHelp->GetParent();
243 }
244 return eventProcessed;
245 }
246
247 // ----------------------------------------------------------------------------
248 // wxContextHelpButton
249 // ----------------------------------------------------------------------------
250
251 /*
252 * wxContextHelpButton
253 * You can add this to your dialogs (especially on non-Windows platforms)
254 * to put the application into context help mode.
255 */
256
257 static const char * csquery_xpm[] = {
258 "12 11 2 1",
259 " c None",
260 ". c #000000",
261 " ",
262 " .... ",
263 " .. .. ",
264 " .. .. ",
265 " .. ",
266 " .. ",
267 " .. ",
268 " ",
269 " .. ",
270 " .. ",
271 " "};
272
273 IMPLEMENT_CLASS(wxContextHelpButton, wxBitmapButton)
274
275 BEGIN_EVENT_TABLE(wxContextHelpButton, wxBitmapButton)
276 EVT_BUTTON(wxID_CONTEXT_HELP, wxContextHelpButton::OnContextHelp)
277 END_EVENT_TABLE()
278
279 wxContextHelpButton::wxContextHelpButton(wxWindow* parent,
280 wxWindowID id,
281 const wxPoint& pos,
282 const wxSize& size,
283 long style)
284 #if defined(__WXPM__)
285 : wxBitmapButton(parent, id, wxBitmap(wxCSQUERY_BITMAP
286 ,wxBITMAP_TYPE_RESOURCE
287 ),
288 pos, size, style)
289 #else
290 : wxBitmapButton(parent, id, wxBitmap(csquery_xpm),
291 pos, size, style)
292 #endif
293 {
294 }
295
296 void wxContextHelpButton::OnContextHelp(wxCommandEvent& WXUNUSED(event))
297 {
298 wxContextHelp contextHelp(GetParent());
299 }
300
301 // ----------------------------------------------------------------------------
302 // wxHelpProvider
303 // ----------------------------------------------------------------------------
304
305 wxHelpProvider *wxHelpProvider::ms_helpProvider = (wxHelpProvider *)NULL;
306
307 // trivial implementation of some methods which we don't want to make pure
308 // virtual for convenience
309
310 void wxHelpProvider::AddHelp(wxWindowBase * WXUNUSED(window),
311 const wxString& WXUNUSED(text))
312 {
313 }
314
315 void wxHelpProvider::AddHelp(wxWindowID WXUNUSED(id),
316 const wxString& WXUNUSED(text))
317 {
318 }
319
320 // removes the association
321 void wxHelpProvider::RemoveHelp(wxWindowBase* WXUNUSED(window))
322 {
323 }
324
325 wxHelpProvider::~wxHelpProvider()
326 {
327 }
328
329 // ----------------------------------------------------------------------------
330 // wxSimpleHelpProvider
331 // ----------------------------------------------------------------------------
332
333 wxString wxSimpleHelpProvider::GetHelp(const wxWindowBase *window)
334 {
335 wxLongToStringHashMap::iterator it = m_hashWindows.find((long)window);
336
337 if ( it == m_hashWindows.end() )
338 {
339 it = m_hashIds.find(window->GetId());
340 if ( it == m_hashIds.end() )
341 return wxEmptyString;
342 }
343
344 return it->second;
345 }
346
347 void wxSimpleHelpProvider::AddHelp(wxWindowBase *window, const wxString& text)
348 {
349 m_hashWindows.erase((long)window);
350 m_hashWindows[(long)window] = text;
351 }
352
353 void wxSimpleHelpProvider::AddHelp(wxWindowID id, const wxString& text)
354 {
355 m_hashIds.erase((long)id);
356 m_hashIds[id] = text;
357 }
358
359 // removes the association
360 void wxSimpleHelpProvider::RemoveHelp(wxWindowBase* window)
361 {
362 m_hashWindows.erase((long)window);
363 }
364
365 bool wxSimpleHelpProvider::ShowHelp(wxWindowBase *window)
366 {
367 #if wxUSE_TIPWINDOW
368 static wxTipWindow* s_tipWindow = NULL;
369
370 if (s_tipWindow)
371 {
372 // Prevent s_tipWindow being nulled in OnIdle,
373 // thereby removing the chance for the window to be closed by ShowHelp
374 s_tipWindow->SetTipWindowPtr(NULL);
375 s_tipWindow->Close();
376 }
377 s_tipWindow = NULL;
378
379 wxString text = GetHelp(window);
380 if ( !text.empty() )
381 {
382 s_tipWindow = new wxTipWindow((wxWindow *)window, text, 100, & s_tipWindow);
383
384 return TRUE;
385 }
386 #endif // wxUSE_TIPWINDOW
387
388 return FALSE;
389 }
390
391 // ----------------------------------------------------------------------------
392 // wxHelpControllerHelpProvider
393 // ----------------------------------------------------------------------------
394
395 wxHelpControllerHelpProvider::wxHelpControllerHelpProvider(wxHelpControllerBase* hc)
396 {
397 m_helpController = hc;
398 }
399
400 bool wxHelpControllerHelpProvider::ShowHelp(wxWindowBase *window)
401 {
402 wxString text = GetHelp(window);
403 if ( !text.empty() )
404 {
405 if (m_helpController)
406 {
407 if (text.IsNumber())
408 return m_helpController->DisplayContextPopup(wxAtoi(text));
409
410 // If the help controller is capable of popping up the text...
411 else if (m_helpController->DisplayTextPopup(text, wxGetMousePosition()))
412 {
413 return TRUE;
414 }
415 else
416 // ...else use the default method.
417 return wxSimpleHelpProvider::ShowHelp(window);
418 }
419 else
420 return wxSimpleHelpProvider::ShowHelp(window);
421
422 }
423
424 return FALSE;
425 }
426
427 // Convenience function for turning context id into wxString
428 wxString wxContextId(int id)
429 {
430 return wxString::Format(_T("%d"), id);
431 }
432
433 // ----------------------------------------------------------------------------
434 // wxHelpProviderModule: module responsible for cleaning up help provider.
435 // ----------------------------------------------------------------------------
436
437 class wxHelpProviderModule : public wxModule
438 {
439 public:
440 bool OnInit();
441 void OnExit();
442
443 private:
444 DECLARE_DYNAMIC_CLASS(wxHelpProviderModule)
445 };
446
447 IMPLEMENT_DYNAMIC_CLASS(wxHelpProviderModule, wxModule)
448
449 bool wxHelpProviderModule::OnInit()
450 {
451 // Probably we don't want to do anything by default,
452 // since it could pull in extra code
453 // wxHelpProvider::Set(new wxSimpleHelpProvider);
454
455 return TRUE;
456 }
457
458 void wxHelpProviderModule::OnExit()
459 {
460 if (wxHelpProvider::Get())
461 {
462 delete wxHelpProvider::Get();
463 wxHelpProvider::Set(NULL);
464 }
465 }
466
467 #endif // wxUSE_HELP