From a1efd0fcbbfcb68d6fa18b9039c16176a214fc8b Mon Sep 17 00:00:00 2001 From: Konrad Rosenbaum Date: Wed, 22 Feb 2012 19:06:32 +0100 Subject: [PATCH] add variadic lambda wrapper (incomplete: does not handle references yet); show context menu in ODF editor --- src/misc/misc.pri | 2 + src/misc/vlambda.cpp | 90 +++++++++++++++++++++++++++ src/misc/vlambda.h | 92 ++++++++++++++++++++++++++++ src/misc/vlambda_p.h | 148 +++++++++++++++++++++++++++++++++++++++++++++ src/templates/odfedit.cpp | 68 ++++++++++++--------- 5 files changed, 371 insertions(+), 29 deletions(-) create mode 100644 src/misc/vlambda.cpp create mode 100644 src/misc/vlambda.h create mode 100644 src/misc/vlambda_p.h diff --git a/src/misc/misc.pri b/src/misc/misc.pri index 8cc486c..a641d8a 100644 --- a/src/misc/misc.pri +++ b/src/misc/misc.pri @@ -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 index 0000000..04d8c4d --- /dev/null +++ b/src/misc/vlambda.cpp @@ -0,0 +1,90 @@ +// +// C++ Interface: misc +// +// Description: miscellaneous helper functions +// +// +// Author: Konrad Rosenbaum , (C) 2012 +// +// Copyright: See README/COPYING.GPL files that come with this distribution +// +// + +#include "vlambda.h" +#include + +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(_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 "<(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 index 0000000..3c422e8 --- /dev/null +++ b/src/misc/vlambda.h @@ -0,0 +1,92 @@ +// +// C++ Interface: variadic lambda class +// +// Description: a lambda to slot wrapper that can use arbitrary slot signatures +// +// +// Author: Konrad Rosenbaum , (C) 2012 +// +// Copyright: See README/COPYING.GPL files that come with this distribution +// +// + +#ifndef MAGICSMOKE_VLAMBDA_H +#define MAGICSMOKE_VLAMBDA_H + +#include +#include +#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 *_t = static_cast *>(_o); + if (_id==0)MVLambdaNS::Call(_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 +}; + +templateclass MVLambda; + +///wrapper for simple lambda expression, so it can be used with signals +template +class MVLambda :public MVLambdaNS::MVLambdaBase,virtual private MVLambdaNS::MVLFinal +{ + private: + std::functionm_ptr; + /// \internal interface for the Qt meta object system + virtual void do_call(void**a){ + MVLambdaNS::Call(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"<l,QObject* parent = 0) + :MVLambdaBase(MVLambdaNS::Count::count, MVLambdaNS::TypeStr::get(), MVLambdaNS::TypeStr::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 index 0000000..941e09d --- /dev/null +++ b/src/misc/vlambda_p.h @@ -0,0 +1,148 @@ +// +// C++ Interface: variadic lambda +// +// Description: helpers for variadic lambda +// +// +// Author: Konrad Rosenbaum , (C) 2012 +// +// Copyright: See README/COPYING.GPL files that come with this distribution +// +// + +#ifndef MAGICSMOKE_VLAMBDA_P_H +#define MAGICSMOKE_VLAMBDA_P_H + +#include +#include +#include +#include + +namespace MVLambdaNS { +/// \internal helper for lambda template: determines the string representation of the functions type signature +templateclass TypeStr; + +template +class TypeStr{ +public: +static const QByteArray get() +{return TypeStr::get()+","+TypeStr::get();} +}; + +template +class TypeStr{ +public: static const QByteArray get() +{T t;return QVariant::fromValue(t).typeName();} +}; + +template +class TypeStr{ +public: static const QByteArray get() +{T t;return QByteArray(QVariant::fromValue(t).typeName())+"&";} +}; +template +class TypeStr{ +public: static const QByteArray get() +{T t;return QByteArray("const ")+QVariant::fromValue(t).typeName()+"&";} +}; +template +class TypeStr{ +public: static const QByteArray get() +{T t;return QByteArray(QVariant::fromValue(t).typeName())+"*";} +}; +template +class TypeStr{ +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{ +public: static const QByteArray get() +{return QByteArray();} +}; + + + +////////////////////////////////////////////////////// +templateclass Count; + +template +class Count{public: static const int count=Count::count + 1;}; + +template<> +class Count<>{public: static const int count=0;}; +/////////////////////////////////////////////////////// +templateclass Call; + +template +class Call +{ + public: + Call(void**vl,std::functioncb) + { + R r; + Call(vl+1,[&](Args...args){r=cb(*reinterpret_cast(vl[0]),args...);}); + if(vl[0])*reinterpret_cast(vl[0])=r; + } +}; +template +class Call +{ + public: + Call(void**vl,std::functioncb) + { + R r=cb(*reinterpret_cast(vl[1])); + if(vl[0])*reinterpret_cast(vl[0])=r; + } +}; +template +class Call +{ + public: + Call(void**vl,std::functioncb) + { + R r=cb(); + if(vl[0])*reinterpret_cast(vl[0])=r; + } +}; + + +template +class Call +{ + public: + Call(void**vl,std::functioncb) + { + Call(vl+1,[&](Args...args){cb(*reinterpret_cast(vl[1]),args...);}); + } +}; +template +class Call +{ + public: + Call(void**vl,std::functioncb) + { + cb(*reinterpret_cast(vl[1])); + } +}; +template<> +class Call +{ + public: + Call(void**,std::functioncb) + { + cb(); + } +}; + +//end of namespace +}; + +#endif diff --git a/src/templates/odfedit.cpp b/src/templates/odfedit.cpp index 424b6f0..0fceebb 100644 --- a/src/templates/odfedit.cpp +++ b/src/templates/odfedit.cpp @@ -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&); //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 *ml; + ml=new MVLambda([=](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()<maAddCond<maAddLoop); + d->setActions(QList()<maWrapInCond<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()<maAddCalc<maInsComment<maDelItem<<(allowElse?d->maAddElse:nullptr)); + d->setActions(QList()<maInsBehindCalc<maInsBehindComment<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()<maAddCalc<maAddComment<maAddCond<maAddLoop<maDelItem<<(allowElse?d->maAddElse:nullptr)); + d->setActions(QList()<maInsBehindCalc<maInsBehindComment<maWrapInCond<maWrapInLoop<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()<maAddCalc<maAddComment<maDelItem<<(allowElse?d->maAddElse:nullptr)); + d->setActions(QList()<maInsBehindCalc<maInsBehindComment<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()<maInsBehindCalc<maInsBehindComment<maAddIntoCalc<maAddIntoComment<maWrapInCond<maWrapInLoop<maUnwrap<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()<maInsBehindCalc<maInsBehindComment<maAddIntoCalc<maAddIntoComment<maWrapInCond<maWrapInLoop<maDelItem<<(allowElse?d->maInsBehindElse:nullptr)); return; } if(nn[1]=="if"){ emit switchStack(d->st_cond); d->mCondExpr->setText(el.attribute("select")); + d->setActions(QList()<maInsBehindCalc<maInsBehindComment<maAddIntoCalc<maAddIntoComment<maWrapInCond<maWrapInLoop<maUnwrap<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()<maInsBehindCalc<maInsBehindComment<maAddIntoCalc<maAddIntoComment<maWrapInCond<maWrapInLoop<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)); } -- 1.7.2.5