add variadic lambda wrapper (incomplete: does not handle references yet);
authorKonrad Rosenbaum <konrad@silmor.de>
Wed, 22 Feb 2012 18:06:32 +0000 (19:06 +0100)
committerKonrad Rosenbaum <konrad@silmor.de>
Wed, 22 Feb 2012 18:06:32 +0000 (19:06 +0100)
show context menu in ODF editor

src/misc/misc.pri
src/misc/vlambda.cpp [new file with mode: 0644]
src/misc/vlambda.h [new file with mode: 0644]
src/misc/vlambda_p.h [new file with mode: 0644]
src/templates/odfedit.cpp

index 8cc486c..a641d8a 100644 (file)
@@ -5,6 +5,7 @@ HEADERS += \
        $$PWD/sclock.h \
        $$PWD/formula.h \
        $$PWD/lambda.h \
+       $$PWD/vlambda.h \
        $$PWD/msengine.h \
        $$PWD/dommodel.h
 
@@ -15,6 +16,7 @@ SOURCES += \
        $$PWD/waitcursor.cpp \
        $$PWD/sclock.cpp \
        $$PWD/formula.cpp \
+       $$PWD/vlambda.cpp \
        $$PWD/msengine.cpp \
        $$PWD/dommodel.cpp
 
diff --git a/src/misc/vlambda.cpp b/src/misc/vlambda.cpp
new file mode 100644 (file)
index 0000000..04d8c4d
--- /dev/null
@@ -0,0 +1,90 @@
+//
+// C++ Interface: misc
+//
+// Description: miscellaneous helper functions
+//
+//
+// Author: Konrad Rosenbaum <konrad@silmor.de>, (C) 2012
+//
+// Copyright: See README/COPYING.GPL files that come with this distribution
+//
+//
+
+#include "vlambda.h"
+#include <QDebug>
+
+using namespace std;
+using namespace MVLambdaNS;
+
+//static
+void MVLambdaBase::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
+{
+    if (_c == QMetaObject::InvokeMetaMethod) {
+        //Q_ASSERT(staticMetaObject.cast(_o));//there is no static meta-object
+        MVLambdaBase *_t = static_cast<MVLambdaBase *>(_o);
+        if(_id== 0 && _t != nullptr) _t->do_call(_a);
+    }
+}
+
+
+//static 
+const QMetaObjectExtraData MVLambdaBase::staticMetaObjectExtraData = {
+    0,  MVLambdaBase::qt_static_metacall
+};
+
+
+MVLambdaBase::MVLambdaBase(int cnt,QByteArray rt, QByteArray cn, QObject* parent)
+:QObject(parent),m_count(cnt),m_callparm(cn),m_callret(rt),
+qt_meta_data({ // content:
+       6,       // revision
+       0,       // classname
+       0,    0, // classinfo
+       1,   14, // methods (14 is start of method info)
+       0,    0, // properties
+       0,    0, // enums/sets
+       0,    0, // constructors
+       0,       // flags
+       0,       // signalCount
+
+       // slots: signature, parameters, type, tag, flags
+       10,    8,    8,    8, 0x0a,
+        0 // eod
+})
+{
+       qDebug()<<"instantiated "<<QString("%2 call(%1)").arg(cn.data()).arg(rt.data());
+       //init string data and meta data array
+       string_metadata=QByteArray("MVLambda\0\0call(",15)+cn+QByteArray(")\0",2);
+       qt_meta_data[15]=string_metadata.size();
+       for(int i=1;i<m_count;i++)string_metadata+=",";//params have no name
+       string_metadata.append(char(0));
+       qt_meta_data[16]=string_metadata.size();
+       string_metadata+=rt;
+       string_metadata.append(char(0));
+       // !!!!!!!
+       // after this line string_metadata must not be changed
+       // !!!!!!!
+       //register meta object
+       meta_object=QMetaObject({{&QObject::staticMetaObject, string_metadata.data(),
+               qt_meta_data, &MVLambdaBase::staticMetaObjectExtraData}});
+}
+
+void* MVLambdaNS::MVLambdaBase::qt_metacast(const char* _clname)
+{
+    if (!_clname) return 0;
+    if (!strcmp(_clname, "MVLambda"))
+        return static_cast<void*>(this);
+    return QObject::qt_metacast(_clname);
+}
+
+int MVLambdaBase::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
+{
+    _id = QObject::qt_metacall(_c, _id, _a);
+    if (_id < 0)
+        return _id;
+    if (_c == QMetaObject::InvokeMetaMethod) {
+        if (_id < 1)
+            do_call(_a);
+        _id -= 1;
+    }
+    return _id;
+}
diff --git a/src/misc/vlambda.h b/src/misc/vlambda.h
new file mode 100644 (file)
index 0000000..3c422e8
--- /dev/null
@@ -0,0 +1,92 @@
+//
+// C++ Interface: variadic lambda class
+//
+// Description: a lambda to slot wrapper that can use arbitrary slot signatures
+//
+//
+// Author: Konrad Rosenbaum <konrad@silmor.de>, (C) 2012
+//
+// Copyright: See README/COPYING.GPL files that come with this distribution
+//
+//
+
+#ifndef MAGICSMOKE_VLAMBDA_H
+#define MAGICSMOKE_VLAMBDA_H
+
+#include <functional>
+#include <QObject>
+#include "vlambda_p.h"
+
+/// Namespace for functions and sub-templates that are internal to the variadic lambda wrapper MVLambda.
+namespace MVLambdaNS {
+/// \internal workarout for missing "final" keyword in GCC 4.6
+//TODO: remove this as soon as "final" is available
+class MVLFinal{protected:MVLFinal(){}};
+
+/// \internal base class for variadic lambda wrapper
+class MVLambdaBase:public QObject
+{
+       const int m_count;
+       const QByteArray m_callparm,m_callret;
+       uint qt_meta_data[20];
+       QByteArray string_metadata;
+       QMetaObject meta_object;
+       virtual void do_call(void**)=0;
+       static void qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a);
+       static const QMetaObjectExtraData staticMetaObjectExtraData;
+       protected:
+//             MVLambdaBase(const MVLambdaBase&m):QObject(parent()),m_callname(m.m_callname){}
+               MVLambdaBase ( int c,QByteArray rt, QByteArray cn, QObject* parent);
+               
+               const QByteArray callParams()const{return m_callparm;}
+               const QByteArray callReturn()const{return m_callret;}
+               
+               /*static void qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
+               {
+                   if (_c == QMetaObject::InvokeMetaMethod) {
+                       Q_ASSERT(staticMetaObject.cast(_o));
+                       MVLambda<Ret(Args...)> *_t = static_cast<MVLambda<Ret(Args...)> *>(_o);
+                       if (_id==0)MVLambdaNS::Call<Args...>(_a,_t->call();
+                   }
+                   Q_UNUSED(_a);
+               }*/
+       public:
+               const QMetaObject *metaObject() const{return &meta_object;}
+               void *qt_metacast(const char *_clname);
+               int qt_metacall(QMetaObject::Call _c, int _id, void **_a);
+
+};
+
+//end of namespace
+};
+
+template<typename _Signature>class MVLambda;
+
+///wrapper for simple lambda expression, so it can be used with signals
+template<typename Ret,typename...Args>
+class MVLambda<Ret(Args...)> :public MVLambdaNS::MVLambdaBase,virtual private MVLambdaNS::MVLFinal
+{
+       private:
+               std::function<Ret(Args...)>m_ptr;
+               /// \internal interface for the Qt meta object system
+               virtual void do_call(void**a){
+                       MVLambdaNS::Call<Ret(Args...)>(a,[&](Args...args)->Ret{return this->call(args...);});
+               }
+       public:
+               ///instantiates the lambda object, e.g.
+               /// \code
+               ///int x=55;
+               ///QPushButton button("Push me!");
+               ///MLambda lambda([&x](){qDebug()<<"x is"<<x;});
+               ///connect(&button,SIGNAL(clicked()),&lambda,SLOT(call()));
+               ///button.show();
+               /// \endcode
+               ///the above code will show the value of the variable 'x' whenever the user clicks the button
+               MVLambda(std::function<Ret(Args...)>l,QObject* parent = 0)
+               :MVLambdaBase(MVLambdaNS::Count<Args...>::count, MVLambdaNS::TypeStr<Ret>::get(), MVLambdaNS::TypeStr<Args...>::get(), parent), m_ptr(l){}
+               
+               ///generic slot that transparently executes the lambda expression
+               Ret call(Args...args){if(m_ptr)return m_ptr(args...);else return Ret();}
+};
+
+#endif
diff --git a/src/misc/vlambda_p.h b/src/misc/vlambda_p.h
new file mode 100644 (file)
index 0000000..941e09d
--- /dev/null
@@ -0,0 +1,148 @@
+//
+// C++ Interface: variadic lambda
+//
+// Description: helpers for variadic lambda
+//
+//
+// Author: Konrad Rosenbaum <konrad@silmor.de>, (C) 2012
+//
+// Copyright: See README/COPYING.GPL files that come with this distribution
+//
+//
+
+#ifndef MAGICSMOKE_VLAMBDA_P_H
+#define MAGICSMOKE_VLAMBDA_P_H
+
+#include <functional>
+#include <QObject>
+#include <QVariant>
+#include <QByteArray>
+
+namespace MVLambdaNS {
+/// \internal helper for lambda template: determines the string representation of the functions type signature
+template<typename...A>class TypeStr;
+
+template <typename F,typename...Args> 
+class TypeStr<F,Args...>{
+public:
+static const QByteArray get()
+{return TypeStr<F>::get()+","+TypeStr<Args...>::get();}
+};
+
+template <typename T> 
+class TypeStr<T>{
+public: static const QByteArray get()
+{T t;return QVariant::fromValue(t).typeName();}
+};
+
+template <typename T> 
+class TypeStr<T&>{
+public: static const QByteArray get()
+{T t;return QByteArray(QVariant::fromValue(t).typeName())+"&";}
+};
+template <typename T> 
+class TypeStr<const T&>{
+public: static const QByteArray get()
+{T t;return QByteArray("const ")+QVariant::fromValue(t).typeName()+"&";}
+};
+template <typename T> 
+class TypeStr<T*>{
+public: static const QByteArray get()
+{T t;return QByteArray(QVariant::fromValue(t).typeName())+"*";}
+};
+template <typename T> 
+class TypeStr<const T*>{
+public: static const QByteArray get()
+{T t;return QByteArray("const ")+QVariant::fromValue(t).typeName()+"*";}
+};
+
+template<>
+class TypeStr<>{
+public: static const QByteArray get()
+{return QByteArray();}
+};
+
+template<>
+class TypeStr<void>{
+public: static const QByteArray get()
+{return QByteArray();}
+};
+
+
+
+//////////////////////////////////////////////////////
+template<typename ...Args>class Count;
+
+template<typename T,typename ...Args>
+class Count<T,Args...>{public: static const int count=Count<Args...>::count + 1;};
+
+template<>
+class Count<>{public: static const int count=0;};
+///////////////////////////////////////////////////////
+template<typename Sig>class Call;
+
+template<typename R,typename T,typename...Args>
+class Call<R(T,Args...)>
+{
+       public:
+               Call(void**vl,std::function<R(T,Args...)>cb)
+               {
+                       R r;
+                       Call<void(Args...)>(vl+1,[&](Args...args){r=cb(*reinterpret_cast<T*>(vl[0]),args...);});
+                       if(vl[0])*reinterpret_cast<R*>(vl[0])=r;
+               }
+};
+template<typename R,typename T>
+class Call<R(T)>
+{
+       public:
+               Call(void**vl,std::function<R(T)>cb)
+               {
+                       R r=cb(*reinterpret_cast<T*>(vl[1]));
+                       if(vl[0])*reinterpret_cast<R*>(vl[0])=r;
+               }
+};
+template<typename R>
+class Call<R()>
+{
+       public:
+               Call(void**vl,std::function<R()>cb)
+               {
+                       R r=cb();
+                       if(vl[0])*reinterpret_cast<R*>(vl[0])=r;
+               }
+};
+
+
+template<typename T,typename...Args>
+class Call<void(T,Args...)>
+{
+       public:
+               Call(void**vl,std::function<void(T,Args...)>cb)
+               {
+                       Call<void(Args...)>(vl+1,[&](Args...args){cb(*reinterpret_cast<T*>(vl[1]),args...);});
+               }
+};
+template<typename T>
+class Call<void(T)>
+{
+       public:
+               Call(void**vl,std::function<void(T)>cb)
+               {
+                       cb(*reinterpret_cast<T*>(vl[1]));
+               }
+};
+template<>
+class Call<void()>
+{
+       public:
+               Call(void**,std::function<void()>cb)
+               {
+                       cb();
+               }
+};
+
+//end of namespace
+};
+
+#endif
index 424b6f0..0fceebb 100644 (file)
@@ -15,6 +15,8 @@
 #include "misc.h"
 #include "odtrender.h"
 #include "dommodel.h"
+#include "lambda.h"
+#include "vlambda.h"
 
 #include "MOTicket"
 #include "MOVoucher"
@@ -77,8 +79,8 @@ class DPTR_CLASS_NAME(MOdfEditor)
                QTableView*mTagAttrs;
                QStandardItemModel*mTagAttrModel;
                //tree menu
-               QAction*maAddCalc,*maAddCond,*maAddComment,*maAddElse,*maAddLoop;
-               QAction*maInsCalc,*maInsComment,*maUnwrap,*maDelItem;
+               QAction*maAddIntoCalc,*maWrapInCond,*maAddIntoComment,*maInsBehindElse,*maWrapInLoop;
+               QAction*maInsBehindCalc,*maInsBehindComment,*maUnwrap,*maDelItem;
                void setActions(const QList<QAction*>&);
                //current node
                QModelIndex mCurIndex;
@@ -128,14 +130,14 @@ MOdfEditor::MOdfEditor(QWidget* parent, Qt::WindowFlags f): QMainWindow(parent,
        m->addSeparator();
        m->addAction(tr("&Close"),this,SLOT(close()));
        
-       m=mb->addMenu(tr("&Edit"));
-       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"));
+       QMenu*medit=m=mb->addMenu(tr("&Edit"));
+       d->maAddIntoCalc=m->addAction(tr("Insert &Calculation into current"));
+       d->maInsBehindCalc=m->addAction(tr("Insert Calculation behind current"));
+       d->maWrapInCond=m->addAction(tr("&Wrap in Condition"));
+       d->maWrapInLoop=m->addAction(tr("Wrap in &Loop"));
+       d->maInsBehindElse=m->addAction(tr("Insert &Else behind current"));
+       d->maAddIntoComment=m->addAction(tr("Insert Comment into current"));
+       d->maInsBehindComment=m->addAction(tr("Insert Comment behind current"));
        m->addSeparator();
        d->maUnwrap=m->addAction(tr("Unwrap Loop/Condition"));
        d->maDelItem=m->addAction(tr("&Remove Item"),this,SLOT(delItem()));
@@ -169,6 +171,14 @@ MOdfEditor::MOdfEditor(QWidget* parent, Qt::WindowFlags f): QMainWindow(parent,
        d->mDomTree->header()->setResizeMode(0,QHeaderView::ResizeToContents);
        d->mDomTree->header()->setStretchLastSection(false);
        connect(d->mDomTree->selectionModel(),SIGNAL(selectionChanged(QItemSelection,QItemSelection)), this,SLOT(selectionChange()));
+       MVLambda<void(QPoint)> *ml;
+       ml=new MVLambda<void(QPoint)>([=](QPoint p){
+               QModelIndex idx=d->mDomTree->indexAt(p);
+               if(idx.isValid())
+                       medit->popup(d->mDomTree->mapToGlobal(p));
+       },this);
+       connect(d->mDomTree,SIGNAL(customContextMenuRequested(QPoint)),ml,SLOT(call(QPoint)));
+       d->mDomTree->setContextMenuPolicy(Qt::CustomContextMenu);
        
        //the editors...
        QStackedWidget*stack;
@@ -388,7 +398,7 @@ void MOdfEditor::selectionChange()
        if(idxl.size()!=1){
                emit switchStack(d->st_none);
                if(idxl.size()>1)
-                       d->setActions(QList<QAction*>()<<d->maAddCond<<d->maAddLoop);
+                       d->setActions(QList<QAction*>()<<d->maWrapInCond<<d->maWrapInLoop);
                return;
        }
        //check element type
@@ -400,20 +410,20 @@ void MOdfEditor::selectionChange()
        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));
+               d->setActions(QList<QAction*>()<<d->maInsBehindCalc<<d->maInsBehindComment<<d->maDelItem<<(allowElse?d->maInsBehindElse: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));
+               d->setActions(QList<QAction*>()<<d->maInsBehindCalc<<d->maInsBehindComment<<d->maWrapInCond<<d->maWrapInLoop<<d->maDelItem<<(allowElse?d->maInsBehindElse: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));
+               d->setActions(QList<QAction*>()<<d->maInsBehindCalc<<d->maInsBehindComment<<d->maDelItem<<(allowElse?d->maInsBehindElse:nullptr));
                return;
        }
        //is it special?
@@ -423,28 +433,28 @@ void MOdfEditor::selectionChange()
                if(nn[1]=="loop"){
                        emit switchStack(d->st_loop);
                        d->mLoopVar->setText(el.attribute("variable"));
+                       d->setActions(QList<QAction*>()<<d->maInsBehindCalc<<d->maInsBehindComment<<d->maAddIntoCalc<<d->maAddIntoComment<<d->maWrapInCond<<d->maWrapInLoop<<d->maUnwrap<<d->maDelItem<<(allowElse?d->maInsBehindElse:nullptr));
                        #warning implement correct actions for special tags
                        return;
                }
                if(nn[1]=="calculate"){
                        emit switchStack(d->st_calc);
                        d->mCalcExpr->setText(el.attribute("exec"));
+                       d->setActions(QList<QAction*>()<<d->maInsBehindCalc<<d->maInsBehindComment<<d->maAddIntoCalc<<d->maAddIntoComment<<d->maWrapInCond<<d->maWrapInLoop<<d->maDelItem<<(allowElse?d->maInsBehindElse:nullptr));
                        return;
                }
                if(nn[1]=="if"){
                        emit switchStack(d->st_cond);
                        d->mCondExpr->setText(el.attribute("select"));
+                       d->setActions(QList<QAction*>()<<d->maInsBehindCalc<<d->maInsBehindComment<<d->maAddIntoCalc<<d->maAddIntoComment<<d->maWrapInCond<<d->maWrapInLoop<<d->maUnwrap<<d->maDelItem<<(allowElse?d->maInsBehindElse:nullptr));
                        return;
                }
-               //else
-               emit switchStack(d->st_none);
-               return;
-       }else{
-               emit switchStack(d->st_tag);
-               #warning implement correct actions for normal tags
-               displayTag();
-               return;
+               //else: fall through to normal tags
        }
+       //else: other tags
+       d->setActions(QList<QAction*>()<<d->maInsBehindCalc<<d->maInsBehindComment<<d->maAddIntoCalc<<d->maAddIntoComment<<d->maWrapInCond<<d->maWrapInLoop<<d->maDelItem<<(allowElse?d->maInsBehindElse:nullptr));
+       emit switchStack(d->st_tag);
+       displayTag();
 }
 
 void MOdfEditor::displayTag()
@@ -478,13 +488,13 @@ void MOdfEditor::saveCurrentNode()
 
 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));
+       maAddIntoCalc->setEnabled(act.contains( maAddIntoCalc));
+       maWrapInCond->setEnabled(act.contains( maWrapInCond));
+       maAddIntoComment->setEnabled(act.contains( maAddIntoComment));
+       maInsBehindElse->setEnabled(act.contains( maInsBehindElse));
+       maWrapInLoop->setEnabled(act.contains( maWrapInLoop));
+       maInsBehindCalc->setEnabled(act.contains( maInsBehindCalc));
+       maInsBehindComment->setEnabled(act.contains( maInsBehindComment));
        maUnwrap->setEnabled(act.contains(maUnwrap));
        maDelItem->setEnabled(act.contains(maDelItem));
 }