Source cleaning, warning fixes.
[wxWidgets.git] / utils / wxrc / wxrc.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: wxrc.cpp
3 // Purpose: XML resource compiler
4 // Author: Vaclav Slavik, Eduardo Marques <edrdo@netcabo.pt>
5 // Created: 2000/03/05
6 // RCS-ID: $Id$
7 // Copyright: (c) 2000 Vaclav Slavik
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
10
11 #if defined(__GNUG__) && !defined(__APPLE__)
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
24 #ifndef WX_PRECOMP
25 #include "wx/app.h"
26 #include "wx/log.h"
27 #endif
28
29 #include "wx/cmdline.h"
30 #include "wx/xml/xml.h"
31 #include "wx/ffile.h"
32 #include "wx/filename.h"
33 #include "wx/wfstream.h"
34
35
36 class XRCWidgetData
37 {
38 public:
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; }
43 private:
44 wxString m_class;
45 wxString m_name;
46 };
47
48 #include "wx/arrimpl.cpp"
49 WX_DECLARE_OBJARRAY(XRCWidgetData,ArrayOfXRCWidgetData);
50 WX_DEFINE_OBJARRAY(ArrayOfXRCWidgetData);
51
52 class XRCWndClassData
53 {
54 private:
55 wxString m_className;
56 wxString m_parentClassName;
57 ArrayOfXRCWidgetData m_wdata;
58
59 void BrowseXmlNode(wxXmlNode* node)
60 {
61 wxString classValue;
62 wxString nameValue;
63 wxXmlNode* children;
64 while (node)
65 {
66 if (node->GetName() == _T("object")
67 && node->GetPropVal(_T("class"),&classValue)
68 && node->GetPropVal(_T("name"),&nameValue))
69 {
70 m_wdata.Add(XRCWidgetData(nameValue,classValue));
71 }
72 children = node->GetChildren();
73 if (children)
74 BrowseXmlNode(children);
75 node = node->GetNext();
76 }
77 }
78
79 public:
80 XRCWndClassData(const wxString& className,const wxString& parentClassName, const wxXmlNode* node) :
81 m_className(className) , m_parentClassName(parentClassName)
82 {
83 BrowseXmlNode(node->GetChildren());
84 }
85
86 const ArrayOfXRCWidgetData& GetWidgetData()
87 {
88 return m_wdata;
89 }
90
91 bool IsRealClass(const wxString& name)
92 {
93 if (name == _T("tool") ||
94 name == _T("unknown") ||
95 name == _T("notebookpage") ||
96 name == _T("separator") ||
97 name == _T("sizeritem") ||
98 name == _T("wxMenuItem"))
99 {
100 return false;
101 }
102 return true;
103 }
104
105 void GenerateHeaderCode(wxFFile& file)
106 {
107
108 file.Write(_T("class ") + m_className + _T(" : public ") + m_parentClassName
109 + _T(" {\nprotected:\n"));
110 size_t i;
111 for(i=0;i<m_wdata.Count();++i)
112 {
113 const XRCWidgetData& w = m_wdata.Item(i);
114 if( !IsRealClass(w.GetClass()) ) continue;
115 if( w.GetName().Length() == 0 ) continue;
116 file.Write(
117 _T(" ") + w.GetClass() + _T("* ") + w.GetName()
118 + _T(";\n"));
119 }
120 file.Write(_T("\nprivate:\n void InitWidgetsFromXRC(){\n")
121 _T(" wxXmlResource::Get()->LoadObject(this,NULL,_T(\"")
122 + m_className
123 + _T("\"), _T(\"")
124 + m_parentClassName
125 + _T("\"));\n"));
126 for(i=0;i<m_wdata.Count();++i)
127 {
128 const XRCWidgetData& w = m_wdata.Item(i);
129 if( !IsRealClass(w.GetClass()) ) continue;
130 if( w.GetName().Length() == 0 ) continue;
131 file.Write( _T(" ")
132 + w.GetName()
133 + _T(" = XRCCTRL(*this,\"")
134 + w.GetName()
135 + _T("\",")
136 + w.GetClass()
137 + _T(");\n")
138 );
139 }
140 file.Write(_T(" }\n"));
141
142 file.Write(
143 _T("public:\n")
144 + m_className
145 + _T("::")
146 + m_className
147 + _T("(){\n")
148 + _T(" InitWidgetsFromXRC();\n")
149 _T(" }\n")
150 _T("};\n")
151 );
152 };
153 };
154 WX_DECLARE_OBJARRAY(XRCWndClassData,ArrayOfXRCWndClassData);
155 WX_DEFINE_OBJARRAY(ArrayOfXRCWndClassData);
156
157
158 class XmlResApp : public wxAppConsole
159 {
160 public:
161 // don't use builtin cmd line parsing:
162 virtual bool OnInit() { return true; }
163 virtual int OnRun();
164
165 private:
166 void ParseParams(const wxCmdLineParser& cmdline);
167 void CompileRes();
168 wxArrayString PrepareTempFiles();
169 void FindFilesInXML(wxXmlNode *node, wxArrayString& flist, const wxString& inputPath);
170
171 wxString GetInternalFileName(const wxString& name, const wxArrayString& flist);
172 void DeleteTempFiles(const wxArrayString& flist);
173 void MakePackageZIP(const wxArrayString& flist);
174 void MakePackageCPP(const wxArrayString& flist);
175 void MakePackagePython(const wxArrayString& flist);
176
177 void OutputGettext();
178 wxArrayString FindStrings();
179 wxArrayString FindStrings(wxXmlNode *node);
180
181 bool flagVerbose, flagCPP, flagPython, flagGettext;
182 wxString parOutput, parFuncname, parOutputPath;
183 wxArrayString parFiles;
184 int retCode;
185
186 ArrayOfXRCWndClassData aXRCWndClassData;
187 bool flagH;
188 void GenCPPHeader();
189 };
190
191 IMPLEMENT_APP_CONSOLE(XmlResApp)
192
193 int XmlResApp::OnRun()
194 {
195 static const wxCmdLineEntryDesc cmdLineDesc[] =
196 {
197 { wxCMD_LINE_SWITCH, _T("h"), _T("help"), _T("show help message"),
198 wxCMD_LINE_VAL_NONE, wxCMD_LINE_OPTION_HELP },
199 { wxCMD_LINE_SWITCH, _T("v"), _T("verbose"), _T("be verbose") },
200 { wxCMD_LINE_SWITCH, _T("e"), _T("extra-cpp-code"), _T("output C++ header file with XRC derived classes") },
201 { wxCMD_LINE_SWITCH, _T("c"), _T("cpp-code"), _T("output C++ source rather than .rsc file") },
202 { wxCMD_LINE_SWITCH, _T("p"), _T("python-code"), _T("output wxPython source rather than .rsc file") },
203 { wxCMD_LINE_SWITCH, _T("g"), _T("gettext"), _T("output list of translatable strings (to stdout or file if -o used)") },
204 { wxCMD_LINE_OPTION, _T("n"), _T("function"), _T("C++/Python function name (with -c or -p) [InitXmlResource]") },
205 { wxCMD_LINE_OPTION, _T("o"), _T("output"), _T("output file [resource.xrs/cpp]") },
206 #if 0 // not yet implemented
207 { wxCMD_LINE_OPTION, _T("l"), _T("list-of-handlers", _T("output list of neccessary handlers to this file" },
208 #endif
209 { wxCMD_LINE_PARAM, NULL, NULL, _T("input file(s)"),
210 wxCMD_LINE_VAL_STRING,
211 wxCMD_LINE_PARAM_MULTIPLE | wxCMD_LINE_OPTION_MANDATORY },
212
213 { wxCMD_LINE_NONE }
214 };
215
216 wxCmdLineParser parser(cmdLineDesc, argc, argv);
217
218 switch (parser.Parse())
219 {
220 case -1:
221 return 0;
222
223 case 0:
224 retCode = 0;
225 ParseParams(parser);
226 if (flagGettext)
227 OutputGettext();
228 else
229 CompileRes();
230 return retCode;
231 }
232 return 1;
233 }
234
235
236
237
238 void XmlResApp::ParseParams(const wxCmdLineParser& cmdline)
239 {
240 flagGettext = cmdline.Found(_T("g"));
241 flagVerbose = cmdline.Found(_T("v"));
242 flagCPP = cmdline.Found(_T("c"));
243 flagPython = cmdline.Found(_T("p"));
244 flagH = flagCPP && cmdline.Found(_T("e"));
245
246
247 if (!cmdline.Found(_T("o"), &parOutput))
248 {
249 if (flagGettext)
250 parOutput = wxEmptyString;
251 else
252 {
253 if (flagCPP)
254 parOutput = _T("resource.cpp");
255 else if (flagPython)
256 parOutput = _T("resource.py");
257 else
258 parOutput = _T("resource.xrs");
259 }
260 }
261 if (!parOutput.empty())
262 {
263 wxFileName fn(parOutput);
264 fn.Normalize();
265 parOutput = fn.GetFullPath();
266 parOutputPath = wxPathOnly(parOutput);
267 }
268 if (!parOutputPath) parOutputPath = _T(".");
269
270 if (!cmdline.Found(_T("n"), &parFuncname))
271 parFuncname = _T("InitXmlResource");
272
273 for (size_t i = 0; i < cmdline.GetParamCount(); i++)
274 {
275 #ifdef __WINDOWS__
276 wxString fn=wxFindFirstFile(cmdline.GetParam(i), wxFILE);
277 while (!fn.empty())
278 {
279 parFiles.Add(fn);
280 fn=wxFindNextFile();
281 }
282 #else
283 parFiles.Add(cmdline.GetParam(i));
284 #endif
285 }
286 }
287
288
289
290
291 void XmlResApp::CompileRes()
292 {
293 wxArrayString files = PrepareTempFiles();
294
295 wxRemoveFile(parOutput);
296
297 if (!retCode)
298 {
299 if (flagCPP){
300 MakePackageCPP(files);
301 if (flagH)
302 GenCPPHeader();
303 }
304 else if (flagPython)
305 MakePackagePython(files);
306 else
307 MakePackageZIP(files);
308 }
309
310 DeleteTempFiles(files);
311 }
312
313
314 wxString XmlResApp::GetInternalFileName(const wxString& name, const wxArrayString& flist)
315 {
316 wxString name2 = name;
317 name2.Replace(_T(":"), _T("_"));
318 name2.Replace(_T("/"), _T("_"));
319 name2.Replace(_T("\\"), _T("_"));
320 name2.Replace(_T("*"), _T("_"));
321 name2.Replace(_T("?"), _T("_"));
322
323 wxString s = wxFileNameFromPath(parOutput) + _T("$") + name2;
324
325 if (wxFileExists(s) && flist.Index(s) == wxNOT_FOUND)
326 {
327 for (int i = 0;; i++)
328 {
329 s.Printf(wxFileNameFromPath(parOutput) + _T("$%03i-") + name2, i);
330 if (!wxFileExists(s) || flist.Index(s) != wxNOT_FOUND)
331 break;
332 }
333 }
334 return s;
335 }
336
337 wxArrayString XmlResApp::PrepareTempFiles()
338 {
339 wxArrayString flist;
340
341 for (size_t i = 0; i < parFiles.Count(); i++)
342 {
343 if (flagVerbose)
344 wxPrintf(_T("processing ") + parFiles[i] + _T("...\n"));
345
346 wxXmlDocument doc;
347
348 if (!doc.Load(parFiles[i]))
349 {
350 wxLogError(_T("Error parsing file ") + parFiles[i]);
351 retCode = 1;
352 continue;
353 }
354
355 wxString name, ext, path;
356 wxSplitPath(parFiles[i], &path, &name, &ext);
357
358 FindFilesInXML(doc.GetRoot(), flist, path);
359 if (flagH)
360 {
361 wxXmlNode* node = (doc.GetRoot())->GetChildren();
362 wxString classValue,nameValue;
363 while(node){
364 if(node->GetName() == _T("object")
365 && node->GetPropVal(_T("class"),&classValue)
366 && node->GetPropVal(_T("name"),&nameValue)){
367
368 aXRCWndClassData.Add(
369 XRCWndClassData(nameValue,classValue,node)
370 );
371 }
372 node = node -> GetNext();
373 }
374 }
375 wxString internalName = GetInternalFileName(parFiles[i], flist);
376
377 doc.Save(parOutputPath + wxFILE_SEP_PATH + internalName);
378 flist.Add(internalName);
379 }
380
381 return flist;
382 }
383
384
385 // Does 'node' contain filename information at all?
386 static bool NodeContainsFilename(wxXmlNode *node)
387 {
388 // Any bitmaps:
389 if (node->GetName() == _T("bitmap"))
390 return true;
391
392 if (node->GetName() == _T("icon"))
393 return true;
394
395 // URLs in wxHtmlWindow:
396 if (node->GetName() == _T("url"))
397 return true;
398
399 // wxBitmapButton:
400 wxXmlNode *parent = node->GetParent();
401 if (parent != NULL &&
402 parent->GetPropVal(_T("class"), _T("")) == _T("wxBitmapButton") &&
403 (node->GetName() == _T("focus") ||
404 node->GetName() == _T("disabled") ||
405 node->GetName() == _T("selected")))
406 return true;
407
408 // wxBitmap or wxIcon toplevel resources:
409 if (node->GetName() == _T("object"))
410 {
411 wxString klass = node->GetPropVal(_T("class"), wxEmptyString);
412 if (klass == _T("wxBitmap") || klass == _T("wxIcon"))
413 return true;
414 }
415
416 return false;
417 }
418
419 // find all files mentioned in structure, e.g. <bitmap>filename</bitmap>
420 void XmlResApp::FindFilesInXML(wxXmlNode *node, wxArrayString& flist, const wxString& inputPath)
421 {
422 // Is 'node' XML node element?
423 if (node == NULL) return;
424 if (node->GetType() != wxXML_ELEMENT_NODE) return;
425
426 bool containsFilename = NodeContainsFilename(node);
427
428 wxXmlNode *n = node->GetChildren();
429 while (n)
430 {
431 if (containsFilename &&
432 (n->GetType() == wxXML_TEXT_NODE ||
433 n->GetType() == wxXML_CDATA_SECTION_NODE))
434 {
435 wxString fullname;
436 if (wxIsAbsolutePath(n->GetContent()) || inputPath.empty())
437 fullname = n->GetContent();
438 else
439 fullname = inputPath + wxFILE_SEP_PATH + n->GetContent();
440
441 if (flagVerbose)
442 wxPrintf(_T("adding ") + fullname + _T("...\n"));
443
444 wxString filename = GetInternalFileName(n->GetContent(), flist);
445 n->SetContent(filename);
446
447 if (flist.Index(filename) == wxNOT_FOUND)
448 flist.Add(filename);
449
450 wxFileInputStream sin(fullname);
451 wxFileOutputStream sout(parOutputPath + wxFILE_SEP_PATH + filename);
452 sin.Read(sout); // copy the stream
453 }
454
455 // subnodes:
456 if (n->GetType() == wxXML_ELEMENT_NODE)
457 FindFilesInXML(n, flist, inputPath);
458
459 n = n->GetNext();
460 }
461 }
462
463
464
465 void XmlResApp::DeleteTempFiles(const wxArrayString& flist)
466 {
467 for (size_t i = 0; i < flist.Count(); i++)
468 wxRemoveFile(parOutputPath + wxFILE_SEP_PATH + flist[i]);
469 }
470
471
472
473 void XmlResApp::MakePackageZIP(const wxArrayString& flist)
474 {
475 wxString files;
476
477 for (size_t i = 0; i < flist.Count(); i++)
478 files += flist[i] + _T(" ");
479 files.RemoveLast();
480
481 if (flagVerbose)
482 wxPrintf(_T("compressing ") + parOutput + _T("...\n"));
483
484 wxString cwd = wxGetCwd();
485 wxSetWorkingDirectory(parOutputPath);
486 int execres = wxExecute(_T("zip -9 -j ") +
487 wxString(flagVerbose ? _T("") : _T("-q ")) +
488 parOutput + _T(" ") + files, true);
489 wxSetWorkingDirectory(cwd);
490 if (execres == -1)
491 {
492 wxLogError(_T("Unable to execute zip program. Make sure it is in the path."));
493 wxLogError(_T("You can download it at http://www.cdrom.com/pub/infozip/"));
494 retCode = 1;
495 return;
496 }
497 }
498
499
500
501 static wxString FileToCppArray(wxString filename, int num)
502 {
503 wxString output;
504 wxString tmp;
505 wxString snum;
506 wxFFile file(filename, wxT("rb"));
507 wxFileOffset offset = file.Length();
508 wxASSERT_MSG( offset >= 0 , wxT("Invalid file length") );
509 wxASSERT_MSG( offset == wxFileOffset(size_t(offset)) , wxT("Huge file not supported") );
510 size_t lng = (size_t)offset;
511
512 snum.Printf(_T("%i"), num);
513 output.Printf(_T("static size_t xml_res_size_") + snum + _T(" = %i;\n"), lng);
514 output += _T("static unsigned char xml_res_file_") + snum + _T("[] = {\n");
515 // we cannot use string literals because MSVC is dumb wannabe compiler
516 // with arbitrary limitation to 2048 strings :(
517
518 unsigned char *buffer = new unsigned char[lng];
519 file.Read(buffer, lng);
520
521 for (size_t i = 0, linelng = 0; i < lng; i++)
522 {
523 tmp.Printf(_T("%i"), buffer[i]);
524 if (i != 0) output << _T(',');
525 if (linelng > 70)
526 {
527 linelng = 0;
528 output << _T("\n");
529 }
530 output << tmp;
531 linelng += tmp.Length()+1;
532 }
533
534 delete[] buffer;
535
536 output += _T("};\n\n");
537
538 return output;
539 }
540
541
542 void XmlResApp::MakePackageCPP(const wxArrayString& flist)
543 {
544 wxFFile file(parOutput, wxT("wt"));
545 size_t i;
546
547 if (flagVerbose)
548 wxPrintf(_T("creating C++ source file ") + parOutput + _T("...\n"));
549
550 file.Write(_T("")
551 _T("//\n")
552 _T("// This file was automatically generated by wxrc, do not edit by hand.\n")
553 _T("//\n\n")
554 _T("#include <wx/wxprec.h>\n")
555 _T("\n")
556 _T("#ifdef __BORLANDC__\n")
557 _T(" #pragma hdrstop\n")
558 _T("#endif\n")
559 _T("\n")
560 _T("")
561 _T("#include <wx/filesys.h>\n")
562 _T("#include <wx/fs_mem.h>\n")
563 _T("#include <wx/xrc/xmlres.h>\n")
564 _T("#include <wx/xrc/xh_all.h>\n")
565 _T("\n"));
566
567 for (i = 0; i < flist.Count(); i++)
568 file.Write(
569 FileToCppArray(parOutputPath + wxFILE_SEP_PATH + flist[i], i));
570
571 file.Write(_T("")
572 _T("void ") + parFuncname + wxT("()\n")
573 _T("{\n")
574 _T("\n")
575 _T(" // Check for memory FS. If not present, load the handler:\n")
576 _T(" {\n")
577 _T(" wxMemoryFSHandler::AddFile(wxT(\"XRC_resource/dummy_file\"), wxT(\"dummy one\"));\n")
578 _T(" wxFileSystem fsys;\n")
579 _T(" wxFSFile *f = fsys.OpenFile(wxT(\"memory:XRC_resource/dummy_file\"));\n")
580 _T(" wxMemoryFSHandler::RemoveFile(wxT(\"XRC_resource/dummy_file\"));\n")
581 _T(" if (f) delete f;\n")
582 _T(" else wxFileSystem::AddHandler(new wxMemoryFSHandler);\n")
583 _T(" }\n")
584 _T("\n"));
585
586 for (i = 0; i < flist.Count(); i++)
587 {
588 wxString s;
589 s.Printf(_T(" wxMemoryFSHandler::AddFile(wxT(\"XRC_resource/") + flist[i] +
590 _T("\"), xml_res_file_%i, xml_res_size_%i);\n"), i, i);
591 file.Write(s);
592 }
593
594 for (i = 0; i < parFiles.Count(); i++)
595 {
596 file.Write(_T(" wxXmlResource::Get()->Load(wxT(\"memory:XRC_resource/") +
597 GetInternalFileName(parFiles[i], flist) + _T("\"));\n"));
598 }
599
600 file.Write(_T("}\n"));
601
602
603 }
604
605 void XmlResApp::GenCPPHeader()
606 {
607 wxString fileSpec = ((parOutput.BeforeLast('.')).AfterLast('/')).AfterLast('\\');
608 wxString heaFileName = fileSpec + _T(".h");
609
610 wxFFile file(heaFileName, wxT("wt"));
611 file.Write(
612 _T("//\n")
613 _T("// This file was automatically generated by wxrc, do not edit by hand.\n")
614 _T("//\n\n")
615 _T("#ifndef __") + fileSpec + _T("_h__\n")
616 _T("#define __") + fileSpec + _T("_h__\n")
617 );
618 for(size_t i=0;i<aXRCWndClassData.Count();++i){
619 aXRCWndClassData.Item(i).GenerateHeaderCode(file);
620 }
621 file.Write(
622 _T("\nvoid \n")
623 + parFuncname
624 + _T("();\n#endif\n"));
625 }
626
627 static wxString FileToPythonArray(wxString filename, int num)
628 {
629 wxString output;
630 wxString tmp;
631 wxString snum;
632 wxFFile file(filename, wxT("rb"));
633 wxFileOffset offset = file.Length();
634 wxASSERT_MSG( offset >= 0 , wxT("Invalid file length") );
635 wxASSERT_MSG( offset == wxFileOffset(size_t(offset)) , wxT("Huge file not supported") );
636 size_t lng = (size_t)offset;
637
638 snum.Printf(_T("%i"), num);
639 output = _T(" xml_res_file_") + snum + _T(" = '''\\\n");
640
641 unsigned char *buffer = new unsigned char[lng];
642 file.Read(buffer, lng);
643
644 for (size_t i = 0, linelng = 0; i < lng; i++)
645 {
646 unsigned char c = buffer[i];
647 if (c == '\n')
648 {
649 tmp = (wxChar)c;
650 linelng = 0;
651 }
652 else if (c < 32 || c > 127 || c == '\'')
653 tmp.Printf(_T("\\x%02x"), c);
654 else if (c == '\\')
655 tmp = _T("\\\\");
656 else
657 tmp = (wxChar)c;
658 if (linelng > 70)
659 {
660 linelng = 0;
661 output << _T("\\\n");
662 }
663 output << tmp;
664 linelng += tmp.Length();
665 }
666
667 delete[] buffer;
668
669 output += _T("'''\n\n");
670
671 return output;
672 }
673
674
675 void XmlResApp::MakePackagePython(const wxArrayString& flist)
676 {
677 wxFFile file(parOutput, wxT("wt"));
678 size_t i;
679
680 if (flagVerbose)
681 wxPrintf(_T("creating Python source file ") + parOutput + _T("...\n"));
682
683 file.Write(
684 _T("#\n")
685 _T("# This file was automatically generated by wxrc, do not edit by hand.\n")
686 _T("#\n\n")
687 _T("import wx\n")
688 _T("import wx.xrc\n\n")
689 );
690
691
692 file.Write(_T("def ") + parFuncname + _T("():\n"));
693
694 for (i = 0; i < flist.Count(); i++)
695 file.Write(
696 FileToPythonArray(parOutputPath + wxFILE_SEP_PATH + flist[i], i));
697
698 file.Write(
699 _T(" # check if the memory filesystem handler has been loaded yet, and load it if not\n")
700 _T(" wx.MemoryFSHandler.AddFile('XRC_resource/dummy_file', 'dummy value')\n")
701 _T(" fsys = wx.FileSystem()\n")
702 _T(" f = fsys.OpenFile('memory:XRC_resource/dummy_file')\n")
703 _T(" wx.MemoryFSHandler.RemoveFile('XRC_resource/dummy_file')\n")
704 _T(" if f is not None:\n")
705 _T(" f.Destroy()\n")
706 _T(" else:\n")
707 _T(" wx.FileSystem.AddHandler(wx.MemoryFSHandler())\n")
708 _T("\n")
709 _T(" # load all the strings as memory files and load into XmlRes\n")
710 );
711
712
713 for (i = 0; i < flist.Count(); i++)
714 {
715 wxString s;
716 s.Printf(_T(" wx.MemoryFSHandler.AddFile('XRC_resource/") + flist[i] +
717 _T("', xml_res_file_%i)\n"), i);
718 file.Write(s);
719 }
720 for (i = 0; i < parFiles.Count(); i++)
721 {
722 file.Write(_T(" wx.xrc.XmlResource.Get().Load('memory:XRC_resource/") +
723 GetInternalFileName(parFiles[i], flist) + _T("')\n"));
724 }
725
726 file.Write(_T("\n"));
727 }
728
729
730
731 void XmlResApp::OutputGettext()
732 {
733 wxArrayString str = FindStrings();
734
735 wxFFile fout;
736 if (parOutput.empty())
737 fout.Attach(stdout);
738 else
739 fout.Open(parOutput, wxT("wt"));
740
741 for (size_t i = 0; i < str.GetCount(); i++)
742 fout.Write(_T("_(\"") + str[i] + _T("\");\n"));
743
744 if (!parOutput) fout.Detach();
745 }
746
747
748
749 wxArrayString XmlResApp::FindStrings()
750 {
751 wxArrayString arr, a2;
752
753 for (size_t i = 0; i < parFiles.Count(); i++)
754 {
755 if (flagVerbose)
756 wxPrintf(_T("processing ") + parFiles[i] + _T("...\n"));
757
758 wxXmlDocument doc;
759 if (!doc.Load(parFiles[i]))
760 {
761 wxLogError(_T("Error parsing file ") + parFiles[i]);
762 retCode = 1;
763 continue;
764 }
765 a2 = FindStrings(doc.GetRoot());
766 WX_APPEND_ARRAY(arr, a2);
767 }
768
769 return arr;
770 }
771
772
773
774 static wxString ConvertText(const wxString& str)
775 {
776 wxString str2;
777 const wxChar *dt;
778
779 for (dt = str.c_str(); *dt; dt++)
780 {
781 if (*dt == wxT('_'))
782 {
783 if ( *(++dt) == wxT('_') )
784 str2 << wxT('_');
785 else
786 str2 << wxT('&') << *dt;
787 }
788 else
789 {
790 switch (*dt)
791 {
792 case wxT('\n') : str2 << wxT("\\n"); break;
793 case wxT('\t') : str2 << wxT("\\t"); break;
794 case wxT('\r') : str2 << wxT("\\r"); break;
795 case wxT('\\') : if ((*(dt+1) != 'n') &&
796 (*(dt+1) != 't') &&
797 (*(dt+1) != 'r'))
798 str2 << wxT("\\\\");
799 else
800 str2 << wxT("\\");
801 break;
802 case wxT('"') : str2 << wxT("\\\""); break;
803 default : str2 << *dt; break;
804 }
805 }
806 }
807
808 return str2;
809 }
810
811
812 wxArrayString XmlResApp::FindStrings(wxXmlNode *node)
813 {
814 wxArrayString arr;
815
816 wxXmlNode *n = node;
817 if (n == NULL) return arr;
818 n = n->GetChildren();
819
820 while (n)
821 {
822 if ((node->GetType() == wxXML_ELEMENT_NODE) &&
823 // parent is an element, i.e. has subnodes...
824 (n->GetType() == wxXML_TEXT_NODE ||
825 n->GetType() == wxXML_CDATA_SECTION_NODE) &&
826 // ...it is textnode...
827 (
828 node/*not n!*/->GetName() == _T("label") ||
829 (node/*not n!*/->GetName() == _T("value") &&
830 !n->GetContent().IsNumber()) ||
831 node/*not n!*/->GetName() == _T("help") ||
832 node/*not n!*/->GetName() == _T("longhelp") ||
833 node/*not n!*/->GetName() == _T("tooltip") ||
834 node/*not n!*/->GetName() == _T("htmlcode") ||
835 node/*not n!*/->GetName() == _T("title") ||
836 node/*not n!*/->GetName() == _T("item")
837 ))
838 // ...and known to contain translatable string
839 {
840 if (!flagGettext ||
841 node->GetPropVal(_T("translate"), _T("1")) != _T("0"))
842 {
843 arr.Add(ConvertText(n->GetContent()));
844 }
845 }
846
847 // subnodes:
848 if (n->GetType() == wxXML_ELEMENT_NODE)
849 {
850 wxArrayString a2 = FindStrings(n);
851 WX_APPEND_ARRAY(arr, a2);
852 }
853
854 n = n->GetNext();
855 }
856 return arr;
857 }