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
15 //
16 // 3/24/95 dawood - Static macros are macros that do not execute unless
17 // their inputs change. Previously, the UI used global variables to
18 // set hardcoded (i.e. tab down, unconnected) inputs to modules in macros.
19 // Now we place the parameter values write in the argument list to the
20 // modules. Among other things this means that we must send a new
21 // definition of the macro (before an execution) each time the user
22 // changes a hardcoded input value.
23 //
24 #define STATIC_MACROS
25
26 #include "DXStrings.h"
27 #include "lex.h"
28 #include "Node.h"
29 #include "NodeDefinition.h"
30 #include "Network.h"
31 #include "DXPacketIF.h"
32 #include "Parameter.h"
33 #include "StandIn.h"
34 #include "ConfigurationDialog.h"
35 #include "ErrorDialogManager.h"
36 #include "WarningDialogManager.h"
37 #include "Ark.h"
38 #include "ListIterator.h"
39 #include "DXApplication.h"
40 #include "ProcessGroupManager.h"
41 #include "EditorWindow.h"
42 #if WORKSPACE_PAGES
43 #include "Dictionary.h"
44 #include "DictionaryIterator.h"
45 #endif
46
47 #if defined(windows) && defined(HAVE_WINSOCK_H)
48 #include <winsock.h>
49 #elif defined(HAVE_CYGWIN_SOCKET_H)
50 #include <cygwin/socket.h>
51 #elif defined(HAVE_SYS_SOCKET_H)
52 #include <sys/socket.h>
53 #endif
54
55
56 //
57 // Define the maxium number of repeatable inputs and outputs.
58 //
59 #define MAX_INPUT_SETS 21
60 #define MAX_OUTPUT_SETS 21
61
62 static char *__indent = " ";
63
setDefinition(NodeDefinition * nd)64 void Node::setDefinition(NodeDefinition *nd)
65 {
66
67 this->definition = nd;
68 if (this->instanceNumber < 1)
69 this->instanceNumber = nd->newInstanceNumber();
70 }
71
Node(NodeDefinition * nd,Network * net,int inst)72 Node::Node(NodeDefinition *nd, Network *net, int inst)
73 {
74
75 this->network = net;
76 this->instanceNumber = inst;
77 this->setDefinition(nd); // This may also set the instance #
78 this->vpe_xpos = this->vpe_ypos = 0;
79 this->labelSymbol = 0;
80 this->standin = NULL;
81 this->cdb = NULL;
82 this->moduleMessageId = NULL;
83 this->nodeCacheability = nd->getDefaultCacheability();
84 this->buildParameterLists();
85 this->marked = FALSE;
86 #if WORKSPACE_PAGES
87 #else
88 this->groupNameSymbol = 0;
89 #endif
90 this->layout_information = NULL;
91 }
92
93
94 //////////////////////////////////////////////////////////////////////////////
95 //
96 // Delete all elements that are considered part of the Node. This includes
97 // input and output parameters, and a Node's standin if it has one.
98 //
~Node()99 Node::~Node()
100 {
101 Parameter *p;
102 ListIterator iterator;
103
104 //
105 // If this node has a messaging protocol and it gets deleted during
106 // execution, be sure that the handler gets removed from the packet
107 // handler so that the handler doesn't get called on a freed node.
108 //
109 if (this->moduleMessageId) {
110 if (this->getNetwork() == theDXApplication->network) {
111 //
112 // don't remove the handler in the case of destroying
113 // a temporary network - i.e. drag-n-drop
114 //
115 DXPacketIF *pif = theDXApplication->getPacketIF();
116 if (pif)
117 pif->setHandler(DXPacketIF::INFORMATION,
118 NULL, (void*)this, this->moduleMessageId);
119 }
120 delete this->moduleMessageId;
121 }
122
123 //
124 // Delete the Configuration Dialog for this node
125 //
126 if (this->cdb) {
127 delete this->cdb;
128 this->cdb = NULL; // Should speed up arc deletion.
129 }
130
131 //
132 // Delete the standin for this node
133 //
134 StandIn *saved_standin = this->standin;
135 this->standin = NULL; // Should speed up arc deletion.
136
137
138
139 //
140 // Delete all the parameters in the Input parameter List
141 //
142 FOR_EACH_NODE_INPUT(this,p,iterator)
143 delete p;
144
145 //
146 // Delete all the parameters in the Output parameter List
147 //
148 FOR_EACH_NODE_OUTPUT(this,p,iterator)
149 delete p;
150
151 //
152 // Now that the parameters and arcs have been deleted we can delete
153 // the StandIn.
154 // NOTE: this depends upon the fact that deletion of the StandIn does not
155 // require reading the state of the Node (i.e. its parameters), otherwise
156 // deletion will need to be placed above Parameter deletion.
157 //
158 if (saved_standin)
159 delete saved_standin;
160
161 if (this->network)
162 this->network->setDirty();
163
164 //
165 // If this is a persistent outboard module, be sure to tell the executive
166 // that it has been deleted.
167 //
168 NodeDefinition *nd = this->definition;
169 if (nd->isOutboard() && nd->isMDFFlagPERSISTENT()) {
170 DXPacketIF *pif = theDXApplication->getPacketIF();
171 if (pif) {
172 char buf[512];
173 #if WORKSPACE_PAGES
174 const char *gname =
175 this->getGroupName(theSymbolManager->getSymbol(PROCESS_GROUP));
176 #else
177 const char *gname = this->getGroupName();
178 #endif
179 if (gname)
180 sprintf(buf,
181 "Executive(\"outboard delete\",\"%s\",%d,\"%s\");\n",
182 this->getNameString(),
183 this->getInstanceNumber(),
184 gname);
185 else
186 sprintf(buf,
187 "Executive(\"outboard delete\",\"%s\",%d);\n",
188 this->getNameString(),
189 this->getInstanceNumber());
190 pif->send(DXPacketIF::FOREGROUND, buf);
191 // FIXME: is the following necessary
192 // pif->sendImmediate("sync");
193 }
194 }
195
196 if (this->layout_information) delete this->layout_information;
197 }
198 //
199 // Determine if this node is a node of the given class
200 //
isA(const char * classname)201 boolean Node::isA(const char *classname)
202 {
203 Symbol s = theSymbolManager->registerSymbol(classname);
204 return this->isA(s);
205 }
206 //
207 // Determine if this node is of the given class.
208 //
isA(Symbol classname)209 boolean Node::isA(Symbol classname)
210 {
211 Symbol s = theSymbolManager->registerSymbol(ClassNode);
212 return (s == classname);
213 }
214
215 //////////////////////////////////////////////////////////////////////////////
216 //
217 // Set the x,y positions on the VPE (visual program editor).
218 // If a standin exists for this node, then ask the StandIn to do it
219 // otherwise just set the values
220 //
setVpePosition(int x,int y)221 void Node::setVpePosition(int x, int y)
222 {
223 this->vpe_xpos = x;
224 this->vpe_ypos = y;
225
226 if (this->standin)
227 this->standin->setXYPosition(x,y);
228
229 }
230 //////////////////////////////////////////////////////////////////////////////
231 //
232 // Get the x,y positions on the VPE (visual program editor).
233 // If a standin exists for this node, then ask the StandIn for the position
234 // otherwise use the values that were read from the .net file.
235 //
getVpePosition(int * x,int * y)236 void Node::getVpePosition(int *x, int *y)
237 {
238 if (this->standin) {
239 this->standin->getXYPosition(x,y);
240 // Do this in case the standin goes away, but the node does not?!
241 this->vpe_xpos = *x;
242 this->vpe_ypos = *y;
243 } else {
244 *x = this->vpe_xpos;
245 *y = this->vpe_ypos;
246 }
247 }
248
249 //////////////////////////////////////////////////////////////////////////////
250 //
251 // Output the names of list of input parameters for this node.
252 // If on input have a value print its name as $module_$instance_$in_$input.
253 // If the input is taking it's value from another node's output, then print
254 // ${outputmodule}_${outputmodule_instance}_out_${outputmodule_output}.
255 //
256 // Note that the trailing newline ('\n') is not printed.
257 //
258 // Like this...
259 //
260 // Import_1_in_1,
261 // Import_1_in_2,
262 // Import_1_in_3,
263 // Import_1_in_4,
264 // Import_1_in_5,
265 // Import_1_in_6
266 //
inputParameterNamesString(const char * varprefix,const char * indent)267 char *Node::inputParameterNamesString(const char *varprefix, const char *indent)
268 {
269 const char *name ;
270 char *retstr;
271 int i, num_params;
272
273 name = this->getNameString();
274 ASSERT(name);
275
276 num_params = inputParameters.getSize();
277 if (num_params == 0)
278 return NULL;
279
280 //
281 // Get some buffers.
282 //
283 if (!indent)
284 indent = "";
285 #if !defined(STATIC_MACROS)
286 int paramlen =
287 (STRLEN(indent) + STRLEN(varprefix) + STRLEN(name) + 16) + 300;
288 char *buf = new char[ paramlen ];
289 retstr = new char[num_params * paramlen ];
290 #else
291 char buf[1024];
292 retstr = new char[num_params * 1024];
293 #endif
294
295 //
296 // Print them
297 //
298 i = 1;
299 *retstr = '\0';
300 char *pstr = retstr;
301 for (i=1 ; i<=num_params ; i++, pstr+=STRLEN(pstr)) {
302 Parameter *p;
303 if ((p = this->getInputParameter(i))->isConnected())
304 {
305 int param;
306 Ark *a = p->getArk(1);
307 ASSERT(a);
308 Node *onode = a->getSourceNode(param);
309 ASSERT(onode);
310 sprintf(buf, "%s%s%s_%d_out_%d", indent,varprefix,
311 onode->getNameString(),
312 onode->getInstanceNumber(), param);
313 }
314 else
315 {
316 #if defined(STATIC_MACROS)
317 //
318 // If this is a macro then print the input value now, otherwise
319 // reference a global variable and print that value later.
320 //
321 if (this->network->isMacro())
322 sprintf(buf,"%s%s",indent,this->getInputValueString(i));
323 else
324 #endif
325 sprintf(buf,"%s%s%s_%d_in_%d", indent, varprefix,
326 name, this->instanceNumber, i);
327 }
328 if (i != num_params)
329 strcat(buf,",\n");
330 strcat(pstr,buf);
331 }
332
333 #if !defined(STATIC_MACROS)
334 delete buf;
335 #endif
336 return retstr;
337 }
338 //
339 // Get the name of the input as specified in the network
340 // (i.e. main_Display_1_in_3)
341 // If buf is not provided the returned string must be deleted
342 // by the caller.
343 //
getNetworkIONameString(int index,boolean input,char * buffer)344 char *Node::getNetworkIONameString( int index, boolean input, char *buffer)
345 {
346 char *buf;
347 const char *prefix = this->network->getPrefix();
348
349 #if defined(STATIC_MACROS)
350 //
351 // Macros do not use input parameter names because we always send
352 // the value of the input in the tools argument list.
353 //
354 // FIXME: now that I've removed the assert, are static macros endangered?
355 //ASSERT(!this->network->isMacro());
356 #endif
357 if (buffer)
358 buf = buffer;
359 else
360 buf = new char[128];
361
362 sprintf(buf,"%s%s_%d_%s_%d",
363 prefix,
364 this->getNameString(),
365 this->getInstanceNumber(),
366 (input ? "in" : "out"),
367 index);
368 return buf;
369 }
370
371 //////////////////////////////////////////////////////////////////////////////
372 //
373 // Output the names of the list of output parameters for this node.
374 // Note that the trailing newline ('\n') is not printed.
375 // It prints out the cache attribute for each output if it differs from
376 // that of the node.
377 //
378 // Like this...
379 //
380 // AutoColor_2_out_1[cache: 0],
381 // AutoColor_2_out_2
382 //
383 //
outputParameterNamesString(const char * varprefix)384 char *Node::outputParameterNamesString(const char *varprefix)
385 {
386 if (this->getOutputCount() == 0)
387 return NULL;
388
389 const char *name ;
390 char *buf, *retstr, *newprefix;
391 int i, paramlen, num_params;
392
393 name = this->getNameString();
394 ASSERT(name);
395
396 /*io = "out";*/
397 num_params = outputParameters.getSize();
398
399 //
400 // Get some buffers.
401 //
402 paramlen = (STRLEN(varprefix) + STRLEN(name) + 16) + 300 + 10;
403 buf = new char[ paramlen ];
404 newprefix = new char[paramlen + STRLEN(varprefix)];
405 retstr = new char[num_params * paramlen ];
406 sprintf(newprefix,"%s%s_%d_out_",varprefix,name,this->instanceNumber);
407
408 //
409 // Print the node name
410 //
411 i = 1;
412 *retstr = '\0';
413 char *pstr = retstr;
414 for (i=1 ; i<=num_params ; i++, pstr+=STRLEN(pstr)) {
415 Parameter *p = this->getOutputParameter(i);
416 ASSERT(p);
417 if (this->getNodeCacheability() == p->getCacheability())
418 sprintf(buf,"%s%d%s", newprefix, i, (i==num_params ? "" : ",\n"));
419 else
420 sprintf(buf,"%s%d[cache: %d]%s",
421 newprefix, i, p->getCacheability(),
422 (i==num_params ? "" : ",\n"));
423 strcat(pstr,buf);
424 }
425
426 delete buf;
427 delete newprefix;
428 return retstr;
429 }
430
431
432 //////////////////////////////////////////////////////////////////////////////
433 //
434 // Save any other files that relevant to this mode
435 // The name passed in is file name used to save the network (without the
436 // .net extension).
437 // By default, nodes do not have auxiliary files.
438 //
auxPrintNodeFile()439 boolean Node::auxPrintNodeFile()
440 {
441 return TRUE;
442 }
443
444 //////////////////////////////////////////////////////////////////////////////
445 //
446 // Print the '|'d section below for this node into what will be a .net file.
447 //
448 // FIXME: Do we need to be able to print to a string, can we just get
449 // by with a FILE?
450 //
451 /*
452 * //
453 * // node Import[1]: x = 48, y = 14, inputs = 6, label = Import
454 || // input[1]: type = 64, value = "network8.dx"
455 * //
456 */
printIOComment(FILE * f,boolean input,int i,const char * indent,boolean valueOnly)457 boolean Node::printIOComment(FILE *f, boolean input, int i,
458 const char *indent, boolean valueOnly)
459 {
460 int status = 1;
461 if (!indent)
462 indent = "";
463
464 if (input)
465 {
466 Parameter *p = this->getInputParameter(i);
467 // Only print it if it is not receiving input from another output
468 // (i.e. it does not have an arc)
469 //
470 // This ifdef is so that we save parameter values even if they have a
471 // connected arc. This is useful for parameters whose arc-fed values
472 // are echoed back to the UI. This includes the data-driven interactors
473 // and some of Image's parameters. dawood 8/22/95
474 //
475 #if 00
476 if (!p->isConnected() && p->hasValue()) {
477 if (valueOnly) {
478 status = fprintf(f,
479 "%s// input[%d]: defaulting = %d, value = %s\n",
480 indent,
481 i,
482 p->isDefaulting() ? 1 : 0,
483 p->getSetValueString());
484 } else {
485 status = fprintf(f,
486 "%s// input[%d]: defaulting = %d, visible = %d,"
487 " type = %d, value = %s\n",
488 indent,
489 i,
490 (p->isDefaulting() ? 1 : 0),
491 (p->isVisible()? 1 : 0),
492 p->getValueType(),
493 p->getSetValueString());
494 }
495 } else if (!valueOnly && p->isViewable() &&
496 (p->isVisibleByDefault() != p->isVisible()))
497 #else
498 if (p->hasValue()) {
499 if (valueOnly) {
500 status = fprintf(f,
501 "%s// input[%d]: defaulting = %d, value = %s\n",
502 indent,
503 i,
504 (p->isDefaulting() || p->isConnected() ? 1 : 0),
505 p->getSetValueString());
506 } else {
507 // When a parameter is connected, print the value as
508 // defaulting, so that when we read it back in, we do a
509 // setInputSetValue() instead of a setInputValue()
510 status = fprintf(f,
511 "%s// input[%d]: defaulting = %d, visible = %d,"
512 " type = %d, value = %s\n",
513 indent,
514 i,
515 (p->isDefaulting() || p->isConnected() ? 1 : 0),
516 (p->isVisible()? 1 : 0),
517 (int) p->getValueType(),
518 p->getSetValueString());
519 }
520 } else if (!valueOnly && p->isViewable() &&
521 (p->isVisibleByDefault() != p->isVisible()))
522 #endif
523 status = fprintf(f,
524 "%s// input[%d]: visible = %d\n",
525 indent,
526 i, (p->isVisible() ? 1 : 0));
527 }
528 else
529 {
530 Parameter *p = this->getOutputParameter(i);
531 // Only print it if it is sending a value to an input
532 // (i.e. it has an arc)
533 if (p->hasValue()) {
534 if (valueOnly) {
535 status = fprintf(f,
536 "%s// output[%d]: defaulting = %d, value = %s\n",
537 indent,
538 i,
539 p->isDefaulting() ? 1 : 0,
540 p->getSetValueString());
541 } else {
542 status = fprintf(f,
543 "%s// output[%d]: visible = %d, type = %d, value = %s\n",
544 indent,
545 i,
546 (p->isVisible()? 1 : 0),
547 (int) p->getValueType(),
548 p->getSetValueString());
549 }
550 } else if (!valueOnly && p->isViewable() &&
551 (p->isVisibleByDefault() != p->isVisible()))
552 status = fprintf(f,
553 "%s// output[%d]: visible = %d\n",
554 indent,
555 i,
556 (p->isVisible() ? 1 : 0));
557 }
558
559 return status > 0;
560 }
561
562 //////////////////////////////////////////////////////////////////////////////
563 //
564 // Print the '|'d section below for this node into what will be a .net file.
565 //
566 // FIXME: for now we don't do the comments (PrintType).
567 // FIXME: Do we need to be able to print to a string, can we just get
568 // by with a FILE?
569 //
570 /*
571 || //
572 || // node Import[1]: x = 48, y = 14, inputs = 6, label = Import
573 || // input[1]: type = 64, value = "network8.dx"
574 || //
575 */
netPrintCommentHeader(FILE * f)576 boolean Node::netPrintCommentHeader(FILE *f)
577 {
578 int i, status, x, y, num;
579 const char *name;
580
581 name = this->getNameString();
582 ASSERT(name);
583
584 status = fprintf(f,"%s// \n",__indent);
585 if (status < 0)
586 return FALSE;
587
588 //
589 // Print the node name comment
590 //
591 this->getVpePosition(&x, &y);
592 if (this->getOutputCount() != this->getDefinition()->getOutputCount())
593 status = fprintf(f,"%s// node %s[%d]: x = %d, y = %d, inputs = %d, "
594 "outputs = %d, label = %s\n",
595 __indent,
596 this->getNameString(),
597 this->getInstanceNumber(), x, y,
598 this->getInputCount(),
599 this->getOutputCount(),
600 this->getLabelString());
601 else
602 status = fprintf(f,"%s// node %s[%d]: x = %d, y = %d, inputs = %d, "
603 "label = %s\n",
604 __indent,
605 this->getNameString(),
606 this->getInstanceNumber(), x, y,
607 this->getInputCount(),
608 this->getLabelString());
609 if (status < 0)
610 return FALSE;
611
612 //
613 // Print the inputs that have values
614 //
615 num = this->getInputCount();
616 for (i=1 ; i<=num ; i++) {
617 if (!this->printIOComment(f, TRUE, i,__indent))
618 return FALSE;
619 }
620
621 //
622 // Print the outputs that have values
623 //
624 num = this->getOutputCount();
625 for (i=1 ; i<=num ; i++) {
626 if (!this->printIOComment(f, FALSE, i, __indent))
627 return FALSE;
628 }
629
630 #if WORKSPACE_PAGES
631 if (!this->printGroupComment(f))
632 #else
633 if(NOT this->netPrintPgrpComment(f))
634 #endif
635 return FALSE;
636
637 if (!this->netPrintAuxComment(f))
638 return FALSE;
639
640 status = fprintf(f,"%s//\n",__indent);
641 if (status < 0)
642 return FALSE;
643
644 return TRUE;
645
646 }
647
648 #if WORKSPACE_PAGES
649 #else
netPrintPgrpComment(FILE * f)650 boolean Node::netPrintPgrpComment(FILE *f)
651 {
652 const char *gname = this->getGroupName();
653 if(NOT gname)
654 return TRUE;
655
656 if(fprintf(f,"%s// process group: %s\n",__indent, gname) < 0)
657 return FALSE;
658
659 return TRUE;
660 }
661 #endif
662
663 //////////////////////////////////////////////////////////////////////////////
664 // Print the '|'d section below for this node. If PrintType is set
665 // then also print the '||'d section. In the example below 'prefix'
666 // contains the 2 leading spaces.
667 //
668 //
669 /*
670 || //
671 || // node Import[1]: x = 48, y = 14, inputs = 6, label = Import
672 || // input[1]: type = 64, value = "network8.dx"
673 || //
674 | Import_1_out_1 =
675 | Import(
676 | Import_1_in_1,
677 | Import_1_in_2,
678 | Import_1_in_3,
679 | Import_1_in_4,
680 | Import_1_in_5,
681 | Import_1_in_6
682 | ) [instance: 1, cache: 1, pgroup: "pg1"];
683 */
netNodeString(const char * prefix)684 char *Node::netNodeString(const char *prefix)
685 {
686 int buflen;
687 const char *name;
688 char *outputs, *inputs, *module, *attributes, *s;
689
690 //
691 // Get the name of the module that is used to do the work for this node.
692 //
693 name = this->getExecModuleNameString();
694 ASSERT(name);
695
696 //
697 // Print the outputs for this node
698 //
699 outputs = this->outputParameterNamesString(prefix);
700
701
702 //
703 // Print the Name of this node as 'Name(\n'
704 //
705 module = new char[STRLEN(__indent) + STRLEN(name) + 16];
706 sprintf(module,"%s%s(",__indent,name);
707
708 //
709 // Print node inputs
710 //
711 inputs = this->inputParameterNamesString(prefix,__indent);
712
713 #if WORKSPACE_PAGES
714 const char *gname = this->getGroupName(theSymbolManager->getSymbol(PROCESS_GROUP));
715 #else
716 const char *gname = this->getGroupName();
717 #endif
718 if(NOT gname)
719 {
720 char *fmt = "%s) [instance: %d, cache: %d];";
721 attributes = new char[STRLEN(__indent) + STRLEN(fmt) + 32];
722 sprintf(attributes, fmt, __indent,
723 this->instanceNumber,
724 this->getNodeCacheability());
725
726 }
727 else
728 {
729 char *fmt = "%s) [instance: %d, cache: %d, group: \"%s\"];";
730 attributes = new char[STRLEN(__indent) + STRLEN(fmt) +
731 STRLEN(gname) + 32];
732 sprintf(attributes, fmt, __indent,
733 this->instanceNumber,
734 this->getNodeCacheability(),
735 gname);
736 }
737
738 buflen = STRLEN(module) + STRLEN(outputs) +
739 STRLEN(inputs) + STRLEN(attributes);
740 s = new char[buflen+40];
741 if (this->getOutputCount() == 0)
742 {
743 sprintf(s,"%s\n%s\n%s\n",
744 module,(inputs ? inputs : "") ,attributes);
745 }
746 else
747 {
748 sprintf(s,"%s = \n%s\n%s\n%s\n",
749 (outputs ? outputs : ""),
750 module,
751 (inputs ? inputs : ""),
752 attributes);
753 }
754
755 if (outputs) delete outputs;
756 delete module;
757 if (inputs) delete inputs;
758 delete attributes;
759
760 return s;
761 }
762 //
763 // Do any work that must be done before sending the macro/network
764 // to the server.
765 // Be default, Nodes do not have any work that needs to be done for sending.
766 //
prepareToSendNode()767 void Node::prepareToSendNode()
768 {
769 }
prepareToSendValue(int index,Parameter * p)770 void Node::prepareToSendValue(int index, Parameter *p)
771 {
772 }
773
netPrintNode(FILE * f,PrintType dest,const char * prefix,PacketIFCallback callback,void * clientdata)774 boolean Node::netPrintNode(FILE *f, PrintType dest, const char *prefix,
775 PacketIFCallback callback, void *clientdata)
776 {
777 char *s;
778 DXPacketIF *pif = theDXApplication->getPacketIF();
779 boolean r = TRUE;
780
781 if (dest == PrintFile || dest == PrintCut || dest == PrintCPBuffer) {
782 if (!this->netPrintCommentHeader(f))
783 return FALSE;
784 } else if (pif) { // We have a connection to the executive/server
785 //
786 // If this node has a message protocol with the executive, then
787 // update any state associated with the protocol.
788 //
789 if (this->hasModuleMessageProtocol())
790 this->updateModuleMessageProtocol(pif);
791 //
792 // Do any work that must be done before executing the macro/network
793 // that this node belongs to.
794 //
795 this->prepareToSendNode();
796 }
797
798 s = this->netNodeString(prefix);
799
800
801 if (dest == PrintFile || dest == PrintCut || dest == PrintCPBuffer) {
802 if (fputs(s, f) < 0)
803 r = FALSE;
804 if (callback != NUL(PacketIFCallback))
805 callback(clientdata,s);
806 } else {
807 ASSERT (dest == PrintExec);
808 pif->sendBytes(s);
809 }
810
811 delete s;
812
813 return r;
814
815 }
816
817 //
818 // Returns a string that is used to register this->ExecModuleMessageHandler()
819 // when this->hasModuleMessageProtocol() return TRUE.
820 // This version, returns an id that is unique to this instance of this node.
821 //
getModuleMessageIdString()822 const char *Node::getModuleMessageIdString()
823 {
824
825 if (!this->moduleMessageId) {
826 const char *name = this->getNameString();
827 int n = STRLEN(name) + 16;
828 this->moduleMessageId = new char[n];
829
830 sprintf(this->moduleMessageId,"%s_%d",name, this->getInstanceNumber());
831 }
832
833 return (const char*)this->moduleMessageId;
834 }
835
836 //
837 // Update the state of message handling for a module/UI message.
838 // This is called only when we send a Node's module call to the executive
839 // and the node has a module messaging protocol as defined by
840 // this->hasModuleMessageProtocol().
841 //
updateModuleMessageProtocol(DXPacketIF * pif)842 void Node::updateModuleMessageProtocol(DXPacketIF *pif)
843 {
844 const char *id = this->getModuleMessageIdString();
845
846 if (this->expectingModuleMessage()) {
847 //
848 // Install a callback to handle messages from the module
849 //
850 pif->setHandler(DXPacketIF::INFORMATION,
851 Node::ExecModuleMessageHandler,
852 (void*)this, id);
853 } else {
854 //
855 // Remove the handler in case it was previously installed.
856 //
857 pif->setHandler(DXPacketIF::INFORMATION,
858 NULL, (void*)this, id);
859 }
860 }
861 //
862 // Return TRUE/FALSE, indicating whether or not we support a message protocol
863 // between the executive module that runs for this node and the UI.
864 // Be default Nodes do not have message protocols.
865 //
hasModuleMessageProtocol()866 boolean Node::hasModuleMessageProtocol()
867 {
868 return FALSE;
869 }
870 //
871 // Return TRUE/FALSE, indicating whether or not we expect to receive
872 // a message from the UI when our module executes in the executive.
873 // Be default Nodes do not expect messages.
874 //
expectingModuleMessage()875 boolean Node::expectingModuleMessage()
876 {
877 return FALSE;
878 }
879 //
880 // This dispatches messages to this->execModuleMessageHandler().
881 // Messages are not noticed unless this handler is installed
882 // (in this->netPrintNode()).
883 //
ExecModuleMessageHandler(void * clientData,int id,void * line)884 void Node::ExecModuleMessageHandler(void *clientData, int id, void *line)
885 {
886 Node *node = (Node*)clientData;
887 node->execModuleMessageHandler(id,(const char*)line);
888 }
889 //
890 // Called when a message is received from the executive after
891 // this->ExecInfoMessageHandler() is registered to receive messages
892 // for this node. The format of the message coming back is defined
893 // by the derived class.
894 //
execModuleMessageHandler(int id,const char * line)895 void Node::execModuleMessageHandler(int id, const char *line)
896 {
897 fprintf(stderr,"Node: Saw unexpected module message, id %d...\n",id);
898 fprintf(stderr,"%s\n",line);
899 }
900
901
902 #if 0
903 //////////////////////////////////////////////////////////////////////////////
904 //
905 // Get name of a parameter and its value
906 // The format of the string is 'Parameter name = value;'.
907 // index is 1 based.
908 // It returns the string representing the assignment.
909 // The returned string must be deleted by the caller.
910 //
911 int Node::getParameterNameEqualsValue(Parameter *p,
912 const char *prefix, int index)
913 {
914 const char *pval;
915 char *p, *retstr, pname[512];
916
917 pname[0] = '\0';
918 this->strcatParameterNameLvalue(pname, p, prefix, index);
919 strcat(s, " = ");
920 if (p->isInput())
921 pval = this->getInputValueString(index);
922 else
923 pval = this->getOutputValueString(index);
924
925 retstr = new char[STRLEN(pname) + STRLEN(pval) + 2];
926
927 p = retstr;
928 strcpy(retstr,pname);
929 p += STRLEN(retstr);
930 strcat(p,v);
931 p += STRLEN(p);
932 strcat(p,";");
933
934 return retstr;
935 }
936 #endif
937
938 //////////////////////////////////////////////////////////////////////////////
939 //
940 // Concatenate the name of a parameter but not its value to the given string.
941 // index is 1 based. it returns the ammount of stuff added to s
942 //
strcatParameterNameLvalue(char * s,Parameter * p,const char * prefix,int index)943 int Node::strcatParameterNameLvalue(char *s, Parameter *p,
944 const char *prefix, int index)
945 {
946
947 const char *ioname;
948
949 if (p->isInput())
950 ioname = "in";
951 else
952 ioname = "out";
953
954 ASSERT(s);
955 s += STRLEN(s);
956 return SPRINTF(s,"%s%s_%d_%s_%d",
957 prefix, this->getNameString(),this->getInstanceNumber(),
958 ioname, index);
959 }
strcatParameterValueString(char * s,Parameter * p,int index)960 int Node::strcatParameterValueString(char *s, Parameter *p, int index)
961 {
962 const char *v = p->getValueString();
963
964 if (s)
965 strcat(s, v);
966 return STRLEN(v);
967 }
968 ///////////////////////////////////////////////////////////////////////////////
969 //
970 // Print the value of the index'th parameter if it contains a value
971 // (i.e. it's arc list is empty). Returns NULL if no string is to be printed.
972 // index is 1 based.
973 // The returned string must be deleted by the caller.
974 //
ioValueString(List * io,int index,const char * prefix)975 char *Node::ioValueString(List *io, int index, const char *prefix)
976 {
977 char *retstr = NUL(char*);
978 Parameter *p;
979
980 ASSERT(index >= 1);
981
982 p = (Parameter*)io->getElement(index);
983 ASSERT(p);
984
985 if (p->isNeededValue()) {
986 const char *pval;
987 int pname_size;
988 char *c, pname[512];
989
990 pname[0] = '\0';
991 pname_size = this->strcatParameterNameLvalue(pname, p, prefix, index);
992 strcat(pname, " = ");
993 pname_size += 3;
994 if (p->isInput())
995 pval = this->getInputValueString(index);
996 else
997 pval = this->getOutputValueString(index);
998
999 retstr = new char[pname_size + STRLEN(pval) + 2];
1000
1001 c = retstr;
1002 strcpy(retstr,pname);
1003 c += STRLEN(retstr);
1004 strcat(c,pval);
1005 c += STRLEN(c);
1006 strcat(c,";");
1007
1008 }
1009 return retstr;
1010 }
1011
1012 ///////////////////////////////////////////////////////////////////////////////
1013 //
1014 // Print the value of the input and output parameters if they contain a value
1015 // (i.e. it's arc list is empty).
1016 // index is 1 based.
1017 // Returns NULL if no values need to be printed, otherwise a string containing
1018 // parameter value pairs.
1019 //
valuesString(const char * prefix)1020 char *Node::valuesString(const char *prefix)
1021 {
1022
1023 char *s=NUL(char*), *buf;
1024 int size, cnt, i;
1025 boolean first = TRUE;;
1026
1027 #if defined(STATIC_MACROS)
1028 //
1029 // Macros do not use global variables as inputs so we do not
1030 // need to send the input value assignments.
1031 //
1032 if (!this->network->isMacro()) {
1033 #endif
1034 //
1035 // Print the input values
1036 //
1037 cnt = this->getInputCount();
1038 for (i=1 ; i<=cnt ; i++) {
1039 if ( (buf = this->inputValueString(i,prefix)) )
1040 {
1041 if (s)
1042 first = FALSE;
1043 size = STRLEN(buf) + STRLEN(s) + 2;
1044 s = (char*)REALLOC(s,size);
1045 if (first)
1046 s = strcpy(s, buf);
1047 else
1048 s = strcat(s,buf);
1049 strcat(s,"\n");
1050 delete buf;
1051 }
1052 }
1053 #if defined(STATIC_MACROS)
1054 }
1055 #endif
1056
1057 //
1058 // Print the output values
1059 //
1060 cnt = this->getOutputCount();
1061 for (i=1 ; i<=cnt ; i++) {
1062 if ( (buf = this->outputValueString(i,prefix)) )
1063 {
1064 if (s)
1065 first = FALSE;
1066 size = STRLEN(buf) + STRLEN(s) + 2;
1067 s = (char*)REALLOC(s,size);
1068 if (first)
1069 s = strcpy(s, buf);
1070 else
1071 s = strcat(s,buf);
1072 strcat(s,"\n");
1073 delete buf;
1074 }
1075 }
1076
1077 return s;
1078
1079 }
1080
printValues(FILE * f,const char * prefix,PrintType dest)1081 boolean Node::printValues(FILE *f, const char *prefix, PrintType dest)
1082 {
1083 char *s;
1084 boolean r = TRUE;
1085
1086 s = this->valuesString(prefix);
1087 if (s) {
1088 if (dest == PrintFile || dest == PrintCut || dest == PrintCPBuffer) {
1089 if (fputs(s, f) < 0)
1090 r = FALSE;
1091 } else {
1092 ASSERT (dest == PrintExec);
1093 DXPacketIF* pif = theDXApplication->getPacketIF();
1094 pif->sendBytes(s);
1095 }
1096
1097 delete s;
1098 }
1099 return r;
1100 }
1101
1102 ///////////////////////////////////////////////////////////////////////////////
1103 //
1104 // Send all values that are in one expression.
sendValues(boolean ignoreDirty)1105 boolean Node::sendValues(boolean ignoreDirty)
1106 {
1107 DXPacketIF *pif = theDXApplication->getPacketIF();
1108
1109 if (!pif)
1110 return TRUE;
1111
1112 const char *prefix = this->network->getPrefix();
1113 int i, cnt;
1114 char *names=NULL;
1115 char *values=NULL;
1116 int nameLen = 0;
1117 int valueLen = 0;
1118
1119 //
1120 // Print the dirty inputs
1121 //
1122 cnt = this->getInputCount();
1123 ListIterator li(this->inputParameters);
1124 Parameter *p;
1125 #if defined(STATIC_MACROS)
1126 //
1127 // Macros do not use global variables as inputs so we do not
1128 // need to send the input value assignments.
1129 //
1130 if (!this->network->isMacro()) {
1131 #endif
1132 for (i=1 ; i<=cnt && NULL != (p = (Parameter *)li.getNext()); i++)
1133 {
1134 if (p->isNeededValue(ignoreDirty))
1135 {
1136 //
1137 // Do any work that is necessary before sending the value .
1138 //
1139 this->prepareToSendValue(i, p);
1140 if (nameLen == 0)
1141 {
1142 names = (char *)MALLOC(100);
1143 *names = '\0';
1144 nameLen = this->strcatParameterNameLvalue(names, p, prefix, i);
1145
1146 int l = this->strcatParameterValueString(NULL, p, i);
1147 values = (char *)MALLOC(l+10);
1148 *values = '\0';
1149 valueLen = this->strcatParameterValueString(values, p, i);
1150 }
1151 else
1152 {
1153 names = (char *)REALLOC((void*)names, nameLen + 100 + 2);
1154 strcat(names, ", ");
1155 nameLen += 2 + this->strcatParameterNameLvalue(names, p, prefix, i);
1156
1157 int l = this->strcatParameterValueString(NULL, p, i);
1158 values = (char *)REALLOC((void*)values, valueLen + l+10);
1159 strcat(values, ", ");
1160 valueLen += 2 + this->strcatParameterValueString(values, p, i);
1161 }
1162 p->clearDirty();
1163 }
1164 }
1165 #if defined(STATIC_MACROS)
1166 }
1167 #endif
1168
1169 //
1170 // Print the outputs that have values
1171 //
1172 cnt = this->getOutputCount();
1173 li.setList(this->outputParameters);
1174 for (i=1 ; i<=cnt && NULL != (p = (Parameter *)li.getNext()); i++)
1175 {
1176 if (p->isNeededValue(ignoreDirty))
1177 {
1178 //
1179 // Do any work that is necessary before sending the value .
1180 //
1181 this->prepareToSendValue(i, p);
1182
1183 if (nameLen == 0)
1184 {
1185 names = (char *)MALLOC(100);
1186 *names = '\0';
1187 nameLen = this->strcatParameterNameLvalue(names, p, prefix, i);
1188
1189 int l = this->strcatParameterValueString(NULL, p, i);
1190 values = (char *)MALLOC(l+10);
1191 *values = '\0';
1192 valueLen = this->strcatParameterValueString(values, p, i);
1193 }
1194 else
1195 {
1196 names = (char *)REALLOC((void*)names, nameLen + 100 + 2);
1197 strcat(names, ", ");
1198 nameLen += 2 + this->strcatParameterNameLvalue(names, p, prefix, i);
1199
1200 int l = this->strcatParameterValueString(NULL, p, i);
1201 values = (char *)REALLOC((void*)values, valueLen + l+10);
1202 strcat(values, ", ");
1203 valueLen += 2 + this->strcatParameterValueString(values, p, i);
1204 }
1205 p->clearDirty();
1206 }
1207 }
1208
1209 if (nameLen > 0)
1210 {
1211 char *s = new char[nameLen + 3 + valueLen + 2];
1212 strcpy(s, names);
1213 strcat(s, " = ");
1214 strcat(s, values);
1215 strcat(s, ";");
1216 pif->send(DXPacketIF::FOREGROUND, s);
1217 delete s;
1218 FREE((void*)names);
1219 FREE((void*)values);
1220 }
1221
1222 return TRUE;
1223 }
1224
1225
1226 //////////////////////////////////////////////////////////////////////////////
1227 //
1228 // Parse the .net file comment section for this node.
1229 //
1230 // Set the instance number, the x,y position, and its inputs.
1231 //
netParseComment(const char * comment,const char * filename,int lineno)1232 boolean Node::netParseComment(const char* comment,
1233 const char* filename, int lineno)
1234 {
1235 ASSERT(comment);
1236
1237 /*
1238 * Ignore comments that we do not recognize
1239 */
1240 return this->netParseNodeComment(comment, filename, lineno) ||
1241 this->parseIOComment(TRUE, comment, filename, lineno) ||
1242 this->parseIOComment(FALSE, comment, filename, lineno) ||
1243 #if WORKSPACE_PAGES
1244 this->parseGroupComment(comment, filename, lineno) ||
1245 #else
1246 this->netParsePgrpComment(comment, filename, lineno) ||
1247 #endif
1248 this->netParseAuxComment(comment,filename,lineno);
1249 }
1250
1251 //
1252 // Empty virtual method to parse comments (if any) that come after the
1253 // 'node', 'input', 'ouput' and 'process group' comments in the .net file.
1254 //
netParseAuxComment(const char * comment,const char * filename,int lineno)1255 boolean Node::netParseAuxComment(const char* comment,
1256 const char* filename, int lineno)
1257 {
1258 return FALSE;
1259 }
1260 //
1261 // Empty virtual method to be overridden by subclasses that prints out
1262 // node specific comments after the standard comments in the .net file.
1263 //
netPrintAuxComment(FILE * f)1264 boolean Node::netPrintAuxComment(FILE *f)
1265 {
1266 return TRUE;
1267 }
1268
1269 #if WORKSPACE_PAGES
1270 #else
netParsePgrpComment(const char * comment,const char * filename,int lineno)1271 boolean Node::netParsePgrpComment(const char* comment,
1272 const char* filename, int lineno)
1273 {
1274 char *name;
1275
1276 if (!EqualSubstring(" process group:",comment,15))
1277 return FALSE;
1278
1279 name = strchr(comment, ':');
1280 name++;
1281 SkipWhiteSpace(name);
1282
1283 if(NOT name) return FALSE;
1284
1285 this->addToGroup(name);
1286 return TRUE;
1287 }
1288 #endif
1289
1290
1291 //
1292 // Parse an 'input[i]' or 'output[i]' .net file comment.
1293 //
parseIOComment(boolean input,const char * comment,const char * filename,int lineno,boolean valueOnly)1294 boolean Node::parseIOComment(boolean input, const char* comment,
1295 const char* filename, int lineno, boolean valueOnly)
1296 {
1297 int defaulting = 0, allowed_params, items_parsed, ionum, r, type_tmp;
1298 int visible = TRUE;
1299 Type type = DXType::UndefinedType;
1300 char *value, *ioname;
1301 boolean parse_error = FALSE;
1302
1303 ASSERT(comment);
1304
1305 if (input) {
1306 if (!EqualSubstring(" input[",comment,7))
1307 return FALSE;
1308
1309 if (valueOnly) {
1310 if (sscanf(comment, " input[%d]: defaulting = %d",
1311 &ionum, &defaulting) != 2)
1312 parse_error = TRUE;
1313 type = DXType::UndefinedType;
1314 } else {
1315 items_parsed = sscanf(comment,
1316 " input[%d]: defaulting = %d, visible = %d, type = %d",
1317 &ionum, &defaulting, &visible, &type_tmp);
1318 type = (Type) type_tmp;
1319
1320 if (items_parsed != 4) {
1321 // Invisibility added 3/30/93
1322 items_parsed = sscanf(comment, " input[%d]: visible = %d",
1323 &ionum, &visible);
1324 if (items_parsed != 2) {
1325 // Backwards compatibility added 3/25/93
1326 items_parsed = sscanf(comment, " input[%d]: type = %d",
1327 &ionum, &type_tmp);
1328 type = (Type) type_tmp;
1329
1330 if (items_parsed != 2) {
1331 items_parsed = sscanf(comment,
1332 " input[%d]: defaulting = %d, type = %d",
1333 &ionum, &defaulting, &type_tmp);
1334 type = (Type) type_tmp;
1335 if (items_parsed != 3)
1336 parse_error = TRUE;
1337 }
1338 }
1339 else
1340 {
1341 defaulting = 1;
1342 }
1343 }
1344 }
1345 ioname = "input";
1346 allowed_params = this->getInputCount();
1347 } else { // An output
1348
1349 if (!EqualSubstring(" output[",comment,8))
1350 return FALSE;
1351
1352 if (valueOnly) {
1353 if (sscanf(comment, " output[%d]: defaulting = %d",
1354 &ionum, &defaulting) != 2)
1355 parse_error = TRUE;
1356 type = DXType::UndefinedType;
1357 } else {
1358 // Invisibility added 3/30/93
1359 items_parsed = sscanf(comment,
1360 " output[%d]: visible = %d, type = %d",
1361 &ionum, &visible, &type_tmp);
1362 type = (Type) type_tmp;
1363
1364 if (items_parsed != 3) {
1365
1366 items_parsed = sscanf(comment, " output[%d]: type = %d",
1367 &ionum, &type_tmp);
1368 type = (Type) type_tmp;
1369
1370 if (items_parsed != 2) {
1371 items_parsed = sscanf(comment, " output[%d]: visible = %d",
1372 &ionum, &visible);
1373 if (items_parsed != 2)
1374 parse_error = TRUE;
1375 }
1376 }
1377 }
1378 ioname = "output";
1379 allowed_params = this->getOutputCount();
1380 }
1381
1382 if (parse_error)
1383 {
1384 ErrorMessage ("Can't parse %s comment file %s line %d",
1385 ioname, filename, lineno);
1386 return TRUE;
1387 }
1388 /*
1389 * If the input parameter is out of bounds, then something is wrong...
1390 */
1391 if (ionum > allowed_params)
1392 {
1393 ErrorMessage ("Bad %s number (%d) file %s line %d",
1394 input? "input": "output", ionum, filename, lineno);
1395 return TRUE;
1396 }
1397
1398
1399
1400 /*
1401 * If parsed ok and node exists, convert value.
1402 */
1403 value = (char *) strstr(comment, "value =");
1404 if (value != NUL(char*))
1405 {
1406 value = strchr(value,'=') + 2;
1407
1408 //
1409 // When we went to the C++ ui, the bit masks for types changed.
1410 // If we're reading a pre-UI++ network then convert the types.
1411 // valueOnly was added in version 3.
1412 //
1413 if (this->getNetwork()->getNetMajorVersion() <= 1)
1414 type = DXType::ConvertVersionType(type);
1415
1416
1417 if (input) {
1418 if (value[0] == '(' && value[STRLEN(value)-1] == ')') {
1419 // Skip descriptive settings
1420 defaulting = 1;
1421 r = DXType::ObjectType;
1422 #if 11
1423 } else if (defaulting) {
1424 #else
1425 //
1426 // This check for NULL shouldn't really be necessary, except
1427 // that there is a bug somewhere in ConfigurationDialog
1428 // that seems too risky to fix just before 3.1
1429 // Bug is as follows,
1430 // 1) Place Echo
1431 // 2) Open CDB and type NULL into first param
1432 // 3) Save net
1433 // 4) Read in net.
1434 // 5) Execute and nothing goes in MsgWin, which is correct
1435 // 6) Open CDB, note non-null value in CDB and execute and get
1436 // a different result.
1437 //
1438 } else if (defaulting || EqualString(value,"NULL")) {
1439 #endif
1440 r = this->setInputSetValue(ionum, value, type, FALSE);
1441 if (r == DXType::UndefinedType &&
1442 type != DXType::UndefinedType)
1443 r = this->setInputSetValue(ionum, value,
1444 DXType::UndefinedType, FALSE);
1445 } else {
1446 r = this->setInputValue(ionum, value, type, FALSE);
1447 if (r == DXType::UndefinedType &&
1448 type != DXType::UndefinedType)
1449 r = this->setInputValue(ionum, value,
1450 DXType::UndefinedType, FALSE);
1451 }
1452 } else {
1453 r = this->setOutputValue(ionum, value, type, FALSE);
1454 if (r == DXType::UndefinedType &&
1455 type != DXType::UndefinedType)
1456 r = this->setOutputValue(ionum, value, DXType::UndefinedType,
1457 FALSE);
1458 }
1459
1460 if (r == DXType::UndefinedType) {
1461 ErrorMessage(
1462 "Encountered an erroneous input value (file %s, line %d)",
1463 filename, lineno);
1464 return TRUE;
1465 }
1466 }
1467
1468 if (!valueOnly) {
1469 if (input) {
1470 this->setInputVisibility(ionum, (boolean)visible);
1471 } else { // Outputs always use the value found in the file
1472 this->useAssignedOutputValue(ionum, FALSE);
1473 this->setOutputVisibility(ionum, (boolean)visible);
1474 }
1475 }
1476
1477
1478 return TRUE;
1479
1480 }
1481
1482
netParseNodeComment(const char * comment,const char * filename,int lineno)1483 boolean Node::netParseNodeComment(const char* comment,
1484 const char* filename, int lineno)
1485 {
1486 int items_parsed;
1487 NodeDefinition *nd;
1488 int instance;
1489 int x;
1490 int y;
1491 int n_inputs;
1492 int n_outputs;
1493 int i;
1494 char node_name[1024];
1495 char labelstr[1024];
1496
1497 /*
1498 * Parse the comment.
1499 */
1500
1501 if (!EqualSubstring(" node ",comment,6))
1502 return FALSE;
1503
1504 items_parsed = // Version DX/6000 2.0 style comments
1505 sscanf
1506 (comment,
1507 " node %[^[][%d]: x = %d, y = %d, inputs = %d, outputs = %d, label = %[^\n]",
1508 node_name,
1509 &instance,
1510 &x,
1511 &y,
1512 &n_inputs,
1513 &n_outputs,
1514 labelstr);
1515
1516 if (items_parsed != 7) { // Try pre Version DX/6000 2.0 style comments
1517 items_parsed = // Version DX/6000 1.2 style comments
1518 sscanf
1519 (comment,
1520 " node %[^[][%d]: x = %d, y = %d, inputs = %d, label = %[^\n]",
1521 node_name,
1522 &instance,
1523 &x,
1524 &y,
1525 &n_inputs,
1526 labelstr);
1527
1528 if (items_parsed != 6) {// Try pre Version DX/6000 1.2 style comments
1529 items_parsed =
1530 sscanf(comment,
1531 " node %[^[][%d]: x = %d, y = %d, label = %[^\n]",
1532 node_name,
1533 &instance,
1534 &x,
1535 &y,
1536 labelstr);
1537 if (items_parsed != 5)
1538 {
1539 // FIXME : should be ModelessErrorMessageDialog
1540 #ifdef NOT_YET
1541 ErrorMessage
1542 ("#10001", "node", filename, lineno);
1543 _error_occurred = TRUE;
1544 #else
1545 ErrorMessage("Can not parse node comment at "
1546 "line %d in file %s",
1547 lineno, filename);
1548 #endif
1549 return TRUE;
1550 }
1551 }
1552 }
1553
1554 /*
1555 * Get definition for this node.
1556 */
1557 nd = (NodeDefinition*)
1558 theNodeDefinitionDictionary->findDefinition(node_name);
1559 if (!nd) {
1560 ErrorMessage("Undefined module %s at line %d in file %s",
1561 node_name, lineno, filename);
1562 return FALSE;
1563 }
1564
1565 // printf ("Number of inputs found = %d, number defined = %d\n",
1566 // n_inputs, this->definition->getInputCount());
1567 /*
1568 * If old syle comment, set number of inputs to that of module definition.
1569 */
1570 if (items_parsed < 7)
1571 n_outputs = this->getOutputCount();
1572 if (items_parsed < 6)
1573 n_inputs = this->getInputCount();
1574
1575 //
1576 // Set the label for this module.
1577 //
1578 this->setLabelString(labelstr);
1579
1580 /*
1581 * Set the instance number in the node.
1582 */
1583 this->setInstanceNumber(instance);
1584 this->setVpePosition(x,y);
1585
1586
1587 /*
1588 * Count the inputs, if not the default and the inputs are repeatable
1589 * then add some inputs.
1590 * If there are fewer inputs in the file, silently assume that
1591 * this is an old network.
1592 */
1593 if (n_inputs != this->getInputCount()) {
1594 if (this->isInputRepeatable()) {
1595 int delta_inputs = n_inputs - this->getInputCount();
1596 boolean adding = delta_inputs > 0;
1597 if (!adding)
1598 delta_inputs = -delta_inputs;
1599 int sets;
1600 if (delta_inputs % this->getInputRepeatCount() != 0) {
1601 ErrorMessage("Number of repeatable input parameters does not "
1602 "divide number of parameters for module %s",
1603 this->getNameString());
1604 return TRUE;
1605 }
1606 sets = delta_inputs/getInputRepeatCount();
1607 for (i=0 ; i<sets ; i++) {
1608 if (adding) {
1609 if (!this->addInputRepeats()) {
1610 ErrorMessage("Can't add repeated input parameters");
1611 return TRUE;
1612 }
1613 } else {
1614 if (!this->removeInputRepeats()) {
1615 ErrorMessage("Can't remove repeated input parameters");
1616 return TRUE;
1617 }
1618 }
1619 }
1620 }
1621 // else expect the network parser to recognize that the definition
1622 // has changed and indicate so.
1623 }
1624
1625 if (n_outputs != this->getOutputCount()) {
1626 if (this->isOutputRepeatable()) {
1627 int delta_outputs = n_outputs - this->getOutputCount();
1628 boolean adding = delta_outputs > 0;
1629 if (!adding)
1630 delta_outputs = -delta_outputs;
1631 int sets;
1632 if (delta_outputs % this->getOutputRepeatCount() != 0) {
1633 ErrorMessage("Number of repeatable output parameters does "
1634 "not divide number of parameters for module %s",
1635 this->getNameString());
1636 return TRUE;
1637 }
1638 sets = delta_outputs/getOutputRepeatCount();
1639 for (i=0 ; i<sets ; i++) {
1640 if (adding) {
1641 if (!this->addOutputRepeats()) {
1642 ErrorMessage("Can't add repeated output parameters");
1643 return TRUE;
1644 }
1645 } else {
1646 if (!this->removeOutputRepeats()) {
1647 ErrorMessage("Can't remove repeated output parameters");
1648 return TRUE;
1649 }
1650 }
1651 }
1652 }
1653 // else expect the network parser to recognize that the definition
1654 // has changed and indicate so.
1655 }
1656
1657
1658 /*
1659 * Increment the module instance count if the current
1660 * node instance count is higher.
1661 */
1662 if (instance > this->definition->getCurrentInstance())
1663 this->definition->setNextInstance(instance+1);
1664
1665 return TRUE;
1666
1667 }
1668
1669 //
1670 // Set the stored value.
1671 // If the parameter is not defaulting, this is
1672 // the same as setValue, but if it is defaulting, then we set the
1673 // value but leave the parameter clean and defaulting and ignore 'send'.
1674 //
1675 // Internal note: We handle our own notification (i.e. calls to
1676 // ioParameterStatusChanged()) so that multiple intermediate notifications
1677 // are avoided.
1678 //
setInputSetValue(int index,const char * value,Type type,boolean send)1679 Type Node::setInputSetValue(int index, const char *value,
1680 Type type,
1681 boolean send)
1682 {
1683
1684 boolean was_defaulting = this->isInputDefaulting(index);
1685
1686 //
1687 // If the parameter is already set (i.e. tab down) then just do
1688 // a normal set and return.
1689 //
1690 if (!was_defaulting)
1691 return this->setInputValue(index,value,type,send);
1692
1693 //
1694 // First set the value, don't send it and don't do notification (this
1695 // is the same as a normal set except we don't do notification).
1696 //
1697 type = this->setIOValue(&this->inputParameters, index, value,
1698 type, FALSE, FALSE);
1699
1700 if (type != DXType::UndefinedType) {
1701 //
1702 // Second, set the parameter back to defaulting, but again, don't
1703 // do notification (again, this is the same as a normal setting of
1704 // a parameter to defaulting, but no notification).
1705 //
1706 this->setIODefaultingStatus(index, TRUE, TRUE, FALSE, FALSE);
1707
1708 //
1709 // Third, clear the parameter's dirty bit as we are only changing
1710 // the set value (i.e. not the value the exec knows about).
1711 //
1712 this->clearInputDirty(index);
1713
1714 //
1715 // Now do the notification that we've jumped through hoops to
1716 // get right!
1717 //
1718 this->notifyIoParameterStatusChanged(TRUE, index,
1719 Node::ParameterSetValueChanged);
1720 }
1721
1722 return type;
1723
1724 }
1725
1726
1727 //
1728 // Mark the given parameter as clean.
1729 //
setIODirty(List * io,int index,boolean dirty)1730 void Node::setIODirty(List *io, int index, boolean dirty)
1731 {
1732 ASSERT(index >= 1);
1733 Parameter *p = (Parameter*)io->getElement(index);
1734 ASSERT(p);
1735 if (dirty)
1736 p->setDirty();
1737 else
1738 p->clearDirty();
1739 #if defined(STATIC_MACROS)
1740 //
1741 // If an input parameter is being marked dirty and it is in a macro
1742 // then we need to resend the macro since the parameters value is
1743 // contained within the macro definition.
1744 //
1745 if (io == &this->inputParameters && this->network->isMacro())
1746 this->network->setDirty();
1747 #endif
1748 }
1749
1750 ///////////////////////////////////////////////////////////////////////////////
1751 //
1752 // Set the index'th parameter value of the parameter list given by io
1753 // to the given value of type t. if t==DXType::UndefinedType, then
1754 // be sure it can be assigned to one of the allowed types in the
1755 // ParameterDefinition. If 'value' is NULL, then clear the value (and handle
1756 // as a successful setting) and return the default type for the given
1757 // parameter.
1758 // We you the Parameter methods to try and help certain values, become
1759 // the given type (i.e. by adding "'s, {}'s, []'s and so on).
1760 // If send is true (the default), the results will be sent to the server
1761 // if possible.
1762 // If notify is TRUE, then call ioParameterStatusChanged() with one of
1763 // Node::ParameterSetValueChanged and Node::ParameterValueChanged.
1764 // index is 1 based.
1765 //
1766 //
setIOValue(List * io,int index,const char * value,Type t,boolean send,boolean notify)1767 Type Node::setIOValue(List *io,
1768 int index,
1769 const char *value,
1770 Type t,
1771 boolean send,
1772 boolean notify)
1773 {
1774 ASSERT( index >= 1 );
1775
1776 Parameter *p = (Parameter*)io->getElement(index);
1777 ASSERT(p);
1778 boolean was_set = !p->isDefaulting();
1779
1780 Type type = DXType::UndefinedType;
1781 if (t == DXType::UndefinedType)
1782 type = p->setValue(value);
1783 else if (p->setValue(value, t))
1784 type = t;
1785
1786 //
1787 // If a NULL value is found (i.e. clearing the value), then return the
1788 // type as the default type for the parameter as "NULL" should match any
1789 // type.
1790 //
1791 if (!value)
1792 type = p->getDefaultType();
1793
1794 if (type != DXType::UndefinedType) { // Success?
1795 //
1796 // And now send the value to the executive if there is a connection.
1797 // Note that we don't need to set the network dirty, because we can
1798 // send the changes ourselves.
1799 //
1800 if (send)
1801 {
1802 DXPacketIF *pif = theDXApplication->getPacketIF();
1803 if (pif != NUL(DXPacketIF*))
1804 this->sendValues(FALSE);
1805 }
1806
1807 if (notify) {
1808 //
1809 // Let those who need to know that the value has changed.
1810 //
1811 this->notifyIoParameterStatusChanged(io == &this->inputParameters, index,
1812 was_set ?
1813 Node::ParameterSetValueChanged :
1814 Node::ParameterValueChanged);
1815 }
1816 }
1817 return type;
1818 }
1819
1820 //
1821 // This is similar to setIOValue.
1822 // We update the values internally, and send the shadowing input
1823 // value back to the executive with an Executive() call.
1824 // We use the Executive call instead of a direct assignment, because if
1825 // we are currently in execute-on-change mode, the assignment would cause
1826 // extra executions. The Executive() call (a dictionary update) avoids that.
1827 //
setIOValueQuietly(List * io,int index,const char * value,Type t)1828 Type Node::setIOValueQuietly(List *io, int index, const char *value, Type t)
1829 {
1830 t = this->setIOValue(io, index, value, t, FALSE);
1831 if (t == DXType::UndefinedType)
1832 return t;
1833
1834 this->sendValuesQuietly();
1835
1836 return t;
1837 }
1838
1839 //
1840 // Send all dirty input and output values to the executive in the
1841 // quiet way using the Executive("assign noexecute",...); call.
1842 //
sendValuesQuietly()1843 void Node::sendValuesQuietly()
1844 {
1845 DXPacketIF *pif = theDXApplication->getPacketIF();
1846 #define MAXMSGLEN 4096 // Longest message that the exec can accept
1847 char msg[MAXMSGLEN];
1848 char varname[500];
1849 const char *varval;
1850 int i;
1851
1852 #if defined(STATIC_MACROS)
1853 //
1854 // Values sent quietly are always global variables. Tool inputs
1855 // inside of macros are never sent as global variables so we want
1856 // to be sure we are not trying to do this.
1857 //
1858 // FIXME: now that I've removed the assert, are static macros endangered?
1859 //ASSERT(!this->network->isMacro());
1860 #endif
1861 if (!pif)
1862 return;
1863
1864 for (i=1 ; i<=this->getInputCount() ; i++) {
1865 Parameter *p = this->getInputParameter(i);
1866 if (p->isNeededValue(FALSE)) {
1867 (void)this->getNetworkInputNameString(i, varname);
1868 varval = this->getInputValueString(i);
1869 sprintf(msg,"Executive(\"assign noexecute\",\"%s\",%s);",
1870 varname,varval);
1871 pif->send(DXPacketIF::FOREGROUND, msg);
1872 p->clearDirty();
1873 }
1874 }
1875 for (i=1 ; i<=this->getOutputCount() ; i++) {
1876 Parameter *p = this->getOutputParameter(i);
1877 if (p->isNeededValue(FALSE)) {
1878 (void)this->getNetworkOutputNameString(i, varname);
1879 varval = this->getOutputValueString(i);
1880 sprintf(msg ,"Executive(\"assign noexecute\",\"%s\",%s);",
1881 varname,varval);
1882 pif->send(DXPacketIF::FOREGROUND, msg);
1883 p->clearDirty();
1884 }
1885 }
1886
1887
1888 }
1889
1890 //
1891 // Notify anybody that needs to know that a parameter has changed its
1892 // value.
1893 //
notifyIoParameterStatusChanged(boolean input,int index,NodeParameterStatusChange status)1894 void Node::notifyIoParameterStatusChanged(boolean input, int index,
1895 NodeParameterStatusChange status)
1896 {
1897 if (!this->network->isDeleted())
1898 this->ioParameterStatusChanged(input, index, status);
1899 }
1900
1901
ioParameterStatusChanged(boolean input,int index,NodeParameterStatusChange status)1902 void Node::ioParameterStatusChanged(boolean input, int index,
1903 NodeParameterStatusChange status)
1904 {
1905
1906 //
1907 // If we have Configuration Dialog, let it know the value, arc or
1908 // visibility was changed.
1909 //
1910 if (this->cdb) {
1911 if (input)
1912 this->cdb->changeInput(index);
1913 else
1914 this->cdb->changeOutput(index);
1915 }
1916
1917 //
1918 // Now notify all nodes receiving this output that the value has changed.
1919 //
1920 if (!input && (status & PARAMETER_VALUE_CHANGED)) {
1921 Ark *a;
1922 List *l = (List*) this->getOutputArks(index);
1923 ListIterator iterator(*l);
1924
1925 while ( (a = (Ark*)iterator.getNext()) ) {
1926 int in_index;
1927 Node *n = a->getDestinationNode(in_index);
1928 n->notifyIoParameterStatusChanged(TRUE, in_index, status);
1929 }
1930 }
1931
1932 //
1933 // Let the standin know about this. We don't notify StandIns about
1934 // arc changes since they are the ones that generate them.
1935 //
1936 if (this->standin && !(status & PARAMETER_ARC_CHANGED))
1937 this->standin->ioStatusChange(index, !input, status);
1938
1939 //
1940 // Tell the network that it has changed.
1941 //
1942 #if defined(STATIC_MACROS)
1943 //
1944 // If this is an input and the tool is in a macro, then we must always
1945 // resend the macro defnition because input values are contained within
1946 // the macro definition. Otherwise we only need to mark the network
1947 // dirty if an arc has changed.
1948 //
1949 if (input && this->network->isMacro())
1950 this->network->setDirty();
1951 else
1952 #endif
1953 if (status & PARAMETER_ARC_CHANGED)
1954 this->network->setDirty();
1955 else
1956 this->network->setFileDirty();
1957 }
1958 //
1959 // Add an Ark to to the index'th parameter of the parameter list given by io.
1960 // index is 1 based.
1961 //
addIOArk(List * io,int index,Ark * a)1962 boolean Node::addIOArk(List *io, int index, Ark *a)
1963 {
1964
1965 Parameter *p;
1966 ASSERT( index >= 1 );
1967
1968 p = (Parameter*)io->getElement(index);
1969
1970 ASSERT(p);
1971 if (!p->addArk(a))
1972 return FALSE;
1973
1974 this->notifyIoParameterStatusChanged(io == &this->inputParameters, index,
1975 Node::ParameterArkAdded);
1976 return TRUE;
1977
1978 }
1979 ////////////////////////////////////////////////////////////////////////////////
1980 //
1981 // Determine if the index'th parameter in the give list is connected
1982 // (i.e. has an arc) to another parameter.
1983 //
isIOConnected(List * io,int index)1984 boolean Node::isIOConnected(List *io, int index)
1985 {
1986
1987 Parameter *p;
1988 ASSERT( index >= 1 );
1989
1990 p = (Parameter*)io->getElement(index);
1991 ASSERT(p);
1992
1993 return p->isConnected();
1994 }
1995 ////////////////////////////////////////////////////////////////////////////////
1996 //
1997 // is the index'th parameter defaulting?
1998 //
isIODefaulting(List * io,int index)1999 boolean Node::isIODefaulting(List *io, int index)
2000 {
2001
2002 Parameter *p;
2003 ASSERT( index >= 1 );
2004
2005 p = (Parameter*)io->getElement(index);
2006 ASSERT(p);
2007
2008 return p->isDefaulting();
2009 }
2010 ////////////////////////////////////////////////////////////////////////////////
2011 //
2012 // is the index'th parameter defaulting?
2013 //
isIOSet(List * io,int index)2014 boolean Node::isIOSet(List *io, int index)
2015 {
2016
2017 Parameter *p;
2018 ASSERT( index >= 1 );
2019
2020 p = (Parameter*)io->getElement(index);
2021 ASSERT(p);
2022
2023 return p->hasValue();
2024 }
2025 ////////////////////////////////////////////////////////////////////////////////
2026 //
2027 // Get the default value of the index'th parameter in the given list.
2028 //
getIODefaultValueString(List * io,int index)2029 const char *Node::getIODefaultValueString(List *io, int index)
2030 {
2031
2032 Parameter *p;
2033 ASSERT( index >= 1 );
2034
2035 p = (Parameter*)io->getElement(index);
2036 ASSERT(p);
2037
2038 ParameterDefinition *d = p->getDefinition();
2039
2040 return d->getDefaultValue();
2041 }
2042 ////////////////////////////////////////////////////////////////////////////////
2043 //
2044 // Get the value of the index'th parameter in the given list.
2045 //
getIOValueString(List * io,int index)2046 const char *Node::getIOValueString(List *io, int index)
2047 {
2048
2049 Parameter *p;
2050 ASSERT( index >= 1 );
2051
2052 p = (Parameter*)io->getElement(index);
2053 ASSERT(p);
2054
2055 return p->getValueString();
2056 }
2057 ////////////////////////////////////////////////////////////////////////////////
2058 //
2059 // Get the type of the set value of the index'th parameter in the given list.
2060 //
getIOSetValueType(List * io,int index)2061 Type Node::getIOSetValueType(List *io, int index)
2062 {
2063
2064 Parameter *p;
2065 ASSERT( index >= 1 );
2066
2067 p = (Parameter*)io->getElement(index);
2068 ASSERT(p);
2069
2070 return (p->hasValue() ? p->getValueType() : DXType::UndefinedType);
2071 }
2072 ////////////////////////////////////////////////////////////////////////////////
2073 //
2074 // Get the set value of the index'th parameter in the given list, ignoring
2075 // whether it's defaulting or not (NULL if not set).
2076 //
getIOSetValueString(List * io,int index)2077 const char *Node::getIOSetValueString(List *io, int index)
2078 {
2079
2080 Parameter *p;
2081 ASSERT( index >= 1 );
2082
2083 p = (Parameter*)io->getElement(index);
2084 ASSERT(p);
2085
2086 return p->getSetValueString();
2087 }
2088 ////////////////////////////////////////////////////////////////////////////////
2089 //
2090 // Get the name of the parameter (as it appears in the MDF).
2091 // If there are repeatable parameter and the index indicates one of
2092 // the repeatable parameters (not in the first set), then add an index#
2093 // For example, Compute uses the following names
2094 // "expression", "input", "input1", "input2",...
2095 //
getIONameString(List * io,int index,char * buf)2096 char *Node::getIONameString(List *io, int index, char *buf)
2097 {
2098 Parameter *p;
2099 ASSERT( index >= 1 );
2100 int repeat_num; // The number on the MDF's REPEAT line
2101 int mdf_params=0; // The number of in/outputs including the first
2102 // set of inputs/outputs
2103 boolean input = (io == &this->inputParameters);
2104 char pname[128];
2105 const char *rval;
2106
2107 p = (Parameter*)io->getElement(index);
2108 ASSERT(p);
2109
2110 rval = p->getNameString();
2111
2112 if ((input && this->isInputRepeatable()) ||
2113 (!input && this->isOutputRepeatable())) {
2114 NodeDefinition *def = this->getDefinition();
2115 if (input) {
2116 repeat_num = def->getInputRepeatCount();
2117 mdf_params = def->getInputCount();
2118 } else {
2119 repeat_num = def->getOutputRepeatCount();
2120 mdf_params = def->getOutputCount();
2121 }
2122 } else {
2123 repeat_num = 0;
2124 }
2125
2126
2127 //
2128 // If there are repeatable parameter and the index indicates one of
2129 // the repeatable parameters (not in the first set), then add an index
2130 // For example, Compute uses the following names
2131 // "expression", "input", "input1", "input2",...
2132 //
2133 if ((repeat_num != 0) && (index > mdf_params)) {
2134 index = (index - mdf_params - 1) / repeat_num + 1;
2135 sprintf(pname,"%s%d",rval,index);
2136 rval = pname;
2137 }
2138
2139 if (buf) {
2140 strcpy(buf,rval);
2141 rval = buf;
2142 } else {
2143 rval = DuplicateString(rval);
2144 }
2145
2146 return (char*)rval;
2147
2148 }
2149
2150 ////////////////////////////////////////////////////////////////////////////////
2151 //
2152 // Get a list of strings that represent the allowed types for the index'th
2153 // parameter in the give list. The return list is null terminated.
2154 //
getIOTypeStrings(List * io,int index)2155 const char * const *Node::getIOTypeStrings(List *io, int index)
2156 {
2157 Parameter *p;
2158 ASSERT( index >= 1 );
2159
2160 p = (Parameter*)io->getElement(index);
2161 ASSERT(p);
2162
2163 return p->getTypeStrings();
2164 }
2165
2166 ////////////////////////////////////////////////////////////////////////////////
2167 //
2168 // Get a list of allowed types for the index'th
2169 // parameter in the give list. The list must NOT be deleted by the caller.
2170 //
getIOTypes(List * io,int index)2171 List *Node::getIOTypes(List *io, int index)
2172 {
2173 Parameter *p;
2174 ASSERT( index >= 1 );
2175
2176 p = (Parameter*)io->getElement(index);
2177 ASSERT(p);
2178
2179 return p->getDefinition()->getTypes();
2180 }
2181
2182 ////////////////////////////////////////////////////////////////////////////////
2183 //
2184 // Get the list of arcs for the index'th parameter in the given list.
2185 //
getIOArks(List * io,int index)2186 const List *Node::getIOArks(List *io, int index)
2187 {
2188 Parameter *p;
2189 ASSERT( index >= 1 );
2190
2191 p = (Parameter*)io->getElement(index);
2192 ASSERT(p);
2193
2194 return (const List*)&p->arcs;
2195 }
2196
2197 ////////////////////////////////////////////////////////////////////////////////
2198 //
2199 // Return TRUE/FALSE indicating whether or not the give parameter from
2200 // the given list is set to be visible.
2201 //
isIOVisible(List * io,int index)2202 boolean Node::isIOVisible(List *io, int index)
2203 {
2204 Parameter *p;
2205 ASSERT( index >= 1 );
2206
2207 p = (Parameter*)io->getElement(index);
2208 ASSERT(p);
2209
2210 return p->isVisible();
2211 }
2212 ////////////////////////////////////////////////////////////////////////////////
2213 //
2214 // Set TRUE/FALSE indicating whether or not the give parameter from
2215 // the given list is set to be visible.
2216 //
setIOVisibility(List * io,int index,boolean v)2217 void Node::setIOVisibility(List *io, int index, boolean v)
2218 {
2219 Parameter *p;
2220 ASSERT( index >= 1 );
2221
2222 p = (Parameter*)io->getElement(index);
2223 ASSERT(p);
2224
2225 if (p->isVisible() == v)
2226 return;
2227
2228 p->setVisibility(v);
2229
2230 this->notifyIoParameterStatusChanged(io == &this->inputParameters, index,
2231 (v ? Node::ParameterBecomesVisible :
2232 Node::ParameterBecomesInvisible));
2233 }
2234
2235 ////////////////////////////////////////////////////////////////////////////////
2236 //
2237 // Set TRUE/FALSE indicating whether or not all parameters from
2238 // the given list is set to be visible.
2239 //
2240 // FIXME:
2241 // See the #if 0's below. It's really bad to be doing an XtSetValues here
2242 // This was done because the Workspace widget doesn't deal with standins being
2243 // managed/unmanaged if they've got lines connected. This needs attention after
2244 // the 3.1 release. (You have to do something like manage/unmanage because watching
2245 // an Image standin grow/shrink is painfull.
2246 //
2247 // A possible fix: Go to WorkspaceW.c. In the GeometryManager method, look for
2248 // PerformSpaceWars. Add a call there to RerouteLines. Then you can switch back
2249 // to {un}manage. Drawback: it's an expensive fix.
2250 //
setAllIOVisibility(List * io,boolean v)2251 void Node::setAllIOVisibility(List *io, boolean v)
2252 {
2253 Parameter *p;
2254 ListIterator li(*io);
2255 int index = 1;
2256 boolean isInput = io == &this->inputParameters;
2257
2258 #if 0
2259 this->standin->unmanage();
2260 #else
2261 XtVaSetValues (this->standin->getRootWidget(),
2262 XmNmappedWhenManaged, False,
2263 NULL);
2264 #endif
2265 while( (p = (Parameter *)li.getNext()) )
2266 {
2267 boolean newv = v || p->isConnected();
2268 boolean oldv = p->isVisible();
2269 if (newv != oldv) {
2270 p->setVisibility(newv);
2271 this->notifyIoParameterStatusChanged(isInput, index,
2272 (newv ? Node::ParameterBecomesVisible :
2273 Node::ParameterBecomesInvisible));
2274 }
2275 ++index;
2276 }
2277 #if 0
2278 this->standin->manage();
2279 #else
2280 XtVaSetValues (this->standin->getRootWidget(),
2281 XmNmappedWhenManaged, True,
2282 NULL);
2283 #endif
2284 }
2285 ////////////////////////////////////////////////////////////////////////////////
2286 //
2287 // Return TRUE/FALSE indicating whether or not the give parameter from
2288 // the given list is viewable.
2289 //
isIOViewable(List * io,int index)2290 boolean Node::isIOViewable(List *io, int index)
2291 {
2292 Parameter *p;
2293 ASSERT( index >= 1 );
2294
2295 p = (Parameter*)io->getElement(index);
2296 ASSERT(p);
2297
2298 return p->isViewable();
2299 }
2300
2301 ////////////////////////////////////////////////////////////////////////////////
2302 //
2303 // Return TRUE/FALSE indicating whether or not the given i/o parameter is
2304 // a required parameter.
2305 //
isIORequired(List * io,int index)2306 boolean Node::isIORequired(List *io, int index)
2307 {
2308 Parameter *p;
2309 ASSERT( index >= 1 );
2310
2311 p = (Parameter*)io->getElement(index);
2312 ASSERT(p);
2313
2314 return p->isRequired();
2315 }
2316 ////////////////////////////////////////////////////////////////////////////////
2317 //
2318 // Return TRUE/FALSE indicating whether or not the given parameter list
2319 // contains parameters that can be hidden.
2320 //
hasHideableIO(List * io)2321 boolean Node::hasHideableIO(List *io)
2322 {
2323 ListIterator iterator(*io);
2324 Parameter *p;
2325 while ( (p = (Parameter*)iterator.getNext()) ) {
2326 if (p->isVisible() && !p->isConnected())
2327 return TRUE;
2328 }
2329 return FALSE;
2330 }
2331 ////////////////////////////////////////////////////////////////////////////////
2332 //
2333 // Return TRUE/FALSE indicating whether or not the given parameter list
2334 // contains parameters that can be exposed.
2335 //
hasExposableIO(List * io)2336 boolean Node::hasExposableIO(List *io)
2337 {
2338 ListIterator iterator(*io);
2339 Parameter *p;
2340
2341 while ( (p = (Parameter*)iterator.getNext()) ) {
2342 if (p->isViewable() && !p->isVisible())
2343 return TRUE;
2344 }
2345 return FALSE;
2346 }
2347
2348 ////////////////////////////////////////////////////////////////////////////////
2349 //
2350 // Get the description for the index'th parameter in the given list.
2351 //
getIODescription(List * io,int index)2352 const char *Node::getIODescription(List *io, int index)
2353 {
2354 Parameter *p;
2355 ASSERT( index >= 1 );
2356
2357 p = (Parameter*)io->getElement(index);
2358 ASSERT(p);
2359
2360 return p->getDescription();
2361 }
2362
2363 ////////////////////////////////////////////////////////////////////////////////
isIOCacheabilityWriteable(List * io,int index)2364 boolean Node::isIOCacheabilityWriteable(List *io, int index)
2365 {
2366 Parameter *p;
2367 ASSERT( index >= 1 );
2368 p = (Parameter*)io->getElement(index);
2369 ASSERT(p);
2370 return p->hasWriteableCacheability();
2371
2372 }
2373 ////////////////////////////////////////////////////////////////////////////////
2374 //
2375 // Get the cacheability for the index'th parameter in the given list.
2376 //
getIOCacheability(List * io,int index)2377 Cacheability Node::getIOCacheability(List *io, int index)
2378 {
2379 Parameter *p;
2380 ASSERT( index >= 1 );
2381 p = (Parameter*)io->getElement(index);
2382 ASSERT(p);
2383 return p->getCacheability();
2384 }
2385
2386 ////////////////////////////////////////////////////////////////////////////////
2387 //
2388 // Set the cacheability for the index'th parameter in the given list.
2389 //
setIOCacheability(List * io,int index,Cacheability c)2390 void Node::setIOCacheability(List *io, int index, Cacheability c)
2391 {
2392 Parameter *p;
2393 ASSERT( index >= 1 );
2394
2395 p = (Parameter*)io->getElement(index);
2396 ASSERT(p);
2397 if (c != p->getCacheability())
2398 {
2399 //
2400 // Version 2.0.0 (possibly an unreleased version) was putting
2401 // 'cache:1' on interactor outputs, which was causing an assertion
2402 // failure. So now, if the cacheability is not writable during
2403 // a .net read, then ignore the request.
2404 //
2405 boolean r = this->isIOCacheabilityWriteable(io, index);
2406 if (!r && this->network->isReadingNetwork())
2407 return;
2408 else
2409 ASSERT(r);
2410 p->setCacheability(c);
2411 this->getNetwork()->setDirty();
2412 if (this->cdb)
2413 this->cdb->changeOutput(index);
2414 }
2415 }
2416
2417 ////////////////////////////////////////////////////////////////////////////////
2418 //
2419 // Set the cacheability for the node.
2420 //
setNodeCacheability(Cacheability val)2421 void Node::setNodeCacheability(Cacheability val)
2422 {
2423 if (val != this->getNodeCacheability())
2424 {
2425 ASSERT(this->hasWriteableCacheability());
2426 this->nodeCacheability = val;
2427 this->getNetwork()->setDirty();
2428 }
2429 }
2430
2431 ////////////////////////////////////////////////////////////////////////////////
2432 //
2433 //
2434 //
2435 //
typeMatchOutputToInput(int output_index,Node * dest,int input_index)2436 boolean Node::typeMatchOutputToInput(int output_index,
2437 Node *dest, int input_index)
2438 {
2439 Parameter *pin, *pout;
2440 ASSERT( output_index >= 1 );
2441 ASSERT( input_index >= 1 );
2442
2443 pout = (Parameter*)this->outputParameters.getElement(output_index);
2444 pin = (Parameter*)dest->inputParameters.getElement(input_index);
2445 ASSERT(pin && pout);
2446
2447 return pin->typeMatch(pout);
2448 }
2449
2450
2451 ////////////////////////////////////////////////////////////////////////////////
2452 //
2453 // Determine if this node has repeatable inputs that can be removed.
2454 // We can remove repeats if the total number of parameters in this node
2455 // is currently greater than the number of non-repeatable input parameters
2456 // found in the definition (the initial number of inputs minus the number of
2457 // repeats).
2458 //
hasRemoveableInput()2459 boolean Node::hasRemoveableInput()
2460 {
2461 NodeDefinition *def = this->definition;
2462 int icnt = this->getInputCount();
2463
2464 if (!def->isInputRepeatable() || (icnt == 0))
2465 return FALSE;
2466
2467 return icnt > (def->getInputCount() - def->getInputRepeatCount());
2468 }
hasRemoveableOutput()2469 boolean Node::hasRemoveableOutput()
2470 {
2471 NodeDefinition *def = this->definition;
2472 int icnt = this->getOutputCount();
2473
2474 if (!def->isOutputRepeatable() || (icnt == 0))
2475 return FALSE;
2476
2477 return icnt > (def->getOutputCount() - def->getOutputRepeatCount());
2478 }
2479 ////////////////////////////////////////////////////////////////////////////////
2480 //
2481 // Add a set of repeatable input or output parameters to the given node.
2482 // This request may be made by the parse (below) or by the Editor or StandIn.
2483 // If we have ConfigurationDialog, let it know about the added parameters.
2484 //
addRepeats(boolean input)2485 boolean Node::addRepeats(boolean input)
2486 {
2487 int i, iocnt, repeats;
2488 List *plist;
2489 ParameterDefinition *pd;
2490 NodeDefinition *nd;
2491 Parameter *p;
2492
2493 nd = this->definition;
2494
2495 if (input) {
2496 repeats = nd->getInputRepeatCount();
2497 plist = &this->inputParameters;
2498 iocnt = this->getInputCount();
2499 } else {
2500 repeats = nd->getOutputRepeatCount();
2501 plist = &this->outputParameters;
2502 iocnt = this->getOutputCount();
2503 }
2504
2505
2506 ASSERT(repeats > 0);
2507
2508 this->network->setDirty(); // Let our network know that we have changed.
2509
2510 for (i=1 ; i<=repeats ; i++) { // Indexing is 1 based
2511 if (input)
2512 pd = (ParameterDefinition*) nd->getInputDefinition(iocnt+i);
2513 else
2514 pd = (ParameterDefinition*) nd->getOutputDefinition(iocnt+i);
2515 p = nd->newParameter(pd,this,iocnt+i);
2516 plist->appendElement(p);
2517 if (this->cdb) { // Let the configuration Dialog know about this
2518 if (input)
2519 this->cdb->newInput(iocnt + i);
2520 else
2521 this->cdb->newOutput(iocnt + i);
2522 }
2523 if (this->standin) { // Let the standin know about this
2524 if (input)
2525 this->standin->addInput(iocnt + i);
2526 else
2527 this->standin->addOutput(iocnt + i);
2528 }
2529 }
2530
2531
2532 return TRUE;
2533 }
2534 ///////////////////////////////////////////////////////////////////////////////
2535 //
2536 // Remove a set of repeatable input or output parameters from the given node.
2537 // The parameters that are removed are deleted.
2538 // NOTE: this is a friend of the Node class.
2539 //
removeRepeats(boolean input)2540 boolean Node::removeRepeats(boolean input)
2541 {
2542 int i, repeats;
2543 List *plist;
2544 Parameter *p;
2545 NodeDefinition *nd;
2546
2547 nd = this->definition;
2548
2549 if (input) {
2550 repeats = nd->getInputRepeatCount();
2551 plist = &this->inputParameters;
2552 } else {
2553 repeats = nd->getOutputRepeatCount();
2554 plist = &this->outputParameters;
2555 }
2556
2557
2558 ASSERT(repeats > 0);
2559
2560 this->network->setDirty(); // Let our network know that we have changed.
2561
2562 int cnt = plist->getSize();
2563 for (i=0 ; i<repeats ; i++) {
2564 p = (Parameter*)plist->getElement(cnt);
2565 delete p;
2566 plist->deleteElement(cnt);
2567 if (this->cdb) {
2568 if (input)
2569 this->cdb->deleteInput(cnt);
2570 else
2571 this->cdb->deleteOutput(cnt);
2572 }
2573 if (this->standin) { // Let the standin know about this
2574 if (input)
2575 this->standin->removeLastInput();
2576 else
2577 this->standin->removeLastOutput();
2578 }
2579 cnt--;
2580 }
2581
2582
2583 return TRUE;
2584 }
2585 ///////////////////////////////////////////////////////////////////////////////
2586 //
2587 // Change a parameter from either the assigned or default value to the
2588 // default or assigned value.
2589 // Set the index'th i/o parameter to use either the default value
2590 // or the assigned valued. if notify is TRUE then call
2591 // ioParameterStatusChanged() with Node::ParameterSetValueToDefaulting.
2592 // If there is a connection to the executive, then send the change.
2593 //
setIODefaultingStatus(int index,boolean input,boolean defaulting,boolean send,boolean notify)2594 void Node::setIODefaultingStatus(int index,
2595 boolean input,
2596 boolean defaulting,
2597 boolean send,
2598 boolean notify)
2599 {
2600 Parameter *p;
2601 if (input)
2602 p = this->getInputParameter(index);
2603 else
2604 p = this->getOutputParameter(index);
2605
2606 boolean was_defaulting = p->isDefaulting();
2607 if (was_defaulting == defaulting)
2608 return;
2609
2610 p->setUnconnectedDefaultingStatus(defaulting);
2611
2612 //
2613 // And now send the value to the executive if there is a connection.
2614 // Note that we don't need to set the network dirty, because we can
2615 // send the changes ourselves.
2616 //
2617 if (send)
2618 {
2619 DXPacketIF *pif = theDXApplication->getPacketIF();
2620 if (pif != NUL(DXPacketIF*))
2621 this->sendValues(FALSE);
2622 }
2623
2624 ASSERT(!p->isConnected());
2625 if (notify)
2626 this->notifyIoParameterStatusChanged(input, index,
2627 Node::ParameterSetValueToDefaulting);
2628
2629
2630 }
2631 ///////////////////////////////////////////////////////////////////////////////
2632 //
2633 // Open this nodes configuration dialog box.
2634 //
openConfigurationDialog(Widget parent)2635 void Node::openConfigurationDialog(Widget parent)
2636 {
2637 if (!this->cdb)
2638 this->newConfigurationDialog(parent);
2639 this->cdb->post();
2640 }
2641 ///////////////////////////////////////////////////////////////////////////////
2642 //
2643 // Define the default action that is taken when the StandIn asks for the
2644 // the default action.
2645 //
openDefaultWindow(Widget parent)2646 void Node::openDefaultWindow(Widget parent)
2647 {
2648 this->openConfigurationDialog(parent);
2649 }
2650
2651 ///////////////////////////////////////////////////////////////////////////////
2652 //
2653 // Display help for this node in a window.
2654 // FIXME: use real help system here.
2655 //
openHelpWindow(Widget parent)2656 void Node::openHelpWindow(Widget parent)
2657 {
2658 ErrorMessage("Help not available for %s\n",this->getNameString());
2659 }
2660
2661 //////////////////////////////////////////////////////////////////////////////
2662 //
2663 // Print the stuff that goes in a .cfg file.
2664 // The default is to succeed without printing anything.
2665 //
cfgPrintNode(FILE * f,PrintType)2666 boolean Node::cfgPrintNode(FILE *f, PrintType)
2667 {
2668 return TRUE;
2669 }
2670 //////////////////////////////////////////////////////////////////////////////
2671 //
2672 // Parse a comment in a .cfg file comment section for this node.
2673 // Be default nodes have lines of the following form
2674 // '// node %s[%d]:'
2675 //
cfgParseComment(const char * comment,const char * filename,int lineno)2676 boolean Node::cfgParseComment(const char* comment,
2677 const char* filename, int lineno)
2678 {
2679 return this->cfgParseNodeLeader(comment,filename,lineno);
2680 }
2681
setLabelString(const char * label)2682 boolean Node::setLabelString(const char *label)
2683 {
2684
2685 this->labelSymbol = theSymbolManager->registerSymbol(label);
2686 if (this->cdb)
2687 this->cdb->changeLabel();
2688 if (this->getStandIn())
2689 this->getStandIn()->notifyLabelChange();
2690 return TRUE;
2691 }
getLabelString()2692 const char *Node::getLabelString()
2693 {
2694 if (this->labelSymbol == 0)
2695 return this->getNameString();
2696 else
2697 return theSymbolManager->getSymbolString(this->labelSymbol);
2698 }
2699
initialize()2700 boolean Node::initialize()
2701 {
2702 return TRUE;
2703 }
2704
deleteArk(Ark * a)2705 boolean Node::deleteArk(Ark *a)
2706 {
2707 Node* sourceNode;
2708 Node* destNode;
2709 int sourceIndex, destIndex;
2710
2711 sourceNode = a->getSourceNode(sourceIndex);
2712 destNode = a->getDestinationNode(destIndex);
2713
2714
2715 destNode->removeInputArk(destIndex, a);
2716 sourceNode->removeOutputArk(sourceIndex, a);
2717
2718 return TRUE;
2719
2720 }
2721
removeIOArk(List * io,int index,Ark * a)2722 boolean Node::removeIOArk(List *io, int index, Ark *a)
2723 {
2724 Parameter *p = (Parameter*)io->getElement(index);
2725
2726 p->removeArk(a);
2727
2728 this->notifyIoParameterStatusChanged(io == &this->inputParameters, index,
2729 Node::ParameterArkRemoved);
2730
2731 return TRUE;
2732 }
2733
2734
2735 void
updateDefinition()2736 Node::updateDefinition()
2737 {
2738 struct ArkInfo {
2739 int srcIndex;
2740 int dstIndex;
2741 Node *src;
2742 Node *dst;
2743 };
2744
2745 //
2746 // Types may have changed so delete the cdb.
2747 //
2748 if (this->cdb) {
2749 delete this->cdb;
2750 this->cdb = NULL;
2751 }
2752
2753 #if 11 // This is the beginning of an attemp to fix bug DAWOOD91
2754 #else
2755 boolean hadStandIn = FALSE;
2756
2757 //
2758 // Recreate the standin if need be
2759 //
2760 if (this->standin) {
2761 delete this->standin;
2762 this->standin = NULL;
2763 hadStandIn = TRUE;
2764 }
2765 #endif
2766
2767 // For each of the input ParameterDefinitions in the new definition,
2768 // make sure that the types of the parameter are correct, and
2769 // disconnect arcs or reset the values to NULL.
2770
2771 int numInputs = this->getInputCount();
2772 boolean *defaulting = NULL;
2773 boolean *visibilities = NULL;
2774 char **values = NULL;
2775 List **inputArks = NULL;
2776 if (numInputs != 0)
2777 {
2778 defaulting = new boolean[numInputs];
2779 values = new char *[numInputs];
2780 inputArks = new List *[numInputs];
2781 visibilities = new boolean[numInputs];
2782 }
2783 int i;
2784 for (i = 1; i <= numInputs; ++i)
2785 {
2786 inputArks[i-1] = NULL;
2787 values[i-1] = NULL;
2788 defaulting[i-1] = FALSE;
2789 visibilities[i-1] = this->isInputVisible(i);
2790 if (this->isInputConnected(i))
2791 {
2792 const List *arcs = this->getInputArks(i);
2793 inputArks[i-1] = new List;
2794 ListIterator li(*(List*)arcs);
2795 Ark *a;
2796 while( (a = (Ark*)li.getNext()) )
2797 {
2798 ArkInfo *ai = new ArkInfo;
2799 ai->src = a->getSourceNode(ai->srcIndex);
2800 ai->dst = a->getDestinationNode(ai->dstIndex);
2801 inputArks[i-1]->appendElement(ai);
2802 }
2803 }
2804 else if (!(defaulting[i-1] = this->isInputDefaulting(i)))
2805 values[i-1] = DuplicateString(this->getInputValueString(i));
2806 delete this->getInputParameter(i);
2807 }
2808 this->inputParameters.clear();
2809
2810 int numOutputs = this->getOutputCount();
2811 List **outputArks = NULL;
2812 if (numOutputs != 0)
2813 outputArks = new List *[numOutputs];
2814 for (i = 1; i <= numOutputs; ++i)
2815 {
2816 outputArks[i-1] = NULL;
2817 if (this->isOutputConnected(i))
2818 {
2819 const List *arcs = this->getOutputArks(i);
2820 outputArks[i-1] = new List;
2821 ListIterator li(*(List*)arcs);
2822 Ark *a;
2823 while( (a = (Ark*)li.getNext()) )
2824 {
2825 ArkInfo *ai = new ArkInfo;
2826 ai->src = a->getSourceNode(ai->srcIndex);
2827 ai->dst = a->getDestinationNode(ai->dstIndex);
2828 outputArks[i-1]->appendElement(ai);
2829 }
2830 }
2831 delete this->getOutputParameter(i);
2832 }
2833 this->outputParameters.clear();
2834
2835 this->buildParameterLists();
2836
2837 for (i = 1; i <= numInputs && i <= this->getInputCount(); ++i)
2838 {
2839 this->setInputVisibility(i, visibilities[i-1]);
2840 if (inputArks[i-1])
2841 {
2842 ListIterator li(*inputArks[i-1]);
2843 ArkInfo *ai;
2844 while( (ai = (ArkInfo*)li.getNext()) )
2845 {
2846 if (ai->src->typeMatchOutputToInput(ai->srcIndex,
2847 ai->dst, ai->dstIndex))
2848 {
2849 Ark *newArk = new Ark(ai->src, ai->srcIndex,
2850 ai->dst, ai->dstIndex);
2851 if (ai->src->getNetwork()->getEditor() &&
2852 ai->src->getStandIn())
2853 ai->src->getStandIn()->addArk(
2854 ai->src->getNetwork()->getEditor(),
2855 newArk);
2856 }
2857 delete ai;
2858 }
2859 delete inputArks[i-1];
2860 }
2861 else if (defaulting[i-1])
2862 this->useDefaultInputValue(i);
2863 else
2864 this->setInputValue(i, values[i-1]);
2865 }
2866 #if 11
2867 // must increase j by the number of repeats added in buildParameterLists()
2868 int repeats = this->getInputCount() - this->definition->getInputCount();
2869 int j = numInputs + repeats;
2870 for (; j >= i; --j)
2871 {
2872 if (this->cdb)
2873 this->cdb->deleteInput(j);
2874 if (this->standin)
2875 this->standin->removeLastInput();
2876 }
2877 for (; i <= this->getInputCount(); ++i)
2878 {
2879 if (this->cdb)
2880 this->cdb->newInput(i);
2881 if (this->standin)
2882 this->standin->addInput(i);
2883 }
2884 #endif
2885 if (numInputs != 0)
2886 {
2887 delete[] defaulting;
2888 delete[] visibilities;
2889 delete[] values;
2890 delete[] inputArks;
2891 }
2892
2893 for (i = 1; i <= numOutputs && i <= this->getOutputCount(); ++i)
2894 {
2895 if (outputArks[i-1])
2896 {
2897 ListIterator li(*outputArks[i-1]);
2898 ArkInfo *ai;
2899 while( (ai = (ArkInfo*)li.getNext()) )
2900 {
2901 if (ai->src->typeMatchOutputToInput(ai->srcIndex,
2902 ai->dst, ai->dstIndex))
2903 {
2904 Ark *newArk = new Ark(ai->src, ai->srcIndex,
2905 ai->dst, ai->dstIndex);
2906 if (ai->src->getNetwork()->getEditor() &&
2907 ai->src->getStandIn())
2908 ai->src->getStandIn()->addArk(
2909 ai->src->getNetwork()->getEditor(),
2910 newArk);
2911 }
2912 delete ai;
2913 }
2914 delete outputArks[i-1];
2915 }
2916 this->notifyIoParameterStatusChanged(FALSE, i, Node::ParameterValueChanged);
2917 }
2918 #if 11
2919 j = numOutputs;
2920 for (; j >= i; --j)
2921 {
2922 if (this->cdb)
2923 this->cdb->deleteOutput(j);
2924 if (this->standin)
2925 this->standin->removeLastOutput();
2926 }
2927 for (; i <= this->getOutputCount(); ++i)
2928 {
2929 if (this->cdb)
2930 this->cdb->newOutput(i);
2931 if (this->standin)
2932 this->standin->addOutput(i);
2933 }
2934 #endif
2935 if (numOutputs != 0)
2936 delete[] outputArks;
2937
2938 #if 11
2939 #else
2940 if (hadStandIn) {
2941 EditorWindow *e = this->getNetwork()->getEditor();
2942 this->standin = this->newStandIn(e->getWorkSpace());
2943 }
2944 #endif
2945
2946 //
2947 // Because of undo in Editor, provide notification that a defintion
2948 // has changed. The undo list will probably have to be tossed out
2949 //
2950 EditorWindow *e = this->getNetwork()->getEditor();
2951 if (e) e->notifyDefinitionChange(this);
2952 }
2953
2954 //
2955 // Based on a Node's definition, build a parameter list for the given node.
2956 //
buildParameterLists()2957 boolean Node::buildParameterLists()
2958 {
2959 int ninputs, noutputs, i;
2960 Parameter *p;
2961 ParameterDefinition *pd;
2962 NodeDefinition *nd = this->getDefinition();
2963
2964 ninputs = nd->getInputCount();
2965 for (i=1 ; i<=ninputs ; i++) {
2966 pd = nd->getInputDefinition(i);
2967 ASSERT(pd);
2968 p = nd->newParameter(pd,this,i);
2969 ASSERT(p);
2970 boolean r = this->appendInput(p); // FIXME: handle error
2971 ASSERT(r);
2972 }
2973 if (nd->isInputRepeatable())
2974 this->addRepeats(TRUE);
2975
2976 noutputs = nd->getOutputCount();
2977 for (i=1 ; i<=noutputs ; i++) {
2978 pd = nd->getOutputDefinition(i);
2979 ASSERT(pd);
2980 p = nd->newParameter(pd,this,i);
2981 ASSERT(p);
2982 boolean r = this->appendOutput(p);
2983 ASSERT(r);
2984 }
2985 if (nd->isOutputRepeatable())
2986 this->addRepeats(FALSE);
2987
2988 return TRUE;
2989 }
2990
2991 #if WORKSPACE_PAGES
2992 #else
setGroupName(const char * name)2993 void Node::setGroupName(const char *name)
2994 {
2995 if (!name) {
2996 this->groupNameSymbol = 0;
2997 } else {
2998 this->groupNameSymbol = theSymbolManager->registerSymbol(name);
2999 }
3000
3001 this->network->setDirty();
3002 }
3003
getGroupName()3004 const char* Node::getGroupName()
3005 {
3006 if (!this->groupNameSymbol)
3007 return NULL;
3008
3009 return theSymbolManager->getSymbolString(this->groupNameSymbol);
3010 }
3011
addToGroup(const char * group)3012 void Node::addToGroup(const char* group)
3013 {
3014 this->setGroupName(group);
3015 theDXApplication->PGManager->registerGroup(group, this->network);
3016 }
3017 #endif
3018
netEndOfMacroNodeString(const char * prefix)3019 char *Node::netEndOfMacroNodeString(const char *prefix)
3020 {
3021 return NULL;
3022 }
3023
netBeginningOfMacroNodeString(const char * prefix)3024 char *Node::netBeginningOfMacroNodeString(const char *prefix)
3025 {
3026 return NULL;
3027 }
3028
3029
3030 //
3031 // Print the invocation of any script language that is
3032 // to occur at the beginning of the containing macro.
3033 //
netPrintBeginningOfMacroNode(FILE * f,PrintType dest,const char * prefix,PacketIFCallback callback,void * clientdata)3034 boolean Node::netPrintBeginningOfMacroNode(FILE *f,
3035 PrintType dest,
3036 const char *prefix,
3037 PacketIFCallback callback,
3038 void *clientdata)
3039 {
3040 boolean r = TRUE;
3041
3042 char *s = netBeginningOfMacroNodeString(prefix);
3043 if (s == NULL)
3044 return TRUE;
3045
3046 if (dest == PrintFile || dest == PrintCut || dest == PrintCPBuffer) {
3047 if (fputs(s, f) < 0)
3048 r = FALSE;
3049 if (callback != NUL(PacketIFCallback))
3050 callback(clientdata,s);
3051 } else {
3052 ASSERT (dest == PrintExec);
3053 DXPacketIF *pif = theDXApplication->getPacketIF();
3054 pif->sendBytes(s);
3055 }
3056
3057
3058 delete s;
3059
3060 return r;
3061 }
3062
3063 //
3064 // Print the invocation of any script language that is
3065 // to occur at the end of the containing macro.
3066 //
netPrintEndOfMacroNode(FILE * f,PrintType dest,const char * prefix,PacketIFCallback callback,void * clientdata)3067 boolean Node::netPrintEndOfMacroNode(FILE *f,
3068 PrintType dest,
3069 const char *prefix,
3070 PacketIFCallback callback,
3071 void *clientdata)
3072 {
3073 boolean r = TRUE;
3074
3075 char *s = netEndOfMacroNodeString(prefix);
3076 if (s == NULL)
3077 return TRUE;
3078
3079 if (dest == PrintFile || dest == PrintCut || dest == PrintCPBuffer) {
3080 if (fputs(s, f) < 0)
3081 r = FALSE;
3082 if (callback != NUL(PacketIFCallback))
3083 callback(clientdata,s);
3084 } else {
3085 ASSERT (dest == PrintExec);
3086 DXPacketIF *pif = theDXApplication->getPacketIF();
3087 pif->sendBytes(s);
3088 }
3089
3090 delete s;
3091
3092 return r;
3093 }
isInputRepeatable()3094 boolean Node::isInputRepeatable()
3095 {
3096 NodeDefinition *def = this->definition;
3097 if (!def->isInputRepeatable())
3098 return FALSE;
3099 int icnt = this->getInputCount();
3100 int rcnt = icnt - (def->getInputCount() - def->getInputRepeatCount());
3101 int sets = rcnt / def->getInputRepeatCount();
3102 return sets < (MAX_INPUT_SETS);
3103 }
isOutputRepeatable()3104 boolean Node::isOutputRepeatable()
3105 {
3106 NodeDefinition *def = this->definition;
3107 if (!def->isOutputRepeatable())
3108 return FALSE;
3109 int icnt = this->getOutputCount();
3110 int rcnt = icnt - (def->getOutputCount() - def->getOutputRepeatCount());
3111 int sets = rcnt / def->getOutputRepeatCount();
3112 return sets < (MAX_OUTPUT_SETS);
3113 }
3114
3115 //
3116 // Reset the node to using the default cfg state (probably before reading
3117 // in a new cfg file).
3118 //
setDefaultCfgState()3119 void Node::setDefaultCfgState()
3120 {
3121 }
3122 //
3123 // Return TRUE if this node has state that will be saved in a .cfg file.
3124 // At this level, nodes do not have cfg state.
3125 //
hasCfgState()3126 boolean Node::hasCfgState()
3127 {
3128 return FALSE;
3129 }
3130
3131
3132 //
3133 // Generate a new instance number for this node. We notify the
3134 // standIn and mark the network and the node dirty.
3135 // The new instance number is returned.
3136 //
assignNewInstanceNumber()3137 int Node::assignNewInstanceNumber()
3138 {
3139 NodeDefinition *nd = this->definition;
3140 ASSERT(nd);
3141 this->instanceNumber = nd->newInstanceNumber();
3142 #if 0
3143 // FIXME: must notify standIn when in UIDebug mode
3144 if (this->standIn) {
3145 this->standIn-??
3146 #endif
3147
3148 //
3149 // Require that the network resend all tools.
3150 //
3151 this->network->setDirty();
3152
3153 //
3154 // Mark all inputs and outputs dirty so that they are resent with the
3155 // new parameter names.
3156 //
3157 int i, cnt = this->getInputCount();
3158 for (i=1 ; i<=cnt ; i++)
3159 this->setInputDirty(i);
3160 cnt = this->getOutputCount();
3161 for (i=1 ; i<=cnt ; i++)
3162 this->setOutputDirty(i);
3163
3164 if (this->moduleMessageId) {
3165 delete this->moduleMessageId;
3166 this->moduleMessageId = NULL;
3167 }
3168 return this->instanceNumber;
3169 }
3170 //
3171 // Disconnect all input and output arcs from this node.
3172 //
3173 boolean Node::disconnectArks()
3174 {
3175 int i;
3176 ListIterator li;
3177 Parameter *p;
3178
3179 //
3180 // Disconnect the inputs.
3181 //
3182 li.setList(this->inputParameters);
3183 for (i=1 ; (p = (Parameter*)li.getNext()) ; i++) {
3184 if (p->isConnected()) {
3185 p->disconnectArks();
3186 this->notifyIoParameterStatusChanged(TRUE, i, Node::ParameterArkRemoved);
3187 }
3188 }
3189
3190 //
3191 // Disconnect the outputs.
3192 //
3193 li.setList(this->outputParameters);
3194 for (i=1 ; (p = (Parameter*)li.getNext()) ; i++) {
3195 if (p->isConnected()) {
3196 p->disconnectArks();
3197 this->notifyIoParameterStatusChanged(FALSE, i, Node::ParameterArkRemoved);
3198 }
3199 }
3200
3201
3202 return TRUE;
3203 }
3204 //
3205 // Return TRUE if the node can be switched (pasted/merged/moved) from the 'from'
3206 // net to the 'to' net.
3207 //
3208 boolean Node::canSwitchNetwork(Network *from, Network *to)
3209 {
3210 if (to->isMacro() && !this->isAllowedInMacro()) {
3211 WarningMessage("%s tools are not allowed in macros.\n"
3212 "Attempt to add a %s tool to macro ignored.",
3213 this->getNameString(), this->getNameString());
3214 return FALSE;
3215 }
3216
3217 return TRUE;
3218 }
3219 //
3220 // Do whatever is necessary to switch the node to the new Network.
3221 //
3222 void Node::switchNetwork(Network *from, Network *to, boolean silently)
3223 {
3224 if (this->cdb) {
3225 delete this->cdb;
3226 this->cdb = NULL;
3227 }
3228 if (this->standin) {
3229 delete this->standin;
3230 this->standin = NULL;
3231 }
3232
3233 this->network = to;
3234 }
3235
3236 //
3237 // Get the selectable values for the n'th input.
3238 // This returns a pointer to a constant array of pointers to
3239 // constant strings which is NOT to be manipulated by the caller.
3240 // The returned array of pointers is NULL terminated.
3241 //
3242 const char * const *Node::getInputValueOptions(int index)
3243 {
3244 Parameter *p;
3245 ASSERT( index >= 1 );
3246
3247 p = (Parameter*)this->inputParameters.getElement(index);
3248 ASSERT(p);
3249
3250 return p->getValueOptions();
3251 }
3252
3253 #ifdef DXUI_DEVKIT
3254
3255 #define OBJVAL_FORMAT "%s_%s"
3256 #define MODINPUT_FORMAT "%s_%d_in"
3257 #define MODOUTPUT_FORMAT "%s_%d_out"
3258 #define INDENT " "
3259
3260 static int phaseNumber = 0;
3261 boolean Node::beginDXCallModule(FILE *f)
3262 {
3263 const char *name = this->getNameString();
3264 int i, instance_number = this->getInstanceNumber();
3265 char modinput_name[128];
3266 char modoutput_name[128];
3267 int input_count = this->getInputCount();
3268 int output_count = this->getOutputCount();
3269
3270 if (phaseNumber == 0) {
3271 phaseNumber = 1;
3272 if (fprintf(f, " /*\n"
3273 " * Temporary variables used by all module calls\n"
3274 " */\n"
3275 " int i, rcode;\n"
3276 " Object objinput[32];\n"
3277 " ModuleInput minput[32];\n"
3278 " ModuleOutput moutput[32];\n"
3279 " /*\n"
3280 " * Per module variables follow (if needed)\n"
3281 " */\n") <= 0)
3282 return FALSE;
3283 }
3284
3285
3286 if (input_count > 0) {
3287 sprintf(modinput_name, MODINPUT_FORMAT,name,instance_number);
3288 for (i=1 ; i<=input_count ; i++) {
3289 if (!this->isInputConnected(i) && !this->isInputDefaulting(i)) {
3290 char oname[128];
3291 Parameter *p = this->getInputParameter(i);
3292 sprintf(oname,OBJVAL_FORMAT,modinput_name,
3293 this->getInputNameString(i));
3294 char *code = p->getObjectCodeDecl(INDENT,oname);
3295 if (code) {
3296 if (fprintf(f,code) <= 0)
3297 return FALSE;
3298 delete code;
3299 }
3300 }
3301 }
3302 }
3303
3304 if (output_count > 0) {
3305 sprintf(modoutput_name, MODOUTPUT_FORMAT,name,instance_number);
3306 for (i=1 ; i<=output_count ; i++) {
3307 if (this->isOutputConnected(i)) {
3308 char oname[256];
3309 sprintf(oname,OBJVAL_FORMAT,modoutput_name,
3310 this->getOutputNameString(i));
3311 if (fprintf(f,"%sObject %s = NULL;\n",INDENT,oname) <= 0)
3312 return FALSE;
3313 }
3314 }
3315 }
3316
3317 return TRUE;
3318
3319 }
3320 boolean Node::callDXCallModule(FILE *f)
3321 {
3322 const char *name = this->getNameString();
3323 int objnum, i, instance_number = this->getInstanceNumber();
3324 boolean r;
3325
3326 if (phaseNumber == 1) {
3327 phaseNumber = 2;
3328 if (fprintf(f,"\n /*\n"
3329 " * Some initializations\n"
3330 " */\n"
3331 " for (i=0 ; i<32 ; i++) \n"
3332 " objinput[i] = NULL;\n") <= 0)
3333 return FALSE;
3334 }
3335
3336 if (fprintf(f,"\n /*\n"
3337 " * %s:%d - setup in/outputs and call module\n"
3338 " */\n",name,instance_number) <= 0)
3339 return FALSE;
3340
3341 char modinput_name[128];
3342 int ninput = 0;
3343 int input_count = this->getInputCount();
3344 if (input_count <= 0) {
3345 strcpy(modinput_name,"NULL");
3346 } else {
3347 //
3348 // Generate the code to set the ModuleInputs
3349 //
3350 sprintf(modinput_name, MODINPUT_FORMAT,name,instance_number);
3351 for (objnum=0, i=1 ; i<=input_count ; i++) {
3352
3353 if (this->isInputDefaulting(i))
3354 continue;
3355
3356 const char *input_name = this->getInputNameString(i);
3357 char input_val[512];
3358 char *init_code = NULL;
3359 if (this->isInputConnected(i)) {
3360 Parameter *p = this->getInputParameter(i);
3361 Ark *a = p->getArk(1);
3362 int param;
3363 ASSERT(a);
3364 Node *onode = a->getSourceNode(param);
3365 ASSERT(onode);
3366 char oname[256];
3367 sprintf(oname, MODOUTPUT_FORMAT,onode->getNameString(),
3368 onode->getInstanceNumber());
3369 sprintf(input_val, "%s_%s", oname,
3370 onode->getOutputNameString(param));
3371
3372 } else { // Parameter has a tab down value
3373 Parameter *p = this->getInputParameter(i);
3374 char oname[256];
3375 sprintf(oname,OBJVAL_FORMAT,modinput_name,
3376 this->getInputNameString(i));
3377 sprintf(input_val, "objinput[%d]", objnum++);
3378 init_code = p->getObjectCreateCode(INDENT,oname,input_val);
3379 }
3380
3381 if (init_code && fprintf(f,init_code) <= 0) {
3382 delete init_code;
3383 return FALSE;
3384 }
3385 r = fprintf(f,"%sDXModSetObjectInput(minput + %d,\"%s\",%s);\n",
3386 INDENT,ninput++, input_name, input_val) > 0;
3387 if (init_code)
3388 delete init_code;
3389 if (!r)
3390 return FALSE;
3391 }
3392 }
3393
3394 //
3395 // Generate the code to set the ModuleOutputs
3396 //
3397 char modoutput_name[128];
3398 int noutput = 0;
3399 int output_count = this->getOutputCount();
3400
3401 //
3402 // Generate the code to set the ModuleOutputs
3403 //
3404 sprintf(modoutput_name, MODOUTPUT_FORMAT,name,instance_number);
3405 for (i=1 ; i<=output_count ; i++) {
3406 if (!this->isOutputConnected(i))
3407 continue;
3408
3409 const char *output_name = this->getOutputNameString(i);
3410 char output_objptr[512];
3411 // FIXME; what if the output has a value (i.e. an interactor)
3412 char oname[256];
3413 sprintf(oname,OBJVAL_FORMAT,modoutput_name,
3414 this->getOutputNameString(i));
3415 sprintf(output_objptr,"&%s",oname);
3416
3417 if (fprintf(f,"%sDXModSetObjectOutput(moutput + %d,\"%s\",%s);\n",
3418 INDENT,noutput++,output_name,output_objptr) <= 0)
3419 return FALSE;
3420 }
3421
3422
3423 //
3424 // Finally, generate the call to DXCallModule
3425 //
3426 if (fprintf(f,"%srcode = DXCallModule(\"%s\",%d,minput,%d,moutput);\n",
3427 INDENT,this->getNameString(),ninput,noutput) <= 0)
3428 return FALSE;
3429
3430
3431 //
3432 // Reference connected outputs
3433 //
3434 for (i=1 ; i<=output_count ; i++)
3435 if (this->isOutputConnected(i))
3436 {
3437 const char *output_name = this->getOutputNameString(i);
3438 char oname[256];
3439
3440 sprintf(oname,OBJVAL_FORMAT,modoutput_name,
3441 this->getOutputNameString(i));
3442
3443 if (fprintf(f,"%sDXReference(%s);\n", INDENT, oname) <= 0)
3444 return FALSE;
3445 }
3446
3447
3448 if (fprintf(f,"%sif (rcode == ERROR) goto error;\n", INDENT) <= 0)
3449 return FALSE;
3450
3451 return TRUE;
3452 }
3453 boolean Node::endDXCallModule(FILE *f)
3454 {
3455
3456 const char *name = this->getNameString();
3457 int i, instance_number = this->getInstanceNumber();
3458 char modinput_name[128];
3459 char modoutput_name[128];
3460 int input_count = this->getInputCount();
3461 int output_count = this->getOutputCount();
3462
3463 phaseNumber = 0;
3464
3465 if (input_count > 0) {
3466 sprintf(modinput_name, MODINPUT_FORMAT,name,instance_number);
3467 for (i=1 ; i<=input_count ; i++) {
3468 if (!this->isInputConnected(i) && !this->isInputDefaulting(i)) {
3469 char oname[256];
3470 sprintf(oname,OBJVAL_FORMAT,modinput_name,
3471 this->getInputNameString(i));
3472 Parameter *p = this->getInputParameter(i);
3473 char *cleanup_code = p->getObjectCleanupCode(INDENT,oname);
3474 if (cleanup_code) {
3475 if (fprintf(f,cleanup_code) <= 0) {
3476 delete cleanup_code;
3477 return FALSE;
3478 }
3479 delete cleanup_code;
3480 }
3481 }
3482 }
3483 }
3484
3485 if (output_count > 0) {
3486 sprintf(modoutput_name, MODOUTPUT_FORMAT,name,instance_number);
3487 for (i=1 ; i<=output_count ; i++) {
3488 if (this->isOutputConnected(i)) {
3489 char oname[256];
3490 sprintf(oname,OBJVAL_FORMAT,modoutput_name,
3491 this->getOutputNameString(i));
3492 if (fprintf(f,"%sif (%s) DXDelete(%s);\n",
3493 INDENT,oname,oname) <= 0)
3494 return FALSE;
3495 }
3496 }
3497 }
3498
3499
3500 return TRUE;
3501
3502 }
3503 #endif // DXUI_DEVKIT
3504 //
3505 // See if the given string is a viable label to be used as an identifier.
3506 // Also make sure it is not a reserved script language word.
3507 // Return TRUE if ok, FALSE otherwise and issue and error message.
3508 //
3509 boolean Node::verifyRestrictedLabel(const char *label)
3510 {
3511 int junk = 0;
3512 if (!IsIdentifier(label, junk) || junk != STRLEN(label))
3513 {
3514 ErrorMessage("%s name \"%s\" must consist of "
3515 "letters, numbers, or the character '_', and "
3516 "begin with a letter",
3517 this->getNameString(),
3518 label);
3519 return FALSE;
3520 }
3521
3522 if (IsReservedScriptingWord(label)) {
3523 ErrorMessage("%s name \"%s\" is a reserved word",
3524 this->getNameString(),
3525 label);
3526 return FALSE;
3527 }
3528
3529 return TRUE;
3530 }
3531
3532 boolean Node::cfgPrintNodeLeader(FILE *f)
3533 {
3534
3535 if (fprintf(f, "//\n// node %s[%d]:\n",
3536 this->getNameString(),
3537 this->getInstanceNumber()) < 0)
3538 return FALSE;
3539
3540 return TRUE;
3541 }
3542 boolean Node::cfgParseNodeLeader(const char *comment,
3543 const char *file, int lineno)
3544 {
3545 int d;
3546 if (sscanf(comment, " node %*[^[][%d]:",&d) != 1)
3547 return FALSE;
3548
3549 return TRUE;
3550 }
3551
3552 boolean Node::printAsJava(FILE* f)
3553 {
3554 if (this->hasJavaRepresentation() == FALSE) return TRUE;
3555
3556 const char* indent = " ";
3557 const char* nn = this->getJavaNodeName();
3558 const char* ns = this->getNameString();
3559 int instno = this->getInstanceNumber();
3560
3561 fprintf (f,
3562 "\n\n%s%s %s_%d = new %s (this.network, \"%s\", %d, \"%s\");\n",
3563 indent, nn, ns, instno, nn, ns, instno, this->getLabelString()
3564 );
3565 fprintf (f,
3566 "%sthis.network.addElement((Object)%s_%d);\n",
3567 indent, ns, instno
3568 );
3569
3570
3571 //
3572 // Loop over all inputs. If the node wants that input's value
3573 // printed as java, then oblige.
3574 //
3575 int i, icnt = this->getInputCount();
3576 for (i=1; i<=icnt; i++) {
3577 char src_name[128];
3578 int src_out = 0;
3579 strcpy (src_name, "null");
3580 if (this->printInputAsJava(i)) {
3581 if (this->isInputConnected(i)) {
3582 const List* ia = (List*)getInputArks(i);
3583 Ark* a = NUL(Ark*);
3584 Node* src = NUL(Node*);
3585 if (ia) {
3586 ListIterator li(*(List*)ia);
3587 a = (Ark*)li.getNext();
3588 }
3589 if (a) src = (Node*)a->getSourceNode(src_out);
3590 if ((src)&&(src->isA(src->hasJavaRepresentation()))) {
3591 const char* src_ns = src->getNameString();
3592 int src_instno = src->getInstanceNumber();
3593 sprintf (src_name, "%s_%d", src_ns, src_instno);
3594 }
3595
3596 fprintf (f, "%s%s_%d.addInputArk (%d, %s, %d);\n",
3597 indent, ns, instno, i, src_name, src_out);
3598 }
3599 const char* valstr = this->getJavaInputValueString(i);
3600 if ((valstr) && (EqualString(valstr, "NULL")==FALSE)) {
3601 if (valstr[0] == '"') {
3602 if (fprintf (f, "%s%s_%d.setInputValueString(%d, %s);\n",
3603 indent, ns, instno, i, valstr) == FALSE) return FALSE;
3604 } else {
3605 if (fprintf (f, "%s%s_%d.setInputValueString(%d, \"%s\");\n",
3606 indent, ns, instno, i, valstr) == FALSE) return FALSE;
3607 }
3608 }
3609 }
3610 }
3611
3612 return TRUE;
3613 }
3614
3615 void Node::setLayoutInformation(Base* li)
3616 {
3617 if (this->layout_information)
3618 delete this->layout_information;
3619 this->layout_information = li;
3620 }
3621