This keyword is not expanded by Git which means it's not replaced with the correct revision value in the releases made using git-based scripts and it's confusing to have lines with unexpanded "$Id$" in the released files. As expanding them with Git is not that simple (it could be done with git archive and export-subst attribute) and there are not many benefits in having them in the first place, just remove all these lines. If nothing else, this will make an eventual transition to Git simpler. Closes #14487. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@74602 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
512 lines
13 KiB
C++
512 lines
13 KiB
C++
/////////////////////////////////////////////////////////////////////////////
|
|
// Name: src/common/cshelp.cpp
|
|
// Purpose: Context sensitive help class implementation
|
|
// Author: Julian Smart, Vadim Zeitlin
|
|
// Modified by:
|
|
// Created: 08/09/2000
|
|
// Copyright: (c) 2000 Julian Smart, Vadim Zeitlin
|
|
// Licence: wxWindows licence
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
// ============================================================================
|
|
// declarations
|
|
// ============================================================================
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// headers
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// For compilers that support precompilation, includes "wx.h".
|
|
#include "wx/wxprec.h"
|
|
|
|
#ifdef __BORLANDC__
|
|
#pragma hdrstop
|
|
#endif
|
|
|
|
#if wxUSE_HELP
|
|
|
|
#ifndef WX_PRECOMP
|
|
#include "wx/app.h"
|
|
#include "wx/module.h"
|
|
#endif
|
|
|
|
#include "wx/tipwin.h"
|
|
#include "wx/cshelp.h"
|
|
|
|
#if wxUSE_MS_HTML_HELP
|
|
#include "wx/msw/helpchm.h" // for ShowContextHelpPopup
|
|
#include "wx/utils.h" // for wxGetMousePosition()
|
|
#endif
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// wxContextHelpEvtHandler private class
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// This class exists in order to eat events until the left mouse button is
|
|
// pressed
|
|
class wxContextHelpEvtHandler: public wxEvtHandler
|
|
{
|
|
public:
|
|
wxContextHelpEvtHandler(wxContextHelp* contextHelp)
|
|
{
|
|
m_contextHelp = contextHelp;
|
|
}
|
|
|
|
virtual bool ProcessEvent(wxEvent& event);
|
|
|
|
//// Data
|
|
wxContextHelp* m_contextHelp;
|
|
|
|
wxDECLARE_NO_COPY_CLASS(wxContextHelpEvtHandler);
|
|
};
|
|
|
|
// ============================================================================
|
|
// implementation
|
|
// ============================================================================
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// wxContextHelp
|
|
// ----------------------------------------------------------------------------
|
|
|
|
/*
|
|
* Invokes context-sensitive help
|
|
*/
|
|
|
|
|
|
IMPLEMENT_DYNAMIC_CLASS(wxContextHelp, wxObject)
|
|
|
|
wxContextHelp::wxContextHelp(wxWindow* win, bool beginHelp)
|
|
{
|
|
m_inHelp = false;
|
|
|
|
if (beginHelp)
|
|
BeginContextHelp(win);
|
|
}
|
|
|
|
wxContextHelp::~wxContextHelp()
|
|
{
|
|
if (m_inHelp)
|
|
EndContextHelp();
|
|
}
|
|
|
|
// Not currently needed, but on some systems capture may not work as
|
|
// expected so we'll leave it here for now.
|
|
#ifdef __WXMOTIF__
|
|
static void wxPushOrPopEventHandlers(wxContextHelp* help, wxWindow* win, bool push)
|
|
{
|
|
if (push)
|
|
win->PushEventHandler(new wxContextHelpEvtHandler(help));
|
|
else
|
|
win->PopEventHandler(true);
|
|
|
|
wxWindowList::compatibility_iterator node = win->GetChildren().GetFirst();
|
|
while (node)
|
|
{
|
|
wxWindow* child = node->GetData();
|
|
wxPushOrPopEventHandlers(help, child, push);
|
|
|
|
node = node->GetNext();
|
|
}
|
|
}
|
|
#endif
|
|
|
|
// Begin 'context help mode'
|
|
bool wxContextHelp::BeginContextHelp(wxWindow* win)
|
|
{
|
|
if (!win)
|
|
win = wxTheApp->GetTopWindow();
|
|
if (!win)
|
|
return false;
|
|
|
|
wxCursor cursor(wxCURSOR_QUESTION_ARROW);
|
|
wxCursor oldCursor = win->GetCursor();
|
|
win->SetCursor(cursor);
|
|
|
|
#ifdef __WXMAC__
|
|
wxSetCursor(cursor);
|
|
#endif
|
|
|
|
m_status = false;
|
|
|
|
#ifdef __WXMOTIF__
|
|
wxPushOrPopEventHandlers(this, win, true);
|
|
#else
|
|
win->PushEventHandler(new wxContextHelpEvtHandler(this));
|
|
#endif
|
|
|
|
win->CaptureMouse();
|
|
|
|
EventLoop();
|
|
|
|
win->ReleaseMouse();
|
|
|
|
#ifdef __WXMOTIF__
|
|
wxPushOrPopEventHandlers(this, win, false);
|
|
#else
|
|
win->PopEventHandler(true);
|
|
#endif
|
|
|
|
win->SetCursor(oldCursor);
|
|
|
|
#ifdef __WXMAC__
|
|
wxSetCursor(wxNullCursor);
|
|
#endif
|
|
|
|
if (m_status)
|
|
{
|
|
wxPoint pt;
|
|
wxWindow* winAtPtr = wxFindWindowAtPointer(pt);
|
|
|
|
#if 0
|
|
if (winAtPtr)
|
|
{
|
|
printf("Picked %s (%d)\n", winAtPtr->GetName().c_str(),
|
|
winAtPtr->GetId());
|
|
}
|
|
#endif
|
|
|
|
if (winAtPtr)
|
|
DispatchEvent(winAtPtr, pt);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool wxContextHelp::EndContextHelp()
|
|
{
|
|
m_inHelp = false;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool wxContextHelp::EventLoop()
|
|
{
|
|
m_inHelp = true;
|
|
|
|
while ( m_inHelp )
|
|
{
|
|
if (wxTheApp->Pending())
|
|
{
|
|
wxTheApp->Dispatch();
|
|
}
|
|
else
|
|
{
|
|
wxTheApp->ProcessIdle();
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool wxContextHelpEvtHandler::ProcessEvent(wxEvent& event)
|
|
{
|
|
if (event.GetEventType() == wxEVT_LEFT_DOWN)
|
|
{
|
|
m_contextHelp->SetStatus(true);
|
|
m_contextHelp->EndContextHelp();
|
|
return true;
|
|
}
|
|
|
|
if ((event.GetEventType() == wxEVT_CHAR) ||
|
|
(event.GetEventType() == wxEVT_KEY_DOWN) ||
|
|
(event.GetEventType() == wxEVT_ACTIVATE) ||
|
|
(event.GetEventType() == wxEVT_MOUSE_CAPTURE_CHANGED))
|
|
{
|
|
// May have already been set to true by a left-click
|
|
//m_contextHelp->SetStatus(false);
|
|
m_contextHelp->EndContextHelp();
|
|
return true;
|
|
}
|
|
|
|
if ((event.GetEventType() == wxEVT_PAINT) ||
|
|
(event.GetEventType() == wxEVT_ERASE_BACKGROUND))
|
|
{
|
|
event.Skip();
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// Dispatch the help event to the relevant window
|
|
bool wxContextHelp::DispatchEvent(wxWindow* win, const wxPoint& pt)
|
|
{
|
|
wxCHECK_MSG( win, false, wxT("win parameter can't be NULL") );
|
|
|
|
wxHelpEvent helpEvent(wxEVT_HELP, win->GetId(), pt,
|
|
wxHelpEvent::Origin_HelpButton);
|
|
helpEvent.SetEventObject(win);
|
|
|
|
return win->GetEventHandler()->ProcessEvent(helpEvent);
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// wxContextHelpButton
|
|
// ----------------------------------------------------------------------------
|
|
|
|
/*
|
|
* wxContextHelpButton
|
|
* You can add this to your dialogs (especially on non-Windows platforms)
|
|
* to put the application into context help mode.
|
|
*/
|
|
|
|
#ifndef __WXPM__
|
|
|
|
static const char * csquery_xpm[] = {
|
|
"12 11 2 1",
|
|
" c None",
|
|
". c #000000",
|
|
" ",
|
|
" .... ",
|
|
" .. .. ",
|
|
" .. .. ",
|
|
" .. ",
|
|
" .. ",
|
|
" .. ",
|
|
" ",
|
|
" .. ",
|
|
" .. ",
|
|
" "};
|
|
|
|
#endif
|
|
|
|
IMPLEMENT_CLASS(wxContextHelpButton, wxBitmapButton)
|
|
|
|
BEGIN_EVENT_TABLE(wxContextHelpButton, wxBitmapButton)
|
|
EVT_BUTTON(wxID_CONTEXT_HELP, wxContextHelpButton::OnContextHelp)
|
|
END_EVENT_TABLE()
|
|
|
|
wxContextHelpButton::wxContextHelpButton(wxWindow* parent,
|
|
wxWindowID id,
|
|
const wxPoint& pos,
|
|
const wxSize& size,
|
|
long style)
|
|
#if defined(__WXPM__)
|
|
: wxBitmapButton(parent, id, wxBitmap(wxCSQUERY_BITMAP
|
|
,wxBITMAP_TYPE_BMP_RESOURCE
|
|
),
|
|
pos, size, style)
|
|
#else
|
|
: wxBitmapButton(parent, id, wxBitmap(csquery_xpm),
|
|
pos, size, style)
|
|
#endif
|
|
{
|
|
}
|
|
|
|
void wxContextHelpButton::OnContextHelp(wxCommandEvent& WXUNUSED(event))
|
|
{
|
|
wxContextHelp contextHelp(GetParent());
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// wxHelpProvider
|
|
// ----------------------------------------------------------------------------
|
|
|
|
wxHelpProvider *wxHelpProvider::ms_helpProvider = NULL;
|
|
|
|
// trivial implementation of some methods which we don't want to make pure
|
|
// virtual for convenience
|
|
|
|
void wxHelpProvider::AddHelp(wxWindowBase * WXUNUSED(window),
|
|
const wxString& WXUNUSED(text))
|
|
{
|
|
}
|
|
|
|
void wxHelpProvider::AddHelp(wxWindowID WXUNUSED(id),
|
|
const wxString& WXUNUSED(text))
|
|
{
|
|
}
|
|
|
|
// removes the association
|
|
void wxHelpProvider::RemoveHelp(wxWindowBase* WXUNUSED(window))
|
|
{
|
|
}
|
|
|
|
wxHelpProvider::~wxHelpProvider()
|
|
{
|
|
}
|
|
|
|
wxString wxHelpProvider::GetHelpTextMaybeAtPoint(wxWindowBase *window)
|
|
{
|
|
if ( m_helptextAtPoint != wxDefaultPosition ||
|
|
m_helptextOrigin != wxHelpEvent::Origin_Unknown )
|
|
{
|
|
wxCHECK_MSG( window, wxEmptyString, wxT("window must not be NULL") );
|
|
|
|
wxPoint pt = m_helptextAtPoint;
|
|
wxHelpEvent::Origin origin = m_helptextOrigin;
|
|
|
|
m_helptextAtPoint = wxDefaultPosition;
|
|
m_helptextOrigin = wxHelpEvent::Origin_Unknown;
|
|
|
|
return window->GetHelpTextAtPoint(pt, origin);
|
|
}
|
|
|
|
return GetHelp(window);
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// wxSimpleHelpProvider
|
|
// ----------------------------------------------------------------------------
|
|
|
|
#define WINHASH_KEY(w) wxPtrToUInt(w)
|
|
|
|
wxString wxSimpleHelpProvider::GetHelp(const wxWindowBase *window)
|
|
{
|
|
wxSimpleHelpProviderHashMap::iterator it = m_hashWindows.find(WINHASH_KEY(window));
|
|
|
|
if ( it == m_hashWindows.end() )
|
|
{
|
|
it = m_hashIds.find(window->GetId());
|
|
if ( it == m_hashIds.end() )
|
|
return wxEmptyString;
|
|
}
|
|
|
|
return it->second;
|
|
}
|
|
|
|
void wxSimpleHelpProvider::AddHelp(wxWindowBase *window, const wxString& text)
|
|
{
|
|
m_hashWindows.erase(WINHASH_KEY(window));
|
|
m_hashWindows[WINHASH_KEY(window)] = text;
|
|
}
|
|
|
|
void wxSimpleHelpProvider::AddHelp(wxWindowID id, const wxString& text)
|
|
{
|
|
wxSimpleHelpProviderHashMap::key_type key = (wxSimpleHelpProviderHashMap::key_type)id;
|
|
m_hashIds.erase(key);
|
|
m_hashIds[key] = text;
|
|
}
|
|
|
|
// removes the association
|
|
void wxSimpleHelpProvider::RemoveHelp(wxWindowBase* window)
|
|
{
|
|
m_hashWindows.erase(WINHASH_KEY(window));
|
|
}
|
|
|
|
bool wxSimpleHelpProvider::ShowHelp(wxWindowBase *window)
|
|
{
|
|
#if wxUSE_MS_HTML_HELP || wxUSE_TIPWINDOW
|
|
#if wxUSE_MS_HTML_HELP
|
|
// m_helptextAtPoint will be reset by GetHelpTextMaybeAtPoint(), stash it
|
|
const wxPoint posTooltip = m_helptextAtPoint;
|
|
#endif // wxUSE_MS_HTML_HELP
|
|
|
|
const wxString text = GetHelpTextMaybeAtPoint(window);
|
|
|
|
if ( !text.empty() )
|
|
{
|
|
// use the native help popup style if it's available
|
|
#if wxUSE_MS_HTML_HELP
|
|
if ( !wxCHMHelpController::ShowContextHelpPopup
|
|
(
|
|
text,
|
|
posTooltip,
|
|
(wxWindow *)window
|
|
) )
|
|
#endif // wxUSE_MS_HTML_HELP
|
|
{
|
|
#if wxUSE_TIPWINDOW
|
|
static wxTipWindow* s_tipWindow = NULL;
|
|
|
|
if ( s_tipWindow )
|
|
{
|
|
// Prevent s_tipWindow being nulled in OnIdle, thereby removing
|
|
// the chance for the window to be closed by ShowHelp
|
|
s_tipWindow->SetTipWindowPtr(NULL);
|
|
s_tipWindow->Close();
|
|
}
|
|
|
|
s_tipWindow = new wxTipWindow((wxWindow *)window, text,
|
|
100, &s_tipWindow);
|
|
#else // !wxUSE_TIPWINDOW
|
|
// we tried wxCHMHelpController but it failed and we don't have
|
|
// wxTipWindow to fall back on, so
|
|
return false;
|
|
#endif // wxUSE_TIPWINDOW
|
|
}
|
|
|
|
return true;
|
|
}
|
|
#else // !wxUSE_MS_HTML_HELP && !wxUSE_TIPWINDOW
|
|
wxUnusedVar(window);
|
|
#endif // wxUSE_MS_HTML_HELP || wxUSE_TIPWINDOW
|
|
|
|
return false;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// wxHelpControllerHelpProvider
|
|
// ----------------------------------------------------------------------------
|
|
|
|
wxHelpControllerHelpProvider::wxHelpControllerHelpProvider(wxHelpControllerBase* hc)
|
|
{
|
|
m_helpController = hc;
|
|
}
|
|
|
|
bool wxHelpControllerHelpProvider::ShowHelp(wxWindowBase *window)
|
|
{
|
|
const wxString text = GetHelpTextMaybeAtPoint(window);
|
|
|
|
if ( text.empty() )
|
|
return false;
|
|
|
|
if ( m_helpController )
|
|
{
|
|
// if it's a numeric topic, show it
|
|
long topic;
|
|
if ( text.ToLong(&topic) )
|
|
return m_helpController->DisplayContextPopup(topic);
|
|
|
|
// otherwise show the text directly
|
|
if ( m_helpController->DisplayTextPopup(text, wxGetMousePosition()) )
|
|
return true;
|
|
}
|
|
|
|
// if there is no help controller or it's not capable of showing the help,
|
|
// fallback to the default method
|
|
return wxSimpleHelpProvider::ShowHelp(window);
|
|
}
|
|
|
|
// Convenience function for turning context id into wxString
|
|
wxString wxContextId(int id)
|
|
{
|
|
return wxString::Format(wxT("%d"), id);
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// wxHelpProviderModule: module responsible for cleaning up help provider.
|
|
// ----------------------------------------------------------------------------
|
|
|
|
class wxHelpProviderModule : public wxModule
|
|
{
|
|
public:
|
|
bool OnInit();
|
|
void OnExit();
|
|
|
|
private:
|
|
DECLARE_DYNAMIC_CLASS(wxHelpProviderModule)
|
|
};
|
|
|
|
IMPLEMENT_DYNAMIC_CLASS(wxHelpProviderModule, wxModule)
|
|
|
|
bool wxHelpProviderModule::OnInit()
|
|
{
|
|
// Probably we don't want to do anything by default,
|
|
// since it could pull in extra code
|
|
// wxHelpProvider::Set(new wxSimpleHelpProvider);
|
|
|
|
return true;
|
|
}
|
|
|
|
void wxHelpProviderModule::OnExit()
|
|
{
|
|
if (wxHelpProvider::Get())
|
|
{
|
|
delete wxHelpProvider::Get();
|
|
wxHelpProvider::Set(NULL);
|
|
}
|
|
}
|
|
|
|
#endif // wxUSE_HELP
|