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

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

/*
 * AnaGram, A System for Syntax Directed Programming
 * Copyright 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();
}