You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
koffice/kexi/plugins/macros/lib/metamethod.cpp

345 lines
8.8 KiB

/***************************************************************************
* This file is part of the KDE project
* copyright (C) 2005 by Sebastian Sauer (mail@dipe.org)
* copyright (C) 2005 by Tobi Krebs (tobi.krebs@gmail.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
* You should have received a copy of the GNU Library General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
***************************************************************************/
#include "metamethod.h"
#include "metaobject.h"
#include "metaparameter.h"
#include "variable.h"
#include "exception.h"
#include <tqobject.h>
#include <tqmetaobject.h>
// to access the TQt3 TQUObject API.
#include <private/tqucom_p.h>
#include <private/tqucomextra_p.h>
#include <kdebug.h>
using namespace KoMacro;
namespace KoMacro {
/**
* @internal d-pointer class to be more flexible on future extension of the
* functionality without to much risk to break the binary compatibility.
*/
class MetaMethod::Private
{
public:
/**
* The signature this @a MetaMethod has.
*/
TQString signature;
/**
* The signature tagname this @a MetaMethod has.
*/
TQString signaturetag;
/**
* The signature arguments this @a MetaMethod has.
*/
TQString signaturearguments;
/**
* Cached signature arguments parsed into a list
* of @a MetaParameter instances.
*/
MetaParameter::List arguments;
/**
* The @a MetaObject this @a MetaMethod belongs to or is NULL
* if this @a MetaMethod doesn't belong to any @a MetaObject
* yet.
*/
KSharedPtr<MetaObject> object;
/**
* The @a MetaMethod::Type this method provides access
* to.
*/
MetaMethod::Type type;
};
}
MetaMethod::MetaMethod(const TQString& signature, Type type, KSharedPtr<MetaObject> object)
: KShared()
, d( new Private() ) // create the private d-pointer instance.
{
d->signature = signature;
d->object = object;
d->type = type;
int startpos = d->signature.find("(");
int endpos = d->signature.findRev(")");
if(startpos < 0 || startpos > endpos) {
throw Exception(TQString("Invalid signature \"%1\"").arg(d->signature));
}
d->signaturetag = d->signature.left(startpos).stripWhiteSpace();
if(d->signaturetag.isEmpty()) {
throw Exception(TQString("Invalid tagname in signature \"%1\"").arg(d->signature));
}
d->signaturearguments = d->signature.mid(startpos + 1, endpos - startpos - 1).stripWhiteSpace();
do {
int commapos = d->signaturearguments.find(",");
int starttemplatepos = d->signaturearguments.find("<");
if(starttemplatepos >= 0 && (commapos < 0 || starttemplatepos < commapos)) {
int endtemplatepos = d->signaturearguments.find(">", starttemplatepos);
if(endtemplatepos <= 0) {
throw Exception(TQString("No closing template-definiton in signature \"%1\"").arg(d->signature));
}
commapos = d->signaturearguments.find(",", endtemplatepos);
}
if(commapos > 0) {
TQString s = d->signaturearguments.left(commapos).stripWhiteSpace();
if(! s.isEmpty()) {
d->arguments.append( new MetaParameter(s) );
}
d->signaturearguments = d->signaturearguments.right(d->signaturearguments.length() - commapos - 1);
}
else {
TQString s = d->signaturearguments.stripWhiteSpace();
if(! s.isEmpty()) {
d->arguments.append( new MetaParameter(s) );
}
break;
}
} while(true);
}
MetaMethod::~MetaMethod()
{
delete d;
}
KSharedPtr<MetaObject> const MetaMethod::object() const
{
return d->object;
}
const TQString MetaMethod::signature() const
{
return d->signature;
}
const TQString MetaMethod::signatureTag() const
{
return d->signaturetag;
}
const TQString MetaMethod::signatureArguments() const
{
return d->signaturearguments;
}
MetaMethod::Type MetaMethod::type() const
{
return d->type;
}
MetaParameter::List MetaMethod::arguments() const
{
return d->arguments;
}
TQUObject* MetaMethod::toTQUObject(Variable::List arguments)
{
uint argsize = d->arguments.size();
if(arguments.size() <= argsize) {
throw Exception(TQString("To less arguments for slot with siganture \"%1\"").arg(d->signature));
}
// The first item in the TQUObject-array is for the returnvalue
// while everything >=1 are the passed parameters.
TQUObject* uo = new TQUObject[ argsize + 1 ];
uo[0] = TQUObject(); // empty placeholder for the returnvalue.
for(uint i = 0; i < argsize; i++) {
KSharedPtr<MetaParameter> metaargument = d->arguments[i];
KSharedPtr<Variable> variable = arguments[i + 1];
if ( !variable ) {
throw Exception(TQString("Variable is undefined !"));
}
if(metaargument->type() != variable->type()) {
throw Exception(TQString("Wrong variable type in method \"%1\". Expected \"%2\" but got \"%3\"").arg(d->signature).arg(metaargument->type()).arg(variable->type()));
}
switch(metaargument->type()) {
case Variable::TypeNone: {
kdDebug() << "Variable::TypeNone" << endl;
uo[i + 1] = TQUObject();
} break;
case Variable::TypeVariant: {
kdDebug() << "Variable::TypeVariant" << endl;
const TQVariant variant = variable->variant();
switch(metaargument->variantType()) {
case TQVariant::String: {
const TQString s = variant.toString();
static_TQUType_TQString.set( &(uo[i + 1]), s );
} break;
case TQVariant::Int: {
const int j = variant.toInt();
static_TQUType_int.set( &(uo[i + 1]), j );
} break;
case TQVariant::Bool: {
const bool b = variant.toBool();
static_TQUType_bool.set( &(uo[i + 1]), b );
} break;
case TQVariant::Double: {
const double d = variant.toDouble();
static_TQUType_double.set( &(uo[i + 1]), d );
} break;
case TQVariant::Invalid: {
static_TQUType_TQVariant.set( &(uo[i + 1]), variant );
}
/*FIXME
static_TQUType_charstar
static_TQUType_ptr.get(uo); TQObject *qobj = (TQObject *)(ptr);
*/
default: {
throw Exception(TQString("Invalid parameter !!!!!!!!!!!!!!!!!!!!!!!"));
} break;
}
} break;
case Variable::TypeObject: {
kdDebug() << "Variable::TypeObject" << endl;
const TQObject* obj = arguments[i + 1]->object();
if(! obj) { //FIXME: move check to MetaParameter?!
throw Exception(TQString("No TQObject !"));
}
static_TQUType_ptr.set( &(uo[i + 1]), obj );
} break;
default: {
throw Exception(TQString("Invalid variable type"));
} break;
}
}
return uo;
}
KSharedPtr<Variable> MetaMethod::toVariable(TQUObject* uo)
{
const TQString desc( uo->type->desc() );
if(desc == "null") {
return new Variable();
}
if(desc == TQSTRING_OBJECT_NAME_STRING) {
const TQString s = static_TQUType_TQString.get(uo);
return new Variable(s);
}
if(desc == "int") {
const int j = static_TQUType_int.get(uo);
return new Variable(j);
}
if(desc == "bool") {
const bool b = static_TQUType_bool.get(uo);
return new Variable(b);
}
if(desc == "double") {
const double d = static_TQUType_double.get(uo);
return new Variable(d);
}
if(desc == "TQVariant") {
TQVariant v = static_TQUType_TQVariant.get(uo);
return new Variable(v);
}
throw Exception(TQString("Invalid parameter '%1'").arg(desc));
}
Variable::List MetaMethod::toVariableList(TQUObject* uo)
{
Variable::List list;
MetaParameter::List::ConstIterator it, end( d->arguments.constEnd() );
for( it = d->arguments.constBegin(); it != end; ++it) {
list.append( toVariable(uo) );
uo++;
}
return list;
}
KSharedPtr<Variable> MetaMethod::invoke(Variable::List arguments)
{
kdDebug() << "KSharedPtr<Variable> MetaMethod::invoke(Variable::List arguments)" << endl;
if(! d->object) {
throw Exception("MetaObject is undefined.");
}
TQObject* obj = d->object->object();
KSharedPtr<Variable> returnvalue;
TQUObject* qu = 0;
try {
qu = toTQUObject(arguments);
switch( d->type ) {
case Signal: {
int index = d->object->indexOfSignal( d->signature.latin1() );
obj->tqt_emit(index, qu);
} break;
case Slot: {
int index = d->object->indexOfSlot( d->signature.latin1() );
obj->tqt_invoke(index, qu);
} break;
default: {
throw Exception("Unknown type.");
} break;
}
returnvalue = toVariable( &qu[0] );
}
catch(Exception& e) {
delete [] qu; // free the TQUObject array and
kdDebug() << "EXCEPTION in KoMacro::MetaMethod::invoke(Variable::List)" << endl;
throw Exception(e); // re-throw exception
}
delete [] qu;
return returnvalue;
}