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