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 #include <sys/types.h>
13 #include <time.h>
14 #include <sys/stat.h>
15 #if defined(HAVE_UNISTD_H)
16 #include <unistd.h>
17 #endif
18 #include <string.h> // for strerror
19 #include <errno.h> // for errno
20 #include <Xm/CascadeB.h>
21 #include <Xm/DrawingA.h>
22 #include <Xm/Frame.h>
23 #include <Xm/Form.h>
24 #include <Xm/Label.h>
25 #include <Xm/List.h>
26 #include <Xm/PushB.h>
27 #include <Xm/RowColumn.h>
28 #include <Xm/ScrolledW.h>
29 #include <Xm/Separator.h>
30 #include <Xm/AtomMgr.h>
31 #if !defined(ibm6000)
32 #define class ____class
33 #define new ____new
34 #endif
35 #include <Xm/ScrolledWP.h>
36 #if !defined(ibm6000)
37 #undef class
38 #undef new
39 #endif
40 #include <Xm/ScrollBar.h>
41 
42 #include <X11/cursorfont.h>
43 
44 
45 #include "../widgets/WorkspaceW.h"
46 #include "EditorWindow.h"
47 #include "Ark.h"
48 #include "ButtonInterface.h"
49 #include "ColormapNode.h"
50 #include "ImageNode.h"
51 #include "ConfigurationDialog.h"
52 #include "ControlPanel.h"
53 #include "EditorToolSelector.h"
54 #include "VPERoot.h"
55 #include "ErrorDialogManager.h"
56 #include "DXApplication.h"
57 #include "DeleteNodeCommand.h"
58 #include "Dictionary.h"
59 #include "DictionaryIterator.h"
60 #include "InteractorNode.h"
61 #include "InteractorInstance.h"
62 #include "Network.h"
63 #include "NoUndoEditorCommand.h"
64 #include "NoUndoDXAppCommand.h"
65 #include "NodeDefinition.h"
66 #include "Node.h"
67 #include "Parameter.h"
68 #include "StandIn.h"
69 #include "ArkStandIn.h"
70 #include "ToggleButtonInterface.h"
71 #include "ToolPanelCommand.h"
72 #include "PanelAccessManager.h"
73 #include "PanelGroupManager.h"
74 #include "CloseWindowCommand.h"
75 #include "List.h"
76 #include "ListIterator.h"
77 #include "ProcessGroupCreateDialog.h"
78 #include "ProcessGroupAssignDialog.h"
79 #include "ControlPanelGroupDialog.h"
80 #include "ControlPanelAccessDialog.h"
81 #include "CreateMacroDialog.h"
82 #include "WarningDialogManager.h"
83 #include "InfoDialogManager.h"
84 #include "FindToolDialog.h"
85 #include "GridDialog.h"
86 #include "DXStrings.h"
87 #include "MacroNode.h"
88 #include "MacroDefinition.h"
89 #include "MacroParameterDefinition.h"
90 #include "MacroParameterNode.h"
91 #include "DeferrableAction.h"
92 #include "QuestionDialogManager.h"
93 #include "Decorator.h"
94 #include "LabelDecorator.h"
95 #include "VPEAnnotator.h"
96 #include "DecoratorStyle.h"
97 #include "DecoratorInfo.h"
98 #include "PrintProgramDialog.h"
99 #include "TransferAccelerator.h"
100 #if WORKSPACE_PAGES
101 #include "PageGroupManager.h"
102 #include "AnnotationGroupManager.h"
103 #include "PageSelector.h"
104 #endif
105 
106 #ifdef DXUI_DEVKIT
107 #include "SaveAsCCodeDialog.h"
108 #endif // DXUI_DEVKIT
109 
110 #include "CascadeMenu.h"
111 #include "TransmitterNode.h"
112 #include "ReceiverNode.h"
113 #include "GlobalLocalNode.h"
114 #include "DXLInputNode.h"
115 #include "GraphLayout.h"
116 #include "UndoMove.h"
117 #include "UndoDeletion.h"
118 #include "UndoRepeatableTab.h"
119 #include "UndoAddArk.h"
120 #include "Stack.h"
121 #include "XHandler.h"
122 
123 #ifndef FORGET_GETSET
124 #include "GetSetConversionDialog.h"
125 Command *EditorWindow::SelectedToGlobalCmd = NULL;
126 Command *EditorWindow::SelectedToLocalCmd = NULL;
127 GetSetConversionDialog *EditorWindow::GetSetDialog = NULL;
128 #endif
129 
130 #ifdef DXD_WIN
131 #define unlink _unlink
132 #endif
133 
134 //
135 // Transmitter/Receiver for the execution/loop sequence numbers
136 #define JAVA_SEQUENCE "java_sequence"
137 
138 // If you change this, you break existing nets
139 #define JAVA_SEQ_PAGE "java tools"
140 
141 #include "EWDefaultResources.h"
142 
143 #define NET_ATOM "NET_CONTENTS"
144 #define CFG_ATOM "CFG_CONTENTS"
145 
146 boolean EditorWindow::ClassInitialized = FALSE;
147 
EditorWindow(boolean isAnchor,Network * network)148 EditorWindow::EditorWindow(boolean  isAnchor, Network* network) :
149 			   DXWindow("editorWindow", isAnchor)
150 {
151     ASSERT(network);
152 
153     //
154     // Save associated network and designate self as the editor
155     // for this network.
156     //
157     this->network = network;
158     this->initialNetwork = TRUE;
159     this->lastSelectedTransmitter = NULL;
160 
161     ASSERT(this->network->editor == NUL(EditorWindow*));
162     this->network->editor = this;
163     this->network->showEditorMessages();
164 
165     //
166     // The panel is visible initially.
167     //
168     this->panelVisible = TRUE;
169 
170     //
171     // Initially set hit detection to FALSE.  It's not saved in
172     // the net file currently.
173     //
174     this->hit_detection = FALSE;
175 
176     //
177     // Set the origin flag
178     //
179     this->resetOrigin();
180 
181     this->findToolDialog 	   = NULL;
182     this->printProgramDialog 	   = NULL;
183     this->saveAsCCodeDialog 	   = NULL;
184     this->panelGroupDialog 	   = NULL;
185     this->gridDialog		   = NULL;
186     this->processGroupCreateDialog = NULL;
187     this->processGroupAssignDialog = NULL;
188     this->createMacroDialog        = NULL;
189     this->insertNetworkDialog      = NULL;
190 
191     //
192     // Initialize member data.
193     //
194     this->currentPanel   = NUL(ControlPanel*);
195 
196     this->fileMenu       = NUL(Widget);
197     this->editMenu       = NUL(Widget);
198     this->windowsMenu    = NUL(Widget);
199     this->optionsMenu    = NUL(Widget);
200 
201     this->fileMenuPulldown       = NUL(Widget);
202     this->editMenuPulldown       = NUL(Widget);
203     this->windowsMenuPulldown    = NUL(Widget);
204     this->optionsMenuPulldown    = NUL(Widget);
205 
206     this->newOption          = NUL(CommandInterface*);
207     this->openOption         = NUL(CommandInterface*);
208     this->loadMacroOption    = NUL(CommandInterface*);
209     this->loadMDFOption    = NUL(CommandInterface*);
210     this->saveOption         = NUL(CommandInterface*);
211     this->saveAsOption       = NUL(CommandInterface*);
212     this->settingsCascade    = NULL;
213     this->saveCfgOption	     = NULL;
214     this->openCfgOption	     = NULL;
215     this->printProgramOption = NUL(CommandInterface*);
216     this->saveAsCCodeOption  = NUL(CommandInterface*);
217     this->quitOption         = NUL(CommandInterface*);
218     this->closeOption         = NUL(CommandInterface*);
219 
220     this->undoOption              = NUL(CommandInterface*);
221     this->valuesOption            = NUL(CommandInterface*);
222     this->findToolOption          = NUL(CommandInterface*);
223     this->Ox			  = -1;
224     this->find_restore_page       = NUL(char*);
225 #ifndef FORGET_GETSET
226     this->programVerifyCascade    = NUL(CascadeMenu*);
227 #endif
228     this->editTabsCascade	  = NULL;
229     this->addInputTabOption	  = NUL(CommandInterface*);
230     this->removeInputTabOption	  = NUL(CommandInterface*);
231     this->editSelectCascade	  = NULL;
232     this->outputCacheabilityCascade	    = NULL;
233     this->editOutputCacheabilityCascade	    = NULL;
234 #if WORKSPACE_PAGES
235     this->pageCascade	          = NULL;
236 #endif
237     this->javaCascade	          = NULL;
238     this->deleteOption            = NUL(CommandInterface*);
239     this->cutOption            	  = NUL(CommandInterface*);
240     this->copyOption              = NUL(CommandInterface*);
241     this->pasteOption             = NUL(CommandInterface*);
242     this->macroNameOption         = NUL(CommandInterface*);
243     this->reflowGraphOption       = NUL(CommandInterface*);
244     this->createMacroOption	  = NULL;
245     this->insertNetworkOption     = NUL(CommandInterface*);
246     this->addAnnotationOption     = NUL(CommandInterface*);
247     this->createProcessGroupOption= NUL(CommandInterface*);
248     this->assignProcessGroupOption= NUL(CommandInterface*);
249     this->commentOption           = NUL(CommandInterface*);
250 
251     this->newControlPanelOption        = NUL(CommandInterface*);
252     this->openControlPanelOption       = NUL(CommandInterface*);
253     this->openAllControlPanelsOption   = NUL(CommandInterface*);
254     this->openControlPanelByNameMenu   = NULL;
255     this->openMacroOption              = NUL(CommandInterface*);
256     this->openImageOption              = NUL(CommandInterface*);
257     this->openColormapEditorOption     = NUL(CommandInterface*);
258 
259     this->toolPalettesOption  = NUL(CommandInterface*);
260     this->panelGroupOption    = NUL(CommandInterface*);
261     this->gridOption          = NUL(CommandInterface*);
262 
263     this->onVisualProgramOption = NUL(CommandInterface*);
264     this->messageWindowOption   = NUL(CommandInterface*);
265     this->workSpace = NULL;
266     this->addingDecorators = NUL(List*);
267     this->pendingPaste = NUL(Network*);
268     this->copiedNet = NUL(char*);
269     this->copiedCfg = NUL(char*);
270 
271     //
272     // Create the commands.
273     //
274 
275     //
276     // File menu commands
277     //
278     this->closeCmd =
279         new CloseWindowCommand("close",this->commandScope,TRUE,this);
280 
281     this->printProgramCmd =
282 	new NoUndoEditorCommand
283 	    ("printProgram", this->commandScope, FALSE,
284 		this, NoUndoEditorCommand::PrintProgram, NoUndoEditorCommand::Ignore);
285 
286 #ifdef DXUI_DEVKIT
287     this->saveAsCCodeCmd =
288 	new NoUndoEditorCommand
289 	    ("saveAsCCode", this->commandScope, FALSE,
290 		this, NoUndoEditorCommand::SaveAsCCode, NoUndoEditorCommand::Ignore);
291 #else
292     this->saveAsCCodeCmd = NULL;
293 #endif
294 
295     //
296     // Edit menu commands
297     //
298     this->undoCmd =
299 	new NoUndoEditorCommand
300 	    ("undo", this->commandScope, FALSE,
301 	        this, NoUndoEditorCommand::Undo, NoUndoEditorCommand::Ignore);
302     this->valuesCmd =
303 	new NoUndoEditorCommand
304 	    ("values", this->commandScope, FALSE,
305 		this, NoUndoEditorCommand::ShowConfiguration,
306 		NoUndoEditorCommand::Ignore);
307 
308     this->findToolCmd =
309 	new NoUndoEditorCommand
310 	    ("findTool", this->commandScope, FALSE,
311 		this, NoUndoEditorCommand::OpenFindTool,
312 		NoUndoEditorCommand::Ignore);
313 
314     this->addInputTabCmd =
315 	new NoUndoEditorCommand
316 	    ("addInputTab", this->commandScope, FALSE,
317 		this, NoUndoEditorCommand::AddInputTab,
318 		NoUndoEditorCommand::AffectsUndo|NoUndoEditorCommand::CanBeUndone);
319 
320     this->removeInputTabCmd =
321 	new NoUndoEditorCommand
322 	    ("removeInputTab", this->commandScope, FALSE,
323 		this, NoUndoEditorCommand::RemoveInputTab,
324 		NoUndoEditorCommand::AffectsUndo|NoUndoEditorCommand::CanBeUndone);
325 
326     this->addOutputTabCmd =
327 	new NoUndoEditorCommand
328 	    ("addOutputTab", this->commandScope, FALSE,
329 		this, NoUndoEditorCommand::AddOutputTab,
330 		NoUndoEditorCommand::AffectsUndo|NoUndoEditorCommand::CanBeUndone);
331 
332     this->removeOutputTabCmd =
333 	new NoUndoEditorCommand
334 	    ("removeOutputTab", this->commandScope, FALSE,
335 		this, NoUndoEditorCommand::RemoveOutputTab,
336 		NoUndoEditorCommand::AffectsUndo|NoUndoEditorCommand::CanBeUndone);
337 
338     this->hideAllTabsCmd =
339 	new NoUndoEditorCommand
340 	    ("hideAllTabs", this->commandScope, FALSE,
341 		this, NoUndoEditorCommand::HideAllTabs);
342 
343     this->revealAllTabsCmd =
344 	new NoUndoEditorCommand
345 	    ("revealAllTabs", this->commandScope, FALSE,
346 		this, NoUndoEditorCommand::RevealAllTabs);
347 
348 #ifndef FORGET_GETSET
349     this->postGetSetCmd =
350 	new NoUndoEditorCommand
351 	    ("postGetSet", this->commandScope, TRUE,
352 		this, NoUndoEditorCommand::PostGetSet,
353 		NoUndoEditorCommand::Ignore);
354     this->toLocalCmd =
355 	new NoUndoEditorCommand
356 	    ("setToLocal", this->commandScope, FALSE,
357 		this, NoUndoEditorCommand::SelectedToLocal);
358     this->toGlobalCmd =
359 	new NoUndoEditorCommand
360 	    ("setToGlobal", this->commandScope, FALSE,
361 		this, NoUndoEditorCommand::SelectedToGlobal);
362 #endif
363 
364     this->deleteNodeCmd =
365 	new DeleteNodeCommand
366 	    ("deleteNode", this->commandScope, FALSE, this);
367 
368     this->cutNodeCmd =
369 	new NoUndoEditorCommand
370 	    ("cutNode", this->commandScope, FALSE,
371 		this, NoUndoEditorCommand::CutNode,
372 		NoUndoEditorCommand::AffectsUndo|NoUndoEditorCommand::CanBeUndone);
373 
374     this->copyNodeCmd =
375 	new NoUndoEditorCommand
376 	    ("copyNode", this->commandScope, FALSE,
377 		this, NoUndoEditorCommand::CopyNode,
378 		NoUndoEditorCommand::Ignore);
379 
380     this->pasteNodeCmd =
381 	new NoUndoEditorCommand
382 	    ("pasteNode", this->commandScope, TRUE,
383 		this, NoUndoEditorCommand::PasteNode);
384 
385     this->selectAllNodeCmd =
386 	new NoUndoEditorCommand
387 	    ("selectAllNode", this->commandScope, FALSE,
388 		this, NoUndoEditorCommand::SelectAll,
389 		NoUndoEditorCommand::Ignore);
390 
391     this->selectConnectedNodeCmd =
392 	new NoUndoEditorCommand
393 	    ("selectConnectedNode", this->commandScope, FALSE,
394 		this, NoUndoEditorCommand::SelectConnected,
395 		NoUndoEditorCommand::Ignore);
396 
397     this->selectUnconnectedNodeCmd =
398 	new NoUndoEditorCommand
399 	    ("selectUnconectedNode", this->commandScope, FALSE,
400 		this, NoUndoEditorCommand::SelectUnconnected,
401 		NoUndoEditorCommand::Ignore);
402 
403     this->selectUpwardNodeCmd =
404 	new NoUndoEditorCommand
405 	    ("selectUpwardNode", this->commandScope, FALSE,
406 		this, NoUndoEditorCommand::SelectUpward,
407 		NoUndoEditorCommand::Ignore);
408 
409     this->selectDownwardNodeCmd =
410 	new NoUndoEditorCommand
411 	    ("selectDownwardNode", this->commandScope, FALSE,
412 		this, NoUndoEditorCommand::SelectDownward,
413 		NoUndoEditorCommand::Ignore);
414 
415     this->deselectAllNodeCmd =
416 	new NoUndoEditorCommand
417 	    ("deselectAllNode", this->commandScope, FALSE,
418 		this, NoUndoEditorCommand::DeselectAll,
419 		NoUndoEditorCommand::Ignore);
420 
421     this->selectUnselectedNodeCmd =
422 	new NoUndoEditorCommand
423 	    ("selectUnselectedNode", this->commandScope, FALSE,
424 		this, NoUndoEditorCommand::SelectUnselected,
425 		NoUndoEditorCommand::Ignore);
426 
427     this->showExecutedCmd =
428 	new NoUndoEditorCommand
429 	    ("showExecuted", this->commandScope, FALSE,
430 		this, NoUndoEditorCommand::ShowExecutedNodes,
431 		NoUndoEditorCommand::Ignore);
432 
433 #ifndef FORGET_GETSET
434     if (!EditorWindow::SelectedToGlobalCmd) {
435 	EditorWindow::SelectedToGlobalCmd = new NoUndoEditorCommand
436 	    ("SelectedToGlobal", this->commandScope, FALSE,
437 		this, NoUndoEditorCommand::ToGlobal);
438 
439 	EditorWindow::SelectedToLocalCmd = new NoUndoEditorCommand
440 	    ("SelectedToLocal", this->commandScope, FALSE,
441 		this, NoUndoEditorCommand::ToLocal);
442     }
443 #endif
444 
445     this->cacheAllOutputsCmd =
446 	new NoUndoEditorCommand
447 	    ("cacheAllOutputsCmd", this->commandScope, TRUE,
448 		this, NoUndoEditorCommand::SetOutputsFullyCached,
449 		NoUndoEditorCommand::Ignore);
450     this->cacheLastOutputsCmd =
451 	new NoUndoEditorCommand
452 	    ("cacheLastOutputsCmd", this->commandScope, TRUE,
453 		this, NoUndoEditorCommand::SetOutputsCacheOnce,
454 		NoUndoEditorCommand::Ignore);
455     this->cacheNoOutputsCmd =
456 	new NoUndoEditorCommand
457 	    ("cacheNoOutputsCmd", this->commandScope, TRUE,
458 		this, NoUndoEditorCommand::SetOutputsNotCached,
459 		NoUndoEditorCommand::Ignore);
460 
461     this->optimizeCacheabilityCmd =
462 	new NoUndoEditorCommand
463 	    ("optimizeCacheabilityCmd", this->commandScope, TRUE,
464 		this, NoUndoEditorCommand::OptimizeOutputCacheability,
465 		NoUndoEditorCommand::Ignore);
466 
467     this->showCacheAllOutputsCmd =
468 	new NoUndoEditorCommand
469 	    ("showCacheAllOutputsCmd", this->commandScope, TRUE,
470 		this, NoUndoEditorCommand::ShowOutputsFullyCached,
471 		NoUndoEditorCommand::Ignore);
472     this->showCacheLastOutputsCmd =
473 	new NoUndoEditorCommand
474 	    ("showCacheLastOutputsCmd", this->commandScope, TRUE,
475 		this, NoUndoEditorCommand::ShowOutputsCacheOnce,
476 		NoUndoEditorCommand::Ignore);
477     this->showCacheNoOutputsCmd =
478 	new NoUndoEditorCommand
479 	    ("showCacheNoOutputsCmd", this->commandScope, TRUE,
480 		this, NoUndoEditorCommand::ShowOutputsNotCached,
481 		NoUndoEditorCommand::Ignore);
482 
483 
484     this->editMacroNameCmd =
485 	new NoUndoEditorCommand
486 	    ("editMacroName", this->commandScope, TRUE,
487 		this, NoUndoEditorCommand::EditMacroName);
488 
489     this->editCommentCmd =
490 	new NoUndoEditorCommand
491 	    ("editComment", this->commandScope, TRUE,
492 		this, NoUndoEditorCommand::EditComment,
493 		NoUndoEditorCommand::Ignore);
494 
495     this->createProcessGroupCmd =
496 	new NoUndoEditorCommand
497 	    ("createProcessGroup", this->commandScope, isAnchor,
498 		this, NoUndoEditorCommand::CreateProcessGroup,
499 		NoUndoEditorCommand::Ignore);
500 
501     this->insertNetCmd =
502 	new NoUndoEditorCommand
503 	    ("insertNet", this->commandScope, TRUE,
504 		this, NoUndoEditorCommand::InsertNetwork);
505 
506     this->addAnnotationCmd =
507 	new NoUndoEditorCommand
508 	    ("addAnnotation", this->commandScope, TRUE,
509 		this, NoUndoEditorCommand::AddAnnotation);
510 
511     this->macroifyCmd =
512 	new NoUndoEditorCommand
513 	    ("macroify", this->commandScope, FALSE,
514 		this, NoUndoEditorCommand::Macroify);
515 
516 #if WORKSPACE_PAGES
517     this->pagifyCmd =
518 	new NoUndoEditorCommand
519 	    ("pagify", this->commandScope, TRUE,
520 		this, NoUndoEditorCommand::Pagify);
521 
522     this->pagifySelectedCmd =
523 	new NoUndoEditorCommand
524 	    ("pagifySelected", this->commandScope, FALSE,
525 		this, NoUndoEditorCommand::PagifySelected);
526 
527     this->autoChopSelectedCmd =
528 	new NoUndoEditorCommand
529 	    ("autoChopSelected", this->commandScope, FALSE,
530 		this, NoUndoEditorCommand::AutoChopSelected);
531 
532     this->autoFuseSelectedCmd =
533 	new NoUndoEditorCommand
534 	    ("autoFuseSelected", this->commandScope, FALSE,
535 		this, NoUndoEditorCommand::AutoFuseSelected);
536 
537     this->deletePageCmd =
538 	new NoUndoEditorCommand
539 	    ("deletePage", this->commandScope, FALSE,
540 		this, NoUndoEditorCommand::DeletePage);
541 
542     this->configurePageCmd =
543 	new NoUndoEditorCommand
544 	    ("configurePage", this->commandScope, TRUE,
545 		this, NoUndoEditorCommand::ConfigurePage,
546 		NoUndoEditorCommand::Ignore);
547 
548     this->moveSelectedCmd =
549 	new NoUndoEditorCommand
550 	    ("moveSelectedNodes", this->commandScope, TRUE,
551 		this, NoUndoEditorCommand::MoveSelected);
552 #endif
553 
554     if (this->network->isMacro() == FALSE) {
555 
556 	this->javifyNetCmd = new NoUndoEditorCommand
557 	    ("javifyNetwork", this->commandScope, FALSE,
558 		this, NoUndoEditorCommand::JavifyNetwork);
559 	this->unjavifyNetCmd = new NoUndoEditorCommand
560 	    ("unJavifyNetwork", this->commandScope, TRUE,
561 		this, NoUndoEditorCommand::UnjavifyNetwork);
562     } else {
563 	this->javifyNetCmd = NUL(Command*);
564 	this->unjavifyNetCmd = NUL(Command*);
565     }
566     this->reflowGraphCmd =
567 	new NoUndoEditorCommand ("reflowGraph", this->commandScope, FALSE,
568 		this, NoUndoEditorCommand::ReflowGraph,
569 		NoUndoEditorCommand::AffectsUndo|NoUndoEditorCommand::CanBeUndone);
570 
571     //
572     // Window's menu commands
573     //
574     this->openMacroCmd =
575         new NoUndoEditorCommand("openMacroCommand", this->commandScope,
576                         FALSE,this, NoUndoEditorCommand::OpenSelectedMacros,
577 			NoUndoEditorCommand::Ignore);
578 
579     this->openColormapCmd =
580         new NoUndoEditorCommand("openColormapCmd",
581                         this->commandScope,
582                         FALSE,
583                         this,
584                         NoUndoEditorCommand::OpenSelectedColormaps,
585 			NoUndoEditorCommand::Ignore);
586     this->openImageCmd =
587         new NoUndoEditorCommand("openImageCommand", this->commandScope,
588                         FALSE,this,
589 			NoUndoEditorCommand::OpenSelectedImageWindows,
590 			NoUndoEditorCommand::Ignore);
591 
592     this->newControlPanelCmd =
593 	new NoUndoEditorCommand
594 	    ("newControlPanel", this->commandScope, TRUE,
595 		this, NoUndoEditorCommand::NewControlPanel,
596 		NoUndoEditorCommand::Ignore);
597 
598     this->openControlPanelCmd =
599 	new NoUndoEditorCommand
600 	    ("openControlPanel", this->commandScope, FALSE,
601 		this, NoUndoEditorCommand::OpenControlPanel,
602 		NoUndoEditorCommand::Ignore);
603 
604     //
605     // Options's menu commands
606     //
607     this->toolPanelCmd =
608 	new ToolPanelCommand
609 	    ("toolPalettes", this->commandScope, TRUE, this);
610 
611     this->hitDetectionCmd =
612 	new NoUndoEditorCommand
613 	    ("hitDetector", this->commandScope, TRUE,
614 		this, NoUndoEditorCommand::HitDetection,
615 		NoUndoEditorCommand::Ignore);
616 
617     this->setPanelAccessCmd =
618 	new NoUndoEditorCommand
619 	    ("setAccess", this->commandScope, FALSE,
620 		this, NoUndoEditorCommand::SetCPAccess,
621 		NoUndoEditorCommand::Ignore);
622 
623     this->setPanelGroupCmd =
624 	new NoUndoEditorCommand
625 	    ("setGroup", this->commandScope, FALSE,
626 		this, NoUndoEditorCommand::SetPanelGroup,
627 		NoUndoEditorCommand::Ignore);
628 
629     this->gridCmd =
630 	new NoUndoEditorCommand
631 	    ("grid", this->commandScope, TRUE,
632 		this, NoUndoEditorCommand::OpenGrid,
633 		NoUndoEditorCommand::Ignore);
634 
635     this->deferrableCommandActivation = new DeferrableAction(
636 				EditorWindow::SetCommandActivation,
637 				(void*)this);
638 
639     this->addInputTabCmd->autoActivate(this->removeInputTabCmd);
640     this->addOutputTabCmd->autoActivate(this->removeOutputTabCmd);
641     this->revealAllTabsCmd->autoActivate(this->hideAllTabsCmd);
642     this->hideAllTabsCmd->autoActivate(this->revealAllTabsCmd);
643 
644     this->resetWindowTitle();
645 
646     //
647     // List of executed nodes
648     //
649     this->executed_nodes = NUL(List*);
650     this->executing_node = NUL(Node*);
651     this->transmitters_added = FALSE;
652     this->errored_standins = NUL(List*);
653 
654     //
655     // Graph layout
656     //
657     this->layout_controller = NULL;
658 
659     //
660     // Undo list management
661     //
662     this->moving_many_standins = FALSE;
663     this->performing_undo = FALSE;
664     this->creating_new_network = FALSE;
665 
666     // work around for a motif bug
667     this->pgKeyHandler = NUL(XHandler*);
668 
669     //
670     // Install the default resources for THIS class (not the derived classes)
671     //
672     if (NOT EditorWindow::ClassInitialized)
673     {
674 	ASSERT(theApplication);
675         EditorWindow::ClassInitialized = TRUE;
676 	this->installDefaultResources(theApplication->getRootWidget());
677     }
678 }
679 
680 
~EditorWindow()681 EditorWindow::~EditorWindow()
682 {
683 
684     //
685     // Delete the dialogs.
686     //
687     if(this->findToolDialog)
688 	delete this->findToolDialog;
689     if(this->printProgramDialog)
690 	delete this->printProgramDialog;
691     if(this->saveAsCCodeDialog)
692 	delete this->saveAsCCodeDialog;
693     if(this->panelGroupDialog)
694 	delete this->panelGroupDialog;
695     if(this->gridDialog)
696 	delete this->gridDialog;
697     if(this->processGroupCreateDialog)
698 	delete this->processGroupCreateDialog;
699     if(this->processGroupAssignDialog)
700 	delete this->processGroupAssignDialog;
701     if(this->createMacroDialog)
702 	delete this->createMacroDialog;
703     if(this->insertNetworkDialog)
704 	delete this->insertNetworkDialog;
705 
706     //
707     // File menu options
708     //
709     if (this->newOption) delete this->newOption;
710     if (this->openOption) delete this->openOption;
711     if (this->loadMacroOption) delete this->loadMacroOption;
712     if (this->loadMDFOption) delete this->loadMDFOption;
713     if (this->saveOption) delete this->saveOption;
714     if (this->saveAsOption) delete this->saveAsOption;
715     if (this->settingsCascade) delete this->settingsCascade;
716     if (this->saveCfgOption) delete this->saveCfgOption;
717     if (this->openCfgOption) delete this->openCfgOption;
718     if (this->printProgramOption) delete this->printProgramOption;
719     if (this->saveAsCCodeOption) delete this->saveAsCCodeOption;
720     if (this->quitOption) delete this->quitOption;
721     if (this->closeOption) delete this->closeOption;
722 
723     //
724     // Edit menu options
725     //
726     if (this->undoOption) delete this->undoOption;
727     if (this->valuesOption) delete this->valuesOption;
728     if (this->findToolOption) delete this->findToolOption;
729 #ifndef FORGET_GETSET
730     if (this->programVerifyCascade) delete this->programVerifyCascade;
731 #endif
732     if (this->editTabsCascade) delete this->editTabsCascade;
733     //if (this->addInputTabOption) delete this->addInputTabOption;
734     //if (this->removeInputTabOption) delete this->removeInputTabOption;
735     if (this->editSelectCascade) delete this->editSelectCascade;
736     if (this->editOutputCacheabilityCascade) delete this->editOutputCacheabilityCascade;
737     if (this->outputCacheabilityCascade) delete this->outputCacheabilityCascade;
738 #if WORKSPACE_PAGES
739     if (this->pageCascade) delete this->pageCascade;
740 #endif
741     if (this->javaCascade) delete this->javaCascade;
742     if (this->deleteOption) delete this->deleteOption;
743     if (this->cutOption) delete this->cutOption;
744     if (this->copyOption) delete this->copyOption;
745     if (this->pasteOption) delete this->pasteOption;
746     if (this->macroNameOption) delete this->macroNameOption;
747     if (this->reflowGraphOption) delete this->reflowGraphOption;
748     if (this->createMacroOption) delete this->createMacroOption;
749     if (this->insertNetworkOption) delete this->insertNetworkOption;
750     if (this->addAnnotationOption) delete this->addAnnotationOption;
751     if (this->createProcessGroupOption) delete this->createProcessGroupOption;
752     if (this->commentOption) delete this->commentOption;
753 
754 
755     //
756     // Windows options
757     //
758     if (this->newControlPanelOption) delete this->newControlPanelOption;
759     if (this->openControlPanelOption) delete this->openControlPanelOption;
760     if (this->openAllControlPanelsOption) delete this->openAllControlPanelsOption;
761     if (this->openControlPanelByNameMenu) delete this->openControlPanelByNameMenu;
762     if (this->openMacroOption) delete this->openMacroOption;
763     if (this->openImageOption) delete this->openImageOption;
764     if (this->openColormapEditorOption) delete this->openColormapEditorOption;
765     if (this->messageWindowOption) delete this->messageWindowOption;
766 
767     //
768     // Options options
769     //
770     if (this->toolPalettesOption) delete this->toolPalettesOption;
771     if (this->gridOption) delete this->gridOption;
772     if (this->panelGroupOption) delete this->panelGroupOption;
773     if (this->panelAccessOption) delete this->panelAccessOption;
774 
775     if (this->onVisualProgramOption) delete this->onVisualProgramOption;
776 
777     if (this->workSpace) delete this->workSpace;
778 
779     //
780     // Delete the commands after the command interfaces.
781     //
782     delete this->toolPanelCmd;
783     delete this->hitDetectionCmd;
784     delete this->showExecutedCmd;
785     delete this->newControlPanelCmd;
786     delete this->openControlPanelCmd;
787     delete this->undoCmd;
788     delete this->valuesCmd;
789     delete this->addInputTabCmd;
790     delete this->removeInputTabCmd;
791     delete this->addOutputTabCmd;
792     delete this->removeOutputTabCmd;
793     delete this->hideAllTabsCmd;
794     delete this->revealAllTabsCmd;
795 #ifndef FORGET_GETSET
796     delete this->postGetSetCmd;
797     delete this->toLocalCmd;
798     delete this->toGlobalCmd;
799 #endif
800     delete this->deleteNodeCmd;
801     delete this->cutNodeCmd;
802     delete this->copyNodeCmd;
803     delete this->pasteNodeCmd;
804     delete this->selectAllNodeCmd;
805     delete this->selectConnectedNodeCmd;
806     delete this->selectUnconnectedNodeCmd;
807     delete this->selectUnselectedNodeCmd;
808     delete this->selectUpwardNodeCmd;
809     delete this->selectDownwardNodeCmd;
810     delete this->cacheAllOutputsCmd;
811     delete this->cacheLastOutputsCmd;
812     delete this->cacheNoOutputsCmd;
813     delete this->showCacheAllOutputsCmd;
814     delete this->showCacheLastOutputsCmd;
815     delete this->showCacheNoOutputsCmd;
816     delete this->optimizeCacheabilityCmd;
817     delete this->deselectAllNodeCmd;
818     delete this->insertNetCmd;
819     delete this->addAnnotationCmd;
820     delete this->macroifyCmd;
821 #if WORKSPACE_PAGES
822     delete this->pagifyCmd;
823     delete this->pagifySelectedCmd;
824     delete this->autoChopSelectedCmd;
825     delete this->autoFuseSelectedCmd;
826     delete this->deletePageCmd;
827     delete this->configurePageCmd;
828     delete this->moveSelectedCmd;
829 #endif
830     if (this->javifyNetCmd) delete this->javifyNetCmd;
831     if (this->unjavifyNetCmd) delete this->unjavifyNetCmd;
832     delete this->reflowGraphCmd;
833     delete this->editMacroNameCmd;
834     delete this->editCommentCmd;
835     delete this->findToolCmd;
836     delete this->gridCmd;
837     delete this->setPanelAccessCmd;
838     delete this->setPanelGroupCmd;
839     delete this->createProcessGroupCmd;
840     delete this->openImageCmd;
841     delete this->openColormapCmd;
842     delete this->openMacroCmd;
843     delete this->closeCmd;
844     delete this->printProgramCmd;
845     if (this->saveAsCCodeCmd) delete this->saveAsCCodeCmd;
846 
847     this->network->editor = NUL(EditorWindow*);
848 
849     delete this->deferrableCommandActivation;
850 
851     //
852     // Delete the category/tool lists for this editor.
853     //
854     delete this->toolSelector;
855 #if WORKSPACE_PAGES
856     delete this->pageSelector;
857 #endif
858 
859     if (this->addingDecorators) delete this->addingDecorators;
860     if (this->pendingPaste) delete this->pendingPaste;
861     if (this->copiedNet) delete this->copiedNet;
862     if (this->copiedCfg) delete this->copiedCfg;
863     if (this->executed_nodes) delete this->executed_nodes;
864     if (this->errored_standins) delete this->errored_standins;
865     if (this->layout_controller) delete this->layout_controller;
866     this->clearUndoList();
867 
868     if (this->find_restore_page) delete this->find_restore_page;
869 
870     if (this->pgKeyHandler) delete this->pgKeyHandler;;
871 }
872 
873 //
874 // Install the default resources for this class.
875 //
installDefaultResources(Widget baseWidget)876 void EditorWindow::installDefaultResources(Widget baseWidget)
877 {
878     this->setDefaultResources(baseWidget, EditorWindow::DefaultResources);
879     this->DXWindow::installDefaultResources(baseWidget);
880 }
881 
SetCommandActivation(void * editor,void * requestData)882 void EditorWindow::SetCommandActivation(void *editor, void *requestData)
883 {
884     ((EditorWindow*)editor)->setCommandActivation();
885 }
886 //
887 // De/Activate any commands that have to do with editing.
888 // Should be called when a node is added or deleted or there is a selection
889 // status change.
890 //
setCommandActivation()891 void EditorWindow::setCommandActivation()
892 {
893     int nselected;
894 
895     int nodes = this->getNetwork()->getNodeCount();
896 
897     int decors = 0;
898     int dselected = 0;
899     decors = this->getNetwork()->decoratorList.getSize();
900     ListIterator it;
901     Decorator *decor;
902     FOR_EACH_NETWORK_DECORATOR(this->getNetwork(),decor,it) {
903 	if (decor->isSelected()) dselected++;
904     }
905 
906     //
907     // Are execution results available?
908     //
909     if ((this->executed_nodes) && (this->executed_nodes->getSize())) {
910 	this->showExecutedCmd->activate();
911     } else {
912 	this->showExecutedCmd->deactivate();
913     }
914 
915     //
916     // count the nodes in the current page
917     //
918     WorkSpace *current_ws = this->workSpace;
919     int page = this->workSpace->getCurrentPage();
920     if (page) current_ws = this->workSpace->getElement(page);
921     int nodes_in_current_page = 0;
922     Node *n;
923     ListIterator iterator;
924     FOR_EACH_NETWORK_NODE(this->network, n, iterator) {
925 	StandIn* si = n->getStandIn();
926 	if (!si) continue;
927 	if (si->getWorkSpace() == current_ws)
928 	    nodes_in_current_page++;
929     }
930 
931     //
932     // Is undo available?  ...also sets button label
933     //
934     this->setUndoActivation();
935 
936     //
937     // Handle commands that depend on whether there are nodes in the current page
938     //
939     if (nodes_in_current_page==0) {
940 	this->reflowGraphCmd->deactivate();
941     } else {
942 	this->reflowGraphCmd->activate();
943     }
944 
945     //
946     // Handle commands that depend on whether there are nodes
947     //
948     if (nodes == 0) {
949 	if (decors == 0)
950 	    this->selectAllNodeCmd->deactivate();
951 	else
952 	    this->selectAllNodeCmd->activate();
953 	this->findToolCmd->deactivate();
954 	this->printProgramCmd->deactivate();
955 	if (this->saveAsCCodeCmd)
956 	    this->saveAsCCodeCmd->deactivate();
957 	nselected = 0;
958 	this->outputCacheabilityCascade->deactivate();
959     } else {
960 	this->selectAllNodeCmd->activate();
961 	this->findToolCmd->activate();
962 	this->printProgramCmd->activate();
963 	if (this->saveAsCCodeCmd)
964 	    this->saveAsCCodeCmd->activate();
965 	nselected = this->getNodeSelectionCount();
966 	this->outputCacheabilityCascade->activate();
967     }
968 
969     //
970     // Set Activation of commands that depend on whether or not the
971     // network is a macro.
972     // FIXME: should ASSERT(net), but just before 2.0 release we'll be
973     //	      VERY careful.
974     //
975     Network *net = this->getNetwork();
976     if ((nodes != 0) && net && !net->isMacro()) {
977         this->createProcessGroupCmd->activate();
978     } else {
979         this->createProcessGroupCmd->deactivate();
980     }
981 
982 #ifndef FORGET_GETSET
983     EditorWindow *ew =
984 	((EditorWindow::GetSetDialog && EditorWindow::GetSetDialog->isManaged())?
985 	  EditorWindow::GetSetDialog->getActiveEditor():
986 	  NULL);
987     if ((EditorWindow::GetSetDialog) &&
988 	(EditorWindow::GetSetDialog->isManaged()) && (!ew)) {
989 	EditorWindow::GetSetDialog->setActiveEditor(this);
990 	ew = EditorWindow::GetSetDialog->getActiveEditor();
991     }
992 #endif
993 
994     //
995     // Handle commands that depend on whether there are populated pages
996     //
997 #if WORKSPACE_PAGES
998     if (this->pageSelector->getSize() > 1) {
999 	this->deletePageCmd->activate();
1000     } else {
1001 	// does it have a group record
1002 	int page_num = this->workSpace->getCurrentPage();
1003 	EditorWorkSpace* ews = this->workSpace;
1004 	if (page_num)
1005 	    ews = (EditorWorkSpace*)this->workSpace->getElement(page_num);
1006 	GroupRecord* grec = this->getGroupOfWorkSpace(ews);
1007 	if (grec)
1008 	    this->deletePageCmd->activate();
1009 	else
1010 	    this->deletePageCmd->deactivate();
1011     }
1012 #endif
1013 
1014     //
1015     // command depends on whether selected nodes are pagifiable
1016     //
1017     boolean mscmd_activate = FALSE;
1018     if ((nselected) || (dselected)) {
1019 	Dialog* diag = this->pageSelector->getMoveNodesDialog();
1020 	if ((diag) && (diag->isManaged())) {
1021 	    if (this->pageSelector->getSize() > 1)
1022 		mscmd_activate = this->areSelectedNodesPagifiable(FALSE);
1023 	    else
1024 		mscmd_activate = FALSE;
1025 	} else {
1026 	    mscmd_activate = TRUE;
1027 	}
1028     }
1029     if (mscmd_activate)
1030 	this->moveSelectedCmd->activate();
1031     else
1032 	this->moveSelectedCmd->deactivate();
1033 
1034     //
1035     // Handle commands that depend on whether there are nodes selected
1036     //
1037     if (nselected == 0) {
1038 	this->valuesCmd->deactivate();
1039 	this->addInputTabCmd->deactivate();
1040 	this->removeInputTabCmd->deactivate();
1041 	this->addOutputTabCmd->deactivate();
1042 	this->removeOutputTabCmd->deactivate();
1043 	this->hideAllTabsCmd->deactivate();
1044 	this->revealAllTabsCmd->deactivate();
1045 	this->autoChopSelectedCmd->deactivate();
1046 	this->autoFuseSelectedCmd->deactivate();
1047 	if (dselected) {
1048 	    this->deleteNodeCmd->activate();
1049 	    this->cutNodeCmd->activate();
1050 	    this->copyNodeCmd->activate();
1051 	    this->pagifySelectedCmd->activate();
1052 	} else {
1053 	    this->cutNodeCmd->deactivate();
1054 	    this->copyNodeCmd->deactivate();
1055 	    this->deleteNodeCmd->deactivate();
1056 	    this->pagifySelectedCmd->deactivate();
1057 	}
1058 	this->selectDownwardNodeCmd->deactivate();
1059 	this->selectUpwardNodeCmd->deactivate();
1060 	this->deselectAllNodeCmd->deactivate();
1061 	this->selectConnectedNodeCmd->deactivate();
1062 #ifndef FORGET_GETSET
1063 	if ((EditorWindow::GetSetDialog) &&
1064 	    (EditorWindow::GetSetDialog->isManaged()) &&
1065 	    (this == EditorWindow::GetSetDialog->getActiveEditor())) {
1066 	    this->SelectedToGlobalCmd->deactivate();
1067 	    this->SelectedToLocalCmd->deactivate();
1068 	}
1069 	this->toLocalCmd->deactivate();
1070 	this->toGlobalCmd->deactivate();
1071 #endif
1072 	this->selectUnconnectedNodeCmd->deactivate();
1073 	this->selectUnselectedNodeCmd->deactivate(); // Same as selectAll
1074 	this->macroifyCmd->deactivate();
1075 	this->openColormapCmd->deactivate();
1076 	this->openMacroCmd->deactivate();
1077 	this->openImageCmd->deactivate();
1078 	this->openControlPanelCmd->deactivate();
1079 	this->editOutputCacheabilityCascade->deactivate();
1080     } else {
1081 	//
1082 	// Commands that can only work selected nodes, but depend on the Node.
1083 	//
1084 	boolean add_input  = FALSE, remove_input  = FALSE;
1085 	boolean add_output = FALSE, remove_output = FALSE;
1086 	boolean hide_all   = FALSE, reveal_all    = FALSE;
1087 	boolean cacheable = FALSE;
1088 #ifndef FORGET_GETSET
1089 	boolean only_gets_n_sets = TRUE;
1090 	boolean convertible = TRUE;
1091 #endif
1092 	Node *n;
1093 	ListIterator iterator;
1094 	FOR_EACH_NETWORK_NODE(this->network, n, iterator) {
1095 	    if ((n->getStandIn()) && (n->getStandIn()->isSelected()))
1096 	    {
1097 #ifndef FORGET_GETSET
1098 		const char *cp = n->getNameString();
1099 		if (!n->isA(ClassGlobalLocalNode))
1100 		    convertible = only_gets_n_sets = FALSE;
1101 		else if ((!EqualString(cp, "Get")) && (!EqualString(cp, "Set")))
1102 		    only_gets_n_sets = FALSE;
1103 #endif
1104 
1105 		if (!add_input && n->isInputRepeatable())
1106 		    add_input = TRUE;
1107 		if (!remove_input && n->hasRemoveableInput())
1108 		    remove_input = TRUE;
1109 		if (!add_output && n->isOutputRepeatable())
1110 		    add_output = TRUE;
1111 		if (!remove_output && n->hasRemoveableOutput())
1112 		    remove_output = TRUE;
1113 		if (!hide_all &&
1114 		    (n->hasHideableInput() || n->hasHideableOutput()))
1115 		    hide_all = TRUE;
1116 		if (!reveal_all &&
1117 		    (n->hasExposableInput() || n->hasExposableOutput()))
1118 		    reveal_all = TRUE;
1119 		int count = n->getOutputCount();
1120 		for (int i=1 ; !cacheable && i<=count  ; i++)
1121 		    cacheable = n->isOutputCacheabilityWriteable(i);
1122 	    }
1123 	}
1124 	(add_input ? 	this->addInputTabCmd->activate() :
1125 			this->addInputTabCmd->deactivate());
1126 	(remove_input ? this->removeInputTabCmd->activate() :
1127 			this->removeInputTabCmd->deactivate());
1128 	(add_output ? 	this->addOutputTabCmd->activate() :
1129 			this->addOutputTabCmd->deactivate());
1130 	(remove_output? this->removeOutputTabCmd->activate() :
1131 			this->removeOutputTabCmd->deactivate());
1132 	(reveal_all ? 	this->revealAllTabsCmd->activate() :
1133 			this->revealAllTabsCmd->deactivate());
1134 	(hide_all ? 	this->hideAllTabsCmd->activate() :
1135 			this->hideAllTabsCmd->deactivate());
1136 	(cacheable ?	this->editOutputCacheabilityCascade->activate() :
1137 			this->editOutputCacheabilityCascade->deactivate());
1138 	//
1139 	// Commands that can only work if there are unselected nodes
1140 	//
1141 	if (nodes > nselected) {
1142 	    this->selectAllNodeCmd->activate();
1143 	    this->selectConnectedNodeCmd->activate();
1144 	    this->selectUnconnectedNodeCmd->activate();
1145 	    this->selectUnselectedNodeCmd->activate();
1146 	    this->selectDownwardNodeCmd->activate();
1147 	    this->selectUpwardNodeCmd->activate();
1148 	} else {	// There are no unselected nodes
1149 	    this->selectAllNodeCmd->deactivate();
1150 	    this->selectConnectedNodeCmd->deactivate();
1151 	    this->selectUnconnectedNodeCmd->deactivate();
1152 	    this->selectUnselectedNodeCmd->deactivate();
1153 	    this->selectDownwardNodeCmd->deactivate();
1154 	    this->selectUpwardNodeCmd->deactivate();
1155 	}
1156 	//
1157 	// And commands that depend on the class of node that is selected.
1158 	//
1159         List *l = this->makeSelectedNodeList(NULL);
1160 	boolean selected_macro = FALSE, selected_image = FALSE;
1161 	boolean selected_colormap = FALSE;
1162 	boolean selected_interactor = FALSE;
1163   	if (l) {
1164 	    ListIterator  iterator(*l);
1165 	    Node *n;
1166 	    while ( (n = (Node*)iterator.getNext()) ) {
1167 		if (!selected_colormap && n->isA(ClassColormapNode))
1168 		    selected_colormap = TRUE;
1169 		if (!selected_macro && n->isA(ClassMacroNode))
1170 		    selected_macro = TRUE;
1171 		if (!selected_image && n->isA(ClassDisplayNode))
1172 		    selected_image = TRUE;
1173 		if (!selected_interactor && n->isA(ClassInteractorNode))
1174 		    selected_interactor = TRUE;
1175 	    }
1176 	    delete l;
1177 	}
1178 	(selected_macro ? 	this->openMacroCmd->activate() :
1179 			  	this->openMacroCmd->deactivate());
1180 	(selected_image ? 	this->openImageCmd->activate() :
1181 	    		  	this->openImageCmd->deactivate());
1182 	(selected_colormap ? 	this->openColormapCmd->activate() :
1183 	    		     	this->openColormapCmd->deactivate());
1184 	(selected_interactor ? 	this->openControlPanelCmd->activate() :
1185 	    			this->openControlPanelCmd->deactivate());
1186 	//
1187 	// And...commands that can only work if there are selected nodes
1188 	//
1189 	this->valuesCmd->activate();
1190 	this->macroifyCmd->activate();
1191 	this->deleteNodeCmd->activate();
1192 	this->cutNodeCmd->activate();
1193 	this->copyNodeCmd->activate();
1194 	this->deselectAllNodeCmd->activate();
1195 	this->pagifySelectedCmd->activate();
1196 	this->autoChopSelectedCmd->activate();
1197 	this->autoFuseSelectedCmd->activate();
1198 
1199 	//
1200 	// Convert Get/Set node commands.  Requires that 1 or more nodes selected and
1201 	// every node selected is a Get or Set.
1202 	//
1203 #ifndef FORGET_GETSET
1204 	if ((only_gets_n_sets) && (EditorWindow::GetSetDialog) &&
1205 	    (this != ew) && (EditorWindow::GetSetDialog->isManaged())) {
1206 	    EditorWindow::GetSetDialog->setActiveEditor(this);
1207 	    ew = EditorWindow::GetSetDialog->getActiveEditor();
1208 	}
1209 	if (convertible) {
1210 	    this->toLocalCmd->activate();
1211 	    this->toGlobalCmd->activate();
1212 	} else {
1213 	    this->toLocalCmd->deactivate();
1214 	    this->toGlobalCmd->deactivate();
1215 	}
1216 	if ((EditorWindow::GetSetDialog) &&
1217 	    (EditorWindow::GetSetDialog->isManaged()) && (this == ew)) {
1218 	    if (only_gets_n_sets) {
1219 		if (!ew) EditorWindow::GetSetDialog->setActiveEditor(this);
1220 		this->SelectedToGlobalCmd->activate();
1221 		this->SelectedToLocalCmd->activate();
1222 	    } else {
1223 		this->SelectedToGlobalCmd->deactivate();
1224 		this->SelectedToLocalCmd->deactivate();
1225 	    }
1226 	}
1227 #endif
1228     }
1229 
1230     //
1231     // If there is at least 1 image node
1232     //
1233     if (this->javifyNetCmd) {
1234 	boolean activate = FALSE;
1235 	List* bns = this->network->makeClassifiedNodeList(ClassImageNode);
1236 	if ((bns) && (bns->getSize() > 0)) {
1237 	    activate = TRUE;
1238 	}
1239 	if (bns) delete bns;
1240 	if (activate) {
1241 	    this->javifyNetCmd->activate();
1242 	    this->unjavifyNetCmd->activate();
1243 	} else {
1244 	    this->javifyNetCmd->deactivate();
1245 	    this->unjavifyNetCmd->deactivate();
1246 	}
1247     }
1248 
1249     this->editTabsCascade->setActivationFromChildren();
1250     this->editSelectCascade->setActivationFromChildren();
1251 }
1252 
1253 //
1254 // Do any work that is required when a Node's status changes (generally
1255 // called by a StandIn).  Mostly what needs to be done is handle command
1256 // activation and deactivation.
1257 //
handleNodeStatusChange(Node * n,NodeStatusChange status)1258 void EditorWindow::handleNodeStatusChange(Node *n, NodeStatusChange status)
1259 {
1260 
1261     switch (status) {
1262 	case Node::NodeSelected:
1263 	case Node::NodeDeselected:
1264 	    // FIXME: should we do this more quickly?
1265             this->deferrableCommandActivation->requestAction(NULL);
1266             if (n->isA(ClassTransmitterNode))
1267                 this->lastSelectedTransmitter = (TransmitterNode*)n;
1268 
1269 	    break;
1270 	default:
1271 	    ASSERT(0);
1272     }
1273 
1274 }
createWorkArea(Widget parent)1275 Widget EditorWindow::createWorkArea(Widget parent)
1276 {
1277     Widget    form;
1278     Widget    hBar;
1279     Widget    vBar;
1280     Dimension height;
1281     Dimension width;
1282     Dimension thickness;
1283 
1284     ASSERT(parent);
1285 
1286     Widget outer_form = XtVaCreateManagedWidget ("workAreaFrame", xmFormWidgetClass,
1287 	    parent,
1288 	XmNshadowType, XmSHADOW_OUT,
1289 	XmNshadowThickness, 1,
1290     NULL);
1291 
1292     form = XtVaCreateManagedWidget ("workArea", xmFormWidgetClass, outer_form,
1293 	XmNtopAttachment, XmATTACH_FORM,
1294 	XmNleftAttachment, XmATTACH_FORM,
1295 	XmNrightAttachment, XmATTACH_FORM,
1296 	XmNbottomAttachment, XmATTACH_FORM,
1297 	XmNtopOffset, 6,
1298 	XmNleftOffset, 6,
1299 	XmNrightOffset, 6,
1300 	XmNbottomOffset, 6,
1301 	XmNshadowThickness, 0,
1302     NULL);
1303 
1304 
1305     //
1306     // Create the category/tool lists as a child of the above form.
1307     //
1308 
1309     this->toolSelector = new EditorToolSelector("toolSelector", this);
1310     if (!this->toolSelector->initialize(form,theNodeDefinitionDictionary))
1311 	ASSERT(0);
1312 
1313     XtVaSetValues (this->toolSelector->getRootWidget(),
1314         XmNtopAttachment,    XmATTACH_FORM,
1315         XmNleftAttachment,   XmATTACH_FORM,
1316         XmNbottomAttachment, XmATTACH_FORM,
1317 	XmNtopOffset, 0,
1318 	XmNleftOffset, 0,
1319 	XmNbottomOffset, 0,
1320     NULL);
1321 
1322 #if WORKSPACE_PAGES
1323     this->pageSelector = new PageSelector (this, form, this->network);
1324     XtVaSetValues (this->pageSelector->getRootWidget(),
1325 	XmNtopAttachment,	XmATTACH_FORM,
1326 	XmNleftAttachment,      XmATTACH_WIDGET,
1327 	XmNleftWidget,          this->toolSelector->getRootWidget(),
1328 	XmNleftOffset,          5,
1329 	XmNrightAttachment,     XmATTACH_FORM,
1330 	XmNrightOffset,		20,
1331     NULL);
1332 #endif
1333 
1334     //
1335     // Create the scrolled window.
1336     //
1337     this->scrolledWindow =
1338 	XtVaCreateManagedWidget
1339 	    ("scrolledWindow",
1340 	     xmScrolledWindowWidgetClass,
1341 	     form,
1342 #if WORKSPACE_PAGES
1343 	     XmNtopAttachment,          XmATTACH_WIDGET,
1344 	     XmNtopWidget,          	this->pageSelector->getRootWidget(),
1345 	     XmNtopOffset,		-1,
1346 #else
1347 	    XmNtopAttachment,	XmATTACH_FORM,
1348 #endif
1349 	     XmNleftAttachment,         XmATTACH_WIDGET,
1350 	     XmNleftWidget,             this->toolSelector->getRootWidget(),
1351 	     XmNleftOffset,             5,
1352 	     XmNrightAttachment,        XmATTACH_FORM,
1353 	     XmNbottomAttachment,       XmATTACH_FORM,
1354 	     XmNscrollingPolicy,        XmAUTOMATIC,
1355 	     XmNvisualPolicy,           XmVARIABLE,
1356 	     XmNscrollBarDisplayPolicy, XmAS_NEEDED,
1357 	     NULL);
1358     //
1359     // Create the workspace object.
1360     //
1361 
1362     this->workSpace = new VPERoot("vpeCanvas", this->scrolledWindow,
1363 				this->network->getWorkSpaceInfo(),
1364 				this, this->pageSelector);
1365     this->workSpace->initializeRootWidget();
1366     this->workSpace->manage();
1367     this->pageSelector->setRootPage((VPERoot*)this->workSpace);
1368 
1369     XtVaSetValues(this->scrolledWindow, XmNworkWindow,
1370 	  this->workSpace->getRootWidget(), NULL);
1371 
1372     //
1373     // Adjust the horizontal/vertical scrollbars to get rid of
1374     // highlighting feature.
1375     //
1376     XtVaGetValues(this->scrolledWindow,
1377 		  XmNhorizontalScrollBar, &hBar,
1378 		  XmNverticalScrollBar,   &vBar,
1379 		  NULL);
1380 
1381     XtVaGetValues(hBar,
1382 		  XmNhighlightThickness, &thickness,
1383 		  XmNheight,             &height,
1384 		  NULL);
1385     height -= thickness * 2;
1386     XtVaSetValues(hBar,
1387 		  XmNhighlightThickness, 0,
1388 		  XmNheight,             height,
1389 		  NULL);
1390 
1391     XtVaGetValues(vBar,
1392 		  XmNhighlightThickness, &thickness,
1393 		  XmNwidth,              &width,
1394 		  NULL);
1395     width -= thickness * 2;
1396     XtVaSetValues(vBar,
1397 		  XmNhighlightThickness, 0,
1398 		  XmNwidth,              width,
1399 		  NULL);
1400 
1401 #if ((XmVERSION==2)&&(XmREVISION>=2))
1402     //
1403     // Pg {Up,Down} is crashing the vpe.  If this bug goes away
1404     // then remove this code.  Finding a bug fix for Motif isn't good
1405     // enough since we build with shared libraries.  Another way
1406     // to fix this might have been to make a translation table
1407     // entry.  I did try that but when I invoked the widget's
1408     // action routine, I got the same crash.
1409     //
1410     // Event handling in libXt is more complex than I what I can write
1411     // code for at this level.  The 0 passed to this constructor is
1412     // supposed to be a window id. 0 means wildcard i.e. we match any
1413     // event.  In KeyPress() we'll try to figure out if the widget
1414     // that belongs to this event is in the hierarchy of this window.
1415     //
1416     if (!this->pgKeyHandler) {
1417 	this->pgKeyHandler = new XHandler(KeyPress, 0, KeyHandler, (void*)this);
1418     }
1419 #endif
1420     //
1421     // Return the topmost widget of the work area.
1422     //
1423     return outer_form;
1424 }
1425 
1426 
createFileMenu(Widget parent)1427 void EditorWindow::createFileMenu(Widget parent)
1428 {
1429     ASSERT(parent);
1430 
1431     Widget pulldown;
1432     Command *cmd;
1433 
1434     //
1435     // Create "File" menu and options.
1436     //
1437     pulldown =
1438 	this->fileMenuPulldown =
1439 	    XmCreatePulldownMenu(parent, "fileMenuPulldown", NUL(ArgList), 0);
1440     this->fileMenu =
1441 	XtVaCreateManagedWidget
1442 	    ("fileMenu",
1443 	     xmCascadeButtonWidgetClass,
1444 	     parent,
1445 	     XmNsubMenuId, pulldown,
1446 	     NULL);
1447 
1448     this->newOption =
1449 	new ButtonInterface(pulldown,
1450 			    "vpeNewOption",
1451 			    this->network->getNewCommand());
1452 
1453     this->openOption =
1454 	new ButtonInterface(pulldown,
1455                             "vpeOpenOption", theDXApplication->openFileCmd);
1456 
1457     this->createFileHistoryMenu(pulldown);
1458 
1459     if ( (cmd = this->network->getSaveCommand()) ) {
1460     	if(this->network->isMacro() == FALSE)
1461 	    this->saveOption = new ButtonInterface(pulldown, "vpeSaveOption", cmd);
1462 	else
1463 	    this->saveOption = new ButtonInterface(pulldown, "vpeSaveMacroOption", cmd);
1464     }
1465 
1466     if ( (cmd = this->network->getSaveAsCommand()) ) {
1467         if(this->network->isMacro() == FALSE)
1468 	    this->saveAsOption = new ButtonInterface(pulldown,
1469 						"vpeSaveAsOption", cmd);
1470 	else
1471 	    this->saveAsOption = new ButtonInterface(pulldown,
1472 						"vpeSaveMacroAsOption", cmd);
1473     }
1474 
1475 
1476     Command *openCfgCmd = this->network->getOpenCfgCommand();
1477     Command *saveCfgCmd = this->network->getSaveCfgCommand();
1478     if (openCfgCmd && saveCfgCmd) {
1479         this->settingsCascade = new CascadeMenu("vpeSettingsCascade",pulldown);
1480 	Widget menu_parent = this->settingsCascade->getMenuItemParent();
1481 	this->saveCfgOption = new ButtonInterface(menu_parent,
1482 						"vpeSaveCfgOption", saveCfgCmd);
1483 	this->openCfgOption = new ButtonInterface(menu_parent,
1484 						"vpeOpenCfgOption", openCfgCmd);
1485     } else if (openCfgCmd) {
1486 	this->openCfgOption = new ButtonInterface(pulldown,
1487 						"vpeOpenCfgOption", openCfgCmd);
1488     } else if (saveCfgCmd) {
1489 	this->saveCfgOption = new ButtonInterface(pulldown,
1490 						"vpeSaveCfgOption", saveCfgCmd);
1491     }
1492 
1493 
1494     XtVaCreateManagedWidget
1495 	    ("optionSeparator", xmSeparatorWidgetClass, pulldown, NULL);
1496 
1497     this->loadMacroOption =
1498 	new ButtonInterface(pulldown,
1499                             "vpeLoadMacroOption", theDXApplication->loadMacroCmd);
1500     this->loadMDFOption =
1501 	new ButtonInterface(pulldown,
1502                             "vpeLoadMDFOption", theDXApplication->loadMDFCmd);
1503 
1504     XtVaCreateManagedWidget
1505 	    ("optionSeparator", xmSeparatorWidgetClass, pulldown, NULL);
1506 
1507     this->printProgramOption = new ButtonInterface(pulldown,
1508                                              "vpePrintProgramOption",
1509                                              this->printProgramCmd);
1510     if (this->saveAsCCodeCmd)
1511 	this->saveAsCCodeOption = new ButtonInterface(pulldown,
1512                                              "vpeSaveAsCCodeOption",
1513                                              this->saveAsCCodeCmd);
1514     XtVaCreateManagedWidget
1515 	    ("optionSeparator", xmSeparatorWidgetClass, pulldown, NULL);
1516 
1517     if (this->isAnchor() && theDXApplication->appAllowsExitOptions())
1518     	this->quitOption =
1519 	   new ButtonInterface(pulldown,"quitOption",theDXApplication->exitCmd);
1520     else
1521     	this->closeOption =
1522 	   new ButtonInterface(pulldown,"vpeCloseOption",this->closeCmd);
1523 
1524     XtAddCallback(pulldown,
1525                   XmNmapCallback,
1526                   (XtCallbackProc)EditorWindow_FileMenuMapCB,
1527                   (XtPointer)this);
1528 }
1529 
1530 
createEditMenu(Widget parent)1531 void EditorWindow::createEditMenu(Widget parent)
1532 {
1533     ASSERT(parent);
1534 
1535     Widget pulldown;
1536     CascadeMenu *cascade_menu;
1537     Widget menu_parent;
1538     CommandInterface *ci;
1539 
1540     //
1541     // Create "Edit" menu and options.
1542     //
1543     pulldown =
1544 	this->editMenuPulldown =
1545 	    XmCreatePulldownMenu(parent, "editMenuPulldown", NUL(ArgList), 0);
1546     this->editMenu =
1547 	XtVaCreateManagedWidget
1548 	    ("editMenu",
1549 	     xmCascadeButtonWidgetClass,
1550 	     parent,
1551 	     XmNsubMenuId, pulldown,
1552 	     NULL);
1553 
1554     this->undoOption = new ButtonInterface (pulldown, "vpeUndoOption", this->undoCmd);
1555     XtVaCreateManagedWidget ("optionSeparator", xmSeparatorWidgetClass, pulldown, NULL);
1556 
1557     //
1558     // Module level functions
1559     //
1560     this->valuesOption =
1561 	new ButtonInterface(pulldown, "vpeValuesOption", this->valuesCmd);
1562 
1563     this->findToolOption =
1564 	new ButtonInterface(pulldown, "vpeFindToolOption", this->findToolCmd);
1565 
1566 
1567     //
1568     // Add/removing tabs
1569     //
1570 #if 0
1571     XtVaCreateManagedWidget("optionSeparator", xmSeparatorWidgetClass,
1572 						pulldown, NULL);
1573 #endif
1574     cascade_menu = this->editTabsCascade =
1575 		new CascadeMenu("vpeEditTabsCascade",pulldown);
1576     menu_parent = cascade_menu->getMenuItemParent();
1577 
1578 
1579     this->addInputTabOption = new ButtonInterface(menu_parent, "vpeAddInputTabOption",
1580 					this->addInputTabCmd);
1581     cascade_menu->appendComponent(this->addInputTabOption);
1582 
1583     this->removeInputTabOption = new ButtonInterface(menu_parent, "vpeRemoveInputTabOption",
1584 					this->removeInputTabCmd);
1585     cascade_menu->appendComponent(this->removeInputTabOption);
1586     ci = new ButtonInterface(menu_parent, "vpeAddOutputTabOption",
1587 					this->addOutputTabCmd);
1588     cascade_menu->appendComponent(ci);
1589 
1590     ci = new ButtonInterface(menu_parent, "vpeRemoveOutputTabOption",
1591 					this->removeOutputTabCmd);
1592     cascade_menu->appendComponent(ci);
1593 
1594     ci = new ButtonInterface(menu_parent, "vpeRevealAllTabsOption",
1595 					this->revealAllTabsCmd);
1596     cascade_menu->appendComponent(ci);
1597 
1598     ci = new ButtonInterface(menu_parent, "vpeHideAllTabsOption",
1599 					this->hideAllTabsCmd);
1600     cascade_menu->appendComponent(ci);
1601 
1602 #ifndef FORGET_GETSET
1603     //
1604     // GetSet Conversion operation
1605     //
1606     cascade_menu = this->programVerifyCascade =
1607 		new CascadeMenu("programVerifyCascade",pulldown);
1608     menu_parent = cascade_menu->getMenuItemParent();
1609 
1610     ci = new ButtonInterface (menu_parent, "getSetConversion", this->postGetSetCmd);
1611     cascade_menu->appendComponent(ci);
1612 
1613     ci = new ButtonInterface (menu_parent, "setToLocal", this->toLocalCmd);
1614     cascade_menu->appendComponent(ci);
1615 
1616     ci = new ButtonInterface (menu_parent, "setToGlobal", this->toGlobalCmd);
1617     cascade_menu->appendComponent(ci);
1618 #endif
1619 
1620     //
1621     // Module selection methods
1622     //
1623 #if 0
1624     XtVaCreateManagedWidget("optionSeparator", xmSeparatorWidgetClass,
1625 						pulldown, NULL);
1626 #endif
1627 
1628     this->editSelectCascade =
1629     cascade_menu = new CascadeMenu("vpeEditSelectCascade",pulldown);
1630     menu_parent = cascade_menu->getMenuItemParent();
1631 
1632     ci = new ButtonInterface(menu_parent, "vpeSelectAllOption",
1633 						this->selectAllNodeCmd);
1634     cascade_menu->appendComponent(ci);
1635 
1636     ci = new ButtonInterface(menu_parent, "vpeSelectConnectedOption",
1637 					this->selectConnectedNodeCmd);
1638     cascade_menu->appendComponent(ci);
1639 
1640     ci = new ButtonInterface(menu_parent, "vpeSelectUnconnectedOption",
1641 					this->selectUnconnectedNodeCmd);
1642     cascade_menu->appendComponent(ci);
1643 
1644     ci = new ButtonInterface(menu_parent, "vpeSelectUpwardOption",
1645 					this->selectUpwardNodeCmd);
1646     cascade_menu->appendComponent(ci);
1647 
1648     ci = new ButtonInterface(menu_parent, "vpeSelectDownwardOption",
1649 					this->selectDownwardNodeCmd);
1650     cascade_menu->appendComponent(ci);
1651 
1652     ci = new ButtonInterface(menu_parent, "vpeDeselectAllOption",
1653 					this->deselectAllNodeCmd);
1654     cascade_menu->appendComponent(ci);
1655 
1656     ci = new ButtonInterface(menu_parent, "vpeSelectUnselectedOption",
1657 					this->selectUnselectedNodeCmd);
1658     cascade_menu->appendComponent(ci);
1659 
1660     ci = new ButtonInterface (menu_parent, "vpeShowExecutedOption",
1661 					this->showExecutedCmd);
1662     cascade_menu->appendComponent(ci);
1663 
1664     //
1665     // Output Cacheability (two cascade menus)
1666     //
1667     this->outputCacheabilityCascade =
1668     cascade_menu = new CascadeMenu("vpeOutputCacheabilityCascade",pulldown);
1669     menu_parent = cascade_menu->getMenuItemParent();
1670 
1671     ci =  new ButtonInterface(menu_parent, "vpeOptimizeCacheability",
1672 					this->optimizeCacheabilityCmd);
1673     cascade_menu->appendComponent(ci);
1674 
1675     // Set
1676     this->editOutputCacheabilityCascade =
1677     cascade_menu = new CascadeMenu("vpeEditOutputCacheabilityCascade",
1678 							menu_parent);
1679     menu_parent = cascade_menu->getMenuItemParent();
1680 
1681     ci = new ButtonInterface(menu_parent, "vpeCacheAllOutputsOption",
1682 						this->cacheAllOutputsCmd);
1683     cascade_menu->appendComponent(ci);
1684 
1685     ci = new ButtonInterface(menu_parent, "vpeCacheLastOutputsOption",
1686 						this->cacheLastOutputsCmd);
1687     cascade_menu->appendComponent(ci);
1688 
1689     ci = new ButtonInterface(menu_parent, "vpeCacheNoOutputsOption",
1690 						this->cacheNoOutputsCmd);
1691     cascade_menu->appendComponent(ci);
1692     // Show
1693     menu_parent = this->outputCacheabilityCascade->getMenuItemParent();
1694     cascade_menu = new CascadeMenu("vpeShowOutputCacheabilityCascade",
1695 							menu_parent);
1696     this->outputCacheabilityCascade->appendComponent(cascade_menu);
1697     menu_parent = cascade_menu->getMenuItemParent();
1698 
1699     ci = new ButtonInterface(menu_parent, "vpeShowCacheAllOutputsOption",
1700 						this->showCacheAllOutputsCmd);
1701     cascade_menu->appendComponent(ci);
1702 
1703     ci = new ButtonInterface(menu_parent, "vpeShowCacheLastOutputsOption",
1704 						this->showCacheLastOutputsCmd);
1705     cascade_menu->appendComponent(ci);
1706 
1707     ci = new ButtonInterface(menu_parent, "vpeShowCacheNoOutputsOption",
1708 						this->showCacheNoOutputsCmd);
1709     cascade_menu->appendComponent(ci);
1710 
1711     //
1712     // Delete, Cut, Copy, Paste
1713     //
1714     XtVaCreateManagedWidget("optionSeparator", xmSeparatorWidgetClass,
1715 						pulldown, NULL);
1716     this->deleteOption =
1717 	new ButtonInterface(pulldown, "vpeDeleteOption", this->deleteNodeCmd);
1718 
1719     if ((theDXApplication->appAllowsSavingNetFile()) &&
1720 	(theDXApplication->appAllowsSavingCfgFile()) &&
1721 	(theDXApplication->appAllowsEditorAccess())) {
1722 	this->copyOption =
1723 	    new ButtonInterface(pulldown, "vpeCopyOption", this->copyNodeCmd);
1724 
1725 	this->cutOption =
1726 	    new ButtonInterface(pulldown, "vpeCutOption", this->cutNodeCmd);
1727 
1728 	this->pasteOption =
1729 	    new ButtonInterface(pulldown, "vpePasteOption", this->pasteNodeCmd);
1730     }
1731 
1732     //
1733     // Annotation
1734     //
1735     XtVaCreateManagedWidget("optionSeparator", xmSeparatorWidgetClass,
1736 						pulldown, NULL);
1737 
1738     this->addAnnotationOption = new ButtonInterface(pulldown, "vpeAddDecorator",
1739 	this->addAnnotationCmd);
1740 
1741     //
1742     // Miscellaneous
1743     //
1744     this->insertNetworkOption =
1745 	new ButtonInterface(pulldown, "vpeInsertNetOption",
1746 			    this->insertNetCmd);
1747 
1748     this->createMacroOption =
1749 	new ButtonInterface(pulldown, "vpeCreateMacroOption",
1750 			    this->macroifyCmd);
1751 
1752 #if WORKSPACE_PAGES
1753     this->pageCascade = cascade_menu = new CascadeMenu("vpePageCascade", pulldown);
1754     menu_parent = cascade_menu->getMenuItemParent();
1755 
1756     ci = new ButtonInterface(menu_parent, "vpeCreatePageOption", this->pagifyCmd);
1757     cascade_menu->appendComponent(ci);
1758 
1759     ci=new ButtonInterface(menu_parent, "vpeSelectedPageOption", this->pagifySelectedCmd);
1760     cascade_menu->appendComponent(ci);
1761 
1762     ci = new ButtonInterface(menu_parent, "vpeDeletePageOption", this->deletePageCmd);
1763     cascade_menu->appendComponent(ci);
1764 
1765     XtVaCreateManagedWidget("optionSeparator", xmSeparatorWidgetClass, menu_parent, NULL);
1766 
1767     ci=new ButtonInterface(menu_parent, "vpeChopPageOption", this->autoChopSelectedCmd);
1768     cascade_menu->appendComponent(ci);
1769 
1770     ci=new ButtonInterface(menu_parent, "vpeFusePageOption", this->autoFuseSelectedCmd);
1771     cascade_menu->appendComponent(ci);
1772 
1773     XtVaCreateManagedWidget("optionSeparator", xmSeparatorWidgetClass, menu_parent, NULL);
1774 
1775     ci = new ButtonInterface(menu_parent,"vpeConfigurePageOption",this->configurePageCmd);
1776     cascade_menu->appendComponent(ci);
1777 
1778     ci = new ButtonInterface(menu_parent, "vpeMoveToPageOption", this->moveSelectedCmd);
1779     cascade_menu->appendComponent(ci);
1780 #endif
1781 
1782     if (this->javifyNetCmd) {
1783 	this->javaCascade = cascade_menu = new CascadeMenu("vpeJavaCascade", pulldown);
1784 	menu_parent = cascade_menu->getMenuItemParent();
1785 
1786 	ci = new ButtonInterface(menu_parent,
1787 	    "vpeJavifyNetOption", this->javifyNetCmd);
1788 	cascade_menu->appendComponent(ci);
1789 
1790 	ci = new ButtonInterface(menu_parent,
1791 	    "vpeUnjavifyNetOption", this->unjavifyNetCmd);
1792 	cascade_menu->appendComponent(ci);
1793 
1794 	Command* cmd = NUL(Command*);
1795 	cmd = this->network->getSaveWebPageCommand();
1796 	if (cmd) {
1797 	    XtVaCreateManagedWidget("optionSeparator",
1798 		xmSeparatorWidgetClass, menu_parent, NULL);
1799 	    ci = new ButtonInterface(menu_parent, "vpeSaveWebPageOption", cmd);
1800 	    cascade_menu->appendComponent(ci);
1801 	}
1802 
1803 	cmd = this->network->getSaveAppletCommand();
1804 	if (cmd) {
1805 	    ci = new ButtonInterface(menu_parent, "vpeSaveAppletOption", cmd);
1806 	    cascade_menu->appendComponent(ci);
1807 	}
1808 
1809 	cmd = this->network->getSaveBeanCommand();
1810 	if (cmd) {
1811 	    ci = new ButtonInterface(menu_parent, "vpeSaveBeanOption", cmd);
1812 	    cascade_menu->appendComponent(ci);
1813 	}
1814 
1815     }
1816 
1817     this->macroNameOption =
1818 	new ButtonInterface(pulldown, "vpeMacroNameOption",
1819 			    this->network->getSetNameCommand());
1820 
1821     this->reflowGraphOption =
1822 	new ButtonInterface(pulldown, "vpeReflowGraphOption",
1823 			    this->reflowGraphCmd);
1824 
1825     this->createProcessGroupOption =
1826 	new ButtonInterface(pulldown, "vpeCreateProcessGroupOption",
1827 			    this->createProcessGroupCmd);
1828 
1829     this->commentOption =
1830 	new ButtonInterface(pulldown, "vpeCommentOption", this->editCommentCmd);
1831 
1832     XtAddCallback(pulldown,
1833                   XmNmapCallback,
1834                   (XtCallbackProc)EditorWindow_EditMenuMapCB,
1835                   (XtPointer)this);
1836 }
1837 
1838 
createWindowsMenu(Widget parent)1839 void EditorWindow::createWindowsMenu(Widget parent)
1840 {
1841     ASSERT(parent);
1842 
1843     Widget            pulldown;
1844 
1845     //
1846     // Create "Windows" menu and options.
1847     //
1848     pulldown =
1849 	this->windowsMenuPulldown =
1850 	    XmCreatePulldownMenu
1851 		(parent, "windowsMenuPulldown", NUL(ArgList), 0);
1852     this->windowsMenu =
1853 	XtVaCreateManagedWidget
1854 	    ("windowsMenu",
1855 	     xmCascadeButtonWidgetClass,
1856 	     parent,
1857 	     XmNsubMenuId, pulldown,
1858 	     NULL);
1859 
1860     this->newControlPanelOption =
1861 	new ButtonInterface
1862 	    (pulldown, "vpeNewControlPanelOption", this->newControlPanelCmd);
1863 
1864     this->openControlPanelOption =
1865 	new ButtonInterface(pulldown, "vpeOpenControlPanelOption",
1866 		this->openControlPanelCmd);
1867 
1868     this->openAllControlPanelsOption =
1869         new ButtonInterface
1870             (pulldown,
1871              "vpeOpenAllControlPanelsOption",
1872              this->network->getOpenAllPanelsCommand());
1873 
1874     this->openControlPanelByNameMenu =
1875                 new CascadeMenu("vpePanelCascade",pulldown);
1876 
1877     XtAddCallback(pulldown,
1878                   XmNmapCallback,
1879                   (XtCallbackProc)EditorWindow_WindowMenuMapCB,
1880                   (XtPointer)this);
1881 
1882 #ifdef PANEL_GROUP_SEPARATED
1883     this->panelGroupPulldown =
1884             XmCreatePulldownMenu
1885                 (pulldown, "panelGroupPulldown", NUL(ArgList), 0);
1886 
1887     this->panelGroupCascade =
1888     cascade =  XtVaCreateManagedWidget
1889             ("vpePanelGroupCascade",
1890              xmCascadeButtonWidgetClass,
1891              pulldown,
1892              XmNsubMenuId, this->panelGroupPulldown,
1893 	     XmNsensitive, TRUE,
1894              NULL);
1895 #endif
1896 
1897     XtVaCreateManagedWidget("optionSeparator",
1898 				xmSeparatorWidgetClass, pulldown, NULL);
1899 
1900     this->openMacroOption =
1901 	new ButtonInterface(pulldown, "vpeOpenMacroOption",
1902 			    this->openMacroCmd);
1903 
1904     this->openImageOption =
1905 	new ButtonInterface(pulldown, "vpeOpenImageOption",
1906 			    this->openImageCmd);
1907 
1908     this->openColormapEditorOption =
1909 	new ButtonInterface
1910 	    (pulldown, "vpeOpenColormapEditorOption", this->openColormapCmd);
1911 
1912     this->messageWindowOption =
1913         new ButtonInterface
1914             (pulldown, "vpeMessageWindowOption",
1915 	     theDXApplication->messageWindowCmd);
1916 
1917 
1918 }
1919 
1920 
createOptionsMenu(Widget parent)1921 void EditorWindow::createOptionsMenu(Widget parent)
1922 {
1923     ASSERT(parent);
1924 
1925     Widget            pulldown;
1926 
1927     //
1928     // Create "Options" menu and options.
1929     //
1930     pulldown =
1931 	this->optionsMenuPulldown =
1932 	    XmCreatePulldownMenu
1933 		(parent, "optionsMenuPulldown", NUL(ArgList), 0);
1934     this->optionsMenu =
1935 	XtVaCreateManagedWidget
1936 	    ("optionsMenu",
1937 	     xmCascadeButtonWidgetClass,
1938 	     parent,
1939 	     XmNsubMenuId, pulldown,
1940 	     NULL);
1941 
1942     this->toolPalettesOption =
1943 	new ToggleButtonInterface
1944 	    (pulldown,
1945 	     "vpeToolPalettesOption",
1946 	     this->toolPanelCmd,
1947 	     this->panelVisible);
1948 
1949     this->hitDetectionOption =
1950 	new ToggleButtonInterface
1951 	    (pulldown,
1952 	     "vpeHitDetectionOption",
1953 	     this->hitDetectionCmd,
1954 	     this->hit_detection);
1955 
1956     this->panelAccessOption =
1957 	new ButtonInterface(pulldown, "vpePanelAccessOption", this->setPanelAccessCmd);
1958 
1959     this->panelGroupOption =
1960 	new ButtonInterface(pulldown, "vpePanelGroupOption", this->setPanelGroupCmd);
1961 
1962     this->gridOption =
1963 	new ButtonInterface(pulldown, "vpeGridOption", this->gridCmd);
1964 
1965     XtAddCallback(pulldown, XmNmapCallback, (XtCallbackProc)
1966 	EditorWindow_OptionsMenuMapCB, (XtPointer)this);
1967 }
1968 
createHelpMenu(Widget parent)1969 void EditorWindow::createHelpMenu(Widget parent)
1970 {
1971     ASSERT(parent);
1972 
1973     this->DXWindow::createHelpMenu(parent);
1974 
1975     XtVaCreateManagedWidget("separator", xmSeparatorWidgetClass,
1976                                         this->helpMenuPulldown,
1977                                         NULL);
1978 
1979     this->onVisualProgramOption =
1980         new ButtonInterface(this->helpMenuPulldown, "vpeOnVisualProgramOption",
1981 				this->network->getHelpOnNetworkCommand());
1982 }
1983 
1984 
createMenus(Widget parent)1985 void EditorWindow::createMenus(Widget parent)
1986 {
1987     ASSERT(parent);
1988 
1989     //
1990     // Create the menus.
1991     //
1992     this->createFileMenu(parent);
1993     this->createEditMenu(parent);
1994     this->createExecuteMenu(parent);
1995     this->createWindowsMenu(parent);
1996     this->createConnectionMenu(parent);
1997     this->createOptionsMenu(parent);
1998     this->createHelpMenu(parent);
1999 
2000     //
2001     // Right justify the help menu (if it exists).
2002     //
2003     if (this->helpMenu)
2004     {
2005 	XtVaSetValues(parent, XmNmenuHelpWidget, this->helpMenu, NULL);
2006     }
2007 }
2008 
2009 
toggleToolPanel()2010 void EditorWindow::toggleToolPanel()
2011 {
2012     Widget toolpanel = this->toolSelector->getRootWidget();
2013 
2014     this->panelVisible = NOT this->panelVisible;
2015     if (!this->panelVisible) {
2016 	//
2017 	// Unmanage the control panel.
2018 	//
2019 	XtUnmanageChild(toolpanel);
2020 	XtVaSetValues (this->scrolledWindow,
2021 	     XmNleftAttachment, XmATTACH_FORM,
2022 	     XmNleftOffset,     0,
2023 	NULL);
2024 #if WORKSPACE_PAGES
2025 	XtVaSetValues (this->pageSelector->getRootWidget(),
2026 	    XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 0, NULL);
2027 #endif
2028     } else {
2029 	//
2030 	// Manage the control panel.
2031 	//
2032 	XtVaSetValues (this->scrolledWindow,
2033 	     XmNleftAttachment, XmATTACH_WIDGET,
2034 	     XmNleftWidget,     toolpanel,
2035 	     XmNleftOffset,     5,
2036 	     NULL);
2037 	XtManageChild(toolpanel);
2038 #if WORKSPACE_PAGES
2039 	XtVaSetValues (this->pageSelector->getRootWidget(),
2040 	    XmNleftAttachment, XmATTACH_WIDGET, XmNleftOffset, 5,
2041 	    XmNleftWidget, toolpanel, NULL);
2042 #endif
2043     }
2044 }
2045 
EditorWindow_EditMenuMapCB(Widget widget,XtPointer clientdata,XtPointer calldata)2046 extern "C" void EditorWindow_EditMenuMapCB(Widget widget,
2047                                    XtPointer clientdata,
2048                                    XtPointer calldata)
2049 {
2050 
2051     //
2052     // We do this here, because the editor does not get notified
2053     // when a node has the number repeatable inputs reduced to zero
2054     // and so can't grey out the 'Remove input' option.  This same argument
2055     // works for other add/remove repeatable input/output options.
2056     //
2057     EditorWindow *editor = (EditorWindow*)clientdata;
2058     editor->deferrableCommandActivation->requestAction(NULL);
2059 
2060     //
2061     // {de}activate the paste option based on selection ownership.
2062     // setCommandActivation() isn't really the right place for these
2063     // because there is no event or notification received when some other
2064     // vpe establishes or loses selection ownership.
2065     //
2066     Display *d = XtDisplay(widget);
2067     Atom file_atom = XmInternAtom (d, NET_ATOM, True);
2068     if (file_atom) {
2069 	Window win = XGetSelectionOwner (d, file_atom);
2070 	if (win == None) editor->pasteNodeCmd->deactivate();
2071 	else editor->pasteNodeCmd->activate();
2072     } else
2073 	editor->pasteNodeCmd->deactivate();
2074 }
EditorWindow_FileMenuMapCB(Widget widget,XtPointer clientdata,XtPointer calldata)2075 extern "C" void EditorWindow_FileMenuMapCB(Widget widget,
2076                                    XtPointer clientdata,
2077                                    XtPointer calldata)
2078 {
2079     EditorWindow *editor = (EditorWindow*)clientdata;
2080 
2081     if(editor->isAnchor() )
2082     {
2083 	if (editor->quitOption) {
2084 	    if(editor->network->saveToFileRequired())
2085 		((ButtonInterface*)editor->quitOption)->setLabel("Quit...");
2086 	    else
2087 		((ButtonInterface*)editor->quitOption)->setLabel("Quit");
2088  	}
2089     }
2090     else
2091     {
2092         editor->newOption->deactivate();
2093         editor->openOption->deactivate();
2094         editor->loadMDFOption->deactivate();
2095         editor->loadMacroOption->deactivate();
2096     }
2097 
2098 }
2099 
EditorWindow_WindowMenuMapCB(Widget widget,XtPointer clientdata,XtPointer calldata)2100 extern "C" void EditorWindow_WindowMenuMapCB(Widget widget,
2101                                    XtPointer clientdata,
2102                                    XtPointer calldata)
2103 {
2104      EditorWindow *editor = (EditorWindow*)clientdata;
2105 
2106     Network *network = editor->network;
2107     CascadeMenu *menu = editor->openControlPanelByNameMenu;
2108     PanelAccessManager *panelMgr = network->getPanelAccessManager();
2109     network->fillPanelCascade(menu, panelMgr);
2110 }
2111 
2112 extern "C"
EditorWindow_OptionsMenuMapCB(Widget widget,XtPointer clientdata,XtPointer)2113 void EditorWindow_OptionsMenuMapCB(Widget widget, XtPointer clientdata, XtPointer )
2114 {
2115     EditorWindow *editor = (EditorWindow*)clientdata;
2116     EditorWorkSpace* ews = editor->workSpace;
2117     WorkSpaceInfo* info = ews->getInfo();
2118     ToggleButtonInterface* tbi = (ToggleButtonInterface*)
2119 	editor->hitDetectionOption;
2120     editor->hit_detection = info->getPreventOverlap();
2121     tbi->setState(editor->hit_detection);
2122 }
2123 
openSelectedINodes()2124 void EditorWindow::openSelectedINodes()
2125 {
2126      Node *node;
2127      List *snlist = this->makeSelectedNodeList();
2128 
2129      if(NOT snlist)
2130 	return;
2131 
2132      ListIterator li(*snlist);
2133 
2134      while( (node = (Node*)li.getNext()) )
2135 	if(node->isA(ClassInteractorNode))
2136 	    ((InteractorNode*)node)->openControlPanels(this->getRootWidget());
2137 
2138      delete snlist;
2139 }
2140 
2141 #if WORKSPACE_PAGES
2142 EditorWorkSpace*
getPage(const char * pageName)2143 EditorWindow::getPage (const char *pageName)
2144 {
2145     EditorWorkSpace *page =
2146 	(EditorWorkSpace*)this->pageSelector->findDefinition(pageName);
2147 
2148     //
2149     // If the page hasn't been created yet, then find its info from the
2150     // page manager.
2151     //
2152     if (!page) {
2153 	PageGroupManager *pmgr = (PageGroupManager*)
2154 	    this->network->getGroupManagers()->findDefinition(PAGE_GROUP);
2155 	PageGroupRecord  *prec = (PageGroupRecord*)pmgr->getGroup (pageName);
2156 	ASSERT(prec);
2157 	page = (EditorWorkSpace*)this->workSpace->addPage();
2158 	ASSERT (this->pageSelector->addDefinition (pageName, page));
2159     }
2160 
2161     return page;
2162 }
2163 #endif
2164 
newNode(Node * n,EditorWorkSpace * where)2165 void EditorWindow::newNode(Node *n, EditorWorkSpace *where)
2166 {
2167     StandIn      *si;
2168     List         *arcs;
2169     Ark          *a;
2170     int           icnt, i, j;
2171     const char   *cp;
2172 
2173     si = n->getStandIn();
2174 
2175     //
2176     // We don't want to always create a new StandIn, because when
2177     // undeleting a node, the standin already exists.
2178     //
2179     if (!si) {
2180 	if (where) {
2181 	    n->newStandIn(where);
2182 #if WORKSPACE_PAGES
2183 	    GroupRecord* grec = this->getGroupOfWorkSpace(where);
2184 	    Symbol page_sym = theSymbolManager->getSymbol(PAGE_GROUP);
2185 	    if (grec) n->setGroupName(grec, page_sym);
2186 #endif
2187 	}
2188 #if WORKSPACE_PAGES
2189 	else if ( (cp = n->getGroupName(theSymbolManager->getSymbol(PAGE_GROUP))) ) {
2190 	    EditorWorkSpace *page = this->getPage(cp);
2191 	    ASSERT(page);
2192 	    //
2193 	    // If page is the current page, then make a standin.
2194 	    //
2195 	    int page_num = this->workSpace->getCurrentPage();
2196 	    EditorWorkSpace* ews = this->workSpace;
2197 	    if (page_num)
2198 		ews = (EditorWorkSpace*)this->workSpace->getElement(page_num);
2199 	    if (ews == page)
2200 		n->newStandIn(page);
2201 	    else
2202 		page->setMembersInitialized(FALSE);
2203 	} else {
2204 	    int page_num = this->workSpace->getCurrentPage();
2205 	    EditorWorkSpace* page = this->workSpace;
2206 	    if (page_num)
2207 		page = (EditorWorkSpace*)this->workSpace->getElement(page_num);
2208 	    GroupRecord* grec = this->getGroupOfWorkSpace(page);
2209 	    Symbol page_sym = theSymbolManager->getSymbol(PAGE_GROUP);
2210 	    if (grec) n->setGroupName(grec, page_sym);
2211 	    n->newStandIn(page);
2212 	}
2213 #else
2214 	else
2215 	    n->newStandIn(this->workSpace);
2216 #endif
2217         si = n->getStandIn();
2218 	if (si) {
2219 	    icnt = n->getInputCount();
2220 	    for (i=1 ; i<=icnt ; i++) {
2221 		arcs = (List *)n->getInputArks(i);
2222 		for (j = 1; (a = (Ark*) arcs->getElement(j)); j++)
2223 		    this->notifyArk(a);
2224 		si->drawTab(i, FALSE);
2225 	    }
2226 	}
2227     } else {
2228 	si->manage();
2229 	si->drawArks(n);
2230     }
2231 
2232     if (this->workSpace->isManaged())
2233         this->deferrableCommandActivation->requestAction(NULL);
2234 }
2235 
2236 
newNetwork()2237 void EditorWindow::newNetwork()
2238 {
2239     Node *node;
2240     ListIterator iterator;
2241 
2242     this->prepareForNewNetwork();
2243 
2244     // This is in case this is the first program being displayed.
2245     if (this->workSpace->isManaged())
2246 	this->workSpace->unmanage();
2247 
2248     FOR_EACH_NETWORK_NODE(this->network, node, iterator) {
2249 	this->newNode(node, NUL(EditorWorkSpace*));
2250     }
2251 
2252     this->deferrableCommandActivation->requestAction(NULL);
2253 
2254     this->workSpace->manage();
2255 
2256     this->completeNewNetwork();
2257 }
2258 
manage()2259 void EditorWindow::manage()
2260 {
2261     this->DXWindow::manage();
2262     if (this->initialNetwork)
2263     {
2264 	this->newNetwork();
2265 	this->initialNetwork = FALSE;
2266     }
2267     Decorator *dec;
2268     ListIterator it;
2269 
2270 
2271     FOR_EACH_NETWORK_DECORATOR(this->network,dec,it) {
2272 #if WORKSPACE_PAGES
2273 	const char* cp;
2274 	VPEAnnotator *vpea = (VPEAnnotator*)dec;
2275 	if ( (cp = vpea->getGroupName(theSymbolManager->getSymbol(PAGE_GROUP))) ) {
2276 	    EditorWorkSpace *page = this->getPage(cp);
2277 	    ASSERT(page);
2278 	} else
2279 #endif
2280 	{
2281 	    int page_num = this->workSpace->getCurrentPage();
2282 	    EditorWorkSpace* page = this->workSpace;
2283 	    if (page_num)
2284 		page = (EditorWorkSpace*)this->workSpace->getElement(page_num);
2285 	    if (!dec->isManaged())
2286 		dec->manage (page);
2287 	}
2288     }
2289 }
2290 
2291 //
2292 // Return a pointer to the editor's notion of the 'current' ControlPanel.
2293 // The return panel may or may not be managed.
2294 //
getCurrentControlPanel(void)2295 ControlPanel *EditorWindow::getCurrentControlPanel(void)
2296 {
2297     if (!this->currentPanel)
2298         this->currentPanel = this->network->newControlPanel();
2299 
2300     return this->currentPanel;
2301 }
2302 
2303 
2304 //
2305 // Implements the 'Values' command.
2306 //
showValues()2307 void EditorWindow::showValues()
2308 {
2309     this->openSelectedNodesCDB();
2310 }
2311 //
2312 // Implements the 'Add/Remove Input/Output Tab' commands.
2313 // If 'adding' is TRUE, we ADD either inputs or outputs, otherwise
2314 // REMOVE.
2315 // If 'input' is true, we operate on the input parameters, otherwise
2316 // the outputs.
2317 //
editSelectedNodeTabs(boolean adding,boolean input)2318 boolean EditorWindow::editSelectedNodeTabs(boolean adding, boolean input)
2319 {
2320     List *l = this->makeSelectedNodeList();
2321     if (l == NULL || l->getSize() == 0) {
2322 	if (l) delete l;
2323 	return TRUE;
2324     }
2325 
2326     Node *node;
2327     boolean r = TRUE;
2328     ListIterator li(*l);
2329 
2330     boolean added_separator = FALSE;
2331     while ( (node = (Node*)li.getNext()) )
2332     {
2333 	if (!this->performing_undo) {
2334 	    if (!added_separator) {
2335 		this->undo_list.push (new UndoSeparator(this));
2336 		added_separator = TRUE;
2337 	    }
2338 	    this->undo_list.push (new UndoRepeatableTab(this, node, adding, input));
2339 	}
2340 	if (adding) {
2341 	    if (input && node->isInputRepeatable()) {
2342 		r = r && node->addInputRepeats();
2343 	    } else if (!input && node->isOutputRepeatable()) {
2344 		r = r && node->addOutputRepeats();
2345 	    }
2346 	} else {
2347 	    if (input && node->hasRemoveableInput()) {
2348 		r = r && node->removeInputRepeats();
2349 	    } else if (!input && node->hasRemoveableOutput()) {
2350 		r = r && node->removeOutputRepeats();
2351 	    }
2352 	}
2353     }
2354 
2355     if (r && !input)
2356         this->deferrableCommandActivation->requestAction(NULL);
2357 
2358     delete l;
2359 
2360     // this->setCommandActivation() doesn't run often enough to deal
2361     // with accelerators.
2362     if ((added_separator) && (!this->undoCmd->isActive()))
2363 	this->setUndoActivation();
2364 
2365     return r;
2366 }
2367 
setSelectedNodeTabVisibility(boolean v)2368 boolean EditorWindow::setSelectedNodeTabVisibility(boolean v)
2369 {
2370     List *l = this->makeSelectedNodeList();
2371     if (l == NULL || l->getSize() == 0) {
2372 	if (l) delete l;
2373 	return TRUE;
2374     }
2375 
2376     ListIterator li(*l);
2377     Node *node;
2378 #if WORKSPACE_PAGES
2379     this->beginPageChange();
2380 #else
2381     this->beginNetworkChange();
2382 #endif
2383     boolean added_separator = FALSE;
2384     while( (node = (Node*)li.getNext()) )
2385     {
2386 	node->setAllInputsVisibility(v);
2387 	node->setAllOutputsVisibility(v);
2388     }
2389     delete l;
2390 #if WORKSPACE_PAGES
2391     this->endPageChange();
2392 #else
2393     this->endNetworkChange();
2394 #endif
2395 
2396     return TRUE;
2397 }
2398 
2399 //
2400 // Do node selection.
2401 //
selectConnection(int dir,boolean connected)2402 boolean EditorWindow::selectConnection(int dir, boolean connected)
2403 {
2404     List *l = this->makeSelectedNodeList();
2405 
2406     if (l == NULL || l->getSize() == 0) {
2407 	if (l) delete l;
2408 	return FALSE;
2409     }
2410 
2411     ListIterator li(*l);
2412     ListIterator iterator;
2413     Node *node, *snode;
2414     List *nlist = &this->network->nodeList;
2415     int nsize = nlist->getSize();
2416     int i, pos;
2417     boolean *mark = new boolean[nsize];
2418 
2419     if (connected)
2420 	this->deselectAllNodes();
2421     else
2422 	this->selectAllNodes();
2423 
2424     while((snode = (Node*)li.getNext())
2425 	  AND (pos = nlist->getPosition((const void*)snode)))
2426     {
2427       	for(i=0; i<nsize; i++)
2428              mark[i] = FALSE;
2429 
2430 	/*mnodes =*/ this->network->connectedNodes(mark, pos-1, dir);
2431 
2432 	pos = 0;
2433 	FOR_EACH_NETWORK_NODE(this->network, node, iterator)
2434 	{
2435 	     if(mark[pos++])
2436 	     	node->getStandIn()->setSelected(connected);
2437 	}
2438     }
2439     delete mark;
2440     delete l;
2441 
2442     return TRUE;
2443 
2444 }
2445 
2446 
2447 //
2448 // Implements the 'Select Downward' command.
2449 //
selectDownwardNodes()2450 boolean EditorWindow::selectDownwardNodes()
2451 {
2452     return this->selectConnection(1, TRUE);
2453 }
2454 //
2455 // Implements the 'Select Upward' command.
2456 //
selectUpwardNodes()2457 boolean EditorWindow::selectUpwardNodes()
2458 {
2459     return this->selectConnection(-1, TRUE);
2460 }
2461 //
2462 // Implements the 'Select Connected' command.
2463 //
selectConnectedNodes()2464 boolean EditorWindow::selectConnectedNodes()
2465 {
2466     return this->selectConnection(0, TRUE);
2467 }
2468 //
2469 // Implements the 'Selected Unconnected' command.
2470 //
selectUnconnectedNodes()2471 boolean EditorWindow::selectUnconnectedNodes()
2472 {
2473     return this->selectConnection(0, FALSE);
2474 }
2475 
2476 //
2477 // look through the network list for selected nodes
2478 // and open the configuration dialog associated with
2479 // the node.
2480 //
2481 #define MAX_SANE_CDBS 5
openSelectedNodesCDB()2482 void EditorWindow::openSelectedNodesCDB()
2483 {
2484     Node *node;
2485     StandIn *standIn;
2486     ListIterator iterator;
2487     int selected_count = 0;
2488 
2489     //
2490     // The sanity check is to prevent opening too many cdbs at once.  This path
2491     // results from Ctrl-F in the vpe and is seldom used incorrectly.  The real
2492     // problem is double clicking on a node in the vpe.  But when we go down that
2493     // path in the code, we don't know if we'll open a cdb or something else so
2494     // it's hard to count them up first.
2495     //
2496     FOR_EACH_NETWORK_NODE(this->network, node, iterator) {
2497         standIn = node->getStandIn();
2498 #if WORKSPACE_PAGES
2499 	if (!standIn) continue;
2500 #endif
2501         if (standIn->isSelected())
2502 	    selected_count++;
2503     }
2504     //
2505     // Sanity check
2506     //
2507     if (selected_count > MAX_SANE_CDBS) {
2508 	char msg[128];
2509 	sprintf (msg, "Really open %d configuration dialogs?", selected_count);
2510 	int response = theQuestionDialogManager->userQuery(this->getRootWidget(),
2511 	    msg, "Confirm Open CDB", "Yes", "No", NULL, 2
2512 	);
2513 	if (response != QuestionDialogManager::OK) return ;
2514     }
2515 
2516     FOR_EACH_NETWORK_NODE(this->network, node, iterator) {
2517         standIn = node->getStandIn();
2518 #if WORKSPACE_PAGES
2519 	if (!standIn) continue;
2520 #endif
2521         if (standIn->isSelected())
2522 	    node->openConfigurationDialog(this->getRootWidget());
2523 
2524     }
2525 
2526 }
2527 //
2528 // look through the network list for selected nodes
2529 // and ask the node to do its default action.
2530 //
doSelectedNodesDefaultAction()2531 void EditorWindow::doSelectedNodesDefaultAction()
2532 {
2533     Node *node;
2534     StandIn *standIn;
2535     ListIterator iterator;
2536 
2537     //
2538     // The sanity check is to prevent opening too many cdbs at once.  This path
2539     // results from a double click in the vpe and is often used incorrectly.
2540     //
2541     int cdb_count = 0;
2542     FOR_EACH_NETWORK_NODE(this->network, node, iterator) {
2543         standIn = node->getStandIn();
2544 #if WORKSPACE_PAGES
2545 	if (!standIn) continue;
2546 #endif
2547         if (standIn->isSelected())
2548 	    if (node->defaultWindowIsCDB())
2549 		cdb_count++;
2550     }
2551     //
2552     // Sanity check
2553     //
2554     if (cdb_count > MAX_SANE_CDBS) {
2555 	char msg[128];
2556 	sprintf (msg, "Really open %d configuration dialogs?", cdb_count);
2557 	int response = theQuestionDialogManager->userQuery(this->getRootWidget(),
2558 	    msg, "Confirm Open CDB", "Yes", "No", NULL, 2
2559 	);
2560 	if (response != QuestionDialogManager::OK) return ;
2561     }
2562 
2563     //
2564     // If there are selected interactor nodes, then deselect all
2565     // InteractorInstances in the existing control panels.
2566     //
2567     FOR_EACH_NETWORK_NODE(this->network, node, iterator) {
2568         if (node->isA(ClassInteractorNode))  {
2569 	    int count = network->getPanelCount();
2570 	    if (count != 0) {
2571 		int i;
2572 		for (i=1; i<=count ; i++) {
2573 		    ControlPanel *cp = network->getPanelByIndex(i);
2574 		    cp->selectAllInstances(FALSE);
2575 		}
2576 	    }
2577 	    break;
2578 	}
2579     }
2580 
2581 
2582     //
2583     // Erase any notion of the current control panel so that selected
2584     // InteractorNodes can add themselves to what will be a newly created
2585     // ControlPanel via this->getCurrentControlPanel().
2586     //
2587     this->currentPanel = NULL;
2588 
2589     theApplication->setBusyCursor(TRUE);
2590     FOR_EACH_NETWORK_NODE(this->network, node, iterator) {
2591         standIn = node->getStandIn();
2592 #if WORKSPACE_PAGES
2593 	if (!standIn) continue;
2594 #endif
2595         if (standIn->isSelected())  {
2596 	    node->openDefaultWindow(this->getRootWidget());
2597 	    ConfigurationDialog *cdb = node->getConfigurationDialog();
2598 	    if (cdb) {
2599 	    	Widget cdbWidget = cdb->getRootWidget();
2600 	    	if (cdbWidget) {
2601 	    		// Transfer Accelerations
2602 	    		TransferAccelerator(cdbWidget,
2603 	    			this->saveOption->getRootWidget(), "ArmAndActivate");
2604 	    		TransferAccelerator(cdbWidget,
2605 	    			this->addInputTabOption->getRootWidget(), "ArmAndActivate");
2606 	    		TransferAccelerator(cdbWidget,
2607 	    			this->removeInputTabOption->getRootWidget(), "ArmAndActivate");
2608 	    		TransferAccelerator(cdbWidget,
2609 	    			this->executeOnceOption->getRootWidget(), "ArmAndActivate");
2610 	    		TransferAccelerator(cdbWidget,
2611 	    			this->executeOnChangeOption->getRootWidget(), "ArmAndActivate");
2612 	    		TransferAccelerator(cdbWidget,
2613 	    			this->endExecutionOption->getRootWidget(), "ArmAndActivate");
2614 	    	}
2615 	    }
2616 	}
2617     }
2618 
2619 
2620     //
2621     // Open the default windows for any selected decorators.
2622     //
2623     Decorator *decor;
2624     FOR_EACH_NETWORK_DECORATOR(this->network, decor, iterator) {
2625 	if ((decor->isSelected()) && (decor->hasDefaultWindow()))
2626 	    decor->openDefaultWindow();
2627     }
2628 
2629 
2630     theApplication->setBusyCursor(FALSE);
2631 
2632 }
2633 
getNodeSelectionCount(const char * classname)2634 int EditorWindow::getNodeSelectionCount(const char *classname)
2635 {
2636     Node	*node;
2637     StandIn	*standIn;
2638     ListIterator iterator;
2639     int		selected = 0;
2640 
2641     FOR_EACH_NETWORK_NODE(this->network, node, iterator) {
2642 	standIn = node->getStandIn();
2643 	if ((standIn) && (standIn->isSelected() &&
2644 	    ((classname == NULL) || node->isA(classname))))
2645 	    selected++;
2646     }
2647     return selected;
2648 }
2649 //
2650 // look through the network list and make a list of selected nodes  of
2651 // the given class.  If classname == NULL, then get all selected nodes.
2652 // If no selected interactors were found then NULL is returned.
2653 //
makeSelectedNodeList(const char * classname)2654 List *EditorWindow::makeSelectedNodeList(const char *classname)
2655 {
2656     List	*l;
2657     List *selected = NULL;;
2658 
2659     if (classname == NULL)
2660 	l = &this->network->nodeList;
2661     else
2662 	l = this->network->makeClassifiedNodeList(classname);
2663 
2664     if (l) {
2665 	ListIterator iterator(*l);
2666         Node *node;
2667   	while ( (node = (Node*)iterator.getNext()) ) {
2668             StandIn *standIn = node->getStandIn();
2669 	    if (standIn && standIn->isSelected()) {
2670 		if (!selected)
2671 		    selected = new List();
2672 	        selected->appendElement((const void*) node);
2673 	    }
2674 	}
2675 	if (classname != NULL)
2676 	    delete l;
2677     }
2678     return selected;
2679 }
2680 
2681 
2682 List *
makeSelectedDecoratorList()2683 EditorWindow::makeSelectedDecoratorList()
2684 {
2685 Decorator *decor;
2686 ListIterator it;
2687 
2688     List *selected = NULL;
2689 
2690     FOR_EACH_NETWORK_DECORATOR(this->network, decor, it) {
2691 	if (decor->isSelected()) {
2692 	    if (!selected) selected = new List;
2693 	    selected->appendElement((const void*)decor);
2694 	}
2695     }
2696     return selected;
2697 }
2698 
2699 //
2700 // Make a sorted list of modules existing in the VPE.
2701 //
makeModuleList()2702 List *EditorWindow::makeModuleList()
2703 {
2704     Node *node;
2705     ListIterator li,iterator;
2706     List   	*l = NUL(List*);
2707     char *name, *module;
2708     int  r, i;
2709 
2710     FOR_EACH_NETWORK_NODE(this->network, node, iterator)
2711     {
2712 	if (!l)
2713 	    l = new List;
2714 
2715 	name = (char*)node->getNameString();
2716 	li.setList(*l);
2717 	i = 1; r = 1;
2718 	while( (module = (char*)li.getNext()) )
2719 	{
2720 	    r = strcmp(module, name);
2721 	    if(r >= 0)	break;
2722 	    i++;
2723 	}
2724 	if(r != 0)
2725 	{
2726 	    name = DuplicateString(node->getNameString());
2727 	    l->insertElement((const void*)name, i);
2728 	}
2729     }
2730     return l;
2731 }
2732 
2733 //
2734 // Notify the source and destination standIn that an arc
2735 // has been added.
2736 //
2737 
notifyArk(Ark * a,boolean added)2738 void EditorWindow::notifyArk(Ark *a, boolean added)
2739 {
2740     StandIn *standIn;
2741     Node    *n;
2742     int      param;
2743 
2744     n = a->getSourceNode(param);
2745     standIn = n->getStandIn();
2746 #if WORKSPACE_PAGES
2747     if (!standIn) return ;
2748 #endif
2749     if (added) {
2750 	standIn->addArk(this, a);
2751     }
2752     if ((!this->performing_undo) && (!this->creating_new_network)) {
2753 	this->undo_list.push (new UndoSeparator(this));
2754 	this->undo_list.push (new UndoAddArk(this, a, added));
2755 	// this->setCommandActivation() doesn't run often enough to deal
2756 	// with accelerators.
2757 	if (!this->undoCmd->isActive())
2758 	    this->setUndoActivation();
2759     }
2760 }
2761 
2762 //
2763 // Move the workSpace inside the scrolled window so that the given x,y
2764 // position is at the upper left corner of the scrolled window unless
2765 // centered is TRUE in which case x,y is the center of the scrolled
2766 // window.
2767 //
moveWorkspaceWindow(int x,int y,boolean centered)2768 void EditorWindow::moveWorkspaceWindow(int x, int y, boolean centered)
2769 {
2770     ASSERT(!centered);// Not implemented yet.
2771 
2772     XmScrolledWindowWidget scrollWindow;
2773     int         value;
2774     int         size;
2775     int         max;
2776     int         min;
2777     int         delta;
2778     int         pdelta;
2779     int		newValue;
2780 
2781     /*
2782      * Convert scrolled window widget to its internal form.
2783      */
2784     scrollWindow = (XmScrolledWindowWidget)this->getScrolledWindow();
2785 
2786     //
2787     // Set ScrollBar's value.
2788     // ...but ensure that the values are legal, making any necessary
2789     // adjustments.  That way callers (like InsertNetworkDialog) don't
2790     // need carnal knowledge of the scrollbars to1 change screen positioning.
2791     //
2792     XmScrollBarGetValues((Widget)scrollWindow->swindow.hScrollBar,
2793                          &value, &size, &delta, &pdelta);
2794     XtVaGetValues ((Widget)scrollWindow->swindow.hScrollBar,
2795 	XmNmaximum, &max, XmNminimum, &min, NULL);
2796 
2797     if (x>= (max-size))
2798 	newValue = max-(size+1);
2799     else
2800 	newValue = x;
2801     newValue = MAX(min,newValue);
2802 
2803 
2804     XmScrollBarSetValues((Widget)scrollWindow->swindow.hScrollBar,
2805 	newValue, size, delta, pdelta, True);
2806 
2807     XmScrollBarGetValues((Widget)scrollWindow->swindow.vScrollBar,
2808                          &value, &size, &delta, &pdelta);
2809     XtVaGetValues ((Widget)scrollWindow->swindow.vScrollBar,
2810 	XmNmaximum, &max, XmNminimum, &min, NULL);
2811 
2812     if (y>= (max-size))
2813 	newValue = max-(size+1);
2814     else
2815 	newValue = y;
2816     newValue = MAX(min,newValue);
2817 
2818     XmScrollBarSetValues((Widget)scrollWindow->swindow.vScrollBar,
2819 	newValue, size, delta, pdelta, True);
2820 }
2821 
getWorkspaceWindowPos(int * x,int * y)2822 void EditorWindow::getWorkspaceWindowPos(int *x, int *y)
2823 {
2824     XmScrolledWindowWidget scrollWindow;
2825     int         value;
2826     int         size;
2827     int         delta;
2828     int         pdelta;
2829 
2830     scrollWindow = (XmScrolledWindowWidget)this->getScrolledWindow();
2831     XmScrollBarGetValues((Widget)scrollWindow->swindow.hScrollBar,
2832 			 &value, &size, &delta, &pdelta);
2833     *x = value;
2834     XmScrollBarGetValues((Widget)scrollWindow->swindow.vScrollBar,
2835 			 &value, &size, &delta, &pdelta);
2836     *y = value;
2837     return ;
2838 }
2839 
2840 //
2841 // moveWorkspaceWindow() used to do some side effect stuff on behalf
2842 // of the FindToolDialog.  I've moved that into a separate method.  I
2843 // hope it's clearer.  The stuff in moveWorkspaceWindow was broken when
2844 // I added vpe pages because the timing of the operations changed.
2845 //
checkPointForFindDialog(FindToolDialog * dialog)2846 void EditorWindow::checkPointForFindDialog(FindToolDialog* dialog)
2847 {
2848     XmScrolledWindowWidget scrollWindow;
2849     Arg                    arg[8];
2850     Cardinal               n;
2851     int                    hScrollValue;
2852     int                    vScrollValue;
2853 
2854     ASSERT (dialog->isManaged());
2855 
2856     int page = this->workSpace->getCurrentPage();
2857     EditorWorkSpace *current_ews = this->workSpace;
2858     if (page) current_ews = (EditorWorkSpace*)this->workSpace->getElement(page);
2859     GroupRecord* grec = this->getGroupOfWorkSpace(current_ews);
2860     if (this->find_restore_page)
2861 	delete this->find_restore_page;
2862     if (grec)
2863 	this->find_restore_page = DuplicateString(grec->getName());
2864     else
2865 	this->find_restore_page = NUL(char*);
2866 
2867     /*
2868      * Convert scrolled window widget to its internal form.
2869      */
2870     scrollWindow = (XmScrolledWindowWidget)this->getScrolledWindow();
2871     /*
2872      * Get drawing window resources.
2873      */
2874     n = 0;
2875     XtSetArg(arg[n], XmNvalue, &hScrollValue); n++;
2876     XtGetValues((Widget)scrollWindow->swindow.hScrollBar, arg, n);
2877 
2878     n = 0;
2879     XtSetArg(arg[n], XmNvalue, &vScrollValue); n++;
2880     XtGetValues((Widget)scrollWindow->swindow.vScrollBar, arg, n);
2881 
2882     /*
2883      * Store the original position.  The original vpe page
2884      * was recorded earlier in this method just prior to
2885      * selecting the vpe page of the destination node.
2886      */
2887     this->Ox = hScrollValue;
2888     this->Oy = vScrollValue;
2889 }
2890 
moveWorkspaceWindow(UIComponent * si)2891 void EditorWindow::moveWorkspaceWindow(UIComponent* si)
2892 {
2893     XmScrolledWindowWidget scrollWindow;
2894     Arg                    arg[8];
2895     Cardinal               n;
2896     int                    hSliderSize;
2897     int                    vSliderSize;
2898     int                    hScrollValue;
2899     int                    vScrollValue;
2900     int                    hScrollMax;
2901     int                    vScrollMax;
2902     int                    newOx;
2903     int                    newOy;
2904 
2905 
2906 #if WORKSPACE_PAGES
2907     //
2908     // Present the proper page for this standin
2909     //
2910     // It's also possible to find the proper page using Node methods but we
2911     // don't ordinarily know the node behind a standin because that's protected info.
2912     //
2913     if (si) {
2914 	Widget page_parent = XtParent(si->getRootWidget());
2915 	if (page_parent != this->workSpace->getRootWidget()) {
2916 	    DictionaryIterator di(*this->pageSelector);
2917 	    EditorWorkSpace* ews;
2918 	    while ( (ews = (EditorWorkSpace*)di.getNextDefinition()) ) {
2919 		if (ews->getRootWidget() == page_parent) {
2920 		    ews->unsetRecordedScrollPos();
2921 		    this->workSpace->showWorkSpace(ews);
2922 		    break;
2923 		}
2924 	    }
2925 	}
2926     }
2927 #endif
2928 
2929     /*
2930      * Convert scrolled window widget to its internal form.
2931      */
2932     scrollWindow = (XmScrolledWindowWidget)this->getScrolledWindow();
2933     /*
2934      * Get drawing window resources.
2935      */
2936     n = 0;
2937     XtSetArg(arg[n], XmNvalue, &hScrollValue); n++;
2938     XtSetArg(arg[n], XmNsliderSize, &hSliderSize); n++;
2939     XtSetArg(arg[n], XmNmaximum, &hScrollMax); n++;
2940     XtGetValues((Widget)scrollWindow->swindow.hScrollBar, arg, n);
2941 
2942     n = 0;
2943     XtSetArg(arg[n], XmNvalue, &vScrollValue); n++;
2944     XtSetArg(arg[n], XmNsliderSize, &vSliderSize); n++;
2945     XtSetArg(arg[n], XmNmaximum, &vScrollMax); n++;
2946     XtGetValues((Widget)scrollWindow->swindow.vScrollBar, arg, n);
2947 
2948     /*
2949      * Check if the module is already in the clip window.
2950      */
2951 
2952      int xpos, ypos, width, height;
2953      if (si) {
2954 	 si->getXYSize(&width, &height);
2955 	 si->getXYPosition(&xpos, &ypos);
2956 	 if ( (xpos + width < hSliderSize + hScrollValue) &&
2957               (ypos + height< vSliderSize + vScrollValue) &&
2958               (xpos > hScrollValue) &&
2959               (ypos > vScrollValue))
2960              return;
2961     }
2962 
2963     /*
2964      * Calculate new origin.
2965      */
2966     if (!si)                 /* RESTORE */
2967     {
2968         newOx = this->Ox;
2969         newOy = this->Oy;
2970         this->Ox = -1;
2971 	if (this->find_restore_page) {
2972 	    EditorWorkSpace* ews = (EditorWorkSpace*)
2973 		this->pageSelector->findDefinition (this->find_restore_page);
2974 	    if (ews) this->workSpace->showWorkSpace(ews);
2975 	} else {
2976 	    // It could be that the original was the "Untitled" page in
2977 	    // which case find_restore_page would legitimatly be NUL.
2978 	    // In that situation we can show the root workspace but only
2979 	    // if we first ensure that the user hasn't deleted it.
2980 	    // Anytime the user has deleted the page we're looking for, we
2981 	    // just silently ignore the problem.
2982 	    EditorWorkSpace* ews = (EditorWorkSpace*)
2983 		this->pageSelector->findDefinition ("Untitled");
2984 	    if (ews) this->workSpace->showWorkSpace(ews);
2985 	}
2986     	this->find_restore_page = NUL(char*);
2987     }
2988     else                       /* FIND */
2989     {
2990         if ((newOx = xpos + width/2-hSliderSize/2) < 0)
2991                 newOx = 0;
2992         if ((newOy = ypos + height/2-vSliderSize/2) < 0)
2993                 newOy = 0;
2994     }
2995 
2996     if (newOx + hSliderSize > hScrollMax)
2997                 newOx = hScrollMax - hSliderSize;
2998 
2999     if (newOy + vSliderSize > vScrollMax)
3000                 newOy = vScrollMax - vSliderSize;
3001 
3002     /*
3003      * Reset the scrolled window's (x,y) origin.(??????????????)
3004      */
3005     scrollWindow->swindow.hOrigin = newOx;
3006     scrollWindow->swindow.vOrigin = newOy;
3007 
3008     /*
3009      * Reset the scrolled bars physically.
3010      */
3011     XtSetArg(arg[0], XmNvalue, newOx);
3012     XtSetValues((Widget)scrollWindow->swindow.hScrollBar, arg, 1);
3013     XtSetArg(arg[0], XmNvalue, newOy);
3014     XtSetValues((Widget)scrollWindow->swindow.vScrollBar, arg, 1);
3015 
3016     /*
3017      * Move the work window to reflect the new state.
3018      */
3019     XtMoveWidget(scrollWindow->swindow.WorkWindow,-newOx,-newOy);
3020 
3021 }
3022 
3023 #if WORKSPACE_PAGES
getGroupOfWorkSpace(EditorWorkSpace * where)3024 GroupRecord* EditorWindow::getGroupOfWorkSpace (EditorWorkSpace* where)
3025 {
3026     //
3027     // If adding to a page, then find out the page name in order to
3028     // set the group record in the added object.  First fetch the group
3029     // manager, then find the name of the workspace page by looping over
3030     // the page dictionary, then fetch the group record from the manager
3031     // using the name, then set the group record into the object.
3032     //
3033     GroupRecord *grec = NUL(GroupRecord*);
3034     Symbol page_sym = theSymbolManager->getSymbol(PAGE_GROUP);
3035 
3036     const char *page_name = NUL(char*);
3037     GroupManager *page_mgr = NUL(GroupManager*);
3038     ASSERT(this->pageSelector);
3039     int count = this->pageSelector->getSize();
3040     int i;
3041     for (i=1; i<=count; i++) {
3042 	if (where == this->pageSelector->getDefinition(i)) {
3043 	    page_name = this->pageSelector->getStringKey(i);
3044 	    break;
3045 	}
3046     }
3047     page_mgr = (GroupManager*)
3048 	this->network->getGroupManagers()->findDefinition(page_sym);
3049     ASSERT(page_mgr);
3050     if (page_name) {
3051 	if (where != this->workSpace) {
3052 	    ASSERT(page_name);
3053 	}
3054 
3055 	//
3056 	// grec could be NULL for the root page when the name is still Untitled.
3057 	//
3058 	grec = page_mgr->getGroup (page_name);
3059 	if (where != this->workSpace) {
3060 	    ASSERT(grec);
3061 	}
3062     }
3063 
3064     return grec;
3065 }
3066 #endif
3067 
3068 //
3069 // Add the current ToolSelector node to the workspace
3070 //
addCurrentNode(int x,int y,EditorWorkSpace * where,boolean stitch)3071 void EditorWindow::addCurrentNode(int x, int y, EditorWorkSpace *where, boolean stitch)
3072 {
3073     NodeDefinition *nodeDef = this->toolSelector->getCurrentSelection();
3074 
3075     if (nodeDef) {
3076 	this->addNode(nodeDef, x, y, where);
3077     } else if (this->addingDecorators) {
3078 
3079 	// Deselect all currently selected nodes
3080 	this->deselectAllNodes();
3081 
3082 	ListIterator it(*this->addingDecorators);
3083 	VPEAnnotator *dec;
3084 	while ( (dec = (VPEAnnotator*)it.getNext()) ) {
3085 	    dec->setXYPosition(x,y);
3086 	    dec->manage(where);
3087 	    dec->setSelected(TRUE);
3088 	    this->network->addDecoratorToList((void*)dec);
3089 #if WORKSPACE_PAGES
3090 	    GroupRecord* grec = this->getGroupOfWorkSpace(where);
3091 	    Symbol page_sym = theSymbolManager->getSymbol(PAGE_GROUP);
3092 	    if (grec)
3093 		dec->setGroupName(grec, page_sym);
3094 #endif
3095 	}
3096 	this->resetCursor();
3097 	this->setCommandActivation();
3098     } else if (this->pendingPaste) {
3099 	// because of stitching, we might be adding nodes to a page that
3100 	// isn't the current page.  So, make sure the destination page
3101 	// is set to the current page.
3102 	if (stitch) {
3103 	    List *all_nodes = this->pendingPaste->makeClassifiedNodeList(ClassNode);
3104 	    Symbol psym = theSymbolManager->getSymbol(PAGE_GROUP);
3105 	    Node* any_node = NUL(Node*);
3106 	    const char* group_name = NUL(const char*);
3107 	    if ((all_nodes) && (all_nodes->getSize() >= 1)) {
3108 		any_node = (Node*)all_nodes->getElement(1);
3109 		group_name = any_node->getGroupName(psym);
3110 	    }
3111 	    if (!any_node) {
3112 		List* all_decs = (List*)this->pendingPaste->getDecoratorList();
3113 		VPEAnnotator* any_dec = NUL(VPEAnnotator*);
3114 		if ((all_decs) && (all_decs->getSize() >= 1)) {
3115 		    any_dec = (VPEAnnotator*)all_decs->getElement(1);
3116 		    group_name = any_dec->getGroupName(psym);
3117 		}
3118 	    }
3119 	    if (group_name) {
3120 		EditorWorkSpace* ews = (EditorWorkSpace*)
3121 		    this->pageSelector->findDefinition(group_name);
3122 		if (ews != NUL(EditorWorkSpace*))
3123 		    this->pageSelector->selectPage(ews);
3124 	    }
3125 	    delete all_nodes;
3126 	}
3127 
3128 	// Deselect all currently selected nodes
3129 	this->deselectAllNodes();
3130 
3131 	this->pendingPaste->setTopLeftPos (x,y);
3132 	List *l = this->pendingPaste->getNonEmptyPanels();
3133 	this->pagifyNetNodes (this->pendingPaste, where, TRUE);
3134 	boolean tmp = this->creating_new_network;
3135 	this->creating_new_network = TRUE;
3136 	this->network->mergeNetworks (this->pendingPaste, l, TRUE, stitch);
3137 	this->creating_new_network = tmp;
3138 	if (l) delete l;
3139 	this->resetCursor();
3140 	this->setCommandActivation();
3141     }
3142 
3143     //
3144     // Check these 2 fields for deletion apart from the other if blocks
3145     // because if you're adding a new node, then you still need to come
3146     // here and delete these objects.
3147     //
3148     if (this->addingDecorators) {
3149 	delete this->addingDecorators;
3150 	this->addingDecorators = 0;
3151     }
3152 
3153     if (this->pendingPaste) {
3154 	delete this->pendingPaste;
3155 	this->pendingPaste = NUL(Network*);
3156     }
3157 }
3158 
3159 //
3160 // Add a node of the specified type to the workspace
3161 //
addNode(NodeDefinition * nodeDef,int x,int y,EditorWorkSpace * where)3162 void EditorWindow::addNode (NodeDefinition *nodeDef, int x, int y, EditorWorkSpace *where)
3163 {
3164     Node *node;
3165 
3166     // Reset the cursor if further placements are not allowed.
3167     if (!this->toolSelector->isSelectionLocked()) {
3168 	this->resetCursor();
3169 	this->toolSelector->deselectAllTools();
3170     }
3171 
3172     node = nodeDef->createNewNode(this->network);
3173     if (node == NULL)
3174 	return;
3175 
3176 #if WORKSPACE_PAGES
3177     GroupRecord* grec;
3178     if (where)
3179 	grec = this->getGroupOfWorkSpace(where);
3180     else {
3181 	EditorWorkSpace *ews;
3182 	int page = this->workSpace->getCurrentPage();
3183 	if (!page)
3184 	    ews = this->workSpace;
3185 	else
3186 	    ews = (EditorWorkSpace*)this->workSpace->getElement(page);
3187 	grec = this->getGroupOfWorkSpace(ews);
3188     }
3189     Symbol page_sym = theSymbolManager->getSymbol(PAGE_GROUP);
3190     if (grec)
3191 	node->setGroupName(grec, page_sym);
3192 #endif
3193 
3194     node->setVpePosition(x,y);
3195     this->network->addNode(node, where);
3196 
3197     // Deselect all currently selected nodes
3198     this->deselectAllNodes();
3199 
3200     // Select the added node
3201     StandIn *si = node->getStandIn();
3202     ASSERT(si);
3203     si->setSelected(TRUE);
3204 
3205     if(this->findToolDialog AND this->findToolDialog->isManaged())
3206     	this->findToolDialog->changeList();
3207 
3208     this->resetExecutionList();
3209 }
3210 
setCursor(int cursorType)3211 void EditorWindow::setCursor(int cursorType)
3212 {
3213 
3214 // Just ask the workspace to set the cursor type
3215 
3216     this->workSpace->setCursor(cursorType);
3217 }
3218 
3219 //
3220 // reset the EditorWindow cursor to the default.
3221 //
resetCursor()3222 void EditorWindow::resetCursor()
3223 {
3224     this->workSpace->resetCursor();
3225 }
3226 
3227 
3228 //
3229 // Create a list of nodes to delete, and call deleteNodes with the list.
3230 //
removeSelectedNodes()3231 void EditorWindow::removeSelectedNodes()
3232 {
3233     Node         *node;
3234     List         *toDelete = NULL;
3235     StandIn      *si;
3236     ListIterator iterator;
3237 
3238     this->deferrableCommandActivation->deferAction();
3239 
3240     //
3241     // Make a copy of the deletions so that the operation can be undone
3242     //
3243     if (!this->performing_undo) {
3244 	this->undo_list.push (new UndoSeparator(this));
3245 	this->undo_list.push(
3246 	    new UndoDeletion (this,
3247 		this->makeSelectedNodeList(NUL(const char*)),
3248 		this->makeSelectedDecoratorList())
3249 	);
3250 	// this->setCommandActivation() doesn't run often enough to deal
3251 	// with accelerators.
3252 	if (!this->undoCmd->isActive())
3253 	    this->setUndoActivation();
3254     }
3255 
3256     //
3257     // Build a list of nodes and unmanage the standIns that go with them.
3258     //
3259     FOR_EACH_NETWORK_NODE(this->network, node, iterator) {
3260         si = node->getStandIn();
3261 #if WORKSPACE_PAGES
3262 	if (!si) continue;
3263 #endif
3264         if (si->isSelected()) {
3265 	    if (!toDelete)
3266 		toDelete = new List;
3267             toDelete->appendElement(node);
3268 	}
3269     }
3270     if (toDelete)
3271     {
3272 	this->deleteNodes(toDelete);
3273 	delete toDelete;
3274     }
3275 
3276     //
3277     // Delete selected decorators.  A separate list isn't required.
3278     //
3279     Decorator *decor;
3280     FOR_EACH_NETWORK_DECORATOR (this->network, decor, iterator) {
3281 	if (decor->isSelected()) {
3282 	    this->network->decoratorList.removeElement((void*)decor);
3283 	    delete decor;
3284 	}
3285     }
3286 
3287     this->deferrableCommandActivation->undeferAction();
3288 
3289     //this->setUndoActivation();
3290 }
3291 
3292 //
3293 // A public interface to deleteNodes... used by Network::replaceInputArks
3294 // so that it can let us do important work when deleting a bunch of nodes.
3295 //
removeNodes(List * toDelete)3296 void EditorWindow::removeNodes(List* toDelete)
3297 {
3298     this->deleteNodes(toDelete);
3299 }
3300 
3301 //
3302 // Called by the DeleteCommand to REALLY delete the nodes.
3303 //
deleteNodes(List * toDelete)3304 void EditorWindow::deleteNodes(List *toDelete)
3305 {
3306     Node         *node;
3307     ListIterator iterator;
3308     Node         *nodePtr;
3309     int		 deleteCnt = toDelete->getSize();
3310 
3311     //
3312     // don't toggle line drawing if erasing a small number of nodes.
3313     // Would it be good to check for lines entering/leaving the selected set?
3314     // If there were no such lines, then would it be unnecessary to toggle line
3315     // routing?
3316     int		threshold = 5;
3317 
3318     //
3319     // turn off line routing if necessary
3320     //
3321     if (deleteCnt > threshold)
3322 	this->beginPageChange();
3323 
3324     //
3325     // In order to maintain consistency between the yellowing of standins and
3326     // page tabs after a run time error, check each deleted node to see if its
3327     // standin is showing an error.
3328     //
3329     boolean errored_node_deleted = FALSE;
3330 
3331     //
3332     // Perform the deletion
3333     //
3334     iterator.setList(*toDelete);
3335     nodePtr = (Node*)iterator.getNext();
3336     while (nodePtr != NULL) {
3337         node = nodePtr;
3338         nodePtr = (Node*)iterator.getNext();
3339 	StandIn* si = node->getStandIn();
3340 	if ((si) && (this->errored_standins))
3341 	    errored_node_deleted|= this->errored_standins->removeElement((void*)si);
3342         this->network->deleteNode(node);
3343     }
3344 
3345     //
3346     // restart line routing if necessary
3347     //
3348     if (deleteCnt > threshold)
3349 	this->endPageChange();
3350     this->lastSelectedTransmitter = NULL;
3351 
3352     if (errored_node_deleted) {
3353 	//
3354 	// resetErrorList with arg==FALSE means update colors but don't
3355 	// toss out the list.
3356 	//
3357 	this->resetErrorList(FALSE);
3358     }
3359 
3360     //
3361     // Update the find tool dialog
3362     //
3363     if(this->findToolDialog AND this->findToolDialog->isManaged())
3364     	this->findToolDialog->changeList();
3365 }
3366 
highlightNodes(int h,List * l)3367 void EditorWindow::highlightNodes(int h, List *l)
3368 {
3369     Node *n;
3370     if (!l)
3371 	l = &this->network->nodeList;
3372 
3373     ListIterator li(*l);
3374     while ( (n = (Node*)li.getNext()) )
3375 	this->highlightNode(n,h);
3376 }
3377 
highlightNode(const char * name,int instance,int flag)3378 void EditorWindow::highlightNode(const char* name, int instance, int flag)
3379 {
3380     Node        *node;
3381 
3382     node = this->network->findNode(theSymbolManager->getSymbol(name),instance);
3383     if (NOT node)
3384 	return;
3385 
3386     this->highlightNode(node,flag);
3387 }
3388 
highlightNode(Node * n,int flag)3389 void EditorWindow::highlightNode(Node *n, int flag)
3390 {
3391     Pixel       color;
3392 
3393     this->executing_node = NUL(Node*);
3394     StandIn* si = n->getStandIn();
3395     switch (flag)
3396     {
3397 	case EditorWindow::ERRORHIGHLIGHT :
3398 	 	color = theDXApplication->getErrorNodeForeground();
3399 		if (!this->errored_standins) this->errored_standins = new List;
3400 		if ((si) && (this->errored_standins->isMember((void*)si) == FALSE))
3401 		    this->errored_standins->appendElement((void*)si);
3402 		break;
3403 
3404 	case EditorWindow::EXECUTEHIGHLIGHT :
3405 	 	color = theDXApplication->getExecutionHighlightForeground();
3406 		if (this->executed_nodes == NUL(List*))
3407 		    this->executed_nodes = new List;
3408 		if (!this->executed_nodes->isMember((const void*)n))
3409 		    this->executed_nodes->appendElement((const void*)n);
3410 		this->showExecutedCmd->activate();
3411 		this->executing_node = n;
3412 		break;
3413 
3414 	case EditorWindow::REMOVEHIGHLIGHT :
3415 	 	color = standInGetDefaultForeground();
3416 		break;
3417 
3418         default:
3419 
3420 	        ASSERT(FALSE);
3421     }
3422 
3423 #if WORKSPACE_PAGES
3424     //
3425     // Notify the pageSelector to highlight the tab of the page containing
3426     // the node whose standin we're trying to hightlight.
3427     //
3428     Symbol psym = theSymbolManager->getSymbol(PAGE_GROUP);
3429     EditorWorkSpace *ews = this->workSpace;
3430     const char* group_name = n->getGroupName(psym);
3431     if (group_name) {
3432 	EditorWorkSpace *page =
3433 		(EditorWorkSpace*)this->pageSelector->findDefinition(group_name);
3434 	ASSERT(page);
3435 	ews = page;
3436     }
3437     this->pageSelector->highlightTab (ews, flag);
3438 
3439     //
3440     // If the flag is ERROR, then make sure that the standin does exist
3441     // because we're going to be moving the vpe there anyway and we need
3442     // the feedback.
3443     //
3444     if ((!si) && (flag == EditorWindow::ERRORHIGHLIGHT)) {
3445 	this->pageSelector->selectPage(ews);
3446 	si = n->getStandIn();
3447 	if (si) {
3448 	    if (!this->errored_standins) this->errored_standins = new List;
3449 	    if (this->errored_standins->isMember((void*)si) == FALSE)
3450 		this->errored_standins->appendElement((void*)si);
3451 	}
3452     }
3453     if (si)
3454 #endif
3455 	si->setLabelColor(color);
3456 }
3457 
selectDecorator(VPEAnnotator * dec,boolean select,boolean warp)3458 boolean EditorWindow::selectDecorator (VPEAnnotator* dec, boolean select, boolean warp)
3459 {
3460     if (dec->getNetwork()->getEditor() != this)
3461 	return FALSE;
3462     //
3463     // Select the proper page.
3464     //
3465     Symbol psym = theSymbolManager->getSymbol(PAGE_GROUP);
3466     const char* group_name = dec->getGroupName(psym);
3467     if ((select) && (warp)) {
3468 	if (group_name) {
3469 	    EditorWorkSpace *page =
3470 		    (EditorWorkSpace*)this->pageSelector->findDefinition(group_name);
3471 	    ASSERT(page);
3472 	    page->unsetRecordedScrollPos();
3473 	    this->pageSelector->selectPage(page);
3474 	    this->populatePage(page);
3475 	    this->workSpace->resize();
3476 	} else {
3477 	    this->workSpace->unsetRecordedScrollPos();
3478 	    this->pageSelector->selectPage(this->workSpace);
3479 	}
3480     } else {
3481 	//
3482 	// If we're not going to bring the selected node into view,
3483 	// then make sure that the node's page is the current page.
3484 	// If it's not, then silently refuse to select the node.
3485 	//
3486 	boolean wrong_page = FALSE;
3487 	EditorWorkSpace *page = NUL(EditorWorkSpace*);
3488 	if (group_name)
3489 	    page = (EditorWorkSpace*)this->pageSelector->findDefinition(group_name);
3490 	else
3491 	    page = this->workSpace;
3492 	int page_no = this->workSpace->getCurrentPage();
3493 	EditorWorkSpace* current_ews = this->workSpace;
3494 	if (page_no) current_ews = (EditorWorkSpace*)this->workSpace->getElement(page_no);
3495 	if (page != current_ews) wrong_page = TRUE;
3496 
3497 	if (wrong_page)
3498 	    return TRUE;
3499     }
3500     dec->setSelected(select);
3501     if (select && warp)
3502 	this->moveWorkspaceWindow(dec);
3503     return TRUE;
3504 }
3505 
selectNode(Node * node,boolean select,boolean warp)3506 boolean EditorWindow::selectNode(Node *node, boolean select, boolean warp)
3507 {
3508     StandIn     *standIn;
3509     ASSERT(node);
3510     if (node->getNetwork()->getEditor() != this)
3511 	return FALSE;
3512 
3513     standIn = node->getStandIn();
3514 #if WORKSPACE_PAGES
3515     //
3516     // Select the proper page.
3517     //
3518     Symbol psym = theSymbolManager->getSymbol(PAGE_GROUP);
3519     const char* group_name = node->getGroupName(psym);
3520     if ((select) && (warp)) {
3521 	if (group_name) {
3522 	    EditorWorkSpace *page =
3523 		    (EditorWorkSpace*)this->pageSelector->findDefinition(group_name);
3524 	    ASSERT(page);
3525 	    page->unsetRecordedScrollPos();
3526 	    this->pageSelector->selectPage(page);
3527 	    this->populatePage(page);
3528 	    this->workSpace->resize();
3529 	} else {
3530 	    this->workSpace->unsetRecordedScrollPos();
3531 	    this->pageSelector->selectPage(this->workSpace);
3532 	    ASSERT(standIn);
3533 	}
3534 	if (!standIn) {
3535 	    standIn = node->getStandIn();
3536 	}
3537 	ASSERT(standIn);
3538     } else if (!standIn) {
3539 	return TRUE;
3540     } else {
3541 	//
3542 	// If we're not going to bring the selected node into view,
3543 	// then make sure that the node's page is the current page.
3544 	// If it's not, then silently refuse to select the node.
3545 	//
3546 	boolean wrong_page = FALSE;
3547 	EditorWorkSpace *page = NUL(EditorWorkSpace*);
3548 	if (group_name)
3549 	    page = (EditorWorkSpace*)this->pageSelector->findDefinition(group_name);
3550 	else
3551 	    page = this->workSpace;
3552 	int page_no = this->workSpace->getCurrentPage();
3553 	EditorWorkSpace* current_ews = this->workSpace;
3554 	if (page_no) current_ews = (EditorWorkSpace*)this->workSpace->getElement(page_no);
3555 	if (page != current_ews) wrong_page = TRUE;
3556 
3557 	if (wrong_page)
3558 	    return TRUE;
3559     }
3560     ASSERT(standIn);
3561 #endif
3562     standIn->setSelected(select);
3563     if (select && warp)
3564 	this->moveWorkspaceWindow(standIn);
3565     return TRUE;
3566 
3567 }
3568 
selectNode(char * name,int instance,boolean select)3569 boolean EditorWindow::selectNode(char* name, int instance, boolean select)
3570 {
3571     Node        *node;
3572 
3573     node = this->network->findNode(theSymbolManager->getSymbol(name),instance);
3574     if (NOT node)
3575 	return (FALSE);
3576     return this->selectNode(node, select, TRUE);
3577 }
3578 
3579 #define SELECT_ALL		0
3580 #define DESELECT_ALL		1
3581 #define SELECT_UNSELECTED	2
3582 #define SELECT_ALL_IN_PAGE	3
3583 
selectUnselectedNodes()3584 void EditorWindow::selectUnselectedNodes()
3585 {
3586     this->selectNodes(SELECT_UNSELECTED);
3587 }
selectAllNodes()3588 void EditorWindow::selectAllNodes()
3589 {
3590 #if WORKSPACE_PAGES
3591     this->selectNodes(SELECT_ALL_IN_PAGE);
3592 #else
3593     this->selectNodes(SELECT_ALL);
3594 #endif
3595 }
deselectAllNodes()3596 void EditorWindow::deselectAllNodes()
3597 {
3598     this->selectNodes(DESELECT_ALL);
3599 }
3600 
selectNodes(int how)3601 void EditorWindow::selectNodes(int how)
3602 {
3603     ListIterator li(this->network->nodeList);
3604     Node        *n;
3605     EditorWorkSpace* page = this->workSpace;
3606 #if WORKSPACE_PAGES
3607     if (this->network->isDeleted()) return ;
3608     int page_num = this->workSpace->getCurrentPage();
3609     if (page_num) page = (EditorWorkSpace*)this->workSpace->getElement(page_num);
3610 #endif
3611 
3612     this->deferrableCommandActivation->deferAction();
3613 
3614     for(n = (Node*)li.getNext(); n; n = (Node*)li.getNext()) {
3615 	StandIn *si = n->getStandIn();
3616 	if (!si) continue;
3617 	switch (how) {
3618 	    case SELECT_ALL:   si->setSelected(TRUE); break;
3619 	    case DESELECT_ALL: si->setSelected(FALSE); break;
3620 	    case SELECT_UNSELECTED: si->setSelected(!si->isSelected()); break;
3621 	    case SELECT_ALL_IN_PAGE: if (si->getWorkSpace() == page)
3622 					si->setSelected(TRUE); break;
3623 	}
3624     }
3625 
3626     // Decorators
3627     Decorator *decor;
3628     ListIterator iterator;
3629     FOR_EACH_NETWORK_DECORATOR (this->network, decor, iterator) {
3630 	switch (how) {
3631 	    case SELECT_ALL: 	decor->setSelected(TRUE); break;
3632 	    case DESELECT_ALL: 	decor->setSelected(FALSE); break;
3633 	    case SELECT_UNSELECTED:	decor->setSelected(!decor->isSelected()); break;
3634 	    case SELECT_ALL_IN_PAGE: if (decor->getWorkSpace() == page)
3635 					decor->setSelected(TRUE); break;
3636 	}
3637     }
3638     this->deferrableCommandActivation->undeferAction();
3639 }
3640 
3641 
3642 
serverDisconnected()3643 void EditorWindow::serverDisconnected()
3644 {
3645     Pixel runColor = theDXApplication->getExecutionHighlightForeground();
3646     Pixel defaultColor = standInGetDefaultForeground();
3647 
3648     // For each node, if the standin's forground color is "execute", reset it.
3649     Node *n;
3650     ListIterator li(this->network->nodeList);
3651     while ( (n = (Node*)li.getNext()) ) {
3652 	StandIn *si = n->getStandIn();
3653 #if WORKSPACE_PAGES
3654 	if (!si) continue;
3655 #endif
3656 	if (si->getLabelColor() == runColor)
3657 	    si->setLabelColor(defaultColor);
3658     }
3659 
3660 
3661     this->DXWindow::serverDisconnected();
3662     this->executing_node = NUL(Node*);
3663     this->resetColorList();
3664 }
3665 
postPanelGroupDialog()3666 void EditorWindow::postPanelGroupDialog()
3667 {
3668     if(NOT this->panelGroupDialog)
3669 	this->panelGroupDialog
3670 	    = new ControlPanelGroupDialog(this->getRootWidget());
3671     this->panelGroupDialog->setData(this->network->getPanelGroupManager());
3672 
3673     this->panelGroupDialog->post();
3674 }
3675 
postProcessGroupCreateDialog()3676 void EditorWindow::postProcessGroupCreateDialog()
3677 {
3678     Network *net = this->getNetwork();
3679     Node *n;
3680     ListIterator iter;
3681     boolean hasloop = FALSE;
3682 
3683     FOR_EACH_NETWORK_NODE(net,n,iter) {
3684         NodeDefinition *nd = n->getDefinition();
3685         hasloop = nd->isMDFFlagLOOP();
3686         if (hasloop)
3687             break;
3688 
3689     }
3690 
3691     if (hasloop) {
3692         InfoMessage("Execution groups, and thus distributed execution, can\n"
3693 		    "not be used in programs that have looping tools at the\n"
3694 		    "top level of the program. If you would like to use \n"
3695 		    "distributed execution, encapsulate your loops within\n"
3696 		    "macros and then create the execution groups.");
3697     } else {
3698         if(NOT this->processGroupCreateDialog)
3699             this->processGroupCreateDialog
3700                 = new ProcessGroupCreateDialog(this);
3701 
3702         this->processGroupCreateDialog->post();
3703     }
3704 }
3705 
3706 #if WORKSPACE_PAGES
setGroup(GroupRecord * grec,Symbol groupID)3707 void EditorWindow::setGroup(GroupRecord *grec, Symbol groupID)
3708 {
3709     //
3710     // Do all Nodes
3711     //
3712     List *nlist = this->makeSelectedNodeList();
3713 
3714     if (nlist) {
3715 	ListIterator li(*nlist);
3716 	Node *node;
3717 
3718 	while( (node = (Node*)li.getNext()) )
3719 	    node->setGroupName(grec, groupID);
3720 
3721 	delete nlist;
3722     }
3723 
3724     //
3725     // Do all Decorators
3726     //
3727     List *seldec = this->makeSelectedDecoratorList();
3728     if (seldec) {
3729 	ListIterator li(*seldec);
3730 	VPEAnnotator *vpea;
3731 	while ( (vpea = (VPEAnnotator*)li.getNext()) )
3732 	    vpea->setGroupName(grec, groupID);
3733 
3734 	delete seldec;
3735     }
3736 
3737 }
3738 
resetGroup(const char * name,Symbol groupID)3739 void EditorWindow::resetGroup(const char* name, Symbol groupID)
3740 {
3741     Node *node;
3742     ListIterator li;
3743 
3744     FOR_EACH_NETWORK_NODE(this->network, node, li)
3745     {
3746   	const char *s = node->getGroupName(groupID);
3747 	if(s && EqualString(name, s))
3748 	    node->setGroupName(NUL(GroupRecord*), groupID);
3749     }
3750 
3751     //
3752     // Do all Decorators
3753     //
3754     Decorator* dec;
3755     FOR_EACH_NETWORK_DECORATOR(this->network, dec, li) {
3756 	VPEAnnotator *vpea = (VPEAnnotator*)dec;
3757   	const char *s = vpea->getGroupName(groupID);
3758 	if(s && EqualString(name, s))
3759 	    vpea->setGroupName(NUL(GroupRecord*), groupID);
3760     }
3761 
3762 }
3763 
selectGroup(const char * name,Symbol groupID)3764 void EditorWindow::selectGroup(const char* name, Symbol groupID)
3765 {
3766     Node *node, *firstNode = NUL(Node*);
3767     ListIterator li;
3768 
3769     this->deselectAllNodes();
3770 
3771     FOR_EACH_NETWORK_NODE(this->network, node, li)
3772     {
3773   	const char *s = node->getGroupName(groupID);
3774         if(s && EqualString(name, s))
3775         {
3776             if (firstNode == NUL(Node*)) {
3777             	this->selectNode(node, TRUE, TRUE);
3778 		firstNode = node;
3779 	    } else
3780             	this->selectNode(node, TRUE, FALSE);
3781         }
3782     }
3783 
3784     //
3785     // Do all Decorators
3786     //
3787     Decorator* dec;
3788     FOR_EACH_NETWORK_DECORATOR(this->network, dec, li) {
3789 	VPEAnnotator *vpea = (VPEAnnotator*)dec;
3790 	const char *group_name = vpea->getGroupName(groupID);
3791 	if ((group_name) && (EqualString(group_name, name))) {
3792 	    vpea->setSelected(TRUE);
3793 	} else {
3794 	    vpea->setSelected(FALSE);
3795 	}
3796     }
3797 
3798     if(NOT firstNode)
3799         WarningMessage("Process group %s is empty.", name);
3800 }
3801 
clearGroup(const char * name,Symbol groupID)3802 void EditorWindow::clearGroup(const char* name, Symbol groupID)
3803 {
3804     Node *node;
3805     ListIterator li;
3806 
3807     FOR_EACH_NETWORK_NODE(this->network, node, li)
3808 	node->setGroupName(NULL, groupID);
3809 
3810     //
3811     // Do all Decorators
3812     //
3813     Decorator* dec;
3814     FOR_EACH_NETWORK_DECORATOR(this->network, dec, li) {
3815 	VPEAnnotator *vpea = (VPEAnnotator*)dec;
3816 	vpea->setGroupName(NUL(GroupRecord*), groupID);
3817     }
3818 }
3819 
3820 //
3821 // Look for the definition of the old group and change dictionary entries so
3822 // that members of that group belong to the new group.  If old_group doesn't
3823 // currently exist, then treat nodes as if they belong if they have no group name.
3824 //
3825 boolean
changeGroup(const char * old_group,const char * new_group,Symbol groupID)3826 EditorWindow::changeGroup (const char* old_group, const char* new_group, Symbol groupID)
3827 {
3828     GroupManager *gmgr = (GroupManager*)
3829 	this->network->getGroupManagers()->findDefinition(groupID);
3830     GroupRecord* old_grec = gmgr->getGroup(old_group);
3831 
3832     //
3833     // If there is an existing group with this name then we'll fail here, but that
3834     // should have been tested for earlier.
3835     //
3836     GroupRecord* new_grec = gmgr->getGroup(new_group);
3837     if (new_grec) return FALSE;
3838 
3839     //
3840     // The call to GroupManager::createGroup()  will produce a call
3841     // to EditorWindow::setGroup().  So, if you're changing a group and something
3842     // is already selected in the vpe, then that thing will be in the new group
3843     // as soon as we come back from createGroup.
3844     //
3845     if (!gmgr->createGroup (new_group, this->network)) return FALSE;
3846     ASSERT (new_grec = gmgr->getGroup(new_group));
3847 
3848     Node* node;
3849     ListIterator li;
3850     FOR_EACH_NETWORK_NODE(this->network, node, li) {
3851 	const char* group_name = node->getGroupName(groupID);
3852 	if ((group_name) && (EqualString(group_name, old_group))) {
3853 	    node->setGroupName(new_grec, groupID);
3854 	} else if ((!group_name) && (!old_grec)) {
3855 	    node->setGroupName(new_grec, groupID);
3856 	}
3857     }
3858     Decorator* dec;
3859     FOR_EACH_NETWORK_DECORATOR(this->network, dec, li) {
3860 	VPEAnnotator* vpea = (VPEAnnotator*)dec;
3861 	const char* group_name = vpea->getGroupName(groupID);
3862 	if ((group_name) && (EqualString(group_name, old_group))) {
3863 	    vpea->setGroupName(new_grec, groupID);
3864 	} else if ((!group_name) && (!old_grec)) {
3865 	    vpea->setGroupName(new_grec, groupID);
3866 	}
3867     }
3868     if (old_grec) {
3869 	ASSERT(gmgr->removeGroup (old_group, this->network));
3870     }
3871     return TRUE;
3872 }
3873 
3874 #else
setProcessGroup(const char * name)3875 void EditorWindow::setProcessGroup(const char* name)
3876 {
3877     List *nlist = this->makeSelectedNodeList();
3878 
3879     if(NOT nlist) return;
3880 
3881     ListIterator li(*nlist);
3882     Node *node;
3883 
3884     while(node = (Node*)li.getNext())
3885 	node->setGroupName(name);
3886 
3887     delete nlist;
3888 }
3889 
resetProcessGroup(const char * name)3890 void EditorWindow::resetProcessGroup(const char* name)
3891 {
3892     Node *node;
3893     ListIterator li;
3894 
3895     FOR_EACH_NETWORK_NODE(this->network, node, li)
3896     {
3897   	const char *s = node->getGroupName();
3898 	if(s && EqualString(name, s))
3899 	    node->setGroupName(NULL);
3900     }
3901 }
3902 
selectProcessGroup(const char * name)3903 void EditorWindow::selectProcessGroup(const char* name)
3904 {
3905     Node *node, *firstNode = NULL;
3906     ListIterator li;
3907 
3908     this->deselectAllNodes();
3909 
3910     FOR_EACH_NETWORK_NODE(this->network, node, li)
3911     {
3912   	const char *s = node->getGroupName();
3913         if(s && EqualString(name, s))
3914         {
3915             if(firstNode)
3916             	this->selectNode(node, TRUE, FALSE);
3917 	    else
3918 		firstNode = node;
3919         }
3920     }
3921 
3922     if(NOT firstNode)
3923         WarningMessage("Process group %s is empty.", name);
3924     else
3925 	this->selectNode(firstNode, TRUE, TRUE);
3926 }
3927 
clearProcessGroup(const char * name)3928 void EditorWindow::clearProcessGroup(const char* name)
3929 {
3930     Node *node;
3931     ListIterator li;
3932 
3933     FOR_EACH_NETWORK_NODE(this->network, node, li)
3934 	node->setGroupName(NULL);
3935 }
3936 #endif
3937 
installWorkSpaceInfo(WorkSpaceInfo * info)3938 void EditorWindow::installWorkSpaceInfo(WorkSpaceInfo *info)
3939 {
3940     ASSERT(this->workSpace);
3941     this->workSpace->installInfo(info);
3942 }
3943 
3944 #if WORKSPACE_PAGES
beginPageChange()3945 void EditorWindow::beginPageChange()
3946 {
3947     int page = this->workSpace->getCurrentPage();
3948     WorkSpace *current_ews = this->workSpace;
3949     if (page) current_ews = this->workSpace->getElement(page);
3950     current_ews->beginManyPlacements();
3951     this->deferrableCommandActivation->deferAction();
3952     this->resetExecutionList();
3953 }
3954 
endPageChange()3955 void EditorWindow::endPageChange()
3956 {
3957     int page = this->workSpace->getCurrentPage();
3958     WorkSpace *current_ews = this->workSpace;
3959     if (page) current_ews = this->workSpace->getElement(page);
3960     current_ews->endManyPlacements();
3961     //
3962     // Don't resize if we need less space.  It's too visually jarring.
3963     //
3964     int reqw, w, reqh, h;
3965     this->workSpace->getMaxWidthHeight(&reqw, &reqh);
3966     this->workSpace->getXYSize(&w,&h);
3967     if ((reqw > w) || (reqh > h)) this->workSpace->resize();
3968 
3969     this->deferrableCommandActivation->requestAction(NULL);
3970     this->deferrableCommandActivation->undeferAction();
3971 }
3972 #endif
3973 
3974 //
3975 // Do what ever is necessary just before changing the current network.
3976 // To make things run faster we turn off line routing.  This should
3977 // be followed by a call to endNetworkChange(), which will re-enable
3978 // line routing.
3979 //
beginNetworkChange()3980 void EditorWindow::beginNetworkChange()
3981 {
3982     WorkSpace *ws = this->workSpace;
3983     ASSERT(ws);
3984     ws->beginManyPlacements();
3985     this->lastSelectedTransmitter = NULL;
3986     this->deferrableCommandActivation->deferAction();
3987     this->resetColorList();
3988 }
3989 //
3990 // Do what ever is necessary just after changing to the current network.
3991 // To make things run faster we turn off line routing in beginNetworkChange()
3992 // which should be called before this is called.
3993 //
endNetworkChange()3994 void EditorWindow::endNetworkChange()
3995 {
3996     WorkSpace *ws = this->workSpace;
3997     ASSERT(ws);
3998     this->lastSelectedTransmitter = NULL;
3999     ws->endManyPlacements();
4000 
4001 #if WORKSPACE_PAGES
4002     //
4003     // All non-empty pages will be created automatically.  Now go and look
4004     // for empty pages and create them.
4005     //
4006     PageGroupManager *pmgr = (PageGroupManager*)
4007 	this->network->getGroupManagers()->findDefinition(PAGE_GROUP);
4008     int gcnt = pmgr->getGroupCount();
4009     if (gcnt) {
4010 	int i;
4011 	for (i=1; i<=gcnt; i++) {
4012 	    const char *pageName = pmgr->getGroupName(i);
4013 	    if (this->pageSelector->findDefinition (pageName)) continue;
4014 	    PageGroupRecord  *prec = (PageGroupRecord*)pmgr->getGroup (pageName);
4015 	    ASSERT(prec);
4016 	    EditorWorkSpace *page = (EditorWorkSpace*) this->workSpace->addPage();
4017 	    page->resetCursor();
4018 	    ASSERT (this->pageSelector->addDefinition (pageName, page));
4019 	}
4020 	//
4021 	// If the root page has no members and its name is still Untitled, then
4022 	// remove the it from the page selector since there's no longer
4023 	// a need for it.
4024 	// On the other hande, if the root page has members, then make sure that
4025 	// it's in the PageSelector.
4026 	//
4027 	int cnt = this->getPageMemberCount (this->workSpace);
4028 	if (!cnt) {
4029 	    if (this->network->getFileName()) {
4030 		EditorWorkSpace* ews = (EditorWorkSpace*)
4031 		    this->pageSelector->findDefinition("Untitled");
4032 		if (this->workSpace == ews) {
4033 		    this->pageSelector->removeDefinition ((void*)this->workSpace);
4034 
4035 		    //
4036 		    // Try to get the leftmost tab's workspace.
4037 		    //
4038 		    EditorWorkSpace* ews = (EditorWorkSpace*)
4039 			this->pageSelector->getInitialWorkSpace();
4040 		    this->workSpace->showWorkSpace(ews);
4041 		}
4042 	    }
4043 	} else {
4044 	    int i,dsize = this->pageSelector->getSize();
4045 	    boolean found = FALSE;
4046 	    for (i=1; i<=dsize; i++) {
4047 		EditorWorkSpace* ews = (EditorWorkSpace*)
4048 		    this->pageSelector->getDefinition(i);
4049 		if (ews == this->workSpace) {
4050 		    found = TRUE;
4051 		    break;
4052 		}
4053 	    }
4054 	    if (!found)
4055 		this->pageSelector->addDefinition ("Untitled", this->workSpace);
4056 	}
4057     }
4058 #endif
4059 
4060     this->deferrableCommandActivation->requestAction(NULL);
4061     this->deferrableCommandActivation->undeferAction();
4062 }
4063 //
4064 // Do what ever is necessary just before and after reading a new network
4065 // These should be called in pairs.
4066 //
prepareForNewNetwork()4067 void EditorWindow::prepareForNewNetwork()
4068 {
4069 
4070     if(this->findToolDialog)
4071 	this->findToolDialog->unmanage();
4072 
4073     if(this->printProgramDialog)
4074 	this->printProgramDialog->unmanage();
4075 
4076     if(this->saveAsCCodeDialog)
4077 	this->saveAsCCodeDialog->unmanage();
4078 
4079     if(this->processGroupCreateDialog)
4080 	this->processGroupCreateDialog->unmanage();
4081 
4082     if(this->panelGroupDialog)
4083         this->panelGroupDialog->unmanage();
4084 
4085     if(this->panelAccessDialog)
4086         this->panelAccessDialog->unmanage();
4087 
4088 #ifndef FORGET_GETSET
4089     if ((EditorWindow::GetSetDialog) && (this->isAnchor()) && (this->network))
4090 	EditorWindow::GetSetDialog->unmanage();
4091 #endif
4092 
4093     this->beginNetworkChange();
4094 
4095 #if WORKSPACE_PAGES
4096     ListIterator it(this->network->decoratorList);
4097     Decorator* dec;
4098     while ( (dec = (Decorator*)it.getNext()) ) {
4099 	if ((dec->getRootWidget()) && (dec->isManaged())) {
4100 	    dec->unmanage();
4101 	    dec->uncreateDecorator();
4102 	}
4103     }
4104     this->destroyStandIns(&this->network->nodeList);
4105     if (this->pageSelector) {
4106 	int i, pcnt = this->pageSelector->getSize();
4107 	    this->network->getGroupManagers()->findDefinition(PAGE_GROUP);
4108 	for (i=1; i<=pcnt; i++) {
4109 	    EditorWorkSpace *ews = (EditorWorkSpace*)
4110 		this->pageSelector->getDefinition(i);
4111 	    if (ews != this->workSpace) {
4112 		WorkSpaceInfo* info = ews->getInfo();
4113 		delete ews;
4114 		delete info;
4115 	    }
4116 	}
4117 	this->pageSelector->clear();
4118     }
4119     this->workSpace->setMembersInitialized(FALSE);
4120     this->workSpace->showRoot();
4121 #endif
4122 
4123     // reset the workspace
4124     // FIXME: shouldn't this be in completeNewNetwork()
4125     this->moveWorkspaceWindow(0,0, FALSE);
4126 
4127     this->creating_new_network = TRUE;
4128 }
completeNewNetwork()4129 void EditorWindow::completeNewNetwork()
4130 {
4131     this->endNetworkChange();
4132     this->clearUndoList();
4133     this->creating_new_network = FALSE;
4134     theDXApplication->refreshErrorIndicators();
4135 
4136 }
4137 
4138 #ifndef FORGET_GETSET
4139 void
postGetSetConversionDialog()4140 EditorWindow::postGetSetConversionDialog()
4141 {
4142     if (!EditorWindow::GetSetDialog)
4143 	EditorWindow::GetSetDialog = new GetSetConversionDialog();
4144 
4145     EditorWindow::GetSetDialog->post();
4146 
4147     List *glns =  this->network->makeNamedNodeList ("Get");
4148     if (!glns) glns = this->network->makeNamedNodeList ("Set");
4149     if (glns) {
4150 	EditorWindow::GetSetDialog->setActiveEditor(this);
4151 	delete glns;
4152     }
4153 }
4154 #endif // FORGET_GETSET
4155 
4156 //
4157 // Open the grid dialog
4158 //
postGridDialog()4159 void EditorWindow::postGridDialog()
4160 {
4161     if (NOT this->gridDialog )
4162 	this->gridDialog = new GridDialog(this->getRootWidget(),
4163 				(WorkSpace*)this->workSpace);
4164     this->gridDialog->post();
4165 }
4166 //
4167 // Open the find tool dialog
4168 //
postFindToolDialog()4169 void EditorWindow::postFindToolDialog()
4170 {
4171     if (NOT this->findToolDialog )
4172        this->findToolDialog = new FindToolDialog(this);
4173     this->findToolDialog->post();
4174 }
4175 //
4176 // Open the print program dialog
4177 //
postPrintProgramDialog()4178 void EditorWindow::postPrintProgramDialog()
4179 {
4180     if (NOT this->printProgramDialog)
4181        this->printProgramDialog = new PrintProgramDialog(this);
4182     this->printProgramDialog->post();
4183 }
4184 
4185 //
4186 // Virtual function called at the beginning/end of Command::execute
4187 // We must turn off tool selection and make sure the cursor is
4188 // back to the normal cursor (i.e. not the Tool placement cursor).
4189 //
beginCommandExecuting()4190 void EditorWindow::beginCommandExecuting()
4191 {
4192     this->toolSelector->deselectAllTools();
4193     this->workSpace->resetCursor();
4194 }
4195 
notifyCPChange(boolean newList)4196 void EditorWindow::notifyCPChange(boolean newList)
4197 {
4198     if(this->panelGroupDialog)
4199     {
4200         if(newList)
4201              this->panelGroupDialog->makeToggles();
4202         this->panelGroupDialog->setToggles();
4203     }
4204 
4205 }
4206 
notify(const Symbol message,const void * msgdata,const char * msg)4207 void EditorWindow::notify(const Symbol message, const void *msgdata, const char *msg)
4208 {
4209     if (message == DXApplication::MsgPanelChanged) {
4210 	//
4211 	// Set the command activations that depend on the number of panels.
4212 	//
4213 	int panelCount = this->network->getPanelCount();
4214 	if (panelCount == 0) {
4215 	    this->openControlPanelByNameMenu->deactivate();
4216 	    this->setPanelAccessCmd->deactivate();
4217 	    this->setPanelGroupCmd->deactivate();
4218 	} else if (panelCount == 1) {
4219 	    this->openControlPanelByNameMenu->activate();
4220 	    this->setPanelAccessCmd->activate();
4221 	    this->setPanelGroupCmd->activate();
4222 	} // else if panelCount == 2 the commands were already activated.
4223     } else if (message == DXApplication::MsgExecute) {
4224 	this->resetColorList();
4225     }
4226     this->DXWindow::notify(message, msgdata, msg);
4227 }
4228 
4229 
4230 //
4231 // Adjust the name of the editor window based on the current network
4232 // name.
4233 //
resetWindowTitle()4234 void EditorWindow::resetWindowTitle()
4235 {
4236     const char *vpe_name = "Visual Program Editor";
4237     char *p = NULL, *t = NULL;
4238     const char *title, *file = this->network->getFileName();
4239 
4240     if (file) {
4241 	p = GetFullFilePath(file);
4242 	t = new char[STRLEN(p) + STRLEN(vpe_name) +3];
4243 	sprintf(t,"%s: %s", vpe_name, p);
4244 #ifdef OS2
4245         if (STRLEN(t)>60)
4246           memmove(t, &t[STRLEN(t)-60],61);
4247 #endif
4248 	title = t;
4249 
4250 #ifndef FORGET_GETSET
4251 	if (EditorWindow::GetSetDialog)
4252 	    EditorWindow::GetSetDialog->notifyTitleChange(this, title);
4253 #endif
4254 
4255     } else {
4256 	title = vpe_name;
4257     }
4258     this->setWindowTitle(title);
4259     if (p) delete p;
4260     if (t) delete t;
4261 }
4262 
4263 //
4264 // Determine if there are any nodes of the give class that are selected.
4265 //
anySelectedNodes(const char * classname)4266 boolean EditorWindow::anySelectedNodes(const char *classname)
4267 {
4268     boolean r;
4269     List *l = this->makeSelectedNodeList(classname);
4270     if (!l)
4271 	return FALSE;
4272 
4273     if (l->getSize() != 0)
4274 	r = TRUE;
4275     else
4276 	r = FALSE;
4277     delete l;
4278     return r;
4279 }
4280 
4281 //
4282 // Return TRUE if there are selected Macros nodes.
4283 //
anySelectedMacros()4284 boolean EditorWindow::anySelectedMacros()
4285 {
4286     return this->anySelectedNodes(ClassMacroNode);
4287 }
anySelectedDisplayNodes()4288 boolean EditorWindow::anySelectedDisplayNodes()
4289 {
4290     return this->anySelectedNodes(ClassDisplayNode);
4291 }
anySelectedColormaps()4292 boolean EditorWindow::anySelectedColormaps()
4293 {
4294     return this->anySelectedNodes(ClassColormapNode);
4295 }
openSelectedMacros()4296 void EditorWindow::openSelectedMacros()
4297 {
4298     List *l = this->makeSelectedNodeList(ClassMacroNode);
4299     if (!l)
4300 	return;
4301     ListIterator li(*l);
4302 
4303     MacroNode *n;
4304     while( (n = (MacroNode *)li.getNext()) ) {
4305         n->openMacro();
4306 	MacroDefinition* md = (MacroDefinition*)n->getDefinition();
4307 	Network* net = md->getNetwork();
4308 	theDXApplication->appendReferencedFile (net->getFileName());
4309     }
4310     delete l;
4311 }
openSelectedImageWindows()4312 void EditorWindow::openSelectedImageWindows()
4313 {
4314     List *l = this->makeSelectedNodeList(ClassDisplayNode);
4315     if (!l)
4316 	return;
4317     ListIterator li(*l);
4318 
4319     DisplayNode *n;
4320     while( (n = (DisplayNode *)li.getNext()) )
4321         n->openImageWindow(TRUE);
4322     delete l;
4323 }
4324 
4325 //
4326 // Print the visual program as a PostScript file using geometry and not
4327 // bitmaps.  We set up the page so that it maps to the current workspace
4328 // and then as the StandIns and ArkStandIns to print themselves.
4329 // If the scale allows and the label_parameters arg is set, then
4330 // label the parameters and display the values.
4331 // We return FALSE and issue and error message if an error occurs.
4332 //
printVisualProgramAsPS(const char * filename,float x_pagesize,float y_pagesize,boolean label_parameters)4333 boolean EditorWindow::printVisualProgramAsPS(const char *filename,
4334 				float x_pagesize, float y_pagesize,
4335 				boolean label_parameters)
4336 {
4337     FILE *fout = fopen(filename,"w");
4338     if (!fout) {
4339 	ErrorMessage("Can't open file %s for writing",filename);
4340 	return FALSE;
4341     }
4342 
4343     //
4344     // Record the current page so that we can flip back there after the
4345     // print operation completes.  (This because we're going to have to visit
4346     // each uninitialized page.)
4347     //
4348     int page = this->workSpace->getCurrentPage();
4349     WorkSpace *current_ews = this->workSpace;
4350     if (page) current_ews = this->workSpace->getElement(page);
4351 
4352     //
4353     // Loop over the dictionary to get the pages to print.  FIXME: this doesn't
4354     // print them in the order in which they appear on the screen.  To do that,
4355     // you must build a new dictionary with the order_number as the key.
4356     //
4357     List* sorted_pages = this->pageSelector->getSortedPages();
4358     ASSERT(sorted_pages);
4359     ListIterator li(*sorted_pages);;
4360     EditorWorkSpace* ews;
4361     int pages_to_print = 0;
4362     int page_num = 1;
4363 
4364     while ( (ews = (EditorWorkSpace*)li.getNext()) )
4365 	if (ews->getPostscriptInclusion()) pages_to_print++;
4366 
4367     if (pages_to_print == 0) {
4368 	ErrorMessage (
4369 	    "You have removed every Visual Program page from the\n"
4370 	    "Postscript output.  (See Edit/Page/Configure Page.)\n"
4371 	    "No output created."
4372 	);
4373 	return FALSE;
4374     }
4375 
4376     boolean current_ews_changed = FALSE;
4377     li.setList(*sorted_pages);
4378     while ( (ews = (EditorWorkSpace*)li.getNext()) ) {
4379 	if (ews->getPostscriptInclusion()) {
4380 	    if (ews->membersInitialized() == FALSE) {
4381 		this->workSpace->showWorkSpace(ews);
4382 		current_ews_changed = TRUE;
4383 	    }
4384 	    if (!this->printVisualProgramAsPS(fout, filename, x_pagesize,y_pagesize,
4385 		label_parameters, ews, page_num, pages_to_print)) {
4386 		    fclose (fout);
4387 		    ErrorMessage("Error writing to file %s", filename);
4388 		    return FALSE;
4389 		}
4390 	    page_num++;
4391 	}
4392     }
4393     fclose (fout);
4394 
4395     delete sorted_pages;
4396 
4397     if (current_ews_changed)
4398 	this->workSpace->showWorkSpace(current_ews);
4399 
4400     return TRUE;
4401 }
4402 
printVisualProgramAsPS(FILE * fout,const char * filename,float x_pagesize,float y_pagesize,boolean label_parameters,EditorWorkSpace * current_ews,int page_number,int of_howmany)4403 boolean EditorWindow::printVisualProgramAsPS(FILE* fout, const char* filename,
4404     float x_pagesize, float y_pagesize, boolean label_parameters,
4405     EditorWorkSpace* current_ews, int page_number, int of_howmany)
4406 {
4407     boolean landscape = FALSE;
4408     Node *n;
4409     float border_percent = .075;
4410     float printable_percent = 1.0 - 2*(border_percent);
4411     int xsize, ysize;
4412     time_t t;
4413     char *tod;
4414     int begx, begy;
4415     int endx, endy;
4416     List *arcs;
4417     StandIn *standIn;
4418     int i, icnt;
4419     int xpos, ypos, width, height;
4420     int xmin=1000000,xmax=0,ymin=1000000,ymax=0;
4421     Ark *a;
4422     // We allocate these ourselves because the hp gives the following message
4423     // sorry, not implemented: label in block with destructors (2048)
4424     ListIterator *iterator = new ListIterator, *iter2 = new ListIterator;
4425     Decorator *dec;
4426     VPEAnnotator *vpea;
4427     Symbol vpeas = theSymbolManager->registerSymbol(ClassVPEAnnotator);
4428     GroupRecord* grec;
4429     const char* group_name;
4430 
4431 
4432     xmin = 0; 	// Always use the upper left corner of the workspace as origin
4433     ymin = 0; 	// 			ditto
4434     FOR_EACH_NETWORK_NODE(this->network, n, (*iterator)) {
4435 	standIn = n->getStandIn();
4436 	if (!standIn)
4437 	    continue;
4438 #if WORKSPACE_PAGES
4439 	if (standIn->getWorkSpace() != current_ews) continue;
4440 #endif
4441 	standIn->getGeometry(&xpos, &ypos, &width, &height);
4442 	xmax = MAX(xpos + width,xmax);
4443 	ymax = MAX(ypos + height,ymax);
4444 
4445     }
4446 
4447     FOR_EACH_NETWORK_DECORATOR (this->network, dec, (*iterator)) {
4448 #if WORKSPACE_PAGES
4449 	if (dec->getWorkSpace() != current_ews) continue;
4450 #endif
4451 	dec->getXYPosition (&xpos, &ypos);
4452 	dec->getXYSize (&width, &height);
4453 	xmax = MAX(xpos + width, xmax);
4454 	ymax = MAX(ypos + height,ymax);
4455     }
4456 
4457     xsize = xmax - xmin;
4458     ysize = ymax - ymin;
4459 
4460     if (xsize > ysize)
4461 	landscape = TRUE;
4462 
4463     /* Required for EPSF-3.0  */
4464     t = time(0);
4465     tod = ctime(&t);
4466     if (page_number == 1) {
4467 	if (fprintf(fout, "%s", "%!PS-Adobe-3.0 EPSF-3.0\n") <= 0) goto error;
4468 	if (fprintf(fout, "%%%%Creator: IBM/Data Explorer\n") <= 0) goto error;
4469 	if (fprintf(fout, "%%%%CreationDate: %s", tod) <= 0) goto error;
4470 	if (fprintf(fout, "%%%%Title:  %s\n",  filename) <= 0) goto error;
4471 	if (fprintf(fout, "%%%%Pages: %d\n", of_howmany) <= 0) goto error;
4472 
4473 	/* Put a Bounding Box specification, required for EPSF-3.0  */
4474 	begx = (int) ((x_pagesize * border_percent) * 72);
4475 	begy = (int) ((y_pagesize * border_percent) * 72);
4476 	endx = (int) ((x_pagesize * 72) - begx);
4477 	endy = (int) ((y_pagesize * 72) - begy);
4478 	if (fprintf(fout, "%%%%BoundingBox: %d %d %d %d\n",
4479 			    begx, begy, endx,endy) <= 0)
4480 	    goto error;
4481 
4482 	//
4483 	// Begin the Setup section
4484 	//
4485 	if (fprintf(fout,"%%%%BeginSetup\n\n") < 0) goto error;
4486 	if (fprintf(fout, "%% Build a temporary dictionary\n%d dict begin\n\n",
4487 						    25) < 0) goto error;
4488 	if (!StandIn::PrintPostScriptSetup(fout))	goto error;
4489 	if (fprintf(fout,"%%%%EndSetup\n\n") < 0) goto error;
4490     }
4491 
4492 
4493     //
4494     // Begin the Page Setup section
4495     //
4496     if (fprintf(fout,"\n%%%%Page: %d %d\n\n", page_number, page_number) <= 0) goto error;
4497 
4498     if (fprintf(fout,"%%%%BeginPageSetup\n\n") < 0) goto error;
4499 
4500 
4501     if ((fprintf(fout,"%% Number of units/inch (don't change this one)\n"
4502                       "/upi 72 def\n") <= 0)  			||
4503         (fprintf(fout,"%% Size of output page in inches\n"
4504 			"/pwidth %f def\n"
4505 			"/pheight %f def\n",
4506                                 x_pagesize,y_pagesize) <= 0)           	||
4507         (fprintf(fout,"%% Size of printable output page in inches\n"
4508 			"/width  %f pwidth  mul def\n"
4509 			"/height %f pheight mul def\n",
4510 			printable_percent, printable_percent) <= 0)   	||
4511         (fprintf(fout,"%% Extents of the used portion of the workspace\n"
4512                         "/xmin %d def\n"
4513                         "/xmax %d def\n"
4514                         "/ymin %d def\n"
4515                         "/ymax %d def\n",
4516                         xmin, xmax,ymin,ymax) <= 0)      	||
4517         (fprintf(fout,"%% Size of the used portion of the workspace\n"
4518                         "/xsize xmax xmin sub def\n"
4519                         "/ysize ymax ymin sub def\n") <= 0))
4520         goto error;
4521 
4522 
4523     if (landscape) {
4524         if ((fprintf(fout,"%% Rotate and translate into Landscape mode\n")
4525                                                         <= 0) ||
4526             (fprintf(fout,"90 rotate\n0 pwidth neg upi mul translate\n\n")
4527                                                         <= 0) ||
4528             (fprintf(fout,"%% Swap the width and height variables\n")
4529 							<= 0) ||
4530             (fprintf(fout,"/tmp width def\n"
4531 			  "/width height def\n"
4532 			  "/height tmp def\n") 		<= 0) ||
4533             (fprintf(fout,"/tmp pwidth def\n"
4534 			  "/pwidth pheight def\n"
4535 			  "/pheight tmp def\n") 	<= 0))
4536             goto error;
4537     }
4538 
4539     if (fprintf(fout,"%% Translate canvas inside page borders\n"
4540 			"%f pwidth mul upi mul dup translate\n",
4541 			border_percent ) <= 0)
4542 	goto error;
4543 
4544     if (fprintf(fout,"%% Scale canvas to the page with origin in upper left\n"
4545 			"/max {	%% Usage : a b max\n"
4546 			"	2 dict begin\n"
4547 		 	"	/a 2 1 roll def\n"
4548 		 	"	/b 2 1 roll def\n"
4549 			"	a b gt\n"
4550 			"	{ a } { b } ifelse\n"
4551 			"	end\n"
4552 			"} def\n"
4553 			"0 height upi mul translate\n"
4554 			"xsize width div ysize height div max\n"
4555 			"upi max\n"		// Use at least 72 dpi
4556 			"upi 2 1 roll div "
4557 			"dup neg "
4558 		 	"scale\n"
4559 			"%% Now Translate to (xmin,ymin)\n"
4560 		 	"xmin neg ymin neg translate\n"	) <= 0)
4561 	goto error;
4562 
4563 
4564     if (fprintf(fout,"%%%%EndPageSetup\n\n") <= 0) goto error;
4565 
4566 
4567     //
4568     // And finally send the visual program.
4569     //
4570     FOR_EACH_NETWORK_NODE(this->network, n, (*iterator)) {
4571 	standIn = n->getStandIn();
4572 	if (!standIn)
4573 	    continue;
4574 #if WORKSPACE_PAGES
4575 	if (standIn->getWorkSpace() != current_ews) continue;
4576 #endif
4577 	standIn->printPostScriptPage(fout, label_parameters && (xsize < 1500));
4578 	icnt = n->getInputCount();
4579 	for (i=1 ; i<=icnt ; i++) {
4580 	    if (n->isInputConnected(i) &&
4581 		n->isInputViewable(i) &&
4582 		n->isInputVisible(i)) {
4583 		arcs = (List*)n->getInputArks(i);
4584 		ASSERT(arcs);
4585 		iter2->setList(*arcs);
4586 		while ( (a = (Ark*)iter2->getNext()) )
4587 		    a->getArkStandIn()->printAsPostScript(fout);
4588 	    }
4589 	}
4590     }
4591 
4592     FOR_EACH_NETWORK_DECORATOR (this->network, dec, (*iterator)) {
4593 #if WORKSPACE_PAGES
4594 	if (dec->getWorkSpace() != current_ews) continue;
4595 #endif
4596 	if (dec->isA(vpeas)) {
4597 	    vpea = (VPEAnnotator*)dec;
4598 	    vpea->printPostScriptPage(fout);
4599 	}
4600     }
4601 
4602     //
4603     // Oh, and one more thing.  ...Page %s: %d of %d
4604     //
4605     char footer[128];
4606     grec = this->getGroupOfWorkSpace((EditorWorkSpace*)current_ews);
4607     group_name = (grec? grec->getName(): "<Untitled>");
4608     sprintf (footer, "%s - page %d of %d", group_name, page_number, of_howmany);
4609     if (fprintf (fout,
4610 	"%% Reset translation, rotation, and scaling for making a page footer\n"
4611 	"initmatrix\n"
4612 	"/Helvetica-Bold findfont\n"
4613 	"[ 10.0 0 0 10.0 0 0 ] makefont setfont\n"
4614 	"%% (page width/2) - (string width/2) for centering the footer\n"
4615 	"(%s) stringwidth pop 0.5 mul neg\n"
4616 	"%f 0.5 mul upi mul add\n"
4617 	"%% 0.5 inches up from the bottom of the page\n"
4618 	"36 moveto\n"
4619 	"(%s) show\n",
4620 	footer, x_pagesize, footer) <=0) goto error;
4621 
4622     //
4623     // Force the page out of the printer
4624     //
4625     if (fprintf(fout,"\nshowpage\n") <= 0) goto error;
4626 
4627     if (page_number == of_howmany)
4628 	if (fprintf(fout,"\nend\n") <= 0)
4629 	    goto error;
4630 
4631     delete iterator;
4632     delete iter2;
4633     return TRUE;
4634 
4635 error:
4636     delete iterator;
4637     delete iter2;
4638     return FALSE;
4639 }
4640 
macroifySelectedNodes(const char * name,const char * cat,const char * desc,const char * fileName)4641 boolean EditorWindow::macroifySelectedNodes(const char *name,
4642 				    const char *cat,
4643 				    const char *desc,
4644 				    const char *fileName)
4645 {
4646     ListIterator li;
4647     Node *node;
4648 
4649     //
4650     // Try and verify that the selected nodes are macrofiable.
4651     //
4652     if (!this->areSelectedNodesMacrofiable())
4653 	return FALSE;
4654 
4655     //
4656     // Get the set of selected nodes.  If there are none, we're done.
4657     //
4658     List *l = this->makeSelectedNodeList();
4659     if (l == NULL || l->getSize() == 0) {
4660 	if (l) delete l;
4661 	return TRUE;
4662     }
4663 
4664     //
4665     // Check to see if all these nodes are allowed in macros, get the
4666     // bounding box of the nodes on the vpe.
4667     //
4668     int x = 0, y = 0;
4669     node = (Node*)l->getElement(1);
4670     node->getVpePosition(&x, &y);
4671     int bboxXmin = x;
4672     int bboxYmin = y;
4673     int bboxYmax = y;
4674     for (li.setList(*l); (node = (Node*)li.getNext()); )
4675     {
4676 
4677 	node->getVpePosition(&x, &y);
4678 	if(x < bboxXmin)
4679 	    bboxXmin = x;
4680 	if(y < bboxYmin)
4681 	    bboxYmin = y;
4682 	if(y > bboxYmax)
4683 	    bboxYmax = y;
4684     }
4685 
4686     //
4687     // Create and setup the new network
4688     //
4689     Network *net = theDXApplication->newNetwork();
4690 
4691     net->setName(name? name: "NewMacro");
4692     net->setCategory(cat? cat: "Macros");
4693     net->setDescription(desc? desc: "new macro");
4694 
4695     if (!net->makeMacro(TRUE))
4696     {
4697 	delete net;
4698 	delete l;
4699 	return FALSE;
4700     }
4701 
4702     MacroDefinition *nd = net->getDefinition();
4703     nd->setNetwork(net);
4704     theDXApplication->macroList.appendElement(net);
4705 
4706     theNodeDefinitionDictionary->replaceDefinition(nd->getNameString(), nd);
4707     ToolSelector::AddTool(nd->getCategorySymbol(),
4708 			  nd->getNameSymbol(),
4709 			  (void *)nd);
4710     ToolSelector::UpdateCategoryListWidget();
4711 
4712     //
4713     // For each arc, if the arc crosses the line between selected and
4714     // unselected nodes, delete it and set up a macro input.
4715     // if it is only in the new macro, delete and recreate the arc.
4716     //
4717     struct connection {
4718 	Node *n;
4719 	int   param;
4720 	Node *pn;
4721     };
4722     List newInputs;
4723     List newOutputs;
4724     connection *con;
4725     for (li.setList(*l); (node = (Node*)li.getNext()); )
4726     {
4727  	List *orig;
4728 	int i;
4729 	for (i = 1; i <= node->getInputCount(); ++i)
4730 	{
4731 	    orig = (List*)node->getInputArks(i);
4732 	    List *inputs = orig->dup();
4733 	    ListIterator li(*inputs);
4734 	    Ark *a;
4735 	    while ( (a = (Ark*)li.getNext()) )
4736 	    {
4737 		int param;
4738 		Node *source = a->getSourceNode(param);
4739 		StandIn *si = source->getStandIn();
4740 		source->deleteArk(a);
4741 		si->deleteArk(a);
4742 
4743 		if (!si->isSelected()) {
4744 		    ListIterator connections(newInputs);
4745 		    while ( (con = (connection *)connections.getNext()) ) {
4746 			if (source == con->n && param == con->param)
4747 			    break;
4748 		    }
4749 		    if (con == NULL) {
4750 			con = new connection;
4751 			con->n = source;
4752 			con->param = param;
4753 
4754 			MacroParameterDefinition *inputDef =
4755 			    (MacroParameterDefinition*)
4756 			    theNodeDefinitionDictionary->
4757 			    findDefinition("Input");
4758 			con->pn = inputDef->createNewNode(net);
4759 			net->addNode(con->pn);
4760 			newInputs.appendElement(con);
4761 		    }
4762 		    new Ark(con->pn, 1, node, i);
4763 		}
4764 		else {
4765 		    new Ark(source, param, node, i);
4766 		}
4767 	    }
4768 	    delete inputs;
4769 	}
4770 
4771 	for (i = 1; i <= node->getOutputCount(); ++i)
4772 	{
4773 	    orig = (List*)node->getOutputArks(i);
4774 	    List *outputs = orig->dup();
4775 	    ListIterator li(*outputs);
4776 	    Ark *a;
4777 	    while ( (a = (Ark*)li.getNext()) )
4778 	    {
4779 		int param;
4780 		Node *dest = a->getDestinationNode(param);
4781 		StandIn *si = dest->getStandIn();
4782 		dest->deleteArk(a);
4783 		si->deleteArk(a);
4784 
4785 		if (!si->isSelected()) {
4786 		    ListIterator connections(newOutputs);
4787 		    while ( (con = (connection*)connections.getNext()) ) {
4788 			if (dest == con->n && param == con->param)
4789 			    break;
4790 		    }
4791 		    if (con == NULL) {
4792 			con = new connection;
4793 			con->n = dest;
4794 			con->param = param;
4795 
4796 			MacroParameterDefinition *outputDef =
4797 			    (MacroParameterDefinition*)
4798 			    theNodeDefinitionDictionary->
4799 			    findDefinition("Output");
4800 			con->pn = outputDef->createNewNode(net);
4801 			con->pn->setVpePosition(0,bboxYmax-bboxYmin+2*80);
4802 			net->addNode(con->pn);
4803 			newOutputs.appendElement(con);
4804 		    }
4805 		    new Ark(node, i, con->pn, 1);
4806 		}
4807 		else {
4808 		    new Ark(node, i, dest, param);
4809 		}
4810 	    }
4811 	    delete outputs;
4812 	}
4813     }
4814 
4815     //
4816     // Switch the nodes to the newly created network.
4817     //
4818     if (!net->mergeNetworks (this->network, NULL, FALSE)) {
4819 	delete l;
4820 	return FALSE;
4821     }
4822 
4823     XmUpdateDisplay(this->getRootWidget());
4824 
4825     //
4826     // Move the nodes to the upper right hand corner after switching them
4827     // to the new net.  This is the last use of "l".
4828     //
4829     for (li.setList(*l); (node = (Node*)li.getNext()); )
4830     {
4831 	node->getVpePosition(&x,&y);
4832 	node->setVpePosition(x-bboxXmin, y-bboxYmin+80);
4833     }
4834     delete l;
4835 
4836     net->sortNetwork();
4837 
4838     node = nd->createNewNode(this->network);
4839     if (!node)
4840     {
4841 	delete net;
4842 	return FALSE;
4843     }
4844     node->setVpePosition(bboxXmin, bboxYmin);
4845 
4846     this->network->addNode(node);
4847 
4848 
4849     int i;
4850     for (i = 1; (con = (connection*)newInputs.getElement(1)); ++i) {
4851 	node->getStandIn()->addArk(this, new Ark(con->n, con->param, node, i));
4852 	delete con;
4853 	newInputs.deleteElement(1);
4854     }
4855     newInputs.clear();
4856     for (i = 1; (con = (connection*)newOutputs.getElement(1)); ++i) {
4857 	node->getStandIn()->addArk(this, new Ark(node, i, con->n, con->param));
4858 	delete con;
4859 	newOutputs.deleteElement(1);
4860     }
4861     newOutputs.clear();
4862 
4863     if (fileName)
4864 	net->saveNetwork(fileName, TRUE);
4865 
4866 #ifndef FORGET_GETSET
4867     if ((EditorWindow::GetSetDialog) && (EditorWindow::GetSetDialog->isManaged()))
4868 	EditorWindow::GetSetDialog->update();
4869 #endif
4870 
4871     return TRUE;
4872 }
4873 
postInsertNetworkDialog()4874 void EditorWindow::postInsertNetworkDialog()
4875 {
4876     if (this->insertNetworkDialog == NULL)
4877 	this->insertNetworkDialog = new InsertNetworkDialog(this->getRootWidget());
4878     this->insertNetworkDialog->post();
4879 }
postCreateMacroDialog()4880 void EditorWindow::postCreateMacroDialog()
4881 {
4882     if (this->createMacroDialog == NULL)
4883 	this->createMacroDialog = new CreateMacroDialog(
4884 					    this->getRootWidget(),
4885 					    this);
4886     this->createMacroDialog->post();
4887 }
optimizeNodeOutputCacheability()4888 void EditorWindow::optimizeNodeOutputCacheability()
4889 {
4890    this->network->optimizeNodeOutputCacheability();
4891 }
4892 //
4893 // Search all nodes and select those with any outputs that match the
4894 // give cachability.
4895 //
selectNodesWithOutputCacheability(Cacheability c)4896 void EditorWindow::selectNodesWithOutputCacheability(Cacheability c)
4897 {
4898     Node *node;
4899 
4900     //
4901     // Scan the tools and select them if any of their outputs have the
4902     // given cachability.
4903     //
4904     ListIterator iterator;
4905     FOR_EACH_NETWORK_NODE(this->network, node, iterator) {
4906 	int i, cnt =  node->getOutputCount();
4907 	boolean select = FALSE;
4908 	for (i=1 ; i<=cnt && !select ; i++)  {
4909 	    if (node->getOutputCacheability(i) == c)
4910 		select = TRUE;
4911 	}
4912 	this->selectNode(node, select, FALSE);
4913     }
4914 
4915 }
4916 //
4917 // Set the cacheability of all outputs of the selected tools to one of
4918 // OutputFullyCached, OutputNotCached or OutputCacheOnce.
4919 // A warning is issued on those nodes that do not have writeable cacheability.
4920 //
setSelectedNodesOutputCacheability(Cacheability c)4921 void EditorWindow::setSelectedNodesOutputCacheability(Cacheability c)
4922 {
4923 #define MAX_IGNORES 256
4924      int i;
4925      Dictionary ignored;
4926      Node *node;
4927      List *snlist = this->makeSelectedNodeList();
4928 
4929      ASSERT((c == OutputFullyCached) || (c == OutputNotCached) ||
4930 	    (c == OutputCacheOnce));
4931 
4932      if (NOT snlist)
4933 	return;
4934 
4935      //
4936      // Scan the list of selected tools and change their outputs' cacheability
4937      // if it is writeable.
4938      //
4939      ListIterator li(*snlist);
4940      while ( (node = (Node*)li.getNext()) ) {
4941 	int i, cnt =  node->getOutputCount();
4942 	for (i=1 ; i<=cnt ; i++)  {
4943 	    if (node->isOutputCacheabilityWriteable(i)) {
4944 		node->setOutputCacheability(i,c);
4945             } else {
4946 		const char *name = node->getNameString();
4947 		if (!ignored.findDefinition(name))
4948 		    ignored.addDefinition(name,name);
4949 	    }
4950 	}
4951      }
4952 
4953      //
4954      // Notify the user about any modules that were skipped above
4955      //
4956      int num_ignored = ignored.getSize();
4957      if (num_ignored > 0) {
4958 	char *name, *p, *tools = new char[num_ignored * 64];
4959 	tools[0] = '\0';
4960 	p = tools;
4961 	DictionaryIterator di(ignored);
4962 	for (i=0 ; (name = (char*)di.getNextDefinition()); i++, p+=STRLEN(p)) {
4963 	    sprintf(p,"%s  ",name);
4964 	    if ((i != 0) && ((i & 3) == 0))
4965 		strcat(p,"\n");	// 4 tool names per line of text.
4966 	}
4967 	WarningMessage("One or more of the outputs of the following tools has "
4968 			"a read-only cacheability setting\n"
4969 		"(operation ignored for those outputs):\n\n%s", tools);
4970 	delete tools;
4971      }
4972      delete snlist;
4973 }
postSaveAsCCodeDialog()4974 void EditorWindow::postSaveAsCCodeDialog()
4975 {
4976 #ifdef DXUI_DEVKIT
4977     if (NOT this->saveAsCCodeDialog)
4978        this->saveAsCCodeDialog = new SaveAsCCodeDialog(
4979 			this->getRootWidget(),this->getNetwork());
4980     this->saveAsCCodeDialog->post();
4981 #endif // DXUI_DEVKIT
4982 }
4983 
4984 //
4985 // This is a helper method for this->areSelectedNodesMacrofiable().
4986 // It recursively descends the connections from the given node to determine
4987 // if it connected to a selected node.  If ignoreDirectConnect is TRUE,
4988 // then we do not care about selected nodes that are directly connected
4989 // to selected nodes.
4990 // Returns TRUE if there is a downstream selected node, otherwise FALSE.
4991 //
isSelectedNodeDownstream(Node * srcNode,boolean ignoreDirectConnect)4992 boolean EditorWindow::isSelectedNodeDownstream(Node *srcNode,
4993                                 boolean ignoreDirectConnect)
4994 {
4995     int         i, j;
4996     StandIn     *srcStandIn = srcNode->getStandIn();
4997 
4998     if (!srcStandIn)
4999         return FALSE;
5000 
5001     boolean     srcSelected = srcStandIn->isSelected();
5002 
5003     ASSERT(!srcSelected || ignoreDirectConnect);
5004 
5005     int numParam = srcNode->getOutputCount();
5006 
5007     for (i = 1; i <= numParam; ++i)
5008     {
5009         if (srcNode->isOutputConnected(i))
5010         {
5011             Ark *a;
5012             List *arcs = (List *)srcNode->getOutputArks(i);
5013             for (j = 1; (a = (Ark*)arcs->getElement(j)); ++j)
5014             {
5015                 int paramInd;
5016                 Node *destNode = a->getDestinationNode(paramInd);
5017 		if (destNode->isMarked())
5018 		    continue;
5019                 StandIn *destStandIn = destNode->getStandIn();
5020 		if (!destStandIn)
5021 		    continue;
5022 		boolean destSelected = destStandIn->isSelected();
5023 		if (srcSelected && !destSelected) {
5024 		    if (this->isSelectedNodeDownstream(destNode,FALSE))
5025 			return TRUE;
5026 		} else if (srcSelected && destSelected) {
5027 		    if (!ignoreDirectConnect)
5028 			return TRUE;
5029 		} else if (!srcSelected && destSelected) {
5030 		    return TRUE;
5031 		} else {    // !srcSelected && !destSelected
5032 		    if (this->isSelectedNodeDownstream(destNode,FALSE))
5033 			return TRUE;
5034                 }
5035 		if (!destSelected)
5036 		    destNode->setMarked();
5037             }
5038         }
5039     }
5040 
5041     return FALSE;
5042 }
5043 //
5044 // Determine if the currently selected set of nodes is macrofiable.  In
5045 // particular, we check for selections that would result in an output
5046 // being connected to on input of the newly created macro.  To do this
5047 // we look at each selected node and determine if its immediate downstream
5048 // unselected nodes are connected (possibly through intermediate nodes)
5049 // to another of the selected nodes.
5050 // Returns TRUE if macrofiable, else returns FALSE and issues and error
5051 // message.
5052 //
areSelectedNodesMacrofiable()5053 boolean EditorWindow::areSelectedNodesMacrofiable()
5054 {
5055 
5056     int      i;
5057     Network  *network = this->network;
5058     int      numNodes = network->nodeList.getSize();
5059     List     tmpNodeList;
5060     ListIterator iterator;
5061     Node        *n;
5062     boolean	saw_tmtr = FALSE, saw_rcvr = FALSE;
5063     List 	*tmtrs = NULL, *rcvrs = NULL;
5064 
5065     if (numNodes == 0)
5066         return TRUE;
5067 
5068     iterator.setList(network->nodeList);
5069     for (i=0 ; (n = (Node*)iterator.getNext()) ; i++)
5070         n->clearMarked();
5071 
5072 //
5073 // The HP gives the following message if I try to use a goto
5074 // CC: "EditorWindow.C", line 3510: sorry, not implemented: label in
5075 //  	block with destructors (2048)
5076 //
5077 #define RETURN_FALSE    if (tmtrs) delete tmtrs;	\
5078 			if (rcvrs) delete rcvrs;	\
5079 			return FALSE;
5080 
5081     iterator.setList(network->nodeList);
5082     while ( (n = (Node*)iterator.getNext()) ) {
5083         StandIn *si = n->getStandIn();
5084         if (si && si->isSelected()) {
5085 	    if (this->isSelectedNodeDownstream(n,TRUE)) {
5086 		ErrorMessage(
5087 		"The currently selected tools can not be macrofied because the"
5088 		"\nresulting macro would have an output connected to an input."
5089 		"\nThis is due to the fact that a data path that leaves the "
5090 		"\nselected tools later reenters the selected tools.");
5091 		RETURN_FALSE;
5092 	    } else if (!n->isAllowedInMacro())  {
5093 		ErrorMessage("Tool %s is not allowed in a macro",
5094 		    n->getNameString());
5095 		RETURN_FALSE;
5096 	    } else if (n->isA(ClassMacroParameterNode)) {
5097 		ErrorMessage(
5098 		    "Tool %s is not allowed in an automatically created macro",
5099 		    n->getNameString());
5100 		RETURN_FALSE;
5101 	    } else if (n->isA(ClassTransmitterNode)) {
5102 		if (!saw_tmtr) {
5103 		    rcvrs = network->makeClassifiedNodeList(ClassReceiverNode);
5104 		    saw_tmtr = TRUE;
5105 		}
5106 		if (rcvrs) {
5107 		    ListIterator iter(*rcvrs);
5108 		    const char *tlabel = n->getLabelString();
5109 		    Node *r;
5110 		    while ( (r = (Node*)iter.getNext()) ) {
5111 			StandIn *rsi = r->getStandIn();
5112 			if (rsi && !rsi->isSelected() &&
5113 				    EqualString(r->getLabelString(),tlabel)) {
5114 			    ErrorMessage(
5115 			    "The currently selected tools can not be macrofied "
5116 			    "because the selected\nTransmitter %s has a "
5117 			    "corresponding Receiver that is not selected.\n",
5118 			    tlabel);
5119 			    RETURN_FALSE;
5120 			}
5121 		    }
5122 		}
5123 	    } else if (n->isA(ClassReceiverNode)) {
5124 		if (!saw_rcvr) {
5125 		    tmtrs =
5126 			network->makeClassifiedNodeList(ClassTransmitterNode);
5127 		    saw_rcvr = TRUE;
5128 		}
5129 		if (tmtrs) {
5130 		    ListIterator iter(*tmtrs);
5131 		    const char *rlabel = n->getLabelString();
5132 		    Node *t;
5133 		    while ( (t = (Node*)iter.getNext()) ) {
5134 			StandIn *tsi = t->getStandIn();
5135 			if (tsi && !tsi->isSelected() &&
5136 				    EqualString(t->getLabelString(),rlabel)) {
5137 			    ErrorMessage(
5138 			    "The currently selected tools can not be macrofied "
5139 			    "because the selected\nReceiver %s has a "
5140 			    "corresponding Transmitter that is not selected.\n",
5141 			    rlabel);
5142 			    RETURN_FALSE;
5143 			}
5144 		    }
5145 		}
5146 	    }
5147 	}
5148     }
5149 
5150     if (tmtrs) delete tmtrs;
5151     if (rcvrs) delete rcvrs;
5152     return TRUE;
5153 
5154 }
5155 
5156 
5157 #ifndef FORGET_GETSET
5158 //
5159 // convert selected nodes (guaranteed to be either Get or Set) to
5160 // Global
5161 //
5162 void
ConvertToGlobal(boolean global)5163 EditorWindow::ConvertToGlobal(boolean global)
5164 {
5165     EditorWindow* e = EditorWindow::GetSetDialog->getActiveEditor();
5166     ASSERT(e);
5167     e->convertToGlobal(global);
5168 }
5169 
5170 void
convertToGlobal(boolean global)5171 EditorWindow::convertToGlobal(boolean global)
5172 {
5173     List *glnlist = this->makeSelectedNodeList();
5174 
5175     // The command can't be active if there is not selected node in the vpe.
5176     ASSERT(glnlist);
5177     ListIterator it(*glnlist);
5178     GlobalLocalNode *gln;
5179 
5180     while ( (gln = (GlobalLocalNode*)it.getNext()) ) {
5181 	ASSERT (((Node*)gln)->isA(ClassGlobalLocalNode));
5182 	// Both of the following return FALSE if the node has never been set
5183 	// Taken together, these 3 ASSERTS mean that everything in the list
5184 	// is either a Get or a Set.
5185 	//ASSERT (!gln->isGlobalNode());
5186 	//ASSERT (!gln->isLocalNode());
5187 
5188 	if (global) gln->setAsGlobalNode();
5189 	else gln->setAsLocalNode();
5190     }
5191     delete glnlist;
5192 
5193     this->setCommandActivation();
5194     if (EditorWindow::GetSetDialog)
5195 	EditorWindow::GetSetDialog->setCommandActivation();
5196 
5197 }
5198 
5199 void
ConvertToLocal()5200 EditorWindow::ConvertToLocal()
5201 {
5202     EditorWindow::ConvertToGlobal(FALSE);
5203 }
5204 
5205 #endif
5206 
5207 
5208 #if WORKSPACE_PAGES
5209 //
5210 // Turn the selected nodes into a page.
5211 //  Any arc of a selected node must go to a node which is also selected.
5212 //  The Edit/Select/Selected Connected command works well for selecting pagifiable nodes.
5213 //
5214 boolean
pagifySelectedNodes(boolean include_selected_nodes)5215 EditorWindow::pagifySelectedNodes(boolean include_selected_nodes)
5216 {
5217 char page_name[64];
5218 
5219     //
5220     // See if the selected nodes are pagifiable.
5221     // Creating the group automatically includes selected nodes, so if we don't
5222     // want them included, deselect them.
5223     //
5224     List *l = NUL(List*);
5225     List *dl = NUL(List*);
5226     boolean pagifiable = this->areSelectedNodesPagifiable(include_selected_nodes);
5227     if ((!pagifiable) && (include_selected_nodes)) {
5228 	return FALSE;
5229     } else if ((pagifiable) && (include_selected_nodes)) {
5230 	l = this->makeSelectedNodeList();
5231 	dl = this->makeSelectedDecoratorList();
5232     } else {
5233 	this->deselectAllNodes();
5234     }
5235 
5236     //
5237     // Find an unused name for a new page.
5238     //
5239     boolean page_name_in_use = TRUE;
5240     int next_page_no = 1;
5241     while (page_name_in_use) {
5242 	sprintf (page_name, "Untitled_%d", next_page_no++);
5243 	const void* def_found = this->pageSelector->findDefinition (page_name);
5244 	if (def_found == NUL(void*))
5245 	    page_name_in_use = FALSE;
5246     }
5247 
5248     //
5249     // Create a new page group in the network.
5250     // Creating the new group also automatically marks selected nodes as belonging.
5251     //
5252     GroupManager *page_mgr = (GroupManager*)
5253 	this->network->getGroupManagers()->findDefinition(PAGE_GROUP);
5254     ASSERT(page_mgr->createGroup (page_name, this->network));
5255 
5256     //
5257     // Make the new WorkSpace page.
5258     //
5259     EditorWorkSpace *page = (EditorWorkSpace*)this->workSpace->addPage();
5260     ASSERT (this->pageSelector->addDefinition (page_name, page));
5261     PageGroupRecord *grec = (PageGroupRecord*)page_mgr->getGroup (page_name);
5262     grec->setComponents (NUL(UIComponent*), page);
5263 
5264     //
5265     // Move the standins and decorators out their old page
5266     //
5267     if ((include_selected_nodes) && ((l) || (dl))) {
5268 
5269 	//
5270 	// prepare to turn off/on line drawing  if moving standins
5271 	//
5272 	EditorWorkSpace *selectedWS = NUL(EditorWorkSpace*);
5273 	if ((l) && (l->getSize())) {
5274 	    Node* n = (Node*)l->getElement(1);
5275 	    StandIn* si = (StandIn*)n->getStandIn();
5276 	    selectedWS = (EditorWorkSpace*)si->getWorkSpace();
5277 	} else if ((dl) && (dl->getSize())) {
5278 	    Decorator* dec = (Decorator*)dl->getElement(1);
5279 	    selectedWS = (EditorWorkSpace*)dec->getWorkSpace();
5280 	}
5281 
5282 	if (selectedWS) selectedWS->beginManyPlacements();
5283 	this->moveDecorators (page, dl, 20, 20, l);
5284 	this->moveStandIns (page, l, 20, 20, dl);
5285 	if (selectedWS) selectedWS->endManyPlacements();
5286     }
5287 
5288     if (l) delete l;
5289     if (dl) delete dl;
5290     return TRUE;
5291 }
5292 #endif
5293 
5294 
5295 
5296 #if WORKSPACE_PAGES
5297 //
5298 // Delete the page and everything inside the page and the page group.
5299 // If the group_name passed in is NULL, then delete the current page.
5300 //
5301 boolean
deletePage(const char * to_delete)5302 EditorWindow::deletePage(const char* to_delete)
5303 {
5304     //
5305     // Find the workspace we're deleting.  We also need to know if we're deleting
5306     // the current workspace.  If current is being deleted, then we'll have to
5307     // present some other workspace after deletion.
5308     //
5309     EditorWorkSpace* ews = NUL(EditorWorkSpace*);
5310     if (to_delete) ews = (EditorWorkSpace*)this->pageSelector->findDefinition (to_delete);
5311     int page = this->workSpace->getCurrentPage();
5312     EditorWorkSpace* current_ews = this->workSpace;
5313     if (page) current_ews = (EditorWorkSpace*)this->workSpace->getElement(page);
5314     if (ews == NUL(EditorWorkSpace*)) ews = current_ews;
5315     boolean deleted_was_current = (ews == current_ews);
5316 
5317     //
5318     // Find all the guys whose group name is the same as the group name of
5319     // the workspace we're deleting.  Somewhat roundabout, but it works for
5320     // both situations... a) deleting a named page, b) deleting the current page.
5321     //
5322     boolean first = TRUE;
5323     const char *group_name = NUL(char*);
5324     Node *node;
5325     ListIterator iter;
5326     List nodeList;
5327     List decorList;
5328     Decorator *decor;
5329     nodeList.clear();
5330     decorList.clear();
5331     FOR_EACH_NETWORK_NODE(this->network, node, iter) {
5332 	StandIn *si = node->getStandIn();
5333 	if (!si) continue;
5334 	WorkSpace* nws = si->getWorkSpace();
5335 	if (nws == ews) {
5336 	    nodeList.appendElement((void*)node);
5337 	    if (first) {
5338 		group_name = node->getGroupName(theSymbolManager->getSymbol(PAGE_GROUP));
5339 		first = FALSE;
5340 	    }
5341 	}
5342     }
5343     FOR_EACH_NETWORK_DECORATOR(this->network, decor, iter) {
5344 	WorkSpace* nws = decor->getWorkSpace();
5345 	if (nws == ews) {
5346 	    decorList.appendElement((void*)decor);
5347 	}
5348     }
5349 
5350     //
5351     // Now all the nodes/decorators are gathered up.  Delete them.
5352     //
5353     this->deleteNodes(&nodeList);
5354     nodeList.clear();
5355     ListIterator it(decorList);
5356     while ( (decor = (Decorator*)it.getNext()) ) {
5357 	this->network->decoratorList.removeElement((void*)decor);
5358 	delete decor;
5359     }
5360 
5361     if ((to_delete) && (group_name)) {
5362 	ASSERT(EqualString(to_delete, group_name));
5363     }
5364 
5365     //
5366     // If there was a node in the group then we'll have the name otherwise
5367     // we don't know the name and we'll have to scan the Dictionary
5368     //
5369     GroupManager *page_mgr = (GroupManager*)
5370 	this->network->getGroupManagers()->findDefinition (PAGE_GROUP);
5371     if (to_delete) {
5372 	this->pageSelector->removeDefinition ((const char*)to_delete);
5373 	page_mgr->removeGroup(to_delete, this->network);
5374     } else if (group_name) {
5375 	this->pageSelector->removeDefinition ((const char*)group_name);
5376 	page_mgr->removeGroup(group_name, this->network);
5377     } else {
5378 	boolean found = FALSE;
5379 	int i, pcnt = this->pageSelector->getSize();
5380 	for (i=1; i<=pcnt; i++) {
5381 	    EditorWorkSpace *def = (EditorWorkSpace*)
5382 		this->pageSelector->getDefinition(i);
5383 	    if (def == ews) {
5384 		group_name = this->pageSelector->getStringKey(i);
5385 		this->pageSelector->removeDefinition ((const char*)group_name);
5386 		found = TRUE;
5387 		break;
5388 	    }
5389 	}
5390 	ASSERT(found);
5391 	page_mgr->removeGroup(group_name, this->network);
5392     }
5393 
5394     //
5395     // If it was really a subpage and not the root page.
5396     //
5397     if (ews != this->workSpace) {
5398 	WorkSpaceInfo* info = ews->getInfo();
5399 	delete ews;
5400 	delete info;
5401     }
5402 
5403     //
5404     // We've deleted what was the visible page.  Now we must find a different page
5405     // to present to the user.  Walk the list of pages looking for one which has
5406     // had standins created. (We don't want to accidently present a mamoth page
5407     // which will take a long time to fill.)  If none is found with standins, then
5408     // try to put up one which contains fewest members.  Else just put up page 0.
5409     // Putting up page 0 might require adding "Untitled" to the pageSelector.
5410     //
5411     if (deleted_was_current) {
5412 	boolean found = FALSE;
5413 	DictionaryIterator di(*this->pageSelector);
5414 	int member_count = 9999999;
5415 	EditorWorkSpace* contains_few_members = NUL(EditorWorkSpace*);
5416 	while ( (ews = (EditorWorkSpace*)di.getNextDefinition()) ) {
5417 	    if (ews->membersInitialized()) {
5418 		found = TRUE;
5419 		this->pageSelector->selectPage(ews);
5420 		break;
5421 	    } else {
5422 		int current_count = this->getPageMemberCount(ews);
5423 		if ((current_count > 0) && (current_count < member_count)) {
5424 		    member_count = current_count;
5425 		    contains_few_members = (EditorWorkSpace*)ews;
5426 		}
5427 		/*if (ews == this->workSpace)
5428 		  contains_root = TRUE;*/
5429 	    }
5430 	}
5431 	if (!found) {
5432 	    if (contains_few_members) {
5433 		this->pageSelector->selectPage(contains_few_members);
5434 	     } else if (this->pageSelector->getSize()) {
5435 		EditorWorkSpace* ws = (EditorWorkSpace*)
5436 		    this->pageSelector->getDefinition(1);
5437 		ASSERT(ws);
5438 		this->pageSelector->selectPage(ws);
5439 	    } else {
5440 		this->pageSelector->addDefinition ("Untitled", this->workSpace);
5441 		this->pageSelector->selectPage(this->workSpace);
5442 	    }
5443 	}
5444     }
5445 
5446     return TRUE;
5447 }
5448 #endif
5449 
5450 
5451 EditorWorkSpace *
getNodesBBox(int * minx,int * miny,int * maxx,int * maxy,List * l,List * dl)5452 EditorWindow::getNodesBBox(int *minx, int *miny, int *maxx, int *maxy, List *l, List *dl)
5453 {
5454     //
5455     // get the bounding box of the nodes on the vpe.
5456     //
5457     int x = 0, y = 0;
5458     int bboxXmin = 0, bboxYmin = 0;
5459     int bboxXmax = 1, bboxYmax = 1;
5460     ListIterator li;
5461     int width, height;
5462     EditorWorkSpace *selectedWorkSpace = NULL;
5463     boolean first = TRUE;
5464 
5465     if (l) {
5466 	li.setList(*l);
5467 	Node *node;
5468 	while ( (node = (Node*)li.getNext()) ) {
5469 	    node->getVpePosition(&x, &y);
5470 	    if (first) {
5471 		bboxXmin = x;
5472 		bboxYmin = y;
5473 		first = FALSE;
5474 	    }
5475 	    StandIn *si = node->getStandIn();
5476 
5477 	    if (si) {
5478 		si->getXYSize (&width, &height);
5479 		if (!selectedWorkSpace)
5480 		    selectedWorkSpace = (EditorWorkSpace*)si->getWorkSpace();
5481 		ASSERT (selectedWorkSpace == (EditorWorkSpace*)si->getWorkSpace());
5482 	    } else {
5483 		width = height = 0;
5484 	    }
5485 
5486 	    if(x < bboxXmin)
5487 		bboxXmin = x;
5488 
5489 	    if((x+width) > bboxXmax)
5490 		bboxXmax = x + width;
5491 
5492 	    if(y < bboxYmin)
5493 		bboxYmin = y;
5494 
5495 	    if((y+height) > bboxYmax)
5496 		bboxYmax = y + height;
5497 	}
5498     }
5499 
5500     if (dl) {
5501 	li.setList(*dl);
5502 	Decorator *dec = NULL;
5503 	while ( (dec = (Decorator*)li.getNext()) ) {
5504 	    dec->getXYPosition (&x, &y);
5505 	    if (first) {
5506 		bboxXmin = x;
5507 		bboxYmin = y;
5508 		first = FALSE;
5509 	    }
5510 	    dec->getXYSize (&width, &height);
5511 
5512 	    if(x < bboxXmin)
5513 		bboxXmin = x;
5514 
5515 	    if((x+width) > bboxXmax)
5516 		bboxXmax = x + width;
5517 
5518 	    if(y < bboxYmin)
5519 		bboxYmin = y;
5520 
5521 	    if((y+height) > bboxYmax)
5522 		bboxYmax = y + height;
5523 	}
5524     }
5525 
5526     *minx = bboxXmin;
5527     *miny = bboxYmin;
5528     *maxx = bboxXmax;
5529     *maxy = bboxYmax;
5530     return selectedWorkSpace;
5531 }
5532 
5533 #if WORKSPACE_PAGES
5534 
5535 //
5536 // Destroy all standins in the list
5537 //
destroyStandIns(List * selectedNodes)5538 void EditorWindow::destroyStandIns(List* selectedNodes)
5539 {
5540 boolean error_node = FALSE;
5541 int i;
5542 ListIterator li(*selectedNodes);
5543 Node *node;
5544 
5545     while ( (node = (Node*)li.getNext()) ) {
5546 	//
5547 	// Destroy the input arcs
5548 	//
5549 	int count = node->getInputCount();
5550 	for (i=1; i<=count; i++) {
5551 	    Ark *a;
5552 	    List *orig = (List*)node->getInputArks(i);
5553 	    List *conns = orig->dup();
5554 	    ListIterator ai(*conns);
5555 	    while ( (a = (Ark*)ai.getNext()) ) {
5556 		ArkStandIn *asi = a->getArkStandIn();
5557 		a->setArkStandIn(NULL);
5558 		delete asi;
5559 	    }
5560 	    delete conns;
5561 	}
5562 
5563 	//
5564 	// Destroy the output arcs
5565 	//
5566 	count = node->getOutputCount();
5567 	for (i=1; i<=count; i++) {
5568 	    Ark *a;
5569 	    List *orig = (List*)node->getOutputArks(i);
5570 	    List *conns = orig->dup();
5571 	    ListIterator ai(*conns);
5572 	    while ( (a = (Ark*)ai.getNext()) ) {
5573 		ArkStandIn *asi = a->getArkStandIn();
5574 		a->setArkStandIn(NULL);
5575 		delete asi;
5576 	    }
5577 	    delete conns;
5578 	}
5579 
5580 
5581 	//
5582 	// Destroy the existing StandIn for the node, making sure to remove it
5583 	// from the error list if necessary.
5584 	//
5585 	StandIn *si = node->getStandIn();
5586 	if (si) {
5587 	    si->unmanage();
5588 	    if (this->errored_standins)
5589 		error_node|= this->errored_standins->removeElement((void*)si);
5590 	    delete si;
5591 	}
5592     }
5593 
5594     if (error_node)
5595 	this->resetErrorList(FALSE);
5596 }
5597 
5598 void
moveStandIns(EditorWorkSpace * page,List * selectedNodes,int xoff,int yoff,List * dl)5599 EditorWindow::moveStandIns(EditorWorkSpace *page, List* selectedNodes, int xoff, int yoff, List *dl)
5600 {
5601 int minx, miny, maxx, maxy;
5602 
5603     if (!selectedNodes) return ;
5604 
5605     this->getNodesBBox (&minx, &miny, &maxx, &maxy, selectedNodes, dl);
5606 
5607     this->destroyStandIns(selectedNodes);
5608 
5609     Node *node;
5610     ListIterator li(*selectedNodes);
5611     while ( (node = (Node*)li.getNext()) ) {
5612 	int x,y;
5613 	//
5614 	// Record bbox relative position, incoming, outgoing arcs
5615 	//
5616 	node->getVpePosition(&x, &y);
5617 
5618 	//
5619 	// Make a new StandIn using the saved position info.
5620 	//
5621 	node->setVpePosition (xoff + x - minx, yoff + y - miny);
5622     }
5623     page->setMembersInitialized(FALSE);
5624 
5625 }
5626 #endif
5627 
5628 
5629 #if WORKSPACE_PAGES
5630 void
moveDecorators(EditorWorkSpace * page,List * seldec,int xoff,int yoff,List * nl)5631 EditorWindow::moveDecorators(EditorWorkSpace *page, List* seldec, int xoff, int yoff, List*nl)
5632 {
5633 int minx, miny, maxx, maxy;
5634 Decorator *dec;
5635 int x,y;
5636 
5637     if (!seldec) return ;
5638 
5639     this->getNodesBBox (&minx, &miny, &maxx, &maxy, nl, seldec);
5640 
5641     Widget page_w = page->getRootWidget();
5642     Window page_wnd = (page_w?XtWindow(page_w):NUL(Window));
5643 
5644     ListIterator it(*seldec);
5645     while ( (dec = (Decorator*)it.getNext()) ) {
5646 	dec->getXYPosition (&x, &y);
5647 	dec->unmanage();
5648 	dec->uncreateDecorator();
5649 	dec->setXYPosition (xoff + x - minx, yoff + y - miny);
5650 	if ((page_w) && (page_wnd))
5651 	    dec->manage(page);
5652 	else
5653 	    page->setMembersInitialized(FALSE);
5654     }
5655 }
5656 
5657 //
5658 // If the standin is selected, then any arcs must go only to a selected standin
5659 // and not to an unselected standin.
5660 //
5661 // This is where nodes might automatically be replaced with Transmitter/Reciever
5662 // pairs.
5663 //
5664 boolean
areSelectedNodesPagifiable(boolean report)5665 EditorWindow::areSelectedNodesPagifiable(boolean report)
5666 {
5667 boolean retVal = TRUE;
5668 EditorWorkSpace *ws = NULL;
5669 
5670 
5671     List *l = this->makeSelectedNodeList();
5672     if ((!l) || (!l->getSize())) {
5673 	if (l) delete l;
5674 	return TRUE;
5675     }
5676 
5677     ListIterator snl(*l);
5678     Node *node;
5679     while ((retVal) && (node = (Node*)snl.getNext())) {
5680 	int i,count = node->getInputCount();
5681 	List *conns = NULL;
5682 
5683 	for (i=1; ((retVal) && (i<=count)); i++) {
5684 	    Ark *a;
5685 	    List *orig = (List*)node->getInputArks(i);
5686 	    conns = orig->dup();
5687 	    ListIterator ai(*conns);
5688 	    while ( (a = (Ark*)ai.getNext()) ) {
5689 		int fromParam, toParam;
5690 		Node *source = a->getSourceNode (fromParam);
5691 		Node *dest = a->getDestinationNode (toParam);
5692 		ASSERT (dest == node);
5693 		StandIn *ssi = source->getStandIn();
5694 		if ((ssi) && (!ssi->isSelected())) {
5695 		    if ((dest->isA(ClassReceiverNode)) &&
5696 			(source->isA(ClassTransmitterNode)) &&
5697 			(EqualString (dest->getLabelString(),source->getLabelString()))) {
5698 		    } else {
5699 			retVal = FALSE;
5700 			if (report) {
5701 			    char msg[512];
5702 			    sprintf (msg,
5703 				"Tool %s connects to unselected tool %s.\nSuggestion: ",
5704 				dest->getNameString(), source->getNameString());
5705 			    strcat (msg,
5706 				"Try the \'Edit/Select Tools/Select Connected\' option");
5707 			    ErrorMessage(msg);
5708 			}
5709 			break;
5710 		    }
5711 		} else if (ssi) {
5712 		    if (!ws) {
5713 			ws = (EditorWorkSpace*)ssi->getWorkSpace();
5714 		    } else if (ws != ssi->getWorkSpace()) {
5715 			retVal = FALSE;
5716 			if (report)
5717 			    ErrorMessage("Tool %s occupies a different page from %s.",
5718 				dest->getNameString(), source->getNameString());
5719 			break;
5720 		    }
5721 		}
5722 	    }
5723 	    delete conns;
5724 	}
5725 
5726 
5727 	count = node->getOutputCount();
5728 	for (i=1; ((retVal) && (i<=count)); i++) {
5729 	    Ark *a;
5730 	    List *orig = (List*)node->getOutputArks(i);
5731 	    conns = orig->dup();
5732 	    ListIterator ai(*conns);
5733 	    while ( (a = (Ark*)ai.getNext()) ) {
5734 		int fromParam, toParam;
5735 		Node *source = a->getSourceNode (fromParam);
5736 		Node *dest = a->getDestinationNode (toParam);
5737 		ASSERT (source == node);
5738 		StandIn *dsi = dest->getStandIn();
5739 		if ((dsi) && (!dsi->isSelected())) {
5740 		    if ((dest->isA(ClassReceiverNode)) &&
5741 			(source->isA(ClassTransmitterNode)) &&
5742 			(EqualString (dest->getLabelString(),source->getLabelString()))) {
5743 		    } else {
5744 			retVal = FALSE;
5745 			if (report) {
5746 			    char msg[512];
5747 			    sprintf (msg,
5748 				"Tool %s has a connection from unselected tool %s.\n",
5749 				source->getNameString(), dest->getNameString());
5750 			    strcat (msg, "Suggestion: "
5751 				"Try the \'Edit/Select Tools/Select Connected\' option");
5752 			    ErrorMessage(msg);
5753 			}
5754 			break;
5755 		    }
5756 		} else if (dsi) {
5757 		    if (!ws) {
5758 			ws = (EditorWorkSpace*)dsi->getWorkSpace();
5759 		    } else if (ws != dsi->getWorkSpace()) {
5760 			retVal = FALSE;
5761 			if (report)
5762 			    ErrorMessage("Tool %s occupies a different page from %s.",
5763 				source->getNameString(), dest->getNameString());
5764 			break;
5765 		    }
5766 		}
5767 	    }
5768 	    delete conns;
5769 	}
5770     }
5771 
5772     delete l;
5773     return retVal;
5774 }
5775 #endif
5776 
5777 //
5778 // Prepare for a new decorator, but don't managed it yet.
5779 //
placeDecorator()5780 boolean EditorWindow::placeDecorator()
5781 {
5782     if (!this->addingDecorators)
5783 	this->addingDecorators = new List;
5784 
5785     DecoratorStyle *ds =
5786 	DecoratorStyle::GetDecoratorStyle("Annotate", DecoratorStyle::DefaultStyle);
5787     ASSERT(ds);
5788     Decorator *d = ds->createDecorator(TRUE);
5789     ASSERT(d);
5790     d->setStyle (ds);
5791 
5792     DecoratorInfo *dnd = new DecoratorInfo (this->network,
5793 	(void*)this,
5794 	(DragInfoFuncPtr)EditorWindow::SetOwner,
5795 	(DragInfoFuncPtr)EditorWindow::DeleteSelections,
5796 	(DragInfoFuncPtr)EditorWindow::Select);
5797     d->setDecoratorInfo(dnd);
5798 
5799     this->addingDecorators->appendElement((void*)d);
5800     this->toolSelector->deselectAllTools();
5801 
5802     //
5803     // Set the cursor to indicate placement
5804     //
5805     ASSERT(this->workSpace);
5806     this->workSpace->setCursor(UPPER_LEFT);
5807     return TRUE;
5808 }
5809 
5810 //
5811 // Change the style of the selected decorator(s)
5812 //
5813 extern "C" void
EditorWindow_SetDecoratorStyleCB(Widget w,XtPointer clientData,XtPointer)5814 EditorWindow_SetDecoratorStyleCB (Widget w, XtPointer clientData, XtPointer)
5815 {
5816 EditorWindow *editor = (EditorWindow*)clientData;
5817 List *decors = editor->makeSelectedDecoratorList();
5818 long ud;
5819 
5820     XtVaGetValues (w, XmNuserData, &ud, NULL);
5821     editor->setDecoratorStyle (decors, (DecoratorStyle*)ud);
5822     if (decors) delete decors;
5823 }
5824 
setDecoratorStyle(List * decors,DecoratorStyle * ds)5825 void EditorWindow::setDecoratorStyle (List *decors, DecoratorStyle *ds)
5826 {
5827     if (!decors) return;
5828     ASSERT(ds);
5829 
5830     //
5831     // For interactors, there is InteractorInstance which handles style
5832     // changes but, for decorators there is nothing.  So, fetch the data,
5833     // make a new decorator, then replace the data.
5834     //
5835     ListIterator it(*decors);
5836     Decorator *dec;
5837     Symbol s = theSymbolManager->registerSymbol(ClassLabelDecorator);
5838     while ( (dec = (Decorator*)it.getNext()) ) {
5839 	if (!dec->isA(s)) continue;
5840 
5841 	LabelDecorator *oldlab = (LabelDecorator*)dec;
5842 	Dialog* sdtDiag = oldlab->getDialog();
5843 	oldlab->associateDialog(NUL(Dialog*));
5844 	WorkSpace *parent = oldlab->getWorkSpace();
5845 	oldlab->unmanage();
5846 	const char *val = oldlab->getLabelValue();
5847 	int x,y;
5848 	oldlab->getXYPosition (&x, &y);
5849 	this->network->removeDecoratorFromList((void*)oldlab);
5850 
5851 	LabelDecorator *newlab = (LabelDecorator*)ds->createDecorator(TRUE);
5852 	ASSERT(newlab);
5853 	newlab->setStyle(ds);
5854 
5855 	DecoratorInfo *dnd = new DecoratorInfo (this->network,
5856 	    (void*)this,
5857 	    (DragInfoFuncPtr)EditorWindow::SetOwner,
5858 	    (DragInfoFuncPtr)EditorWindow::DeleteSelections,
5859 	    (DragInfoFuncPtr)EditorWindow::Select);
5860 	newlab->setDecoratorInfo(dnd);
5861 
5862 	if ((val) && (val[0]))
5863 	    newlab->setLabel(val);
5864 	newlab->setXYPosition(x,y);
5865 	this->network->addDecoratorToList ((void*)newlab);
5866 
5867 	//
5868 	// Transfer resource settings.
5869 	//
5870 	oldlab->transferResources(newlab);
5871 	newlab->setFont(oldlab->getFont());
5872 	newlab->associateDialog(sdtDiag);
5873 	this->newDecorator (newlab, (EditorWorkSpace*)parent);
5874 
5875 	delete oldlab;
5876     }
5877 
5878     this->network->setFileDirty();
5879 }
5880 
5881 //
5882 // Edit/{Cut,Copy} means produce the chunk of .net/.cfg file the same as
5883 // would happen with drag-n-drop and store that chunk somewhere so that it
5884 // can be supplied to a requestor.
5885 //
cutSelectedNodes()5886 boolean EditorWindow::cutSelectedNodes()
5887 {
5888     if (this->copySelectedNodes(TRUE) == FALSE) {
5889 	return FALSE;
5890     }
5891     this->removeSelectedNodes();
5892     this->setUndoActivation();
5893     return TRUE;
5894 }
5895 
5896 #ifdef DXD_OS_NON_UNIX
5897 #define RD_FLAG "rb"
5898 #else
5899 #define RD_FLAG "r"
5900 #endif
5901 
copySelectedNodes(boolean delete_property)5902 boolean EditorWindow::copySelectedNodes(boolean delete_property)
5903 {
5904 char msg[128];
5905 Display *d = XtDisplay(this->getRootWidget());
5906 Atom file_atom = XmInternAtom (d, NET_ATOM, False);
5907 Atom delete_atom = XmInternAtom (d, "DELETE", False);
5908 Screen *screen = XtScreen(this->getRootWidget());
5909 Window root = RootWindowOfScreen(screen);
5910 
5911     int net_len, cfg_len;
5912     char* cfg_buffer;
5913     char* net_buffer = this->createNetFileFromSelection(net_len, &cfg_buffer, cfg_len);
5914     if (!net_buffer) return FALSE;
5915 
5916     //
5917     // Safeguard:  I don't know if this is necessary.  Maybe calling XtOwnSelection
5918     // can have unintended consequences if you're already the selection owner?
5919     // Maybe libXt will tell me I lost the selection because someone took it?
5920     // So, I'll disown the selection before reasserting ownership.
5921     //
5922     Widget w = XtNameToWidget (this->getRootWidget(), "*optionSeparator");
5923     ASSERT (w);
5924     XtVaSetValues (w, XmNuserData, this, NULL);
5925     Time tstamp = XtLastTimestampProcessed(d);
5926     Window win = XGetSelectionOwner (d, file_atom);
5927     if ((win != None) && (XtWindow(w) == win))
5928 	XtDisownSelection (w, file_atom, tstamp);
5929 
5930     unsigned char del_buf[16];
5931     if (delete_property) strcpy ((char*)del_buf, "TRUE");
5932     else strcpy ((char*)del_buf, "FALSE");
5933     XChangeProperty (d, root, delete_atom, XA_STRING, 8, PropModeReplace,
5934 	del_buf, strlen((char*)del_buf));
5935 
5936     //
5937     // XtOwnSelection registers 3 callbacks but there is no clientData to pass.
5938     // Therefore I need some other way to get back the this pointer inside
5939     // these 3 callbacks.  I am using XmNuserData in the widget for this purpose.
5940     // I picked such an obscure widget because I suspect that if the widget is the
5941     // root of some UIComponent, the XmNuserData slot will already be in use.
5942     //
5943     boolean retVal;
5944     if (XtOwnSelection (w, file_atom, tstamp,
5945 	(XtConvertSelectionProc)EditorWindow_ConvertSelectionCB,
5946 	(XtLoseSelectionProc)EditorWindow_LoseSelectionCB,
5947 	(XtSelectionDoneProc)EditorWindow_SelectionDoneCB)) {
5948 	this->pasteNodeCmd->activate();
5949 	retVal = TRUE;
5950     } else {
5951 	this->pasteNodeCmd->deactivate();
5952 	retVal = FALSE;
5953     }
5954 
5955     //
5956     // Assign to copied{Net,Cfg} after owning the selection in case owning also
5957     // makes you lose it.
5958     //
5959     if (this->copiedNet) delete this->copiedNet;
5960     this->copiedNet = (char *)net_buffer;
5961     if (this->copiedCfg) delete this->copiedCfg;
5962     this->copiedCfg = (char *)cfg_buffer;
5963 
5964     return retVal;
5965 }
5966 
5967 //
5968 // caller must free the returned memory
5969 //
createNetFileFromSelection(int & net_len,char ** cfg_out,int & cfg_len)5970 char* EditorWindow::createNetFileFromSelection(int& net_len, char** cfg_out, int& cfg_len)
5971 {
5972 char netfilename[256];
5973 char cfgfilename[256];
5974 FILE *netf;
5975 char msg[128];
5976 
5977     net_len = cfg_len = 0;
5978     if (cfg_out) *cfg_out = NUL(char*);
5979 
5980     //
5981     // It should be unnecessary to perform this check because command activation
5982     // should prevent being here if both counts are 0, however kbd accelerators
5983     // can get us here and we might not have any way of preempting that.
5984     //
5985     int nselected = this->getNodeSelectionCount();
5986     int dselected = 0;
5987     ListIterator it;
5988     Decorator *decor;
5989     FOR_EACH_NETWORK_DECORATOR(this->getNetwork(),decor,it)
5990 	if (decor->isSelected()) dselected++;
5991     if ((dselected == 0) && (nselected == 0)) return NUL(char*);
5992 
5993     //
5994     // Get 2 temp file names for the .net and .cfg files
5995     // FIXME:  We need a DXApplication::getTmpFile().  The code
5996     // to form tmp file names off the tmp directory is used in several places.
5997     //
5998     const char *tmpdir = theDXApplication->getTmpDirectory();
5999     int tmpdirlen = STRLEN(tmpdir);
6000     if (!tmpdirlen) return NULL;
6001     if (tmpdir[tmpdirlen-1] == '/') {
6002 	sprintf(netfilename, "%sdx%d.net", tmpdir, getpid());
6003 	sprintf(cfgfilename, "%sdx%d.cfg", tmpdir, getpid());
6004     } else {
6005 	sprintf(netfilename, "%s/dx%d.net", tmpdir, getpid());
6006 	sprintf(cfgfilename, "%s/dx%d.cfg", tmpdir, getpid());
6007     }
6008     unlink (netfilename);
6009     unlink (cfgfilename);
6010 
6011     if ((netf = fopen(netfilename, "a+")) == NULL) {
6012 	sprintf (msg, "Copy failed: %s", strerror(errno));
6013 	WarningMessage(msg);
6014 	return NUL(char*);
6015     }
6016 
6017     //
6018     // Save .net/.cfg into the temp directory;
6019     //
6020     this->network->printNetwork (netf, PrintCut);
6021     this->network->cfgPrintNetwork (cfgfilename, PrintCut);
6022     fclose(netf);
6023 
6024 
6025     //
6026     // Read the .net and .cfg back it, and save their contents
6027     //
6028     netf = NUL(FILE*);
6029     if ((netf = fopen(netfilename, RD_FLAG)) == NULL) {
6030 	sprintf (msg, "Copy failed (fopen): %s", strerror(errno));
6031 	WarningMessage(msg);
6032 	return NUL(char*);
6033     }
6034 
6035     unsigned char *cfg_buffer = NULL;
6036 
6037     struct STATSTRUCT statb;
6038     if (cfg_out) {
6039 	FILE *cfgf = fopen(cfgfilename, RD_FLAG);
6040 	if ((cfgf) && (STATFUNC(cfgfilename, &statb) != -1)) {
6041 	    cfg_len = (unsigned int)statb.st_size;
6042 	    cfg_buffer = (unsigned char *)(cfg_len?new char[1+cfg_len]:NULL);
6043 
6044 	    if (fread((char*)cfg_buffer, sizeof(char), cfg_len, cfgf) != cfg_len) {
6045 		sprintf (msg, "Copy failed (fread): %s", strerror(errno));
6046 		WarningMessage(msg);
6047 		fclose(cfgf);
6048 		delete cfg_buffer;
6049 		return NUL(char*);
6050 	    }
6051 	    cfg_buffer[cfg_len] = '\0';
6052 	    fclose(cfgf);
6053 	    cfgf = NUL(FILE*);
6054 	    unlink (cfgfilename);
6055 	}
6056     }
6057 
6058     if (STATFUNC(netfilename, &statb) == -1) {
6059 	sprintf (msg, "Copy failed (stat): %s", strerror(errno));
6060 	WarningMessage(msg);
6061 	fclose(netf);
6062         return NUL(char*);
6063     }
6064     net_len = (unsigned int)statb.st_size;
6065     if (!net_len) return NUL(char*);
6066     if (net_len > 63000) {
6067 	WarningMessage ("Too much data. Try transferring in pieces.");
6068 	fclose(netf);
6069 	return NUL(char*);
6070     }
6071     unsigned char *net_buffer = (unsigned char *)(net_len?new char[1+net_len]:NULL);
6072 
6073     if (fread((char*)net_buffer, sizeof(char), net_len, netf) != net_len) {
6074 	sprintf (msg, "Copy failed (fread): %s", strerror(errno));
6075 	WarningMessage(msg);
6076 	fclose(netf);
6077 	delete net_buffer;
6078         return NUL(char*);
6079     }
6080     net_buffer[net_len] = '\0';
6081     fclose(netf);
6082     unlink (netfilename);
6083 
6084     if (cfg_out) *cfg_out = (char*)cfg_buffer;
6085     else if (cfg_buffer) delete cfg_buffer;
6086     return (char*)net_buffer;
6087 }
6088 
6089 //
6090 // Edit/Paste means request the saved chunk of .net/.cfg text and do an
6091 // insertNetwork operation.
6092 //
pasteCopiedNodes()6093 boolean EditorWindow::pasteCopiedNodes()
6094 {
6095 Display *d = XtDisplay(this->getRootWidget());
6096 Atom file_atom = XmInternAtom (d, NET_ATOM, False);
6097 boolean proceed = TRUE;
6098 
6099     //
6100     // command activation is handled clumsily for cut/copy/paste because
6101     // there is no notification when someone gains/loses selection ownership.
6102     //
6103     if (file_atom) {
6104 	Window win = XGetSelectionOwner (d, file_atom);
6105 	if (win == None) proceed = FALSE;
6106     } else
6107 	proceed = FALSE;
6108 
6109     if (!proceed) {
6110 	this->pasteNodeCmd->deactivate();
6111 	return FALSE;
6112     }
6113 
6114     XtGetSelectionValue (this->getRootWidget(), file_atom, XA_STRING,
6115 	(XtSelectionCallbackProc)EditorWindow_SelectionReadyCB, (XtPointer)this,
6116 	XtLastTimestampProcessed(d));
6117     return TRUE;
6118 }
SetOwner(void * b)6119 void EditorWindow::SetOwner(void *b)
6120 {
6121 EditorWindow *ew = (EditorWindow*)b;
6122 Network *netw = ew->getNetwork();
6123     netw->setCPSelectionOwner(NUL(ControlPanel*));
6124 }
6125 
DeleteSelections(void * b)6126 void EditorWindow::DeleteSelections(void *b)
6127 {
6128 EditorWindow *ew = (EditorWindow*)b;
6129 Command *cmd = ew->getDeleteNodeCmd();
6130 
6131     cmd->execute();
6132 }
6133 
Select(void * b)6134 void EditorWindow::Select(void *b)
6135 {
6136 EditorWindow *ew = (EditorWindow*)b;
6137     ew->setCommandActivation();
6138 }
6139 
6140 #if EXPOSE_SET_SELECTION
setCopiedNet(const char * text)6141 void EditorWindow::setCopiedNet(const char* text)
6142 {
6143 Display *d = XtDisplay(this->getRootWidget());
6144 Atom file_atom = XmInternAtom (d, NET_ATOM, False);
6145 Atom delete_atom = XmInternAtom (d, "DELETE", False);
6146 Atom cfg_atom = XmInternAtom (d, CFG_ATOM, False);
6147 Screen *screen = XtScreen(this->getRootWidget());
6148 Window root = RootWindowOfScreen(screen);
6149 Time tstamp = XtLastTimestampProcessed(d);
6150 
6151     Widget w = XtNameToWidget (this->getRootWidget(), "*optionSeparator");
6152     ASSERT (w);
6153 
6154     if (this->copiedNet) {
6155 	delete this->copiedNet;
6156 	this->copiedNet = NUL(char*);
6157 	this->pasteNodeCmd->deactivate();
6158 	XtDisownSelection (w, file_atom, tstamp);
6159     }
6160     if (this->copiedCfg) {
6161 	delete this->copiedCfg;
6162 	this->copiedCfg = NUL(char*);
6163     }
6164 
6165     if ((text) && (text[0])) {
6166 	XtVaSetValues (w, XmNuserData, this, NULL);
6167 	if (XtOwnSelection (w, file_atom, tstamp,
6168 	    (XtConvertSelectionProc)EditorWindow_ConvertSelectionCB,
6169 	    (XtLoseSelectionProc)EditorWindow_LoseSelectionCB,
6170 	    (XtSelectionDoneProc)EditorWindow_SelectionDoneCB))
6171 	    this->pasteNodeCmd->activate();
6172 	else
6173 	    this->pasteNodeCmd->deactivate();
6174 
6175 	this->copiedNet = DuplicateString(text);
6176 
6177 	unsigned char del_buf[16];
6178 	strcpy ((char*)del_buf, "FALSE");
6179 	XChangeProperty (d, root, delete_atom, XA_STRING, 8, PropModeReplace,
6180 	    del_buf, strlen((char*)del_buf));
6181     }
6182 }
6183 #endif
6184 
EditorWindow_ConvertSelectionCB(Widget w,Atom * selection,Atom * target,Atom * type,XtPointer * value,unsigned long * length,int * format)6185 boolean EditorWindow_ConvertSelectionCB(Widget w, Atom *selection, Atom *target,
6186     Atom *type, XtPointer *value, unsigned long *length, int *format)
6187 {
6188 Display *d = XtDisplay(w);
6189 Atom file_atom = XmInternAtom (d, NET_ATOM, False);
6190 Atom cfg_atom = XmInternAtom (d, CFG_ATOM, False);
6191 Screen *screen = XtScreen(w);
6192 Window root = RootWindowOfScreen(screen);
6193 
6194     //
6195     // The this pointer was supposed to be in userData.  If anyone else is using
6196     // userData on the widget, then this scheme won't work
6197     // because these callbacks lack a clientData argument.
6198     //
6199     XtPointer ud;
6200     XtVaGetValues (w, XmNuserData, &ud, NULL);
6201     EditorWindow *editor = (EditorWindow*)ud;
6202     ASSERT(editor);
6203 
6204     //
6205     // FIXME:  there was an ASSERT in place of this if but the ASSERT often failed.
6206     // It's meaning was:  If this editor received a request for the selection,
6207     // then it must have asserted ownership of the selection.  If it did that, then
6208     // it must have stored copiedNet.  I don't understand how that can fail.
6209     // Maybe I'm doing something wrong in LoseSelectionCB, I don't know.
6210     //
6211     // I may have fixed it by disowning the selection prior to owning it.  It turned
6212     // out that asking to own the selection if I already owned it, would produce
6213     // a call to my LoseSelection callback which would throw out selection data.
6214     //
6215     ASSERT (*selection == file_atom);
6216     if (editor->copiedNet) {
6217 
6218 
6219 	*value = editor->copiedNet;
6220 	*length = strlen(editor->copiedNet);
6221 	*format = 8;
6222 	*type = XA_STRING;
6223 
6224 	if (editor->copiedCfg)
6225 	    XChangeProperty (d, root, cfg_atom, XA_STRING, 8, PropModeReplace,
6226 		(unsigned char*)editor->copiedCfg, strlen(editor->copiedCfg));
6227 
6228 	return TRUE;
6229     } else {
6230 	XtDisownSelection (w, *selection, XtLastTimestampProcessed(XtDisplay(w)));
6231 	editor->pasteNodeCmd->deactivate();
6232 	return FALSE;
6233     }
6234 }
6235 
EditorWindow_LoseSelectionCB(Widget w,Atom *)6236 void EditorWindow_LoseSelectionCB(Widget w, Atom *)
6237 {
6238     //
6239     // The this pointer was supposed to be in userData.  If anyone else is using
6240     // userData on the widget, then this scheme won't work
6241     // because these callbacks lack a clientData argument.
6242     //
6243     XtPointer ud;
6244     XtVaGetValues (w, XmNuserData, &ud, NULL);
6245     EditorWindow *editor = (EditorWindow*)ud;
6246     ASSERT(editor);
6247 
6248     if (editor->copiedNet) {
6249 	delete editor->copiedNet;
6250 	editor->copiedNet = NUL(char*);
6251     }
6252     if (editor->copiedCfg) {
6253 	delete editor->copiedCfg;
6254 	editor->copiedCfg = NUL(char*);
6255     }
6256     editor->pasteNodeCmd->deactivate();
6257 }
6258 
EditorWindow_SelectionDoneCB(Widget w,Atom *,Atom *)6259 void EditorWindow_SelectionDoneCB(Widget w, Atom *, Atom *) {}
6260 
EditorWindow_SelectionReadyCB(Widget w,XtPointer clientData,Atom * selection,Atom * type,XtPointer value,unsigned long * length,int * format)6261 void EditorWindow_SelectionReadyCB (Widget w, XtPointer clientData, Atom *selection,
6262     Atom *type, XtPointer value, unsigned long *length, int *format)
6263 {
6264 EditorWindow *editor = (EditorWindow*)clientData;
6265 int status;
6266 FILE *netf;
6267 Display *d = XtDisplay(editor->getRootWidget());
6268 Atom file_atom = XmInternAtom (d, NET_ATOM, False);
6269 Atom cfg_atom = XmInternAtom (d, CFG_ATOM, False);
6270 Screen *screen = XtScreen(editor->getRootWidget());
6271 Window root = RootWindowOfScreen(screen);
6272 unsigned long bytes_after;
6273 char *net_buffer;
6274 Atom actual_type;
6275 int actual_format;
6276 unsigned long n_items;
6277 char msg[128];
6278 
6279     //
6280     // Get temp file names
6281     //
6282     char net_file_name[256];
6283     char cfg_file_name[256];
6284     //
6285     // It's good that this file name is formed using getTmpDirectory()
6286     // because later we're going to check to see if the file name
6287     // begins with the tmp directory and if so, leave it out of
6288     // the list of recently-referenced files.
6289     //
6290     const char *tmpdir = theDXApplication->getTmpDirectory();
6291     int tmpdirlen = STRLEN(tmpdir);
6292     if (!tmpdirlen) return ;
6293     if (tmpdir[tmpdirlen-1] == '/') {
6294 	sprintf(net_file_name, "%sdx%d.net", tmpdir, getpid());
6295 	sprintf(cfg_file_name, "%sdx%d.cfg", tmpdir, getpid());
6296     } else {
6297 	sprintf(net_file_name, "%s/dx%d.net", tmpdir, getpid());
6298 	sprintf(cfg_file_name, "%s/dx%d.cfg", tmpdir, getpid());
6299     }
6300     unlink (net_file_name);
6301     unlink (cfg_file_name);
6302 
6303 
6304     //
6305     // Put the file contents into the files
6306     //
6307     if ((netf = fopen(net_file_name, "w")) == NULL) {
6308 	sprintf (msg, "Paste failed (fopen): %s", strerror(errno));
6309 	WarningMessage(msg);
6310 	return ;
6311     }
6312     fwrite ((char*)value, sizeof(char), *length, netf);
6313     fclose(netf);
6314     XtFree((char*)value);
6315 
6316     status = XGetWindowProperty (d, root, cfg_atom, 0,
6317 	    63000>>2, False, XA_STRING, &actual_type,
6318 	    &actual_format, &n_items, &bytes_after,
6319 	    (unsigned char **)&net_buffer);
6320 
6321     if ((status == Success) && (net_buffer)) {
6322 	if ((netf = fopen(cfg_file_name, "w")) == NULL) {
6323 	    sprintf (msg, "Paste failed (fopen): %s", strerror(errno));
6324 	    WarningMessage(msg);
6325 	    unlink (cfg_file_name);
6326 	    return ;
6327 	}
6328 	fwrite (net_buffer, sizeof(char), n_items, netf);
6329 	fclose(netf);
6330 	XFree(net_buffer);
6331 	unlink (cfg_file_name);
6332     }
6333 
6334 
6335     editor->setPendingPaste (net_file_name, NUL(char*), TRUE);
6336 
6337     unlink (net_file_name);
6338 
6339     unsigned char *del_buf;
6340     Atom delete_atom = XmInternAtom (d, "DELETE", False);
6341     status = XGetWindowProperty (d, root, delete_atom, 0, 4, False, XA_STRING,
6342 	&actual_type, &actual_format, &n_items, &bytes_after, &del_buf);
6343     if ((status == Success) && (del_buf) && (!strcmp((char*)del_buf, "FALSE"))) {
6344     } else {
6345 	XDeleteProperty (d, root, file_atom);
6346 	XDeleteProperty (d, root, cfg_atom);
6347 	//
6348 	// Force no one to own the selection.  XtDisown ought to be superfluous,
6349 	// but I'm not sure how/if the intrinsics find out about things like this
6350 	// done thru Xlib.  We're trying to make sure nobody has the selection,
6351 	// and also to let our own intrinsics know we don't.
6352 	//
6353 	Time tstamp = XtLastTimestampProcessed(d);
6354 	XtDisownSelection (w, file_atom, tstamp);
6355 	XSetSelectionOwner (d, file_atom, None, CurrentTime);
6356 	editor->pasteNodeCmd->deactivate();
6357     }
6358     if (del_buf) XFree(del_buf);
6359 
6360 
6361     editor->workSpace->setCursor(UPPER_LEFT);
6362 }
6363 
6364 //
6365 // Broken out of SelectionReadyCB so that it can be reused by UndoDeletion
6366 //
setPendingPaste(const char * net_file_name,const char * cfg_file_name,boolean ignoreUndefinedModules)6367 boolean EditorWindow::setPendingPaste (const char* net_file_name,
6368 	const char* cfg_file_name, boolean ignoreUndefinedModules)
6369 {
6370     //
6371     // Prepare a new network
6372     //
6373     if (this->addingDecorators) {
6374 	ListIterator it(*this->addingDecorators);
6375 	Decorator *dec;
6376 	while ( (dec = (Decorator*)it.getNext()) )  delete dec;
6377 	this->addingDecorators->clear();
6378 	delete this->addingDecorators;
6379 	this->addingDecorators = NULL;
6380     }
6381 
6382     if (this->pendingPaste) delete this->pendingPaste;
6383     this->pendingPaste = theDXApplication->newNetwork(TRUE);
6384     ASSERT(this->pendingPaste);
6385     if (!this->pendingPaste->readNetwork (net_file_name, NULL, TRUE)) {
6386 	delete this->pendingPaste;
6387 	this->pendingPaste = NULL;
6388 	WarningMessage ("Paste failed");
6389 	unlink (net_file_name);
6390 	return FALSE;
6391     }
6392     this->toolSelector->deselectAllTools();
6393     return TRUE;
6394 }
6395 
6396 //
6397 // Find the last selected transmitter node.  If it no longer exists,
6398 // then find the most recently placed one.  This is useful for the
6399 // ReceiverNode, which needs to no the most recent Transmitter to attach
6400 // to.
6401 //
getMostRecentTransmitterNode()6402 TransmitterNode *EditorWindow::getMostRecentTransmitterNode()
6403 {
6404     Node *node = NULL;
6405 
6406     //
6407     // Find all transmitters
6408     //
6409     List *l = this->network->makeClassifiedNodeList(ClassTransmitterNode);
6410 
6411     //
6412     // Find
6413     //   1) the one that is in lastSelectedTransmitter, or
6414     //   2) the one with the highest instance number.
6415     //
6416     if (l) {
6417         Node *last=NULL;
6418         ListIterator iter(*l);
6419 
6420 	//
6421 	// Look for one that matches the last selected node.
6422 	// Note, that we aren't sure that lastSelectedTransmitter is still
6423 	// in the network.
6424 	//
6425 	if (this->lastSelectedTransmitter) {
6426 	    while ( (last = (Node*)iter.getNext()) ) {
6427 		if (last == this->lastSelectedTransmitter) {
6428 		    node = last;
6429 		    break;
6430 		}
6431 	    }
6432 	}
6433 	if (!node) {	// If none found that match lastSelectedTransmitter
6434 	    int maxinst = 0;
6435 	    iter.setList(*l);
6436 	    while ( (node = (Node*)iter.getNext()) ) {
6437 		    int newinst = node->getInstanceNumber();
6438 		    if ((maxinst == 0) || (newinst > maxinst)) {
6439 			maxinst = newinst;
6440 			last = node;
6441 		    }
6442 	    }
6443 	    node = last;
6444         }
6445         delete l;
6446     }
6447 
6448     return (TransmitterNode*)node;
6449 
6450 }
6451 
6452 //
6453 // Visit the most recently executed nodes changing their label color.
6454 // Check every addition to the list for a connection to Transmitter.  If
6455 // found add the Transmitter to the list.  Then add all corresponding
6456 // Receivers to the list also.
6457 //
showExecutedNodes()6458 boolean EditorWindow::showExecutedNodes()
6459 {
6460     this->deselectAllNodes();
6461 
6462     if (!this->executed_nodes) return FALSE;
6463     if (!this->executed_nodes->getSize()) return FALSE;
6464 
6465     ListIterator it;
6466     Node* n;
6467 
6468     //
6469     // See if the network contains any moduless nodes
6470     //
6471     List modless;
6472     Symbol sym;
6473     Symbol interactor_sym;
6474     if (!this->transmitters_added) {
6475 	//
6476 	// Search the network for nodes which aren't backed up by modules.
6477 	// These will have be to selected depending on what else executed.
6478 	// It does no good to add DXLOutputNode to the list because we're doing
6479 	// a bottom-up search.  DXLOutputNode has no outputs.  I tried adding
6480 	// ClassNondrivenInteractorNode instead of InteractorNode.  The problem
6481 	// there is that some InteractorNodes (subclassing off DrivenNode and not
6482 	// subclassing off NondrivenInteractorNode) are really not driven, so you
6483 	// have to test each one using isDataDriven().
6484 	//
6485 	sym = theSymbolManager->registerSymbol(ClassMacroParameterNode);
6486 	modless.appendElement((void*)sym);
6487 	sym = theSymbolManager->registerSymbol(ClassTransmitterNode);
6488 	modless.appendElement((void*)sym);
6489 	sym = theSymbolManager->registerSymbol(ClassReceiverNode);
6490 	modless.appendElement((void*)sym);
6491 	sym = theSymbolManager->registerSymbol(ClassDXLInputNode);
6492 	modless.appendElement((void*)sym);
6493 	interactor_sym = sym = theSymbolManager->registerSymbol(ClassInteractorNode);
6494 	modless.appendElement((void*)sym);
6495 
6496 
6497 	ListIterator it(modless);
6498 	boolean found_some = FALSE;
6499 	while ((found_some == FALSE) && (sym = (Symbol)(long)it.getNext())) {
6500 	    const char* cp = theSymbolManager->getSymbolString(sym);
6501 	    ASSERT ((cp) && (cp[0]));
6502 	    List* nodes = this->network->makeClassifiedNodeList(cp);
6503 	    if ((nodes) && (nodes->getSize()))
6504 		found_some = TRUE;
6505 	    if (nodes)
6506 		delete nodes;
6507 	}
6508 	if (found_some == FALSE)
6509 	    this->transmitters_added = TRUE;
6510     }
6511 
6512     //
6513     // Loop until no change to the list of executed_nodes is made.  Must loop
6514     // because if one moduleless node is added, that guy could be connected to
6515     // others who should be added, but we won't know until the next pass.
6516     //
6517     // FIXME: would someone please rewrite this loop in the form of a recursive
6518     // subroutine call.
6519     //
6520     boolean change_made = TRUE;
6521     List appendables;
6522     List recent1;
6523     List recent2;
6524     boolean first_time = TRUE;
6525     while ((!this->transmitters_added) && (change_made)) {
6526 	int i, j;
6527 
6528 	change_made = FALSE;
6529 
6530 	//
6531 	// First time thru the loop look at every executed node.  On subsequent
6532 	// iterations, look only at those nodes which were added on the previous
6533 	// iteration.
6534 	//
6535 	if (first_time) it.setList(*this->executed_nodes);
6536 	else it.setList(recent1);
6537 
6538 	while ( (n = (Node*)it.getNext()) ) {
6539 	    int numParam = n->getInputCount();
6540 	    for (i = 1; i <= numParam; ++i) {
6541 		if (n->isInputConnected(i)) {
6542 		    Ark *a;
6543 		    List *arcs = (List *)n->getInputArks(i);
6544 		    for (j = 1; (a = (Ark*)arcs->getElement(j)); ++j) {
6545 			int paramInd;
6546 			Node *srcNode = a->getSourceNode(paramInd);
6547 			boolean moduleless_node = FALSE;
6548 
6549 			ListIterator mit(modless);
6550 			while ( (sym = (Symbol)(long)mit.getNext()) ) {
6551 			    if (srcNode->isA(sym)) {
6552 				if (sym == interactor_sym) {
6553 				    InteractorNode* in = (InteractorNode*)srcNode;
6554 				    if (in->isDataDriven() == FALSE) {
6555 					moduleless_node = TRUE;
6556 					break;
6557 				    }
6558 				} else {
6559 				    moduleless_node = TRUE;
6560 				    break;
6561 				}
6562 			    }
6563 			}
6564 
6565 			if (moduleless_node) {
6566 			    if (!appendables.isMember((void*)srcNode)) {
6567 				appendables.appendElement((void*)srcNode);
6568 				recent2.appendElement((void*)srcNode);
6569 				change_made = TRUE;
6570 			    }
6571 			}
6572 		    }
6573 		}
6574 	    }
6575 	}
6576 	recent1.clear();
6577 	it.setList(recent2);
6578 	while ( (n = (Node*)it.getNext()) )
6579 	    recent1.appendElement((void*)n);
6580 	recent2.clear();
6581 	first_time = FALSE;
6582     }
6583     it.setList(appendables);
6584     while ( (n = (Node*)it.getNext()) )
6585 	this->executed_nodes->appendElement((void*)n);
6586     this->transmitters_added = TRUE;
6587 
6588     it.setList(*this->executed_nodes);
6589     while ( (n = (Node*)it.getNext()) )
6590 	this->selectNode(n, TRUE, FALSE);
6591 
6592     return TRUE;
6593 }
6594 
6595 //
6596 // A counterpart to newNode().  Used only for vpe annotation.
6597 //
newDecorator(Decorator * dec,EditorWorkSpace * where)6598 void EditorWindow::newDecorator (Decorator* dec, EditorWorkSpace* where)
6599 {
6600 
6601 #if WORKSPACE_PAGES
6602     const char* cp;
6603     VPEAnnotator *vpea = (VPEAnnotator*)dec;
6604     if ( (cp = vpea->getGroupName(theSymbolManager->getSymbol(PAGE_GROUP))) ) {
6605 	EditorWorkSpace *page = this->getPage(cp);
6606 	ASSERT(page);
6607 	//
6608 	// If page is equal to the current page, then manage the decorator.
6609 	//
6610 	int page_num = this->workSpace->getCurrentPage();
6611 	EditorWorkSpace* ews = this->workSpace;
6612 	if (page_num)
6613 	    ews = (EditorWorkSpace*)this->workSpace->getElement(page_num);
6614 	if (ews == page)
6615 	    vpea->manage(page);
6616 	else
6617 	    page->setMembersInitialized(FALSE);
6618     } else {
6619 	EditorWorkSpace* current_page = where;
6620 	if (!current_page) {
6621 	    int page = this->workSpace->getCurrentPage();
6622 	    if (page)
6623 		current_page = (EditorWorkSpace*)this->workSpace->getElement(page);
6624 	    else
6625 		current_page = this->workSpace;
6626 	}
6627 	GroupRecord* grec = this->getGroupOfWorkSpace(current_page);
6628 	Symbol page_sym = theSymbolManager->getSymbol(PAGE_GROUP);
6629 	if (grec) vpea->setGroupName (grec, page_sym);
6630 	if (current_page->getRootWidget())
6631 	    vpea->manage(current_page);
6632 	else
6633 	    current_page->setMembersInitialized(FALSE);
6634     }
6635 #else
6636     if ((where) && (where->getRootWidget()))
6637 	dec->manage(where);
6638     else if (this->workSpace->getRootWidget())
6639 	dec->manage(this->workSpace);
6640 #endif
6641 }
6642 
6643 //
6644 // EditorWindow maintains a list of greened nodes so that we can go back
6645 // sometime later and see what executed.  Several steps are required to
6646 // unset the list and the lis must be unset in several situations so
6647 // encapsulate it here.
6648 //
resetExecutionList()6649 void EditorWindow::resetExecutionList()
6650 {
6651     if (this->executed_nodes) this->executed_nodes->clear();
6652     this->showExecutedCmd->deactivate();
6653     this->transmitters_added = FALSE;
6654 }
6655 
6656 #if WORKSPACE_PAGES
resetErrorList(boolean reset_all)6657 void EditorWindow::resetErrorList(boolean reset_all)
6658 {
6659     if (reset_all) {
6660 	if (this->errored_standins) delete this->errored_standins;
6661 	this->errored_standins = NUL(List*);
6662     } else if (this->errored_standins) {
6663 	if (this->errored_standins->getSize() == 0) {
6664 	    delete this->errored_standins;
6665 	    this->errored_standins = NUL(List*);
6666 	}
6667     }
6668 
6669     //
6670     // reset all page tab colors keeping those yellow which
6671     // still have yellow standins
6672     //
6673     List yellow_tabs;
6674     if (this->errored_standins) {
6675 	ListIterator it(*this->errored_standins);
6676 	StandIn* si;
6677 	while ( (si = (StandIn*)it.getNext()) ) {
6678 	    WorkSpace* page = si->getWorkSpace();
6679 	    yellow_tabs.appendElement((void*)page);
6680 	}
6681     }
6682 
6683     DictionaryIterator di(*this->pageSelector);
6684     EditorWorkSpace* ews;
6685     while ( (ews = (EditorWorkSpace*)di.getNextDefinition()) )
6686 	if (yellow_tabs.isMember((void*)ews) == FALSE)
6687 	    this->pageSelector->highlightTab (ews, EditorWindow::REMOVEHIGHLIGHT);
6688 }
6689 #endif
6690 
6691 #if WORKSPACE_PAGES
6692 
getPageMemberCount(WorkSpace * page)6693 int EditorWindow::getPageMemberCount(WorkSpace* page)
6694 {
6695     const char* page_name = NUL(char*);
6696     int i,count = this->pageSelector->getSize();
6697     for (i=1; i<=count; i++) {
6698 	if (page == this->pageSelector->getDefinition(i)) {
6699 	    page_name = this->pageSelector->getStringKey(i);
6700 	    break;
6701 	}
6702     }
6703     if (page != this->workSpace) {
6704 	ASSERT(page_name);
6705     }
6706 
6707     int kidCnt = 0;
6708     ListIterator it;
6709     Node* node;
6710     Decorator* dec;
6711     Symbol psym = theSymbolManager->getSymbol(PAGE_GROUP);
6712     FOR_EACH_NETWORK_NODE (this->network, node, it) {
6713 	const char* nodes_page_name = node->getGroupName(psym);
6714 	if ((!nodes_page_name) && ((!page) || (page == this->workSpace))) {
6715 	    kidCnt++;
6716 	} else {
6717 	    if (EqualString(page_name, nodes_page_name)) {
6718 		kidCnt++;
6719 	    }
6720 	}
6721     }
6722 
6723     FOR_EACH_NETWORK_DECORATOR (this->network, dec, it) {
6724 	VPEAnnotator* vpea = (VPEAnnotator*)dec;
6725 	const char* nodes_page_name = vpea->getGroupName(psym);
6726 	if ((!nodes_page_name) && ((!page) || (page == this->workSpace))) {
6727 	    kidCnt++;
6728 	} else {
6729 	    if (EqualString(page_name, nodes_page_name)) {
6730 		kidCnt++;
6731 	    }
6732 	}
6733     }
6734     return kidCnt;
6735 }
6736 
populatePage(EditorWorkSpace * ews)6737 void EditorWindow::populatePage(EditorWorkSpace* ews)
6738 {
6739     Symbol psym = theSymbolManager->getSymbol(PAGE_GROUP);
6740     GroupRecord* grec = this->getGroupOfWorkSpace(ews);
6741 
6742     //
6743     // There is a page button associated with a workspace and that workspace
6744     // has no group?  Shouldn't happen unless you just haven't made the group yet.
6745     //
6746     //if (!grec) return ;
6747 
6748     const char* page_name = (grec?grec->getName():NUL(char*));
6749     Node* node;
6750     ListIterator it;
6751     Decorator* dec;
6752 
6753     //
6754     // Loop over nodes looking for those belonging to the page.  When found
6755     // check to see if the nodes have standins.  This tells us if we need to
6756     // do work to populate the page.
6757     //
6758     boolean standins_created = FALSE;
6759     if (ews->membersInitialized() == FALSE) {
6760 	FOR_EACH_NETWORK_NODE (this->network, node, it) {
6761 	    const char* cp = node->getGroupName(psym);
6762 	    if (((cp == NUL(char*)) && (page_name == NUL(char*))) ||
6763 		(EqualString(cp, page_name))) {
6764 		StandIn* si = node->getStandIn();
6765 		if (!si) {
6766 		    if (!standins_created)
6767 			ews->beginManyPlacements();
6768 		    node->newStandIn(ews);
6769 		    standins_created = TRUE;
6770 		    if (node == this->executing_node)
6771 			this->highlightNode(node, EditorWindow::EXECUTEHIGHLIGHT);
6772 		} else {
6773 		    //
6774 		    // I would like to put a break here but I can't assume that if
6775 		    // the page contains 1 standin, that all nodes in the page have
6776 		    // standins.  Reason:  Edit/Insert Visual Program could have
6777 		    // placed new standins here which haven't been created yet.
6778 		    //
6779 		    //break;
6780 		}
6781 	    }
6782 	}
6783 
6784 	//
6785 	// This says we're not going to toggle lineRouting/overlap if we're adding
6786 	// only decorators.  Good?
6787 	//
6788 	FOR_EACH_NETWORK_DECORATOR(this->network,dec,it) {
6789 	    if (dec->getRootWidget()) continue;
6790 	    VPEAnnotator* vpea = (VPEAnnotator*)dec;
6791 	    const char* cp = vpea->getGroupName(psym);
6792 	    if (((cp == NUL(char*)) && (page_name == NUL(char*))) ||
6793 		(EqualString(cp, page_name))) {
6794 		vpea->manage(ews);
6795 	    }
6796 	}
6797     }
6798 
6799     if (standins_created) {
6800 	boolean old_value = this->creating_new_network;
6801 	this->creating_new_network = TRUE;
6802 	FOR_EACH_NETWORK_NODE (this->network, node, it) {
6803 	    const char* cp = node->getGroupName(psym);
6804 	    if (((cp == NUL(char*)) && (page_name == NUL(char*))) ||
6805 		(EqualString(cp, page_name))) {
6806 		StandIn* si = node->getStandIn();
6807 		ASSERT(si);
6808 		int icnt = node->getInputCount();
6809 		int i;
6810 		for (i=1 ; i<=icnt ; i++) {
6811 		    List* arcs = (List *)node->getInputArks(i);
6812 		    Ark* a;
6813 		    int j;
6814 		    for (j = 1; (a = (Ark*) arcs->getElement(j)); j++) {
6815 			int dummy;
6816 			Node* tn = a->getSourceNode(dummy);
6817 			ASSERT(tn);
6818 			if (tn->getStandIn() == NUL(StandIn*)) continue;
6819 			if (a->getArkStandIn() == NUL(ArkStandIn*))
6820 			    this->notifyArk(a);
6821 		    }
6822 		    si->drawTab(i, FALSE);
6823 		}
6824 	    }
6825 	}
6826 	this->creating_new_network = old_value;
6827 	ews->endManyPlacements();
6828 	ews->setMembersInitialized();
6829     }
6830 }
6831 #endif
6832 
6833 //
6834 // Change all nodes and decorators in tmpnet so that they think they live
6835 // in ews and belong to the corresponding group.  The is used when dropping
6836 // a selection of network onto a page tab.  An apparent wierdness here is that
6837 // we'll change all nodes in tmpnet without regard to their current grouping.
6838 // That should be OK however, because there is no way using drag-n-drop to
6839 // select nodes which live in more than 1 page/group.
6840 // The try_current_page argument means that we should allow the operation to proceed
6841 // if it looks like we're trying to paste into a page with no group operation.  Letting
6842 // it go ahead will put the nodes in the currently selected page.  That's good behavior
6843 // in the case of Edit/Paste but bad behavior when dropping onto a page tab.
6844 //
pagifyNetNodes(Network * tmpnet,EditorWorkSpace * ews,boolean try_current_page)6845 boolean EditorWindow::pagifyNetNodes
6846 (Network* tmpnet, EditorWorkSpace* ews, boolean try_current_page)
6847 {
6848     Symbol groupID = theSymbolManager->getSymbol(PAGE_GROUP);
6849 
6850     //
6851     // It's not OK for grec to be NULL because if it's NULL, then when
6852     // Network::mergeNetworks() works on tmpnet, it won't be able to adjust
6853     // the group pointers. Allow the operation to proceed if there is no
6854     // group and there is also no workspace.  In that case just erase the
6855     // group information and let the chips fall where they may.  That should
6856     // mean that everything will be placed in whatever is the current page.
6857     //
6858     GroupRecord* grec = this->getGroupOfWorkSpace(ews);
6859     const char* group_name = NUL(char*);
6860     if (grec) {
6861 	group_name = grec->getName();
6862     }
6863     if ((!group_name) && (!try_current_page)) return FALSE;
6864 
6865 
6866     //
6867     // Find the page manager from the old net and make a group record for the
6868     // new group name.
6869     //
6870     Dictionary* dict = tmpnet->getGroupManagers();
6871     GroupManager* page_mgr = (GroupManager*)dict->findDefinition(groupID);
6872     //
6873     // This can only fail if the group already exists, which is OK.
6874     //
6875     GroupRecord* new_grec = NUL(GroupRecord*);
6876     if (group_name) {
6877 	page_mgr->createGroup (group_name, tmpnet);
6878 	new_grec = page_mgr->getGroup(group_name);
6879 	if (!new_grec) return FALSE;
6880     }
6881 
6882 
6883     Node* node;
6884     ListIterator li;
6885     Decorator* dec;
6886     FOR_EACH_NETWORK_NODE(tmpnet, node, li) {
6887 	node->setGroupName(new_grec, groupID);
6888     }
6889     FOR_EACH_NETWORK_DECORATOR(tmpnet, dec, li) {
6890 	VPEAnnotator* vpea = (VPEAnnotator*)dec;
6891 	vpea->setGroupName(new_grec, groupID);
6892     }
6893     return TRUE;
6894 }
6895 
pagifySelectedNodes(EditorWorkSpace * ews)6896 boolean EditorWindow::pagifySelectedNodes(EditorWorkSpace* ews)
6897 {
6898     Symbol groupID = theSymbolManager->getSymbol(PAGE_GROUP);
6899 
6900     GroupRecord* grec = this->getGroupOfWorkSpace(ews);
6901     const char* group_name = NUL(char*);
6902     if (grec) group_name = grec->getName();
6903     if (!group_name) return FALSE;
6904 
6905     List* selno = this->makeSelectedNodeList();
6906     List* seldec = this->makeSelectedDecoratorList();
6907     EditorWorkSpace* selectedWS = NUL(EditorWorkSpace*);
6908 
6909     if ((selno) && (selno->getSize())) {
6910 	Node* n = (Node*)selno->getElement(1);
6911 	StandIn* si = (StandIn*)n->getStandIn();
6912 	selectedWS = (EditorWorkSpace*)si->getWorkSpace();
6913     } else if ((seldec) && (seldec->getSize())) {
6914 	Decorator* dec = (Decorator*)seldec->getElement(1);
6915 	selectedWS = (EditorWorkSpace*)dec->getWorkSpace();
6916     }
6917 
6918 
6919     if (selectedWS) selectedWS->beginManyPlacements();
6920     if (seldec) {
6921 	ListIterator it(*seldec);
6922 	VPEAnnotator* dec;
6923 	while ( (dec = (VPEAnnotator*)it.getNext()) )
6924 	    dec->setGroupName(grec, groupID);
6925 	this->moveDecorators (ews, seldec, 20, 20, selno);
6926     }
6927     if (selno) {
6928 	ListIterator it(*selno);
6929 	Node* n;
6930 	while ( (n = (Node*)it.getNext()) )
6931 	    n->setGroupName(grec, groupID);
6932 	this->moveStandIns (ews, selno, 20, 20, seldec);
6933     }
6934     if (selectedWS) selectedWS->endManyPlacements();
6935     if (selno) delete selno;
6936     if (seldec) delete seldec;
6937 
6938     this->setCommandActivation();
6939     return TRUE;
6940 }
6941 
configurePage()6942 boolean EditorWindow::configurePage()
6943 {
6944     this->pageSelector->postPageNameDialog();
6945     return TRUE;
6946 }
postMoveSelectedDialog()6947 boolean EditorWindow::postMoveSelectedDialog()
6948 {
6949     this->pageSelector->postMoveNodesDialog();
6950     this->setCommandActivation();
6951     return TRUE;
6952 }
6953 
6954 //
6955 // Break any arc which connects a selected node to an unselected node.
6956 // Replace the arc with transmitter/receiver combination.
6957 //
autoChopSelectedNodes()6958 boolean EditorWindow::autoChopSelectedNodes()
6959 {
6960     List* sellist = this->makeSelectedNodeList();
6961     if ((sellist == NUL(List*)) || (sellist->getSize() == 0))
6962 	return TRUE;
6963 
6964     Network* net = this->getNetwork();
6965     Dictionary tmits;
6966     Dictionary rcvrs;
6967     boolean status = net->chopArks(sellist, &tmits, &rcvrs);
6968 
6969     DictionaryIterator di(rcvrs);
6970     Node* n;
6971     while ( (n = (Node*)di.getNextDefinition()) ) {
6972         StandIn* si = n->getStandIn();
6973 	if (si) {
6974 	    List* arcs = (List *)n->getOutputArks(1);
6975 	    int j;
6976 	    Ark* a;
6977 	    for (j = 1; (a = (Ark*) arcs->getElement(j)) ; j++)
6978 		this->notifyArk(a);
6979 	    si->drawTab(1, FALSE);
6980 	}
6981     }
6982     delete sellist;
6983 
6984     if (this->selectConnectedNodeCmd->isActive())
6985 	this->selectConnectedNodeCmd->execute();
6986 
6987     return status;
6988 }
6989 
autoFuseSelectedNodes()6990 boolean EditorWindow::autoFuseSelectedNodes()
6991 {
6992 ListIterator it;
6993 Node* n;
6994 List rcvrs;
6995 int dummy;
6996 
6997     List* sellist = this->makeSelectedNodeList();
6998     if ((sellist == NUL(List*)) || (sellist->getSize() == 0))
6999 	return TRUE;
7000 
7001     Network* net = this->getNetwork();
7002 
7003     it.setList(*sellist);
7004     while ( (n = (Node*)it.getNext()) )
7005 	if (n->isA(ClassReceiverNode))
7006 	    rcvrs.appendElement((void*)n);
7007 
7008     //
7009     // If the original list contains only a transmitter(s), then augment the
7010     // list by adding all the receivers they're feeding.  In other words, if
7011     // the user selects a transmitter and asks to rewire it, then assume
7012     // she wants to get rid of all corresponding receivers.
7013     //
7014     if (rcvrs.getSize() == 0) {
7015 	it.setList(*sellist);
7016 	while ( (n = (Node*)it.getNext()) ) {
7017 	    if (n->isA(ClassTransmitterNode) == FALSE) continue;
7018 	    List* orig = (List*)n->getOutputArks(1);
7019 	    if ((!orig) || (orig->getSize() == 0)) continue;
7020 	    ListIterator ai(*orig);
7021 	    Ark* a;
7022 	    while ( (a = (Ark*)ai.getNext()) ) {
7023 		Node* rcvr = a->getDestinationNode(dummy);
7024 		ASSERT(rcvr->isA(ClassReceiverNode));
7025 		rcvrs.appendElement((void*)rcvr);
7026 	    }
7027 	}
7028     }
7029 
7030     //
7031     // Make a new list by augmenting the original.  For every
7032     // non-(transmitter/receiver) node , if its got no selected
7033     // receiver node inputs, then add all its receiver node inputs.
7034     //
7035     it.setList(*sellist);
7036     while ( (n = (Node*)it.getNext()) ) {
7037 	if (n->isA(ClassTransmitterNode)) continue;
7038 	if (n->isA(ClassReceiverNode)) continue;
7039 	int icnt = n->getInputCount();
7040 	int i;
7041 	List toadd;
7042 	boolean unusable_receiver = FALSE;
7043 	for (i=1; i<=icnt; i++) {
7044 	    List* orig = (List*)n->getInputArks(i);
7045 	    if ((!orig) || (orig->getSize() == 0)) continue;
7046 	    ASSERT(orig->getSize() == 1);
7047 	    Ark* a = (Ark*)orig->getElement(1);;
7048 	    Node* src = a->getSourceNode(dummy);
7049 	    if (src->isA(ClassReceiverNode)) {
7050 		List* oa = (List*)src->getOutputArks(1);
7051 		ASSERT(oa);
7052 		if (oa->getSize() == 1) {
7053 		    toadd.appendElement((void*)src);
7054 		} else {
7055 		    ListIterator oi(*oa);
7056 		    Ark* a;
7057 		    boolean included = TRUE;
7058 		    while ( (a = (Ark*)oi.getNext()) ) {
7059 			Node* dest = a->getDestinationNode(dummy);
7060 			if (sellist->isMember((void*)dest) == FALSE) {
7061 			    included = FALSE;
7062 			    break;
7063 			}
7064 		    }
7065 		    if (included)
7066 			toadd.appendElement((void*)src);
7067 		}
7068 		StandIn* si = src->getStandIn();
7069 		if (si) unusable_receiver = si->isSelected();
7070 	    }
7071 	    if (unusable_receiver) break;
7072 	}
7073 	if (unusable_receiver == FALSE) {
7074 	    ListIterator ta(toadd);
7075 	    Node* add;
7076 	    while ( (add = (Node*)ta.getNext()) ) {
7077 		if (rcvrs.isMember(add) == FALSE)
7078 		    rcvrs.appendElement((void*)add);
7079 	    }
7080 	}
7081     }
7082 
7083     //
7084     // Network::replaceInputArks() operates stritly on
7085     // the basis of the Receviers it encounters
7086     //
7087     boolean status = net->replaceInputArks(&rcvrs, NUL(List*));
7088 
7089     delete sellist;
7090 
7091     return status;
7092 }
7093 
toggleHitDetection()7094 boolean EditorWindow::toggleHitDetection()
7095 {
7096     WorkSpaceInfo *wsinfo = this->workSpace->getInfo();
7097     ToggleButtonInterface* tbi = (ToggleButtonInterface*)
7098 	this->hitDetectionOption;
7099     this->hit_detection = tbi->getState();
7100     wsinfo->setPreventOverlap(this->hit_detection);
7101     this->workSpace->installInfo(NULL);
7102     return TRUE;
7103 }
7104 
7105 String EditorWindow::SequenceNet[] = {
7106 #include "sequence.h"
7107 };
7108 
unjavifyNetwork()7109 boolean EditorWindow::unjavifyNetwork()
7110 {
7111     List* rlist = this->network->makeClassifiedNodeList(ClassReceiverNode);
7112     if (rlist) {
7113 	List to_delete;
7114 	ListIterator it(*rlist);
7115 	Node* n;
7116 	while ( (n = (Node*)it.getNext()) ) {
7117 	    if (EqualString(n->getLabelString(), JAVA_SEQUENCE))
7118 		to_delete.appendElement((void*)n);
7119 	}
7120 
7121 	if (to_delete.getSize() > 0)
7122 	    this->deleteNodes(&to_delete);
7123 	delete rlist;
7124 	rlist = NUL(List*);
7125     }
7126     //
7127     // Before asking to delete the page, make sure that the page
7128     // exists. Reason: deletePage will delete "Untitled" otherwise.
7129     //
7130     EditorWorkSpace* ews = (EditorWorkSpace*)
7131 	this->pageSelector->findDefinition(JAVA_SEQ_PAGE);
7132     if (ews != NUL(EditorWorkSpace*)) {
7133 	this->pageSelector->selectPage(ews);
7134 	this->deletePage(NUL(char*));
7135     }
7136 
7137     rlist = (List*)this->network->makeNamedNodeList("WebOptions");
7138     if (rlist) {
7139 	this->deleteNodes(rlist);
7140 	delete rlist;
7141 	rlist = NUL(List*);
7142     }
7143 
7144     rlist = (List*)this->network->makeClassifiedNodeList(ClassImageNode);
7145     if (rlist) {
7146 	ListIterator it(*rlist);
7147 	ImageNode* n;
7148 	while ( (n = (ImageNode*)it.getNext()) )
7149 	    n->unjavifyNode();
7150 	delete rlist;
7151 	rlist = NUL(List*);
7152     }
7153 
7154     return TRUE;
7155 }
7156 
7157 //
7158 // Add the special java page.  Then merge in a network.
7159 //
javifyNetwork()7160 boolean EditorWindow::javifyNetwork()
7161 {
7162     //
7163     // We must be able to create an instance of the WebOptions macro
7164     //
7165     NodeDefinition* wopt_nd = (NodeDefinition*)
7166 	theNodeDefinitionDictionary->findDefinition("WebOptions");
7167 
7168     if (!wopt_nd) {
7169 	// try loading web-options
7170 	char* macros = "/java/server/dxmacros";
7171 	const char* uiroot = theDXApplication->getUIRoot();
7172 	char* jxmacros;
7173 	fprintf(stderr, "WebOptions macro not in DXMACROS path\n");
7174 	fprintf(stderr, "attempting to load from configure-time parameters\n");
7175     	if (!uiroot)
7176         	uiroot = "/usr/local/dx";
7177 	jxmacros=(char*)malloc(strlen(uiroot)+strlen(macros)+2);
7178 	strcpy(jxmacros,uiroot);
7179 	strcat(jxmacros,macros);
7180 	MacroDefinition::LoadMacroDirectories(jxmacros,TRUE,NULL,FALSE);
7181 	free(jxmacros);
7182     	wopt_nd = (NodeDefinition*) theNodeDefinitionDictionary->findDefinition("WebOptions");
7183     }
7184     if (!wopt_nd) {
7185 	ErrorMessage (
7186 	    "The definition of macro WebOptions is missing.\n"
7187 	    "Load the macros from /usr/local/dx/java/server/dxmacros.\n"
7188 	    "Otherwise, this visual program will not function properly\n"
7189 	    "under control of DXServer.\n");
7190 	return FALSE;
7191     }
7192 
7193 
7194     //
7195     // Open a tmp file and write out sequence.net then read it
7196     // back into a temporary Network.
7197     //
7198     GroupManager *page_mgr = (GroupManager*)
7199 	this->network->getGroupManagers()->findDefinition(PAGE_GROUP);
7200     Symbol gmgr_sym = page_mgr->getManagerSymbol();
7201     if (this->pageSelector->findDefinition(JAVA_SEQ_PAGE) == NULL) {
7202 	const char* tmpdir = theIBMApplication->getTmpDirectory();
7203 	char uniq_file[512];
7204 	sprintf (uniq_file, "%s/foo.bar", tmpdir);
7205 	char* holder_file = UniqueFilename(uniq_file);
7206 	FILE* holder = fopen(holder_file, "w");
7207 	sprintf (uniq_file, "%s.net", holder_file);
7208 	FILE* uniq_f = fopen(uniq_file, "w");
7209 
7210 	int ll;
7211 	for (ll = 0; EditorWindow::SequenceNet[ll] != NULL; ll += 1)
7212 		fprintf (uniq_f, "%s", EditorWindow::SequenceNet[ll]);
7213 	fclose(uniq_f);
7214 	uniq_f = NUL(FILE*);
7215 
7216 	//
7217 	// Merging in the temporary network puts the nodes into java seqno page.
7218 	//
7219 	boolean non_java_net = TRUE;
7220 	Network* tmpnet = theDXApplication->newNetwork(non_java_net);
7221 	ASSERT(tmpnet);
7222 	boolean status = tmpnet->readNetwork(uniq_file, NULL, TRUE);
7223 	unlink (uniq_file);
7224 	fclose(holder);
7225 	unlink(holder_file);
7226 	delete holder_file;
7227 	if (status == FALSE) {
7228 	    delete tmpnet;
7229 	    return FALSE;
7230 	}
7231 
7232 	//
7233 	// Create a new page group in the network.
7234 	// Creating the new group also automatically marks selected nodes as belonging.
7235 	//
7236 	const char* page_name = JAVA_SEQ_PAGE;
7237 	this->deselectAllNodes();
7238 	ASSERT(page_mgr->createGroup (page_name, this->network));
7239 
7240 	//
7241 	// Make the new WorkSpace page.
7242 	//
7243 	EditorWorkSpace *page = (EditorWorkSpace*)this->workSpace->addPage();
7244 	ASSERT (this->pageSelector->addDefinition (page_name, page));
7245 	PageGroupRecord *grec = (PageGroupRecord*)page_mgr->getGroup (page_name);
7246 	grec->setComponents (NUL(UIComponent*), page);
7247 	this->workSpace->showWorkSpace(page);
7248 	gmgr_sym = page_mgr->getManagerSymbol();
7249 
7250 	this->network->mergeNetworks(tmpnet, NUL(List*), TRUE);
7251 	delete tmpnet;
7252     }
7253 
7254     //
7255     // Look for Image tools.  For each one, connect 2 transmitters - 1 for
7256     // loop number, the other for sequence number.
7257     //
7258     List* imgs = this->network->makeClassifiedNodeList(ClassImageNode);
7259     if (imgs) {
7260 	int x, y;
7261 	NodeDefinition *rcvr_nd = (NodeDefinition*)
7262 	    theNodeDefinitionDictionary->findDefinition("Receiver");
7263 	ASSERT(rcvr_nd);
7264 
7265 	ListIterator it(*imgs);
7266 	ImageNode* bn;
7267 	while ( (bn = (ImageNode*)it.getNext()) ) {
7268 	    Node* rcvr = NUL(Node*);
7269 	    Node* wopt = NUL(Node*);
7270 	    boolean adding_rcvr = TRUE;
7271 	    if (bn->isJavified() == FALSE) {
7272 		bn->getVpePosition(&x,&y);
7273 
7274 		List* rlist = this->network->makeClassifiedNodeList(ClassReceiverNode);
7275 		if (rlist) {
7276 		    const char* current_page_name = bn->getGroupName(gmgr_sym);
7277 		    ListIterator it(*rlist);
7278 		    Node* n;
7279 		    while ( (n = (Node*)it.getNext()) ) {
7280 			boolean same_page = FALSE;
7281 			if (EqualString(JAVA_SEQUENCE, n->getLabelString())) {
7282 			    const char* page_name = n->getGroupName(gmgr_sym);
7283 			    if (EqualString(page_name, current_page_name)) {
7284 				same_page = TRUE;
7285 				rcvr = (ReceiverNode*)n;
7286 			    }
7287 			}
7288 			if (same_page) {
7289 			    adding_rcvr = FALSE;
7290 			    break;
7291 			}
7292 		    }
7293 		    delete rlist;
7294 		    rlist = NUL(List*);
7295 		}
7296 
7297 		if (adding_rcvr) {
7298 		    rcvr = rcvr_nd->createNewNode(this->network);
7299 		    this->network->copyGroupInfo(bn, rcvr);
7300 		    rcvr->setVpePosition (x + 90, MAX(0,y-250));
7301 		    rcvr->setLabelString (JAVA_SEQUENCE);
7302 		} else {
7303 		    ASSERT(rcvr);
7304 		}
7305 
7306 		wopt = wopt_nd->createNewNode(this->network);
7307 		this->network->copyGroupInfo(bn, wopt);
7308 
7309 		const char* group_name = bn->getGroupName(page_mgr->getManagerSymbol());
7310 		EditorWorkSpace* ews =
7311 		    (EditorWorkSpace*)this->pageSelector->findDefinition(group_name);
7312 		if (!ews) {
7313 		    ews = (EditorWorkSpace*)this->workSpace;
7314 		    this->workSpace->showWorkSpace(ews);
7315 		}
7316 
7317 		wopt->setVpePosition (x + 40, MAX(0,y-100));
7318 
7319 		//this->network->addNode(wopt, ews);
7320 		this->network->addNode(wopt, NUL(EditorWorkSpace*));
7321 		if (adding_rcvr) {
7322 		    //this->network->addNode(rcvr, ews);
7323 		    this->network->addNode(rcvr, NUL(EditorWorkSpace*));
7324 		}
7325 	    }
7326 	    bn->javifyNode(wopt, rcvr);
7327 	}
7328 	delete imgs;
7329     }
7330 
7331     return TRUE;
7332 }
7333 
reflowEntireGraph()7334 boolean EditorWindow::reflowEntireGraph()
7335 {
7336     WorkSpace *current_ws = this->workSpace;
7337     int page = this->workSpace->getCurrentPage();
7338     if (page) current_ws = this->workSpace->getElement(page);
7339     if (!this->layout_controller)
7340 	this->layout_controller = new GraphLayout(this);
7341     boolean retval = this->layout_controller->entireGraph(
7342 	    current_ws, this->network->nodeList, this->network->decoratorList);
7343 
7344     // This will cause the ui to prompt the user to save.  In the past we
7345     // always tried to avoid this prompt if repositioning of standIns was
7346     // the only change.  We'll see if this is nice.
7347     if (retval) this->network->setFileDirty();
7348     return retval;
7349 }
7350 
7351 //
7352 // ewsc can be a StandIn or a VPEAnnotation.  A callback from the workspace
7353 // widget has told us that the component has been moved.  We fetch its
7354 // location (which is still the old location) and save it so that it can
7355 // be undone.
7356 //
saveLocationForUndo(UIComponent * uic,boolean mouse,boolean same_event)7357 void EditorWindow::saveLocationForUndo (UIComponent* uic, boolean mouse, boolean same_event)
7358 {
7359     boolean separator_pushed = same_event||this->moving_many_standins;
7360     if (this->performing_undo) return ;
7361 
7362     boolean found_it = FALSE;
7363     if ((TRUE)||(mouse)||(this->moving_many_standins)) {
7364 	ASSERT(uic);
7365 	ListIterator iterator;
7366 	Node* n;
7367 	FOR_EACH_NETWORK_NODE(this->network, n, iterator) {
7368 	    if (n->getStandIn() == uic) {
7369 		StandIn* si = (StandIn*)uic;
7370 
7371 		// error check
7372 		// can't do this error check because something that affects
7373 		// a standIn's label can cause  bumper cars even if those
7374 		// standIns aren't in the current page
7375 		//WorkSpace *current_ws = this->workSpace;
7376 		//int page = this->workSpace->getCurrentPage();
7377 		//if (page) current_ws = this->workSpace->getElement(page);
7378 		//ASSERT (current_ws == si->getWorkSpace());
7379 
7380 		if (!separator_pushed) {
7381 		    this->undo_list.push(new UndoSeparator(this));
7382 		    separator_pushed = TRUE;
7383 		}
7384 
7385 		this->undo_list.push ( new UndoStandInMove (
7386 			this, si, n->getNameString(), n->getInstanceNumber()
7387 		    )
7388 		);
7389 		found_it = TRUE;
7390 		break;
7391 	    }
7392 	}
7393 	Decorator* dec;
7394 	FOR_EACH_NETWORK_DECORATOR(this->network, dec, iterator) {
7395 	    if (dec == uic) {
7396 
7397 		if (!separator_pushed) {
7398 		    this->undo_list.push(new UndoSeparator(this));
7399 		    separator_pushed = TRUE;
7400 		}
7401 
7402 		this->undo_list.push (new UndoDecoratorMove (this, (VPEAnnotator*)dec));
7403 		found_it = TRUE;
7404 		break;
7405 	    }
7406 	}
7407 	// don't do this because if you drop one thing on top of
7408 	// another, someone might unmanage a widget which means
7409 	// we'll not be able to find out what happened.
7410 	//ASSERT(found_it);
7411     }
7412 
7413     // this->setCommandActivation() doesn't run often enough to deal
7414     // with accelerators.
7415     if ((found_it) && (!this->undoCmd->isActive()))
7416 	this->setUndoActivation();
7417 }
7418 
clearUndoList()7419 void EditorWindow::clearUndoList()
7420 {
7421     if (this->undo_list.getSize() == 0) return;
7422     UndoableAction* undoable;
7423     while ((undoable=(UndoableAction*)this->undo_list.pop()))
7424 	delete undoable;
7425     this->undo_list.clear();
7426     this->setUndoActivation();
7427 }
7428 
beginMultipleCanvasMovements()7429 void EditorWindow::beginMultipleCanvasMovements()
7430 {
7431     this->moving_many_standins = TRUE;
7432     this->undo_list.push(new UndoSeparator(this));
7433 }
7434 
undo()7435 boolean EditorWindow::undo()
7436 {
7437     boolean many_placements = TRUE;//(this->undo_list.getSize() >= 2);
7438     WorkSpace *current_ws = this->workSpace;
7439     if (many_placements) {
7440 	int page = this->workSpace->getCurrentPage();
7441 	if (page) current_ws = this->workSpace->getElement(page);
7442 	current_ws->beginManyPlacements();
7443     }
7444     this->performing_undo = TRUE;
7445     UndoableAction* undoable;
7446 
7447     Stack short_stack;
7448     List undo_candidates;
7449     ListIterator iter;
7450     const char* couldnt_undo = NUL(const char*);
7451     int count = 0;
7452     while ((undoable=(UndoableAction*)this->undo_list.pop())) {
7453 	if (undoable->isSeparator()) break;
7454 	undoable->prepare();
7455 	undo_candidates.appendElement(undoable);
7456 	count++;
7457     }
7458     for (int i=count; i>=1; i--) {
7459 	undoable = (UndoableAction*)undo_candidates.getElement(i);
7460 	if (undoable->canUndo()) {
7461 	    short_stack.push(undoable);
7462 	} else {
7463 	    couldnt_undo = undoable->getLabel();
7464 	}
7465     }
7466 
7467 
7468     if (couldnt_undo) {
7469 	if (short_stack.getSize() == 0) {
7470 	    WarningMessage( "An operation could not be undone: %s", couldnt_undo);
7471 	} else {
7472 	    ErrorMessage ("Part of the operation could not be undone: %s", couldnt_undo);
7473 	}
7474     }
7475 
7476     boolean first_in_list = TRUE;
7477     while ((undoable=(UndoableAction*)short_stack.pop())) {
7478 	undoable->undo(first_in_list);
7479 	first_in_list = FALSE;
7480     }
7481 
7482     iter.setList(undo_candidates);
7483     while (undoable = (UndoableAction*)iter.getNext()) {
7484 	undoable->postpare();
7485     }
7486 
7487     this->performing_undo = FALSE;
7488     if (many_placements) {
7489 	current_ws->endManyPlacements();
7490     }
7491 
7492     this->setUndoActivation();
7493 
7494     return TRUE;
7495 }
7496 
setUndoActivation()7497 void EditorWindow::setUndoActivation()
7498 {
7499     //if (this->deferrableCommandActivation->isActionDeferred()) return ;
7500 
7501     // These 2 numbers work like the float on your sump pump.  When
7502     // the level gets really high (up to check_when) the pump runs
7503     // and gets rid of material until it's low (down to max_stack_prune).
7504     // how many individual events are we going to keep around?
7505     int max_stack_prune = 10;
7506     // how big does the stack get before we check it for pruning.
7507     int check_when = 30;
7508 
7509     // set up for subsequent undo
7510     char button_label[64];
7511     strcpy (button_label, "Undo");
7512     int current_size = this->undo_list.getSize();
7513     if (current_size > 0) {
7514 
7515 	UndoableAction* undoable;
7516 	if (current_size >= check_when) {
7517 	    int saved = 0;
7518 	    Stack tmpStack;
7519 	    while ((undoable=(UndoableAction*)this->undo_list.pop())) {
7520 		if (undoable->isSeparator()) {
7521 		    saved++;
7522 		    tmpStack.push(undoable);
7523 		} else if (saved < max_stack_prune) {
7524 		    tmpStack.push(undoable);
7525 		} else {
7526 		    break;
7527 		}
7528 	    }
7529 	    while ((undoable=(UndoableAction*)this->undo_list.pop()))
7530 		delete undoable;
7531 
7532 	    while(undoable = (UndoableAction*)tmpStack.pop()) {
7533 		this->undo_list.push(undoable);
7534 	    }
7535 	}
7536 
7537 	undoable = (UndoableAction*)this->undo_list.peek();
7538 	const char* cp = undoable->getLabel();
7539 	strcat (button_label, " ");
7540 	strcat (button_label, cp);
7541 	this->undoCmd->activate();
7542     } else {
7543 	this->undoCmd->deactivate();
7544     }
7545     XmString xmstr = XmStringCreateLtoR (button_label, "bold");
7546     XtVaSetValues (this->undoOption->getRootWidget(), XmNlabelString, xmstr, NULL);
7547     XmStringFree(xmstr);
7548 }
7549 
KeyHandler(XEvent * event,void * clientData)7550 boolean EditorWindow::KeyHandler(XEvent *event, void *clientData)
7551 {
7552     EditorWindow *ew = (EditorWindow*)clientData;
7553     return ew->keyHandler(event);
7554 }
7555 
7556 #if !defined(XK_MISCELLANY)
7557 #define XK_MISCELLANY
7558 #endif
7559 #include <X11/keysym.h>
keyHandler(XEvent * event)7560 boolean EditorWindow::keyHandler(XEvent* event)
7561 {
7562     if (event->type != KeyPress) return TRUE;
7563 
7564     KeySym lookedup = XLookupKeysym(((XKeyEvent*)event), 0);
7565     if ((lookedup!=XK_End) && (lookedup!=XK_Page_Up) && (lookedup!=XK_Page_Down))
7566 	return TRUE;
7567 
7568     Widget ww = XtWindowToWidget(XtDisplay(this->getRootWidget()), event->xany.window);
7569     boolean is_descendant = FALSE;
7570     //
7571     // Choice of window is significant.  By using workArea, we're grabbing any
7572     // event that is in the vpe or tool selector.  I thought it would be OK
7573     // to get only the events inside the scrolledWindow however, the tool selector
7574     // crashes when given pg-up/pg-down also.  It would be nice if there were
7575     // a better way of computing ancestory.
7576     //
7577     // Window win = XtWindow(this->scrolledWindow);
7578     //
7579     Window win = XtWindow(this->workArea);
7580     while ((ww) && (!XtIsShell(ww))) {
7581 	if (XtWindow(ww) == win) {
7582 	    is_descendant = TRUE;
7583 	    break;
7584 	}
7585 	ww = XtParent(ww);
7586     }
7587     if (!is_descendant) return TRUE;
7588 
7589     XmScrolledWindowWidget scrollWindow;
7590     int xsize,xdelta,xpdelta,x;
7591     int ysize,ydelta,ypdelta,y;
7592 
7593     //
7594     // Here, it would be nice to fetch the vertical scrollbar's max value
7595     // and use that in the XK_End calculation, but that causes a core dump
7596     // inside  Motif the same way Page-Up/Page-Down do.
7597     //
7598     //int max;
7599     //XtVaGetValues ((Widget)scrollWindow->swindow.vScrollBar, XmNmaximum, &max, NULL);
7600 
7601     scrollWindow = (XmScrolledWindowWidget)this->getScrolledWindow();
7602     XmScrollBarGetValues((Widget)scrollWindow->swindow.hScrollBar,
7603 			 &x, &xsize, &xdelta, &xpdelta);
7604     XmScrollBarGetValues((Widget)scrollWindow->swindow.vScrollBar,
7605 			 &y, &ysize, &ydelta, &ypdelta);
7606     if (lookedup == XK_Page_Up) {
7607 	y-=ypdelta;
7608 	y=MAX(y,0);
7609     } else if (lookedup == XK_Page_Down) {
7610 	y+=ypdelta;
7611     } else if (lookedup == XK_End) {
7612 	//y = max-(ysize+1);
7613 	y+=2*ypdelta;
7614     }
7615     this->moveWorkspaceWindow(x,y,FALSE);
7616     return FALSE;
7617 }
7618 
saveAllLocationsForUndo(UndoableAction * gridding)7619 void  EditorWindow::saveAllLocationsForUndo (UndoableAction* gridding)
7620 {
7621     this->undo_list.push(new UndoSeparator(this));
7622     Node* n;
7623     ListIterator iterator;
7624     FOR_EACH_NETWORK_NODE(this->network, n, iterator) {
7625 	StandIn* si = n->getStandIn();
7626 	if (!si) continue;
7627 
7628 	this->undo_list.push ( new UndoStandInMove (
7629 		this, si, n->getNameString(), n->getInstanceNumber()
7630 	    )
7631 	);
7632     }
7633 
7634     Decorator* dec;
7635     FOR_EACH_NETWORK_DECORATOR(this->network, dec, iterator) {
7636 	if (dec->getRootWidget())
7637 	    this->undo_list.push (new UndoDecoratorMove (this, (VPEAnnotator*)dec));
7638     }
7639     this->undo_list.push(gridding);
7640 
7641     // this->setCommandActivation() doesn't run often enough to deal
7642     // with accelerators.
7643     if (!this->undoCmd->isActive())
7644 	this->setUndoActivation();
7645 }
7646