Loops cannot be nested.
+<h3>Conditional Output</h3>
+
+The output of parsed lines can be suppressed:
+
+<pre>
+#IF:MYVAR < 66
+output if the value is smaller than 66
+#ELSE
+output otherwise
+#ENDIF
+</pre>
+
+A condition consists of exactly two values (both may be variables) and an operator. More complex expressions are not possible at the moment. If the condition evaluates to false, then the output and calculation of all lines until #ELSE or #ENDIF is suppressed.<p>
+
+At the moment the #ELSE statement reverses the output suppression between #IF and #ENDIF. Multiple #ELSEs are possible at the moment, but should not be relied upon in case the logic changes in subsequent versions.<p>
+
+Conditions cannot be nested, but conditions can be embedded in loops or be put around loops. If a condition is put around a loop, it does not prevent the processor from evaluating the loop, only the output and internal calculations are suppressed.<p>
+
+<table frame="1" border="1">
+<tr><td><b>Operator</b></td><td><b>Description</b></td></tr>
+<tr><td><</td><td>lighter than</td></tr>
+<tr><td><=</td><td>lighter or equal</td></tr>
+<tr><td>></td><td>greater than</td></tr>
+<tr><td>>=</td><td>greater or equal</td></tr>
+<tr><td><></td><td>not equal</td></tr>
+<tr><td>!=</td><td>not equal</td></tr>
+<tr><td>=</td><td>equal</td></tr>
+<tr><td>==</td><td>equal</td></tr>
+</table>
+
+
<h3>Calculations</h3>
Numeric variables allow some very simple calculations in place:
More complex calculations can be done with the #CALC statement:
<pre>
-#CALC:TVAR/MONEY:@VAR1@ * @VAR2@ + 4
+#CALC:TVAR/MONEY:VAR1 * VAR2 + 4
</pre>
-The above creates the temporary variable "@#TVAR@" that is the product of @VAR1@ and @VAR2@'s content plus 4. It is marked as a monetary value.<p>
+The above creates the temporary variable "@#TVAR@" that is the product of @VAR1@ and @VAR2@'s content plus 4. It is marked as a monetary value. Please note that the variables are not enclosed in "@".<p>
Calculations are restricted to the operators below and are always done from left to right - more complex formulas require several lines. Tokens must be space separated. If no type or a non-existing type is requested INT is assumed. All calculations are done using 64bit signed integers. If the processor comes across an illegal token it sets the variable to "error".<p>
+Literals (above: "4") must be integers.<p>
+
<table frame="1" border="1">
<tr><td><b>Operator</b></td><td><b>Description</b></td></tr>
<tr><td>+</td><td>adding</td></tr>
File name: <tt>eventsummary.odtt</tt><p>
-Loop: <tt>TICKETS</tt> - this loop iterates over the ticket price categories.<p>
+Loops:<br/>
+<tt>TICKETS</tt> - this loop iterates over the ticket price categories.<br/>
+<tt>ORDERS</tt> - this loop iterates over all orders that contain tickets for this event.<p>
Variables:
<table frame="1" border="1">
<tr><td><b>Variable</b></td><td><b>Description</b></td></tr>
<tr><td>@TITLE@</td><td>title of the event</td></tr>
<tr><td>@ARTIST@</td><td>artist of the event</td></tr>
+<tr><td>@ROOM@</td><td>room of the event</td></tr>
<tr><td>@START@</td><td>start date and time in the currently active locale</td></tr>
<tr><td>@CAPACITY@</td><td>maximum amount of tickets that can be sold</td></tr>
<tr><td>@RESERVED@</td><td>tickets that are currently reserved for a seller</td></tr>
Loops: <br>
<tt>TICKETS</tt> - this loop iterates over each ticket in the order.<br>
-<tt>ADDRESSLINES</tt> - this loop iterates over the lines of the address.<p>
+<tt>ACCTICKETS</tt> - this loop iterates over ticket categories in the order. Each category contains tickets for the same event with the same price.<br>
+<tt>ADDRESSLINES</tt> - this loop iterates over the lines of the address. (obsolete)<br>
+<tt>VOUCHERS</tt> - this loop iterates over all vouchers of the order.<p>
-(TODO: loop for vouchers)<p>
Variables:
<table frame="1" border="1">
<tr><td>@ACCTICKETS:ENDTIME@</td><td>the end date and time of the event for this ticket type</td></tr>
<tr><td>@ACCTICKETS:ROOM@</td><td>the room/place of the event for this ticket type</td></tr>
<tr/>
-<tr><td>@ADDRESSLINES@</td><td>amount of lines that the address has</td></tr>
-<tr><td>@ADDRESSLINES:LINE@</td><td>current line in the address loop</td></tr>
+<tr><td>@ADDRESSLINES@</td><td>amount of lines that the address has (obsolete)</td></tr>
+<tr><td>@ADDRESSLINES:LINE@</td><td>current line in the address loop (obsolete)</td></tr>
<tr/>
<tr><td>@VOUCHERS@</td><td>the amount of vouchers in the order</td></tr>
<tr><td>@VOUCHERS:PRICE@</td><td>the price of this voucher</td></tr>
QUnZip temp;
QFile tfile;
QString newline;
+ bool inif,iftrue;
struct LocalVar{
MOdtRenderer::VarType type;
{
parent=p;
newline=" ";
+ inif=iftrue=true;
//open ZIP
if(tfile.open(QIODevice::ReadOnly))temp.open(&tfile);
//TODO: make sure this is a valid ZIP file, preferably with some ODT content
//...line by line
for(int k=0;k<lbuf.size();k++){
ret+=renderLine(lbuf[k],lname,j);
- ret+="\n";
}
}
//reset state
}else{//not a loop or statement
//convert line
ret+=renderLine(fbuf[i],"",-1);
- ret+="\n";
}
}
}
QString ret,vname;
bool isvar=false;
static QString vc="ABCDEFGHIJKLMNOPQRSTUVWXYZ:+-0123456789$#";
- //check for statements
+ //check for conditionals
+ if(line.trimmed().startsWith("#IF:")){
+ QString stmt=line.trimmed().mid(3).trimmed();
+ qDebug("????????????????If: %s",stmt.toAscii().data());
+ //split out var name
+ //get list of statement tokens
+ QStringList stl=stmt.split(" ");
+ if(stl.size()!=3){
+ qDebug("???????????If failed, expected 3 tokens, got %i tokens",stl.size());
+ return "";
+ }
+ iftrue=inif=true;
+ //go through
+ qint64 op1=intToken(stl[0],loop,lpos);
+ qint64 op2=intToken(stl[2],loop,lpos);
+ if(stl[1]=="<")iftrue=op1<op2;else
+ if(stl[1]==">")iftrue=op1>op2;else
+ if(stl[1]=="=" || stl[1]=="=")iftrue=op1==op2;else
+ if(stl[1]=="<=")iftrue=op1<=op2;else
+ if(stl[1]==">=")iftrue=op1>=op2;else
+ if(stl[1]=="<>" || stl[1]=="!=")iftrue=op1!=op2;
+ else {
+ qDebug("??????????IfError: unknown operator");
+ return "";
+ }
+ return "";
+ }else
+ if(line.trimmed()=="#ELSE"){
+ iftrue=!iftrue;
+ return "";
+ }else
+ if(line.trimmed()=="#ENDIF"){
+ inif=false;
+ return "";
+ }
+ //check if state
+ if(inif && !iftrue)return "";
+ //check for other statements
if(line.trimmed().startsWith("#SETNEWLINE:")){
//set a new newline translation
newline=line.trimmed().mid(12).trimmed();
if(newline=="")newline=" ";
return "";
- }
+ }else
if(line.trimmed().startsWith("#CALC:")){
//do a calculation
//get full statement
QStringList stl=stmt.mid(p+1).trimmed().split(" ");
//go through
qint64 res=intToken(stl[0],loop,lpos);
- qDebug("??????????CalcInit: %lli",res);
+// qDebug("??????????CalcInit: %lli",res);
for(int i=1;i<stl.size();i+=2){
if((i+1)>=stl.size()){
setLocalVarError(var);
- qDebug("??????????CalcError: missing operand");
+ qDebug("??????????CalcError: missing last operand");
return "";
}
- qDebug("??????????Calc: operator '%s' operand '%s' -> '%lli'",stl[i].toAscii().data(),stl[i+1].toAscii().data(),intToken(stl[i+1],loop,lpos));
- if(stl[i]=="+")res+=intToken(stl[i+1],loop,lpos);else
- if(stl[i]=="-")res-=intToken(stl[i+1],loop,lpos);else
- if(stl[i]=="*")res*=intToken(stl[i+1],loop,lpos);else
- if(stl[i]=="/")res/=intToken(stl[i+1],loop,lpos);else
- if(stl[i]=="%")res%=intToken(stl[i+1],loop,lpos);
- else {
+ qint64 op2=intToken(stl[i+1],loop,lpos);
+// qDebug("??????????Calc: operator '%s' operand '%s' -> '%lli'",stl[i].toAscii().data(),stl[i+1].toAscii().data(),op2);
+ if(stl[i]=="+")res+=op2;else
+ if(stl[i]=="-")res-=op2;else
+ if(stl[i]=="*")res*=op2;else
+ if(stl[i]=="/"){
+ if(op2!=0)res/=op2;
+ else{
+ qDebug("??????????CalcError: division operand %s is zero",stl[i+1].toAscii().data());
+ return "";
+ }
+ }else
+ if(stl[i]=="%"){
+ if(op2!=0)res%=op2;
+ else{
+ qDebug("??????????CalcError: modulo operand %s is zero",stl[i+1].toAscii().data());
+ return "";
+ }
+ }else {
setLocalVarError(var);
- qDebug("??????????CalcError: unknown operator");
+ qDebug("??????????CalcError: unknown operator %s",stl[i].toAscii().data());
return "";
}
}
ret+="@"+vname;
}
//return transformed line
- return ret;
+ return ret + "\n";
}
static inline QString formatVar(QVariant r,MOdtRenderer::VarType tp,bool loc,int offset)
qint64 MOdtRendererPrivate::intToken(QString vname,QString loop,int lpos)
{
+ //check for literals
+ bool islit;
+ qint64 lit=vname.toLongLong(&islit);
+ if(islit)return lit;
//split the variable
QStringList vnl=vname.split(":");
if(vnl.size()<2){