1 /***********************************************************************/
2 /* Open Visualization Data Explorer                                    */
3 /* (C) Copyright IBM Corp. 1989,1999                                   */
4 /* ALL RIGHTS RESERVED                                                 */
5 /* This code licensed under the                                        */
6 /*    "IBM PUBLIC LICENSE - Open Visualization Data Explorer"          */
7 /***********************************************************************/
8 
9 #include <dxconfig.h>
10 #include "../base/defines.h"
11 
12 
13 
14 #include "IBMVersion.h"
15 #include "ReceiverNode.h"
16 #include "TransmitterNode.h"
17 #include "ParameterDefinition.h"
18 
19 #include "Ark.h"
20 #include "ConfigurationDialog.h"
21 #include "ListIterator.h"
22 #include "ErrorDialogManager.h"
23 #include "WarningDialogManager.h"
24 #include "Network.h"
25 #include "EditorWindow.h"
26 #include "lex.h"
27 
28 
29 // FIXME: should be static class data
30 static boolean initializing = FALSE;
31 
ReceiverNode(NodeDefinition * nd,Network * net,int instnc)32 ReceiverNode::ReceiverNode(NodeDefinition *nd, Network *net, int instnc) :
33     UniqueNameNode(nd, net, instnc)
34 {
35 }
initialize()36 boolean ReceiverNode::initialize()
37 {
38     const char *label;
39 
40     label = this->getLabelString();
41     Network *net = this->getNetwork();
42     EditorWindow *editor = net->getEditor();
43     if (!net->isReadingNetwork() && editor) {
44 	TransmitterNode *tmtr = editor->getMostRecentTransmitterNode();
45 	if (tmtr)
46 	    label = tmtr->getLabelString();
47     }
48     initializing = TRUE;
49     this->setLabelString(label);
50     initializing = FALSE;
51 
52     return TRUE;
53 }
54 
~ReceiverNode()55 ReceiverNode::~ReceiverNode()
56 {
57 }
58 
59 
60 //
61 // Is this receiver connected to a Transmitter.
62 //
isTransmitterConnected()63 boolean ReceiverNode::isTransmitterConnected()
64 {
65     return this->isInputConnected(1);
66 }
67 
netNodeString(const char * prefix)68 char *ReceiverNode::netNodeString(const char *prefix)
69 {
70     char      *string = new char[200];
71     char      *outputParam;
72 
73     outputParam = this->outputParameterNamesString(prefix);
74     sprintf(string,"%s = %s;\n", outputParam, this->getLabelString());
75 
76     delete outputParam;
77     return string;
78 }
79 
80 //
81 // When a Receiver gets a new label, it has to disconnect from its existing
82 // transmitter, and connect to the new one.  This will work even if it's
83 // the transmitter that's changing our label.
setLabelString(const char * label)84 boolean ReceiverNode::setLabelString(const char *label)
85 {
86     if (EqualString(label, this->getLabelString()))
87 	return TRUE;
88 
89     if (initializing && this->getNetwork()->isReadingNetwork())
90         return this->UniqueNameNode::setLabelString(label);
91 
92     if (!this->verifyRestrictedLabel(label))
93 	return FALSE;
94 
95     //
96     // Skip the conflict check when reading in a newer style net since
97     // there can't be any conflict in these nets.
98     //
99     const char* conflict = NUL(char*);
100     if (this->getNetwork()->isReadingNetwork()) {
101         int net_major = this->getNetwork()->getNetMajorVersion();
102         int net_minor = this->getNetwork()->getNetMinorVersion();
103         int net_micro = this->getNetwork()->getNetMicroVersion();
104         int net_version =   VERSION_NUMBER( net_major, net_minor, net_micro);
105         if (net_version < VERSION_NUMBER(3,1,1))
106 	    conflict = this->getNetwork()->nameConflictExists(this, label);
107     }
108 
109     //
110     // If there is a name conflict while reading a network, it's important to try
111     // to continue in spite of the conflict and fix things up later.  Reason: older
112     // versions of dx allowed the name conflict and we would like to try and fix
113     // things and report what happened rather than read the net incorrectly.
114     //
115     if ((conflict) && (this->getNetwork()->isReadingNetwork() == FALSE)) {
116 	ErrorMessage("A %s with name \"%s\" already exists.", conflict, label);
117 	return FALSE;
118     }
119 
120     boolean found = FALSE;
121     List *ia = (List*)this->getInputArks(1);
122     if ((ia) && (ia->getSize() > 0)) {
123 	Ark *a = (Ark*)ia->getElement(1);
124 	int dummy;
125 	if (EqualString(a->getSourceNode(dummy)->getLabelString(), label))
126 	    found = TRUE;
127 	else
128 	    delete a;
129     }
130     ia = NUL(List*);
131 
132 
133     if (!found) {
134 	List* l = this->getNetwork()->makeClassifiedNodeList(ClassTransmitterNode, FALSE);
135 	ListIterator iterator;
136 	Node *n;
137 
138 	if ((l) && (this->getNetwork()->isReadingNetwork() == FALSE)) {
139 	    //
140 	    // Before creating any Arks, check for cycles.
141 	    //
142 	    iterator.setList(*l);
143 	    while ( (n = (Node*)iterator.getNext()) ) {
144 		if (EqualString(label, n->getLabelString())) {
145 		    Network* net = this->getNetwork();
146 		    if (net->checkForCycle(n, this)) {
147 			ErrorMessage (
148 			    "Unable to rename Receiver \"%s\" to \"%s\"\n"
149 			    "because that would cause a cyclic connection.",
150 			    this->getLabelString(), label
151 			);
152 			delete l;
153 			return FALSE;
154 		    }
155 		}
156 	    }
157 	}
158 
159 	if (l) {
160 	    iterator.setList(*l);
161 	    while ( (n = (Node*)iterator.getNext()) ) {
162 		if (EqualString(label, n->getLabelString()))
163 		{
164 		    found = TRUE;
165 		    // link me to transmitter
166 		    new Ark(n, 1, this, 1);
167 		}
168 	    }
169 	    delete l;
170 	}
171     }
172 
173     //
174     // There was a name conflict because earlier versions of dx were less restrictive.
175     // Record the transmitter for later fixup.  When the transmitter is fixed up,
176     // then we'll automatically get fixed up also.  Caveat:  if there is no transmitter
177     // connected, then it's cool to refuse the name because then we're not breaking
178     // anything.
179     //
180     if (conflict) {
181 	ASSERT (this->getNetwork()->isReadingNetwork());
182 	if (this->isTransmitterConnected() == FALSE) {
183 	    ErrorMessage("A %s with name \"%s\" already exists.", conflict, label);
184 	    return FALSE;
185 	}
186 	List *l = (List*)this->getInputArks(1);
187 	ASSERT (l->getSize() > 0);
188 	Ark *a = (Ark*)l->getElement(1);
189 	int dummy;
190 	TransmitterNode* tn = (TransmitterNode*)a->getSourceNode(dummy);
191 	this->getNetwork()->fixupTransmitter(tn);
192     }
193 
194     return this->UniqueNameNode::setLabelString(label);
195 
196 }
197 //
198 // Determine if this node is of the given class.
199 //
isA(Symbol classname)200 boolean ReceiverNode::isA(Symbol classname)
201 {
202     Symbol s = theSymbolManager->registerSymbol(ClassReceiverNode);
203     if (s == classname)
204 	return TRUE;
205     else
206 	return this->UniqueNameNode::isA(classname);
207 }
208 
209 //
210 // Get the node that is connected to the Transmitter that this Receiver
211 // is receiving from.  IF there is no Transmitter for this Receiver, or
212 // the Transmitter is not connected, return NULL, otherwise the Node.
213 //
getUltimateSourceNode(int * param_no)214 Node *ReceiverNode::getUltimateSourceNode(int* param_no)
215 {
216     int startPos = 1;
217 
218     //
219     // Loop over nodes named the same as our getLabelString().  Normally,
220     // this wouldn't be necessary, but you can name a ProbeList the same
221     // as a transmitter.  Keep a loop counter just as a sanity check, although
222     // according to the logic in Network::findNode, it shouldn't be needed.
223     //
224     Node* tmtr = NUL(Node*);
225     int i = 0;
226     while (1) {
227 	tmtr = this->getNetwork()->findNode(this->getLabelString(), &startPos, TRUE);
228 	if (!tmtr) break;
229 	if (tmtr->isA(ClassTransmitterNode)) break;
230 	if (++i > 100) break;
231     }
232 
233     if (!tmtr)
234 	return NULL;
235 
236     List *arcList = (List*)tmtr->getInputArks(1);
237     int narcs = arcList->getSize();
238     ASSERT(narcs <= 1);
239     if (narcs == 0)
240 	return NULL;
241 
242     Ark *a = (Ark*)arcList->getElement(1);
243     ASSERT(a);
244     int paramInd;
245     Node *n = a->getSourceNode(paramInd);
246     if (param_no) *param_no = paramInd;
247     if (EqualString(n->getClassName(),ClassReceiverNode))
248 	return ((ReceiverNode*)n)->getUltimateSourceNode();
249     else
250 	return n;
251 }
252 
253 
254 //
255 // Switch the node from one net to another.  Look for a transmitter
256 // to connect to.
257 //
switchNetwork(Network * from,Network * to,boolean silently)258 void ReceiverNode::switchNetwork(Network *from, Network *to, boolean silently)
259 {
260     const char *label = this->getLabelString();
261 
262     //
263     // Check for a connected input.  If there is an arc, do nothing
264     // because any required name change on the part of the transmitter
265     // will keep us up-to-date.  If there is no arc, then it's tough to
266     // know what name to use.
267     //
268     List *l = (List*)this->getInputArks(1);
269     boolean found = FALSE;
270     if (l->getSize() > 0) {
271 	Ark *a = (Ark*)l->getElement(1);
272 	int dummy;
273 	if (EqualString(a->getSourceNode(dummy)->getLabelString(), label))   {
274 	    found = TRUE;
275 	} else  {
276 	    delete a;
277 	}
278     }
279 
280     boolean avoiding_cycle = FALSE;
281     if (!found) {
282 	l = to->makeClassifiedNodeList(ClassTransmitterNode, FALSE);
283 	if (l) {
284 	    Node *n;
285 	    ListIterator iterator(*l);
286 	    while ( (n = (Node*)iterator.getNext()) ) {
287 		if (EqualString(label, n->getLabelString())) {
288 		    if (to->checkForCycle(n, this)) {
289 			avoiding_cycle = TRUE;
290 			break;
291 		    }
292 		}
293 	    }
294 
295 	    if (!avoiding_cycle) {
296 		iterator.setList(*l);
297 		while ( (n = (Node*)iterator.getNext()) ) {
298 		    if (EqualString(label, n->getLabelString())) {
299 			// link me to transmitter
300 			new Ark(n, 1, this, 1);
301 			found = TRUE;
302 		    }
303 		}
304 	    }
305 	    delete l;
306 	}
307     }
308 
309     //
310     // If the receiver has no arc, then check for name uniqueness and rename the
311     // receiver if necessary.  (If the receiver has an arc, then it's up to the
312     // transmitter to handle name uniqueness.)
313     //
314     if (!found) {
315 	if (!avoiding_cycle) {
316 	    const char* conflict = to->nameConflictExists(this, label);
317 	    if (conflict){
318 		if (!silently)
319 		    WarningMessage ("A %s with name \"%s\" already exists.",
320 			conflict, label);
321 		this->setLabelString ("Receiver");
322 	    }
323 	} else {
324 	    if (!silently)
325 		WarningMessage (
326 		    "Receiver \"%s\" has been renamed \"%s\"\n"
327 		    "due to a cyclic connection.",
328 		    this->getLabelString(), "Receiver"
329 		);
330 	    this->setLabelString ("Receiver");
331 	}
332     }
333 
334     this->UniqueNameNode::switchNetwork(from, to, silently);
335 }
336 
337 
namesConflict(const char * his_label,const char * my_label,const char * his_classname)338 boolean ReceiverNode::namesConflict (const char* his_label, const char* my_label,
339     const char* his_classname)
340 {
341 
342     //
343     // You can always match names with other TransmitterNodes or ReceiverNodes.
344     //
345     if (EqualString (his_classname, this->getClassName())) return FALSE;
346     if (EqualString (his_classname, ClassTransmitterNode)) return FALSE;
347 
348     //
349     // You can always use the name Receiver.
350     //
351     if (EqualString (my_label, "Reciever")) return FALSE;
352 
353     return this->UniqueNameNode::namesConflict (his_label, my_label, his_classname);
354 }
355