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 #if defined(HAVE_IOSTREAM)
13 # include <iostream>
14 #else
15 # if defined(HAVE_IOSTREAM_H)
16 # include <iostream.h>
17 # endif
18 # if defined(HAVE_STREAM_H)
19 # include <stream.h>
20 # endif
21 #endif
22
23 #include <Xm/RowColumn.h>
24 #include <Xm/CascadeB.h>
25 #include <Xm/Separator.h>
26 #include "DXWindow.h"
27 #include "DXApplication.h"
28 //#include "QuitCommand.h"
29 #include "CommandInterface.h"
30 #include "CommandScope.h"
31 #include "Command.h"
32 #include "ButtonInterface.h"
33 #include "ToggleButtonInterface.h"
34 #include "Network.h"
35 #include "ProcessGroupManager.h"
36 #include "ControlPanelAccessDialog.h"
37 #include "ErrorDialogManager.h"
38 #include "NoUndoDXWindowCommand.h"
39 #include "anchor.bm"
40 #include "OpenFileCommand.h"
41 #include "ListIterator.h"
42 #include "CascadeMenu.h"
43
44 Symbol DXWindow::lastMsg = 0;
45 const void *DXWindow::lastMsgData = NULL;
46
47 #include "DXWDefaultResources.h"
48
DXWindow(const char * name,boolean isAnchor,boolean usesMenuBar)49 DXWindow::DXWindow(const char* name,
50 boolean isAnchor, boolean usesMenuBar):
51 IBMMainWindow(name, usesMenuBar)
52 {
53 this->anchor = isAnchor;
54 this->startup = FALSE;
55 this->anchorPixmap = NUL(Pixmap);
56 this->anchorButton = NUL(Widget);
57
58 this->executeMenu = NUL(Widget);
59 this->executeMenuPulldown = NUL(Widget);
60 this->executeOnceOption = NUL(CommandInterface*);
61 this->executeOnChangeOption = NUL(CommandInterface*);
62 this->endExecutionOption = NUL(CommandInterface*);
63 this->sequencerOption = NUL(CommandInterface*);
64
65 this->connectionMenu = NUL(Widget);
66 this->connectionMenuPulldown = NUL(Widget);
67 this->startServerOption = NUL(CommandInterface*);
68 this->disconnectFromServerOption = NUL(CommandInterface*);
69 this->resetServerOption = NUL(CommandInterface*);
70 this->processGroupAssignmentOption = NUL(CommandInterface*);
71
72 this->panelAccessDialog = NULL;
73
74 this->toggleWindowStartupCmd = NULL;
75 this->toggleWindowStartupOption = NULL;
76
77 this->helpTutorialOption = NUL(CommandInterface*);
78
79 ASSERT(!usesMenuBar || this->commandScope);
80 }
81
~DXWindow()82 DXWindow::~DXWindow()
83 {
84 //
85 // Cause the window to be taken of the display immediately.
86 // This is useful when reading in a new network when we don't
87 // get to the X main loop until after deleting the current net
88 // and reading in the next so that windows from the last network
89 // can be left up until after the new network is read in.
90 //
91 if (this->getRootWidget() && XtIsRealized(this->getRootWidget()))
92 XtUnmapWidget(this->getRootWidget());
93
94 if (this->anchorPixmap && this->menuBar)
95 {
96 XFreePixmap(XtDisplay(this->menuBar), this->anchorPixmap);
97 }
98
99 //
100 // Execute menu
101 //
102 if (this->executeOnceOption) delete this->executeOnceOption;
103 if (this->executeOnChangeOption) delete this->executeOnChangeOption;
104 if (this->endExecutionOption) delete this->endExecutionOption;
105 if (this->sequencerOption) delete this->sequencerOption;
106
107 //
108 // Connection menu
109 //
110 if (this->startServerOption) delete this->startServerOption;
111 if (this->disconnectFromServerOption)
112 delete this->disconnectFromServerOption;
113 if (this->resetServerOption) delete this->resetServerOption;
114 if (this->processGroupAssignmentOption)
115 delete this->processGroupAssignmentOption;
116
117 if (this->panelAccessDialog) delete this->panelAccessDialog;
118
119 if (this->helpTutorialOption) delete this->helpTutorialOption;
120
121 if (this->toggleWindowStartupOption)
122 delete this->toggleWindowStartupOption;
123
124 if (this->toggleWindowStartupCmd)
125 delete this->toggleWindowStartupCmd;
126
127 //
128 // file history menu
129 //
130 ListIterator iter(this->file_history_buttons);
131 ButtonInterface* bi;
132 while ((bi=(ButtonInterface*)iter.getNext())) delete bi;
133 iter.setList(this->file_history_commands);
134 Command* cmd;
135 while ((cmd=(Command*)iter.getNext())) delete cmd;
136 }
beginExecution()137 void DXWindow::beginExecution()
138 {
139 // Make sure the widget present
140 if (this->executeMenu != NULL) {
141 XtVaSetValues(this->executeMenu,
142 XmNforeground,
143 theDXApplication->getExecutionHighlightForeground(),
144 NULL);
145 }
146 }
standBy()147 void DXWindow::standBy()
148 {
149 // Make sure the widget present
150 if (this->executeMenu != NULL) {
151 XtVaSetValues(this->executeMenu,
152 XmNforeground,
153 theDXApplication->getBackgroundExecutionForeground(),
154 NULL);
155 }
156 }
endExecution()157 void DXWindow::endExecution()
158 {
159 // Make sure the widget present
160 if (this->executeMenu != NULL) {
161 XtVaSetValues(this->executeMenu,
162 XmNforeground,
163 theDXApplication->getForeground(),
164 NULL);
165 }
166 }
serverDisconnected()167 void DXWindow::serverDisconnected()
168 {
169 this->endExecution();
170 }
171
172
173 //
174 // Install the default resources for this class.
175 //
installDefaultResources(Widget baseWidget)176 void DXWindow::installDefaultResources(Widget baseWidget)
177 {
178 this->setDefaultResources(baseWidget, DXWindow::DefaultResources);
179 this->IBMMainWindow::installDefaultResources(baseWidget);
180 }
181
182
createMenuBar(Widget parent)183 void DXWindow::createMenuBar(Widget parent)
184 {
185 this->IBMMainWindow::createMenuBar(parent);
186 this->setAnchor(this->anchor);
187 }
188
189 //
190 // Create the anchor button widget and add the pixmap if desired and not
191 // already present
192 //
createAnchor(boolean addPixmap)193 void DXWindow::createAnchor(boolean addPixmap)
194 {
195 ASSERT(this->menuBar);
196
197 if (!this->anchorButton) {
198 this->anchorButton = XtVaCreateWidget
199 ("anchorButton",
200 xmCascadeButtonWidgetClass,
201 this->menuBar,
202 XmNlabelType, XmPIXMAP,
203 NULL);
204 XtUninstallTranslations (this->anchorButton);
205 }
206 //
207 // If an anchor pixmap has not yet been created, do it now.
208 // (This code should be executed only once.)
209 //
210 if (addPixmap && !this->anchorPixmap)
211 {
212 Pixel foreground;
213 Pixel background;
214 int depth;
215 //
216 // Create the anchor button.
217 //
218 XtVaGetValues (this->menuBar,
219 XmNdepth, &depth,
220 NULL);
221
222 //
223 // It's bad to use a color name here.
224 // I made the pixmap placement happen earlier to avoid the
225 // flashing which resulted when doing it at a convenient time.
226 // If you fetch colors from this->menuBar now, then on an hp700 you
227 // wind up with workspace default colors because that's what hpvue wants.
228 //
229 # if defined(hp700) && 0
230 XrmValue from, toinout;
231 from.addr = "#b4b4b4b4b4b4";
232 from.size = 1+strlen(from.addr);
233 toinout.addr = (XPointer)&background;
234 toinout.size = sizeof(Pixel);
235 XtConvertAndStore(this->menuBar, XmRString, &from, XmRPixel, &toinout);
236 # else
237 XtVaGetValues (this->getRootWidget(), XmNbackground, &background, NULL);
238 # endif
239 foreground = theDXApplication->getForeground();
240
241 Window wind;
242 Screen *scr = XtScreen(this->menuBar);
243 wind = RootWindowOfScreen(scr);
244 this->anchorPixmap =
245 XCreatePixmapFromBitmapData
246 (XtDisplay(this->menuBar),
247 wind,
248 anchor_bits,
249 anchor_width,
250 anchor_height,
251 foreground,
252 background,
253 depth);
254
255 XtVaSetValues
256 (this->anchorButton,
257 XmNlabelType, XmPIXMAP,
258 XmNlabelPixmap, this->anchorPixmap,
259 XmNlabelInsensitivePixmap, this->anchorPixmap,
260 NULL);
261
262 }
263
264 }
265
closeWindow()266 void DXWindow::closeWindow()
267 {
268 if (theDXApplication->appAllowsExitOptions()) {
269 if (this->anchor)
270 theDXApplication->exitCmd->execute();
271 else
272 this->unmanage();
273 } else {
274 this->iconify();
275 }
276 }
277
manage()278 void DXWindow::manage()
279 {
280
281 this->IBMMainWindow::manage();
282
283 //
284 // Get notified with the last message.
285 //
286 this->notify(DXWindow::lastMsg,DXWindow::lastMsgData);
287
288 this->setAnchor(this->anchor);
289 }
290
notify(const Symbol message,const void * data,const char * msg)291 void DXWindow::notify(const Symbol message, const void *data, const char *msg)
292 {
293 if(NOT message) // no previouse message.
294 return;
295
296 if (message == DXApplication::MsgExecute)
297 {
298 DXWindow::lastMsgData = data;
299 DXWindow::lastMsg = message;
300 this->beginExecution();
301 }
302 else if (message == DXApplication::MsgStandBy)
303 {
304 DXWindow::lastMsgData = data;
305 DXWindow::lastMsg = message;
306 this->standBy();
307 }
308 else if (message == DXApplication::MsgExecuteDone)
309 {
310 DXWindow::lastMsgData = data;
311 DXWindow::lastMsg = message;
312 this->endExecution();
313 }
314 else if (message == DXApplication::MsgServerDisconnected)
315 {
316 this->serverDisconnected();
317 }
318 else if (message == Command::MsgBeginExecuting)
319 {
320 this->beginCommandExecuting();
321 }
322 else if (message == Command::MsgEndExecuting)
323 {
324 this->endCommandExecuting();
325 }
326 else if (message == DXApplication::MsgPanelChanged)
327 {
328 if (this->panelAccessDialog && this->panelAccessDialog->isManaged()) {
329 this->panelAccessDialog->update();
330 if (this->title) {
331 char *s = new char[STRLEN(this->title) + 32];
332 sprintf(s,"Control Panel Access:%s",this->title);
333 this->panelAccessDialog->setDialogTitle(s);
334 delete s;
335 } else
336 this->panelAccessDialog->setDialogTitle(
337 "Control Panel Access...");
338 }
339 }
340 else
341 this->IBMMainWindow::notify(message,data,msg);
342 }
343
344 //
345 // Virtual function called at the beginning of Command::execute.
346 //
beginCommandExecuting()347 void DXWindow::beginCommandExecuting()
348 {
349 return;
350 }
351 //
352 // Virtual function called at the end of Command::execute.
353 //
endCommandExecuting()354 void DXWindow::endCommandExecuting()
355 {
356 return;
357 }
358
createExecuteMenu(Widget parent)359 void DXWindow::createExecuteMenu(Widget parent)
360 {
361 ASSERT(parent);
362 Widget pulldown;
363
364 if (!theDXApplication->appAllowsExecuteMenus())
365 return;
366
367 //
368 // Create "Execute" menu and options.
369 //
370 pulldown =
371 this->executeMenuPulldown =
372 XmCreatePulldownMenu
373 (parent, "executeMenuPulldown", NUL(ArgList), 0);
374
375 this->executeMenu =
376 XtVaCreateManagedWidget
377 ("executeMenu",
378 xmCascadeButtonWidgetClass,
379 parent,
380 XmNsubMenuId, pulldown,
381 NULL);
382
383 this->executeOnceOption =
384 new ButtonInterface(pulldown,
385 "executeOnceOption",
386 theDXApplication->executeOnceCmd);
387
388 this->executeOnChangeOption =
389 new ButtonInterface(pulldown,
390 "executeOnChangeOption",
391 theDXApplication->executeOnChangeCmd);
392
393 this->endExecutionOption =
394 new ButtonInterface(pulldown,
395 "endExecutionOption",
396 theDXApplication->endExecutionCmd);
397
398 XtVaCreateManagedWidget
399 ("optionSeparator", xmSeparatorWidgetClass, pulldown, NULL);
400
401 this->sequencerOption =
402 new ButtonInterface(pulldown,
403 "sequencerOption",
404 theDXApplication->openSequencerCmd);
405 #if USE_REMAP // 6/14/93
406 XtVaCreateManagedWidget
407 ("optionSeparator", xmSeparatorWidgetClass, pulldown, NULL);
408
409 Network *network = theDXApplication->network;
410 //this->sequencerOption =
411 new ToggleButtonInterface(pulldown,
412 "remapInteractorOutputsOption",
413 theDXApplication->toggleRemapInteractorsCmd,
414 (network ? network->isRemapInteractorOutputMode() :
415 DEFAULT_REMAP_INTERACTOR_MODE));
416 #endif
417 }
418
419
createHelpMenu(Widget parent)420 void DXWindow::createHelpMenu(Widget parent)
421 {
422 boolean addHelp = theDXApplication->appAllowsDXHelp();
423 // this->createBaseHelpMenu(parent, addHelp, addHelp && this->isAnchor());
424 // if (theDXApplication->appAllowsDXHelp() && this->isAnchor()) {
425 this->createBaseHelpMenu(parent, addHelp, addHelp);
426 if (addHelp) {
427 XtVaCreateManagedWidget("separator", xmSeparatorWidgetClass,
428 this->helpMenuPulldown,
429 NULL);
430 this->helpTutorialOption =
431 new ButtonInterface(this->helpMenuPulldown, "helpTutorialOption",
432 theDXApplication->helpTutorialCmd);
433 }
434
435 }
436
437
createConnectionMenu(Widget parent)438 void DXWindow::createConnectionMenu(Widget parent)
439 {
440 ASSERT(parent);
441 ASSERT(this->menuBar);
442
443 Widget pulldown;
444
445 if (!theDXApplication->appAllowsConnectionMenus())
446 return;
447
448 //
449 // Create "Connection" menu and options.
450 //
451 pulldown =
452 this->connectionMenuPulldown =
453 XmCreatePulldownMenu
454 (parent, "connectionMenuPulldown", NUL(ArgList), 0);
455 this->connectionMenu =
456 XtVaCreateManagedWidget
457 ("connectionMenu",
458 xmCascadeButtonWidgetClass,
459 parent,
460 XmNsubMenuId, pulldown,
461 NULL);
462
463 XtAddCallback(pulldown,
464 XmNmapCallback,
465 (XtCallbackProc)DXWindow_ConnectionMenuMapCB,
466 (XtPointer)this);
467
468 this->startServerOption =
469 new ButtonInterface(pulldown, "startServerOption",
470 theDXApplication->connectToServerCmd);
471
472 this->disconnectFromServerOption =
473 new ButtonInterface(pulldown, "disconnectFromServerOption",
474 theDXApplication->disconnectFromServerCmd);
475
476 this->resetServerOption =
477 new ButtonInterface(pulldown, "resetServerOption",
478 theDXApplication->resetServerCmd);
479
480
481 if (theDXApplication->appAllowsPGroupAssignmentChange()) {
482 XtVaCreateManagedWidget("optionSeparator",
483 xmSeparatorWidgetClass, pulldown, NULL);
484
485 this->processGroupAssignmentOption =
486 new ButtonInterface(pulldown, "processGroupAssignmentOption",
487 theDXApplication->assignProcessGroupCmd);
488
489 }
490
491 }
492
DXWindow_ConnectionMenuMapCB(Widget w,XtPointer clientdata,XtPointer calldata)493 extern "C" void DXWindow_ConnectionMenuMapCB(Widget w,
494 XtPointer clientdata,
495 XtPointer calldata)
496 {
497 #if WORKSPACE_PAGES
498 GroupManager *gmgr = theDXApplication->getProcessGroupManager();
499 if(gmgr->getGroupCount())
500 #else
501 if(theDXApplication->PGManager->getGroupCount())
502 #endif
503 theDXApplication->assignProcessGroupCmd->activate();
504 else
505 theDXApplication->assignProcessGroupCmd->deactivate();
506 }
507
508 //
509 // Post the panel access dialog with this window PanelAccessManager info.
510 //
postPanelAccessDialog(PanelAccessManager * pam)511 void DXWindow::postPanelAccessDialog( PanelAccessManager *pam)
512 {
513
514 if (!this->panelAccessDialog) {
515 ASSERT(pam);
516 this->panelAccessDialog = new ControlPanelAccessDialog(
517 this->getRootWidget(),
518 //theDXApplication->getRootWidget(),
519 pam);
520 }
521
522 this->panelAccessDialog->post();
523 if (this->title) {
524 char *s = new char[STRLEN(this->title) + 32];
525 sprintf(s,"Control Panel Access:%s",this->title);
526 this->panelAccessDialog->setDialogTitle(s);
527 delete s;
528 } else
529 this->panelAccessDialog->setDialogTitle("Control Panel Access...");
530 }
printComment(FILE * f)531 boolean DXWindow::printComment(FILE *f)
532 {
533 int xsize, ysize, xpos, ypos;
534
535 if (!this->getGeometry(&xpos, &ypos, &xsize,&ysize))
536 return TRUE;
537
538 if (!UIComponent::PrintGeometryComment(f,xpos,ypos,xsize,ysize))
539 return FALSE;
540
541 return TRUE;
542 }
parseComment(const char * line,const char * file,int lineno)543 boolean DXWindow::parseComment(const char *line, const char *file,
544 int lineno)
545 {
546 int items, xsize=0, ysize=0, xpos=0, ypos=0;
547 float norm_xsize, norm_ysize, norm_xpos, norm_ypos;
548 int display_xsize, display_ysize;
549
550
551 if (!EqualSubstring(line," window: position =",19)) {
552 #if DX_MAJOR_VERSION == 3 && DX_MINOR_VERSION == 0 && DX_MICRO_VERSION == 0
553 if (EqualSubstring(line," window: pos=(",14)) {
554 ErrorMessage("Bad comment found in file '%s' line %d.\n"
555 "This comment is only found in unreleased versions of DX and\n"
556 "so is not being supported. You can fix your .cfg by deleting\n"
557 "the offending line. \n"
558 "(Customers should never get this message)", file,lineno);
559 }
560 #endif
561 return FALSE;
562 }
563
564 #if INCLUDE_FLAGS_COMMENT // Not used as of version 2.1
565 int flags;
566 items = sscanf(line," window: position = (%f,%f), size = %fx%f, "
567 "flags = 0x%x\n",
568 &norm_xpos,&norm_ypos,&norm_xsize,&norm_ysize, &flags);
569
570 if (items == 5) {
571 if ((norm_xsize < 3) && (norm_ysize < 3)) {
572 display_xsize = DisplayWidth(theApplication->getDisplay(),0);
573 display_ysize = DisplayHeight(theApplication->getDisplay(),0);
574 xpos = (int) (display_xsize * norm_xpos + .5);
575 ypos = (int) (display_ysize * norm_ypos + .5);
576 xsize = (int) (display_xsize * norm_xsize + .5);
577 ysize = (int) (display_ysize * norm_ysize + .5);
578 }
579 #else
580
581 if (UIComponent::ParseGeometryComment(line, file, lineno, &xpos, &ypos,
582 &xsize, &ysize, NULL)) {
583
584 #endif
585 #if INCLUDE_FLAGS_COMMENT // Not used as of version 2.1
586 if (flags & 1)
587 this->setStartup(TRUE);
588 else
589 this->setStartup(FALSE);
590 #endif
591 } else {
592 ErrorMessage("Bad comment found in file '%s' line %d (ignoring)",
593 file,lineno);
594 return TRUE;
595 }
596
597 if (theDXApplication->applyWindowPlacements()) {
598 this->setGeometry(xpos, ypos, xsize,ysize);
599 }
600
601 return TRUE;
602 }
603 //
604 // Reset the window to use the default settings for the state that is
605 // printed by the printComment() method.
606 //
607 void DXWindow::useDefaultCommentState()
608 {
609 this->setStartup(FALSE);
610 }
611
612
613 //
614 // Add a toggle button interface that toggles the startup up state of this
615 // window to the given parent widget.
616 //
617 Widget DXWindow::addStartupToggleOption(Widget parent)
618 {
619 if (!this->toggleWindowStartupCmd)
620 this->toggleWindowStartupCmd =
621 new NoUndoDXWindowCommand("toggleWindowStartup",
622 this->commandScope, TRUE,
623 this,
624 NoUndoDXWindowCommand::ToggleWindowStartup);
625
626
627 this->toggleWindowStartupOption =
628 new ToggleButtonInterface
629 (parent, "toggleWindowStartupOption",
630 this->toggleWindowStartupCmd, this->startup);
631
632 return this->toggleWindowStartupOption->getRootWidget();
633
634 }
635 //
636 // Changes whether or not this window is supposed to open up automatically
637 // on startup.
638 //
639 void DXWindow::toggleWindowStartup()
640 {
641 this->setStartup(!this->startup);
642 }
643 //
644 // Change whether or not this window is an startup window.
645 //
646 void DXWindow::setStartup(boolean setting)
647 {
648 this->startup = setting;
649
650 if (this->toggleWindowStartupOption)
651 this->toggleWindowStartupOption->setState(setting);
652 }
653
654 //
655 // Change whether or not this window is an anchor window.
656 //
657 void DXWindow::setAnchor(boolean isAnchor)
658 {
659 this->anchor = isAnchor;
660
661 if (isAnchor && this->hasMenuBar) {
662 this->createAnchor(TRUE);
663 XtManageChild(this->anchorButton);
664 } else if (this->anchorButton) {
665 XtUnmanageChild(this->anchorButton);
666 }
667
668 }
669
670
671 void DXWindow::getGeometryNameHierarchy(String names[], int* count, int max)
672 {
673 int cnt = *count;
674 if (cnt >= (max-1)) {
675 this->IBMMainWindow::getGeometryNameHierarchy(names, count, max);
676 return ;
677 }
678
679 #ifdef DXD_NON_UNIX_DIR_SEPARATOR
680 char fsep = '\\';
681 #else
682 char fsep = '/';
683 #endif
684
685 const char* fname = theDXApplication->network->getFileName();
686 //
687 // Remove the extension and all leading names, leaving
688 // only WindVorticity for examples
689 //
690 if ((!fname) || (!fname[0])) {
691 this->IBMMainWindow::getGeometryNameHierarchy(names, count, max);
692 return ;
693 }
694
695 int len = strlen(fname);
696 int i;
697 int last_slash = -1;
698 for (i=len-1; i>=0; i--) {
699 if ((fname[i] == fsep) || (fname[i] == '/')) {
700 last_slash = i;
701 break;
702 }
703 }
704 last_slash++;
705 char* file;
706 file = DuplicateString(&fname[last_slash]);
707
708 len = strlen(file);
709 for (i=len-1; i>=0; i--) if (file[i]=='.') {file[i] = '\0'; break; }
710
711 if (file[0]) {
712 names[cnt++] = file;
713 *count = cnt;
714 }
715
716 this->IBMMainWindow::getGeometryNameHierarchy(names, count, max);
717 }
718
719
720 void DXWindow::getGeometryAlternateNames(String* names, int* count, int max)
721 {
722 int cnt = *count;
723 if (cnt < (max-1)) {
724 char* name = DuplicateString(this->name);
725 names[cnt++] = name;
726 *count = cnt;
727 }
728 this->IBMMainWindow::getGeometryAlternateNames(names, count, max);
729 }
730
731 void DXWindow::createFileHistoryMenu (Widget parent)
732 {
733 if (!this->isAnchor()) return ;
734
735 //
736 // if there is no history, and we don't have the ability to
737 // store history, then don't bother offering the menu.
738 //
739 char fname[256];
740 if (!theIBMApplication->getApplicationDefaultsFileName(fname)) {
741 List recent_nets;
742 theDXApplication->getRecentNets(recent_nets);
743 if (recent_nets.getSize()==0) {
744 return ;
745 }
746 }
747
748 this->file_history_cascade = new CascadeMenu("fileHistory", parent);
749
750 //
751 // put the callback on the menu parent in which we create the cascade
752 // because that allows us to grey out the cascade button before the
753 // user has a chance to click on it.
754 //
755 XtAddCallback(parent, XmNmapCallback,
756 (XtCallbackProc)DXWindow_FileHistoryMenuMapCB, (XtPointer)this);
757 }
758
759 void DXWindow::buildFileHistoryMenu()
760 {
761 if (!this->file_history_cascade) return ;
762
763 ListIterator iter(this->file_history_buttons);
764 ButtonInterface* bi;
765 while ((bi=(ButtonInterface*)iter.getNext())) {
766 bi->unmanage();
767 delete bi;
768 }
769 this->file_history_buttons.clear();
770
771 iter.setList(this->file_history_commands);
772 Command* cmd;
773 while ((cmd=(Command*)iter.getNext())) delete cmd;
774 this->file_history_commands.clear();
775
776 Widget menu_parent = this->file_history_cascade->getMenuItemParent();
777
778 List recent_nets;
779 theDXApplication->getRecentNets(recent_nets);
780 if (recent_nets.getSize()==0) {
781 this->file_history_cascade->deactivate();
782
783 //
784 // make a 1 button menu if there is no content available.
785 // I don't think this necessary, but it won't hurt. No one
786 // will see it.
787 //
788 const char* cp = "(null)";
789 Symbol s = theSymbolManager->registerSymbol(cp);
790 cmd = new OpenFileCommand(s);
791 this->file_history_commands.appendElement(cmd);
792 bi = new ButtonInterface(menu_parent, "openFile", cmd);
793 bi->setLabel(cp);
794 this->file_history_buttons.appendElement(bi);
795 cmd->deactivate();
796 } else {
797 this->file_history_cascade->activate();
798 //
799 // Stick each button's label into this list, then before making
800 // new buttons, ensure that the button's label is unique. If
801 // it isn't unique, then use the file's full path instead of
802 // just the base name. This list actually serves 2 purposes.
803 // It also records allocated memory so that we free it before
804 // finishing.
805 //
806 List baseNames;
807 iter.setList(recent_nets);
808 Symbol s;
809 while ((s=(Symbol)(long)iter.getNext())) {
810 cmd = new OpenFileCommand(s);
811 this->file_history_commands.appendElement(cmd);
812 bi = new ButtonInterface(menu_parent, "openFile", cmd);
813 this->file_history_buttons.appendElement(bi);
814
815 const char* fullpath = theSymbolManager->getSymbolString(s);
816 char* cp = GetFileBaseName(fullpath,0);
817 baseNames.appendElement(cp);
818 boolean unique = TRUE;
819 ListIterator biter(baseNames);
820 const char* cmprtr;
821 while ((cmprtr = (const char*)biter.getNext())) {
822 if ((cmprtr!=cp) && (EqualString(cmprtr, cp))) {
823 unique = FALSE;
824 break;
825 }
826 }
827 if (!unique) {
828 cp = DuplicateString(fullpath);
829 baseNames.appendElement(cp);
830 }
831 bi->setLabel(cp);
832 }
833 iter.setList(baseNames);
834 char* cp;
835 while ((cp=(char*)iter.getNext())) delete cp;
836 }
837 }
838
839 extern "C" void DXWindow_FileHistoryMenuMapCB(Widget , XtPointer clientdata, XtPointer )
840 {
841 DXWindow* dxw = (DXWindow*)clientdata;
842 dxw->buildFileHistoryMenu();
843 }
844
845