From 409c44fa052550f41d79db26bdf8c0ee83a558f4 Mon Sep 17 00:00:00 2001 From: Konrad Rosenbaum Date: Thu, 8 Mar 2012 09:04:32 +0100 Subject: [PATCH] wrapping and unwrapping in odf edit --- src/misc/dommodel.cpp | 97 +++++++++++++------------------------------- src/misc/dommodel.h | 20 ++------- src/templates/odfedit.cpp | 84 +++++++++++++++++++++++++++++++++++++- src/templates/odfedit.h | 6 +++ 4 files changed, 120 insertions(+), 87 deletions(-) diff --git a/src/misc/dommodel.cpp b/src/misc/dommodel.cpp index 1635789..4232300 100644 --- a/src/misc/dommodel.cpp +++ b/src/misc/dommodel.cpp @@ -230,8 +230,21 @@ void MDomItemModel::setNode(const QModelIndex& index, const QDomNode& node) dataChanged(index,index); } +void MDomItemModel::insertNodes(const QDomNodeList& newnodes, const QModelIndex& parent, int row) +{ + QListnnl; + for(int i=0;i()<& newnodes, const QModelIndex& parent, int row) +{ + if(newnodes.size()<1)return; //check parent validity if(!parent.isValid())return; int pid=parent.internalId(); @@ -239,24 +252,31 @@ void MDomItemModel::insertNode(const QDomNode& newnode, const QModelIndex& paren //only add to tags (TODO: there are a few other node types that can have children) if(!d->domCache[pid].node.isElement())return; //get the parent and a clone of the new node - QDomNode nn=newnode.cloneNode(); QDomElement pn=d->domCache[pid].node.toElement(); const int rcnt=rowCount(parent); //handle appending if(row<0 || row>=rcnt){ - beginInsertRows(parent,rcnt,rcnt); - pn.appendChild(nn); - d->domCache[pid].children.append(d->buildCache(nn,pid)); + const int rmax=rcnt+newnodes.size()-1; + beginInsertRows(parent,rcnt,rmax); + for(QDomNode nd:newnodes){ + QDomNode nn=nd.cloneNode(); + pn.appendChild(nn); + d->domCache[pid].children.append(d->buildCache(nn,pid)); + } endInsertRows(); return; } //handle inserting //get current occupant of this row QDomNode sibl=node(index(row,0,parent)); - beginInsertRows(parent,row,row); + const int rmax=row+newnodes.size()-1; + beginInsertRows(parent,row,rmax); //insert - pn.insertBefore(nn,sibl); - d->domCache[pid].children.insert(row,d->buildCache(nn,pid)); + for(QDomNode nd:newnodes){ + QDomNode nn=nd.cloneNode(); + pn.insertBefore(nn,sibl); + d->domCache[pid].children.insert(row,d->buildCache(nn,pid)); + } endInsertRows(); } @@ -483,7 +503,7 @@ bool MDomItemModel::removeRows(int row, int count, const QModelIndex& parent) if(!d->domCache.contains(pid)) return false; //check the parent has those children - if(rowCount(parent)>(row+count)) + if(rowCount(parent)<(row+count)) return false; //warn the view beginRemoveRows(parent,row,row+count-1); @@ -500,68 +520,9 @@ bool MDomItemModel::removeRows(int row, int count, const QModelIndex& parent) foreach(int cid,cids)d->removeNode(cid); //update view endRemoveRows(); + return true; } -void MDomItemModel::reparentNode(const QModelIndex& index, const QDomElement& el) -{ - //find index and parent - if(!index.isValid())return; - int nid=index.internalId(); - if(!d->domCache.contains(nid))return; - int pid=d->domCache[nid].parent; - if(pid<0 || !d->domCache.contains(pid))return; - //invalidate model, TODO: find a less invasive call - beginResetModel(); - //reparent both - QDomElement nelem=el.cloneNode().toElement(); - int neid=d->buildCache(nelem,pid); - QDomNode sibl=d->domCache[nid].node.previousSibling(); - nelem.appendChild(d->domCache[nid].node); - if(sibl.isNull()) - d->domCache[pid].node.insertBefore(nelem,QDomNode()); - else - d->domCache[pid].node.insertAfter(nelem,sibl); - //correct references - d->domCache[nid].parent=neid; - int oidx=d->domCache[pid].children.indexOf(nid); - d->domCache[pid].children.replace(oidx,neid); - d->domCache[neid].children.append(nid); - //update view - endResetModel(); -} - -void MDomItemModel::reparentNode(const QModelIndex& node, const QModelIndex& newparent, int row) -{ - //get node ids - if(!node.isValid() || !newparent.isValid())return; - int nid=node.internalId(); - int npid=newparent.internalId(); - if(nid<=0 || npid<=0 || !d->domCache.contains(nid) || !d->domCache.contains(npid)) - return; - int opid=d->domCache[nid].parent; - if(opid<=0 || !d->domCache.contains(opid))return; - //get position in new parent - int cnt=0; - QDomNode neigh; - foreach(int cid,d->domCache[npid].children){ - if(!d->showType.contains(d->domCache[cid].node.nodeType())) - continue; - //TODO:this is probably wrong - if(cnt++>row)break; - neigh=d->domCache[cid].node; - } - //TODO:insert node in new parent - //TODO:move logical IDs - //TODO:tell view -#warning implement -} - -void MDomItemModel::reparentNode(const QModelIndexList& nodes, const QModelIndex& newparent, int row) -{ -#warning implement -} - - void MDomItemModel::setContentFromNodeCall(int role,MDomModelFunctor f) { if(role==DomNodeRole)return; diff --git a/src/misc/dommodel.h b/src/misc/dommodel.h index a770e5f..6086fe7 100644 --- a/src/misc/dommodel.h +++ b/src/misc/dommodel.h @@ -109,26 +109,14 @@ class MDomItemModel:public QAbstractItemModel virtual void setNode(const QModelIndex&index,const QDomNode&); ///insert a node into the parent at given position (if no position is given: append) virtual void insertNode(const QDomNode&newnode,const QModelIndex&parent,int row=-1); + ///insert a list of nodes into the parent at given position (if no position is given: append) + virtual void insertNodes(const QDomNodeList&newnodes,const QModelIndex&parent,int row=-1); + ///insert a list of nodes into the parent at given position (if no position is given: append) + virtual void insertNodes(const QList&newnodes,const QModelIndex&parent,int row=-1); ///removes the nodes at the given position and their child nodes virtual bool removeRows(int row, int count, const QModelIndex&parent=QModelIndex()); ///removes the node at the given position and its child nodes virtual void removeNode(const QModelIndex&); - /** places the node at the given index inside the new node and then places the new node at that position - in fact moving the node at index one hierarchy level down - \param index the node to be reparented - \param newnode the node that will replace the node and take it as its new child*/ - virtual void reparentNode(const QModelIndex&index,const QDomElement&newnode); - /** places the node in a new parent that is already inside the model - \param node the node to be reparented - \param newparent the new parent of this node - \param row the position inside the parent where to insert that node, if row is greater than the current size of the parent or if it is negative the node will be appended - this call invalidates the new and old parent index of the node*/ - virtual void reparentNode(const QModelIndex&node,const QModelIndex&newparent,int row=-1); - /** places the nodes in a new parent that is already inside the model - \param nodes the nodes to be reparented - \param newparent the new parent of this node - \param row the position inside the parent where to insert the new nodes - they will be inserted in the order they are contained in the list, if row is greater than the current size of the parent or if it is negative the node will be appended - this call invalidates the new and old parent indexes of the nodes*/ - virtual void reparentNode(const QModelIndexList&nodes,const QModelIndex&newparent,int row=-1); /**Customize the way the model returns data to the view, per default the model only has code to generate a text representation for Qt::DisplayRole. You can override any role, including Qt::DisplayRole, except for DomNodeRole. The callback takes a const reference to QDomNode as argument and should convert it to a QVariant appropriate for the role. \param role the role to be customized diff --git a/src/templates/odfedit.cpp b/src/templates/odfedit.cpp index e366ed8..6ebe313 100644 --- a/src/templates/odfedit.cpp +++ b/src/templates/odfedit.cpp @@ -71,6 +71,7 @@ class DPTR_CLASS_NAME(MOdfEditor) //widgets QTreeView*mDomTree; MDomItemModel*mDomModel; + void expandTree(const QModelIndex&); //stack indexes int st_none,st_tag,st_text,st_loop,st_calc,st_comment,st_cond,st_special; //stack widgets @@ -140,13 +141,13 @@ MOdfEditor::MOdfEditor(QWidget* parent, Qt::WindowFlags f): QMainWindow(parent, QMenu*medit=m=mb->addMenu(tr("&Edit")); d->maAddIntoCalc=m->addAction(tr("Insert &Calculation into current"),this,SLOT(insCalcIntoCurrent())); d->maInsBehindCalc=m->addAction(tr("Insert Calculation behind current"),this,SLOT(insCalcBehindCurrent())); - d->maWrapInCond=m->addAction(tr("&Wrap in Condition")); - d->maWrapInLoop=m->addAction(tr("Wrap in &Loop")); + d->maWrapInCond=m->addAction(tr("&Wrap in Condition"),this,SLOT(wrapInCond())); + d->maWrapInLoop=m->addAction(tr("Wrap in &Loop"),this,SLOT(wrapInLoop())); d->maInsBehindElse=m->addAction(tr("Insert &Else behind current"),this,SLOT(insElse())); d->maAddIntoComment=m->addAction(tr("Insert Comment into current"),this,SLOT(insCommentIntoCurrent())); d->maInsBehindComment=m->addAction(tr("Insert Comment behind current"),this,SLOT(insCommentBehindCurrent())); m->addSeparator(); - d->maUnwrap=m->addAction(tr("Unwrap Loop/Condition")); + d->maUnwrap=m->addAction(tr("Unwrap Loop/Condition"),this,SLOT(unwrapItem())); d->maDelItem=m->addAction(tr("&Remove Item"),this,SLOT(delItem())); m=mb->addMenu(tr("&Data")); @@ -639,6 +640,8 @@ void MOdfEditor::insCalcIntoCurrent() //insert calculation QDomNode nn=cnode.ownerDocument().createElement(OdfTemplatePrefix+":calculate"); d->mDomModel->insertNode(nn,idx,0); + //make sure it is visible + d->expandTree(idx); } void MOdfEditor::insElse() @@ -690,4 +693,79 @@ void MOdfEditor::insCommentIntoCurrent() //insert comment QDomNode nn=cnode.ownerDocument().createComment(tr("new comment")); d->mDomModel->insertNode(nn,idx,0); + //make sure it is visible + d->expandTree(idx); +} + +void MOdfEditor::wrapInCond(QString tag) +{ + //get selection + const QModelIndexList &idxl=d->mDomTree->selectionModel()->selectedRows(); + if(idxl.size()==0)return; + //keep only items that have no parent in the list + // (i.e. eliminate children, since this algo is recursive anyway) + QModelIndexList idxl2; + for(QModelIndex idx:idxl) + if(!idxl.contains(idx.parent()))idxl2< ndlist; + qSort(idxl2.begin(),idxl2.end(),[](const QModelIndex&a,const QModelIndex&b){return a.row()idx.row())frow=idx.row(); + ndlist<mDomModel->node(idx); + } + if(ndlist.size()<1)return; + //create new parent node + QDomElement np=ndlist[0].ownerDocument().createElement(OdfTemplatePrefix+":"+tag); + //copy the moved items in + for(QDomNode nd:ndlist)np.appendChild(nd); + //remove the old items + d->mDomModel->removeRows(frow,lrow-frow+1,pidx); + //add the new item + d->mDomModel->insertNode(np,pidx,frow); + //expand + d->expandTree(d->mDomModel->index(frow,0,pidx)); +} + +void MOdfEditor::Private::expandTree(const QModelIndex& idx) +{ + //expand this + mDomTree->expand(idx); + //recurse + const int rc=mDomModel->rowCount(idx); + for(int i=0;iindex(i,0,idx)); +} + + +void MOdfEditor::wrapInLoop() +{ + wrapInCond("loop"); +} + +void MOdfEditor::unwrapItem() +{ + //get the item + QModelIndex idx=d->mDomTree->currentIndex(); + if(!idx.isValid())return; + //get the node and parent index + QDomElement el=d->mDomModel->node(idx).toElement(); + QModelIndex pidx=idx.parent(); + const int row=idx.row(); + //remove the original + d->mDomModel->removeNode(idx); + //insert the children into the parent node at the correct position + d->mDomModel->insertNodes(el.childNodes(),pidx,row); + //expand the tree + d->expandTree(pidx); } diff --git a/src/templates/odfedit.h b/src/templates/odfedit.h index 55274a1..ab38921 100644 --- a/src/templates/odfedit.h +++ b/src/templates/odfedit.h @@ -70,6 +70,12 @@ class MOdfEditor:public QMainWindow void insElse(); ///helper: delete an item void delItem(); + ///helper: wrap marked items in a condition + void wrapInCond(QString tag="if"); + ///helper: wrap marked items in a loop + void wrapInLoop(); + ///helper: unwrap the loop or condition + void unwrapItem(); signals: ///used to switch to the correct editor widget void switchStack(int); -- 1.7.2.5