// 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.JComponent; import javax.swing.JFileChooser; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTabbedPane; 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.AbstractStruct; import org.infinity.resource.Profile; import org.infinity.resource.Resource; import org.infinity.resource.ResourceFactory; import org.infinity.resource.StructEntry; import org.infinity.resource.Viewable; import org.infinity.resource.dlg.DlgResource; import org.infinity.resource.key.FileResourceEntry; import org.infinity.resource.key.ResourceEntry; public final class ReferenceHitFrame 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 Object query; private final SortableTable table; public ReferenceHitFrame(Object query, Component parent) { super("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(Object.class); table = new SortableTable(Arrays.asList(new String[]{"File", "Name", "Attribute"}), colClasses, Arrays.asList(new Integer[]{100, 100, 300})); 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); showEntryInViewer(row, res); } } } }); 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); showEntryInViewer(row, res); if (res instanceof DlgResource) ((ViewFrame) parent).toFront(); } else { NearInfinity.getInstance().showResourceEntry(entry); Viewable viewable = NearInfinity.getInstance().getViewable(); showEntryInViewer(row, viewable); if (viewable instanceof DlgResource) NearInfinity.getInstance().toFront(); } } } 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); showEntryInViewer(row, res); } } else if (event.getSource() == bsave) { JFileChooser chooser = new JFileChooser(Profile.getGameRoot().toFile()); chooser.setDialogTitle("Save 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(); } } } } private void showEntryInViewer(int row, Viewable viewable) { if (viewable instanceof DlgResource) { DlgResource dlgRes = (DlgResource) viewable; JComponent detailViewer = dlgRes.getViewerTab(0); JTabbedPane parent = (JTabbedPane) detailViewer.getParent(); dlgRes.showStateWithStructEntry( ((ReferenceHit)table.getTableItemAt(row)).getStructEntry()); // make sure we see the detail viewer parent.getModel().setSelectedIndex(parent.indexOfComponent(detailViewer)); } else if (viewable instanceof AbstractStruct) { ((AbstractStruct)viewable).getViewer().selectEntry( ((ReferenceHit)table.getTableItemAt(row)).getStructEntry().getOffset()); } } // --------------------- 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 name, StructEntry ref) { table.addTableItem(new ReferenceHit(entry, name, ref)); } // -------------------------- INNER CLASSES -------------------------- private static final class ReferenceHit implements TableItem { private final ResourceEntry entry; private final String name; private final StructEntry ref; private ReferenceHit(ResourceEntry entry, String name, StructEntry ref) { this.entry = entry; this.name = name; this.ref = ref; } @Override public Object getObjectAt(int columnIndex) { switch (columnIndex) { case 0: return entry; case 1: if (name != null) { return name; } else { if (entry instanceof FileResourceEntry) { return entry.getActualPath().getParent().toString(); } else { return ""; } } default: if (ref != null) { return ref.getName() + '=' + ref; } else { return null; } } } public StructEntry getStructEntry() { return ref; } @Override public String toString() { StringBuffer buf = new StringBuffer("File: "); buf.append(entry.toString()); if (name != null) buf.append(" Name: ").append(name); if (ref != null) buf.append(" Attribute: ").append(ref.getName() + '=' + ref); return buf.toString(); } } }