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