From e73551891fe0f201108599005d1d95fc833706bf Mon Sep 17 00:00:00 2001 From: Konrad Rosenbaum Date: Sun, 19 Feb 2012 21:44:39 +0100 Subject: [PATCH] more on odf editor --- pack | 2 +- src/misc/dommodel.cpp | 27 +++++- src/misc/dommodel.h | 3 + src/mwin/overview.cpp | 9 ++ src/mwin/overview.h | 1 + src/templates/odfedit.cpp | 238 ++++++++++++++++++++++++++++++++++++++++++--- src/templates/odfedit.h | 11 ++ 7 files changed, 273 insertions(+), 18 deletions(-) diff --git a/pack b/pack index 124750d..148c47b 160000 --- a/pack +++ b/pack @@ -1 +1 @@ -Subproject commit 124750d5e19a642f69f28a3299380bb95ba3d089 +Subproject commit 148c47b29a616af46ed6690019d32b85ed568fac diff --git a/src/misc/dommodel.cpp b/src/misc/dommodel.cpp index 7bad551..5961e62 100644 --- a/src/misc/dommodel.cpp +++ b/src/misc/dommodel.cpp @@ -48,6 +48,7 @@ class DPTR_CLASS_NAME(MDomItemModel) QMap contentFromNode; //config for element display int elemAttrLen,elemTextLen; + bool showtypeLabel; //header data QMap,QVariant>horizHeader,vertHeader; @@ -69,6 +70,7 @@ MDomItemModel::Private::Private() { showType<showtypeLabel == show)return; + //send a model reset if this has an actual effect, ie. if we do the rendering + bool b=!d->contentFromNode.contains(Qt::DisplayRole); + if(b)beginResetModel(); + //change params + d->showtypeLabel=show; + //tell the view + if(b)endResetModel(); +} + QDomNode MDomItemModel::node(const QModelIndex& index) const { if(!index.isValid()){ @@ -246,7 +261,9 @@ QVariant MDomItemModel::displayFromNode(const QDomNode& node) const if(node.isNull())return "NULL node"; switch(node.nodeType()){ case QDomNode::ElementNode:{ - QString r="tag <"+node.nodeName(); + QString r; + if(d->showtypeLabel)r+="tag "; + r+="<"+node.nodeName(); QString a,t; //append attribs if(d->elemAttrLen>=0 && node.hasAttributes()){ @@ -284,12 +301,14 @@ QVariant MDomItemModel::displayFromNode(const QDomNode& node) const return r; } case QDomNode::AttributeNode: - return "attribute "+node.nodeName()+"="+node.nodeValue(); + return (d->showtypeLabel?"attribute ":"")+node.nodeName()+"="+node.nodeValue(); case QDomNode::TextNode: case QDomNode::CDATASectionNode: - return "text \""+QString(node.nodeValue()).replace('\n',' ')+"\""; + return QString(d->showtypeLabel?"text ":"")+"\""+QString(node.nodeValue()).replace('\n',' ')+"\""; + case QDomNode::CommentNode: + return QString(d->showtypeLabel?"comment ":"")+""; default: - return "node ("+QString::number(node.nodeType())+"): "+node.nodeName()+" - \""+node.nodeValue()+"\""; + return (d->showtypeLabel?("node ("+QString::number(node.nodeType())+"): "):QString())+node.nodeName()+" - \""+node.nodeValue()+"\""; } } diff --git a/src/misc/dommodel.h b/src/misc/dommodel.h index e465032..744cbad 100644 --- a/src/misc/dommodel.h +++ b/src/misc/dommodel.h @@ -102,6 +102,9 @@ class MDomItemModel:public QAbstractItemModel */ void showElementProperties(int maxattr,int maxtext); + ///if true the default display routine will show a node type label + void showTypeLabel(bool show=true); + ///replaces the node at the index, you cannot replace the entire document with this function - use setDomDocument for this virtual void setNode(const QModelIndex&index,const QDomNode&); ///removes the nodes at the given position and their child nodes diff --git a/src/mwin/overview.cpp b/src/mwin/overview.cpp index 92ab620..9252ebc 100644 --- a/src/mwin/overview.cpp +++ b/src/mwin/overview.cpp @@ -20,6 +20,7 @@ #include "backupdlg.h" #include "payedit.h" #include "orderauditdlg.h" +#include "odfedit.h" #include "aclwin.h" #include "carttab.h" @@ -119,6 +120,8 @@ MOverview::MOverview(QString pk) ->setEnabled(req->hasRight(req->RSetTemplate)); m2->addAction(tr("&Update Templates Now"),req,SLOT(updateTemplates())) ->setEnabled(req->hasRight(req->RGetTemplateList)); + m2->addSeparator(); + m2->addAction(tr("&ODF Editor..."),this,SLOT(editOdfTemplate())); m2=m->addMenu(tr("A&udit")); m2->addAction(tr("&Order Audit..."),this,SLOT(orderAudit())); @@ -608,6 +611,12 @@ void MOverview::editTemplates() te->show(); } +void MOverview::editOdfTemplate() +{ + MOdfEditor *oe=new MOdfEditor(this); + oe->show(); +} + void MOverview::wizardMode() { MWizard wiz(this); diff --git a/src/mwin/overview.h b/src/mwin/overview.h index a76ee50..1eb313e 100644 --- a/src/mwin/overview.h +++ b/src/mwin/overview.h @@ -118,6 +118,7 @@ class MOverview:public MTabWin /**open template editor*/ void editTemplates(); + void editOdfTemplate(); /**switch to wizard mode*/ void wizardMode(); diff --git a/src/templates/odfedit.cpp b/src/templates/odfedit.cpp index 409bcf1..424b6f0 100644 --- a/src/templates/odfedit.cpp +++ b/src/templates/odfedit.cpp @@ -20,6 +20,7 @@ #include "MOVoucher" #include + #include #include #include @@ -47,13 +48,15 @@ #include #include #include +#include #include #include #include #include +#include +#include #include #include -#include class DPTR_CLASS_NAME(MOdfEditor) @@ -66,6 +69,20 @@ class DPTR_CLASS_NAME(MOdfEditor) //widgets QTreeView*mDomTree; MDomItemModel*mDomModel; + //stack indexes + int st_none,st_tag,st_text,st_loop,st_calc,st_comment,st_cond; + //stack widgets + QLineEdit*mLoopVar,*mCalcExpr,*mTagName,*mCondExpr; + QTextEdit*mText,*mComment; + QTableView*mTagAttrs; + QStandardItemModel*mTagAttrModel; + //tree menu + QAction*maAddCalc,*maAddCond,*maAddComment,*maAddElse,*maAddLoop; + QAction*maInsCalc,*maInsComment,*maUnwrap,*maDelItem; + void setActions(const QList&); + //current node + QModelIndex mCurIndex; + QDomNode mCurNode; //file contents struct File{ QString name; @@ -80,6 +97,24 @@ class DPTR_CLASS_NAME(MOdfEditor) DEFINE_DPTR(MOdfEditor); +static QVariant displayColorHelper(const QDomNode& node) +{ + static const QColor textbg("#c0c0ff"),commentbg("#c0c0c0"),specialbg("#ffc0c0"); + switch(node.nodeType()){ + case QDomNode::CommentNode:return commentbg; + case QDomNode::TextNode: + case QDomNode::CDATASectionNode: + return textbg; + case QDomNode::ElementNode: + if(node.nodeName().startsWith(OdfTemplatePrefix+":")) + return specialbg; + //fall through + default: //use default color + return QVariant(); + } +} + + MOdfEditor::MOdfEditor(QWidget* parent, Qt::WindowFlags f): QMainWindow(parent, f) { setWindowTitle(tr("ODF Template Editor")); @@ -94,12 +129,16 @@ MOdfEditor::MOdfEditor(QWidget* parent, Qt::WindowFlags f): QMainWindow(parent, m->addAction(tr("&Close"),this,SLOT(close())); m=mb->addMenu(tr("&Edit")); - m->addAction(tr("Insert &Calculation")); - m->addAction(tr("Insert C&ondition")); - m->addAction(tr("Insert &Else")); - m->addAction(tr("Insert &Loop")); + d->maAddCalc=m->addAction(tr("Insert &Calculation into current")); + d->maInsCalc=m->addAction(tr("Insert Calculation behind current")); + d->maAddCond=m->addAction(tr("&Wrap in Condition")); + d->maAddLoop=m->addAction(tr("Wrap in &Loop")); + d->maAddElse=m->addAction(tr("Insert &Else behind current")); + d->maAddComment=m->addAction(tr("Insert Comment into current")); + d->maInsComment=m->addAction(tr("Insert Comment behind current")); m->addSeparator(); - m->addAction(tr("&Remove Item"),this,SLOT(delItem())); + d->maUnwrap=m->addAction(tr("Unwrap Loop/Condition")); + d->maDelItem=m->addAction(tr("&Remove Item"),this,SLOT(delItem())); m=mb->addMenu(tr("&Data")); m->addAction(tr("Import from Order...")); @@ -110,25 +149,83 @@ MOdfEditor::MOdfEditor(QWidget* parent, Qt::WindowFlags f): QMainWindow(parent, //central QSplitter*central=new QSplitter(Qt::Vertical); setCentralWidget(central); - QVBoxLayout*vl,*vl2; - QHBoxLayout*hl,*hl2; - QPushButton*p; + QVBoxLayout*vl; + QHBoxLayout*hl; + central->setStretchFactor(0,1); + central->setStretchFactor(1,5); + central->setOrientation(Qt::Horizontal); + //DOM tree central->addWidget(d->mDomTree=new QTreeView); d->mDomTree->setModel(d->mDomModel=new MDomItemModel(this)); d->mDomTree->setEditTriggers(QAbstractItemView::NoEditTriggers); d->mDomModel->setHeaderData(0,Qt::Horizontal,tr("Document XML Tree"),Qt::DisplayRole); d->mDomModel->showAllNodeTypes(); -// d->mDomModel->addShowNodeType(QDomNode::AttributeNode); - d->mDomTree->setSelectionMode(QAbstractItemView::SingleSelection); + d->mDomModel->showTypeLabel(false); + d->mDomModel->setContentFromNodeCall(Qt::BackgroundColorRole,displayColorHelper); + d->mDomTree->setSelectionMode(QAbstractItemView::ContiguousSelection); d->mDomTree->setSelectionBehavior(QAbstractItemView::SelectRows); d->mDomTree->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); d->mDomTree->header()->setResizeMode(0,QHeaderView::ResizeToContents); d->mDomTree->header()->setStretchLastSection(false); + connect(d->mDomTree->selectionModel(),SIGNAL(selectionChanged(QItemSelection,QItemSelection)), this,SLOT(selectionChange())); + + //the editors... + QStackedWidget*stack; + central->addWidget(stack=new QStackedWidget); + connect(this,SIGNAL(switchStack(int)),stack,SLOT(setCurrentIndex(int))); + d->st_none=stack->addWidget(new QWidget); + QWidget*w; + //text node editor + d->st_text=stack->addWidget(w=new QWidget); + w->setLayout(vl=new QVBoxLayout); + vl->addWidget(new QLabel(tr("

Plain Text

"))); + vl->addWidget(d->mText=new QTextEdit); + //tag editor + d->st_tag=stack->addWidget(w=new QWidget); + w->setLayout(vl=new QVBoxLayout); + vl->addWidget(new QLabel(tr("

Tag

"))); + vl->addLayout(hl=new QHBoxLayout); + hl->addWidget(new QLabel(tr("Tag Name:"))); + hl->addWidget(d->mTagName=new QLineEdit,1); + vl->addSpacing(15); + vl->addWidget(new QLabel(tr("Attributes:"))); + vl->addWidget(d->mTagAttrs=new QTableView,1); + d->mTagAttrs->setModel(d->mTagAttrModel=new QStandardItemModel); + //loop editor + d->st_loop=stack->addWidget(w=new QWidget); + w->setLayout(vl=new QVBoxLayout); + vl->addWidget(new QLabel(tr("

Loop

"))); + vl->addLayout(hl=new QHBoxLayout); + hl->addWidget(new QLabel(tr("Loop Variable"))); + hl->addWidget(d->mLoopVar=new QLineEdit); + vl->addStretch(1); + //calc editor + d->st_calc=stack->addWidget(w=new QWidget); + w->setLayout(vl=new QVBoxLayout); + vl->addWidget(new QLabel(tr("

Calculation

"))); + vl->addLayout(hl=new QHBoxLayout); + hl->addWidget(new QLabel(tr("Expression"))); + hl->addWidget(d->mCalcExpr=new QLineEdit); + vl->addStretch(1); + //calc editor + d->st_cond=stack->addWidget(w=new QWidget); + w->setLayout(vl=new QVBoxLayout); + vl->addWidget(new QLabel(tr("

Condition

"))); + vl->addLayout(hl=new QHBoxLayout); + hl->addWidget(new QLabel(tr("Expression"))); + hl->addWidget(d->mCondExpr=new QLineEdit); + vl->addStretch(1); + //comment editor + d->st_comment=stack->addWidget(w=new QWidget); + w->setLayout(vl=new QVBoxLayout); + vl->addWidget(new QLabel(tr("

Comment

"))); + vl->addWidget(d->mComment=new QTextEdit,1); //statusbar statusBar()->setSizeGripEnabled(true); setAttribute(Qt::WA_DeleteOnClose); + updateDisplay(); } @@ -192,6 +289,7 @@ void MOdfEditor::parseTemplate(QByteArray bytes) if(!dov1){ d->mDomModel->setDomDocument(d->mContent); d->mDomTree->expandAll(); + qDebug()<<"done parsing template"; return; } //try again @@ -206,6 +304,7 @@ void MOdfEditor::parseTemplate(QByteArray bytes) // qDebug()<<"dump\n"<mContent.toByteArray(); d->mDomModel->setDomDocument(d->mContent); d->mDomTree->expandAll(); + qDebug()<<"done converting and parsing template"; } void MOdfEditor::openFile() @@ -246,10 +345,11 @@ void MOdfEditor::saveFileAs() void MOdfEditor::updateDisplay() { if(d->mFileName=="") - setWindowTitle(tr("Label Template Editor")); + setWindowTitle(tr("ODF Template Editor")); else - setWindowTitle(tr("Label Template Editor [%1]").arg(d->mFileName)); + setWindowTitle(tr("ODF Template Editor [%1]").arg(d->mFileName)); //basics + selectionChange(); } void MOdfEditor::saveTemplate(QFile& fd) @@ -276,3 +376,115 @@ void MOdfEditor::saveXmlPart(QIODevice& fd) //save fd.write(d->mContent.toByteArray()); } + +void MOdfEditor::selectionChange() +{ + saveCurrentNode(); + d->mCurIndex=QModelIndex(); + d->mCurNode=QDomNode(); + d->setActions(QList()); + //get selection + QModelIndexList idxl=d->mDomTree->selectionModel()->selectedRows(); + if(idxl.size()!=1){ + emit switchStack(d->st_none); + if(idxl.size()>1) + d->setActions(QList()<maAddCond<maAddLoop); + return; + } + //check element type + d->mCurIndex=idxl[0]; + d->mCurNode=d->mDomModel->node(idxl[0]); + QDomNode pn=d->mDomModel->node(idxl[0].parent()); + bool allowElse=pn.isElement() && pn.nodeName()==(OdfTemplatePrefix+":if"); + //comment? + if(d->mCurNode.isComment()){ + emit switchStack(d->st_comment); + d->mComment->setText(d->mCurNode.nodeValue()); + d->setActions(QList()<maAddCalc<maInsComment<maDelItem<<(allowElse?d->maAddElse:nullptr)); + return; + } + //is it normal text? + if(d->mCurNode.isCharacterData()){ + emit switchStack(d->st_text); + d->mText->setText(d->mCurNode.nodeValue()); + d->setActions(QList()<maAddCalc<maAddComment<maAddCond<maAddLoop<maDelItem<<(allowElse?d->maAddElse:nullptr)); + return; + } + //henceforth we are only interested in elements. + if(!d->mCurNode.isElement()){ + emit switchStack(d->st_none); + d->setActions(QList()<maAddCalc<maAddComment<maDelItem<<(allowElse?d->maAddElse:nullptr)); + return; + } + //is it special? + const QStringList nn=d->mCurNode.nodeName().split(':'); + if(nn.size()==2 && nn[0]==OdfTemplatePrefix){ + QDomElement el=d->mCurNode.toElement(); + if(nn[1]=="loop"){ + emit switchStack(d->st_loop); + d->mLoopVar->setText(el.attribute("variable")); + #warning implement correct actions for special tags + return; + } + if(nn[1]=="calculate"){ + emit switchStack(d->st_calc); + d->mCalcExpr->setText(el.attribute("exec")); + return; + } + if(nn[1]=="if"){ + emit switchStack(d->st_cond); + d->mCondExpr->setText(el.attribute("select")); + return; + } + //else + emit switchStack(d->st_none); + return; + }else{ + emit switchStack(d->st_tag); + #warning implement correct actions for normal tags + displayTag(); + return; + } +} + +void MOdfEditor::displayTag() +{ + QDomElement el=d->mCurNode.toElement(); + d->mTagAttrModel->clear(); + if(el.isNull()){ + d->mTagName->setText(""); + return; + } + d->mTagName->setText(el.tagName()); + //redo model + if(d->mTagAttrModel->columnCount()<2){ + d->mTagAttrModel->insertColumns(0,2); + d->mTagAttrModel->setHorizontalHeaderLabels(QStringList()<mTagAttrModel->insertRows(0,al.size()); + for(int i=0;imTagAttrModel->setData(d->mTagAttrModel->index(i,0),at.name()); + d->mTagAttrModel->setData(d->mTagAttrModel->index(i,1),at.value()); + } + d->mTagAttrs->resizeColumnsToContents(); +} + +void MOdfEditor::saveCurrentNode() +{ +#warning implement +} + +void MOdfEditor::Private::setActions(const QList< QAction* >& act) +{ + maAddCalc->setEnabled(act.contains(maAddCalc)); + maAddCond->setEnabled(act.contains(maAddCond)); + maAddComment->setEnabled(act.contains(maAddComment)); + maAddElse->setEnabled(act.contains(maAddElse)); + maAddLoop->setEnabled(act.contains(maAddLoop)); + maInsCalc->setEnabled(act.contains(maInsCalc)); + maInsComment->setEnabled(act.contains(maInsComment)); + maUnwrap->setEnabled(act.contains(maUnwrap)); + maDelItem->setEnabled(act.contains(maDelItem)); +} diff --git a/src/templates/odfedit.h b/src/templates/odfedit.h index 4688e44..96de8f7 100644 --- a/src/templates/odfedit.h +++ b/src/templates/odfedit.h @@ -21,6 +21,7 @@ class QFile; class QIODevice; +class QDomNode; /**An editor for ticket templates.*/ class MOdfEditor:public QMainWindow { @@ -50,6 +51,16 @@ class MOdfEditor:public QMainWindow void saveTemplate(QFile&); ///helper: saves the XML part of the template (device must be writable) void saveXmlPart(QIODevice&); + ///helper: react on selection changes in the DOM tree + void selectionChange(); + signals: + ///used to switch to the correct editor widget + void switchStack(int); + private: + ///helper to save the current node when selection changes + void saveCurrentNode(); + ///helper to display a tag + void displayTag(); }; #endif -- 1.7.2.5