* Copyright (C) 2010 Robert Futrell
* robert_futrell at users.sourceforge.net
* http://fifesoft.com/rsyntaxtextarea
* This library is distributed under a modified BSD license. See the included
* RSTALanguageSupport.License.txt file for details.
package org.fife.rsta.ac;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.ComponentOrientation;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowEvent;
import java.awt.event.WindowFocusListener;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.BorderFactory;
import javax.swing.InputMap;
import javax.swing.JComponent;
import javax.swing.JPanel;
import javax.swing.JRootPane;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.JWindow;
import javax.swing.KeyStroke;
import javax.swing.UIManager;
import javax.swing.border.Border;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.plaf.basic.BasicTextFieldUI;
import javax.swing.tree.DefaultTreeCellRenderer;
import org.fife.ui.rsyntaxtextarea.focusabletip.TipUtil;
import org.fife.ui.rsyntaxtextarea.PopupWindowDecorator;
import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
* A popup window that displays a text field and tree, allowing the user to
* jump to a specific part of code in the current source file.
public class GoToMemberWindow extends JWindow {
private RSyntaxTextArea textArea;
private JTextField field;
private AbstractSourceTree tree;
private Listener listener;
* @param parent The parent window (hosting the text component).
* @param textArea The text area.
* @param tree The source tree appropriate for the current language.
public GoToMemberWindow(Window parent, RSyntaxTextArea textArea,
AbstractSourceTree tree) {
this.textArea = textArea;
ComponentOrientation o = parent.getComponentOrientation();
JPanel contentPane = new JPanel(new BorderLayout());
contentPane.setBorder(TipUtil.getToolTipBorder());
listener = new Listener();
addWindowFocusListener(listener);
parent.addComponentListener(listener);
field = createTextField();
contentPane.add(field, BorderLayout.NORTH);
tree.setShowMajorElementsOnly(true);
tree.setGotoSelectedElementOnClick(false);
tree.setFocusable(false);
tree.addMouseListener(listener);
JScrollPane sp = new JScrollPane(tree);
sp.setViewportBorder(BorderFactory.createEmptyBorder());
Color bg = TipUtil.getToolTipBackground();
((DefaultTreeCellRenderer)tree.getCellRenderer()).setBackgroundNonSelectionColor(bg);
// Give apps a chance to decorate us with drop shadows, etc.
setContentPane(contentPane);
PopupWindowDecorator decorator = PopupWindowDecorator.get();
//System.out.println(decorator);
decorator.decorate(this);
applyComponentOrientation(o);
JRootPane pane = getRootPane();
InputMap im = pane.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "EscapePressed");
ActionMap am = pane.getActionMap();
am.put("EscapePressed", new AbstractAction() {
public void actionPerformed(ActionEvent e) {
* Creates the text field allowing the user to enter filter text.
* @return The text field.
private JTextField createTextField() {
JTextField field = new JTextField(30);
field.setUI(new BasicTextFieldUI());
field.setBorder(new TextFieldBorder());
field.addActionListener(listener);
field.addKeyListener(listener);
field.getDocument().addDocumentListener(listener);
// Force refocus of text area to prevent NPE in GoToMemberAction's
// (TextAction's) getTextComponent(ActinEvent) when a different
// component is focused and this action is executed twice.
textArea.requestFocusInWindow();
* Listens for events in this window.
private class Listener extends MouseAdapter implements WindowFocusListener,
ComponentListener, DocumentListener, ActionListener, KeyListener {
public void actionPerformed(ActionEvent e) {
if (tree.gotoSelectedElement()) {
public void changedUpdate(DocumentEvent e) {
public void componentHidden(ComponentEvent e) {
public void componentMoved(ComponentEvent e) {
public void componentResized(ComponentEvent e) {
public void componentShown(ComponentEvent e) {
private void handleDocumentEvent(DocumentEvent e) {
tree.filter(field.getText());
tree.selectFirstNodeMatchingFilter();
public void insertUpdate(DocumentEvent e) {
public void keyPressed(KeyEvent e) {
switch (e.getKeyCode()) {
tree.selectNextVisibleRow();
tree.selectPreviousVisibleRow();
public void keyReleased(KeyEvent e) {
public void keyTyped(KeyEvent e) {
public void mouseClicked(MouseEvent e) {
if (e.getClickCount()==2) {
tree.gotoSelectedElement();
public void removeUpdate(DocumentEvent e) {
public void uninstall() {
field.removeActionListener(this);
field.getDocument().removeDocumentListener(this);
tree.removeMouseListener(this);
removeWindowFocusListener(this);
public void windowGainedFocus(WindowEvent e) {
public void windowLostFocus(WindowEvent e) {
* The border for the filtering text field.
private static class TextFieldBorder implements Border {
public Insets getBorderInsets(Component c) {
return new Insets(2, 5, 3, 5);
public boolean isBorderOpaque() {
public void paintBorder(Component c, Graphics g, int x, int y,
g.setColor(UIManager.getColor("controlDkShadow"));
g.drawLine(x,y+h-1, x+w-1,y+h-1);