From: Konrad Rosenbaum Date: Sun, 16 Mar 2014 14:06:13 +0000 (+0100) Subject: fix ODF editing, add copy item X-Git-Url: http://git.silmor.de/gitweb/?a=commitdiff_plain;h=ec116d9a4be8b8fa4a73a8582e26b937696ba6a6;p=web%2Fkonrad%2Fsmoke.git fix ODF editing, add copy item --- diff --git a/src/misc/domiterator.h b/src/misc/domiterator.h new file mode 100644 index 0000000..5161c53 --- /dev/null +++ b/src/misc/domiterator.h @@ -0,0 +1,42 @@ +// +// C++ Implementation: DOM node iterator for range based for loops +// +// +// Author: Konrad Rosenbaum , (C) 2013-2014 +// +// Copyright: See README/COPYING.GPL files that come with this distribution +// +// originally introduced at http://silmor.de/qtstuff.domfor.php + +#ifndef SMOKE_DOM_ITERATOR_H +#define SMOKE_DOM_ITERATOR_H + +class QDomNodeIterator +{ + int pos; + const QDomNodeList&container; +public: + //constructors and assignments + QDomNodeIterator(const QDomNodeList&l,int p):pos(p),container(l){} + QDomNodeIterator(const QDomNodeIterator&)=default; + QDomNodeIterator(QDomNodeIterator&&)=default; + QDomNodeIterator& operator=(const QDomNodeIterator&)=default; + QDomNodeIterator& operator=(QDomNodeIterator&&)=default; + + //increment + QDomNodeIterator& operator++(){pos++;return *this;} + + //comparison + bool operator==(const QDomNodeIterator&o){return pos==o.pos && container==o.container;} + bool operator!=(const QDomNodeIterator&o){return pos!=o.pos || container!=o.container;} + + //indirection + QDomNode operator*(){return container.at(pos);} +}; + +//begin and end +inline QDomNodeIterator begin(const QDomNodeList&l){return QDomNodeIterator(l,0);} +inline QDomNodeIterator end(const QDomNodeList&l){return QDomNodeIterator(l,l.size());} + + +#endif diff --git a/src/misc/dommodel.cpp b/src/misc/dommodel.cpp index 7c81656..62f61ad 100644 --- a/src/misc/dommodel.cpp +++ b/src/misc/dommodel.cpp @@ -2,7 +2,7 @@ // C++ Implementation: DOM model // // -// Author: Konrad Rosenbaum , (C) 2012 +// Author: Konrad Rosenbaum , (C) 2012-2014 // // Copyright: See README/COPYING.GPL files that come with this distribution // @@ -192,10 +192,10 @@ QDomNode MDomItemModel::node(const QModelIndex& index) const { if(!index.isValid()){ if(!d->domCache.contains(d->docidx)) return QDomNode(); - else return d->domCache[d->docidx].node.cloneNode(); + else return d->domCache[d->docidx].node; } if(!d->domCache.contains(index.internalId()))return QDomNode(); - QDomNode node=d->domCache[index.internalId()].node.cloneNode(); + QDomNode node=d->domCache[index.internalId()].node; qDebug()<<"returning node"<& newnodes, const QModelI //insert for(QDomNode nd:newnodes){ QDomNode nn=nd.cloneNode(); - pn.insertBefore(nn,sibl); + qDebug()<<"Attempting insert with"<domCache[pid].children.insert(row,d->buildCache(nn,pid)); } endInsertRows(); diff --git a/src/templates/odfedit.cpp b/src/templates/odfedit.cpp index 86dcbd6..7b45f37 100644 --- a/src/templates/odfedit.cpp +++ b/src/templates/odfedit.cpp @@ -16,6 +16,7 @@ #include "odtrender.h" #include "dommodel.h" #include "cleanup.h" +#include "domiterator.h" #include "orderwin.h" #include "eventsummary.h" @@ -91,11 +92,12 @@ class DPTR_CLASS_NAME(MOdfEditor) //tree menu QAction*maAddIntoCalc,*maWrapInCond,*maAddIntoComment; QAction*maInsBehindElse,*maWrapInLoop; - QAction*maInsBehindCalc,*maInsBehindComment,*maUnwrap,*maDelItem; - void setActions(const QList&); + QAction*maInsBehindCalc,*maInsBehindComment,*maUnwrap; + QAction*maInsItemInto,*maInsItemBehind,*maCpyItem,*maDelItem; + void setActions(const QList&,bool haveselect=true); //current node QModelIndex mCurIndex; - QDomNode mCurNode; + QDomNode mCurNode,mClipNode; bool mChanged; //test printing QString mTestFile; @@ -158,6 +160,10 @@ MOdfEditor::MOdfEditor(QWidget* parent, Qt::WindowFlags f): QMainWindow(parent, 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->maCpyItem=m->addAction(tr("Copy current item to clipboard"),this,SLOT(copyItem())); + d->maInsItemInto=m->addAction(tr("Insert clipboard into current"),this,SLOT(pasteItemInto())); + d->maInsItemBehind=m->addAction(tr("Insert clipboard behind current"),this,SLOT(pasteItemBehind())); m->addSeparator(); d->maUnwrap=m->addAction(tr("Unwrap Loop/Condition"),this,SLOT(unwrapItem())); d->maDelItem=m->addAction(tr("&Remove Item"),this,SLOT(delItem())); @@ -389,6 +395,7 @@ void MOdfEditor::parseTemplate(QByteArray bytes,bool istempl) void MOdfEditor::openFile(bool istemp) { + d->mClipNode.clear(); QString title=istemp?tr("Open ODF Template"):tr("Open ODF File"); QString flt=istemp?tr("ODF Template File (*.od?t);;All Files (*)"):tr("ODF File (*.od?);;All Files (*)"); QString fn=QFileDialog::getOpenFileName(this,title,currentDir(),flt); @@ -574,13 +581,13 @@ void MOdfEditor::selectionChange() MCleanup clean([&](){setChanged(false);}); d->mCurIndex=QModelIndex(); d->mCurNode=QDomNode(); - d->setActions(QList()); + d->setActions(QList(),false); //get selection QModelIndexList idxl=d->mDomTree->selectionModel()->selectedRows(); if(idxl.size()!=1){ emit switchStack(d->st_none); if(idxl.size()>1) - d->setActions(QList()<maWrapInCond<maWrapInLoop); + d->setActions(QList()<maWrapInCond<maWrapInLoop,false); return; } //check element type @@ -732,7 +739,7 @@ void MOdfEditor::saveCurrentNode() // qDebug()<<"done saving"; } -void MOdfEditor::Private::setActions(const QList< QAction* >& act) +void MOdfEditor::Private::setActions(const QList< QAction* >& act,bool haveselect) { maAddIntoCalc->setEnabled(act.contains( maAddIntoCalc)); maWrapInCond->setEnabled(act.contains( maWrapInCond)); @@ -743,6 +750,9 @@ void MOdfEditor::Private::setActions(const QList< QAction* >& act) maInsBehindComment->setEnabled(act.contains( maInsBehindComment)); maUnwrap->setEnabled(act.contains(maUnwrap)); maDelItem->setEnabled(act.contains(maDelItem)); + maCpyItem->setEnabled(haveselect); + maInsItemBehind->setEnabled(haveselect && !mClipNode.isNull()); + maInsItemInto->setEnabled(haveselect && !mClipNode.isNull()); } void MOdfEditor::insCalcBehindCurrent() @@ -849,7 +859,7 @@ void MOdfEditor::wrapInCond(QString tag) if(lrow<0)frow=lrow=idx.row(); if(lrowidx.row())frow=idx.row(); - ndlist<mDomModel->node(idx); + ndlist<mDomModel->node(idx).cloneNode(true); } if(ndlist.size()<1)return; //create new parent node @@ -886,7 +896,7 @@ void MOdfEditor::unwrapItem() QModelIndex idx=d->mDomTree->currentIndex(); if(!idx.isValid())return; //get the node and parent index - QDomElement el=d->mDomModel->node(idx).toElement(); + QDomElement el=d->mDomModel->node(idx).cloneNode(true).toElement(); QModelIndex pidx=idx.parent(); const int row=idx.row(); //remove the original @@ -896,3 +906,96 @@ void MOdfEditor::unwrapItem() //expand the tree d->expandTree(pidx); } + +void MOdfEditor::pasteItemBehind() +{ + //get current + QModelIndex idx=d->mDomTree->currentIndex(); + if(!idx.isValid())return; + QDomNode cnode=d->mDomModel->node(idx); + if(cnode.isNull())return; + //check + if(d->mClipNode.isNull()){ + QMessageBox::warning(this,tr("Warning"),tr("There is nothing in the clipboard. Please copy a node first.")); + return; + } + //insert item + d->mDomModel->insertNode(d->mClipNode,idx.parent(),idx.row()+1); +} + +void MOdfEditor::pasteItemInto() +{ + //get current + QModelIndex idx=d->mDomTree->currentIndex(); + if(!idx.isValid())return; + QDomNode cnode=d->mDomModel->node(idx); + if(cnode.isNull())return; + //check + if(d->mClipNode.isNull()){ + QMessageBox::warning(this,tr("Warning"),tr("There is nothing in the clipboard. Please copy a node first.")); + return; + } + //insert item + d->mDomModel->insertNode(d->mClipNode,idx,0); + //make sure it is visible + d->expandTree(idx); +} + +static inline +QDomNode xclonenode(const QDomNode&node) +{ + if(node.isNull())return QDomNode(); + QDomDocument doc=node.ownerDocument(); + QDomNode nn; + switch(node.nodeType()){ + case QDomNode::ElementNode: + nn=doc.createElement(node.nodeName()); + for(const QDomNode&ond:node.childNodes()) + nn.appendChild(xclonenode(ond)); + break; + case QDomNode::AttributeNode: + nn=doc.createAttribute(node.nodeName()); + nn.setNodeValue(node.nodeValue()); + break; + case QDomNode::TextNode: + nn=doc.createTextNode(node.nodeValue()); + break; + case QDomNode::CharacterDataNode: + case QDomNode::CDATASectionNode: + nn=doc.createCDATASection(node.nodeValue()); + break; + case QDomNode::ProcessingInstructionNode: + nn=doc.createProcessingInstruction(node.nodeName(),node.nodeValue()); + break; + case QDomNode::CommentNode: + nn=doc.createComment(node.nodeValue()); + break; + //those are currently not supported or it is completely useless to copy them + case QDomNode::EntityReferenceNode: + case QDomNode::EntityNode: + case QDomNode::DocumentNode: + case QDomNode::DocumentTypeNode: + case QDomNode::DocumentFragmentNode: + case QDomNode::NotationNode: + case QDomNode::BaseNode: + return QDomNode(); + } + return nn; +} + +void MOdfEditor::copyItem() +{ + //get current + QModelIndex idx=d->mDomTree->currentIndex(); + if(!idx.isValid())return; + QDomNode cnode=d->mDomModel->node(idx); + if(cnode.isNull())return; + //remember + if(!d->mClipNode.isNull())d->mClipNode.clear(); + d->mClipNode=cnode.cloneNode(true); + //housekeeping + d->maInsItemBehind->setEnabled(!d->mClipNode.isNull()); + d->maInsItemInto->setEnabled(!d->mClipNode.isNull()); + if(d->mClipNode.isNull()) + QMessageBox::warning(this,tr("Warning"),tr("Sorry, this kinde of node cannot be copied.")); +} diff --git a/src/templates/odfedit.h b/src/templates/odfedit.h index 241b5d7..c901699 100644 --- a/src/templates/odfedit.h +++ b/src/templates/odfedit.h @@ -79,6 +79,12 @@ class MOdfEditor:public QMainWindow void wrapInLoop(); ///helper: unwrap the loop or condition void unwrapItem(); + ///helper: copy arbitrary item to clipboard + void copyItem(); + ///helper: insert clipboard item into current + void pasteItemInto(); + ///helper: insert clipboard item after current + void pasteItemBehind(); ///helper: test new template on an order void testOrder();