/* * Copyright (c) 2009, SQL Power Group Inc. * * This file is part of SQL Power Library. * * SQL Power Library 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 3 of the License, or * (at your option) any later version. * * SQL Power Library 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 this program. If not, see <http://www.gnu.org/licenses/>. */ package ca.sqlpower.swingui.table; import java.awt.Graphics2D; import java.awt.event.ActionEvent; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.font.FontRenderContext; import java.awt.geom.Rectangle2D; import java.io.File; import java.io.FileNotFoundException; import java.io.PrintWriter; import java.text.Format; import java.util.HashMap; import java.util.Map; import java.util.concurrent.Callable; import javax.swing.AbstractAction; import javax.swing.Action; import javax.swing.JDialog; import javax.swing.JFileChooser; import javax.swing.JPopupMenu; import javax.swing.table.TableModel; import javax.swing.text.Document; import ca.sqlpower.swingui.DataEntryPanelBuilder; import ca.sqlpower.swingui.FontSelector; import ca.sqlpower.swingui.SPSUtils; /** * This class contains a JTable that displays the given model. The JTable can be sorted * by clicking on headers, the font can be changed and selected rows can be exported. * * The class also contains a text area that can be used to filter the table as a user * types into the text area. */ public class FancyExportableJTable extends EditableJTable { /** * This mouse listener will make a pop-up menu appear to allow users to modify properties * of the table or export selected regions. */ private class PopupMenuMouseListener implements MouseListener { private JPopupMenu menu; public PopupMenuMouseListener() { menu = new JPopupMenu(); menu.add(new AbstractAction("Change Font Size..") { public void actionPerformed(ActionEvent arg0) { final FontSelector fontSelector = new FontSelector(getFont()); Callable<Boolean> okCall = new Callable<Boolean>() { public Boolean call() { setFont(fontSelector.getSelectedFont()); TableUtils.fitColumnWidths(FancyExportableJTable.this, 15); FontRenderContext frc = ((Graphics2D) getGraphics()).getFontRenderContext(); Rectangle2D fontBounds = fontSelector.getSelectedFont().getMaxCharBounds(frc); setRowHeight((int) fontBounds.getHeight()); return true; } }; Callable<Boolean> cancelCall = new Callable<Boolean>() { public Boolean call() throws Exception { return true; } }; JDialog d = DataEntryPanelBuilder.createDataEntryPanelDialog( fontSelector, getTopLevelAncestor(), "Choose a font", "OK", okCall, cancelCall); d.setVisible(true); } }); menu.add(exportHTMLAction); menu.add(exportCSVAction); menu.pack(); } public void mouseClicked(MouseEvent e) { if (e.getButton() == MouseEvent.BUTTON3) { menu.show(e.getComponent(), e.getX(), e.getY()); } else { menu.setVisible(false); } } public void mouseEntered(MouseEvent e) {} public void mouseExited(MouseEvent e) {} public void mousePressed(MouseEvent e) {} public void mouseReleased(MouseEvent e) {} } /** * This action will export the table in its current state to HTML. */ private final Action exportHTMLAction = new AbstractAction("Export Selected to HTML..") { public void actionPerformed(ActionEvent e) { TableModelHTMLFormatter htmlFormatter= new TableModelHTMLFormatter(); for (Map.Entry<Integer, Format> entry : columnFormatters.entrySet()) { htmlFormatter.setFormatter(entry.getKey(), entry.getValue()); } JFileChooser chooser = new JFileChooser(); chooser.addChoosableFileFilter(SPSUtils.HTML_FILE_FILTER); chooser.setFileFilter(SPSUtils.HTML_FILE_FILTER); int chooserResult = chooser.showSaveDialog(FancyExportableJTable.this); if (chooserResult == JFileChooser.APPROVE_OPTION) { File file = chooser.getSelectedFile(); try { PrintWriter writer = new PrintWriter(file); if (getSelectedRows().length != 0){ htmlFormatter.formatToStream(getModel(), writer, getSelectedRows()); } else { htmlFormatter.formatToStream(getModel(), writer); } } catch (FileNotFoundException ex) { throw new RuntimeException("Could not open file " + file.getName(), ex); } } } }; /** * Formatters for the export for columns. */ private final Map<Integer, Format> columnFormatters = new HashMap<Integer, Format>(); /** * This action will export the table in its current state to CSV. */ private final Action exportCSVAction = new AbstractAction("Export Selected to CSV..") { public void actionPerformed(ActionEvent e) { TableModelCSVFormatter csvFormatter = new TableModelCSVFormatter(); for (Map.Entry<Integer, Format> entry : columnFormatters.entrySet()) { csvFormatter.setFormatter(entry.getKey(), entry.getValue()); } JFileChooser chooser = new JFileChooser(); chooser.addChoosableFileFilter(SPSUtils.CSV_FILE_FILTER); chooser.setFileFilter(SPSUtils.CSV_FILE_FILTER); int chooserResult = chooser.showSaveDialog(FancyExportableJTable.this); if (chooserResult == JFileChooser.APPROVE_OPTION) { File file = chooser.getSelectedFile(); try { PrintWriter writer = new PrintWriter(file); if (getSelectedRows().length != 0) { csvFormatter.formatToStream(getModel(), writer, getSelectedRows()); } else { csvFormatter.formatToStream(getModel(), writer); } } catch (FileNotFoundException ex) { throw new RuntimeException("Could not open file " + file.getName(), ex); } } } }; /** * The text converter for the search table model. This is used to get the strings * of cells in the table to compare them against the text field used in searching. */ private TableTextConverter textConverter = new TableTextConverter() { public String getTextForCell(Object cellValue) { if (cellValue != null) { return cellValue.toString(); } else { return ""; } } public int modelIndex(int viewIndex) { return viewIndex; } }; /** * The sort decorator attached to this table. */ private TableModelSortDecorator sortDecorator; public FancyExportableJTable(TableModel model, Document doc) { sortDecorator = new TableModelSortDecorator(model, getTableHeader()); model = sortDecorator; if (doc != null) { TableModelSearchDecorator newModel = new TableModelSearchDecorator(model); newModel.setDoc(doc); newModel.setTableTextConverter(textConverter); model = newModel; } setModel(model); addMouseListener(new PopupMenuMouseListener()); TableUtils.fitColumnWidths(this, 15); } public FancyExportableJTable(TableModel model) { this(model, null); } @Override public void setModel(TableModel model) { TableModel m = getModel(); if (! (m instanceof TableModelWrapper)) { super.setModel(model); } else { TableModelWrapper lowestWrapper = (TableModelWrapper) m; // down the rabbit hole as far as it goes while (lowestWrapper.getWrappedModel() instanceof TableModelWrapper) { lowestWrapper = (TableModelWrapper) lowestWrapper.getWrappedModel(); } lowestWrapper.setWrappedModel(model); } } @Override public void createDefaultColumnsFromModel() { super.createDefaultColumnsFromModel(); TableUtils.fitColumnWidths(this, 15); } /** * This will get the {@link TableModelSortDecorator} attached to this * table if it exists. If this table does not have a sort decorator * null will be returned. * @return */ public TableModelSortDecorator getTableModelSortDecorator() { return sortDecorator; } /** * Returns the action that will export the table to HTML. This is * the same action that appears when right clicking on the table. */ public Action getExportHTMLAction() { return exportHTMLAction; } /** * Returns the action that will export the table to CSV. This is * the same action that appears when right clicking on the table. */ public Action getExportCSVAction() { return exportCSVAction; } /** * Sets a formatter for the given column of a table model for exporting to * CSV or HTML. If the column does not exist because the table is too small * the formatter will not be used. */ public void setColumnFormatter(int column, Format formatter) { columnFormatters.put(column, formatter); } }