#include "ticketrender.h"
#include "MOTicket"
-
-#include<QAction>
-#include<QBoxLayout>
-#include<QComboBox>
-#include<QCoreApplication>
-#include<QDateTimeEdit>
-#include<QDomDocument>
-#include<QDomElement>
-#include<QDoubleSpinBox>
-#include<QFileDialog>
-#include<QHeaderView>
-#include<QItemDelegate>
-#include<QLabel>
-#include<QLineEdit>
-#include<QMenu>
-#include<QMenuBar>
-#include<QMessageBox>
-#include<QPointF>
-#include<QSettings>
-#include<QSignalMapper>
-#include<QSizeF>
-#include<QSplitter>
-#include<QStandardItemModel>
-#include<QStatusBar>
-#include<QTableView>
-#include<QTemporaryFile>
-#include<QUnZip>
-#include<QZip>
+#include "MOVoucher"
+
+#include <QAction>
+#include <QBoxLayout>
+#include <QComboBox>
+#include <QCoreApplication>
+#include <QDateTimeEdit>
+#include <QDebug>
+#include <QDomDocument>
+#include <QDomElement>
+#include <QDoubleSpinBox>
+#include <QFileDialog>
+#include <QFontDatabase>
+#include <QHeaderView>
+#include <QInputDialog>
+#include <QItemDelegate>
+#include <QLabel>
+#include <QLineEdit>
+#include <QMenu>
+#include <QMenuBar>
+#include <QMessageBox>
+#include <QPointF>
+#include <QPushButton>
+#include <QScrollArea>
+#include <QSettings>
+#include <QSignalMapper>
+#include <QSizeF>
+#include <QSplitter>
+#include <QStandardItemModel>
+#include <QStatusBar>
+#include <QTableView>
+#include <QTemporaryFile>
+#include <QUnZip>
+#include <QZip>
#define HRECT 1
#define HFONT 2
{editor->setGeometry(option.rect);}
};
-class MTENullDelegate:public QItemDelegate
+class MTELabelDelegate:public QItemDelegate
{
+ MTicketEditor*mParent;
public:
- MTENullDelegate(QObject *parent = 0):QItemDelegate(parent) {}
+ MTELabelDelegate(MTicketEditor *parent):QItemDelegate(parent)
+ {mParent=parent;}
QWidget *createEditor(QWidget *, const QStyleOptionViewItem &,
- const QModelIndex &) const {return 0;}
- void setEditorData(QWidget *, const QModelIndex &) const{}
+ const QModelIndex &) const;
+ void setEditorData(QWidget *, const QModelIndex &) const;
void setModelData(QWidget *, QAbstractItemModel *,
- const QModelIndex &) const {}
- void updateEditorGeometry(QWidget *,const QStyleOptionViewItem &,
- const QModelIndex &) const {}
+ const QModelIndex &) const ;
+ void updateEditorGeometry(QWidget *editor,const QStyleOptionViewItem &option,
+ const QModelIndex &) const {editor->setGeometry(option.rect);}
};
class DPTR_CLASS_NAME(MTicketEditor)
Barcode=0x400|HRECT,
};
struct Line_s{
+ Line_s(){type=Unknown;smooth=false;fontsize=0;align=Qt::AlignCenter;}
+ Line_s(int t){type=(Type)t;smooth=false;fontsize=0;align=Qt::AlignCenter;}
Type type;
QSizeF size;
QPointF offset;
QComboBox*unitbox;
QTableView*itemtable,*filetable,*expltable;
QStandardItemModel*itemmodel,*filemodel,*explmodel;
- QWidget*ticketpicture,*voucherpicture;
+ QLabel*ticketpicture;
+ QSlider*zoomslide;
};
DEFINE_DPTR(MTicketEditor);
//menu
QMenuBar*mb=menuBar();
QMenu*m=mb->addMenu(tr("&File"));
- m->addAction(tr("&Open File..."),this,SLOT(openFile()));
- m->addAction(tr("&Save"),this,SLOT(saveFile()));
+ m->addAction(tr("&Open File..."),this,SLOT(openFile()))
+ ->setShortcut(QKeySequence(Qt::Key_Control|Qt::Key_O));
+ m->addAction(tr("&Save"),this,SLOT(saveFile()))
+ ->setShortcut(QKeySequence(Qt::Key_Control|Qt::Key_S));
m->addAction(tr("Save &as..."),this,SLOT(saveFileAs()));
m->addSeparator();
- m->addAction(tr("&Download from server..."),this,SLOT(download()));
- m->addAction(tr("&Upload to server..."),this,SLOT(upload()));
- m->addSeparator();
m->addAction(tr("&Close"),this,SLOT(close()));
m=mb->addMenu(tr("&Edit"));
QMenu *aim=m->addMenu(tr("Add Item"));
- m->addAction(tr("Delete Item"),this,SLOT(delItem()));
+ m->addAction(tr("Remove Item"),this,SLOT(delItem()));
m->addSeparator();
m->addAction(tr("Add File"),this,SLOT(addFile()));
- m->addAction(tr("Delete File"),this,SLOT(delFile()));
+ m->addAction(tr("Remove File"),this,SLOT(delFile()));
QSignalMapper*map=new QSignalMapper(this);
map->setMapping(aim->addAction(tr("Add Text Item"),map,SLOT(map())),(int)Private::Text);
map->setMapping(aim->addAction(tr("Add Picture Item"),map,SLOT(map())),(int)Private::Picture);
setCentralWidget(central);
QWidget*w=new QWidget;
central->addWidget(w);
- QVBoxLayout*vl;
- QHBoxLayout*hl;
+ QVBoxLayout*vl,*vl2;
+ QHBoxLayout*hl,*hl2;
+ QPushButton*p;
w->setLayout(vl=new QVBoxLayout);
vl->addLayout(hl=new QHBoxLayout,0);
+ //basic data line
hl->addWidget(new QLabel(tr("Label Size:")));
hl->addWidget(d->labelwidth=new QDoubleSpinBox);
hl->addWidget(new QLabel("x"));
d->unitbox->addItem(tr("Millimeter"),"mm");
d->unitbox->addItem(tr("Inch"),"in");
hl->addStretch(1);
- vl->addWidget(d->itemtable=new QTableView);
+ //item table
+ vl->addWidget(w=new QWidget);
+ w->setLayout(vl2=new QVBoxLayout);
+ vl2->addWidget(d->itemtable=new QTableView,1);
d->itemtable->setModel(d->itemmodel=new QStandardItemModel(this));
d->itemtable->horizontalHeader()->show();
d->itemtable->verticalHeader()->hide();
+ d->itemtable->setItemDelegate(new MTELabelDelegate(this));
+ vl2->addLayout(hl2=new QHBoxLayout,0);
+ hl2->addStretch(1);
+ hl2->addWidget(p=new QPushButton(QIcon(":/arrowup.png"),tr("Move up")),0);
+ connect(p,SIGNAL(clicked()),this,SLOT(upItem()));
+ hl2->addWidget(p=new QPushButton(QIcon(":/arrowdown.png"),tr("Move down")),0);
+ connect(p,SIGNAL(clicked()),this,SLOT(downItem()));
+ hl2->addSpacing(10);
+ hl2->addWidget(p=new QPushButton(tr("Add Item")),0);
+ p->setMenu(aim);
+ hl2->addWidget(p=new QPushButton(tr("Remove Item")),0);
+ connect(p,SIGNAL(clicked()),this,SLOT(delItem()));
+ //bottom
QSplitter*split;
central->addWidget(split=new QSplitter);
- split->addWidget(d->filetable=new QTableView);
+ //file table
+ split->addWidget(w=new QWidget);
+ w->setLayout(vl2=new QVBoxLayout);
+ vl2->addWidget(d->filetable=new QTableView,1);
d->filetable->setModel(d->filemodel=new QStandardItemModel(this));
d->filetable->horizontalHeader()->show();
d->filetable->verticalHeader()->hide();
- d->filetable->setItemDelegate(new MTENullDelegate(this));
+ d->filetable->setEditTriggers(QAbstractItemView::NoEditTriggers);
+ vl2->addLayout(hl2=new QHBoxLayout,0);
+ hl2->addStretch(1);
+ hl2->addWidget(p=new QPushButton(tr("Add File")),0);
+ connect(p,SIGNAL(clicked()),this,SLOT(addFile()));
+ hl2->addWidget(p=new QPushButton(tr("Remove File")),0);
+ connect(p,SIGNAL(clicked()),this,SLOT(delFile()));
+ //label display
QTabWidget*tab;
split->addWidget(tab=new QTabWidget);
- tab->addTab(d->ticketpicture=new QWidget,tr("As Ticket"));
- tab->addTab(d->voucherpicture=new QWidget,tr("As Voucher"));
+ tab->addTab(w=new QWidget,tr("As Label"));
+ w->setLayout(vl=new QVBoxLayout);
+ vl->addLayout(hl=new QHBoxLayout,0);
+ hl->addWidget(new QLabel(tr("Zoom:")),0);
+ hl->addWidget(d->zoomslide=new QSlider,1);
+ d->zoomslide->setOrientation(Qt::Horizontal);
+ d->zoomslide->setRange(-10,10);
+ d->zoomslide->setTickPosition(QSlider::TicksBothSides);
+ connect(d->zoomslide,SIGNAL(valueChanged(int)),this,SLOT(rerender()));
+ hl->addWidget(p=new QPushButton(tr("Refresh")),0);
+ connect(p,SIGNAL(clicked()),this,SLOT(rerender()));
+ QScrollArea*sa;
+ vl->addWidget(sa=new QScrollArea,1);
+ sa->setWidget(d->ticketpicture=new QLabel);
+ sa->setWidgetResizable(true);
+ d->ticketpicture->setScaledContents(false);
+ d->ticketpicture->setAlignment(Qt::AlignCenter);
tab->addTab(d->expltable=new QTableView,tr("Example Data"));
d->expltable->setModel(d->explmodel=new QStandardItemModel(this));
d->expltable->setItemDelegate(new MTEExampleDelegate(this));
}
}
+static inline QString align2xml(Qt::Alignment a)
+{
+ switch(a){
+ case Qt::AlignTop:
+ return "top";
+ case Qt::AlignBottom:
+ return "bottom";
+ case Qt::AlignHCenter:
+ case Qt::AlignVCenter:
+ return "center";
+ case Qt::AlignLeft:
+ return "left";
+ case Qt::AlignRight:
+ return "right";
+ default:
+ return "";
+ }
+}
+
void MTicketEditor::parseTemplate(QByteArray bytes)
{
QDomDocument doc;
else
saveFile(d->mFileName);
}
-void MTicketEditor::saveFile ( QString )
+void MTicketEditor::saveFile ( QString fn)
{
-
+ QFile fd(fn);
+ if(!fd.open(QIODevice::ReadWrite|QIODevice::Truncate)){
+ QMessageBox::warning(this,tr("Warning"),tr("Unable to write to file %1").arg(fn));
+ return;
+ }
+ saveTemplate(fd);
+ fd.close();
}
void MTicketEditor::saveFileAs()
{
saveFile(fn);
}
}
-void MTicketEditor::download()
-{
-
-}
-void MTicketEditor::upload()
-{
-
-}
void MTicketEditor::updateDisplay()
{
rerender();
}
+QWidget* MTELabelDelegate::createEditor(QWidget* parent, const QStyleOptionViewItem& , const QModelIndex& index) const
+{
+ //get type
+ int tp=index.model()->data(index.model()->index(index.row(),0),Qt::UserRole).toInt();
+ switch(index.column()){
+ case 0:
+ return 0;
+ case 1:case 2:
+ if(tp&HRECT){
+ QLineEdit*ed=new QLineEdit(parent);
+ ed->setValidator(new QRegExpValidator(QRegExp("^(-?)[0-9\\.]+ (-?)[0-9\\.]+"),ed));
+ return ed;
+ }else return 0;
+ case 3:
+ if(tp&HFONT || tp&HFILE)
+ return new QComboBox(parent);
+ else return 0;
+ case 4:
+ if(tp&HFONT)
+ return new QDoubleSpinBox(parent);
+ else return 0;
+ case 5:
+ if(tp&HSMOOTH)
+ return new QComboBox(parent);
+ else return 0;
+ case 6:case 7:
+ if(tp&HALIGN)
+ return new QComboBox(parent);
+ else return 0;
+ case 8:
+ if(tp&HCONTENT)
+ return new QLineEdit(parent);
+ else return 0;
+ default: return 0;
+ }
+}
+
+void MTELabelDelegate::setEditorData(QWidget* editor, const QModelIndex& index) const
+{
+ const QAbstractItemModel*model=index.model();
+ int tp=model->data(model->index(index.row(),0),Qt::UserRole).toInt();
+ int line=index.row();
+ QComboBox*cb;
+ switch(index.column()){
+ case 1:case 2:case 8:
+ ((QLineEdit*)editor)->setText(model->data(index).toString());
+ break;
+ case 3:{
+ cb=(QComboBox*)editor;
+ QStringList k=mParent->d->mFiles.keys();
+ qSort(k);
+ QString c=model->data(index).toString();
+ if(tp&HFONT){
+ for(int i=0;i<k.size();i++)
+ cb->addItem("@"+k[i]);
+ k=QFontDatabase().families();
+ qSort(k);
+ cb->addItems(k);
+ for(int i=0;i<cb->count();i++)
+ if(cb->itemText(i)==c)
+ cb->setCurrentIndex(i);
+ }else{
+ cb->addItems(k);
+ for(int i=0;i<k.size();i++)
+ if(c==k[i])
+ cb->setCurrentIndex(i);
+ }
+ break;
+ }
+ case 4:
+ ((QDoubleSpinBox*)editor)->setValue(model->data(index).toDouble());
+ break;
+ case 5:
+ cb=(QComboBox*)editor;
+ cb->addItem(tr("edged"));
+ cb->addItem(tr("smooth"));
+ cb->setCurrentIndex(mParent->d->mLines[line].smooth?1:0);
+ break;
+ case 6:
+ cb=(QComboBox*)editor;
+ cb->addItem(align2str(Qt::AlignLeft),Qt::AlignLeft);
+ cb->addItem(align2str(Qt::AlignHCenter),Qt::AlignHCenter);
+ cb->addItem(align2str(Qt::AlignRight),Qt::AlignRight);
+ switch(mParent->d->mLines[line].align&Qt::AlignHorizontal_Mask){
+ case Qt::AlignHCenter:cb->setCurrentIndex(1);break;
+ case Qt::AlignRight:cb->setCurrentIndex(2);break;
+ default:break;
+ }
+ break;
+ case 7:
+ cb=(QComboBox*)editor;
+ cb->addItem(align2str(Qt::AlignTop),Qt::AlignTop);
+ cb->addItem(align2str(Qt::AlignVCenter),Qt::AlignVCenter);
+ cb->addItem(align2str(Qt::AlignBottom),Qt::AlignBottom);
+ switch(mParent->d->mLines[line].align&Qt::AlignVertical_Mask){
+ case Qt::AlignVCenter:cb->setCurrentIndex(1);break;
+ case Qt::AlignBottom:cb->setCurrentIndex(2);break;
+ default:break;
+ }
+ break;
+ default:break;
+ }
+}
+
+void MTELabelDelegate::setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const
+{
+ int tp=index.model()->data(index.model()->index(index.row(),0),Qt::UserRole).toInt();
+ QString s;
+ int line=index.row();
+ QComboBox*cb;
+ switch(index.column()){
+ case 1:
+ s=((QLineEdit*)editor)->text();
+ mParent->d->mLines[line].offset=str2point(s);
+ model->setData(index,point2str(mParent->d->mLines[line].offset));
+ break;
+ case 2:
+ s=((QLineEdit*)editor)->text();
+ mParent->d->mLines[line].size=str2size(s);
+ model->setData(index,size2str(mParent->d->mLines[line].size));
+ break;
+ case 3:
+ cb=(QComboBox*)editor;
+ if(tp&HFONT){
+ mParent->d->mLines[line].font=cb->currentText();
+ }else{
+ mParent->d->mLines[line].file=cb->currentText();
+ }
+ model->setData(index,cb->currentText());
+ break;
+ case 4:
+ mParent->d->mLines[line].fontsize=((QDoubleSpinBox*)editor)->value();
+ model->setData(index,mParent->d->mLines[line].fontsize);
+ break;
+ case 5:
+ mParent->d->mLines[line].smooth=((QComboBox*)editor)->currentIndex()!=0;
+ model->setData(index,((QComboBox*)editor)->currentText());
+ break;
+ case 6:
+ cb=((QComboBox*)editor);
+ mParent->d->mLines[line].align&=Qt::AlignVertical_Mask;
+ mParent->d->mLines[line].align|=Qt::AlignmentFlag(cb->itemData(cb->currentIndex()).toInt());
+ model->setData(index,cb->currentText());
+ break;
+ case 7:
+ cb=((QComboBox*)editor);
+ mParent->d->mLines[line].align&=Qt::AlignHorizontal_Mask;
+ mParent->d->mLines[line].align|=Qt::AlignmentFlag(cb->itemData(cb->currentIndex()).toInt());
+ model->setData(index,cb->currentText());
+ break;
+ case 8:
+ s=((QLineEdit*)editor)->text();
+ mParent->d->mLines[line].content=s;
+ model->setData(index,s);
+ break;
+ default:break;
+ }
+ mParent->rerender();
+}
+
+
+class MTELabel:public MLabel
+{
+ QMap<QString,QString>exdata;
+ public:
+ MTELabel(QMap<QString,QString>dt)
+ {
+ exdata=dt;
+ exdata.insert("TICKETID",dt["BARCODE"]);
+ exdata.insert("VOUCHERID",dt["BARCODE"]);
+ }
+ QString getVariable(QString s)const
+ {
+ QString ret=exdata.value(s);
+ if(s=="PRICE"||s=="VALUE")
+ ret=cent2str(str2cent(ret));
+ else if(s=="DATETIME")
+ ret=unix2dateTime(QDateTime::fromString(ret,Qt::ISODate).toTime_t());
+ return ret;
+ }
+};
+
void MTicketEditor::rerender()
{
QMap<QString,QString>exdata;
d->explmodel->data(d->explmodel->index(i,1)).toString()
);
}
+ MTELabel label(exdata);
+ //calculate scaling factor
+ int zfi=d->zoomslide->value();
+ qreal zff=1.0;
+ if(zfi!=0){
+ for(int i=0;i<zfi;i++)zff*=1.2;
+ for(int i=0;i>zfi;i--)zff/=1.2;
+ }
//render ticket
- MOTicket t;
- t.setticketid(exdata.value("BARCODE"));
- t.setprice(str2cent(exdata.value("PRICE")));
QTemporaryFile tfile(QDir::tempPath()+"/templateXXXXXX.xtt");
tfile.open();
saveTemplate(tfile);
- MTicketRenderer rend(tfile.fileName());
- rend.render(t,*(d->ticketpicture));
- //render voucher
+ MLabelRenderer rend(tfile.fileName());
+ QSize size(rend.labelSize(*d->ticketpicture).toSize());
+ QImage tick=QPixmap(size*zff).toImage();
+ tick.setDotsPerMeterX(tick.dotsPerMeterX()*zff);
+ tick.setDotsPerMeterY(tick.dotsPerMeterY()*zff);
+ tick.fill(0xffffffff);
+ if(!rend.render(label,tick))
+ qDebug("unable to render");
+ //scale and display
+ d->ticketpicture->setPixmap(QPixmap::fromImage(tick));
}
void MTicketEditor::saveTemplate(QFile& fd)
{QBuffer buf;buf.open(QIODevice::ReadWrite);
saveXmlPart(buf);buf.seek(0);
zip.storeFile("template.xml",buf);}
+ QStringList k=d->mFiles.keys();
+ for(int i=0;i<k.size();i++){
+ QBuffer buf;
+ buf.open(QIODevice::ReadWrite);
+ buf.write(d->mFiles[k[i]]);
+ buf.seek(0);
+ zip.storeFile(k[i],buf);
+ }
zip.close();
fd.flush();
}
void MTicketEditor::saveXmlPart(QIODevice& fd)
{
-
+ QDomDocument doc;
+ QDomElement root=doc.createElement("LabelTemplate");
+ root.setAttribute("size",size2str(d->mSize));
+ root.setAttribute("unit",d->mUnit);
+ for(int i=0;i<d->mLines.size();i++){
+ Private::Line_s ln=d->mLines[i];
+ QDomElement el;
+ switch(ln.type){
+ case Private::LoadFont:el=doc.createElement("LoadFont");break;
+ case Private::Picture:el=doc.createElement("Picture");break;
+ case Private::Text:el=doc.createElement("Text");break;
+ case Private::Barcode:el=doc.createElement("Barcode");break;
+ default:continue;
+ }
+ if(ln.type&HRECT){
+ el.setAttribute("size",size2str(ln.size));
+ el.setAttribute("offset",point2str(ln.offset));
+ }
+ if(ln.type&HFILE)
+ el.setAttribute("file",ln.file);
+ if(ln.type&HFONT){
+ el.setAttribute("font",ln.font);
+ el.setAttribute("fontsize",ln.fontsize);
+ }
+ if(ln.type&HSMOOTH)
+ el.setAttribute("smooth",ln.smooth?"1":"0");
+ if(ln.type&HALIGN){
+ el.setAttribute("align",align2xml(ln.align&Qt::AlignHorizontal_Mask));
+ el.setAttribute("valign",align2xml(ln.align&Qt::AlignVertical_Mask));
+ }
+ if(ln.type&HCONTENT)
+ el.appendChild(doc.createTextNode(ln.content));
+ root.appendChild(el);
+ }
+ doc.appendChild(root);
+ //save
+ fd.write(doc.toByteArray());
}
void MTicketEditor::addFile()
{
-
+ QString fn=QFileDialog::getOpenFileName(this,tr("Add File to Label"));
+ if(fn=="")return;
+ //try to read it
+ QFile fd(fn);
+ if(!fd.open(QIODevice::ReadOnly)){
+ QMessageBox::warning(this,tr("Warning"),tr("Unable to read file %1").arg(fn));
+ return;
+ }
+ QByteArray fdata=fd.readAll();
+ fd.close();
+ //ask for internal name
+ fn=QFileInfo(fn).fileName();
+ fn=QInputDialog::getText(this,tr("File Name"),tr("Please enter the internal file name:"),QLineEdit::Normal,fn);
+ if(fn=="")return;
+ fn=QFileInfo(fn).fileName();
+ if(fn=="")return;
+ //append
+ d->mFiles.insert(fn,fdata);
+ updateDisplay();
}
void MTicketEditor::delFile()
{
-
+ //get file name
+ QModelIndex idx=d->filetable->currentIndex();
+ if(!idx.isValid())return;
+ QString fn=d->filemodel->data(d->filemodel->index(idx.row(),0)).toString();
+ if(fn=="")return;
+ //ask
+ if(QMessageBox::question(this,tr("Really delete?"),tr("Really remove file '%1' from the label?").arg(fn),QMessageBox::No|QMessageBox::Yes)!=QMessageBox::Yes)
+ return;
+ //delete
+ d->mFiles.remove(fn);
+ updateDisplay();
}
-void MTicketEditor::addItem(int )
+void MTicketEditor::addItem(int type)
{
-
+ d->mLines.append(Private::Line_s(type));
+ updateDisplay();
}
void MTicketEditor::delItem()
{
+ QModelIndex idx=d->itemtable->currentIndex();
+ if(!idx.isValid())return;
+ d->mLines.removeAt(idx.row());
+ updateDisplay();
+}
+void MTicketEditor::downItem()
+{
+ QModelIndex idx=d->itemtable->currentIndex();
+ if(!idx.isValid())return;
+ int r=idx.row();
+ if(r>=(d->mLines.size()-1))return;
+ Private::Line_s tmp=d->mLines[r];
+ d->mLines[r]=d->mLines[r+1];
+ d->mLines[r+1]=tmp;
+ updateDisplay();
+ d->itemtable->setCurrentIndex(d->itemmodel->index(r+1,idx.column()));
+}
+void MTicketEditor::upItem()
+{
+ QModelIndex idx=d->itemtable->currentIndex();
+ if(!idx.isValid())return;
+ int r=idx.row();
+ if(r<=0)return;
+ Private::Line_s tmp=d->mLines[r];
+ d->mLines[r]=d->mLines[r-1];
+ d->mLines[r-1]=tmp;
+ updateDisplay();
+ d->itemtable->setCurrentIndex(d->itemmodel->index(r-1,idx.column()));
}