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

Node.cpp

/*
 * Node.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 <string.h>
#include <ctype.h>
#include "stdafx.h"

#include "Node.h"
#include "Scene.h"
#include "Field.h"
#include "FieldValue.h"
#include "FieldCommand.h"
#include "Proto.h"
#include "Path.h"
#include "SFNode.h"
#include "MFNode.h"
#include "SFString.h"
#include "MFString.h"
#include "EventIn.h"
#include "EventOut.h"
#include "ExposedField.h"
#include "URL.h"
#include "DuneApp.h"
#include "NodeScript.h"

#define HANDLE_SIZE 2.0f

NodeData::NodeData(Scene *scene, Proto *proto)
{
    static unsigned long identifier_source=0;
    identifier_source++;
    _identifier=identifier_source;

    _scene = scene;
    _graphX = _graphY = 0;
    _graphWidth = _graphHeight = 0;
    _scene->addNode((Node*)this);
    _refs = 0;
    _flags = 1<<NODE_FLAG_COLLAPSED;
    _proto = proto;

    int         i;
    _numFields = _proto->getNumFields();
    _fields = new FieldValue *[_numFields];
    for (i = 0; i < _numFields; i++) {
      _fields[i] = _proto->getField(i)->getDefault()->copy();
      _fields[i]->ref();
    }
    _numEventIns = _proto->getNumEventIns();
    _inputs = new SocketList[_numEventIns];
    _numEventOuts = _proto->getNumEventOuts();
    _outputs = new SocketList[_numEventOuts];
    _numberUse = 1;
}

NodeData::NodeData(const Node &node)
{
    _identifier=node._identifier;  // FIXME: unclear: should all IDs be unique??

    _scene = node._scene;
    _refs = 0;
    _graphX = _graphY = 0;
    _graphWidth = _graphHeight = 0;
    _scene->addNode((Node*)this);
    _flags = node._flags;
    _proto = node._proto;
    _numFields = _proto->getNumFields();
    _fields = new FieldValue *[_numFields];
    if (_name.length() !=0)
        _scene->def(_name, (Node*)this);

    for (int i = 0; i < _numFields; i++) {
      _fields[i] = node._fields[i]->copy();
      _fields[i]->ref();
    }
    _numEventIns = _proto->getNumEventIns();
    _inputs = new SocketList[_numEventIns];
    _numEventOuts = _proto->getNumEventOuts();
    _outputs = new SocketList[_numEventOuts];
    _numberUse = 1;
}

Node::Node(Scene *scene, Proto *proto) : NodeData(scene,proto) 
{
    _commentsList = new NodeList;     
}

Node::Node(const Node &node) : NodeData(node)
{
    _geometricParentIter=node._geometricParentIter;
    _commentsList = new NodeList;
}

Node::Node(const Node &node, Proto *proto) : NodeData(node)
{ 
    _geometricParentIter=node._geometricParentIter;
    _proto = proto;
    for (int i = 0; i < proto->getNumEventOuts(); i++)
      _outputs[i] = node._outputs[i];
    _commentsList = new NodeList;
}

Node::~Node()
{
    _scene->removeNode(this);
    for (int i = 0; i < _numFields; i++) {
      _fields[i]->unref();
    }
    _numFields = 0;
    delete [] _fields;
    delete [] _inputs;
    delete [] _outputs;
    delete _commentsList;
    _scene->undef(_name);
}

const MyString& 
NodeData::getName(void)
{
   if (needsDEF())
      if (_name.length() == 0) 
         _scene->generateUniqueNodeName((Node*)this);       
   return _name; 
}

bool
NodeData::hasName(void)
{
   if (_name[0]) 
       return true;
   else
       return false;
}


FieldValue *
NodeData::getField(int index, bool ignoreproto) const
{
    // fixme: PROTO implemenation incomplete
    if (ignoreproto) 
        if (_proto->isPROTO()) return NULL;

    assert (index >= 0 && index < _numFields);

    if (ignoreproto)
        if (_fields[index]->getType() == SFNODE) {
            Node* node = ((SFNode *) _fields[index])->getValue();
            if (node)
                if (node->getProto()->isPROTO())
                    return NULL;
        }
    
    return _fields[index];
}

void
NodeData::setField(int index, FieldValue *value)
{
    assert (index >= 0 && index < _numFields);
    if (_fields[index]!=NULL)
        assert( _fields[index]->getType() == value->getType() );


    // if field is an SFNode or MFNode type, remove old values from 
    // children's parent list

    if (value->getType() == SFNODE) {
      Node *child = ((SFNode *) _fields[index])->getValue();
      if (child) child->removeParent((Node*)this, index);
    } else if (value->getType() == MFNODE) {
      NodeList *childList = ((MFNode *) _fields[index])->getValues();
      if (childList) {
          for (int i = 0; i < childList->size(); i++) {
            Node *child = childList->get(i);
            if (child) child->removeParent((Node*)this, index);
          }
      }
    }

    value->clamp(_proto->getField(index)->getMin(), 
             _proto->getField(index)->getMax());

    _fields[index]->unref();
    _fields[index] = value;
    _fields[index]->ref();

    if (value->getType() == SFNODE) {
      Node *child = ((SFNode *) value)->getValue();
      if (child) child->addParent((Node*)this, index);
    } else if (value->getType() == MFNODE) {
      NodeList *childList = ((MFNode *) value)->getValues();
      if (childList) {
          for (int i = 0; i < childList->size(); i++) {
            Node *child = childList->get(i);
            if (child) child->addParent((Node*)this, index);
          }
      }
    }
}

void
Node::addFieldNodeList(int index, NodeList *childList)
{
    assert (index >= 0 && index < _numFields);
    if (((MFNode*)_fields[index])->getSize() == 0)
        setField(index, new MFNode(childList));
    else {
        for (int i = 0; i < childList->size(); i++) {
            Node *child = childList->get(i);
            FieldValue* newField= ((MFNode*)_fields[index])->addNode(child);
            newField->clamp(_proto->getField(index)->getMin(), 
                        _proto->getField(index)->getMax());

            _fields[index]->unref();
            _fields[index] = newField;
            _fields[index]->ref();
            if (child) {
                child->addParent(this, index);
            }
        }
    }
    ((MFNode*)_fields[index])->getValues();
}

int NodeData::write(int f, int indent)
{
    if (_proto) {
        TheApp->checkSelectionLinenumberCounting(_scene, (Node*) 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((Node*)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 ,(const char *) _proto->getName()) )
            RET_ONERROR( mywritestr(f ," ") )
            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( 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);
}

bool            
NodeData::writeEXTERNPROTO(int filedes)
{
    // used to write a EXTERNPROTO definition of a new VRML200x node
    return true;
}

bool
NodeData::needsDEF() const
{
    if (_name.length() != 0) return true;

    if (getNumParents() > 1) return true;

    for (int i = 0; i < _numEventIns; i++) {
      if (_inputs[i].size() > 0) {
          return true;
      }
    }

    for (int j = 0; j < _numEventOuts; j++) {
      if (_outputs[j].size() > 0) {
          return true;
      }
    }

    return false;
}

int NodeData::writeFields(int f, int indent)
{
    if (!_proto) return(0);
    const char       *oldBase = _scene->getURL();
    const char       *newBase = _scene->getNewURL();
    bool        tempSave = _scene->isTempSave();

    for (int i = 0; i < _numFields; i++) {
      Field       *field = _proto->getField(i);
      FieldValue  *value = _fields[i];
        int type = field->getType();
      if (value) {
            // see bug: testing in NodeData::writeFields in TODO file
            if (!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(i, value);
                         FieldUpdate* fieldUpdate=new FieldUpdate((Node*)this,
                                                                  i);
                         _scene->UpdateViews(NULL, UPDATE_FIELD, 
                                             (Hint *) fieldUpdate);
                         delete fieldUpdate;
                 } else {
                     delete value;
                 }
              } else {
                RET_ONERROR( value->write(f, indent) )
              }
            }
      }
    }
    return(0);
}

FieldValue *
NodeData::rewriteField(FieldValue *value, const char *oldBase, const char *newBase)
{
    MyString      r;

    switch (value->getType()) {
      case SFSTRING:
      r = rewriteURL(((SFString *) value)->getValue(), oldBase, newBase);
#ifdef _WIN32
        // handle invalid paths like c:/something
        if (r != NULL)
            r.gsubOnce("|",":"); 
#endif
      return new SFString(r);
      case MFSTRING:
      {
        bool flag = false;
      StringArray *a = new StringArray();
      int n = ((MFString *) value)->getSize();
        if (n != 0)
            flag = notJavascript((const char*)(((MFString *) value)->
                                               getValue(0)));
      for (int i = 0; i < n; i++) {
            const char* url = (const char*) ((MFString *) value)->getValue(i);
            if (notURN(url) && flag) {
               /* need to replace "vrmlscript:" ? */
             (*a)[i] = rewriteURL(url, oldBase, newBase);
#ifdef _WIN32
               // handle invalid paths like c:/something
               if ((*a)[i] != NULL)
                   ((*a)[i]).gsubOnce("|",":"); 
#endif
               }
            else
               (*a)[i] = url;
 
      }
      return new MFString(a);
      }
      default:
      assert( 0 );
      return NULL;
    }
}

int NodeData::writeRoutes(int f, int indent) const
{
    int                       i;
    SocketList::Iterator       *j;

    if (!_proto) return(0);

    for (i = 0; i < _numEventIns; i++) {
      for (j = _inputs[i].first(); j != NULL; j = j->next()) {
          if (j->item()._node->getFlag(NODE_FLAG_TOUCHED)) {
                MyString routestring;

            Node  *src = j->item()._node;
                routestring="ROUTE ";
                routestring+=src->getName();
                routestring+=".";
                routestring+=src->getProto()->
                             getEventOut(j->item()._index)->getName();
                routestring+=" TO ";
                routestring+=_name;
                routestring+=".";
                routestring+=getProto()->getEventIn(i)->getName();
                _scene->addRouteString(routestring);
          }
      }
    }

    for (i = 0; i < _numEventOuts; i++) {
      for (j = _outputs[i].first(); j != NULL; j = j->next()) {
          if (j->item()._node->getFlag(NODE_FLAG_TOUCHED)) {
                MyString routestring;

            Node  *dst = j->item()._node;
                routestring="ROUTE ";
                routestring+=_name;
                routestring+=".";
                routestring+=getProto()->getEventOut(i)->getName();
                routestring+=" TO ";
                routestring+=dst->getName();
                routestring+=".";
                routestring+=dst->getProto()->getEventIn(j->item()._index)->
                             getName();
                _scene->addRouteString(routestring);
          }
      }
    }

#ifndef HAVE_ROUTE_AT_END
    if (indent==0)
       RET_ONERROR( _scene->writeRouteStrings(f) )
#endif
    return(0);
}

int
NodeData::lookupEventIn(const MyString &name) const
{
    return _proto ? _proto->lookupEventIn(name) : INVALID_INDEX;
}

int
NodeData::lookupEventOut(const MyString &name) const
{
    return _proto ? _proto->lookupEventOut(name) : INVALID_INDEX;
}

MyString
NodeData::newEventName(int typeEnum, bool out)
{
    char name[1024];
    MyString eventName = "";
    const char *typestr = typeEnumToString(typeEnum);
    if (typestr[0] == 'M')
        eventName += "m";
    for (int i = 2; i < strlen(typestr); i++)
        eventName += tolower(typestr[i]);
    int counter = 0;
    bool foundflag;
    do {
        foundflag = false;
        counter++;
        char *format = "%d_in";
        if (out)
            format = "%d_out";
        mysnprintf(name, 1023, (const char *)format, counter);

        int numberEvents = 0;
        if (out)
            numberEvents = _proto->getNumEventOuts();
        else
            numberEvents = _proto->getNumEventIns();
        for (int i = 0; i < numberEvents; i++) {
            char *oldName;
            if (out)
               oldName = (char*)(const char*) _proto->getEventOut(i)->getName();
            else 
               oldName = (char*)(const char*) _proto->getEventIn(i)->getName();
            MyString cmpName = "";
            cmpName += eventName;
            cmpName += name; 
            if (strcmp(oldName, (const char*)cmpName) == 0)
                foundflag = true;
        }
    } while (foundflag == true);
    eventName += name;
    return eventName;
}

void
NodeData::addInput(int eventIn, Node *src, int eventOut)
{
    if (eventIn >= _numEventIns)
        if (getType() == NODE_SCRIPT) {
            int typeEnum = src->getProto()->getEventOut(eventOut)->getType();
            ((NodeScript *)this)->addEventIn(typeEnum, 
                                             newEventName(typeEnum, false));
            update();
            NodeUpdate *hint= new NodeUpdate((Node *)this, NULL, 0);
            _scene->UpdateViews(NULL, UPDATE_CHANGE_INTERFACE_NODE, 
                                (Hint*) hint);
        }
    _inputs[eventIn].append(Socket(src, eventOut));
}

void
NodeData::addOutput(int eventOut, Node *dst, int eventIn)
{
    if (eventOut >= _numEventOuts)
        if (getType() == NODE_SCRIPT) {
            int typeEnum = dst->getProto()->getEventIn(eventIn)->getType();
            ((NodeScript *)this)->addEventOut(typeEnum, 
                                              newEventName(typeEnum, true));
            update();
            NodeUpdate *hint= new NodeUpdate((Node *)this, NULL, 0);
            _scene->UpdateViews(NULL, UPDATE_CHANGE_INTERFACE_NODE, 
                                (Hint*) hint);
        }
    _outputs[eventOut].append(Socket(dst, eventIn));
}

void
NodeData::removeInput(int eventIn, Node *src, int eventOut)
{
    SocketList::Iterator *j = _inputs[eventIn].find(Socket(src, eventOut));
    if (j) 
      _inputs[eventIn].remove(j);
}

void
NodeData::removeOutput(int eventOut, Node *dst, int eventIn)
{
    SocketList::Iterator      *j = _outputs[eventOut].find(Socket(dst, eventIn));
    if (j)
      _outputs[eventOut].remove(j);
}

void
NodeData::update()
{
    // used by Script to update its fields and
    // used by shapes to redraw after a change of a MF-field
}

void
NodeData::reInit()
{
    // used to reinitialise private data of a "copy"-ed node
    // e.g. to reinitialise mesh data of some geometric shapes
}


void
Node::addParent(Node *parent, int field)
{
    _parents.append(Parent(parent, field, this));
    _geometricParentIter = _parents.last();
}

int
NodeData::findChild(Node *child, int field) const
{
    assert(field >= 0 && field < _numFields);

    FieldValue    *value = _fields[field];

    if (value->getType() == SFNODE) {
      return (((SFNode *) value)->getValue() == child) ? 0 : -1;
    } else if (value->getType() == MFNODE) {
      NodeList    *list = ((MFNode *) value)->getValues();
      for (int i = 0; i < list->size(); i++) {
          if (list->get(i) == child) return i;
      }
      return -1;
    } else {
      return -1;
    }
}

bool
Node::hasAncestor(Node *node) const
{
    if (this != _scene->getRoot()) {
        if (hasParent()) {
            Node *parent = getParent();
            if (parent == node || parent->hasAncestor(node)) 
                return true;
        }  
    }
    return false;
}

int
NodeData::findValidFieldType(int childType)
{
    int match = -1;
    for (int field = 0; field < _numFields; field++) {
      if (validChildType(field, childType)) {
          if (match != -1) return -1;         // ambiguous
          match = field;
      }
    }
    return match;
}

int
NodeData::findValidField(Node *child)
{
    return findValidFieldType(child->getNodeClass());
}

bool
NodeData::validChild(int field, Node *child)
{
    return validChildType(field, child->getNodeClass());
}

bool
NodeData::validChildType(int field, int childType)
{
    if (field < 0 || field >= _numFields) return false;

    Field       *def = _proto->getField(field);

    if (def->getType() == SFNODE && ((SFNode *) _fields[field])->getValue() != NULL)
      return false;

    if (def->getType() == SFNODE || def->getType() == MFNODE) {
      int   nodeType = def->getNodeType();

      if (nodeType == ANY_NODE) {
          return true;
      } else if (childType == nodeType) {
          return true;
      } else if (isClassType(childType) && isClassType(nodeType) &&  
                   (childType & nodeType)) {
          return true;
      } else
           return false;
    } else {
      return false;
    }
}

void
NodeData::setFlagRec(int flag)
{
    setFlag(flag);

    for (int i = 0; i < _numFields; i++) {
      if (_fields[i]->getType() == MFNODE) {
          ((MFNode *) _fields[i])->getValues()->setFlag(flag);
      } else if (_fields[i]->getType() == SFNODE) {
          SFNode *value = (SFNode *) _fields[i];
          if (value->getValue()) value->getValue()->setFlagRec(flag);
      }
    }
}

void
NodeData::clearFlagRec(int flag)
{
    setFlag(flag);

    for (int i = 0; i < _numFields; i++) {
      if (_fields[i]->getType() == MFNODE) {
          ((MFNode *) _fields[i])->getValues()->clearFlag(flag);
      } else if (_fields[i]->getType() == SFNODE) {
          SFNode *value = (SFNode *) _fields[i];
          if (value->getValue()) value->getValue()->clearFlagRec(flag);
      }
    }
}

Path *
NodeData::getPrimaryPath() const
{
    int           len = 0;
    const Node       *node, *root = _scene->getRoot();

    for (node = (Node*)this; node != root; node = node->getParent()) {
      len += 2;
    }

    int        *list = new int[len];

    int i = len-1;
    
    for (node = (Node*)this; node != root; node = node->getParent()) {
      Node     *parent = node->getParent();
      int       field = node->getParentField();
      FieldValue *value = parent->getField(field);
      if (value->getType() == MFNODE) {
          list[i--] = ((MFNode *) value)->getValues()->find((Node *) node);
      } else if (value->getType() == SFNODE)  {
          list[i--] = 0;
      } else {
          assert(false);
      }
      list[i--] = field;
    }

    Path    *path = new Path(list, len, _scene);
    delete [] list;
    return path;
}


bool
Node::isInScene(Scene* scene) const
{
    if (scene != _scene) 
       return false;
    if (this == _scene->getRoot()) return true;
    if (!this->hasParent())
       return false;
    if (this->getParent()->isInScene(scene))
       return true;
    return false;
}

void
NodeData::sendEvent(int eventOut, double timestamp, FieldValue *value)
{
    assert(eventOut >= 0 && eventOut <= _numEventOuts);

    value->ref();

    SocketList::Iterator    *i;

    for (i = _outputs[eventOut].first(); i != NULL; i = i->next()) {
      Socket      s = i->item();

      s._node->receiveEvent(s._index, timestamp, value);
    }

    value->unref();
}

void
NodeData::receiveEvent(int eventIn, double /* timestamp */, FieldValue *value)
{
    // check to see if this eventIn is part of an exposedField or
    // conntected to a normal field

    int field = -1;
    ExposedField       *e = _proto->getEventIn(eventIn)->getExposedField();

    if (e)
        field = e->getField();
    else 
        field = _proto->getEventIn(eventIn)->getField();
    
    if (field != -1) {
      // set the appropriate field
      setField(field, value);
      _scene->OnFieldChange((Node*)this, field);

        // fire off an event here?
    }        
}

/// compare content
bool
NodeData::isEqual(Node* node)
{
    if (_identifier==node->_identifier)
       return true;
    else
       return false;
}

bool
NodeData::hasFieldFlag(int flag)
{
    for (int field = 0; field < _numFields; field++) {
        Field *def = _proto->getField(field);
      if (def->getFlags() & FF_URL)
            return true;
    }
    return false;
}

bool              
hasRoute(SocketList socketlist)
{
   if (socketlist.first() == NULL) 
      return false;
   else
      return true;
}

bool 
Node::isAnimateable(void)
{
    Proto *proto = getProto();
    for (int i = 0; i < proto->getNumEventIns(); i++) {
        int type = proto->getEventIn(i)->getType();
        if (typeDefaultValue(type)->isAnimateable() && 
            typeDefaultValue(type)->hasAnimationSupport())
            return true;
    }
    return false;
}

bool
Node::isInvalidChild(void)
{
    if (this == _scene->getRoot())
        return true;
    if (isInvalidChildNode() &&
        (getParent()->getProto()->getField(getParentField())->getType() 
         == MFNODE)
       )
        return true;
    return false;
}

void
Node::removeParent(Node *parent, int field)
{
    ParentList::Iterator *i = _parents.find(Parent(parent, field, this));

    if (!i) {
#ifdef DEBUG
      assert(false);
#else
        return;
#endif
    } else {
      _parents.remove(i);
    }
}

Vec3f               
Node::getMinBoundingBox(void)
{
   Vec3f ret(0, 0, 0);
   return ret;
}

Vec3f               
Node::getMaxBoundingBox(void)
{
   Vec3f ret(0, 0, 0);
   return ret;
}

void 
Node::appendComment(Node *node)
{ 
    _commentsList->append(node); 
}

void Node::appendTo(NodeList* nodelist)
{
    for (int i = 0;i < _commentsList->size(); i++)
       nodelist->append((*_commentsList)[i]);
    nodelist->append(this);
    _commentsList->resize(0);
}



Generated by  Doxygen 1.6.0   Back to index