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