Files
wxWidgets/src/generic/helpext.cpp
Vadim Zeitlin 3f66f6a5b3 Remove all lines containing cvs/svn "$Id$" keyword.
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
2013-07-26 16:02:46 +00:00

488 lines
12 KiB
C++

/////////////////////////////////////////////////////////////////////////////
// Name: src/generic/helpext.cpp
// Purpose: an external help controller for wxWidgets
// Author: Karsten Ballueder
// Modified by:
// Created: 04/01/98
// Copyright: (c) Karsten Ballueder
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#if wxUSE_HELP && !defined(__WXWINCE__)
#ifndef WX_PRECOMP
#include "wx/list.h"
#include "wx/string.h"
#include "wx/utils.h"
#include "wx/intl.h"
#include "wx/msgdlg.h"
#include "wx/choicdlg.h"
#include "wx/log.h"
#endif
#include "wx/filename.h"
#include "wx/textfile.h"
#include "wx/generic/helpext.h"
#include <stdio.h>
#include <ctype.h>
#include <sys/stat.h>
#if !defined(__WINDOWS__) && !defined(__OS2__)
#include <unistd.h>
#endif
#ifdef __WINDOWS__
#include "wx/msw/mslu.h"
#endif
#ifdef __WXMSW__
#include <windows.h>
#include "wx/msw/winundef.h"
#endif
// ----------------------------------------------------------------------------
// constants
// ----------------------------------------------------------------------------
// Name for map file.
#define WXEXTHELP_MAPFILE wxT("wxhelp.map")
// Character introducing comments/documentation field in map file.
#define WXEXTHELP_COMMENTCHAR ';'
// The ID of the Contents section
#define WXEXTHELP_CONTENTS_ID 0
// Name of environment variable to set help browser.
#define WXEXTHELP_ENVVAR_BROWSER wxT("WX_HELPBROWSER")
// Is browser a netscape browser?
#define WXEXTHELP_ENVVAR_BROWSERISNETSCAPE wxT("WX_HELPBROWSER_NS")
IMPLEMENT_CLASS(wxExtHelpController, wxHelpControllerBase)
wxExtHelpController::wxExtHelpController(wxWindow* parentWindow)
: wxHelpControllerBase(parentWindow)
{
m_MapList = NULL;
m_NumOfEntries = 0;
m_BrowserIsNetscape = false;
wxChar *browser = wxGetenv(WXEXTHELP_ENVVAR_BROWSER);
if (browser)
{
m_BrowserName = browser;
browser = wxGetenv(WXEXTHELP_ENVVAR_BROWSERISNETSCAPE);
m_BrowserIsNetscape = browser && (wxAtoi(browser) != 0);
}
}
wxExtHelpController::~wxExtHelpController()
{
DeleteList();
}
#if WXWIN_COMPATIBILITY_2_8
void wxExtHelpController::SetBrowser(const wxString& browsername, bool isNetscape)
{
m_BrowserName = browsername;
m_BrowserIsNetscape = isNetscape;
}
#endif
void wxExtHelpController::SetViewer(const wxString& viewer, long flags)
{
m_BrowserName = viewer;
m_BrowserIsNetscape = (flags & wxHELP_NETSCAPE) != 0;
}
bool wxExtHelpController::DisplayHelp(const wxString &relativeURL)
{
// construct hte URL to open -- it's just a file
wxString url(wxT("file://") + m_helpDir);
url << wxFILE_SEP_PATH << relativeURL;
// use the explicit browser program if specified
if ( !m_BrowserName.empty() )
{
if ( m_BrowserIsNetscape )
{
wxString command;
command << m_BrowserName
<< wxT(" -remote openURL(") << url << wxT(')');
if ( wxExecute(command, wxEXEC_SYNC) != -1 )
return true;
}
if ( wxExecute(m_BrowserName + wxT(' ') + url, wxEXEC_SYNC) != -1 )
return true;
}
//else: either no browser explicitly specified or we failed to open it
// just use default browser
return wxLaunchDefaultBrowser(url);
}
class wxExtHelpMapEntry : public wxObject
{
public:
int entryid;
wxString url;
wxString doc;
wxExtHelpMapEntry(int iid, wxString const &iurl, wxString const &idoc)
{ entryid = iid; url = iurl; doc = idoc; }
};
void wxExtHelpController::DeleteList()
{
if (m_MapList)
{
wxList::compatibility_iterator node = m_MapList->GetFirst();
while (node)
{
delete (wxExtHelpMapEntry *)node->GetData();
m_MapList->Erase(node);
node = m_MapList->GetFirst();
}
wxDELETE(m_MapList);
}
}
// This must be called to tell the controller where to find the documentation.
// @param file - NOT a filename, but a directory name.
// @return true on success
bool wxExtHelpController::Initialize(const wxString& file)
{
return LoadFile(file);
}
bool wxExtHelpController::ParseMapFileLine(const wxString& line)
{
const wxChar *p = line.c_str();
// skip whitespace
while ( isascii(*p) && wxIsspace(*p) )
p++;
// skip empty lines and comments
if ( *p == wxT('\0') || *p == WXEXTHELP_COMMENTCHAR )
return true;
// the line is of the form "num url" so we must have an integer now
wxChar *end;
const unsigned long id = wxStrtoul(p, &end, 0);
if ( end == p )
return false;
p = end;
while ( isascii(*p) && wxIsspace(*p) )
p++;
// next should be the URL
wxString url;
url.reserve(line.length());
while ( isascii(*p) && !wxIsspace(*p) )
url += *p++;
while ( isascii(*p) && wxIsspace(*p) )
p++;
// and finally the optional description of the entry after comment
wxString doc;
if ( *p == WXEXTHELP_COMMENTCHAR )
{
p++;
while ( isascii(*p) && wxIsspace(*p) )
p++;
doc = p;
}
m_MapList->Append(new wxExtHelpMapEntry(id, url, doc));
m_NumOfEntries++;
return true;
}
// file is a misnomer as it's the name of the base help directory
bool wxExtHelpController::LoadFile(const wxString& file)
{
wxFileName helpDir(wxFileName::DirName(file));
helpDir.MakeAbsolute();
bool dirExists = false;
#if wxUSE_INTL
// If a locale is set, look in file/localename, i.e. If passed
// "/usr/local/myapp/help" and the current wxLocale is set to be "de", then
// look in "/usr/local/myapp/help/de/" first and fall back to
// "/usr/local/myapp/help" if that doesn't exist.
const wxLocale * const loc = wxGetLocale();
if ( loc )
{
wxString locName = loc->GetName();
// the locale is in general of the form xx_YY.zzzz, try the full firm
// first and then also more general ones
wxFileName helpDirLoc(helpDir);
helpDirLoc.AppendDir(locName);
dirExists = helpDirLoc.DirExists();
if ( ! dirExists )
{
// try without encoding
const wxString locNameWithoutEncoding = locName.BeforeLast(wxT('.'));
if ( !locNameWithoutEncoding.empty() )
{
helpDirLoc = helpDir;
helpDirLoc.AppendDir(locNameWithoutEncoding);
dirExists = helpDirLoc.DirExists();
}
}
if ( !dirExists )
{
// try without country part
wxString locNameWithoutCountry = locName.BeforeLast(wxT('_'));
if ( !locNameWithoutCountry.empty() )
{
helpDirLoc = helpDir;
helpDirLoc.AppendDir(locNameWithoutCountry);
dirExists = helpDirLoc.DirExists();
}
}
if ( dirExists )
helpDir = helpDirLoc;
}
#endif // wxUSE_INTL
if ( ! dirExists && !helpDir.DirExists() )
{
wxLogError(_("Help directory \"%s\" not found."),
helpDir.GetFullPath().c_str());
return false;
}
const wxFileName mapFile(helpDir.GetFullPath(), WXEXTHELP_MAPFILE);
if ( ! mapFile.FileExists() )
{
wxLogError(_("Help file \"%s\" not found."),
mapFile.GetFullPath().c_str());
return false;
}
DeleteList();
m_MapList = new wxList;
m_NumOfEntries = 0;
wxTextFile input;
if ( !input.Open(mapFile.GetFullPath()) )
return false;
for ( wxString& line = input.GetFirstLine();
!input.Eof();
line = input.GetNextLine() )
{
if ( !ParseMapFileLine(line) )
{
wxLogWarning(_("Line %lu of map file \"%s\" has invalid syntax, skipped."),
(unsigned long)input.GetCurrentLine(),
mapFile.GetFullPath().c_str());
}
}
if ( !m_NumOfEntries )
{
wxLogError(_("No valid mappings found in the file \"%s\"."),
mapFile.GetFullPath().c_str());
return false;
}
m_helpDir = helpDir.GetFullPath(); // now it's valid
return true;
}
bool wxExtHelpController::DisplayContents()
{
if (! m_NumOfEntries)
return false;
wxString contents;
wxList::compatibility_iterator node = m_MapList->GetFirst();
wxExtHelpMapEntry *entry;
while (node)
{
entry = (wxExtHelpMapEntry *)node->GetData();
if (entry->entryid == WXEXTHELP_CONTENTS_ID)
{
contents = entry->url;
break;
}
node = node->GetNext();
}
bool rc = false;
wxString file;
file << m_helpDir << wxFILE_SEP_PATH << contents;
if (file.Contains(wxT('#')))
file = file.BeforeLast(wxT('#'));
if ( wxFileExists(file) )
rc = DisplaySection(WXEXTHELP_CONTENTS_ID);
// if not found, open homemade toc:
return rc ? true : KeywordSearch(wxEmptyString);
}
bool wxExtHelpController::DisplaySection(int sectionNo)
{
if (! m_NumOfEntries)
return false;
wxBusyCursor b; // display a busy cursor
wxList::compatibility_iterator node = m_MapList->GetFirst();
wxExtHelpMapEntry *entry;
while (node)
{
entry = (wxExtHelpMapEntry *)node->GetData();
if (entry->entryid == sectionNo)
return DisplayHelp(entry->url);
node = node->GetNext();
}
return false;
}
bool wxExtHelpController::DisplaySection(const wxString& section)
{
bool isFilename = (section.Find(wxT(".htm")) != -1);
if (isFilename)
return DisplayHelp(section);
else
return KeywordSearch(section);
}
bool wxExtHelpController::DisplayBlock(long blockNo)
{
return DisplaySection((int)blockNo);
}
bool wxExtHelpController::KeywordSearch(const wxString& k,
wxHelpSearchMode WXUNUSED(mode))
{
if (! m_NumOfEntries)
return false;
wxString *choices = new wxString[m_NumOfEntries];
wxString *urls = new wxString[m_NumOfEntries];
int idx = 0;
bool rc = false;
bool showAll = k.empty();
wxList::compatibility_iterator node = m_MapList->GetFirst();
{
// display a busy cursor
wxBusyCursor b;
wxString compA, compB;
wxExtHelpMapEntry *entry;
// we compare case insensitive
if (! showAll)
{
compA = k;
compA.LowerCase();
}
while (node)
{
entry = (wxExtHelpMapEntry *)node->GetData();
compB = entry->doc;
bool testTarget = ! compB.empty();
if (testTarget && ! showAll)
{
compB.LowerCase();
testTarget = compB.Contains(compA);
}
if (testTarget)
{
urls[idx] = entry->url;
// doesn't work:
// choices[idx] = (**i).doc.Contains((**i).doc.Before(WXEXTHELP_COMMENTCHAR));
//if (choices[idx].empty()) // didn't contain the ';'
// choices[idx] = (**i).doc;
choices[idx] = wxEmptyString;
for (int j=0; ; j++)
{
wxChar targetChar = entry->doc.c_str()[j];
if ((targetChar == 0) || (targetChar == WXEXTHELP_COMMENTCHAR))
break;
choices[idx] << targetChar;
}
idx++;
}
node = node->GetNext();
}
}
switch (idx)
{
case 0:
wxMessageBox(_("No entries found."));
break;
case 1:
rc = DisplayHelp(urls[0]);
break;
default:
if (showAll)
idx = wxGetSingleChoiceIndex(_("Help Index"),
_("Help Index"),
idx, choices);
else
idx = wxGetSingleChoiceIndex(_("Relevant entries:"),
_("Entries found"),
idx, choices);
if (idx >= 0)
rc = DisplayHelp(urls[idx]);
break;
}
delete [] urls;
delete [] choices;
return rc;
}
bool wxExtHelpController::Quit()
{
return true;
}
void wxExtHelpController::OnQuit()
{
}
#endif // wxUSE_HELP