diff anagram/vaclgui/gtview.cpp @ 0:13d2b8934445

Import AnaGram (near-)release tree into Mercurial.
author David A. Holland
date Sat, 22 Dec 2007 17:52:45 -0500
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/anagram/vaclgui/gtview.cpp	Sat Dec 22 17:52:45 2007 -0500
@@ -0,0 +1,2176 @@
+/*
+ * AnaGram, A System for Syntax Directed Programming
+ * Copyright 1997-2002 Parsifal Software. All Rights Reserved.
+ * See the file COPYING for license and usage terms.
+ *
+ * gtview.cpp
+ */
+
+//#include <commctrl.h>
+//#include <imsgbox.hpp>
+#include <windows.h>
+
+#include "agstring.h"
+#include "arrays.h"
+#include "ctrlpanel.hpp"
+#include "data.h"
+#include "dc.h"
+#include "dspar.hpp"
+#include "dvplug.hpp"
+#include "gtview.hpp"
+#include "helpview.hpp"
+#include "minmax.h"
+#include "myalloc.h"
+#include "p.h"
+#include "rule.h"
+#include "tracedc.h"
+#include "vaclgui-res.h"
+#include "vaclgui.hpp"
+
+//#define INCLUDE_LOGGING
+#include "log.h"
+
+
+#define RESET       "&Reset"
+#define HELP        "&Help"
+#define PROCEED     "&Proceed"
+#define SINGLE_STEP "&Single step"
+
+//static char *buttonLabel[] = {
+//  RESET, HELP, PROCEED, SINGLE_STEP
+//};
+
+GTView::GTView(GTWindow *owner_, DcRef<FtParserDc> parserDc_)
+  : ICanvas(nextChildId(), owner_, owner_, IRectangle(),
+	    ICanvas::classDefaultStyle | IWindow::clipChildren)
+  , parserDc(parserDc_)
+  , parser(parserDc->parser)
+  , stackViewData(new AgDataViewPlug(parserDc))
+  , mainSplitter(nextChildId(), this, this,
+                 IRectangle(), ISplitCanvas::horizontal | IWindow::visible)
+  , tracePanels(nextChildId(), &mainSplitter, &mainSplitter)
+  , leftPanel(nextChildId(), &tracePanels, &tracePanels)
+  , stackView(&leftPanel)
+  , stackTitle(nextChildId(), &leftPanel, &leftPanel)
+  , rightPanel(nextChildId(), &tracePanels, &tracePanels)
+  , tokenListView(&rightPanel)
+  , tokenListTitle(nextChildId(), &rightPanel, &rightPanel)
+  , bottomPanel(nextChildId(), &mainSplitter, &mainSplitter,
+                IRectangle(), ISplitCanvas::vertical | visible)
+  , reductionChoiceView(&bottomPanel)
+  , ruleView(&bottomPanel)
+  , focusControl(GTWindow::tokenTab)
+  , activePanel(GTWindow::tokenTab)
+  , frame(owner_)
+  , dataColorChange(this, onColorChange)
+  , fontChange(this, onFontChange)
+  , leftButtonState(buttonIdle)
+  , itemStack(parser.x1x_new())
+{
+  LOGSECTION("GTView::GTView");
+  LOGV(id());
+
+  LOGV((int) &stackView);
+  LOGV((int) &stackView.dataArea);
+  LOGV((int) &tokenListView);
+  LOGV((int) &tokenListView.dataArea);
+
+  setFont(tokenListView.dataArea.font());
+
+  dataColorChange.attach(&ColorSpec::inactiveCursor);
+  dataColorChange.attach(&ColorSpec::activeCursor);
+  fontChange.attach(&FontSpec::columnHead);
+
+  ruleView.setEnterAction(AgAction());
+  stackView.helpTopic = "Token Stack";
+  tokenListView.helpTopic = "Allowable Input";
+  tokenListView.copyTitle = "Grammar Trace: Allowable Input";
+  ruleView.copyTitle = "Grammar Trace: Rule Stack";
+  reductionChoiceView.copyTitle = "Grammar Trace: Reduction Choices";
+  stackView.copyTitle = "Grammar Trace: Parser Stack";
+
+  stackView.init(stackViewData);
+  parserDc->windowConnector = stackViewData;
+
+  reductionMenu = new FtParserReductionDc(parser);
+  AgDataViewPlug *connector = new AgDataViewPlug(reductionMenu);
+  reductionMenu->windowConnector = connector;
+  reductionChoiceView.init(connector);
+
+  bottomPanel.setSplitWindowPercentage(&reductionChoiceView, 0);
+  bottomPanel.setSplitWindowPercentage(&ruleView, 100);
+
+  stackTitle
+   . setText("Parser Stack")
+   . setAlignment(IStaticText::centerCenter)
+   . setBackgroundColor(ColorSpec::inactiveTitle.bg())
+   . setForegroundColor(ColorSpec::inactiveTitle.fg())
+   ;
+  AgString tokenTitle = 
+    AgString::format("Allowable input - State %d", parser.state.number);
+  tokenListTitle
+   . setText(tokenTitle.pointer())
+   . setAlignment(IStaticText::centerCenter)
+   . setBackgroundColor(ColorSpec::inactiveTitle.bg())
+   . setForegroundColor(ColorSpec::inactiveTitle.fg())
+   ;
+  LOGS("titles set up");
+  int width = stackTitle.minimumSize().width();
+  int height = font().externalLeading() + font().maxSize().height();
+  ISize minSize(width, 5*height);
+
+  leftPanel
+   . addToCell(&stackView, 1,1)
+   . addToCell(&stackTitle, 1,2)
+   . setColumnWidth(1,width,true)
+   . setRowHeight(1,0,true)
+   . setMinimumSize(minSize)
+   ;
+  width = tokenListTitle.minimumSize().width();
+  minSize= ISize(width, 5*height);
+  rightPanel
+   . addToCell(&tokenListView, 1,1)
+   . addToCell(&tokenListTitle,1,2)
+   . setColumnWidth(1,width,true)
+   . setRowHeight(1,0,true)
+   . setMinimumSize(minSize)
+   ;
+
+  //dc_ref ruleWindow = parserDc->rule_stack(parser.stateStack.size());
+  itemStack = parser.x1x_new();
+  //dc_ref ruleWindow = new rule_stack_dc(itemStack, parser.stateStack.size(),
+  //                                    parserDc->head_title);
+  ruleControl = new rule_stack_dc(itemStack,parser.stateStack.size(), 
+				  parserDc->head_title);
+  //parser.ruleControl = ruleWindow;
+  //ruleConnector = new AgDataViewPlug(ruleWindow);
+  ruleConnector = new AgDataViewPlug(ruleControl);
+  //ruleWindow->windowConnector = ruleConnector;
+  ruleControl->windowConnector = ruleConnector;
+  ruleView.init(ruleConnector);
+
+  mainSplitter.setSplitWindowPercentage(&tracePanels, 55);
+  mainSplitter.setSplitWindowPercentage(&bottomPanel, 45);
+  tracePanels.setSplitWindowPercentage(&leftPanel, 25);
+  tracePanels.setSplitWindowPercentage(&rightPanel, 75);
+
+  AgFocusHandler::handleEventsFor(&stackView.dataArea);
+  IMouseHandler::handleEventsFor(&stackTitle);
+  AgFocusHandler::handleEventsFor(&tokenListView.dataArea);
+  IMouseHandler::handleEventsFor(&tokenListTitle);
+  AgFocusHandler::handleEventsFor(&reductionChoiceView.dataArea);
+  AgFocusHandler::handleEventsFor(&ruleView.dataArea);
+  //AgFocusHandler::handleEventsFor(&frame->comboBox);
+  //AgFocusHandler::handleEventsFor(&frame->containerBar);
+  IFocusHandler::handleEventsFor(&frame->comboBox);
+  //IFocusHandler::handleEventsFor(&frame->containerBar);
+  IPaintHandler::handleEventsFor(this);
+  LOGS("all done");
+}
+
+GTView::~GTView() {
+  AgFocusHandler::stopHandlingEventsFor(&stackView.dataArea);
+  IMouseHandler::stopHandlingEventsFor(&stackTitle);
+  AgFocusHandler::stopHandlingEventsFor(&tokenListView.dataArea);
+  IMouseHandler::stopHandlingEventsFor(&tokenListTitle);
+  AgFocusHandler::stopHandlingEventsFor(&reductionChoiceView.dataArea);
+  AgFocusHandler::stopHandlingEventsFor(&ruleView.dataArea);
+  //AgFocusHandler::stopHandlingEventsFor(&frame->comboBox);
+  //AgFocusHandler::stopHandlingEventsFor(&frame->containerBar);
+  IFocusHandler::stopHandlingEventsFor(&frame->comboBox);
+  //IFocusHandler::stopHandlingEventsFor(&frame->containerBar);
+  IPaintHandler::stopHandlingEventsFor(this);
+}
+
+
+Boolean GTView::paintWindow(IPaintEvent &event) {
+  LOGSECTION("GTView::paintWindow");
+  LOGV(event.rect().asString());
+  event.clearBackground(IGUIColor::dialogBgnd);
+  return false;
+}
+
+GTView &GTView::refreshRules(int rule) {
+  LOGSECTION("GTView::refreshRules");
+  LOGV(rule);
+  delete_tsd(itemStack);
+  itemStack = parser.x1x_new();
+  //parser.ruleControl->parser_stack = parser.itemStack;
+  ruleControl->parser_stack = itemStack;
+  int k = itemStack->nt;
+  int ln = parser.stateStack.size();
+  LOGV(itemStack->nt);
+  LOGV(parser.stateStack.size());
+  //parser.ruleControl->des->d_size.y = k;
+  ruleControl->des->d_size.y = k;
+  //ruleWindow->des->d_size.y = k;
+  ruleControl->des->d_size.y = k;
+  LOGV(k);
+  while (k--) {
+    int sx, sn, fn, fx;
+    xtxf(itemStack, k, &sx, &sn, &fn, &fx);
+    int length = Rule(fn)->length();
+    LOGV(length);
+    if (sx == ln && rule == 0) {
+      break;
+    }
+    if (rule && fn == rule && fx == 0 && sx+length >= ln) {
+      break;
+    }
+  }
+  k = itemStack->nt - 1 - k;
+  LOGV(k);
+
+  ruleView
+    . reset()
+    . setCursorLine(itemStack->nt-1)
+    . setCursorLine(k).synchCursor(k)
+    . refresh();
+  frame->ruleViewLine = k;
+  return *this;
+}
+
+Boolean GTView::mouseClicked(IMouseClickEvent &event) {
+  LOGSECTION("GTView::mouseClicked");
+  if (event.mouseAction() != IMouseClickEvent::down) {
+    return false;
+  }
+  if (event.controlWindow() == &tokenListTitle) {
+    LOGS("tokenList should get focus");
+    if (!tokenListView.dataArea.hasFocus()) {
+      tokenListView.dataArea.setFocus();
+    }
+    return false;
+  }
+  else if (event.controlWindow() == &stackTitle) {
+    LOGS("stackView should get focus");
+    if (!stackView.dataArea.hasFocus()) {
+      stackView.dataArea.setFocus();
+    }
+    return false;
+  }
+  return false;
+}
+
+
+Boolean GTView::gotFocus(IControlEvent &event) {
+  LOGSECTION("GTView::gotFocus(c)");
+  return gotFocus((IEvent &)event);
+}
+
+Boolean GTView::gotFocus(IEvent &event) {
+  LOGSECTION("GTView::gotFocus");
+  LOGV(ruleView.windowId);
+  if (event.controlWindow() == 0) {
+    return false;
+  }
+#ifdef INCLUDE_LOGGING
+  IWindowHandle handle = (void *) event.parameter1();
+  IWindow *lastWindow;
+  do {
+    lastWindow = IWindow::windowWithHandle(handle);
+    LOGV((int) lastWindow);
+    handle = GetParent(handle);
+  } while (lastWindow == 0 && handle != 0);
+  LOGV((int) event.controlWindow()) LCV((int)event.dispatchingWindow());
+#endif
+  if (event.controlWindow() == &stackView.dataArea) {
+    stackTitle.setBackgroundColor(ColorSpec::activeTitle.bg());
+    stackTitle.setForegroundColor(ColorSpec::activeTitle.fg());
+    stackTitle.refresh();
+    focusControl = activePanel = GTWindow::stackTab;
+  }
+  else if (event.controlWindow() == &tokenListView.dataArea) {
+    tokenListTitle.setBackgroundColor(ColorSpec::activeTitle.bg());
+    tokenListTitle.setForegroundColor(ColorSpec::activeTitle.fg());
+    tokenListTitle.refresh();
+    focusControl = GTWindow::tokenTab;
+  }
+  else if (event.controlWindow() == &reductionChoiceView.dataArea) {
+    focusControl = activePanel = GTWindow::choiceTab;
+  }
+  else if (event.controlWindow() == &ruleView.dataArea) {
+    focusControl = activePanel = GTWindow::ruleTab;
+  }
+  else if (event.controlWindow() == &frame->comboBox) {
+    focusControl = activePanel = GTWindow::comboTab;
+  }
+  else if (event.controlWindow() == &frame->containerBar) {
+    focusControl = activePanel = GTWindow::comboTab;
+  }
+  else if (event.dispatchingWindow() == &frame->comboBox) {
+    focusControl = activePanel = GTWindow::comboTab;
+  }
+  else if (event.dispatchingWindow() == &frame->containerBar) {
+    focusControl = activePanel = GTWindow::comboTab;
+  }
+  else {
+    return false;
+  }
+
+  // Can't field mouse clicks reliably on combobox, so we show
+  // help using gotFocus().
+  LOGV(leftButtonState);
+  if (focusControl == GTWindow::comboTab
+      && leftButtonState == buttonIdle
+      && ControlPanel::helpCursorSet) {
+    //ControlPanel::helpCursorSet = 0;
+    //AgHelpWindow::showHelp("Text Entry");
+    //ControlPanel::resetCursor();
+    followUpPending = 1;
+    defer(this, followUpFocusMsg);
+    return true;
+  }
+
+
+  frame->stepButton.disableDefault();
+  frame->resetButton.disableDefault();
+  frame->helpButton.disableDefault();
+  frame->proceedButton.enableDefault();
+  LOGV(ruleView.windowId);
+  LOGV(focusControl);
+  return false;
+}
+
+void GTView::followUpFocusMsg() {
+  if (!followUpPending) {
+    return;
+  }
+  ControlPanel::helpCursorSet = 0;
+  AgHelpWindow::showHelp("Text Entry");
+  ControlPanel::resetCursor();
+  followUpPending = 0;
+}
+
+Boolean GTView::lostFocus(IControlEvent &event) {
+  LOGSECTION("GTView::lostFocus(c)");
+  return lostFocus((IEvent &) event);
+}
+
+Boolean GTView::lostFocus(IEvent &event) {
+  LOGSECTION("GTView::lostFocus");
+  LOGV(focusControl);
+#ifdef INCLUDE_LOGGING
+  IWindowHandle handle = (void *) event.parameter1();
+  IWindow *nextWindow;
+  do {
+    nextWindow = IWindow::windowWithHandle(handle);
+    LOGV((int) nextWindow);
+    handle = GetParent(handle);
+  } while (nextWindow == 0 && handle != 0);
+
+  LOGV((int) nextWindow);
+  LOGV((int) event.controlWindow()) LCV((int)event.dispatchingWindow());
+#endif
+  if (event.controlWindow() == &stackView.dataArea) {
+    stackTitle.setBackgroundColor(ColorSpec::inactiveTitle.bg());
+    stackTitle.setForegroundColor(ColorSpec::inactiveTitle.fg());
+    stackTitle.refresh();
+  }
+  if (event.controlWindow() == &tokenListView.dataArea) {
+    tokenListTitle.setBackgroundColor(ColorSpec::inactiveTitle.bg());
+    tokenListTitle.setForegroundColor(ColorSpec::inactiveTitle.fg());
+    tokenListTitle.refresh();
+  }
+  LOGV(focusControl);
+  return false;
+}
+
+
+Boolean GTWindow::virtualKeyPress(IKeyboardEvent &event) {
+  LOGSECTION("GTWindow::virtualKeyPress");
+  ok_ptr(this);
+  int increment = 0;
+  int &focusControl = canvas.focusControl;
+  int &activePanel = canvas.activePanel;
+  LOGV(focusControl);
+  LOGV((int) event.controlWindow()) LCV((int) event.dispatchingWindow());
+  LOGV(event.virtualKey());
+  switch (event.virtualKey()) {
+    case IKeyboardEvent::enter:
+    case IKeyboardEvent::newLine: {
+      //activePanel = focusControl;
+      if (focusControl >= proceedTab) {
+	tabControl[focusControl].action.performDeferred();
+	IPushButton *button = (IPushButton *)tabControl[focusControl].window;
+	button->disableDefault();
+	button->unhighlight();
+      }
+      else {
+	activePanel = focusControl;
+	proceed();
+      }
+      return true;
+    }
+    case IKeyboardEvent::right:
+    case IKeyboardEvent::down:
+      if (focusControl < proceedTab) {
+	return AgFrame::virtualKeyPress(event);
+      }
+      if (focusControl + 1 == nTabs) {
+	increment = proceedTab - focusControl;
+      }
+      else {
+	increment = 1;
+      }
+      break;
+    case IKeyboardEvent::tab:
+      increment = 1;
+      break;
+    case IKeyboardEvent::left:
+    case IKeyboardEvent::up:
+      if (focusControl < proceedTab) {
+	return AgFrame::virtualKeyPress(event);
+      }
+      if (focusControl == proceedTab) {
+	increment = nTabs - 1 - proceedTab;
+      }
+      else {
+	increment = nTabs - 1;
+      }
+      break;
+    case IKeyboardEvent::backTab:
+      increment = nTabs - 1;
+      break;
+    default:
+      return AgFrame::virtualKeyPress(event);
+  }
+  if (event.controlWindow() != event.dispatchingWindow()) {
+    return true;
+  }
+  IPushButton *button;
+  if (focusControl >= proceedTab) {
+    button = (IPushButton *) tabControl[focusControl].window;
+    button->unhighlight();
+    button->disableDefault();
+  }
+  do {
+    focusControl = (focusControl + increment) % nTabs;
+  } while (!tabControl[focusControl].enabled);
+  LOGV(focusControl) LCV(increment);
+  if (focusControl >= proceedTab) {
+    button = (IPushButton *) tabControl[focusControl].window;
+  }
+  else {
+    button = &proceedButton;
+  }
+  button->enableDefault();
+  setFocus();
+  return true;
+}
+
+Boolean GTWindow::mouseClicked(IMouseClickEvent &event) {
+  LOGSECTION("GTWindow::mouseClicked");
+  GTView::ButtonState &lbs = canvas.leftButtonState;
+  ok_ptr(this);
+  LOGV(event.mouseButton()) LCV(event.mouseAction());
+  if (event.mouseButton() != 0) {
+    return false;
+  }
+  LOGV(lbs);
+  if (event.mouseAction() == IMouseClickEvent::down) {
+    lbs = GTView::buttonDown;
+  }
+  else if (event.mouseAction() == IMouseClickEvent::up) {
+    lbs = GTView::waitingForClick;
+  }
+  else if (event.mouseAction() == IMouseClickEvent::click) {
+    lbs = GTView::buttonIdle;
+  }
+  LOGV(lbs);
+  int &focusControl = canvas.focusControl;
+  int &activePanel = canvas.activePanel;
+  LOGV(focusControl) LCV(activePanel);
+  IWindow *controlWindow = event.controlWindow();
+  LOGV((int)controlWindow) LCV((int)event.dispatchingWindow());
+  if (event.controlWindow() == &statusField) {
+    return false;
+  }
+
+  int tab;
+  for (tab = 0; tab < nTabs; tab++) {
+    LOGV(tab) LCV((int) tabControl[tab].window);
+    if (controlWindow == tabControl[tab].window) {
+      break;
+    }
+  }
+  if (tab == nTabs) {
+    return False;
+  }
+
+  LOGV(ControlPanel::helpCursorSet);
+  if (ControlPanel::helpCursorSet) {
+    if (event.mouseAction() == IMouseClickEvent::up) {
+      ControlPanel::helpCursorSet = 0;
+      canvas.followUpPending = 0;
+      LOGV(tabControl[tab].helpTopic);
+      AgHelpWindow::showHelp(tabControl[tab].helpTopic);
+      ControlPanel::resetCursor();
+    }
+    return true;
+  }
+  LOGV(focusControl) LCV(activePanel);
+  if (tab < proceedTab) {
+    return false;
+  }
+  if (focusControl >= proceedTab) {
+    IPushButton *button = (IPushButton *) tabControl[focusControl].window;
+    button->unhighlight();
+    button->disableDefault();
+  }
+  IPushButton *button = (IPushButton *) tabControl[tab].window;
+  if (event.mouseAction() == IMouseClickEvent::down) {
+    if (focusControl < proceedTab) activePanel = focusControl;
+    button->highlight();
+    button->setFocus();
+    focusControl = tab;
+    button->capturePointer();
+    return true;
+  }
+  if (event.mouseAction() == IMouseClickEvent::up) {
+    button->unhighlight();
+    button->releasePointer();
+    AgAction &action = tabControl[tab].action;
+    IWindowHandle h = tabControl[tab].window->handle();
+    if (h == event.windowUnderPointer()) {
+      action.performDeferred();
+    }
+    else if (activePanel < proceedTab) {
+      button->disableDefault();
+      proceedButton.enableDefault();
+      focusControl = activePanel;
+      setFocus();
+    }
+    else {
+      button->disableDefault();
+      proceedButton.enableDefault();
+      focusControl = proceedTab;
+      setFocus();
+    }
+  }
+  return true;
+}
+
+Boolean GTWindow::characterKeyPress(IKeyboardEvent &event) {
+  LOGSECTION("GTWindow::characterKeyPress");
+  ok_ptr(this);
+  if (event.isCtrlDown()) {
+    return true;
+  }
+  if (canvas.focusControl < proceedTab) {
+    canvas.activePanel = canvas.focusControl;
+  }
+  char character = event.character();
+  switch (character) {
+    case 'p':
+    case 'P':
+      proceed();
+      return true;
+    case 's':
+    case 'S':
+      doStep();
+      return true;
+    case 'r':
+    case 'R':
+      resetParser();
+      return true;
+    case 'h':
+    case 'H':
+      AgHelpWindow::showHelp("Grammar Trace");
+      helpButton.disableDefault();
+      helpButton.unhighlight();
+      stepButton.enableDefault();
+      //canvas.focusControl = tokenTab;
+      if (comboBox.text().length()) {
+	canvas.focusControl = comboTab;
+      }
+      else {
+	canvas.focusControl = tokenTab;
+      }
+      return true;
+  }
+  return false;
+}
+
+GTWindow &GTWindow::setFocus() {
+  LOGSECTION("GTWindow::setFocus");
+  //int protectHelp = ControlPanel::helpCursorSet;
+  //ControlPanel::helpCursorSet = 0;
+  ok_ptr(this);
+  int &focusControl = canvas.focusControl;
+  if (focusControl < proceedTab) {
+    canvas.activePanel = focusControl;
+  }
+  LOGV(focusControl);
+  LOGV(canvas.ruleView.windowId);
+  assert(focusControl >= 0 && focusControl < nTabs);
+  LOGV(canvas.ruleView.windowId);
+  tabControl[focusControl].window->setFocus();
+  LOGV(canvas.ruleView.windowId);
+  IPushButton *button;
+  for (int i = proceedTab; i < nTabs; i++) {
+    button = (IPushButton *)tabControl[i].window;
+    LOGV((int) button);
+    button->disableDefault();
+    button->unhighlight();
+  }
+  LOGV(canvas.ruleView.windowId);
+  if (focusControl >= proceedTab) {
+    button = (IPushButton *)tabControl[focusControl].window;
+  }
+  else {
+    button = &proceedButton;
+  }
+  LOGV(canvas.ruleView.windowId);
+  LOGV((int) button);
+  button->enableDefault();
+  LOGV(canvas.ruleView.windowId);
+  //ControlPanel::helpCursorSet = protectHelp;
+  LOGS("all done");
+  return *this;
+}
+
+void GTWindow::init() {
+  LOGSECTION("GTWindow::init");
+  ok_ptr(this);
+  tabControl[stackTab] = TabControl(&canvas.stackView.dataArea,
+				    "Parser Stack Pane");
+  tabControl[tokenTab] = TabControl(&canvas.tokenListView.dataArea,
+				    "Allowable Input Pane");
+  tabControl[choiceTab] = TabControl(&canvas.reductionChoiceView.dataArea,
+				     "Reduction Choices Pane");
+  tabControl[choiceTab].enabled = 0;
+  tabControl[ruleTab] = TabControl(&canvas.ruleView.dataArea,
+				   "Rule Stack Pane");
+  tabControl[comboTab]
+    = TabControl(&comboBox, "Text Entry Field",
+		 actionObject(this, comboBoxEnter));
+  tabControl[proceedTab]
+    = TabControl(&proceedButton, "Proceed", actionObject(this, proceed));
+  tabControl[stepTab]
+    = TabControl(&stepButton, "Single Step", actionObject(this, doStep));
+  tabControl[resetTab]
+    = TabControl(&resetButton, "Reset", actionObject(this, resetParser));
+  tabControl[helpTab]
+    = TabControl(&helpButton, "Grammar Trace", actionObject(this, showHelp));
+/*
+  LOGV((int) &comboBox) LCV((int) &containerBar);
+  new ControlHelpDemon(&containerBar, "Container Bar");
+  new ControlHelpDemon(&toolBar, "Tool Bar");
+*/
+  //parser.displayControl = parserDc;
+  setClient(&canvas);
+  addExtension(&toolBar, IFrameWindow::belowClient, IFrameWindow::thickLine);
+
+  IFont buttonFont = stepButton.font();
+  int buttonWidth = buttonFont.textWidth(" Synch Parse ");
+  LOGV(buttonWidth);
+  IColor buttonTextColor = resetButton.foregroundColor();
+
+  ISize minimum = stepButton.minimumSize();
+  minimum.setWidth(buttonWidth);
+  stepButton.setMinimumSize(minimum);
+  statusField.setFont(buttonFont);
+  LOGV(statusField.font().name());
+  int statusFieldWidth = buttonFont.textWidth("MSelect reduction tokenM");
+  statusField.setMinimumSize(ISize(statusFieldWidth,minimum.height()));
+  LOGV(statusField.minimumSize().asString());
+  statusField.setBackgroundColor(IGUIColor::dialogBgnd);
+  statusField.setForegroundColor(buttonTextColor);
+
+  ISize margin = toolBar.margin();
+  margin.setHeight(0);
+  toolBar.setMargin(margin);
+  containerBar.setMargin(ISize());
+  margin = buttonGroup.margin();
+  margin.setWidth(0);
+  margin.setHeight(margin.height()/2);
+  buttonGroup.setMargin(margin);
+  ISize pad = buttonGroup.pad();
+  pad.setWidth(0);
+  buttonGroup.setPad(pad);
+
+  proceedButton.enableDefault();
+
+  LOGV(proceedButton.minimumSize().asString());
+  LOGV(stepButton.minimumSize().asString());
+  LOGV(resetButton.minimumSize().asString());
+  LOGV(helpButton.minimumSize().asString());
+
+  int minWidth = toolBar.minimumSize().width();
+  LOGV(parser.stateStack.size());
+  tokenList = parserDc->tokenMenu(parser.stateStack.size());
+  LOGV((int) (dc *)tokenList);
+  tokenList->windowConnector = new AgDataViewPlug(tokenList);
+  LOGV((int)tokenList->windowConnector);
+
+  canvas.tokenListView
+   . init(tokenList->windowConnector->windowData())
+   . adjustMaxWidth("Token0\tAction\tToken Name")
+   . setColumnTitles("Token\tAction\tToken Name")
+   ;
+  canvas.stackView
+   . adjustMaxWidth(" 1\tState:\tToken0\tToken Name")
+   . setColumnTitles("\tState\tToken\tToken Name")
+   ;
+  int loopControl = 2;
+  ISize sizeLeft;
+  ISize sizeRight;
+  while (loopControl--) {
+    int desktopWidth = IWindow::desktopWindow()->size().width();
+    sizeLeft = canvas.stackView.suggestSize();
+    if (sizeLeft.width() > desktopWidth/6) {
+      sizeLeft.setWidth(desktopWidth/3);
+    }
+    sizeRight = canvas.tokenListView.suggestSize();
+    if (sizeRight.width() > desktopWidth/2) {
+      sizeRight.setWidth(desktopWidth/2);
+    }
+    int thickness = 
+      2*canvas.tracePanels.splitBarThickness(ISplitCanvas::splitBarEdge);
+    LOGV(canvas.tracePanels.splitBarThickness(ISplitCanvas::splitBarEdge));
+    LOGV(canvas.tracePanels.splitBarThickness(ISplitCanvas::splitBarMiddle));
+    LOGV(borderWidth());
+    thickness += 
+      canvas.tracePanels.splitBarThickness(ISplitCanvas::splitBarMiddle);
+    thickness += 2*borderWidth();
+    int width = sizeLeft.width() + sizeRight.width() + thickness;
+    int height = max(6*sizeLeft.height(), sizeRight.height());
+    LOGV(height);
+    height =
+      min(height,
+	  3*AgDataView::defaultWindowHeight*canvas.stackView.lineHeight()/2);
+    height += 2*canvas.stackView.columnHeadTitle.size().height();
+    height += canvas.stackTitle.minimumSize().height();
+    LOGV(height);
+    if (width < minWidth) {
+      width = minWidth;
+    }
+    if (width > (2*desktopWidth)/3) {
+      width = (2*desktopWidth)/3;
+    }
+    int toolbarWidth = toolBar.minimumSize().width();
+    if (width < toolbarWidth) {
+      width = toolbarWidth;
+    }
+    ISize clientSize(width, height);
+    LOGV(clientSize.asString());
+    IRectangle frameRect(frameRectFor(clientSize));
+    ISize frameSize = frameRect.size();
+    LOGV(frameSize.asString());
+    ISize resultant = clientRectFor(frameRect).size();
+    LOGV(resultant.asString());
+    sizeTo(frameRect.size());
+    LOGV(sizeLeft.asString());
+    LOGV(sizeRight.asString());
+    setStatusField();
+  }
+
+  int left = canvas.stackView.tableWidth;
+  int right = canvas.tokenListView.tableWidth;
+  if (left > sizeLeft.width())  {
+    left = sizeLeft.width();
+  }
+  if (right > sizeRight.width()) {
+    right = sizeRight.width();
+  }
+
+  LOGV(left);
+  LOGV(right);
+
+  canvas.tracePanels.setSplitWindowPercentage(&canvas.leftPanel, left);
+  canvas.tracePanels.setSplitWindowPercentage(&canvas.rightPanel, right);
+  positionFrame();
+
+  stackViewLine = parser.stateStack.size();
+  canvas.stackView
+   . setEnterAction(AgAction())
+   . setSelectAction(actionObject(this, stackSelect))
+   . setCursorLine(stackViewLine)
+   ;
+  canvas.ruleView
+   . setSelectAction(actionObject(this, ruleSelect))
+   . setEnterAction(AgAction())
+   ;
+  canvas.tokenListView
+   //. setEnterAction(AgAction())
+   . setEnterAction(actionObject(this, tokenEnter))
+   . setSelectAction(actionObject(this, tokenSelect))
+   ;
+  canvas.reductionChoiceView
+   . setEnterAction(actionObject(this, reductionChoiceEnter))
+   . setSelectAction(actionObject(this, reductionChoiceSelect))
+   ;
+
+  listViewLine = canvas.tokenListView.getCursorLine();
+
+  LOGV(listViewLine);
+  stackViewLine = parser.stateStack.size();
+  ruleViewLine = canvas.ruleView.getCursorLine();
+  LOGV(canvas.ruleView.windowId);
+
+  syntaxDependent = 1;
+  LOGV(parser.stateStack.size());
+  IShowListHandler::handleEventsFor(&comboBox);
+  listViewLine = 
+    tokenList->positionCursor(parser.state.number,parser.state.token);
+  LOGV(canvas.ruleView.windowId);
+  canvas.tokenListView.setCursorLine(listViewLine);
+  LOGV(canvas.ruleView.windowId);
+  synchRules(parser.stateStack.size(), parser.state.token);
+  LOGV(canvas.ruleView.windowId);
+  frameHandler->setDeactivateAction(actionObject(this, onDeactivate));
+  LOGV(canvas.ruleView.windowId);
+  AgFocusHandler::handleEventsFor(this);
+  for (int i = 0; i < nTabs; i++) {
+    IKeyboardHandler::handleEventsFor(tabControl[i].window);
+    if (i == comboTab) {
+      continue;
+    }
+    IMouseHandler::handleEventsFor(tabControl[i].window);
+  }
+  IMouseHandler::handleEventsFor(&statusField);
+  IKeyboardHandler::handleEventsFor(&containerBar);
+  LOGV(canvas.ruleView.windowId);
+  show();
+  LOGV(canvas.ruleView.windowId);
+  //setFocus();
+  //LOGS("Returned from setFocus");
+  LOGV(canvas.ruleView.windowId);
+  canvas.ruleView.setCursorLine(canvas.itemStack->nt - 1);
+  refresh();
+  LOGS("refresh call returned");
+  canvas.ruleView.setCursorLine(ruleViewLine);
+  canvas.tokenListView.dataArea.setFocus();
+  LOGS("all done");
+}
+
+GTWindow::GTWindow(trace_window_dc* gtControl)
+  : AgFrame(  IFrameWindow::dialogBackground
+	    | IFrameWindow::systemMenu
+	    | IFrameWindow::maximizeButton
+	    | IFrameWindow::sizingBorder)
+  , parser((gtControl == 0 ? 0 : gtControl->parser_stack))
+  , parserDc(new FtParserDc(parser))
+  , canvas(this, parserDc)
+  , toolBar(this, ISetCanvas::packTight | ISetCanvas::centerVerticalAlign)
+  , containerBar(&toolBar, ISetCanvas::packTight)
+  , statusField(nextChildId(), &containerBar, &containerBar, IRectangle(),
+		  IStaticText::defaultStyle()
+		| IStaticText::center
+		| IStaticText::vertCenter
+		| IStaticText::border3D)
+  , statusFieldHelp(&statusField, "Parse Status")
+  , comboBox(&containerBar, "Now is the time for ")
+  //, comboBoxHelp(&comboBox, "Grammar Trace Text Entry")
+  , buttonGroup(&toolBar, ISetCanvas::packExpanded)
+  , proceedButton(IDTB_PROCEED, &buttonGroup, PROCEED)
+  , stepButton(IDTB_STEP, &buttonGroup, SINGLE_STEP)
+  , resetButton(IDTB_RESET, &buttonGroup, RESET)
+  , helpButton(IDTB_HELP, &buttonGroup, HELP)
+  , comboBoxActive(0)
+  , comboBoxListShowing(0)
+  , ruleSelectActive(0)
+  , selectedToken(0)
+{
+  LOGSECTION("GTWindow::GTWindow");
+  ok_ptr(this);
+  AgString title;
+  if (gtControl == 0) {
+    title = "Grammar Trace";
+  }
+  else {
+    if (gtControl->foot_title.exists()) {
+      title = AgString::format("%s (%s)",
+			       gtControl->head_title.pointer(),
+			       gtControl->foot_title.pointer());
+    }
+    else {
+      title = gtControl->head_title;
+    }
+  }
+  LOGV(title.pointer());
+  AgString objectName = AgString::format("AnaGram : %s", 
+					 simple_file_name.pointer());
+  LOGV(objectName.pointer());
+  windowTitle.setObjectText(objectName.pointer());
+  windowTitle.setViewText(title.pointer());
+  registerTitle(title.pointer());
+  init();
+}
+
+GTWindow::GTWindow(tsd *initialStates, AgString headTitle, AgString footTitle)
+  : AgFrame(  IFrameWindow::dialogBackground
+	    | IFrameWindow::systemMenu
+	    | IFrameWindow::maximizeButton
+	    | IFrameWindow::sizingBorder)
+  , parser(initialStates)
+  , parserDc(new FtParserDc(parser))
+  , canvas(this, parserDc)
+  , toolBar(this, ISetCanvas::packTight | ISetCanvas::centerVerticalAlign)
+  , containerBar(&toolBar, ISetCanvas::packTight)
+  , statusField(nextChildId(), &containerBar, &containerBar, IRectangle(),
+		  IStaticText::defaultStyle()
+		| IStaticText::center
+		| IStaticText::vertCenter
+		| IStaticText::border3D)
+  , statusFieldHelp(&statusField, "Parse Status")
+  , comboBox(&containerBar, "Now is the time for ")
+  //, comboBoxHelp(&comboBox, "Grammar Trace Text Entry")
+  , buttonGroup(&toolBar, ISetCanvas::packExpanded)
+  , proceedButton(IDTB_PROCEED, &buttonGroup, PROCEED)
+  , stepButton(IDTB_STEP, &buttonGroup, SINGLE_STEP)
+  , resetButton(IDTB_RESET, &buttonGroup, RESET)
+  , helpButton(IDTB_HELP, &buttonGroup, HELP)
+  , comboBoxActive(0)
+  , comboBoxListShowing(0)
+  , ruleSelectActive(0)
+  , selectedToken(0)
+{
+  LOGSECTION("GTWindow::GTWindow");
+  ok_ptr(this);
+
+  AgString objectName = AgString::format("AnaGram : %s",
+					 simple_file_name.pointer());
+  LOGV(objectName.pointer());
+  AgString title;
+  if (footTitle.exists()) {
+    title = AgString::format("%s (%s)",
+			     headTitle.pointer(),
+			     footTitle.pointer());
+  }
+  else {
+    title = headTitle;
+  }
+
+  windowTitle.setObjectText(objectName.pointer());
+  windowTitle.setViewText(title.pointer());
+  registerTitle(title.pointer());
+  init();
+  comboBox.setEnterAction(actionObject(this, comboBoxEnter));
+}
+
+void GTWindow::setRuleViewCursor() {
+  LOGSECTION("GTWindow::setRuleViewCursor");
+  ok_ptr(this);
+  LOGV(canvas.ruleView.cursorLine);
+  canvas.ruleView.setCursorLine(canvas.itemStack->nt - 1);
+  LOGV(canvas.ruleView.cursorLine);
+  canvas.ruleView.setCursorLine(ruleViewLine);
+  LOGV(canvas.ruleView.cursorLine);
+}
+
+void GTWindow::onDeactivate() {
+  LOGSECTION("GTWindow::onDeactivate");
+  ok_ptr(this);
+  //if (comboBox.hasFocus()) canvas.focusControl = comboTab;
+}
+
+
+GTWindow::~GTWindow() {
+  IShowListHandler::stopHandlingEventsFor(&comboBox);
+  AgFocusHandler::stopHandlingEventsFor(this);
+  for (int i = 0; i < nTabs; i++) {
+    IKeyboardHandler::stopHandlingEventsFor(tabControl[i].window);
+    if (i == comboTab) {
+      continue;
+    }
+    IMouseHandler::stopHandlingEventsFor(tabControl[i].window);
+  }
+  IMouseHandler::stopHandlingEventsFor(&statusField);
+  IKeyboardHandler::stopHandlingEventsFor(&containerBar);
+}
+
+AgString GTWindow::copyTitle() {
+  ok_ptr(this);
+  switch (canvas.focusControl) {
+    case stackTab: return canvas.stackView.copyTitle;;
+    case tokenTab: return canvas.tokenListView.copyTitle;;
+    case choiceTab: return canvas.reductionChoiceView.copyTitle;;
+    case ruleTab: return canvas.ruleView.copyTitle;;
+  }
+  return AgString();
+}
+
+GTWindow  &GTWindow::copyTo(IClipboard &c) {
+  ok_ptr(this);
+  switch (canvas.focusControl) {
+    case stackTab: canvas.stackView.copyTo(c); break;
+    case tokenTab: canvas.tokenListView.copyTo(c); break;
+    case choiceTab: canvas.reductionChoiceView.copyTo(c); break;
+    case ruleTab: canvas.ruleView.copyTo(c); break;
+  }
+  return *this;
+}
+
+/*
+GTView &GTView::completeReduction() {
+  LOGSECTION("GTView::completeReduction");
+  reductionMenu->des->d_size.y = 0;
+  bottomPanel.setSplitWindowPercentage(&reductionChoiceView, 0);
+  bottomPanel.setSplitWindowPercentage(&ruleView, 100);
+  bottomPanel.refresh();
+  tabControl[comboTab].enabled = 0;
+  frame->reductionChoiceLine = reductionChoiceView.getCursorLine();
+  int token = ibnfs[ibnfb[parser.ruleToReduce]+frame->reductionChoiceLine];
+  LOGV(token);
+  parser.completeReduction(token);
+  return *this;
+}
+*/
+
+void GTWindow::reductionChoiceSelect() {
+  LOGSECTION("GTWindow::reductionChoiceSelect");
+  ok_ptr(this);
+  int sn = parser.reductionState.number;
+  reductionChoiceLine = canvas.reductionChoiceView.getCursorLine();
+  int tn = canvas.reductionMenu->token(reductionChoiceLine);
+  parser.reductionState.token= tn;
+  LOGV(sn) LCV(tn);
+  listViewLine = tokenList->positionCursor(sn,tn);
+  canvas.tokenListView.setCursorLine(listViewLine);
+  canvas.stackView.repaintLine(parser.stateStack.size());
+}
+
+void GTWindow::ruleSelect() {
+  LOGSECTION("GTWindow::ruleSelect");
+  ok_ptr(this);
+  LOGV(listViewLine);
+  LOGV(stackViewLine);
+  LOGV(ruleViewLine);
+  int tn = 0;
+  int k = canvas.ruleView.getCursorLine();
+  if (k == ruleViewLine) {
+    return;
+  }
+  ruleViewLine = k;
+  LOGV(k);
+  k = canvas.itemStack->nt - k - 1;
+  LOGV(k);
+  int sx, sn, fn, fx;
+  xtxf(canvas.itemStack, k, &sx, &sn, &fn, &fx);
+  int length = Rule(fn)->length();
+  LOGV(fn);
+  LOGV(fx);
+  LOGV(length);
+  if (fx < length) {
+    //tn = lstptr(map_form_number[fn],tokens)[fx];
+    tn = Rule(fn).token(fx);
+  }
+  int stackDepth = parser.stateStack.size();
+  int stackLevel = sx;
+  LOGV(stackLevel) LCV(stackDepth);
+  if (stackLevel == stackDepth && 
+      parser.processState == FtParser::selectionRequired) {
+    if (fx >= length) {
+      return;
+    }
+    //int tn = lstptr(map_form_number[fn],tokens)[fx];
+    int tn = Rule(fn).token(fx);
+    LOGV(tn);
+    int n = ibnfn[parser.ruleToReduce];
+    while (n--) {
+      LOGV(n);
+      LOGV(ibnfs[ibnfb[parser.ruleToReduce]+n]);
+      if (ibnfs[ibnfb[parser.ruleToReduce]+n] == tn) {
+	break;
+      }
+    }
+    LOGV(fn) LCV(n) LCV(tn);
+    if (n < 0) {
+      return;
+    }
+    canvas.reductionChoiceView.setCursorLine(n);
+    parser.reductionState.token = tn;
+    synchTokenList(sn, tn);
+    canvas.stackView.repaintLine(stackDepth);
+    return;
+  }
+  canvas.stackView.setCursorLine(stackLevel);
+  stackViewLine = stackLevel;
+  synchTokenList(sn, tn);
+}
+
+void GTWindow::setLookaheadToken(unsigned token) {
+  LOGSECTION("GTWindow::setLookaheadToken");
+  ok_ptr(this);
+  LOGV(parser.stateStack.size());
+  LOGV(canvas.stackView.cursorLine);
+  parser.state.token = token;
+  LOGV(token);
+  int line = parser.stateStack.size();
+  canvas.stackView.setCursorLine(line);
+}
+
+
+void GTWindow::synchRules(unsigned stackIndex, unsigned token) {
+  LOGSECTION("GTWindow::synchRules");
+  ok_ptr(this);
+  LOGV(stackIndex) LCV(token);
+  unsigned stackLocation = canvas.itemStack->nt;
+  LOGV(stackLocation);
+  int snx, sn, sx;
+  if (stackIndex >= parser.stateStack.size()) {
+    sn = parser.state.number;
+  }
+  else {
+    sn = parser.stateStack[stackIndex].number;
+  }
+  state_number_map *sp = &map_state_number[sn];
+  LOGV(stackLocation);
+  while (stackLocation--) {
+    int fn, fx;
+    xtxf(canvas.itemStack,stackLocation, &sx, &snx, &fn, &fx);
+    if (sx == stackIndex) {
+      break;
+    }
+  }
+  assert(sx == stackIndex);
+  int k = stackLocation;
+  LOGV(sn);
+  LOGV(token);
+  if (stackIndex >= parser.stateStack.size()) {
+    ruleViewLine = canvas.itemStack->nt - stackLocation - 1;
+    do {
+      int fn, fx;
+      xtxf(canvas.itemStack, k, &sx, &snx, &fn, &fx);
+      if (fx < Rule(fn)->length()
+          && token == Rule(fn).token(fx))
+          //&& token == lstptr(map_form_number[fn],tokens)[fx])
+      {
+        k = canvas.itemStack->nt - k - 1;
+        canvas.ruleView.setCursorLine(k).synchCursor(k);
+        ruleViewLine = k;
+        return;
+      }
+      unsigned *p = lstptr(*sp,reductions);
+      unsigned n = sp->n_reductions;
+      while (n--) {
+        unsigned tn = *p++;
+        unsigned rule = *p++;
+        if (rule == fn && tn == token) {
+          k = canvas.itemStack->nt - k - 1;
+          canvas.ruleView.setCursorLine(k).synchCursor(k);
+          ruleViewLine = k;
+          return;
+        }
+      }
+      k--;
+    } while (k >= 0 && sx == stackIndex);
+    canvas.ruleView.setCursorLine(ruleViewLine).synchCursor(ruleViewLine);
+    return;
+  }
+  int nextState;
+  if (stackIndex + 1 >= parser.stateStack.size()) {
+    nextState = parser.state.number;
+  }
+  else {
+    nextState = parser.stateStack[stackIndex+1].number;
+  }
+  int charToken = map_state_number[nextState].char_token;
+  LOGV(nextState) LCV(charToken);
+  do {
+    int fn, fx;
+    xtxf(canvas.itemStack, k, &sx, &snx, &fn, &fx);
+    int length = Rule(fn)->length();
+    LOGV(k) LCV(snx);
+    LOGV(fn) LCV(fx) LCV(length);
+    //if (sx == stackIndex && fx < length
+    //    && token == lstptr(map_form_number[fn],tokens)[fx]) {
+    if (fx < length
+        && charToken == Rule(fn).token(fx)) {
+        //&& charToken == lstptr(map_form_number[fn],tokens)[fx]) {
+      k = canvas.itemStack->nt - k - 1;
+      canvas.ruleView.setCursorLine(k).synchCursor(k);
+      ruleViewLine = k;
+      return;
+    }
+    k--;
+    LOGV(k);
+    LOGV(sn) LCV(snx);
+  } while (k >= 0 && sx == stackIndex);
+}
+
+void GTWindow::setUpViews() {
+  LOGSECTION("GTWindow::setUpViews");
+  ok_ptr(this);
+  unsigned stackDepth = parser.stateStack.size();
+  int stackCursor = stackDepth;
+  LOGV(tokenList->state_number);
+  canvas.activePanel = canvas.focusControl;
+  if (parser.processState == FtParser::selectionRequired) {
+    LOGV(statusField.font().name());
+    showReductionSelection();
+    LOGV(statusField.font().name());
+    stackCursor = parser.reductionIndex;
+    canvas.focusControl = canvas.activePanel = choiceTab;
+    tabControl[choiceTab].enabled = 1;
+  }
+  else if (parser.ruleToReduce) {
+    parser.ruleToReduce = 0;
+    canvas.reductionMenu->des->d_size.y = 0;
+    canvas.bottomPanel.setSplitWindowPercentage(&canvas.reductionChoiceView,0);
+    canvas.bottomPanel.setSplitWindowPercentage(&canvas.ruleView, 100);
+    canvas.bottomPanel.refresh();
+    tabControl[choiceTab].enabled = 0;
+  }
+  LOGV(tokenList->state_number);
+  canvas.refreshRules(parser.ruleToReduce);
+  LOGV(tokenList->state_number);
+  IString text = comboBox.text();
+  LOGV(parser.state.token);
+  int sn = parser.state.number;
+  int tn = 0;
+  if (parser.processState != FtParser::ready) {
+    tn = parser.state.token;
+  }
+  if (parser.processState == FtParser::selectionRequired) {
+    LOGS("selection required");
+    sn = parser.reductionState.number;
+    tn = 
+      canvas.reductionMenu->token(canvas.reductionChoiceView.getCursorLine());
+    LOGV(sn) LCV(tn);
+  }
+  else if (parser.processState <= FtParser::running) {
+    tn = parser.state.token;
+    parser.processState = FtParser::ready;
+  }
+  else if (canvas.focusControl == comboTab) {
+    LOGS("Text in the combobox");
+    LOGV(text);
+    if (text.length()) {
+      parser.prime((const char*) text);
+      tn = parser.state.token;
+      LOGV(tn);
+      state_number_map *sp = &map_state_number[sn];
+      unsigned *tokenPointer = lstptr(*sp,t_actions);
+      int k;
+      for (k = 0; tokenPointer[k]; k++) {
+	if (tokenPointer[k] == tn) {
+	  break;
+	}
+      }
+      LOGV(tn) LCV(k) LCV(tokenPointer[k]);
+      tn = tokenPointer[k];
+      int snx;
+      k = canvas.ruleView.getCursorLine();
+      LOGV(k) LCV(canvas.itemStack->nt);
+      k = canvas.itemStack->nt - k - 1;
+      LOGV(k) LCV(sn);
+      if (tn) {
+	do {
+	  int sx, fn, fx;
+	  xtxf(canvas.itemStack, k, &sx, &snx, &fn, &fx);
+	  LOGV(k) LCV(sx) LCV(snx) LCV(fn) LCV(fx);;
+	  int length = Rule(fn)->length();
+	  LOGV(length);
+	  if (sn == snx && fx < length) {
+	    if (tn == Rule(fn).token(fx)) {
+	      break;
+	    }
+	    //if (tn == lstptr(map_form_number[fn],tokens)[fx]) break;
+	  }
+	  if (k == 0) {
+	    break;
+	  }
+	  k--;
+	} while (sn == snx);
+      }
+      LOGV(sn) LCV(snx);
+      if (tn && sn == snx) {
+        k = canvas.itemStack->nt - k - 1;
+        canvas.ruleView.setCursorLine(k).synchCursor(k);
+        ruleViewLine = k;
+      }
+      else {
+	tn == 0;
+      }
+    }
+  }
+  LOGV(tokenList->state_number);
+  LOGV(parser.state.token);
+  if (parser.processState == FtParser::running) {
+    parser.processState = FtParser::ready;
+  }
+  LOGV(sn);
+  LOGV(tn);
+
+  canvas.stackView
+   . reset()
+   . setLayoutDistorted(IWindow::layoutChanged | IWindow::immediateUpdate, 0)
+   . setCursorLine(stackCursor)
+   . refresh()
+   ;
+  LOGV(tokenList->state_number);
+  LOGV(parser.state.token);
+  stackViewLine = stackCursor;
+  LOGS("stackView set up");
+
+  LOGS("new token menu created");
+  LOGV(parser.state.number);
+  tokenList->reset(parser.state.number);
+
+  LOGV(parser.state.token);
+  LOGV(tokenList->state_number);
+  LOGS("new tokenList created");
+  char buf[100];
+  sprintf(buf, "Allowable input - State %d", parser.state.number);
+  //AgString tokenTitle = AgString::format("Allowable input - State %d", 
+  //                                     parser.state.number);
+  //LOGV(tokenTitle.pointer());
+  canvas.tokenListTitle
+   //. setText(tokenTitle.pointer())
+   . setText(buf)
+   . refresh()
+   ;
+  LOGS("tokenListTitle set up");
+  LOGV(tokenList->state_number);
+  listViewLine = tokenList->positionCursor(sn, tn);
+  canvas.tokenListView
+   . reset()
+   . setCursorLine(listViewLine)
+   . setLayoutDistorted(IWindow::layoutChanged | IWindow::immediateUpdate, 0)
+   . refresh()
+   ;
+  LOGV(parser.state.token);
+  LOGS("tokenListView set up");
+  LOGV(tokenList->state_number);
+  LOGV(listViewLine);
+  LOGV(stackViewLine);
+  LOGV(ruleViewLine);
+  LOGV(parser.location());
+  setStatusField();
+  LOGV(tokenList->state_number);
+  setFocus();
+  LOGV(tokenList->state_number);
+}
+
+void GTWindow::reductionChoiceEnter() {
+  LOGSECTION("GTWindow::reductionChoiceEnter");
+  ok_ptr(this);
+  tabControl[choiceTab].enabled = 0;
+  reductionChoiceLine = canvas.reductionChoiceView.getCursorLine();
+  int tn = canvas.reductionMenu->token(reductionChoiceLine);
+  parser.reductionState.token = tn;
+  unsigned sn = parser.reductionState.number;
+  LOGV(sn) LCV(tn);
+  listViewLine = tokenList->positionCursor(sn,tn);
+  canvas.tokenListView.setCursorLine(listViewLine);
+  if (comboBox.text().length()) canvas.focusControl = comboTab;
+  else canvas.focusControl = tokenTab;
+  acceptToken();
+  setFocus();
+}
+
+Boolean GTWindow::windowResize(IResizeEvent &event){
+  LOGSECTION("GTWindow::windowResize");
+  ok_ptr(this);
+  if (event.controlWindow() != this) {
+    return false;
+  }
+  LOGV(id());
+  canvas.mainSplitter.sizeTo(
+    clientRectFor(IRectangle(IPoint(), event.newSize())).size()
+  );
+  return false;
+}
+
+void GTWindow::synchTokenList(unsigned sn, unsigned tn) {
+  LOGSECTION("GTWindow::synchTokenList");
+  ok_ptr(this);
+  AgString tokenTitle = AgString::format("Allowable input - State %d", sn);
+  canvas.tokenListTitle.setText(tokenTitle.pointer());
+
+  LOGV(sn);
+
+  tokenList->reset(sn);
+
+  listViewLine = tokenList->positionCursor(sn,tn);
+  canvas.tokenListView
+   . reset()
+   . setCursorLine(listViewLine)
+   . setLayoutDistorted(IWindow::layoutChanged | IWindow::immediateUpdate, 0)
+   . refresh()
+   ;
+}
+
+void GTWindow::stackSelect() {
+  LOGSECTION("GTWindow::stackSelect");
+  ok_ptr(this);
+  int ln = canvas.stackView.getCursorLine();
+  LOGV(listViewLine);
+  LOGV(stackViewLine);
+  LOGV(ruleViewLine);
+  FtParser::State state =
+    (ln >= parser.stateStack.size()) ? parser.state : parser.stateStack[ln];
+  int sn = state.number, tn = state.token;
+  synchTokenList(sn, tn);
+  synchRules(ln, tn);
+}
+
+GTWindow &GTWindow::showReductionSelection() {
+  LOGSECTION("GTWindow::showReductionSelection");
+  ok_ptr(this);
+
+  LOGV(statusField.font().name());
+
+  canvas.reductionMenu = new FtParserReductionDc(parser);
+  AgDataViewPlug *connector = new AgDataViewPlug(canvas.reductionMenu);
+  canvas.reductionMenu->windowConnector = connector;
+
+  canvas.reductionChoiceView.init(connector);
+
+  LOGV(canvas.reductionMenu->columnHeadTitle.pointer());
+  LOGV(connector->columnHeadTitle().pointer());
+
+  canvas.reductionChoiceView.setEnterAction(actionObject(this, 
+						       reductionChoiceEnter));
+
+  ISize tableSize = canvas.reductionChoiceView.suggestSize();
+
+  int width = 40*font().avgCharWidth();
+  int testWidth = tableSize.width();
+  if (testWidth < width/2) {
+    width = width/2;
+  }
+  else if (testWidth > 2*width) {
+    width = 2*width;
+  }
+  else {
+    width = testWidth;
+  }
+
+  int rightWidth = canvas.bottomPanel.size().width();
+
+  int thickness = 
+    2*canvas.tracePanels.splitBarThickness(ISplitCanvas::splitBarEdge);
+  thickness += 
+    canvas.tracePanels.splitBarThickness(ISplitCanvas::splitBarMiddle);
+  canvas.bottomPanel.setSplitWindowPercentage(&canvas.reductionChoiceView, 
+					      width);
+  canvas.bottomPanel.setSplitWindowPercentage(&canvas.ruleView, 
+					      rightWidth - width - thickness);
+
+  canvas.bottomPanel.refresh();
+  LOGV(canvas.size().asString());
+  reductionChoiceLine = parser.reductionSelection;
+  canvas.reductionChoiceView
+   . setCursorLine(reductionChoiceLine)
+   . synchCursor(reductionChoiceLine)
+   ;
+  canvas.focusControl = choiceTab;
+  setFocus();
+
+  int sn = parser.reductionState.number;
+  int tn = canvas.reductionMenu->token(0);
+  listViewLine = tokenList->positionCursor(sn, tn);
+  canvas.tokenListView.setCursorLine(listViewLine);
+
+  return *this;
+}
+
+void GTWindow::comboBoxSelect() {
+  LOGSECTION("GTWindow::comboBoxSelect");
+  ok_ptr(this);
+  IString text = comboBox.itemText(comboBox.selection());
+  LOGV((char *) text);
+  comboBox.setText(text);
+}
+
+void GTWindow::comboBoxEnter() {
+  LOGSECTION("GTWindow::comboBoxEnter");
+  ok_ptr(this);
+  canvas.focusControl = comboTab;
+  int selection = comboBox.selection();
+  LOGV(selection);
+  LOGV(IComboBox::notFound);
+  LOGV(comboBox.isListShowing());
+  LOGV(comboBox.hasChanged());
+  if (comboBoxListShowing) {
+    comboBoxListShowing = 0;
+    LOGV(selection);
+    if (selection == IComboBox::notFound) {
+      return;
+    }
+    IString text = comboBox.itemText(selection);
+    LOGV((char *) text);
+    comboBox.setText(text);
+    LOGV(comboBox.selection());
+    return;
+  }
+  comboBoxProceed();
+  proceedButton.unhighlight();
+}
+
+Boolean GTWindow::listShown(IControlEvent &) {
+  LOGSECTION("GTWindow::listShown");
+  ok_ptr(this);
+  comboBoxListShowing = 1;
+  return false;
+}
+
+void GTWindow::ComboBox::saveText() {
+  LOGSECTION("GTWindow::comboBox::saveText()");
+  IString contents = text();
+  if (contents.length() == 0) {
+    return;
+  }
+  int n = count();
+  while (n--) {
+    if (itemText(n) == contents) {
+      remove(n);
+      break;
+    }
+  }
+  addAsFirst(contents);
+  IEntryField::removeAll();
+  n = count();
+  LOGV(count());
+  if (n < 8 && n > minimumRows()) {
+    setMinimumRows(8);
+  }
+  LOGV(minimumRows());
+}
+
+void GTWindow::proceed() {
+  LOGSECTION("GTWindow::proceed");
+  ok_ptr(this);
+  IString text = comboBox.text();
+  LOGV(text);
+  LOGV(canvas.focusControl);
+  //if (comboBox.hasFocus()) {
+  //  canvas.focusControl = canvas.activePanel = comboTab;
+  //}
+  LOGV(canvas.focusControl) LCV(canvas.activePanel);
+  //switch(canvas.focusControl) {
+  switch(canvas.activePanel) {
+    case stackTab:
+    case ruleTab: {
+      messageBeep();
+      setFocus();
+      return;
+    }
+    case tokenTab: {
+      tokenProceed();
+      break;
+    }
+    case choiceTab: {
+      reductionChoiceEnter();
+      break;
+    }
+    case comboTab: {
+      comboBoxProceed();
+      break;
+    }
+    case proceedTab: {                   // proceed button has focus
+      if (parser.processState == FtParser::selectionRequired) {
+	reductionChoiceEnter();
+      }
+      else if (text.length() > 0) {
+	comboBoxProceed();
+      }
+      else tokenProceed();
+      break;
+    }
+    default:
+      assert(0);
+  }
+
+  proceedButton.unhighlight();
+  proceedButton.enableDefault();
+  setFocus();
+}
+
+void GTWindow::doStep() {
+  LOGSECTION("GTWindow::doStep");
+  ok_ptr(this);
+  IString text = comboBox.text();
+  LOGV(text);
+
+  LOGV(canvas.focusControl);
+  //if (comboBox.hasFocus()) {
+  //  canvas.focusControl = canvas.activePanel = comboTab;
+  //}
+  LOGV(canvas.focusControl) LCV(canvas.activePanel);
+  //switch(canvas.focusControl) {
+  switch(canvas.activePanel) {
+    case stackTab:
+    case ruleTab: {
+      messageBeep();
+      setFocus();
+      return;
+    }
+    case tokenTab: {
+      canvas.focusControl = tokenTab;
+      acceptToken();
+      break;
+    }
+    case choiceTab: {
+      reductionChoiceEnter();
+      break;
+    }
+    case comboTab: {
+      comboBoxStep();
+      break;
+    }
+    case stepTab: {                   // step button has focus
+      if (parser.processState == FtParser::selectionRequired) {
+	reductionChoiceEnter();
+      }
+      else if (text.length() > 0) {
+	comboBoxStep();
+      }
+      else {
+	canvas.focusControl = tokenTab;
+	acceptToken();
+      }
+      break;
+    }
+    default:
+      assert(0);
+  }
+
+  proceedButton.enableDefault();
+  stepButton.unhighlight();
+  stepButton.disableDefault();
+  setFocus();
+}
+
+
+void GTWindow::comboBoxProceed() {
+  LOGSECTION("GTWindow::comboBoxProceed");
+  ok_ptr(this);
+  canvas.focusControl = comboTab;
+  if (parser.processState == FtParser::finished) {
+    messageBeep();
+    setFocus();
+    return;
+  }
+  LOGV(comboBox.selectedTextLength());
+  LOGV(comboBox.hasSelectedText());
+  IString text = comboBox.text();
+  LOGV((char *) text);
+  if (text.length() == 0) {
+    messageBeep();
+    setFocus();
+    return;
+  }
+
+  if (parser.processState == FtParser::selectionRequired) {
+    parser.ruleToReduce = 0;
+    canvas.reductionMenu->des->d_size.y = 0;
+    canvas.bottomPanel.setSplitWindowPercentage(&canvas.reductionChoiceView,0);
+    canvas.bottomPanel.setSplitWindowPercentage(&canvas.ruleView, 100);
+    tabControl[choiceTab].enabled = 0;
+    canvas.bottomPanel.refresh();
+    parser.processState = FtParser::running;
+  }
+
+  unsigned stackLevel = canvas.stackView.getCursorLine();
+  unsigned stackDepth = parser.stateStack.size();
+  if (stackLevel != stackDepth) {
+    LOGV(stackDepth);
+    while (stackDepth > stackLevel) {
+      parser.stateStack.pop(parser.state);
+      stackDepth--;
+    }
+    parserDc->des->d_size.y = stackLevel+1;
+  }
+
+  parser.parse(text);
+  if (parser.processState > FtParser::running) {
+    messageBeep();
+  }
+  LOGV(comboBox.selectedTextLength());
+  LOGV(comboBox.hasSelectedText());
+
+  int k = (char *) text + strlen(text) - (char *) parser.state.pointer;
+  comboBox.saveText();
+  comboBox.setText((char *) parser.state.pointer);
+  if (k > 0) {
+    comboBox.setText((char *) parser.state.pointer);
+  }
+
+  if (parser.processState == FtParser::selectionRequired) {
+    int k = parser.stateStack.size() - parser.reductionIndex;
+    assert((unsigned) k <= (unsigned) parser.stateStack.size());
+    LOGV(k);
+    parser.stateStack.discardData(k);
+    parser.state = parser.reductionState;
+  }
+  LOGV(parser.state.number);
+  LOGV(parser.state.token);
+  tokenList->reset(parser.state.number);
+  stackDepth = parser.stateStack.size();
+  //parser.displayControl->des->d_size.y = stackDepth+1;
+  parserDc->des->d_size.y = stackDepth+1;
+  LOGV(stackDepth);
+  LOGV(parser.processState);
+  LOGV(tokenList->state_number);
+
+  setUpViews();
+}
+
+void GTWindow::comboBoxStep() {
+  LOGSECTION("GTWindow::comboBoxStep");
+  ok_ptr(this);
+  LOGV(comboBox.selectedTextLength());
+  LOGV(comboBox.hasSelectedText());
+  IString text = comboBox.text();
+  LOGV((char *) text);
+  if (text.length() == 0 || parser.processState == FtParser::finished) {
+    messageBeep();
+    return;
+  }
+
+  if (parser.processState == FtParser::selectionRequired) {
+    parser.ruleToReduce = 0;
+    tabControl[choiceTab].enabled = 0;
+    canvas.reductionMenu->des->d_size.y = 0;
+    canvas.bottomPanel.setSplitWindowPercentage(&canvas.reductionChoiceView,0);
+    canvas.bottomPanel.setSplitWindowPercentage(&canvas.ruleView, 100);
+    canvas.bottomPanel.refresh();
+    parser.processState = FtParser::running;
+  }
+
+  canvas.focusControl = comboTab;
+  unsigned stackLevel = canvas.stackView.getCursorLine();
+  unsigned stackDepth = parser.stateStack.size();
+  if (stackLevel != stackDepth) {
+    LOGV(stackDepth);
+    while (stackDepth > stackLevel) {
+      parser.stateStack.pop(parser.state);
+      stackDepth--;
+    }
+    parserDc->des->d_size.y = stackLevel+1;
+  }
+
+  LOGV((int)(char *) text);
+  LOGV(parser.state.pointer);
+
+  parser.processState = FtParser::running;
+  parser.step(text);
+  if (parser.processState > FtParser::running) {
+    messageBeep();
+  }
+
+  LOGV(comboBox.selectedTextLength());
+  LOGV(comboBox.hasSelectedText());
+  int k = (char *) text + strlen(text) - (char *) parser.state.pointer;
+  LOGV(k);
+  comboBox.saveText();
+  if (k > 0) {
+    comboBox.setText((char *) parser.state.pointer);
+  }
+
+  if (parser.processState == FtParser::selectionRequired) {
+    int k = parser.stateStack.size() - parser.reductionIndex;
+    assert((unsigned) k <= (unsigned) parser.stateStack.size());
+    LOGV(k);
+    parser.stateStack.discardData(k);
+    parser.state = parser.reductionState;
+  }
+  LOGV(parser.state.number);
+  LOGV(parser.state.token);
+  tokenList->reset(parser.state.number);
+  stackDepth = parser.stateStack.size();
+  //parser.displayControl->des->d_size.y = stackDepth+1;
+  parserDc->des->d_size.y = stackDepth+1;
+  LOGV(stackDepth);
+  LOGV(parser.processState);
+  LOGV(tokenList->state_number);
+
+  setUpViews();
+}
+
+void GTWindow::tokenSelect() {
+  LOGSECTION("GTWindow::tokenSelect");
+  ok_ptr(this);
+  LOGV(canvas.tokenListView.getCursorLine());
+
+  int line = canvas.tokenListView.getCursorLine();
+  LOGV(line);
+  LOGV(listViewLine);
+  LOGV(stackViewLine);
+  LOGV(ruleViewLine);
+
+  int stackLine = canvas.stackView.getCursorLine();
+  LOGV(stackLine);
+  if (stackLine == stackViewLine && line == listViewLine) {
+    return;
+  }
+  listViewLine = line;
+  int stackDepth = parser.stateStack.size();
+  LOGV(stackDepth);
+  int sn;
+  if (stackLine >= stackDepth) {
+    sn = parser.state.number;
+  }
+  else {
+    sn = parser.stateStack[stackLine].number;
+  }
+  LOGV(sn);
+  state_number_map *sp = &map_state_number[sn];
+
+  unsigned token = lstptr(*sp,t_actions)[line];
+  LOGV(token);
+  if (parser.processState == FtParser::selectionRequired) {
+    int n = ibnfn[parser.ruleToReduce];
+    while (n--) {
+      if (token == ibnfs[ibnfb[parser.ruleToReduce]+n]) {
+        canvas.reductionChoiceView.setCursorLine(n);
+        reductionChoiceLine = n;
+        break;
+      }
+    }
+  }
+}
+
+void GTWindow::acceptToken() {
+  LOGSECTION("GTWindow::acceptToken");
+  ok_ptr(this);
+  LOGV(canvas.tokenListView.getCursorLine());
+  LOGV(listViewLine);
+  LOGV(stackViewLine);
+  LOGV(ruleViewLine);
+
+  canvas.focusControl = tokenTab;
+  if (parser.processState == FtParser::finished) {
+    messageBeep();
+    setFocus();
+    return;
+  }
+  int line = canvas.tokenListView.getCursorLine();
+  LOGV(tokenList->state_number);
+
+
+  int stackLevel = canvas.stackView.getCursorLine();
+  int stackDepth = parser.stateStack.size();
+  if (stackLevel != stackDepth) {
+    LOGV(stackDepth);
+    while (stackDepth > stackLevel) {
+      parser.stateStack.pop(parser.state);
+      stackDepth--;
+    }
+    parserDc->des->d_size.y = stackLevel+1;
+  }
+
+  LOGV(parser.state.token);
+
+  if (parser.processState == FtParser::selectionRequired) {
+    parser.ruleToReduce = 0;
+    tabControl[choiceTab].enabled = 0;
+    canvas.reductionMenu->des->d_size.y = 0;
+    canvas.bottomPanel.setSplitWindowPercentage(&canvas.reductionChoiceView,0);
+    canvas.bottomPanel.setSplitWindowPercentage(&canvas.ruleView, 100);
+    canvas.bottomPanel.refresh();
+    parser.processState = FtParser::running;
+  }
+
+  state_number_map *sp = &map_state_number[parser.state.number];
+  unsigned token = lstptr(*sp, t_actions)[line];
+
+  LOGV(canvas.tokenListView.cursorLine);
+  AgString lineText = canvas.tokenListView.windowData->
+    getLine(canvas.tokenListView.cursorLine);
+  LOGV(lineText.pointer());
+  if (lineText == "No Default") {
+    messageBeep();
+    setFocus();
+    return;
+  }
+
+  LOGV(parser.state.token);
+  parser.stepToken(token);
+
+  if (parser.processState > FtParser::running) {
+    messageBeep();
+  }
+
+  if (parser.processState == FtParser::selectionRequired) {
+    int k = parser.stateStack.size() - parser.reductionIndex;
+    assert((unsigned) k <= (unsigned) parser.stateStack.size());
+    LOGV(k);
+    parser.stateStack.discardData(k);
+    parser.state = parser.reductionState;
+    unsigned stackDepth = parser.stateStack.size();
+    //parser.displayControl->des->d_size.y = stackDepth+1;
+    parserDc->des->d_size.y = stackDepth+1;
+  }
+  LOGV(parser.state.number);
+  LOGV(parser.state.token);
+  tokenList->reset(parser.state.number);
+  stackDepth = parser.stateStack.size();
+  //parser.displayControl->des->d_size.y = stackDepth+1;
+  parserDc->des->d_size.y = stackDepth+1;
+
+  LOGV(stackDepth);
+  LOGV(parser.processState);
+  LOGV(tokenList->state_number);
+  setUpViews();
+  LOGV(tokenList->state_number);
+  AgFrame::windowRegistry.refresh("Trace Coverage");
+}
+
+void GTWindow::tokenEnter() {
+  LOGSECTION("GTWindow::tokenEnter");
+  ok_ptr(this);
+  //acceptToken();
+  //comboBox.saveText();
+  tokenProceed();
+}
+
+
+void GTWindow::tokenProceed() {
+  LOGSECTION("GTWindow::tokenProceed");
+  ok_ptr(this);
+  LOGV(canvas.tokenListView.getCursorLine());
+  LOGV(listViewLine);
+  LOGV(stackViewLine);
+  LOGV(ruleViewLine);
+  canvas.focusControl = tokenTab;
+  if (parser.processState == FtParser::finished) {
+    messageBeep();
+    setFocus();
+    return;
+  }
+  int line = canvas.tokenListView.getCursorLine();
+  LOGV(tokenList->state_number);
+
+
+  int stackLevel = canvas.stackView.getCursorLine();
+  int stackDepth = parser.stateStack.size();
+  if (stackLevel != stackDepth) {
+    LOGV(stackDepth);
+    while (stackDepth > stackLevel) {
+      parser.stateStack.pop(parser.state);
+      stackDepth--;
+    }
+    parserDc->des->d_size.y = stackLevel+1;
+  }
+
+  LOGV(parser.state.token);
+
+  if (parser.processState == FtParser::selectionRequired) {
+    parser.ruleToReduce = 0;
+    tabControl[choiceTab].enabled = 0;
+    canvas.reductionMenu->des->d_size.y = 0;
+    canvas.bottomPanel.setSplitWindowPercentage(&canvas.reductionChoiceView,0);
+    canvas.bottomPanel.setSplitWindowPercentage(&canvas.ruleView, 100);
+    canvas.bottomPanel.refresh();
+    parser.processState = FtParser::running;
+  }
+
+  state_number_map *sp = &map_state_number[parser.state.number];
+  unsigned token = lstptr(*sp,t_actions)[line];
+
+  LOGV(canvas.tokenListView.cursorLine);
+  AgString lineText = canvas.tokenListView.windowData->
+    getLine(canvas.tokenListView.cursorLine);
+  LOGV(lineText.pointer());
+  if (lineText == "No Default") {
+    messageBeep();
+    setFocus();
+    return;
+  }
+
+  LOGV(parser.state.token);
+  if (token) {
+    parser.parseToken(token);
+  }
+  else {
+    parser.stepToken(token);
+  }
+
+  if (parser.processState > FtParser::running) {
+    messageBeep();
+  }
+
+  if (parser.processState == FtParser::selectionRequired) {
+    int k = parser.stateStack.size() - parser.reductionIndex;
+    assert((unsigned) k <= (unsigned) parser.stateStack.size());
+    LOGV(k);
+    parser.stateStack.discardData(k);
+    parser.state = parser.reductionState;
+    unsigned stackDepth = parser.stateStack.size();
+    //parser.displayControl->des->d_size.y = stackDepth+1;
+    parserDc->des->d_size.y = stackDepth+1;
+  }
+  LOGV(parser.state.number);
+  LOGV(parser.state.token);
+  tokenList->reset(parser.state.number);
+  stackDepth = parser.stateStack.size();
+  //parser.displayControl->des->d_size.y = stackDepth+1;
+  parserDc->des->d_size.y = stackDepth+1;
+
+  //comboBox.saveText();
+
+  LOGV(stackDepth);
+  LOGV(parser.processState);
+  LOGV(tokenList->state_number);
+  setUpViews();
+  LOGV(tokenList->state_number);
+  AgFrame::windowRegistry.refresh("Trace Coverage");
+}
+
+Boolean GTWindow::findNext(AgString s) {
+  LOGSECTION("GTWindow::findNext");
+  ok_ptr(this);
+  LOGV(canvas.focusControl);
+  int flag;
+  switch (canvas.focusControl) {
+    case stackTab: {
+      flag = canvas.stackView.findNext(s);
+      if (flag) {
+	stackSelect();
+      }
+      return flag;
+    }
+    case tokenTab: {
+      flag = canvas.tokenListView.findNext(s);
+      if (flag) {
+	tokenSelect();
+      }
+      return flag;
+    }
+    case choiceTab: {
+      flag = canvas.reductionChoiceView.findNext(s);
+      if (flag) {
+	reductionChoiceSelect();
+      }
+      return flag;
+    }
+    case ruleTab: {
+      flag = canvas.ruleView.findNext(s);
+      if (flag) {
+	ruleSelect();
+      }
+      return flag;
+    }
+    default:
+      messageBeep();
+      return false;
+  }
+}
+
+Boolean GTWindow::findPrev(AgString s) {
+  LOGSECTION("GTWindow::findPrev");
+  ok_ptr(this);
+  LOGV(canvas.focusControl);
+  int flag;
+  switch (canvas.focusControl) {
+    case stackTab: {
+      flag = canvas.stackView.findPrev(s);
+      if (flag) {
+	stackSelect();
+      }
+      return flag;
+    }
+    case tokenTab: {
+      flag = canvas.tokenListView.findPrev(s);
+      if (flag) {
+	tokenSelect();
+      }
+      return flag;
+    }
+    case choiceTab: {
+      flag = canvas.reductionChoiceView.findPrev(s);
+      if (flag) {
+	reductionChoiceSelect();
+      }
+      return flag;
+    }
+    case ruleTab: {
+      flag = canvas.ruleView.findPrev(s);
+      if (flag) {
+	ruleSelect();
+      }
+      return flag;
+    }
+    default:
+      messageBeep();
+      return false;
+  }
+}
+
+
+char *GTWindow::processStateText[] = {
+  "Ready",
+  "Running",                                   //running,
+  "Parse Complete",                          //finished,
+  "Syntax Error",           //syntaxError,
+  "Unexpected End of File", //unexpectedEndOfFile,
+  "Select Reduction Token",  //selectionRequired
+  "Selection Error"
+};
+
+GTWindow &GTWindow::setStatusField() {
+  ok_ptr(this);
+  char *msg = processStateText[parser.processState];
+  statusField.setText(msg);
+  statusField.refresh();
+  AgString tokenTitle = AgString::format("Allowable input - State %d", 
+					 parser.state.number);
+  canvas.tokenListTitle.setText(tokenTitle.pointer());
+  return *this;
+}
+
+void GTWindow::resetParser() {
+  LOGSECTION("GTWindow::resetParser");
+  ok_ptr(this);
+  if (parser.ruleToReduce) {
+    parser.ruleToReduce = 0;
+    canvas.reductionMenu->des->d_size.y = 0;
+    canvas.bottomPanel.setSplitWindowPercentage(&canvas.reductionChoiceView,0);
+    canvas.bottomPanel.setSplitWindowPercentage(&canvas.ruleView, 100);
+    canvas.bottomPanel.refresh();
+  }
+  tabControl[choiceTab].enabled = 0;
+  comboBox.saveText();
+  parser.reset();
+  LOGV(parser.state.token);
+  LOGV(parser.processState);
+  int stackDepth = parser.stateStack.size();
+  parserDc->des->d_size.y = stackDepth + 1;
+  canvas.stackView.setCursorLine(stackDepth);
+  tokenList->reset(parser.state.number);
+  LOGV(parser.state.token);
+  canvas.tokenListView.reset();
+  LOGV(parser.state.token);
+  LOGV(parser.state.token);
+  LOGV(parser.processState);
+  listViewLine
+    = tokenList->positionCursor(parser.state.number, parser.state.token);
+  canvas.tokenListView.setCursorLine(listViewLine);
+  LOGV(parser.state.token);
+  canvas.refreshRules(0);
+  synchRules(parser.stateStack.size(), parser.state.token);
+  LOGV(parser.processState);
+
+//  if (comboBox.text().length()) canvas.focusControl = comboTab;
+//  else canvas.focusControl = tokenTab;
+  canvas.focusControl = tokenTab;
+  setFocus();
+  canvas.stackView.refresh();
+  canvas.tokenListView.refresh();
+  LOGV(parser.processState);
+  setStatusField();
+  resetButton.unhighlight();
+  resetButton.disableDefault();
+  proceedButton.enableDefault();
+}
+
+void GTWindow::showHelp() {
+  ok_ptr(this);
+  AgHelpWindow::showHelp("Grammar Trace");
+  helpButton.unhighlight();
+  helpButton.disableDefault();
+  proceedButton.enableDefault();
+  if (comboBox.text().length()) {
+    canvas.focusControl = comboTab;
+  }
+  else {
+    canvas.focusControl = tokenTab;
+  }
+}
+