#use genphpscan.sh to regenerate it!
HEADERS += \
-../www/inc/global_functions.php \
-../www/inc/tr.php \
-../www/inc/global_variables.php \
+../www/inc/db/db_mysql.php \
../www/inc/db/db_scheme.php \
../www/inc/db/db.php \
-../www/inc/db/db_mysql.php \
-../www/inc/machine/template.php \
+../www/inc/wob/wt_cart_ticket.php \
+../www/inc/wob/wt_users.php \
+../www/inc/wob/wt_cart.php \
+../www/inc/wob/wo_Voucher.php \
+../www/inc/wob/wt_host.php \
+../www/inc/wob/wt_room.php \
+../www/inc/wob/wt_moneylog.php \
+../www/inc/wob/wt_customer.php \
+../www/inc/wob/wo_CartVoucher.php \
+../www/inc/wob/wt_webuser.php \
+../www/inc/wob/wt_shipping.php \
+../www/inc/wob/wt_websession.php \
+../www/inc/wob/wt_voucher.php \
+../www/inc/wob/wt_event.php \
+../www/inc/wob/wo_CartOrder.php \
+../www/inc/wob/wt_order.php \
+../www/inc/wob/autoload.php \
+../www/inc/wob/wt_session.php \
+../www/inc/wob/wo_Order.php \
+../www/inc/wob/wt_template.php \
+../www/inc/wob/wt_userhosts.php \
+../www/inc/wob/wo_User.php \
+../www/inc/wob/wt_userrole.php \
+../www/inc/wob/wo_Ticket.php \
+../www/inc/wob/wo_CartTicket.php \
+../www/inc/wob/wt_cart_voucher.php \
+../www/inc/wob/wt_config.php \
+../www/inc/wob/schema.php \
+../www/inc/wob/wt_ticket.php \
+../www/inc/wbase/exception.php \
+../www/inc/wbase/object.php \
+../www/inc/wbase/autoload.php \
+../www/inc/wbase/table.php \
+../www/inc/wbase/schema.php \
+../www/inc/loader_nonadmin.php \
+../www/inc/listing.php \
+../www/inc/machine/cauth_hash.php \
../www/inc/machine/version.php \
-../www/inc/machine/cauth_string.php \
../www/inc/machine/host.php \
../www/inc/machine/cauth_mhash.php \
-../www/inc/machine/cauth_hash.php \
../www/inc/machine/session.php \
-../www/inc/rendering/cart_listing.php \
+../www/inc/machine/template.php \
+../www/inc/machine/cauth_string.php \
+../www/inc/global_variables.php \
+../www/inc/loader.php \
+../www/inc/global_functions.php \
+../www/inc/tr.php \
../www/inc/rendering/event_listing.php \
-../www/inc/rendering/order_listing.php \
+../www/inc/rendering/cart_listing.php \
../www/inc/rendering/submit.php \
-../www/inc/loader.php \
-../www/inc/listing.php \
-../www/inc/classes/websession.php \
+../www/inc/rendering/order_listing.php \
../www/inc/classes/random.php \
-../www/inc/classes/room.php \
-../www/inc/classes/ticket.php \
-../www/inc/classes/cart.php \
../www/inc/classes/parser.php \
-../www/inc/classes/language_manager.php \
../www/inc/classes/customer.php \
-../www/inc/classes/error.php \
+../www/inc/classes/language_manager.php \
+../www/inc/classes/ticket.php \
../www/inc/classes/event.php \
-../www/inc/classes/config_manager.php \
../www/inc/classes/order.php \
+../www/inc/classes/config_manager.php \
+../www/inc/classes/cart.php \
+../www/inc/classes/room.php \
../www/inc/classes/voucher.php \
-../www/inc/loader_nonadmin.php \
+../www/inc/classes/websession.php \
+../www/inc/classes/error.php \
+../www/test.php \
../www/admin.php \
-../www/index.php \
+../www/config.php \
../www/machine.php \
+../www/index.php \
+../www/info.php \
moneylog.h \
autoupdate.h \
domquery.h
-
+
#some PHP files are listed in this file to scan them for translatable items
#use genphpscan.sh to regenerate it.
include( phpscan.pri )
include(../zip/zip.pri)
include(wbase/wbase.pri)
+include(wob/wob.pri)
LIBS += -lgmp
--- /dev/null
+//
+// C++ Implementation: wobject
+//
+// Description:
+//
+//
+// Author: Konrad Rosenbaum <konrad@silmor.de>, (C) 2009
+//
+// Copyright: See README/COPYING files that come with this distribution
+//
+//
+
+#include "WObject.h"
\ No newline at end of file
--- /dev/null
+//
+// C++ Interface: wobject
+//
+// Description:
+//
+//
+// Author: Konrad Rosenbaum <konrad@silmor.de>, (C) 2009
+//
+// Copyright: See README/COPYING files that come with this distribution
+//
+//
+
+#ifndef WOLF_WOBJECT_H
+#define WOLF_WOBJECT_H
+
+#include <QObject>
+#include <QList>
+
+#include "nullable.h"
+#include "exception.h"
+
+class QDomElement;
+
+class WObject:public QObject
+{
+ protected:
+ WObject(){}
+};
+
+class WDeserializerException:public WException
+{
+ public:
+ WDeserializerException(QString e):WException(e,"Deserializer"){}
+};
+
+#endif
--- /dev/null
+//
+// C++ Implementation: wtransaction
+//
+// Description:
+//
+//
+// Author: Konrad Rosenbaum <konrad@silmor.de>, (C) 2009
+//
+// Copyright: See README/COPYING files that come with this distribution
+//
+//
--- /dev/null
+//
+// C++ Interface: wtransaction
+//
+// Description:
+//
+//
+// Author: Konrad Rosenbaum <konrad@silmor.de>, (C) 2009
+//
+// Copyright: See README/COPYING files that come with this distribution
+//
+//
+
+#ifndef WOLF_TRANSACTION_H
+#define WOLF_TRANSACTION_H
+
+#include <QObject>
+#include <QList>
+
+#include "nullable.h"
+
+class WTransaction:public QObject
+{
+};
+
+#endif
--- /dev/null
+//
+// C++ Interface: exception
+//
+// Description:
+//
+//
+// Author: Konrad Rosenbaum <konrad@silmor.de>, (C) 2009
+//
+// Copyright: See README/COPYING files that come with this distribution
+//
+//
+
+#ifndef WOLF_EXCEPTION_H
+#define WOLF_EXCEPTION_H
+
+#include <QString>
+
+class WException
+{
+ protected:
+ WException(QString e,QString c){err=e;comp=c;}
+
+ QString error()const{return err;}
+ QString component()const{return comp;}
+ private:
+ QString err,comp;
+};
+
+#endif
Nullable(const T&t){isnull=false;elem=t;}
Nullable(const Nullable<T>&t){isnull=t.isnull;elem=t.elem;}
- Nullable<T>& operator=(const T&t){isnull=false;elem=t;}
- Nullable<T>& operator=(const Nullable<T>&t){isnull=t.isnull;elem=t.elem;}
+ Nullable<T>& operator=(const T&t){isnull=false;elem=t;return *this;}
+ Nullable<T>& operator=(const Nullable<T>&t){isnull=t.isnull;elem=t.elem;return *this;}
bool isNull()const{return isnull;}
-HEADERS += wbase/nullable.h
+HEADERS += \
+ wbase/nullable.h \
+ wbase/WObject.h \
+ wbase/WTransaction.h
+
+SOURCES += \
+ wbase/WObject.cpp \
+ wbase/WTransaction.cpp
+
+INCLUDEPATH += ./wbase ./wob
\ No newline at end of file
<Property name="orderid" type="int"/>
<ToXml name="inOrder">ticketid eventid price status</ToXml>
+ <ToXml name="Full">ticketid eventid price status orderid</ToXml>
<Mapping table="ticket">
<Map column="ticketid"/>
</Class>
<Transaction name="GetTicket">
- <Input name="ticketid" type="astring"/>
- <Output type="Ticket"/>
+ <Input>
+ <Var name="ticketid" type="astring"/>
+ </Input>
+ <Output>
+ <Var name="ticket" type="Ticket/Full"/>
+ </Output>
</Transaction>
-
<Class name="Voucher">
<Enum name="VoucherState">
<Value name="Ok"/>
<!-- etc.pp. -->
<ToXml name="Short">orderid customerid seller amountpaid state amountdue</ToXml>
- <ToXml name="Full">orderid customerid seller amountpaid state amountdue tickets/Full vouchers/Full</ToXml>
+ <ToXml name="Full">orderid customerid seller amountpaid state amountdue tickets/inOrder vouchers/inOrder</ToXml>
</Class>
</Wolf>
\ No newline at end of file
<Column name="timeout" type="int64" notnull="yes"/>
</Table>
+ <Transaction name="ServerInfo" mode="open">
+ <Input>
+ <Call lang="php" method="serverInfoXml2"/>
+ </Input>
+ <Output>
+ <Var name="ServerVersion" type="string"/>
+ <Var name="MinimumProtocolVersion" type="int"/>
+ <Var name="ServerProtocolVersion" type="int"/>
+ </Output>
+ </Transaction>
+
+ <Transaction name="Login" mode="open">
+ <Input>
+ <Var name="username" type="string"/>
+ <Var name="password" type="string"/>
+ </Input>
+ <Output>
+ <Var name="sessionid" type="string"/>
+ </Output>
+ </Transaction>
+
+ <Transaction name="GetMyRoles" mode="auth">
+ <Input/>
+ <Output>
+ <Var name="role" type="List:astring"/>
+ </Output>
+ </Transaction>
+
<Class name="User">
- <Property name="name" column="uname" type="astring"/>
- <Property name="password" column="passwd" type="string"/>
+ <Property name="name" type="astring"/>
+ <Property name="password" type="string"/>
<Property name="description" type="string"/>
</Class>
</Wolf>
\ No newline at end of file
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);
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);
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);
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="class "+cna+" extends "+cls.baseClass()+"{\n\n";
+ QString code="class "+cna+" extends "+cls.serverBaseClass()+"{\n\n";
tf.write(code.toAscii());
//enums
m_svnExe="svn";
m_dbInst="dbInst";
m_dbSchema="dbSchema";
+ m_error=false;
inst=this;
}
}
//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;
if(cls.isValid()){
m_classes.append(cls);
emit newClass(cls);
+ if(m_error)return false;
}else
return false;
}else
if(tbl.isValid()){
m_tables.append(tbl);
emit newTable(tbl);
+ if(m_error)return false;
}else
return false;
}else
if(trn.isValid()){
m_transactions.append(trn);
emit newTransaction(trn);
+ if(m_error)return false;
}else
return false;
}else
m_dbVer=el.attribute("version");
}else
if(tn=="QtClientOutput"){
- new WocQtClientOut(el.attribute("sourceDir","."), el.attribute("subDir","qtwob"), el.attribute("priInclude","qtwob.pri"));
+ new WocQtClientOut(el.attribute("sourceDir","."), el.attribute("subDir","qtwob"), el.attribute("priInclude","qtwob.pri"),str2bool(el.attribute("clean","0")));
+ if(m_error)return false;
}else
if(tn=="PHPServerOutput"){
new WocPHPServerOut(el.attribute("sourceDir","."), el.attribute("subDir","phpwob"), el.attribute("extension",".inc"), str2bool(el.attribute("clean","0")));
+ if(m_error)return false;
}else
if(tn=="Version"){
if(el.hasAttribute("comm"))
return false;
}
+void WocProcessor::errorFound()
+{
+ m_error=true;
+}
+
/******************************************************************************
* WocOutput
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(){}
return;
}
qDebug("Info: parsing class %s",m_name.toAscii().data());
- m_base=cls.attribute("base","WObject");
+ m_sbase=cls.attribute("serverbase","WObject");
+ m_cbase=cls.attribute("clientbase","WObject");
//scan properties
QDomNodeList nl=cls.elementsByTagName("Property");
for(int i=0;i<nl.size();i++){
return true;
return false;
}
+
+
+/******************************************************************************
+ * 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
+ QDomNodeList nl=root.elementsByTagName("Input");
+ for(int i=0;i<nl.size();i++){
+ QDomElement el=nl.at(i).toElement();
+ if(el.isNull())continue;
+ //variables
+ QDomNodeList nl2=el.elementsByTagName("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));
+ }
+ //calls
+ nl2=el.elementsByTagName("Call");
+ for(int j=0;j<nl2.size();j++){
+ QDomElement el2=nl2.at(j).toElement();
+ if(el2.isNull())continue;
+ QString nm=el2.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=el2.attribute("method");
+ m_call.insert(nm,mt);
+ }
+ }
+ //output
+ nl=root.elementsByTagName("Output");
+ for(int i=0;i<nl.size();i++){
+ QDomElement el=nl.at(i).toElement();
+ if(el.isNull())continue;
+ //variables
+ QDomNodeList nl2=el.elementsByTagName("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));
+ }
+ }
+}
+
+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 "";
+}
/**returns the class name*/
QString name()const{return m_name;}
- /**returns the name of the class it is derived from (on the server side)*/
- QString baseClass()const{return m_base;}
+ /**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;
bool m_valid,m_abstract;
//name: class name
//base: name of parent class
- QString m_name,m_base;
+ QString m_name,m_sbase,m_cbase;
//property info
struct s_prop{
QString name,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<QPair<QString,int> > columnEnums(QString)const;
+ /**returns all enum definitions of the table; see also columnEnums */
QList<QPair<QString,int> > 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;}
private:
bool m_valid,m_backup;
QList<QMap<QString,QString> >m_presets;
};
+/**internal representation of a transaction*/
class WocTransaction
{
public:
- WocTransaction(const QDomElement&){}
- bool isValid(){return true;}
+ /**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;}
+
+ private:
+ QString m_name;
+ bool m_valid;
+ AuthMode m_mode;
+ QMap<QString,QString> m_call;
+ QList<QPair<QString,QString> >m_input,m_output;
};
+/**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:
- virtual void finalize()=0;
+ /**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 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 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;
signals:
void sfinalize();
void newClass(const WocClass&);
void newTable(const WocTable&);
void newTransaction(const WocTransaction&);
-
+ private slots:
+ void errorFound();
private:
QString m_baseDir,m_wobDir,m_verComm,m_verNeedComm,m_verHR;
QString m_svnTarget,m_svnRev,m_svnExe,m_dbInst,m_dbSchema,m_dbVer;
+ bool m_error;
QList<WocTable> m_tables;
QList<WocClass> m_classes;
static WocProcessor*inst;
+ /**helper: calls SVN and parses its output*/
void callSvn();
};
#include "qtout.h"
-WocQtClientOut::WocQtClientOut(QString srcDir,QString subDir,QString prifile){}
-void WocQtClientOut::finalize(){}
-void WocQtClientOut::newClass(const WocClass&){}
-void WocQtClientOut::newTable(const WocTable&){}
-void WocQtClientOut::newTransaction(const WocTransaction&){}
+#include <QDir>
+
+WocQtClientOut::WocQtClientOut(QString srcDir,QString subDir,QString prifile,bool clean)
+{
+ qDebug("Info: creating Qt Client Output Generator.");
+ m_basedir=WocProcessor::instance()->baseDir()+"/"+srcDir;
+ m_subdir=subDir;
+ //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 project file
+ m_pri.setFileName(m_basedir+"/"+m_subdir+"/"+prifile);
+ 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"));
+}
+
+WocQtClientOut::~WocQtClientOut(){}
+
+void WocQtClientOut::finalize()
+{
+ m_pri.close();
+}
+
+void WocQtClientOut::newTable(const WocTable&){/*not needed, Qt client is a few levels higher*/}
+
+//start section of all header files
+static const QByteArray HDRSTART=
+ "//AUTOMATICALLY GENERATED FILE\n"
+ "#ifndef WOBGEN_%\n"
+ "#define WOBGEN_%\n\n";
+//end section of all header files
+static const QByteArray HDREND="\n//END OF FILE\n#endif\n";
+
+//start section of all source files
+static const QByteArray SRCSTART=
+ "//AUTOMATICALLY GENERATED FILE\n"
+ "#include \"%.h\"\n"
+ "#include <QDomElement>\n"
+ "#include <QDomNodeList>\n";
+//end section of all source files
+static const QByteArray SRCEND="\n//END OF FILE\n";
+
+void WocQtClientOut::newClass(const WocClass&cls)
+{
+ QString cn="WO"+cls.name();
+ QString cna=cn;
+ if(cls.isAbstract())cna+="Abstract";
+ addFile(cna);
+ QFile hdr(m_basedir+"/"+m_subdir+"/"+cna+".h");
+ QFile 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\n";
+ QStringList k=cls.propertyNames();
+ for(int i=0;i<k.size();i++)
+ if(cls.propertyIsObject(k[i]))
+ hcd+="#include \"WO"+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);
+
+ //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,QFile&hdr,QFile&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<QPair<QString,int> >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].first+"="+QString::number(ev[j].second);
+ }
+ 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].first.toLower()+"\")return "+ev[j].first+";\n";
+ }
+ scd+="\tif(ok)*ok=false;\n\treturn "+ev[0].first+";\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].first+")return \""+ev[j].first+"\";\n";
+ }
+ scd+="\treturn \"\";\n}\n";
+ }
+ hdr.write(hcd.toAscii());
+ src.write(scd.toAscii());
+}
+
+void WocQtClientOut::classProperties(const WocClass&cls,QFile&hdr,QFile&)
+{
+ 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.propertyIsObject(p))r+="WO"+cls.propertyPlainType(p);
+ else r+=cls.propertyPlainType(p);
+ r+=">";
+ return r;
+}
+
+void WocQtClientOut::classDeserializer(const WocClass&cls,QFile&hdr,QFile&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
+ hcd+="\t"+cn+"(const QDomElement&);\n";
+ scd+=cn+"::"+cn+"(const QDomElement&root)\n\t:WObject()\n{\n";
+ scd+="\tQDomNodeList nl;\n";
+ for(int i=0;i<k.size();i++){
+ if(cls.propertyIsList(k[i])){
+ scd+="\tnl=root.elementsByTagName(\""+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(\"Class "+cn+" property "+k[i]+" is integer list, but non-integer was found.\");\n";
+ }else
+ if(cls.propertyIsString(k[i])){
+ scd+="\t\tadd"+k[i]+"(el.text());\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(\"Class "+cn+" property "+k[i]+" is enum list, invalid value was found.\");\n";
+ }else
+ if(cls.propertyIsObject(k[i])){
+ scd+="\t\tadd"+k[i]+"(WO"+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(\"Class "+cn+" property "+k[i]+" is integer, but non-integer was found.\");\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(\"Class "+cn+" property "+k[i]+" is enum, invalid value was found.\");\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=root.elementsByTagName(\""+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.propertyIsObject(k[i])){
+ scd+="\t\tset"+k[i]+"(WO"+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,QFile&hdr,QFile&src)
+{
+ //TODO: implement
+}
+
+void WocQtClientOut::newTransaction(const WocTransaction&trn)
+{
+ QString cn="WT"+trn.name();
+ addFile(cn);
+ QFile hdr(m_basedir+"/"+m_subdir+"/"+cn+".h");
+ QFile 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;
+ }
+ //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\n";
+ hcd+="class "+cn+":public WTransaction\n{\n public:\n";
+ hdr.write(hcd.toAscii());
+
+ //lead out
+ hdr.write(QByteArray("\n};\n"));
+ hdr.write(QByteArray(HDREND).replace("%",cn.toAscii()));
+ src.write(QByteArray(SRCEND).replace("%",cn.toAscii()));
+}
+
+void WocQtClientOut::addFile(QString bn)
+{
+ QString code="HEADERS+="+m_subdir+"/"+bn+".h\nSOURCES+="+m_subdir+"/"+bn+".cpp\n";
+ m_pri.write(code.toAscii());
+}
\ No newline at end of file
#include "processor.h"
+#include <QFile>
+
class WocQtClientOut:public WocOutput
{
public:
- WocQtClientOut(QString srcDir,QString subDir,QString prifile);
+ WocQtClientOut(QString srcDir,QString subDir,QString prifile,bool clean);
+ ~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;
+ QFile m_pri;
+
+ /**helper: adds a file to the project file*/
+ void addFile(QString basename);
+ /**helper: generate enums for classes*/
+ void classEnums(const WocClass&,QFile&,QFile&,QString);
+ /**helper: generate properties*/
+ void classProperties(const WocClass&,QFile&,QFile&);
+ /**helper: generate constructors/deserializer/copiers*/
+ void classDeserializer(const WocClass&,QFile&,QFile&,QString);
+ /**helper: generate serializers*/
+ void classSerializers(const WocClass&,QFile&,QFile&);
+ /**helper: generate a proper Qt type for a property*/
+ QString qttype(const WocClass&,QString,bool dolist=true);
};
#endif