1 /***********************************************************************/
2 /* Open Visualization Data Explorer                                    */
3 /* (C) Copyright IBM Corp. 1989,1999                                   */
4 /* ALL RIGHTS RESERVED                                                 */
5 /* This code licensed under the                                        */
6 /*    "IBM PUBLIC LICENSE - Open Visualization Data Explorer"          */
7 /***********************************************************************/
8 
9 #include <dxconfig.h>
10 #include "../base/defines.h"
11 
12 
13 
14 
15 
16 #include <ctype.h>
17 #include <errno.h>
18 #include <string.h>
19 
20 #include <Xm/CascadeB.h>
21 #include <Xm/Form.h>
22 #include <Xm/Frame.h>
23 #include <Xm/List.h>
24 #include <Xm/RowColumn.h>
25 #include <Xm/Separator.h>
26 
27 #include "DXStrings.h"
28 #include "MsgWin.h"
29 
30 #include "DXApplication.h"
31 #include "ButtonInterface.h"
32 #include "EditorWindow.h"
33 #include "ErrorDialogManager.h"
34 #include "QuestionDialogManager.h"
35 #include "ListIterator.h"
36 #include "MWClearCmd.h"
37 #include "MWFileDialog.h"
38 #include "ExecCommandDialog.h"
39 #include "Network.h"
40 #include "NoUndoMWCmd.h"
41 #include "ToggleButtonInterface.h"
42 #include "RepeatingToggle.h"
43 #include "DXPacketIF.h"
44 
45 #include "MWDefaultResources.h"
46 
47 boolean MsgWin::ClassInitialized = FALSE;
48 
49 //
50 // Constructor:
51 //
MsgWin()52 MsgWin::MsgWin(): DXWindow("messageWindow", FALSE)
53 {
54 
55     this->fileMenu = NULL;
56     this->editMenu = NULL;
57     this->executeMenu = NULL;
58     this->optionsMenu = NULL;
59     this->helpMenu = NULL;
60 
61     this->nextErrorOption =  NULL;
62     this->prevErrorOption =  NULL;
63     this->clearOption = NULL;
64     this->logOption = NULL;
65     this->saveOption = NULL;
66     this->closeOption = NULL;
67     this->infoOption = NULL;
68     this->warningOption = NULL;
69     this->errorOption = NULL;
70     this->execScriptOption = NULL;
71 
72     this->clearCmd = new MWClearCmd("clear", this->commandScope, FALSE, this);
73     this->logCmd   = new NoUndoMWCmd("log", this->commandScope, TRUE,
74 	this, NoUndoMWCmd::Log);
75     this->saveCmd  = new NoUndoMWCmd("save", this->commandScope, TRUE,
76 	this, NoUndoMWCmd::Save);
77     this->closeCmd = new NoUndoMWCmd("close", this->commandScope, TRUE,
78 	this, NoUndoMWCmd::Close);
79     this->nextErrorCmd = new NoUndoMWCmd("nextError", this->commandScope, TRUE,
80 	this, NoUndoMWCmd::NextError);
81     this->prevErrorCmd = new NoUndoMWCmd("prevError", this->commandScope, TRUE,
82 	this, NoUndoMWCmd::PrevError);
83 
84     if (theDXApplication->appAllowsScriptCommands()) {
85 	this->execScriptCmd = new NoUndoMWCmd("execScript", this->commandScope,
86     			theDXApplication->disconnectFromServerCmd->isActive(),
87 			this, NoUndoMWCmd::ExecScript);
88 
89 	theDXApplication->connectedToServerCmd->autoActivate(this->execScriptCmd);
90 	theDXApplication->disconnectedFromServerCmd->autoDeactivate(this->execScriptCmd);
91 
92 	this->traceCmd = new NoUndoMWCmd ("traceOn", this->commandScope,
93 	    TRUE, this, NoUndoMWCmd::Tracing);
94 #if 0
95 	theDXApplication->connectedToServerCmd->autoActivate(this->traceCmd);
96 #endif
97 
98 	this->memoryCmd = new NoUndoMWCmd ("memory", this->commandScope,
99 	    FALSE, this, NoUndoMWCmd::Memory);
100 	theDXApplication->connectedToServerCmd->autoActivate(this->memoryCmd);
101 	theDXApplication->disconnectedFromServerCmd->autoDeactivate(this->memoryCmd);
102     } else {
103 	this->execScriptCmd = NULL;
104 	this->traceCmd = NUL(Command*);
105 	this->memoryCmd = NUL(Command*);
106     }
107 
108     this->intervalId = 0;
109     this->firstMsg   = FALSE;
110     this->executing  = FALSE;
111     this->beenManaged= FALSE;
112 
113     this->logFile    = NULL;
114     this->saveDialog = NULL;
115     this->logDialog  = NULL;
116     this->execCommandDialog = NULL;
117 
118 
119     //
120     // Install the default resources for THIS class (not the derived classes)
121     //
122     if (NOT MsgWin::ClassInitialized)
123     {
124 	ASSERT(theApplication);
125         MsgWin::ClassInitialized = TRUE;
126 	this->installDefaultResources(theApplication->getRootWidget());
127     }
128 }
129 //
130 // Destructor:
131 //
~MsgWin()132 MsgWin::~MsgWin()
133 {
134     this->clear();
135 
136     if (this->nextErrorOption)
137     	delete this->nextErrorOption;
138     if (this->prevErrorOption)
139     	delete this->prevErrorOption;
140     if (this->clearOption)
141     	delete this->clearOption;
142     if (this->logOption)
143     	delete this->logOption;
144     if (this->saveOption)
145     	delete this->saveOption;
146     if (this->closeOption)
147     	delete this->closeOption;
148     if (this->infoOption)
149     	delete this->infoOption;
150     if (this->warningOption)
151     	delete this->warningOption;
152     if (this->errorOption)
153     	delete this->errorOption;
154     if (this->execScriptOption)
155     	delete this->execScriptOption;
156 
157     delete this->clearCmd;
158     delete this->logCmd;
159     delete this->saveCmd;
160     delete this->closeCmd;
161     delete this->nextErrorCmd;
162     delete this->prevErrorCmd;
163     if (this->execScriptCmd)
164         delete this->execScriptCmd;
165     if (this->traceCmd)
166 	delete this->traceCmd;
167     if (this->memoryCmd)
168 	delete this->memoryCmd;
169 
170 
171     //
172     // for now, logDialog and fileDialog are the same.
173     //
174     if (this->logDialog)
175 	delete this->logDialog;
176 
177     if (this->execCommandDialog)
178 	delete this->execCommandDialog;
179 }
180 
181 
182 //
183 // Install the default resources for this class.
184 //
installDefaultResources(Widget baseWidget)185 void MsgWin::installDefaultResources(Widget baseWidget)
186 {
187     this->setDefaultResources(baseWidget, MsgWin::DefaultResources);
188     this->DXWindow::installDefaultResources(baseWidget);
189 }
190 
manage()191 void MsgWin::manage()
192 {
193     this->beenManaged = TRUE;
194     this->DXWindow::manage();
195 }
196 
createMenus(Widget parent)197 void MsgWin::createMenus(Widget parent)
198 {
199     this->createFileMenu(parent);
200     this->createEditMenu(parent);
201     this->createExecuteMenu(parent);
202     if (theDXApplication->appAllowsScriptCommands())
203 	this->createCommandsMenu(parent);
204     this->createOptionsMenu(parent);
205     this->createHelpMenu(parent);
206 
207     //
208     // Right justify the help menu (if it exists).
209     //
210     if (this->helpMenu)
211     {
212         XtVaSetValues(parent, XmNmenuHelpWidget, this->helpMenu, NULL);
213     }
214 }
createFileMenu(Widget parent)215 void MsgWin::createFileMenu(Widget parent)
216 {
217     ASSERT(parent);
218 
219     //
220     // Create "File" menu and options.
221     //
222     Widget pulldown =
223 	this->fileMenuPulldown =
224 	    XmCreatePulldownMenu(parent, "fileMenuPulldown", NUL(ArgList), 0);
225     this->fileMenu =
226 	XtVaCreateManagedWidget
227 	    ("fileMenu",
228 	     xmCascadeButtonWidgetClass,
229 	     parent,
230 	     XmNsubMenuId, pulldown,
231 	     NULL);
232 
233     this->logOption = new ToggleButtonInterface(pulldown, "msgLogOption",
234 	this->logCmd, this->logFile != NULL);
235     this->saveOption = new ButtonInterface(pulldown, "msgSaveOption",
236 	this->saveCmd);
237 
238     XtVaCreateManagedWidget
239 	    ("fileSeparator", xmSeparatorWidgetClass, pulldown, NULL);
240 
241     this->closeOption = new ButtonInterface(pulldown, "msgCloseOption",
242 	this->closeCmd);
243 }
244 
createEditMenu(Widget parent)245 void MsgWin::createEditMenu(Widget parent)
246 {
247     ASSERT(parent);
248 
249     //
250     // Create "File" menu and options.
251     //
252     Widget pulldown =
253 	this->editMenuPulldown =
254 	    XmCreatePulldownMenu(parent, "editMenuPulldown", NUL(ArgList), 0);
255     this->editMenu =
256 	XtVaCreateManagedWidget
257 	    ("editMenu",
258 	     xmCascadeButtonWidgetClass,
259 	     parent,
260 	     XmNsubMenuId, pulldown,
261 	     NULL);
262 
263     this->nextErrorOption =
264 		new ButtonInterface(pulldown,
265 			"msgNextErrorOption", this->nextErrorCmd);
266     this->prevErrorOption =
267 		new ButtonInterface(pulldown,
268 			"msgPrevErrorOption", this->prevErrorCmd);
269 
270     XtVaCreateManagedWidget
271 	    ("editSeparator", xmSeparatorWidgetClass, pulldown, NULL);
272 
273     this->clearOption = new ButtonInterface(pulldown, "msgClearOption",
274 	this->clearCmd);
275 
276 }
277 
createCommandsMenu(Widget parent)278 void MsgWin::createCommandsMenu(Widget parent)
279 {
280     ASSERT(parent);
281     if ((!this->traceCmd) && (!this->execScriptCmd) && (!this->memoryCmd)) return ;
282 
283     Widget pulldown = this->optionsMenuPulldown =
284 	XmCreatePulldownMenu(parent, "commandsMenuPulldown", NUL(ArgList), 0);
285     this->commandsMenu =
286 	XtVaCreateManagedWidget
287 	    ("commandsMenu",
288 	     xmCascadeButtonWidgetClass,
289 	     parent,
290 	     XmNsubMenuId, pulldown,
291 	     NULL);
292 
293     if (this->traceCmd)
294 	this->traceOption = new RepeatingToggle (pulldown, "msgTraceOption",
295 	    this->traceCmd, theDXApplication->showInstanceNumbers());
296 
297     if (this->execScriptCmd)
298 	this->execScriptOption = new ButtonInterface(pulldown,
299 	    "msgExecScriptOption", this->execScriptCmd);
300 
301     if (this->memoryCmd)
302 	this->memoryOption = new ButtonInterface (pulldown,
303 	    "msgShowMemoryOption", this->memoryCmd);
304 }
305 
createOptionsMenu(Widget parent)306 void MsgWin::createOptionsMenu(Widget parent)
307 {
308     ASSERT(parent);
309 
310     //
311     // Create "File" menu and options.
312     //
313     Widget pulldown = this->optionsMenuPulldown =
314 	XmCreatePulldownMenu(parent, "optionsMenuPulldown", NUL(ArgList), 0);
315     this->optionsMenu =
316 	XtVaCreateManagedWidget
317 	    ("optionsMenu",
318 	     xmCascadeButtonWidgetClass,
319 	     parent,
320 	     XmNsubMenuId, pulldown,
321 	     NULL);
322 
323     if (theDXApplication->appAllowsMessageInfoOption())
324 	this->infoOption = new ToggleButtonInterface(pulldown,
325 		"msgInfoOption", theDXApplication->toggleInfoEnable,
326 		theDXApplication->isInfoEnabled());
327 
328     if (theDXApplication->appAllowsMessageWarningOption())
329 	this->warningOption = new ToggleButtonInterface(pulldown,
330 		"msgWarningOption", theDXApplication->toggleWarningEnable,
331 		theDXApplication->isWarningEnabled());
332 
333     this->errorOption = new ToggleButtonInterface(pulldown, "msgErrorOption",
334 	theDXApplication->toggleErrorEnable, theDXApplication->isErrorEnabled());
335 }
336 
createWorkArea(Widget parent)337 Widget MsgWin::createWorkArea(Widget parent)
338 {
339     Widget top = XtVaCreateManagedWidget(
340 	"workAreaFrame", xmFrameWidgetClass, parent,
341 	XmNshadowType,		XmSHADOW_OUT,
342 	XmNmarginWidth,		5,
343 	XmNmarginHeight,	5,
344 	NULL);
345 
346     Widget form = XtVaCreateManagedWidget(
347 	"workArea", xmFormWidgetClass, top,
348 	NULL);
349 
350     Widget frame = XtVaCreateManagedWidget(
351 	"msgFrame", xmFrameWidgetClass, form,
352 	XmNtopAttachment,	XmATTACH_FORM,
353 	XmNbottomAttachment,	XmATTACH_FORM,
354 	XmNleftAttachment,	XmATTACH_FORM,
355 	XmNrightAttachment,	XmATTACH_FORM,
356 	NULL);
357 
358     Arg arg[10];
359     XtSetArg(arg[0], XmNlistSizePolicy, XmCONSTANT);
360     XtSetArg(arg[1], XmNselectionPolicy, XmSINGLE_SELECT);
361     this->list = XmCreateScrolledList(frame, "msgList", arg, 2);
362     this->installComponentHelpCallback(this->list);
363     XtAddCallback(this->list,
364 		  XmNsingleSelectionCallback,
365 		  (XtCallbackProc)MsgWin_SelectCB,
366 		  (XtPointer)this);
367 
368     XtManageChild(this->list);
369 
370     return top;
371 }
372 
addInformation(const char * info)373 void MsgWin::addInformation(const char *info)
374 {
375     ASSERT(info);
376     if (!this->isInitialized())
377 	this->initialize();
378     if (!theDXApplication->isInfoEnabled())
379 	return;
380 
381     if (!info)
382 	return;
383 
384     const char *newLine = strchr(info, '\n');
385     char *s = NULL;
386     if (newLine)
387     {
388 	s = DuplicateString(info);
389 	s[newLine - info] = '\0';
390 	info = s;
391     }
392 
393 
394     if (executing)
395     {
396 	if (this->intervalId == 0)
397 	    this->intervalId = XtAppAddTimeOut(
398 		theApplication->getApplicationContext(),
399 		5000,
400 		(XtTimerCallbackProc)MsgWin_FlushTimeoutTO,
401 		(XtPointer)this);
402 	if (this->firstMsg)
403 	{
404 	    this->firstMsg = FALSE;
405 	    if (this->logFile)
406 	    {
407 		fputs("Begin Execution\n", this->logFile);
408 		fflush(this->logFile);
409 	    }
410 	    XmString s = XmStringCreate("Begin Execution", "oblique");
411 	    XmListAddItemUnselected(this->list, s, 0);
412 	    XmStringFree(s);
413 	    int itemCount;
414 	    XtVaGetValues(this->list, XmNitemCount, &itemCount, NULL);
415 	    XmListSetBottomPos(this->list, itemCount);
416 
417 	    this->clearCmd->activate();
418 	}
419 	int vic;
420 	XtVaGetValues(this->list, XmNvisibleItemCount, &vic, NULL);
421 	this->batchedLines.appendElement((void*)DuplicateString(info));
422 	if (vic <= this->batchedLines.getSize())
423 	    this->flushBuffer();
424     }
425     else
426     {
427 	if (this->logFile)
428 	{
429 	    fputs(info, this->logFile);
430 	    fputc('\n', this->logFile);
431 	    fflush(this->logFile);
432 	}
433 	XmString s = XmStringCreate((char*)info, "normal");
434 	XmListAddItemUnselected(this->list, s, 0);
435 	XmStringFree(s);
436 	int itemCount;
437 	XtVaGetValues(this->list, XmNitemCount, &itemCount, NULL);
438 	XmListSetBottomPos(this->list, itemCount);
439 
440 	this->clearCmd->activate();
441     }
442 
443     if (s != NULL)
444 	delete[] s;
445 
446     if (theDXApplication->doesInfoOpenMessage())
447     {
448 	if (!this->isManaged())
449 	    this->manage();
450     }
451 }
452 
infoOpen()453 void MsgWin::infoOpen()
454 {
455     if (!this->isInitialized())
456 	this->initialize();
457     if (!theDXApplication->isInfoEnabled())
458 	return;
459     if (!this->isManaged())
460 	this->manage();
461 }
462 
463 
addError(const char * error)464 void MsgWin::addError(const char *error)
465 {
466 	ASSERT(error);
467 	if (!theDXApplication->isErrorEnabled())
468 		return;
469 	if (!error)
470 		return;
471 	if (!this->isInitialized())
472 		this->initialize();
473 
474 	this->flushBuffer();
475 
476 	if (this->firstMsg)
477 	{
478 		this->firstMsg = FALSE;
479 		if (this->logFile)
480 		{
481 			fputs("Begin Execution\n", this->logFile);
482 			fflush(this->logFile);
483 		}
484 		XmString s = XmStringCreate("Begin Execution", "oblique");
485 		XmListAddItemUnselected(this->list, s, 0);
486 		XmStringFree(s);
487 		int itemCount;
488 		XtVaGetValues(this->list, XmNitemCount, &itemCount, NULL);
489 		XmListSetBottomPos(this->list, itemCount);
490 
491 		this->clearCmd->activate();
492 	}
493 
494 	//
495 	// Manage it before we save the error message, otherwise manage()
496 	// causes DXWindow::manage() to do a notify(BeginExecution) which clears
497 	// the list of lines.
498 	//
499 	if (theDXApplication->doesErrorOpenMessage() && !this->isManaged())
500 		this->manage();
501 
502 	//
503 	// If this is a module error, change the format and report it.
504 	//  0:  ERROR:  2::/main:0/Compute:0: Bad parameter: expression must be a string
505 	//
506 	char net[100];
507 	int  inst;
508 	const char *topNet = theDXApplication->network->getNameString();
509 	int l;
510 	if (sscanf(error, " %*d:  ERROR:  %*d::/%[^:]:%d/%n", net, &inst, &l) == 2 &&
511 		EqualString(net, topNet))
512 	{
513 		char *line = new char[STRLEN(error)+1];
514 		char *p = line;
515 		const char *o = error + l;
516 		boolean names = TRUE;
517 		boolean skipDigits = FALSE;
518 		boolean moreNames = TRUE;
519 		while(names && *o)
520 		{
521 			if (!skipDigits && *o == ':')
522 			{
523 				skipDigits = TRUE;
524 				if (moreNames)
525 				{
526 					*p++ = *o++;
527 					*p++ = ' ';
528 				}
529 				else
530 					o++;
531 			}
532 			else if (*o == '/')
533 			{
534 				skipDigits = FALSE;
535 				o++;
536 			}
537 			else if (skipDigits && isdigit(*o))
538 				o++;
539 			else if (skipDigits && *o == ':')
540 			{
541 				names = FALSE;
542 				o++;
543 			}
544 			else
545 			{
546 				const char *colon = strchr(o, ':');
547 				if (moreNames)
548 				{
549 					char modName[100];
550 					strncpy(modName, o, colon - o);
551 					modName[colon - o] = '\0';
552 					char netName[100];
553 					if (sscanf(modName, "%*[^_]_%[^_]_%*d", netName) == 1)
554 					{
555 						strcpy(p, netName);
556 						p += STRLEN(netName);
557 						*p++ = ':';
558 						moreNames = FALSE;
559 					}
560 					else
561 					{
562 						strncpy(p, modName, colon-o);
563 						p += colon-o;
564 					}
565 				}
566 				o = colon;
567 			}
568 		}
569 		*p = '\0';
570 
571 		if (this->logFile)
572 		{
573 			fputs("ERROR: ", this->logFile);
574 			fputs(line, this->logFile);
575 			fputs(o, this->logFile);
576 			fputc('\n', this->logFile);
577 		}
578 		XmString errorString = XmStringCreate("ERROR: ", "bold");
579 		XmString nameString = XmStringCreate((char*)line, "bold");
580 		XmString text = XmStringCreate((char*)o, "oblique");
581 		XmString firstHalf = XmStringConcat(errorString, nameString);
582 		XmString s = XmStringConcat(firstHalf, text);
583 		XmStringFree(errorString);
584 		XmStringFree(nameString);
585 		XmStringFree(firstHalf);
586 		XmStringFree(text);
587 		delete[] line;
588 
589 		XmListAddItemUnselected(this->list, s, 0);
590 		XmStringFree(s);
591 		int itemCount;
592 		XtVaGetValues(this->list, XmNitemCount, &itemCount, NULL);
593 		XmListSetBottomPos(this->list, itemCount);
594 
595 		this->clearCmd->activate();
596 
597 		SelectableLine *l = new SelectableLine;
598 		XtVaGetValues(this->list, XmNitemCount, &l->position, NULL);
599 		l->line = DuplicateString(error);
600 		this->selectableLines.appendElement((void*)l);
601 	}
602 	else
603 	{
604 		if (this->logFile)
605 		{
606 			fputs(error, this->logFile);
607 			fputc('\n', this->logFile);
608 		}
609 		XmString s = XmStringCreate((char*)error, "bold");
610 
611 		XmListAddItemUnselected(this->list, s, 0);
612 		XmStringFree(s);
613 		int itemCount;
614 		XtVaGetValues(this->list, XmNitemCount, &itemCount, NULL);
615 		XmListSetBottomPos(this->list, itemCount);
616 
617 		this->clearCmd->activate();
618 	}
619 	if (theDXApplication->doesErrorOpenMessage())
620 	{
621 		if (!this->beenBeeped)
622 		{
623 			XBell(XtDisplay(this->getRootWidget()), 0);
624 			XFlush(XtDisplay(this->getRootWidget()));
625 			this->beenBeeped = TRUE;
626 		}
627 		if (!this->isManaged())
628 			this->manage();
629 		else
630 			XRaiseWindow(XtDisplay(this->getRootWidget()),
631 			XtWindow(this->getRootWidget()));
632 	}
633 
634 }
addWarning(const char * warning)635 void MsgWin::addWarning(const char *warning)
636 {
637     ASSERT(warning);
638     if (!theDXApplication->isWarningEnabled())
639 	return;
640     if (!this->isInitialized())
641 	this->initialize();
642     if (!warning)
643 	return;
644 
645     this->flushBuffer();
646 
647     if (this->firstMsg)
648     {
649 	this->firstMsg = FALSE;
650 	if (this->logFile)
651 	{
652 	    fputs("Begin Execution\n", this->logFile);
653 	    fflush(this->logFile);
654 	}
655 	XmString s = XmStringCreate("Begin Execution", "oblique");
656 	XmListAddItemUnselected(this->list, s, 0);
657 	XmStringFree(s);
658 	int itemCount;
659 	XtVaGetValues(this->list, XmNitemCount, &itemCount, NULL);
660 	XmListSetBottomPos(this->list, itemCount);
661 
662 	this->clearCmd->activate();
663     }
664 
665     if (this->logFile)
666     {
667 	fputs(warning, this->logFile);
668 	fputc('\n', this->logFile);
669 	fflush(this->logFile);
670     }
671     XmString s = XmStringCreate((char*)warning, "normal");
672     XmListAddItemUnselected(this->list, s, 0);
673     XmStringFree(s);
674     int itemCount;
675     XtVaGetValues(this->list, XmNitemCount, &itemCount, NULL);
676     XmListSetBottomPos(this->list, itemCount);
677 
678     if (theDXApplication->doesWarningOpenMessage())
679     {
680 	if (!this->isManaged())
681 	    this->manage();
682 	else
683 	    XRaiseWindow(XtDisplay(this->getRootWidget()),
684 		   XtWindow(this->getRootWidget()));
685     }
686 }
687 
beginExecution()688 void MsgWin::beginExecution()
689 {
690     this->DXWindow::beginExecution();
691 
692     this->firstMsg  = TRUE;
693     this->executing = TRUE;
694     this->beenBeeped = FALSE;
695 
696     this->clearSelectableLines();
697 }
698 
clearSelectableLines()699 void MsgWin::clearSelectableLines()
700 {
701     ListIterator li(this->selectableLines);
702     SelectableLine *l;
703     while( (l = (SelectableLine*)li.getNext()) )
704     {
705 	delete[] l->line;
706 	delete l;
707     }
708     this->selectableLines.clear();
709     // XmListDeselectAllItems(this->list);
710 }
711 
endExecution()712 void MsgWin::endExecution()
713 {
714     this->DXWindow::endExecution();
715 
716     this->executing = FALSE;
717     this->flushBuffer();
718 
719     if (this->selectableLines.getSize() > 0)
720     {
721 	this->findNextError(FALSE);
722 	this->nextErrorCmd->activate();
723 	this->prevErrorCmd->activate();
724     }
725     else
726     {
727 	this->nextErrorCmd->deactivate();
728 	this->prevErrorCmd->deactivate();
729     }
730 }
731 
standBy()732 void MsgWin::standBy()
733 {
734     this->DXWindow::standBy();
735 
736     this->executing = FALSE;
737     this->flushBuffer();
738 
739     if (this->selectableLines.getSize() > 0)
740     {
741 	this->findNextError(FALSE);
742 	this->nextErrorCmd->activate();
743 	this->prevErrorCmd->activate();
744     }
745     else
746     {
747 	this->nextErrorCmd->deactivate();
748 	this->prevErrorCmd->deactivate();
749     }
750 }
751 
MsgWin_FlushTimeoutTO(XtPointer closure,XtIntervalId *)752 extern "C" void MsgWin_FlushTimeoutTO(XtPointer closure, XtIntervalId*)
753 {
754     MsgWin *mw = (MsgWin*) closure;
755 
756     mw->intervalId = 0;
757     mw->flushBuffer();
758 }
flushBuffer()759 void MsgWin::flushBuffer()
760 {
761     int nItems = this->batchedLines.getSize();
762     if (nItems == 0)
763 	return;
764 
765     XmString *items = new XmString[nItems];
766     ListIterator li(this->batchedLines);
767     char *s;
768     int i;
769     for (i = 0; i < nItems && (s = (char*)li.getNext()); ++i)
770     {
771 	if (this->logFile)
772 	{
773 	    fputs(s, this->logFile);
774 	    fputc('\n', this->logFile);
775 	}
776 	items[i] = XmStringCreate(s, "normal");
777 	delete[] s;
778     }
779 
780     XmListAddItems(this->list, items, nItems, 0);
781 
782     if (this->logFile)
783 	fflush(this->logFile);
784 
785     int itemCount;
786     XtVaGetValues(this->list, XmNitemCount, &itemCount, NULL);
787     XmListSetBottomPos(this->list, itemCount);
788 
789     for (i = 0; i < nItems; ++i)
790 	XmStringFree(items[i]);
791     delete[] items;
792 
793     this->batchedLines.clear();
794 
795     if (this->intervalId)
796     {
797 	XtRemoveTimeOut(this->intervalId);
798 	this->intervalId = 0;
799     }
800 
801     this->clearCmd->activate();
802 }
803 
clear()804 boolean MsgWin::clear()
805 {
806     this->flushBuffer();
807     if (this->intervalId)
808     {
809 	XtRemoveTimeOut(this->intervalId);
810 	this->intervalId = 0;
811     }
812 
813     int nItems = this->batchedLines.getSize();
814     char *s;
815     ListIterator li(this->batchedLines);
816     for (int i = 0; i < nItems && (s = (char*)li.getNext()); ++i)
817 	delete[] s;
818     this->batchedLines.clear();
819 
820     this->clearSelectableLines();
821 
822     XmListDeleteAllItems(this->list);
823 
824     this->clearCmd->deactivate();
825     this->beenBeeped = FALSE;
826 
827     return TRUE;
828 }
829 
log(const char * file)830 boolean MsgWin::log(const char *file)
831 {
832     this->flushBuffer();
833     if (file == NULL && this->logFile)
834     {
835 	fclose(this->logFile);
836 	delete[] this->logFileName;
837 	this->logFile = NULL;
838 	this->logFileName = NULL;
839 	this->logOption->setState(FALSE);
840     }
841     else
842     {
843 	if (this->logFile)
844 	{
845 	    fclose(this->logFile);
846 	    delete[] this->logFileName;
847 	}
848 	this->logFile = fopen(file, "w");
849 	if (this->logFile == NULL)
850 	{
851 	    ErrorMessage("Failed to open %s: %s", file, strerror(errno));
852 	    this->logFileName = NULL;
853 	    this->logOption->setState(FALSE);
854 	    return FALSE;
855 	}
856 	this->logFileName = DuplicateString(file);
857 	this->logOption->setState(TRUE);
858     }
859 
860     return TRUE;
861 }
862 
save(const char * file)863 boolean MsgWin::save(const char *file)
864 {
865     if (file)
866     {
867 	FILE *f = fopen(file, "w");
868 	if (f == NULL)
869 	{
870 	    ErrorMessage("Failed to open %s: %s", file, strerror(errno));
871 	    return FALSE;
872 	}
873 	int itemCount;
874 	XmStringTable items;
875 	XtVaGetValues(this->list,
876 	    XmNitemCount, &itemCount,
877 	    XmNitems, &items,
878 	    NULL);
879 
880 	for (int i = 0; i < itemCount; ++i)
881 	{
882 	    XmStringContext context;
883 	    if (!XmStringInitContext(&context, items[i]))
884 		continue;
885 	    XmStringCharSet tag;
886 	    XmStringDirection dir;
887 	    Boolean separator;
888 	    char *s;
889 	    while (XmStringGetNextSegment(context, &s, &tag, &dir, &separator))
890 	    {
891 		fputs(s, f);
892 		XtFree(s);
893 	    }
894 	    fputc('\n', f);
895 	}
896 
897 	fclose(f);
898     }
899 
900     return TRUE;
901 }
902 
postExecCommandDialog()903 void MsgWin::postExecCommandDialog()
904 {
905     if (!this->execCommandDialog)
906 	this->execCommandDialog =
907 	    new ExecCommandDialog(this->getRootWidget());
908     this->execCommandDialog->post();
909 }
910 
postLogDialog()911 void MsgWin::postLogDialog()
912 {
913     if (!this->logDialog)
914 	this->logDialog = this->saveDialog =
915 	    new MWFileDialog(this->getRootWidget(), this);
916     this->logDialog->postAs(TRUE);
917 }
918 
postSaveDialog()919 void MsgWin::postSaveDialog()
920 {
921     if (!this->logDialog)
922 	this->logDialog = this->saveDialog =
923 	    new MWFileDialog(this->getRootWidget(), this);
924     this->logDialog->postAs(FALSE);
925 }
926 
MsgWin_SelectCB(Widget w,XtPointer closure,XtPointer callData)927 extern "C" void MsgWin_SelectCB(Widget w, XtPointer closure, XtPointer callData)
928 {
929     MsgWin *mw = (MsgWin*)closure;
930     XmListCallbackStruct *l = (XmListCallbackStruct*)callData;
931 
932     ASSERT(l->reason == XmCR_SINGLE_SELECT);
933 
934 
935     //
936     // An attempt to avoid nagging the user...   if doesErrorOpenVpe() ==
937     // DXApplication::MayOpenVpe then selectLine() will check this extra
938     // param to see if it should prompt the user.  I would like to prompt only
939     // in certain circumstances to avoid nagging.
940     //
941     boolean prompt = TRUE;
942 #if 0
943     if (l->event) {
944 	if ((l->event->type == ButtonPress) ||
945 	    (l->event->type == ButtonRelease) ||
946 	    (l->event->type == KeyPress) ||
947 	    (l->event->type == KeyRelease)) {
948 	    if (l->event->xany.window == XtWindow(w)) {
949 		prompt = FALSE;
950 	    }
951 	}
952     }
953 #endif
954     mw->selectLine(l->item_position, prompt);
955 }
956 
957 
selectLine(int pos,boolean promptUser)958 void MsgWin::selectLine(int pos, boolean promptUser)
959 {
960     ListIterator li(this->selectableLines);
961     SelectableLine *l;
962     boolean questionPosted = FALSE;
963 
964     while( (l = (SelectableLine*)li.getNext()) )
965     {
966 	if (l->position == pos)
967 	{
968 	    break;
969 	}
970     }
971     if (l == NULL)
972 	return;
973 
974     //  0:  ERROR:  2::/main:0/Compute:0: Bad parameter: expression must be a string
975     char netName[100];
976     char nodeName[100];
977     int  inst;
978     int  len;
979     Network *net = NULL;
980 
981     //
982     // For each macro (denoted by the /macroname:digit/ sequence),
983     // find it in the net's editor (if there is either a net or an instance),
984     // and look up the net.
985     const char *line = strchr(l->line, '/');
986     char c;
987     ASSERT(line);
988     while (sscanf(line, "/%[^:]:%d%n%c", netName, &inst, &len, &c) == 3 &&
989 	c == '/')
990     {
991 	if (net)
992 	{
993 	    // Handle "main_Image_3" style macro names.
994 	    char prefix[100];
995 	    if (sscanf(netName, "%[^_]_%[^_]_%*d", prefix, nodeName) == 2 &&
996 		    EqualString(prefix, net->getNameString()))
997 	    {
998 		strcpy(netName, nodeName);
999 		break;
1000 	    }
1001 
1002 	    questionPosted = this->openEditorIfNecessary(net,netName,inst,
1003 						promptUser);
1004 	}
1005 	if (EqualString(netName, theDXApplication->network->getNameString()))
1006 	    net = theDXApplication->network;
1007 	else
1008 	{
1009 	    net = NULL;
1010 	    Network *macro;
1011 	    li.setList(theDXApplication->macroList);
1012 	    while( (macro = (Network*)li.getNext()) )
1013 		if (EqualString(netName, macro->getNameString()))
1014 		    net = macro;
1015 	    if (net == NULL)
1016 		break;
1017 	}
1018 	line += len;
1019     }
1020     //
1021     // Handle the module at the end, which may be an Image.
1022     //
1023     if (sscanf(line, "/%[^:]:%d%n%c", netName, &inst, &len, &c) == 3 &&
1024 	(c == ':' || c == '/'))
1025     {
1026 	if (net)
1027 	{
1028 	    // Handle "main_Image_3" style macro names.
1029 	    char prefix[100];
1030 	    if (sscanf(netName, "%[^_]_%[^_]_%*d", prefix, nodeName) == 2 &&
1031 		    EqualString(prefix, net->getNameString()))
1032 		strcpy(netName, nodeName);
1033 
1034 	    questionPosted |=
1035 			this->openEditorIfNecessary(net,netName,inst,
1036 						promptUser);
1037 
1038 	}
1039     }
1040 
1041     //
1042     // Raise this window above the editors that were just raised
1043     //
1044     if (theDXApplication->doesErrorOpenMessage()) {
1045         if (!this->isManaged())
1046             this->manage();
1047             //
1048             // If we have put a question dialog, then it might be nice to
1049 	    // leave it on top instead of the MsgWin.
1050             //
1051         else if (!questionPosted)
1052             XRaiseWindow(XtDisplay(this->getRootWidget()),
1053                XtWindow(this->getRootWidget()));
1054     }
1055 
1056 }
1057 
1058 //
1059 // Make a tiny class for passing the editor window info to some
1060 // static callbacks.  Martin added this (mid Oct. 1995) in order to
1061 // provide the ability to abort opening a vpe on error. That process can
1062 // be very slow for huge nets.  You cannot use
1063 // theQuestionDialogManager->userQuery() inside selectLine because selectLine()
1064 // is called by notify() and you must not cause any sort of heavily modal
1065 // pause inside notify() because {un}greening is happening.
1066 //
1067 class EdInfo {
1068     public:
1069 	char 		*nodeName;
1070 	Network 	*net;
1071 	int 		inst;
1072 	EditorWindow 	*editor;
1073 
EdInfo(const char * nodeName,Network * net,EditorWindow * e,int inst)1074 	EdInfo (const char *nodeName, Network *net, EditorWindow *e, int inst) {
1075 	    this->nodeName= DuplicateString(nodeName);
1076 	    this->net = net;
1077 	    this->editor = e;
1078 	    this->inst = inst;
1079 	};
~EdInfo()1080 	~EdInfo () {
1081 	    if (this->nodeName) delete[] this->nodeName;
1082 	};
1083 };
1084 //
1085 // If there is an editor opened on the net, or if there is a resource
1086 // in DXApplication which says to open an editor on the net...
1087 // If the resource says NEVER but the window is already opened, then
1088 // ignore the resource.
1089 // If the application indicates we should prompt the user and the promptUser
1090 // flag is set, then prompt the user with a Yes/No dialog about opening
1091 // the editor.
1092 //
1093 // Return TRUE, if we posted a dialog to ask the user if we should post
1094 // the window.
1095 //
openEditorIfNecessary(Network * net,const char * nodeName,int inst,boolean promptUser)1096 boolean MsgWin::openEditorIfNecessary(Network *net,
1097 				const char *nodeName, int inst,
1098 				boolean promptUser)
1099 {
1100     EditorWindow *e = net->getEditor();
1101     EdInfo *edinfo = new EdInfo (nodeName, net, e, inst);
1102     int show_status = theDXApplication->doesErrorOpenVpe(net);
1103     boolean questionPosted = FALSE;
1104 
1105     if (show_status == DXApplication::MustOpenVpe) {
1106 	MsgWin::ShowEditor((XtPointer)edinfo);
1107     } else if (show_status == DXApplication::DontOpenVpe) {
1108 	if (e && e->isManaged())
1109 	    MsgWin::ShowEditor((XtPointer)edinfo);
1110 	else
1111 	    MsgWin::NoShowEditor((XtPointer)edinfo);
1112     } else if (show_status == DXApplication::MayOpenVpe) {
1113 	if (e && e->isManaged())
1114 	    MsgWin::ShowEditor((XtPointer)edinfo);
1115 	else if (promptUser) {
1116 	    //
1117 	    // Must be FULL_APPLICATION_MODAL so that the user can't do
1118 	    // File/Open while the question dialog is on the screen.
1119 	    // Must also be a child of theDXApplication and not of
1120 	    // this becuase if you mwm dismiss the MsgWin then the
1121 	    // entire ui is hosed.
1122 	    //
1123 	    const char *macro = net->getNameString();
1124 	    const char *file = net->getFileName();
1125 	    char *confMsg = new char[32 + STRLEN(file) + STRLEN(macro)];
1126 	    sprintf (confMsg, "Open editor on %s (%s)?", macro, file);
1127 	    theQuestionDialogManager->modalPost(
1128 		theDXApplication->getAnchor()->getRootWidget(),
1129 		confMsg, "Open Editor Confirmation",
1130 		(void*)edinfo,
1131 		MsgWin::ShowEditor, MsgWin::NoShowEditor, NULL,
1132 		"Yes", "No", NULL,
1133 		XmDIALOG_FULL_APPLICATION_MODAL
1134 	    );
1135 	    delete[] confMsg;
1136 	    questionPosted = TRUE;
1137 	}
1138     }
1139 
1140     return questionPosted;
1141 }
1142 
ShowEditor(XtPointer cdata)1143 void MsgWin::ShowEditor (XtPointer cdata)
1144 {
1145     EdInfo *ei = (EdInfo*)cdata;
1146 
1147     if (ei->editor == NULL)
1148 	ei->editor = theDXApplication->newNetworkEditor(ei->net);
1149     //
1150     //  On the last tool, we open up containing editor for the user.
1151     //
1152     if (ei->editor) {
1153 	ei->editor->manage();
1154 	ei->editor->deselectAllNodes();
1155 	ei->editor->selectNode (ei->nodeName, ei->inst, TRUE);
1156     }
1157     delete ei;
1158 }
NoShowEditor(XtPointer cdata)1159 void MsgWin::NoShowEditor (XtPointer cdata)
1160 {
1161     EdInfo *ei = (EdInfo*)cdata;
1162 
1163     delete ei;
1164     Widget w = theQuestionDialogManager->getRootWidget();
1165     if ((w) && (XtIsManaged(w))) XtUnmanageChild (w);
1166 }
1167 
1168 //
1169 // callers are: a menu bar button, and endExecution (which happens quite often
1170 // including during File/New, File/Open).  For the menu bar button, we cycle thru
1171 // error messages ad infinitum.  For internal use we want to visit each member of
1172 // the list at most once.  So if activateSameSelection==FALSE, then don't reset
1173 // pos=0 and do another loop over all selections.
1174 //
findNextError(boolean activateSameSelection)1175 void MsgWin::findNextError(boolean activateSameSelection)
1176 {
1177     int *positions;
1178     int npos;
1179     int pos;
1180     int itemCount;
1181     int topItem;
1182     int visibleItems;
1183 
1184     XtVaGetValues(this->list,
1185 	XmNitemCount, &itemCount,
1186 	XmNtopItemPosition, &topItem,
1187 	XmNvisibleItemCount, &visibleItems,
1188 	NULL);
1189 
1190     if (XmListGetSelectedPos(this->list, &positions, &npos))
1191     {
1192 	pos = positions[npos-1];
1193 	XtFree((char*)positions);
1194     }
1195     else
1196     {
1197 	pos = 0;
1198     }
1199 
1200     ListIterator li(this->selectableLines);
1201     SelectableLine *s;
1202     boolean found = FALSE;
1203     while( (s = (SelectableLine*)li.getNext()) )
1204     {
1205 	if (s->position > pos)
1206 	{
1207 	    found = TRUE;
1208 	    XmListSelectPos(this->list, s->position, True);
1209 	    if (s->position < topItem || s->position >= topItem + visibleItems)
1210 		XmListSetBottomPos(this->list, s->position);
1211 	    break;
1212 	}
1213     }
1214     if ((!found) && (activateSameSelection))
1215     {
1216 	li.setPosition(1);
1217 	pos = 0;
1218 	while( (s = (SelectableLine*)li.getNext()) )
1219 	{
1220 	    if (s->position > pos)
1221 	    {
1222 		found = TRUE;
1223 		XmListSelectPos(this->list, s->position, True);
1224 		if (s->position < topItem ||
1225 			s->position >= topItem + visibleItems)
1226 		    XmListSetBottomPos(this->list, s->position);
1227 		break;
1228 	    }
1229 	}
1230     }
1231 }
1232 
findPrevError()1233 void MsgWin::findPrevError()
1234 {
1235     int *positions;
1236     int npos;
1237     int pos;
1238     int itemCount;
1239     int topItem;
1240     int visibleItems;
1241     XtVaGetValues(this->list,
1242 	XmNitemCount, &itemCount,
1243 	XmNtopItemPosition, &topItem,
1244 	XmNvisibleItemCount, &visibleItems,
1245 	NULL);
1246     if (XmListGetSelectedPos(this->list, &positions, &npos))
1247     {
1248 	pos = positions[npos-1];
1249 	XtFree((char*)positions);
1250     }
1251     else
1252     {
1253 	pos = itemCount + 1;
1254     }
1255 
1256     int i = this->selectableLines.getSize();
1257     SelectableLine *s;
1258     boolean found = FALSE;
1259     for (; i > 0 && (s = (SelectableLine*)this->selectableLines.getElement(i));
1260 	 --i)
1261     {
1262 	if (s->position < pos)
1263 	{
1264 	    found = TRUE;
1265 	    XmListSelectPos(this->list, s->position, True);
1266 	    if (s->position < topItem || s->position >= topItem + visibleItems)
1267 		XmListSetBottomPos(this->list, s->position);
1268 	    break;
1269 	}
1270     }
1271     if (!found)
1272     {
1273 	i = this->selectableLines.getSize();
1274 	pos = itemCount + 1;
1275 	for (; i > 0 &&
1276 		(s = (SelectableLine*)this->selectableLines.getElement(i));
1277 	     --i)
1278 	{
1279 	    if (s->position < pos)
1280 	    {
1281 		found = TRUE;
1282 		XmListSelectPos(this->list, s->position, True);
1283 		if (s->position < topItem ||
1284 			s->position >= topItem + visibleItems)
1285 		    XmListSetBottomPos(this->list, s->position);
1286 		break;
1287 	    }
1288 	}
1289     }
1290 }
1291 
1292 
1293 
toggleTracing()1294 boolean MsgWin::toggleTracing()
1295 {
1296 boolean on_or_off = this->traceOption->getState();
1297 const char *cmd = (on_or_off? "Trace(\"0\",1);\n" : "Trace(\"0\", 0);\n" );
1298 
1299     //
1300     // Issue the script command
1301     //
1302     DXPacketIF *p = theDXApplication->getPacketIF();
1303     if (p) {
1304 	theDXApplication->getMessageWindow()->addInformation(cmd);
1305 	p->send(DXPacketIF::FOREGROUND, cmd);
1306 	theDXApplication->showInstanceNumbers(on_or_off);
1307 	return TRUE;
1308     } else {
1309 	theDXApplication->showInstanceNumbers(on_or_off);
1310 	return FALSE;
1311     }
1312 }
1313 
memoryUse()1314 boolean MsgWin::memoryUse()
1315 {
1316     //
1317     // Issue the script command
1318     //
1319     char *cmd = "Usage(\"memory\",0);\n";
1320     DXPacketIF *p = theDXApplication->getPacketIF();
1321     if (p) {
1322 	theDXApplication->getMessageWindow()->addInformation(cmd);
1323 	p->send(DXPacketIF::FOREGROUND, cmd);
1324 	return TRUE;
1325     }
1326 
1327     return FALSE;
1328 }
1329