view anagram/vaclgui/ctrlpanel.cpp @ 21:1c9dac05d040

Add lint-style FALLTHROUGH annotations to fallthrough cases. (in the parse engine and thus the output code) Document this, because the old output causes warnings with gcc10.
author David A. Holland
date Mon, 13 Jun 2022 00:04:38 -0400
parents 13d2b8934445
children
line wrap: on
line source

/*
 * AnaGram, A System for Syntax Directed Programming
 * Copyright 1993-2002 Parsifal Software. All Rights Reserved.
 * See the file COPYING for license and usage terms.
 *
 * ctrlpanel.cpp
 */

#include <direct.h>
#include <fcntl.h>
#include <stdio.h>
#include "port.h"

#include <icritsec.hpp>
#include <imsgbox.hpp>

#include "about.hpp"
#include "agcstack.h"
#include "agfiledialog.hpp"
#include "readprofile.h"
#include "agrect.hpp"
#include "anom.h"
#include "bpe3.h"
#include "charsdc.h"
#include "conflictdc.h"
#include "config.h"
#include "coveragedc.h"
#include "ctrlpanel.hpp"
#include "dc.h"
#include "dpanel.hpp"
#include "error.h"
#include "errordc.h"
#include "file.h"
#include "fileview.hpp"
#include "ftview.hpp"
#include "gtview.hpp"
#include "helpview.hpp"
#include "items.h"
#include "keytabdc.h"
#include "keyword.h"
#include "openfile.hpp"
#include "operations.h"
#include "p.h"
#include "symtabdc.h"
#include "textfile.h"
#include "tokentabdc.h"
#include "proctabdc.h"
#include "profile-defs.h"
#include "q1a.h"
#include "rproc.h"
#include "ruletabdc.h"
#include "vaclgui.hpp"
#include "version.h"
#include "wm1.h"

//#define INCLUDE_LOGGING
#include "log.h"


#define TILDE '&'


ControlPanel  *controlPanel = 0;
IPoint         controlPanelLocation(-1, -1);

IRectangle     syntaxFileRect;
int            syntaxFileId = 0;


int                  ControlPanel::helpCursorSet = 0;
IPointerHandle       ControlPanel::helpCursor;
IPointerHandle       ControlPanel::activeCursor;
ISystemPointerHandle ControlPanel::waitCursor(ISystemPointerHandle::wait);

static IGraphicPushButton::Style
  buttonStyle =   IGraphicPushButton::sizeToGraphic
                | IGraphicPushButton::tabStop
                | IWindow::visible;


static void showWhatsNew() {
  AgHelpWindow::showHelpCentered("What's New");
}

ControlPanel::ControlPanel(unsigned long windowId)
  : IFrameWindow(windowId, AgFrame::frameParent, 0, IRectangle(),
		   IFrameWindow::titleBar
		 | IFrameWindow::systemMenu
		 | IFrameWindow::minimizeButton
		 //| IFrameWindow::border
		 | IFrameWindow::dialogBackground
		 | IFrameWindow::windowList
		 | IFrameWindow::sizingBorder
		 | IFrameWindow::noMoveWithOwner)
  , menuBar(windowId, this)
  , systemMenu(this)
  , systemMenuFont(menuFont = systemMenu.font())
  , canvas(nextChildId(), this, this, IRectangle(),
	     ISetCanvas::verticalDecks
	   | ISetCanvas::leftAlign
	   | ISetCanvas::packEven
	   | IWindow::clipChildren
	   | visible)
  , buttonCanvas(nextChildId(), &canvas, &canvas, IRectangle(),
		   ISetCanvas::horizontalDecks
		 | ISetCanvas::centerVerticalAlign
		 | IWindow::clipChildren
		 | ISetCanvas::leftAlign
		 | ISetCanvas::packTight 
		 | visible)
  , agButton(IDI_BMP_AG, &buttonCanvas, &buttonCanvas,
	     IDI_BMP_AG, IRectangle(), buttonStyle)
  , bpButton(IDI_BMP_BP, &buttonCanvas, &buttonCanvas,
	     IDI_BMP_BP, IRectangle(), buttonStyle)
  , ftButton(IDI_BMP_FT, &buttonCanvas, &buttonCanvas,
	     IDI_BMP_FT, IRectangle(), buttonStyle)
  , gtButton(IDI_BMP_GT, &buttonCanvas, &buttonCanvas,
	     IDI_BMP_GT, IRectangle(), buttonStyle)
  , warnButton(IDI_BMP_WARN, &buttonCanvas, &buttonCanvas,
	       IDI_BMP_WARN, IRectangle(), buttonStyle)
  , confButton(IDI_BMP_CONF, &buttonCanvas, &buttonCanvas,
	       IDI_BMP_CONF, IRectangle(), buttonStyle)
  , helpButton(IDI_BMP_HELPICON, &buttonCanvas, &buttonCanvas,
	       IDI_BMP_HELPICON, IRectangle(), buttonStyle)
  , statusControl(IDI_STATUS, &buttonCanvas, &buttonCanvas, IRectangle(),
		    IStaticText::defaultStyle()
		  | IStaticText::border3D)
  , statusControlHelp(&statusControl, "Status Indicator")
  , searchCanvas(nextChildId(), &canvas, &canvas, IRectangle(),
		   ISetCanvas::horizontalDecks
		 | ISetCanvas::leftAlign
		 | ISetCanvas::packTight
		 | IWindow::clipChildren
		 | visible)
  , searchKeyBox(IDI_SEARCH_KEY, &searchCanvas, "Size of Search key space")
  , searchKeyHelp(&searchKeyBox, "Search Key")
  , findNextButton(IDI_BMP_FINDNEXT, &searchCanvas, &searchCanvas,
		   IDI_BMP_FINDNEXT, IRectangle(), buttonStyle)
  , findPrevButton(IDI_BMP_FINDPREV, &searchCanvas, &searchCanvas,
		   IDI_BMP_FINDPREV, IRectangle(), buttonStyle)
  , flyText(nextChildId(), this)
  , flyOver(&flyText)
  , openFileName()
  //, busyFlag(false)
  , windowTitle(this, "AnaGram")
  , autobuildFlag(0)
  , showSyntaxFlag(1)
  , showStatsFlag(1)
  , stayOnTopFlag(1)
  //, minimized(0)
  , topmostFlag(0)
  , textColorChange(this, onTextColorChange)
  , linkColorChange(this, onLinkColorChange)
  , traversedColorChange(this, onTraversedColorChange)
  , quitAction(actionObject(this, quit))
  , accelerator(IDW_FRAME_WINDOW, this)
  , helpRequested(0)
{
  LOGSECTION("ControlPanel::ControlPanel");
  controlPanel = this;

  AgString initializer = AgFetchProfile("initializationData");
  LOGS("profile retrieved");
  if (initializer.exists() && initializeFrom(initializer.pointer())) {
    LOGS("initialization problem");
    IMessageBox messageBox(controlPanel);
    messageBox.setTitle("AnaGram");
    messageBoxShowing++;
    messageBox.show("Error initializing from registry",
		    IMessageBox::information);
    messageBoxShowing--;
  }
  LOGV(recentFiles.size());

  analyzeThread.adjustPriority(-1);

  waitCursor = ISystemPointerHandle(ISystemPointerHandle::wait);

  searchKeyBox.enterAction = actionObject(this, findNext);

  flyOver.setHelpText(handle(), IDI_BMP_AG);

  helpCursor = IPointerHandle(LoadCursor(0, IDC_HELP));

  textColorChange.attach(&ColorSpec::helpText);
  linkColorChange.attach(&ColorSpec::helpLink);
  traversedColorChange.attach(&ColorSpec::helpUsedLink);

  buttonCanvas.setDeckCount(1);
  searchCanvas.setDeckCount(1);
  canvas.setDeckCount(1);
  buttonCanvas.setText("");

  LOGV(agButton.size().asString());

  ISize padSize = buttonCanvas.pad();
  padSize.setWidth(4);
  buttonCanvas.setPad(padSize);

  buttonCanvas.setMargin(ISize(4, 2));

  searchCanvas.setMargin(ISize(4, 2));

  padSize = searchCanvas.pad();
  padSize.setWidth(4);
  searchCanvas.setPad(padSize);

  ISize margin = canvas.margin();
  margin.setHeight(0);
  canvas.setMargin(margin);

  padSize = canvas.pad();
  padSize.setHeight(0);
  canvas.setPad(padSize);

  setClient(&canvas);       // Set canvas control for client area


  // Set self as command event handler

  flyOver.handleEventsFor(&buttonCanvas);
  flyOver.handleEventsFor(&searchCanvas);
  IFrameWindow::removeDefaultHandler();
  IFrameHandler::handleEventsFor(this);
  ICommandHandler::handleEventsFor(this);
  IMouseHandler::handleEventsFor(this);
  IPaintHandler::handleEventsFor(&canvas);
  IPaintHandler::handleEventsFor(&buttonCanvas);
  IPaintHandler::handleEventsFor(&searchCanvas);
  IKeyboardHandler::handleEventsFor(this);
  //IResizeHandler::handleEventsFor(this);
  LOGS("Command handler attached");

  userHandler = new AgUserHandler;
  userHandler->handleEventsFor(this);
  AgHelpHandler::handleEventsFor(this);

  IMenuHandler::handleEventsFor(this);
  IFocusHandler::handleEventsFor(&searchCanvas);
  IFocusHandler::handleEventsFor(&searchKeyBox);

  systemMenu.deleteItem(ISystemMenu::idMaximize);
  //systemMenu.deleteItem(ISystemMenu::idSize);
  systemMenu.disableItem(ISystemMenu::idRestore);

  statusControl.setFont(IFont("Arial", 8));

  menuBar.disableMinimumSizeCaching();
  static const int menuIdList[] = {
    IDM_FILE, IDM_BROWSE, IDM_OPTIONS, IDM_WINDOWS, IDM_HELP, 0
  };
  int i;
  int menuWidth = 0;
  for (i = 0; menuIdList[i]; i++) {
    int itemWidth = menuBar.itemRect(menuIdList[i]).width();
    LOGV(itemWidth);
    menuWidth += itemWidth;
  }
  LOGV(menuWidth);

  int statusWidth = statusControl.font().textWidth("   Analyzed   ");
  ISize minSize(statusWidth, agButton.minimumSize().height());
  statusControl.setMinimumSize(minSize);

  statusControl.setAlignment(IStaticText::centerCenter);
  setStatus();

  int minWidth = buttonCanvas.minimumSize().width();
  if (minWidth < menuWidth) {
    statusWidth += menuWidth - minWidth;
    minSize.setWidth(statusWidth);
    statusControl.setMinimumSize(minSize);
    minWidth = menuWidth;
  }
  minSize = searchKeyBox.minimumSize();
  minWidth -= 2*agButton.size().width();
  minWidth -= 2*searchCanvas.pad().width();
  minWidth -= 2*searchCanvas.margin().width();

  minSize.setWidth(minWidth);
  searchKeyBox.setMinimumSize(minSize);

  LOGV(menuFont.name()) LCV(menuFont.pointSize());
  LOGV(font().name()) LCV(font().pointSize());

  LOGS("Menu handler attached");

  // Set application icon
  //setIcon(IDI_ICON);
  //iconHandle = icon();
  setIcon(iconHandle);

  LOGS("Icon set");
  IRectangle desktopRect = desktopWindow()->rect();

  int titleBarHeight = 24;
  cascadeIncrement = IPoint(titleBarHeight, titleBarHeight);
  cascadeOrigin = IPoint(0, 0);

  int verticalOffset = 0;

  LOGV(cascadeOrigin.asString());

  cascadeOffset = cascadeOrigin;

  minSize = canvas.minimumSize();
  LOGV(minSize);
  IRectangle frameRect = frameRectFor(IRectangle(IPoint(0, 0), minSize));
  IRectangle clientRect = clientRectFor(frameRect);
  //minimumSize = frameRect.size();
  LOGV(frameRect.asString());
  cint measure = desktopRect.size();
  cint panelSize = frameRect.size();
  IPoint where = controlPanelLocation;
  LOGV(where);
  if (where.x() < 0) {
    where = (IPair) place(measure, panelSize, 20);
  }
  LOGV(where);
  frameRect.moveTo(where);
  frameRect = adjustPos(frameRect);
  LOGV(frameRect.asString());
  //sizeTo(frameRect.size());
  //moveTo(where);
  moveSizeTo(frameRect);
  LOGV(menuBar.size().asString());
  LOGV(canvas.position()) LCV(canvas.size()) LCV(size());
  LOGV(menuBar.itemRect(IDM_FILE).asString());
  LOGV(menuBar.itemRect(IDM_HELP).asString());
/*
  i = menuWidth = 0;
  for (i = 0; menuIdList[i]; i++) {
    menuWidth += menuBar.itemRect(menuIdList[i]).width();
  }
  LOGV(menuWidth);
*/

  //maxDataPanelWidth = where.x();

  verticalOffset += frameRect.size().height();

// Set focus to this window and show
  setFocus();
  show();

  if (commandLineFile.exists()) {
    defer(this, openCommandLineFile);
  }
  if (!initializer.exists() || lastVersion < INTVERSION) {
    defer(showWhatsNew);
  }
}

void closeActionWindow() {
  LOGSECTION("closeActionWindow");
  pActionWindow->close();
}


/***********************************************************/
/* Application main window destructor.  It stops the event */
/* handling and deletes any objects on the heap.           */
/***********************************************************/
ControlPanel :: ~ControlPanel ()
{
  LOGSECTION("ControlPanel::~ControlPanel");
  flyOver.stopHandlingEventsFor(&buttonCanvas);
  flyOver.stopHandlingEventsFor(&searchCanvas);
  ICommandHandler::stopHandlingEventsFor(this);
  IFrameHandler::stopHandlingEventsFor(this);
  IMenuHandler::stopHandlingEventsFor(this);
  IMouseHandler::stopHandlingEventsFor(this);
  userHandler->stopHandlingEventsFor(this);
  AgHelpHandler::stopHandlingEventsFor(this);
  IPaintHandler::stopHandlingEventsFor(&canvas);
  IPaintHandler::stopHandlingEventsFor(&buttonCanvas);
  IPaintHandler::stopHandlingEventsFor(&searchCanvas);
  IFocusHandler::stopHandlingEventsFor(&searchCanvas);
  IFocusHandler::stopHandlingEventsFor(&searchKeyBox);
  IKeyboardHandler::stopHandlingEventsFor(this);
  //IResizeHandler::stopHandlingEventsFor(this);
  delete userHandler;
  controlPanel = 0;
  defer(closeActionWindow);
}

/*
Boolean ControlPanel::windowResize(IResizeEvent &event){
  LOGSECTION("ControlPanel::windowResize");
  ok_ptr(this);

  if (event.controlWindow() != this) {
    return false;
  }
  LOGV(event.newSize().asString());
  if (!isVisible()) {
    return false;
  }
  if (!(event.newSize() >= minimumSize)) {
    sizeTo(minimumSize);
    return true;
  }
  //canvas.sizeTo(clientRectFor(IRectangle(IPoint(), event.newSize())).size());
  LOGV(id());
  return false;
}
*/

Boolean ControlPanel::ComboBox::enter(IControlEvent &event) {
  LOGSECTION("ControlPanel::ComboBox::enter");
  LOGV(listShowing);
  if (listShowing) {
    unsigned s = selection();
    LOGV(s) LCV(IComboBox::notFound);
    if (s == IComboBox::notFound) {
      return false;
    }
    IString text = itemText(s);
    LOGV((char *) text);
    setText(text);
    listShowing = 0;
    return false;
  }
  else {
    LOGV(selection());
    LOGV(IComboBox::notFound);
    LOGV(isListShowing());
    LOGV(hasChanged());
    enterAction.perform();
    IString contents = text();
    if (contents.length() == 0) {
      return false;
    }
    int n = count();
    while (n--) {
      if (itemText(n) == contents) {
      	remove(n);
      	break;
      }
    }
    addAsFirst(contents);
    n = count();
    LOGV(count());
    if (n < 8 && n > minimumRows()) {
      setMinimumRows(8);
    }
    LOGV(minimumRows());
  }
  return true;
}

Boolean ControlPanel::ComboBox::listShown(IControlEvent &event) {
  LOGSECTION("ControlPanel::ComboBox::listShown");
  listShowing = 1;
  return false;
}

void ControlPanel::idSyntaxFile(AgString name) {
  LOGSECTION("ControlPanel::idSyntaxFile");
  openFileName = infile_name = name;   // Store selected file name
  errorReportFile = AgString();
  openFileTimestamp = getFileTimestamp(name.pointer());
  AgString settingsFileName
    = openFileName.lastCut("\\/").leftI().concat("*.syn");
  restoreDirectory();
/*
  char drive[_MAX_DRIVE];
  _splitpath(openFileName.pointer(), drive, NULL, NULL, NULL);
  _chdrive(toupper(drive[0]) - 'A' + 1);
  LOGV(directoryName.pointer());
  chdir(directoryName.pointer());
  work_dir_name = directoryName;
*/
  AgString fileName = openFileName.lastCut("\\/").rightX();

  simple_file_name = fileName.lastCut('.').leftX();

  LOGV(fileName.pointer());
  LOGV(simple_file_name.pointer());
}

void ControlPanel::restoreDirectory() {
  LOGSECTION("ControlPanel::restoreDirectory");
  AgString directoryName
    = openFileName.lastCut("\\/").leftX();
  if (directoryName[directoryName.size() - 1] == ':') {
    directoryName.concat("\\");
  }
  char drive[_MAX_DRIVE];
  _splitpath(openFileName.pointer(), drive, NULL, NULL, NULL);
  _chdrive(toupper(drive[0]) - 'A' + 1);
  LOGV(directoryName.pointer());
  chdir(directoryName.pointer());
  work_dir_name = directoryName;
}

void ControlPanel::loadSyntaxFile() {
  LOGSECTION("ControlPanel::loadSyntaxFile");

  inputFile = text_file(openFileName);
  reset_parser();
  errorList.reset();

  setStatus();
  windowTitle.setViewText(simple_file_name.pointer());
  if (showSyntaxFlag) {
    syntaxFileId = nextChildId();
    FileWindow *fileWindow = new FileWindow(syntaxFileId, inputFile,
					    syntaxFileRect);
    fileWindow->enableCursorBar();
    fileWindow->setAutoDeleteObject();
    fileWindow->syntaxDependent = 1;
    LOGV(syntax_state);
    if (syntaxFileRect.area() <= 0) {
      AgQuadrant quad = findQuadrant(controlPanel);
      if (quad == lowerRight) {
	quad = upperRight;
      }
      else {
	quad = lowerRight;
      }
      AgRectangle bestRect(
        AgRectangle::desktop().position(quad),
        fileWindow->size(),
        opposite(quad)
      );
      IPoint where = (IPair) bestRect.position();
      fileWindow->moveTo(where);
      LOGV(where.asString());
    }
    //cascadeOffset -= cascadeIncrement;
    fileWindow->show();
  }
}

void ControlPanel::makeControlPanel() {
  LOGSECTION("makeControlPanel");
  controlPanel = new ControlPanel(IDW_FRAME_WINDOW);
  controlPanel->setAutoDeleteObject();
  LOGS("Control panel complete");
  if (errorList.size()) {
    defer(controlPanel, showErrors);
  }
}

ControlPanel &ControlPanel::makeTopmost() {
  LOGSECTION_OFF("ControlPanel::makeTopmost");
  if (!stayOnTopFlag || topmostFlag++) {
    return *this;
  }

  SetWindowPos(
    handle(),
    HWND_TOP,        //HWND_TOPMOST,
    0,0,0,0,
    SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);

  topmostFlag = 0;
  return *this;
}

void ControlPanel::monitor(IThread &thread) {
  LOGSECTION_OFF("ControlPanel::monitor");
  StatisticsWindow *window = 
    (StatisticsWindow *) AgFrame::windowRegistry.find("Statistical Summary");
  if (window == NULL) {
    window = new StatisticsWindow();
    window->setAutoDeleteObject();
    IPoint where = (IPair) placeRelative(window->size(), controlPanel);
    window->moveTo(where);
  }
  window->show().setFocus();
  {
    ICritSec cookie;
    analyzeThreadActive = 1;
  }
  IReference<ITimerFn> timerFn = new TimerFn(timer, *window, thread);
  timer.start(timerFn, 250);
}

void ControlPanel::onLinkColorChange() {
  LOGSECTION("ControlPanel::onLinkColorChange");
  ColorSpec::helpText.bg() = ColorSpec::helpLink.bg();
  ColorSpec::helpUsedLink.bg() = ColorSpec::helpLink.bg();
}

void ControlPanel::onTextColorChange() {
  LOGSECTION("ControlPanel::onTextColorChange");
  ColorSpec::helpLink.bg() = ColorSpec::helpText.bg();
  ColorSpec::helpUsedLink.bg() = ColorSpec::helpText.bg();
}

void ControlPanel::onTraversedColorChange() {
  LOGSECTION("ControlPanel::onTraversedColorChange");
  ColorSpec::helpText.bg() = ColorSpec::helpUsedLink.bg();
  ColorSpec::helpLink.bg() = ColorSpec::helpUsedLink.bg();
}

void ControlPanel::openCommandLineFile() {
  LOGSECTION("ControlPanel::openCommandLineFile");
  char *p = commandLineFile.pointer();
  LOGV(p);
  FILE *file = fopen(p, "r");
  if (file == 0) {
    char *q = strrchr(p, '\\');
    if (q == 0) {
      q = p;
    }
    LOGV(q);
    if (strrchr(q, '.') == 0) {
      commandLineFile = commandLineFile.concat(".syn");
      p = commandLineFile.pointer();
      LOGV(p);
      file = fopen(p, "r");
    }
  }
  if (file == 0) {
    AgString msg = AgString::format("Cannot open %s", 
				    commandLineFile.pointer());
    IMessageBox messageBox(controlPanel);
    messageBoxShowing++;
    messageBox.show(msg.pointer(), IMessageBox::information);
    messageBoxShowing--;
    return;
  }
  fclose(file);
  activeCursor = waitCursor;
  resetCursor();
  LOGS("Wait cursor set");

  AgString fullpath(_MAX_PATH);
  _fullpath(fullpath.pointer(), commandLineFile.pointer(), _MAX_PATH);
  idSyntaxFile(fullpath);
  monitor(analyzeThread);
  loadSyntaxFile();
  //analyzeThread.adjustPriority(-20);
  //analyzeThread.start(new AnalyzeGrammarFn(this));
  *buildErrorMsg = 0;
  rememberFile(fullpath);
  if (autobuildFlag) {
    IReference<IThreadFn> fn = new BuildParserFn(this);
    analyzeThread.start(fn);
  }
  else {
    IReference<IThreadFn> fn = new AnalyzeGrammarFn(this);
    analyzeThread.start(fn);
  }
}

char *ControlPanel::removeTilde(char *s) {
  char *copy = s;
  char *t = s;
  while (*s) {
    if (*s != TILDE) {
      *t++ = *s;
    }
    s++;
  }
  *t = 0;
  return copy;
}

void ControlPanel::selectMenuItem(long id) {
  menuBar.selectItem(id);
}

void ControlPanel::setStatus() {
  LOGSECTION("ControlPanel::setStatus");
  LOGV(simple_file_name);
  LOGV(syntax_state);
  LOGV(syntaxStateString[syntax_state]);
  statusControl.setText(syntaxStateString[syntax_state]);
}

void ControlPanel::showErrors() {
  dc_ref error_display = new error_display_dc;
  error_display->des->d_size.y = errorList.size();
  AgDataViewPlug *connector = new AgDataViewPlug(error_display);
  error_display->windowConnector = connector;
  AgDataPanel* newPanel = new AgDataPanel(connector);
  cascadeOffset -= cascadeIncrement;
  AgRectangle rect(controlPanel->position(), controlPanel->size());
  LayoutRef ref(rect);
  IPoint warningPos = placeWindow(newPanel->size(), ref);
  newPanel->moveTo(warningPos);
  newPanel->setAutoDeleteObject();
  newPanel->show().setFocus();
}

void ControlPanel::TimerFn::timerExpired(unsigned long) {
  LOGSECTION_ON("Timer expired");
  LOGV((int) &window);
  LOGV((int) AgFrame::windowRegistry.find("Statistical Summary"));
  LOGV(messageBoxShowing);
  if (messageBoxShowing) {
    timer.stop();
    return;
  }
  int windowExists(&window == 
		   AgFrame::windowRegistry.find("Statistical Summary"));
  if (windowExists) {
    //LOGSECTION("Critical section");
    ICritSec cookie;
    window.updateDisplay();
  }
  {
    //LOGSECTION("Critical section");
    ICritSec cookie;
    controlPanel->setStatus();
  }
  if (!thread.isStarted() || !analyzeThreadActive) {
    timer.stop();
    LOGS("Timer stopped");
    LOGV(controlPanel->showStatsFlag) LCV(windowExists);
    IPoint warningPos;
    if (windowExists && !controlPanel->showStatsFlag) {
      AgFrame::windowRegistry.remove(window.id());
      window.close();
      windowExists = false;
    }
    else if (windowExists) {
      window.setFocus();
    }
    ControlPanel::activeCursor = IPointerHandle();
    controlPanel->resetCursor();
    LOGS("Cursor set to default");
    LOGV(errorList.size());
    IFrameWindow *errorWindow = AgFrame::windowRegistry.find("Warnings");
    if (errorWindow != NULL) {
      AgFrame::windowRegistry.remove(errorWindow->id());
      errorWindow->close();
    }
/*
    AgDataPanel *errorWindow = (AgDataPanel *) AgFrame::windowRegistry.find("Warnings");
    if (errorWindow != NULL) {
      LOGS("errorWindow exists");
      errorWindow->dataView->reset();
      errorWindow->show().setFocus();
    }
    else if (errorList.size()) {
*/
    if (errorList.size()) {
      //pop_up_window(new error_display_dc);
      dc_ref error_display = new error_display_dc;
      error_display->des->d_size.y = errorList.size();
      AgDataViewPlug *connector = new AgDataViewPlug(error_display);
      error_display->windowConnector = connector;
      AgDataPanel* newPanel = new AgDataPanel(connector);
      cascadeOffset -= cascadeIncrement;
      AgRectangle rect(controlPanel->position(), controlPanel->size());
      LayoutRef ref(rect);
      if (windowExists) {
        rect = AgRectangle(window.position(), window.size());
        ref.merge(rect);
      }
      warningPos = placeWindow(newPanel->size(), ref);
      newPanel->moveTo(warningPos);
      newPanel->setAutoDeleteObject();
      newPanel->show().setFocus();
    }
    if (*buildErrorMsg) {
      IMessageBox messageBox(controlPanel);
      LOGS("Showing message Box");
      messageBoxShowing++;
      messageBox.show(buildErrorMsg, IMessageBox::information);
      messageBoxShowing--;
      *buildErrorMsg = 0;
      LOGS("Done showing message box");
    }
    LOGV(thread.variable("Error Message"));
    if (*(char *) thread.variable("Error Message")) {
      controlPanel->quitAction.performDeferred();
    }
  }
  LOGV(analyzeThreadActive) LCV(thread.isStarted());
}

Boolean ControlPanel::showHelp(IEvent &event) {
  LOGSECTION("ControlPanel::showHelp");
  helpRequested = 1;
  return AgHelpWindow::showHelp(selectedMenuText);
}

Boolean ControlPanel::gotFocus(IControlEvent &event) {
  LOGSECTION("ControlPanel::gotFocus");
  LOGV((int) event.controlWindow()) LCV((int) &searchKeyBox);
  if (event.controlWindow() != &searchKeyBox) return false;
  if (helpCursorSet) {
    ControlPanel::helpCursorSet = 0;
    AgHelpWindow::showHelp("Search Key");
    ControlPanel::resetCursor();
    return true;
  }
  agButton.disableDefault();
  return true;
}

Boolean ControlPanel::virtualKeyPress(IKeyboardEvent &event) {
  LOGSECTION("ControlPanel::virtualKeyPress");
  LOGV((int) event.virtualKey());
  LOGV(event.isShiftDown()) LCV(event.isCtrlDown()) LCV(event.isAltDown());
  switch (event.virtualKey()) {
    case IKeyboardEvent::f8: {
      if (event.isShiftDown() || event.isCtrlDown() || event.isAltDown()) {
	return false;
      }

      int first = 0, last = AgFrame::windowRegistry.size();
      while (first < last) {
	LOGV(AgFrame::windowRegistry[first].id)
	  LCV(AgFrame::windowRegistry[first].title.pointer());
	if (AgFrame::windowRegistry[first].isActive) {
	  LOGS("found it");
	  AgFrame::windowRegistry[first].window->setFocus();
	  break;
	}
	first++;
      }
      return true;
    }
  }
  return false;
}

Boolean ControlPanel::paintWindow(IPaintEvent &event) {
  LOGSECTION("ControlPanel::paintWindow");
  LOGV(event.rect().asString());
  event.clearBackground(IGUIColor::dialogBgnd);
  return false;
}


Boolean ControlPanel::mouseClicked(IMouseClickEvent &event) {
  LOGSECTION("ControlPanel::mouseClicked");
  //IWindow *controlWindow = event.controlWindow();
  //LOGV(controlWindow->id());
  LOGV(buttonCanvas.id());
  LOGV(event.mouseAction());
  IWindow *window = windowWithHandle(event.windowUnderPointer());
  LOGV(window ? window->id(): 0);
  if (window) switch (window->id()) {
    case IDI_BMP_AG      :
    case IDI_BMP_BP      :
    case IDI_BMP_FT      :
    case IDI_BMP_GT      :
    case IDI_BMP_WARN    :
    case IDI_BMP_CONF    :
    case IDI_BMP_HELPICON:
    case IDI_BMP_FINDNEXT:
    case IDI_BMP_FINDPREV:
    case IDI_SEARCH_KEY  :
    return false;
  }
  helpCursorSet = 0;
  resetCursor();
  return false;
}

void ControlPanel::resetCursor() {
  LOGSECTION("ControlPanel::resetCursor");
  int n = AgFrame::windowRegistry.size();
  while (n--) {
    AgFrame *frame = AgFrame::windowRegistry[n].window;
    frame->setMousePointer(activeCursor);
  }
  if (controlPanel) {
    controlPanel->setMousePointer(activeCursor);
  }
  LOGS("Cursor reset");
}

ControlPanel &ControlPanel::close() {
  LOGSECTION("ControlPanel::close");
  closeRect = rect();
  IFrameWindow::close();
  return *this;
}

void ControlPanel::quit() {
  LOGSECTION("ControlPanel::quit");
  LOGV(analyzeThreadActive);
  if (analyzeThread.isStarted() || analyzeThreadActive) {
    analyzeThread.stop();
    {
      ICritSec cookie;
      analyzeThreadActive = 0;
      quitAction.performDeferred();
    }
    return;
  }
  int n = AgFrame::windowRegistry.size();
  if (n) {
    closeWindows();
    defer(reset_parser);
    quitAction.performDeferred();
    return;
  }
  gatherProfile();
  close();
  controlPanel = 0;
}

/***********************************************************/
/* ControlPanel main window command event handler             */
/***********************************************************/

Boolean ControlPanel::systemCommand(ICommandEvent &event) {
  LOGSECTION("ControlPanel::systemCommand");
  LOGV(event.commandId());
  int commandId = event.commandId() & 0xfff0;
  LOGV(commandId);
  if (messageBoxShowing) {
    messageBeep();
    return true;
  }
  if (commandId == ISystemMenu::idClose) {
    LOGSECTION("ISystemMenu::idClose");
    quitAction.performDeferred();
    return true;
  }
  else if (commandId == ISystemMenu::idMinimize) {
    hideWindows();
    systemMenu.disableItem(ISystemMenu::idMinimize);
    systemMenu.disableItem(ISystemMenu::idMove);
    systemMenu.enableItem(ISystemMenu::idRestore);
  }
  else if (commandId == ISystemMenu::idRestore) {
    LOGSECTION("ISystemMenu::idRestore");
    restoreWindows();
    systemMenu.enableItem(ISystemMenu::idMinimize);
    systemMenu.enableItem(ISystemMenu::idMove);
    systemMenu.disableItem(ISystemMenu::idRestore);
    return false;
  }
  return false;
}

Boolean ControlPanel::deactivated(IFrameEvent &event) {
  LOGSECTION_OFF("ControlPanel::deactivated");
  if (event.controlWindow() != this) {
    return false;
  }
  AgFrame::activeWindowCount--;
  LOGV(AgFrame::activeWindowCount);
  return false;
}

Boolean ControlPanel::activated(IFrameEvent &event) {
  LOGSECTION("ControlPanel::activated");
  if (event.controlWindow() != this) {
    return false;
  }
  AgFrame::activeWindowCount++;
  LOGV(AgFrame::activeWindowCount);
  IWindowHandle previous((void *) event.parameter2());
  IWindow *previousWindow = windowWithHandle(previous);
  LOGV((int) previousWindow);
  if (previousWindow == 0) {
    int k = AgFrame::windowRegistry.size();
    while (k--) {
      if (!AgFrame::windowRegistry[k].isActive) {
	continue;
      }
      LOGV(k);
      AgFrame::windowRegistry[k].window->setFocus();
      break;
    }
  }
  setFocus();
  if (isMinimized()) {
    return false;
  }
  //if (!minimized) return false;
  //minimized = false;
  int n = AgFrame::windowRegistry.size();
  for (int i = 0; i< n; i++) {
    AgFrame *window = AgFrame::windowRegistry[i].window;
    LOGV(AgFrame::windowRegistry[i].isShowing);
    LOGV(AgFrame::windowRegistry[i].title.pointer());
    if (AgFrame::windowRegistry[i].isShowing) {
      window->show();
    }
  }
  return false;
}

void ControlPanel::findNext() {
  LOGSECTION("ControlPanel::findNext");
  AgString key = (char *) searchKeyBox.text();
  LOGV(key);
  int n = AgFrame::windowRegistry.size();
  LOGV(n);
  AgFrame *window = 0;
  while (n--) {
    if (AgFrame::windowRegistry[n].isActive) {
      window = AgFrame::windowRegistry[n].window;
      break;
    }
  }
  LOGV((int) window);
  if (window == 0) {
    messageBeep();
    return;
  }
  LOGV((int) window);
  if (!window->isVisible() || key.size() == 0) {
    messageBeep();
    return;
  }
  window->setFocus();
  LOGS("focus has been set");
  if (!window->findNext(key)) {
    messageBeep();
  }
  n = searchKeyBox.count();
  while (n--) {
    if (searchKeyBox.itemText(n) == key.pointer()) {
      searchKeyBox.remove(n);
      break;
    }
  }
  searchKeyBox.addAsFirst(key.pointer());
  searchKeyBox.setText(key.pointer());
  searchKeyBox.selectRange();
}

void ControlPanel::findPrev() {
  LOGSECTION("ControlPanel::findPrev");
  AgString key = (char *) searchKeyBox.text();
  LOGV(key);
  int n = AgFrame::windowRegistry.size();
  AgFrame *window = 0;
  while (n--) {
    if (AgFrame::windowRegistry[n].isActive) {
      window = AgFrame::windowRegistry[n].window;
      break;
    }
  }
  if (window == 0) {
    messageBeep();
    return;
  }
  LOGV((int) window);
  if (!window->isVisible() || key.size() == 0) {
    messageBeep();
    return;
  }
  window->setFocus();
  LOGS("focus has been set");
  if (!window->findPrev(key)) messageBeep();
  n = searchKeyBox.count();
  while (n--) {
    if (searchKeyBox.itemText(n) == key.pointer()) {
      searchKeyBox.remove(n);
      break;
    }
  }
  searchKeyBox.addAsFirst(key.pointer());
  searchKeyBox.setText(key.pointer());
  searchKeyBox.selectRange();
}

static AgString ascii(int x) {
  char buf[20];
  itoa(x, buf, 10);
  return buf;
}

void ControlPanel::gatherProfile() {
  LOGSECTION("ControlPanel::gatherProfile");
  AgCharStack charStack;
  ColorDialog::stackSettings(charStack);
  FontDialog::stackSettings(charStack);
  charStack << "Autobuild=" << ascii(autobuildFlag) << '\n';
  charStack << "ShowStatistics=" << ascii(showStatsFlag) << '\n';
  charStack << "ShowSyntax=" << ascii(showSyntaxFlag) << '\n';
  charStack << "StayOnTop=" << ascii(stayOnTopFlag) << '\n';
  charStack << "cpLoc=" << position().asString() << '\n';
  IString r = syntaxFileRect.asString();
  char *q = strchr((char *)r, '(');
  charStack << "sfRect=" << q << '\n';
  int n = recentFiles.size();
  int i = n - 6;
  if (i < 0) i = 0;
  while (i < n) {
    charStack << "RecentFile:" << recentFiles[i] << '\n';
    i++;
  }
  charStack << "Version=" << ascii(INTVERSION) << "\n";
  charStack << "endInitializationData";
  AgString string = charStack.popString();
  LOGV(string);
  AgStoreProfile("initializationData", string.pointer());
}

void ControlPanel::rememberFile(AgString fileName) {
  LOGSECTION("ControlPanel::rememberFile");
  LOGV(fileName);
  int n = recentFiles.size();
  for (int i = 0; i < n; i++) {
    if (recentFiles[i].iEq(fileName)) {
      n--;
      while (i < n) {
        recentFiles[i] = recentFiles[i+1];
        i++;
      }
      recentFiles[i] = fileName;
      LOGV(i) LCV(n);
      return;
    }
  }
  LOGS("Not there, add it");
  if (n >= 12) {
    for (i = 0; i < 11; i++) recentFiles[i] = recentFiles[i+1];
    recentFiles[i] = fileName;
    return;
  }
  recentFiles.push(fileName);
  LOGV(recentFiles.size());
}

Boolean ControlPanel::command(ICommandEvent &cmdEvent) {
  IResourceLibrary  resLib;

  LOGSECTION("ControlPanel::command");
  LOGV(cmdEvent.commandId());

  LOGV(helpCursorSet);
  if (analyzeThreadActive) return true;
  if (messageBoxShowing) {
    messageBeep();
    return true;
  }
  if (helpCursorSet) {
    //setMousePointer(activeCursor);
    activeCursor = IPointerHandle();
    resetCursor();
    helpCursorSet = 0;
    AgString topic;
    LOGV(ControlPanel::selectedMenuText);
    if (!ControlPanel::selectedMenuText.exists()) {
      switch (cmdEvent.commandId()) {
        case IDI_BMP_AG       : selectedMenuText = "Analyze Grammar"; break;
        case IDI_BMP_BP       : selectedMenuText = "Build Parser"; break;
        case IDI_BMP_FT       : selectedMenuText = "File Trace"; break;
        case IDI_BMP_GT       : selectedMenuText = "Grammar Trace"; break;
        case IDI_BMP_WARN     : selectedMenuText = "Warnings"; break;
        case IDI_BMP_CONF     : selectedMenuText = "Conflicts"; break;
        case IDI_BMP_HELPICON : selectedMenuText = "Help Cursor"; break;
        case IDI_BMP_FINDNEXT : selectedMenuText = "Find Next"; break;
        case IDI_BMP_FINDPREV : selectedMenuText = "Find Previous"; break;
      }
    }
    LOGV(selectedMenuText);
    AgHelpWindow::showHelp(selectedMenuText);
    selectedMenuText.discardData();
    return true;
  }
  if (ControlPanel::selectedMenuText.exists()) {
    selectedMenuText.discardData();
  }
  switch (cmdEvent.commandId()) {
    case IDI_BMP_HELPICON: {
      //MouseDrop *mouseDrop = new MouseDrop(this);
      setMousePointer(helpCursor);
      helpCursorSet = 1;
      int n = AgFrame::windowRegistry.size();
      while (n--) {
        AgFrame *frame = AgFrame::windowRegistry[n].window;
        if (frame->helpCursorSupported) {
	  frame->setMousePointer(helpCursor);
	}
      }
      return true;
    }
    case IDI_BMP_AG:
    case IDM_ANALYZE: {
      // Create and show File open dialog
      LOGSECTION("IDM_ANALYZE");
      AgFileDialog dialog(this);
      dialog.setFilter("Syntax Files\0*.syn\0All Files\0*.*\0");
      dialog.setTitle("Analyze Grammar");
      dialog.setExt("syn");
      if (dialog.showModally()) {
        //IPointerHandle pointerHandle = mousePointer();
        LOGSECTION("Starting fileread and analysis");
        //ISystemPointerHandle waitPointer(ISystemPointerHandle::wait);
        activeCursor = waitCursor;
        //setMousePointer(waitCursor);
        resetCursor();
        LOGS("Wait cursor set");
        //close_syntax_windows();
        //reset_parser();
        LOGS("Parser reset");
        //logWindows();

        closeSyntaxWindows();
        AgString fileName = dialog.fileName();
        idSyntaxFile(fileName);
        *buildErrorMsg = 0;
        monitor(analyzeThread);
        loadSyntaxFile();
        rememberFile(fileName);
        IReference<IThreadFn> fn = new AnalyzeGrammarFn(this);
        analyzeThread.start(fn);
      }
      return true;
    }
    case IDM_REANALYZE: {
      LOGSECTION("IDM_REANALYZE");
      activeCursor = waitCursor;
      resetCursor();
      closeSyntaxWindows();
      idSyntaxFile(openFileName);
      *buildErrorMsg = 0;
      monitor(analyzeThread);
      loadSyntaxFile();
      IReference<IThreadFn> fn = new AnalyzeGrammarFn(this);
      analyzeThread.start(fn);
      return true;
    }
    case IDI_BMP_BP:
    case IDM_BUILD_PARSER: {
      LOGSECTION("IDM_BUILD_PARSER");
      AgFileDialog dialog(this);
      dialog.setFilter("Syntax Files\0*.syn\0All Files\0*.*\0");
      dialog.setTitle("Build Parser");
      dialog.setExt("syn");
      if (!dialog.showModally()) {
	return true;
      }
      activeCursor = waitCursor;
      resetCursor();
      closeSyntaxWindows();
      AgString fileName = dialog.fileName();
      idSyntaxFile(fileName);
      monitor(analyzeThread);
      loadSyntaxFile();
      buildErrorMsg[0] = 0;
      rememberFile(fileName);
      IReference<IThreadFn> fn = new BuildParserFn(this);
      analyzeThread.start(fn);

      return true;

    }
    case IDM_REBUILD: {
      LOGSECTION("IDM_REBUILD");
      restoreDirectory();
      activeCursor = waitCursor;
      closeSyntaxWindows();
      idSyntaxFile(openFileName);
      monitor(analyzeThread);
      loadSyntaxFile();
      buildErrorMsg[0] = 0;
      IReference<IThreadFn> fn = new BuildParserFn(this);
      analyzeThread.start(fn);
      return true;
    }
    case IDM_BUILD: {
      LOGSECTION("IDM_BUILD");
      restoreDirectory();
      monitor(analyzeThread);
      activeCursor = waitCursor;
      resetCursor();
      *buildErrorMsg = 0;
      IReference<IThreadFn> fn = new BuildParserFn(this);
      analyzeThread.start(fn);
      return true;
    }
    case IDM_COPY: {
      IClipboard clipboard(handle());
      clipboard.empty();
      int n = AgFrame::windowRegistry.size();
      while (n--) {
	if (AgFrame::windowRegistry[n].isActive) {
	  LOGS("found it");
          AgFrame::windowRegistry[n].window->copyTo(clipboard);
	  break;
	}
      }
      return true;
    }
    case IDM_EXIT: {
      LOGSECTION("IDM_EXIT");
      if (analyzeThread.isStarted()) {
	analyzeThread.stop();
      }
      quitAction.performDeferred();
      return true;
    }
    case IDI_BMP_WARN: {
      LOGSECTION("IDI_BMP_WARN");
      if (errorList.size()) {
	pop_up_window(new error_display_dc);
      }
      else {
	messageBeep();
      }
      return 1;
    }
    case IDI_BMP_CONF: {
      LOGSECTION("IDI_BMP_CONF");
      if (unres_con->nt) {
	pop_up_window(new unres_con_dc);
      }
      else {
	messageBeep();
      }
      return 1;
    }
    case IDM_ERROR_TRACE: {
      LOGSECTION("IDM_ERROR_TRACE");
      AgFileDialog dialog(this);
      dialog.setFilter("Trace Files\0*.etr\0All Files\0*.*\0");
      dialog.setTitle("Select Error Trace File");
      dialog.setExt("etr");
      if (dialog.showModally()) {
        etr_file_name = dialog.fileName();
        FILE *ag_file = fopen(etr_file_name.pointer(), "r");
        LOGV(etr_file_name.pointer());
        LOGV((int) ag_file);
        if (ag_file == 0) {
          AgString msg = AgString::format("Cannot open %s",
					  etr_file_name.pointer());
          IMessageBox messageBox(controlPanel);
          messageBoxShowing++;
          messageBox.show(msg.pointer(), IMessageBox::information);
          messageBoxShowing--;
          return true;
        }
        if (getFileTimestamp(etr_file_name.pointer()) < openFileTimestamp) {
          IMessageBox messageBox(controlPanel);
          messageBoxShowing++;
          if (messageBox.show("Trace file is older than syntax",
			      IMessageBox::okCancelButton) 
	      == IMessageBox::cancel) {
	    return true;
	  }
          messageBoxShowing--;
        }
        LOGV(etr_file_name.pointer());
        LOGV((int) &etr_file_name);
        tsd *et = build_et(ag_file);
        fclose(ag_file);
        GTWindow *trace = new GTWindow(et, "Error Trace", etr_file_name);
        delete_tsd(et);
        trace->setAutoDeleteObject();
      }
      return true;
    }
    case IDI_BMP_GT:
      if (syntax_state < syntax_analyzed) {
        messageBeep();
        return true;
      }
    case IDM_GRAMMAR_TRACE: {
      if (syntax_state < syntax_analyzed) {
	return true;
      }
      LOGSECTION("IDM_GRAMMAR_TRACE");
      //GTWindow *trace = new GTWindow(0);
      GTWindow *trace = new GTWindow(0, "Grammar Trace");
      trace->setAutoDeleteObject();
      return true;
    }
    case IDI_BMP_FT:
      if (syntax_state < syntax_analyzed) {
        messageBeep();
        return true;
      }
    case IDM_FILE_TRACE: {
      if (syntax_state < syntax_analyzed) {
	return true;
      }
      LOGSECTION("IDM_FILE_TRACE");
      // Create and show File open dialog
      AgFileDialog dialog(this);
      //char buf[200];
      //if (strcmp(test_file_mask, "*.*") == 0) {
      if (test_file_mask == "*.*") {
        dialog.setFilter("All Files\0*.*\0");
      }
      else {
        char buf[200];
        sprintf(buf, "Test Files%c%s%cAll Files%c*.*%c", 0, 
		test_file_mask.pointer(), 0, 0, 0);
        LOGV(buf);
        dialog.setFilter(buf);
/*
        sss("Test Files");
        acs(0);
        ass(test_file_mask.pointer());
        acs(0);
        ass("All Files");
        acs(0);
        ass("*.*");
        acs(0);
        acs(0);
        dialog.setFilter(string_base);
        rcs();
*/
      }
      dialog.setTitle("Select Test File");
      AgString ext = test_file_mask.lastCut('.').rightX();
      if (!ext.firstCut('*').exists()) {
        dialog.setExt(ext.pointer());
      }
      if (dialog.showModally()) {
        AgString fileName = dialog.fileName();
        LOGV(fileName.pointer());

        int flags = (test_file_binary ? O_BINARY : O_TEXT) | O_RDONLY;
        FileTraceWindow *trace = new FileTraceWindow(fileName, flags);
        trace->setAutoDeleteObject();
      }
      return true;
    }
    case IDM_EDIT_FIND:
      searchKeyBox.setFocus();
      return true;
    case IDM_EDIT_FINDNEXT:
    case IDI_BMP_FINDNEXT: {
      LOGSECTION("IDI_BMP_FINDNEXT");
      findNext();
      return true;
    }
    case IDM_EDIT_FINDPREV:
    case IDI_BMP_FINDPREV: {
      LOGSECTION("IDI_BMP_FINDPREV");
      findPrev();
      return true;
    }
    case IDM_AUTOBUILD: {
      autobuildFlag = !autobuildFlag;
      return true;
    }
    case IDM_SHOW_SYNTAX: {
      showSyntaxFlag = !showSyntaxFlag;
      return true;
    }
    case IDM_SHOW_STATS: {
      LOGSECTION("IDM_SHOW_STATS");
      showStatsFlag = !showStatsFlag;
      return true;
    }
    case IDM_STAY_ON_TOP: {
      stayOnTopFlag = !stayOnTopFlag;
      return true;
    }
    case IDM_COLORS: {
      LOGSECTION("IDM_COLORS");
      ColorDialog *dialog =
	(ColorDialog *) AgFrame::windowRegistry.find("Set Colors");
      if (dialog == 0) {
        dialog = new ColorDialog;
        dialog->setAutoDeleteObject();
      }
      dialog->show();
      dialog->mySetFocus();
      return true;
    }
    case IDM_FONT: {
      LOGSECTION("IDM_FONT");
      FontDialog *dialog = 
	(FontDialog *) AgFrame::windowRegistry.find("Set Fonts");
      if (dialog == 0) {
        dialog = new FontDialog;
        dialog->setAutoDeleteObject();
      }
      dialog->show();
      dialog->mySetFocus();
      return true;
    }
    case IDM_HELP_PROG_DEV: {
      AgHelpWindow::showHelp("Program Development");
      return true;
    }
    case IDM_HELP_START: {
      //AgHelpWindow *helpWindow = 
      //  new AgHelpWindow(controlPanel, "Getting Started");
      //AgHelpWindow *helpWindow = new AgHelpWindow("Getting Started");
      //helpWindow->setAutoDeleteObject();
      AgHelpWindow::showHelp("Getting Started");
      return true;
    }
    case IDM_HELP_NEW: {
      AgHelpWindow::showHelp("What's New");
      return true;
    }
    case IDM_HELP_LICENSE: {
      AgHelpWindow::showHelp("License");
      return true;
    }
    case IDM_HELP_INDEX: {
      LOGSECTION("IDM_HELP_INDEX");
      help_index_dc *help_index = new help_index_dc;
      AgDataViewPlug *connector = new AgDataViewPlug(help_index);
      help_index->windowConnector = connector;
      AgDataPanel *helpWindow = new AgDataPanel(connector);
      helpWindow->dataView->setEnterAction(
	actionObject(helpWindow->dataView, AgDataView::showHelp)
      );
      helpWindow->setAutoDeleteObject();
      helpWindow->show().setFocus();
      return true;
    }
    case IDM_HELP_USING: {
      AgHelpWindow::showHelp("Using Help");
      return true;
    }
    case IDM_HELP_PRODINFO: {
      LOGSECTION("IDM_HELP_PRODINFO");
      AgFrame *productInfo = AgFrame::windowRegistry.find("About AnaGram");
      if (productInfo == 0) {
        productInfo = new AboutBox();
        productInfo->setAutoDeleteObject();
        IPoint where = (IPair) place(IWindow::desktopWindow()->size(),
				     productInfo->size(), 11);
        productInfo->moveTo(where);
      }
      productInfo->show().setFocus();
      LOGS("About box should be showing");
      return true;
    }
    case IDM_CHAR_MAP:
      pop_up_window(new char_map_dc);
      return true;
    case IDM_CHAR_SETS:
      pop_up_window(new char_set_dc);
      return true;
    case IDM_UNRES_CON:
      pop_up_window(new unres_con_dc);
      return true;
    case IDM_CONFIG_PARAM:
      LOGS("Select config params");
      pop_up_window(new param_table_dc);
      return true;
    case IDM_ANOMALY_TABLE:
      pop_up_window(new anomaly_table_dc);
      return true;
    case IDM_KEYWORD_TABLE:
      pop_up_window(new keyword_table_dc);
      return true;
    case IDM_PARTITION_SETS:
      pop_up_window(new partition_table_dc);
      return true;
    case IDM_PROC_TABLE:
      pop_up_window(new proc_table_dc);
      return true;
    case IDM_RES_CON:
      pop_up_window(new res_con_dc);
      return true;
    case IDM_RULE_TABLE:
      pop_up_window(new rule_table_dc);
      return true;
    case IDM_STATE_TABLE:
      pop_up_window(new state_table_dc);
      return true;
    case IDM_SYMBOL_TABLE:
      pop_up_window(new symbol_table_dc);
      return true;
    case IDM_TRACE_COUNTS:
      //pop_up_window(new rule_count_dc("Trace Coverage", trace_counts));
      pop_up_window(new rule_count_dc("Trace Coverage", traceCounts));
      return true;
    case IDM_TOKEN_TABLE:
      pop_up_window(new token_table_dc);
      return true;
    case IDM_ERROR_TABLE: {
      pop_up_window(new error_display_dc);
      return true;
    }
    case IDM_RULE_COUNTS: {
      LOGSECTION("IDM_RULE_COUNTS");
      AgFileDialog dialog(this);
      dialog.setFilter("Coverage Files\0*.nrc\0All Files\0*.*\0");
      dialog.setTitle("Select Rule Coverage File");
      dialog.setExt("nrc");
      if (dialog.showModally()) {
        AgString fileName = dialog.fileName();
        FILE *ag_file = fopen(fileName.pointer(), "r");
        LOGV(fileName.pointer());
        LOGV((int) ag_file);
        if (ag_file == 0) {
          AgString msg = AgString::format("Cannot open %s",
					  fileName.pointer());
          IMessageBox messageBox(controlPanel);
          messageBoxShowing++;
          messageBox.show(msg.pointer(), IMessageBox::information);
          messageBoxShowing--;
          return true;
        }
        fclose(ag_file);
        if (getFileTimestamp(fileName.pointer()) < openFileTimestamp) {
          IMessageBox messageBox(controlPanel);
          messageBoxShowing++;
          IMessageBox::Response response = 
	    messageBox.show("Coverage file is older than syntax",
			    IMessageBox::okCancelButton);
          messageBoxShowing--;
          if (response == IMessageBox::cancel) {
	    return true;
	  }
        }
        LOGV(fileName.pointer());
        dc_ref windowData = read_counts(fileName);
        if (windowData.exists()) {
          pop_up_window(read_counts(fileName));
          return true;
        }
        IMessageBox messageBox(controlPanel);
        messageBoxShowing++;
        messageBox.show("Not a valid coverage file",
			IMessageBox::okButton);
        messageBoxShowing--;
      }
      return true;
    }
    case IDM_STATISTICS: {
      LOGSECTION("IDM_STATISTICS");
      if (AgFrame::windowRegistry.action("Statistical Summary")) {
	return true;
      }
      AgFrame *window = new StatisticsWindow();
      window->setAutoDeleteObject();
      window->positionFrame();
      window->show().setFocus();
      return true;
    }
    case IDM_SYNTAX_FILE: {
      LOGSECTION("IDM_SYNTAX_FILE");
      if (AgFrame::windowRegistry.action(syntaxFileId)) {
	return true;
      }
      LOGS("Not in registry");
      syntaxFileId = nextChildId();
      FileWindow *fileWindow = new FileWindow(syntaxFileId, inputFile,
					      syntaxFileRect);
      fileWindow->enableCursorBar();
      fileWindow->setAutoDeleteObject();
      fileWindow->syntaxDependent = 1;
      //IPoint where = (IPair) place(IWindow::desktopWindow()->size(), 
      //                             fileWindow->size(), 22);
      if (syntaxFileRect.area() <= 0) {
        AgQuadrant quad = findQuadrant(controlPanel);
        if (quad == lowerRight) {
	  quad = upperRight;
	}
        else {
	  quad = lowerRight;
	}
        AgRectangle bestRect(
          AgRectangle::desktop().position(quad),
          fileWindow->size(),
          opposite(quad)
        );
        IPoint where = (IPair) bestRect.position();
        fileWindow->moveTo(where);
      }
      //cascadeOffset -= cascadeIncrement;
      fileWindow->show().setFocus();
      LOGS("file created");
      return true;
    }
    case IDM_CASCADE: {
      LOGSECTION("IDM_CASCADE");
      int n = AgFrame::windowRegistry.size();
      AgFrame::windowRegistry.cascadeFlag++;
      LOGV(n);
      if (n == 0) {
	return true;
      }
      cascadeOffset = cascadeOrigin;
      for (int i = 0; i < n; i++) {
        WindowRecord &windowRecord = AgFrame::windowRegistry[i];
        LOGV(windowRecord.title.pointer());
        LOGV(cascadeOffset.asString());
        windowRecord.window->positionFrame();
        windowRecord.window->show().mySetFocus();
        windowRecord.isActive = 0;
      }
      if (n) {
	AgFrame::windowRegistry[n-1].isActive = 1;
      }
      AgFrame::windowRegistry.cascadeFlag--;
      return true;
    }
    case IDM_CLOSE_WINDOWS: {
      closeWindows();
      return true;
    }
    case IDM_HIDE_WINDOWS: {
      hideWindows();
      return true;
    }
    case IDM_RESTORE_WINDOWS: {
      restoreWindows();
      return true;
    }
    default: {
      LOGSECTION("defaultCommand");
      LOGV(cmdEvent.commandId());
      LOGV(IDM_RECENT_FILES);
      unsigned fileIndex = cmdEvent.commandId() - IDM_RECENT_FILES;
      LOGV(fileIndex);
      LOGV(recentFiles.size());
      if (fileIndex < recentFiles.size()) {
        LOGSECTION("RecentFile");
        AgString fileName = recentFiles[fileIndex];
        FILE *f = fopen(fileName.pointer(), "r");
	if (f == 0) {
	  char msg[MAX_PATH+100];
	  sprintf(msg, "Cannot open %s", fileName.pointer());
	  IMessageBox messageBox(controlPanel);
	  messageBoxShowing++;
	  messageBox.show(msg, IMessageBox::information);
	  messageBoxShowing--;
	  return true;
	}
        fclose(f);
        LOGS("Starting fileread and analysis");
        activeCursor = waitCursor;
        resetCursor();
        closeSyntaxWindows();
        idSyntaxFile(fileName);
        monitor(analyzeThread);
        loadSyntaxFile();
        buildErrorMsg[0] = 0;
        LOGV((int) &analyzeThread);
        LOGV((int) &IThread::current());
        rememberFile(fileName);
        if (autobuildFlag) {
          IReference<IThreadFn> fn = new BuildParserFn(this);
          analyzeThread.start(fn);
        }
        else {
          IReference<IThreadFn> fn = new AnalyzeGrammarFn(this);
          analyzeThread.start(fn);
        }
        return true;
      }
      if (AgFrame::windowRegistry.action(cmdEvent.commandId())) {
	return true;
      }
    }
  } /* end switch */
  return false;
}


Boolean ControlPanel::menuSelected(IMenuEvent &event) {
  LOGSECTION_OFF("ControlPanel::menuSelected");
  IMenuItem menuItem = event.menuItem();
  selectedMenuText = removeTilde(menuItem.text());
  LOGV(selectedMenuText.pointer());
  selectedMenuText = selectedMenuText.lastCut(':').leftX();
  char *menuName[] = {"Action", "Browse", "Options", "Windows", "Help"};
  for (int i = 0; i < 5; i++) {
    if (selectedMenuText == menuName[i]) {
      break;
    }
  }
  if (i < 5) {
    selectedMenuText = selectedMenuText.concat(" Menu");
  }
  LOGV(selectedMenuText.pointer());
  return false;
}

AgString ControlPanel::selectedMenuText;

Boolean ControlPanel::menuShowing(IMenuEvent &event, ISubmenu &submenu) {
  LOGSECTION_OFF("ControlPanel::menuShowing");
  LOGV(event.menuItemId());
  AgFrame::menuShowingFlag = 1;
  LOGV(AgFrame::menuShowingFlag);
  switch (event.menuItemId()) {
    case IDM_OPTIONS: {
      submenu.checkItem(IDM_AUTOBUILD, autobuildFlag);
      submenu.checkItem(IDM_SHOW_SYNTAX, showSyntaxFlag);
      submenu.checkItem(IDM_SHOW_STATS, showStatsFlag);
      submenu.checkItem(IDM_STAY_ON_TOP, stayOnTopFlag);
      return true;
    }
  }
  if (helpCursorSet) {
    return true;
  }
  switch (event.menuItemId()) {
    case IDM_FILE: {
      LOGSECTION_OFF("File Menu Showing");
      LOGV(syntax_state);
      if (simple_file_name.exists()) {
        IMenuItem item = submenu.menuItem(IDM_BUILD);
        AgString text = AgString::format("Bui%cld %s", TILDE, 
					 simple_file_name.pointer());
        item.setText(text.pointer());
        submenu.setItem(item);
        LOGV(text.pointer());
        LOGV((char *) item.text());
      }
      if (syntax_state == syntax_analyzed ||
	  (syntax_state > syntax_reset && syntax_state < syntax_analyzed &&
	   getFileTimestamp(openFileName.pointer()) > openFileTimestamp)) {
        LOGV("syntax analyzed");
      }
      else {
	submenu.disableItem(IDM_BUILD);
      }
      if (simple_file_name.exists()) {
        IMenuItem item = submenu.menuItem(IDM_REBUILD);
        AgString text = AgString::format("Rebuil%cd %s", TILDE,
					 simple_file_name.pointer());
        item.setText(text.pointer());
        submenu.setItem(item);
        LOGV(text.pointer());
        LOGV((char *) item.text());
      }
      if (syntax_state == engine_built) {
        if (getFileTimestamp(openFileName.pointer()) <= openFileTimestamp) {
	  submenu.disableItem(IDM_REBUILD);
	}
      }
      else {
	submenu.disableItem(IDM_REBUILD);
      }
      if (simple_file_name.exists()) {
        AgString text = AgString::format("%cReanalyze %s", TILDE, 
					 simple_file_name.pointer());
        IMenuItem item = submenu.menuItem(IDM_REANALYZE);
        item.setText(text.pointer());
        submenu.setItem(item);
        LOGV(text.pointer());
        LOGV((char *) item.text());
      }
      if (syntax_state > syntax_reset) {
        if (getFileTimestamp(openFileName.pointer()) <= openFileTimestamp) {
          submenu.disableItem(IDM_REANALYZE);
        }
      }
      else {
	submenu.disableItem(IDM_REANALYZE);
      }

      if (!error_trace || syntax_state < syntax_analyzed) {
	submenu.disableItem(IDM_ERROR_TRACE);
      }
      if (syntax_state < syntax_analyzed) {
	submenu.disableItem(IDM_GRAMMAR_TRACE);
      }
      LOGV(char_set_dict->nsx);
      if (syntax_state < syntax_analyzed
	  || char_set_dict->nsx <= 1
	  || badRecursionFlag) {
	submenu.disableItem(IDM_FILE_TRACE);
      }

      if (recentFiles.size() == 0) {
	return true;
      }
      LOGV(recentFiles.size());
      submenu.addSeparator(1000);
      int i;
      int nFiles = recentFiles.size();
      int n = nFiles;
      for (i = 1; i <= n; i++) {
	AgString fileName = recentFiles[nFiles-i];
	int length = fileName.size();
        char text[_MAX_PATH + 10];
	if (length > 35) {
	  char head[30];
	  strncpy(head, fileName.pointer(), 15);
	  head[15] = 0;
	  sprintf(text, "%c%d. %s ... %s", TILDE, i, head,
		  fileName.pointer() + length - 15);
	}
        else {
	  sprintf(text, "%c%d. %s", TILDE, i, fileName.pointer());
	}
        submenu.addText(IDM_RECENT_FILES + nFiles-i, text);
      }
      return true;
    }
    case IDM_BROWSE: {
      LOGSECTION_OFF("IDM_BROWSE");
      if (syntax_state < syntax_analyzed) {
        submenu.disableItem(IDM_RES_CON);
        submenu.disableItem(IDM_UNRES_CON);
        submenu.disableItem(IDM_STATE_TABLE);
        submenu.disableItem(IDM_ANOMALY_TABLE);
      }
      else {
        if (key_mess->nt == 0) {
	  submenu.disableItem(IDM_ANOMALY_TABLE);
	}
        if (unres_con->nt == 0) {
	  submenu.disableItem(IDM_UNRES_CON);
	}
        if (prr->nt == 0) {
	  submenu.disableItem(IDM_RES_CON);
	}
      }
      if (syntax_state < syntax_parsed) {
        submenu.disableItem(IDM_CHAR_MAP);
        submenu.disableItem(IDM_CHAR_SETS);
        submenu.disableItem(IDM_RULE_TABLE);
        submenu.disableItem(IDM_PROC_TABLE);
        submenu.disableItem(IDM_RULE_COUNTS);
        submenu.disableItem(IDM_TOKEN_TABLE);
        submenu.disableItem(IDM_SYMBOL_TABLE);
        submenu.disableItem(IDM_TRACE_COUNTS);
        submenu.disableItem(IDM_KEYWORD_TABLE);
        submenu.disableItem(IDM_PARTITION_SETS);
        submenu.disableItem(IDM_STATISTICS);
      }
      else {
        if (n_chars == 0) {
	  submenu.disableItem(IDM_CHAR_MAP);
	}
        if (char_set_dict->nsx <= 1) {
	  submenu.disableItem(IDM_CHAR_SETS);
	}
        if (Keyword::count() <= 1) {
	  submenu.disableItem(IDM_KEYWORD_TABLE);
	}
        if (part_dict->nsx <= 1) {
	  submenu.disableItem(IDM_PARTITION_SETS);
	}
        if (Procedure::count() <= 1) {
	  submenu.disableItem(IDM_PROC_TABLE);
	}
        if (!rule_coverage) {
	  submenu.disableItem(IDM_RULE_COUNTS);
	}
        if (!traceCounts.exists()) {
	  submenu.disableItem(IDM_TRACE_COUNTS);
	}
      }

      int disableFlag = true;
      LOGS("disable syntax file selection");
      LOGV(disableFlag);
      if (simple_file_name.exists()) {
        AgString text = AgString::format("Syntax %cFile - %s", TILDE, 
					 simple_file_name.pointer());
        IMenuItem item = submenu.menuItem(IDM_SYNTAX_FILE);
        item.setText(text.pointer());
        submenu.setItem(item);
        LOGV(text.pointer());
        disableFlag = 0;
      }
      LOGV(disableFlag);
      if (disableFlag) {
	submenu.disableItem(IDM_SYNTAX_FILE);
      }
      LOGS("disableFlag set");

      if (errorList.size() == 0) {
	submenu.disableItem(IDM_ERROR_TABLE);
      }
      return true;
    }
    case IDM_WINDOWS: {
      LOGSECTION_OFF("IDM_WINDOWS");
      int ln;
      int n = AgFrame::windowRegistry.size();
      LOGV(n);
      if (n == 0) {
        submenu.disableItem(IDM_CASCADE);
        submenu.disableItem(IDM_CLOSE_WINDOWS);
        submenu.disableItem(IDM_HIDE_WINDOWS);
        submenu.disableItem(IDM_RESTORE_WINDOWS);
        submenu.disableItem(IDM_COPY);
        return true;
      }
      else {
        int i, k;
        for (i = k = 0; i < n; i++) {
          if (!AgFrame::windowRegistry[i].window->isVisible()) {
	    k++;
	  }
        }
        if (k == 0) {
	  submenu.disableItem(IDM_RESTORE_WINDOWS);
	}

        for (i = k = 0; i < n; i++) {
          if (AgFrame::windowRegistry[i].window->isVisible()) {
	    k++;
	  }
        }
        if (k == 0) {
	  submenu.disableItem(IDM_HIDE_WINDOWS);
	}
      }

      AgFrame *activeWindow = 0;
      while (n--) {
	if (AgFrame::windowRegistry[n].isActive) {
	  activeWindow = AgFrame::windowRegistry[n].window;
	  break;
	}
      }
      LOGV((int) activeWindow);
      if (activeWindow) {
	LOGV(activeWindow->copyTitle());
      }
      int disableFlag = 
	(activeWindow == 0) || !activeWindow->copyTitle().exists();
      if (disableFlag) {
	submenu.disableItem(IDM_COPY);
      }
      else {
        char buf[200];
        sprintf(buf, "Co%cpy %s", TILDE, activeWindow->copyTitle().pointer());
        IMenuItem item = submenu.menuItem(IDM_COPY);
        item.setDisabled(disableFlag);
        item.setText(buf);
        submenu.setItem(item);
      }
      submenu.addSeparator(10000);
      int itemHeight = submenu.itemRect(IDM_COPY).size().height();
      LOGV(submenu.itemRect(IDM_COPY).asString()) LCV(itemHeight);
      if (itemHeight == 0) {
        itemHeight = submenu.font().maxCharHeight();
        LOGV(itemHeight);
      }
      int magicNumber = IWindow::desktopWindow()->size().height()/itemHeight;
      LOGV(magicNumber);

      n = AgFrame::windowRegistry.size();
      for (ln = 0; ln < n; ln++) {
        WindowRecord &windowRecord = AgFrame::windowRegistry[ln];
        int view = windowRecord.window->windowTitle.viewNumber();
        AgString title = windowRecord.title;
        if (view) {
          char buf[10];
          sprintf(buf, ":%d", view);
          title = windowRecord.title.concat(buf);
        }
        submenu.addText(windowRecord.id, title.pointer());
        //submenu.checkItem(windowRecord.id, windowRecord.isActive);

        IMenuItem item(windowRecord.id);
        item.setText(title.pointer());
        item.setChecked(windowRecord.isActive);
        if ((ln + 7) % magicNumber == 0) {
          item.setLayout(IMenuItem::splitWithSeparatorLayout);
        }
        submenu.setItem(item);
        LOGV(windowRecord.title.pointer());
      }
      return true;
    }
  }
  return false;
}

Boolean ControlPanel::menuEnded(IMenuEvent &event) {
  LOGSECTION("ControlPanel::menuEnded");
  LOGV(selectedMenuText);
  AgFrame::menuShowingFlag = 0;
  LOGV(AgFrame::menuShowingFlag);
  if (helpRequested) {
    AgHelpWindow::showHelp(selectedMenuText);
    helpRequested = 0;
  }
  if (!helpCursorSet) {
    selectedMenuText.discardData();
  }
  return false;
}

void ControlPanel::closeWindows() {
  LOGSECTION("ControlPanel::closeWindows");
  int n = AgFrame::windowRegistry.size();
  LOGV(n);
  AgStack<AgFrame*> windowStack;
  for (int i = 0; i< n; i++) {
    AgFrame *window = AgFrame::windowRegistry[i].window;
    windowStack.push(window);
    LOGV(AgFrame::windowRegistry[i].title.pointer());
    window->closeModalDialog();
    window->closeAction.performDeferred();
  }
  while(windowStack.size()) {
    AgFrame *window = windowStack.pop();
    AgFrame::windowRegistry.remove(window->id());
  }
  cascadeOffset = cascadeOrigin;
}

void ControlPanel::hideWindows() {
  LOGSECTION("ControlPanel::hideWindows");
  int n = AgFrame::windowRegistry.size();
  for (int i = 0; i< n; i++) {
    AgFrame *window = AgFrame::windowRegistry[i].window;
    LOGV(AgFrame::windowRegistry[i].title.pointer());
    AgFrame::windowRegistry[i].isShowing = window->isVisible();
    window->hide();
    AgFrame::windowRegistry[i].isActive = 0;
  }
}

void ControlPanel::restoreWindows() {
  LOGSECTION("ControlPanel::restoreWindows");
  int n = AgFrame::windowRegistry.size();
  int i;
  int active = AgFrame::windowRegistry.size();
  for (i = 0; i< n; i++) {
    LOGV(AgFrame::windowRegistry[i].isShowing);
    LOGV(AgFrame::windowRegistry[i].title.pointer());
    AgFrame::windowRegistry[i].window->IWindow::show();
    AgFrame::windowRegistry[i].isShowing = 0;
    if (AgFrame::windowRegistry[i].isActive) {
      active = i;
    }
  }
  n = AgFrame::windowRegistry.size();
  if (active && active < n) {
    AgFrame::windowRegistry[active].window->mySetFocus();
  }
}

void ControlPanel::closeSyntaxWindows() {
  LOGSECTION("ControlPanel::closeSyntaxWindows");
  int n = AgFrame::windowRegistry.size();
  AgStack<AgFrame*> windowStack;
  for (int i = 0; i < n; i++) {
    AgFrame *window = AgFrame::windowRegistry[i].window;
    if (!window->syntaxDependent) {
      continue;
    }
    window->closeModalDialog();
    window->closeAction.performDeferred();
    windowStack.push(window);
  }
  while(windowStack.size()) {
    AgFrame *window = windowStack.pop();
    AgFrame::windowRegistry.remove(window->id());
  }

  if (AgFrame::windowRegistry.size() == 0) {
    cascadeOffset = cascadeOrigin;
  }
}