From: Konrad Rosenbaum Date: Mon, 30 Jan 2012 19:44:17 +0000 (+0100) Subject: start drafting ODF editor X-Git-Url: http://git.silmor.de/gitweb/?a=commitdiff_plain;h=d82561415053906101e2a34dcf5fd5873aa11ddc;p=web%2Fkonrad%2Fsmoke.git start drafting ODF editor --- diff --git a/src/templates/odfedit.cpp b/src/templates/odfedit.cpp new file mode 100644 index 0000000..faed04e --- /dev/null +++ b/src/templates/odfedit.cpp @@ -0,0 +1,883 @@ +// +// C++ Implementation: ticket template editor +// +// Description: +// +// +// Author: Konrad Rosenbaum , (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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 + QMapmFiles; + 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; + }; + QListmLines; + //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()<explmodel->insertRows(0,ex1.size()); + QSettings set; + set.beginGroup("labeleditor/examples"); + for(int i=0;iexplmodel->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;imLines.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;iunitbox->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()<mFiles.keys(); + for(int i=0;imFiles.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() + <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;iaddItem("@"+k[i]); + k=QFontDatabase().families(); + qSort(k); + cb->addItems(k); + for(int i=0;icount();i++) + if(cb->itemText(i)==c) + cb->setCurrentIndex(i); + }else{ + cb->addItems(k); + for(int i=0;isetCurrentIndex(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 +{ + QMapexdata; + public: + MTELabel(QMapdt) + { + 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() +{ + QMapexdata; + for(int i=0;iexplmodel->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;izfi;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;imFiles[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;imLines.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())); +} diff --git a/src/templates/odfedit.h b/src/templates/odfedit.h new file mode 100644 index 0000000..f7c9d1c --- /dev/null +++ b/src/templates/odfedit.h @@ -0,0 +1,89 @@ +// +// C++ Interface: ODF template editor +// +// Description: +// +// +// Author: Konrad Rosenbaum , (C) 2010-2012 +// +// Copyright: See README/COPYING.GPL files that come with this distribution +// +// + +#ifndef MAGICSMOKE_ODFEDIT_H +#define MAGICSMOKE_ODFEDIT_H + +#include +#include +#include + +#include + +class QFile; +class QIODevice; +/**An editor for ticket templates.*/ +class MOdfEditor:public QMainWindow +{ + Q_OBJECT + DECLARE_DPTR(d); + friend class MOELabelDelegate; + public: + ///instantiates the editor + MOdfEditor(QWidget* parent = 0, Qt::WindowFlags f = 0); + + public slots: + ///loads a template file, this is a helper for openFile and download + void loadFile(QString); + ///shows a file open dialog and then opens the selected file + void openFile(); + ///saves the file - if it is local, otherwise calls saveFileAs + void saveFile(); + ///asks for a new file name + void saveFileAs(); + ///helper for saveFile and upload + void saveFile(QString); + private slots: + ///renders the label + void rerender(); + ///parses the XML part of the template file and fills internal ressources + void parseTemplate(QByteArray); + ///pushes all data from internal ressources to the display + void updateDisplay(); + ///add a specific kind of item line + void addItem(int); + ///delete currently selected item line + void delItem(); + ///move selected item up + void upItem(); + ///move selected item down + void downItem(); + ///add a file (image/font) to the template + void addFile(); + ///delete the selected file from the template + void delFile(); + ///used by constructor to load example data for the example label + void loadExampleData(); + ///saves all data to the file (must be open ReadWrite) + void saveTemplate(QFile&); + ///helper: saves the XML part of the template (device must be writable) + void saveXmlPart(QIODevice&); +}; + +/// \internal helper for the ticket editor +class MOELabelDelegate:public QItemDelegate +{ + Q_OBJECT + MOdfEditor*mParent; + public: + MOELabelDelegate(MOdfEditor *parent):QItemDelegate(parent) + {mParent=parent;} + QWidget *createEditor(QWidget *, const QStyleOptionViewItem &, + const QModelIndex &) const; + void setEditorData(QWidget *, const QModelIndex &) const; + void setModelData(QWidget *, QAbstractItemModel *, + const QModelIndex &) const ; + void updateEditorGeometry(QWidget *editor,const QStyleOptionViewItem &option, + const QModelIndex &) const {editor->setGeometry(option.rect);} +}; + +#endif diff --git a/src/templates/odtrender.cpp b/src/templates/odtrender.cpp index 86363fb..655df4c 100644 --- a/src/templates/odtrender.cpp +++ b/src/templates/odtrender.cpp @@ -14,7 +14,10 @@ #include "odtrender.h" #include "office.h" +#include #include +#include +#include #include #include #include @@ -59,6 +62,7 @@ class MOdtRendererPrivate QFile tfile; QString newline; bool inif,iftrue; + QDomDocument cdoc; struct LocalVar{ MOdtRenderer::VarType type; @@ -73,6 +77,7 @@ MOdtRenderer::MOdtRenderer(MTemplate file) d->extension=file.targetExtension(); } +const QString OdfTemplateNS("http://smoke.silmor.de/odftemplate/namespace"); MOdtRendererPrivate::MOdtRendererPrivate(QString file,MOdtRenderer*p) :tfile(file) { @@ -81,7 +86,44 @@ MOdtRendererPrivate::MOdtRendererPrivate(QString file,MOdtRenderer*p) inif=iftrue=true; //open ZIP if(tfile.open(QIODevice::ReadOnly))temp.open(&tfile); + else { + qDebug()<<"Error opening ODF template file"<olst=old.split('\n'); + foreach(const QByteArray&line,olst){ + nba+=line; + nba+='\n'; + } + qDebug()<<"conversion test"< @@ -269,7 +270,10 @@ void MTemplateEditor::editItem() tp=MTemplate::legalTypes(base); } if(tp&MTemplate::OdfTemplateMask){ - QMessageBox::warning(this,"Sorry","Sorry, no ODF editor yet."); + MOdfEditor *ed=new MOdfEditor(this); + if(fn!="") + ed->loadFile(tmp.cacheFileName()); + ed->show(); }else if(tp==MTemplate::LabelTemplate){ MTicketEditor *ed=new MTicketEditor(this); diff --git a/src/templates/templates.pri b/src/templates/templates.pri index 5ef18a9..9790050 100644 --- a/src/templates/templates.pri +++ b/src/templates/templates.pri @@ -1,19 +1,21 @@ HEADERS += \ - templates/odtrender.h \ - templates/ticketrender.h \ - templates/office.h \ - templates/labeldlg.h \ - templates/templates.h \ - templates/templatedlg.h \ - templates/ticketedit.h + $$PWD/odtrender.h \ + $$PWD/ticketrender.h \ + $$PWD/office.h \ + $$PWD/labeldlg.h \ + $$PWD/templates.h \ + $$PWD/templatedlg.h \ + $$PWD/ticketedit.h \ + $$PWD/odfedit.h SOURCES += \ - templates/odtrender.cpp \ - templates/ticketrender.cpp \ - templates/office.cpp \ - templates/labeldlg.cpp \ - templates/templates.cpp \ - templates/templatedlg.cpp \ - templates/ticketedit.cpp + $$PWD/odtrender.cpp \ + $$PWD/ticketrender.cpp \ + $$PWD/office.cpp \ + $$PWD/labeldlg.cpp \ + $$PWD/templates.cpp \ + $$PWD/templatedlg.cpp \ + $$PWD/ticketedit.cpp \ + $$PWD/odfedit.cpp -INCLUDEPATH += ./templates \ No newline at end of file +INCLUDEPATH += $$PWD \ No newline at end of file