/***********************************************************************/ /* Open Visualization Data Explorer */ /* (C) Copyright IBM Corp. 1989,1999 */ /* ALL RIGHTS RESERVED */ /* This code licensed under the */ /* "IBM PUBLIC LICENSE - Open Visualization Data Explorer" */ /***********************************************************************/ #include #include "UIConfig.h" #include "defines.h" #include "MacroParameterNode.h" #include "MacroParameterDefinition.h" #include "Parameter.h" #include "ParameterDefinition.h" #include "Network.h" #include "MacroDefinition.h" #include "DXApplication.h" #include "Arc.h" #include "ConfigurationDialog.h" #include "DXType.h" #include "ListIterator.h" #include "ErrorDialogManager.h" #include "WarningDialogManager.h" #include "lex.h" MacroParameterNode::MacroParameterNode(NodeDefinition *nd, Network *net, int instnc) : UniqueNameNode(nd, net, instnc) { this->index = -1; } MacroParameterNode::~MacroParameterNode() { Network *net = this->getNetwork(); MacroDefinition *md = net->getDefinition(); Parameter *p; ParameterDefinition *pd = this->getParameterDefinition(); if (this->isInput()) { if (pd && !net->isDeleted() || net == theDXApplication->network) { if(!net->isDeleted()) { if (this->index != net->getInputCount()) { int newIndex = net->getInputCount()+1; this->moveIndex(newIndex, FALSE); } else { for (int i = this->index; i > 1; --i) if (!this->moveIndex(i - 1, FALSE)) break; // this->index = i; } } if (md) md->removeInput(pd); if (pd) delete pd; } p = this->getOutputParameter(1); } else { if (pd && !net->isDeleted() || net == theDXApplication->network) { if(!net->isDeleted()) { if (this->index != net->getOutputCount()) { int newIndex = net->getOutputCount()+1; this->moveIndex(newIndex, FALSE); } else { for (int i = this->index; i > 1; --i) if (!this->moveIndex(i - 1, FALSE)) break; } } if (md) md->removeOutput(pd); if (pd) delete pd; } p = this->getInputParameter(1); } if(p) delete p->getDefinition(); if (net == theDXApplication->network) { if (md && md->getInputCount() == 0 && md->getOutputCount() == 0) net->makeMacro(FALSE); } } boolean MacroParameterNode::initialize() { this->UniqueNameNode::initialize(); Network *net = this->getNetwork(); if (!net->isMacro()) net->makeMacro(TRUE); MacroDefinition *md = net->getDefinition(); ParameterDefinition *param; boolean input = this->isInput(); if (!md->isReadingNet()) { param = new ParameterDefinition(-1); param->addType(new DXType(DXType::ObjectType)); } char s[100]; if (input) { if (!md->isReadingNet()) { int n = md->getFirstAvailableInputPosition(); param->markAsInput(); if (n <= md->getInputCount()) { ParameterDefinition *dummyPd = md->getInputDefinition(n); ASSERT(dummyPd->isDummy()); md->replaceInput(param,dummyPd); } else { md->addInput(param); } this->setIndex(n); sprintf(s, "input_%d", this->index); param->setName(s); param->setDefaultValue("(no default)"); } // // The Parameter must have its own ParameterDefinition since // it may change depending upon what we are connected to. // FIXME: ParameterDefinition should have a dup() method. // Parameter *p = this->getOutputParameter(1); ParameterDefinition *pd = p->getDefinition(); #if 11 ParameterDefinition *newpd = pd->duplicate(); #else ParameterDefinition *newpd = new ParameterDefinition(pd->getNameSymbol()); List *l = pd->getTypes(); DXType *dxt; for (ListIterator li(*l); dxt = (DXType*)li.getNext();) newpd->addType(dxt); newpd->markAsOutput(); newpd->setDefaultVisibility(pd->getDefaultVisibility()); newpd->setViewability(pd->isViewable()); newpd->setDescription(pd->getDescription()); newpd->setWriteableCacheability(pd->hasWriteableCacheability()); newpd->setDefaultCacheability(pd->getDefaultCacheability()); if (pd->isRequired()) newpd->setRequired(); else newpd->setNotRequired(); if (pd->isDefaultValue()) newpd->setDefaultValue(pd->getDefaultValue()); else newpd->setDescriptiveValue(pd->getDefaultValue()); #endif p->setDefinition(newpd); } else { if (!md->isReadingNet()) { int n = md->getFirstAvailableOutputPosition(); param->markAsOutput(); if (n <= md->getOutputCount()) { ParameterDefinition *dummyPd = md->getOutputDefinition(n); ASSERT(dummyPd->isDummy()); md->replaceOutput(param,dummyPd); } else { md->addOutput(param); } this->setIndex(n); sprintf(s, "output_%d", this->index); param->setName(s); param->setDefaultValue("(no default)"); } // // The Parameter must have its own ParameterDefinition since // it may change depending upon what we are connected to. // FIXME: ParameterDefinition should have a dup() method. // Parameter *p = this->getInputParameter(1); ParameterDefinition *pd = p->getDefinition(); #if 11 ParameterDefinition *newpd = pd->duplicate(); #else ParameterDefinition *newpd = new ParameterDefinition(pd->getNameSymbol()); List *l = pd->getTypes(); DXType *dxt; for (ListIterator li(*l); dxt = (DXType*)li.getNext();) newpd->addType(dxt); newpd->markAsInput(); newpd->setDefaultVisibility(pd->getDefaultVisibility()); newpd->setViewability(pd->isViewable()); newpd->setDescription(pd->getDescription()); newpd->setWriteableCacheability(pd->hasWriteableCacheability()); newpd->setDefaultCacheability(pd->getDefaultCacheability()); if (pd->isRequired()) newpd->setRequired(); else newpd->setNotRequired(); if (pd->isDefaultValue()) newpd->setDefaultValue(pd->getDefaultValue()); else newpd->setDescriptiveValue(pd->getDefaultValue()); #endif p->setDefinition(newpd); } return TRUE; } const char *MacroParameterNode::getParameterNameString() { ParameterDefinition *pd = this->getParameterDefinition(); ASSERT(pd); return pd->getNameString(); } ParameterDefinition *MacroParameterNode::getParameterDefinition( boolean includeDummies) { MacroDefinition *md = this->getNetwork()->getDefinition(); // // During deletion of a MacroDefinition, there is no MacroDefinition // for this node and therefore no ParameterDefinition. So return NULL. // if (!md) return NULL; int idx = this->getIndex(); if (idx <= 0) return NULL; if (this->isInput()) { ASSERT(this->isInputRepeatable() == FALSE); if (idx > md->getInputCount()) return NULL; } else { ASSERT(this->isOutputRepeatable() == FALSE); if (idx > md->getOutputCount()) return NULL; } ParameterDefinition *pd; if (this->isInput()) { if (includeDummies) pd = md->getInputDefinition(idx); else pd = md->getNonDummyInputDefinition(idx); } else { if (includeDummies) pd = md->getOutputDefinition(idx); else pd = md->getNonDummyOutputDefinition(idx); } return pd; } char *MacroParameterNode::netNodeString(const char *prefix) { char *string; ParameterDefinition *param = this->getParameterDefinition(); ASSERT(param); const char *name = param->getNameString(); if (this->isInput()) { ASSERT(this->getOutputCount() == 1); char *outputs = this->outputParameterNamesString(prefix); string = new char[STRLEN(outputs) + STRLEN(name) + 6]; sprintf(string, "%s = %s;\n", outputs, name); delete outputs; } else { ASSERT(this->getInputCount() == 1); char *inputs = this->inputParameterNamesString(prefix); string = new char[STRLEN(inputs) + STRLEN(name) + 6]; sprintf(string, "%s = %s;\n", name, inputs); delete inputs; } return string; } boolean MacroParameterNode::netParseAuxComment(const char* comment, const char *file, int lineno) { #define PARAM_COMMENT " parameter: position = " #define PARAM_FMT " parameter: position = %d, name = '%[^']', value = '%[^']'"\ ", descriptive = %d, description = '%[^']', required = %d, visible = %d" #define PARAM_FMT1 " parameter: position = %d, name = '%[^']', value = '%[^']'"\ ", descriptive = %d, description = '%[^']', required = %d" if (EqualSubstring(PARAM_COMMENT, comment, STRLEN(PARAM_COMMENT))) { int pos; char name[1000]; char value[1000]; int descriptive; char description[1000]; int required, visible; int itemsParsed = sscanf(comment, PARAM_FMT, &pos, name, value, &descriptive, description, &required, &visible); if (itemsParsed != 7) { itemsParsed = sscanf(comment, PARAM_FMT1, &pos, name, value, &descriptive, description, &required); if (itemsParsed != 6) return this->UniqueNameNode::netParseAuxComment(comment,file,lineno); visible = TRUE; } MacroDefinition *md = this->getNetwork()->getDefinition(); if (!this->getNetwork()->isMacro()) this->getNetwork()->makeMacro(TRUE); if (this->isInput()) { this->moveIndex(pos); ParameterDefinition *pd = this->getParameterDefinition(); pd->setName(name); pd->setDescription(description); if (required) pd->setRequired(); else if (descriptive) pd->setDescriptiveValue(value); else if (IsBlankString(value)) pd->setDefaultValue("(no default)"); else pd->setDefaultValue(value); pd->setDefaultVisibility((boolean)visible); } else { this->moveIndex(pos); ParameterDefinition *pd = this->getParameterDefinition(); pd->setName(name); pd->setDescription(description); pd->setDefaultVisibility((boolean)visible); } return TRUE; } else return this->UniqueNameNode::netParseAuxComment(comment,file,lineno); } boolean MacroParameterNode::addIOArc(List *io, int index, Arc *a) { List *newTypesList = NULL; if (this->isInput()) { int i; Node *dest = a->getDestinationNode(i); Parameter *pin = ((MacroParameterNode*)dest)->getInputParameter(i); ParameterDefinition *pind = pin->getDefinition(); ParameterDefinition *macroPd = this->getParameterDefinition(); List *outTypes = macroPd->getTypes(); newTypesList = DXType::IntersectTypeLists( *outTypes, *pind->getTypes()); ListIterator li(*outTypes); DXType *t; while(t = (DXType*)li.getNext()) { macroPd->removeType(t); } Parameter *pout = this->getOutputParameter(1); ParameterDefinition *nodePd = pout->getDefinition(); outTypes = nodePd->getTypes(); li.setList(*outTypes); while(t = (DXType*)li.getNext()) { nodePd->removeType(t); } li.setList(*newTypesList); while(t = (DXType*)li.getNext()) { DXType *newt = t->duplicate(); nodePd->addType(newt); macroPd->addType(t); } delete newTypesList; } else { int i; Node *dest = a->getSourceNode(i); Parameter *pin = ((MacroParameterNode*)dest)->getOutputParameter(i); ParameterDefinition *pind = pin->getDefinition(); ParameterDefinition *macroPd = this->getParameterDefinition(); List *outTypes = macroPd->getTypes(); newTypesList = DXType::IntersectTypeLists( *outTypes, *pind->getTypes()); ListIterator li(*outTypes); DXType *t; while(t = (DXType*)li.getNext()) { macroPd->removeType(t); } Parameter *pout = this->getInputParameter(1); ParameterDefinition *nodePd = pout->getDefinition(); outTypes = nodePd->getTypes(); li.setList(*outTypes); while(t = (DXType*)li.getNext()) { nodePd->removeType(t); } li.setList(*newTypesList); while(t = (DXType*)li.getNext()) { DXType *newt = t->duplicate(); nodePd->addType(newt); macroPd->addType(t); } delete newTypesList; } if (this->getConfigurationDialog()) { this->getConfigurationDialog()->changeInput(1); this->getConfigurationDialog()->changeOutput(1); } return this->UniqueNameNode::addIOArc(io, index, a); } boolean MacroParameterNode::removeIOArc(List *io, int index, Arc *a) { int destIndex; Node *dest = a->getDestinationNode(destIndex); int srcIndex; Node *src = a->getSourceNode(srcIndex); if (!this->UniqueNameNode::removeIOArc(io, index, a)) return FALSE; ParameterDefinition *macroPd = this->getParameterDefinition(); // // During deletion of a MacroDefinition, there is no MacroDefinition // for this node and therefore no ParameterDefinition. So just return. // if (!macroPd) return TRUE; Parameter *pout; if (this->isInput()) pout = this->getOutputParameter(1); else pout = this->getInputParameter(1); ParameterDefinition *nodePd = pout->getDefinition(); List *outTypes = macroPd->getTypes(); DXType *t; while(t = (DXType*)(outTypes->getElement(1))) { macroPd->removeType(t); } outTypes = nodePd->getTypes(); while(t = (DXType*)(outTypes->getElement(1))) { nodePd->removeType(t); } // for each arc connected to this, intersect this type // list with "typesList" and set this to be the current types list. const List *arcs; if (this->isInput()) arcs = this->getOutputArcs(srcIndex); else arcs = this->getInputArcs(destIndex); ListIterator li; li.setList(*(List *)arcs); List *typesList = new List; typesList->appendElement(new DXType(DXType::ObjectType)); while(a = (Arc*)li.getNext()) { ParameterDefinition *pind; if (this->isInput()) { int dummy; Node *dest = a->getDestinationNode(dummy); pind = ((MacroParameterNode*)dest)->getInputParameter(dummy)-> getDefinition(); } else { int dummy; Node *dest = a->getSourceNode(dummy); pind = ((MacroParameterNode*)dest)->getOutputParameter(dummy)-> getDefinition(); } List *newTypesList = DXType::IntersectTypeLists( *typesList, *pind->getTypes()); // FIXME: don't you have to delete the items in the list first? delete typesList; typesList = newTypesList; } li.setList(*typesList); while(t = (DXType*)li.getNext()) { DXType *newt = t->duplicate(); nodePd->addType(newt); macroPd->addType(t); } delete typesList; if (this->isInput()) { if (this->getConfigurationDialog()) this->getConfigurationDialog()->changeInput(1); } else { if (this->getConfigurationDialog()) this->getConfigurationDialog()->changeOutput(1); } return TRUE; } void MacroParameterNode::setIndex(int index) { this->index = index; } boolean MacroParameterNode::moveIndex(int index, boolean issue_error) { if (index == this->index) return TRUE; if (this->index == -1) { this->setIndex(index); return TRUE; } //ParameterDefinition *macroPd = this->getParameterDefinition(); boolean result; if (this->isInput()) result = this->getNetwork()->moveInputPosition(this, index); else result = this->getNetwork()->moveOutputPosition(this, index); if (result) this->setIndex(index); else if (issue_error) ErrorMessage("Cannot move %s %d to %d, " "it would overwrite another %s.", this->getNameString(), this->index, index, this->getNameString()); if (this->getConfigurationDialog()) { if (this->isInput()) this->getConfigurationDialog()->changeInput(1); else this->getConfigurationDialog()->changeOutput(1); } return result; } boolean MacroParameterNode::netPrintAuxComment(FILE *f) { if (!this->UniqueNameNode::netPrintAuxComment(f)) return FALSE; ParameterDefinition *pd = this->getParameterDefinition(); #define PARAM_OFMT " parameter: position = %d, name = '%s', value = '%s'"\ ", descriptive = %d, description = '%s', required = %d"\ ", visible = %d\n" const char *dflt = pd->getDefaultValue(); if (dflt == NULL || *dflt == '\0' || EqualString(dflt,"NULL")) dflt = " "; const char *desc = pd->getDescription(); if (desc == NULL || *desc == '\0') desc = " "; if (fprintf(f, " //" PARAM_OFMT, this->index, pd->getNameString(), dflt, pd->isDefaultDescriptive(), desc, pd->isRequired(), pd->getDefaultVisibility()) < 0) return FALSE; return TRUE; } // // Determine if this node an input or output // Should not be called until after initialization. // boolean MacroParameterNode::isInput() { return this->getDefinition()->getInputCount() == 0; } // // Determine if this node is of the given class. // boolean MacroParameterNode::isA(Symbol classname) { Symbol s = theSymbolManager->registerSymbol(ClassMacroParameterNode); if (s == classname) return TRUE; else return this->UniqueNameNode::isA(classname); } // // Match output_index of this node to input_index of n. Returns TRUE // if they can connect. // boolean MacroParameterNode::typeMatchOutputToInput( int output_index, Node *n, int input_index) { ASSERT( output_index >= 1 ); ASSERT( input_index >= 1 ); List *tout = this->getOutputTypes(output_index); List *tin = n->getInputTypes(input_index); ASSERT(tin && tout); List *newTypesList = DXType::IntersectTypeLists(*tin, *tout); boolean result = (newTypesList != NULL && newTypesList->getSize() != 0); if (newTypesList != NULL) // FIXME: don't you have to delete the items in the list first? delete newTypesList; return result; } const char* MacroParameterNode::getUniqueName() { ParameterDefinition *pd = this->getParameterDefinition(); return pd->getNameString(); } boolean MacroParameterNode::canSwitchNetwork(Network *from, Network *to) { if (!to->canBeMacro()) { WarningMessage( "Attempt to add %s tool to network would make the \n" "network a macro, but the network contains tools which will\n" "not allow it to become a macro.\n" "Attempt ignored.", this->getNameString()); return FALSE; } return this->UniqueNameNode::canSwitchNetwork(from,to); } void MacroParameterNode::switchNetwork(Network *from, Network *to) { MacroDefinition *md = from->getDefinition(); ParameterDefinition *pd = this->getParameterDefinition(); ParameterDefinition *dummyPd; int n; dummyPd = new ParameterDefinition(-1); dummyPd->setDummy(TRUE); dummyPd->addType(new DXType(DXType::ObjectType)); if(this->isInput()) md->replaceInput(dummyPd, pd); else md->replaceOutput(dummyPd, pd); // // Switch the Network pointers // this->UniqueNameNode::switchNetwork(from, to); // // Make sure we are a macro // to->makeMacro(TRUE); md = to->getDefinition(); if(this->isInput()) { n = md->getFirstAvailableInputPosition(); if (n <= md->getInputCount()) { dummyPd = md->getInputDefinition(n); ASSERT(dummyPd->isDummy()); md->replaceInput(pd,dummyPd); } else { md->addInput(pd); } this->setIndex(n); } else { n = md->getFirstAvailableOutputPosition(); if (n <= md->getOutputCount()) { ParameterDefinition *dummyPd = md->getOutputDefinition(n); ASSERT(dummyPd->isDummy()); md->replaceOutput(pd,dummyPd); } else { md->addOutput(pd); } this->setIndex(n); } // // See if the input is named input_%d or output_%d // and if so, change it to match the possibly new index. // pd = this->getParameterDefinition(); char buf[64]; if (this->isInput()) { strcpy(buf,"input_"); } else { strcpy(buf,"output_"); } int buflen = strlen(buf); const char* current_name = pd->getNameString(); const char* new_name = NUL(char*); boolean name_reset = FALSE; if (EqualSubstring(current_name, buf, buflen)) { int endint = 0; const char *end = ¤t_name[strlen(current_name)]; if (IsInteger(current_name+buflen,endint) && ((current_name+buflen+endint) == end)) { sprintf(buf+buflen,"%d",this->getIndex()); pd->setName(buf); name_reset = TRUE; } } // // Resolve name conflicts with other nodes using global names. // if (!name_reset) { int name_clash=0, i; if (this->isInput()) { int count = to->getInputCount(); for (i=1 ; !name_clash && (i <= count) ; i++) { ParameterDefinition *opd = to->getInputDefinition(i); if ((i != this->getIndex()) && EqualString(current_name,opd->getNameString())) name_clash = i; } } else { int count = to->getOutputCount(); for (i=1 ; !name_clash && (i <= count) ; i++) { ParameterDefinition *opd = to->getOutputDefinition(i); if ((i != this->getIndex()) && EqualString(current_name,opd->getNameString())) name_clash = i; } } if (name_clash) { char name_buf[64]; if (this->isInput()) { sprintf(name_buf,"input_%d", this->getIndex()); } else { sprintf(name_buf,"output_%d", this->getIndex()); } new_name = name_buf; WarningMessage ( "Parameter name `%s' is the same name used by parameter #%d.\n" "Your macro %s has been renamed \"%s\".", current_name, name_clash, (this->isInput()? "Input" : "Output"), new_name ); pd->setName(name_buf); name_reset = TRUE; } } if (!name_reset) { const char* conflict = to->nameConflictExists(this, this->getUniqueName()); if (conflict) { char name_buf[64]; if (this->isInput()) { sprintf(name_buf,"input_%d", this->getIndex()); } else { sprintf(name_buf,"output_%d", this->getIndex()); } new_name = name_buf; WarningMessage ( "A %s with name \"%s\" already exists.\n" "Your macro %s has been renamed \"%s\".", conflict, this->getUniqueName(), (this->isInput()? "Input" : "Output"), name_buf ); pd->setName(name_buf); name_reset = TRUE; } } }