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 java.util.Vector;
040: import java.util.LinkedList;
041: import java.util.ArrayList;
042: import java.util.Enumeration;
043: import java.io.File;
044:
045: import javax.swing.*;
046: import javax.swing.event.*;
047: import javax.swing.tree.*;
048: import javax.swing.table.*;
049: import javax.swing.text.BadLocationException;
050: import java.awt.event.*;
051: import java.awt.*;
052: import javax.swing.text.BadLocationException;
053: import javax.swing.text.Position;
054:
055: import javax.swing.border.CompoundBorder;
056: import javax.swing.border.LineBorder;
057: import javax.swing.border.MatteBorder;
058:
059: import edu.rice.cs.drjava.model.RegionManagerListener;
060: import edu.rice.cs.drjava.model.DocumentRegion;
061: import edu.rice.cs.drjava.model.MovingDocumentRegion;
062: import edu.rice.cs.drjava.model.SimpleDocumentRegion;
063: import edu.rice.cs.drjava.model.OpenDefinitionsDocument;
064: import edu.rice.cs.drjava.model.FileMovedException;
065: import edu.rice.cs.drjava.model.RegionManager;
066: import edu.rice.cs.drjava.config.*;
067: import edu.rice.cs.drjava.DrJava;
068: import edu.rice.cs.plt.tuple.Pair;
069: import edu.rice.cs.util.swing.Utilities;
070: import edu.rice.cs.util.UnexpectedException;
071: import edu.rice.cs.util.StringOps;
072: import edu.rice.cs.drjava.config.OptionConstants;
073:
074: /** Panel for displaying find results. This class is a swing class which should only be accessed from the event thread.
075: * @version $Id$
076: */
077: public class FindResultsPanel extends
078: RegionsTreePanel<MovingDocumentRegion> {
079: protected JButton _goToButton;
080: protected JButton _bookmarkButton;
081: protected JButton _removeButton;
082: protected JComboBox _colorBox;
083: protected RegionManager<MovingDocumentRegion> _regionManager;
084: protected int _lastIndex;
085:
086: /** Saved option listeners kept in this field so they can be removed for garbage collection */
087: private LinkedList<Pair<Option<Color>, OptionListener<Color>>> _colorOptionListeners = new LinkedList<Pair<Option<Color>, OptionListener<Color>>>();
088:
089: /** Constructs a new find results panel. This is swing class which should only be accessed from the event thread.
090: * @param frame the MainFrame
091: * @param rm the region manager associated with this panel
092: * @param title for the panel
093: */
094: public FindResultsPanel(MainFrame frame,
095: RegionManager<MovingDocumentRegion> rm, String title) {
096: super (frame, title);
097: _regionManager = rm;
098: _regionManager
099: .addListener(new RegionManagerListener<MovingDocumentRegion>() {
100: public void regionAdded(MovingDocumentRegion r,
101: int index) {
102: addRegion(r);
103: }
104:
105: public void regionChanged(MovingDocumentRegion r,
106: int index) {
107: regionRemoved(r);
108: regionAdded(r, index);
109: }
110:
111: public void regionRemoved(MovingDocumentRegion r) {
112: removeRegion(r);
113: }
114: });
115:
116: OptionListener<Color> temp;
117: Pair<Option<Color>, OptionListener<Color>> pair;
118: for (int i = 0; i < OptionConstants.FIND_RESULTS_COLORS.length; ++i) {
119: temp = new FindResultsColorOptionListener(i);
120: pair = new Pair<Option<Color>, OptionListener<Color>>(
121: OptionConstants.FIND_RESULTS_COLORS[i], temp);
122: _colorOptionListeners.add(pair);
123: DrJava.getConfig().addOptionListener(
124: OptionConstants.FIND_RESULTS_COLORS[i], temp);
125: }
126: }
127:
128: static class ColorComboRenderer extends JPanel implements
129: ListCellRenderer {
130: private Color m_c = Color.black;
131: private DefaultListCellRenderer defaultRenderer = new DefaultListCellRenderer();
132: private final static Dimension preferredSize = new Dimension(0,
133: 20);
134:
135: public ColorComboRenderer() {
136: super ();
137: setBorder(new CompoundBorder(new MatteBorder(2, 10, 2, 10,
138: Color.white), new LineBorder(Color.black)));
139: }
140:
141: public Component getListCellRendererComponent(JList list,
142: Object value, int row, boolean sel, boolean hasFocus) {
143: Component renderer;
144: if (value instanceof Color) {
145: m_c = (Color) value;
146: renderer = this ;
147: } else {
148: JLabel l = (JLabel) defaultRenderer
149: .getListCellRendererComponent(list, value, row,
150: sel, hasFocus);
151: l.setHorizontalAlignment(JLabel.CENTER);
152: renderer = l;
153: }
154: // Taken out because this is a 1.5 method; not sure if it's necessary
155: //renderer.setPreferredSize(preferredSize);
156: return renderer;
157: }
158:
159: public void paint(Graphics g) {
160: setBackground(m_c);
161: super .paint(g);
162: }
163: }
164:
165: /** Creates the buttons for controlling the regions. Should be overridden. */
166: protected JComponent[] makeButtons() {
167: Action goToAction = new AbstractAction("Go to") {
168: public void actionPerformed(ActionEvent ae) {
169: goToRegion();
170: }
171: };
172: _goToButton = new JButton(goToAction);
173:
174: Action bookmarkAction = new AbstractAction("Bookmark") {
175: public void actionPerformed(ActionEvent ae) {
176: _bookmark();
177: }
178: };
179: _bookmarkButton = new JButton(bookmarkAction);
180:
181: Action removeAction = new AbstractAction("Remove") {
182: public void actionPerformed(ActionEvent ae) {
183: _remove();
184: }
185: };
186: _removeButton = new JButton(removeAction);
187:
188: // "Highlight" label panel
189: final JPanel highlightPanel = new JPanel();
190: final Color normalColor = highlightPanel.getBackground();
191: highlightPanel.add(new JLabel("Highlight:"));
192:
193: _colorBox = new JComboBox();
194: for (int i = 0; i < OptionConstants.FIND_RESULTS_COLORS.length; ++i) {
195: _colorBox.addItem(DrJava.getConfig().getSetting(
196: OptionConstants.FIND_RESULTS_COLORS[i]));
197: }
198: _colorBox.addItem("None");
199: _colorBox.setRenderer(new ColorComboRenderer());
200: _colorBox.addActionListener(new ActionListener() {
201: public void actionPerformed(ActionEvent e) {
202: if (_lastIndex < OptionConstants.FIND_RESULTS_COLORS.length) {
203: --DefinitionsPane.FIND_RESULTS_PAINTERS_USAGE[_lastIndex];
204: }
205: _lastIndex = _colorBox.getSelectedIndex();
206: if (_lastIndex < OptionConstants.FIND_RESULTS_COLORS.length) {
207: ++DefinitionsPane.FIND_RESULTS_PAINTERS_USAGE[_lastIndex];
208: highlightPanel
209: .setBackground(DrJava
210: .getConfig()
211: .getSetting(
212: OptionConstants.FIND_RESULTS_COLORS[_lastIndex]));
213: } else
214: highlightPanel.setBackground(normalColor);
215:
216: _frame
217: .refreshFindResultsHighlightPainter(
218: FindResultsPanel.this ,
219: DefinitionsPane.FIND_RESULTS_PAINTERS[_lastIndex]);
220: }
221: });
222: // find the first available color, or choose "None"
223: for (_lastIndex = 0; _lastIndex < OptionConstants.FIND_RESULTS_COLORS.length; ++_lastIndex) {
224: if (DefinitionsPane.FIND_RESULTS_PAINTERS_USAGE[_lastIndex] == 0)
225: break;
226: }
227: if (_lastIndex < OptionConstants.FIND_RESULTS_COLORS.length) {
228: ++DefinitionsPane.FIND_RESULTS_PAINTERS_USAGE[_lastIndex];
229: }
230: _colorBox.setSelectedIndex(_lastIndex);
231: _frame.refreshFindResultsHighlightPainter(
232: FindResultsPanel.this ,
233: DefinitionsPane.FIND_RESULTS_PAINTERS[_lastIndex]);
234:
235: return new JComponent[] { _goToButton, _bookmarkButton,
236: _removeButton, highlightPanel, _colorBox };
237: }
238:
239: /** @return the selected painter for these find results. */
240: public ReverseHighlighter.DefaultUnderlineHighlightPainter getSelectedPainter() {
241: return DefinitionsPane.FIND_RESULTS_PAINTERS[_lastIndex];
242: }
243:
244: /** Turn the selected regions into bookmarks. */
245: private void _bookmark() {
246: for (final MovingDocumentRegion r : getSelectedRegions()) {
247: DocumentRegion bookmark = _model.getBookmarkManager()
248: .getRegionOverlapping(r.getDocument(),
249: r.getStartOffset(), r.getEndOffset());
250: if (bookmark == null) {
251: try {
252: DocumentRegion newR = new SimpleDocumentRegion(r
253: .getDocument(), r.getDocument().getFile(),
254: r.getStartOffset(), r.getEndOffset());
255: _model.getBookmarkManager().addRegion(newR);
256: } catch (FileMovedException fme) {
257: throw new UnexpectedException(fme);
258: }
259: }
260: }
261: }
262:
263: /** Action performed when the Enter key is pressed. Should be overridden. */
264: protected void performDefaultAction() {
265: goToRegion();
266: }
267:
268: /** Remove the selected regions. */
269: private void _remove() {
270: for (MovingDocumentRegion r : getSelectedRegions())
271: _regionManager.removeRegion(r);
272: if (_regionManager.getRegions().size() == 0) {
273: _close();
274: }
275: }
276:
277: /** Update button state and text. */
278: protected void updateButtons() {
279: ArrayList<MovingDocumentRegion> regs = getSelectedRegions();
280: _goToButton.setEnabled(regs.size() == 1);
281: _bookmarkButton.setEnabled(regs.size() > 0);
282: _removeButton.setEnabled(regs.size() > 0);
283: }
284:
285: /** Makes popup menu actions. Should be overridden if additional actions besides "Go to" and "Remove" are added. */
286: protected AbstractAction[] makePopupMenuActions() {
287: AbstractAction[] acts = new AbstractAction[] {
288: new AbstractAction("Go to") {
289: public void actionPerformed(ActionEvent e) {
290: goToRegion();
291: }
292: }, new AbstractAction("Bookmark") {
293: public void actionPerformed(ActionEvent e) {
294: _bookmark();
295: }
296: }, new AbstractAction("Remove") {
297: public void actionPerformed(ActionEvent e) {
298: _remove();
299: }
300: } };
301: return acts;
302: }
303:
304: /** Close the pane. */
305: public void _close() {
306: super ._close();
307: freeResources();
308: }
309:
310: /** Free the resources; this can be used if the panel was never actually displayed. */
311: public void freeResources() {
312: _regionManager.clearRegions();
313: _model.disposeFindResultsManager(_regionManager);
314: for (Pair<Option<Color>, OptionListener<Color>> p : _colorOptionListeners) {
315: DrJava.getConfig().removeOptionListener(p.first(),
316: p.second());
317: }
318: if (_lastIndex < OptionConstants.FIND_RESULTS_COLORS.length) {
319: --DefinitionsPane.FIND_RESULTS_PAINTERS_USAGE[_lastIndex];
320: }
321: }
322:
323: /** Factory method to create user objects put in the tree.
324: * If subclasses extend RegionTreeUserObj, they need to override this method. */
325: protected RegionTreeUserObj<MovingDocumentRegion> makeRegionTreeUserObj(
326: MovingDocumentRegion r) {
327: return new FindResultsRegionTreeUserObj(r);
328: }
329:
330: /** Class that gets put into the tree. The toString() method determines what's displayed in the tree. */
331: protected static class FindResultsRegionTreeUserObj extends
332: RegionTreeUserObj<MovingDocumentRegion> {
333: protected int _lineNumber;
334:
335: public FindResultsRegionTreeUserObj(MovingDocumentRegion r) {
336: super (r);
337: _lineNumber = _region.getDocument().getLineOfOffset(
338: _region.getStartOffset()) + 1;
339: }
340:
341: public String toString() {
342: final StringBuilder sb = new StringBuilder();
343: sb.append("<html>");
344: sb.append(lineNumber());
345: sb.append(": ");
346: sb.append(_region.getString());
347: sb.append("</html>");
348: return sb.toString();
349: }
350: }
351:
352: /** The OptionListener for FIND_RESULTS_COLOR. */
353: private class FindResultsColorOptionListener implements
354: OptionListener<Color> {
355: private int _index;
356:
357: public FindResultsColorOptionListener(int i) {
358: _index = i;
359: }
360:
361: public void optionChanged(OptionEvent<Color> oce) {
362: int pos = _colorBox.getSelectedIndex();
363: _colorBox.removeItemAt(_index);
364: _colorBox.insertItemAt(oce.value, _index);
365: _colorBox.setSelectedIndex(pos);
366: if (pos == _index) {
367: _frame.refreshFindResultsHighlightPainter(
368: FindResultsPanel.this,
369: DefinitionsPane.FIND_RESULTS_PAINTERS[_index]);
370: }
371: }
372: }
373: }
|