]> git.saurik.com Git - wxWidgets.git/blob - src/common/cshelp.cpp
Applied patch [ 774886 ] wxnotebook bug
[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 #ifdef __GNUG__
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 #if 0
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();
101
102 wxNode* node = win->GetChildren().First();
103 while (node)
104 {
105 wxWindow* child = (wxWindow*) node->Data();
106 wxPushOrPopEventHandlers(help, child, push);
107
108 node = node->Next();
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 win->PushEventHandler(new wxContextHelpEvtHandler(this));
132 //wxPushOrPopEventHandlers(this, win, TRUE);
133
134 win->CaptureMouse();
135
136 EventLoop();
137
138 win->ReleaseMouse();
139
140 win->PopEventHandler(TRUE);
141 //wxPushOrPopEventHandlers(this, win, FALSE);
142
143 win->SetCursor(oldCursor);
144
145 if (m_status)
146 {
147 wxPoint pt;
148 wxWindow* winAtPtr = wxFindWindowAtPointer(pt);
149 /*
150 if (winAtPtr)
151 {
152 wxString msg;
153 msg.Printf("Picked %s (%d)", (const char*) winAtPtr->GetName(), winAtPtr->GetId());
154 cout << msg << '\n';
155 }
156 */
157
158 if (winAtPtr)
159 DispatchEvent(winAtPtr, pt);
160 }
161
162 return TRUE;
163 }
164
165 bool wxContextHelp::EndContextHelp()
166 {
167 m_inHelp = FALSE;
168
169 return TRUE;
170 }
171
172 bool wxContextHelp::EventLoop()
173 {
174 m_inHelp = TRUE;
175
176 while ( m_inHelp )
177 {
178 if (wxTheApp->Pending())
179 {
180 wxTheApp->Dispatch();
181 }
182 else
183 {
184 wxTheApp->ProcessIdle();
185 }
186 }
187
188 return TRUE;
189 }
190
191 bool wxContextHelpEvtHandler::ProcessEvent(wxEvent& event)
192 {
193 if (event.GetEventType() == wxEVT_LEFT_DOWN)
194 {
195 m_contextHelp->SetStatus(TRUE);
196 m_contextHelp->EndContextHelp();
197 return TRUE;
198 }
199
200 if ((event.GetEventType() == wxEVT_CHAR) ||
201 (event.GetEventType() == wxEVT_KEY_DOWN) ||
202 (event.GetEventType() == wxEVT_ACTIVATE) ||
203 (event.GetEventType() == wxEVT_MOUSE_CAPTURE_CHANGED))
204 {
205 // May have already been set to TRUE by a left-click
206 //m_contextHelp->SetStatus(FALSE);
207 m_contextHelp->EndContextHelp();
208 return TRUE;
209 }
210
211 if ((event.GetEventType() == wxEVT_PAINT) ||
212 (event.GetEventType() == wxEVT_ERASE_BACKGROUND))
213 {
214 event.Skip();
215 return FALSE;
216 }
217
218 return TRUE;
219 }
220
221 // Dispatch the help event to the relevant window
222 bool wxContextHelp::DispatchEvent(wxWindow* win, const wxPoint& pt)
223 {
224 wxWindow* subjectOfHelp = win;
225 bool eventProcessed = FALSE;
226 while (subjectOfHelp && !eventProcessed)
227 {
228 wxHelpEvent helpEvent(wxEVT_HELP, subjectOfHelp->GetId(), pt) ;
229 helpEvent.SetEventObject(this);
230
231 eventProcessed = win->GetEventHandler()->ProcessEvent(helpEvent);
232
233 // Go up the window hierarchy until the event is handled (or not).
234 // I.e. keep submitting ancestor windows until one is recognised
235 // by the app code that processes the ids and displays help.
236 subjectOfHelp = subjectOfHelp->GetParent();
237 }
238 return eventProcessed;
239 }
240
241 // ----------------------------------------------------------------------------
242 // wxContextHelpButton
243 // ----------------------------------------------------------------------------
244
245 /*
246 * wxContextHelpButton
247 * You can add this to your dialogs (especially on non-Windows platforms)
248 * to put the application into context help mode.
249 */
250
251 static const char * csquery_xpm[] = {
252 "12 11 2 1",
253 " c None",
254 ". c #000000",
255 " ",
256 " .... ",
257 " .. .. ",
258 " .. .. ",
259 " .. ",
260 " .. ",
261 " .. ",
262 " ",
263 " .. ",
264 " .. ",
265 " "};
266
267 IMPLEMENT_CLASS(wxContextHelpButton, wxBitmapButton)
268
269 BEGIN_EVENT_TABLE(wxContextHelpButton, wxBitmapButton)
270 EVT_BUTTON(wxID_CONTEXT_HELP, wxContextHelpButton::OnContextHelp)
271 END_EVENT_TABLE()
272
273 wxContextHelpButton::wxContextHelpButton(wxWindow* parent,
274 wxWindowID id,
275 const wxPoint& pos,
276 const wxSize& size,
277 long style)
278 #if defined(__WXPM__)
279 : wxBitmapButton(parent, id, wxBitmap(wxCSQUERY_BITMAP
280 ,wxBITMAP_TYPE_RESOURCE
281 ),
282 pos, size, style)
283 #else
284 : wxBitmapButton(parent, id, wxBitmap(csquery_xpm),
285 pos, size, style)
286 #endif
287 {
288 }
289
290 void wxContextHelpButton::OnContextHelp(wxCommandEvent& WXUNUSED(event))
291 {
292 wxContextHelp contextHelp(GetParent());
293 }
294
295 // ----------------------------------------------------------------------------
296 // wxHelpProvider
297 // ----------------------------------------------------------------------------
298
299 wxHelpProvider *wxHelpProvider::ms_helpProvider = (wxHelpProvider *)NULL;
300
301 // trivial implementation of some methods which we don't want to make pure
302 // virtual for convenience
303
304 void wxHelpProvider::AddHelp(wxWindowBase * WXUNUSED(window),
305 const wxString& WXUNUSED(text))
306 {
307 }
308
309 void wxHelpProvider::AddHelp(wxWindowID WXUNUSED(id),
310 const wxString& WXUNUSED(text))
311 {
312 }
313
314 // removes the association
315 void wxHelpProvider::RemoveHelp(wxWindowBase* WXUNUSED(window))
316 {
317 }
318
319 wxHelpProvider::~wxHelpProvider()
320 {
321 }
322
323 // ----------------------------------------------------------------------------
324 // wxSimpleHelpProvider
325 // ----------------------------------------------------------------------------
326
327 wxString wxSimpleHelpProvider::GetHelp(const wxWindowBase *window)
328 {
329 wxLongToStringHashMap::iterator it = m_hashWindows.find((long)window);
330
331 if ( it == m_hashWindows.end() )
332 {
333 it = m_hashIds.find(window->GetId());
334 if ( it == m_hashIds.end() )
335 return wxEmptyString;
336 }
337
338 return it->second;
339 }
340
341 void wxSimpleHelpProvider::AddHelp(wxWindowBase *window, const wxString& text)
342 {
343 m_hashWindows.erase((long)window);
344 m_hashWindows[(long)window] = text;
345 }
346
347 void wxSimpleHelpProvider::AddHelp(wxWindowID id, const wxString& text)
348 {
349 m_hashIds.erase((long)id);
350 m_hashIds[id] = text;
351 }
352
353 // removes the association
354 void wxSimpleHelpProvider::RemoveHelp(wxWindowBase* window)
355 {
356 m_hashWindows.erase((long)window);
357 }
358
359 bool wxSimpleHelpProvider::ShowHelp(wxWindowBase *window)
360 {
361 #if wxUSE_TIPWINDOW
362 static wxTipWindow* s_tipWindow = NULL;
363
364 if (s_tipWindow)
365 {
366 // Prevent s_tipWindow being nulled in OnIdle,
367 // thereby removing the chance for the window to be closed by ShowHelp
368 s_tipWindow->SetTipWindowPtr(NULL);
369 s_tipWindow->Close();
370 }
371 s_tipWindow = NULL;
372
373 wxString text = GetHelp(window);
374 if ( !text.empty() )
375 {
376 s_tipWindow = new wxTipWindow((wxWindow *)window, text, 100, & s_tipWindow);
377
378 return TRUE;
379 }
380 #endif // wxUSE_TIPWINDOW
381
382 return FALSE;
383 }
384
385 // ----------------------------------------------------------------------------
386 // wxHelpControllerHelpProvider
387 // ----------------------------------------------------------------------------
388
389 wxHelpControllerHelpProvider::wxHelpControllerHelpProvider(wxHelpControllerBase* hc)
390 {
391 m_helpController = hc;
392 }
393
394 bool wxHelpControllerHelpProvider::ShowHelp(wxWindowBase *window)
395 {
396 wxString text = GetHelp(window);
397 if ( !text.empty() )
398 {
399 if (m_helpController)
400 {
401 if (text.IsNumber())
402 return m_helpController->DisplayContextPopup(wxAtoi(text));
403
404 // If the help controller is capable of popping up the text...
405 else if (m_helpController->DisplayTextPopup(text, wxGetMousePosition()))
406 {
407 return TRUE;
408 }
409 else
410 // ...else use the default method.
411 return wxSimpleHelpProvider::ShowHelp(window);
412 }
413 else
414 return wxSimpleHelpProvider::ShowHelp(window);
415
416 }
417
418 return FALSE;
419 }
420
421 // Convenience function for turning context id into wxString
422 wxString wxContextId(int id)
423 {
424 return wxString::Format(_T("%d"), id);
425 }
426
427 // ----------------------------------------------------------------------------
428 // wxHelpProviderModule: module responsible for cleaning up help provider.
429 // ----------------------------------------------------------------------------
430
431 class wxHelpProviderModule : public wxModule
432 {
433 public:
434 bool OnInit();
435 void OnExit();
436
437 private:
438 DECLARE_DYNAMIC_CLASS(wxHelpProviderModule)
439 };
440
441 IMPLEMENT_DYNAMIC_CLASS(wxHelpProviderModule, wxModule)
442
443 bool wxHelpProviderModule::OnInit()
444 {
445 // Probably we don't want to do anything by default,
446 // since it could pull in extra code
447 // wxHelpProvider::Set(new wxSimpleHelpProvider);
448
449 return TRUE;
450 }
451
452 void wxHelpProviderModule::OnExit()
453 {
454 if (wxHelpProvider::Get())
455 {
456 delete wxHelpProvider::Get();
457 wxHelpProvider::Set(NULL);
458 }
459 }
460
461 #endif // wxUSE_HELP