more on odf editor
authorKonrad Rosenbaum <konrad@silmor.de>
Sun, 19 Feb 2012 20:44:39 +0000 (21:44 +0100)
committerKonrad Rosenbaum <konrad@silmor.de>
Sun, 19 Feb 2012 20:44:39 +0000 (21:44 +0100)
pack
src/misc/dommodel.cpp
src/misc/dommodel.h
src/mwin/overview.cpp
src/mwin/overview.h
src/templates/odfedit.cpp
src/templates/odfedit.h

diff --git a/pack b/pack
index 124750d..148c47b 160000 (submodule)
--- a/pack
+++ b/pack
@@ -1 +1 @@
-Subproject commit 124750d5e19a642f69f28a3299380bb95ba3d089
+Subproject commit 148c47b29a616af46ed6690019d32b85ed568fac
index 7bad551..5961e62 100644 (file)
@@ -48,6 +48,7 @@ class DPTR_CLASS_NAME(MDomItemModel)
                QMap<int,MDomModelFunctor> contentFromNode;
                //config for element display
                int elemAttrLen,elemTextLen;
+               bool showtypeLabel;
                //header data
                QMap<QPair<int,int>,QVariant>horizHeader,vertHeader;
                
@@ -69,6 +70,7 @@ MDomItemModel::Private::Private()
 {
        showType<<QDomNode::ElementNode;
        elemAttrLen=20;elemTextLen=30;
+       showtypeLabel=true;
 }
 
 
@@ -173,6 +175,19 @@ void MDomItemModel::showElementProperties(int ma,int mt)
        if(b)endResetModel();
 }
 
+void MDomItemModel::showTypeLabel(bool show)
+{
+       //ignore if there is no change
+       if(d->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 ":"")+"<!-- "+node.nodeValue()+" -->";
                default:
-                       return "node ("+QString::number(node.nodeType())+"): "+node.nodeName()+" - \""+node.nodeValue()+"\"";
+                       return (d->showtypeLabel?("node ("+QString::number(node.nodeType())+"): "):QString())+node.nodeName()+" - \""+node.nodeValue()+"\"";
        }
 }
 
index e465032..744cbad 100644 (file)
@@ -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
index 92ab620..9252ebc 100644 (file)
@@ -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);
index a76ee50..1eb313e 100644 (file)
@@ -118,6 +118,7 @@ class MOverview:public MTabWin
                
                /**open template editor*/
                void editTemplates();
+               void editOdfTemplate();
                
                /**switch to wizard mode*/
                void wizardMode();
index 409bcf1..424b6f0 100644 (file)
@@ -20,6 +20,7 @@
 #include "MOVoucher"
 
 #include <DPtr>
+
 #include <QAction>
 #include <QBoxLayout>
 #include <QComboBox>
 #include <QSignalMapper>
 #include <QSizeF>
 #include <QSplitter>
+#include <QStackedWidget>
 #include <QStandardItemModel>
 #include <QStatusBar>
 #include <QTableView>
 #include <QTemporaryFile>
+#include <QTextEdit>
+#include <QTreeView>
 #include <QUnZip>
 #include <QZip>
-#include <QTreeView>
 
 
 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<QAction*>&);
+               //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("<h1>Plain Text<h1>")));
+       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("<h1>Tag</h1>")));
+       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("<h1>Loop</h1>")));
+       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("<h1>Calculation</h1>")));
+       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("<h1>Condition</h1>")));
+       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("<h1>Comment</h1>")));
+       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"<<d->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<QAction*>());
+       //get selection
+       QModelIndexList idxl=d->mDomTree->selectionModel()->selectedRows();
+       if(idxl.size()!=1){
+               emit switchStack(d->st_none);
+               if(idxl.size()>1)
+                       d->setActions(QList<QAction*>()<<d->maAddCond<<d->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<QAction*>()<<d->maAddCalc<<d->maInsComment<<d->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<QAction*>()<<d->maAddCalc<<d->maAddComment<<d->maAddCond<<d->maAddLoop<<d->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<QAction*>()<<d->maAddCalc<<d->maAddComment<<d->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()<<tr("Attribute")<<tr("Value"));
+       }
+       QDomNamedNodeMap al=el.attributes();
+       d->mTagAttrModel->insertRows(0,al.size());
+       for(int i=0;i<al.size();i++){
+               QDomAttr at=al.item(i).toAttr();
+               d->mTagAttrModel->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));
+}
index 4688e44..96de8f7 100644 (file)
@@ -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