--- /dev/null
+//
+// C++ Implementation: qtout
+//
+// Description:
+//
+//
+// Author: Konrad Rosenbaum <konrad@silmor.de>, (C) 2009
+//
+// Copyright: See README/COPYING files that come with this distribution
+//
+//
+
+#include "htmlout.h"
+
+#include <QDir>
+#include <QDomElement>
+
+WocHtmlOut::WocHtmlOut(QDomElement&el)
+{
+ qDebug("Info: creating Html Output Generator.");
+ WocProcessor*woc=WocProcessor::instance();
+ m_basedir=woc->baseDir()+"/"+el.attribute("sourceDir",".");
+ m_subdir=el.attribute("subDir","htmlwob");
+ bool clean=str2bool(el.attribute("clean","0"));
+ //cleanup directory (remove normal files, assume remainder is harmless)
+ QDir d(m_basedir+"/"+m_subdir);
+ if(d.exists() && clean){
+ QStringList ent=d.entryList(QDir::Files);
+ for(int i=0;i<ent.size();i++)
+ d.remove(ent[i]);
+ }
+ //get/create directory
+ if(!d.exists())QDir(".").mkpath(m_basedir+"/"+m_subdir);
+
+ //create index file
+ m_index.setFileName(m_basedir+"/"+m_subdir+"/index.html");
+ if(!m_index.open(QIODevice::WriteOnly|QIODevice::Truncate)){
+ qDebug("Error: cannot create HTML index file %s.",m_index.fileName().toAscii().data());
+ emit errorFound();
+ return;
+ }
+ m_index.write(QByteArray("<html>\n<head>\n"));
+ m_index.write(QByteArray("<title>Project Index</title>\n"));
+
+ m_index.write(QByteArray("</head><body>\n"));
+ //write project info
+ QString inf="<h1>Project "+woc->projectName()+"</h1>\n";
+ inf+="Human Readable Version: "+woc->verHR()+"<br/>";
+ inf+="Communication Layer Version: "+woc->verComm()+"<br/>";
+ inf+="Minimum Compatible Version: "+woc->verNeedComm()+"<p/>";
+
+ inf+="SVN Repository URL: "+woc->svnRepositoryUrl()+"<br/>";
+ inf+="SVN Repository Root: "+woc->svnRepositoryRoot()+"<br/>";
+ inf+="SVN Revision: "+woc->svnRevision()+"<p/>";
+
+ inf+="Database Instance Object: "+woc->dbInst()+"<br/>";
+ inf+="Database Schema Object: "+woc->dbSchema()+"<br/>";
+ inf+="Database Schema Version: "+woc->dbVersion()+"<p/>";
+
+ m_index.write(inf.toAscii());
+
+ //write global docu
+ QStringList dcs=woc->docStrings();
+ for(int i=0;i<dcs.size();i++){
+ inf="<p>"+dcs[i]+"</p>\n";
+ m_index.write(inf.toAscii());
+ }
+}
+
+WocHtmlOut::~WocHtmlOut(){}
+
+void WocHtmlOut::finalize()
+{
+ //TODO: write index table content
+ m_index.write(QByteArray("<h1>Index</h1>\n"));
+ m_index.write(QByteArray("<table><tr><td><h2>Classes</h2></td><td><h2>Transactions</td><td><h2>Tables</h2></td></tr>\n"));
+ m_index.write(QByteArray("<tr><td valign=\"top\"><ul>\n"));
+ QStringList sl=WocProcessor::instance()->classNames();
+ QString s;
+ qSort(sl);
+ for(int i=0;i<sl.size();i++)
+ s+="<li><a href=\"class-"+sl[i]+".html\">"+sl[i]+"</a></li>\n";
+ m_index.write(s.toAscii());
+
+ m_index.write(QByteArray("</ul></td><td valign=\"top\"><ul>"));
+ sl=WocProcessor::instance()->transactionNames();
+ s="";
+ qSort(sl);
+ for(int i=0;i<sl.size();i++)
+ s+="<li><a href=\"trn-"+sl[i]+".html\">"+sl[i]+"</a></li>\n";
+ m_index.write(s.toAscii());
+
+ m_index.write(QByteArray("</ul></td><td valign=\"top\"><ul>"));
+ sl=WocProcessor::instance()->tableNames();
+ s="";
+ qSort(sl);
+ for(int i=0;i<sl.size();i++)
+ s+="<li><a href=\"table-"+sl[i]+".html\">"+sl[i]+"</a></li>\n";
+ m_index.write(s.toAscii());
+
+ m_index.write(QByteArray("</ul></td></tr></table>\n"));
+
+ m_index.write(QByteArray("\n</body></html>\n"));
+ m_index.close();
+}
+
+void WocHtmlOut::newTable(const WocTable&tbl)
+{
+ QString cn=tbl.name();
+ QFile htm(m_basedir+"/"+m_subdir+"/table-"+cn+".html");
+ if(!htm.open(QIODevice::WriteOnly|QIODevice::Truncate)){
+ qDebug("Error: cannot create html file for table %s.",cn.toAscii().data());
+ emit errorFound();
+ return;
+ }
+ //lead in
+ htm.write(QString("<html><title>Table "+cn+"</title><body>\n").toAscii());
+
+ QString hcd;
+ //table declaration
+ hcd+="<h1>Table "+cn+"</h1>\n";
+
+ if(tbl.isAuditable()){
+ hcd+="<p>This table is audited, see <a href=\"table-"+tbl.name()+"_audit.html\">"
+ +tbl.name()+"_audit</a> for details.</p>\n";
+ }
+
+ QStringList td=tbl.docStrings();
+ for(int i=0;i<td.size();i++)
+ hcd+="<p>"+td[i]+"</p>\n";
+
+ hcd+="<table frame=\"1\" border=\"1\"><tr><td><b>Column Name</b></td><td><b>Type</b></td><td><b>Properties</b></td><td><b>Docu</b></td></tr>\n";
+ QStringList cl=tbl.columns();
+ for(int i=0;i<cl.size();i++){
+ hcd+="<tr><td>"+cl[i]+"</td><td>"+tbl.columnType(cl[i])+"</td><td>";
+ if(tbl.columnIsPrimary(cl[i]))
+ hcd+="Primary-Key ";
+ if(tbl.columnIsNull(cl[i]))
+ hcd+="NULL-able ";
+ if(tbl.columnHasDefault(cl[i]))
+ hcd+="default=\""+tbl.columnDefault(cl[i])+"\" ";
+ if(tbl.columnIsForeign(cl[i])){
+ QStringList cf=tbl.columnForeign(cl[i]).split(":");
+ hcd+="Foreign-Key=<a href=\"table-"+cf[0]+".html\">"+cf[0]+"("+cf[1]+")</a> ";
+ }
+ if(tbl.columnIsIndexed(cl[i]))
+ hcd+="Indexed ";
+ if(tbl.columnIsUnique(cl[i]))
+ hcd+="Unique";
+ hcd+="</td><td>"+tbl.columnDoc(cl[i])+"</td></tr>\n";
+ }
+ hcd+="</table>\n";
+
+ //enums
+ for(int i=0;i<cl.size();i++){
+ QList<WocEnum >lst=tbl.columnEnums(cl[i]);
+ if(lst.size()>0){
+ hcd+="<h2>Enum for column "+cl[i]+"</h2>\n<ul>\n";
+ for(int j=0;j<lst.size();j++){
+ hcd+="<li>"+lst[j].name+"="+QString::number(lst[j].val);
+ if(lst[j].doc!="")hcd+="<br/>"+lst[j].doc;
+ hcd+="</li>\n";
+ }
+ hcd+="</ul>\n";
+ }
+ }
+
+ //foreign getters
+ cl=tbl.foreigns();
+ if(cl.size()>0){
+ hcd+="<h2>Foreign Getters</h2>\n<ul>";
+ for(int i=0;i<cl.size();i++){
+ hcd+="<li>"+cl[i];
+ QString s=tbl.foreignDoc(cl[i]);
+ if(s!="")hcd+="<br/>"+s;
+ hcd+="</li>\n";
+ }
+ }
+
+ //presets
+ QList<QMap<QString,QString> >pre=tbl.presets();
+ if(pre.size()>0){
+ hcd+="<h2>Presets</h2>\n<table frame=\"1\" border=\"1\">\n<tr>";
+ cl=tbl.columns();
+ for(int i=0;i<cl.size();i++)
+ hcd+="<td><b>"+cl[i]+"</b></td>";
+ hcd+="</tr>\n";
+ for(int i=0;i<pre.size();i++){
+ hcd+="<tr>";
+ for(int j=0;j<cl.size();j++){
+ hcd+="<td>";
+ if(pre[i].contains(cl[j]))
+ hcd+=pre[i][cl[j]];
+ hcd+="</td>";
+ }
+ hcd+="</tr>\n";
+ }
+ hcd+="</table>\n";
+ }
+
+ hcd+="</body></html>\n";
+ htm.write(hcd.toAscii());
+}
+
+void WocHtmlOut::newClass(const WocClass&cls)
+{
+ QString cn=cls.name();
+ QFile htm(m_basedir+"/"+m_subdir+"/class-"+cn+".html");
+ if(!htm.open(QIODevice::WriteOnly|QIODevice::Truncate)){
+ qDebug("Error: cannot create html file for class %s.",cn.toAscii().data());
+ emit errorFound();
+ return;
+ }
+ //lead in
+ htm.write(QString("<html><title>Class "+cn+"</title><body>\n").toAscii());
+
+ QString hcd;
+ //class declaration
+ hcd+="<h1>";
+ if(cls.isAbstract(""))hcd+="Abstract ";
+ hcd+="Class "+cn+"</h1>\n";
+
+ //conditional abstract
+ QStringList ab=cls.abstractLangs();
+ if(ab.size()>0){
+ hcd+="<p>The class is conditionally abstract in: ";
+ for(int i=0;i<ab.size();i++){
+ if(i)hcd+=", ";
+ hcd+=ab[i];
+ }
+ hcd+="</p>\n";
+ }
+
+ //docu
+ QStringList doc=cls.docStrings();
+ for(int i=0;i<doc.size();i++)
+ hcd+="<p>"+doc[i]+"</p>\n";
+ htm.write(hcd.toAscii());
+
+ //enums
+ classEnums(cls,htm);
+
+ //properties
+ classProperties(cls,htm);
+
+ //mappings
+ classMappings(cls,htm);
+
+ //lead out
+ htm.write(QByteArray("</body></html>\n"));
+}
+
+void WocHtmlOut::classEnums(const WocClass&cls,QFile&hdr)
+{
+ QStringList k=cls.enumTypes();
+ if(k.size()==0)return;
+ QString hcd="<h2>Enums</h2>\n";
+ for(int i=0;i<k.size();i++){
+ //type
+ hcd+="<h3>enum "+k[i]+"</h3>\n";
+ hcd+="<table frame=\"1\" border=\"1\">";
+ hcd+="<tr><td><b>Symbol</b></td><td><b>Value</b></td><td><b>Docu</b></td></tr>\n";
+ QList<WocEnum>ev=cls.enumValues(k[i]);
+ for(int j=0;j<ev.size();j++){
+ hcd+="<tr><td>"+ev[j].name+"</td><td>"+QString::number(ev[j].val)
+ +"</td><td>"+ev[j].doc+"</td></tr>\n";
+ }
+ hcd+="</table>\n";
+ }
+ hdr.write(hcd.toAscii());
+}
+
+void WocHtmlOut::classProperties(const WocClass&cls,QFile&hdr)
+{
+ QStringList k=cls.propertyNames();
+ if(k.size()==0)return;
+ QString hcd;
+ //declare members
+ hcd="<h2>Properties</h2>\n<ul>\n";
+ for(int i=0;i<k.size();i++){
+ hcd+="<li>"+k[i]+" (";
+ if(cls.propertyIsObject(k[i]))
+ hcd+="<a href=\"class-"+cls.propertyPlainType(k[i])+".html\">";
+ hcd+=cls.propertyType(k[i]);
+ if(cls.propertyIsObject(k[i]))
+ hcd+="</a>";
+ hcd+=")";
+ QString d=cls.propDoc(k[i]);
+ if(d!="")hcd+="<br/>"+d;
+ hcd+="</li>\n";
+ }
+ hcd+="</ul>\n";
+ //write
+ hdr.write(hcd.toAscii());
+}
+
+void WocHtmlOut::classMappings(const WocClass&cls,QFile&hdr)
+{
+ QStringList k=cls.mappingTables();
+ if(k.size()==0)return;
+ QString hcd;
+ for(int i=0;i<k.size();i++){
+ hcd+="<h2>Mapping for Table <a href=\"table-"+k[i]+".html\">"+k[i]+"</a></h2>\n";
+ hcd+="<table frame=\"1\" border=\"1\">\n";
+ hcd+="<tr><td><b>Property</b></td><td><b>Column</b></td></tr>\n";
+ QMap<QString,QString> map=cls.mapping(k[i]);
+ QStringList k2=map.keys();
+ for(int j=0;j<k2.size();j++){
+ hcd+="<tr><td>"+k2[j]+"</td><td>"+map[k2[j]]+"</td></tr>\n";
+ }
+ hcd+="</table>\n";
+ }
+
+ hdr.write(hcd.toAscii());
+}
+
+void WocHtmlOut::newTransaction(const WocTransaction&trn)
+{
+ QString cn=trn.name();
+ QFile htm(m_basedir+"/"+m_subdir+"/trn-"+cn+".html");
+ if(!htm.open(QIODevice::WriteOnly|QIODevice::Truncate)){
+ qDebug("Error: cannot create HTML file for transaction %s.",cn.toAscii().data());
+ emit errorFound();
+ return;
+ }
+ //basics
+ QStringList in=trn.inputNames();
+ QStringList out=trn.outputNames();
+ QStringList doc=trn.docStrings();
+ //lead in
+ QString hcd;
+ hcd="<html><title>Transaction "+cn+"</title><body>\n<h1>Transaction "+cn+"</h1>\n";
+ //auth mode
+ hcd+="<p>Authentication mode: ";
+ switch(trn.authMode()){
+ case WocTransaction::Checked:hcd+="Checked (known user, must have the privilege)";break;
+ case WocTransaction::Auth:hcd+="Authenticated (known user, any/no privileges)";break;
+ case WocTransaction::Open:hcd+="Open (unauthenticated, any user)";break;
+ default:hcd+="Ooops. Unknown Mode.";break;
+ }
+ hcd+="</p>\n";
+ //docu
+ for(int i=0;i<doc.size();i++)
+ hcd+="<p>"+doc[i]+"</p>\n";
+ //in/out
+ hcd+="<h2>Inputs:</h2>\n<ul>\n";
+ for(int i=0;i<in.size();i++){
+ hcd+="<li>"+in[i]+": ";
+ QString t=trn.inputType(in[i]);
+ if(trn.isObjectType(t))
+ hcd+="<a href=\"class-"+trn.plainType(t)+".html\">";
+ hcd+=t;
+ if(trn.isObjectType(t))
+ hcd+="</a>";
+ //add docu
+ t=trn.inputDoc(in[i]);
+ if(t!="")hcd+="<br/>"+t;
+ hcd+="</li>\n";
+ }
+ hcd+="</ul>\n<h2>Outputs:</h2>\n<ul>\n";
+ for(int i=0;i<out.size();i++){
+ hcd+="<li>"+out[i]+": ";
+ QString t=trn.outputType(out[i]);
+ if(trn.isObjectType(t))
+ hcd+="<a href=\"class-"+trn.plainType(t)+".html\">";
+ hcd+=t;
+ if(trn.isObjectType(t))
+ hcd+="</a>";
+ //add docu
+ t=trn.outputDoc(out[i]);
+ if(t!="")hcd+="<br/>"+t;
+ hcd+="</li>\n";
+ }
+ hcd+="</ul>\n";
+ //privileges
+ QStringList pri=trn.privileges();
+ if(pri.size()){
+ hcd+="<h2>Privileges</h2>\n<ul>\n";
+ for(int i=0;i<pri.size();i++){
+ hcd+="<li>"+pri[i];
+ QString d=trn.privilegeDoc(pri[i]);
+ if(d!="")
+ hcd+="<br/>"+d;
+ hcd+="</li>\n";
+ }
+ hcd+="</ul>\n";
+ }
+ hcd+="</body></html>\n";
+ htm.write(hcd.toAscii());
+}
--- /dev/null
+//
+// C++ Interface: qtout
+//
+// Description:
+//
+//
+// Author: Konrad Rosenbaum <konrad@silmor.de>, (C) 2009
+//
+// Copyright: See README/COPYING files that come with this distribution
+//
+//
+
+#ifndef WOC_HTMLOUT_H
+#define WOC_HTMLOUT_H
+
+#include "processor.h"
+
+#include <QFile>
+
+class QDomElement;
+
+class WocHtmlOut:public WocOutput
+{
+ public:
+ WocHtmlOut(QDomElement&);
+ ~WocHtmlOut();
+ protected:
+ virtual void finalize();
+ virtual void newClass(const WocClass&);
+ virtual void newTable(const WocTable&);
+ virtual void newTransaction(const WocTransaction&);
+ private:
+ QString m_basedir,m_subdir;
+ QFile m_index;
+
+ /**helper: generate enums for classes*/
+ void classEnums(const WocClass&,QFile&);
+ /**helper: generate properties*/
+ void classProperties(const WocClass&,QFile&);
+ /**helper: generate mappings*/
+ void classMappings(const WocClass&,QFile&);
+
+};
+
+#endif
--- /dev/null
+//
+// C++ Implementation: mfile
+//
+// Description:
+//
+//
+// Author: Konrad Rosenbaum <konrad@silmor.de>, (C) 2010
+//
+// Copyright: See README/COPYING files that come with this distribution
+//
+//
+
+#include "mfile.h"
+
+#include <QFileInfo>
+
+//static
+QMap<QString,QStringList> MFile::touched;
+
+MFile::MFile(QString n,QObject*parent):QFile(n+",new",parent),name(n){isopen=false;}
+MFile::MFile(QObject *parent):QFile(parent){isopen=false;}
+MFile::~MFile()
+{
+ if(isopen)close();
+}
+
+void MFile::close()
+{
+// qDebug("Info: closing %s",name.toAscii().data());
+ //compare
+ bool ident=false;
+ if(isopen){
+ QFile::close();
+ QFile::open(QIODevice::ReadOnly);
+ QByteArray here=readAll();
+ QFile there(name);
+ if(there.open(QIODevice::ReadOnly)){
+ ident=(here == there.readAll());
+ there.close();
+ }
+ }
+ //actual close
+ QFile::close();
+ //move
+ if(isopen){
+ isopen=false;
+ if(ident){
+ //if identical: remove new version to preserve file time
+ remove();
+ }else{
+ //if not identical: use new version, remove old one
+ QFile(name).remove();
+ QFile(name+",new").rename(name);
+ }
+ }
+}
+
+void MFile::setFileName(QString n)
+{
+ name=n;
+ QFile::setFileName(n+",new");
+}
+
+bool MFile::open(QIODevice::OpenMode m)
+{
+ isopen=QFile::open(m);
+ if(isopen){
+ //remember it
+ QFileInfo fi(name);
+ QString p=fi.absolutePath();
+ QString f=fi.fileName();
+ if(!touched.contains(p))touched.insert(p,QStringList());
+ if(!touched[p].contains(f))touched[p]<<f;
+ }
+ return isopen;
+}
+
+bool MFile::touchedFile(QString name)
+{
+ QFileInfo fi(name);
+ QString p=fi.absolutePath();
+ QString f=fi.fileName();
+ if(!touched.contains(p))return false;
+ return touched[p].contains(f);
+}
--- /dev/null
+//
+// C++ Interface: mfile
+//
+// Description:
+//
+//
+// Author: Konrad Rosenbaum <konrad@silmor.de>, (C) 2010
+//
+// Copyright: See README/COPYING files that come with this distribution
+//
+//
+
+#ifndef WOC_MFILE_H
+#define WOC_MFILE_H
+
+#include <QFile>
+#include <QMap>
+#include <QStringList>
+
+/**overwrites QFile to only generate a file if its new version differs from an existing one, it creates a temporary file with ",new" added to the file name; additionally it records all file names that it touches;
+this is not a complete implementation - just enough for woc*/
+class MFile:public QFile
+{
+ public:
+ MFile(QString name,QObject*parent=0);
+ MFile(QObject *parent=0);
+ ~MFile();
+
+ virtual void close();
+ virtual bool open(QIODevice::OpenMode m);
+
+ QString fileName()const{return name;}
+ void setFileName(QString n);
+
+ static bool touchedFile(QString);
+ private:
+ //flag to show whether file is open
+ bool isopen;
+ //original name of the file
+ QString name;
+
+ //stores touched files
+ static QMap<QString,QStringList> touched;
+};
+
+#endif
--- /dev/null
+//
+// C++ Implementation: phpout
+//
+// Description:
+//
+//
+// Author: Konrad Rosenbaum <konrad@silmor.de>, (C) 2009
+//
+// Copyright: See README/COPYING files that come with this distribution
+//
+//
+
+#include "phpout.h"
+
+#include <QDir>
+#include <QDomElement>
+
+static const QByteArray PHPSTART("<?\n//THIS IS AN AUTOGENERATED FILE, DONT CHANGE!\n\n");
+static const QByteArray PHPEND("\n//END OF AUTOGENERATED FILE\n?>");
+
+static const QByteArray SCHEMASTART("class WobSchema extends WobSchemaBase\n{\nfunction __construct(){\n");
+static const QByteArray SCHEMAEND("}};\n");
+
+static const QByteArray TRANSACTCLASS("class WobTransaction extends WobTransactionBase\n{\n");
+static const QByteArray TRANSACTSTART(" static public function handle(){switch(WobTransactionBase::getTransactionName()){\n");
+static const QByteArray TRANSACTEND("\tdefault:WobTransactionBase::noSuchTransaction();break;\n }}\n");
+
+WocPHPServerOut::WocPHPServerOut(const QDomElement&el)
+{
+ qDebug("Info: creating PHP Server Output Generator.");
+ m_basedir=WocProcessor::instance()->baseDir()+"/"+el.attribute("sourceDir",".");
+ m_subdir=el.attribute("subDir","phpwob");
+ m_fileext=el.attribute("extension",".inc");
+ QList<QDomElement> nl=elementsByTagName(el,"Authenticator");
+ if(nl.size()){
+ QDomElement el2=nl.at(0).toElement();
+ m_isauth=el2.attribute("isAuthenticated","false");
+ m_hasrole=el2.attribute("hasRole","false");
+ m_username=el2.attribute("userName","\"\"");
+ m_authinit=el2.attribute("init","");
+ }else{
+ m_isauth="false";
+ m_hasrole="false";
+ m_username="\"\"";
+ }
+ //cleanup directory (remove normal files, assume remainder is harmless)
+ QDir d(m_basedir+"/"+m_subdir);
+ if(d.exists() && str2bool(el.attribute("clean","0"))){
+ QStringList ent=d.entryList(QDir::Files);
+ for(int i=0;i<ent.size();i++)
+ d.remove(ent[i]);
+ }
+ //get/create directory
+ if(!d.exists())QDir(".").mkpath(m_basedir+"/"+m_subdir);
+ //create loader
+ m_loader.setFileName(m_basedir+"/"+m_subdir+"/autoload"+m_fileext);
+ if(!m_loader.open(QIODevice::ReadWrite|QIODevice::Truncate)){
+ qDebug("Error: PHP Server Generator - cannot create loader file, deactivating output.");
+ emit errorFound();
+ return;
+ }
+ m_loader.write(PHPSTART);
+ //create schema file
+ m_schema.setFileName(m_basedir+"/"+m_subdir+"/schema"+m_fileext);
+ if(!m_schema.open(QIODevice::ReadWrite|QIODevice::Truncate)){
+ qDebug("Error: PHP Server Generator - cannot create DB schema file.");
+ emit errorFound();
+ return;
+ }
+ m_schema.write(PHPSTART);
+ m_schema.write(SCHEMASTART);
+ m_schema.write(("\t$this->sversion=\""+WocProcessor::instance()->dbVersion()+"\";\n").toAscii());
+ addLoad("WobSchema","schema");
+ //create Transaction file
+ m_transact.setFileName(m_basedir+"/"+m_subdir+"/transaction"+m_fileext);
+ if(!m_transact.open(QIODevice::ReadWrite|QIODevice::Truncate)){
+ qDebug("Error: PHP Server Generator - cannot create transaction processor file.");
+ emit errorFound();
+ return;
+ }
+ m_transact.write(PHPSTART);
+ m_transact.write(TRANSACTCLASS);
+ transInfo();
+ m_transact.write(TRANSACTSTART);
+ addLoad("WobTransaction","transaction");
+}
+
+void WocPHPServerOut::transInfo()
+{
+ WocProcessor*woc=WocProcessor::instance();
+ m_transact.write(QString(" static public function commVersion(){return \""+woc->verComm()+"\";}\n").toAscii());
+ m_transact.write(QString(" static public function needCommVersion(){return \""+woc->verNeedComm()+"\";}\n").toAscii());
+ m_transact.write(QString(" static public function version(){return \""+woc->verHR()+"\";}\n").toAscii());
+ m_transact.write(QString(" static public function svnVersion(){return \""+woc->svnRevision()+"\";}\n\n").toAscii());
+ m_transact.write(QString(" static public function svnRepositoryRoot(){return \""+woc->svnRepositoryRoot()+"\";}\n\n").toAscii());
+ m_transact.write(QString(" static public function svnRepositoryUrl(){return \""+woc->svnRepositoryUrl()+"\";}\n\n").toAscii());
+}
+
+void WocPHPServerOut::transInfo2()
+{
+ WocProcessor*woc=WocProcessor::instance();
+ //transaction names
+ QString code=" static public function transactionNames(){\n\treturn array(";
+ QStringList tns=woc->transactionNames();
+ for(int i=0;i<tns.size();i++){
+ if(i)code+=",";
+ code+="\n\t\ttranslate(\"_TransactionNames\",\""+tns[i]+"\")";
+ }
+ code+=");\n }\n";
+ //privilege names
+ code+="static public function privilegeNames(){\n\treturn array(";
+ QStringList priv=woc->privilegeNames();
+ for(int i=0;i<priv.size();i++){
+ if(i)code+=",\n\t\t";else code+="\n\t\t";
+ code+="translate(\"_PrivilegeNames\",\""+priv[i]+"\")";
+ }
+ code+="\n\t);\n}\n";
+
+ m_transact.write(code.toAscii());
+}
+
+void WocPHPServerOut::finalize()
+{
+ if(m_loader.isOpen()){
+ m_loader.write(PHPEND);
+ m_loader.close();
+ }
+ if(m_schema.isOpen()){
+ m_schema.write(SCHEMAEND);
+ m_schema.write(PHPEND);
+ m_schema.close();
+ }
+ if(m_transact.isOpen()){
+ m_transact.write(TRANSACTEND);
+ transInfo2();
+ m_transact.write("};\n");
+ m_transact.write(PHPEND);
+ m_transact.close();
+ }
+}
+
+void WocPHPServerOut::newTable(const WocTable&tbl)
+{
+ if(!m_loader.isOpen())return;
+ WocProcessor *woc=WocProcessor::instance();
+ //create table file
+ QString fn=m_subdir+"/wt_"+tbl.name()+m_fileext;
+ QFile tf(m_basedir+"/"+fn);
+ if(!tf.open(QIODevice::ReadWrite|QIODevice::Truncate)){
+ qDebug("Error: cannot create PHP table file %s.",fn.toAscii().data());
+ emit errorFound();
+ return;
+ }
+ tf.write(PHPSTART);
+ QString code="/* TRANSLATOR WT"+tbl.name()+" */\nclass WT"+tbl.name()+" extends "+tbl.baseClass()+"\n{\n";
+ //initializer
+ code+="protected function __construct(array $data,$isfromdb){parent::__construct($data,$isfromdb,\""+tbl.name()+"\");}\n\n";
+
+ //static new instance for insert only
+ code+="public static function newRow(array $data=array()){return new WT"+tbl.name()+"($data,false);}\n\n";
+
+ //static get instance
+ QStringList cols=tbl.columns();
+ QStringList pcols=tbl.primaryColumns();
+ //header
+ code+="public static function getFromDB(";
+ for(int i=0;i<pcols.size();i++){
+ if(i)code+=",";
+ code+="$"+pcols[i];
+ }
+ QString dbi="$"+woc->dbInst();
+ //DB query
+ code+="){\n\tglobal "+dbi+";\n\t$res="+dbi+"->select(\""+tbl.name()+"\",\"*\",\"";
+ for(int i=0;i<pcols.size();i++){
+ if(i)code+=" AND ";
+ code+=pcols[i]+"=\"."+dbi+"->escapeColumn(\""+tbl.name()+"\",\""+pcols[i]+"\",$"+pcols[i]+").\"";
+ }
+ code+="\");\n";
+ //check result
+ code+="\tif($res===false)return false;\n\tif(count($res)<1)return false;\n\telse return new WT"+tbl.name()+"($res[0],true);\n}\n\n";
+
+ //static get selection
+ code+="public static function selectFromDB($where=\"\",$orderby=\"\"){\n\tglobal "+dbi+";\n\t$res="+dbi+"->select(\""+tbl.name()+"\",\"*\",$where,$orderby);\n\tif($res===false || count($res)<1)return array();\n\t";
+ code+="$r=array();\n\tforeach($res as $row)\n\t\t$r[]=new WT"+tbl.name()+"($row,true);\n\treturn $r;\n}\n\n";
+
+ //go through columns, generate specific code
+ for(int i=0;i<cols.size();i++){
+ //automatic resolution of internal foreign keys
+ if(tbl.columnIsForeign(cols[i])){
+ code+="public function getObjectFor"+cols[i]+"(){\n\tglobal "+dbi+";\n\treturn WT";
+ QStringList foreign=tbl.columnForeign(cols[i]).split(":");
+ code+=foreign[0]+"::selectFromDB(\""+foreign[1]+"=\"."+dbi+"->escapeColumn(\""+foreign[0]+"\",\""+foreign[1]+"\",$this->"+cols[i]+"));\n}\n\n";
+ }
+ //implement enum check for set method of enum columns
+ if(tbl.columnType(cols[i]).startsWith("enum")){
+ code+="protected function verifyValue"+cols[i]+"($v){if(false";
+ QList<WocEnum>ens=tbl.columnEnums(cols[i]);
+ QList<int>envs;
+ for(int j=0;j<ens.size();j++){
+ int v=ens[j].val;
+ if(envs.contains(v))continue;
+ envs.append(v);
+ code+="||$v=="+QString::number(v);
+ }
+ code+=")return true;else return false;}\n\n";
+ }
+ }
+
+ //reverse resolution of configured foreign keys
+ QStringList fs=tbl.foreigns();
+ for(int i=0;i<fs.size();i++){
+ QString via=tbl.foreignQuery(fs[i]);
+ //parse via
+ QStringList v1=via.split("=");
+ if(v1.size()!=2){
+ qDebug("Warning: Foreign clause %s of table %s has illegal syntax. Should be foreigntable:column=localcolumn.",fs[i].toAscii().data(),tbl.name().toAscii().data());
+ continue;
+ }
+ QString local=v1[1].trimmed();
+ QStringList foreign=v1[0].split(":");
+ if(foreign.size()!=2){
+ qDebug("Warning: Foreign clause %s of table %s has illegal syntax. Should be foreigntable:column=localcolumn.",fs[i].toAscii().data(),tbl.name().toAscii().data());
+ continue;
+ }
+ code+="public function "+fs[i]+"(){\n\tglobal "+dbi+";\n\treturn WT"+foreign[0]+"::selectFromDB(\""+foreign[1]+"=\"."+dbi+"->escapeColumn(\"";
+ code+=foreign[0]+"\",\""+foreign[1]+"\",$this->"+local+"));\n}\n\n";
+ }
+
+ //create enum constants
+ QList<WocEnum>ens=tbl.getEnums();
+ for(int i=0;i<ens.size();i++){
+ code+="const "+ens[i].name+"="+QString::number(ens[i].val)+";\n";
+ }
+
+ //hasproperty function
+ code+="public function hasProperty($p){switch($p){\n";
+ for(int i=0;i<cols.size();i++)
+ code+="\tcase \""+cols[i]+"\":\n";
+ QStringList aps=tbl.auditColumns();
+ for(int i=0;i<aps.size();i++)
+ code+="\tcase \""+aps[i]+"\":\n";
+ code+="\t\treturn true;\n\tdefault:return false;}}\n";
+
+ //create audit stuff
+ if(tbl.isAuditable()){
+ code+="public function isAuditable(){return true;}\n";
+ code+="protected function createAudit(){$ad=WT"+tbl.name()+"_audit::newRow($this->data);\n";
+ code+="\treturn $ad->insert();\n}\n";
+ }
+
+ //create newKey function
+ code+="public function newKey(){\n\tparent::newKey();\n";
+ for(int i=0;i<cols.size();i++){
+ QString c=tbl.columnCall(cols[i],"php");
+ if(c=="")continue;
+ code+="\t$this->cdata[\""+cols[i]+"\"]="+c+";\n";
+ }
+ code+="}\n";
+
+ //write table class
+ code+="};\n";
+ tf.write(code.toAscii());
+ tf.write(PHPEND);
+ tf.close();
+
+ //extend schema file
+ //column definitions
+ code="\t$this->scheme[\""+tbl.name()+"\"]=array(";
+ for(int i=0;i<cols.size();i++){
+ if(i)code+=",";
+ code+="\n\t\t\""+cols[i]+"\"=>array(\"";
+ code+=tbl.columnType(cols[i])+"\"";
+ if(!tbl.columnIsNull(cols[i]))code+=",\"notnull\"";
+ if(tbl.columnIsForeign(cols[i]))code+=",\"foreignkey:"+tbl.columnForeign(cols[i])+"\"";
+ if(pcols.size()<2 && tbl.columnIsPrimary(cols[i]))code+=",\"primarykey\"";
+ if(tbl.columnHasDefault(cols[i]))code+=",\"default:"+tbl.columnDefault(cols[i])+"\"";
+ if(tbl.columnIsIndexed(cols[i]))code+=",\"index\"";
+ if(tbl.columnIsUnique(cols[i]))code+=",\"unique\"";
+ code+=")";
+ }
+ if(pcols.size()>=2){
+ code+=",\n\t\t\":primarykey\"=>array(";
+ for(int i=0;i<pcols.size();i++){
+ if(i)code+=",";
+ code+="\""+pcols[i]+"\"";
+ }
+ code+=")";
+ }
+ code+="\n\t);\n";
+ if(tbl.inBackup())code+="\t$this->backup[]=\""+tbl.name()+"\";\n";
+ //write presets
+ QList<QMap<QString,QString> >presets=tbl.presets();
+ if(presets.size()>0){
+ code+="\t$this->preset[\""+tbl.name()+"\"]=array(";
+ for(int i=0;i<presets.size();i++){
+ if(i)code+=",";
+ code+="\n\t\tarray(";
+ QStringList k=presets[i].keys();
+ for(int j=0;j<k.size();j++){
+ if(j)code+=",";
+ code+="\""+k[j]+"\"=>"+presets[i][k[j]];
+ }
+ code+=")";
+ }
+ code+="\n\t);\n";
+ }
+
+ //write
+ m_schema.write(code.toAscii());
+
+ //create autoloading
+ addLoad("WT"+tbl.name(),"wt_"+tbl.name());
+}
+
+void WocPHPServerOut::addLoad(QString cn,QString fn)
+{
+ QString ld="$AUTOCLASS[\""+cn+"\"]=\""+m_subdir+"/"+fn+m_fileext+"\";\n";
+ m_loader.write(ld.toAscii());
+}
+
+void WocPHPServerOut::newClass(const WocClass&cls)
+{
+ //cover basics
+ QString cn=className(cls);
+ QString cna=abstractClassName(cls);
+ QString fn="wo_"+cls.name();
+ addLoad(cna,fn);
+ fn=m_subdir+"/"+fn+m_fileext;
+ QFile tf(m_basedir+"/"+fn);
+ if(!tf.open(QIODevice::ReadWrite|QIODevice::Truncate)){
+ qDebug("Error: cannot create PHP object file %s.",fn.toAscii().data());
+ emit errorFound();
+ return;
+ }
+ tf.write(PHPSTART);
+
+ ////
+ //generate code
+ QString code="/* TRANSLATOR "+cna+" */\nclass "+cna+" extends "+cls.serverBaseClass()+"{\n\n";
+ tf.write(code.toAscii());
+
+ //property declaration and constructor
+ tf.write(classConstruct(cls).toAscii());
+
+ //enums
+ tf.write(classEnums(cls).toAscii());
+
+ //properties
+ tf.write(classProperties(cls).toAscii());
+
+ //mappings
+ tf.write(classMappings(cls).toAscii());
+
+ //serializers
+ tf.write(classSerializers(cls).toAscii());
+
+ //de-serializer
+ tf.write(classDeserializers(cls).toAscii());
+
+ //end of class
+ code="\n//end of class\n};\n";
+ tf.write(code.toAscii());
+
+ tf.write(PHPEND);
+ tf.close();
+}
+
+QString WocPHPServerOut::classConstruct(const WocClass&cls)
+{
+ QString code;
+ QStringList k=cls.propertyNames();
+ for(int i=0;i<k.size();i++){
+ code+="protected $prop_"+k[i];
+ if(!cls.propertyIsList(k[i]))code+="=null";
+ code+=";\n";
+ }
+ code+="public function __construct()\n{\n";
+ for(int i=0;i<k.size();i++)
+ if(cls.propertyIsList(k[i]))
+ code+="\t$this->prop_"+k[i]+"=array();";
+ code+="}\n";
+ return code;
+}
+
+QString WocPHPServerOut::classEnums(const WocClass&cls)
+{
+ QString code;
+ QStringList k=cls.enumTypes();
+ for(int i=0;i<k.size();i++){
+ code+="//enum "+k[i]+"\n";
+ QList<WocEnum>ev=cls.enumValues(k[i]);
+ for(int j=0;j<ev.size();j++)
+ code+="const "+ev[j].name+"="+QString::number(ev[j].val)+";\n";
+ }
+ return code;
+}
+
+QString WocPHPServerOut::classProperties(const WocClass&cls)
+{
+ QString code;
+ QStringList k=cls.propertyNames();
+ for(int i=0;i<k.size();i++){
+ code+="\n";
+ //generate validator
+ code+=classPropertyValidator(cls,k[i]);
+ //generic getter
+ code+="public function get"+k[i]+"(){return $this->prop_"+k[i]+";}\n";
+ //is it a list?
+ if(cls.propertyIsList(k[i])){
+ //lists...
+ //getters
+ code+=classPropertyListGetters(cls,k[i]);
+ //setters
+ code+=classPropertyListSetters(cls,k[i]);
+ }else{
+ //non-lists...
+ //getters
+ code+=classPropertyScalarGetters(cls,k[i]);
+ //setter
+ code+=classPropertyScalarSetters(cls,k[i]);
+ }
+ }
+
+ return code;
+}
+
+QString WocPHPServerOut::classPropertyValidator(const WocClass&cls,QString prop)
+{
+ QString code;
+ code+="static public function validate"+prop+"($value){\n";
+ if(cls.propertyIsEnum(prop)){
+ QList<WocEnum>ev=cls.enumValues(cls.propertyPlainType(prop));
+ code+="\tif(is_numeric($value)){\n\t\t$value=$value+0;\n";
+ for(int j=0;j<ev.size();j++){
+ code+="\t\tif($value=="+QString::number(ev[j].val)+")return true;\n";
+ }
+ code+="\t\treturn false;\n\t}else{\n";
+ for(int j=0;j<ev.size();j++){
+ code+="\t\tif($value==\""+ev[j].name+"\")return true;\n";
+ }
+ code+="\t\treturn false;\n\t}\n";
+ }else
+ if(cls.propertyIsInt(prop))
+ code+="\treturn is_numeric($value);\n";
+ else
+ if(cls.propertyIsString(prop)||cls.propertyIsBlob(prop))
+ code+="\treturn true;\n";//TODO: special handling for astring
+ else
+ if(cls.propertyIsBool(prop))
+ code+="\treturn is_bool($value);\n";
+ else
+ if(cls.propertyIsObject(prop))
+ code+="\treturn is_a($value,\"WO"+cls.propertyPlainType(prop)+"\");\n";
+ else{
+ qDebug("Warning: unable to generate validator for class %s property %s: unknown type.",cls.name().toAscii().data(),prop.toAscii().data());
+ code+="\treturn false;\n";
+ }
+ code+="}\n";
+
+ return code;
+}
+
+QString WocPHPServerOut::classPropertyListGetters(const WocClass&cls,QString prop)
+{
+ QString code;
+ if(cls.propertyIsString(prop))
+ code+="public function getstrlist_"+prop+"(){return $this->prop_"+prop+";}\n";
+ else
+ if(cls.propertyIsBlob(prop)){
+ code+="public function getstrlist_"+prop+"(){\n\t$ret=array();\n";
+ code+="\tforeach($this->prop_"+prop+" as $p)$ret[]=base64_encode($this->prop_"+prop+");";
+ code+="\treturn $ret;\n}\n";
+ }else
+ if(cls.propertyIsInt(prop)){
+ code+="public function getstrlist_"+prop+"(){\n";
+ code+="\t$ret=array();\n\tforeach($this->prop_"+prop+" as $p)$ret[]=\"\".$p;\n";
+ code+="\treturn $ret;\n}\n";
+ }else
+ if(cls.propertyIsBool(prop)){
+ code+="public function getstrlist_"+prop+"(){\n";
+ code+="\t$ret=array();\n\tforeach($this->prop_"+prop+" as $p)$ret[]=$p?\"yes\":\"no\";\n";
+ code+="\treturn $ret;\n}\n";
+ }else
+ if(cls.propertyIsEnum(prop)){
+ code+="public function getstrlist_"+prop+"(){\n";
+ code+="\t$ret=array();\n";
+ code+="\tforeach($this->prop_"+prop+" as $p)switch($p){\n";
+ QList<WocEnum> ev=cls.enumValues(cls.propertyPlainType(prop));
+ for(int j=0;j<ev.size();j++){
+ code+="\t\tcase "+QString::number(ev[j].val)+":$ret[]=\""+ev[j].name+"\";break;\n";
+ }
+ code+="\t\tdefault:$ret[]=null;break;\n\t}\n\treturn $ret;\n}\n";
+ }
+
+ return code;
+}
+
+QString WocPHPServerOut::classPropertyListSetters(const WocClass&cls,QString prop)
+{
+ QString code;
+ code+="public function clear_"+prop+"(){$this->prop_"+prop+"=array();}\n";
+ QString acode;//body of add_ function, see below
+ code+="public function set"+prop+"(array $values){\n";
+ if(cls.propertyIsEnum(prop)){
+ QList<WocEnum>ev=cls.enumValues(cls.propertyPlainType(prop));
+ code+="\t$prop=array();\n";
+ code+="\tforeach($values as $value){\n";
+ code+="\t\tif(is_numeric($value)){\n\t\t\t$value=$value+0;\n";
+ acode+="\tif(is_numeric($value)){\n\t\t$value=$value+0;\n";
+ for(int j=0;j<ev.size();j++){
+ code+="\t\t\tif($value=="+QString::number(ev[j].val)+"){\n";
+ code+="\t\t\t\t$prop[]="+QString::number(ev[j].val)+";\n";
+ code+="\t\t\t}else\n";
+ acode+="\t\tif($value=="+QString::number(ev[j].val)+"){\n";
+ acode+="\t\t\t$this->prop_"+prop+"[]="+QString::number(ev[j].val)+";\n";
+ acode+="\t\t\treturn true;\n\t\t}\n";
+ }
+ code+="\t\t\treturn false;\n\t\t}else{\n";
+ acode+="\t\treturn false;\n\t}else{\n";
+ for(int j=0;j<ev.size();j++){
+ code+="\t\t\tif($value==\""+ev[j].name+"\"){\n";
+ code+="\t\t\t\t$prop[]="+QString::number(ev[j].val)+";\n";
+ code+="\n\t\t\t}else\n";
+ acode+="\t\tif($value==\""+ev[j].name+"\"){\n";
+ acode+="\t\t\t$this->prop_"+prop+"[]="+QString::number(ev[j].val)+";\n";
+ acode+="\t\t\treturn true;\n\t\t}\n";
+ }
+ code+="\t\t\treturn false;\n\t\t}\n\t}\n";
+ code+="\t$this->prop_"+prop+"=$prop;\n";
+ code+="\treturn true;\n";
+ acode+="\t\treturn false;\n\t}\n";
+ }else
+ if(cls.propertyIsInt(prop)){
+ code+="\t$prop=array();\n\tforeach($values as $value)\n";
+ code+="\t\tif(is_numeric($value)){\n\t\t\t$prop[]=0+$value;\n\t\t}else return false;\n";
+ code+="\t$this->prop_"+prop+"=$prop;\n\treturn true;\n";
+ acode+="\tif(is_numeric($value)){\n";
+ acode+="\t\t$this->prop_"+prop+"=0+$value;\n\t\treturn true;\n\t}else return false;\n";
+ }else
+ if(cls.propertyIsBool(prop)){
+ code+="\t$prop=array();\n\tforeach($values as $value)\n";
+ code+="\t\tif(is_bool($value))$prop[]=$value!=false;else\n";
+ code+="\t\tif($value==\"yes\")$prop[]=true;else\n";
+ code+="\t\tif($value==\"no\")$prop[]=false;else return false;\n";
+ code+="\t$this->prop_"+prop+"=$prop;\n\treturn true;\n";
+ acode+="\tif(is_bool($value)){\n";
+ acode+="\t\t$this->prop_"+prop+"=$value!=false;\n\t\treturn true;\n\t}else return false;\n";
+ }else
+ if(cls.propertyIsString(prop)||cls.propertyIsBlob(prop)){
+ code+="\t$prop=array();\n\tforeach($values as $value)$prop[]=\"\".$value;\n";
+ code+="\t$this->prop_"+prop+"=$prop;\n\treturn true;\n";
+ //TODO: special handling for astring
+ acode+="\t$this->prop_"+prop+"[]=\"\".$value;\n\treturn true;\n";
+ }else
+ if(cls.propertyIsObject(prop)){
+ code+="\t$prop=array();\n\tforeach($values as $value)\n";
+ code+="\t\tif(is_a($value,\"WO"+cls.propertyPlainType(prop)+"\"))\n";
+ code+="\t\t\t$prop[]=$value;\n";
+ code+="\t\telse return false;\n";
+ code+="\t$this->prop_"+prop+"=$prop;\n";
+ code+="\treturn true;\n";
+ acode+="\tif(is_a($value,\"WO"+cls.propertyPlainType(prop)+"\")){\n";
+ acode+="\t\t$this->prop_"+prop+"[]=$value;\n";
+ acode+="\t\treturn true;\n";
+ acode+="\t}else return false;\n";
+ }else{
+ qDebug("Warning: unable to generate setter for class %s property %s: unknown type.",cls.name().toAscii().data(),prop.toAscii().data());
+ code+="\treturn false;\n";
+ }
+ code+="}\n";
+ code+="public function add_"+prop+"($value){\n"+acode+"}\n";
+
+ return code;
+}
+
+QString WocPHPServerOut::classPropertyScalarGetters(const WocClass&cls,QString prop)
+{
+ QString code;
+ if(cls.propertyIsString(prop))
+ code+="public function getstr_"+prop+"(){return $this->prop_"+prop+";}\n";
+ else
+ if(cls.propertyIsBlob(prop))
+ code+="public function getstr_"+prop+"(){return base64_encode($this->prop_"+prop+");}\n";
+ else
+ if(cls.propertyIsInt(prop))
+ code+="public function getstr_"+prop+"(){return \"\".$this->prop_"+prop+";}\n";
+ else
+ if(cls.propertyIsBool(prop))
+ code+="public function getstr_"+prop+"(){return $this->prop_"+prop+"?\"yes\":\"no\";}\n";
+ else
+ if(cls.propertyIsEnum(prop)){
+ code+="public function getstr_"+prop+"(){\n\tswitch($this->prop_"+prop+"){\n";
+ QList<WocEnum> ev=cls.enumValues(cls.propertyPlainType(prop));
+ for(int j=0;j<ev.size();j++){
+ code+="\t\tcase "+QString::number(ev[j].val)+":return translate(\""+abstractClassName(cls)+"\",\""+ev[j].name+"\");\n";
+ }
+ code+="\t\tdefault:return null;\n\t}\n}\n";
+ }
+
+ return code;
+}
+
+QString WocPHPServerOut::classPropertyScalarSetters(const WocClass&cls,QString prop)
+{
+ QString code;
+ code+="public function set"+prop+"($value){\n";
+ if(cls.propertyIsEnum(prop)){
+ QList<WocEnum>ev=cls.enumValues(cls.propertyPlainType(prop));
+ code+="\tif(is_numeric($value)){\n\t\t$value=$value+0;\n";
+ for(int j=0;j<ev.size();j++){
+ code+="\t\tif($value=="+QString::number(ev[j].val)+"){\n";
+ code+="\t\t\t$this->prop_"+prop+"="+QString::number(ev[j].val)+";\n";
+ code+="\t\t\treturn true;\n\t\t}\n";
+ }
+ code+="\t\treturn false;\n\t}else{\n";
+ for(int j=0;j<ev.size();j++){
+ code+="\t\tif($value==\""+ev[j].name+"\"){\n";
+ code+="\t\t\t$this->prop_"+prop+"="+QString::number(ev[j].val)+";\n";
+ code+="\t\t\treturn true;\n\t\t}\n";
+ }
+ code+="\t\treturn false;\n\t}\n";
+ }else
+ if(cls.propertyIsInt(prop))
+ code+="\tif(is_numeric($value)){\n\t\t$this->prop_"+prop+"=0+$value;\n\t\treturn true;\n\t}else return false;\n";
+ else
+ if(cls.propertyIsBool(prop)){
+ code+="\tif(is_bool($value))$this->prop_"+prop+"=$value!=false;else\n";
+ code+="\tif($value==\"yes\")$this->prop_"+prop+"=true;else\n";
+ code+="\tif($value==\"no\")$this->prop_"+prop+"=false;\n\telse return false;\n";
+ code+="\treturn true;\n";
+ }else
+ if(cls.propertyIsString(prop)||cls.propertyIsBlob(prop))
+ code+="\t$this->prop_"+prop+"=\"\".$value;\n\treturn true;\n";
+ //TODO: special handling for astring
+ //TODO: do something about Blob
+ else
+ if(cls.propertyIsObject(prop)){
+ code+="\tif(is_a($value,\"WO"+cls.propertyPlainType(prop)+"\")){\n";
+ code+="\t\t$this->prop_"+prop+"=$value;\n";
+ code+="\t\treturn true;\n\t}\n";
+ }else{
+ qDebug("Warning: unable to generate setter for class %s property %s: unknown type.",cls.name().toAscii().data(),prop.toAscii().data());
+ code+="\treturn false;\n";
+ }
+ code+="}\n";
+
+ return code;
+}
+
+QString WocPHPServerOut::classSerializers(const WocClass&cls)
+{
+ QString code;
+ //toString function (wraps toXml)
+ code+="\npublic function toString(){\n\t$xml=new DomDocument;\n";
+ code+="\t$xml->appendChild($this->toXml($xml));\n\treturn $xml->saveXml();\n}\n";
+ //toXml function:
+ code+="public function toXml($xml,$elementname=\""+cls.name()+"\"){\n";
+ code+="\t$root=$xml->createElement($elementname);\n";
+ //add properties
+ QStringList p=cls.propertyNames();
+ for(int j=0;j<p.size();j++)
+ code+=propertyToXml(cls,p[j]);
+ //return result
+ code+="\treturn $root;\n}\n";
+ return code;
+}
+
+QString WocPHPServerOut::classDeserializers(const WocClass&cls)
+{
+ QString code;
+ QStringList k;
+ code+="\nstatic public function fromString($txt){\n\t$xml=new DomDocument;\n";
+ code+="\tif(!$xml->loadXml(trim($txt)))";
+ code+="\n\t\tthrow WobXmlException(translate(\""+abstractClassName(cls)+"\",\"Unable to deserialize object of type "+className(cls)+": invalid XML.\"));";
+ code+="\n\treturn self::fromXml($xml,$xml->documentElement);\n}\n";
+ code+="static public function fromXml($xml,$elem){\n\t$data=new "+className(cls)+"();\n";
+ k=cls.propertyNames();
+ for(int i=0;i<k.size();i++){
+ //scan properties
+ if(cls.propertyIsList(k[i])){
+ code+="\t$data->clear_"+k[i]+"();\n";
+ code+="\tforeach(WObject::elementsByTagName($elem,\""+k[i]+"\") as $el){\n";
+ if(cls.propertyIsObject(k[i])){
+ code+="\t\t$data->add_"+k[i]+"(WO"+cls.propertyPlainType(k[i])+"::fromXml($xml,$el));\n";
+ }else if(cls.propertyIsBlob(k[i])){
+ code+="\t\t$data->add_"+k[i]+"(base64_decode($el->textContent));\n";
+ }else{
+ code+="\t\t$data->add_"+k[i]+"($el->textContent);\n";
+ }
+ code+="\t}\n";
+ }else{
+ if(cls.propertyIsObject(k[i])){
+ code+="\tforeach(WObject::elementsByTagName($elem,\""+k[i]+"\") as $el){\n";
+ code+="\t\t$data->set"+k[i]+"(WO"+cls.propertyPlainType(k[i])+"::fromXml($xml,$el));\n";
+ code+="\t}\n";
+ }else
+ if(cls.propertyIsAttribute(k[i])){
+ code+="\tif($elem->hasAttribute(\""+k[i]+"\"))\n";
+ code+="\t\t$data->set"+k[i]+"($elem->getAttribute(\""+k[i]+"\"));\n";
+ }else{
+ code+="\tforeach(WObject::elementsByTagName($elem,\""+k[i]+"\") as $el){\n";
+ if(cls.propertyIsBlob(k[i]))
+ code+="\t\t$data->set"+k[i]+"(base64_decode($el->textContent));\n";
+ else
+ code+="\t\t$data->set"+k[i]+"($el->textContent);\n";
+ code+="\t}\n";
+ }
+ }
+ }
+ code+="\treturn $data;\n}\n";
+ return code;
+}
+
+QString WocPHPServerOut::classMappings(const WocClass&cls)
+{
+ //implement mappings
+ QString code;
+ QStringList k=cls.mappingTables();
+ for(int i=0;i<k.size();i++){
+ WocTable tab=WocProcessor::instance()->table(k[i]);
+ //single object mapping
+ code+="\nstatic public function fromTable"+k[i]+"($table){\n";
+ code+="\tif($table === false)return false;\n";
+ code+="\t$data=new WO"+cls.name()+"();\n";
+ QMap<QString,QString>map=cls.mapping(k[i]);
+ QStringList mapk=cls.mappingProperties(k[i]);
+ for(int j=0;j<mapk.size();j++){
+ QString meth=cls.mapMethod(k[i],mapk[j],"php");
+ if(meth!="")code+="\t$data->prop_"+mapk[j]+"="+meth+";\n";
+ else code+="\t$data->prop_"+mapk[j]+"=$table->"+map[mapk[j]]+";\n";
+ }
+ code+="\treturn $data;\n}\n";
+ //wrapper for multi-object mapping
+ code+="static public function fromTableArray"+k[i]+"(array $table){\n\t$ret=array();\n";
+ code+="\tfor($i=0;$i<count($table);$i++)$ret[]=self::fromTable"+k[i]+"($table[$i]);\n";
+ code+="\treturn $ret;\n}\n";
+ //reverse mapping
+ code+="public function toTable"+k[i]+"(&$table){\n";
+ for(int j=0;j<mapk.size();j++){
+ //do not reverse translate method conversions
+ QString meth=cls.mapMethod(k[i],mapk[j],"php").trimmed();
+ if(meth!="")continue;
+ //check that column exists
+ if(tab.hasColumn(map[mapk[j]])){
+ code+="\tif($this->prop_"+mapk[j]+"!==null && $table->"+map[mapk[j]]+"!=$this->prop_"+mapk[j]+")\n";
+ code+="\t\t$table->"+map[mapk[j]]+"=$this->prop_"+mapk[j]+";\n";
+ }
+ }
+ code+="\treturn $table;\n}\n";
+ }
+
+ return code;
+}
+
+QString WocPHPServerOut::propertyToXml(const WocClass&cls,QString sl)
+{
+ QString prop=sl.trimmed();
+ //is it a list?
+ if(cls.propertyIsList(prop)){
+ //is it a class?
+ if(cls.propertyIsObject(prop)){
+ QString code="\tforeach($this->get"+prop+"() as $o)\n\t\t";
+ code+="$root->appendChild($o->toXml($xml,\""+prop+"\"));\n";
+ return code;
+ }else{
+ //there is no way to create lists of attributes, hence we always create elements
+ QString code="\tforeach($this->getstrlist_"+prop+"() as $e)\n\t\t";
+ code+="$root->appendChild($xml->createElement(\""+prop+"\",xq($e)));\n";
+ return code;
+ }
+ }
+ //non lists:
+ QString code="\t$p=$this->get"+prop+"();\n\tif($p!==null)";
+ //is it an attribute?
+ if(cls.propertyIsAttribute(prop))
+ return code+"\t$root->setAttribute(\""+prop+"\",$this->getstr_"+prop+"());\n";
+ //is it an element?
+ if(cls.propertyIsElement(prop))
+ return code+"\t$root->appendChild($xml->createElement(\""+prop+"\",xq($this->getstr_"+prop+"())));\n";
+ //is it a class?
+ if(cls.propertyIsObject(prop))
+ return code+"$root->appendChild($p->toXml($xml,\""+prop+"\"));\n";
+ //anything else?
+ qDebug("Warning: end of WocPHPServerOut::propertyToXml - this code should not be reachable.");
+ return "//internal generator error!\n";
+}
+
+void WocPHPServerOut::newTransaction(const WocTransaction&trn)
+{
+ //create file
+ QString cn=trnClassName(trn);
+ QString fn="wtr_"+trn.name();
+ addLoad(cn,fn);
+ fn=m_subdir+"/"+fn+m_fileext;
+ QFile tf(m_basedir+"/"+fn);
+ if(!tf.open(QIODevice::ReadWrite|QIODevice::Truncate)){
+ qDebug("Error: cannot create PHP object file %s.",fn.toAscii().data());
+ emit errorFound();
+ return;
+ }
+ tf.write(PHPSTART);
+
+ ////
+ //generate code
+ QString code="/* TRANSLATOR "+cn+" */\nclass "+cn+" extends WobTransaction{\n";
+ //constructor
+ code+=trnConstruct(trn);
+ tf.write(code.toAscii());
+
+ //request handler:
+ code="public function handleRequest(){\n";
+
+ //security handling
+ switch(trn.authMode()){
+ case WocTransaction::Checked:
+ code+="\t/*security check: authenticated and authorized*/\n";
+ code+="\t"+m_authinit+";\n";
+ code+="\tif(!"+m_isauth+"||!"+QString(m_hasrole).replace("%","\""+trn.name()+"\"")+")$this->notAuthenticated();\n";
+ break;
+ case WocTransaction::Auth:
+ code+="\t/*security check: authenticated*/\n";
+ code+="\t"+m_authinit+";\n";
+ code+="\tif(!"+m_isauth+")$this->notAuthenticated();\n";
+ break;
+ default:
+ code+="\t/*no security check, open function*/\n";
+ break;//none
+ }
+
+ //parse low level XML
+ code+="\t/*low level XML parsing*/\n";
+ code+="\tglobal $HTTP_RAW_POST_DATA;\n\tif(isset($HTTP_RAW_POST_DATA))$txt=$HTTP_RAW_POST_DATA;else $txt=\"\";\n";
+ code+="\t$xml=new DOMDocument;\n\tif(!$xml->loadXML($txt))$this->xmlParserError();\n";
+ code+="\t$root=$xml->documentElement;\n";
+
+ //parse inputs
+ code+=trnInput(trn);
+
+ //call
+ if(trn.hasCall("php")){
+ code+="\t/*call actual functionality:*/\n";
+ code+="\ttry{"+trn.callFunction("php")+"}catch(Exception $e){$this->handleException($e);}\n";
+ }else{
+ code+="\t/*normally here would be the PHP call, but it is missing from the config*/\n";
+ code+="\t$this->abortNotImplemented();\nreturn;\n";
+ qDebug("Warning: transaction %s does not have a PHP call!",trn.name().toAscii().data());
+ }
+
+ //encode outputs/handle errors
+ code+=trnOutput(trn);
+
+ code+="}\n";
+ tf.write(code.toAscii());
+
+ //getters/setters
+ tf.write(trnGetSet(trn).toAscii());
+
+ //direct execution
+ tf.write(trnExecute(trn).toAscii());
+
+ //privileges
+ tf.write(trnPrivileges(trn).toAscii());
+
+ //end
+ code="\n//end of class\n}\n";
+ tf.write(code.toAscii());
+ tf.write(PHPEND);
+ tf.close();
+
+ ////
+ //generate loader code
+ code="\tcase \""+trn.name()+"\":$trn=new "+cn+";$trn->handleRequest();break;\n";
+ m_transact.write(code.toAscii());
+}
+
+QString WocPHPServerOut::trnConstruct(const WocTransaction&trn)
+{
+ QString code="public function __construct(){\n\t$this->ainput=array(";
+ QStringList sl=trn.inputNames();
+ for(int i=0;i<sl.size();i++){
+ if(i)code+=",";
+ code+="\""+sl[i]+"\"=>";
+ if(trn.isListType(trn.inputType(sl[i])))code+="array()";
+ else code+="false";
+ }
+ code+=");\n";
+ code+="\t$this->tinput=array(";
+ for(int i=0;i<sl.size();i++){
+ if(i)code+=",";
+ code+="\""+sl[i]+"\"=>\"";
+ code+=trn.inputType(sl[i]);
+ code+="\"";
+ }
+ code+=");\n";
+
+
+ code+="\t$this->aoutput=array(";
+ sl=trn.outputNames();
+ for(int i=0;i<sl.size();i++){
+ if(i)code+=",";
+ code+="\""+sl[i]+"\"=>";
+ if(trn.isListType(trn.outputType(sl[i])))code+="array()";
+ else code+="false";
+ }
+ code+=");\n";
+ code+="\t$this->toutput=array(";
+ for(int i=0;i<sl.size();i++){
+ if(i)code+=",";
+ code+="\""+sl[i]+"\"=>\"";
+ code+=trn.outputType(sl[i]);
+ code+="\"";
+ }
+ code+=");\n}\n";
+ return code;
+}
+
+QString WocPHPServerOut::trnInput(const WocTransaction&trn)
+{
+ QString code="\t/*start of input parsing*/\n";
+ code+="\ttry{\n";
+ QStringList sl=trn.inputNames();
+ for(int i=0;i<sl.size();i++){
+ QString t=trn.inputType(sl[i]);
+ if(trn.isAttributeType(t)){
+ code+="\t\t$this->ainput[\""+sl[i]+"\"]=$root->getAttribute(\""+sl[i]+"\")";
+ if(trn.isIntType(t))code+="+0";
+ if(trn.isBoolType(t))code+="==\"yes\"";
+ code+=";\n";
+ }else{
+ if(trn.isListType(t)){
+ QString pt=trn.plainType(t);
+ code+="\t\tforeach(WObject::elementsByTagName($root,\""+sl[i]+"\") as $el){\n";
+ if(trn.isObjectType(t)){
+ code+="\t\t\t$this->ainput[\""+sl[i]+"\"][]=WO"+pt+"::fromXml($xml,$el);\n";
+ }else if(trn.isBlobType(t)){
+ code+="\t\t\t$this->ainput[\""+sl[i]+"\"][]=base64_decode($el->textContent);\n";
+ }else{
+ code+="\t\t\t$this->ainput[\""+sl[i]+"\"][]=$el->textContent";
+ if(trn.isIntType(t))code+="+0";
+ if(trn.isBoolType(t))code+="==\"yes\"";
+ code+=";\n";
+ }
+ code+="\t\t}\n";
+ }else{
+ code+="\t\tforeach(WObject::elementsByTagName($root,\""+sl[i]+"\") as $el){\n";
+ if(trn.isObjectType(t)){
+ code+="\t\t\t$this->ainput[\""+sl[i]+"\"]=WO"+t+"::fromXml($xml,$el);\n";
+ }else if(trn.isBlobType(t)){
+ code+="\t\t\t$this->ainput[\""+sl[i]+"\"]=base64_decode($el->textContent);\n";
+ }else{
+ code+="\t\t\t$this->ainput[\""+sl[i]+"\"]=$el->textContent";
+ if(trn.isIntType(t))code+="+0";
+ code+=";\n";
+ }
+ code+="\t\t}\n";
+ }
+ }
+ }
+ code+="\t}catch(Exception $e){$this->handleException($e);}\n";
+ code+="\t/*end of input parsing*/\n";
+ return code;
+}
+
+QString WocPHPServerOut::trnOutput(const WocTransaction&trn)
+{
+ QStringList sl=trn.outputNames();
+ QString code="\t/*start of output encoding*/\n";
+ code+="\ttry{\n\t\t$xml=new DOMDocument;\n";
+ code+="\t\t$root=$xml->createElement(\"WobResponse\");\n";
+ for(int i=0;i<sl.size();i++){
+ QString t=trn.outputType(sl[i]);
+ if(trn.isAttributeType(t)){
+ code+="\t\t$root->setAttribute(\""+sl[i]+"\",$this->aoutput[\""+sl[i]+"\"]);\n";
+ }else{
+ if(trn.isListType(t)){
+ if(trn.isObjectType(t)){
+ code+="\t\tforeach($this->aoutput[\""+sl[i]+"\"] as $o)\n";
+ code+="\t\t\tif(is_a($o,\"WO"+trn.plainType(t)+"\"))\n";
+ code+="\t\t\t\t$root->appendChild($o->toXml"+trn.typeSerializer(t)+"($xml,\""+sl[i]+"\"));\n";
+ }else if(trn.isBlobType(t)){
+ code+="\t\tforeach($this->aoutput[\""+sl[i]+"\"] as $v)\n";
+ code+="\t\t\t$root->appendChild($xml->createElement(\""+sl[i]+"\",base64_encode($v)));\n";
+ }else{
+ code+="\t\tforeach($this->aoutput[\""+sl[i]+"\"] as $v)\n";
+ code+="\t\t\t$root->appendChild($xml->createElement(\""+sl[i]+"\",xq($v)));\n";
+ }
+ }else{
+ if(trn.isObjectType(t)){
+ code+="\t\t$o=$this->aoutput[\""+sl[i]+"\"];\n";
+ code+="\t\tif(is_a($o,\"WO"+trn.plainType(t)+"\"))\n";
+ code+="\t\t\t$root->appendChild($o->toXml"+trn.typeSerializer(t)+"($xml,\""+sl[i]+"\"));\n";
+ }else if(trn.isBlobType(t)){
+ code+="\t\t$root->appendChild($xml->createElement(\""+sl[i]+"\",base64_encode($this->aoutput[\""+sl[i]+"\"])));\n";
+ }else{
+ code+="\t\t$root->appendChild($xml->createElement(\""+sl[i]+"\",xq($this->aoutput[\""+sl[i]+"\"])));\n";
+ }
+ }
+ }
+ }
+ code+="\t\t$xml->appendChild($root);\n";
+ code+="\t\theader(\"X-WobResponse-Status: Ok\");\n";
+ code+="\t\tprint($xml->saveXml());\n";
+ code+="\t}catch(Exception $e){$this->handleException($e);}\n";
+ code+="\t/*end of output*/\n";
+ return code;
+}
+
+QString WocPHPServerOut::trnGetSet(const WocTransaction&trn)
+{
+ QString code;
+ //getters
+ QStringList sl=trn.inputNames();
+ for(int i=0;i<sl.size();i++){
+ code+="public function get"+sl[i]+"(){return $this->ainput[\""+sl[i]+"\"];}\n";
+ }
+ //setters
+ sl=trn.outputNames();
+ for(int i=0;i<sl.size();i++){
+ QString add;
+ QString t=trn.outputType(sl[i]);
+ code+="public function set"+sl[i]+"($v){\n";
+ if(trn.isListType(t)){
+ add="public function add"+sl[i]+"($vv){\n";
+ code+="\t$this->aoutput[\""+sl[i]+"\"]=array();\n";
+ code+="\tforeach($v as $vv){\n";
+ if(trn.isIntType(t)){
+ code+="\t\tif(is_numeric($vv))$this->aoutput[\""+sl[i]+"\"][]=$vv+0;\n";
+ add+="\tif(is_numeric($vv))$this->aoutput[\""+sl[i]+"\"][]=$vv+0;\n";
+ }else
+ if(trn.isBoolType(t)){
+ code+="\t\tif(is_bool($vv))$this->aoutput[\""+sl[i]+"\"][]=$vv!=false;\n";
+ add+="\tif(is_bool($vv))$this->aoutput[\""+sl[i]+"\"][]=$vv!=false;\n";
+ }else
+ if(trn.isObjectType(t)){
+ code+="\t\tif(is_a($vv,\"WO"+trn.plainType(t)+"\"))$this->aoutput[\""+sl[i]+"\"][]=$vv;\n";
+ add+="\tif(is_a($vv,\"WO"+trn.plainType(t)+"\"))$this->aoutput[\""+sl[i]+"\"][]=$vv;\n";
+ }else{
+ code+="\t\t$this->aoutput[\""+sl[i]+"\"][]=\"\".$vv;\n";
+ add+="\t$this->aoutput[\""+sl[i]+"\"][]=\"\".$vv;\n";
+ }
+ code+="\t}\n";
+ add+="}\n";
+ }else{
+ if(trn.isIntType(t)){
+ code+="\tif(is_numeric($v))$this->aoutput[\""+sl[i]+"\"]=$v+0;\n";
+ }else
+ if(trn.isBoolType(t)){
+ code+="\tif(is_bool($v))$this->aoutput[\""+sl[i]+"\"]=$v!=false;\n";
+ }else
+ if(trn.isObjectType(t)){
+ code+="\tif(is_a($v,\"WO"+trn.plainType(t)+"\"))$this->aoutput[\""+sl[i]+"\"]=$v;\n";
+ }else{
+ code+="\t$this->aoutput[\""+sl[i]+"\"]=\"\".$v;\n";
+ }
+ }
+ code+="}\n"+add;
+ }
+
+
+ return code;
+}
+
+QString WocPHPServerOut::trnExecute(const WocTransaction&trn)
+{
+ QStringList in=trn.inputNames();
+ QString code="static public function execute(";
+ for(int i=0;i<in.size();i++){
+ if(i)code+=",";
+ code+="$"+in[i];
+ }
+ code+=")\n{\n\t$inst=new "+trnClassName(trn)+";\n";
+ for(int i=0;i<in.size();i++)
+ code+="\t$this->ainput[\""+in[i]+"\"]=$"+in[i]+";\n";
+ code+="\tself::$running=\""+trn.name()+"\";\n";
+ code+="\t$inst->do_execute();\n";
+ code+="\tself::$running=\"\";\n";
+ code+="\treturn $inst;\n}\n";
+ code+="private function do_execute(){"+trn.callFunction("php")+"}\n";
+ return code;
+}
+
+QString WocPHPServerOut::trnPrivileges(const WocTransaction&trn)
+{
+ //privilege inventory
+ QString code;
+ code+="static public function privileges(){\n\treturn array(";
+ QString cn=trnClassName(trn);
+ QStringList priv=trn.privileges();
+ for(int i=0;i<priv.size();i++){
+ if(i)code+=",\n\t\t";else code+="\n\t\t";
+ code+="\""+priv[i]+"\"";
+ }
+ code+="\n\t);\n}\n";
+ //constants for use by custom code
+ for(int i=0;i<priv.size();i++)
+ code+="const Priv_"+priv[i]+"=\""+priv[i]+"\";\n";
+ //check method
+ code+="public function havePrivilege($priv){\n";
+ code+="\tif(!in_array($priv,self::privileges()))return false;\n";
+ code+="\treturn "+QString(m_hasrole).replace("%","(\""+trn.name()+":\".$priv)")+";\n}\n";
+
+ return code;
+}
--- /dev/null
+//
+// C++ Interface: phpout
+//
+// Description:
+//
+//
+// Author: Konrad Rosenbaum <konrad@silmor.de>, (C) 2009
+//
+// Copyright: See README/COPYING files that come with this distribution
+//
+//
+
+#ifndef WOC_PHPOUT_H
+#define WOC_PHPOUT_H
+
+#include <QFile>
+
+#include "processor.h"
+
+class QDomElement;
+
+/**generates output for a PHP server side*/
+class WocPHPServerOut:public WocOutput
+{
+ public:
+ /**initializes the output object*/
+ WocPHPServerOut(const QDomElement&);
+ protected:
+ /**writes any last words after parsing finished*/
+ virtual void finalize();
+ /**creates a class*/
+ virtual void newClass(const WocClass&);
+ /**creates a table*/
+ virtual void newTable(const WocTable&);
+ /**creates a transaction*/
+ virtual void newTransaction(const WocTransaction&);
+ private:
+ QString m_basedir,m_subdir,m_fileext;
+ QString m_isauth,m_hasrole,m_username,m_authinit;
+ QFile m_loader,m_schema,m_transact;
+
+ /**helper: adds a loader line for a class to autoload.php*/
+ void addLoad(QString classname,QString filename);
+
+ /**helper: generates PHP code to transform a class property to XML*/
+ QString propertyToXml(const WocClass&,QString);
+ /**helper: generate class constructor*/
+ QString classConstruct(const WocClass&);
+ /**helper: generate class internal enums*/
+ QString classEnums(const WocClass&);
+ /**helper: generate class internal props*/
+ QString classProperties(const WocClass&);
+ /**helper: generate class internal serializers*/
+ QString classSerializers(const WocClass&);
+ /**helper: generate class internal deserializers*/
+ QString classDeserializers(const WocClass&);
+ /**helper: generate class internal mappers*/
+ QString classMappings(const WocClass&);
+ /**helper: generate property validator*/
+ QString classPropertyValidator(const WocClass&,QString);
+ /**helper: generate getters for list properties*/
+ QString classPropertyListGetters(const WocClass&,QString);
+ /**helper: generate setters for list properties*/
+ QString classPropertyListSetters(const WocClass&,QString);
+ /**helper: generate getters for scalar properties*/
+ QString classPropertyScalarGetters(const WocClass&,QString);
+ /**helper: generate setters for sclar properties*/
+ QString classPropertyScalarSetters(const WocClass&,QString);
+
+ /**helper: create info functions (mainly version info) at the start*/
+ void transInfo();
+ /**helper: create info functions (mainly version info) at the end*/
+ void transInfo2();
+
+ /**helper: create transaction constructor*/
+ QString trnConstruct(const WocTransaction&);
+ /**helper: create transaction input parser*/
+ QString trnInput(const WocTransaction&);
+ /**helper: create transaction output serializer*/
+ QString trnOutput(const WocTransaction&);
+ /**helper: create getters and setters*/
+ QString trnGetSet(const WocTransaction&);
+ /**helper: create direct execution code for web interface*/
+ QString trnExecute(const WocTransaction&);
+ /**helper: create privilege check code for web interface*/
+ QString trnPrivileges(const WocTransaction&);
+
+ /**helper: return the PHP-class-name of a WocClass*/
+ QString className(const WocClass&c){return "WO"+c.name();}
+ /**helper: return the PHP-class-name of a WocClass plus Abstract if it is abstract*/
+ QString abstractClassName(const WocClass&c){return "WO"+c.name()+QString(c.isAbstract("php")?"Abstract":"");}
+
+ /**helper: returns the PHP-class-name for a WocTransaction*/
+ QString trnClassName(const WocTransaction&t){return "WTr"+t.name();}
+};
+
+#endif
--- /dev/null
+//
+// C++ Implementation: processor
+//
+// Description:
+//
+//
+// Author: Konrad Rosenbaum <konrad@silmor.de>, (C) 2009
+//
+// Copyright: See README/COPYING files that come with this distribution
+//
+//
+
+#include "processor.h"
+
+#include "phpout.h"
+#include "qtout.h"
+#include "htmlout.h"
+
+#include "domquery.h"
+
+#include <QDir>
+#include <QDomDocument>
+#include <QDomElement>
+#include <QProcess>
+
+QList<QDomElement>elementsByTagName(const QDomElement&root,QString tag)
+{
+ QDomNodeList cn=root.childNodes();
+ QList<QDomElement>ret;
+ for(int i=0;i<cn.size();i++){
+ QDomElement e=cn.at(i).toElement();
+ if(e.isNull())continue;
+ if(e.tagName()!=tag)continue;
+ ret<<e;
+ }
+ return ret;
+}
+
+
+WocProcessor* WocProcessor::inst=0;
+
+WocProcessor::WocProcessor()
+{
+ m_baseDir=QDir(".").absolutePath();
+ m_wobDir=".";
+ m_verComm="0";
+ m_verNeedComm="0";
+ m_verHR="0.0";
+ m_svnTarget=".";
+ m_svnRev="unknown uncertain";
+ m_svnExe="svn";
+ m_dbInst="dbInst";
+ m_dbSchema="dbSchema";
+ m_error=false;
+ m_projname="WobProject";
+
+ inst=this;
+}
+
+bool WocProcessor::processFile(QString fn)
+{
+ //open file
+ QFile fd(fn);
+ if(!fd.open(QIODevice::ReadOnly)){
+ qDebug("Error: cannot read file %s",fn.toLocal8Bit().data());
+ return false;
+ }
+ //get XML content
+ QDomDocument doc;
+ QString err;int eln,ecl;
+ if(!doc.setContent(&fd,&err,&eln,&ecl)){
+ qDebug("Error: XML parser error in file %s line %i column %i: %s",fn.toLocal8Bit().data(),eln,ecl,err.toLocal8Bit().data());
+ fd.close();
+ return false;
+ }
+ fd.close();
+ QDomElement root=doc.documentElement();
+ if(root.isNull() || root.tagName()!="Wolf"){
+ qDebug("Error: XML File %s is not a Wolf.",fn.toLocal8Bit().data());
+ return false;
+ }
+ //go on, process file
+ qDebug("Info: processing file %s...",fn.toLocal8Bit().data());
+ m_error=false;
+ QDomNodeList nl=root.childNodes();
+ for(int i=0;i<nl.size();i++){
+ if(!nl.at(i).isElement())continue;
+ QDomElement el=nl.at(i).toElement();
+ if(el.isNull())continue;
+ QString tn=el.tagName();
+ if(tn=="Class"){
+ WocClass cls(el);
+ if(cls.isValid()){
+ m_classes.append(cls);
+ emit newClass(cls);
+ if(m_error)return false;
+ }else
+ return false;
+ }else
+ if(tn=="Table"){
+ WocTable tbl(el);
+ if(tbl.isValid()){
+ m_tables.append(tbl);
+ emit newTable(tbl);
+ if(m_error)return false;
+ if(tbl.isAuditable()){
+ WocTable atbl=tbl.auditTable();
+ m_tables.append(atbl);
+ emit newTable(atbl);
+ if(m_error)return false;
+ }
+ }else
+ return false;
+ }else
+ if(tn=="Transaction"){
+ WocTransaction trn(el);
+ if(trn.isValid()){
+ m_transactions.append(trn);
+ emit newTransaction(trn);
+ if(m_error)return false;
+ }else
+ return false;
+ }else
+ if(tn=="Project"){
+ if(el.hasAttribute("baseDir"))
+ m_baseDir=el.attribute("baseDir");
+ if(el.hasAttribute("wobDir"))
+ m_wobDir=el.attribute("wobDir");
+ if(el.hasAttribute("name"))
+ m_projname=el.attribute("name");
+ }else
+ if(tn=="Include"){
+ if(!processFile(m_baseDir+"/"+m_wobDir+"/"+el.attribute("file")))
+ return false;
+ }else
+ if(tn=="DataBase"){
+ if(el.hasAttribute("instance"))
+ m_dbInst=el.attribute("instance","dbInst");
+ if(el.hasAttribute("schema"))
+ m_dbSchema=el.attribute("schema","dbSchema");
+ if(el.hasAttribute("version"))
+ m_dbVer=el.attribute("version");
+ QList<QDomElement> nl=elementsByTagName(el,"AuditTables");
+ for(int i=0;i<nl.size();i++)
+ WocTable::parseAuditStatic(nl.at(i).toElement());
+ }else
+ if(tn=="QtClientOutput"){
+ new WocQtClientOut(el);
+ if(m_error)return false;
+ }else
+ if(tn=="PHPServerOutput"){
+ new WocPHPServerOut(el);
+ if(m_error)return false;
+ }else
+ if(tn=="HtmlOutput"){
+ new WocHtmlOut(el);
+ if(m_error)return false;
+ }else
+ if(tn=="Version"){
+ if(el.hasAttribute("comm"))
+ m_verComm=el.attribute("comm");
+ if(el.hasAttribute("needcomm"))
+ m_verNeedComm=el.attribute("needcomm");
+ if(el.hasAttribute("humanReadable"))
+ m_verHR=el.attribute("humanReadable");
+ if(el.hasAttribute("svnTarget"))
+ m_svnTarget=el.attribute("target");
+ if(el.hasAttribute("svnExe"))
+ m_svnExe=el.attribute("exe");
+ callSvn();
+ }else
+ if(tn=="Doc"){
+ QString s=el.text().trimmed();
+ if(s!="")m_docstrings<<s;
+ }
+ else{
+ qDebug("Warning: file %s has unknown element '%s' at line %i column %i", fn.toLocal8Bit().data(), tn.toLocal8Bit().data(), el.lineNumber(), el.columnNumber());
+ }
+ }
+ //TODO: verify classes
+ //TODO: verify transactions
+
+ //return success
+ return true;
+}
+
+void WocProcessor::callSvn()
+{
+ //svn info
+ QString svntgt=m_baseDir+"/"+m_svnTarget;
+ QProcess svn;
+ svn.setProcessChannelMode(QProcess::MergedChannels);
+ svn.setWorkingDirectory(svntgt);
+ svn.start(m_svnExe,QStringList()<<"info"<<"-R"<<"--xml"<<"--non-interactive"<<".");
+ svn.waitForFinished();
+ if(svn.exitCode()!=0){
+ qDebug("Warning: error while calling svn info.");
+ return;
+ }else{
+ QDomDocument doc;
+ if(!doc.setContent(svn.readAllStandardOutput())){
+ qDebug("Warning: unable to parse output of svn info.");
+ return;
+ }
+ //parse it:revisions
+ QStringList rl=MDomQuery(doc,"/*/entry/@revision");
+ if(rl.size()==0){
+ m_svnRev="unknown";
+ }else{
+ int minv,maxv;
+ minv=maxv=rl[0].toInt();
+ for(int i=1;i<rl.size();i++){
+ int cv=rl[i].toInt();
+ if(cv<minv)minv=cv;
+ if(cv>maxv)maxv=cv;
+ }
+ if(minv==maxv)
+ m_svnRev=QString::number(maxv);
+ else
+ m_svnRev=QString::number(minv)+"-"+QString::number(maxv);
+ }
+ //parse for repository path
+ MDomNodeList nl=MDomQuery(doc,"/*/entry");
+ for(int i=0;i<nl.size();i++){
+ QDomElement el=nl.at(i).toElement();
+ if(el.isNull())continue;
+ if(el.attribute("path")=="."){
+ rl=MDomQuery(el,"url");
+ if(rl.size()>0)m_svnUrl=rl[0];
+ rl=MDomQuery(el,"repository/root");
+ if(rl.size()>0)m_svnRoot=rl[0];
+ break;//we can stop now
+ }
+ }
+ }
+ //svn status
+ svn.start(m_svnExe,QStringList()<<"status"<<"--xml"<<"--non-interactive"<<".");
+ svn.waitForFinished();
+ if(svn.exitCode()!=0){
+ qDebug("Warning: error while calling svn status.");
+ m_svnRev+=" uncertain";
+ return;
+ }else{
+ QDomDocument doc;
+ if(!doc.setContent(svn.readAllStandardOutput())){
+ qDebug("Warning: unable to parse output of svn status.");
+ m_svnRev+=" uncertain";
+ return;
+ }
+ QStringList rl=MDomQuery(doc,"/status/target/entry/wc-status/@item");
+ bool ismod=false;
+ for(int i=0;i<rl.size();i++){
+ if(rl[i]=="unversioned" || rl[i]=="normal")continue;
+ ismod=true;
+ break;
+ }
+ if(ismod)m_svnRev+=" modified";
+ else m_svnRev+=" vanilla";
+ }
+ qDebug("Info: SVN version info: \"%s\".",m_svnRev.toAscii().data());
+}
+
+void WocProcessor::finalize()
+{
+ emit sfinalize();
+}
+
+bool WocProcessor::hasTable(QString n)const
+{
+ for(int i=0;i<m_tables.size();i++)
+ if(m_tables[i].name()==n)return true;
+ return false;
+}
+
+WocTable WocProcessor::table(QString n)const
+{
+ for(int i=0;i<m_tables.size();i++)
+ if(m_tables[i].name()==n)return m_tables[i];
+ return WocTable();
+}
+
+bool WocProcessor::hasClass(QString n)const
+{
+ for(int i=0;i<m_classes.size();i++)
+ if(m_classes[i].name()==n)return true;
+ return false;
+}
+
+void WocProcessor::errorFound()
+{
+ m_error=true;
+}
+
+QStringList WocProcessor::transactionNames()const
+{
+ QStringList l;
+ for(int i=0;i<m_transactions.size();i++)
+ l<<m_transactions[i].name();
+ return l;
+}
+
+QStringList WocProcessor::classNames()const
+{
+ QStringList l;
+ for(int i=0;i<m_classes.size();i++)
+ l<<m_classes[i].name();
+ return l;
+}
+
+QStringList WocProcessor::tableNames()const
+{
+ QStringList l;
+ for(int i=0;i<m_tables.size();i++)
+ l<<m_tables[i].name();
+ return l;
+}
+
+QStringList WocProcessor::privilegeNames()const
+{
+ QStringList l;
+ for(int i=0;i<m_transactions.size();i++){
+ QString cn=m_transactions[i].name();
+ QStringList priv=m_transactions[i].privileges();
+ for(int j=0;j<priv.size();j++)
+ l<<(cn+":"+priv[j]);
+ }
+ return l;
+}
+
+/******************************************************************************
+ * WocOutput
+ ******************************************************************************/
+
+WocOutput::WocOutput()
+{
+ connect(WocProcessor::instance(),SIGNAL(sfinalize()),this,SLOT(finalize()));
+ connect(WocProcessor::instance(),SIGNAL(newClass(const WocClass&)),this,SLOT(newClass(const WocClass&)));
+ connect(WocProcessor::instance(),SIGNAL(newTable(const WocTable&)),this,SLOT(newTable(const WocTable&)));
+ connect(WocProcessor::instance(),SIGNAL(newTransaction(const WocTransaction&)),this,SLOT(newTransaction(const WocTransaction&)));
+ connect(this,SIGNAL(errorFound()),WocProcessor::instance(),SLOT(errorFound()));
+}
+
+WocOutput::~WocOutput(){}
+
+/******************************************************************************
+ * WocClass
+ ******************************************************************************/
+
+WocClass::WocClass(const QDomElement&cls)
+{
+ //scan basics
+ m_valid=true;
+ m_abstract=str2bool(cls.attribute("abstract","0"));
+ WocProcessor *woc=WocProcessor::instance();
+ QRegExp symok("[a-z_][a-z0-9_]*",Qt::CaseInsensitive);
+ m_name=cls.attribute("name");
+ if(m_name==""){
+ qDebug("Error: unnamed class at line %i column %i.",cls.lineNumber(),cls.columnNumber());
+ m_valid=false;
+ return;
+ }
+ if(woc->hasClass(m_name)){
+ qDebug("Error: double definition of class %s at line %i column %i.",m_name.toAscii().data(),cls.lineNumber(),cls.columnNumber());
+ m_valid=false;
+ return;
+ }
+ if(!symok.exactMatch(m_name)){
+ qDebug("Error: Illegal class name %s.",m_name.toAscii().data());
+ m_valid=false;
+ return;
+ }
+ qDebug("Info: parsing class %s",m_name.toAscii().data());
+ m_sbase=cls.attribute("serverbase","WObject");
+ m_cbase=cls.attribute("clientbase","WObject");
+ //scan properties
+ QList<QDomElement> nl=elementsByTagName(cls,"Property");
+ for(int i=0;i<nl.size();i++){
+ QDomElement el=nl.at(i).toElement();
+ if(el.isNull())continue;
+ s_prop p;
+ p.name=el.attribute("name");
+ if(!symok.exactMatch(p.name)){
+ qDebug("Error: Illegal property %s in class %s.",p.name.toAscii().data(),m_name.toAscii().data());
+ m_valid=false;
+ return;
+ }
+ if(hasProperty(p.name)){
+ qDebug("Error: Double definition of property %s in class %s.",p.name.toAscii().data(),m_name.toAscii().data());
+ m_valid=false;
+ return;
+ }
+ p.type=el.attribute("type");
+ p.isid=str2bool(el.attribute("id","0"));
+ p.isabstract=str2bool(el.attribute("abstract","0"));
+ m_props.append(p);
+ //docu
+ QString s=el.text().trimmed();
+ if(s!="")m_propdoc.insert(p.name,s);
+ }
+ //scan enums
+ nl=elementsByTagName(cls,"Enum");
+ for(int i=0;i<nl.size();i++){
+ QDomElement el=nl.at(i).toElement();
+ if(el.isNull())continue;
+ QString nm=el.attribute("name");
+ if(!symok.exactMatch(nm)){
+ qDebug("Error: Illegal enum type %s in class %s.",nm.toAscii().data(),m_name.toAscii().data());
+ m_valid=false;
+ return;
+ }
+ if(hasEnumType(nm)){
+ qDebug("Error: Double definition of enum type %s in class %s.",nm.toAscii().data(),m_name.toAscii().data());
+ m_valid=false;
+ return;
+ }
+ QList<WocEnum>ev;
+ //check whether there is a reference
+ if(el.hasAttribute("refColumn")){
+ QStringList ref=el.attribute("refColumn").split(":");
+ if(ref.size()!=2){
+ qDebug("Error: illegal enum reference in class %s enum %s.",m_name.toAscii().data(),nm.toAscii().data());
+ m_valid=false;
+ return;
+ }
+ if(!woc->hasTable(ref[0])){
+ qDebug("Error: enum reference in class %s enum %s points to non-existant table.",m_name.toAscii().data(),nm.toAscii().data());
+ m_valid=false;
+ return;
+ }
+ WocTable tab=woc->table(ref[0]);
+ if(!tab.hasColumn(ref[1])){
+ qDebug("Error: enum reference in class %s enum %s points to non-existant column.",m_name.toAscii().data(),nm.toAscii().data());
+ m_valid=false;
+ return;
+ }
+ ev=tab.columnEnums(ref[1]);
+ }
+ //scan values
+ QList<QDomElement> nl2=elementsByTagName(el,"Value");
+ int nxval=0;
+ for(int j=0;j<nl2.size();j++){
+ QDomElement el2=nl2.at(j).toElement();
+ if(el2.isNull())continue;
+ QString n=el2.attribute("name");
+ if(n==""){
+ qDebug("Warning: anonymous enum value in class %s enum %s. Ignoring it.",m_name.toAscii().data(),nm.toAscii().data());
+ continue;
+ }
+ nxval=el2.attribute("value",QString::number(nxval)).toInt(0,0);
+ ev.append(WocEnum(n,nxval,el2.text().trimmed()));
+ nxval++;
+ //TODO: check that value name does not exist yet
+ }
+ m_enumvals.insert(nm,ev);
+ }
+ //scan mappings
+ nl=elementsByTagName(cls,"Mapping");
+ for(int i=0;i<nl.size();i++){
+ QDomElement el=nl.at(i).toElement();
+ if(el.isNull())continue;
+ QString name=el.attribute("table");
+ if(!symok.exactMatch(name)){
+ qDebug("Error: Illegal mapping %s in class %s.",name.toAscii().data(),m_name.toAscii().data());
+ m_valid=false;
+ return;
+ }
+ if(hasMapping(name)){
+ qDebug("Error: Double definition of mapping %s in class %s.",name.toAscii().data(),m_name.toAscii().data());
+ m_valid=false;
+ return;
+ }
+ QList<s_map>map;
+ QList<QDomElement> nl2=elementsByTagName(el,"Map");
+ for(int j=0;j<nl2.size();j++){
+ QDomElement el2=nl2.at(j).toElement();
+ if(el2.isNull())continue;
+ s_map sm;
+ sm.column=el2.attribute("column");
+ sm.property=el2.attribute("property");
+ if(sm.property=="")sm.property=sm.column;
+ if(sm.column=="")sm.column=sm.property;
+ if(sm.column==""){
+ qDebug("Warning: empty mapping in class %s mapping %s. Ignoring it.",m_name.toAscii().data(),name.toAscii().data());
+ continue;
+ }
+ QList<QDomElement> nl3=elementsByTagName(el2,"Call");
+ for(int k=0;k<nl3.size();k++){
+ QDomElement el3=nl3.at(k).toElement();
+ if(el3.isNull())continue;
+ QString lang=el3.attribute("lang");
+ QString meth=el3.attribute("method","false");
+ sm.method.insert(lang,meth);
+ }
+ map.append(sm);
+ }
+ m_maps.insert(name,map);
+ }
+ //docu
+ nl=elementsByTagName(cls,"Doc");
+ for(int i=0;i<nl.size();i++){
+ QString s=nl.at(i).toElement().text().trimmed();
+ if(s!="")m_docstrings<<s;
+ }
+ //check abstraction
+ if(!m_abstract && isAbstract("")){
+ qDebug("Warning: class %s should be declared abstract.",m_name.toAscii().data());
+ }
+ //conditional abstraction (must be after check or we'll get false positives)
+ nl=elementsByTagName(cls,"Abstract");
+ for(int i=0;i<nl.size();i++){
+ QString s=nl.at(i).toElement().attribute("lang").trimmed();
+ if(s!="")m_cabstract<<s;
+ }
+}
+
+bool WocClass::hasProperty(QString p)const
+{
+ for(int i=0;i<m_props.size();i++)
+ if(m_props[i].name==p)return true;
+ return false;
+}
+
+QStringList WocClass::propertyNames()const
+{
+ QStringList r;
+ for(int i=0;i<m_props.size();i++)
+ r<<m_props[i].name;
+ return r;
+}
+
+QString WocClass::propertyType(QString p)const
+{
+ for(int i=0;i<m_props.size();i++)
+ if(m_props[i].name==p)return m_props[i].type;
+ return "";
+}
+
+bool WocClass::propertyIsIdentity(QString p)const
+{
+ for(int i=0;i<m_props.size();i++)
+ if(m_props[i].name==p)return m_props[i].isid;
+ return false;
+}
+
+bool WocClass::propertyIsAbstract(QString p)const
+{
+ for(int i=0;i<m_props.size();i++)
+ if(m_props[i].name==p)return m_props[i].isabstract;
+ return false;
+}
+
+bool WocClass::isAbstract(QString l)const
+{
+ if(m_cabstract.contains(l))return true;
+ for(int i=0;i<m_props.size();i++)
+ if(m_props[i].isabstract)return true;
+ return m_abstract;
+}
+
+QString WocClass::propertyPlainType(QString p)const
+{
+ QString r=propertyType(p);
+ if(r.startsWith("List:"))return r.mid(5);
+ else return r;
+}
+
+const QStringList WocClass::attrtypes=QStringList()<<"astring"<<"int"<<"int32"<<"int64"<<"bool";
+bool WocClass::propertyIsAttribute(QString p)const
+{
+ QString t=propertyPlainType(p);
+ if(attrtypes.contains(t))return true;
+ if(hasEnumType(t))return true;
+ return false;
+}
+
+const QStringList WocClass::elemtypes=QStringList()<<"string"<<"blob";
+bool WocClass::propertyIsElement(QString p)const
+{
+ QString t=propertyPlainType(p);
+ if(elemtypes.contains(t))return true;
+ if(hasEnumType(t))return true;
+ return false;
+}
+
+bool WocClass::propertyIsObject(QString p)const
+{
+ QString t=propertyPlainType(p);
+ //default types take precedence over classes
+ if(attrtypes.contains(t))return false;
+ if(elemtypes.contains(t))return false;
+ //enums shadow classes
+ if(hasEnumType(t))return false;
+ //check that the class exists
+ return WocProcessor::instance()->hasClass(t);
+}
+
+bool WocClass::propertyIsEnum(QString p)const
+{
+ QString t=propertyPlainType(p);
+ //default types take precedence over enums
+ if(attrtypes.contains(t))return false;
+ if(elemtypes.contains(t))return false;
+ //enums
+ return hasEnumType(t);
+}
+
+bool WocClass::propertyIsList(QString p)const
+{
+ if(propertyType(p).startsWith("List:"))return true;
+ else return false;
+}
+
+QMap<QString,QString> WocClass::mapping(QString m)const
+{
+ if(!m_maps.contains(m))return QMap<QString,QString>();
+ QList<s_map> sml=m_maps[m];
+ QMap<QString,QString>ret;
+ for(int i=0;i<sml.size();i++)
+ ret.insert(sml[i].property,sml[i].column);
+ return ret;
+}
+
+QStringList WocClass::mappingProperties(QString m)const
+{
+ if(!m_maps.contains(m))return QStringList();
+ QList<s_map> sml=m_maps[m];
+ QStringList ret;
+ for(int i=0;i<sml.size();i++)
+ ret<<sml[i].property;
+ return ret;
+}
+
+QString WocClass::mapMethod(QString table,QString property,QString lang)const
+{
+ if(!m_maps.contains(table))return "";
+ QList<s_map> sml=m_maps[table];
+ for(int i=0;i<sml.size();i++)
+ if(sml[i].property==property){
+ if(sml[i].method.contains(lang))return sml[i].method[lang];
+ else return "";
+ }
+ return "";
+}
+
+
+/******************************************************************************
+ * WocTable
+ ******************************************************************************/
+
+WocTable::WocTable()
+{
+ m_backup=m_valid=m_audit=false;
+}
+
+WocTable::WocTable(const QDomElement&tbl)
+{
+ m_valid=true;
+ //parse XML
+ m_name=tbl.attribute("name");
+ WocProcessor*woc=WocProcessor::instance();
+ QRegExp good("[a-z][a-z0-9_]*",Qt::CaseInsensitive);
+ //check name syntax, check it does not exist yet
+ if(woc->hasTable(m_name)){
+ qDebug("Error: double definition of table %s.",m_name.toAscii().data());
+ m_valid=false;
+ return;
+ }
+ if(!good.exactMatch(m_name)){
+ qDebug("Error: table %s does not have a regular name.",m_name.toAscii().data());
+ m_valid=false;
+ return;
+ }
+ m_backup=str2bool(tbl.attribute("backup","0"));
+ m_base=tbl.attribute("base","WobTable");
+ m_audit=str2bool(tbl.attribute("audit","0"));
+ qDebug("Info: parsing table %s",m_name.toAscii().data());
+ //Columns
+ QList<QDomElement> nl=elementsByTagName(tbl,"Column");
+ for(int i=0;i<nl.size();i++){
+ QDomElement el=nl.at(i).toElement();
+ if(el.isNull())continue;
+ QPair<bool,s_col> cl=parseColumn(el,m_name);
+ if(!cl.first)return;
+ if(hasColumn(cl.second.name)){
+ qDebug("Error: double definition of column %s in table %s.",cl.second.name.toAscii().data(),m_name.toAscii().data());
+ m_valid=false;
+ return;
+ }
+ m_columns.append(cl.second);
+ }
+ //Audit Columns
+ nl=elementsByTagName(tbl,"AuditColumn");
+ for(int i=0;i<nl.size();i++){
+ QDomElement el=nl.at(i).toElement();
+ if(el.isNull())continue;
+ QPair<bool,s_col> cl=parseColumn(el,m_name);
+ if(!cl.first)return;
+ m_auditcolumns.append(cl.second);
+ }
+
+ //Foreign getter methods
+ nl=elementsByTagName(tbl,"Foreign");
+ for(int i=0;i<nl.size();i++){
+ QDomElement el=nl.at(i).toElement();
+ if(el.isNull())continue;
+ m_foreign.append(QPair<QString,QString>(el.attribute("method"),el.attribute("via")));
+ //TODO: validate foreign getter
+ //docu
+ QString s=el.text().trimmed();
+ if(s!="")m_fordocs.insert(el.attribute("method"),s);
+ }
+
+ //Presets
+ nl=elementsByTagName(tbl,"Preset");
+ for(int i=0;i<nl.size();i++){
+ QDomElement el=nl.at(i).toElement();
+ if(el.isNull())continue;
+ QMap<QString,QString>ps;
+ QList<QDomElement> nl2=elementsByTagName(el,"V");
+ for(int j=0;j<nl2.size();j++){
+ QDomElement el2=nl2.at(j).toElement();
+ if(el2.isNull())continue;
+ if(!el2.hasAttribute("col") || (!el2.hasAttribute("val") && !el2.hasAttribute("code"))){
+ qDebug("Error: table definition %s contains illegal preset.",m_name.toAscii().data());
+ m_valid=false;
+ return;
+ }
+ QString nm=el2.attribute("col");
+ if(!hasColumn(nm)){
+ qDebug("Error: table definition %s contains preset for invalid column %s.",m_name.toAscii().data(),nm.toAscii().data());
+ m_valid=false;
+ return;
+ }
+ QString v;
+ if(el2.hasAttribute("val"))v="\""+el2.attribute("val").replace("\"","\\\"")+"\"";
+ else v=el2.attribute("code");
+ ps.insert(nm,v);
+ }
+ if(ps.size()>0)m_presets.append(ps);
+ }
+
+ //Docu
+ nl=elementsByTagName(tbl,"Doc");
+ for(int i=0;i<nl.size();i++){
+ QString s=nl.at(i).toElement().text().trimmed();
+ if(s!="")m_docstrings<<s;
+ }
+
+ //sanity checks
+ //check we have any columns at all
+ if(m_columns.size()==0){
+ qDebug("Error: table %s does not have any columns.",m_name.toAscii().data());
+ m_valid=false;
+ return;
+ }
+ //check that we have a primary key
+ if(primaryColumns().size()==0){
+ qDebug("Warning: table %s does not have any primary key columns.",m_name.toAscii().data());
+ }
+}
+
+
+QPair<bool,WocTable::s_col> WocTable::parseColumn(const QDomElement&el,QString m_name)
+{
+ s_col cl;
+ QRegExp good("[a-z][a-z0-9_]*",Qt::CaseInsensitive);
+ cl.name=el.attribute("name");
+ //check name syntax, check it is not doubled
+ if(!good.exactMatch(cl.name)){
+ qDebug("Error: table %s column %s does not have a regular name.",m_name.toAscii().data(),cl.name.toAscii().data());
+ return QPair<bool,s_col>(false,s_col());
+ }
+ cl.isprime=str2bool(el.attribute("primarykey","0"));
+ cl.isunique=str2bool(el.attribute("unique","0"));
+ cl.isindex=str2bool(el.attribute("index","0"));
+ if(cl.isprime)cl.isnull=false;
+ else cl.isnull=true;
+ if(el.hasAttribute("null"))
+ cl.isnull=str2bool(el.attribute("null"));
+ else if(el.hasAttribute("notnull"))
+ cl.isnull=!str2bool(el.attribute("notnull","0"));
+ cl.type=el.attribute("type");
+ //TODO: validate type
+ cl.foreign=el.attribute("foreignkey");
+ WocProcessor*woc=WocProcessor::instance();
+ //check foreign key exists
+ if(cl.foreign!=""){
+ QStringList fgn=cl.foreign.split(":");
+ if(fgn.size()!=2){
+ qDebug("Error: table %s column %s: foreign key definition must use syntax 'table:column'",m_name.toAscii().data(),cl.name.toAscii().data());
+ return QPair<bool,s_col>(false,s_col());
+ }
+ if(!woc->hasTable(fgn[0])){
+ qDebug("Error: table %s column %s: foreign key target table %s does not exist",m_name.toAscii().data(),cl.name.toAscii().data(),fgn[0].toAscii().data());
+ return QPair<bool,s_col>(false,s_col());
+ }
+ if(!woc->table(fgn[0]).hasColumn(fgn[1])){
+ qDebug("Error: table %s column %s: foreign key target table/column %s does not exist",m_name.toAscii().data(),cl.name.toAscii().data(),cl.foreign.toAscii().data());
+ return QPair<bool,s_col>(false,s_col());
+ }
+ }
+ cl.defaultval=el.attribute("default");
+ //TODO: validate default against type
+ QList<QDomElement> nl2=elementsByTagName(el,"Value");
+ int nxval=0;
+ //enum values
+ for(int j=0;j<nl2.size();j++){
+ QDomElement el2=nl2.at(j).toElement();
+ if(el2.isNull())continue;
+ QString n=el2.attribute("name");
+ if(n==""){
+ qDebug("Warning: anonymous enum value in table %s column %s. Ignoring it.",m_name.toAscii().data(),cl.name.toAscii().data());
+ continue;
+ }
+ nxval=el2.attribute("value",QString::number(nxval)).toInt(0,0);
+ cl.enumvals.append(WocEnum(n,nxval,el2.text().trimmed()));
+ nxval++;
+ }
+ //default calls
+ nl2=elementsByTagName(el,"Call");
+ for(int j=0;j<nl2.size();j++){
+ QDomElement el2=nl2.at(j).toElement();
+ if(el2.isNull())continue;
+ QString lang=el2.attribute("lang");
+ QString meth=el2.attribute("method","false");
+ cl.methodcalls.insert(lang,meth);
+ }
+ //docu
+ QDomNodeList nl3=el.childNodes();
+ for(int j=0;j<nl3.size();j++){
+ QDomNode n=nl3.at(j);
+ if(n.isText()||n.isCDATASection())cl.doc+=" "+n.nodeValue();
+ else
+ if(n.isElement()&&n.nodeName()=="Doc")cl.doc+=" "+n.toElement().text();
+ }
+ cl.doc=cl.doc.trimmed();
+
+ return QPair<bool,s_col>(true,cl);
+}
+
+QStringList WocTable::columns()const
+{
+ QStringList r;
+ for(int i=0;i<m_columns.size();i++)
+ r<<m_columns[i].name;
+ return r;
+}
+
+QStringList WocTable::auditColumns()const
+{
+ QStringList r;
+ for(int i=0;i<m_staticauditcolumns.size();i++)
+ r<<m_staticauditcolumns[i].name;
+ for(int i=0;i<m_auditcolumns.size();i++)
+ r<<m_auditcolumns[i].name;
+ return r;
+}
+
+QStringList WocTable::primaryColumns()const
+{
+ QStringList r;
+ for(int i=0;i<m_columns.size();i++)
+ if(m_columns[i].isprime)
+ r<<m_columns[i].name;
+ return r;
+}
+
+QString WocTable::columnType(QString c)const
+{
+ for(int i=0;i<m_columns.size();i++)
+ if(m_columns[i].name==c)
+ return m_columns[i].type;
+ return "";
+}
+
+bool WocTable::columnIsNull(QString c)const
+{
+ for(int i=0;i<m_columns.size();i++)
+ if(m_columns[i].name==c)
+ return m_columns[i].isnull;
+ return false;
+}
+
+bool WocTable::columnIsPrimary(QString c)const
+{
+ for(int i=0;i<m_columns.size();i++)
+ if(m_columns[i].name==c)
+ return m_columns[i].isprime;
+ return false;
+}
+
+bool WocTable::columnHasDefault(QString c)const
+{
+ for(int i=0;i<m_columns.size();i++)
+ if(m_columns[i].name==c)
+ return m_columns[i].defaultval!="";
+ return false;
+}
+
+QString WocTable::columnDefault(QString c)const
+{
+ for(int i=0;i<m_columns.size();i++)
+ if(m_columns[i].name==c)
+ return m_columns[i].defaultval;
+ return "";
+}
+
+bool WocTable::hasColumn(QString c)const
+{
+ for(int i=0;i<m_columns.size();i++)
+ if(m_columns[i].name==c)
+ return true;
+ return false;
+}
+
+QList<WocEnum> WocTable::columnEnums(QString c)const
+{
+ for(int i=0;i<m_columns.size();i++)
+ if(m_columns[i].name==c)
+ return m_columns[i].enumvals;
+ return QList<WocEnum>();
+}
+
+QList<WocEnum> WocTable::getEnums()const
+{
+ QList<WocEnum> r;
+ for(int i=0;i<m_columns.size();i++)
+ for(int j=0;j<m_columns[i].enumvals.size();j++)
+ r.append(m_columns[i].enumvals[j]);
+ return r;
+}
+bool WocTable::columnIsForeign(QString c)const
+{
+ for(int i=0;i<m_columns.size();i++)
+ if(m_columns[i].name==c)
+ return m_columns[i].foreign!="";
+ return false;
+}
+
+QString WocTable::columnForeign(QString c)const
+{
+ for(int i=0;i<m_columns.size();i++)
+ if(m_columns[i].name==c)
+ return m_columns[i].foreign;
+ return "";
+}
+
+bool WocTable::columnIsIndexed(QString c)const
+{
+ for(int i=0;i<m_columns.size();i++)
+ if(m_columns[i].name==c)
+ return m_columns[i].isindex;
+ return false;
+}
+
+bool WocTable::columnIsUnique(QString c)const
+{
+ for(int i=0;i<m_columns.size();i++)
+ if(m_columns[i].name==c)
+ return m_columns[i].isunique;
+ return false;
+}
+
+QString WocTable::columnDoc(QString c)const
+{
+ for(int i=0;i<m_columns.size();i++)
+ if(m_columns[i].name==c)
+ return m_columns[i].doc;
+ return "";
+}
+
+
+QStringList WocTable::foreigns()const
+{
+ QStringList r;
+ for(int i=0;i<m_foreign.size();i++)
+ r<<m_foreign[i].first;
+ return r;
+}
+
+QString WocTable::foreignQuery(QString f)const
+{
+ for(int i=0;i<m_foreign.size();i++)
+ if(m_foreign[i].first==f)
+ return m_foreign[i].second;
+ return "";
+}
+
+bool WocTable::haveForeign(QString f)const
+{
+ for(int i=0;i<m_foreign.size();i++)
+ if(m_foreign[i].first==f)
+ return true;
+ return false;
+}
+
+QString WocTable::columnCall(QString col,QString lang)const
+{
+ for(int i=0;i<m_columns.size();i++){
+ s_col cl=m_columns[i];
+ if(cl.name==col){
+ if(!cl.methodcalls.contains(lang))return "";
+ else return cl.methodcalls[lang];
+ }
+ }
+ return "";
+}
+
+QList<WocTable::s_col>WocTable::m_staticauditcolumns;
+void WocTable::parseAuditStatic(const QDomElement&el)
+{
+ QList<QDomElement> nl=elementsByTagName(el,"Column");
+ for(int i=0;i<nl.size();i++){
+ QDomElement el2=nl.at(i).toElement();
+ if(el2.isNull())continue;
+ QPair<bool,s_col>cl=parseColumn(el2,"(global audit settings)");
+ if(!cl.first){
+ WocProcessor::instance()->errorFound();
+ return;
+ }
+ m_staticauditcolumns.append(cl.second);
+ }
+}
+
+WocTable WocTable::auditTable()const
+{
+ WocTable adt;
+ adt.m_valid=m_valid;
+ adt.m_backup=m_backup;
+ adt.m_audit=false;
+ adt.m_name=m_name+"_audit";//enhance the name
+ adt.m_base="WobTable";//revert to default
+ adt.m_foreign=m_foreign;
+ adt.m_fordocs=m_fordocs;
+ adt.m_docstrings=m_docstrings;
+ //these stay empty: m_presets, m_auditcolumns
+
+ //now for the complicated stuff
+ //create primary key
+ s_col cl;
+ cl.name="auditid";cl.type="seq64";cl.doc="additional primary key for auditing";
+ cl.isindex=cl.isunique=cl.isnull=false;cl.isprime=true;
+ adt.m_columns.append(cl);
+ //copy common columns
+ adt.m_columns.append(m_staticauditcolumns);
+ //copy normal columns
+ for(int i=0;i<m_columns.size();i++){
+ //get and reset
+ cl=m_columns[i];
+ cl.isprime=cl.isunique=false;
+ cl.methodcalls.clear();
+ if(cl.type.left(3)=="seq")cl.type="int"+cl.type.mid(3);
+ //no foreign keys
+ cl.foreign="";
+ //add
+ adt.m_columns.append(cl);
+ }
+ //copy local audit columns
+ adt.m_columns.append(m_auditcolumns);
+
+ //return result
+ return adt;
+}
+
+
+/******************************************************************************
+ * WocTransaction
+ ******************************************************************************/
+
+WocTransaction::WocTransaction(const QDomElement&root)
+{
+ m_valid=true;
+ m_mode=Checked;
+ QRegExp rval("[a-z][a-z0-9_]*",Qt::CaseInsensitive);
+ //get basics
+ m_name=root.attribute("name");
+ if(!rval.exactMatch(m_name)){
+ qDebug("Error: invalid transaction name %s.",m_name.toAscii().data());
+ m_valid=false;
+ return;
+ }
+ qDebug("Info: parsing transaction %s",m_name.toAscii().data());
+ if(root.hasAttribute("mode")){
+ QString m=root.attribute("mode").toLower();
+ if(m=="checked")m_mode=Checked;else
+ if(m=="auth")m_mode=Auth;else
+ if(m=="open")m_mode=Open;
+ else{
+ qDebug("Error: invalid transaction mode %s in transaction %s, must be checked, auth, or open.",m.toAscii().data(),m_name.toAscii().data());
+ m_valid=false;
+ return;
+ }
+ }
+ //input tag
+ QList<QDomElement> nl=elementsByTagName(root,"Input");
+ for(int i=0;i<nl.size();i++){
+ QDomElement el=nl.at(i).toElement();
+ if(el.isNull())continue;
+ //variables
+ QList<QDomElement> nl2=elementsByTagName(el,"Var");
+ for(int j=0;j<nl2.size();j++){
+ QDomElement el2=nl2.at(j).toElement();
+ if(el2.isNull())continue;
+ QString nm=el2.attribute("name");
+ if(!rval.exactMatch(nm)){
+ qDebug("Error: invalid input variable %s in transaction %s.",nm.toAscii().data(),m_name.toAscii().data());
+ m_valid=false;
+ return;
+ }
+ if(hasInput(nm)){
+ qDebug("Error: double definition of input variable %s in transaction %s.",nm.toAscii().data(),m_name.toAscii().data());
+ m_valid=false;
+ return;
+ }
+ QString tp=el2.attribute("type");
+ //TODO: validate type
+ m_input.append(QPair<QString,QString>(nm,tp));
+ //docu
+ QString s=el2.text().trimmed();
+ if(s!="")m_indoc.insert(nm,s);
+ }
+ }
+ //call tag
+ nl=elementsByTagName(root,"Call");
+ for(int j=0;j<nl.size();j++){
+ QDomElement el=nl.at(j).toElement();
+ if(el.isNull())continue;
+ QString nm=el.attribute("lang");
+ if(hasCall(nm)){
+ qDebug("Error: double definition of input variable %s in transaction %s.",nm.toAscii().data(),m_name.toAscii().data());
+ m_valid=false;
+ return;
+ }
+ QString mt=el.attribute("method");
+ m_call.insert(nm,mt);
+ }
+ //output
+ nl=elementsByTagName(root,"Output");
+ for(int i=0;i<nl.size();i++){
+ QDomElement el=nl.at(i).toElement();
+ if(el.isNull())continue;
+ //variables
+ QList<QDomElement> nl2=elementsByTagName(el,"Var");
+ for(int j=0;j<nl2.size();j++){
+ QDomElement el2=nl2.at(j).toElement();
+ if(el2.isNull())continue;
+ QString nm=el2.attribute("name");
+ if(!rval.exactMatch(nm)){
+ qDebug("Error: invalid output variable %s in transaction %s.",nm.toAscii().data(),m_name.toAscii().data());
+ m_valid=false;
+ return;
+ }
+ if(hasOutput(nm)){
+ qDebug("Error: double definition of output variable %s in transaction %s.",nm.toAscii().data(),m_name.toAscii().data());
+ m_valid=false;
+ return;
+ }
+ QString tp=el2.attribute("type");
+ //TODO: validate type
+ m_output.append(QPair<QString,QString>(nm,tp));
+ //docu
+ QString s=el2.text().trimmed();
+ if(s!="")m_outdoc.insert(nm,s);
+ }
+ }
+ //docu
+ nl=elementsByTagName(root,"Doc");
+ for(int i=0;i<nl.size();i++){
+ QString s=nl.at(i).toElement().text().trimmed();
+ if(s!="")m_docstrings<<s;
+ }
+ //privileges
+ nl=elementsByTagName(root,"Privilege");
+ for(int i=0;i<nl.size();i++){
+ QString s=nl.at(i).toElement().attribute("name").trimmed();
+ if(s!="")m_privileges<<s;
+ m_privdoc.insert(s,nl.at(i).toElement().text().trimmed());
+ }
+}
+
+bool WocTransaction::hasInput(QString v)const
+{
+ for(int i=0;i<m_input.size();i++)
+ if(m_input[i].first==v)return true;
+ return false;
+}
+
+QStringList WocTransaction::inputNames()const
+{
+ QStringList r;
+ for(int i=0;i<m_input.size();i++)
+ r<<m_input[i].first;
+ return r;
+}
+
+QString WocTransaction::inputType(QString v)const
+{
+ for(int i=0;i<m_input.size();i++)
+ if(m_input[i].first==v)return m_input[i].second;
+ return "";
+}
+
+bool WocTransaction::hasOutput(QString v)const
+{
+ for(int i=0;i<m_output.size();i++)
+ if(m_output[i].first==v)return true;
+ return false;
+}
+
+QStringList WocTransaction::outputNames()const
+{
+ QStringList r;
+ for(int i=0;i<m_output.size();i++)
+ r<<m_output[i].first;
+ return r;
+}
+
+QString WocTransaction::outputType(QString v)const
+{
+ for(int i=0;i<m_output.size();i++)
+ if(m_output[i].first==v)return m_output[i].second;
+ return "";
+}
--- /dev/null
+//
+// C++ Interface: processor
+//
+// Description:
+//
+//
+// Author: Konrad Rosenbaum <konrad@silmor.de>, (C) 2009
+//
+// Copyright: See README/COPYING files that come with this distribution
+//
+//
+
+#ifndef WOC_PROCESSOR_H
+#define WOC_PROCESSOR_H
+
+#include <QList>
+#include <QMap>
+#include <QObject>
+#include <QPair>
+#include <QStringList>
+
+class QDomElement;
+
+QList<QDomElement>elementsByTagName(const QDomElement&,QString);
+
+inline bool str2bool(QString s)
+{
+ bool b;
+ int i=s.toInt(&b,0);
+ if(b)return i?true:false;
+ s=s.toLower();
+ if(s=="yes"||s=="y"||s=="on"||s=="true"||s=="t")return true;
+ return false;
+}
+
+
+/**helper structure to store enums in classes and tables*/
+struct WocEnum {
+ QString name,doc;
+ int val;
+ WocEnum(){val=0;}
+ WocEnum(QString n,int v,QString d=""){name=n;val=v;doc=d;}
+};
+
+/**stores a communication class including serialization and deserialization information*/
+class WocClass
+{
+ public:
+ /**parses XML to create itself*/
+ WocClass(const QDomElement&);
+
+ /**returns whether parsing was successful and this instance represents a valid communication class*/
+ bool isValid()const{return m_valid;}
+
+ /**returns the class name*/
+ QString name()const{return m_name;}
+ /**returns the name of the class it is derived from (on the server side) - default: WObject*/
+ QString serverBaseClass()const{return m_sbase;}
+ /**returns the parent class of the class on client side- default: WObject*/
+ QString clientBaseClass()const{return m_cbase;}
+
+ /**returns true of it has a property with this name*/
+ bool hasProperty(QString)const;
+ /**returns a list of all property names*/
+ QStringList propertyNames()const;
+ /**returns the type string of the property, including "List:" if applicable*/
+ QString propertyType(QString)const;
+ /**returns the plain type string of the property without "List:"*/
+ QString propertyPlainType(QString)const;
+ /**returns whether this property identifies the object instance*/
+ bool propertyIsIdentity(QString)const;
+ /**returns whether this property is abstract*/
+ bool propertyIsAbstract(QString)const;
+ /**returns whether this property is serialized as XML attribute*/
+ bool propertyIsAttribute(QString)const;
+ /**returns whether this property is serialized as XML element*/
+ bool propertyIsElement(QString)const;
+ /**returns whether this property has an enum type*/
+ bool propertyIsEnum(QString)const;
+ /**returns whether the property is an object*/
+ bool propertyIsObject(QString)const;
+ /**returns whether the property is a list of values (false for scalars)*/
+ bool propertyIsList(QString)const;
+ /**returns whether the property type is integer*/
+ bool propertyIsInt(QString p)const{QString pt=propertyPlainType(p);return pt=="int" || pt=="int32" || pt=="int64";}
+ /**returns whether the property type is boolean*/
+ bool propertyIsBool(QString p)const{return propertyPlainType(p)=="bool";}
+ /**returns whether the property type is string*/
+ bool propertyIsString(QString p)const{QString pt=propertyPlainType(p);return pt=="string"||pt=="astring";}
+ /**returns whether the property type is blob*/
+ bool propertyIsBlob(QString p)const{QString pt=propertyPlainType(p);return pt=="blob";}
+
+ /**returns whether the class is abstract in the requested language (needs to be customized); it is automatically abstract if any property is abstract*/
+ bool isAbstract(QString)const;
+ /**returns the languages in which the class is conditionally abstract*/
+ QStringList abstractLangs()const{return m_cabstract;}
+
+ /**returns the names of all enum types of this class*/
+ QStringList enumTypes()const{return m_enumvals.keys();}
+ /**returns true if the given enum type exists in this class*/
+ bool hasEnumType(QString t)const{return m_enumvals.contains(t);}
+ /**returns a list of enum values as name-value pairs*/
+ QList<WocEnum> enumValues(QString t)const{return m_enumvals[t];}
+
+ /**returns true if the given mapping exists*/
+ bool hasMapping(QString m)const{return m_maps.contains(m);}
+ /**returns the names of all tables for which a mapping exists*/
+ QStringList mappingTables()const{return m_maps.keys();}
+ /**returns the (correctly ordered) properties for a mapping*/
+ QStringList mappingProperties(QString)const;
+ /**returns the specific mapping; map key=property, map value=column*/
+ QMap<QString,QString> mapping(QString m)const;
+ /**returns the method for a specific mapping or an empty string if it does not exist in the specified language*/
+ QString mapMethod(QString table,QString property,QString lang)const;
+
+ /**returns documentation for this class*/
+ QStringList docStrings()const{return m_docstrings;}
+ /**returns documentation for a property*/
+ QString propDoc(QString p)const
+ {if(m_propdoc.contains(p))return m_propdoc[p];else return "";}
+
+ private:
+ //valid: parsing the WOLF succeeded
+ //abstract: the class is declared abstract (isAbstract may return true even if this is false)
+ //cabstract: conditional abstract - just for one or two languages; abstract overrides cabstract!
+ bool m_valid,m_abstract;
+ QStringList m_cabstract;
+ //name: class name
+ //base: name of parent class (s=server, c=client)
+ QString m_name,m_sbase,m_cbase;
+ //property info
+ struct s_prop{
+ QString name,type;
+ bool isid,isabstract;
+ };
+ QList<s_prop> m_props;
+ //mappings: "table-name" => List of ("column-name","property-name")
+ struct s_map{
+ QString column,property;
+ QMap<QString,QString>method;//lang->method
+ };
+ QMap<QString,QList<s_map> >m_maps;
+ //enum types: "type-name" => List of ("constant-name",int-constant-value)
+ QMap<QString,QList<WocEnum> >m_enumvals;
+ //serializers: "name" => List of properties (syntax Objects: "propertyname/Serializer"
+// QMap<QString,QStringList> m_serial;
+
+ //docu
+ QStringList m_docstrings;
+ QMap<QString,QString>m_propdoc;
+
+ //helper: contains predefined types sorted by serialization type
+ static const QStringList attrtypes,elemtypes;
+};
+
+/**stores the internal representation of a database table and its abstraction class*/
+class WocTable
+{
+ public:
+ /**initializes an invalid table*/
+ WocTable();
+ /**initializes a table from XML*/
+ WocTable(const QDomElement&);
+
+ /**returns whether this instance is valid, ie. whether parsing was successful*/
+ bool isValid()const{return m_valid;}
+
+ /**returns the table name*/
+ QString name()const{return m_name;}
+ /**returns whether the table is marked for backup*/
+ bool inBackup()const{return m_backup;}
+ /**returns the parent class of the table class - default: WobTable*/
+ QString baseClass()const{return m_base;}
+
+ /**returns whether the table has a column with this name*/
+ bool hasColumn(QString)const;
+ /**returns a list of all defined column names*/
+ QStringList columns()const;
+ /**returns the list of all primary key columns*/
+ QStringList primaryColumns()const;
+ /**returns the data type of the column*/
+ QString columnType(QString)const;
+ /**returns whether the column allows NULLs*/
+ bool columnIsNull(QString)const;
+ /**returns whether the column is part of the primary key*/
+ bool columnIsPrimary(QString)const;
+ /**returns whether the column has a default*/
+ bool columnHasDefault(QString)const;
+ /**returns the default value of the column (empty string if there is none)*/
+ QString columnDefault(QString)const;
+ /**returns whether the column is a foreign key*/
+ bool columnIsForeign(QString)const;
+ /**returns the foreign key reference of the column in the format table:column*/
+ QString columnForeign(QString)const;
+ /**returns whether the column has an index*/
+ bool columnIsIndexed(QString)const;
+ /**returns whether the column has a unique constraint*/
+ bool columnIsUnique(QString)const;
+ /**returns enum definitions of the column - each pair contains the symbolic name in first and the assigned integer value in second*/
+ QList<WocEnum> columnEnums(QString)const;
+ /**returns the insert call of a column for a specific language; empty string if there is none*/
+ QString columnCall(QString col,QString lang)const;
+
+ /**returns all enum definitions of the table; see also columnEnums */
+ QList<WocEnum> getEnums()const;
+
+ /**returns a list of all foreign definitions - methods that return data from other tables*/
+ QStringList foreigns()const;
+ /**returns the definition of a specific foreign table query method*/
+ QString foreignQuery(QString)const;
+ /**returns whether a foreign table query method exists*/
+ bool haveForeign(QString)const;
+
+ /**returns a list of all preset values (to be generated when the DB is created);
+ each entry in the list is a dictionary with the column name as key and the intended preset value as value - each entry of the list is one DB row, each key-value-pair in the map is one preset value in that row*/
+ QList<QMap<QString,QString> > presets()const{return m_presets;}
+
+ /**parses the static part of auditing*/
+ static void parseAuditStatic(const QDomElement&);
+ /**returns whether the table is auditable*/
+ bool isAuditable()const{return m_audit;}
+ /**creates and returns the table instance that represents the audit table*/
+ WocTable auditTable()const;
+ /**returns the names of audit columns (except auditid)*/
+ QStringList auditColumns()const;
+
+ /**returns table documentation*/
+ QStringList docStrings()const{return m_docstrings;}
+ /**returns column documentation*/
+ QString columnDoc(QString c)const;
+ /**returns foreign getter documentation*/
+ QString foreignDoc(QString c)const
+ {if(m_fordocs.contains(c))return m_fordocs[c];else return "";}
+
+ private:
+ bool m_valid,m_backup,m_audit;
+ QString m_name,m_base;
+ struct s_col {
+ QString name,type,foreign,defaultval,doc;
+ bool isnull,isprime,isindex,isunique;
+ QList<WocEnum>enumvals;
+ QMap<QString,QString>methodcalls;
+ };
+ QList<s_col>m_columns,m_auditcolumns;
+ static QList<s_col>m_staticauditcolumns;
+ QList<QPair<QString,QString> >m_foreign;
+ QList<QMap<QString,QString> >m_presets;
+
+ QStringList m_docstrings;
+ QMap<QString,QString>m_fordocs;
+
+ //helper method: parses a single column element
+ static QPair<bool,s_col> parseColumn(const QDomElement&,QString);
+};
+
+/**internal representation of a transaction*/
+class WocTransaction
+{
+ public:
+ /**initializes a transaction from XML*/
+ WocTransaction(const QDomElement&);
+ /**returns whether parsing it was successful*/
+ bool isValid()const{return m_valid;}
+
+ /**returns the name of the transaction*/
+ QString name()const{return m_name;}
+
+ /**returns whether an input variable exists*/
+ bool hasInput(QString v)const;
+ /**returns the names of all inputs in the order of definition*/
+ QStringList inputNames()const;
+ /**returns the type of an input variable*/
+ QString inputType(QString)const;
+
+ /**returns whether an output variable exists*/
+ bool hasOutput(QString v)const;
+ /**returns the names of all outputs in the order of definition*/
+ QStringList outputNames()const;
+ /**returns the type of an output variable*/
+ QString outputType(QString)const;
+
+ /**returns whether a specific language binding exists for a call*/
+ bool hasCall(QString c)const{return m_call.contains(c);}
+ /**returns the called function*/
+ QString callFunction(QString c)const{return m_call[c];}
+
+ /**authentication mode*/
+ enum AuthMode {
+ /**default: need a valid session and the privilege*/
+ Checked,
+ /**only need to be authenticated, every valid user can do it*/
+ Auth,
+ /**available even to anonymous/unauthenticated users*/
+ Open
+ };
+ AuthMode authMode()const{return m_mode;}
+
+ /**returns true if the type given is a list*/
+ bool isListType(QString t)const{return t.startsWith("List:");}
+ /**returns the type without list or xml qualifiers*/
+ QString plainType(QString t)const{
+ if(t.startsWith("List:"))t=t.mid(5);
+ QStringList l=t.split("/",QString::SkipEmptyParts);
+ if(l.size()>0)t=l[0];else t="unknown";
+ return t;
+ }
+ /**returns the XML serializer for Object types*/
+ QString typeSerializer(QString t)const{
+ QStringList l=t.split("/",QString::SkipEmptyParts);
+ if(l.size()>1)return l[1];
+ else return "";
+ }
+ /**returns true if the type is integer*/
+ bool isIntType(QString t)const{QString pt=plainType(t);return pt=="int" || pt=="int32" || pt=="int64";}
+ /**returns true if the type is boolean*/
+ bool isBoolType(QString t)const{return plainType(t)=="bool";}
+ /**returns true if the type is a string*/
+ bool isStringType(QString t)const{QString p=plainType(t);return p=="astring"||p=="string";}
+ /**returns true if the type is a blob*/
+ bool isBlobType(QString t)const{QString p=plainType(t);return p=="blob";}
+ /**returns true if the type is to be encoded as attribute*/
+ bool isAttributeType(QString t)const{return t=="astring"||t=="int"||t=="int32"||t=="int64"||t=="bool";}
+ /**returns true if the type is to be encoded as element*/
+ bool isElementType(QString t)const{return !isAttributeType(t);}
+ /**return true if the type is an object type*/
+ bool isObjectType(QString t)const{QString p=plainType(t);return p!="astring"&&p!="string"&&p!="int"&&p!="int32"&&p!="int64"&&p!="bool"&&p!="blob";}
+
+ /**return the documentation of the transaction*/
+ QStringList docStrings()const{return m_docstrings;}
+ /**return docu of input element*/
+ QString inputDoc(QString v)const
+ {if(m_indoc.contains(v))return m_indoc[v];else return "";}
+ /**return docu of output element*/
+ QString outputDoc(QString v)const
+ {if(m_outdoc.contains(v))return m_outdoc[v];else return "";}
+ /**return docu of a privilege*/
+ QString privilegeDoc(QString p)const
+ {if(m_privdoc.contains(p))return m_privdoc[p];else return "";}
+
+ /**return privileges that exist inside this transaction*/
+ QStringList privileges()const{return m_privileges;}
+ private:
+ QString m_name;
+ bool m_valid;
+ AuthMode m_mode;
+ QMap<QString,QString> m_call;
+ QList<QPair<QString,QString> >m_input,m_output;
+ QStringList m_privileges;
+ //docu
+ QStringList m_docstrings;
+ QMap<QString,QString>m_indoc,m_outdoc,m_privdoc;
+};
+
+/**base class of all output generators*/
+class WocOutput:public QObject
+{
+ Q_OBJECT
+ public:
+ /**the constructor should set up and initialize the environment of the generator*/
+ WocOutput();
+ /**currently there is no guarantee that the destructor is ever called.*/
+ virtual ~WocOutput();
+
+ protected slots:
+ /**called whenever the parser finds a new class in the XML input; some references might not exist yet*/
+ virtual void newClass(const WocClass&)=0;
+ /**called whenever the parser finds a new table in the XML input; the parser guarantees that tables it depends on already exist (it will throw an error otherwise)*/
+ virtual void newTable(const WocTable&)=0;
+ /**called whenever the parser finds a new transaction; the parser guarantees that all referenced types exist (it will throw an error otherwise)*/
+ virtual void newTransaction(const WocTransaction&)=0;
+ /**called when the parsing is complete: it should clean up the generators environment; it may not be called if woc stops with an error*/
+ virtual void finalize()=0;
+ signals:
+ void errorFound();
+};
+
+/**central processing singleton*/
+class WocProcessor:public QObject
+{
+ Q_OBJECT
+ public:
+ WocProcessor();
+
+ /**called from main loop to parse a file*/
+ bool processFile(QString);
+ /**called from main loop to finalize its work*/
+ void finalize();
+
+ /**returns the instance of the processor (if it exists yet)*/
+ static WocProcessor* instance(){return inst;}
+
+ /**returns the base directory of the project (all other pathes are relative to it)*/
+ QString baseDir()const{return m_baseDir;}
+ /**returns the directory where WOLFs are found, should normally not be used outside this class*/
+ QString wobDir()const{return m_wobDir;}
+ /**returns the project name (default="WobProject")*/
+ QString projectName()const{return m_projname;}
+ /**returns the current communication protocol version*/
+ QString verComm()const{return m_verComm;}
+ /**returns the communication protocol version that is at least needed to be compatible*/
+ QString verNeedComm()const{return m_verNeedComm;}
+ /**returns a human readable version string*/
+ QString verHR()const{return m_verHR;}
+ /**returns the SVN revision of the project: it contains two tokens, the first one is the current revision or min-max if the working copy contains mixed revisions; the second token contains the word "vanilla" if there are no local modifications, or "modified" if there are local modifications*/
+ QString svnRevision()const{return m_svnRev;}
+ /**returns the SVN Repository Root*/
+ QString svnRepositoryRoot()const{return m_svnRoot;}
+ /**returns the complete SVN Repository URL*/
+ QString svnRepositoryUrl()const{return m_svnUrl;}
+ /**returns the variable name that will contain the database driver instance*/
+ QString dbInst()const{return m_dbInst;}
+ /**returns the variable name that will contain the database schema object*/
+ QString dbSchema()const{return m_dbSchema;}
+ /**returns the database schema version*/
+ QString dbVersion()const{return m_dbVer;}
+
+ /**returns whether a table exists*/
+ bool hasTable(QString)const;
+ /**returns the requested table*/
+ WocTable table(QString)const;
+
+ /**returns whether a class exists*/
+ bool hasClass(QString)const;
+
+ /**returns a list of transaction names*/
+ QStringList transactionNames()const;
+ /**returns a list of class names*/
+ QStringList classNames()const;
+ /**returns a list of table names*/
+ QStringList tableNames()const;
+
+ /**returns global docu*/
+ QStringList docStrings()const{return m_docstrings;}
+
+ /**returns the qualified names of all privileges*/
+ QStringList privilegeNames()const;
+ signals:
+ void sfinalize();
+ void newClass(const WocClass&);
+ void newTable(const WocTable&);
+ void newTransaction(const WocTransaction&);
+ public slots:
+ void errorFound();
+ private:
+ QString m_baseDir,m_wobDir,m_verComm,m_verNeedComm,m_verHR,m_projname;
+ QString m_svnTarget,m_svnRev,m_svnExe,m_svnRoot,m_svnUrl;
+ QString m_dbInst,m_dbSchema,m_dbVer;
+ QStringList m_docstrings;
+ bool m_error;
+
+ QList<WocTable> m_tables;
+ QList<WocClass> m_classes;
+ QList<WocTransaction> m_transactions;
+
+ static WocProcessor*inst;
+
+ /**helper: calls SVN and parses its output*/
+ void callSvn();
+};
+
+
+#endif
--- /dev/null
+//
+// C++ Implementation: qtout
+//
+// Description:
+//
+//
+// Author: Konrad Rosenbaum <konrad@silmor.de>, (C) 2009
+//
+// Copyright: See README/COPYING files that come with this distribution
+//
+//
+
+#include "qtout.h"
+
+#include <QDir>
+#include <QDomElement>
+
+//start section of all header files
+static const QByteArray HDRSTART=
+ "//AUTOMATICALLY GENERATED FILE\n"
+ "//DO NOT EDIT THIS FILE DIRECTLY, USE THE XML SOURCE!\n"
+ "#ifndef WOBGEN_%\n"
+ "#define WOBGEN_%\n\n";
+//end section of all header files
+static const QByteArray HDREND="\n//END OF AUTOMATICALLY GENERATED FILE\n#endif\n";
+
+//start section of all source files
+static const QByteArray SRCSTART=
+ "//AUTOMATICALLY GENERATED FILE\n"
+ "//DO NOT EDIT THIS FILE DIRECTLY, USE THE XML SOURCE!\n"
+ "#include \"%.h\"\n"
+ "#include <QDomElement>\n"
+ "#include <QDomDocument>\n";
+//end section of all source files
+static const QByteArray SRCEND="\n//END OF AUTOMATICALLY GENERATED FILE\n";
+
+WocQtClientOut::WocQtClientOut(QDomElement&el)
+{
+ qDebug("Info: creating Qt Client Output Generator.");
+ m_basedir=WocProcessor::instance()->baseDir()+"/"+el.attribute("sourceDir",".");
+ m_subdir=el.attribute("subDir","qtwob");
+ m_clean=str2bool(el.attribute("clean","0"));
+ m_prefix=el.attribute("classPrefix","Wob");
+ //get/create directory
+ QDir d(m_basedir+"/"+m_subdir);
+ if(!d.exists())QDir(".").mkpath(m_basedir+"/"+m_subdir);
+
+ //create project file
+ m_pri.setFileName(m_basedir+"/"+m_subdir+"/"+el.attribute("priInclude","qtwob.pri"));
+ if(!m_pri.open(QIODevice::WriteOnly|QIODevice::Truncate)){
+ qDebug("Error: cannot create Qt project file %s.",m_pri.fileName().toAscii().data());
+ emit errorFound();
+ return;
+ }
+ m_pri.write(QByteArray("#AUTOMATICALLY GENERATED FILE - DONT CHANGE!\n"));
+
+ //create interface class
+ WocProcessor*woc=WocProcessor::instance();
+ QString pn=woc->projectName();
+ m_ifacecpp.setFileName(m_basedir+"/"+m_subdir+"/"+m_prefix+"Interface.cpp");
+ if(!m_ifacecpp.open(QIODevice::WriteOnly|QIODevice::Truncate)){
+ qDebug("Error: cannot create Qt interface file %s.",m_ifacecpp.fileName().toAscii().data());
+ emit errorFound();
+ return;
+ }
+ m_ifacecpp.write(QByteArray(SRCSTART).replace('%',m_prefix+"Interface"));
+ m_iface.setFileName(m_basedir+"/"+m_subdir+"/"+m_prefix+"Interface.h");
+ if(!m_iface.open(QIODevice::WriteOnly|QIODevice::Truncate)){
+ qDebug("Error: cannot create Qt interface file %s.",m_iface.fileName().toAscii().data());
+ emit errorFound();
+ return;
+ }
+ m_iface.write(QByteArray(HDRSTART).replace("%",m_prefix.toAscii()+"INTERFACE_H"));
+ m_iface.write(QByteArray("#include \""+m_prefix.toAscii()+"Include.h\"\n#include \"WInterface.h\"\n"));
+ m_iface.write(QByteArray("#include <QStringList>\n"));
+ m_iface.write(QString("class "+m_prefix+"Interface:public WInterface\n{\n Q_OBJECT\n").toAscii());
+ m_iface.write(QString(" public:\n "+m_prefix+"Interface(QString name=\""+pn+"\"):WInterface(name){}\n").toAscii());
+ m_iface.write(QString(" static "+m_prefix+"Interface*instance(QString name=\""+pn+"\")\n\t{return qobject_cast<"+m_prefix+"Interface*>(WInterface::instance(name));}\n\n").toAscii());
+ m_iface.write(QString(" static QString commVersion(){return \""+woc->verComm()+"\";}\n").toAscii());
+ m_iface.write(QString(" static QString needCommVersion(){return \""+woc->verNeedComm()+"\";}\n").toAscii());
+ m_iface.write(QString(" static QString version(){return \""+woc->verHR()+"\";}\n").toAscii());
+ m_iface.write(QString(" static QString svnVersion(){return \""+woc->svnRevision()+"\";}\n\n").toAscii());
+ m_iface.write(QString(" static QString svnRepositoryRoot(){return \""+woc->svnRepositoryRoot()+"\";}\n\n").toAscii());
+ m_iface.write(QString(" static QString svnRepositoryUrl(){return \""+woc->svnRepositoryUrl()+"\";}\n\n").toAscii());
+
+ //create all includer
+ m_hdr.setFileName(m_basedir+"/"+m_subdir+"/"+m_prefix+"Include.h");
+ if(!m_hdr.open(QIODevice::WriteOnly|QIODevice::Truncate)){
+ qDebug("Error: cannot create Qt header file %s.",m_hdr.fileName().toAscii().data());
+ emit errorFound();
+ return;
+ }
+ m_hdr.write(QByteArray(HDRSTART).replace("%",m_prefix.toAscii()+"INCLUDE_H"));
+ addFile(m_prefix.toAscii()+"Interface");
+}
+
+WocQtClientOut::~WocQtClientOut(){}
+
+void WocQtClientOut::finalize()
+{
+ trnList();
+ m_ifacecpp.write(SRCEND);
+ m_ifacecpp.close();
+ m_iface.write(QByteArray("};\n")+HDREND);
+ m_iface.close();
+ m_pri.write(QByteArray("\n#END OF AUTOGENERATED PRI FILE\n"));
+ m_pri.close();
+ m_hdr.write(HDREND);
+ m_hdr.close();
+ //cleanup directory (remove untouched normal files, assume remainder is harmless)
+ QDir d(m_basedir+"/"+m_subdir);
+ if(m_clean){
+ QStringList ent=d.entryList(QDir::Files);
+ for(int i=0;i<ent.size();i++)
+ if(!MFile::touchedFile(m_basedir+"/"+m_subdir+"/"+ent[i])){
+ qDebug("Info: removing old file %s",ent[i].toAscii().data());
+ d.remove(ent[i]);
+ }
+ }
+}
+
+void WocQtClientOut::newTable(const WocTable&){/*not needed, Qt client is a few levels higher*/}
+
+void WocQtClientOut::newClass(const WocClass&cls)
+{
+ QString cn=m_prefix+"O"+cls.name();
+ QString cna=cn;
+ if(cls.isAbstract("qt"))cna+="Abstract";
+ addFile(cna);
+ MFile hdr(m_basedir+"/"+m_subdir+"/"+cna+".h");
+ MFile src(m_basedir+"/"+m_subdir+"/"+cna+".cpp");
+ if(!hdr.open(QIODevice::WriteOnly|QIODevice::Truncate) ||
+ !src.open(QIODevice::WriteOnly|QIODevice::Truncate)){
+ qDebug("Error: cannot create class files for class %s.",cn.toAscii().data());
+ emit errorFound();
+ return;
+ }
+ //lead in
+ hdr.write(QByteArray(HDRSTART).replace("%",cna.toAscii()));
+ src.write(QByteArray(SRCSTART).replace("%",cna.toAscii()));
+
+ QString hcd;
+ QString scd;
+ //includes
+ hcd="#include \""+cls.clientBaseClass()+".h\"\n#include <QCoreApplication>\n\n";
+ QStringList k=cls.propertyNames();
+ for(int i=0;i<k.size();i++)
+ if(cls.propertyIsObject(k[i]))
+ hcd+="#include \""+m_prefix+"O"+cls.propertyPlainType(k[i])+".h\"\n";
+
+ //class declaration
+ hcd+="class "+cna+":public "+cls.clientBaseClass()+"\n{\n";
+ hdr.write(hcd.toAscii());
+
+ //enums
+ classEnums(cls,hdr,src,cna);
+
+ //properties
+ classProperties(cls,hdr,src);
+
+ //serializer
+ classSerializers(cls,hdr,src,cna);
+
+ //deserializer (constructor)
+ classDeserializer(cls,hdr,src,cna);
+
+ //lead out
+ hdr.write(QByteArray("\n};\n"));
+ hdr.write(QByteArray(HDREND).replace("%",cna.toAscii()));
+ src.write(QByteArray(SRCEND).replace("%",cna.toAscii()));
+}
+
+void WocQtClientOut::classEnums(const WocClass&cls,MFile&hdr,MFile&src,QString cn)
+{
+ QStringList k=cls.enumTypes();
+ if(k.size()==0)return;
+ QString hcd=" public:\n";
+ QString scd;
+ for(int i=0;i<k.size();i++){
+ //type
+ hcd+="\tenum "+k[i]+"{";
+ QList<WocEnum>ev=cls.enumValues(k[i]);
+ if(ev.size()<1){
+ qDebug("Error: enums must have at least one member - class %s enum %s",cls.name().toAscii().data(),k[i].toAscii().data());
+ emit errorFound();
+ return;
+ }
+ for(int j=0;j<ev.size();j++){
+ if(j)hcd+=",";
+ hcd+="\n\t\t"+ev[j].name+"="+QString::number(ev[j].val);
+ }
+ hcd+="\n\t};\n";
+ //string converters
+ hcd+="\tstatic "+k[i]+" str2"+k[i]+"(QString,bool*ok=0);\n";
+ hcd+="\tstatic QString "+k[i]+"2str("+k[i]+");\n";
+ scd+=cn+"::"+k[i]+" "+cn+"::str2"+k[i]+"(QString s,bool*ok)\n{\n";
+ scd+="\ts=s.toLower();if(ok)*ok=true;\n";
+ for(int j=0;j<ev.size();j++){
+ scd+="\tif(s==\""+ev[j].name.toLower()+"\")return "+ev[j].name+";\n";
+ }
+ scd+="\tif(ok)*ok=false;\n\treturn "+ev[0].name+";\n}\n";
+ scd+="QString "+cn+"::"+k[i]+"2str("+k[i]+" e)\n{\n";
+ for(int j=0;j<ev.size();j++){
+ scd+="\tif(e=="+ev[j].name+")return \""+ev[j].name+"\";\n";
+ }
+ scd+="\treturn \"\";\n}\n";
+ //localized string converters
+ hcd+="\tstatic "+k[i]+" locstr2"+k[i]+"(QString,bool*ok=0);\n";
+ hcd+="\tstatic QString "+k[i]+"2locstr("+k[i]+");\n";
+ scd+=cn+"::"+k[i]+" "+cn+"::locstr2"+k[i]+"(QString s,bool*ok)\n{\n";
+ scd+="\ts=s.toLower();if(ok)*ok=true;\n";
+ for(int j=0;j<ev.size();j++){
+ scd+="\tif(s==QCoreApplication::translate(\""+cn+"\",\""+ev[j].name+"\").toLower())return "+ev[j].name+";\n";
+ }
+ scd+="\tif(ok)*ok=false;\n\treturn "+ev[0].name+";\n}\n";
+ scd+="QString "+cn+"::"+k[i]+"2locstr("+k[i]+" e)\n{\n";
+ for(int j=0;j<ev.size();j++){
+ scd+="\tif(e=="+ev[j].name+")return QCoreApplication::translate(\""+cn+"\",\""+ev[j].name+"\");\n";
+ }
+ scd+="\treturn \"\";\n}\n";
+ }
+ hdr.write(hcd.toAscii());
+ src.write(scd.toAscii());
+}
+
+void WocQtClientOut::classProperties(const WocClass&cls,MFile&hdr,MFile&)
+{
+ QStringList k=cls.propertyNames();
+ if(k.size()==0)return;
+ QString hcd,scd;
+ //declare members
+ hcd=" protected:\n";
+ for(int i=0;i<k.size();i++){
+ hcd+="\t"+qttype(cls,k[i])+" mp_"+k[i]+";\n";
+ }
+ //declare getters
+ hcd+=" public:\n";
+ for(int i=0;i<k.size();i++){
+ hcd+="\tvirtual "+qttype(cls,k[i])+" "+k[i]+"()const{return mp_"+k[i]+";}\n";
+ }
+
+ //declare setters
+ for(int i=0;i<k.size();i++){
+ hcd+="\tvirtual void set"+k[i]+"("+qttype(cls,k[i])+" s){mp_"+k[i]+"=s;}\n";
+ if(cls.propertyIsList(k[i])){
+ hcd+="\tvirtual void clear"+k[i]+"(){mp_"+k[i]+".clear();}\n";
+ hcd+="\tvirtual void add"+k[i]+"("+qttype(cls,k[i],false)+" a){mp_"+k[i]+".append(a);}\n";
+ }
+ }
+ //write
+ hdr.write(hcd.toAscii());
+}
+
+QString WocQtClientOut::qttype(const WocClass&cls,QString p,bool dolist)
+{
+ QString r;
+ if(cls.propertyIsList(p)&&dolist)r="QList<";
+ else r="Nullable<";
+ if(cls.propertyIsString(p))r+="QString";else
+ if(cls.propertyIsInt(p))r+="qint64";else
+ if(cls.propertyIsBool(p))r+="bool";else
+ if(cls.propertyIsBlob(p))r+="QByteArray";else
+ if(cls.propertyIsObject(p))r+=m_prefix+"O"+cls.propertyPlainType(p);
+ else r+=cls.propertyPlainType(p);
+ r+=">";
+ return r;
+}
+
+void WocQtClientOut::classDeserializer(const WocClass&cls,MFile&hdr,MFile&src,QString cn)
+{
+ QString hcd,scd;
+ hcd=" public:\n";
+ //this is needed to allow WObjects to be Nullable and some other operations...
+ hcd+="\t"+cn+"(){}\n";
+
+ //implement copiers
+ QStringList k=cls.propertyNames();
+ hcd+="\t"+cn+"(const "+cn+"&);\n";
+ scd+=cn+"::"+cn+"(const "+cn+"&o)\n\t:WObject()\n{\n";
+ for(int i=0;i<k.size();i++)
+ scd+="\tmp_"+k[i]+"=o.mp_"+k[i]+";\n";
+ scd+="}\n";
+ hcd+="\t"+cn+"& operator=(const "+cn+"&);\n";
+ scd+=cn+"& "+cn+"::operator=(const "+cn+"&o)\n{\n";
+ for(int i=0;i<k.size();i++)
+ scd+="\tmp_"+k[i]+"=o.mp_"+k[i]+";\n";
+ scd+="\treturn *this;\n}\n";
+
+ //implement deserializer (as constructor)
+ hcd+="\t"+cn+"(const QDomElement&);\n";
+ scd+=cn+"::"+cn+"(const QDomElement&root)\n\t:WObject()\n{\n";
+ scd+="\tQList<QDomElement> nl;\n";
+ for(int i=0;i<k.size();i++){
+ if(cls.propertyIsList(k[i])){
+ scd+="\tnl=elementsByTagName(root,\""+k[i]+"\");\n";
+ scd+="\tfor(int i=0;i<nl.size();i++){\n\t\tQDomElement el=nl.at(i).toElement();\n";
+ scd+="\t\tif(el.isNull())continue;\n";
+ if(cls.propertyIsInt(k[i])){
+ scd+="\t\tbool b;\n\t\tint ct=el.text().toInt(&b);\n";
+ scd+="\t\tif(b)add"+k[i]+"(ct);\n";
+ scd+="\t\telse throw WDeserializerException(QCoreApplication::translate(\"WobTransaction\",\"Class '%1' property '%2' is integer list, but non-integer was found.\").arg(\""+cn+"\").arg(\""+k[i]+"\"));\n";
+ }else
+ if(cls.propertyIsBool(k[i])){
+ scd+="\t\tadd"+k[i]+"(el.text()==\"yes\");\n";
+ }else
+ if(cls.propertyIsString(k[i])){
+ scd+="\t\tadd"+k[i]+"(el.text());\n";
+ }else
+ if(cls.propertyIsBlob(k[i])){
+ scd+="\t\tadd"+k[i]+"(QByteArray::fromBase64(el.text().toAscii()));\n";
+ }else
+ if(cls.propertyIsEnum(k[i])){
+ scd+="\t\tbool b;\n";
+ QString pt=cls.propertyPlainType(k[i]);
+ scd+="\t\t"+pt+" ct=str2"+pt+"(root.attribute(\""+k[i]+"\"),&b);\n";
+ scd+="\t\tif(b)add"+k[i]+"(ct);\n";
+ scd+="\t\telse throw WDeserializerException(QCoreApplication::translate(\"WobTransaction\",\"Class '%1' property '%2' is enum list, invalid value was found.\").arg(\""+cn+"\").arg(\""+k[i]+"\"));\n";
+ }else
+ if(cls.propertyIsObject(k[i])){
+ scd+="\t\tadd"+k[i]+"("+m_prefix+"O"+cls.propertyPlainType(k[i])+"(el));\n";
+ }else{
+ scd+="#error \"Internal Generator error.\"\n";
+ qDebug("Error: unable to generate code for property %s of type %s.",k[i].toAscii().data(),cls.propertyType(k[i]).toAscii().data());
+ emit errorFound();
+ return;
+ }
+ scd+="\t}\n";
+ }else{
+ //non-list types
+ //attribute stored types
+ if(cls.propertyIsAttribute(k[i])){
+ scd+="\tif(root.hasAttribute(\""+k[i]+"\")){\n";
+ if(cls.propertyIsInt(k[i])){
+ scd+="\t\tbool b;\n\t\tint ct=root.attribute(\""+k[i]+"\").toInt(&b);\n";
+ scd+="\t\tif(b)set"+k[i]+"(ct);\n";
+ scd+="\t\telse throw WDeserializerException(QCoreApplication::translate(\"WobTransaction\",\"Class '%1' property '%2' is integer, but non-integer was found.\").arg(\""+cn+"\").arg(\""+k[i]+"\"));\n";
+ }else
+ if(cls.propertyIsBool(k[i])){
+ scd+="\t\tset"+k[i]+"(root.attribute(\""+k[i]+"\")==\"yes\");\n";
+ }else
+ if(cls.propertyIsString(k[i])){
+ scd+="\t\tset"+k[i]+"(root.attribute(\""+k[i]+"\"));\n";
+ }else
+ if(cls.propertyIsEnum(k[i])){
+ scd+="\t\tbool b;\n";
+ QString pt=cls.propertyPlainType(k[i]);
+ scd+="\t\t"+pt+" ct=str2"+pt+"(root.attribute(\""+k[i]+"\"),&b);\n";
+ scd+="\t\tif(b)set"+k[i]+"(ct);\n";
+ scd+="\t\telse throw WDeserializerException(QCoreApplication::translate(\"WobTransaction\",\"Class '%1' property '%2' is enum, invalid value was found.\").arg(\""+cn+"\").arg(\""+k[i]+"\"));\n";
+ }else{
+ scd+="#error \"Internal Generator error.\"\n";
+ qDebug("Error: unable to generate code for property %s of type %s.",k[i].toAscii().data(),cls.propertyType(k[i]).toAscii().data());
+ emit errorFound();
+ return;
+ }
+ scd+="\t}\n";
+ }else{
+ //element stored types...
+ scd+="\tnl=elementsByTagName(root,\""+k[i]+"\");\n";
+ scd+="\tif(nl.size()>0){\n";
+ if(cls.propertyIsString(k[i])){
+ scd+="\t\tset"+k[i]+"(nl.at(0).toElement().text());\n";
+ }else
+ if(cls.propertyIsBlob(k[i])){
+ scd+="\t\tset"+k[i]+"(QByteArray::fromBase64(nl.at(0).toElement().text().toAscii()));\n";
+ }else
+ if(cls.propertyIsObject(k[i])){
+ scd+="\t\tset"+k[i]+"("+m_prefix+"O"+cls.propertyPlainType(k[i])+"(nl.at(0).toElement()));\n";
+ }else{
+ scd+="#error \"Internal Generator error.\"\n";
+ qDebug("Error: unable to generate code for property %s of type %s.",k[i].toAscii().data(),cls.propertyType(k[i]).toAscii().data());
+ emit errorFound();
+ return;
+ }
+ scd+="\t}\n";
+ }
+ }
+ }
+ scd+="}\n";
+
+ //write it...
+ hdr.write(hcd.toAscii());
+ src.write(scd.toAscii());
+}
+
+void WocQtClientOut::classSerializers(const WocClass&cls,MFile&hdr,MFile&src,QString cn)
+{
+ QString hcd=" public:\n";
+ QString scd;
+ hcd+="\tQString toString();\n";
+ scd+="QString "+cn+"::toString()\n{\n";
+ scd+="\tQDomDocument doc;\n\tdoc.appendChild(toXml(doc));\n";
+ scd+="\treturn doc.toString();\n}\n";
+ hcd+="\tQDomElement toXml(QDomDocument&,QString name=\""+cls.name()+"\");\n";
+ scd+="QDomElement "+cn+"::toXml(QDomDocument&doc,QString name)\n{\n";
+ scd+="\tQDomElement r=doc.createElement(name);\n";
+ QStringList p=cls.propertyNames();
+ for(int j=0;j<p.size();j++){
+ QStringList pv=p[j].split("/",QString::SkipEmptyParts);
+ if(pv.size()<1){
+ qDebug("Error: encountered empty property while creating serializer for class %s.",cls.name().toAscii().data());
+ emit errorFound();
+ return;
+ }
+ QString prop=pv[0];
+ QString var;
+ if(pv.size()>1)var=pv[1];
+ //is it a list
+ if(cls.propertyIsList(prop)){
+ scd+="\tfor(int i=0;i<mp_"+prop+".size();i++){\n";
+ if(cls.propertyIsObject(prop))
+ scd+="\t\tr.appendChild(mp_"+prop+"[i].toXml"+var+"(doc,\""+prop+"\"));\n";
+ else
+ if(cls.propertyIsEnum(prop)){
+ scd+="\t\tQDomElement el=doc.createElement(\""+prop+"\");\n";
+ scd+="\t\tel.appendChild(doc.createTextNode("+cls.propertyPlainType(prop)+"2str(mp_"+prop+"[i])));\n";
+ scd+="\t\tr.appendChild(el);\n";
+ }else
+ if(cls.propertyIsString(prop)){
+ scd+="\t\tQDomElement el=doc.createElement(\""+prop+"\");\n";
+ scd+="\t\tel.appendChild(doc.createTextNode(mp_"+prop+"[i]));\n";
+ scd+="\t\tr.appendChild(el);\n";
+ }else
+ if(cls.propertyIsBool(prop)){
+ scd+="\t\tQDomElement el=doc.createElement(\""+prop+"\");\n";
+ scd+="\t\tel.appendChild(doc.createTextNode(mp_"+prop+"[i]?\"yes\":\"no\"));\n";
+ scd+="\t\tr.appendChild(el);\n";
+ }else
+ if(cls.propertyIsBlob(prop)){
+ scd+="\t\tQDomElement el=doc.createElement(\""+prop+"\");\n";
+ scd+="\t\tel.appendChild(doc.createTextNode(mp_"+prop+"[i].toBase64()));\n";
+ scd+="\t\tr.appendChild(el);\n";
+ }else
+ if(cls.propertyIsInt(prop)){
+ scd+="\t\tQDomElement el=doc.createElement(\""+prop+"\");\n";
+ scd+="\t\tel.appendChild(doc.createTextNode(QString::number(mp_"+prop+"[i])));\n";
+ scd+="\t\tr.appendChild(el);\n";
+ }else{
+ qDebug("Error: cannot generate serializer for class %s property %s.",cls.name().toAscii().data(),prop.toAscii().data());
+ emit errorFound();
+ return;
+ }
+ scd+="\t}\n";
+ }else{
+ //non lists
+ scd+="\tif(!mp_"+prop+".isNull()){\n";
+ if(cls.propertyIsAttribute(prop)){
+ if(cls.propertyIsBool(prop))
+ scd+="\t\tr.setAttribute(\""+prop+"\",mp_"+prop+".value()?\"yes\":\"no\");\n";
+ else
+ scd+="\t\tr.setAttribute(\""+prop+"\",mp_"+prop+".value());\n";
+ }else{
+ if(cls.propertyIsObject(prop)){
+ scd+="\t\tr.appendChild(mp_"+prop+".value().toXml"+var+"(doc,\""+prop+"\"));\n";
+ }else
+ if(cls.propertyIsString(prop)){
+ scd+="\t\tQDomElement el=doc.createElement(\""+prop+"\");\n";
+ scd+="\t\tel.appendChild(doc.createTextNode(mp_"+prop+".value()));\n";
+ scd+="\t\tr.appendChild(el);\n";
+ }else
+ if(cls.propertyIsBlob(prop)){
+ scd+="\t\tQDomElement el=doc.createElement(\""+prop+"\");\n";
+ scd+="\t\tel.appendChild(doc.createTextNode(mp_"+prop+".value().toBase64()));\n";
+ scd+="\t\tr.appendChild(el);\n";
+ }else{
+ qDebug("Error: cannot generate serializer for class %s property %s.",cls.name().toAscii().data(),prop.toAscii().data());
+ emit errorFound();
+ return;
+ }
+ }
+ scd+="\t}\n";
+ }
+ }
+ scd+="\treturn r;\n}\n";
+ hdr.write(hcd.toAscii());
+ src.write(scd.toAscii());
+}
+
+void WocQtClientOut::newTransaction(const WocTransaction&trn)
+{
+ QString cn=m_prefix+"T"+trn.name();
+ addFile(cn);
+ MFile hdr(m_basedir+"/"+m_subdir+"/"+cn+".h");
+ MFile src(m_basedir+"/"+m_subdir+"/"+cn+".cpp");
+ if(!hdr.open(QIODevice::WriteOnly|QIODevice::Truncate) ||
+ !src.open(QIODevice::WriteOnly|QIODevice::Truncate)){
+ qDebug("Error: cannot create class files for transaction %s.",cn.toAscii().data());
+ emit errorFound();
+ return;
+ }
+ //basics
+ QStringList in=trn.inputNames();
+ QStringList out=trn.outputNames();
+ //lead in
+ hdr.write(QByteArray(HDRSTART).replace("%",cn.toAscii()));
+ src.write(QByteArray(SRCSTART).replace("%",cn.toAscii()));
+ QString hcd;
+ QString scd;
+ hcd="#include \"WTransaction.h\"\n";
+ scd+="#include \"WInterface.h\"\n#include <QCoreApplication>\n";
+ for(int i=0;i<in.size();i++){
+ QString tp=qtobjtype(trn,in[i],In);
+ if(tp!="")hcd+="#include <"+tp+".h>\n";
+ }
+ for(int i=0;i<out.size();i++){
+ QString tp=qtobjtype(trn,out[i],Out);
+ if(tp!="")hcd+="#include <"+tp+".h>\n";
+ }
+ hcd+="\nclass "+cn+":public WTransaction\n{\n";
+ hdr.write(hcd.toAscii());
+
+ //create properties
+ QString inlist,clist;
+ hcd=" private:\n";
+ for(int i=0;i<in.size();i++){
+ hcd+="\t"+qttype(trn,in[i],In)+"in_"+in[i]+";\n";
+ if(i){inlist+=",";clist+=",";}
+ inlist+="const "+qttype(trn,in[i],In)+"&a"+in[i];
+ clist+="a"+in[i];
+ }
+ for(int i=0;i<out.size();i++)
+ hcd+="\t"+qttype(trn,out[i],Out)+"out_"+out[i]+";\n";
+ hdr.write(hcd.toAscii());
+
+ //query method decl
+ hdr.write(QByteArray("\tvoid netquery();\n"));
+
+ //global interface code
+ QString sif=" "+cn+" query"+trn.name()+"("+inlist+")\n\t";
+ sif+="{return "+cn+"::query("+clist+(clist!=""?",":"")+"name());}\n";
+ m_iface.write(sif.toAscii());
+
+ //create constructors
+ if(inlist!="")inlist+=",";
+ inlist+="QString iface";
+ if(clist!="")clist+=",";
+ clist+="iface";
+ QString defparm="=\""+WocProcessor::instance()->projectName()+"\"";
+ //define parametric constructor
+ hcd=" public:\n";
+ hcd+="\t"+cn+"("+inlist+defparm+");\n";
+ //parametric constructor implementation
+ scd+=cn+"::"+cn+"("+inlist+")\n\t:WTransaction(iface)\n{\n";
+ for(int i=0;i<in.size();i++){
+ scd+="\tin_"+in[i]+"=a"+in[i]+";\n";
+ }
+ scd+="}\n\n";
+ //decl copy constructor
+ hcd+="\t"+cn+"(const "+cn+"&);\n";
+ //copy constructor implementation
+ scd+=cn+"::"+cn+"(const "+cn+"&t)\n\t:WTransaction(t)\n{\n";
+ for(int i=0;i<in.size();i++){
+ scd+="\tin_"+in[i]+"=t.in_"+in[i]+";\n";
+ }
+ scd+="}\n\n";
+ //decl copy operator
+ hcd+="\t"+cn+"& operator=(const "+cn+"&);\n";
+ //copy operator implemented
+ scd+=cn+"& "+cn+"::operator=(const "+cn+"&t)\n{\n";
+ scd+="\tWTransaction::operator=(t);\n";
+ for(int i=0;i<in.size();i++){
+ scd+="\tin_"+in[i]+"=t.in_"+in[i]+";\n";
+ }
+ for(int i=0;i<out.size();i++){
+ scd+="\tout_"+out[i]+"=t.out_"+out[i]+";\n";
+ }
+ scd+="\treturn *this;\n}\n\n";
+
+ //query method implemented
+ scd+="void "+cn+"::netquery()\n{\n";
+ scd+="\tWTLog log(this,\""+trn.name()+"\");\n";
+ scd+="\tQDomDocument doc;QDomElement root=doc.createElement(\"WobRequest\");\n";
+ scd+="\tQDomElement tmp;\n";
+ scd+="\tWInterface *iface=WInterface::instance(m_iface);\n";
+ scd+="\tif(iface==0){m_errtype=\"_iface\";m_errstr=\"interface not found\";m_stage=Error;log.setError(m_errstr);return;}\n";
+ //encode input
+ scd+=trnInput(trn);
+ scd+="\tdoc.appendChild(root);\n";
+ //query
+ scd+="\tQByteArray rba=executeQuery(\""+trn.name()+"\",doc.toByteArray());\n";
+ //decode output
+ scd+=trnOutput(trn);
+ scd+="}\n";
+ hdr.write(hcd.toAscii());
+ src.write(scd.toAscii());
+
+
+ //create getters
+ hcd="";
+ for(int i=0;i<out.size();i++){
+ QString tp=qttype(trn,out[i],Out);
+ hcd+="\t"+tp+" get"+out[i]+"(){return out_"+out[i]+";}\n";
+ }
+ //create queries
+ scd="";
+ hcd+="\tstatic "+cn+" query("+inlist+defparm+");\n";
+ scd+=cn+" "+cn+"::query("+inlist+")\n{\n";
+ scd+="\t"+cn;
+ if(clist!="")scd+=" r("+clist+");\n";else scd+=" r;";
+ scd+="\tr.netquery();\n\treturn r;\n}\n";
+
+ //lead out
+ hdr.write(hcd.toAscii());
+ src.write(scd.toAscii());
+ hdr.write(QByteArray("\n};\n"));
+ hdr.write(QByteArray(HDREND).replace("%",cn.toAscii()));
+ src.write(QByteArray(SRCEND).replace("%",cn.toAscii()));
+}
+
+QString WocQtClientOut::trnInput(const WocTransaction&trn)
+{
+ QString code="\t/*start of input encoding*/\n";
+ QStringList sl=trn.inputNames();
+ for(int i=0;i<sl.size();i++){
+ QString t=trn.inputType(sl[i]);
+ if(trn.isAttributeType(t)){
+ code+="\troot.setAttribute(\""+sl[i]+"\",in_"+sl[i];
+ if(trn.isBoolType(t))
+ code+="?\"yes\":\"no\"";
+ code+=");\n";
+ }else{
+ if(trn.isListType(t)){
+ QString pt=trn.plainType(t);
+ code+="\tfor(int i=0;i<in_"+sl[i]+".size();i++){\n";
+ if(trn.isObjectType(t)){
+ code+="\t\ttmp=in_"+sl[i]+"[i].toXml(doc,\""+sl[i]+"\");\n";
+ }else{
+ code+="\t\ttmp=doc.createElement(\""+sl[i]+"\");\n";
+ code+="\t\ttmp.appendChild(doc.createTextNode(";
+ if(trn.isIntType(t))
+ code+="QString::number(in_"+sl[i]+"[i])";
+ else
+ if(trn.isBoolType(t))
+ code+="in_"+sl[i]+"[i]?\"yes\":\"no\"";
+ else
+ if(trn.isBlobType(t))
+ code+="in_"+sl[i]+".toBase64()";
+ else
+ code+="in_"+sl[i]+"[i]";
+ code+="));\n";
+ }
+ code+="\t\troot.appendChild(tmp);\n";
+ code+="\t}\n";
+ }else{
+ if(trn.isObjectType(t)){
+ code+="\troot.appendChild(in_"+sl[i]+".toXml(doc,\""+sl[i]+"\"));\n";
+ }else{
+ code+="\ttmp=doc.createElement(\""+sl[i]+"\");\n";
+ code+="\ttmp.appendChild(doc.createTextNode(";
+ if(trn.isIntType(t))
+ code+="QString::number(in_"+sl[i]+")";
+ else
+ if(trn.isBlobType(t))
+ code+="in_"+sl[i]+".toBase64()";
+ else
+ code+="in_"+sl[i];
+ code+="));\n\troot.appendChild(tmp);\n";
+ }
+ }
+ }
+ }
+ code+="\t/*end of input encoding*/\n";
+ return code;
+}
+
+QString WocQtClientOut::trnOutput(const WocTransaction&trn)
+{
+ QStringList sl=trn.outputNames();
+ QString code="\t/*start of output decoding*/\n";
+ //basic XML parsing
+ code+="\tif(rba.isEmpty())return;\n";
+ code+="\tdoc=QDomDocument();\n";
+ code+="\tQString emsg;int eln,ecl;\n";
+ code+="\tif(!doc.setContent(rba,&emsg,&eln,&ecl)){\n";
+ code+="\t\tm_stage=Error;m_errtype=\"_iface\";m_errstr=QString(QCoreApplication::translate(\"WobTransaction\",\"XML result parser error line %1 col %2: %3\")).arg(eln).arg(ecl).arg(emsg);\n\t\tlog.setError(m_errstr);\n\t\treturn;\n\t}\n";
+ code+="\troot=doc.documentElement();\n";
+ //decide where to go, error handling
+ code+="\tif(m_wobstatus!=\"ok\"){\n\t\tm_stage=Error;m_errtype=\"_server\";m_errstr=\"unknown server error\";\n";
+ code+="\t\tQList<QDomElement> nl=elementsByTagName(root,\"Error\");\n";
+ code+="\t\tif(nl.size()==0){\n\t\t\tlog.setError(m_errstr);\n\t\t\treturn;\n\t\t}\n";
+ code+="\t\ttmp=nl.at(0).toElement();\n";
+ code+="\t\tm_errtype=tmp.attribute(\"type\",\"_server\");\n";
+ code+="\t\tm_errstr=tmp.text();\n\t\tlog.setError(m_errstr);\n\t\treturn;\n\t}\n";
+ code+="\tQList<QDomElement> nl;\n";
+ //parse parameters
+ for(int i=0;i<sl.size();i++){
+ QString t=trn.outputType(sl[i]);
+ if(trn.isAttributeType(t)){
+ code+="\tout_"+sl[i]+"=root.attribute(\""+sl[i]+"\")";
+ if(trn.isIntType(t))code+=".toInt()";else
+ if(trn.isBoolType(t))code+="==\"yes\"";
+ code+=";\n";
+ }else{
+ code+="\tnl=elementsByTagName(root,\""+sl[i]+"\");\n";
+ if(trn.isListType(t)){
+ code+="\tfor(int i=0;i<nl.size();i++){\n";
+ if(trn.isObjectType(t)){
+ code+="\t\ttry{out_"+sl[i]+".append("+qtobjtype(trn,sl[i],Out)+"(nl.at(i).toElement()));}catch(WException e){m_stage=Error;m_errtype=e.component();m_errstr=e.error();log.setError(m_errstr);}\n";
+ }else if(trn.isIntType(t)){
+ code+="\t\tout_"+sl[i]+".append(nl.at(i).toElement().text().toInt());\n";
+ }else if(trn.isBoolType(t)){
+ code+="\t\tout_"+sl[i]+".append(nl.at(i).toElement().text()==\"yes\");\n";
+ }else if(trn.isBlobType(t)){
+ code+="\t\tout_"+sl[i]+".append(QByteArray::fromBase64(nl.at(i).toElement().text().toAscii()));\n";
+ }else{//can only be string
+ code+="\t\tout_"+sl[i]+".append(nl.at(i).toElement().text());\n";
+ }
+ code+="\t}\n";
+ }else{
+ code+="\tif(nl.size()>0){\n";
+ if(trn.isObjectType(t)){
+ code+="\t\ttry{out_"+sl[i]+"="+qtobjtype(trn,sl[i],Out)+"(nl.at(0).toElement());}catch(WException e){m_stage=Error;m_errtype=e.component();m_errstr=e.error();log.setError(m_errstr);}\n";
+ }else if(trn.isBlobType(t)){
+ code+="\t\tout_"+sl[i]+"=QByteArray::fromBase64(nl.at(0).toElement().text().toAscii());\n";
+ }else{//can only be string
+ code+="\t\tout_"+sl[i]+"=nl.at(0).toElement().text();\n";
+ }
+ code+="\t}\n";
+ }
+ }
+ }
+ code+="\t/*end of output*/\n";
+ return code;
+}
+
+void WocQtClientOut::trnList()
+{
+ QString code;
+ //header
+ code+=" enum Right {\n NoRight";
+ QStringList r=WocProcessor::instance()->transactionNames();
+ QStringList p=WocProcessor::instance()->privilegeNames();
+ QStringList pp=p;
+ for(int i=0;i<r.size();i++)
+ code+=",\n R"+r[i];
+ for(int i=0;i<p.size();i++)
+ code+=",\n P"+pp[i].replace(':',"_");
+ code+="\n };\n";
+ code+=" static QString rightToString(Right);\n";
+ code+=" static QString rightToLocalString(Right);\n";
+ code+=" static Right stringToRight(QString);\n";
+ code+=" static QStringList allKnownRightsString();\n";
+ code+=" static QList<Right> allKnownRights();\n";
+ m_iface.write(code.toAscii());
+
+ code="QString "+m_prefix+"Interface::rightToString(Right r)\n{\n\tswitch(r){\n";
+ for(int i=0;i<r.size();i++)
+ code+="\t\tcase R"+r[i]+":return \""+r[i]+"\";\n";
+ for(int i=0;i<p.size();i++)
+ code+="\t\tcase P"+pp[i]+":return \""+p[i]+"\";\n";
+ code+="\t\tdefault:return \"\";\n\t}\n}\n";
+ code+="QString "+m_prefix+"Interface::rightToLocalString(Right r)\n{\n\tswitch(r){\n";
+ for(int i=0;i<r.size();i++)
+ code+="\t\tcase R"+r[i]+":return tr(\""+r[i]+"\");\n";
+ for(int i=0;i<p.size();i++)
+ code+="\t\tcase P"+pp[i]+":return tr(\""+p[i]+"\");\n";
+ code+="\t\tdefault:return \"\";\n\t}\n}\n";
+ code+=m_prefix+"Interface::Right "+m_prefix+"Interface::stringToRight(QString s)\n{\n";
+ for(int i=0;i<r.size();i++)
+ code+="\tif(s==\""+r[i]+"\")return R"+r[i]+";else\n";
+ for(int i=0;i<p.size();i++)
+ code+="\tif(s==\""+p[i]+"\")return P"+pp[i]+";else\n";
+ code+="\treturn NoRight;\n}\n";
+ code+="QList<"+m_prefix+"Interface::Right> "+m_prefix+"Interface::allKnownRights()\n{\n";
+ code+="\tQList<Right> ret;ret";
+ for(int i=0;i<r.size();i++)
+ code+="<<R"+r[i];
+ for(int i=0;i<p.size();i++)
+ code+="<<P"+pp[i];
+ code+=";\n\treturn ret;\n}\n";
+ code+="QStringList "+m_prefix+"Interface::allKnownRightsString()\n{\n";
+ code+="\tQStringList ret;ret";
+ for(int i=0;i<r.size();i++)
+ code+="<<\""+r[i]+"\"";
+ for(int i=0;i<p.size();i++)
+ code+="<<\""+p[i]+"\"";
+ code+=";\n\treturn ret;\n}\n";
+ m_ifacecpp.write(code.toAscii());
+}
+
+QString WocQtClientOut::qttype(const WocTransaction&trn,QString v,InOut io)
+{
+ QString tp=io==In?trn.inputType(v):trn.outputType(v);
+ QString r,e;
+ if(tp.startsWith("List:")){
+ r="QList<";e=">";
+ tp=tp.mid(5);
+ }else
+ if(io==Out){
+ r="Nullable<";
+ e=">";
+ }
+ if(tp=="astring" || tp=="string")r+="QString";else
+ if(tp=="int"||tp=="int32"||tp=="int64")r+="qint64";else
+ if(tp=="blob")r+="QByteArray";else
+ if(tp=="bool")r+="bool";else
+ if(tp==""){
+ qDebug("Warning: the final type of property %s is empty!",v.toAscii().data());
+ r+="void";
+ }else r+=m_prefix+"O"+tp.split("/",QString::SkipEmptyParts).at(0);
+ r+=e;r+=" ";
+ return r;
+}
+
+QString WocQtClientOut::qtobjtype(const WocTransaction&trn,QString v,InOut io)
+{
+ QString tp=io==In?trn.inputType(v):trn.outputType(v);
+ if(tp.startsWith("List:"))
+ tp=tp.mid(5);
+ if(tp=="astring" || tp=="string" || tp=="int" || tp=="int32" || tp=="int64" || tp=="bool" || tp=="blob")
+ return "";
+ else
+ return m_prefix+"O"+tp;
+}
+
+void WocQtClientOut::addFile(QString bn)
+{
+ QString code="HEADERS+="+m_subdir+"/"+bn+".h\nSOURCES+="+m_subdir+"/"+bn+".cpp\n";
+ m_pri.write(code.toAscii());
+ m_hdr.write(QByteArray("#include \"%.h\"\n").replace('%',bn.toAscii()));
+}
\ No newline at end of file
--- /dev/null
+//
+// C++ Interface: qtout
+//
+// Description:
+//
+//
+// Author: Konrad Rosenbaum <konrad@silmor.de>, (C) 2009
+//
+// Copyright: See README/COPYING files that come with this distribution
+//
+//
+
+#ifndef WOC_QTOUT_H
+#define WOC_QTOUT_H
+
+#include "processor.h"
+
+#include "mfile.h"
+
+class QDomElement;
+
+class WocQtClientOut:public WocOutput
+{
+ public:
+ WocQtClientOut(QDomElement&);
+ ~WocQtClientOut();
+ protected:
+ virtual void finalize();
+ virtual void newClass(const WocClass&);
+ virtual void newTable(const WocTable&);
+ virtual void newTransaction(const WocTransaction&);
+ private:
+ QString m_basedir,m_subdir,m_prefix;
+ MFile m_pri,m_iface,m_ifacecpp,m_hdr;
+ bool m_clean;
+
+ /**helper: adds a file to the project file*/
+ void addFile(QString basename);
+ /**helper: generate enums for classes*/
+ void classEnums(const WocClass&,MFile&,MFile&,QString);
+ /**helper: generate properties*/
+ void classProperties(const WocClass&,MFile&,MFile&);
+ /**helper: generate constructors/deserializer/copiers*/
+ void classDeserializer(const WocClass&,MFile&,MFile&,QString);
+ /**helper: generate serializers*/
+ void classSerializers(const WocClass&,MFile&,MFile&,QString);
+ /**helper: generate a proper Qt type for a property*/
+ QString qttype(const WocClass&,QString,bool dolist=true);
+
+ enum InOut{In,Out};
+ /**helper: generate a proper QT type for a transaction variable*/
+ QString qttype(const WocTransaction&,QString,InOut);
+ /**helper: generate a proper QT type for a transaction variable, WO* only */
+ QString qtobjtype(const WocTransaction&,QString,InOut);
+
+ /**helper generates the transaction input encoding*/
+ QString trnInput(const WocTransaction&);
+ /**helper generates the transaction output decoding*/
+ QString trnOutput(const WocTransaction&);
+ /**helper generates enums and strings for all transactions*/
+ void trnList();
+};
+
+#endif
--- /dev/null
+//
+// C++ Implementation: woc
+//
+// Description:
+//
+//
+// Author: Konrad Rosenbaum <konrad@silmor.de>, (C) 2009
+//
+// Copyright: See README/COPYING files that come with this distribution
+//
+//
+
+#include <QCoreApplication>
+#include <QStringList>
+
+#include "processor.h"
+
+int main(int argc,char**argv)
+{
+ QCoreApplication app(argc,argv);
+ //get arguments
+ QStringList args=app.arguments();
+ args.removeFirst();
+ //process files
+ WocProcessor proc;
+ for(int i=0;i<args.size();i++)
+ if(!proc.processFile(args[i])){
+ qDebug("aborting scan.");
+ return 1;
+ }
+ //call finalizer
+ proc.finalize();
+ qDebug("done.");
+ //return success
+ return 0;
+}
\ No newline at end of file
--- /dev/null
+TEMPLATE=app
+TARGET=../woc/woc
+QT-=gui
+QT+=xml
+CONFIG+=console
+
+#compilation output:
+DESTDIR = ../woc
+OBJECTS_DIR = .ctmp
+MOC_DIR = .ctmp
+RCC_DIR = .ctmp
+
+
+SOURCES+= \
+ processor.cpp \
+ woc.cpp \
+ qtout.cpp \
+ phpout.cpp \
+ htmlout.cpp \
+ mfile.cpp \
+ ../src/misc/domquery.cpp
+HEADERS+= \
+ processor.h \
+ phpout.h \
+ qtout.h \
+ htmlout.h \
+ mfile.h \
+ ../src/misc/domquery.h
+
+INCLUDEPATH += ../src/misc
\ No newline at end of file