package org.alastairmailer;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;
import java.util.Set;
import java.util.Vector;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.ListCellRenderer;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableModel;
import net.sf.jabref.BibtexEntry;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.CorruptIndexException;
@SuppressWarnings(value={"serial"})
public class LuceneSearchPanel extends JFrame {
private class LuceneSearchTableModel extends DefaultTableModel {
public final String[] columnNames = new String[] {"Relevance", "", "Filename"};
public LuceneSearchTableModel() {
super();
setColumnIdentifiers(columnNames);
}
@Override
public boolean isCellEditable(int row, int column) {
return false;
}
@Override
public Class<?> getColumnClass(int columnIndex) {
switch (columnIndex) {
case 0:
return String.class;
case 1:
return Document.class;
case 2:
return String.class;
}
return null;
}
@Override
public String getColumnName(int column) {
return columnNames[column];
}
/**
* Number of rows of initial results to request caching for
*/
public final static int CACHE_ROWS = 5;
public void clear() {
for (int i = 0; i < this.getRowCount(); i++) {
this.removeRow(i);
}
this.getDataVector().clear();
this.setRowCount(0);
}
}
private JTextField searchText;
private JButton searchButton;
private JTable resultsTable;
private LuceneSearchTableModel myModel;
private JPanel contextPanel = new JPanel();
private JComboBox databaseCombo;
private JPanel bBarFH;
private JButton selectButton;
private JComboBox selectCombo;
private Vector<BibtexEntry> bibItemList;
private LuceneSidePanelPlugin plugin;
public LuceneSearchPanel(LuceneSidePanelPlugin plugin) {
super();
this.plugin = plugin;
buildPanel();
addListeners();
}
public LuceneSearchPanel(LuceneSidePanelPlugin plugin, LuceneBibtexDatabase ldb) {
this(plugin);
databaseCombo.setSelectedItem(ldb);
}
private void buildPanel() {
setSize(new Dimension(600, 400));
setTitle("Search database for terms");
Container contentPane = getContentPane();
GridBagLayout gBag = new GridBagLayout();
contentPane.setLayout(gBag);
JLabel searchLabel = new JLabel("Search:");
contentPane.add(searchLabel, new GridBagConstraints() {
{
fill = GridBagConstraints.NONE;
gridx = 0;
gridy = 0;
weightx = 0;
weighty = 0;
insets = new Insets(5, 5, 5, 5);
}
});
databaseCombo = new JComboBox(plugin.getDatabases());
databaseCombo.setRenderer(new ListCellRenderer() {
ImageIcon errorIcon = new ImageIcon(LuceneSidePanelPlugin.getResourceURL("images/warning-small.png"));
ImageIcon updateIcon = new ImageIcon(LuceneSidePanelPlugin.getResourceURL("images/update-small.png"));
ImageIcon blankIcon = new ImageIcon(LuceneSidePanelPlugin.getResourceURL("images/blank-small.png"));
public Component getListCellRendererComponent(JList list,
Object value, int index, boolean isSelected,
boolean cellHasFocus) {
LuceneBibtexDatabase ldb = (LuceneBibtexDatabase)value;
ImageIcon ic = null;
String tooltip = "";
JLabel l = null;
// if (ldb.isUpdating()) {
// ic = this.updateIcon;
// tooltip = ldb.toString() + ": updating";
// } else if (ldb.indexingError() || !ldb.isIndexed()) {
// ic = this.errorIcon;
// tooltip = ldb.toString() + ": error accessing database - please rebuild manually";
// } else {
// ic = this.blankIcon;
// }
try {
if (!ldb.indexCurrent()) {
ic = this.errorIcon;
tooltip = "The index for this database is not current";
}
l = new JLabel(ldb.toString(), ic, JLabel.LEFT);
l.setBackground(isSelected ? list.getSelectionBackground() : list.getBackground());
l.setForeground(isSelected ? list.getSelectionForeground() : list.getForeground());
} catch (IOException e) {
l = new JLabel(ldb.toString(), null, JLabel.LEFT);
tooltip = "The index for this database is not readable";
l.setEnabled(false);
l.setFocusable(false);
}
l.setOpaque(true);
l.setToolTipText(tooltip);
return l;
}
});
for (LuceneBibtexDatabase ldb : plugin.getDatabases()) {
if (ldb.getDb().equals(plugin.getFrame().basePanel().database())) {
databaseCombo.setSelectedItem(ldb);
}
}
databaseCombo.addActionListener(new ActionListener() {
LuceneBibtexDatabase previous = null;
public void actionPerformed(ActionEvent a) {
LuceneBibtexDatabase selected = (LuceneBibtexDatabase)databaseCombo.getSelectedItem();
if (selected == null) {
searchButton.setEnabled(false);
} else {
if (selected.getIndexDir() == null || selected.getFileDir() == null) {
databaseCombo.setSelectedItem((Object)previous);
} else {
previous = selected;
searchButton.setEnabled(true);
}
}
}
});
contentPane.add(databaseCombo, new GridBagConstraints() {
{
fill = GridBagConstraints.NONE;
gridx = 1;
gridy = 0;
weightx = 0;
weighty = 0;
}
});
JLabel forLabel = new JLabel("for");
contentPane.add(forLabel, new GridBagConstraints() {
{
fill = GridBagConstraints.NONE;
gridx = 2;
gridy = 0;
weightx = 0;
weighty = 0;
insets = new Insets(0, 5, 0, 5);
}
});
searchText = new JTextField();
contentPane.add(searchText, new GridBagConstraints() {
{
fill = GridBagConstraints.HORIZONTAL;
gridx = 3;
gridy = 0;
weightx = 1.0;
weighty = 0.0;
}
});
searchButton = new JButton("Search");
contentPane.add(searchButton, new GridBagConstraints() {
{
fill = GridBagConstraints.NONE;
gridx = 4;
gridy = 0;
weightx = 0.0;
weighty = 0.0;
insets = new Insets(5, 0, 5, 5);
}
});
myModel = new LuceneSearchTableModel();
resultsTable = new JTable(myModel);
resultsTable.setDefaultRenderer(File.class, FiletypeHandler.getRenderer());
JScrollPane scroller = new JScrollPane(resultsTable);
contentPane.add(scroller, new GridBagConstraints() {
{
gridx = 0;
gridy = 1;
weightx = 0.5;
weighty = 0.2;
gridwidth = 5;
fill = GridBagConstraints.BOTH;
insets = new Insets(0, 5, 0, 5);
}
});
JPanel buttonBar = new JPanel();
buttonBar.setLayout(new BoxLayout(buttonBar, BoxLayout.LINE_AXIS));
bibItemList = new Vector<BibtexEntry>();
selectCombo = new JComboBox(bibItemList);
selectCombo.setToolTipText("JabRef entries linked to this file");
selectCombo.setEnabled(false);
buttonBar.add(selectCombo);
buttonBar.add(Box.createHorizontalStrut(10));
selectButton = new JButton("Select in JabRef");
selectButton.setEnabled(false);
selectButton.setToolTipText("Select entry in JabRef");
buttonBar.add(selectButton);
buttonBar.add(Box.createHorizontalStrut(20 + 10));
bBarFH = new JPanel();
buttonBar.add(bBarFH);
contextPanel.setLayout(new BorderLayout());
contentPane.add(buttonBar, new GridBagConstraints() {
{
gridx = 0;
gridy = 2;
weightx = 0.0;
weighty = 0.0;
gridwidth = 5;
fill = GridBagConstraints.BOTH;
insets = new Insets(0, 5, 5, 5);
}
});
contextPanel.setLayout(new BorderLayout());
contentPane.add(contextPanel, new GridBagConstraints() {
{
gridx = 0;
gridy = 3;
weightx = 0.5;
weighty = 0.5;
gridwidth = 5;
fill = GridBagConstraints.BOTH;
insets = new Insets(0, 5, 5, 5);
}
});
}
private void addListeners() {
searchText.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent a) {
runQuery();
}
});
searchButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent a) {
runQuery();
}
});
selectButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
LuceneBibtexDatabase db = plugin.getDatabases().get(databaseCombo.getSelectedIndex());
BibtexEntry be = (BibtexEntry)selectCombo.getSelectedItem();
plugin.getFrame().showBasePanel(db.getBp());
db.getBp().showEntry(be);
}
});
resultsTable.setSelectionModel(new SingleSelectionModel() {
public void updateSingleSelection(int oldValue, int newValue) {
if (newValue != -1) {
Document d = (Document)resultsTable.getModel().getValueAt(newValue, 1);
LuceneBibtexDatabase db = plugin.getDatabases().get(databaseCombo.getSelectedIndex());
File file = new File(db.getFileDir(), d.get("rel_path"));
FiletypeHandler fh = FiletypeHandler.getHandler(file);
contextPanel.removeAll();
bBarFH.removeAll();
Set<BibtexEntry> entries = db.getBibtexEntries(d.get("rel_path"));
bibItemList.clear();
if (entries != null) {
selectButton.setEnabled(true);
selectCombo.setEnabled(true);
bibItemList.addAll(entries);
selectCombo.setSelectedIndex(0);
} else {
selectCombo.setSelectedIndex(-1);
selectButton.setEnabled(false);
selectCombo.setEnabled(false);
}
if (fh != null) {
bBarFH.add(fh.getButtonBar());
contextPanel.add(fh.getContextComponent(), BorderLayout.CENTER);
fh.showContext(file, searchText.getText());
contextPanel.revalidate();
} else {
System.out.println("Error: " + file);
}
}
}
});
resultsTable.getModel().addTableModelListener(new TableModelListener() {
public void tableChanged(TableModelEvent e) {
int first = e.getFirstRow();
int last = e.getLastRow();
TableModel m = resultsTable.getModel();
if (first < 0 || last > m.getRowCount()) {
} else if (last < LuceneSearchTableModel.CACHE_ROWS) {
for (int i = first; i < last + 1; i++) {
Document d = (Document)m.getValueAt(i, 1);
LuceneBibtexDatabase db = plugin.getDatabases().get(databaseCombo.getSelectedIndex());
File f = new File(db.getFileDir(), d.get("rel_path"));
FiletypeHandler fh = FiletypeHandler.getHandler(f);
if (e.getType() == TableModelEvent.INSERT) {
fh.cache(f, searchText.getText().split(" "));
} else if (e.getType() == TableModelEvent.DELETE) {
fh.decache(f);
} else if (e.getType() == TableModelEvent.UPDATE) {
fh.cache(f, searchText.getText().split(" "));
}
}
}
}
});
}
public void setQuery(String text) {
searchText.setText(text);
}
public void runQuery(String text) {
searchText.setText(text);
this.runQuery();
}
public void runQuery() {
contextPanel.removeAll();
bBarFH.removeAll();
bibItemList.clear();
selectCombo.setSelectedIndex(-1);
selectButton.setEnabled(false);
selectCombo.setEnabled(false);
contextPanel.revalidate();
myModel.clear();
String text = searchText.getText();
LuceneBibtexDatabase ldb = (LuceneBibtexDatabase)databaseCombo.getSelectedItem();
try {
SearchQuery query = new SearchQuery(text, ldb, myModel);
(new Thread(query)).start();
} catch (CorruptIndexException e) {
JOptionPane.showMessageDialog(plugin.getFrame(), "The specified index is corrupted, please rebuild the index.", "Corrupt Index", JOptionPane.WARNING_MESSAGE);
} catch (IOException e) {
JOptionPane.showMessageDialog(plugin.getFrame(), "The index directory could not be read. Please ensure it exists and is readable.", "Cannot read index", JOptionPane.WARNING_MESSAGE);
}
}
}