applied patch 744616: WXRC extension for automated use (Eduardo Marques)

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@25520 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Václav Slavík
2004-02-05 21:58:29 +00:00
parent 00233716e4
commit 1dce6f094a
4 changed files with 413 additions and 24 deletions

View File

@@ -1,7 +1,7 @@
/////////////////////////////////////////////////////////////////////////////
// Name: wxrc.cpp
// Purpose: XML resource compiler
// Author: Vaclav Slavik
// Author: Vaclav Slavik, Eduardo Marques <edrdo@netcabo.pt>
// Created: 2000/03/05
// RCS-ID: $Id$
// Copyright: (c) 2000 Vaclav Slavik
@@ -33,16 +33,112 @@
#include "wx/wfstream.h"
class XRCWidgetData
{
public:
XRCWidgetData(const wxString& vname,const wxString& vclass)
: m_class(vclass), m_name(vname) {}
const wxString& GetName() const { return m_name; }
const wxString& GetClass() const { return m_class; }
private:
wxString m_class;
wxString m_name;
};
#include "wx/arrimpl.cpp"
WX_DECLARE_OBJARRAY(XRCWidgetData,ArrayOfXRCWidgetData);
WX_DEFINE_OBJARRAY(ArrayOfXRCWidgetData);
class XRCWndClassData
{
private:
wxString m_className;
wxString m_parentClassName;
ArrayOfXRCWidgetData m_wdata;
void BrowseXmlNode(wxXmlNode* node)
{
wxString classValue;
wxString nameValue;
wxXmlNode* children;
while (node)
{
if (node->GetName() == _T("object")
&& node->GetPropVal(_T("class"),&classValue)
&& node->GetPropVal(_T("name"),&nameValue))
{
m_wdata.Add(XRCWidgetData(nameValue,classValue));
}
children = node->GetChildren();
if (children)
BrowseXmlNode(children);
node = node->GetNext();
}
}
public:
XRCWndClassData(const wxString& className,const wxString& parentClassName, const wxXmlNode* node) :
m_className(className) , m_parentClassName(parentClassName) {
BrowseXmlNode(node->GetChildren());
}
const ArrayOfXRCWidgetData& GetWidgetData(){
return m_wdata;
}
void GenerateHeaderCode(wxFFile& file){
file.Write(_T("class ") + m_className + _T(" : public ") + m_parentClassName
+ _T(" {\nprotected:\n"));
for(size_t i=0;i<m_wdata.Count();++i){
const XRCWidgetData& w = m_wdata.Item(i);
file.Write(
_T(" ") + w.GetClass() + _T("* ") + w.GetName()
+ _T(";\n"));
}
file.Write(_T("\nprivate:\n void InitWidgetsFromXRC(){\n")
_T(" wxXmlResource::Get()->LoadObject(this,NULL,\"")
+ m_className
+ +_T("\",\"")
+ m_parentClassName
+ _T("\");\n"));
for(size_t i=0;i<m_wdata.Count();++i){
const XRCWidgetData& w = m_wdata.Item(i);
file.Write(
_T(" ")
+ w.GetName()
+ _T(" = XRCCTRL(*this,\"")
+ w.GetName()
+ _T("\",")
+ w.GetClass()
+ _T(");\n")
);
}
file.Write(_T(" }\n"));
file.Write(
_T("public:\n")
+ m_className
+ _T("::")
+ m_className
+ _T("(){\n")
+ _T(" InitWidgetsFromXRC();\n")
_T(" }\n")
_T("};\n"));
};
};
WX_DECLARE_OBJARRAY(XRCWndClassData,ArrayOfXRCWndClassData);
WX_DEFINE_OBJARRAY(ArrayOfXRCWndClassData);
class XmlResApp : public wxAppConsole
{
public:
// don't use builtin cmd line parsing:
virtual bool OnInit() { return true; }
virtual int OnRun();
private:
private:
void ParseParams(const wxCmdLineParser& cmdline);
void CompileRes();
wxArrayString PrepareTempFiles();
@@ -62,6 +158,10 @@ private:
wxString parOutput, parFuncname, parOutputPath;
wxArrayString parFiles;
int retCode;
ArrayOfXRCWndClassData aXRCWndClassData;
bool flagH;
void GenCPPHeader();
};
IMPLEMENT_APP_CONSOLE(XmlResApp)
@@ -73,6 +173,7 @@ int XmlResApp::OnRun()
{ wxCMD_LINE_SWITCH, _T("h"), _T("help"), _T("show help message"),
wxCMD_LINE_VAL_NONE, wxCMD_LINE_OPTION_HELP },
{ wxCMD_LINE_SWITCH, _T("v"), _T("verbose"), _T("be verbose") },
{ wxCMD_LINE_SWITCH, _T("e"), _T("extra-cpp-code"), _T("output C++ header file with XRC derived classes") },
{ wxCMD_LINE_SWITCH, _T("c"), _T("cpp-code"), _T("output C++ source rather than .rsc file") },
{ wxCMD_LINE_SWITCH, _T("p"), _T("python-code"), _T("output wxPython source rather than .rsc file") },
{ wxCMD_LINE_SWITCH, _T("g"), _T("gettext"), _T("output list of translatable strings (to stdout or file if -o used)") },
@@ -131,6 +232,8 @@ void XmlResApp::ParseParams(const wxCmdLineParser& cmdline)
flagVerbose = cmdline.Found(_T("v"));
flagCPP = cmdline.Found(_T("c"));
flagPython = cmdline.Found(_T("p"));
flagH = flagCPP && cmdline.Found(_T("e"));
if (!cmdline.Found(_T("o"), &parOutput))
{
@@ -146,10 +249,13 @@ void XmlResApp::ParseParams(const wxCmdLineParser& cmdline)
parOutput = _T("resource.xrs");
}
}
wxFileName fn(parOutput);
fn.Normalize();
parOutput = fn.GetFullPath();
parOutputPath = wxPathOnly(parOutput);
if (!parOutput.empty())
{
wxFileName fn(parOutput);
fn.Normalize();
parOutput = fn.GetFullPath();
parOutputPath = wxPathOnly(parOutput);
}
if (!parOutputPath) parOutputPath = _T(".");
if (!cmdline.Found(_T("n"), &parFuncname))
@@ -181,8 +287,11 @@ void XmlResApp::CompileRes()
if (!retCode)
{
if (flagCPP)
if (flagCPP){
MakePackageCPP(files);
if (flagH)
GenCPPHeader();
}
else if (flagPython)
MakePackagePython(files);
else
@@ -238,7 +347,22 @@ wxArrayString XmlResApp::PrepareTempFiles()
wxSplitPath(parFiles[i], &path, &name, &ext);
FindFilesInXML(doc.GetRoot(), flist, path);
if (flagH)
{
wxXmlNode* node = (doc.GetRoot())->GetChildren();
wxString classValue,nameValue;
while(node){
if(node->GetName() == _T("object")
&& node->GetPropVal(_T("class"),&classValue)
&& node->GetPropVal(_T("name"),&nameValue)){
aXRCWndClassData.Add(
XRCWndClassData(nameValue,classValue,node)
);
}
node = node -> GetNext();
}
}
wxString internalName = GetInternalFileName(parFiles[i], flist);
doc.Save(parOutputPath + wxFILE_SEP_PATH + internalName);
@@ -362,7 +486,6 @@ void XmlResApp::MakePackageZIP(const wxArrayString& flist)
static wxString FileToCppArray(wxString filename, int num)
{
wxString output;
@@ -467,6 +590,28 @@ _T("\n"));
}
void XmlResApp::GenCPPHeader()
{
wxString fileSpec = (parOutput.BeforeLast('.')).AfterLast('/');
wxString heaFileName = fileSpec + _T(".h");
wxFFile file(heaFileName, wxT("wt"));
file.Write(
_T("//\n")
_T("// This file was automatically generated by wxrc, do not edit by hand.\n")
_T("//\n\n")
_T("#ifndef __") + fileSpec + _T("_h__\n")
_T("#define __") + fileSpec + _T("_h__\n")
);
for(size_t i=0;i<aXRCWndClassData.Count();++i){
aXRCWndClassData.Item(i).GenerateHeaderCode(file);
}
file.Write(
_T("\nvoid \n")
+ parFuncname
+ _T("();\n#endif\n"));
}
static wxString FileToPythonArray(wxString filename, int num)
{
wxString output;
@@ -550,8 +695,10 @@ void XmlResApp::OutputGettext()
wxArrayString str = FindStrings();
wxFFile fout;
if (!parOutput) fout.Attach(stdout);
else fout.Open(parOutput, wxT("wt"));
if (parOutput.empty())
fout.Attach(stdout);
else
fout.Open(parOutput, wxT("wt"));
for (size_t i = 0; i < str.GetCount(); i++)
fout.Write(_T("_(\"") + str[i] + _T("\");\n"));

View File

@@ -126,6 +126,7 @@ All (GUI):
a new ID for the item using wxNewId(). As a consequence of this,
the value of wxID_SEPARATOR was changed from -1 to -2 in order to
not clash.
- added option to generate C++ headers to wxrc utility (Eduardo Marques)
wxMSW:

View File

@@ -1,3 +1,6 @@
% Note: -e/C++ header generation documentation added by
% Eduardo Marques <edrdo@netcabo.pt>
%
\section{XML-based resource system overview}\label{xrcoverview}
Classes: \helpref{wxXmlResource}{wxxmlresource}, \helpref{wxXmlResourceHandler}{wxxmlresourcehandler}
@@ -112,6 +115,8 @@ To compile binary resource files, use the command-line wxrc utility. It takes on
\item -h (--help): show a help message
\item -v (--verbose): show verbose logging information
\item -c (--cpp-code): write C++ source rather than a XRS file
\item -e (--extra-cpp-code): if used together with -c, generates C++ header file
containing class definitions for the windows defined by the XRC file (see special subsection)
\item -u (--uncompressed): do not compress XML files (C++ only)
\item -g (--gettext): output .po catalog (to stdout, or a file if -o is used)
\item -n (--function) <name>: specify C++ function name (use with -c)
@@ -448,6 +453,95 @@ This is the XML file (resource.xrc) for the XRC sample.
Please see Technical Note 14 (docs/tech/tn0014.txt) in your wxWindows
distribution.
\subsection{C++ header file generation}\label{xrccppheader}
Using the {\tt -e} switch together with {\tt -c}, a C++ header file is written
containing class definitions for the GUI windows defined in the XRC file.
This code generation can make it easier to use XRC and automate program
development.
The classes can be used as basis for development, freeing the
programmer from dealing with most of the XRC specifities (e.g. {\tt XRCCTRL}).
For each top level window defined in the XRC file a C++ class definition is
generated, containing as class members the named widgets of the window.
A default constructor for each class is also generated. Inside the constructor
all XRC loading is done and all class members representing widgets are initialized.
A simple example will help understand how the scheme works. Suppose you have
a XRC file defining a top level window {\tt TestWnd\_Base}, which subclasses {\tt wxFrame} (any
other class like {\tt wxDialog} will do also), and has subwidgets {\tt wxTextCtrl} A and {\tt wxButton} B.
The XRC file and corresponding class definition in the header file will be something like:
\begin{verbatim}
<?xml version="1.0"?>
<resource version="2.3.0.1">
<object class="wxFrame" name="TestWnd_Base">
<size>-1,-1</size>
<title>Test</title>
<object class="wxBoxSizer">
<orient>wxHORIZONTAL</orient>
<object class="sizeritem">
<object class="wxTextCtrl" name="A">
<label>Test label</label>
</object>
</object>
<object class="sizeritem">
<object class="wxButton" name="B">
<label>Test button</label>
</object>
</object>
</object>
</object>
</resource>
class TestWnd_Base : public wxFrame {
protected:
wxTextCtrl* A;
wxButton* B;
private:
void InitWidgetsFromXRC(){
wxXmlResource::Get()->LoadObject(this,NULL,"TestWnd","wxFrame");
A = XRCCTRL(*this,"A",wxTextCtrl);
B = XRCCTRL(*this,"B",wxButton);
}
public:
TestWnd::TestWnd(){
InitWidgetsFromXRC();
}
};
\end{verbatim}
The generated window class can be used as basis for the full window class. The
class members which represent widgets may be accessed by name instead of using
{\tt XRCCTRL} every time you wish to reference them (note that they are {\tt protected} class members),
though you must still use {\tt XRCID} to refer to widget ids in the event
table.
Example:
\begin{verbatim}
#include "resource.h"
class TestWnd : public TestWnd_Base {
public:
TestWnd(){
// A, B already initialised at this point
A->SetValue("Updated in TestWnd::TestWnd");
B->SetValue("Nice :)");
}
void OnBPressed(wxEvent& event){
Close();
}
DECLARE_EVENT_TABLE();
};
BEGIN_EVENT_TABLE(TestWnd,TestWnd_Base)
EVT_BUTTON(XRCID("B"),TestWnd::OnBPressed)
END_EVENT_TABLE()
\end{verbatim}
\subsection{Adding new resource handlers}\label{newresourcehandlers}
Coming soon.

View File

@@ -1,7 +1,7 @@
/////////////////////////////////////////////////////////////////////////////
// Name: wxrc.cpp
// Purpose: XML resource compiler
// Author: Vaclav Slavik
// Author: Vaclav Slavik, Eduardo Marques <edrdo@netcabo.pt>
// Created: 2000/03/05
// RCS-ID: $Id$
// Copyright: (c) 2000 Vaclav Slavik
@@ -33,16 +33,112 @@
#include "wx/wfstream.h"
class XRCWidgetData
{
public:
XRCWidgetData(const wxString& vname,const wxString& vclass)
: m_class(vclass), m_name(vname) {}
const wxString& GetName() const { return m_name; }
const wxString& GetClass() const { return m_class; }
private:
wxString m_class;
wxString m_name;
};
#include "wx/arrimpl.cpp"
WX_DECLARE_OBJARRAY(XRCWidgetData,ArrayOfXRCWidgetData);
WX_DEFINE_OBJARRAY(ArrayOfXRCWidgetData);
class XRCWndClassData
{
private:
wxString m_className;
wxString m_parentClassName;
ArrayOfXRCWidgetData m_wdata;
void BrowseXmlNode(wxXmlNode* node)
{
wxString classValue;
wxString nameValue;
wxXmlNode* children;
while (node)
{
if (node->GetName() == _T("object")
&& node->GetPropVal(_T("class"),&classValue)
&& node->GetPropVal(_T("name"),&nameValue))
{
m_wdata.Add(XRCWidgetData(nameValue,classValue));
}
children = node->GetChildren();
if (children)
BrowseXmlNode(children);
node = node->GetNext();
}
}
public:
XRCWndClassData(const wxString& className,const wxString& parentClassName, const wxXmlNode* node) :
m_className(className) , m_parentClassName(parentClassName) {
BrowseXmlNode(node->GetChildren());
}
const ArrayOfXRCWidgetData& GetWidgetData(){
return m_wdata;
}
void GenerateHeaderCode(wxFFile& file){
file.Write(_T("class ") + m_className + _T(" : public ") + m_parentClassName
+ _T(" {\nprotected:\n"));
for(size_t i=0;i<m_wdata.Count();++i){
const XRCWidgetData& w = m_wdata.Item(i);
file.Write(
_T(" ") + w.GetClass() + _T("* ") + w.GetName()
+ _T(";\n"));
}
file.Write(_T("\nprivate:\n void InitWidgetsFromXRC(){\n")
_T(" wxXmlResource::Get()->LoadObject(this,NULL,\"")
+ m_className
+ +_T("\",\"")
+ m_parentClassName
+ _T("\");\n"));
for(size_t i=0;i<m_wdata.Count();++i){
const XRCWidgetData& w = m_wdata.Item(i);
file.Write(
_T(" ")
+ w.GetName()
+ _T(" = XRCCTRL(*this,\"")
+ w.GetName()
+ _T("\",")
+ w.GetClass()
+ _T(");\n")
);
}
file.Write(_T(" }\n"));
file.Write(
_T("public:\n")
+ m_className
+ _T("::")
+ m_className
+ _T("(){\n")
+ _T(" InitWidgetsFromXRC();\n")
_T(" }\n")
_T("};\n"));
};
};
WX_DECLARE_OBJARRAY(XRCWndClassData,ArrayOfXRCWndClassData);
WX_DEFINE_OBJARRAY(ArrayOfXRCWndClassData);
class XmlResApp : public wxAppConsole
{
public:
// don't use builtin cmd line parsing:
virtual bool OnInit() { return true; }
virtual int OnRun();
private:
private:
void ParseParams(const wxCmdLineParser& cmdline);
void CompileRes();
wxArrayString PrepareTempFiles();
@@ -62,6 +158,10 @@ private:
wxString parOutput, parFuncname, parOutputPath;
wxArrayString parFiles;
int retCode;
ArrayOfXRCWndClassData aXRCWndClassData;
bool flagH;
void GenCPPHeader();
};
IMPLEMENT_APP_CONSOLE(XmlResApp)
@@ -73,6 +173,7 @@ int XmlResApp::OnRun()
{ wxCMD_LINE_SWITCH, _T("h"), _T("help"), _T("show help message"),
wxCMD_LINE_VAL_NONE, wxCMD_LINE_OPTION_HELP },
{ wxCMD_LINE_SWITCH, _T("v"), _T("verbose"), _T("be verbose") },
{ wxCMD_LINE_SWITCH, _T("e"), _T("extra-cpp-code"), _T("output C++ header file with XRC derived classes") },
{ wxCMD_LINE_SWITCH, _T("c"), _T("cpp-code"), _T("output C++ source rather than .rsc file") },
{ wxCMD_LINE_SWITCH, _T("p"), _T("python-code"), _T("output wxPython source rather than .rsc file") },
{ wxCMD_LINE_SWITCH, _T("g"), _T("gettext"), _T("output list of translatable strings (to stdout or file if -o used)") },
@@ -131,6 +232,8 @@ void XmlResApp::ParseParams(const wxCmdLineParser& cmdline)
flagVerbose = cmdline.Found(_T("v"));
flagCPP = cmdline.Found(_T("c"));
flagPython = cmdline.Found(_T("p"));
flagH = flagCPP && cmdline.Found(_T("e"));
if (!cmdline.Found(_T("o"), &parOutput))
{
@@ -146,10 +249,13 @@ void XmlResApp::ParseParams(const wxCmdLineParser& cmdline)
parOutput = _T("resource.xrs");
}
}
wxFileName fn(parOutput);
fn.Normalize();
parOutput = fn.GetFullPath();
parOutputPath = wxPathOnly(parOutput);
if (!parOutput.empty())
{
wxFileName fn(parOutput);
fn.Normalize();
parOutput = fn.GetFullPath();
parOutputPath = wxPathOnly(parOutput);
}
if (!parOutputPath) parOutputPath = _T(".");
if (!cmdline.Found(_T("n"), &parFuncname))
@@ -181,8 +287,11 @@ void XmlResApp::CompileRes()
if (!retCode)
{
if (flagCPP)
if (flagCPP){
MakePackageCPP(files);
if (flagH)
GenCPPHeader();
}
else if (flagPython)
MakePackagePython(files);
else
@@ -238,7 +347,22 @@ wxArrayString XmlResApp::PrepareTempFiles()
wxSplitPath(parFiles[i], &path, &name, &ext);
FindFilesInXML(doc.GetRoot(), flist, path);
if (flagH)
{
wxXmlNode* node = (doc.GetRoot())->GetChildren();
wxString classValue,nameValue;
while(node){
if(node->GetName() == _T("object")
&& node->GetPropVal(_T("class"),&classValue)
&& node->GetPropVal(_T("name"),&nameValue)){
aXRCWndClassData.Add(
XRCWndClassData(nameValue,classValue,node)
);
}
node = node -> GetNext();
}
}
wxString internalName = GetInternalFileName(parFiles[i], flist);
doc.Save(parOutputPath + wxFILE_SEP_PATH + internalName);
@@ -362,7 +486,6 @@ void XmlResApp::MakePackageZIP(const wxArrayString& flist)
static wxString FileToCppArray(wxString filename, int num)
{
wxString output;
@@ -467,6 +590,28 @@ _T("\n"));
}
void XmlResApp::GenCPPHeader()
{
wxString fileSpec = (parOutput.BeforeLast('.')).AfterLast('/');
wxString heaFileName = fileSpec + _T(".h");
wxFFile file(heaFileName, wxT("wt"));
file.Write(
_T("//\n")
_T("// This file was automatically generated by wxrc, do not edit by hand.\n")
_T("//\n\n")
_T("#ifndef __") + fileSpec + _T("_h__\n")
_T("#define __") + fileSpec + _T("_h__\n")
);
for(size_t i=0;i<aXRCWndClassData.Count();++i){
aXRCWndClassData.Item(i).GenerateHeaderCode(file);
}
file.Write(
_T("\nvoid \n")
+ parFuncname
+ _T("();\n#endif\n"));
}
static wxString FileToPythonArray(wxString filename, int num)
{
wxString output;
@@ -550,8 +695,10 @@ void XmlResApp::OutputGettext()
wxArrayString str = FindStrings();
wxFFile fout;
if (!parOutput) fout.Attach(stdout);
else fout.Open(parOutput, wxT("wt"));
if (parOutput.empty())
fout.Attach(stdout);
else
fout.Open(parOutput, wxT("wt"));
for (size_t i = 0; i < str.GetCount(); i++)
fout.Write(_T("_(\"") + str[i] + _T("\");\n"));