]> git.saurik.com Git - wxWidgets.git/blame - utils/wxrc/wxrc.cpp
added bakefile format manifest
[wxWidgets.git] / utils / wxrc / wxrc.cpp
CommitLineData
56d2f750
VS
1/////////////////////////////////////////////////////////////////////////////
2// Name: wxrc.cpp
3// Purpose: XML resource compiler
4// Author: Vaclav Slavik
5// Created: 2000/03/05
6// RCS-ID: $Id$
7// Copyright: (c) 2000 Vaclav Slavik
8// Licence: wxWindows licence
9/////////////////////////////////////////////////////////////////////////////
10
ab7ce33c 11#if defined(__GNUG__) && !defined(__APPLE__)
56d2f750
VS
12 #pragma implementation
13 #pragma interface
14#endif
15
16// For compilers that support precompilation, includes "wx/wx.h".
17#include "wx/wxprec.h"
18
19#ifdef __BORLANDC__
20 #pragma hdrstop
21#endif
22
23// for all others, include the necessary headers (this file is usually all you
24// need because it includes almost all "standard" wxWindows headers
25#ifndef WX_PRECOMP
26 #include "wx/wx.h"
27#endif
28
29#include "wx/cmdline.h"
cecc483e 30#include "wx/xml/xml.h"
56d2f750 31#include "wx/ffile.h"
4249ec2c 32#include "wx/filename.h"
f6853b4a
VS
33#include "wx/wfstream.h"
34
35
cecc483e 36class XmlResApp : public wxAppConsole
56d2f750
VS
37{
38public:
031dfec8 39
56d2f750
VS
40 virtual int OnRun();
41
42private:
43
44 void ParseParams(const wxCmdLineParser& cmdline);
45 void CompileRes();
46 wxArrayString PrepareTempFiles();
f6853b4a
VS
47 void FindFilesInXML(wxXmlNode *node, wxArrayString& flist, const wxString& inputPath);
48
a7501aeb 49 wxString GetInternalFileName(const wxString& name, const wxArrayString& flist);
56d2f750
VS
50 void DeleteTempFiles(const wxArrayString& flist);
51 void MakePackageZIP(const wxArrayString& flist);
52 void MakePackageCPP(const wxArrayString& flist);
b8b8c49b 53 void MakePackagePython(const wxArrayString& flist);
c8b7a961
VS
54
55 void OutputGettext();
56 wxArrayString FindStrings();
57 wxArrayString FindStrings(wxXmlNode *node);
56d2f750 58
b8b8c49b 59 bool flagVerbose, flagCPP, flagPython, flagGettext;
56d2f750
VS
60 wxString parOutput, parFuncname, parOutputPath;
61 wxArrayString parFiles;
62 int retCode;
63};
64
65IMPLEMENT_APP(XmlResApp)
66
67int XmlResApp::OnRun()
68{
69 static const wxCmdLineEntryDesc cmdLineDesc[] =
70 {
2b5f62a0 71 { wxCMD_LINE_SWITCH, _T("h"), _T("help"), _T("show help message"),
99cd20be 72 wxCMD_LINE_VAL_NONE, wxCMD_LINE_OPTION_HELP },
2b5f62a0
VZ
73 { wxCMD_LINE_SWITCH, _T("v"), _T("verbose"), _T("be verbose") },
74 { wxCMD_LINE_SWITCH, _T("c"), _T("cpp-code"), _T("output C++ source rather than .rsc file") },
75 { wxCMD_LINE_SWITCH, _T("p"), _T("python-code"), _T("output wxPython source rather than .rsc file") },
76 { wxCMD_LINE_SWITCH, _T("g"), _T("gettext"), _T("output list of translatable strings (to stdout or file if -o used)") },
77 { wxCMD_LINE_OPTION, _T("n"), _T("function"), _T("C++/Python function name (with -c or -p) [InitXmlResource]") },
78 { wxCMD_LINE_OPTION, _T("o"), _T("output"), _T("output file [resource.xrs/cpp]") },
99cd20be 79#if 0 // not yet implemented
2b5f62a0 80 { wxCMD_LINE_OPTION, _T("l"), _T("list-of-handlers", _T("output list of neccessary handlers to this file" },
99cd20be 81#endif
2b5f62a0 82 { wxCMD_LINE_PARAM, NULL, NULL, _T("input file(s)"),
99cd20be
VS
83 wxCMD_LINE_VAL_STRING,
84 wxCMD_LINE_PARAM_MULTIPLE | wxCMD_LINE_OPTION_MANDATORY },
56d2f750
VS
85
86 { wxCMD_LINE_NONE }
87 };
88
89 wxCmdLineParser parser(cmdLineDesc, argc, argv);
90
91 switch (parser.Parse())
92 {
93 case -1:
94 return 0;
95 break;
96
97 case 0:
98 retCode = 0;
99 ParseParams(parser);
c8b7a961
VS
100 if (flagGettext)
101 OutputGettext();
102 else
103 CompileRes();
56d2f750
VS
104 return retCode;
105 break;
106
107 default:
108 return 1;
109 break;
110 }
111}
112
113
114
115
116void XmlResApp::ParseParams(const wxCmdLineParser& cmdline)
117{
2b5f62a0
VZ
118 flagGettext = cmdline.Found(_T("g"));
119 flagVerbose = cmdline.Found(_T("v"));
120 flagCPP = cmdline.Found(_T("c"));
121 flagPython = cmdline.Found(_T("p"));
56d2f750 122
2b5f62a0 123 if (!cmdline.Found(_T("o"), &parOutput))
c8b7a961
VS
124 {
125 if (flagGettext)
126 parOutput = wxEmptyString;
127 else
b8b8c49b
VS
128 {
129 if (flagCPP)
2b5f62a0 130 parOutput = _T("resource.cpp");
b8b8c49b 131 else if (flagPython)
2b5f62a0 132 parOutput = _T("resource.py");
b8b8c49b 133 else
2b5f62a0 134 parOutput = _T("resource.xrs");
b8b8c49b 135 }
c8b7a961 136 }
4249ec2c
VS
137 wxFileName fn(parOutput);
138 fn.Normalize();
139 parOutput = fn.GetFullPath();
56d2f750 140 parOutputPath = wxPathOnly(parOutput);
2b5f62a0 141 if (!parOutputPath) parOutputPath = _T(".");
56d2f750 142
2b5f62a0
VZ
143 if (!cmdline.Found(_T("n"), &parFuncname))
144 parFuncname = _T("InitXmlResource");
56d2f750
VS
145
146 for (size_t i = 0; i < cmdline.GetParamCount(); i++)
f65a69e9
VS
147 {
148#ifdef __WINDOWS__
149 wxString fn=wxFindFirstFile(cmdline.GetParam(i), wxFILE);
150 while (!fn.IsEmpty())
151 {
152 parFiles.Add(fn);
153 fn=wxFindNextFile();
154 }
155#else
56d2f750 156 parFiles.Add(cmdline.GetParam(i));
f65a69e9
VS
157#endif
158 }
56d2f750
VS
159}
160
161
162
163
164void XmlResApp::CompileRes()
165{
166 wxArrayString files = PrepareTempFiles();
167
168 wxRemoveFile(parOutput);
169
56d2f750
VS
170 if (!retCode)
171 {
172 if (flagCPP)
173 MakePackageCPP(files);
b8b8c49b
VS
174 else if (flagPython)
175 MakePackagePython(files);
56d2f750
VS
176 else
177 MakePackageZIP(files);
178 }
179
180 DeleteTempFiles(files);
181}
182
183
a7501aeb
VS
184wxString XmlResApp::GetInternalFileName(const wxString& name, const wxArrayString& flist)
185{
186 wxString name2 = name;
2b5f62a0
VZ
187 name2.Replace(_T(":"), _T("_"));
188 name2.Replace(_T("/"), _T("_"));
189 name2.Replace(_T("\\"), _T("_"));
190 name2.Replace(_T("*"), _T("_"));
191 name2.Replace(_T("?"), _T("_"));
a7501aeb 192
2b5f62a0 193 wxString s = wxFileNameFromPath(parOutput) + _T("$") + name2;
a7501aeb
VS
194
195 if (wxFileExists(s) && flist.Index(s) == wxNOT_FOUND)
196 {
197 for (int i = 0;; i++)
198 {
2b5f62a0 199 s.Printf(wxFileNameFromPath(parOutput) + _T("$%03i-") + name2, i);
a7501aeb
VS
200 if (!wxFileExists(s) || flist.Index(s) != wxNOT_FOUND)
201 break;
202 }
203 }
204 return s;
205}
56d2f750
VS
206
207wxArrayString XmlResApp::PrepareTempFiles()
208{
209 wxArrayString flist;
210
211 for (size_t i = 0; i < parFiles.Count(); i++)
212 {
213 if (flagVerbose)
2b5f62a0 214 wxPrintf(_T("processing ") + parFiles[i] + _T("...\n"));
56d2f750
VS
215
216 wxXmlDocument doc;
217
218 if (!doc.Load(parFiles[i]))
219 {
2b5f62a0 220 wxLogError(_T("Error parsing file ") + parFiles[i]);
56d2f750
VS
221 retCode = 1;
222 continue;
223 }
224
f6853b4a
VS
225 wxString name, ext, path;
226 wxSplitPath(parFiles[i], &path, &name, &ext);
227
228 FindFilesInXML(doc.GetRoot(), flist, path);
56d2f750 229
a7501aeb
VS
230 wxString internalName = GetInternalFileName(parFiles[i], flist);
231
4249ec2c 232 doc.Save(parOutputPath + wxFILE_SEP_PATH + internalName);
a7501aeb 233 flist.Add(internalName);
56d2f750
VS
234 }
235
236 return flist;
237}
238
239
4249ec2c
VS
240// Does 'node' contain filename information at all?
241static bool NodeContainsFilename(wxXmlNode *node)
242{
243 // Any bitmaps:
244 if (node->GetName() == _T("bitmap"))
245 return TRUE;
246
247 // URLs in wxHtmlWindow:
248 if (node->GetName() == _T("url"))
249 return TRUE;
250
251 // wxBitmapButton:
252 wxXmlNode *parent = node->GetParent();
253 if (parent != NULL &&
254 parent->GetPropVal(_T("class"), _T("")) == _T("wxBitmapButton") &&
255 (node->GetName() == _T("focus") ||
256 node->GetName() == _T("disabled") ||
257 node->GetName() == _T("selected")))
258 return TRUE;
259
260 // wxBitmap or wxIcon toplevel resources:
261 if (node->GetName() == _T("object"))
262 {
263 wxString klass = node->GetPropVal(_T("class"), wxEmptyString);
264 if (klass == _T("wxBitmap") || klass == _T("wxIcon"))
265 return TRUE;
266 }
267
268 return FALSE;
269}
56d2f750 270
f6853b4a
VS
271// find all files mentioned in structure, e.g. <bitmap>filename</bitmap>
272void XmlResApp::FindFilesInXML(wxXmlNode *node, wxArrayString& flist, const wxString& inputPath)
273{
2b5f62a0
VZ
274 // Is 'node' XML node element?
275 if (node == NULL) return;
276 if (node->GetType() != wxXML_ELEMENT_NODE) return;
277
4249ec2c 278 bool containsFilename = NodeContainsFilename(node);
2b5f62a0
VZ
279
280 wxXmlNode *n = node->GetChildren();
f6853b4a
VS
281 while (n)
282 {
2b5f62a0 283 if (containsFilename &&
f6853b4a 284 (n->GetType() == wxXML_TEXT_NODE ||
2b5f62a0 285 n->GetType() == wxXML_CDATA_SECTION_NODE))
f6853b4a
VS
286 {
287 wxString fullname;
2b5f62a0
VZ
288 if (wxIsAbsolutePath(n->GetContent()) || inputPath.empty())
289 fullname = n->GetContent();
290 else
4249ec2c 291 fullname = inputPath + wxFILE_SEP_PATH + n->GetContent();
a7501aeb
VS
292
293 if (flagVerbose)
2b5f62a0
VZ
294 wxPrintf(_T("adding ") + fullname + _T("...\n"));
295
a7501aeb 296 wxString filename = GetInternalFileName(n->GetContent(), flist);
f6853b4a 297 n->SetContent(filename);
f6853b4a 298
2b5f62a0
VZ
299 if (flist.Index(filename) == wxNOT_FOUND)
300 flist.Add(filename);
f6853b4a
VS
301
302 wxFileInputStream sin(fullname);
4249ec2c 303 wxFileOutputStream sout(parOutputPath + wxFILE_SEP_PATH + filename);
f6853b4a
VS
304 sin.Read(sout); // copy the stream
305 }
2b5f62a0 306
f6853b4a
VS
307 // subnodes:
308 if (n->GetType() == wxXML_ELEMENT_NODE)
309 FindFilesInXML(n, flist, inputPath);
2b5f62a0 310
f6853b4a
VS
311 n = n->GetNext();
312 }
313}
314
315
316
56d2f750
VS
317void XmlResApp::DeleteTempFiles(const wxArrayString& flist)
318{
319 for (size_t i = 0; i < flist.Count(); i++)
4249ec2c 320 wxRemoveFile(parOutputPath + wxFILE_SEP_PATH + flist[i]);
56d2f750
VS
321}
322
323
324
325void XmlResApp::MakePackageZIP(const wxArrayString& flist)
326{
327 wxString files;
328
329 for (size_t i = 0; i < flist.Count(); i++)
2b5f62a0 330 files += flist[i] + _T(" ");
56d2f750
VS
331 files.RemoveLast();
332
333 if (flagVerbose)
2b5f62a0 334 wxPrintf(_T("compressing ") + parOutput + _T("...\n"));
4249ec2c
VS
335
336 wxString cwd = wxGetCwd();
337 wxSetWorkingDirectory(parOutputPath);
338 int execres = wxExecute(_T("zip -9 -j ") +
339 wxString(flagVerbose ? _T("") : _T("-q ")) +
340 parOutput + _T(" ") + files, TRUE);
341 wxSetWorkingDirectory(cwd);
342 if (execres == -1)
56d2f750 343 {
2b5f62a0
VZ
344 wxLogError(_T("Unable to execute zip program. Make sure it is in the path."));
345 wxLogError(_T("You can download it at http://www.cdrom.com/pub/infozip/"));
56d2f750
VS
346 retCode = 1;
347 return;
348 }
349}
350
351
352
353
354static wxString FileToCppArray(wxString filename, int num)
355{
356 wxString output;
56d2f750 357 wxString tmp;
f6853b4a 358 wxString snum;
5851504d 359 wxFFile file(filename, wxT("rb"));
56d2f750
VS
360 size_t lng = file.Length();
361
2b5f62a0
VZ
362 snum.Printf(_T("%i"), num);
363 output.Printf(_T("static size_t xml_res_size_") + snum + _T(" = %i;\n"), lng);
364 output += _T("static unsigned char xml_res_file_") + snum + _T("[] = {\n");
e066e256
VS
365 // we cannot use string literals because MSVC is dumb wannabe compiler
366 // with arbitrary limitation to 2048 strings :(
56d2f750
VS
367
368 unsigned char *buffer = new unsigned char[lng];
369 file.Read(buffer, lng);
370
f6853b4a 371 for (size_t i = 0, linelng = 0; i < lng; i++)
56d2f750 372 {
2b5f62a0
VZ
373 tmp.Printf(_T("%i"), buffer[i]);
374 if (i != 0) output << _T(',');
e066e256 375 if (linelng > 70)
f6853b4a
VS
376 {
377 linelng = 0;
2b5f62a0 378 output << _T("\n");
f6853b4a 379 }
e066e256
VS
380 output << tmp;
381 linelng += tmp.Length()+1;
56d2f750
VS
382 }
383
384 delete[] buffer;
385
2b5f62a0 386 output += _T("};\n\n");
56d2f750
VS
387
388 return output;
389}
390
391
392void XmlResApp::MakePackageCPP(const wxArrayString& flist)
393{
5851504d 394 wxFFile file(parOutput, wxT("wt"));
56d2f750
VS
395 size_t i;
396
397 if (flagVerbose)
2b5f62a0 398 wxPrintf(_T("creating C++ source file ") + parOutput + _T("...\n"));
56d2f750 399
2b5f62a0
VZ
400 file.Write(_T("")
401_T("//\n")
402_T("// This file was automatically generated by wxrc, do not edit by hand.\n")
403_T("//\n\n")
404_T("#include <wx/wxprec.h>\n")
405_T("\n")
406_T("#ifdef __BORLANDC__\n")
407_T(" #pragma hdrstop\n")
408_T("#endif\n")
409_T("\n")
410_T("#ifndef WX_PRECOMP\n")
411_T(" #include <wx/wx.h>\n")
412_T("#endif\n")
413_T("")
414_T("#include <wx/filesys.h>\n")
415_T("#include <wx/fs_mem.h>\n")
416_T("#include <wx/xrc/xmlres.h>\n")
417_T("#include <wx/xrc/xh_all.h>\n")
418_T("\n"));
56d2f750
VS
419
420 for (i = 0; i < flist.Count(); i++)
4249ec2c
VS
421 file.Write(
422 FileToCppArray(parOutputPath + wxFILE_SEP_PATH + flist[i], i));
56d2f750 423
2b5f62a0 424 file.Write(_T("")
5851504d 425_T("void ") + parFuncname + wxT("()\n")
2b5f62a0
VZ
426_T("{\n")
427_T("\n")
428_T(" // Check for memory FS. If not present, load the handler:\n")
429_T(" {\n")
5851504d 430_T(" wxMemoryFSHandler::AddFile(wxT(\"XRC_resource/dummy_file\"), wxT(\"dummy one\"));\n")
2b5f62a0 431_T(" wxFileSystem fsys;\n")
5851504d
VS
432_T(" wxFSFile *f = fsys.OpenFile(wxT(\"memory:XRC_resource/dummy_file\"));\n")
433_T(" wxMemoryFSHandler::RemoveFile(wxT(\"XRC_resource/dummy_file\"));\n")
2b5f62a0
VZ
434_T(" if (f) delete f;\n")
435_T(" else wxFileSystem::AddHandler(new wxMemoryFSHandler);\n")
436_T(" }\n")
437_T("\n"));
56d2f750
VS
438
439 for (i = 0; i < flist.Count(); i++)
440 {
441 wxString s;
5851504d
VS
442 s.Printf(_T(" wxMemoryFSHandler::AddFile(wxT(\"XRC_resource/") + flist[i] +
443 _T("\"), xml_res_file_%i, xml_res_size_%i);\n"), i, i);
56d2f750
VS
444 file.Write(s);
445 }
f6853b4a
VS
446
447 for (i = 0; i < parFiles.Count(); i++)
448 {
5851504d
VS
449 file.Write(_T(" wxXmlResource::Get()->Load(wxT(\"memory:XRC_resource/") +
450 GetInternalFileName(parFiles[i], flist) + _T("\"));\n"));
f6853b4a 451 }
56d2f750 452
2b5f62a0 453 file.Write(_T("}\n"));
56d2f750 454
f6853b4a 455
56d2f750 456}
c8b7a961 457
b8b8c49b
VS
458static wxString FileToPythonArray(wxString filename, int num)
459{
460 wxString output;
461 wxString tmp;
462 wxString snum;
5851504d 463 wxFFile file(filename, wxT("rb"));
b8b8c49b
VS
464 size_t lng = file.Length();
465
2b5f62a0
VZ
466 snum.Printf(_T("%i"), num);
467 output = _T(" xml_res_file_") + snum + _T(" = \"\"\"\\\n");
b8b8c49b
VS
468
469 unsigned char *buffer = new unsigned char[lng];
470 file.Read(buffer, lng);
471
472 for (size_t i = 0, linelng = 0; i < lng; i++)
473 {
474 unsigned char c = buffer[i];
475 if (c == '\n')
476 {
477 tmp = (wxChar)c;
478 linelng = 0;
479 }
480 else if (c < 32 || c > 127)
2b5f62a0 481 tmp.Printf(_T("\\x%02x"), c);
b8b8c49b 482 else if (c == '\\')
2b5f62a0 483 tmp = _T("\\\\");
b8b8c49b
VS
484 else
485 tmp = (wxChar)c;
486 if (linelng > 70)
487 {
488 linelng = 0;
2b5f62a0 489 output << _T("\\\n");
b8b8c49b
VS
490 }
491 output << tmp;
492 linelng += tmp.Length();
493 }
494
495 delete[] buffer;
496
2b5f62a0 497 output += _T("\"\"\"\n\n");
b8b8c49b
VS
498
499 return output;
500}
501
502
503void XmlResApp::MakePackagePython(const wxArrayString& flist)
504{
5851504d 505 wxFFile file(parOutput, wxT("wt"));
b8b8c49b
VS
506 size_t i;
507
508 if (flagVerbose)
2b5f62a0 509 wxPrintf(_T("creating Python source file ") + parOutput + _T("...\n"));
b8b8c49b
VS
510
511 file.Write(
2b5f62a0
VZ
512 _T("#\n")
513 _T("# This file was automatically generated by wxrc, do not edit by hand.\n")
514 _T("#\n\n")
515 _T("from wxPython.wx import *\n")
516 _T("from wxPython.xrc import *\n\n")
b8b8c49b
VS
517 );
518
519
2b5f62a0 520 file.Write(_T("def ") + parFuncname + _T("():\n"));
b8b8c49b
VS
521
522 for (i = 0; i < flist.Count(); i++)
4249ec2c
VS
523 file.Write(
524 FileToPythonArray(parOutputPath + wxFILE_SEP_PATH + flist[i], i));
b8b8c49b
VS
525
526 for (i = 0; i < flist.Count(); i++)
527 {
528 wxString s;
2b5f62a0 529 s.Printf(_T(" wxXmlResource_Get().LoadFromString(xml_res_file_%i)\n"), i);
b8b8c49b
VS
530 file.Write(s);
531 }
532}
533
c8b7a961
VS
534
535
536void XmlResApp::OutputGettext()
537{
538 wxArrayString str = FindStrings();
539
540 wxFFile fout;
541 if (!parOutput) fout.Attach(stdout);
5851504d 542 else fout.Open(parOutput, wxT("wt"));
c8b7a961
VS
543
544 for (size_t i = 0; i < str.GetCount(); i++)
0653d364 545 fout.Write(_T("_(\"") + str[i] + _T("\");\n"));
c8b7a961
VS
546
547 if (!parOutput) fout.Detach();
548}
549
550
551
552wxArrayString XmlResApp::FindStrings()
553{
554 wxArrayString arr, a2;
555
556 for (size_t i = 0; i < parFiles.Count(); i++)
557 {
558 if (flagVerbose)
2b5f62a0 559 wxPrintf(_T("processing ") + parFiles[i] + _T("...\n"));
c8b7a961
VS
560
561 wxXmlDocument doc;
562 if (!doc.Load(parFiles[i]))
563 {
2b5f62a0 564 wxLogError(_T("Error parsing file ") + parFiles[i]);
c8b7a961
VS
565 retCode = 1;
566 continue;
567 }
568 a2 = FindStrings(doc.GetRoot());
569 WX_APPEND_ARRAY(arr, a2);
570 }
571
572 return arr;
573}
574
575
576
c109ef11
VS
577static wxString ConvertText(const wxString& str)
578{
579 wxString str2;
580 const wxChar *dt;
581
582 for (dt = str.c_str(); *dt; dt++)
583 {
584 if (*dt == wxT('_'))
585 {
586 if ( *(++dt) == wxT('_') )
587 str2 << wxT('_');
588 else
589 str2 << wxT('&') << *dt;
590 }
591 else
592 {
593 switch (*dt)
594 {
595 case wxT('\n') : str2 << wxT("\\n"); break;
596 case wxT('\t') : str2 << wxT("\\t"); break;
597 case wxT('\r') : str2 << wxT("\\r"); break;
2b5f62a0
VZ
598 case wxT('\\') : if ((*(dt+1) != 'n') &&
599 (*(dt+1) != 't') &&
600 (*(dt+1) != 'r'))
601 str2 << wxT("\\\\");
602 else
603 str2 << wxT("\\");
604 break;
904a226c 605 case wxT('"') : str2 << wxT("\\\""); break;
c109ef11
VS
606 default : str2 << *dt; break;
607 }
608 }
609 }
610
611 return str2;
612}
613
614
c8b7a961
VS
615wxArrayString XmlResApp::FindStrings(wxXmlNode *node)
616{
617 wxArrayString arr;
618
619 wxXmlNode *n = node;
620 if (n == NULL) return arr;
621 n = n->GetChildren();
622
623 while (n)
624 {
625 if ((node->GetType() == wxXML_ELEMENT_NODE) &&
626 // parent is an element, i.e. has subnodes...
627 (n->GetType() == wxXML_TEXT_NODE ||
628 n->GetType() == wxXML_CDATA_SECTION_NODE) &&
629 // ...it is textnode...
630 (
631 node/*not n!*/->GetName() == _T("label") ||
632 (node/*not n!*/->GetName() == _T("value") &&
633 !n->GetContent().IsNumber()) ||
634 node/*not n!*/->GetName() == _T("help") ||
635 node/*not n!*/->GetName() == _T("longhelp") ||
636 node/*not n!*/->GetName() == _T("tooltip") ||
637 node/*not n!*/->GetName() == _T("htmlcode") ||
0653d364
VS
638 node/*not n!*/->GetName() == _T("title") ||
639 node/*not n!*/->GetName() == _T("item")
c8b7a961 640 ))
c109ef11 641 // ...and known to contain translatable string
c8b7a961 642 {
c109ef11 643 arr.Add(ConvertText(n->GetContent()));
c8b7a961
VS
644 }
645
646 // subnodes:
647 if (n->GetType() == wxXML_ELEMENT_NODE)
648 {
649 wxArrayString a2 = FindStrings(n);
650 WX_APPEND_ARRAY(arr, a2);
651 }
652
653 n = n->GetNext();
654 }
655 return arr;
656}