~brian-sidebotham/wxwidgets-cmake/wxpython-2.9.4

« back to all changes in this revision

Viewing changes to src/common/cshelp.cpp

  • Committer: Brian Sidebotham
  • Date: 2013-08-03 14:30:08 UTC
  • Revision ID: brian.sidebotham@gmail.com-20130803143008-c7806tkych1tp6fc
Initial import into Bazaar

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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: cshelp.cpp 68859 2011-08-23 04:55:46Z DS $
 
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
 
48
class wxContextHelpEvtHandler: public wxEvtHandler
 
49
{
 
50
public:
 
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
    wxDECLARE_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
 
 
77
IMPLEMENT_DYNAMIC_CLASS(wxContextHelp, wxObject)
 
78
 
 
79
wxContextHelp::wxContextHelp(wxWindow* win, bool beginHelp)
 
80
{
 
81
    m_inHelp = false;
 
82
 
 
83
    if (beginHelp)
 
84
        BeginContextHelp(win);
 
85
}
 
86
 
 
87
wxContextHelp::~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__
 
96
static 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'
 
115
bool 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
 
 
176
bool wxContextHelp::EndContextHelp()
 
177
{
 
178
    m_inHelp = false;
 
179
 
 
180
    return true;
 
181
}
 
182
 
 
183
bool 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
 
 
202
bool 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
 
233
bool wxContextHelp::DispatchEvent(wxWindow* win, const wxPoint& pt)
 
234
{
 
235
    wxCHECK_MSG( win, false, wxT("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
 
 
256
static 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
 
 
274
IMPLEMENT_CLASS(wxContextHelpButton, wxBitmapButton)
 
275
 
 
276
BEGIN_EVENT_TABLE(wxContextHelpButton, wxBitmapButton)
 
277
    EVT_BUTTON(wxID_CONTEXT_HELP, wxContextHelpButton::OnContextHelp)
 
278
END_EVENT_TABLE()
 
279
 
 
280
wxContextHelpButton::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_BMP_RESOURCE
 
288
                                                        ),
 
289
                                    pos, size, style)
 
290
#else
 
291
                   : wxBitmapButton(parent, id, wxBitmap(csquery_xpm),
 
292
                                    pos, size, style)
 
293
#endif
 
294
{
 
295
}
 
296
 
 
297
void wxContextHelpButton::OnContextHelp(wxCommandEvent& WXUNUSED(event))
 
298
{
 
299
    wxContextHelp contextHelp(GetParent());
 
300
}
 
301
 
 
302
// ----------------------------------------------------------------------------
 
303
// wxHelpProvider
 
304
// ----------------------------------------------------------------------------
 
305
 
 
306
wxHelpProvider *wxHelpProvider::ms_helpProvider = NULL;
 
307
 
 
308
// trivial implementation of some methods which we don't want to make pure
 
309
// virtual for convenience
 
310
 
 
311
void wxHelpProvider::AddHelp(wxWindowBase * WXUNUSED(window),
 
312
                             const wxString& WXUNUSED(text))
 
313
{
 
314
}
 
315
 
 
316
void wxHelpProvider::AddHelp(wxWindowID WXUNUSED(id),
 
317
                             const wxString& WXUNUSED(text))
 
318
{
 
319
}
 
320
 
 
321
// removes the association
 
322
void wxHelpProvider::RemoveHelp(wxWindowBase* WXUNUSED(window))
 
323
{
 
324
}
 
325
 
 
326
wxHelpProvider::~wxHelpProvider()
 
327
{
 
328
}
 
329
 
 
330
wxString wxHelpProvider::GetHelpTextMaybeAtPoint(wxWindowBase *window)
 
331
{
 
332
    if ( m_helptextAtPoint != wxDefaultPosition ||
 
333
            m_helptextOrigin != wxHelpEvent::Origin_Unknown )
 
334
    {
 
335
        wxCHECK_MSG( window, wxEmptyString, wxT("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
 
 
355
wxString 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
 
 
369
void wxSimpleHelpProvider::AddHelp(wxWindowBase *window, const wxString& text)
 
370
{
 
371
    m_hashWindows.erase(WINHASH_KEY(window));
 
372
    m_hashWindows[WINHASH_KEY(window)] = text;
 
373
}
 
374
 
 
375
void 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
 
383
void wxSimpleHelpProvider::RemoveHelp(wxWindowBase* window)
 
384
{
 
385
    m_hashWindows.erase(WINHASH_KEY(window));
 
386
}
 
387
 
 
388
bool wxSimpleHelpProvider::ShowHelp(wxWindowBase *window)
 
389
{
 
390
#if wxUSE_MS_HTML_HELP || wxUSE_TIPWINDOW
 
391
#if wxUSE_MS_HTML_HELP
 
392
    // m_helptextAtPoint will be reset by GetHelpTextMaybeAtPoint(), stash it
 
393
    const wxPoint posTooltip = m_helptextAtPoint;
 
394
#endif // wxUSE_MS_HTML_HELP
 
395
 
 
396
    const wxString text = GetHelpTextMaybeAtPoint(window);
 
397
 
 
398
    if ( !text.empty() )
 
399
    {
 
400
        // use the native help popup style if it's available
 
401
#if wxUSE_MS_HTML_HELP
 
402
        if ( !wxCHMHelpController::ShowContextHelpPopup
 
403
                                   (
 
404
                                        text,
 
405
                                        posTooltip,
 
406
                                        (wxWindow *)window
 
407
                                   ) )
 
408
#endif // wxUSE_MS_HTML_HELP
 
409
        {
 
410
#if wxUSE_TIPWINDOW
 
411
            static wxTipWindow* s_tipWindow = NULL;
 
412
 
 
413
            if ( s_tipWindow )
 
414
            {
 
415
                // Prevent s_tipWindow being nulled in OnIdle, thereby removing
 
416
                // the chance for the window to be closed by ShowHelp
 
417
                s_tipWindow->SetTipWindowPtr(NULL);
 
418
                s_tipWindow->Close();
 
419
            }
 
420
 
 
421
            s_tipWindow = new wxTipWindow((wxWindow *)window, text,
 
422
                                            100, &s_tipWindow);
 
423
#else // !wxUSE_TIPWINDOW
 
424
            // we tried wxCHMHelpController but it failed and we don't have
 
425
            // wxTipWindow to fall back on, so
 
426
            return false;
 
427
#endif // wxUSE_TIPWINDOW
 
428
        }
 
429
 
 
430
        return true;
 
431
    }
 
432
#else // !wxUSE_MS_HTML_HELP && !wxUSE_TIPWINDOW
 
433
    wxUnusedVar(window);
 
434
#endif // wxUSE_MS_HTML_HELP || wxUSE_TIPWINDOW
 
435
 
 
436
    return false;
 
437
}
 
438
 
 
439
// ----------------------------------------------------------------------------
 
440
// wxHelpControllerHelpProvider
 
441
// ----------------------------------------------------------------------------
 
442
 
 
443
wxHelpControllerHelpProvider::wxHelpControllerHelpProvider(wxHelpControllerBase* hc)
 
444
{
 
445
    m_helpController = hc;
 
446
}
 
447
 
 
448
bool wxHelpControllerHelpProvider::ShowHelp(wxWindowBase *window)
 
449
{
 
450
    const wxString text = GetHelpTextMaybeAtPoint(window);
 
451
 
 
452
    if ( text.empty() )
 
453
        return false;
 
454
 
 
455
    if ( m_helpController )
 
456
    {
 
457
        // if it's a numeric topic, show it
 
458
        long topic;
 
459
        if ( text.ToLong(&topic) )
 
460
            return m_helpController->DisplayContextPopup(topic);
 
461
 
 
462
        // otherwise show the text directly
 
463
        if ( m_helpController->DisplayTextPopup(text, wxGetMousePosition()) )
 
464
            return true;
 
465
    }
 
466
 
 
467
    // if there is no help controller or it's not capable of showing the help,
 
468
    // fallback to the default method
 
469
    return wxSimpleHelpProvider::ShowHelp(window);
 
470
}
 
471
 
 
472
// Convenience function for turning context id into wxString
 
473
wxString wxContextId(int id)
 
474
{
 
475
    return wxString::Format(wxT("%d"), id);
 
476
}
 
477
 
 
478
// ----------------------------------------------------------------------------
 
479
// wxHelpProviderModule: module responsible for cleaning up help provider.
 
480
// ----------------------------------------------------------------------------
 
481
 
 
482
class wxHelpProviderModule : public wxModule
 
483
{
 
484
public:
 
485
    bool OnInit();
 
486
    void OnExit();
 
487
 
 
488
private:
 
489
    DECLARE_DYNAMIC_CLASS(wxHelpProviderModule)
 
490
};
 
491
 
 
492
IMPLEMENT_DYNAMIC_CLASS(wxHelpProviderModule, wxModule)
 
493
 
 
494
bool wxHelpProviderModule::OnInit()
 
495
{
 
496
    // Probably we don't want to do anything by default,
 
497
    // since it could pull in extra code
 
498
    // wxHelpProvider::Set(new wxSimpleHelpProvider);
 
499
 
 
500
    return true;
 
501
}
 
502
 
 
503
void wxHelpProviderModule::OnExit()
 
504
{
 
505
    if (wxHelpProvider::Get())
 
506
    {
 
507
        delete wxHelpProvider::Get();
 
508
        wxHelpProvider::Set(NULL);
 
509
    }
 
510
}
 
511
 
 
512
#endif // wxUSE_HELP