/**
  * Will select the Mars Messages tab error message that matches the given specifications, if it is
  * found. Matching is done by constructing a string using the parameter values and searching the
  * text area for the last occurrance of that string.
  *
  * @param fileName A String containing the file path name.
  * @param line Line number for error message
  * @param column Column number for error message
  */
 public void selectErrorMessage(String fileName, int line, int column) {
   String errorReportSubstring =
       new java.io.File(fileName).getName()
           + ErrorList.LINE_PREFIX
           + line
           + ErrorList.POSITION_PREFIX
           + column;
   int textPosition = assemble.getText().lastIndexOf(errorReportSubstring);
   if (textPosition >= 0) {
     int textLine = 0;
     int lineStart = 0;
     int lineEnd = 0;
     try {
       textLine = assemble.getLineOfOffset(textPosition);
       lineStart = assemble.getLineStartOffset(textLine);
       lineEnd = assemble.getLineEndOffset(textLine);
       assemble.setSelectionColor(Color.YELLOW);
       assemble.select(lineStart, lineEnd);
       assemble.getCaret().setSelectionVisible(true);
       assemble.repaint();
     } catch (BadLocationException ble) {
       // If there is a problem, simply skip the selection
     }
   }
 }
 /**
  * Post a message to the assembler display
  *
  * @param message String to append to assembler display text
  */
 public void postMarsMessage(String message) {
   assemble.append(message);
   // can do some crude cutting here.  If the document gets "very large",
   // let's cut off the oldest text. This will limit scrolling but the limit
   // can be set reasonably high.
   if (assemble.getDocument().getLength() > MAXIMUM_SCROLLED_CHARACTERS) {
     try {
       assemble.getDocument().remove(0, NUMBER_OF_CHARACTERS_TO_CUT);
     } catch (BadLocationException ble) {
       // only if NUMBER_OF_CHARACTERS_TO_CUT > MAXIMUM_SCROLLED_CHARACTERS
     }
   }
   assemble.setCaretPosition(assemble.getDocument().getLength());
   setSelectedComponent(assembleTab);
 }
  /** Constructor for the class, sets up two fresh tabbed text areas for program feedback. */
  public MessagesPane() {
    super();
    this.setMinimumSize(new Dimension(0, 0));
    assemble = new JTextArea();
    run = new JTextArea();
    assemble.setEditable(false);
    run.setEditable(false);
    // Set both text areas to mono font.  For assemble
    // pane, will make messages more readable.  For run
    // pane, will allow properly aligned "text graphics"
    // DPS 15 Dec 2008
    Font monoFont = new Font(Font.MONOSPACED, Font.PLAIN, 12);
    assemble.setFont(monoFont);
    run.setFont(monoFont);

    JButton assembleTabClearButton = new JButton("Clear");
    assembleTabClearButton.setToolTipText("Clear the Mars Messages area");
    assembleTabClearButton.addActionListener(
        new ActionListener() {
          public void actionPerformed(ActionEvent e) {
            assemble.setText("");
          }
        });
    assembleTab = new JPanel(new BorderLayout());
    assembleTab.add(createBoxForButton(assembleTabClearButton), BorderLayout.WEST);
    assembleTab.add(
        new JScrollPane(
            assemble,
            ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
            ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED),
        BorderLayout.CENTER);
    assemble.addMouseListener(
        new MouseAdapter() {
          public void mouseClicked(MouseEvent e) {
            String text;
            int lineStart = 0;
            int lineEnd = 0;
            try {
              int line = assemble.getLineOfOffset(assemble.viewToModel(e.getPoint()));
              lineStart = assemble.getLineStartOffset(line);
              lineEnd = assemble.getLineEndOffset(line);
              text = assemble.getText(lineStart, lineEnd - lineStart);
            } catch (BadLocationException ble) {
              text = "";
            }
            if (text.length() > 0) {
              // If error or warning, parse out the line and column number.
              if (text.startsWith(ErrorList.ERROR_MESSAGE_PREFIX)
                  || text.startsWith(ErrorList.WARNING_MESSAGE_PREFIX)) {
                assemble.select(lineStart, lineEnd);
                assemble.setSelectionColor(Color.YELLOW);
                assemble.repaint();
                int separatorPosition = text.indexOf(ErrorList.MESSAGE_SEPARATOR);
                if (separatorPosition >= 0) {
                  text = text.substring(0, separatorPosition);
                }
                String[] stringTokens = text.split("\\s"); // tokenize with whitespace delimiter
                String lineToken = ErrorList.LINE_PREFIX.trim();
                String columnToken = ErrorList.POSITION_PREFIX.trim();
                String lineString = "";
                String columnString = "";
                for (int i = 0; i < stringTokens.length; i++) {
                  if (stringTokens[i].equals(lineToken) && i < stringTokens.length - 1)
                    lineString = stringTokens[i + 1];
                  if (stringTokens[i].equals(columnToken) && i < stringTokens.length - 1)
                    columnString = stringTokens[i + 1];
                }
                int line = 0;
                int column = 0;
                try {
                  line = Integer.parseInt(lineString);
                } catch (NumberFormatException nfe) {
                  line = 0;
                }
                try {
                  column = Integer.parseInt(columnString);
                } catch (NumberFormatException nfe) {
                  column = 0;
                }
                // everything between FILENAME_PREFIX and LINE_PREFIX is filename.
                int fileNameStart =
                    text.indexOf(ErrorList.FILENAME_PREFIX) + ErrorList.FILENAME_PREFIX.length();
                int fileNameEnd = text.indexOf(ErrorList.LINE_PREFIX);
                String fileName = "";
                if (fileNameStart < fileNameEnd
                    && fileNameStart >= ErrorList.FILENAME_PREFIX.length()) {
                  fileName = text.substring(fileNameStart, fileNameEnd).trim();
                }
                if (fileName != null && fileName.length() > 0) {
                  selectEditorTextLine(fileName, line, column);
                  selectErrorMessage(fileName, line, column);
                }
              }
            }
          }
        });

    JButton runTabClearButton = new JButton("Clear");
    runTabClearButton.setToolTipText("Clear the Run I/O area");
    runTabClearButton.addActionListener(
        new ActionListener() {
          public void actionPerformed(ActionEvent e) {
            run.setText("");
          }
        });
    runTab = new JPanel(new BorderLayout());
    runTab.add(createBoxForButton(runTabClearButton), BorderLayout.WEST);
    runTab.add(
        new JScrollPane(
            run,
            ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
            ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED),
        BorderLayout.CENTER);
    this.addTab("Mars Messages", assembleTab);
    this.addTab("Run I/O", runTab);
    this.setToolTipTextAt(
        0,
        "Messages produced by Run menu. Click on assemble error message to select erroneous line");
    this.setToolTipTextAt(1, "Simulated MIPS console input and output");
  }