tags:

views:

285

answers:

1

The solution may be simple. Then again it may not be possible.

I have the base callback class:

class CFCallback {
    int command_;
    int transfer_rate_;
    public:
    CFCallback(int command, int transfer_rate = 0) {
        command_ = command; transfer_rate_ = transfer_rate; }
    virtual ~CFCallback() {}
    virtual void operator()(void *data) = 0;
    int GetCommand() { return command_; }
    int GetTransferRate() { return transfer_rate_; }
};

And here's one example of deriving from CFCallback:

void CFPacketVersion::InitiateVersion() {
    class InitiateVersionCB : public CFCallback {
        CFPacketVersion *visitor_;
        public:
        InitiateVersionCB(CFPacketVersion *v, int command) :
            CFCallback(command) {
            visitor_ = v;
        }
        void operator()(void *data) {
            Packet *pkt = (Packet *)data;
            unsigned char *pkt_data = pkt->GetData();
            std::string version = "";
            for(unsigned int i = 0; i < pkt->GetDataLength(); i++ )
                version+= pkt_data[i];
            delete []pkt_data;
            boost::regex rex("CFA(.*?):h(.*?),v(.*?)$");
            boost::smatch what;
            if( boost::regex_match(version, what, rex) ) {
                if(visitor_->GetModel()->GetName() != what[1].str() )
                    LCDInfo("Crystalfontz: Model mismatch");
                visitor_->SetHardwareVersion(what[2]);
                visitor_->SetFirmwareVersion(what[3]);
            }
        }
    };
    GetVersion(new InitiateVersionCB(this, 1));
}

GetVersion(CFCallback *) is provided to the script engine.

I want to be able to do the same thing as seen in InitiateVersion, but on the javascript side of things. Is that possible?

I know I need to register meta type info for CFCallback. But I don't know if it's possible to use a pointer to a CFCallback. What I tried initially didn't work.

Also, seeing as CFCallback is a functor, I'm not sure how I translate that over to javascript. I imagine I can make CFCallback a QObject and provide a signal emitted from operator(). If you have any tips, please share.

+2  A: 

I'm afraid it won't work the way you've set it up.

If you want to be able to create the callback in javascript, you need a QObject with an accessible GetVersion(QScriptValue) which the script will the use to pass a script-based implementation of the callback. Note, though, that the callback will not be able to work with untyped (void*) data - you need to pass either a valid QtScript object or QObject with a proper interface (like the Packet one in your example!)

You could then wrap it up like this:

QtScript:

function mycb(packet) {
  var pkt_data = packet.getData(); // pkt_data is probably a String or custom object with proper interface so to simplify things get the version as string
  var version = pkt_data.toString();
  pkt_data.release(); // to simulate delete [] pkt_data; this is part of custom interface
  // proceed further with the regex checks

}

GetVersion(mycb); // implies that you define the GetVersion() as a property of the global object

C++:

QScriptValue getVersion(QScriptContext *ctx, QScriptEngine *engine)
{
 void *data = ...;
 Packet pkt_data = wrapPacketData(data);
 // Packet is interface registered with QtScript or inherits QObject
 // it has methods getData(), toString() and release()
 QScriptValueList args;
 QScriptValue pkt_data_param = engine->newQObject(&pkt_data);
 args << pkt_data_param;
 QScriptValue cb = ctx->argument(0); 
 Q_ASSERT(cb.isFunction()); // we expect a function object!
 cb.call(QScriptValue(), args);
}
QScriptValue getVersionFun = engine->newFunction(getVersion);
engine->globalObject().setProperty(QLatin1String("GetVersion"), getVersionFun);