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