Files
wxWidgets/src/generic/helpext.cpp
Vadim Zeitlin 5276b0a53c Use wxDELETE() and wxDELETEA() when possible.
Use wxDELETE[A]() functions which automatically NULL out their arguments after
deleting them instead of doing it manually.

Closes #9685.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@64656 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
2010-06-20 18:18:23 +00:00

489 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
// RCS-ID: $Id$
// 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 id;
wxString url;
wxString doc;
wxExtHelpMapEntry(int iid, wxString const &iurl, wxString const &idoc)
{ id = 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->id == 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 (contents.length() && 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->id == 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