diff anagram/vaclgui/trfview.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/trfview.cpp	Sat Dec 22 17:52:45 2007 -0500
@@ -0,0 +1,986 @@
+/*
+ * AnaGram, A System for Syntax Directed Programming
+ * Copyright 1997-2002 Parsifal Software. All Rights Reserved.
+ * See the file COPYING for license and usage terms.
+ *
+ * trfview.cpp
+ */
+
+#include <icoordsy.hpp>
+#include <windows.h>
+
+#include "agstring.h"
+#include "cint.h"
+#include "config.h"
+#include "ctrlpanel.hpp"
+#include "ftpar.h" // for precedes()
+#include "ftview.hpp"
+#include "minmax.h"
+#include "trfview.hpp"
+#include "vaclgui.hpp"
+
+//#define INCLUDE_LOGGING
+#include "log.h"
+
+
+#define PARSE_LOCATION (parser.location())
+
+DigSetter::Style TraceFileView::displayStyle[4] = {
+  DigSetter::Style(FontSpec::traceFile, ColorSpec::traceFileScanned),
+  DigSetter::Style(FontSpec::traceFile, ColorSpec::traceFileUnscanned),
+  DigSetter::Style(FontSpec::traceFile, ColorSpec::traceFileHilite),
+  DigSetter::Style(FontSpec::traceFile, ColorSpec::dialogBackground)
+};
+
+TraceFileView::TraceFileView(IWindow *owner, text_file &file_, 
+			     AgString fileName)
+  : FileView(owner, file_)
+  , windowFont(FontSpec::traceFile)
+  , margin(windowFont.avgCharWidth())
+  , painting(0)
+  , enWidth(windowFont.avgCharWidth())
+  , setter(&dataArea, displayStyle)
+  , beginHighlight(0,0)
+  , endHighlight(0,0)
+  , activeHighlight(0)
+  , parseAction(actionObject(this, parseToCursor))
+  , parser(file_.text)
+  , dataColorChange(this, onColorChange)
+  , fontChange(this, onFontChange)
+  , clickEnabled(0)
+  , doubleClickEnabled(0)
+{
+  LOGSECTION("TraceFileView::TraceFileView");
+  LOGV((int) this);
+
+  dataColorChange.attach(&ColorSpec::traceFileScanned);
+  dataColorChange.attach(&ColorSpec::traceFileUnscanned);
+  dataColorChange.attach(&ColorSpec::traceFileHilite);
+
+  fontChange.attach(&FontSpec::traceFile);
+
+  for (int i = 0; i < 256; i++) {
+    charWidth[i] = windowFont.charWidth(i);
+  }
+  tableWidth = findMaxWidth();
+  dataHole.setBackgroundColor(ColorSpec::traceFileUnscanned.bg());
+  pixelCursor.x = margin;
+  enableCursor();
+
+  IMousePointerHandler::handleEventsFor(&verticalScrollBar);
+  IMousePointerHandler::handleEventsFor(&horizontalScrollBar);
+  IMousePointerHandler::handleEventsFor(&dataHole);
+}
+
+
+TraceFileView::~TraceFileView() {
+  LOGSECTION("TraceFileView::~TraceFileView");
+  IMousePointerHandler::stopHandlingEventsFor(&verticalScrollBar);
+  IMousePointerHandler::stopHandlingEventsFor(&horizontalScrollBar);
+  IMousePointerHandler::stopHandlingEventsFor(&dataHole);
+}
+
+void TraceFileView::onFontChange() {
+  LOGSECTION("TraceFileView::onFontChange");
+  setFont(FontSpec::syntaxFile);
+  dataHole.setFont(FontSpec::dataTable);
+  windowFont = FontSpec::traceFile;
+  //for (int i = 0; i < 256; i++) {
+  //  charWidth[i] = windowFont.charWidth(i);
+  //}
+  doLayout();
+  refresh();
+}
+
+void TraceFileView::reload() {
+  LOGSECTION("TraceFileView::reload");
+  LOGV((int) file.text.pointer());
+  file.read_file();
+  parser.text = file.text;
+  LOGV((int) file.text.pointer());
+  doLayout();
+}
+
+TraceFileView &TraceFileView::doLayout() {
+  setFont(windowFont);
+  for (int i = 0; i < 256; i++) {
+    charWidth[i] = windowFont.charWidth(i);
+  }
+  enWidth = windowFont.avgCharWidth();
+  margin = enWidth;
+  lineHeight = windowFont.maxSize().height() + windowFont.externalLeading();
+  FileView::doLayout();
+  return *this;
+}
+
+cint TraceFileView::getCursorLocation() {
+  return cursorLocation;
+}
+
+int TraceFileView::findMaxWidth() {
+  LOGSECTION("TraceFileView::findMaxWidth");
+  int maxWidth = 0;
+  int nl = nLines();
+  LOGV(nl);
+
+  while (nl--) {
+    AgString line = getLine(nl);
+    if (!line.exists()) {
+      continue;
+    }
+    LOGV(line.pointer());
+    int width = measureWidth(line.pointer());
+    if (width > maxWidth) {
+      LOGV(nl) LCV(width);
+      maxWidth = width;
+    }
+  }
+  maxWidth += 2*margin;
+  LOGV(maxWidth);
+  return maxWidth;
+}
+
+ISize TraceFileView::suggestSize() {
+  LOGSECTION("TraceFileView::suggestSize");
+  int n = nLines();
+  if (n < 5) {
+    n = 5;
+  }
+  if (n > defaultWindowHeight) {
+    n = defaultWindowHeight;
+  }
+  int height = n*(windowFont.maxSize().height() + 
+		  windowFont.externalLeading());
+  int width = 60*windowFont.avgCharWidth() + 2 * margin;
+  int minWidth = 40*windowFont.avgCharWidth() + 2 * margin;
+  LOGV(width) LCV(minWidth);
+  LOGV(tableWidth);
+  if (width > tableWidth) {
+    width = tableWidth;
+  }
+  if (width < minWidth) {
+    width = minWidth;
+  }
+  return ISize(width, height);
+}
+
+TraceFileView &TraceFileView::parseLine(int ln, AgString line, 
+					int begin, int end) {
+  LOGSECTION("TraceFileView::parseLine");
+  char *p = line.pointer();
+  if (p == 0) {
+    p = "";
+  }
+  assert(p != 0);
+  nDigs = 0;
+  nHoles = 0;
+  int ncw = 0;
+
+  int holeX = 0;
+  int x = margin;
+
+  int columnWidth = enWidth*tab_spacing;
+
+  int wordWidth = 0;
+
+  cint parseLoc = PARSE_LOCATION;
+  if (activeHighlight && precedes(parseLoc, endHighlight)) {
+    parseLoc = endHighlight;
+  }
+  int topToBaseline = windowFont.maxAscender();
+  cint where(0, topToBaseline + ln*lineHeight);
+  int hPos = horizontalScrollBar.scrollBoxPosition();
+  cint size(0, lineHeight);
+  cint loc(-1, ln+verticalScrollBar.scrollBoxPosition());
+  int styleIndex = !precedes(loc, parseLoc);
+  LOGV(loc);
+  LOGV(cursorLocation);
+  LOGV(styleIndex);
+  LOGV(measure);
+  LOGV(tableWidth);
+  LOGV((char *) dataArea.size().asString());
+  if (activeHighlight && styleIndex == 0) {
+    styleIndex = 2*(!precedes(loc, beginHighlight) &&
+		    precedes(loc, endHighlight));
+  }
+
+  loc.x = 0;
+  for (; *p && x <= end; p++, loc.x++) {
+    int newStyleIndex = !precedes(loc, parseLoc);
+    LOGV(loc);
+    LOGV(cursorLocation);
+    LOGV(parseLoc);
+    LOGV(newStyleIndex);
+
+    if (activeHighlight && newStyleIndex == 0) {
+      newStyleIndex = 2*(!precedes(loc, beginHighlight) && 
+			 precedes(loc, endHighlight));
+    }
+    if (newStyleIndex != styleIndex) {
+      cint holeLocation(holeX - hPos, where.y - topToBaseline);
+      LOGV(where.y) LCV(topToBaseline) LCV(holeLocation.y);
+      size.x = x - holeX;
+      if (x >= begin) {
+        hole.push(DigSetter::Hole(holeLocation, size, styleIndex));
+        LOGV(holeLocation);
+        LOGV(size);
+        LOGV(styleIndex);
+        nHoles++;
+      }
+      if (ncw) {
+        where.x = x-wordWidth - hPos;
+        if (x >= begin) {
+          dig.push(DigSetter::Dig(p-ncw, ncw,where, styleIndex));
+          nDigs++;
+        }
+        LOGV(ncw) LCV(p-ncw) LCV(x) LCV(wordWidth);
+        wordWidth = ncw = 0;
+      }
+      styleIndex = newStyleIndex;
+      holeX = x;
+    }
+    if (*p == '\t') {
+      LOGSECTION("TraceFileView::parseLine::tab");
+      if (ncw) {
+        where.x = x-wordWidth - hPos;
+        if (x >= begin) {
+          dig.push(DigSetter::Dig(p-ncw, ncw,where, styleIndex));
+          nDigs++;
+	}
+        LOGV(ncw) LCV(p-ncw) LCV(x) LCV(wordWidth);
+        wordWidth = ncw = 0;
+      }
+      LOGV(x) LCV(columnWidth);
+      x = ((x - margin + columnWidth)/columnWidth) * columnWidth + margin;
+      LOGV(x);
+      continue;
+    }
+    if (*p == ' ') {
+      if (ncw) {
+        where.x = x-wordWidth - hPos;
+        if (x >= begin) {
+          dig.push(DigSetter::Dig(p-ncw, ncw,where, styleIndex));
+          nDigs++;
+        }
+        LOGV(ncw) LCV(p-ncw) LCV(x) LCV(wordWidth);
+        wordWidth = ncw = 0;
+      }
+      x += enWidth;
+      continue;
+    }
+    int w = charWidth[*(unsigned char *) p];
+    x += w;
+    wordWidth += w;
+    ncw++;
+  }
+  if (ncw) {
+    where.x = x-wordWidth - hPos;
+    dig.push(DigSetter::Dig(p-ncw, ncw,where, styleIndex));
+    nDigs++;
+    LOGV(ncw) LCV(p-ncw) LCV(x) LCV(wordWidth);
+    wordWidth = ncw = 0;
+  }
+  int newStyleIndex = !precedes(loc, parseLoc);
+  if (activeHighlight && newStyleIndex == 0) {
+    newStyleIndex = 2*(!precedes(loc, beginHighlight) &&
+		       precedes(loc, endHighlight));
+  }
+  if (newStyleIndex != styleIndex) {
+    LOGV(newStyleIndex);
+    LOGV(styleIndex);
+    cint holeLocation(holeX - hPos, where.y - topToBaseline);
+    LOGV(holeX);
+    LOGV(hPos);
+    size.x = x - holeX;
+    if (x >= begin) {
+      hole.push(DigSetter::Hole(holeLocation, size, styleIndex));
+      LOGV(holeLocation);
+      LOGV(size);
+      LOGV(styleIndex);
+      nHoles++;
+    }
+    styleIndex = newStyleIndex;
+    holeX = x;
+  }
+  where.x = holeX;
+  if (*p == 0) {
+    x = measure;
+  }
+  size.x = x - holeX;
+  size.x = measure - holeX;
+  cint holeLocation(holeX - hPos, where.y - topToBaseline);
+  hole.push(DigSetter::Hole(holeLocation, size, styleIndex));
+  LOGV(holeLocation);
+  LOGV(size);
+  LOGV(styleIndex);
+  nHoles++;
+  LOGV(nHoles) LCV(nDigs);
+  return *this;
+}
+
+int TraceFileView::measureWidth(const char *line) {
+  LOGSECTION("TraceFileView::measureWidth");
+  const char *p = line;
+  assert(p != 0);
+  int x = 0;
+
+  int columnWidth = enWidth*tab_spacing;
+
+  for (; *p; p++) {
+    if (*p == '\t') {
+      x = ((x + columnWidth)/columnWidth) * columnWidth + enWidth;
+      continue;
+    }
+    if (*p == ' ') {
+      x += enWidth;
+      continue;
+    }
+    int width = charWidth[*(unsigned char *) p];
+    x += width;
+    if (x > 1000) {
+      LOGV((unsigned)*p);
+      LOGV(charWidth[*(unsigned char *) p]);
+      LOGV(charWidth[*p]);
+      LOGV(width) LCV(p);
+    }
+  }
+  return x;
+}
+
+
+int TraceFileView::charPosition(int xPos, AgString line) {
+  int i = 0;
+  int x = margin;
+  int columnWidth = enWidth*tab_spacing;
+  unsigned char *p = (unsigned char *)line.pointer();
+
+  //LOGSECTION("TraceFileView::charPosition", Log::off);
+  LOGSECTION_OFF("TraceFileView::charPosition");
+
+  if (p) for (i = 0; p[i]; i++) {
+    int newX = x + charWidth[p[i]];
+    if (p[i] == '\t') {
+      LOGV(x);
+      newX = margin + ((x-margin + columnWidth)/columnWidth) * columnWidth;
+      LOGV(x);
+    }
+    if (p[i] == ' ') {
+      LOGV(x);
+      newX = x + enWidth;
+    }
+    //if (newX > xPos) {
+    if (xPos <= (x+newX)/2) {
+      LOGV(i);
+      LOGV(newX);
+      return i;
+    }
+    x = newX;
+    LOGV(i);
+    LOGV(x);
+  }
+  return i;
+}
+
+int TraceFileView::xPosition(int charPos, AgString line) {
+  int i;
+  int x = margin;
+  int columnWidth = enWidth*tab_spacing;
+  unsigned char *p = (unsigned char *) line.pointer();
+
+  //LOGSECTION("TraceFileView::xPosition", Log::off);
+  LOGSECTION_OFF("TraceFileView::xPosition");
+  LOGV(p);
+  LOGV(tab_spacing) LCV(enWidth) LCV(columnWidth);
+  LOGV(font().charWidth(' '));
+
+  if (p) for (i = 0; p[i] && i < charPos; i++) {
+    if (p[i] == '\t') {
+      LOGS("tab") LCV(x);
+      x = margin + ((x-margin + columnWidth)/columnWidth) * columnWidth;
+      LOGV(x);
+      continue;
+    }
+    if (p[i] == ' ') {
+      LOGV(x);
+      x += enWidth;
+      continue;
+    }
+    x += charWidth[p[i]];
+    LOGV(i);
+    LOGV(x);
+  }
+  return x;
+}
+
+
+Boolean TraceFileView::paintWindow(IPaintEvent &event) {
+  if (event.controlWindow() != &dataArea) {
+    return false;
+  }
+  if (painting) {
+    return true;
+  }
+  hideCursor();
+  painting++;
+  LOGSECTION("TraceFileView::paintWindow");
+
+  LOGV(windowFont.name());
+  setter.setEvent(event);
+
+  IRectangle invalidRect(
+    ICoordinateSystem::isConversionNeeded()
+    ? ICoordinateSystem::convertToApplication(event.rect(),dataArea.size())
+    : event.rect()
+  );
+  LOGV((char*) invalidRect.asString());
+  LOGV(dataArea.size().asString());
+
+  LOGV(rect().asString());
+  LOGV(verticalScrollBar.rect().asString());
+
+  topLine       = verticalScrollBar.scrollBoxPosition();
+  int hPos      = horizontalScrollBar.scrollBoxPosition();
+
+  int minX = invalidRect.minX() + hPos;
+  int maxX = invalidRect.maxX() + hPos;
+
+  int baseLine  = verticalScrollBar.scrollBoxPosition();
+  int topY = baseLine*lineHeight;
+  int minY = invalidRect.minY();
+  int maxY = invalidRect.maxY();
+  //int bottomY = dataHole.size().height();
+
+  invalidRect = IRectangle(IPoint(minX,minY),
+			   (IPoint(maxX, maxY)));
+
+  LOGV(invalidRect.asString());
+  LOGV(lineHeight);
+
+  int firstLine = baseLine + invalidRect.minY()/lineHeight;
+  int lastLine = baseLine + (invalidRect.maxY()+lineHeight - 1)/lineHeight - 1;
+
+  int windowWidth = dataArea.size().width();
+  measure = windowWidth > tableWidth ? windowWidth : tableWidth;
+  measure += 2*margin;
+
+  LOGV(windowWidth);
+  LOGV(tableWidth);
+  LOGV(measure);
+  //int topToBaseline = font.maxAscender();
+
+  //int whereX = 0;
+  int whereY = firstLine*lineHeight - topY;  //topline location
+
+  LOGV(topLine);
+  LOGV(firstLine);
+  LOGV(lastLine);
+  LOGV(horizontalScrollBar.scrollBoxPosition());
+
+  //int lastInvalidLine = lastLine;
+  if (lastLine >= nLines()) {
+    lastLine = nLines() - 1;
+  }
+  //int windowHeight = dataArea.size().height();
+  int dataAreaWidth = windowWidth;
+  ISize lineSize(dataAreaWidth, lineHeight);
+  int k;
+
+  LOGV(beginHighlight);
+  LOGV(endHighlight);
+
+  LOGV(minX) LCV(maxX);
+
+  for (k = firstLine; k <= lastLine; k++, whereY += lineHeight) {
+    int i;
+    LOGV(k) LCV(whereY);
+    AgString line = getLine(k);
+    LOGV(line.pointer());
+    parseLine(k - baseLine, line, minX, maxX);
+    LOGV(hole[0].where.y);
+    LOGV(k);
+    for (i = 0; i < nHoles; i++) {
+      if (pixelCursor.x > hole[nHoles-1].where.x) {
+        LOGV(i);
+        LOGV(hole[i].where);
+        LOGV(hole[i].size);
+      }
+      setter.clear(hole[i]);
+    }
+    LOGV(nHoles) LCS("holes cleared");
+    for (i = 0; i < nDigs; i++) {
+      if (pixelCursor.x > hole[nHoles-1].where.x) {
+        LOGV(i);
+        LOGV(dig[i].where);
+      }
+      setter.setDig(dig[i]);
+    }
+    dig.discardData();
+    hole.discardData();
+    LOGV(nDigs);
+    LOGV(line.pointer());
+  }
+  invalidRect = IRectangle(IPoint(minX - hPos,whereY),
+			   (IPoint(maxX - hPos, maxY)));
+  if (invalidRect.height() > 0) {
+    setter.clear(DigSetter::Hole(invalidRect, 3));
+  }
+  setter.closeEvent();
+  showCursor();
+  painting = false;
+  return true;
+}
+
+TraceFileView &TraceFileView::refreshLines(int first, int last) {
+  LOGSECTION("refreshLines");
+  int baseLine = verticalScrollBar.scrollBoxPosition();
+  first -= baseLine;
+  last  -= baseLine;
+  first = first * lineHeight;
+  last =  (last+1) * lineHeight;
+  IRectangle r(IPoint(0,first),IPoint(measure, last));
+  LOGV(r.asString());
+  //hideCursor();
+  dataArea.refresh(r,true);
+  //showCursor();
+  return *this;
+}
+
+TraceFileView &TraceFileView::turnHighlightOff() {
+  LOGSECTION("turnHighlightOff");
+  int flag = activeHighlight;
+  activeHighlight = 0;
+  if (flag) {
+    LOGV(beginHighlight);
+    refreshLines(beginHighlight.y, endHighlight.y);
+    //setCursorLocation(parser.state.position());
+  }
+  return *this;
+}
+
+TraceFileView &TraceFileView::turnHighlightOn(unsigned ln) {
+  LOGSECTION("turnHighlightOn");
+  if (activeHighlight) {
+    activeHighlight = 0;
+    refreshLines(beginHighlight.y, endHighlight.y);
+  }
+  unsigned stackDepth = parser.stateStack.size();
+  LOGV(parser.state.position());
+  LOGV(parser.reductionState.position());
+  LOGV(parser.processState);
+  LOGV(ln);
+  LOGV(parser.reductionIndex);
+
+  if (parser.processState == FtParser::selectionRequired && 
+      ln >= parser.reductionIndex) {
+    beginHighlight = parser.reductionState.position();
+    endHighlight = parser.state.position();
+  }
+  else if (ln >= stackDepth) {
+    //setCursorLocation(parser.state.position());
+    scrollTo(parser.state.position());
+    return *this;
+  }
+  else {
+    beginHighlight = parser.stateStack[ln++].position();
+    if (ln < stackDepth) {
+      endHighlight = parser.stateStack[ln].position();
+    }
+    else if (parser.processState == FtParser::selectionRequired
+          && parser.reductionIndex >= parser.stateStack.size()) {
+      endHighlight = parser.reductionState.position();
+    }
+    else {
+      endHighlight = parser.state.position();
+    }
+  }
+  activeHighlight = 1;
+  LOGV(beginHighlight);
+  LOGV(endHighlight);
+  //setCursorLocation(beginHighlight);
+  scrollTo(beginHighlight);
+  refreshLines(beginHighlight.y, endHighlight.y);
+  return *this;
+}
+
+TraceFileView &TraceFileView::step() {
+  LOGSECTION("TraceFileView::step");
+  cint oldLoc = PARSE_LOCATION;
+  LOGV(oldLoc);
+  switch (parser.processState) {
+    case FtParser::selectionError:
+      parser.processState = FtParser::selectionRequired;
+      /* FALLTHROUGH */  /* ? - I think so */
+    case FtParser::selectionRequired:
+      parser.completeReduction();
+  }
+  if (parser.processState > FtParser::running) {
+    if (precedes(cursorLocation, PARSE_LOCATION)) {
+      if (parser.processState == FtParser::finished) {
+	parser.reset();
+      }
+      parser.processState = FtParser::running;
+      refreshHighlight(oldLoc);
+    }
+    else {
+      messageBeep();
+      return *this;
+    }
+  }
+  FileTraceWindow *x = (FileTraceWindow *) frameWindow;
+  ISystemPointerHandle newHandle(ISystemPointerHandle::wait);
+  x->setMousePointer(newHandle);
+  x->setStatusField("Running");
+
+  turnHighlightOff();
+  if (oldLoc != cursorLocation) {
+    parseToCursor();
+    return *this;
+  }
+  parser.step();
+  setCursorLocation(PARSE_LOCATION);
+  refreshHighlight(oldLoc);
+  onEnter();
+  return *this;
+}
+
+
+TraceFileView &TraceFileView::parse() {
+  LOGSECTION("TraceFileView::parse");
+  switch (parser.processState) {
+    case FtParser::finished:
+      messageBeep();
+      return *this;
+    case FtParser::selectionError:
+      parser.processState = FtParser::selectionRequired;
+      /* FALLTHROUGH */  /* ? - I think so */
+    case FtParser::selectionRequired:
+      parser.completeReduction();
+  }
+  if (parser.processState > FtParser::running) {
+    return *this;
+  }
+
+  FileTraceWindow *x = (FileTraceWindow *) frameWindow;
+  ISystemPointerHandle newHandle(ISystemPointerHandle::wait);
+  x->setMousePointer(newHandle);
+  x->setStatusField("Running");
+
+  turnHighlightOff();
+  cint oldLoc = PARSE_LOCATION;
+  LOGV(oldLoc);
+  parser.parse();
+  setCursorLocation(PARSE_LOCATION);
+  refreshHighlight(oldLoc);
+  onEnter();
+  return *this;
+}
+
+Boolean TraceFileView::virtualKeyPress(IKeyboardEvent &event) {
+  LOGSECTION("TraceFileView::virtualKeyPress");
+  LOGV(event.virtualKey());
+  switch (event.virtualKey()) {
+    case IKeyboardEvent::left:
+    case IKeyboardEvent::up:
+    case IKeyboardEvent::pageUp:
+    case IKeyboardEvent::right:
+    case IKeyboardEvent::down:
+    case IKeyboardEvent::pageDown:
+    case IKeyboardEvent::home:
+    case IKeyboardEvent::end:
+    {
+      int flag = PARSE_LOCATION == cursorLocation;
+      AgView::virtualKeyPress(event);
+      AgString line = getLine(cursorLocation.y);
+      pixelCursor.x = xPosition(cursorLocation.x, line);
+      cursorLocation.x = charPosition(pixelCursor.x, line);
+      if (flag) {
+	parseAction();
+      }
+      else if (PARSE_LOCATION == cursorLocation) {
+	resynchAction();
+      }
+      if (PARSE_LOCATION != cursorLocation) {
+	desynchAction();
+      }
+      return true;
+    }
+    case IKeyboardEvent::newLine:
+    case IKeyboardEvent::enter:
+    {
+      LOGSECTION("TraceFileView::enter");
+      cint oldLoc = PARSE_LOCATION;
+
+      LOGV(oldLoc);
+      LOGV(cursorLocation);
+      if (cursorLocation != oldLoc) {
+        parseAction();
+        return true;
+      }
+      parser.step();
+      cursorLocation = PARSE_LOCATION;
+      LOGV(cursorLocation);
+      cursorLine = cursorLocation.y;
+      pixelCursor.x = xPosition(cursorLocation.x,getLine(cursorLine));
+      pixelCursor.y = cursorLine*lineHeight;
+      setCursorPos(pixelCursor);
+      refreshHighlight(oldLoc);
+      onEnter();
+      return true;
+    }
+  }
+  return false;
+};
+
+Boolean TraceFileView::mousePointerChange(IMousePointerEvent &event) {
+  LOGSECTION("TraceFileView::mousePointerChange");
+  if (event.controlWindow() != &dataHole) {
+    return false;
+  }
+  if (ControlPanel::helpCursorSet) {
+    event.setMousePointer(ControlPanel::helpCursor);
+  }
+  else {
+    event.setMousePointer(ISystemPointerHandle(ISystemPointerHandle::text));
+  }
+  LOGS("Pointer changed");
+  return true;
+}
+
+Boolean TraceFileView::mouseClicked(IMouseClickEvent &event) {
+  LOGSECTION("TraceFileView::mouseClickEvent");
+  LOGV(event.mouseButton());
+  LOGV(event.mouseAction());
+  if (event.mouseAction() == IMouseClickEvent::down) {
+    dataArea.setFocus();
+  }
+  if (event.controlWindow() == &verticalScrollBar ||
+      event.controlWindow() == &horizontalScrollBar) {
+    //if (event.mouseAction() == IMouseClickEvent::down) {
+    //  dataArea.setFocus();
+    //}
+    return false;
+  }
+  if (event.windowUnderPointer() != dataArea.handle()) {
+    return false;
+  }
+  if (event.controlWindow() != event.dispatchingWindow()) {
+    return false;
+  }
+
+  clickEnabled |= event.mouseAction() == IMouseClickEvent::down;
+  clickEnabled &= !ControlPanel::helpCursorSet;
+  int line = event.mousePosition().y()/lineHeight;
+  line += verticalScrollBar.scrollBoxPosition();
+  if (line >= nLines()) {
+    return false;
+  }
+
+  LOGV((int) event.controlWindow()) LCV((int) event.dispatchingWindow());
+
+  if (event.mouseButton() != IMouseClickEvent::button1) {
+    return false;
+  }
+  switch (event.mouseAction()) {
+    case IMouseClickEvent::down:
+    case IMouseClickEvent::up:
+      return false;
+    case IMouseClickEvent::click: {
+      if (!clickEnabled) {
+	return false;
+      }
+      clickEnabled = 0;
+      doubleClickEnabled = 1;
+      LOGSECTION("TraceFileView::click");
+      //setFocus();
+      cursorLine = line;
+      int offset = horizontalScrollBar.scrollBoxPosition();
+      int whereX = event.mousePosition().x() + offset;
+      LOGV(cursorLine) LCV(offset) LCV(whereX);
+      AgString text = getLine(line);
+      cint loc(charPosition(whereX, text), line);
+      LOGV(loc);
+
+      LOGV(cursorLocation) LCV(PARSE_LOCATION);
+      int synchFlag = cursorLocation == PARSE_LOCATION;
+      cursorLocation = loc;
+      cursorLine = cursorLocation.y;
+      pixelCursor.x = xPosition(loc.x, text);
+      pixelCursor.y = loc.y*lineHeight;
+      LOGV(pixelCursor);
+      setCursorPos(pixelCursor);
+      LOGV(cursorLocation) LCV(PARSE_LOCATION);
+      if (!synchFlag && PARSE_LOCATION == cursorLocation) {
+	resynchAction();
+      }
+      if (synchFlag && cursorLocation != PARSE_LOCATION) {
+	desynchAction();
+      }
+      return false;
+    }
+    case IMouseClickEvent::doubleClick: {
+      if (!doubleClickEnabled) {
+	return false;
+      }
+      doubleClickEnabled = 0;
+      LOGSECTION("TraceFileView::doubleClick");
+      //setFocus();
+      cursorLine = line;
+      int offset = horizontalScrollBar.scrollBoxPosition();
+      int whereX = event.mousePosition().x() + offset;
+      LOGV(cursorLine) LCV(offset) LCV(whereX);
+      AgString text = getLine(line);
+      cint loc(charPosition(whereX, text), line);
+      LOGV(loc);
+
+      cursorLocation = loc;
+      cursorLine = cursorLocation.y;
+      pixelCursor.x = xPosition(loc.x, text);
+      pixelCursor.y = loc.y*lineHeight;
+      LOGV(pixelCursor);
+      setCursorPos(pixelCursor);
+      parseAction();
+      return false;
+    }
+  }
+  //return TraceFileView::mouseClicked(event);
+  return false;
+}
+
+Boolean TraceFileView::findNext(AgString s) {
+  int synchFlag = cursorLocation == PARSE_LOCATION;
+  int flag = FileView::findNext(s);
+  if (!synchFlag && PARSE_LOCATION == cursorLocation) {
+    resynchAction();
+  }
+  if (synchFlag && cursorLocation != PARSE_LOCATION) {
+    desynchAction();
+  }
+  return flag;
+}
+
+Boolean TraceFileView::findPrev(AgString s) {
+  int synchFlag = cursorLocation == PARSE_LOCATION;
+  int flag = FileView::findPrev(s);
+  if (!synchFlag && PARSE_LOCATION == cursorLocation) {
+    resynchAction();
+  }
+  if (synchFlag && cursorLocation != PARSE_LOCATION) {
+    desynchAction();
+  }
+  return flag;
+}
+
+TraceFileView &TraceFileView::refreshHighlight(cint oldLoc) {
+  LOGSECTION("TraceFileView::refreshHighlight");
+  int newLine = cursorLocation.y;
+  int hPos = horizontalScrollBar.scrollBoxPosition();
+  LOGV(hPos);
+  if (cursorLocation != oldLoc) {
+    LOGV(oldLoc);
+    LOGV(cursorLocation);
+    int top = min(oldLoc.y, newLine);
+    top -= verticalScrollBar.scrollBoxPosition();
+    int bottom = max(oldLoc.y, newLine);
+    bottom -= verticalScrollBar.scrollBoxPosition();
+    bottom++;
+    //hideCursor();
+    LOGV(top);
+    LOGV(bottom);
+    updateCursor();
+    if (newLine == oldLoc.y) {
+      //int whereY = top*lineHeight;
+      AgString line = getLine(newLine);
+      int oldX = xPosition(oldLoc.x, line);
+      if (oldLoc.x == 0) {
+	oldX = 0;
+      }
+      IPoint oldPoint(oldX-hPos, lineHeight*top);
+      int newX = xPosition(cursorLocation.x, line);
+      if (cursorLocation.x == 0) {
+	newX = 0;
+      }
+      IPoint newPoint(newX - hPos, lineHeight*bottom);
+      LOGV(oldPoint.asString());
+      LOGV(newPoint.asString());
+      IRectangle rectangle(oldPoint, newPoint);
+      dataArea.refresh(rectangle, true);
+      LOGV(rectangle.asString());
+    }
+    else {
+      int width = dataArea.size().width();
+      IRectangle rectangle(0, lineHeight*top, width, lineHeight*bottom);
+      dataArea.refresh(rectangle, true);
+      LOGV(rectangle.asString());
+    }
+    //showCursor();
+  }
+  return *this;
+}
+
+
+void TraceFileView::parseToCursor() {
+  LOGSECTION("TraceFileView::parseToCursor");
+  cint oldLoc = PARSE_LOCATION;
+  LOGV(oldLoc);
+  LOGV(cursorLocation);
+  switch (parser.processState) {
+    case FtParser::finished: {
+      if (precedes(cursorLocation, PARSE_LOCATION)) {
+        parser.reset();
+        refreshHighlight(oldLoc);
+        oldLoc = PARSE_LOCATION;
+        break;
+      }
+      messageBeep();
+      return;
+    }
+    case FtParser::selectionError:
+      parser.processState = FtParser::selectionRequired;
+      /* FALLTHROUGH */  /* ? - I think so */
+    case FtParser::selectionRequired:
+      parser.completeReduction();
+      break;
+    case FtParser::syntaxError:
+      if (!precedes(cursorLocation, PARSE_LOCATION)) {
+        messageBeep();
+        return;
+      }
+    default:
+      parser.processState = FtParser::running;
+      refreshHighlight(oldLoc);
+      break;
+  }
+  LOGV(cursorLocation) LCV(PARSE_LOCATION);
+  turnHighlightOff();
+  LOGV(cursorLocation) LCV(PARSE_LOCATION);
+
+  //if (PARSE_LOCATION == cursorLocation) return;
+  if (PARSE_LOCATION != cursorLocation) {
+    FileTraceWindow *x = (FileTraceWindow *) frameWindow;
+    ISystemPointerHandle newHandle(ISystemPointerHandle::wait);
+    x->setMousePointer(newHandle);
+    x->setStatusField("Running");
+
+    //parser.parseTo(&cursorLocation);
+    do {
+    	parser.parseTo(&cursorLocation);
+	if (parser.processState != FtParser::selectionRequired) {
+	  continue;
+	}
+	int fileIndex = (char *) parser.state.pointer - parser.text.pointer();
+	int tn = reductionTable[fileIndex];
+	LOGV(fileIndex) LCV(tn);
+	if (tn == 0) {
+	  continue;
+	}
+	parser.completeReduction(tn);
+    } while (parser.processState <= FtParser::running && 
+	     precedes(PARSE_LOCATION, cursorLocation));
+    setCursorLocation(PARSE_LOCATION);
+    LOGV(oldLoc);
+    LOGV(cursorLocation);
+    refreshHighlight(oldLoc);
+  }
+  onEnter();
+}
+