From ad56cc72d0b981f9e8b3f1d8a63c15fbfca3849d Mon Sep 17 00:00:00 2001 From: konrad Date: Mon, 24 Mar 2008 19:27:03 +0000 Subject: [PATCH] * overview for orders * ticket class * ticket rendering * finalized template handling * fixed code-39 generation * added draft of a bill template git-svn-id: https://silmor.de/svn/softmagic/smoke/trunk@140 6e3c4bff-ac9f-4ac1-96c5-d2ea494d3e33 --- doc/prog_protocol.html | 2 +- doc/prog_tickettemplate.html | 10 +- examples/bill.odt | Bin 0 -> 10348 bytes examples/ticket.xtt | Bin 484 -> 492 bytes src/code39.cpp | 28 +- src/code39.h | 4 +- src/event.cpp | 43 +++- src/event.h | 11 + src/eventsummary.cpp | 8 +- src/mainwindow.cpp | 2 +- src/order.cpp | 286 +++++++++++++++++- src/order.h | 167 ++++++++++- src/orderwin.cpp | 218 ++++++++++++++ src/orderwin.h | 78 +++++ src/overview.cpp | 55 +++- src/overview.h | 5 + src/smoke.pro | 6 +- src/smoke_de.ts | 674 ++++++++++++++++++++++++++++++++---------- src/smoke_de_SAX.ts | 674 ++++++++++++++++++++++++++++++++---------- src/ticketrender.cpp | 470 +++++++++++++++++++++++++++++ src/ticketrender.h | 47 +++ src/webrequest.cpp | 113 +++++++- src/webrequest.h | 16 +- www/inc/classes/order.php | 13 + www/inc/machine/template.php | 2 +- www/machine.php | 7 +- 26 files changed, 2573 insertions(+), 366 deletions(-) create mode 100644 examples/bill.odt create mode 100644 src/orderwin.cpp create mode 100644 src/orderwin.h create mode 100644 src/ticketrender.cpp create mode 100644 src/ticketrender.h diff --git a/doc/prog_protocol.html b/doc/prog_protocol.html index 2109eb4..6469b99 100644 --- a/doc/prog_protocol.html +++ b/doc/prog_protocol.html @@ -573,6 +573,6 @@ The Hash is caculated at the server side and can be used to find out whether the The gettemplate transaction returns a specific template. The request contains only the file name, the response contains the template file as content. In case of an error the content is left empty and the status code is set appropriately. -Setting a Template +

Setting a Template

The settemplate transaction creates a new template file. The request contains the file name terminated with a newline ("\n") and then the binary content of the template - it is important that there are no additional characters between the newline and the template content. The response contains the new hash of the template or error details. \ No newline at end of file diff --git a/doc/prog_tickettemplate.html b/doc/prog_tickettemplate.html index dfdbcf0..e691887 100644 --- a/doc/prog_tickettemplate.html +++ b/doc/prog_tickettemplate.html @@ -17,9 +17,8 @@ The template.xml file describes the painting operations that form the t <TicketTemplate unit="mm|in|px" size="11 22"> <LoadFont file="nameInsideArchive.ttf"/> <Picture file="nameInsideArchive.png" size="11 22" offset="33 44" smooth="1"/> - <Text font="fontFamilyName" embeddedFont="fontFamilyName" fontsize="sizeInPt" - offset="11 22" align="left|right|center" valign="top|bottom|center" - >some string with @VARIABLES@ to print</Text> + <Text font="fontFamilyName" fontsize="sizeInPt" offset="11 22" size="33 44" align="left|right|center" + valign="top|bottom|center" >some string with @VARIABLES@ to print</Text> <Barcode offset="11 22" size="33 44"/> ... </TicketTemplate> @@ -38,13 +37,12 @@ The elements are: The attributes are - + - + - diff --git a/examples/bill.odt b/examples/bill.odt new file mode 100644 index 0000000000000000000000000000000000000000..2d79f00aa066f929d8ddef9d7fc0c5a07d2c3e4c GIT binary patch literal 10348 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 literal 0 HcmV?d00001 diff --git a/examples/ticket.xtt b/examples/ticket.xtt index 8744b4a5bea1a01d42a51b9f63e5dfc5d72de3af..be0929d624b3165e62a8343f70c8b1259de6455b 100644 GIT binary patch literal 492 zcmWIWW@Zs#U|`^2$m=S%__hA?rT|6;hR;k43_J{?3?-?#1v!Z&sd^Q;IiVq(49o(} z&)hp^JaZ4NU}1Q{{DOJvr2Bq{3`CBtf2!HH*M%+h@p{H4DLC$A>jM`fu2j54B1@UuLWRw!H3sW;I{={Xk2NFvegG&l92ZIUE(9Nxzw#Cap7> z$18nr@!<`rtUggo!={#fc{VA?;DPHdZywRl+6l%}IdmT$yliw!Av{6iWhlG7h)&9i zsmCSO1Qt#goY3vsv&&`Szva=*2WGL};s5P&Qnc~zy{ozgO3e#vpZ3f-nPc+iYS2wt zNuQh2{DGPu44NcASI!AK_(i>E>uRGK$qzdoNgR0<{nE*B-80S@{?9+(bi9;YoOled-39gb~9=x03@F9Zd`@}EGYA!JXtE-u&85idDr+@t!pL26v!5 zP6p=RXP&r!y#B;Jw1S1<1@jB$-bv^E4mk)MJO4@KvD`$bOx=1Ofh&_dHY9DydX$^n zzG>rb?`_dZ9sG|E|CErsqomr{Y%qQ9%#{6qYd2r!j{MSBZ{@PjW2M^(*2}erEE{{) zZt&k@wu4VH#II`kw5O+~EXwYdy)HYhBEF4RY|n{|KBvn|*zB%anhP1)oW065lkK$D zy0#w+6V+M+_Z=+hoaH*DVa{126W!&(-xqi$cm_}Fu)A2~m@wJhO;S{n=kMtPk-p}O z8?I|yF>^3jnD4XTnn3;HrUo?~?SzC+%0|h{xZ=fZ^dy$e{C90xp-Epk!}CNd-fsc( z0?%?kG_E)+{KV*B$YHBh3CBv@EuDOfcZ3@SPWk+%V%9sxSp_op-uXZKy#I&uu0>jt z3N5E@(uyxz_%d(%fjIHrpgk{lJday__vNh(%Bn@@&brIwp2?IgDYG^Fulz3m?9Afy iME0ri0p5&E;>=j$V)6<`HBi7$zQ`!b)((sv1_l64O}|9| diff --git a/src/code39.cpp b/src/code39.cpp index a4eb35c..e292b5b 100644 --- a/src/code39.cpp +++ b/src/code39.cpp @@ -54,7 +54,7 @@ static QMap initmap() map.insert('K',"0001010101110001"); map.insert('L',"0100010101110001"); map.insert('M',"0001000101011101"); - map.insert('0',"0101000101110001"); + map.insert('N',"0101000101110001"); map.insert('O',"0001010001011101"); map.insert('P',"0100010001011101"); map.insert('Q',"0101010001110001"); @@ -81,12 +81,15 @@ static char code39mod(QString str) return c39mod[sum%43].toAscii(); } -QPixmap code39(QString str) +QImage code39(QString str) { //check string, return empty pixmap if invalid str=str.toUpper(); for(int i=0;i %c",str.toAscii().data(),code39mod(str)); + //define xpm + char *xpm[4]; + QByteArray xpmsz=QString().sprintf("%i 1 2 1",rstr.size()).toAscii(); + xpm[0]=xpmsz.data(); + xpm[1]="0\tg #000000"; + xpm[2]="1\tg #FFFFFF"; + QByteArray xpmc=rstr.toAscii(); + xpm[3]=xpmc.data(); //create pixmap - QPixmap pix(str.size()*16,1); - QPainter dev(&pix); - dev.setPen(Qt::black); - //paint - pix.fill(Qt::white); - for(int i=0;i +#include #include /**Takes a string and converts it into a code-39 bar code. Code-39 allows letters (case-insensitive), digits, spaces and the special chars "-.$/+%". The bar code pixmap will be 1 pixel high and 16 pixels wide for each character (plus start/stop character and checksum character) - it needs to be scaled up to fit the intended size.*/ -QPixmap code39(QString); +QImage code39(QString); diff --git a/src/event.cpp b/src/event.cpp index 6c71acd..05abff0 100644 --- a/src/event.cpp +++ b/src/event.cpp @@ -24,6 +24,14 @@ MEvent::MEvent(MWebRequest*r,int id) refresh(); } +MEvent::MEvent() +{ + req=0; + eventid=-1; + m_starttime=m_endtime=m_capacity=m_defaultprice=0; + m_valid=m_complete=false; +} + MEvent::MEvent(MWebRequest*r,QDomElement&el) { req=r; @@ -41,6 +49,29 @@ MEvent::MEvent(MWebRequest*r,QDomElement&el) else initFromElement(el); } +MEvent::MEvent(const MEvent&e) +{ + operator=(e); +} + +MEvent& MEvent::operator=(const MEvent&e) +{ + req=e.req; + eventid=e.eventid; + m_title=e.m_title; + m_artist=e.m_artist; + m_description=e.m_description; + m_starttime=e.m_starttime; + m_endtime=e.m_endtime; + m_roomid=e.m_roomid; + m_capacity=e.m_capacity; + m_defaultprice=e.m_defaultprice; + m_cancelreason=e.m_cancelreason; + m_valid=e.m_valid; + m_complete=e.m_complete; + return *this; +} + void MEvent::refresh() { m_starttime=QDateTime::currentDateTime().toTime_t(); @@ -218,4 +249,14 @@ void MEvent::setPrice(QString str) if(ps.size()>=1)prc=ps[0].toInt()*100; if(ps.size()>=2)prc+=ps[1].toInt(); m_defaultprice=prc; -} \ No newline at end of file +} + +QString MEvent::startTimeString()const +{ + return QDateTime::fromTime_t(m_starttime).toString(QCoreApplication::translate("MEvent","yyyy-MM-dd hh:mm ap","date/time format")); +} + +QString MEvent::endTimeString()const +{ + return QDateTime::fromTime_t(m_endtime).toString(QCoreApplication::translate("MEvent","yyyy-MM-dd hh:mm ap","date/time format")); +} diff --git a/src/event.h b/src/event.h index 19ef9d6..2d3dea6 100644 --- a/src/event.h +++ b/src/event.h @@ -22,13 +22,20 @@ class QDomElement; class MEvent { public: + /**creates an invalid event*/ + MEvent(); /**creates an event by ID, the constructor asks the server/database for details*/ MEvent(MWebRequest*,int); /**creates an event via a DOM-element, used by WebRequest::getAllEvents*/ MEvent(MWebRequest*,QDomElement&); + /**copies an event*/ + MEvent(const MEvent&); /**destructs an event*/ ~MEvent(); + /**copies the event*/ + MEvent& operator=(const MEvent&); + /**updates data from the database, can be used to upgrade an incomplete event to a complete one*/ void refresh(); @@ -48,6 +55,10 @@ class MEvent int startTime()const{return m_starttime;} /**returns the end time of the event as Unix timestamp*/ int endTime()const{return m_endtime;} + /**returns the start time of the event as localized string*/ + QString startTimeString()const; + /**returns the end time of the event as localized string*/ + QString endTimeString()const; /**returns the room of the event, the room must be one out of the list of valid rooms*/ QString room()const{return m_roomid;} /**returns the amount of tickets than can be sold for this event, initially this should be a copy of the rooms capacity*/ diff --git a/src/eventsummary.cpp b/src/eventsummary.cpp index 0a9acdb..0869e71 100644 --- a/src/eventsummary.cpp +++ b/src/eventsummary.cpp @@ -23,6 +23,7 @@ #include #include #include +#include MEventSummary::MEventSummary(QWidget*par,MWebRequest*rq,int eid) :QDialog(par) @@ -139,7 +140,12 @@ void MEventSummary::getSummaryData() void MEventSummary::print() { - MOdtSignalRenderer rend("../examples/eventsummary.odtt"); + QString tf=req->getTemplate("eventsummary.odtt"); + if(tf==""){ + QMessageBox::warning(this,tr("Warning"),tr("Unable to get template file (eventsummary.odtt). Giving up.")); + return; + } + MOdtSignalRenderer rend(tf); connect(&rend,SIGNAL(getVariable(QString,QString&)),this,SLOT(getVariable(QString,QString&))); connect(&rend,SIGNAL(getLoopIterations(QString,int&)),this,SLOT(getLoopIterations(QString,int&))); connect(&rend,SIGNAL(getLoopVariable(QString,int,QString,QString&)),this,SLOT(getLoopVariable(QString,int,QString,QString&))); diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 6495198..778dd8b 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -199,7 +199,7 @@ void MMainWindow::startLogin() //make it impossible for the user to interfere setEnabled(false); //create request object - MWebRequest *mw=new MWebRequest; + MWebRequest *mw=new MWebRequest(profiles->itemData(profiles->currentIndex()).toString()); mw->setUrl(serverurl->text()); if(useproxy->isChecked()) mw->setProxy(proxyname->text(),proxyport->value(),proxyuser->text(),proxypass->text()); diff --git a/src/order.cpp b/src/order.cpp index 68ec1d2..6779cf9 100644 --- a/src/order.cpp +++ b/src/order.cpp @@ -20,8 +20,9 @@ MOrder::MOrder() { req=0; m_orderid=m_customer=-1; - m_price=m_paid=0; + m_price=m_paid=m_otime=m_stime=0; m_status=Invalid; + m_complete=false; } MOrder::MOrder(MWebRequest*r,qint32 id) @@ -30,7 +31,7 @@ MOrder::MOrder(MWebRequest*r,qint32 id) getFromDB(id); } -MOrder::MOrder(MWebRequest*r,QDomElement&e) +MOrder::MOrder(MWebRequest*r,const QDomElement&e) { req=r; parseXml(e); @@ -38,12 +39,25 @@ MOrder::MOrder(MWebRequest*r,QDomElement&e) MOrder::MOrder(const MOrder&o) { + operator=(o); +} + +MOrder& MOrder::operator=(const MOrder&o) +{ req=o.req; m_orderid=o.m_orderid; m_customer=o.m_customer; m_price=o.m_price; m_paid=o.m_paid; m_status=o.m_status; + m_otime=o.m_otime; + m_stime=o.m_stime; + m_complete=o.m_complete; + m_tickets=o.m_tickets; + m_seller=o.m_seller; + m_deladdress=o.m_deladdress; + m_comment=o.m_comment; + return *this; } int MOrder::orderID()const @@ -53,7 +67,7 @@ int MOrder::orderID()const bool MOrder::isValid()const { - return m_orderid>=0 && m_status!=Invalid; + return m_status!=Invalid; } int MOrder::customerID()const @@ -78,6 +92,10 @@ QString MOrder::orderStatusString()const case Sent:return QCoreApplication::translate("MOrder","sent","state"); case Cancelled:return QCoreApplication::translate("MOrder","cancelled","state"); case Closed:return QCoreApplication::translate("MOrder","closed","state"); + case CheckOk:return QCoreApplication::translate("MOrder","check: ok","state"); + case CheckSaleOnly:return QCoreApplication::translate("MOrder","check: sale only","state"); + case CheckOrderOnly:return QCoreApplication::translate("MOrder","check: order only","state"); + case CheckFail:return QCoreApplication::translate("MOrder","check: failed","state"); default:return QCoreApplication::translate("MOrder","invalid","state"); } } @@ -143,17 +161,35 @@ int MOrder::amountToRefund()const bool MOrder::isSent()const { - //only in placed mode there is a need for action, hence in all other modes we assum sent + //only in placed mode there is a need for action, hence in all other modes we assume sent return m_status!=Placed; } void MOrder::getFromDB(qint32 i) { - //TODO + if(!req)return; + if(i<0)return; + //request + if(!req->request("getorder",QByteArray::number(i)))return; + if(req->responseStatus()!=MWebRequest::Ok)return; + //parse + QDomDocument doc; + if(!doc.setContent(req->responseBody())){ + qDebug("Unable to parse response to getorder request."); + return; + } + parseXml(doc.documentElement()); } void MOrder::parseXml(const QDomElement&e) { + //reset + m_complete=false; + m_otime=m_stime=0; + m_seller=""; + m_deladdress=""; + m_comment=""; + m_tickets.clear(); //Basics bool b; m_orderid=e.attribute("id","-1").toInt(&b); @@ -171,6 +207,244 @@ void MOrder::parseXml(const QDomElement&e) if(st=="placed")m_status=Placed;else if(st=="sent")m_status=Sent;else if(st=="cancelled")m_status=Cancelled;else - if(st=="closed")m_status=Closed; + if(st=="closed")m_status=Closed;else + if(st=="ok")m_status=CheckOk;else + if(st=="saleonly")m_status=CheckSaleOnly;else + if(st=="orderonly")m_status=CheckOrderOnly;else + if(st=="fail")m_status=CheckFail; else m_status=Invalid; + //complete stuff + if(!e.hasAttribute("seller"))return; + m_complete=true; + m_otime=e.attribute("ordertime","0").toInt(); + m_stime=e.attribute("senttime","0").toInt(); + m_seller=e.attribute("seller"); + QDomNodeList nl=e.elementsByTagName("DeliveryAddress"); + for(int i=0;i MOrder::tickets() +{ + makeComplete(); + return m_tickets; +} + +/****************************************************************************** + * Ticket + ******************************************************************************/ + +MTicket::MTicket() +{ + req=0; + m_eventid=m_orderid=-1; + m_price=0; + m_status=Invalid; +} + +MTicket::MTicket(MWebRequest*r,const QDomElement&e) +{ + req=r; + m_eventid=e.attribute("event","-1").toInt(); + m_orderid=e.attribute("order","-1").toInt(); + m_id=e.attribute("id"); + m_price=e.attribute("price","0").toInt(); + QString st=e.attribute("status"); + if(st=="bought")m_status=Bought;else + if(st=="refund")m_status=Refund;else + if(st=="used")m_status=Used;else + if(st=="reserved")m_status=Reserved;else + if(st=="ok")m_status=CheckOk;else + if(st=="saleonly")m_status=CheckSaleOnly;else + if(st=="orderonly")m_status=CheckOrderOnly;else + if(st=="toolate")m_status=CheckFailTooLate;else + if(st=="exhausted")m_status=CheckFailExhausted;else + if(st=="cancelled")m_status=CheckFailCancelled;else + if(st=="invalid")m_status=CheckFailEventInvalid; + else m_status=Invalid; +} + +MTicket::MTicket(const MTicket&t) +{ + operator=(t); +} + +MTicket& MTicket::operator=(const MTicket&t) +{ + req=t.req; + m_eventid=t.m_eventid; + m_orderid=t.m_orderid; + m_price=t.m_price; + m_status=t.m_status; + m_id=t.m_id; + return *this; +} + +bool MTicket::isValid()const +{ + return m_status!=Invalid; +} + +QString MTicket::ticketID()const +{ + return m_id; +} + +qint32 MTicket::orderID()const +{ + return m_orderid; +} + +int MTicket::price()const +{ + return m_price; +} + +QString MTicket::priceString()const +{ + return QString::number(m_price/100)+QCoreApplication::translate("MTicket",".","decimal dot")+QString().sprintf("%02d",m_price%100); +} + +qint32 MTicket::eventID()const +{ + return m_eventid; +} + +MEvent MTicket::event()const +{ + if(m_status==Invalid)return MEvent(); + if(m_eventid<0)return MEvent(); + if(!m_event.isValid()) + m_event=MEvent(req,m_eventid); + return m_event; +} + +MTicket::TicketStatus MTicket::status()const +{ + return m_status; +} + +QString MTicket::statusString()const +{ + switch(m_status){ + case Bought:return QCoreApplication::translate("MTicket","bought","ticket state"); + case Refund:return QCoreApplication::translate("MTicket","to refund","ticket state"); + case Used:return QCoreApplication::translate("MTicket","used","ticket state"); + case Reserved:return QCoreApplication::translate("MTicket","reserved","ticket state"); + case CheckOk:return QCoreApplication::translate("MTicket","ok","ticket state"); + case CheckSaleOnly:return QCoreApplication::translate("MTicket","sale only","ticket state"); + case CheckOrderOnly:return QCoreApplication::translate("MTicket","order only","ticket state"); + case CheckFailTooLate:return QCoreApplication::translate("MTicket","too late: event over","ticket state"); + case CheckFailExhausted:return QCoreApplication::translate("MTicket","no more tickets","ticket state"); + case CheckFailCancelled:return QCoreApplication::translate("MTicket","event cancelled","ticket state"); + case CheckFailEventInvalid:return QCoreApplication::translate("MTicket","no such event","ticket state"); + default:return QCoreApplication::translate("MTicket","invalid","ticket state"); + } +} + +void MTicket::setOrderID(qint32 o) +{ + m_orderid=o; } diff --git a/src/order.h b/src/order.h index f1a883c..9a1e3ba 100644 --- a/src/order.h +++ b/src/order.h @@ -14,12 +14,104 @@ #define MAGICSMOKE_ORDER_H #include +#include +#include #include "customer.h" +#include "event.h" + class MWebRequest; class QDomElement; +/**this class represents a single ticket*/ +class MTicket +{ + public: + /**creates an invalid ticket*/ + MTicket(); + /**creates a ticket from XML*/ + MTicket(MWebRequest*,const QDomElement&); + /**copies a ticket*/ + MTicket(const MTicket&); + + /**copies the ticket*/ + MTicket& operator=(const MTicket&); + + /**returns whether the ticket is valid*/ + bool isValid()const; + + /**returns the ID of the ticket*/ + QString ticketID()const; + + /**returns the ID of the order this ticket belongs to (-1 if it is invalid or does not belong to an order)*/ + qint32 orderID()const; + + /**returns the price of the ticket (in cent)*/ + int price()const; + + /**returns the price of the ticket as localized string*/ + QString priceString()const; + + /**returns the ID of the event the ticket belongs to*/ + qint32 eventID()const; + + /**returns the event for this ticket (queries DB once)*/ + MEvent event()const; + + /**represents the status of a ticket*/ + enum TicketStatus{ + /**the ticket object is invalid*/ + Invalid=0, + /**Mask to find out whether the ticket is stored or has a check status*/ + Mask=0xf0, + /**Flag: the ticket is stored in the DB (status&Mask==MaskIsStored)*/ + MaskIsStored=0x10, + /**the ticket has been bought, but not yet used*/ + Bought=0x10, + /**the ticket has been refunded or needs refund (eg. after the event was cancelled)*/ + Refund=0x11, + /**the ticket has been used*/ + Used=0x12, + /**the ticket has been reserved by a seller*/ + Reserved=0x13, + /**Flag: the ticket has been checked only (status&Mask==MaskIsChecked)*/ + MaskIsChecked=0x20, + /**check status: the ticket can be ordered*/ + CheckOk=0x20, + /**check status: the ticket can only be sold, not ordered for later delivery*/ + CheckSaleOnly=0x21, + /**check status: this ticket can be ordered for later delivery, but not sold*/ + CheckOrderOnly=0x22, + /**check status: the ticket order fails, because order times are over*/ + CheckFailTooLate=0x23, + /**check status: the ticket order fails, because there are not enough tickets left*/ + CheckFailExhausted=0x24, + /**check status: the ticket order fails, because the event was cancelled*/ + CheckFailCancelled=0x25, + /**check status: the ticket order fails, because the event does not exist*/ + CheckFailEventInvalid=0x26 + }; + + /**returns the status of the ticket*/ + TicketStatus status()const; + + /**returns the ticket status as string*/ + QString statusString()const; + + protected: + friend class MOrder; + /**sets the order-ID of the ticket, used by MOrder*/ + void setOrderID(qint32); + + private: + MWebRequest*req; + qint32 m_eventid,m_orderid,m_price; + TicketStatus m_status; + QString m_id; + mutable MEvent m_event; +}; + class MOrder { public: @@ -28,11 +120,14 @@ class MOrder /**create order by id*/ MOrder(MWebRequest*,qint32); /**create order from XML element*/ - MOrder(MWebRequest*,QDomElement&); + MOrder(MWebRequest*,const QDomElement&); /**copy order*/ MOrder(const MOrder&); - /**returns the order ID (-1 for invalid orders)*/ + /**copies the order*/ + MOrder& operator=(const MOrder&); + + /**returns the order ID (-1 for invalid orders or after a simple check)*/ int orderID()const; /**returns whether the order is valid*/ @@ -47,15 +142,29 @@ class MOrder /**status*/ enum OrderStatus{ /**the order is invalid (not a DB state)*/ - Invalid, + Invalid=0, + /**mask code to find general status of the order*/ + Mask=0xf0, + /**status codes that have this bit (status&Mask==MaskIsStored) set are stored in the DB*/ + MaskIsStored=0x10, /**the order has been placed, nothing is delivered or paid*/ - Placed, + Placed=0x10, /**the tickets/vouchers have been shipped*/ - Sent, + Sent=0x11, /**the order was cancelled*/ - Cancelled, + Cancelled=0x12, /**the order is closed (currently unused state)*/ - Closed + Closed=0x13, + /**status codes that have this bit (status&Mask==MaskIsChecked) set are checked only*/ + MaskIsChecked=0x20, + /**check status: this order would pass*/ + CheckOk=0x20, + /**check status: this order can be sold, but not ordered for later delivery*/ + CheckSaleOnly=0x21, + /**check status: this order can be ordered for later delivery, but not sold*/ + CheckOrderOnly=0x22, + /**check status: the order fails*/ + CheckFail=0x23 }; /**returns the status of the order*/ @@ -91,10 +200,49 @@ class MOrder /**returns whether the tickets of this order have already been shipped*/ bool isSent()const; + /**returns the order date+time*/ + QDateTime orderDateTime(); + + /**returns the order date+time as string*/ + QString orderDateTimeStr(); + + /**returns the order date only*/ + QDate orderDate(); + + /**returns the order date only as string*/ + QString orderDateStr(); + + /**returns the shipping date+time*/ + QDateTime sentDateTime(); + + /**returns the shipping date+time as string*/ + QString sentDateTimeStr(); + + /**returns the shipping date only*/ + QDate sentDate(); + + /**returns the shipping date only as string*/ + QString sentDateStr(); + + /**returns the seller of this order*/ + QString seller(); + + /**returns the delivery address (empty string if none is set)*/ + QString deliveryAddress(); + + /**returns the comment of the order (empty string if none set)*/ + QString comment(); + + /**returns the list of tickets of this order*/ + QList tickets(); + private: MWebRequest*req; - int m_orderid,m_customer,m_price,m_paid; + int m_orderid,m_customer,m_price,m_paid,m_otime,m_stime; OrderStatus m_status; + QString m_seller,m_deladdress,m_comment; + bool m_complete; + QList m_tickets; /**internal: requests the order from the database*/ void getFromDB(qint32); @@ -104,6 +252,9 @@ class MOrder /**helper: converts a cent value into a localized string*/ static QString cent2string(int); + + /**internal: makes sure the order is completely retrieved*/ + void makeComplete(); }; #endif diff --git a/src/orderwin.cpp b/src/orderwin.cpp new file mode 100644 index 0000000..7e4b6ec --- /dev/null +++ b/src/orderwin.cpp @@ -0,0 +1,218 @@ +// +// C++ Implementation: orderwin +// +// Description: +// +// +// Author: Konrad Rosenbaum , (C) 2008 +// +// Copyright: See README/COPYING files that come with this distribution +// +// + +#include "orderwin.h" +#include "event.h" +#include "webrequest.h" +#include "ticketrender.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +MOrderWindow::MOrderWindow(QWidget*par,MWebRequest*r,const MOrder&o) + :QMainWindow(par),req(r),m_order(o) +{ + setWindowTitle(tr("Order Details")); + m_changed=false; + + QMenuBar*mb=menuBar(); + QMenu *m=mb->addMenu(tr("&Order")); + m->addAction(tr("&Order...")); + m->addAction(tr("&Sell...")); + m->addSeparator(); + m->addAction(tr("C&ancel Order...")); + m->addSeparator(); + m->addAction(tr("&Close"),this,SLOT(close())); + m=mb->addMenu(tr("&Payment")); + m->addAction(tr("Receive &Payment...")); + m->addAction(tr("&Refund...")); + m=mb->addMenu(tr("P&rinting")); + m->addAction(tr("Print &Bill...")); + m->addAction(tr("Save Bill &as file...")); + m->addSeparator(); + m->addAction(tr("Print &Tickets...")); + m->addAction(tr("Print &Current Ticket..."),this,SLOT(printCurrentTicket())); + m->addAction(tr("&View Tickets..."),this,SLOT(ticketView())); + + QWidget*w; + setCentralWidget(w=new QWidget); + QVBoxLayout *vl; + w->setLayout(vl=new QVBoxLayout); + + QGridLayout*gl; + vl->addLayout(gl=new QGridLayout,0); + int rw=0; + gl->addWidget(new QLabel(tr("Order ID:")),rw,0); + gl->addWidget(m_orderid=new QLabel(QString::number(m_order.orderID())),rw,1); + gl->addWidget(new QLabel(tr("Order Date:")),++rw,0); + gl->addWidget(m_orderdate=new QLabel(m_order.orderDateTimeStr()),rw,1); + gl->addWidget(new QLabel(tr("Shipping Date:")),++rw,0); + gl->addWidget(m_sentdate=new QLabel(m_order.sentDateTimeStr()),rw,1); + gl->addWidget(new QLabel(tr("Customer:")),++rw,0); + gl->addWidget(new QLabel(m_order.customer().getNameAddress()),rw,1); + gl->addWidget(new QLabel(tr("Sold by:")),++rw,0); + gl->addWidget(new QLabel(m_order.seller()),rw,1); + gl->addWidget(new QLabel(tr("Total Price:")),++rw,0); + gl->addWidget(new QLabel(m_order.totalPriceString()),rw,1); + gl->addWidget(new QLabel(tr("Already Paid:")),++rw,0); + gl->addWidget(new QLabel(m_order.amountPaidString()),rw,1); + gl->addWidget(new QLabel(tr("Order State:")),++rw,0); + gl->addWidget(m_state=new QLabel(m_order.orderStatusString()),rw,1); + gl->setColumnStretch(0,0); + gl->setColumnStretch(1,10); + + vl->addSpacing(10); + vl->addWidget(m_tickettable=new QTableView,10); + m_tickettable->setModel(m_ticketmodel=new QStandardItemModel(this)); + m_tickettable->setEditTriggers(QAbstractItemView::NoEditTriggers); + updateTable(); + + req->dataDir(); +} + +void MOrderWindow::updateTable() +{ + QList tickets=m_order.tickets(); + QList events; + if(tickets.size()>0) + events=req->getAllEvents(); + m_ticketmodel->setHorizontalHeaderLabels(QStringList()<insertRows(0,tickets.size()); + for(int i=0;isetData(m_ticketmodel->index(i,0),tickets[i].ticketID()); + m_ticketmodel->setData(m_ticketmodel->index(i,3),tickets[i].statusString()); + m_ticketmodel->setData(m_ticketmodel->index(i,4),tickets[i].priceString()); + //find event + MEvent ev;int eid=tickets[i].eventID(); + for(int j=0;jsetData(m_ticketmodel->index(i,1),ev.title()); + m_ticketmodel->setData(m_ticketmodel->index(i,2),ev.startTimeString()); + } + m_tickettable->resizeColumnsToContents(); +} + +void MOrderWindow::setChanged() +{ + m_changed=true; +} + +bool MOrderWindow::isChanged()const +{ + return m_changed; +} + +void MOrderWindow::ticketView() +{ + QListtickets=m_order.tickets(); + if(tickets.size()<1)return; + MTicketView tv(this,tickets); + tv.exec(); +} + +void MOrderWindow::printCurrentTicket() +{ + //get current ticketid + QModelIndexList lst=m_tickettable->selectionModel()->selectedIndexes(); + if(lst.size()<1)return; + QModelIndex idx=m_ticketmodel->index(lst[0].row(),0); + QString id=m_ticketmodel->data(idx).toString(); + if(id=="")return; + //find ticket + QListtickets=m_order.tickets(); + MTicket tick; + for(int i=0;i()< tickets) +{ + //sanity check + if(tickets.size()<1)return; + //get template + QString tf=req->getTemplate("ticket.xtt"); + if(tf==""){ + QMessageBox::warning(this,tr("Warning"),tr("Unable to get template file (ticket.xtt). Giving up.")); + return; + } + //get printer settings + QPrinter printer; + QPrintDialog pd(&printer,this); + if(pd.exec()!=QDialog::Accepted)return; + //TODO: insert label arrangement + //TODO: fix to use correct template + MTicketRenderer render(tf); + QPainter painter(&printer); + render.render(tickets[0],printer,&painter); + +} + + +/*************************************************************************************/ + +MTicketView::MTicketView(QWidget*w,QListt) + :QDialog(w),tickets(t) +{ + setWindowTitle(tr("Preview Tickets")); + + QVBoxLayout*vl; + setLayout(vl=new QVBoxLayout); + QComboBox *cb; + vl->addWidget(cb=new QComboBox,0); + cb->setEditable(false); + for(int i=0;iaddItem(tickets[i].ticketID()); + vl->addWidget(disp=new QLabel,10); + //TODO: get the real template! + render=new MTicketRenderer("../examples/ticket.xtt"); + changeTicket(0); + connect(cb,SIGNAL(currentIndexChanged(int)),this,SLOT(changeTicket(int))); +} + +MTicketView::~MTicketView() +{ + delete render; +} + +void MTicketView::changeTicket(int idx) +{ + + QSizeF sz=render->ticketSize(*disp); + QPixmap tick(sz.toSize()); + tick.fill(); + if(!render->render(tickets[idx],tick)) + qDebug("unable to render"); + disp->setPixmap(tick); +} diff --git a/src/orderwin.h b/src/orderwin.h new file mode 100644 index 0000000..3eb8e16 --- /dev/null +++ b/src/orderwin.h @@ -0,0 +1,78 @@ +// +// C++ Interface: orderwin +// +// Description: +// +// +// Author: Konrad Rosenbaum , (C) 2008 +// +// Copyright: See README/COPYING files that come with this distribution +// +// + +#ifndef MAGICSMOKE_ORDERWIN_H +#define MAGICSMOKE_ORDERWIN_H + +#include +#include "order.h" + +class QLabel; +class QTableView; +class QStandardItemModel; +class MWebRequest; + +/**displays an order and allows the user to execute several commands on it*/ +class MOrderWindow:public QMainWindow +{ + Q_OBJECT + public: + /**creates the order window*/ + MOrderWindow(QWidget*,MWebRequest*,const MOrder&); + + /**returns whether the order has been changed by this window*/ + bool isChanged()const; + + private slots: + /**internal: mark order as changed*/ + void setChanged(); + + /**internal: updates the ticket table*/ + void updateTable(); + + /**internal: show the tickets as graphics*/ + void ticketView(); + /**internal: print the currently selected ticket*/ + void printCurrentTicket(); + /**internal: print all tickets*/ + void printTickets(); + /**internal helper: print list of tickets*/ + void printTickets(QList); + + private: + MWebRequest*req; + MOrder m_order; + bool m_changed; + QLabel *m_orderid,*m_orderdate,*m_sentdate,*m_state; + QTableView *m_tickettable; + QStandardItemModel *m_ticketmodel; +}; + +class MTicketRenderer; + +/**helper class: displays tickets*/ +class MTicketView:public QDialog +{ + Q_OBJECT + public: + MTicketView(QWidget*,QList); + ~MTicketView(); + + private slots: + void changeTicket(int); + private: + QList tickets; + QLabel*disp; + MTicketRenderer*render; +}; + +#endif diff --git a/src/overview.cpp b/src/overview.cpp index 76bdf8d..d9b12c9 100644 --- a/src/overview.cpp +++ b/src/overview.cpp @@ -15,6 +15,7 @@ #include "eventedit.h" #include "checkdlg.h" #include "eventsummary.h" +#include "orderwin.h" #include #include @@ -38,6 +39,8 @@ #include #include #include +#include +#include #define ORDERNONE 0 #define ORDERALL 0xff @@ -59,6 +62,8 @@ MOverview::MOverview(MWebRequest*mw,QString pk) m->addAction(tr("&Offline mode"))->setEnabled(false); m->addAction(tr("Change my &Password"),this,SLOT(setMyPassword())) ->setEnabled(req->hasRole("setmypasswd")); m->addSeparator(); + m->addAction(tr("&Upload Template..."),this,SLOT(uploadTemplate())); + m->addSeparator(); m->addAction(tr("&Close Session"),this,SLOT(close())); m=mb->addMenu(tr("&Event")); @@ -176,13 +181,12 @@ MOverview::MOverview(MWebRequest*mw,QString pk) ordertable->setSelectionMode(QAbstractItemView::SingleSelection); ordertable->setEditTriggers(QAbstractItemView::NoEditTriggers); hl->addLayout(vl=new QVBoxLayout,0); - vl->addWidget(new QPushButton(tr("Details...")),0); - vl->addSpacing(10); - vl->addWidget(new QPushButton(tr("Payment")),0); - vl->addWidget(new QPushButton(tr("Refund")),0); - vl->addSpacing(10); - vl->addWidget(new QPushButton(tr("Print Tickets")),0); - vl->addWidget(new QPushButton(tr("Print Bill")),0); + vl->addWidget(p=new QPushButton(tr("Update")),0); + connect(p,SIGNAL(clicked()),this,SLOT(updateOrders())); + vl->addSpacing(15); + vl->addWidget(p=new QPushButton(tr("Details...")),0); + connect(p,SIGNAL(clicked()),this,SLOT(orderDetails())); + p->setEnabled(req->hasRole("getorder")); vl->addStretch(10); //Entrance Control Tab @@ -883,6 +887,43 @@ void MOverview::updateOrders() } } +void MOverview::orderDetails() +{ + //get selected order + int id; + QModelIndexList ilst=ordertable->selectionModel()->selectedIndexes(); + if(ilst.size()<1)return; + QModelIndex idx=ordermodel->index(ilst[0].row(),0); + id=ordermodel->data(idx,Qt::UserRole).toInt(); + if(id<0)return; + //open order window + MOrderWindow *om=new MOrderWindow(this,req,MOrder(req,id)); + om->setAttribute(Qt::WA_DeleteOnClose); + om->show(); +} + +void MOverview::uploadTemplate() +{ + //get file + QString fn=QFileDialog::getOpenFileName(this,tr("Please select a template file.")); + if(fn=="")return; + //get template name + QString tn=QFileInfo(fn).fileName(); + QRegExp fr("[a-z0-9_\\.]+"); + do{ + bool ok; + tn=QInputDialog::getText(this,tr("Enter Template Name"),tr("Please enter a name for the template file, it should contain only letters, digits, underscores and dots:"),QLineEdit::Normal,tn,&ok).toLower(); + if(!ok)return; + if(fr.exactMatch(tn))break; + QMessageBox::warning(this,tr("Warning"),tr("The template name must only contain letters, digits, underscores and dots.")); + }while(true); + //send it + if(req->setTemplate(tn,fn)) + QMessageBox::information(this,tr("Success"),tr("Successfully uploaded the template.")); + else + QMessageBox::warning(this,tr("Warning"),tr("Unable to upload the template.")); +} + /**********************************************/ MPasswordChange::MPasswordChange(QWidget*par,QString user) diff --git a/src/overview.h b/src/overview.h index 70529ad..d82abe3 100644 --- a/src/overview.h +++ b/src/overview.h @@ -57,6 +57,8 @@ class MOverview:public QMainWindow /**get all orders, update list*/ void updateOrders(); + /**open order detail window*/ + void orderDetails(); /**update list of users*/ void updateUsers(); @@ -114,6 +116,9 @@ class MOverview:public QMainWindow /**react on entry in Entrance tab*/ void entranceValidate(); + /**upload Templates*/ + void uploadTemplate(); + private: //my session object QPointerreq; diff --git a/src/smoke.pro b/src/smoke.pro index c3e7303..14e9cae 100644 --- a/src/smoke.pro +++ b/src/smoke.pro @@ -38,7 +38,9 @@ SOURCES = \ customer.cpp \ checkdlg.cpp \ eventsummary.cpp \ - odtrender.cpp + odtrender.cpp \ + ticketrender.cpp \ + orderwin.cpp #some PHP files are listed below to scan them for translatable items: HEADERS = \ @@ -57,6 +59,8 @@ HEADERS = \ checkdlg.h \ eventsummary.h \ odtrender.h \ + ticketrender.h \ + orderwin.h \ ../www/machine.php \ ../www/inc/machine/session.php \ ../www/inc/machine/host.php \ diff --git a/src/smoke_de.ts b/src/smoke_de.ts index f6ba829..baa2a27 100644 --- a/src/smoke_de.ts +++ b/src/smoke_de.ts @@ -219,7 +219,7 @@ Sie haben nicht das Recht diese Transaktin durchzuführen. - + Internal Error: unknown command, hiccup in code structure. Interner Fehler: unbekanntes Kommando, Fehler in Code-Struktur. Bitte melden Sie diesen Fehler und wie es dazu kam dem Programmierer. @@ -293,6 +293,16 @@ eventsummary Veranstaltungübersicht + + + getorderlist + + + + + getorder + + MCheckDialog @@ -310,47 +320,47 @@ MCustomerDialog - + Customer %1 Kunde %1 - + New Customer Neuer Kunde - + Name: Name: - + Address: Rechnungsadresse: - + Contact Information: Kontaktinformationen: - + Web-Login/eMail: Web-Login/eMail: - + Comment: Kommentar: - + Save Speichern - + Cancel Abbrechen @@ -358,42 +368,42 @@ MCustomerListDialog - + Select a Customer Kunde auswählen - + Customers Kunden - + Details... Details... - + Create new... Neu... - + Delete... Löschen... - + Select Auswählen - + Cancel Abbrechen - + Close Schließen @@ -401,22 +411,28 @@ MEvent - + Event is not complete, cannot save. Veranstaltung ist nicht komplett. Kann nicht speichern. - + [0-9]+\.[0-9]{2} price validator regexp [0-9]+,[0-9]{2} - + . price decimal dot , + + + yyyy-MM-dd hh:mm ap + date/time format + ddd, d.M.yyyy hh:mm + MEventEditor @@ -532,94 +548,94 @@ MEventSummary - + Summary for Event %1 Übersicht zu Veranstaltung %1 - + Title: Titel: - + Artist: Künstler: - + Start: Beginn: - + yyyy-MM-dd hh:mm ap Date+Time format for displaying event start time ddd, d.M.yyyy hh:mm - + Capacity: Sitzplätze: - + Tickets currently reserved: Momentan reservierte Karten: - + Tickets currently cancelled: Momentan abgesagte Karten: - + Tickets currently usable: Momentan nutzbare Karten: - + Total Income: Umsatz: - + . decimal dot , - + Price Preis - + Bought Gekauft - + Used Benutzt - + Unused Unbenutzt - + Print Drucken - + Save as... Speichern unter... - + Close Schließen @@ -838,583 +854,920 @@ At least %1 Bits of random are required. + MOrder + + + placed + state + + + + + sent + state + + + + + cancelled + state + + + + + closed + state + + + + + check: ok + state + + + + + check: sale only + state + + + + + check: order only + state + + + + + check: failed + state + + + + + invalid + state + + + + + . + decimal dot + , + + + + yyyy-MM-dd hh:mm ap + date/time format + ddd, d.M.yyyy hh:mm + + + + yyyy-MM-dd + date format + d.M.yyyy + + + + MOrderWindow + + + Order Details + + + + + &Order + + + + + &Order... + + + + + &Sell... + + + + + C&ancel Order... + + + + + &Close + + + + + &Payment + + + + + Receive &Payment... + + + + + &Refund... + + + + + P&rinting + + + + + Print &Bill... + + + + + Save Bill &as file... + + + + + Print &Tickets... + + + + + Print &Current Ticket... + + + + + &View Tickets... + + + + + Order ID: + + + + + Order Date: + + + + + Shipping Date: + + + + + Customer: + Kunde + + + + Sold by: + + + + + Total Price: + + + + + Already Paid: + + + + + Order State: + + + + + Ticket ID + + + + + Event + + + + + Start Time + Anfangszeit + + + + Status + + + + + Price + Preis + + + MOverview - + &Session &Session - + &Re-Login &Login wiederholen - + &Close Session Session &schließen - + &Event &Veranstaltung - + &Customer &Kunde - + C&onfigure &Konfigurieren - + Events Veranstaltungen - + Warning Warnung - + I was unable to renew the login at the server, the error was: %1 Der erneute Login ist fehlgeschlagen: %1 - + &Offline mode &Offlinemodus - + &New Event... &Neue Veranstaltung... - + &Show all customers &Alle Kunden anzeigen - + C&art &Einkaufswagen - + Add &Ticket Eintrittskarte &hinzufügen - + Add &Voucher &Gutschein hinzufügen - + &Remove Item &Entfernen - + &Abort Shopping &Einkauf abbrechen - + &Show all orders &Alle Bestellungen anzeigen - + New Event... Neue Veranstaltung... - + Details... Details... - + Order Ticket... Bestellen... - + Shopping Cart Einkaufswagen - + Add Ticket Eintrittskarte hinzufügen - + Add Voucher Gutschein hinzufügen - + Remove Item Entfernen - + Customer: Kunde - + Delivery Address: Lieferadresse: - + Comments: Kommentare: - + Clear Von vorn - + Start Time Anfangszeit - + Title Titel - + ddd MMMM d yyyy, h:mm ap time format ddd, d.M.yyyy hh:mm - + &Update Event List &Veranstaltungsliste auffrischen - + &Show/Edit details... &Details anzeigen/editieren... - + Users Nutzer - + New User... Neuer Nutzer... - + Delete User... Nutzer löschen... - + Description... Beschreibung.,. - + Hosts... Hosts... - + Roles... Rollen... - + Hosts Hosts - + Login Name Loginname - + Description Beschreibung - + New User Neuer Nutzer - + Please enter new user name (only letters, digits, and underscore allowed): Neuen Nutzernamen eingeben (Buchstaben, Ziffern, Unterstrich): - + Error Fehler - + The user name must contain only letters, digits, and underscores and must be at least one character long! Der Nutzername darf nur aus Buchstaben, Ziffern und Unterstrich bestehen. Er muss mindestens ein Zeichen enthalten. - + Edit Description Beschreibung ändern - + Descriptionof user %1: Beschreibung von Nutzer %1: - + Change my &Password Mein &Passwort ändern - + Set Password... Passwort setzen... - + New Host... Neuer Host... - + Add This Host... Diesen Host hinzufügen... - + Delete Host... Host löschen... - + Generate New Key... Neuen Schlüssel anlegen... - + Import... Importieren... - + Export... Exportieren... - + Password Passwort - + Please enter an initial password for the user: Bitte geben Sie ein intiales Passwort ein: - + Delete User? Nutzer löschen? - + Really delete user '%1'? Nutzer '%1' wirklich löschen? - + Error setting password: %1 Passwort kann nicht gesetzt werden: %1 - + The password must be non-empty and both lines must match Das Passwort darf nicht leer sein und beide Zeilen müssen übereinstimmen. - + Host Name Hostname - + Host Key Hostkey - + Create New Host Neuen Host anlegen - + Please enter a host name: Bitte geben Sie einen neuen Hostnamen ein: - + The key of this new host could only be generated with %1 bits entropy. Store anyway? Der Key dieses Hosts konnte nur mit %1 Bits Entropie angelegt werde. Trotzdem speichern? - + Delete this Host? Diesen Host löschen? - + Really delete host '%1'? Den Host '%1' wirklich löschen? - + Change Host Key? Hostkey ändern? - + Really change the key of host '%1'? Den Key von Host '%1' wirklich ändern? - + The new key of this host could only be generated with %1 bits entropy. Store anyway? Der Key dieses Hosts konnte nur mit %1 Bits Entropie angelegt werde. Trotzdem speichern? - + Import Key from File Key aus Datei importieren - + Unable to open file %1 for reading: %2 Datei %1 kann nicht zum Lesen geöffnet werden: %2 - + This is not a host key file. Dies ist keine Hostkeydatei. - + This host key file does not contain a valid host name. Die Hostkeydatei enthält keinen gültigen Hostnamen. - + This host key file does not contain a valid key. Diese Datei enthält keinen gültigen Hostkey. - + The key check sum did not match. Please get a clean copy of the host key file. Die Checksumme dieser Datei ist fehlgeschlagen. Bitte besorgen Sie eine neue Kopie der Datei. - + This host cannot be exported. Dieser Host kann nicht exportiert werden. - + Export Key to File Hostkey als Datei speichern - + Unable to open file %1 for writing: %2 Datei %1 kann nicht zum Schreiben geöffnet werden: %2 - + Order Items Bestellung anlegen - + Sell Items Verkaufen - + Order List Bestellungsliste - + -select mode- -Modus auswählen- - + All Orders Alle Bestellungen - + Open Orders Offene Bestellungen - + Outstanding Payments Noch nicht bezahlt - + Outstanding Refunds Offene Rückerstattungen Payment - Bezahlen + Bezahlen Refund - Rückerstattung + Rückerstattung Print Tickets - Eintrittskarten drucken + Eintrittskarten drucken Print Bill - Rechnung drucken + Rechnung drucken - + Amount Anzahl - + Select Event to order Ticket Bitte wählen Sie eine Verstaltung aus, um zu bestellen - + Select Auswählen - + Cancel Abbrechen - + There is nothing in the order. Ignoring it. Bestellung ist leer. Vorgang abgebrochen. - + Please chose a customer first! Bitte wählen Sie zunächst einen Kunden aus! - + The request failed. Anfrage ist fehlgeschlagen. - + A problem occurred during the order: %1 Die Bestellung ist fehlgeschlagen: %1 - + Entrance Einlasskontrolle - + Ticket Ok Eintrittskarte gültig - + Ticket Already Used Die Eintrittkarte wurde bereits benutzt! - + Ticket Not Paid Die Eintrittskarte ist noch nicht bezahlt! - + Ticket Summary... Eintrittskartenübersicht... + + + Undelivered Orders + + + + + Update + + + + + Status + + + + + Total + + + + + Paid + + + + + Customer + + MPasswordChange - + Change my password Mein Passwort ändern - + Reset password of user %1 Passwort von Nutzer %1 setzen - + Old Password: Altes Passwort: - + New Password: Neues Passwort: - + Repeat Password: Paswort wiederholen: - + Set Password Passwort setzen - + Cancel Abbrechen + MTicket + + + . + decimal dot + , + + + + bought + ticket state + + + + + to refund + ticket state + + + + + used + ticket state + + + + + reserved + ticket state + + + + + ok + ticket state + + + + + sale only + ticket state + + + + + order only + ticket state + + + + + too late: event over + ticket state + + + + + no more tickets + ticket state + + + + + event cancelled + ticket state + + + + + no such event + ticket state + + + + + invalid + ticket state + + + + + MTicketView + + + Preview Tickets + + + + MUserHost @@ -1490,7 +1843,7 @@ At least %1 Bits of random are required. Authentifikation fehlgeschlagen. - + Error parsing EventList XML data (line %1 column %2): %3 Fehler beim Lesen der XML-Daten (Zeile %1, Spalte %2): %3 @@ -1500,25 +1853,30 @@ At least %1 Bits of random are required. Passwort kann nicht geändert werden: altes Passwort ist falsch. - + Error parsing RoomList XML data (line %1 column %2): %3 Fehler beim Lesen der Daten (RoomList; Zeile %1, Spalte %2): %3 - + Error parsing UserList XML data (line %1 column %2): %3 Fehler beim Lesen der Daten (UserList; Zeile %1, Spalte %2): %3 - + Error parsing HostList XML data (line %1 column %2): %3 Fehler beim Lesen der Daten (HostList; Zeile %1, Spalte %2): %3 - + Error parsing CustomerList XML data (line %1 column %2): %3 Fehler beim Lesen der Daten (CustomerList; Zeile %1, Spalte %2): %3 + + + Error parsing OrderList XML data (line %1 column %2): %3 + + initkey diff --git a/src/smoke_de_SAX.ts b/src/smoke_de_SAX.ts index cfae056..f380f5a 100644 --- a/src/smoke_de_SAX.ts +++ b/src/smoke_de_SAX.ts @@ -218,7 +218,7 @@ Des darfsde nisch. Da mussde den Baba Adminischdrador frachn. - + Internal Error: unknown command, hiccup in code structure. Isch hab da een Broblem. Irschendwie gibsd das Gommando nur halb, aber och ni' rischdisch. Frach ma' den Brogrammierer. @@ -292,6 +292,16 @@ eventsummary + + + getorderlist + + + + + getorder + + MCheckDialog @@ -309,47 +319,47 @@ MCustomerDialog - + Customer %1 Gunde %1 - + New Customer Neier Gunde - + Name: Dor Name: - + Address: De Adresse: - + Contact Information: Wie mor den erreischen gann: - + Web-Login/eMail: Wie er sisch im Web anmelden gann: - + Comment: Gommendar: - + Save Schbeichorn - + Cancel Doch ni' machen @@ -357,42 +367,42 @@ MCustomerListDialog - + Select a Customer Gunde auswählen - + Customers Gunden - + Details... Dedails anzeichen... - + Create new... Neuen anlechen... - + Delete... Wechschmeißen... - + Select Auswählen - + Cancel Mach ma ni' - + Close Zumachn @@ -400,22 +410,28 @@ MEvent - + Event is not complete, cannot save. De Veranschdaldung is ni gombledd, das gansch so ni abschiggn. - + [0-9]+\.[0-9]{2} price validator regexp [0-9]+,[0-9]{2} - + . price decimal dot , + + + yyyy-MM-dd hh:mm ap + date/time format + + MEventEditor @@ -531,94 +547,94 @@ MEventSummary - + Summary for Event %1 - + Title: Diddel: - + Artist: Günsdlor: - + Start: - + yyyy-MM-dd hh:mm ap Date+Time format for displaying event start time - + Capacity: Magsimale Gäsde: - + Tickets currently reserved: - + Tickets currently cancelled: - + Tickets currently usable: - + Total Income: - + . decimal dot , - + Price - + Bought - + Used - + Unused - + Print - + Save as... - + Close Zumachn @@ -837,54 +853,272 @@ At least %1 Bits of random are required. + MOrder + + + placed + state + + + + + sent + state + + + + + cancelled + state + + + + + closed + state + + + + + check: ok + state + + + + + check: sale only + state + + + + + check: order only + state + + + + + check: failed + state + + + + + invalid + state + + + + + . + decimal dot + , + + + + yyyy-MM-dd hh:mm ap + date/time format + + + + + yyyy-MM-dd + date format + + + + + MOrderWindow + + + Order Details + + + + + &Order + + + + + &Order... + + + + + &Sell... + + + + + C&ancel Order... + + + + + &Close + + + + + &Payment + + + + + Receive &Payment... + + + + + &Refund... + + + + + P&rinting + + + + + Print &Bill... + + + + + Save Bill &as file... + + + + + Print &Tickets... + + + + + Print &Current Ticket... + + + + + &View Tickets... + + + + + Order ID: + + + + + Order Date: + + + + + Shipping Date: + + + + + Customer: + Gunde: + + + + Sold by: + + + + + Total Price: + + + + + Already Paid: + + + + + Order State: + + + + + Ticket ID + + + + + Event + + + + + Start Time + Anfangszeit + + + + Status + + + + + Price + + + + MOverview - + &Session &Sidsung - + &Re-Login &Noch'ma einloggn - + &Close Session Sidsung &Zumachn - + &Event &Veranschdaldung - + &Customer &Gunde - + C&onfigure G&onfiguriern - + Events Veranschdaldungen - + Warning Dumm gelaufen - + I was unable to renew the login at the server, the error was: %1 Isch gann de' Verbindung off'n gross'n Reschner nisch erneuern. Der will nisch weil: %1 - + &Offline mode &Ohne Neds und Dobbelden Boden @@ -894,92 +1128,92 @@ At least %1 Bits of random are required. &Dedails anzeigen... - + &New Event... Veranschdaldung &absach'n... - + &Show all customers &Alle Gunden anzeigen - + C&art Eing&aufswagen - + Add &Ticket Ein&driddsgarde hinzufüchen - + Add &Voucher &Gudschein hinzufüchen - + &Remove Item Doch &ni' nehm' - + &Abort Shopping &Eingauf Abbrechen - + &Show all orders &Alle Beschdellungen anzeichen - + New Event... Neue Veranschdaldung... - + Details... Dedails anzeichen... - + Order Ticket... Eindriddsgarde beschdellen... - + Shopping Cart Eingaufswagen - + Add Ticket Eindriddsgarde hinzufüchen - + Add Voucher Gudschein hinzufüchen - + Remove Item Doch ni' nehm' - + Customer: Gunde: - + Delivery Address: Adresse wo's Zeuch hin soll: - + Comments: Wischdiches Gelaber und Gerede: @@ -989,441 +1223,560 @@ At least %1 Bits of random are required. Beschdellung abschbeichern - + Clear Wechwerfen und von vorne! - + Start Time Anfangszeit - + Title Diddel - + ddd MMMM d yyyy, h:mm ap time format ddd, d.M.yyyy hh:mm - + &Update Event List &Voranschdaldungsliste nochma holen - + &Show/Edit details... &Dedails anzeichen... - + Users Nudsor - + New User... Neier Nudsor... - + Delete User... Nudsor löschen... - + Description... Beschreibung... - + Hosts... Reschnor... - + Roles... Rollen... - + Hosts Reschnor - + Login Name Name zum Anmelden - + Description Beschreibung - + New User Neier Nudsor - + Please enter new user name (only letters, digits, and underscore allowed): Bidde gib ma nen neien Nudsornam' ein (nur Buchschdaben, Ziffern und "_"): - + Error Gans doller falschor Fehler - + The user name must contain only letters, digits, and underscores and must be at least one character long! Dor Nudsorname darf nur Buchschdaben, Ziffern und "_" endhalden. Umlaude sind böse. Und mindesdens een Buchschdaben lang mussor och sein. - + Edit Description Beschreibung ändorn - + Descriptionof user %1: Beschreibung vom Nudsor %1: - + Change my &Password Mei eechnes &Bassword ändorn - + Set Password... Bassword sedsen... - + New Host... Neier Reschnor... - + Add This Host... Die Gisde hier hinzufüchen... - + Delete Host... Reschnor löschen... - + Generate New Key... Neien Schlüssel erzeuchen... - + Import... Imbordieren... - + Export... Eggsbordieren... - + Password Bassword - + Please enter an initial password for the user: Bidde gib ma een Bassword für den Nudsor ein: - + Delete User? Nudsor löschen? - + Really delete user '%1'? Nudsor '%1' wirklich löschen? Bissde Dir da och gans sischor? - + Error setting password: %1 Gann Bassword ni sedsen: %1 - + The password must be non-empty and both lines must match Das Bassword darf nisch leer sein und beide Basswordzeilen müssen gleisch sein. - + Host Name Reschnorname - + Host Key Reschnorschlüssel - + Create New Host Neien Reschnor anlechen - + Please enter a host name: Gib ma nen Nam' für de Gisde ein: - + The key of this new host could only be generated with %1 bits entropy. Store anyway? Dor Schlüssel von der Gisde hat nur %1 zufällige Bids. Das is a bissl wenisch. Drodsdem schbeichorn? - + Delete this Host? De Gisdge löschen? - + Really delete host '%1'? De Gisde '%1' wirklisch löschen? Bissde da och sischor? - + Change Host Key? Den Schlüssel von dem Reschnor ändorn? - + Really change the key of host '%1'? Wirglich den Schlüssel von dem Reschnor '%1' ändorn? Gans sischor? - + The new key of this host could only be generated with %1 bits entropy. Store anyway? Dor Schlüssel von der Gisde hat nur %1 zufällige Bids. Das is a bissl wenisch. Drodsdem schbeichorn? - + Import Key from File Schlüssel aus nor Dadai holen - + Unable to open file %1 for reading: %2 Gann de Dadai %1 nisch lesen. Des iss jedsd geene Ordografieschwäche, sondern: %2 - + This is not a host key file. Das is abor doch gar ge Schlüssel! Willsde misch verarschen? - + This host key file does not contain a valid host name. De Schlüsseldadai had nen gans seldsamen Reschnornamen da drin. Desdorweschen gannsch die ni nehm. - + This host key file does not contain a valid key. De Dadai is a bissl gabudd. Die mussde nochmal holen, ich gann die so ned lesen. - + The key check sum did not match. Please get a clean copy of the host key file. Isch hab da ma nachgereschned. De Scheggsumme vom Schlüssel is falsch. Das gannsch Dir so ni abnehm. - + This host cannot be exported. Den Reschnor gannsch ni schbeichorn. - + Export Key to File Schlüssel als Dadei ablechen - + Unable to open file %1 for writing: %2 Gann de Dadai %1 nicht zum Schreiben offmachen weil: %2 - + Order Items Ne Beschdellung anlegn. - + Sell Items Vorkofen - + Order List Beschdelllisde - + -select mode- -wähl ma was aus- - + All Orders Alle Beschdellungen - + Open Orders Offene Beschdellungen - + Outstanding Payments Wo noch ni bezahld is - + Outstanding Refunds Wo was zurügerschdadded werden muss Payment - Bezahln + Bezahln Refund - Zurügerschdadden + Zurügerschdadden Print Tickets - Eindriddsgarde druggn + Eindriddsgarde druggn Print Bill - Reschnung druggn + Reschnung druggn - + Amount Anzahl - + Select Event to order Ticket Wähl ma ne Voranschdaldung aus um ne Garde zu beschdelln - + Select Auswähln - + Cancel Ni machen - + There is nothing in the order. Ignoring it. Da is doch gar nischd drin. Isch mach das jedsd ni! - + Please chose a customer first! Du mussd schon nen Gunden auswähln, sonsd wees isch doch ni wer's griechen soll! - + The request failed. De Anfrache is schiefgegangen. - + A problem occurred during the order: %1 Isch hadde nen Broblem mit dor Beschdellung: %1 - + Entrance Einlassgondrolle - + Ticket Ok Eindriddsgarde is in Ordnung - + Ticket Already Used Die habsch schonmal gesehn, da will eener bedrüchen. - + Ticket Not Paid Eindriddsgarde is nisch bedsahld. Schiggn ma' an de Gasse. - + Ticket Summary... + + + Undelivered Orders + + + + + Update + + + + + Status + + + + + Total + + + + + Paid + + + + + Customer + + MPasswordChange - + Change my password Mei eechnes Bassword ändorn - + Reset password of user %1 Bassword vom Nudsor %1 zurügsedsen - + Old Password: Aldes Bassword: - + New Password: Neies Bassword: - + Repeat Password: Nochma neies Bassword: - + Set Password Bassword sedsen - + Cancel Vorgisses, ni sedsen + MTicket + + + . + decimal dot + , + + + + bought + ticket state + + + + + to refund + ticket state + + + + + used + ticket state + + + + + reserved + ticket state + + + + + ok + ticket state + + + + + sale only + ticket state + + + + + order only + ticket state + + + + + too late: event over + ticket state + + + + + no more tickets + ticket state + + + + + event cancelled + ticket state + + + + + no such event + ticket state + + + + + invalid + ticket state + + + + + MTicketView + + + Preview Tickets + + + + MUserHost @@ -1499,7 +1852,7 @@ At least %1 Bits of random are required. Isch gann misch ned anmälden. - + Error parsing EventList XML data (line %1 column %2): %3 Isch gann des XML von dor EventList no vorschdehn (Zeile %1, Schbalde %2) weil: %3 @@ -1509,25 +1862,30 @@ At least %1 Bits of random are required. Gann Bassword ni' ändorn, das alde war falsch! - + Error parsing RoomList XML data (line %1 column %2): %3 Isch gann des XML von dor RoomList no vorschdehn (Zeile %1, Schbalde %2) weil: %3 - + Error parsing UserList XML data (line %1 column %2): %3 Isch gann des XML von dor UserList no vorschdehn (Zeile %1, Schbalde %2) weil: %3 - + Error parsing HostList XML data (line %1 column %2): %3 Isch gann des XML von dor HostList no vorschdehn (Zeile %1, Schbalde %2) weil: %3 - + Error parsing CustomerList XML data (line %1 column %2): %3 Isch gann des XML von dor CustomerList no vorschdehn (Zeile %1, Schbalde %2) weil: %3 + + + Error parsing OrderList XML data (line %1 column %2): %3 + + initkey diff --git a/src/ticketrender.cpp b/src/ticketrender.cpp new file mode 100644 index 0000000..c5fe6e9 --- /dev/null +++ b/src/ticketrender.cpp @@ -0,0 +1,470 @@ +// +// C++ Implementation: odtrender +// +// Description: +// +// +// Author: Konrad Rosenbaum , (C) 2008 +// +// Copyright: See README/COPYING files that come with this distribution +// +// + +#include "ticketrender.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "zip/qunzip.h" +#include "zip/qzip.h" +#include "code39.h" +#include "order.h" + + +class MTicketRendererPrivate +{ + protected: + friend class MTicketRenderer; + + MTicketRendererPrivate(QString file,MTicketRenderer*p); + ~MTicketRendererPrivate(); + + //part of the constructor + void prepare(QUnZip&); + + //called by MTicketRenderer + bool render(const MTicket&,QPaintDevice&,QPainter*,QPointF); + + //called by MTicketRenderer + QSizeF ticketSize(const QPaintDevice&); + + private: + MTicketRenderer*parent; + //internal font-IDs + QList fdb; + //image cache: + QMap idb; + //XML template cache (template.xml) + QDomDocument txml; + //contains the unit of measurement + QString unit; + //contains the size of the ticket in "unit" + QSizeF tsize; + //after constructor: contains whether this object is correctly initialized + bool canrender; + + //does the actual rendering work + void render(QDomElement&,const MTicket&,QPaintDevice&,QPainter*,QPointF); + + //renders a single line + QString renderLine(const MTicket&,QString); + + //gets variable content from the ticket + QString getVariable(const MTicket&,QString); + + //parses element to extract offset + QPointF getoffset(QDomElement&,bool); + + //parses element to extract size + QSizeF getsize(QDomElement&,bool); + + //converts a point to "natural" coordinates + QPointF tonatural(const QPaintDevice&,QPointF); + + //converts a size to "natural" coordinates + QSizeF tonatural(const QPaintDevice&,QSizeF); +}; + +MTicketRenderer::MTicketRenderer(QString file) +{ + d=new MTicketRendererPrivate(file,this); +} + +MTicketRendererPrivate::MTicketRendererPrivate(QString file,MTicketRenderer*p) +{ + parent=p; + canrender=false; + //open ZIP + QUnZip temp; + QFile tfile(file); + if(tfile.open(QIODevice::ReadOnly))temp.open(&tfile); + else return; + prepare(temp); + temp.close(); + tfile.close(); + qDebug("Ticket Renderer initialized: %s",canrender?"ready!":"error, can't render."); +} + +void MTicketRendererPrivate::prepare(QUnZip&temp) +{ + //make sure this is a valid ZIP file + if(!temp.locateFile("template.xml")){ + qDebug("Ticket renderer: can't find template.xml"); + canrender=false; + return; + } + //load XML + QBuffer buffer; + buffer.open(QBuffer::ReadWrite); + temp.getCurrentFile(buffer); + if(!txml.setContent(buffer.data())){ + qDebug("Ticket renderer: can't parse template.xml - XML fault."); + canrender=false; + return; + } + //assume we can render now + canrender=true; + //parse document element + QDomElement doc=txml.documentElement(); + unit=doc.attribute("unit","mm"); + if(unit!="mm"&&unit!="in"){ + qDebug("Ticket renderer: illegal unit in template.xml."); + canrender=false; + return; + } + tsize=getsize(doc,true); + if(!canrender)return; + //check for fonts + QDomNodeList nl=txml.elementsByTagName("LoadFont"); + QStringList fndb; + for(int i=0;irender(ticket,pdev,painter,offset); +} + +bool MTicketRendererPrivate::render(const MTicket&ticket,QPaintDevice&pdev,QPainter*painter,QPointF offset) +{ + //sanity check + if(!canrender){ + qDebug("Ticket Renderer: render called, but can't render."); + return false; + } + //actually render + QDomElement el=txml.documentElement(); + render(el,ticket,pdev,painter,offset); + //return result (canrender may be changed by renderer + return canrender; +} + +QPointF MTicketRendererPrivate::getoffset(QDomElement&el,bool isfatal) +{ + QStringList off=el.attribute("offset").split(" "); + if(off.size()!=2){ + if(isfatal){ + qDebug("Ticket renderer error: Illegal offset in %s at line %i column %i.",el.tagName().toAscii().data(),el.lineNumber(),el.columnNumber()); + canrender=false; + } + return QPointF(); + } + QPointF ret; + bool b; + ret.setX(off[0].toDouble(&b)); + if(!b){ + if(isfatal){ + qDebug("Ticket renderer error: Illegal offset in %s at line %i column %i.",el.tagName().toAscii().data(),el.lineNumber(),el.columnNumber()); + canrender=false; + } + return QPointF(); + } + ret.setY(off[1].toDouble(&b)); + if(!b){ + if(isfatal){ + qDebug("Ticket renderer error: Illegal offset in %s at line %i column %i.",el.tagName().toAscii().data(),el.lineNumber(),el.columnNumber()); + canrender=false; + } + return QPointF(); + } + return ret; +} + +QSizeF MTicketRendererPrivate::getsize(QDomElement&el,bool isfatal) +{ + QStringList lst=el.attribute("size").split(" "); + if(lst.size()!=2){ + if(isfatal){ + qDebug("Ticket renderer error: Illegal size (%i items) in %s at line %i column %i.",lst.size(),el.tagName().toAscii().data(),el.lineNumber(),el.columnNumber()); + canrender=false; + } + return QSizeF(); + } + QSizeF ret; + bool b; + ret.setWidth(lst[0].toDouble(&b)); + if(!b){ + if(isfatal){ + qDebug("Ticket renderer error: Illegal size (invalid width) in %s at line %i column %i.",el.tagName().toAscii().data(),el.lineNumber(),el.columnNumber()); + canrender=false; + } + return QSizeF(); + } + ret.setHeight(lst[1].toDouble(&b)); + if(!b){ + if(isfatal){ + qDebug("Ticket renderer error: Illegal size (invalid height) in %s at line %i column %i.",el.tagName().toAscii().data(),el.lineNumber(),el.columnNumber()); + canrender=false; + } + return QSizeF(); + } + return ret; +} + +QPointF MTicketRendererPrivate::tonatural(const QPaintDevice&dev,QPointF p) +{ + double fac; + if(unit=="mm")fac=25.4; + else fac=1.0; + p.setX(p.x()*dev.logicalDpiX()/fac); + p.setY(p.y()*dev.logicalDpiY()/fac); + return p; +} + +QSizeF MTicketRendererPrivate::tonatural(const QPaintDevice&dev,QSizeF s) +{ + double fac; + if(unit=="mm")fac=25.4; + else fac=1.0; + s.setWidth(s.width()*dev.logicalDpiX()/fac); + s.setHeight(s.height()*dev.logicalDpiY()/fac); + return s; +} + +void MTicketRendererPrivate::render(QDomElement&sup, const MTicket&tick, QPaintDevice&pdev, QPainter*painter, QPointF offset) +{ + //initialize painter + QPainter *paint; + if(painter) + paint=painter; + else + paint=new QPainter(&pdev); + QPointF noff=tonatural(pdev,offset); + QSizeF nsize=tonatural(pdev,tsize); + paint->setClipRect(QRectF(noff,nsize)); + //parse file + QDomNodeList nl=sup.childNodes(); + for(int i=0;idrawImage(QRectF(tonatural(pdev,off)+noff,tonatural(pdev,sz)),idb[fname]); + }else + if(enm=="Text"){ + //get attributes + QPointF off=getoffset(el,true); + if(!canrender){ + return; + } + QSizeF sz=getsize(el,true); + if(!canrender){ + return; + } + //get text + QString text=renderLine(tick,el.text().trimmed()); + //get font; TODO: introduce weight and italic settings + QString font=el.attribute("font","Helvetica"); + int size=el.attribute("fontsize","10").toInt(); + if(size<1)size=10; + paint->setFont(QFont(font,size)); + //get alignment + int flag=0; + QString al=el.attribute("align","left"); + if(al=="left")flag=Qt::AlignLeft;else + if(al=="right")flag=Qt::AlignRight; + else flag=Qt::AlignHCenter; + al=el.attribute("valign","top"); + if(al=="top")flag|=Qt::AlignTop;else + if(al=="bottom")flag|=Qt::AlignBottom; + else flag|=Qt::AlignVCenter; + //render + paint->drawText(QRectF(tonatural(pdev,off)+noff,tonatural(pdev,sz)),flag,text); + }else + if(enm=="Barcode"){ + //get attributes + QPointF off=getoffset(el,true); + if(!canrender){ + return; + } + QSizeF sz=getsize(el,true); + if(!canrender){ + return; + } + QString cd=getVariable(tick,"TICKETID"); + //paint + //TODO: find a way to switch off antialiasing + QRectF rect(tonatural(pdev,off)+noff,tonatural(pdev,sz)); + paint->drawImage(rect,code39(cd)); + }else{ + qDebug("Ticket renderer error: unknown element %s in ticket template at line %i column %i.",enm.toAscii().data(),el.lineNumber(),el.columnNumber()); + canrender=false; + return; + } + } + if(!painter) + delete paint; +} + +QString MTicketRendererPrivate::renderLine(const MTicket&tick,QString line) +{ + QString ret,vname; + bool isvar=false; + static QString vc="ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + //scan characters + for(int i=0;iticketSize(dev); +} + +QSizeF MTicketRendererPrivate::ticketSize(const QPaintDevice&dev) +{ + return tonatural(dev,tsize); +} diff --git a/src/ticketrender.h b/src/ticketrender.h new file mode 100644 index 0000000..b07ce48 --- /dev/null +++ b/src/ticketrender.h @@ -0,0 +1,47 @@ +// +// C++ Interface: odtrender +// +// Description: +// +// +// Author: Konrad Rosenbaum , (C) 2008 +// +// Copyright: See README/COPYING files that come with this distribution +// +// + +#ifndef MAGICSMOKE_TICKETRENDER_H +#define MAGICSMOKE_TICKETRENDER_H + +#include +#include +#include + +class MTicketRendererPrivate; +class MTicket; +class QPaintDevice; +class QPainter; + +/**abstract base class for all ODT rendering classes*/ +class MTicketRenderer +{ + public: + /**instantiates a renderer loaded from template file*/ + MTicketRenderer(QString file); + /**deletes the renderer*/ + virtual ~MTicketRenderer(); + + /**renders the ticket; returns whether the rendering was successful*/ + virtual bool render(const MTicket&ticket,QPaintDevice&pdev,QPainter*painter=0,QPointF offset=QPointF()); + + /**returns the size of the ticket in the coordinates of the specified paint device (used for preview)*/ + virtual QSizeF ticketSize(const QPaintDevice&); + + protected: + friend class MTicketRendererPrivate; + + private: + MTicketRendererPrivate*d; +}; + +#endif diff --git a/src/webrequest.cpp b/src/webrequest.cpp index c12d5b3..b22d539 100644 --- a/src/webrequest.cpp +++ b/src/webrequest.cpp @@ -13,6 +13,7 @@ #include "webrequest.h" #include "keygen.h" #include "hmac.h" +#include "main.h" #include #include @@ -20,9 +21,11 @@ #include #include #include +#include -MWebRequest::MWebRequest() +MWebRequest::MWebRequest(QString pid) { + profileid=pid; webtimeout=30000; finid=0;finerr=fin=false; proxyport=-1; @@ -35,6 +38,21 @@ MWebRequest::MWebRequest() } MWebRequest::~MWebRequest(){} +QString MWebRequest::dataDir()const +{ + QString dd="profile."+profileid; + QDir dir(::dataDir); + if(!dir.exists(dd)) + if(!dir.mkpath(dd)) + qDebug("Warning: oh dir! Can't create my data directory!"); + return ::dataDir+"/"+dd; +} + +QString MWebRequest::settingsGroup()const +{ + return "profsettings/"+profileid; +} + bool MWebRequest::request(QString hreq,QByteArray data) { //set up request @@ -318,6 +336,7 @@ QList MWebRequest::getAllEvents() { errstr=""; if(!request("geteventlist"))return QList(); + if(responseStatus()!=Ok)return QList(); //parse return document QDomDocument doc; QString msg;int ln,cl; @@ -341,6 +360,7 @@ QList MWebRequest::getAllRooms() { errstr=""; if(!request("getroomdata",""))return QList(); + if(responseStatus()!=Ok)return QList(); //parse return document QDomDocument doc; QString msg;int ln,cl; @@ -364,6 +384,7 @@ QList MWebRequest::getAllUsers() { errstr=""; if(!request("getusers",""))return QList(); + if(responseStatus()!=Ok)return QList(); //parse return document QDomDocument doc; QString msg;int ln,cl; @@ -387,6 +408,7 @@ QList MWebRequest::getAllHosts() { errstr=""; if(!request("gethosts",""))return QList(); + if(responseStatus()!=Ok)return QList(); //parse return document QDomDocument doc; QString msg;int ln,cl; @@ -410,6 +432,7 @@ QList MWebRequest::getAllCustomers() { errstr=""; if(!request("getcustomerlist",""))return QList(); + if(responseStatus()!=Ok)return QList(); //parse return document QDomDocument doc; QString msg;int ln,cl; @@ -433,6 +456,7 @@ QList MWebRequest::getAllOrders() { errstr=""; if(!request("getorderlist",""))return QList(); + if(responseStatus()!=Ok)return QList(); //parse return document QDomDocument doc; QString msg;int ln,cl; @@ -487,3 +511,90 @@ QString MWebRequest::hostName() { return hostname; } + +QString MWebRequest::getTemplate(QString f) +{ + //syntax check + f=f.toLower(); + QRegExp fregexp("[a-z0-9_\\.]+"); + if(!fregexp.exactMatch(f))return ""; + //do we need an update? + QString dname=dataDir()+"/templates/"; + QSettings set; + set.beginGroup("templates/"+profileid); + QDateTime last=QDateTime::fromTime_t(set.value("lastupdate",0).toInt()+300); + if(last fmap; + for(int i=0;infmap; + for(int i=0;iappendChild($doc); //output + header("X-MagicSmoke-Status: Ok"); print($xml->saveXml()); } +function getOrderXml($oid) +{ + $order=new Order($oid); + if($order->isValid()){ + header("X-MagicSmoke-Status: Ok"); + $order->dumpXml(); + }else{ + header("X-MagicSmoke-Status: Error"); + die(tr("No such orderID in database.")); + } +} + ?> \ No newline at end of file diff --git a/www/inc/machine/template.php b/www/inc/machine/template.php index 0239af3..560a156 100644 --- a/www/inc/machine/template.php +++ b/www/inc/machine/template.php @@ -38,7 +38,7 @@ function getTemplate($fname) function setTemplate($data) { - $pos=strpos($data,'\n'); + $pos=strpos($data,"\n"); if($pos===false){ header("X-MagicSmoke-Status: Error"); die(tr("Unable to find file name")); diff --git a/www/machine.php b/www/machine.php index b941ed0..1614254 100644 --- a/www/machine.php +++ b/www/machine.php @@ -23,7 +23,7 @@ $ALLOWEDREQUESTS=array( tr("geteventlist"),tr("geteventdata"),tr("seteventdata"),tr("eventsummary"), //event infos tr("getroomdata"),tr("setroomdata"),//room infos tr("getcustomerlist"),tr("getcustomer"),tr("setcustomer"), //customer info - tr("checkorder"),tr("createorder"),tr("createsale"),tr("getorderlist"), //sell/order stuff + tr("checkorder"),tr("createorder"),tr("createsale"),tr("getorderlist"),tr("getorder"), //sell/order stuff tr("gettemplatelist"),tr("gettemplate"),tr("settemplate") //templates ); /**contains the low-level request name from the client*/ @@ -280,6 +280,11 @@ if($SMOKEREQUEST=="getorderlist"){ getOrderListXml(); exit(); } +//get a single order +if($SMOKEREQUEST=="getorder"){ + getOrderXml(trim($REQUESTDATA)+0); + exit(); +} //EOF -- 1.7.2.5
AttributeDescription
unitdescribes in what unit sizes and offsets are described in the template, possible values are "mm" (Millimeter), "in" (Inches), "px" (Pixels), the default is "mm". Except for "px" all of them are allowed to use fractions.
unitdescribes in what unit sizes and offsets are described in the template, possible values are "mm" (Millimeter), "in" (Inches); the default is "mm". All of them are allowed to use fractions.
sizedescribes the size the element is scaled to (or in the case of the complete ticket: its total size), it is two positive numbers separated by a space: "width height"
offsetdescribes the position of the element as "X Y" coordinates. Positive numbers describe the distance from the upper left corner, negative numbers the distance from the lower right corner.
offsetdescribes the position of the element as "X Y" coordinates. They describe the distance from the upper left corner.
filea relative file name within the template ZIP file
smoothfor Pictures: describes whether the scaling should be done using edged (0) or smooth (1) scaling
fontcontains the name of a font family that is used for rendering the text (eg. "Helvetica"), the font is searched in the complete font database of the host
embeddedFontcontains the name of a font family that is used for rendering the text, it is searched in the dynmically loaded fonts that are embedded in the template ZIP file; if font and embeddedFont are present, embeddedFont takes precedence
fontsizethe height of the text to render in pt (default is 10)
alignhorizontal alignment of the text: "left" starts the text at its offset, "right" places the text left of its offset, "center" puts the horizontal center of the text on the offset
valignvertical alignment of the text: "top" puts the text below its offset, "bottom" places the text above of its offset, "center" puts the vertical center of the text on the offset