Logo Search packages:      
Sourcecode: whitedune version File versions  Download package

NodeScript.cpp

/*
 * NodeScript.cpp
 *
 * Copyright (C) 1999 Stephen F. White
 * 
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program (see the file "COPYING" for details); if 
 * not, write to the Free Software Foundation, Inc., 675 Mass Ave, 
 * Cambridge, MA 02139, USA.
 */

#include <stdio.h>
#include "stdafx.h"

#include "NodeScript.h"
#include "Scene.h"
#include "Proto.h"
#include "FieldValue.h"
#include "MFString.h"
#include "SFBool.h"
#include "ExposedField.h"
#include "Field.h"
#include "EventIn.h"
#include "EventOut.h"
#include "DuneApp.h"
#include "RouteCommand.h"
#include "UnRouteCommand.h"

ProtoScript::ProtoScript(Scene *scene)
  : Proto(scene, "Script")
{
    url.set(
          addExposedField(MFSTRING, "url", new MFString(), 
                          FF_HIDDEN | FF_URL, NULL));
    directOutput.set(
          addField(SFBOOL, "directOutput", new SFBool(false), FF_HIDDEN, NULL));
    mustEvaluate.set(
          addField(SFBOOL, "mustEvaluate", new SFBool(false), FF_HIDDEN, NULL));
}

Node *
ProtoScript::create(Scene *scene)
{ 
    return new NodeScript(scene); 
}

int
NodeScript::getUrlField()
{
    return url_Index();
}


NodeScript::NodeScript(Scene *scene)
  : Node(scene, new ProtoScript(scene))
{
    _interface = new InterfaceArray;
    _routeList = NULL;
}

NodeScript::~NodeScript()
{
    delete _proto;
    delete _interface;
}

int NodeScript::write(int f, int indent)
{
    TheApp->checkSelectionLinenumberCounting(_scene, this);
    RET_ONERROR( indentf(f, indent) )
    if (getFlag(NODE_FLAG_DEFED)) {
        RET_ONERROR( mywritestr(f ,"USE ") )
        RET_ONERROR( mywritestr(f ,(const char *) _name) )
        RET_ONERROR( mywritestr(f ,"\n") )
        TheApp->incSelectionLinenumber();
    } else {
        if (needsDEF()) {
                if (!_name[0]) _scene->generateUniqueNodeName(this);
              RET_ONERROR( mywritestr(f,"DEF ") )
                RET_ONERROR( mywritestr(f, (const char *) _name) )
                RET_ONERROR( mywritestr(f," ") )
            }
        setFlag(NODE_FLAG_DEFED);
        RET_ONERROR( mywritestr(f, "Script ") )
        if (!TheApp->GetkrFormating()) {
            RET_ONERROR( mywritestr(f, "\n") )
            TheApp->incSelectionLinenumber();
            RET_ONERROR( indentf(f, indent + TheApp->GetIndent()) )
        }
        RET_ONERROR( mywritestr(f, "{\n") )
        TheApp->incSelectionLinenumber();
        RET_ONERROR( _proto->writeWithoutFields(f, indent + 
                                                   TheApp->GetIndent()) )
        RET_ONERROR( writeFields(f, indent + TheApp->GetIndent()) )
        if (!TheApp->GetkrFormating())
            RET_ONERROR( indentf(f, indent + TheApp->GetIndent()) )
        else
            RET_ONERROR( indentf(f, indent) )
        RET_ONERROR( mywritestr(f, "}\n") )
        TheApp->incSelectionLinenumber();
        if (indent==0) {
            RET_ONERROR( mywritestr(f ,"\n") )
            TheApp->incSelectionLinenumber();
        }
        RET_ONERROR( writeRoutes(f, indent) )
        setFlag(NODE_FLAG_TOUCHED);
    }
    return(0);
}

int NodeScript::writeField(int f, int indent, int fieldIndex)
{
    const char       *oldBase = _scene->getURL();
    const char       *newBase = _scene->getNewURL();
    bool        tempSave = _scene->isTempSave();

    Field         *field = _proto->getField(fieldIndex);
    FieldValue    *value = _fields[fieldIndex];
    if (field->getFlags() & FF_HIDDEN) {
        if (value && !value->equals(field->getDefault())) {
            RET_ONERROR( indentf(f, indent) )
            RET_ONERROR( mywritestr(f ,(const char *) field->getName()) )
            RET_ONERROR( mywritestr(f ," ") )
            if ((field->getFlags() & FF_URL) && (!TheApp->GetKeepURLs())) {
                value = rewriteField(value, oldBase, newBase);
                RET_ONERROR( value->write(f, indent) )
                if (!tempSave) {
                    setField(fieldIndex, value);
            } else {
                    delete value;
                }
          } else if (field->getFlags() & FF_HIDDEN) {
                RET_ONERROR( value->write(f, indent) )
            } else {
                RET_ONERROR( write(f, indent) )
            }
        }
    } else {
        RET_ONERROR( indentf(f, indent) )
        RET_ONERROR( mywritestr(f ,"field ") )
        RET_ONERROR( mywritestr(f ,typeEnumToString(field->getType())) ) 
        RET_ONERROR( mywritestr(f ," ") )
        RET_ONERROR( mywritestr(f ,(const char *) field->getName()) )
        RET_ONERROR( mywritestr(f ," ") )
        if (value) RET_ONERROR( value->write(f, indent) )
    }
    return(0);
}

int NodeScript::writeFields(int f, int indent)
{
    if (!_proto) return(0);
    int i;
    int urlIndex = -1;
    for (i = 0; i < _numFields; i++) 
        if (strcmp(_proto->getField(i)->getName(), "url")==0)
            urlIndex = i;
        else
            RET_ONERROR( writeField(f, indent, i) )
    // scriptnode without "url" field ?
    assert (urlIndex != -1);
    RET_ONERROR( writeField(f, indent, urlIndex) )
    MFString *url = (MFString *) getField(urlIndex);
    for (i=0; i < url->getSize() ; i++)
        if (url != NULL) {
            // count end of line characters in url
            char* string= (char*) ((const char*) url->getValue(i));
            while ((string=strchr(string, '\n')) !=NULL) {
                TheApp->incSelectionLinenumber();
                string++;
            }
        }

    return(0);
}

 
//  When a eventIn is deleted, the routes must be updated.
//  Routes are handled via "sockets", a list which contain (for eventIns)
//  the node of source of a route and a integer index to the event/field 
//  of the source route

void NodeScript::updateEventIn(int newIndex, int oldIndex)
{
     CommandList* deleteList = new CommandList();
     for (SocketList::Iterator *i = _inputs[oldIndex].first(); i != NULL; 
          i = i->next()) {
       Socket  outS = i->item();
         for (SocketList::Iterator *j = 
              outS._node->getOutput(outS._index).first(); j != NULL; 
              j = j->next()) {
             Socket inS = j->item();
             if ((inS._node == this) && (inS._index == oldIndex)) {
                 // delete old route
                 deleteList->append(new UnRouteCommand(outS._node, outS._index, 
                                                       this, oldIndex));
                 
                 // add new route to _routeList
                 if (!_routeList) _routeList = new CommandList();
                 _routeList->append(new RouteCommand(outS._node, outS._index, 
                                                     this, newIndex));
             }
         }
     }
     _scene->execute(deleteList);
}

//  When a eventOut is deleted, the routes must be updated.
//  Routes are handled via "sockets", a list which contain (for eventOut)
//  the node of target of a route and a integer index to the event/field 
//  of the target route

void NodeScript::updateEventOut(int newIndex, int oldIndex)
{
     CommandList* deleteList = new CommandList();
     for (SocketList::Iterator *i = _outputs[oldIndex].first(); i != NULL; 
          i = i->next()) {
       Socket  inS = i->item();
         for (SocketList::Iterator *j = inS._node->getInput(inS._index)
              .first(); j != NULL; j = j->next()) {
             Socket outS = j->item();
             if ((outS._node == this) && (outS._index == oldIndex)) {
                 // delete old route
                 deleteList->append(new UnRouteCommand(
                                    this, oldIndex,inS._node, inS._index));
                                                       
                 // add new route to _routeList
                 if (!_routeList) _routeList = new CommandList();
                 _routeList->append(new RouteCommand(
                                    this, newIndex,inS._node, inS._index));
             }
         }
     }
     _scene->execute(deleteList);
}

// since scripts can have dynamically-added fields, we need to update
// the node's fields after the script is defined.
// Same problem for the scriptinterfacebuilder (ScriptDialog) (add or delete)
//
// It is important, that only one item (field, eventIn or eventOut) can
// be added or deleted during this call of update.

void
NodeScript::update()
{
    int         i;

    int newNumFields = _proto->getNumFields();
    // add 
    if (_numFields < newNumFields) {
      FieldValue  **newFields = new FieldValue *[newNumFields];
      for (i = 0; i < _numFields; i++) {
          newFields[i] = _fields[i];
      }
      for (i = _numFields; i < newNumFields; i++) {
          newFields[i] = _proto->getField(i)->getDefault();
            if (newFields[i])
             newFields[i]->ref();
      }

        // avoid delete of _fields[something]
        for (i = 0 ; i < _numFields ; i++)
            _fields[i] = NULL;
      delete [] _fields;
      _fields = newFields;
      _numFields = newNumFields;
    } else {
        // delete ?
        for (i = 0; i < _numFields; i++)
            if ((_proto->getField(i)->getFlags() & FF_DELETED) != 0) {
                // delete !
                newNumFields = _numFields-1;
                FieldValue    **newFields = new FieldValue *[newNumFields];
                int newIndex=0;
                for (int j = 0; j < _numFields; j++)
                    if (j != i)
                      newFields[newIndex++] = _fields[j];
                _proto->_fields.remove(i);

                // avoid delete of _fields[something]
                for (i = 0 ; i < _numFields ; i++)
                    _fields[i] = NULL;
              delete [] _fields;
              _fields = newFields;
              _numFields = newNumFields;
                break;
            }
    }

    int newNumEventIns = _proto->getNumEventIns();
    // add 
    if (_numEventIns < newNumEventIns) {
      SocketList  *newInputs = new SocketList[newNumEventIns];
      for (i = 0; i < _numEventIns; i++) {
          newInputs[i] = _inputs[i];
      }

        // avoid delete of _inputs[something]
        for (i = 0 ; i < _numEventIns ; i++)
            _inputs[i] = SocketList();
      delete [] _inputs;
      _inputs = newInputs;
      _numEventIns = newNumEventIns;
    } else {
        // delete ?
        for (i = 0; i < _numEventIns; i++)
            if ((_proto->getEventIn(i)->getFlags() & FF_DELETED) != 0) {
                // delete !
                newNumEventIns = _numEventIns-1;
                SocketList    *newInputs = new SocketList[newNumEventIns];
                int newIndex=0;
                for (int j = 0; j < _numEventIns; j++) {
                    if (newIndex != j)
                      updateEventIn(newIndex, j);
                    if (j != i)
                      newInputs[newIndex++] = _inputs[j];
                }

                _proto->_eventIns.remove(i);

                // avoid delete of _inputs[something!=i]
                for (int k = 0 ; k < _numEventIns ; k++)
                    if (k != i)
                        _inputs[k] = SocketList();
              delete [] _inputs;
              _inputs = newInputs;
              _numEventIns = newNumEventIns;
                // execute addRouteCommands from updateEventIn()
                if (_routeList) _scene->execute(_routeList);
                _routeList = NULL;
                break;
            }
    }

    int newNumEventOuts = _proto->getNumEventOuts();
    // add 
    if (_numEventOuts < newNumEventOuts) {
      SocketList  *newOutputs = new SocketList[newNumEventOuts];
      for (i = 0; i < _numEventOuts; i++) {
          newOutputs[i] = _outputs[i];
      }

        // avoid delete of _outputs[something]
        for (i = 0 ; i < _numEventOuts ; i++)
            _outputs[i] = SocketList();
      delete [] _outputs;
      _outputs = newOutputs;
      _numEventOuts = newNumEventOuts;
    } else {
        // delete ?
        for (i = 0; i < _numEventOuts; i++)
            if ((_proto->getEventOut(i)->getFlags() & FF_DELETED) != 0) {
                // delete !
                newNumEventOuts = _numEventOuts-1;
                SocketList    *newOutputs = new SocketList[newNumEventOuts];
                int newIndex=0;
                for (int j = 0; j < _numEventOuts; j++) {
                    if (newIndex != j)
                      updateEventOut(newIndex, j);
                    if (j != i) 
                      newOutputs[newIndex++] = _outputs[j];
                }
                _proto->_eventOuts.remove(i);

                // avoid delete of _outputs[something!=i]
                for (int k = 0 ; k < _numEventIns ; k++)
                    if (k != i)
                        _outputs[k] = SocketList();
              delete [] _outputs;
              _outputs = newOutputs;
              _numEventOuts = newNumEventOuts;
                // execute addRouteCommands from updateEventIn()
                if (_routeList) _scene->execute(_routeList);
                _routeList = NULL;
                break;
            }
    }
}

// collect array of dynamic field's, eventIn's and eventOut's of ScriptNode
void
NodeScript::buildInterfaceData(void) 
{
    int i;
    _interface->resize(0);
    Proto* proto = getProto();
    if (proto == NULL)
        return;
    for (i=0; i < proto->getNumFields(); i++)
        if (!(proto->getField(i)->getFlags() && (FF_HIDDEN || FF_URL))) 
            _interface->append(new InterfaceData(EL_FIELD_DEF, i));
    for (i=0; i < proto->getNumEventOuts(); i++) {
        // ignore Exposedfields (eg. "url")
        bool isExposedField = false;
        for (int j=0; j < proto->_exposedFields.size(); j++) {
            MyString exposedName = strdup(proto->getExposedField(j)->getName());
            exposedName += "_changed";
            if (strcmp(proto->getEventOut(i)->getName(), exposedName) == 0)
               isExposedField = true;
        }
        if (isExposedField) 
            continue;
        _interface->append(new InterfaceData(EL_EVENT_OUT, i));
    }
    for (i=0; i < proto->getNumEventIns(); i++) {
        // ignore Exposedfields (eg. "url")
        bool isExposedField = false;
        for (int j=0; j < proto->_exposedFields.size(); j++) {
            MyString exposedName = "set_";
            exposedName += proto->getExposedField(j)->getName();
            if (strcmp(proto->getEventIn(i)->getName(), exposedName) == 0)
               isExposedField = true;
        }
        if (isExposedField) 
            continue;
        _interface->append(new InterfaceData(EL_EVENT_IN, i));
    }
}


Generated by  Doxygen 1.6.0   Back to index