renamed wxXmlProperty to wxXmlAttribute, plus implied method names changes (bug ...
[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 // For compilers that support precompilation, includes "wx/wx.h".
12 #include "wx/wxprec.h"
13
14 #ifdef __BORLANDC__
15 #pragma hdrstop
16 #endif
17
18 // for all others, include the necessary headers
19 #ifndef WX_PRECOMP
20 #include "wx/app.h"
21 #include "wx/log.h"
22 #include "wx/wxcrtvararg.h"
23 #endif
24
25 #include "wx/cmdline.h"
26 #include "wx/xml/xml.h"
27 #include "wx/ffile.h"
28 #include "wx/filename.h"
29 #include "wx/wfstream.h"
30 #include "wx/utils.h"
31 #include "wx/hashset.h"
32 #include "wx/mimetype.h"
33
34 WX_DECLARE_HASH_SET(wxString, wxStringHash, wxStringEqual, StringSet);
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 StringSet m_ancestorClassNames;
58 ArrayOfXRCWidgetData m_wdata;
59
60 void BrowseXmlNode(wxXmlNode* node)
61 {
62 wxString classValue;
63 wxString nameValue;
64 wxXmlNode* children;
65 while (node)
66 {
67 if (node->GetName() == _T("object")
68 && node->GetAttribute(_T("class"),&classValue)
69 && node->GetAttribute(_T("name"),&nameValue))
70 {
71 m_wdata.Add(XRCWidgetData(nameValue,classValue));
72 }
73 children = node->GetChildren();
74 if (children)
75 BrowseXmlNode(children);
76 node = node->GetNext();
77 }
78 }
79
80 public:
81 XRCWndClassData(const wxString& className,
82 const wxString& parentClassName,
83 const wxXmlNode* node) :
84 m_className(className) , m_parentClassName(parentClassName)
85 {
86 if ( className == _T("wxMenu") )
87 {
88 m_ancestorClassNames.insert(_T("wxMenu"));
89 m_ancestorClassNames.insert(_T("wxMenuBar"));
90 }
91 else if ( className == _T("wxMDIChildFrame") )
92 {
93 m_ancestorClassNames.insert(_T("wxMDIParentFrame"));
94 }
95 else if( className == _T("wxMenuBar") ||
96 className == _T("wxStatusBar") ||
97 className == _T("wxToolBar") )
98 {
99 m_ancestorClassNames.insert(_T("wxFrame"));
100 }
101 else
102 {
103 m_ancestorClassNames.insert(_T("wxWindow"));
104 }
105
106 BrowseXmlNode(node->GetChildren());
107 }
108
109 const ArrayOfXRCWidgetData& GetWidgetData()
110 {
111 return m_wdata;
112 }
113
114 bool CanBeUsedWithXRCCTRL(const wxString& name)
115 {
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") )
125 {
126 return false;
127 }
128 return true;
129 }
130
131 void GenerateHeaderCode(wxFFile& file)
132 {
133
134 file.Write(_T("class ") + m_className + _T(" : public ") + m_parentClassName
135 + _T(" {\nprotected:\n"));
136 size_t i;
137 for(i=0;i<m_wdata.GetCount();++i)
138 {
139 const XRCWidgetData& w = m_wdata.Item(i);
140 if( !CanBeUsedWithXRCCTRL(w.GetClass()) ) continue;
141 if( w.GetName().Length() == 0 ) continue;
142 file.Write(
143 _T(" ") + w.GetClass() + _T("* ") + w.GetName()
144 + _T(";\n"));
145 }
146 file.Write(_T("\nprivate:\n void InitWidgetsFromXRC(wxWindow *parent){\n")
147 _T(" wxXmlResource::Get()->LoadObject(this,parent,_T(\"")
148 + m_className
149 + _T("\"), _T(\"")
150 + m_parentClassName
151 + _T("\"));\n"));
152 for(i=0;i<m_wdata.GetCount();++i)
153 {
154 const XRCWidgetData& w = m_wdata.Item(i);
155 if( !CanBeUsedWithXRCCTRL(w.GetClass()) ) continue;
156 if( w.GetName().Length() == 0 ) continue;
157 file.Write( _T(" ")
158 + w.GetName()
159 + _T(" = XRCCTRL(*this,\"")
160 + w.GetName()
161 + _T("\",")
162 + w.GetClass()
163 + _T(");\n"));
164 }
165 file.Write(_T(" }\n"));
166
167 file.Write( _T("public:\n"));
168
169 if ( m_ancestorClassNames.size() == 1 )
170 {
171 file.Write
172 (
173 m_className +
174 _T("(") +
175 *m_ancestorClassNames.begin() +
176 _T(" *parent=NULL){\n") +
177 _T(" InitWidgetsFromXRC((wxWindow *)parent);\n")
178 _T(" }\n")
179 _T("};\n")
180 );
181 }
182 else
183 {
184 file.Write(m_className + _T("(){\n") +
185 _T(" InitWidgetsFromXRC(NULL);\n")
186 _T(" }\n")
187 _T("};\n"));
188
189 for ( StringSet::const_iterator it = m_ancestorClassNames.begin();
190 it != m_ancestorClassNames.end();
191 ++it )
192 {
193 file.Write(m_className + _T("(") + *it + _T(" *parent){\n") +
194 _T(" InitWidgetsFromXRC((wxWindow *)parent);\n")
195 _T(" }\n")
196 _T("};\n"));
197 }
198 }
199 }
200 };
201 WX_DECLARE_OBJARRAY(XRCWndClassData,ArrayOfXRCWndClassData);
202 WX_DEFINE_OBJARRAY(ArrayOfXRCWndClassData)
203
204
205 class XmlResApp : public wxAppConsole
206 {
207 public:
208 // don't use builtin cmd line parsing:
209 virtual bool OnInit() { return true; }
210 virtual int OnRun();
211
212 private:
213 void ParseParams(const wxCmdLineParser& cmdline);
214 void CompileRes();
215 wxArrayString PrepareTempFiles();
216 void FindFilesInXML(wxXmlNode *node, wxArrayString& flist, const wxString& inputPath);
217
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);
223
224 void OutputGettext();
225 wxArrayString FindStrings();
226 wxArrayString FindStrings(wxXmlNode *node);
227
228 bool flagVerbose, flagCPP, flagPython, flagGettext;
229 wxString parOutput, parFuncname, parOutputPath;
230 wxArrayString parFiles;
231 int retCode;
232
233 ArrayOfXRCWndClassData aXRCWndClassData;
234 bool flagH;
235 void GenCPPHeader();
236 };
237
238 IMPLEMENT_APP_CONSOLE(XmlResApp)
239
240 int XmlResApp::OnRun()
241 {
242 static const wxCmdLineEntryDesc cmdLineDesc[] =
243 {
244 { wxCMD_LINE_SWITCH, _T("h"), _T("help"), _T("show help message"),
245 wxCMD_LINE_VAL_NONE, wxCMD_LINE_OPTION_HELP },
246 { wxCMD_LINE_SWITCH, _T("v"), _T("verbose"), _T("be verbose"), (wxCmdLineParamType)0, 0 },
247 { wxCMD_LINE_SWITCH, _T("e"), _T("extra-cpp-code"), _T("output C++ header file with XRC derived classes"), (wxCmdLineParamType)0, 0 },
248 { wxCMD_LINE_SWITCH, _T("c"), _T("cpp-code"), _T("output C++ source rather than .rsc file"), (wxCmdLineParamType)0, 0 },
249 { wxCMD_LINE_SWITCH, _T("p"), _T("python-code"), _T("output wxPython source rather than .rsc file"), (wxCmdLineParamType)0, 0 },
250 { wxCMD_LINE_SWITCH, _T("g"), _T("gettext"), _T("output list of translatable strings (to stdout or file if -o used)"), (wxCmdLineParamType)0, 0 },
251 { wxCMD_LINE_OPTION, _T("n"), _T("function"), _T("C++/Python function name (with -c or -p) [InitXmlResource]"), (wxCmdLineParamType)0, 0 },
252 { wxCMD_LINE_OPTION, _T("o"), _T("output"), _T("output file [resource.xrs/cpp]"), (wxCmdLineParamType)0, 0 },
253 #if 0 // not yet implemented
254 { wxCMD_LINE_OPTION, _T("l"), _T("list-of-handlers"), _T("output list of necessary handlers to this file"), (wxCmdLineParamType)0, 0 },
255 #endif
256 { wxCMD_LINE_PARAM, NULL, NULL, _T("input file(s)"),
257 wxCMD_LINE_VAL_STRING,
258 wxCMD_LINE_PARAM_MULTIPLE | wxCMD_LINE_OPTION_MANDATORY },
259
260 { wxCMD_LINE_NONE, NULL, NULL, NULL, (wxCmdLineParamType)0, 0 }
261 };
262
263 wxCmdLineParser parser(cmdLineDesc, argc, argv);
264
265 switch (parser.Parse())
266 {
267 case -1:
268 return 0;
269
270 case 0:
271 retCode = 0;
272 ParseParams(parser);
273 if (flagGettext)
274 OutputGettext();
275 else
276 CompileRes();
277 return retCode;
278 }
279 return 1;
280 }
281
282
283
284
285 void XmlResApp::ParseParams(const wxCmdLineParser& cmdline)
286 {
287 flagGettext = cmdline.Found(_T("g"));
288 flagVerbose = cmdline.Found(_T("v"));
289 flagCPP = cmdline.Found(_T("c"));
290 flagPython = cmdline.Found(_T("p"));
291 flagH = flagCPP && cmdline.Found(_T("e"));
292
293
294 if (!cmdline.Found(_T("o"), &parOutput))
295 {
296 if (flagGettext)
297 parOutput = wxEmptyString;
298 else
299 {
300 if (flagCPP)
301 parOutput = _T("resource.cpp");
302 else if (flagPython)
303 parOutput = _T("resource.py");
304 else
305 parOutput = _T("resource.xrs");
306 }
307 }
308 if (!parOutput.empty())
309 {
310 wxFileName fn(parOutput);
311 fn.Normalize();
312 parOutput = fn.GetFullPath();
313 parOutputPath = wxPathOnly(parOutput);
314 }
315 if (!parOutputPath) parOutputPath = _T(".");
316
317 if (!cmdline.Found(_T("n"), &parFuncname))
318 parFuncname = _T("InitXmlResource");
319
320 for (size_t i = 0; i < cmdline.GetParamCount(); i++)
321 {
322 #ifdef __WINDOWS__
323 wxString fn=wxFindFirstFile(cmdline.GetParam(i), wxFILE);
324 while (!fn.empty())
325 {
326 parFiles.Add(fn);
327 fn=wxFindNextFile();
328 }
329 #else
330 parFiles.Add(cmdline.GetParam(i));
331 #endif
332 }
333 }
334
335
336
337
338 void XmlResApp::CompileRes()
339 {
340 wxArrayString files = PrepareTempFiles();
341
342 wxRemoveFile(parOutput);
343
344 if (!retCode)
345 {
346 if (flagCPP){
347 MakePackageCPP(files);
348 if (flagH)
349 GenCPPHeader();
350 }
351 else if (flagPython)
352 MakePackagePython(files);
353 else
354 MakePackageZIP(files);
355 }
356
357 DeleteTempFiles(files);
358 }
359
360
361 wxString XmlResApp::GetInternalFileName(const wxString& name, const wxArrayString& flist)
362 {
363 wxString name2 = name;
364 name2.Replace(_T(":"), _T("_"));
365 name2.Replace(_T("/"), _T("_"));
366 name2.Replace(_T("\\"), _T("_"));
367 name2.Replace(_T("*"), _T("_"));
368 name2.Replace(_T("?"), _T("_"));
369
370 wxString s = wxFileNameFromPath(parOutput) + _T("$") + name2;
371
372 if (wxFileExists(s) && flist.Index(s) == wxNOT_FOUND)
373 {
374 for (int i = 0;; i++)
375 {
376 s.Printf(wxFileNameFromPath(parOutput) + _T("$%03i-") + name2, i);
377 if (!wxFileExists(s) || flist.Index(s) != wxNOT_FOUND)
378 break;
379 }
380 }
381 return s;
382 }
383
384 wxArrayString XmlResApp::PrepareTempFiles()
385 {
386 wxArrayString flist;
387
388 for (size_t i = 0; i < parFiles.GetCount(); i++)
389 {
390 if (flagVerbose)
391 wxPrintf(_T("processing ") + parFiles[i] + _T("...\n"));
392
393 wxXmlDocument doc;
394
395 if (!doc.Load(parFiles[i]))
396 {
397 wxLogError(_T("Error parsing file ") + parFiles[i]);
398 retCode = 1;
399 continue;
400 }
401
402 wxString name, ext, path;
403 wxSplitPath(parFiles[i], &path, &name, &ext);
404
405 FindFilesInXML(doc.GetRoot(), flist, path);
406 if (flagH)
407 {
408 wxXmlNode* node = (doc.GetRoot())->GetChildren();
409 wxString classValue,nameValue;
410 while(node){
411 if(node->GetName() == _T("object")
412 && node->GetAttribute(_T("class"),&classValue)
413 && node->GetAttribute(_T("name"),&nameValue)){
414
415 aXRCWndClassData.Add(
416 XRCWndClassData(nameValue,classValue,node)
417 );
418 }
419 node = node -> GetNext();
420 }
421 }
422 wxString internalName = GetInternalFileName(parFiles[i], flist);
423
424 doc.Save(parOutputPath + wxFILE_SEP_PATH + internalName);
425 flist.Add(internalName);
426 }
427
428 return flist;
429 }
430
431
432 // Does 'node' contain filename information at all?
433 static bool NodeContainsFilename(wxXmlNode *node)
434 {
435 const wxString name = node->GetName();
436
437 // Any bitmaps (bitmap2 is used for disabled toolbar buttons):
438 if ( name == _T("bitmap") || name == _T("bitmap2") )
439 return true;
440
441 if ( name == _T("icon") )
442 return true;
443
444 // wxBitmapButton:
445 wxXmlNode *parent = node->GetParent();
446 if (parent != NULL &&
447 parent->GetAttribute(_T("class"), _T("")) == _T("wxBitmapButton") &&
448 (name == _T("focus") ||
449 name == _T("disabled") ||
450 name == _T("selected")))
451 return true;
452
453 // wxBitmap or wxIcon toplevel resources:
454 if ( name == _T("object") )
455 {
456 wxString klass = node->GetAttribute(_T("class"), wxEmptyString);
457 if (klass == _T("wxBitmap") ||
458 klass == _T("wxIcon") ||
459 klass == _T("data") )
460 return true;
461 }
462
463 // URLs in wxHtmlWindow:
464 if ( name == _T("url") &&
465 parent != NULL &&
466 parent->GetAttribute(_T("class"), _T("")) == _T("wxHtmlWindow") )
467 {
468 // FIXME: this is wrong for e.g. http:// URLs
469 return true;
470 }
471
472 return false;
473 }
474
475 // find all files mentioned in structure, e.g. <bitmap>filename</bitmap>
476 void XmlResApp::FindFilesInXML(wxXmlNode *node, wxArrayString& flist, const wxString& inputPath)
477 {
478 // Is 'node' XML node element?
479 if (node == NULL) return;
480 if (node->GetType() != wxXML_ELEMENT_NODE) return;
481
482 bool containsFilename = NodeContainsFilename(node);
483
484 wxXmlNode *n = node->GetChildren();
485 while (n)
486 {
487 if (containsFilename &&
488 (n->GetType() == wxXML_TEXT_NODE ||
489 n->GetType() == wxXML_CDATA_SECTION_NODE))
490 {
491 wxString fullname;
492 if (wxIsAbsolutePath(n->GetContent()) || inputPath.empty())
493 fullname = n->GetContent();
494 else
495 fullname = inputPath + wxFILE_SEP_PATH + n->GetContent();
496
497 if (flagVerbose)
498 wxPrintf(_T("adding ") + fullname + _T("...\n"));
499
500 wxString filename = GetInternalFileName(n->GetContent(), flist);
501 n->SetContent(filename);
502
503 if (flist.Index(filename) == wxNOT_FOUND)
504 flist.Add(filename);
505
506 wxFileInputStream sin(fullname);
507 wxFileOutputStream sout(parOutputPath + wxFILE_SEP_PATH + filename);
508 sin.Read(sout); // copy the stream
509 }
510
511 // subnodes:
512 if (n->GetType() == wxXML_ELEMENT_NODE)
513 FindFilesInXML(n, flist, inputPath);
514
515 n = n->GetNext();
516 }
517 }
518
519
520
521 void XmlResApp::DeleteTempFiles(const wxArrayString& flist)
522 {
523 for (size_t i = 0; i < flist.GetCount(); i++)
524 wxRemoveFile(parOutputPath + wxFILE_SEP_PATH + flist[i]);
525 }
526
527
528
529 void XmlResApp::MakePackageZIP(const wxArrayString& flist)
530 {
531 wxString files;
532
533 for (size_t i = 0; i < flist.GetCount(); i++)
534 files += flist[i] + _T(" ");
535 files.RemoveLast();
536
537 if (flagVerbose)
538 wxPrintf(_T("compressing ") + parOutput + _T("...\n"));
539
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);
546 if (execres == -1)
547 {
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/"));
550 retCode = 1;
551 return;
552 }
553 }
554
555
556
557 static wxString FileToCppArray(wxString filename, int num)
558 {
559 wxString output;
560 wxString tmp;
561 wxString snum;
562 wxFFile file(filename, wxT("rb"));
563 wxFileOffset offset = file.Length();
564 wxASSERT_MSG( offset >= 0 , wxT("Invalid file length") );
565
566 const size_t lng = wx_truncate_cast(size_t, offset);
567 wxASSERT_MSG( lng == offset, wxT("Huge file not supported") );
568
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 :(
574
575 unsigned char *buffer = new unsigned char[lng];
576 file.Read(buffer, lng);
577
578 for (size_t i = 0, linelng = 0; i < lng; i++)
579 {
580 tmp.Printf(_T("%i"), buffer[i]);
581 if (i != 0) output << _T(',');
582 if (linelng > 70)
583 {
584 linelng = 0;
585 output << _T("\n");
586 }
587 output << tmp;
588 linelng += tmp.Length()+1;
589 }
590
591 delete[] buffer;
592
593 output += _T("};\n\n");
594
595 return output;
596 }
597
598
599 void XmlResApp::MakePackageCPP(const wxArrayString& flist)
600 {
601 wxFFile file(parOutput, wxT("wt"));
602 size_t i;
603
604 if (flagVerbose)
605 wxPrintf(_T("creating C++ source file ") + parOutput + _T("...\n"));
606
607 file.Write(""
608 "//\n"
609 "// This file was automatically generated by wxrc, do not edit by hand.\n"
610 "//\n\n"
611 "#include <wx/wxprec.h>\n"
612 "\n"
613 "#ifdef __BORLANDC__\n"
614 " #pragma hdrstop\n"
615 "#endif\n"
616 "\n"
617 ""
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"
622 "\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"
626 "#else\n"
627 " #define XRC_ADD_FILE(name, data, size, mime) \\\n"
628 " wxMemoryFSHandler::AddFile(name, data, size)\n"
629 "#endif\n"
630 "\n");
631
632 for (i = 0; i < flist.GetCount(); i++)
633 file.Write(
634 FileToCppArray(parOutputPath + wxFILE_SEP_PATH + flist[i], i));
635
636 file.Write(""
637 "void " + parFuncname + "()\n"
638 "{\n"
639 "\n"
640 " // Check for memory FS. If not present, load the handler:\n"
641 " {\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"
648 " }\n"
649 "\n");
650
651 for (i = 0; i < flist.GetCount(); i++)
652 {
653 wxString s;
654
655 wxString mime;
656 wxString ext = wxFileName(flist[i]).GetExt();
657 if ( ext.Lower() == _T("xrc") )
658 mime = _T("text/xml");
659 else
660 {
661 wxFileType *ft = wxTheMimeTypesManager->GetFileTypeFromExtension(ext);
662 if ( ft )
663 ft->GetMimeType(&mime);
664 }
665
666 s.Printf(" XRC_ADD_FILE(wxT(\"XRC_resource/" + flist[i] +
667 "\"), xml_res_file_%i, xml_res_size_%i, _T(\"%s\"));\n",
668 i, i, mime.c_str());
669 file.Write(s);
670 }
671
672 for (i = 0; i < parFiles.GetCount(); i++)
673 {
674 file.Write(" wxXmlResource::Get()->Load(wxT(\"memory:XRC_resource/" +
675 GetInternalFileName(parFiles[i], flist) + "\"));\n");
676 }
677
678 file.Write("}\n");
679
680
681 }
682
683 void XmlResApp::GenCPPHeader()
684 {
685 wxString fileSpec = ((parOutput.BeforeLast('.')).AfterLast('/')).AfterLast('\\');
686 wxString heaFileName = fileSpec + _T(".h");
687
688 wxFFile file(heaFileName, wxT("wt"));
689 file.Write(
690 "//\n"
691 "// This file was automatically generated by wxrc, do not edit by hand.\n"
692 "//\n\n"
693 "#ifndef __" + fileSpec + "_h__\n"
694 "#define __" + fileSpec + "_h__\n"
695 );
696 for(size_t i=0;i<aXRCWndClassData.GetCount();++i){
697 aXRCWndClassData.Item(i).GenerateHeaderCode(file);
698 }
699 file.Write(
700 "\nvoid \n"
701 + parFuncname
702 + "();\n#endif\n");
703 }
704
705 static wxString FileToPythonArray(wxString filename, int num)
706 {
707 wxString output;
708 wxString tmp;
709 wxString snum;
710 wxFFile file(filename, wxT("rb"));
711 wxFileOffset offset = file.Length();
712 wxASSERT_MSG( offset >= 0 , wxT("Invalid file length") );
713
714 const size_t lng = wx_truncate_cast(size_t, offset);
715 wxASSERT_MSG( offset == lng, wxT("Huge file not supported") );
716
717 snum.Printf(_T("%i"), num);
718 output = " xml_res_file_" + snum + " = '''\\\n";
719
720 unsigned char *buffer = new unsigned char[lng];
721 file.Read(buffer, lng);
722
723 for (size_t i = 0, linelng = 0; i < lng; i++)
724 {
725 unsigned char c = buffer[i];
726 if (c == '\n')
727 {
728 tmp = (wxChar)c;
729 linelng = 0;
730 }
731 else if (c < 32 || c > 127 || c == '\'')
732 tmp.Printf(_T("\\x%02x"), c);
733 else if (c == '\\')
734 tmp = _T("\\\\");
735 else
736 tmp = (wxChar)c;
737 if (linelng > 70)
738 {
739 linelng = 0;
740 output << _T("\\\n");
741 }
742 output << tmp;
743 linelng += tmp.Length();
744 }
745
746 delete[] buffer;
747
748 output += _T("'''\n\n");
749
750 return output;
751 }
752
753
754 void XmlResApp::MakePackagePython(const wxArrayString& flist)
755 {
756 wxFFile file(parOutput, wxT("wt"));
757 size_t i;
758
759 if (flagVerbose)
760 wxPrintf(_T("creating Python source file ") + parOutput + _T("...\n"));
761
762 file.Write(
763 "#\n"
764 "# This file was automatically generated by wxrc, do not edit by hand.\n"
765 "#\n\n"
766 "import wx\n"
767 "import wx.xrc\n\n"
768 );
769
770
771 file.Write("def " + parFuncname + "():\n");
772
773 for (i = 0; i < flist.GetCount(); i++)
774 file.Write(
775 FileToPythonArray(parOutputPath + wxFILE_SEP_PATH + flist[i], i));
776
777 file.Write(
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"
784 " f.Destroy()\n"
785 " else:\n"
786 " wx.FileSystem.AddHandler(wx.MemoryFSHandler())\n"
787 "\n"
788 " # load all the strings as memory files and load into XmlRes\n"
789 );
790
791
792 for (i = 0; i < flist.GetCount(); i++)
793 {
794 wxString s;
795 s.Printf(" wx.MemoryFSHandler.AddFile('XRC_resource/" + flist[i] +
796 "', xml_res_file_%i)\n", i);
797 file.Write(s);
798 }
799 for (i = 0; i < parFiles.GetCount(); i++)
800 {
801 file.Write(" wx.xrc.XmlResource.Get().Load('memory:XRC_resource/" +
802 GetInternalFileName(parFiles[i], flist) + "')\n");
803 }
804
805 file.Write("\n");
806 }
807
808
809
810 void XmlResApp::OutputGettext()
811 {
812 wxArrayString str = FindStrings();
813
814 wxFFile fout;
815 if (parOutput.empty())
816 fout.Attach(stdout);
817 else
818 fout.Open(parOutput, wxT("wt"));
819
820 for (size_t i = 0; i < str.GetCount(); i++)
821 fout.Write("_(\"" + str[i] + "\");\n");
822
823 if (!parOutput) fout.Detach();
824 }
825
826
827
828 wxArrayString XmlResApp::FindStrings()
829 {
830 wxArrayString arr, a2;
831
832 for (size_t i = 0; i < parFiles.GetCount(); i++)
833 {
834 if (flagVerbose)
835 wxPrintf(_T("processing ") + parFiles[i] + _T("...\n"));
836
837 wxXmlDocument doc;
838 if (!doc.Load(parFiles[i]))
839 {
840 wxLogError(_T("Error parsing file ") + parFiles[i]);
841 retCode = 1;
842 continue;
843 }
844 a2 = FindStrings(doc.GetRoot());
845 WX_APPEND_ARRAY(arr, a2);
846 }
847
848 return arr;
849 }
850
851
852
853 static wxString ConvertText(const wxString& str)
854 {
855 wxString str2;
856 const wxChar *dt;
857
858 for (dt = str.c_str(); *dt; dt++)
859 {
860 if (*dt == wxT('_'))
861 {
862 if ( *(++dt) == wxT('_') )
863 str2 << wxT('_');
864 else
865 str2 << wxT('&') << *dt;
866 }
867 else
868 {
869 switch (*dt)
870 {
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') &&
875 (*(dt+1) != 't') &&
876 (*(dt+1) != 'r'))
877 str2 << wxT("\\\\");
878 else
879 str2 << wxT("\\");
880 break;
881 case wxT('"') : str2 << wxT("\\\""); break;
882 default : str2 << *dt; break;
883 }
884 }
885 }
886
887 return str2;
888 }
889
890
891 wxArrayString XmlResApp::FindStrings(wxXmlNode *node)
892 {
893 wxArrayString arr;
894
895 wxXmlNode *n = node;
896 if (n == NULL) return arr;
897 n = n->GetChildren();
898
899 while (n)
900 {
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...
906 (
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")
916 ))
917 // ...and known to contain translatable string
918 {
919 if (!flagGettext ||
920 node->GetAttribute(_T("translate"), _T("1")) != _T("0"))
921 {
922 arr.Add(ConvertText(n->GetContent()));
923 }
924 }
925
926 // subnodes:
927 if (n->GetType() == wxXML_ELEMENT_NODE)
928 {
929 wxArrayString a2 = FindStrings(n);
930 WX_APPEND_ARRAY(arr, a2);
931 }
932
933 n = n->GetNext();
934 }
935 return arr;
936 }