/* A BeanShell macro script to search and open a recent file or a file in the current directory.
*
*
* - Press TAB or A+j (S+TAB or A+k) to select next (prev) file.
* - Press ENTER to open the selected file.
* - Press ESCAPE to close.
*
*
* This Script is a modification of Recent_Files.bsh, written by
* Jeroen Budts and Ollie Rutherfurd.
* Copyright (C) 2001-2004 Ollie Rutherfurd, oliver@rutherfurd.net
* Modified by AhLeung Cheng
*
* {{{ License
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with the jEdit program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
* }}}
*/
import java.util.regex.Pattern;
class Entry {
Entry(String p, Icon i) {
int sep = p.lastIndexOf(File.separator)+1;
name = p.substring(sep);
dir = p.substring(0, sep);
icon = i;
}
String name, dir;
Icon icon;
}
BufferCellRenderer() {
Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
Entry v = (Entry)value;
l = new JLabel(""+v.name+" "+v.dir+"");
l.setOpaque(true);
l.setIcon(v.icon);
l.setBorder(new javax.swing.border.EmptyBorder(2,2,2,2));
if (isSelected) {
l.setBackground(list.getSelectionBackground());
l.setForeground(list.getSelectionForeground());
}
return l;
}
return this;
}
SearchRecentAndCurrentDirDialog(doModal, dialogDimension) {
JList fileList = new JList();
JTextField textField = new JTextField();
textField.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "esc");
textField.getActionMap().put("esc", new AbstractAction() { public void actionPerformed(ActionEvent e) { dialog.dispose(); }} );
textField.getActionMap().put("up", new AbstractAction() { public void actionPerformed(ActionEvent e) { move(-1); }} );
textField.getActionMap().put("down", new AbstractAction() { public void actionPerformed(ActionEvent e) { move(1); }} );
JPanel content = new JPanel(new BorderLayout());
content.add(textField, BorderLayout.NORTH);
content.add(new JScrollPane(fileList), BorderLayout.CENTER);
dialog = new JDialog(view, doModal);
dialog.setContentPane(content);
dialog.setSize(dialogDimension);
dialog.setLocationRelativeTo(view);
dialog.setVisible(true);
SwingUtilities.invokeLater(this); // i.e., the run() method will be invoked later
void move(int d) {
int len = fileList.getModel().getSize();
int i = (fileList.getSelectedIndex() + len + d) % len;
fileList.setSelectedIndex(i);
fileList.ensureIndexIsVisible(i);
}
void actionPerformed(ActionEvent e) {
if (textField.getText().startsWith(":")) { // if input starts with ':', go to that line
line = Integer.parseInt(textField.getText().substring(1));
if ((line < 1) || (line > buffer.getLineCount())) view.getToolkit().beep(); // ref: http://community.jedit.org/?q=node/view/2609
else textArea.setCaretPosition(textArea.getLineStartOffset(line - 1));
}
else {
Entry f = fileList.getSelectedValue();
jEdit.openFile(view, f.dir+f.name);
}
dialog.dispose();
}
// DocumentListener
void changedUpdate(e) {}
void removeUpdate(e) { SwingUtilities.invokeLater(this); }
void insertUpdate(e) { SwingUtilities.invokeLater(this); }
// MouseListener
void mouseEntered(e) {}
void mouseExited(e) {}
void mousePressed(e) {}
void mouseReleased(e) {}
void mouseClicked(e) { if (SwingUtilities.isLeftMouseButton(e)) { actionPerformed(null); } }
Vector allEntries = null;
String keyword = null;
void run() {
if (allEntries==null) { // initialize the list here to speed up dialog display time
HashMap icons = new HashMap();
for (Buffer b:jEdit.getBuffers()) icons.put(b.getPath(), b.getIcon());
List historyList = BufferHistory.getHistory();
allEntries = new Vector(historyList.size() + 100);
final Icon emptyIcon = new Icon() { int getIconHeight() { return 10; } int getIconWidth() { return 10; } void paintIcon(Component c, Graphics g, int x, int y) {}};
final Icon dotIcon = new Icon() { int getIconHeight() { return 10; } int getIconWidth() { return 10; } void paintIcon(Component c, Graphics g, int x, int y) { g.setColor(Color.black); g.fillOval(x+4, y+4, 2, 2); }};
for (BufferHistory.Entry h:historyList) {
Icon icon = icons.get(h.path);
allEntries.add(new Entry(h.path, icon==null? emptyIcon:icon));
if (icon==null) icons.put(h.path, null); // to avoid duplicated entry when adding current dir files
}
for (f : new File(buffer.getDirectory()).listFiles()) { // TODO: use file filter? http://www.avajava.com/tutorials/lessons/how-do-i-use-a-filefilter-to-display-only-the-directories-within-a-directory.html
if (!f.isDirectory()) {
p = f.getCanonicalPath();
if (!icons.containsKey(p)) allEntries.add(new Entry(p, dotIcon));
}
}
textField.setFocusTraversalKeysEnabled(false); // to capture TAB and S+TAB
im = textField.getInputMap();
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_TAB, 0), "down");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_TAB, InputEvent.SHIFT_DOWN_MASK), "up");
im.put(KeyStroke.getKeyStroke("DOWN"), "down");
im.put(KeyStroke.getKeyStroke("UP"), "up");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_J, InputEvent.CTRL_DOWN_MASK), "down");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_J, InputEvent.ALT_DOWN_MASK), "down"); // support both CTRL and ALT
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_K, InputEvent.CTRL_DOWN_MASK), "up");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_K, InputEvent.ALT_DOWN_MASK), "up");
textField.getDocument().addDocumentListener(this);
textField.addActionListener(this);
fileList.setCellRenderer(BufferCellRenderer());
fileList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
fileList.addMouseListener(this);
}
if (textField.getText().equals(keyword)) return;
keyword = textField.getText();
if (keyword.equals("")) {
fileList.setListData(allEntries);
fileList.setSelectedIndex(1); // initially select the next recent buffer
} else {
Vector v = new Vector();
for (Entry f:allEntries) if (Pattern.compile(Pattern.quote(keyword), Pattern.CASE_INSENSITIVE).matcher(f.name).find()) v.add(f);
fileList.setListData(v); // ref: JList.setListData threading issues http://stackoverflow.com/questions/4547113
fileList.setSelectedIndex(0); // select the top match
}
};
}
SearchRecentAndCurrentDirDialog(false, new Dimension(700, 600));