// Near Infinity - An Infinity Engine Browser and Editor
// Copyright (C) 2001 - 2005 Jon Olav Hauglid
// See LICENSE.txt for license information
package org.infinity.search;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.BufferedWriter;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import org.infinity.NearInfinity;
import org.infinity.gui.BrowserMenuBar;
import org.infinity.gui.Center;
import org.infinity.gui.ChildFrame;
import org.infinity.gui.SortableTable;
import org.infinity.gui.TableItem;
import org.infinity.gui.ViewFrame;
import org.infinity.icon.Icons;
import org.infinity.resource.Profile;
import org.infinity.resource.Resource;
import org.infinity.resource.ResourceFactory;
import org.infinity.resource.TextResource;
import org.infinity.resource.Viewable;
import org.infinity.resource.key.ResourceEntry;
final class TextHitFrame extends ChildFrame implements ActionListener, ListSelectionListener
{
private final Component parent;
private final JButton bopen = new JButton("Open", Icons.getIcon(Icons.ICON_OPEN_16));
private final JButton bopennew = new JButton("Open in new window", Icons.getIcon(Icons.ICON_OPEN_16));
private final JButton bsave = new JButton("Save...", Icons.getIcon(Icons.ICON_SAVE_16));
private final JLabel count;
private final SortableTable table;
private final String query;
TextHitFrame(final String query, Component parent)
{
super("Search Result", true);
this.query = query;
this.parent = parent;
setIconImage(Icons.getIcon(Icons.ICON_HISTORY_16).getImage());
List<Class<? extends Object>> colClasses = new ArrayList<Class<? extends Object>>(3);
colClasses.add(Object.class); colClasses.add(Object.class); colClasses.add(Integer.class);
table = new SortableTable(Arrays.asList(new String[]{"File", "Text", "Line"}),
colClasses, Arrays.asList(new Integer[]{100, 300, 50}));
bopen.setMnemonic('o');
bopennew.setMnemonic('n');
bsave.setMnemonic('s');
getRootPane().setDefaultButton(bopennew);
JPanel panel = new JPanel(new FlowLayout(FlowLayout.CENTER));
panel.add(bopen);
panel.add(bopennew);
panel.add(bsave);
count = new JLabel(table.getRowCount() + " hits found", JLabel.CENTER);
count.setFont(count.getFont().deriveFont((float)count.getFont().getSize() + 2.0f));
JPanel pane = (JPanel)getContentPane();
pane.setLayout(new BorderLayout(0, 3));
JScrollPane scrollTable = new JScrollPane(table);
scrollTable.getViewport().setBackground(table.getBackground());
pane.add(count, BorderLayout.NORTH);
pane.add(scrollTable, BorderLayout.CENTER);
pane.add(panel, BorderLayout.SOUTH);
pane.setBorder(BorderFactory.createEmptyBorder(3, 3, 3, 3));
bopen.setEnabled(false);
bopennew.setEnabled(false);
table.setFont(BrowserMenuBar.getInstance().getScriptFont());
table.getSelectionModel().addListSelectionListener(this);
final ChildFrame frame = this;
table.addMouseListener(new MouseAdapter()
{
@Override
public void mouseReleased(MouseEvent event)
{
if (event.getClickCount() == 2) {
int row = table.getSelectedRow();
if (row != -1) {
Resource res = ResourceFactory.getResource((ResourceEntry)table.getValueAt(row, 0));
new ViewFrame(frame, res);
if (res instanceof TextResource)
((TextResource)res).highlightText(((Integer)table.getValueAt(row, 2)).intValue(), query);
}
}
}
});
bopen.addActionListener(this);
bopennew.addActionListener(this);
bsave.addActionListener(this);
pack();
Center.center(this, parent.getBounds());
}
// --------------------- Begin Interface ActionListener ---------------------
@Override
public void actionPerformed(ActionEvent event)
{
if (event.getSource() == bopen) {
int row = table.getSelectedRow();
if (row != -1) {
ResourceEntry entry = (ResourceEntry)table.getValueAt(row, 0);
if (parent instanceof ViewFrame && parent.isVisible()) {
Resource res = ResourceFactory.getResource(entry);
((ViewFrame)parent).setViewable(res);
if (res instanceof TextResource)
((TextResource)res).highlightText(((Integer)table.getValueAt(row, 2)).intValue(), query);
}
else {
NearInfinity.getInstance().showResourceEntry(entry);
Viewable viewable = NearInfinity.getInstance().getViewable();
if (viewable instanceof TextResource)
((TextResource)viewable).highlightText(((Integer)table.getValueAt(row, 2)).intValue(), query);
}
}
}
else if (event.getSource() == bopennew) {
int row = table.getSelectedRow();
if (row != -1) {
Resource res = ResourceFactory.getResource((ResourceEntry)table.getValueAt(row, 0));
new ViewFrame(this, res);
if (res instanceof TextResource)
((TextResource)res).highlightText(((Integer)table.getValueAt(row, 2)).intValue(), query);
}
}
else if (event.getSource() == bsave) {
JFileChooser chooser = new JFileChooser(Profile.getGameRoot().toFile());
chooser.setDialogTitle("Save search result");
chooser.setSelectedFile(new File(chooser.getCurrentDirectory(), "result.txt"));
if (chooser.showSaveDialog(this) == JFileChooser.APPROVE_OPTION) {
Path output = chooser.getSelectedFile().toPath();
if (Files.exists(output)) {
String options[] = {"Overwrite", "Cancel"};
if (JOptionPane.showOptionDialog(this, output + " exists. Overwrite?",
"Save result", JOptionPane.YES_NO_OPTION,
JOptionPane.WARNING_MESSAGE, null, options, options[0]) != 0)
return;
}
try (BufferedWriter bw = Files.newBufferedWriter(output)) {
bw.write("Searched for: " + query); bw.newLine();
bw.write("Number of hits: " + table.getRowCount()); bw.newLine();
for (int i = 0; i < table.getRowCount(); i++) {
bw.write(table.getTableItemAt(i).toString()); bw.newLine();
}
JOptionPane.showMessageDialog(this, "Result saved to " + output, "Save complete",
JOptionPane.INFORMATION_MESSAGE);
} catch (IOException e) {
JOptionPane.showMessageDialog(this, "Error while saving " + output,
"Error", JOptionPane.ERROR_MESSAGE);
e.printStackTrace();
}
}
}
}
// --------------------- End Interface ActionListener ---------------------
// --------------------- Begin Interface ListSelectionListener ---------------------
@Override
public void valueChanged(ListSelectionEvent event)
{
bopen.setEnabled(true);
bopennew.setEnabled(true);
}
// --------------------- End Interface ListSelectionListener ---------------------
@Override
public void setVisible(boolean b)
{
table.tableComplete();
count.setText(table.getRowCount() + " hit(s) found");
if (b && table.getRowCount() == 0)
JOptionPane.showMessageDialog(parent, "No hits found", "Info", JOptionPane.INFORMATION_MESSAGE);
else
super.setVisible(b);
}
public void addHit(ResourceEntry entry, String line, int lineNr)
{
table.addTableItem(new TextHit(entry, line.trim(), lineNr));
}
// -------------------------- INNER CLASSES --------------------------
private static final class TextHit implements TableItem
{
private final ResourceEntry entry;
private final String line;
private final Integer linenr;
private TextHit(ResourceEntry entry, String name, int linenr)
{
this.entry = entry;
line = name;
this.linenr = new Integer(linenr);
}
@Override
public Object getObjectAt(int columnIndex)
{
if (columnIndex == 0)
return entry;
else if (columnIndex == 1)
return line;
return linenr;
}
@Override
public String toString()
{
return String.format("File: %1$s Text: %2$s Line: %3$d",
entry.toString(), line, linenr);
}
}
}