--- /dev/null
+//
+// C++ Implementation: ticket template editor
+//
+// Description:
+//
+//
+// Author: Konrad Rosenbaum <konrad@silmor.de>, (C) 2010-2011
+//
+// Copyright: See README/COPYING.GPL files that come with this distribution
+//
+//
+
+#include "odfedit.h"
+#include "centbox.h"
+#include "misc.h"
+#include "ticketrender.h"
+
+#include "MOTicket"
+#include "MOVoucher"
+
+#include <DPtr>
+#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
+#define HFILE 4
+#define HALIGN 8
+#define HSMOOTH 0x10
+#define HCONTENT 0x20
+
+class MOEExampleDelegate:public QItemDelegate
+{
+ public:
+ MOEExampleDelegate(QObject *parent = 0):QItemDelegate(parent){}
+
+ QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &,
+ const QModelIndex &index) const
+ {
+ if(index.column()!=1)return 0;
+ QString tp=index.model()->data(index,Qt::UserRole).toString();
+ if(tp=="string")return new QLineEdit(parent);
+ if(tp=="money")return new MCentSpinBox(parent);
+ if(tp=="date")return new QDateTimeEdit(parent);
+ return 0;
+ }
+
+ void setEditorData(QWidget *editor, const QModelIndex &index) const
+ {
+ const QAbstractItemModel*model=index.model();
+ QString tp=index.model()->data(index,Qt::UserRole).toString();
+ if(tp=="string")
+ ((QLineEdit*)editor)->setText(model->data(index).toString());
+ if(tp=="money")
+ ((MCentSpinBox*)editor)->setValue(str2cent(model->data(index).toString()));
+ if(tp=="date")
+ ((QDateTimeEdit*)editor)->setDateTime(QDateTime::fromString(model->data(index).toString(),Qt::ISODate));
+
+ }
+ void setModelData(QWidget *editor, QAbstractItemModel *model,
+ const QModelIndex &index) const
+ {
+ QString tp=index.model()->data(index,Qt::UserRole).toString();
+ if(tp=="string")
+ model->setData(index, ((QLineEdit*)editor)->text());
+ if(tp=="money")
+ model->setData(index, cent2str(((MCentSpinBox*)editor)->value()));
+ if(tp=="date")
+ model->setData(index, ((QDateTimeEdit*)editor)->dateTime().toString(Qt::ISODate));
+ }
+
+ void updateEditorGeometry(QWidget *editor,
+ const QStyleOptionViewItem &option, const QModelIndex &) const
+ {editor->setGeometry(option.rect);}
+};
+
+class DPTR_CLASS_NAME(MOdfEditor)
+{
+ public:
+ //template file
+ QString mFileName;
+ //file contents
+ QMap<QString,QByteArray>mFiles;
+ QString mUnit;
+ QSizeF mSize;
+ enum Type{
+ Unknown=0,
+ LoadFont=0x100|HFILE,
+ Picture=0x200|HFILE|HRECT|HSMOOTH,
+ Text=0x300|HFONT|HRECT|HALIGN|HCONTENT,
+ 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;
+ QString file;
+ bool smooth;
+ QString font;
+ double fontsize;
+ Qt::Alignment align;
+ QString content;
+ };
+ QList<Line_s>mLines;
+ //widgets
+ QDoubleSpinBox*labelwidth,*labelheight;
+ QComboBox*unitbox;
+ QTableView*itemtable,*filetable,*expltable;
+ QStandardItemModel*itemmodel,*filemodel,*explmodel;
+ QLabel*ticketpicture;
+ QSlider*zoomslide;
+};
+
+DEFINE_DPTR(MOdfEditor);
+
+MOdfEditor::MOdfEditor(QWidget* parent, Qt::WindowFlags f): QMainWindow(parent, f)
+{
+ setWindowTitle(tr("Label Editor"));
+ //menu
+ QMenuBar*mb=menuBar();
+ QMenu*m=mb->addMenu(tr("&File"));
+ m->addAction(tr("&Open File..."), this, SLOT(openFile()), tr("Ctrl+O","open file shortcut"));
+ m->addAction(tr("&Save"), this, SLOT(saveFile()), tr("Ctrl+S","save file shortcut"));
+ m->addAction(tr("Save &as..."),this,SLOT(saveFileAs()));
+ m->addSeparator();
+ m->addAction(tr("&Close"),this,SLOT(close()));
+ m=mb->addMenu(tr("&Edit"));
+ QMenu *aim=m->addMenu(tr("&Add Item"));
+ m->addAction(tr("&Remove Item"),this,SLOT(delItem()));
+ m->addSeparator();
+ m->addAction(tr("Add &File"),this,SLOT(addFile()));
+ m->addAction(tr("Remove F&ile"),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);
+ map->setMapping(aim->addAction(tr("Add &Barcode Item"),map,SLOT(map())),(int)Private::Barcode);
+ map->setMapping(aim->addAction(tr("Add &Load Font Item"),map,SLOT(map())),(int)Private::LoadFont);
+ connect(map,SIGNAL(mapped(int)),this,SLOT(addItem(int)));
+
+ //central
+ QSplitter*central=new QSplitter(Qt::Vertical);
+ setCentralWidget(central);
+ QWidget*w=new QWidget;
+ central->addWidget(w);
+ 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"));
+ hl->addWidget(d->labelheight=new QDoubleSpinBox);
+ hl->addWidget(d->unitbox=new QComboBox);
+ d->unitbox->addItem(tr("Millimeter"),"mm");
+ d->unitbox->addItem(tr("Inch"),"in");
+ hl->addStretch(1);
+ //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 MOELabelDelegate(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);
+ //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->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(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 MOEExampleDelegate(this));
+ d->expltable->horizontalHeader()->show();
+ d->expltable->verticalHeader()->hide();
+
+ //statusbar
+ statusBar()->setSizeGripEnabled(true);
+ setAttribute(Qt::WA_DeleteOnClose);
+ loadExampleData();
+}
+
+const QString example(
+"BARCODE\tABCDEFGHIJK\tstring\n"
+"PRICE\t12.34\tmoney\n"
+"ROOM\tThe invisible Cabinet\tstring\n"
+"TITLE\tSome title, this is.\tstring\n"
+"DATETIME\t2023-01-23T19:54\tdate\n"
+"ARTIST\tHenry the Drycleaner\tstring\n"
+"PRICECATEGORY\tExpensive\tstring\n"
+"PRICECATEGORYABBR\texp\tstring\n"
+"VALUE\t12.00\tmoney");
+
+void MOdfEditor::loadExampleData()
+{
+ d->explmodel->clear();
+ d->explmodel->setHorizontalHeaderLabels(QStringList()<<tr("Variable")<<tr("Content"));
+ QStringList ex1=example.split("\n");
+ d->explmodel->insertRows(0,ex1.size());
+ QSettings set;
+ set.beginGroup("labeleditor/examples");
+ for(int i=0;i<ex1.size();i++){
+ QStringList ex2=ex1[i].split("\t");
+ d->explmodel->setData(d->explmodel->index(i,0),ex2[0]);
+ d->explmodel->setData(d->explmodel->index(i,1), set.value(ex2[0],ex2[1]));
+ d->explmodel->setData(d->explmodel->index(i,1), ex2[2], Qt::UserRole);
+ }
+}
+
+
+void MOdfEditor::loadFile(QString fn)
+{
+ //try to open the file
+ if(fn=="")return;
+ QFile fd(fn);
+ if(!fd.open(QIODevice::ReadOnly)){
+ QMessageBox::warning(this, tr("Error"), tr("Unable to open file '%1' for reading.").arg(fn));
+ return;
+ }
+ QUnZip unz;
+ if(!unz.open(&fd)){
+ QMessageBox::warning(this, tr("Error"), tr("Unable to interpret file '%1'.").arg(fn));
+ return;
+ }
+ //clear cache
+ d->mFiles.clear();
+ d->mLines.clear();
+ //read data
+ unz.gotoFirstFile();
+ do{
+ QString ifn;
+ unz.getCurrentFileInfo(ifn,0);
+ QBuffer buf;buf.open(QIODevice::ReadWrite);
+ unz.getCurrentFile(buf);
+ if(ifn=="template.xml")
+ parseTemplate(buf.data());
+ else
+ d->mFiles.insert(ifn,buf.data());
+ }while(unz.gotoNextFile());
+ //update display
+ updateDisplay();
+}
+
+static inline QSizeF str2size(QString s)
+{
+ QStringList sl=s.trimmed().split(" ");
+ if(sl.size()!=2)return QSizeF();
+ return QSizeF(sl[0].toDouble(),sl[1].toDouble());
+}
+
+static inline QString size2str(QSizeF s)
+{
+ return QString("%1 %2").arg(s.width()).arg(s.height());
+}
+
+static inline QPointF str2point(QString s)
+{
+ QStringList sl=s.trimmed().split(" ");
+ if(sl.size()!=2)return QPointF();
+ return QPointF(sl[0].toDouble(),sl[1].toDouble());
+}
+
+static inline QString point2str(QPointF p)
+{
+ return QString("%1 %2").arg(p.x()).arg(p.y());
+}
+
+static inline QString align2str(Qt::Alignment a)
+{
+ switch(a){
+ case Qt::AlignTop:
+ return QCoreApplication::translate("MOdfEditor","top");
+ case Qt::AlignBottom:
+ return QCoreApplication::translate("MOdfEditor","bottom");
+ case Qt::AlignHCenter:
+ case Qt::AlignVCenter:
+ return QCoreApplication::translate("MOdfEditor","center");
+ case Qt::AlignLeft:
+ return QCoreApplication::translate("MOdfEditor","left");
+ case Qt::AlignRight:
+ return QCoreApplication::translate("MOdfEditor","right");
+ default:
+ return QCoreApplication::translate("MOdfEditor","align (%1)").arg((int)a);
+ }
+}
+
+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 MOdfEditor::parseTemplate(QByteArray bytes)
+{
+ QDomDocument doc;
+ if(!doc.setContent(bytes)){
+ QMessageBox::warning(this,tr("Warning"),tr("Unable to interpret template data."));
+ return;
+ }
+ QDomElement root=doc.documentElement();
+ d->mSize=str2size(root.attribute("size"));
+ d->mUnit=root.attribute("unit","mm");
+ QDomNodeList nl=root.childNodes();
+ for(int i=0;i<nl.size();i++){
+ QDomElement el=nl.at(i).toElement();
+ if(el.isNull())continue;
+ QString tn=el.tagName();
+ Private::Line_s line;
+ if(tn=="LoadFont")line.type=Private::LoadFont;else
+ if(tn=="Picture")line.type=Private::Picture;else
+ if(tn=="Text")line.type=Private::Text;else
+ if(tn=="Barcode")line.type=Private::Barcode;
+ else line.type=Private::Unknown;
+ line.file=el.attribute("file");
+ line.font=el.attribute("font");
+ line.fontsize=el.attribute("fontsize","10").toDouble();
+ line.offset=str2point(el.attribute("offset"));
+ line.size=str2size(el.attribute("size"));
+ line.smooth=el.attribute("smoot")=="1";
+ line.align=0;
+ tn=el.attribute("align");
+ if(tn=="left")line.align=Qt::AlignLeft;else
+ if(tn=="right")line.align=Qt::AlignRight;else
+ if(tn=="center")line.align=Qt::AlignHCenter;
+ tn=el.attribute("valign");
+ if(tn=="top")line.align|=Qt::AlignTop;else
+ if(tn=="bottom")line.align|=Qt::AlignBottom;else
+ if(tn=="center")line.align|=Qt::AlignVCenter;
+ line.content=el.text();
+ d->mLines.append(line);
+ }
+}
+
+void MOdfEditor::openFile()
+{
+ QString fn=QFileDialog::getOpenFileName(this,tr("Open Ticket Template"));
+ if(fn!=""){
+ d->mFileName=fn;
+ loadFile(fn);
+ }
+}
+
+void MOdfEditor::saveFile()
+{
+ if(d->mFileName=="" || d->mFileName.left(2)==":/")
+ saveFileAs();
+ else
+ saveFile(d->mFileName);
+}
+void MOdfEditor::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 MOdfEditor::saveFileAs()
+{
+ QString fn=QFileDialog::getSaveFileName(this,tr("Save Ticket Template"),d->mFileName);
+ if(fn!=""){
+ d->mFileName=fn;
+ saveFile(fn);
+ }
+}
+
+void MOdfEditor::updateDisplay()
+{
+ if(d->mFileName=="")
+ setWindowTitle(tr("Label Template Editor"));
+ else
+ setWindowTitle(tr("Label Template Editor [%1]").arg(d->mFileName));
+ //basics
+ d->labelwidth->setValue(d->mSize.width());
+ d->labelheight->setValue(d->mSize.height());
+ for(int i=0;i<d->unitbox->count();i++)
+ if(d->unitbox->itemData(i).toString()==d->mUnit)
+ d->unitbox->setCurrentIndex(i);
+ //files
+ d->filemodel->clear();
+ if(d->filemodel->columnCount()<2)
+ d->filemodel->insertColumns(0,2);
+ d->filemodel->insertRows(0,d->mFiles.size());
+ d->filemodel->setHorizontalHeaderLabels(QStringList()<<tr("File Name")<<tr("Size"));
+ QStringList fnames=d->mFiles.keys();
+ for(int i=0;i<d->mFiles.size();i++){
+ d->filemodel->setData(d->filemodel->index(i,0),fnames[i]);
+ d->filemodel->setData(d->filemodel->index(i,1),d->mFiles[fnames[i]].size());
+ }
+ d->filetable->resizeColumnsToContents();
+ //items
+ d->itemmodel->clear();
+ d->itemmodel->insertRows(0,d->mLines.size());
+ d->itemmodel->setHorizontalHeaderLabels(QStringList()
+ <<tr("Type")
+ <<tr("Offset")
+ <<tr("Size")
+ <<tr("File/Font")
+ <<tr("Font Size")
+ <<tr("Scaling")
+ <<tr("Horiz. Alignment")
+ <<tr("Vert. Alignment")
+ <<tr("Text Data")
+ );
+ for(int i=0;i<d->mLines.size();i++){
+ QString tp;
+ Private::Type tpe=d->mLines[i].type;
+ switch(tpe){
+ case Private::LoadFont:tp=tr("Load Font File");break;
+ case Private::Picture:tp=tr("Show Picture");break;
+ case Private::Text:tp=tr("Show Text Line");break;
+ case Private::Barcode:tp=tr("Show Barcode");break;
+ default:tp=tr("Unknown");break;
+ }
+ d->itemmodel->setData(d->itemmodel->index(i,0),tp);
+ d->itemmodel->setData(d->itemmodel->index(i,0),(int)tpe,Qt::UserRole);
+ if(tpe&HRECT){
+ d->itemmodel->setData(d->itemmodel->index(i,2), size2str(d->mLines[i].size));
+ d->itemmodel->setData(d->itemmodel->index(i,1), point2str(d->mLines[i].offset));
+ }
+ if(tpe&HFONT){
+ d->itemmodel->setData(d->itemmodel->index(i,3),d->mLines[i].font);
+ d->itemmodel->setData(d->itemmodel->index(i,4),d->mLines[i].fontsize);
+ }
+ if(tpe&HFILE)
+ d->itemmodel->setData(d->itemmodel->index(i,3),d->mLines[i].file);
+ if(tpe&HSMOOTH)
+ d->itemmodel->setData(d->itemmodel->index(i,5), d->mLines[i].smooth?tr("smooth"):tr("edged"));
+ if(tpe&HALIGN){
+ d->itemmodel->setData(d->itemmodel->index(i,6), align2str(d->mLines[i].align&Qt::AlignHorizontal_Mask));
+ d->itemmodel->setData(d->itemmodel->index(i,7), align2str(d->mLines[i].align&Qt::AlignVertical_Mask));
+ }
+ if(tpe&HCONTENT)
+ d->itemmodel->setData(d->itemmodel->index(i,8), d->mLines[i].content);
+ }
+ d->itemtable->resizeColumnsToContents();
+ //do rendering
+ rerender();
+}
+
+QWidget* MOELabelDelegate::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 MOELabelDelegate::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 MOELabelDelegate::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 MOdfEditor::rerender()
+{
+ QMap<QString,QString>exdata;
+ for(int i=0;i<d->explmodel->rowCount();i++){
+ exdata.insert(
+ d->explmodel->data(d->explmodel->index(i,0)).toString(),
+ 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
+ QTemporaryFile tfile(QDir::tempPath()+"/templateXXXXXX.xtt");
+ tfile.open();
+ saveTemplate(tfile);
+ 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 MOdfEditor::saveTemplate(QFile& fd)
+{
+ QZip zip;
+ zip.open(&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 MOdfEditor::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 MOdfEditor::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 MOdfEditor::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 MOdfEditor::addItem(int type)
+{
+ d->mLines.append(Private::Line_s(type));
+ updateDisplay();
+}
+
+void MOdfEditor::delItem()
+{
+ QModelIndex idx=d->itemtable->currentIndex();
+ if(!idx.isValid())return;
+ d->mLines.removeAt(idx.row());
+ updateDisplay();
+}
+
+void MOdfEditor::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 MOdfEditor::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()));
+}