/***********************************************************************/ /* Open Visualization Data Explorer */ /* (C) Copyright IBM Corp. 1989,1999 */ /* ALL RIGHTS RESERVED */ /* This code licensed under the */ /* "IBM PUBLIC LICENSE - Open Visualization Data Explorer" */ /***********************************************************************/ #include #include "UIConfig.h" #include #include #include #include #include #include #include #include #include "defines.h" #include "Strings.h" #include "MsgWin.h" #include "DXApplication.h" #include "ButtonInterface.h" #include "EditorWindow.h" #include "ErrorDialogManager.h" #include "QuestionDialogManager.h" #include "ListIterator.h" #include "MWClearCmd.h" #include "MWFileDialog.h" #include "ExecCommandDialog.h" #include "Network.h" #include "NoUndoMWCmd.h" #include "ToggleButtonInterface.h" #include "RepeatingToggle.h" #include "DXPacketIF.h" boolean MsgWin::ClassInitialized = FALSE; String MsgWin::DefaultResources[] = { ".title: Message Window", ".iconName: Message Window", "*fileMenu.labelString: File", "*allowShellResize: False", "*fileMenu.mnemonic: F", "*msgClearOption.labelString: Clear", "*msgClearOption.mnemonic: C", "*msgLogOption.labelString: Log...", "*msgLogOption.mnemonic: g", "*msgSaveOption.labelString: Save As...", "*msgSaveOption.mnemonic: S", "*msgCloseOption.labelString: Close", "*msgCloseOption.mnemonic: l", "*msgCloseOption.accelerator: CtrlQ", "*msgCloseOption.acceleratorText: Ctrl+Q", "*editMenu.labelString: Edit", "*editMenu.mnemonic: E", "*commandsMenu.labelString: Commands", "*commandsMenu.mnemonic: C", "*msgShowMemoryOption.labelString: Show Memory Use", "*msgShowMemoryOption.mnemonic: M", "*msgTraceOption.labelString: Debug Tracing", "*msgTraceOption.mnemonic: T", "*msgExecScriptOption.labelString: Execute Script Command...", "*msgExecScriptOption.mnemonic: S", "*msgNextErrorOption.labelString: Next Error", "*msgNextErrorOption.mnemonic: N", "*msgNextErrorOption.accelerator: CtrlN", "*msgNextErrorOption.acceleratorText: Ctrl+N", "*msgPrevErrorOption.labelString: Previous Error", "*msgPrevErrorOption.mnemonic: P", "*msgPrevErrorOption.accelerator: CtrlP", "*msgPrevErrorOption.acceleratorText: Ctrl+P", "*optionsMenu.labelString: Options", "*optionsMenu.mnemonic: O", "*msgInfoOption.labelString: Information Messages", "*msgInfoOption.mnemonic: I", "*msgWarningOption.labelString: Warning Messages", "*msgWarningOption.mnemonic: W", "*msgErrorOption.labelString: Error Messages", "*msgErrorOption.mnemonic: E", "*msgFrame.shadowThickness: 2", "*msgFrame.marginWidth: 3", "*msgFrame.marginHeight: 3", "*msgList.visibleItemCount: 12", "*workArea.width: 600", NULL }; // // Constructor: // MsgWin::MsgWin(): DXWindow("messageWindow", FALSE) { this->fileMenu = NULL; this->editMenu = NULL; this->executeMenu = NULL; this->optionsMenu = NULL; this->helpMenu = NULL; this->nextErrorOption = NULL; this->prevErrorOption = NULL; this->clearOption = NULL; this->logOption = NULL; this->saveOption = NULL; this->closeOption = NULL; this->infoOption = NULL; this->warningOption = NULL; this->errorOption = NULL; this->execScriptOption = NULL; this->clearCmd = new MWClearCmd("clear", this->commandScope, FALSE, this); this->logCmd = new NoUndoMWCmd("log", this->commandScope, TRUE, this, NoUndoMWCmd::Log); this->saveCmd = new NoUndoMWCmd("save", this->commandScope, TRUE, this, NoUndoMWCmd::Save); this->closeCmd = new NoUndoMWCmd("close", this->commandScope, TRUE, this, NoUndoMWCmd::Close); this->nextErrorCmd = new NoUndoMWCmd("nextError", this->commandScope, TRUE, this, NoUndoMWCmd::NextError); this->prevErrorCmd = new NoUndoMWCmd("prevError", this->commandScope, TRUE, this, NoUndoMWCmd::PrevError); if (theDXApplication->appAllowsScriptCommands()) { this->execScriptCmd = new NoUndoMWCmd("execScript", this->commandScope, theDXApplication->disconnectFromServerCmd->isActive(), this, NoUndoMWCmd::ExecScript); theDXApplication->connectedToServerCmd->autoActivate(this->execScriptCmd); theDXApplication->disconnectedFromServerCmd->autoDeactivate(this->execScriptCmd); this->traceCmd = new NoUndoMWCmd ("traceOn", this->commandScope, TRUE, this, NoUndoMWCmd::Tracing); #if 0 theDXApplication->connectedToServerCmd->autoActivate(this->traceCmd); #endif this->memoryCmd = new NoUndoMWCmd ("memory", this->commandScope, FALSE, this, NoUndoMWCmd::Memory); theDXApplication->connectedToServerCmd->autoActivate(this->memoryCmd); theDXApplication->disconnectedFromServerCmd->autoDeactivate(this->memoryCmd); } else { this->execScriptCmd = NULL; this->traceCmd = NUL(Command*); this->memoryCmd = NUL(Command*); } this->intervalId = 0; this->firstMsg = FALSE; this->executing = FALSE; this->beenManaged= FALSE; this->logFile = NULL; this->saveDialog = NULL; this->logDialog = NULL; this->execCommandDialog = NULL; // // Install the default resources for THIS class (not the derived classes) // if (NOT MsgWin::ClassInitialized) { ASSERT(theApplication); MsgWin::ClassInitialized = TRUE; this->installDefaultResources(theApplication->getRootWidget()); } } // // Destructor: // MsgWin::~MsgWin() { this->clear(); if (this->nextErrorOption) delete this->nextErrorOption; if (this->prevErrorOption) delete this->prevErrorOption; if (this->clearOption) delete this->clearOption; if (this->logOption) delete this->logOption; if (this->saveOption) delete this->saveOption; if (this->closeOption) delete this->closeOption; if (this->infoOption) delete this->infoOption; if (this->warningOption) delete this->warningOption; if (this->errorOption) delete this->errorOption; if (this->execScriptOption) delete this->execScriptOption; delete this->clearCmd; delete this->logCmd; delete this->saveCmd; delete this->closeCmd; delete this->nextErrorCmd; delete this->prevErrorCmd; if (this->execScriptCmd) delete this->execScriptCmd; if (this->traceCmd) delete this->traceCmd; if (this->memoryCmd) delete this->memoryCmd; // // for now, logDialog and fileDialog are the same. // if (this->logDialog) delete this->logDialog; if (this->execCommandDialog) delete this->execCommandDialog; } // // Install the default resources for this class. // void MsgWin::installDefaultResources(Widget baseWidget) { this->setDefaultResources(baseWidget, MsgWin::DefaultResources); this->DXWindow::installDefaultResources(baseWidget); } void MsgWin::manage() { this->beenManaged = TRUE; this->DXWindow::manage(); } void MsgWin::createMenus(Widget parent) { this->createFileMenu(parent); this->createEditMenu(parent); this->createExecuteMenu(parent); if (theDXApplication->appAllowsScriptCommands()) this->createCommandsMenu(parent); this->createOptionsMenu(parent); this->createHelpMenu(parent); // // Right justify the help menu (if it exists). // if (this->helpMenu) { XtVaSetValues(parent, XmNmenuHelpWidget, this->helpMenu, NULL); } } void MsgWin::createFileMenu(Widget parent) { ASSERT(parent); // // Create "File" menu and options. // Widget pulldown = this->fileMenuPulldown = XmCreatePulldownMenu(parent, "fileMenuPulldown", NUL(ArgList), 0); this->fileMenu = XtVaCreateManagedWidget ("fileMenu", xmCascadeButtonWidgetClass, parent, XmNsubMenuId, pulldown, NULL); this->clearOption = new ButtonInterface(pulldown, "msgClearOption", this->clearCmd); this->logOption = new ToggleButtonInterface(pulldown, "msgLogOption", this->logCmd, this->logFile != NULL); this->saveOption = new ButtonInterface(pulldown, "msgSaveOption", this->saveCmd); this->closeOption = new ButtonInterface(pulldown, "msgCloseOption", this->closeCmd); } void MsgWin::createEditMenu(Widget parent) { ASSERT(parent); // // Create "File" menu and options. // Widget pulldown = this->editMenuPulldown = XmCreatePulldownMenu(parent, "editMenuPulldown", NUL(ArgList), 0); this->editMenu = XtVaCreateManagedWidget ("editMenu", xmCascadeButtonWidgetClass, parent, XmNsubMenuId, pulldown, NULL); this->nextErrorOption = new ButtonInterface(pulldown, "msgNextErrorOption", this->nextErrorCmd); this->prevErrorOption = new ButtonInterface(pulldown, "msgPrevErrorOption", this->prevErrorCmd); } void MsgWin::createCommandsMenu(Widget parent) { ASSERT(parent); if ((!this->traceCmd) && (!this->execScriptCmd) && (!this->memoryCmd)) return ; Widget pulldown = this->optionsMenuPulldown = XmCreatePulldownMenu(parent, "commandsMenuPulldown", NUL(ArgList), 0); this->commandsMenu = XtVaCreateManagedWidget ("commandsMenu", xmCascadeButtonWidgetClass, parent, XmNsubMenuId, pulldown, NULL); if (this->traceCmd) this->traceOption = new RepeatingToggle (pulldown, "msgTraceOption", this->traceCmd, theDXApplication->showInstanceNumbers()); if (this->execScriptCmd) this->execScriptOption = new ButtonInterface(pulldown, "msgExecScriptOption", this->execScriptCmd); if (this->memoryCmd) this->memoryOption = new ButtonInterface (pulldown, "msgShowMemoryOption", this->memoryCmd); } void MsgWin::createOptionsMenu(Widget parent) { ASSERT(parent); // // Create "File" menu and options. // Widget pulldown = this->optionsMenuPulldown = XmCreatePulldownMenu(parent, "optionsMenuPulldown", NUL(ArgList), 0); this->optionsMenu = XtVaCreateManagedWidget ("optionsMenu", xmCascadeButtonWidgetClass, parent, XmNsubMenuId, pulldown, NULL); if (theDXApplication->appAllowsMessageInfoOption()) this->infoOption = new ToggleButtonInterface(pulldown, "msgInfoOption", theDXApplication->toggleInfoEnable, theDXApplication->isInfoEnabled()); if (theDXApplication->appAllowsMessageWarningOption()) this->warningOption = new ToggleButtonInterface(pulldown, "msgWarningOption", theDXApplication->toggleWarningEnable, theDXApplication->isWarningEnabled()); this->errorOption = new ToggleButtonInterface(pulldown, "msgErrorOption", theDXApplication->toggleErrorEnable, theDXApplication->isErrorEnabled()); } Widget MsgWin::createWorkArea(Widget parent) { Widget top = XtVaCreateManagedWidget( "workAreaFrame", xmFrameWidgetClass, parent, XmNshadowType, XmSHADOW_OUT, XmNmarginWidth, 5, XmNmarginHeight, 5, NULL); Widget form = XtVaCreateManagedWidget( "workArea", xmFormWidgetClass, top, NULL); Widget frame = XtVaCreateManagedWidget( "msgFrame", xmFrameWidgetClass, form, XmNtopAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, NULL); Arg arg[10]; XtSetArg(arg[0], XmNlistSizePolicy, XmCONSTANT); XtSetArg(arg[1], XmNselectionPolicy, XmSINGLE_SELECT); this->list = XmCreateScrolledList(frame, "msgList", arg, 2); this->installComponentHelpCallback(this->list); XtAddCallback(this->list, XmNsingleSelectionCallback, (XtCallbackProc)MsgWin_SelectCB, (XtPointer)this); XtManageChild(this->list); return top; } void MsgWin::addInformation(const char *info) { ASSERT(info); if (!this->isInitialized()) this->initialize(); if (!theDXApplication->isInfoEnabled()) return; if (!info) return; char *newLine = strchr(info, '\n'); char *s = NULL; if (newLine) { s = DuplicateString(info); s[newLine - info] = '\0'; info = s; } if (executing) { if (this->intervalId == 0) this->intervalId = XtAppAddTimeOut( theApplication->getApplicationContext(), 5000, (XtTimerCallbackProc)MsgWin_FlushTimeoutTO, (XtPointer)this); if (this->firstMsg) { this->firstMsg = FALSE; if (this->logFile) { fputs("Begin Execution\n", this->logFile); fflush(this->logFile); } XmString s = XmStringCreate("Begin Execution", "oblique"); XmListAddItemUnselected(this->list, s, 0); XmStringFree(s); int itemCount; XtVaGetValues(this->list, XmNitemCount, &itemCount, NULL); XmListSetBottomPos(this->list, itemCount); this->clearCmd->activate(); } int vic; XtVaGetValues(this->list, XmNvisibleItemCount, &vic, NULL); this->batchedLines.appendElement((void*)DuplicateString(info)); if (vic <= this->batchedLines.getSize()) this->flushBuffer(); } else { if (this->logFile) { fputs(info, this->logFile); fputc('\n', this->logFile); fflush(this->logFile); } XmString s = XmStringCreate((char*)info, "normal"); XmListAddItemUnselected(this->list, s, 0); XmStringFree(s); int itemCount; XtVaGetValues(this->list, XmNitemCount, &itemCount, NULL); XmListSetBottomPos(this->list, itemCount); this->clearCmd->activate(); } if (s != NULL) delete s; if (theDXApplication->doesInfoOpenMessage()) { if (!this->isManaged()) this->manage(); } } void MsgWin::infoOpen() { if (!this->isInitialized()) this->initialize(); if (!theDXApplication->isInfoEnabled()) return; if (!this->isManaged()) this->manage(); } void MsgWin::addError(const char *error) { ASSERT(error); if (!theDXApplication->isErrorEnabled()) return; if (!error) return; if (!this->isInitialized()) this->initialize(); this->flushBuffer(); if (this->firstMsg) { this->firstMsg = FALSE; if (this->logFile) { fputs("Begin Execution\n", this->logFile); fflush(this->logFile); } XmString s = XmStringCreate("Begin Execution", "oblique"); XmListAddItemUnselected(this->list, s, 0); XmStringFree(s); int itemCount; XtVaGetValues(this->list, XmNitemCount, &itemCount, NULL); XmListSetBottomPos(this->list, itemCount); this->clearCmd->activate(); } // // Manage it before we save the error message, otherwise manage() // causes DXWindow::manage() to do a notify(BeginExecution) which clears // the list of lines. // if (theDXApplication->doesErrorOpenMessage() && !this->isManaged()) this->manage(); // // If this is a module error, change the format and report it. // 0: ERROR: 2::/main:0/Compute:0: Bad parameter: expression must be a string // char net[100]; int inst; const char *topNet = theDXApplication->network->getNameString(); int l; if (sscanf(error, " %*d: ERROR: %*d::/%[^:]:%d/%n", net, &inst, &l) == 2 && EqualString(net, topNet)) { char *line = new char[STRLEN(error)+1]; char *p = line; const char *o = error + l; boolean names = TRUE; boolean skipDigits = FALSE; boolean moreNames = TRUE; while(names && *o) { if (!skipDigits && *o == ':') { skipDigits = TRUE; if (moreNames) { *p++ = *o++; *p++ = ' '; } else o++; } else if (*o == '/') { skipDigits = FALSE; o++; } else if (skipDigits && isdigit(*o)) o++; else if (skipDigits && *o == ':') { names = FALSE; o++; } else { char *colon = strchr(o, ':'); if (moreNames) { char modName[100]; strncpy(modName, o, colon - o); modName[colon - o] = '\0'; char netName[100]; if (sscanf(modName, "%*[^_]_%[^_]_%*d", netName) == 1) { strcpy(p, netName); p += STRLEN(netName); *p++ = ':'; moreNames = FALSE; } else { strncpy(p, modName, colon-o); p += colon-o; } } o = colon; } } *p = '\0'; if (this->logFile) { fputs("ERROR: ", this->logFile); fputs(line, this->logFile); fputs(o, this->logFile); fputc('\n', this->logFile); } XmString errorString = XmStringCreate("ERROR: ", "bold"); XmString nameString = XmStringCreate((char*)line, "bold"); XmString text = XmStringCreate((char*)o, "oblique"); XmString firstHalf = XmStringConcat(errorString, nameString); XmString s = XmStringConcat(firstHalf, text); XmStringFree(errorString); XmStringFree(nameString); XmStringFree(firstHalf); XmStringFree(text); delete line; XmListAddItemUnselected(this->list, s, 0); XmStringFree(s); int itemCount; XtVaGetValues(this->list, XmNitemCount, &itemCount, NULL); XmListSetBottomPos(this->list, itemCount); this->clearCmd->activate(); SelectableLine *l = new SelectableLine; XtVaGetValues(this->list, XmNitemCount, &l->position, NULL); l->line = DuplicateString(error); this->selectableLines.appendElement((void*)l); } else { if (this->logFile) { fputs(error, this->logFile); fputc('\n', this->logFile); } XmString s = XmStringCreate((char*)error, "bold"); XmListAddItemUnselected(this->list, s, 0); XmStringFree(s); int itemCount; XtVaGetValues(this->list, XmNitemCount, &itemCount, NULL); XmListSetBottomPos(this->list, itemCount); this->clearCmd->activate(); } if (theDXApplication->doesErrorOpenMessage()) { if (!this->beenBeeped) { XBell(XtDisplay(this->getRootWidget()), 0); XFlush(XtDisplay(this->getRootWidget())); this->beenBeeped = TRUE; } if (!this->isManaged()) this->manage(); else XRaiseWindow(XtDisplay(this->getRootWidget()), XtWindow(this->getRootWidget())); } } void MsgWin::addWarning(const char *warning) { ASSERT(warning); if (!theDXApplication->isWarningEnabled()) return; if (!this->isInitialized()) this->initialize(); if (!warning) return; this->flushBuffer(); if (this->firstMsg) { this->firstMsg = FALSE; if (this->logFile) { fputs("Begin Execution\n", this->logFile); fflush(this->logFile); } XmString s = XmStringCreate("Begin Execution", "oblique"); XmListAddItemUnselected(this->list, s, 0); XmStringFree(s); int itemCount; XtVaGetValues(this->list, XmNitemCount, &itemCount, NULL); XmListSetBottomPos(this->list, itemCount); this->clearCmd->activate(); } if (this->logFile) { fputs(warning, this->logFile); fputc('\n', this->logFile); fflush(this->logFile); } XmString s = XmStringCreate((char*)warning, "normal"); XmListAddItemUnselected(this->list, s, 0); XmStringFree(s); int itemCount; XtVaGetValues(this->list, XmNitemCount, &itemCount, NULL); XmListSetBottomPos(this->list, itemCount); if (theDXApplication->doesWarningOpenMessage()) { if (!this->isManaged()) this->manage(); else XRaiseWindow(XtDisplay(this->getRootWidget()), XtWindow(this->getRootWidget())); } } void MsgWin::beginExecution() { this->DXWindow::beginExecution(); this->firstMsg = TRUE; this->executing = TRUE; this->beenBeeped = FALSE; this->clearSelectableLines(); } void MsgWin::clearSelectableLines() { ListIterator li(this->selectableLines); SelectableLine *l; while(l = (SelectableLine*)li.getNext()) { delete l->line; delete l; } this->selectableLines.clear(); // XmListDeselectAllItems(this->list); } void MsgWin::endExecution() { this->DXWindow::endExecution(); this->executing = FALSE; this->flushBuffer(); if (this->selectableLines.getSize() > 0) { this->findNextError(FALSE); this->nextErrorCmd->activate(); this->prevErrorCmd->activate(); } else { this->nextErrorCmd->deactivate(); this->prevErrorCmd->deactivate(); } } void MsgWin::standBy() { this->DXWindow::standBy(); this->executing = FALSE; this->flushBuffer(); if (this->selectableLines.getSize() > 0) { this->findNextError(FALSE); this->nextErrorCmd->activate(); this->prevErrorCmd->activate(); } else { this->nextErrorCmd->deactivate(); this->prevErrorCmd->deactivate(); } } extern "C" void MsgWin_FlushTimeoutTO(XtPointer closure, XtIntervalId*) { MsgWin *mw = (MsgWin*) closure; mw->intervalId = 0; mw->flushBuffer(); } void MsgWin::flushBuffer() { int nItems = this->batchedLines.getSize(); if (nItems == 0) return; XmString *items = new XmString[nItems]; ListIterator li(this->batchedLines); char *s; int i; for (i = 0; i < nItems && (s = (char*)li.getNext()); ++i) { if (this->logFile) { fputs(s, this->logFile); fputc('\n', this->logFile); } items[i] = XmStringCreate(s, "normal"); delete s; } XmListAddItems(this->list, items, nItems, 0); if (this->logFile) fflush(this->logFile); int itemCount; XtVaGetValues(this->list, XmNitemCount, &itemCount, NULL); XmListSetBottomPos(this->list, itemCount); for (i = 0; i < nItems; ++i) XmStringFree(items[i]); delete items; this->batchedLines.clear(); if (this->intervalId) { XtRemoveTimeOut(this->intervalId); this->intervalId = 0; } this->clearCmd->activate(); } boolean MsgWin::clear() { this->flushBuffer(); if (this->intervalId) { XtRemoveTimeOut(this->intervalId); this->intervalId = 0; } int nItems = this->batchedLines.getSize(); char *s; ListIterator li(this->batchedLines); for (int i = 0; i < nItems && (s = (char*)li.getNext()); ++i) delete s; this->batchedLines.clear(); this->clearSelectableLines(); XmListDeleteAllItems(this->list); this->clearCmd->deactivate(); this->beenBeeped = FALSE; return TRUE; } boolean MsgWin::log(const char *file) { this->flushBuffer(); if (file == NULL && this->logFile) { fclose(this->logFile); delete this->logFileName; this->logFile = NULL; this->logFileName = NULL; this->logOption->setState(FALSE); } else { if (this->logFile) { fclose(this->logFile); delete this->logFileName; } this->logFile = fopen(file, "w"); if (this->logFile == NULL) { ErrorMessage("Failed to open %s: %s", file, strerror(errno)); this->logFileName = NULL; this->logOption->setState(FALSE); return FALSE; } this->logFileName = DuplicateString(file); this->logOption->setState(TRUE); } return TRUE; } boolean MsgWin::save(const char *file) { if (file) { FILE *f = fopen(file, "w"); if (f == NULL) { ErrorMessage("Failed to open %s: %s", file, strerror(errno)); return FALSE; } int itemCount; XmStringTable items; XtVaGetValues(this->list, XmNitemCount, &itemCount, XmNitems, &items, NULL); for (int i = 0; i < itemCount; ++i) { XmStringContext context; if (!XmStringInitContext(&context, items[i])) continue; XmStringCharSet tag; XmStringDirection dir; Boolean separator; char *s; while (XmStringGetNextSegment(context, &s, &tag, &dir, &separator)) { fputs(s, f); XtFree(s); } fputc('\n', f); } fclose(f); } return TRUE; } void MsgWin::postExecCommandDialog() { if (!this->execCommandDialog) this->execCommandDialog = new ExecCommandDialog(this->getRootWidget()); this->execCommandDialog->post(); } void MsgWin::postLogDialog() { if (!this->logDialog) this->logDialog = this->saveDialog = new MWFileDialog(this->getRootWidget(), this); this->logDialog->postAs(TRUE); } void MsgWin::postSaveDialog() { if (!this->logDialog) this->logDialog = this->saveDialog = new MWFileDialog(this->getRootWidget(), this); this->logDialog->postAs(FALSE); } extern "C" void MsgWin_SelectCB(Widget w, XtPointer closure, XtPointer callData) { MsgWin *mw = (MsgWin*)closure; XmListCallbackStruct *l = (XmListCallbackStruct*)callData; ASSERT(l->reason == XmCR_SINGLE_SELECT); // // An attempt to avoid nagging the user... if doesErrorOpenVpe() == // DXApplication::MayOpenVpe then selectLine() will check this extra // param to see if it should prompt the user. I would like to prompt only // in certain circumstances to avoid nagging. // boolean prompt = TRUE; #if 0 if (l->event) { if ((l->event->type == ButtonPress) || (l->event->type == ButtonRelease) || (l->event->type == KeyPress) || (l->event->type == KeyRelease)) { if (l->event->xany.window == XtWindow(w)) { prompt = FALSE; } } } #endif mw->selectLine(l->item_position, prompt); } void MsgWin::selectLine(int pos, boolean promptUser) { ListIterator li(this->selectableLines); SelectableLine *l; boolean questionPosted = FALSE; while(l = (SelectableLine*)li.getNext()) { if (l->position == pos) { break; } } if (l == NULL) return; // 0: ERROR: 2::/main:0/Compute:0: Bad parameter: expression must be a string char netName[100]; char nodeName[100]; int inst; int len; Network *net = NULL; // // For each macro (denoted by the /macroname:digit/ sequence), // find it in the net's editor (if there is either a net or an instance), // and look up the net. char *line = strchr(l->line, '/'); char c; ASSERT(line); while (sscanf(line, "/%[^:]:%d%n%c", netName, &inst, &len, &c) == 3 && c == '/') { if (net) { // Handle "main_Image_3" style macro names. char prefix[100]; if (sscanf(netName, "%[^_]_%[^_]_%*d", prefix, nodeName) == 2 && EqualString(prefix, net->getNameString())) { strcpy(netName, nodeName); break; } questionPosted = this->openEditorIfNecessary(net,netName,inst, promptUser); } if (EqualString(netName, theDXApplication->network->getNameString())) net = theDXApplication->network; else { net = NULL; Network *macro; li.setList(theDXApplication->macroList); while(macro = (Network*)li.getNext()) if (EqualString(netName, macro->getNameString())) net = macro; if (net == NULL) break; } line += len; } // // Handle the module at the end, which may be an Image. // if (sscanf(line, "/%[^:]:%d%n%c", netName, &inst, &len, &c) == 3 && (c == ':' || c == '/')) { if (net) { // Handle "main_Image_3" style macro names. char prefix[100]; if (sscanf(netName, "%[^_]_%[^_]_%*d", prefix, nodeName) == 2 && EqualString(prefix, net->getNameString())) strcpy(netName, nodeName); questionPosted |= this->openEditorIfNecessary(net,netName,inst, promptUser); } } // // Raise this window above the editors that were just raised // if (theDXApplication->doesErrorOpenMessage()) { if (!this->isManaged()) this->manage(); // // If we have put a question dialog, then it might be nice to // leave it on top instead of the MsgWin. // else if (!questionPosted) XRaiseWindow(XtDisplay(this->getRootWidget()), XtWindow(this->getRootWidget())); } } // // Make a tiny class for passing the editor window info to some // static callbacks. Martin added this (mid Oct. 1995) in order to // provide the ability to abort opening a vpe on error. That process can // be very slow for huge nets. You cannot use // theQuestionDialogManager->userQuery() inside selectLine because selectLine() // is called by notify() and you must not cause any sort of heavily modal // pause inside notify() because {un}greening is happening. // class EdInfo { public: char *nodeName; Network *net; int inst; EditorWindow *editor; EdInfo (const char *nodeName, Network *net, EditorWindow *e, int inst) { this->nodeName= DuplicateString(nodeName); this->net = net; this->editor = e; this->inst = inst; }; ~EdInfo () { if (this->nodeName) delete this->nodeName; }; }; // // If there is an editor opened on the net, or if there is a resource // in DXApplication which says to open an editor on the net... // If the resource says NEVER but the window is already opened, then // ignore the resource. // If the application indicates we should prompt the user and the promptUser // flag is set, then prompt the user with a Yes/No dialog about opening // the editor. // // Return TRUE, if we posted a dialog to ask the user if we should post // the window. // boolean MsgWin::openEditorIfNecessary(Network *net, const char *nodeName, int inst, boolean promptUser) { EditorWindow *e = net->getEditor(); EdInfo *edinfo = new EdInfo (nodeName, net, e, inst); int show_status = theDXApplication->doesErrorOpenVpe(net); boolean questionPosted = FALSE; if (show_status == DXApplication::MustOpenVpe) { MsgWin::ShowEditor((XtPointer)edinfo); } else if (show_status == DXApplication::DontOpenVpe) { if (e && e->isManaged()) MsgWin::ShowEditor((XtPointer)edinfo); else MsgWin::NoShowEditor((XtPointer)edinfo); } else if (show_status == DXApplication::MayOpenVpe) { if (e && e->isManaged()) MsgWin::ShowEditor((XtPointer)edinfo); else if (promptUser) { // // Must be FULL_APPLICATION_MODAL so that the user can't do // File/Open while the question dialog is on the screen. // Must also be a child of theDXApplication and not of // this becuase if you mwm dismiss the MsgWin then the // entire ui is hosed. // const char *macro = net->getNameString(); const char *file = net->getFileName(); char *confMsg = new char[32 + STRLEN(file) + STRLEN(macro)]; sprintf (confMsg, "Open editor on %s (%s)?", macro, file); theQuestionDialogManager->modalPost( theDXApplication->getAnchor()->getRootWidget(), confMsg, "Open Editor Confirmation", (void*)edinfo, MsgWin::ShowEditor, MsgWin::NoShowEditor, NULL, "Yes", "No", NULL, XmDIALOG_FULL_APPLICATION_MODAL ); delete confMsg; questionPosted = TRUE; } } return questionPosted; } void MsgWin::ShowEditor (XtPointer cdata) { EdInfo *ei = (EdInfo*)cdata; if (ei->editor == NULL) ei->editor = theDXApplication->newNetworkEditor(ei->net); // // On the last tool, we open up containing editor for the user. // if (ei->editor) { ei->editor->manage(); ei->editor->deselectAllNodes(); ei->editor->selectNode (ei->nodeName, ei->inst, TRUE); } delete ei; } void MsgWin::NoShowEditor (XtPointer cdata) { EdInfo *ei = (EdInfo*)cdata; delete ei; Widget w = theQuestionDialogManager->getRootWidget(); if ((w) && (XtIsManaged(w))) XtUnmanageChild (w); } // // callers are: a menu bar button, and endExecution (which happens quite often // including during File/New, File/Open). For the menu bar button, we cycle thru // error messages ad infinitum. For internal use we want to visit each member of // the list at most once. So if activateSameSelection==FALSE, then don't reset // pos=0 and do another loop over all selections. // void MsgWin::findNextError(boolean activateSameSelection) { int *positions; int npos; int pos; int itemCount; int topItem; int visibleItems; XtVaGetValues(this->list, XmNitemCount, &itemCount, XmNtopItemPosition, &topItem, XmNvisibleItemCount, &visibleItems, NULL); if (XmListGetSelectedPos(this->list, &positions, &npos)) { pos = positions[npos-1]; XtFree((char*)positions); } else { pos = 0; } ListIterator li(this->selectableLines); SelectableLine *s; boolean found = FALSE; while(s = (SelectableLine*)li.getNext()) { if (s->position > pos) { found = TRUE; XmListSelectPos(this->list, s->position, True); if (s->position < topItem || s->position >= topItem + visibleItems) XmListSetBottomPos(this->list, s->position); break; } } if ((!found) && (activateSameSelection)) { li.setPosition(1); pos = 0; while(s = (SelectableLine*)li.getNext()) { if (s->position > pos) { found = TRUE; XmListSelectPos(this->list, s->position, True); if (s->position < topItem || s->position >= topItem + visibleItems) XmListSetBottomPos(this->list, s->position); break; } } } } void MsgWin::findPrevError() { int *positions; int npos; int pos; int itemCount; int topItem; int visibleItems; XtVaGetValues(this->list, XmNitemCount, &itemCount, XmNtopItemPosition, &topItem, XmNvisibleItemCount, &visibleItems, NULL); if (XmListGetSelectedPos(this->list, &positions, &npos)) { pos = positions[npos-1]; XtFree((char*)positions); } else { pos = itemCount + 1; } int i = this->selectableLines.getSize(); SelectableLine *s; boolean found = FALSE; for (; i > 0 && (s = (SelectableLine*)this->selectableLines.getElement(i)); --i) { if (s->position < pos) { found = TRUE; XmListSelectPos(this->list, s->position, True); if (s->position < topItem || s->position >= topItem + visibleItems) XmListSetBottomPos(this->list, s->position); break; } } if (!found) { i = this->selectableLines.getSize(); pos = itemCount + 1; for (; i > 0 && (s = (SelectableLine*)this->selectableLines.getElement(i)); --i) { if (s->position < pos) { found = TRUE; XmListSelectPos(this->list, s->position, True); if (s->position < topItem || s->position >= topItem + visibleItems) XmListSetBottomPos(this->list, s->position); break; } } } } boolean MsgWin::toggleTracing() { boolean on_or_off = this->traceOption->getState(); char *cmd = (on_or_off?"Trace(\"0\",1);\n" : "Trace(\"0\", 0);\n" ); // // Issue the script command // DXPacketIF *p = theDXApplication->getPacketIF(); if (p) { theDXApplication->getMessageWindow()->addInformation(cmd); p->send(DXPacketIF::FOREGROUND, cmd); theDXApplication->showInstanceNumbers(on_or_off); return TRUE; } else { theDXApplication->showInstanceNumbers(on_or_off); return FALSE; } } boolean MsgWin::memoryUse() { // // Issue the script command // char *cmd = "Usage(\"memory\",0);\n"; DXPacketIF *p = theDXApplication->getPacketIF(); if (p) { theDXApplication->getMessageWindow()->addInformation(cmd); p->send(DXPacketIF::FOREGROUND, cmd); return TRUE; } return FALSE; }