001: /*BEGIN_COPYRIGHT_BLOCK
002: *
003: * Copyright (c) 2001-2007, JavaPLT group at Rice University (javaplt@rice.edu)
004: * All rights reserved.
005: *
006: * Redistribution and use in source and binary forms, with or without
007: * modification, are permitted provided that the following conditions are met:
008: * * Redistributions of source code must retain the above copyright
009: * notice, this list of conditions and the following disclaimer.
010: * * Redistributions in binary form must reproduce the above copyright
011: * notice, this list of conditions and the following disclaimer in the
012: * documentation and/or other materials provided with the distribution.
013: * * Neither the names of DrJava, the JavaPLT group, Rice University, nor the
014: * names of its contributors may be used to endorse or promote products
015: * derived from this software without specific prior written permission.
016: *
017: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
018: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
019: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
020: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
021: * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
022: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
023: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
024: * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
025: * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
026: * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
027: * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
028: *
029: * This software is Open Source Initiative approved Open Source Software.
030: * Open Source Initative Approved is a trademark of the Open Source Initiative.
031: *
032: * This file is part of DrJava. Download the current version of this project
033: * from http://www.drjava.org/ or http://sourceforge.net/projects/drjava/
034: *
035: * END_COPYRIGHT_BLOCK*/
036:
037: package edu.rice.cs.drjava.ui;
038:
039: import javax.swing.*;
040: import javax.swing.text.*;
041: import java.awt.*;
042: import java.awt.event.KeyEvent;
043: import java.awt.datatransfer.*;
044:
045: import java.util.List; //import java.util.LinkedList;
046: import java.util.Vector;
047:
048: import edu.rice.cs.util.swing.*;
049: import edu.rice.cs.util.UnexpectedException;
050: import edu.rice.cs.drjava.config.*;
051: import edu.rice.cs.drjava.*;
052: import edu.rice.cs.drjava.model.DJDocument;
053: import edu.rice.cs.drjava.model.definitions.indent.Indenter;
054: import edu.rice.cs.util.OperationCanceledException;
055: import edu.rice.cs.drjava.model.repl.*;
056:
057: /** The view component for repl interaction.
058: * @version $Id: InteractionsPane.java 4255 2007-08-28 19:17:37Z mgricken $
059: */
060: public abstract class InteractionsPane extends AbstractDJPane implements
061: OptionConstants, ClipboardOwner {
062:
063: /** The custom keymap for the interactions pane. */
064: protected Keymap _keymap;
065:
066: /** Whether to draw text as antialiased. */
067: private boolean _antiAliasText = false;
068:
069: static StyledEditorKit EDITOR_KIT;
070:
071: static {
072: EDITOR_KIT = new InteractionsEditorKit();
073: }
074:
075: /** A runnable object that causes the editor to beep. */
076: protected Runnable _beep = new Runnable() {
077: public void run() {
078: Toolkit.getDefaultToolkit().beep();
079: }
080: };
081:
082: /** The OptionListener for TEXT_ANTIALIAS. */
083: private class AntiAliasOptionListener implements
084: OptionListener<Boolean> {
085: public void optionChanged(OptionEvent<Boolean> oce) {
086: _antiAliasText = oce.value.booleanValue();
087: InteractionsPane.this .repaint();
088: }
089: }
090:
091: /** Returns a runnable object that beeps to the user. */
092: public Runnable getBeep() {
093: return _beep;
094: }
095:
096: private InteractionsDJDocument _doc;
097:
098: // private List<Integer> _listOfPrompt = new Vector<Integer>(); // Vector used because it is synchronized. // NOT USED
099:
100: /** Creates an InteractionsPane with the given document.
101: * Uses default keymap name ("INTERACTIONS_KEYMAP")
102: * @param doc StyledDocument containing the interactions history.
103: */
104: public InteractionsPane(InteractionsDJDocument doc) {
105: this ("INTERACTIONS_KEYMAP", doc);
106: }
107:
108: /** Creates an InteractionsPane with the given document.
109: * @param keymapName the name of the keymap for this pane
110: * @param doc StyledDocument containing the interactions history.
111: */
112: public InteractionsPane(String keymapName,
113: InteractionsDJDocument doc) {
114: super (doc);
115: _doc = doc;
116: //add actions for enter key, etc.
117: _keymap = addKeymap(keymapName, getKeymap());
118:
119: setCaretPosition(doc.getLength());
120: setHighlighter(new ReverseHighlighter());
121: _highlightManager = new HighlightManager(this );
122:
123: _antiAliasText = DrJava.getConfig().getSetting(TEXT_ANTIALIAS)
124: .booleanValue();
125:
126: // Setup color listeners.
127:
128: new ForegroundColorListener(this );
129: new BackgroundColorListener(this );
130:
131: OptionListener<Boolean> aaTemp = new AntiAliasOptionListener();
132: DrJava.getConfig().addOptionListener(
133: OptionConstants.TEXT_ANTIALIAS, aaTemp);
134: }
135:
136: /** We lost ownership of what we put in the clipboard. */
137: public void lostOwnership(Clipboard clipboard, Transferable contents) {
138: // ignore
139: }
140:
141: /** Widens the visibilitly of the processKeyEvent method; it is protected in the superclass. */
142: public void processKeyEvent(KeyEvent e) {
143: super .processKeyEvent(e);
144: }
145:
146: /** Assigns the given keystroke to the given action in this pane.
147: * @param stroke keystroke that triggers the action
148: * @param action Action to perform
149: */
150: public void addActionForKeyStroke(KeyStroke stroke, Action action) {
151: // we don't want multiple keys bound to the same action
152: KeyStroke[] keys = _keymap.getKeyStrokesForAction(action);
153: if (keys != null) {
154: for (int i = 0; i < keys.length; i++)
155: _keymap.removeKeyStrokeBinding(keys[i]);
156: }
157: _keymap.addActionForKeyStroke(stroke, action);
158: setKeymap(_keymap);
159: }
160:
161: /** Sets this pane's beep to be a different runnable object. Defaults to Toolkit.getDefaultToolkit().beep().
162: * @param beep Runnable command to notify the user
163: */
164: public void setBeep(Runnable beep) {
165: _beep = beep;
166: }
167:
168: /** Highlights the given text with error highlight.
169: * @param offset the offset in the text
170: * @param length the length of the error to highlight
171: */
172: public void highlightError(int offset, int length) {
173: _highlightManager.addHighlight(offset, offset + length,
174: ERROR_PAINTER);
175: }
176:
177: /** Overriding this method ensures that all new documents created in this editor pane use our editor kit
178: * (and thus our model).
179: */
180: protected EditorKit createDefaultEditorKit() {
181: return EDITOR_KIT;
182: }
183:
184: /** Enable anti-aliased text by overriding paintComponent. */
185: protected void paintComponent(Graphics g) {
186: if (g == null)
187: return; // Addresses bug 1651914
188: if (_antiAliasText && g instanceof Graphics2D) {
189: Graphics2D g2d = (Graphics2D) g;
190: g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
191: RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
192: }
193: super .paintComponent(g);
194: }
195:
196: /** Returns the DJDocument held by the pane. */
197: public DJDocument getDJDocument() {
198: return _doc;
199: }
200:
201: /** Updates the current location and highlight (if one exists). Adds prompt position to prompt list. */
202: protected void matchUpdate(int offset) {
203: if (!_doc.hasPrompt())
204: return;
205: _doc.setCurrentLocation(offset);
206: _removePreviousHighlight();
207:
208: // addToPromptList(getPromptPos()); // NOT USED
209: int to = getCaretPosition();
210: int from = _doc.balanceBackward(); //_doc()._reduced.balanceBackward();
211: if (from > -1) {
212: // Found a matching open brace to this close brace
213: from = to - from;
214: /* if (_notCrossesPrompt(to,from)) */_addHighlight(from,
215: to); // _listOfPrompt NOT USED
216: // Highlighter.Highlight[] _lites = getHighlighter().getHighlights();
217: }
218: // if this wasn't a close brace, check for an open brace
219: else {
220: // (getCaretPosition will be the start of the highlight)
221: from = to;
222: to = getDJDocument().balanceForward();
223:
224: if (to > -1) {
225: to = to + from;
226: /* if (_notCrossesPrompt(to,from)) */_addHighlight(
227: from - 1, to); // _listOfPrompt NOT USED
228: // Highlighter.Highlight[] _lites = getHighlighter().getHighlights();
229: }
230: }
231: }
232:
233: // /** Returns the list of prompts. Used for tests. */
234: // List<Integer> getPromptList() { return _listOfPrompt; } // NOT USED
235:
236: // /** Resets the list of prompts. Called when the interactions pane is reset. */ // NOT USED
237: // public void resetPrompts() {
238: //// System.err.println("Clearing prompt list");
239: // _listOfPrompt.clear();
240: // }
241:
242: // NOT USED
243: // /** Adds the position to the list of prompt positions. package private for tests. Does not necessarily run in
244: // * event thread. _listOfPrompt is a Vector which is thread safe. */
245: // void addToPromptList(int pos) {
246: // if (! _listOfPrompt.contains(new Integer(pos))) _listOfPrompt.add(new Integer(pos));
247: // }
248:
249: // /** Returns true if the two locations do not have a prompt between them. */ // NOT USED
250: // private boolean _notCrossesPrompt(int to, int from) {
251: //// DrJava.consoleErr().println("To: " + to + " , From: " + from);
252: // boolean toReturn = true;
253: // for (Integer prompt : _listOfPrompt) {
254: // toReturn &= ((to >= prompt && from >= prompt) || (to <= prompt && from <= prompt));
255: // }
256: // return toReturn;
257: // }
258:
259: /** Indent the given selection, for the given reason, in the current document. Should only run in the event queuel
260: * @param selStart - the selection start
261: * @param selEnd - the selection end
262: * @param reason - the reason for the indent
263: * @param pm - the ProgressMonitor used by the indenter
264: */
265: protected void indentLines(int selStart, int selEnd,
266: Indenter.IndentReason reason, ProgressMonitor pm) {
267: assert EventQueue.isDispatchThread();
268: try {
269: _doc.indentLines(selStart, selEnd, reason, pm);
270: setCaretPos(_doc.getCurrentLocation());
271: } catch (OperationCanceledException oce) {
272: throw new UnexpectedException(oce);
273: }
274: }
275:
276: /** Returns true if the indent is to be performed. The code in the definitions pane prompts the user, but this
277: * requires a copy of mainframe, and a reason to do so. The user does not need to be prompted here. The cutoff
278: * in the definitions pane for the prompt is 10000 characters, which is unlikely to occur in the interactions
279: * pane very often if at all.
280: * @param selStart - the selection start
281: * @param selEnd - the selection end
282: */
283: protected boolean shouldIndent(int selStart, int selEnd) {
284: return true;
285: }
286:
287: /** Gets the current prompt position */
288: public abstract int getPromptPos();
289: }
|