1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: XML resource compiler
4 // Author: Vaclav Slavik, Eduardo Marques <edrdo@netcabo.pt>
7 // Copyright: (c) 2000 Vaclav Slavik
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
11 // For compilers that support precompilation, includes "wx/wx.h".
12 #include "wx/wxprec.h"
18 // for all others, include the necessary headers
22 #include "wx/wxcrtvararg.h"
25 #include "wx/cmdline.h"
26 #include "wx/xml/xml.h"
28 #include "wx/filename.h"
29 #include "wx/wfstream.h"
31 #include "wx/hashset.h"
32 #include "wx/mimetype.h"
34 WX_DECLARE_HASH_SET(wxString
, wxStringHash
, wxStringEqual
, StringSet
);
39 XRCWidgetData(const wxString
& vname
,const wxString
& vclass
)
40 : m_class(vclass
), m_name(vname
) {}
41 const wxString
& GetName() const { return m_name
; }
42 const wxString
& GetClass() const { return m_class
; }
48 #include "wx/arrimpl.cpp"
49 WX_DECLARE_OBJARRAY(XRCWidgetData
,ArrayOfXRCWidgetData
);
50 WX_DEFINE_OBJARRAY(ArrayOfXRCWidgetData
)
56 wxString m_parentClassName
;
57 StringSet m_ancestorClassNames
;
58 ArrayOfXRCWidgetData m_wdata
;
60 void BrowseXmlNode(wxXmlNode
* node
)
67 if (node
->GetName() == _T("object")
68 && node
->GetAttribute(_T("class"),&classValue
)
69 && node
->GetAttribute(_T("name"),&nameValue
))
71 m_wdata
.Add(XRCWidgetData(nameValue
,classValue
));
73 children
= node
->GetChildren();
75 BrowseXmlNode(children
);
76 node
= node
->GetNext();
81 XRCWndClassData(const wxString
& className
,
82 const wxString
& parentClassName
,
83 const wxXmlNode
* node
) :
84 m_className(className
) , m_parentClassName(parentClassName
)
86 if ( className
== _T("wxMenu") )
88 m_ancestorClassNames
.insert(_T("wxMenu"));
89 m_ancestorClassNames
.insert(_T("wxMenuBar"));
91 else if ( className
== _T("wxMDIChildFrame") )
93 m_ancestorClassNames
.insert(_T("wxMDIParentFrame"));
95 else if( className
== _T("wxMenuBar") ||
96 className
== _T("wxStatusBar") ||
97 className
== _T("wxToolBar") )
99 m_ancestorClassNames
.insert(_T("wxFrame"));
103 m_ancestorClassNames
.insert(_T("wxWindow"));
106 BrowseXmlNode(node
->GetChildren());
109 const ArrayOfXRCWidgetData
& GetWidgetData()
114 bool CanBeUsedWithXRCCTRL(const wxString
& name
)
116 if (name
== _T("tool") ||
117 name
== _T("data") ||
118 name
== _T("unknown") ||
119 name
== _T("notebookpage") ||
120 name
== _T("separator") ||
121 name
== _T("sizeritem") ||
122 name
== _T("wxMenuBar") ||
123 name
== _T("wxMenuItem") ||
124 name
== _T("wxStaticBoxSizer") )
131 void GenerateHeaderCode(wxFFile
& file
)
134 file
.Write(_T("class ") + m_className
+ _T(" : public ") + m_parentClassName
135 + _T(" {\nprotected:\n"));
137 for(i
=0;i
<m_wdata
.GetCount();++i
)
139 const XRCWidgetData
& w
= m_wdata
.Item(i
);
140 if( !CanBeUsedWithXRCCTRL(w
.GetClass()) ) continue;
141 if( w
.GetName().Length() == 0 ) continue;
143 _T(" ") + w
.GetClass() + _T("* ") + w
.GetName()
146 file
.Write(_T("\nprivate:\n void InitWidgetsFromXRC(wxWindow *parent){\n")
147 _T(" wxXmlResource::Get()->LoadObject(this,parent,_T(\"")
152 for(i
=0;i
<m_wdata
.GetCount();++i
)
154 const XRCWidgetData
& w
= m_wdata
.Item(i
);
155 if( !CanBeUsedWithXRCCTRL(w
.GetClass()) ) continue;
156 if( w
.GetName().Length() == 0 ) continue;
159 + _T(" = XRCCTRL(*this,\"")
165 file
.Write(_T(" }\n"));
167 file
.Write( _T("public:\n"));
169 if ( m_ancestorClassNames
.size() == 1 )
175 *m_ancestorClassNames
.begin() +
176 _T(" *parent=NULL){\n") +
177 _T(" InitWidgetsFromXRC((wxWindow *)parent);\n")
184 file
.Write(m_className
+ _T("(){\n") +
185 _T(" InitWidgetsFromXRC(NULL);\n")
189 for ( StringSet::const_iterator it
= m_ancestorClassNames
.begin();
190 it
!= m_ancestorClassNames
.end();
193 file
.Write(m_className
+ _T("(") + *it
+ _T(" *parent){\n") +
194 _T(" InitWidgetsFromXRC((wxWindow *)parent);\n")
201 WX_DECLARE_OBJARRAY(XRCWndClassData
,ArrayOfXRCWndClassData
);
202 WX_DEFINE_OBJARRAY(ArrayOfXRCWndClassData
)
205 class XmlResApp
: public wxAppConsole
208 // don't use builtin cmd line parsing:
209 virtual bool OnInit() { return true; }
213 void ParseParams(const wxCmdLineParser
& cmdline
);
215 wxArrayString
PrepareTempFiles();
216 void FindFilesInXML(wxXmlNode
*node
, wxArrayString
& flist
, const wxString
& inputPath
);
218 wxString
GetInternalFileName(const wxString
& name
, const wxArrayString
& flist
);
219 void DeleteTempFiles(const wxArrayString
& flist
);
220 void MakePackageZIP(const wxArrayString
& flist
);
221 void MakePackageCPP(const wxArrayString
& flist
);
222 void MakePackagePython(const wxArrayString
& flist
);
224 void OutputGettext();
225 wxArrayString
FindStrings();
226 wxArrayString
FindStrings(wxXmlNode
*node
);
228 bool flagVerbose
, flagCPP
, flagPython
, flagGettext
;
229 wxString parOutput
, parFuncname
, parOutputPath
;
230 wxArrayString parFiles
;
233 ArrayOfXRCWndClassData aXRCWndClassData
;
238 IMPLEMENT_APP_CONSOLE(XmlResApp
)
240 int XmlResApp::OnRun()
242 static const wxCmdLineEntryDesc cmdLineDesc
[] =
244 { wxCMD_LINE_SWITCH
, "h", "help", "show help message", wxCMD_LINE_VAL_NONE
, wxCMD_LINE_OPTION_HELP
},
245 { wxCMD_LINE_SWITCH
, "v", "verbose", "be verbose" },
246 { wxCMD_LINE_SWITCH
, "e", "extra-cpp-code", "output C++ header file with XRC derived classes" },
247 { wxCMD_LINE_SWITCH
, "c", "cpp-code", "output C++ source rather than .rsc file" },
248 { wxCMD_LINE_SWITCH
, "p", "python-code", "output wxPython source rather than .rsc file" },
249 { wxCMD_LINE_SWITCH
, "g", "gettext", "output list of translatable strings (to stdout or file if -o used)" },
250 { wxCMD_LINE_OPTION
, "n", "function", "C++/Python function name (with -c or -p) [InitXmlResource]" },
251 { wxCMD_LINE_OPTION
, "o", "output", "output file [resource.xrs/cpp]" },
252 #if 0 // not yet implemented
253 { wxCMD_LINE_OPTION
, "l", "list-of-handlers", "output list of necessary handlers to this file" },
255 { wxCMD_LINE_PARAM
, NULL
, NULL
, "input file(s)",
256 wxCMD_LINE_VAL_STRING
,
257 wxCMD_LINE_PARAM_MULTIPLE
| wxCMD_LINE_OPTION_MANDATORY
},
262 wxCmdLineParser
parser(cmdLineDesc
, argc
, argv
);
264 switch (parser
.Parse())
284 void XmlResApp::ParseParams(const wxCmdLineParser
& cmdline
)
286 flagGettext
= cmdline
.Found("g");
287 flagVerbose
= cmdline
.Found("v");
288 flagCPP
= cmdline
.Found("c");
289 flagPython
= cmdline
.Found("p");
290 flagH
= flagCPP
&& cmdline
.Found("e");
293 if (!cmdline
.Found("o", &parOutput
))
296 parOutput
= wxEmptyString
;
300 parOutput
= _T("resource.cpp");
302 parOutput
= _T("resource.py");
304 parOutput
= _T("resource.xrs");
307 if (!parOutput
.empty())
309 wxFileName
fn(parOutput
);
311 parOutput
= fn
.GetFullPath();
312 parOutputPath
= wxPathOnly(parOutput
);
314 if (!parOutputPath
) parOutputPath
= _T(".");
316 if (!cmdline
.Found("n", &parFuncname
))
317 parFuncname
= _T("InitXmlResource");
319 for (size_t i
= 0; i
< cmdline
.GetParamCount(); i
++)
322 wxString fn
=wxFindFirstFile(cmdline
.GetParam(i
), wxFILE
);
329 parFiles
.Add(cmdline
.GetParam(i
));
337 void XmlResApp::CompileRes()
339 wxArrayString files
= PrepareTempFiles();
341 wxRemoveFile(parOutput
);
346 MakePackageCPP(files
);
351 MakePackagePython(files
);
353 MakePackageZIP(files
);
356 DeleteTempFiles(files
);
360 wxString
XmlResApp::GetInternalFileName(const wxString
& name
, const wxArrayString
& flist
)
362 wxString name2
= name
;
363 name2
.Replace(_T(":"), _T("_"));
364 name2
.Replace(_T("/"), _T("_"));
365 name2
.Replace(_T("\\"), _T("_"));
366 name2
.Replace(_T("*"), _T("_"));
367 name2
.Replace(_T("?"), _T("_"));
369 wxString s
= wxFileNameFromPath(parOutput
) + _T("$") + name2
;
371 if (wxFileExists(s
) && flist
.Index(s
) == wxNOT_FOUND
)
373 for (int i
= 0;; i
++)
375 s
.Printf(wxFileNameFromPath(parOutput
) + _T("$%03i-") + name2
, i
);
376 if (!wxFileExists(s
) || flist
.Index(s
) != wxNOT_FOUND
)
383 wxArrayString
XmlResApp::PrepareTempFiles()
387 for (size_t i
= 0; i
< parFiles
.GetCount(); i
++)
390 wxPrintf(_T("processing ") + parFiles
[i
] + _T("...\n"));
394 if (!doc
.Load(parFiles
[i
]))
396 wxLogError(_T("Error parsing file ") + parFiles
[i
]);
401 wxString name
, ext
, path
;
402 wxSplitPath(parFiles
[i
], &path
, &name
, &ext
);
404 FindFilesInXML(doc
.GetRoot(), flist
, path
);
407 wxXmlNode
* node
= (doc
.GetRoot())->GetChildren();
408 wxString classValue
,nameValue
;
410 if(node
->GetName() == _T("object")
411 && node
->GetAttribute(_T("class"),&classValue
)
412 && node
->GetAttribute(_T("name"),&nameValue
)){
414 aXRCWndClassData
.Add(
415 XRCWndClassData(nameValue
,classValue
,node
)
418 node
= node
-> GetNext();
421 wxString internalName
= GetInternalFileName(parFiles
[i
], flist
);
423 doc
.Save(parOutputPath
+ wxFILE_SEP_PATH
+ internalName
);
424 flist
.Add(internalName
);
431 // Does 'node' contain filename information at all?
432 static bool NodeContainsFilename(wxXmlNode
*node
)
434 const wxString name
= node
->GetName();
436 // Any bitmaps (bitmap2 is used for disabled toolbar buttons):
437 if ( name
== _T("bitmap") || name
== _T("bitmap2") )
440 if ( name
== _T("icon") )
444 wxXmlNode
*parent
= node
->GetParent();
445 if (parent
!= NULL
&&
446 parent
->GetAttribute(_T("class"), _T("")) == _T("wxBitmapButton") &&
447 (name
== _T("focus") ||
448 name
== _T("disabled") ||
449 name
== _T("hover") ||
450 name
== _T("selected")))
453 // wxBitmap or wxIcon toplevel resources:
454 if ( name
== _T("object") )
456 wxString klass
= node
->GetAttribute(_T("class"), wxEmptyString
);
457 if (klass
== _T("wxBitmap") ||
458 klass
== _T("wxIcon") ||
459 klass
== _T("data") )
463 // URLs in wxHtmlWindow:
464 if ( name
== _T("url") &&
466 parent
->GetAttribute(_T("class"), _T("")) == _T("wxHtmlWindow") )
468 // FIXME: this is wrong for e.g. http:// URLs
475 // find all files mentioned in structure, e.g. <bitmap>filename</bitmap>
476 void XmlResApp::FindFilesInXML(wxXmlNode
*node
, wxArrayString
& flist
, const wxString
& inputPath
)
478 // Is 'node' XML node element?
479 if (node
== NULL
) return;
480 if (node
->GetType() != wxXML_ELEMENT_NODE
) return;
482 bool containsFilename
= NodeContainsFilename(node
);
484 wxXmlNode
*n
= node
->GetChildren();
487 if (containsFilename
&&
488 (n
->GetType() == wxXML_TEXT_NODE
||
489 n
->GetType() == wxXML_CDATA_SECTION_NODE
))
492 if (wxIsAbsolutePath(n
->GetContent()) || inputPath
.empty())
493 fullname
= n
->GetContent();
495 fullname
= inputPath
+ wxFILE_SEP_PATH
+ n
->GetContent();
498 wxPrintf(_T("adding ") + fullname
+ _T("...\n"));
500 wxString filename
= GetInternalFileName(n
->GetContent(), flist
);
501 n
->SetContent(filename
);
503 if (flist
.Index(filename
) == wxNOT_FOUND
)
506 wxFileInputStream
sin(fullname
);
507 wxFileOutputStream
sout(parOutputPath
+ wxFILE_SEP_PATH
+ filename
);
508 sin
.Read(sout
); // copy the stream
512 if (n
->GetType() == wxXML_ELEMENT_NODE
)
513 FindFilesInXML(n
, flist
, inputPath
);
521 void XmlResApp::DeleteTempFiles(const wxArrayString
& flist
)
523 for (size_t i
= 0; i
< flist
.GetCount(); i
++)
524 wxRemoveFile(parOutputPath
+ wxFILE_SEP_PATH
+ flist
[i
]);
529 void XmlResApp::MakePackageZIP(const wxArrayString
& flist
)
533 for (size_t i
= 0; i
< flist
.GetCount(); i
++)
534 files
+= flist
[i
] + _T(" ");
538 wxPrintf(_T("compressing ") + parOutput
+ _T("...\n"));
540 wxString cwd
= wxGetCwd();
541 wxSetWorkingDirectory(parOutputPath
);
542 int execres
= wxExecute(_T("zip -9 -j ") +
543 wxString(flagVerbose
? _T("\"") : _T("-q \"")) +
544 parOutput
+ _T("\" ") + files
, true);
545 wxSetWorkingDirectory(cwd
);
548 wxLogError(_T("Unable to execute zip program. Make sure it is in the path."));
549 wxLogError(_T("You can download it at http://www.cdrom.com/pub/infozip/"));
557 static wxString
FileToCppArray(wxString filename
, int num
)
562 wxFFile
file(filename
, wxT("rb"));
563 wxFileOffset offset
= file
.Length();
564 wxASSERT_MSG( offset
>= 0 , wxT("Invalid file length") );
566 const size_t lng
= wx_truncate_cast(size_t, offset
);
567 wxASSERT_MSG( lng
== offset
, wxT("Huge file not supported") );
569 snum
.Printf(_T("%i"), num
);
570 output
.Printf(_T("static size_t xml_res_size_") + snum
+ _T(" = %i;\n"), lng
);
571 output
+= _T("static unsigned char xml_res_file_") + snum
+ _T("[] = {\n");
572 // we cannot use string literals because MSVC is dumb wannabe compiler
573 // with arbitrary limitation to 2048 strings :(
575 unsigned char *buffer
= new unsigned char[lng
];
576 file
.Read(buffer
, lng
);
578 for (size_t i
= 0, linelng
= 0; i
< lng
; i
++)
580 tmp
.Printf(_T("%i"), buffer
[i
]);
581 if (i
!= 0) output
<< _T(',');
588 linelng
+= tmp
.Length()+1;
593 output
+= _T("};\n\n");
599 void XmlResApp::MakePackageCPP(const wxArrayString
& flist
)
601 wxFFile
file(parOutput
, wxT("wt"));
605 wxPrintf(_T("creating C++ source file ") + parOutput
+ _T("...\n"));
609 "// This file was automatically generated by wxrc, do not edit by hand.\n"
611 "#include <wx/wxprec.h>\n"
613 "#ifdef __BORLANDC__\n"
618 "#include <wx/filesys.h>\n"
619 "#include <wx/fs_mem.h>\n"
620 "#include <wx/xrc/xmlres.h>\n"
621 "#include <wx/xrc/xh_all.h>\n"
623 "#if wxCHECK_VERSION(2,8,5) && wxABI_VERSION >= 20805\n"
624 " #define XRC_ADD_FILE(name, data, size, mime) \\\n"
625 " wxMemoryFSHandler::AddFileWithMimeType(name, data, size, mime)\n"
627 " #define XRC_ADD_FILE(name, data, size, mime) \\\n"
628 " wxMemoryFSHandler::AddFile(name, data, size)\n"
632 for (i
= 0; i
< flist
.GetCount(); i
++)
634 FileToCppArray(parOutputPath
+ wxFILE_SEP_PATH
+ flist
[i
], i
));
637 "void " + parFuncname
+ "()\n"
640 " // Check for memory FS. If not present, load the handler:\n"
642 " wxMemoryFSHandler::AddFile(wxT(\"XRC_resource/dummy_file\"), wxT(\"dummy one\"));\n"
643 " wxFileSystem fsys;\n"
644 " wxFSFile *f = fsys.OpenFile(wxT(\"memory:XRC_resource/dummy_file\"));\n"
645 " wxMemoryFSHandler::RemoveFile(wxT(\"XRC_resource/dummy_file\"));\n"
646 " if (f) delete f;\n"
647 " else wxFileSystem::AddHandler(new wxMemoryFSHandler);\n"
651 for (i
= 0; i
< flist
.GetCount(); i
++)
656 wxString ext
= wxFileName(flist
[i
]).GetExt();
657 if ( ext
.Lower() == _T("xrc") )
658 mime
= _T("text/xml");
661 wxFileType
*ft
= wxTheMimeTypesManager
->GetFileTypeFromExtension(ext
);
663 ft
->GetMimeType(&mime
);
666 s
.Printf(" XRC_ADD_FILE(wxT(\"XRC_resource/" + flist
[i
] +
667 "\"), xml_res_file_%i, xml_res_size_%i, _T(\"%s\"));\n",
672 for (i
= 0; i
< parFiles
.GetCount(); i
++)
674 file
.Write(" wxXmlResource::Get()->Load(wxT(\"memory:XRC_resource/" +
675 GetInternalFileName(parFiles
[i
], flist
) + "\"));\n");
683 void XmlResApp::GenCPPHeader()
685 wxString fileSpec
= ((parOutput
.BeforeLast('.')).AfterLast('/')).AfterLast('\\');
686 wxString heaFileName
= fileSpec
+ _T(".h");
688 wxFFile
file(heaFileName
, wxT("wt"));
691 "// This file was automatically generated by wxrc, do not edit by hand.\n"
693 "#ifndef __" + fileSpec
+ "_h__\n"
694 "#define __" + fileSpec
+ "_h__\n"
696 for(size_t i
=0;i
<aXRCWndClassData
.GetCount();++i
){
697 aXRCWndClassData
.Item(i
).GenerateHeaderCode(file
);
705 static wxString
FileToPythonArray(wxString filename
, int num
)
710 wxFFile
file(filename
, wxT("rb"));
711 wxFileOffset offset
= file
.Length();
712 wxASSERT_MSG( offset
>= 0 , wxT("Invalid file length") );
714 const size_t lng
= wx_truncate_cast(size_t, offset
);
715 wxASSERT_MSG( offset
== lng
, wxT("Huge file not supported") );
717 snum
.Printf(_T("%i"), num
);
718 output
= " xml_res_file_" + snum
+ " = '''\\\n";
720 unsigned char *buffer
= new unsigned char[lng
];
721 file
.Read(buffer
, lng
);
723 for (size_t i
= 0, linelng
= 0; i
< lng
; i
++)
725 unsigned char c
= buffer
[i
];
731 else if (c
< 32 || c
> 127 || c
== '\'')
732 tmp
.Printf(_T("\\x%02x"), c
);
740 output
<< _T("\\\n");
743 linelng
+= tmp
.Length();
748 output
+= _T("'''\n\n");
754 void XmlResApp::MakePackagePython(const wxArrayString
& flist
)
756 wxFFile
file(parOutput
, wxT("wt"));
760 wxPrintf(_T("creating Python source file ") + parOutput
+ _T("...\n"));
764 "# This file was automatically generated by wxrc, do not edit by hand.\n"
771 file
.Write("def " + parFuncname
+ "():\n");
773 for (i
= 0; i
< flist
.GetCount(); i
++)
775 FileToPythonArray(parOutputPath
+ wxFILE_SEP_PATH
+ flist
[i
], i
));
778 " # check if the memory filesystem handler has been loaded yet, and load it if not\n"
779 " wx.MemoryFSHandler.AddFile('XRC_resource/dummy_file', 'dummy value')\n"
780 " fsys = wx.FileSystem()\n"
781 " f = fsys.OpenFile('memory:XRC_resource/dummy_file')\n"
782 " wx.MemoryFSHandler.RemoveFile('XRC_resource/dummy_file')\n"
783 " if f is not None:\n"
786 " wx.FileSystem.AddHandler(wx.MemoryFSHandler())\n"
788 " # load all the strings as memory files and load into XmlRes\n"
792 for (i
= 0; i
< flist
.GetCount(); i
++)
795 s
.Printf(" wx.MemoryFSHandler.AddFile('XRC_resource/" + flist
[i
] +
796 "', xml_res_file_%i)\n", i
);
799 for (i
= 0; i
< parFiles
.GetCount(); i
++)
801 file
.Write(" wx.xrc.XmlResource.Get().Load('memory:XRC_resource/" +
802 GetInternalFileName(parFiles
[i
], flist
) + "')\n");
810 void XmlResApp::OutputGettext()
812 wxArrayString str
= FindStrings();
815 if (parOutput
.empty())
818 fout
.Open(parOutput
, wxT("wt"));
820 for (size_t i
= 0; i
< str
.GetCount(); i
++)
821 fout
.Write("_(\"" + str
[i
] + "\");\n");
823 if (!parOutput
) fout
.Detach();
828 wxArrayString
XmlResApp::FindStrings()
830 wxArrayString arr
, a2
;
832 for (size_t i
= 0; i
< parFiles
.GetCount(); i
++)
835 wxPrintf(_T("processing ") + parFiles
[i
] + _T("...\n"));
838 if (!doc
.Load(parFiles
[i
]))
840 wxLogError(_T("Error parsing file ") + parFiles
[i
]);
844 a2
= FindStrings(doc
.GetRoot());
845 WX_APPEND_ARRAY(arr
, a2
);
853 static wxString
ConvertText(const wxString
& str
)
858 for (dt
= str
.c_str(); *dt
; dt
++)
862 if ( *(++dt
) == wxT('_') )
865 str2
<< wxT('&') << *dt
;
871 case wxT('\n') : str2
<< wxT("\\n"); break;
872 case wxT('\t') : str2
<< wxT("\\t"); break;
873 case wxT('\r') : str2
<< wxT("\\r"); break;
874 case wxT('\\') : if ((*(dt
+1) != 'n') &&
881 case wxT('"') : str2
<< wxT("\\\""); break;
882 default : str2
<< *dt
; break;
891 wxArrayString
XmlResApp::FindStrings(wxXmlNode
*node
)
896 if (n
== NULL
) return arr
;
897 n
= n
->GetChildren();
901 if ((node
->GetType() == wxXML_ELEMENT_NODE
) &&
902 // parent is an element, i.e. has subnodes...
903 (n
->GetType() == wxXML_TEXT_NODE
||
904 n
->GetType() == wxXML_CDATA_SECTION_NODE
) &&
905 // ...it is textnode...
907 node
/*not n!*/->GetName() == _T("label") ||
908 (node
/*not n!*/->GetName() == _T("value") &&
909 !n
->GetContent().IsNumber()) ||
910 node
/*not n!*/->GetName() == _T("help") ||
911 node
/*not n!*/->GetName() == _T("longhelp") ||
912 node
/*not n!*/->GetName() == _T("tooltip") ||
913 node
/*not n!*/->GetName() == _T("htmlcode") ||
914 node
/*not n!*/->GetName() == _T("title") ||
915 node
/*not n!*/->GetName() == _T("item")
917 // ...and known to contain translatable string
920 node
->GetAttribute(_T("translate"), _T("1")) != _T("0"))
922 arr
.Add(ConvertText(n
->GetContent()));
927 if (n
->GetType() == wxXML_ELEMENT_NODE
)
929 wxArrayString a2
= FindStrings(n
);
930 WX_APPEND_ARRAY(arr
, a2
);