*** empty log message ***
[wxWidgets.git] / src / generic / helphtml.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: helphtml.cpp
3 // Purpose: base class for html help systems
4 // Author: Karsten Ballueder
5 // Modified by:
6 // Created: 04/01/98
7 // RCS-ID: $Id$
8 // Copyright: (c) Karsten Ballueder
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 #ifdef __GNUG__
13 # pragma implementation "helphtml.h"
14 #endif
15
16 #include "wx/wxprec.h"
17
18 #ifdef __BORLANDC__
19 #pragma hdrstop
20 #endif
21
22 #if wxUSE_HELP
23
24 #ifndef WX_PRECOMP
25 #include "wx/setup.h"
26 #include "wx/string.h"
27 #include "wx/utils.h"
28 #include "wx/list.h"
29 #include "wx/intl.h"
30 #include "wx/msgdlg.h"
31 #include "wx/choicdlg.h"
32 #endif
33
34 #include "wx/helpbase.h"
35 #include "wx/generic/helpext.h"
36
37 #include <stdio.h>
38 #include <ctype.h>
39 #ifndef __MWERKS__
40 #include <sys/stat.h>
41 #endif
42
43 #if !defined(__WINDOWS__) && !defined(__OS2__)
44 #include <unistd.h>
45 #endif
46
47 #define CONTENTS_ID 0
48
49 class wxExtHelpMapEntry : public wxObject
50 {
51 public:
52 int id;
53 wxString url;
54 wxString doc;
55 wxExtHelpMapEntry(int iid, wxString const &iurl, wxString const &idoc)
56 { id = iid; url = iurl; doc = idoc; }
57 };
58
59 IMPLEMENT_ABSTRACT_CLASS(wxHTMLHelpControllerBase, wxHelpControllerBase)
60
61 /**
62 This class implements help via an external browser.
63 It requires the name of a directory containing the documentation
64 and a file mapping numerical Section numbers to relative URLS.
65 */
66
67 wxHTMLHelpControllerBase::wxHTMLHelpControllerBase()
68 {
69 m_MapList = (wxList*) NULL;
70 m_NumOfEntries = 0;
71 }
72
73 void
74 wxHTMLHelpControllerBase::DeleteList()
75 {
76 if(m_MapList)
77 {
78 wxNode *node = m_MapList->First();
79 while (node)
80 {
81 delete (wxExtHelpMapEntry *)node->Data();
82 delete node;
83 node = m_MapList->First();
84 }
85 delete m_MapList;
86 m_MapList = (wxList*) NULL;
87 }
88 }
89
90 wxHTMLHelpControllerBase::~wxHTMLHelpControllerBase()
91 {
92 DeleteList();
93 }
94
95 /** This must be called to tell the controller where to find the
96 documentation.
97 @param file - NOT a filename, but a directory name.
98 @return true on success
99 */
100 bool
101 wxHTMLHelpControllerBase::Initialize(const wxString& file)
102 {
103 return LoadFile(file);
104 }
105
106
107 // ifile is the name of the base help directory
108 bool
109 wxHTMLHelpControllerBase::LoadFile(const wxString& ifile)
110 {
111 wxString mapFile, file, url, doc;
112 int id,i,len;
113 char buffer[WXEXTHELP_BUFLEN];
114
115 wxBusyCursor b; // display a busy cursor
116
117 if(! ifile.IsEmpty())
118 {
119 file = ifile;
120 if(! wxIsAbsolutePath(file))
121 {
122 wxChar* f = wxGetWorkingDirectory();
123 file = f;
124 delete[] f; // wxGetWorkingDirectory returns new memory
125 file << WXEXTHELP_SEPARATOR << ifile;
126 }
127 else
128 file = ifile;
129
130 #if wxUSE_INTL
131 // If a locale is set, look in file/localename, i.e.
132 // If passed "/usr/local/myapp/help" and the current wxLocale is
133 // set to be "de", then look in "/usr/local/myapp/help/de/"
134 // first and fall back to "/usr/local/myapp/help" if that
135 // doesn't exist.
136 if(wxGetLocale() && !wxGetLocale()->GetName().IsEmpty())
137 {
138 wxString newfile;
139 newfile << WXEXTHELP_SEPARATOR << wxGetLocale()->GetName();
140 if(wxDirExists(newfile))
141 file = newfile;
142 else
143 {
144 newfile = WXEXTHELP_SEPARATOR;
145 const wxChar *cptr = wxGetLocale()->GetName().c_str();
146 while(*cptr && *cptr != wxT('_'))
147 newfile << *(cptr++);
148 if(wxDirExists(newfile))
149 file = newfile;
150 }
151 }
152 #endif
153
154 if(! wxDirExists(file))
155 return FALSE;
156
157 mapFile << file << WXEXTHELP_SEPARATOR << WXEXTHELP_MAPFILE;
158 }
159 else // try to reload old file
160 mapFile = m_MapFile;
161
162 if(! wxFileExists(mapFile))
163 return FALSE;
164
165 DeleteList();
166 m_MapList = new wxList;
167 m_NumOfEntries = 0;
168
169 FILE *input = fopen(mapFile.fn_str(),"rt");
170 if(! input)
171 return FALSE;
172 do
173 {
174 if(fgets(buffer,WXEXTHELP_BUFLEN,input) && *buffer != WXEXTHELP_COMMENTCHAR)
175 {
176 len = strlen(buffer);
177 if(buffer[len-1] == '\n')
178 buffer[len-1] = '\0'; // cut of trailing newline
179 if(sscanf(buffer,"%d", &id) != 1)
180 break; // error
181 for(i=0; isdigit(buffer[i])||isspace(buffer[i])||buffer[i]=='-'; i++)
182 ; // find begin of URL
183 url = "";
184 while(buffer[i] && ! isspace(buffer[i]) && buffer[i] !=
185 WXEXTHELP_COMMENTCHAR)
186 url << buffer[i++];
187 while(buffer[i] && buffer[i] != WXEXTHELP_COMMENTCHAR)
188 i++;
189 doc = "";
190 if(buffer[i])
191 doc = (buffer + i + 1); // skip the comment character
192 m_MapList->Append(new wxExtHelpMapEntry(id,url,doc));
193 m_NumOfEntries++;
194 }
195 }while(! feof(input));
196 fclose(input);
197
198 m_MapFile = file; // now it's valid
199 return TRUE;
200 }
201
202
203 bool
204 wxHTMLHelpControllerBase::DisplayContents()
205 {
206 if(! m_NumOfEntries)
207 return FALSE;
208
209 wxString contents;
210 wxNode *node = m_MapList->First();
211 wxExtHelpMapEntry *entry;
212 while(node)
213 {
214 entry = (wxExtHelpMapEntry *)node->Data();
215 if(entry->id == CONTENTS_ID)
216 {
217 contents = entry->url;
218 break;
219 }
220 node = node->Next();
221 }
222
223 bool rc = FALSE;
224 wxString file;
225 file << m_MapFile << WXEXTHELP_SEPARATOR << contents;
226 if(file.Contains(wxT('#')))
227 file = file.BeforeLast(wxT('#'));
228 if(contents.Length() && wxFileExists(file))
229 rc = DisplaySection(CONTENTS_ID);
230
231 // if not found, open homemade toc:
232 return rc ? TRUE : KeywordSearch(wxT(""));
233 }
234
235 bool
236 wxHTMLHelpControllerBase::DisplaySection(int sectionNo)
237 {
238 if(! m_NumOfEntries)
239 return FALSE;
240
241 wxBusyCursor b; // display a busy cursor
242 wxNode *node = m_MapList->First();
243 wxExtHelpMapEntry *entry;
244 while(node)
245 {
246 entry = (wxExtHelpMapEntry *)node->Data();
247 if(entry->id == sectionNo)
248 return DisplayHelp(entry->url);
249 node = node->Next();
250 }
251 return FALSE;
252 }
253
254 bool
255 wxHTMLHelpControllerBase::DisplayBlock(long blockNo)
256 {
257 return DisplaySection((int)blockNo);
258 }
259
260 bool
261 wxHTMLHelpControllerBase::KeywordSearch(const wxString& k)
262 {
263 if(! m_NumOfEntries)
264 return FALSE;
265
266 wxString *choices = new wxString[m_NumOfEntries];
267 wxString *urls = new wxString[m_NumOfEntries];
268 wxString compA, compB;
269
270 int idx = 0, j;
271 bool rc;
272 bool showAll = k.IsEmpty();
273 wxNode *node = m_MapList->First();
274 wxExtHelpMapEntry *entry;
275
276 {
277 wxBusyCursor b; // display a busy cursor
278 compA = k; compA.LowerCase(); // we compare case insensitive
279 while(node)
280 {
281 entry = (wxExtHelpMapEntry *)node->Data();
282 compB = entry->doc; compB.LowerCase();
283 if((showAll || compB.Contains(k)) && ! compB.IsEmpty())
284 {
285 urls[idx] = entry->url;
286 // doesn't work:
287 // choices[idx] = (**i).doc.Contains((**i).doc.Before(WXEXTHELP_COMMENTCHAR));
288 //if(choices[idx].IsEmpty()) // didn't contain the ';'
289 // choices[idx] = (**i).doc;
290 choices[idx] = "";
291 for(j=0;entry->doc.c_str()[j]
292 && entry->doc.c_str()[j] != WXEXTHELP_COMMENTCHAR; j++)
293 choices[idx] << entry->doc.c_str()[j];
294 idx++;
295 }
296 node = node->Next();
297 }
298 }
299
300 if(idx == 1)
301 rc = DisplayHelp(urls[0]);
302 else if(idx == 0)
303 {
304 wxMessageBox(_("No entries found."));
305 rc = FALSE;
306 }
307 else
308 {
309 idx = wxGetSingleChoiceIndex(showAll ? _("Help Index") : _("Relevant entries:"),
310 showAll ? _("Help Index") : _("Entries found"),
311 idx,choices);
312 if(idx != -1)
313 rc = DisplayHelp(urls[idx]);
314 else
315 rc = FALSE;
316 }
317 delete[] urls;
318 delete[] choices;
319
320 return rc;
321 }
322
323
324 bool
325 wxHTMLHelpControllerBase::Quit()
326 {
327 return TRUE;
328 }
329
330 void
331 wxHTMLHelpControllerBase::OnQuit()
332 {
333 }
334
335 #endif // wxUSE_HELP