woc creates WObjects for qt side
authorkonrad <konrad@6e3c4bff-ac9f-4ac1-96c5-d2ea494d3e33>
Sun, 22 Feb 2009 15:33:09 +0000 (15:33 +0000)
committerkonrad <konrad@6e3c4bff-ac9f-4ac1-96c5-d2ea494d3e33>
Sun, 22 Feb 2009 15:33:09 +0000 (15:33 +0000)
git-svn-id: https://silmor.de/svn/softmagic/smoke/trunk@274 6e3c4bff-ac9f-4ac1-96c5-d2ea494d3e33

16 files changed:
src/phpscan.pri
src/smoke.pro
src/wbase/WObject.cpp [new file with mode: 0644]
src/wbase/WObject.h [new file with mode: 0644]
src/wbase/WTransaction.cpp [new file with mode: 0644]
src/wbase/WTransaction.h [new file with mode: 0644]
src/wbase/exception.h [new file with mode: 0644]
src/wbase/nullable.h
src/wbase/wbase.pri
wob/order.wolf
wob/user.wolf
woc/phpout.cpp
woc/processor.cpp
woc/processor.h
woc/qtout.cpp
woc/qtout.h

index 4f163c5..c5f4b00 100644 (file)
@@ -3,40 +3,77 @@
 #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 \
 
index 83deff3..5fb39bd 100644 (file)
@@ -82,7 +82,7 @@ HEADERS = \
        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 )
@@ -97,5 +97,6 @@ TRANSLATIONS = \
 
 include(../zip/zip.pri)
 include(wbase/wbase.pri)
+include(wob/wob.pri)
 
 LIBS += -lgmp
diff --git a/src/wbase/WObject.cpp b/src/wbase/WObject.cpp
new file mode 100644 (file)
index 0000000..85ad4d2
--- /dev/null
@@ -0,0 +1,13 @@
+//
+// 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
diff --git a/src/wbase/WObject.h b/src/wbase/WObject.h
new file mode 100644 (file)
index 0000000..6e57f15
--- /dev/null
@@ -0,0 +1,36 @@
+//
+// 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
diff --git a/src/wbase/WTransaction.cpp b/src/wbase/WTransaction.cpp
new file mode 100644 (file)
index 0000000..926ba37
--- /dev/null
@@ -0,0 +1,11 @@
+//
+// C++ Implementation: wtransaction
+//
+// Description: 
+//
+//
+// Author: Konrad Rosenbaum <konrad@silmor.de>, (C) 2009
+//
+// Copyright: See README/COPYING files that come with this distribution
+//
+//
diff --git a/src/wbase/WTransaction.h b/src/wbase/WTransaction.h
new file mode 100644 (file)
index 0000000..2f0b656
--- /dev/null
@@ -0,0 +1,25 @@
+//
+// 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
diff --git a/src/wbase/exception.h b/src/wbase/exception.h
new file mode 100644 (file)
index 0000000..59e4c6e
--- /dev/null
@@ -0,0 +1,29 @@
+//
+// 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
index 7a802eb..3b90ed3 100644 (file)
@@ -21,8 +21,8 @@ template<class T>class Nullable
                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;}
                
index cb96ee1..90988ba 100644 (file)
@@ -1 +1,10 @@
-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
index aaa244b..8b2c486 100644 (file)
@@ -92,6 +92,7 @@
                <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
index 119742a..348ffe2 100644 (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
index c505e26..716ebf6 100644 (file)
@@ -39,6 +39,7 @@ WocPHPServerOut::WocPHPServerOut(QString srcDir,QString subDir,QString ext,bool
        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);
@@ -46,6 +47,7 @@ WocPHPServerOut::WocPHPServerOut(QString srcDir,QString subDir,QString ext,bool
        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);
@@ -76,6 +78,7 @@ void WocPHPServerOut::newTable(const WocTable&tbl)
        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);
@@ -224,13 +227,14 @@ void WocPHPServerOut::newClass(const WocClass&cls)
        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
index a1e8dec..ee29475 100644 (file)
@@ -47,6 +47,7 @@ WocProcessor::WocProcessor()
        m_svnExe="svn";
        m_dbInst="dbInst";
        m_dbSchema="dbSchema";
+       m_error=false;
        
        inst=this;
 }
@@ -75,6 +76,7 @@ bool WocProcessor::processFile(QString fn)
        }
        //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;
@@ -86,6 +88,7 @@ bool WocProcessor::processFile(QString fn)
                        if(cls.isValid()){
                                m_classes.append(cls);
                                emit newClass(cls);
+                               if(m_error)return false;
                        }else
                                return false;
                }else
@@ -94,6 +97,7 @@ bool WocProcessor::processFile(QString fn)
                        if(tbl.isValid()){
                                m_tables.append(tbl);
                                emit newTable(tbl);
+                               if(m_error)return false;
                        }else
                                return false;
                }else
@@ -102,6 +106,7 @@ bool WocProcessor::processFile(QString fn)
                        if(trn.isValid()){
                                m_transactions.append(trn);
                                emit newTransaction(trn);
+                               if(m_error)return false;
                        }else
                                return false;
                }else
@@ -124,10 +129,12 @@ bool WocProcessor::processFile(QString fn)
                                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"))
@@ -242,6 +249,11 @@ bool WocProcessor::hasClass(QString n)const
        return false;
 }
 
+void WocProcessor::errorFound()
+{
+       m_error=true;
+}
+
 
 /******************************************************************************
  * WocOutput
@@ -253,6 +265,7 @@ WocOutput::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(){}
@@ -285,7 +298,8 @@ WocClass::WocClass(const QDomElement&cls)
                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++){
@@ -804,3 +818,144 @@ bool WocTable::haveForeign(QString f)const
                        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 "";
+}
index 2ce2e0f..fa39f5b 100644 (file)
@@ -33,8 +33,10 @@ class WocClass
                
                /**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;
@@ -93,7 +95,7 @@ class WocClass
                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;
@@ -111,38 +113,64 @@ class WocClass
                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;
@@ -157,61 +185,132 @@ class WocTable
                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;
@@ -219,6 +318,7 @@ class WocProcessor:public QObject
                
                static WocProcessor*inst;
                
+               /**helper: calls SVN and parses its output*/
                void callSvn();
 };
 
index 9c2c412..21390de 100644 (file)
 
 #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
index 9c438e7..a487c37 100644 (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