From eb32853b005776ec3683a84d60eb504560b50bb3 Mon Sep 17 00:00:00 2001 From: Konrad Rosenbaum Date: Tue, 6 Mar 2012 08:56:49 +0100 Subject: [PATCH] enable odf editor to actually edit existing items --- src/misc/dommodel.cpp | 33 ++++++++++----- src/misc/lambda.h | 15 +++++++ src/templates/odfedit.cpp | 98 ++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 125 insertions(+), 21 deletions(-) diff --git a/src/misc/dommodel.cpp b/src/misc/dommodel.cpp index 5961e62..9404a64 100644 --- a/src/misc/dommodel.cpp +++ b/src/misc/dommodel.cpp @@ -195,7 +195,9 @@ QDomNode MDomItemModel::node(const QModelIndex& index) const else return d->domCache[d->docidx].node.cloneNode(); } if(!d->domCache.contains(index.internalId()))return QDomNode(); - return d->domCache[index.internalId()].node.cloneNode(); + QDomNode node=d->domCache[index.internalId()].node.cloneNode(); + qDebug()<<"returning node"<domCache.contains(nid))return; int pid=d->domCache[nid].parent; if(pid<=0 || !d->domCache.contains(pid))return; - //tell the view it is getting nasty, TODO: find a better way - beginResetModel(); + //invalidate children + int csize=d->domCache[nid].children.size()-1; + beginRemoveRows(index,0,csize); + for(int n:d->domCache[nid].children)d->removeNode(n); + d->domCache[nid].children.clear(); + endRemoveRows(); //replace the node in DOM - QDomNode nnode=d->domCache[pid].node.replaceChild(node.cloneNode(),d->domCache[nid].node); - //add the new node - int nnid=d->buildCache(nnode,pid); - //replace reference - int i=d->domCache[pid].children.indexOf(nid); - d->domCache[pid].children.replace(i,nnid); - //remove the old node (inrecursion==true, so the method does not mess with DOM) - d->removeNode(nid,true); + qDebug()<<"replacing node"<domCache[nid].node.nodeValue()<<"new"<domCache[pid].node.replaceChild(nnode,d->domCache[nid].node); + d->domCache[nid].node=nnode; + qDebug()<<" new nodes type is"<domCache[nid].children.append(d->buildCache(nl.at(i),nid)); + endInsertRows(); //tell the view we are finished - endResetModel(); + dataChanged(index,index); } int MDomItemModel::columnCount(const QModelIndex&) const diff --git a/src/misc/lambda.h b/src/misc/lambda.h index 5408647..53f451d 100644 --- a/src/misc/lambda.h +++ b/src/misc/lambda.h @@ -39,4 +39,19 @@ class MLambda:public QObject void call(){if(m_ptr)m_ptr();} }; +///clean-up function: executes a lambda expression when it is destructed (i.e. when the instance leaves its scope +class MCleanup +{ + std::functionm_ptr; + public: + ///instantiates a new cleanup object and remembers the given function for later execution + MCleanup(const std::function&f):m_ptr(f){} + + ///sets a new cleanup function, removing the old one + void setFunction(const std::function&f){m_ptr=f;} + + ///destructs the object and executes the cleanup function + ~MCleanup(){if(m_ptr)m_ptr();} +}; + #endif diff --git a/src/templates/odfedit.cpp b/src/templates/odfedit.cpp index d08066b..ad4e56c 100644 --- a/src/templates/odfedit.cpp +++ b/src/templates/odfedit.cpp @@ -72,13 +72,14 @@ class DPTR_CLASS_NAME(MOdfEditor) QTreeView*mDomTree; MDomItemModel*mDomModel; //stack indexes - int st_none,st_tag,st_text,st_loop,st_calc,st_comment,st_cond; + int st_none,st_tag,st_text,st_loop,st_calc,st_comment,st_cond,st_special; //stack widgets QLineEdit*mLoopVar,*mCalcExpr,*mTagName,*mCondExpr; QTextEdit*mText,*mComment; QTableView*mTagAttrs; QStandardItemModel*mTagAttrModel; - bool mChanged; + QStackedWidget*mStack; + QLabel*mSpecial; //tree menu QAction*maAddIntoCalc,*maWrapInCond,*maAddIntoComment,*maInsBehindElse,*maWrapInLoop; QAction*maInsBehindCalc,*maInsBehindComment,*maUnwrap,*maDelItem; @@ -86,6 +87,7 @@ class DPTR_CLASS_NAME(MOdfEditor) //current node QModelIndex mCurIndex; QDomNode mCurNode; + bool mChanged; //file contents struct File{ QString name; @@ -96,7 +98,10 @@ class DPTR_CLASS_NAME(MOdfEditor) File(QString n,Type t,const QByteArray&c):name(n),type(t),content(c){} }; QList mFiles; - Private():mChanged(false){st_none=st_tag=st_text=st_loop=st_calc=st_comment=st_cond=-1;} + Private():mChanged(false) + { + st_none=st_tag=st_text=st_loop=st_calc=st_comment=st_cond=st_special=-1; + } }; DEFINE_DPTR(MOdfEditor); @@ -185,14 +190,22 @@ MOdfEditor::MOdfEditor(QWidget* parent, Qt::WindowFlags f): QMainWindow(parent, //the editors... QStackedWidget*stack; central->addWidget(stack=new QStackedWidget); + d->mStack=stack; connect(this,SIGNAL(switchStack(int)),stack,SLOT(setCurrentIndex(int))); d->st_none=stack->addWidget(new QWidget); QWidget*w; //text node editor + d->st_special=stack->addWidget(w=new QWidget); + w->setLayout(vl=new QVBoxLayout); + vl->addWidget(new QLabel(tr("

Special Template Tag

"))); + vl->addWidget(d->mSpecial=new QLabel("...")); + vl->addStretch(1); + //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); + connect(d->mText,SIGNAL(textChanged()),this,SLOT(setChanged())); //tag editor d->st_tag=stack->addWidget(w=new QWidget); w->setLayout(vl=new QVBoxLayout); @@ -208,6 +221,19 @@ MOdfEditor::MOdfEditor(QWidget* parent, Qt::WindowFlags f): QMainWindow(parent, connect(d->mTagAttrModel,SIGNAL(dataChanged(QModelIndex,QModelIndex)), this,SLOT(setChanged())); connect(d->mTagAttrModel,SIGNAL(rowsRemoved(const QModelIndex&,int,int)), this,SLOT(setChanged())); connect(d->mTagAttrModel,SIGNAL(rowsInserted(const QModelIndex&,int,int)), this,SLOT(setChanged())); + vl->addLayout(hl=new QHBoxLayout); + MLambda *btn;QPushButton*p; + btn=new MLambda([=](){d->mTagAttrModel->insertRow(d->mTagAttrModel->rowCount());},this); + hl->addStretch(1); + hl->addWidget(p=new QPushButton("Add")); + connect(p,SIGNAL(clicked()),btn,SLOT(call())); + btn=new MLambda([=](){ + QModelIndex idx=d->mTagAttrs->currentIndex(); + if(idx.isValid()) + d->mTagAttrModel->removeRow(idx.row(),idx.parent()); + },this); + hl->addWidget(p=new QPushButton("Remove")); + connect(p,SIGNAL(clicked()),btn,SLOT(call())); //loop editor d->st_loop=stack->addWidget(w=new QWidget); w->setLayout(vl=new QVBoxLayout); @@ -249,6 +275,8 @@ MOdfEditor::MOdfEditor(QWidget* parent, Qt::WindowFlags f): QMainWindow(parent, void MOdfEditor::setChanged(bool ch) { + if(ch!=d->mChanged) +// qDebug()<<"set changed state"<mChanged=ch; } @@ -415,6 +443,7 @@ void MOdfEditor::saveXmlPart(QIODevice& fd) void MOdfEditor::selectionChange() { saveCurrentNode(); + MCleanup clean([&](){setChanged(false);}); d->mCurIndex=QModelIndex(); d->mCurNode=QDomNode(); d->setActions(QList()); @@ -474,9 +503,10 @@ void MOdfEditor::selectionChange() d->setActions(QList()<maInsBehindCalc<maInsBehindComment<maAddIntoCalc<maAddIntoComment<maWrapInCond<maWrapInLoop<maUnwrap<maDelItem<<(allowElse?d->maInsBehindElse:nullptr)); return; } - if(nn[1]=="template"){ - emit switchStack(d->st_none); + if(nn[1]=="template" || nn[1]=="else"){ + emit switchStack(d->st_special); d->setActions(QList()); + d->mSpecial->setText(tr("Tag Type: %1").arg(htmlize(nn[1]))); return; } //else: fall through to normal tags @@ -515,11 +545,61 @@ void MOdfEditor::saveCurrentNode() { //nothing to do? if(!d->mChanged)return; -#warning implement - - qDebug()<<"fake saving item"; + setChanged(false);//prevent it from calling itself + //make sure we are in non-changed state afterwards + MCleanup cleanchanged([&](){setChanged(false);}); + //what is being displayed? + const int itemtype=d->mStack->currentIndex(); + //non-changeable types + if(!d->mCurIndex.isValid() || itemtype==d->st_none || itemtype==d->st_special){ + qDebug()<<"Warning: invalid item, or uneditable item type - why is it changed though?"; + return; + } + //get current item + QDomNode cnode=d->mCurNode; + QModelIndex cidx=d->mCurIndex; + //remember new current item + QModelIndex ncidx=d->mDomTree->currentIndex(); + d->mDomTree->setCurrentIndex(QModelIndex()); + MCleanup cleanindex([&](){d->mDomTree->setCurrentIndex(ncidx);}); + //handle item + if(itemtype==d->st_comment){ + cnode.setNodeValue(d->mComment->toPlainText()); + }else if(itemtype==d->st_text){ + cnode.setNodeValue(d->mText->toPlainText()); + }else if(itemtype==d->st_tag){ + QDomElement el=cnode.toElement(); + QMapnattr; + for(int i=0;imTagAttrModel->rowCount();i++) + nattr.insert( + d->mTagAttrModel->data(d->mTagAttrModel->index(i,0)).toString(), + d->mTagAttrModel->data(d->mTagAttrModel->index(i,1)).toString() + ); + QDomNamedNodeMap oattr=el.attributes(); + for(int i=0;imTagName->text()); +// unneccessary, since it is shared: cnode=el; + }else if(itemtype==d->st_calc){ + cnode.toElement().setAttribute("exec",d->mCalcExpr->text()); + }else if(itemtype==d->st_loop){ + cnode.toElement().setAttribute("variable",d->mLoopVar->text()); + }else if(itemtype==d->st_cond){ + cnode.toElement().setAttribute("select",d->mCondExpr->text()); + }else{ + qDebug()<<"Internal Error: unknown node type"<mChanged=false; + d->mDomModel->setNode(cidx,cnode); +// qDebug()<<"done saving"; } void MOdfEditor::Private::setActions(const QList< QAction* >& act) -- 1.7.2.5