<pre>
<Wolf>
+ <Doc>Documentation...</Doc>
<Project baseDir=".." wobDir="wob"/>
<Version comm="0100" needcomm="0100" humanReadable="1.1 alpha" svnTarget="."/>
</Wolf>
Above the <Project> tag tells woc what the overall project directory is (relative to its current working directory) and where, relative to the baseDir, it will find all wolf files.<p>
+The <Doc> tag can be used to create project documentation. Each tag generates one paragraph. HTML can be embedded by escaping the "<" character as "&lt;".<p>
+
The <Version> tag describes the communication protocol:
<table frame="1" border="1">
<tr><td>base</td><td>optional, contains the class that this tables class is derived from, the base class must be derived from WobTable (default is to derive from WobTable directly)</td></tr>
</table><p>
+The Table tag can have Doc subtags to embed documentation.<p>
+
Column attributes:
<table frame="1" border="1">
<tr><td><b>Attribute</b></td><td><b>Description</b></td></tr>
The Value tags for enum types function similar to enums in C++. If a value attribute is given that value is assigned to the enum symbol, if no value is given the previous one is increased by one (the first value is 0).<p>
+Columns can be documented by adding the description directly to the Column tag or by embedding it with a Doc tag inside the Column tag. Enum values can be documented by embedding the description between <Value> and </Value>.<p>
+
<h2>Communication Abstraction Layer</h2>
The Communication Abstraction Layer is the servers upper bound towards the client. It hides the complexities of serializing data onto the network transport protocol by providing communication classes that do this automatically. The configuration of this layer is split into two major components: communication classes and transactions. While the communication classes describe what data can be transported over the connection, the transactions describe what operations can be performed.<p>
<ToXml name="Full">orderid customerid seller amountpaid state amountdue tickets/inOrder vouchers/inOrder</ToXml>
</pre>
-Above the property "tickets" is a list of Ticket and "inOrder" is a serialization defined above for Ticket.
+Above the property "tickets" is a list of Ticket and "inOrder" is a serialization defined above for Ticket.<p>
+
+Classes can be documented by adding Doc subtags. Properties can be documented by adding the description directly into the Property tag. Enum values can be documented by adding the description directly into the Value tag.
<h3>Transactions</h3>
<tr><td>method</td><td>the function to call - it must take exactly one argument: the transaction object</td></tr>
</table><p>
-Transactions are represented as classes. On the client side they are used to execute the query and to represent the result. On the server side they internally verify the input and authenticate the transaction and are then used to take and encode the output or possible error conditions.
+Transactions are represented as classes. On the client side they are used to execute the query and to represent the result. On the server side they internally verify the input and authenticate the transaction and are then used to take and encode the output or possible error conditions.<p>
+
+Transactions can be documented by adding Doc tags. Inputs and Outputs can be documented by adding the description directly into the Var tags.
<h2>Server Abstraction Layer</h2>
#include "orderwin.h"
#include "overview.h"
-//#include "user.h"
-//#include "host.h"
-
#include <QApplication>
#include <QBoxLayout>
#include <QCheckBox>
</Table>
<Transaction name="Backup">
+ <Doc>This transaction allows to make a complete database backup. The backup file is replayed into the database via the admin.php interface.</Doc>
<Input/>
<Call lang="php" method="global $db;$this->setbackup($db->dumpBackup());"/>
<Output>
- <Var name="backup" type="string"/>
+ <Var name="backup" type="string">Contains the structured backup data.</Var>
</Output>
</Transaction>
-->
<Wolf>
<Table name="room" backup="yes">
- <Column name="roomid" type="string:64" primarykey="yes"/>
- <Column name="capacity" type="int32" notnull="yes"/>
- <Column name="description" type="text"/>
+ <Doc>Stores rooms that can be used for events.</Doc>
+ <Column name="roomid" type="string:64" primarykey="yes">Name of the room</Column>
+ <Column name="capacity" type="int32" notnull="yes">Amount of people fitting into the room, zero means unlimited, this can be overridden per event.</Column>
+ <Column name="description" type="text">A short description of the room to help users. Currently not used extensively.</Column>
</Table>
<Table name="seatplan" backup="yes">
- see COPYING.AGPL for details
-->
<Wolf>
+ <Doc>These files describe the database schema and communication protocol of MagicSmoke.</Doc>
+ <Doc>(c) Konrad Rosenbaum, 2009<br/>these files are protected under the GNU AGPLv3 or at your option any newer</Doc>
<!-- generic settings -->
<Project baseDir=".." wobDir="wob" name="MagicSmoke"/>
<Version comm="0100" needcomm="0100" humanReadable="1.91 alpha" svnTarget="."/>
<DataBase instance="db" schema="dbScheme" version="01.04">
<AuditTables>
- <Column name="audittime" type="int64">
+ <Column name="audittime" type="int64">Time at which the change was made.
<Call lang="php" method="time()"/>
</Column>
- <Column name="audituname" type="string:64">
+ <Column name="audituname" type="string:64">The user name of the user who made the change.
<Call lang="php" method="Session::currentUserName()"/>
</Column>
- <Column name="audittransaction" type="string:64">
+ <Column name="audittransaction" type="string:64">The transaction name under which the change was made.
<Call lang="php" method="WobTransactionBase::getExecutingName()"/>
</Column>
</AuditTables>
-->
<Wolf>
<Table name="shipping" backup="yes">
- <Column name="shipid" type="seq32" primarykey="yes"/>
- <Column name="cost" type="int32" notnull="yes"/> <!--default cost of this shipping type-->
- <Column name="flags" type="string"/>
- <Column name="description" type="string"/> <!--description for the shipping type-->
+ <Doc>This table contains descriptions of shipping methods, the actual cost can be overridden in each order.</Doc>
+ <Column name="shipid" type="seq32" primarykey="yes"/>
+ <Column name="cost" type="int32" notnull="yes">default cost of this shipping type in cents</Column>
+ <Column name="flags" type="string">flags showing who can use this method</Column>
+ <Column name="description" type="string">description for the shipping type</Column>
</Table>
<Table name="paymenttype" backup="yes">
+ <Doc>This table contains acceptable payment methods. (Under construction.)</Doc>
<Column name="paytype" type="string:64" primarykey="yes"/>
<Column name="description" type="string"/>
<Column name="dataname" type="string:64" null="yes"/>
<Preset><V col="paytype" val="cash"/><V col="description" val="default paytype: cash"/></Preset>
</Table>
<Table name="order" backup="yes" audit="yes">
+ <Doc>This table contains all orders and sales.</Doc>
<Column name="orderid" type="seq32" primarykey="yes"/>
<!--customer-->
- <Column name="customerid" type="int32" foreignkey="customer:customerid"/>
+ <Column name="customerid" type="int32" foreignkey="customer:customerid">
+ ID of the customer connected to this order.
+ </Column>
<!--seller (_online for web forms)-->
- <Column name="soldby" type="string:64" foreignkey="user:uname"/>
+ <Column name="soldby" type="string:64" foreignkey="user:uname">User name of the user who entered it into the system. "_web" for the online system.</Column>
<!--if not null/empty: this address for delivery, customer address for invoice-->
- <Column name="invoiceaddress" type="int64" foreignkey="address:addressid" null="yes"/>
- <Column name="deliveryaddress" type="int64" foreignkey="address:addressid" null="yes"/>
+ <Column name="invoiceaddress" type="int64" foreignkey="address:addressid" null="yes">
+ If not null: the address the invoice goes to.
+ </Column>
+ <Column name="deliveryaddress" type="int64" foreignkey="address:addressid" null="yes">
+ If not null: the address the delivery goes to.
+ If null: assumed to be identical to invoiceaddress.
+ </Column>
<!--status, see ORDER_* constants-->
<Column name="status" type="enum32" notnull="yes">
- <Value name="Placed" value="0"/>
- <Value name="Sent" value="1"/>
- <Value name="Sold" value="1"/>
- <Value name="Cancelled" value="2"/>
- <Value name="Reserved" value="4"/>
- <Value name="Closed" value="0x80"/>
+ <Doc>Status the order is in right now.</Doc>
+ <Value name="Placed" value="0">The order has been placed, but not acted upon yet.</Value>
+ <Value name="Sent" value="1">The order has been sent out or handed to the customer.</Value>
+ <Value name="Sold" value="1">Alias for Sent. Semantically: it is sold if it has been sent and paid.</Value>
+ <Value name="Cancelled" value="2">The order has been cancelled, if anything has been paid, it must be paid back.</Value>
+ <Value name="Reserved" value="4">The order is just a reservation for a limited time, application logic must determine the timeout.</Value>
+ <Value name="Closed" value="0x80">The order is closed out of the system - the payment status is ignored from now on. Currently not used.</Value>
+ </Column>
+ <Column name="ordertime" type="int32" notnull="yes">When the order was created</Column>
+ <Column name="senttime" type="int32">When the order was sent to the customer</Column>
+ <Column name="comments" type="text">comments made on web form (eg. "urgently needed for dads birthday")</Column>
+ <Column name="amountpaid" type="int32">
+ how much has been paid already (including used vouchers);
+ this is for comparison with the price fields in ticket and voucher tables
+ </Column>
+ <Column name="shippingcosts" type="int32" default="0">shipping price; this is not re-imbursed for orders that have been sent and then cancelled</Column>
+ <Column name="shippingtype" type="int32" null="yes" foreignkey="shipping:shipid">
+ pointer to shipping type (none per default, programmatic default is in config)
</Column>
- <Column name="ordertime" type="int32" notnull="yes"/>
- <Column name="senttime" type="int32"/>
- <!--comments made on web form (eg. "urgently needed for dads birthday")-->
- <Column name="comments" type="text"/>
- <!--how much has been paid already (including used vouchers)
- this is for comparison with the price fields in ticket and voucher tables-->
- <Column name="amountpaid" type="int32"/>
- <!--shipping price-->
- <Column name="shippingcosts" type="int32" default="0"/>
- <!--pointer to shipping type (none per default, programmatic default is in config)-->
- <Column name="shippingtype" type="int32" null="yes" foreignkey="shipping:shipid"/>
<!-- in audit: monitor the type of payment -->
<AuditColumn name="paytype" type="string:64" foreignkey="paymenttype:paytype"/>
<AuditColumn name="paydata" type="string"/>
- <Foreign method="getTickets" via="ticket:orderid=orderid"/>
- <Foreign method="getVouchers" via="voucher:orderid=orderid"/>
- <Foreign method="getItems" via="item:orderid=orderid"/>
+ <Foreign method="getTickets" via="ticket:orderid=orderid">Returns the tickets for this order</Foreign>
+ <Foreign method="getVouchers" via="voucher:orderid=orderid">Returns the vochers sold by this order</Foreign>
+ <Foreign method="getItems" via="item:orderid=orderid">Returns additional sold items for this order</Foreign>
</Table>
<Table name="ticket" backup="yes" base="BarcodeTable" audit="yes">
- <!--a 8-32 char code (code39: case-insensitive letters+digits) for the ticket-->
<Column name="ticketid" type="string:32" primarykey="yes">
+ a 8-32 char code (code39: case-insensitive letters+digits) for the ticket;
+ automatically generated
<Call lang="php" method="BarcodeTable::getNewTicketId()"/>
</Column>
<Column name="eventid" type="int32" foreignkey="event:eventid"/>
<Column name="pricecategoryid" type="int32" foreignkey="pricecategory:pricecategoryid"/>
<!--status of ticket (see TICKET_* constants)-->
<Column name="status" type="enum32" notnull="yes">
- <Value name="Reserved" value="0x311"/> <!--dec: 785-->
- <Value name="Ordered" value="0x312"/> <!--dec: 786-->
- <Value name="Used" value="0x303"/> <!--dec: 771-->
- <Value name="Cancelled" value="0x4"/> <!--dec: 4-->
- <Value name="Refund" value="0x4"/>
- <Value name="MaskBlock" value="0x100"/> <!--dec: 256-->
- <Value name="MaskPay" value="0x200"/> <!--dec: 512-->
- <Value name="MaskUsable" value="0x300"/> <!--dec: 768-->
- <Value name="MaskReturnable" value="0x10"/> <!--dec: 16-->
+ <Value name="Reserved" value="0x311"> <!--dec: 785-->
+ The ticket is reserved for a customer, it blocks the seat, but is not to be paid yet.</Value>
+ <Value name="Ordered" value="0x312"> <!--dec: 786-->
+ The ticket is ordered/sold and possibly paid for (payment is stored in its order).</Value>
+ <Value name="Used" value="0x303"> <!--dec: 771-->
+ The ticket has been used.</Value>
+ <Value name="Cancelled" value="0x4"> <!--dec: 4-->
+ The ticket has been given back for some reason and needs to be re-imbursed (if paid already).</Value>
+ <Value name="Refund" value="0x4">Alias for Cancelled</Value>
+ <Value name="MaskBlock" value="0x100"> <!--dec: 256-->
+ Masking value: if this bit is set the ticket blocks a seat.</Value>
+ <Value name="MaskPay" value="0x200"> <!--dec: 512-->
+ Masking value: if this bit is set the ticket must be paid by the customer.</Value>
+ <Value name="MaskUsable" value="0x300"> <!--dec: 768-->
+ Masking value: combines Block+Pay - the ticket can be used to watch a show.</Value>
+ <Value name="MaskReturnable" value="0x10"> <!--dec: 16-->
+ Masking value: if this bit is set the ticket can still be cancelled.</Value>
</Column>
<Column name="orderid" type="int32" foreignkey="order:orderid" notnull="yes"/>
<Column name="seat" type="string:32" null="yes"/>
</Table>
<Table name="product" backup="yes">
+ <Doc>A saleable product other than tickets or vouchers (eg. merchandizing).</Doc>
<Column name="productid" type="seq32" primarykey="yes"/>
<Column name="name" type="string" notnull="yes"/>
<Column name="description" type="text"/>
<!-- amount that is in the inventory, or -1 if it is unlimited -->
<Column name="inventory" type="int32" notnull="yes"/>
<Column name="price" type="int32" notnull="yes"/>
- <Column name="barcode" type="string" null="yes"/>
+ <Column name="barcode" type="string" null="yes">usually the EAN code</Column>
<Column name="flags" type="string"/>
<Column name="tax" type="int32"/>
</Table>
<Table name="item" backup="yes" audit="yes">
+ <Doc>A sold item other than a ticket or voucher.</Doc>
<Column name="itemid" type="seq64" primarykey="yes"/>
<Column name="productid" type="int32" foreignkey="product:productid" notnull="yes"/>
<Column name="orderid" type="int32" foreignkey="order:orderid" notnull="yes"/>
<Class name="Ticket">
+ <Doc>This class represents the data of a ticket as stored in the database.</Doc>
<Enum name="TicketState" refColumn="ticket:status"/>
- <Property name="ticketid" type="astring" id="yes"/>
+ <Property name="ticketid" type="astring" id="yes">uniquely identifies the ticket, this ID is automatically generated when the ticket is created by the server</Property>
<Property name="eventid" type="int"/>
<Property name="price" type="int"/>
<Property name="status" type="TicketState"/>
WocHtmlOut::WocHtmlOut(QDomElement&el)
{
qDebug("Info: creating Html Output Generator.");
- m_basedir=WocProcessor::instance()->baseDir()+"/"+el.attribute("sourceDir",".");
+ 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)
m_index.write(QByteArray("<title>Project Index</title>\n"));
m_index.write(QByteArray("</head><body>\n"));
- //TODO: write project info
+ //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("<h2>Classes</h2>\n<ul>\n"));
+ 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);
s+="<li><a href=\"class-"+sl[i]+".html\">"+sl[i]+"</a></li>\n";
m_index.write(s.toAscii());
- m_index.write(QByteArray("</ul>\n<h2>Transactions</h2>\n<ul>"));
+ m_index.write(QByteArray("</ul></td><td valign=\"top\"><ul>"));
sl=WocProcessor::instance()->transactionNames();
s="";
qSort(sl);
s+="<li><a href=\"trn-"+sl[i]+".html\">"+sl[i]+"</a></li>\n";
m_index.write(s.toAscii());
- m_index.write(QByteArray("</ul>\n<h2>Tables</h2>\n<ul>"));
+ m_index.write(QByteArray("</ul></td><td valign=\"top\"><ul>"));
sl=WocProcessor::instance()->tableNames();
s="";
qSort(sl);
s+="<li><a href=\"table-"+sl[i]+".html\">"+sl[i]+"</a></li>\n";
m_index.write(s.toAscii());
- m_index.write(QByteArray("</ul>\n"));
+ m_index.write(QByteArray("</ul></td></tr></table>\n"));
m_index.write(QByteArray("\n</body></html>\n"));
m_index.close();
QString hcd;
//table declaration
hcd+="<h1>Table "+cn+"</h1>\n";
- hcd+="<table frame=\"1\" border=\"1\"><tr><td><b>Column Name</b></td><td><b>Type</b></td><td><b>Properties</b></td></tr>\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>";
hcd+="Indexed ";
if(tbl.columnIsUnique(cl[i]))
hcd+="Unique";
- hcd+="</td></tr>\n";
+ hcd+="</td><td>"+tbl.columnDoc(cl[i])+"</td></tr>\n";
}
hcd+="</table>\n";
//enums
for(int i=0;i<cl.size();i++){
- QList<QPair<QString,int> >lst=tbl.columnEnums(cl[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].first+"="+QString::number(lst[j].second)+"</li>\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());
}
hcd+="<h1>";
if(cls.isAbstract())hcd+="Abstract ";
hcd+="Class "+cn+"</h1>\n";
+ 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);
- //TODO: mappings
+ //mappings
+ classMappings(cls,htm);
//lead out
htm.write(QByteArray("</body></html>\n"));
//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></tr>\n";
- QList<QPair<QString,int> >ev=cls.enumValues(k[i]);
+ 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].first+"</td><td>"+QString::number(ev[j].second)+"</td></tr>\n";
+ hcd+="<tr><td>"+ev[j].name+"</td><td>"+QString::number(ev[j].val)
+ +"</td><td>"+ev[j].doc+"</td></tr>\n";
}
hcd+="</table>\n";
}
if(k.size()==0)return;
QString hcd;
//declare members
- hcd="<h2>Properties</h2>\n";
+ hcd="<h2>Properties</h2>\n<ul>\n";
for(int i=0;i<k.size();i++){
- hcd+=k[i]+"<br/>\n";
+ 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();
//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]+": "+trn.inputType(in[i])+"</li>\n";
- //TODO: link class types
+ 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]+": "+trn.outputType(out[i])+"</li>\n";
- //TODO: link class types
+ 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";
hcd+="</body></html>\n";
void classEnums(const WocClass&,QFile&);
/**helper: generate properties*/
void classProperties(const WocClass&,QFile&);
- /**helper: generate constructors/deserializer/copiers*/
- void classDeserializer(const WocClass&,QFile&);
- /**helper: generate serializers*/
- void classSerializers(const WocClass&,QFile&);
+ /**helper: generate mappings*/
+ void classMappings(const WocClass&,QFile&);
};
//implement enum check for set method of enum columns
if(tbl.columnType(cols[i]).startsWith("enum")){
code+="private function verifyValue"+cols[i]+"($v){if(false";
- QList<QPair<QString,int> >ens=tbl.columnEnums(cols[i]);
+ QList<WocEnum>ens=tbl.columnEnums(cols[i]);
QList<int>envs;
for(int j=0;j<ens.size();j++){
- int v=ens[j].second;
+ int v=ens[j].val;
if(envs.contains(v))continue;
envs.append(v);
code+="||$v=="+QString::number(v);
}
//create enum constants
- QList<QPair<QString,int> >ens=tbl.getEnums();
+ QList<WocEnum>ens=tbl.getEnums();
for(int i=0;i<ens.size();i++){
- code+="const "+ens[i].first+"="+QString::number(ens[i].second)+";\n";
+ code+="const "+ens[i].name+"="+QString::number(ens[i].val)+";\n";
}
//hasproperty function
QStringList k=cls.enumTypes();
for(int i=0;i<k.size();i++){
code+="//enum "+k[i]+"\n";
- QList<QPair<QString,int> >ev=cls.enumValues(k[i]);
+ QList<WocEnum>ev=cls.enumValues(k[i]);
for(int j=0;j<ev.size();j++)
- code+="const "+ev[j].first+"="+QString::number(ev[j].second)+";\n";
+ code+="const "+ev[j].name+"="+QString::number(ev[j].val)+";\n";
}
return code;
}
QString code;
code+="static public function validate"+prop+"($value){\n";
if(cls.propertyIsEnum(prop)){
- QList<QPair<QString,int> >ev=cls.enumValues(cls.propertyPlainType(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].second)+")return true;\n";
+ 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].first+"\")return true;\n";
+ code+="\t\tif($value==\""+ev[j].name+"\")return true;\n";
}
code+="\t\treturn false;\n\t}\n";
}else
code+="public function getstrlist_"+prop+"(){\n";
code+="\t$ret=array();\n";
code+="\tforeach($this->prop_"+prop+" as $p)switch($p){\n";
- QList<QPair<QString,int> > ev=cls.enumValues(cls.propertyPlainType(prop));
+ QList<WocEnum> ev=cls.enumValues(cls.propertyPlainType(prop));
for(int j=0;j<ev.size();j++){
- code+="\t\tcase "+QString::number(ev[j].second)+":$ret[]=\""+ev[j].first+"\";break;\n";
+ 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";
}
QString acode;//body of add_ function, see below
code+="public function set_"+prop+"(array $values){\n";
if(cls.propertyIsEnum(prop)){
- QList<QPair<QString,int> >ev=cls.enumValues(cls.propertyPlainType(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].second)+"){\n";
- code+="\t\t\t\t$prop[]="+QString::number(ev[j].second)+";\n";
+ 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].second)+"){\n";
- acode+="\t\t\t$this->prop_"+prop+"[]="+QString::number(ev[j].second)+";\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].first+"\"){\n";
- code+="\t\t\t\t$prop[]="+QString::number(ev[j].second)+";\n";
+ 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].first+"\"){\n";
- acode+="\t\t\t$this->prop_"+prop+"[]="+QString::number(ev[j].second)+";\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";
else
if(cls.propertyIsEnum(prop)){
code+="public function getstr_"+prop+"(){\n\tswitch($this->prop_"+prop+"){\n";
- QList<QPair<QString,int> > ev=cls.enumValues(cls.propertyPlainType(prop));
+ QList<WocEnum> ev=cls.enumValues(cls.propertyPlainType(prop));
for(int j=0;j<ev.size();j++){
- code+="\t\tcase "+QString::number(ev[j].second)+":return translate(\""+abstractClassName(cls)+"\",\""+ev[j].first+"\");\n";
+ 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";
}
QString code;
code+="public function set_"+prop+"($value){\n";
if(cls.propertyIsEnum(prop)){
- QList<QPair<QString,int> >ev=cls.enumValues(cls.propertyPlainType(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].second)+"){\n";
- code+="\t\t\t$this->prop_"+prop+"="+QString::number(ev[j].second)+";\n";
+ 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].first+"\"){\n";
- code+="\t\t\t$this->prop_"+prop+"="+QString::number(ev[j].second)+";\n";
+ 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";
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());
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=cls.elementsByTagName("Enum");
m_valid=false;
return;
}
- QList<QPair<QString,int> >ev;
+ QList<WocEnum>ev;
//check whether there is a reference
if(el.hasAttribute("refColumn")){
QStringList ref=el.attribute("refColumn").split(":");
continue;
}
nxval=el2.attribute("value",QString::number(nxval)).toInt(0,0);
- ev.append(QPair<QString,int>(n,nxval));
+ ev.append(WocEnum(n,nxval,el2.text().trimmed()));
nxval++;
//TODO: check that value name does not exist yet
}
}
m_maps.insert(name,map);
}
+ //docu
+ nl=cls.elementsByTagName("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());
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
if(ps.size()>0)m_presets.append(ps);
}
+ //Docu
+ nl=tbl.elementsByTagName("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){
continue;
}
nxval=el2.attribute("value",QString::number(nxval)).toInt(0,0);
- cl.enumvals.append(QPair<QString,int>(n,nxval));
+ cl.enumvals.append(WocEnum(n,nxval,el2.text().trimmed()));
nxval++;
}
//default calls
QString meth=el2.attribute("method","false");
cl.methodcalls.insert(lang,meth);
}
+ //docu
+ nl2=el.childNodes();
+ for(int j=0;j<nl2.size();j++){
+ QDomNode n=nl2.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);
}
return false;
}
-QList<QPair<QString,int> > WocTable::columnEnums(QString c)const
+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<QPair<QString,int> >();
+ return QList<WocEnum>();
}
-QList<QPair<QString,int> > WocTable::getEnums()const
+QList<WocEnum> WocTable::getEnums()const
{
- QList<QPair<QString,int> > r;
+ 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 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;
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.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
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
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=root.elementsByTagName("Doc");
+ for(int i=0;i<nl.size();i++){
+ QString s=nl.at(i).toElement().text().trimmed();
+ if(s!="")m_docstrings<<s;
+ }
}
bool WocTransaction::hasInput(QString v)const
}
+/**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
{
/**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<QPair<QString,int> > enumValues(QString t)const{return m_enumvals[t];}
+ 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 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)
bool m_valid,m_abstract;
//name: class name
- //base: name of parent class
+ //base: name of parent class (s=server, c=client)
QString m_name,m_sbase,m_cbase;
//property info
struct s_prop{
};
QMap<QString,QList<s_map> >m_maps;
//enum types: "type-name" => List of ("constant-name",int-constant-value)
- QMap<QString,QList<QPair<QString,int> > >m_enumvals;
+ 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;
/**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;
+ 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<QPair<QString,int> > getEnums()const;
+ QList<WocEnum> getEnums()const;
/**returns a list of all foreign definitions - methods that return data from other tables*/
QStringList foreigns()const;
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;
+ QString name,type,foreign,defaultval,doc;
bool isnull,isprime,isindex,isunique;
- QList<QPair<QString,int> >enumvals;
+ QList<WocEnum>enumvals;
QMap<QString,QString>methodcalls;
};
QList<s_col>m_columns,m_auditcolumns;
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);
};
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 "";}
private:
QString m_name;
bool m_valid;
AuthMode m_mode;
QMap<QString,QString> m_call;
QList<QPair<QString,QString> >m_input,m_output;
+ //docu
+ QStringList m_docstrings;
+ QMap<QString,QString>m_indoc,m_outdoc;
};
/**base class of all output generators*/
QStringList classNames()const;
/**returns a list of table names*/
QStringList tableNames()const;
+
+ QStringList docStrings()const{return m_docstrings;}
signals:
void sfinalize();
void newClass(const WocClass&);
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;
for(int i=0;i<k.size();i++){
//type
hcd+="\tenum "+k[i]+"{";
- QList<QPair<QString,int> >ev=cls.enumValues(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();
}
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\t"+ev[j].name+"="+QString::number(ev[j].val);
}
hcd+="\n\t};\n";
//string converters
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(s==\""+ev[j].name.toLower()+"\")return "+ev[j].name+";\n";
}
- scd+="\tif(ok)*ok=false;\n\treturn "+ev[0].first+";\n}\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].first+")return \""+ev[j].first+"\";\n";
+ scd+="\tif(e=="+ev[j].name+")return \""+ev[j].name+"\";\n";
}
scd+="\treturn \"\";\n}\n";
}