package view;
//----- JDK Imports ------------------------------------------------------------
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.Vector;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JEditorPane;
import javax.swing.JInternalFrame;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTextPane;
import javax.swing.KeyStroke;
import javax.swing.ScrollPaneConstants;
import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener;
import javax.swing.event.InternalFrameEvent;
import javax.swing.event.InternalFrameListener;
import javax.swing.text.BadLocationException;
import javax.swing.text.DefaultHighlighter;
import javax.swing.text.Highlighter;
import javax.swing.text.Style;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyleContext;
import javax.swing.text.StyledDocument;
//----- Phoenix Imports --------------------------------------------------------
import controller.PhoenixController;
import controller.SchemeController;
/**
* Video Phoenix
* Version 0.2.0
* Copyright (c) 2007 Lunderskov, Ian; Pan, Jiabei; Rebelsky, Samuel;
* Whisenhunt, Heather; Young, Ian; Zuleta Benavides, Luis.
* All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* This window provides a scripting-based interaction platform between the user
* and Phoenix.
*
* @author Lunderskov, Ian; Pan, Jiabei; Rebelsky, Samuel; Whisenhunt, Heather;
* Young, Ian; Zuleta Benavides, Luis
* @author Glimmer Labs 2006-2007
* @version 0.2.0
*/
@SuppressWarnings("serial")
public class SchemeWindow extends JInternalFrame implements KeyListener,
ActionListener, InternalFrameListener
{
/*--------*-------------------------------------------------------------------
* Fields *
*--------*/
// flags indicating whether the input and output area are maximized
Boolean upMax = false;
Boolean downMax = false;
// SchemeController for this SchemeWindow
public SchemeController controller;
// main display window
public PhoenixWindow view;
// saved input
public static String savedInput = "";
// vector to store calls and an index
Vector<String> calls;
int index;
// current location in calls
int current;
// outputArea's styled document object
public StyledDocument doc;
// input and output areas - scrollpanes in editor/text panes
JSplitPane textSplitPane;
JScrollPane inputAreaPane;
public SchemeEditor inputArea;
public JMenuedTextPane outputArea;
public JScrollPane outputAreaPane;
// buttons for controlling the window
JPanel buttons;
JButton prevButton;
JButton nextButton;
JButton helpButton;
public JButton runButton;
public JButton killButton;
// whether Escape is currently depressed
// for recognizing esc+p "previous" and esc+n "next" in editor pane
Boolean flagEsc = false;
// icons
ImageIcon runIcon =
new ImageIcon(PhoenixController.getImage("play.gif"));
ImageIcon nextIcon =
new ImageIcon(PhoenixController.getImage("next.gif"));
ImageIcon prevIcon =
new ImageIcon(PhoenixController.getImage("prev.gif"));
/*--------------*-------------------------------------------------------------
* Constructors *
*--------------*/
/**
* Construct a SchemeWindow of default size
*
* @param controller SchemeController for this SchemeWindow
*/
public SchemeWindow(SchemeController controller)
{
// set resizable, closable, maximizable, iconifiable
super("Interaction Window", true, true, true, true);
this.controller = controller;
this.view = controller.phoenix.view;
setLayout(new BorderLayout());
// set close operation
this.setDefaultCloseOperation(JInternalFrame.HIDE_ON_CLOSE);
// set up fields in a split pane
this.inputArea = new SchemeEditor();
this.inputArea.addKeyListener(this);
this.inputAreaPane = new JScrollPane(this.inputArea);
this.inputArea.requestFocusInWindow();
this.inputAreaPane.setHorizontalScrollBarPolicy(
ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
this.inputAreaPane.setVerticalScrollBarPolicy(
ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
this.outputArea = new JMenuedTextPane();
this.outputArea.setEditable(false);
// style initializations
this.doc = this.outputArea.getStyledDocument();
this.outputPaneStyles(this.doc);
// set up control buttons
this.buttons = new JPanel();
this.buttons.setLayout(new GridBagLayout());
GridBagConstraints cons = new GridBagConstraints();
this.runButton = new JButton(runIcon);
this.runButton.addActionListener(this);
this.runButton.setToolTipText("Execute Commands");
this.prevButton = new JButton(prevIcon);
this.prevButton.addActionListener(this);
this.prevButton.setToolTipText("Go to Previous Command");
this.nextButton = new JButton(nextIcon);
this.nextButton.addActionListener(this);
this.nextButton.setToolTipText("Go to Next Command");
this.helpButton = new JButton(new ImageIcon(PhoenixController.getImage(
"help.gif")));
this.helpButton.setToolTipText("Help");
this.helpButton.addActionListener(this);
this.killButton = new JButton(new ImageIcon(PhoenixController.getImage(
"kill.gif")));
this.killButton.setToolTipText("Terminate Current Command");
this.killButton.addActionListener(this);
this.killButton.setEnabled(false);
cons.fill = GridBagConstraints.HORIZONTAL;
cons.gridheight = 1;
cons.gridwidth = 8;
cons.gridx = 0;
cons.gridy = 0;
this.buttons.add(this.prevButton, cons);
cons.gridx = 0;
cons.gridy = 1;
this.buttons.add(this.runButton, cons);
cons.gridx = 0;
cons.gridy = 2;
this.buttons.add(this.nextButton, cons);
cons.gridx = 0;
cons.gridy = 3;
this.buttons.add(this.killButton, cons);
cons.gridx = 0;
cons.gridy = 8;
this.buttons.add(this.helpButton, cons);
this.outputAreaPane = new JScrollPane(this.outputArea);
this.outputAreaPane.setHorizontalScrollBarPolicy(
ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
this.outputAreaPane.setVerticalScrollBarPolicy(
ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED);
JPanel panel = new JPanel();
panel.setLayout(new BorderLayout());
panel.add(this.inputAreaPane, BorderLayout.CENTER);
panel.add(this.buttons, BorderLayout.EAST);
this.add(panel, BorderLayout.SOUTH);
this.textSplitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT,
this.outputAreaPane, panel);
this.textSplitPane.setResizeWeight(1);
this.add(this.textSplitPane, BorderLayout.CENTER);
// size the window
this.setBounds(200, 0, 450, 400);
this.setVisible(true);
// initialize index to a value indicating no calls
// and calls to a value indicating no history
this.index = 0;
this.current = 0;
this.calls = new Vector<String>();
this.calls.setSize(50);
this.runButton.addKeyListener(this);
this.prevButton.addKeyListener(this);
this.nextButton.addKeyListener(this);
this.killButton.addKeyListener(this);
this.helpButton.addKeyListener(this);
this.outputArea.addKeyListener(this);
this.view.add(this);
} // SchemeWindow(MainFrame)
/*---------*------------------------------------------------------------------
* Methods *
*---------*/
/**
* Get the SchemeController for this SchemeWindow
*
* @return controller SchemeController for this SchemeWindow
*/
public SchemeController getController()
{
return this.controller;
} // getController()
/**
* Set the text of the output area, erasing previous contents
*
* @param str String to be displayed
*/
public void setOutputText(String str)
{
this.outputArea.setText(str);
} // setOutputText(String)
/**
* Get the text of the output area
*
* @return output Text of the output area
*/
public String getOutputText()
{
return this.outputArea.getText();
} // getOutputText()
/**
* Set the text of the input area, erasing previous contents
*
* @param str String to be displayed
*/
public void setInputText(String str)
{
this.inputArea.setText(str);
} // setInputText(String)
/**
* Get the text of the input area
*
* @return input Text of the input area
*/
public String getInputText()
{
return this.inputArea.getText();
} // getInputText()
/**
* Get a style by name
*
* @param name Name of the style
* @return style Style associated with name
*/
public Style getStyle(String name)
{
return this.doc.getStyle(name);
} // getStyle(String)
/**
* Set a style
*
* @param name Name of the style
* @param style Style
*/
public void setStyle(String name, Style style)
{
this.doc.addStyle(name, style);
} // setStyle(String, Style)
/**
* Available styles for the output pane
*
* @param doc StyledDocument for which styles are available
*/
public void outputPaneStyles(StyledDocument doc)
{
StyleContext sctx = new StyleContext();
Style def = sctx.getStyle(StyleContext.DEFAULT_STYLE);
// Our basic style
Style regular = doc.addStyle("regular", def);
StyleConstants.setFontFamily(regular, "Arial");
StyleConstants.setFontSize(regular, 12);
// Style for input echoed in the window
doc.addStyle("input", regular);
// Style for output
doc.addStyle("output", regular);
StyleConstants.setBold(doc.getStyle("output"), true);
// Style for scheme error
doc.addStyle("scheme_error", regular);
StyleConstants.setItalic(doc.getStyle("scheme_error"), true);
StyleConstants.setForeground(doc.getStyle("scheme_error"),
new java.awt.Color(255, 0, 0));
} // outputPaneStyles(StyledDocument)
/**
* Interpret the Scheme expression in input area
*/
public void schemeCall()
{
// remove the trailing blank space
String input = this.getInputText().trim();
if (input.length() == 0)
{
return;
} // if (input.length() == 0)
// update the Vector of previous Scheme calls
this.updateCalls(input);
// This is the line that may throw an exception
SchemeController.schemeCall(SchemeWindow.savedInput + "\n" + input, true);
this.controller.printStyledText("\n" + input + "\n", "input");
this.setInputText("");
SchemeWindow.savedInput = "";
} // schemeCall()
/**
* Update history
*
* @param call Call to be entered into history
*/
public void updateCalls(String call)
{
this.index++;
this.current = this.index;
if (this.index == 50)
{
this.index = 0;
} // if (this.index == 50)
call = call.substring(0, call.length());
this.calls.setElementAt(call, this.index);
} // updateCalls(String)
/**
* Handle key presses
*
* @param event Key pressed event
*/
public void keyPressed(KeyEvent event)
{
// if escape key is being pressed
if (event.getKeyCode() == KeyEvent.VK_ESCAPE)
{
// set flag for use with esc+p and esc+n commands
this.flagEsc = true;
// prevent keystroke from being processed by other listeners
event.consume();
} // if (event.getKeyCode() == KeyEvent.VK_ESCAPE)
// if keystroke is shift+enter
else if (event.isShiftDown() && event.getKeyCode() == KeyEvent.VK_ENTER
&& runButton.isEnabled())
{
// run - process input from input window
schemeCall();
} // else if (event.isShiftDown() && event.getKeyCode() == ...
// if keystroke is page-up or esc+p
else if ((event.getKeyCode() == KeyEvent.VK_PAGE_UP)
|| ((event.getKeyCode() == KeyEvent.VK_P) && this.flagEsc))
{
// previous - show previous command stored in history
this.setInputText(this.calls.get(this.current));
if (this.current == 1)
{
this.current = 1;
} // if (this.current == 1)
else if (this.current > 1)
{
this.current--;
} // else if (this.current > 1)
} // else if ((event.getKeyCode() == KeyEvent.VK_PAGE_UP) ...
// if keystroke is page-down or esc+n
else if ((event.getKeyCode() == KeyEvent.VK_PAGE_DOWN)
|| ((event.getKeyCode() == KeyEvent.VK_N) && this.flagEsc))
{
// next - show next command stored in history
if (this.current < this.index)
{
this.current++;
} // else if (this.current < index)
this.setInputText(this.calls.get(this.current));
} // else if ((event.getKeyCode() == KeyEvent.VK_PAGE_DOWN) ...
else if (event.isControlDown() && event.getKeyCode() == KeyEvent.VK_D)
{
if (this.downMax)
{
this.textSplitPane.setDividerLocation(0.64f);
this.downMax = false;
this.upMax = false;
} // if (this.downMax)
else
{
this.textSplitPane.setDividerLocation(0f);
this.downMax = true;
this.upMax = false;
} // else
} // else if (event.isControlDown() && event.getKeyCode() == ...
else if (event.isControlDown() && event.getKeyCode() == KeyEvent.VK_E)
{
if (this.upMax)
{
this.textSplitPane.setDividerLocation(0.64f);
this.upMax = false;
this.downMax = false;
} // if (this.upMax)
else
{
this.textSplitPane.setDividerLocation(1f);
this.upMax = true;
this.downMax = false;
} // else
} // else if (event.isControlDown() && event.getKeyCode() == ...
} // keyPressed(KeyEvent)
/**
* Handle keys typed
*
* @param event Key type event
*/
public void keyTyped(KeyEvent event)
{
if (this.flagEsc)
{
// prevent keystroke from being processed by other listeners
event.consume();
} // if (this.flagEsc)
} // keyTyped(KeyEvent)
/**
* Handle key releases
*
* @param event Key release event
*/
public void keyReleased(KeyEvent event)
{
if (this.flagEsc)
{
// prevent keystroke from being processed by other listeners
event.consume();
} // if (this.flagEsc)
// if escape key is being released
if (event.getKeyCode() == KeyEvent.VK_ESCAPE)
{
// reset flag to false
this.flagEsc = false;
} // if (event.getKeyCode() == KeyEvent.VK_ESCAPE)
} // keyReleased(KeyEvent)
/**
* Handle mouse actions
*
* @param event Action event
*/
public void actionPerformed(ActionEvent event)
{
// if action came from the run button
if ((JButton) event.getSource() == this.runButton)
{
// run
this.schemeCall();
} // if ((JButton) event.getSource() == this.runButton)
// if action came from the previous button
else if ((JButton) event.getSource() == this.prevButton)
{
// display previous command in history
this.setInputText(this.calls.get(this.current));
if (this.current > 1)
{
this.current--;
} // if (this.current > 1)
} // else if ((JButton) event.getSource() == this.prevButton)
// if action came from the next button
else if ((JButton) event.getSource() == this.nextButton)
{
// display next command in history
if (this.current < this.index)
{
this.current++;
} // else if (this.current < index)
this.setInputText(this.calls.get(this.current));
} // else if ((JButton) event.getSource() == this.nextButton)
// if action came from the help button
else if ((JButton) event.getSource() == this.helpButton)
{
// show help
PhoenixWindow.getController().showHelp();
} // else if ((JButton) event.getSource() == this.helpButton)
// if action came from the kill button
else if ((JButton) event.getSource() == this.killButton)
{
// interrupt the command interpreter's thread
SchemeController.cmdListener.interrupt();
} // else if ((JButton) event.getSource() == this.killButton)
} // mouseClicked(MouseEvent)
/**
* Handle internal frame activated
*
* @param event Internal frame activated event
*/
public void internalFrameActivated(InternalFrameEvent event)
{
this.moveToFront();
} // internalFrameActivated(InternalFrameEvent)
/**
* Handle internal frame opened
*
* @param event Internal frame opened event
*/
public void internalFrameOpened(InternalFrameEvent event)
{
this.moveToFront();
} // internalFrameOpened(InternalFrameEvent)
/**
* Handle internal frame closed
*
* @param event Internal frame closed event
*/
public void internalFrameClosed(InternalFrameEvent event)
{
// do nothing when frame is closed
} // internalFrameClosed(InternalFrameEvent)
/**
* Handle internal frame closing
*
* @param event Internal frame closing event
*/
public void internalFrameClosing(InternalFrameEvent event)
{
// do nothing when frame is closing
} // internalFrameClosing(InternalFrameEvent)
/**
* Handle internal frame deactivated
*
* @param event Internal frame deactivated event
*/
public void internalFrameDeactivated(InternalFrameEvent event)
{
// do nothing when frame is deactivated
} // internalFrameDeactivated(InternalFrameEvent)
/**
* Handle internal frame deiconified
*
* @param event Internal frame deiconified event
*/
public void internalFrameDeiconified(InternalFrameEvent event)
{
// do nothing when frame is expanded
} // internalFrameDeiconified(InternalFrameEvent)
/**
* Handle internal frame iconified
*
* @param event Internal frame iconified event
*/
public void internalFrameIconified(InternalFrameEvent event)
{
// do nothing when frame is minimized
} // internalFrameIconified(InternalFrameEvent)
// inspired by http://blog.csdn.net/mq612/archive/2006/09/21/1260761.aspx
public class JMenuedTextPane extends JTextPane implements MouseListener
{
private JPopupMenu pop = null;
private JMenuItem copy = null;
private JMenuItem selectAll = null;
/**
* Create a new JMenuedTextPane
*/
public JMenuedTextPane()
{
super();
init();
} // JMenuedTextPane()
/* initialize */
private void init()
{
this.addMouseListener(this);
this.setFont(new Font("Monospaced", Font.PLAIN, 12));
this.pop = new JPopupMenu();
this.pop.add(this.copy = new JMenuItem("Copy"));
this.pop.add(this.selectAll = new JMenuItem("Select All"));
this.copy.setAccelerator(KeyStroke.getKeyStroke('C', InputEvent.CTRL_MASK));
this.selectAll.setAccelerator(KeyStroke.getKeyStroke('A',
InputEvent.CTRL_MASK));
this.copy.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
action(event);
} // actionPerformed(ActionEvent)
});
this.selectAll.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
action(event);
} // actionPerformed(ActionEvent)
});
this.add(pop);
} // init()
public void action(ActionEvent event)
{
String str = event.getActionCommand();
if (str.equals(this.copy.getText()))
{
this.copy();
} // if (str.equals(this.copy.getText()))
else if (str.equals(this.selectAll.getText()))
{
this.selectAll();
} // else if (str.equals(this.selectAll.getText()))
} // action(ActionEvent)
public boolean isCanCopy()
{
return (! (this.getSelectionStart() == this.getSelectionEnd()));
} // isCanCopy()
public void mousePressed(MouseEvent event)
{
if (event.getButton() == MouseEvent.BUTTON3)
{
this.copy.setEnabled(isCanCopy());
this.pop.show(this, event.getX(), event.getY());
} // if (event.getButton() == MouseEvent.BUTTON3)
} // mousePressed(MouseEvent)
public void mouseClicked(MouseEvent event)
{
// do nothing when mouse is clicked
} // mouseClicked(MouseEvent)
public void mouseEntered(MouseEvent event)
{
// do nothing when mouse enters frame
} // mouseEntered(MouseEvent)
public void mouseExited(MouseEvent event)
{
// do nothing when mouse exits frame
} // mouseExited(MouseEvent)
public void mouseReleased(MouseEvent event)
{
// do nothing when mouse is released
} // mouseReleased(MouseEvent)
} // class JMenuedTextPane
// context menu portion inspired by http://blog.csdn.net/mq612/archive/
// 2006/09/21/1260761.aspx
// Highlighter for JEditorPane inspired by http://www.exampledepot.
// com/egs/javax.swing.text/style_HiliteWords.html
public class SchemeEditor extends JEditorPane implements MouseListener,
CaretListener
{
private JPopupMenu pop = null;
private JMenuItem copy = null;
private JMenuItem paste = null;
private JMenuItem cut = null;
private JMenuItem selectAll = null;
private Highlighter hilite = this.getHighlighter();
public SchemeEditor()
{
super();
this.addMouseListener(this);
this.addCaretListener(this);
this.setFont(new Font("Monospaced", Font.PLAIN, 12));
this.pop = new JPopupMenu();
this.pop.add(this.cut = new JMenuItem("Cut"));
this.pop.add(this.copy = new JMenuItem("Copy"));
this.pop.add(this.paste = new JMenuItem("Paste"));
this.pop.add(this.selectAll = new JMenuItem("Select All"));
this.copy.setAccelerator(KeyStroke.getKeyStroke('C', InputEvent.CTRL_MASK));
this.paste.setAccelerator(KeyStroke.getKeyStroke('V', InputEvent.CTRL_MASK));
this.cut.setAccelerator(KeyStroke.getKeyStroke('X', InputEvent.CTRL_MASK));
this.selectAll.setAccelerator(KeyStroke.getKeyStroke('A', InputEvent.CTRL_MASK));
this.copy.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
action(event);
} // actionPerformed(ActionEvent)
});
this.paste.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
action(event);
} // actionPerformed(ActionEvent)
});
this.cut.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
action(event);
} // actionPerformed(ActionEvent)
});
this.selectAll.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
action(event);
} // actionPerformed(ActionEvent)
});
} // JMenuedEditorPane()
public void action(ActionEvent event)
{
String str = event.getActionCommand();
if (str.equals(this.copy.getText()))
{
this.copy();
} // if (str.equals(copy.getText()))
else if (str.equals(this.paste.getText()))
{
this.paste();
} // else if (str.equals(paste.getText()))
else if (str.equals(this.cut.getText()))
{
this.cut();
} // else if (str.equals(cut.getText()))
else if (str.equals(this.selectAll.getText()))
{
this.selectAll();
} // else if (str.equals(selectAll.getText()))
} // action(ActionEvent)
public boolean isClipboardString()
{
boolean b = false;
Clipboard clipboard = this.getToolkit().getSystemClipboard();
Transferable content = clipboard.getContents(this);
try
{
if (content.getTransferData(DataFlavor.stringFlavor) instanceof String)
{
b = true;
} // if (content.getTransferData(DataFlavor.stringFlavor) instanceof ...
} // try
catch (Exception e)
{
// do nothing
} // catch (Exception)
return b;
} // isClipboardString()
public boolean isCanCopy()
{
return (! (this.getSelectionStart() == this.getSelectionEnd()));
} // isCanCopy()
public void mousePressed(MouseEvent event)
{
if (event.getButton() == MouseEvent.BUTTON3)
{
this.copy.setEnabled(isCanCopy());
this.paste.setEnabled(isClipboardString());
this.cut.setEnabled(isCanCopy());
this.pop.show(this, event.getX(), event.getY());
} // if (event.getButton() == MouseEvent.BUTTON3)
} // mousePressed(MouseEvent)
public void mouseClicked(MouseEvent event)
{
// do nothing when mouse is clicked
} // mouseClicked(MouseEvent)
public void mouseEntered(MouseEvent event)
{
// do nothing when mouse enters frame
} // mouseEntered(MouseEvent)
public void mouseExited(MouseEvent event)
{
// do nothing when mouse exits frame
} // mouseExited(MouseEvent)
public void mouseReleased(MouseEvent event)
{
// do nothing when mouse is released
} // mouseReleasedd(MouseEvent)
private int getMatchingCloseParen(int open)
throws BadLocationException
{
int i = 0;
int length = this.getText().length();
int danglingParen = 1;
boolean insideQuotes = false;
boolean success = false;
String now = "";
for (i = open + 1; (i < length) && (!success); i++)
{
now = this.getText(i, 1);
if (!insideQuotes && (now.equals("(")))
{
danglingParen++;
} // if (!insideQuotes && (now.equals("(")))
else if (!insideQuotes && now.equals(")"))
{
danglingParen--;
} // else if (!insideQuotes && now.equals(")"))
else if (now.equals("\"") && (!this.getText(i - 1, 1).equals("\\")))
{
insideQuotes = !insideQuotes;
} // else if (now.equals("\"") && (!this.getText(i - 1, 1).equals("\\")))
if (danglingParen == 0)
{
success = true;
} // if (danglingParen == 0)
} // for
if (success)
{
return i;
} // if (success)
else
{
return -1;
} // else
} // getMatchingCloseParen(int)
private int getMatchingOpenParen(int close)
throws BadLocationException
{
int i = 0;
int danglingParen = 1;
boolean insideQuotes = false;
boolean success = false;
String now = "";
for (i = close - 1; (i >= 0) && (!success); i--)
{
now = this.getText(i, 1);
if (!insideQuotes && (now.equals(")")))
{
danglingParen++;
} // if (!insideQuotes && (now.equals(")")))
else if (!insideQuotes && now.equals("("))
{
danglingParen--;
} // else if (!insideQuotes && now.equals("("))
else if (now.equals("\"") && (!this.getText(i - 1, 1).equals("\\")))
{
insideQuotes = !insideQuotes;
} // else if (now.equals("\"") && (!this.getText(i - 1, 1).equals("\\")))
if (danglingParen == 0)
{
success = true;
} // if (danglingParen == 0)
} // for
if (success)
{
return i+1;
} // if (success)
else
{
return -1;
} // else
} // getMatchingCloseParen(int)
public void caretUpdate(CaretEvent event)
{
int dot = event.getDot();
if (dot != event.getMark())
{
removeHighlights();
return;
} // if (dot != event.getMark())
removeHighlights();
try
{
if ((dot != 0) && (this.getText(dot - 1, 1).equals(")")))
{
int pos = getMatchingOpenParen(dot - 1);
if (pos != -1)
{
this.hilite.addHighlight(pos, dot, new ParenHighLighter());
} // if (pos != -1)
else
{
this.hilite.addHighlight(dot - 1, dot, new DanglingHighLighter());
} // else
} // if ((dot != 0) && (this.getText(dot - 1, 1).equals(")")))
else if ((this.getText(dot, 1).equals("(")))
{
int pos = getMatchingCloseParen(dot);
if (pos != -1)
{
this.hilite.addHighlight(dot, pos + 1, new ParenHighLighter());
} // if (pos != -1)
} // else if ((this.getText(dot, 1).equals("(")))
} // try
catch (BadLocationException e)
{
// do nothing
} // catch (BadLocationException)
} // caretUpdate(CaretEvent)
class ParenHighLighter extends DefaultHighlighter.DefaultHighlightPainter
{
public ParenHighLighter()
{
super(Color.LIGHT_GRAY);
} // public ParentHighLighter()
} // class ParenHighLighter
class DanglingHighLighter extends DefaultHighlighter.DefaultHighlightPainter
{
public DanglingHighLighter()
{
super(Color.PINK);
} // DanglingHighLighter()
} // class DanglingHighLighter
public void removeHighlights()
{
Highlighter.Highlight[] hilites = this.hilite.getHighlights();
for (int i=0; i<hilites.length; i++)
{
if ((hilites[i].getPainter() instanceof ParenHighLighter)
|| ((hilites[i].getPainter() instanceof DanglingHighLighter)))
{
this.hilite.removeHighlight(hilites[i]);
} // if ((hilites[i].getPainter() instanceof ParenHighLighter)
} // for
} // removeHighlights()
} // class JMenuedEditorPane
} // class SchemeWindow