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