Main Page | Packages | Class Hierarchy | Alphabetical List | Class List | File List | Class Members | Related Pages

InfoViewer.java

00001 /**
00002  * C-JDBC: Clustered JDBC.
00003  * Copyright (C) 2002-2004 French National Institute For Research In Computer
00004  * Science And Control (INRIA).
00005  * Contact: c-jdbc@objectweb.org
00006  * 
00007  * This library is free software; you can redistribute it and/or modify it
00008  * under the terms of the GNU Lesser General Public License as published by the
00009  * Free Software Foundation; either version 2.1 of the License, or any later
00010  * version.
00011  * 
00012  * This library is distributed in the hope that it will be useful, but WITHOUT
00013  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00014  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
00015  * for more details.
00016  * 
00017  * You should have received a copy of the GNU Lesser General Public License
00018  * along with this library; if not, write to the Free Software Foundation,
00019  * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
00020  *
00021  * Initial developer(s): Emmanuel Cecchet.
00022  * Contributor(s): Mathieu Peltier.
00023  */
00024 
00025 package org.objectweb.cjdbc.console.views;
00026 
00027 import java.awt.Dimension;
00028 import java.awt.GridLayout;
00029 import java.awt.event.ActionEvent;
00030 import java.io.File;
00031 import java.io.FileOutputStream;
00032 import java.io.PrintStream;
00033 
00034 import javax.swing.AbstractAction;
00035 import javax.swing.JFileChooser;
00036 import javax.swing.JFrame;
00037 import javax.swing.JMenu;
00038 import javax.swing.JMenuBar;
00039 import javax.swing.JMenuItem;
00040 import javax.swing.JOptionPane;
00041 import javax.swing.JPanel;
00042 import javax.swing.JScrollPane;
00043 import javax.swing.JTable;
00044 import javax.swing.KeyStroke;
00045 import javax.swing.WindowConstants;
00046 import javax.swing.table.AbstractTableModel;
00047 
00048 import org.objectweb.cjdbc.common.i18n.Translate;
00049 
00050 /**
00051  * Graphical SQL statistics viewer. Quick and dirty implementation.
00052  * 
00053  * @author <a href="mailto:Mathieu.Peltier@inrialpes.fr">Mathieu Peltier </a>
00054  * @author <a href="mailto:Emmanuel.Cecchet@inria.fr">Emmanuel Cecchet </a>
00055  * @version 1.0
00056  */
00057 public abstract class InfoViewer
00058 {
00059 
00060   private InfoTableSorter sorter;
00061   private JPanel          panel;
00062   private JFrame          frame;
00063   private InfoTableModel  model;
00064 
00065   // Info Options
00066   private String[]        columnNames;
00067   protected String        frameTitle;
00068   protected String        infoViewerMenuBarString;
00069   protected String        actionToolTipText;
00070   protected String        actionErrorMessage;
00071   protected String        actionSuccessMessage;
00072   protected String        tableHeaderToolTipText;
00073 
00074   private Object[][]      data;
00075 
00076   /**
00077    * Create a InfoViewer
00078    * 
00079    * @param data Stats to display in the table
00080    */
00081   public InfoViewer(Object[][] data)
00082   {
00083     if (data != null)
00084     {
00085       this.data = getDataTypes(data);
00086       columnNames = getColumnNames();
00087       setLabels();
00088     }
00089   }
00090 
00091   /**
00092    * Subclasses should overide this method to get coherent sorting
00093    * 
00094    * @param stats to display
00095    * @return same sized objects array but with proper types default is strings
00096    *         only
00097    */
00098   protected abstract Object[][] getDataTypes(Object[][] stats);
00099 
00100   /**
00101    * Get column names
00102    * 
00103    * @return a array of strings
00104    */
00105   public abstract String[] getColumnNames();
00106 
00107   /**
00108    * Return the list of traceable data for this viewer
00109    * 
00110    * @return an array of names
00111    */
00112   public int[] getTraceableColumns()
00113   {
00114     return new int[0];
00115   }
00116 
00117   /**
00118    * Set the labels for the frame
00119    */
00120   public abstract void setLabels();
00121 
00122   /**
00123    * Update the data in the InfoTableModel and refresh the frame
00124    * 
00125    * @param data fresh and new
00126    */
00127   public void updateData(Object[][] data)
00128   {
00129     this.data = getDataTypes(data);
00130     if (frame != null)
00131     {
00132       frame.repaint();
00133       frame.setVisible(true);
00134       model.setData(data);
00135     }
00136     else
00137     {
00138       createAndShowGUI();
00139     }
00140   }
00141 
00142   /**
00143    * For thread safety, this method should be invoked from the event-dispatching
00144    * thread.
00145    */
00146   private void createAndShowGUI()
00147   {
00148     panel = new JPanel(new GridLayout(1, 0));
00149     model = new InfoTableModel(data);
00150 
00151     sorter = new InfoTableSorter(model);
00152     JTable table = new JTable(sorter); //NEW
00153     sorter.addMouseListenerToHeaderInTable(table); //ADDED
00154     // THIS
00155     table.setPreferredScrollableViewportSize(new Dimension(640, 200));
00156     table.getColumnModel().getColumn(0).setPreferredWidth(340);
00157     for (int i = 1; i < columnNames.length; i++)
00158       table.getColumnModel().getColumn(i).setPreferredWidth(50);
00159 
00160     //Set up tool tips for column headers.
00161     table.getTableHeader().setToolTipText(tableHeaderToolTipText);
00162 
00163     //Create the scroll pane and add the table to it.
00164     JScrollPane scrollPane = new JScrollPane(table);
00165 
00166     //Add the scroll pane to this panel.
00167     panel.add(scrollPane);
00168 
00169     //Create and set up the window.
00170     frame = new JFrame(frameTitle);
00171     frame.setJMenuBar(new InfoViewerMenuBar());
00172     frame.setDefaultCloseOperation(WindowConstants.HIDE_ON_CLOSE);
00173     panel.setOpaque(true); // content panes must be opaque
00174     frame.setContentPane(panel);
00175 
00176     //Display the window.
00177     frame.pack();
00178     frame.setVisible(true);
00179   }
00180 
00181   /**
00182    * Display text. This allows to show text without loading graphic contents
00183    * 
00184    * @param data to display
00185    * @return a formatted <code>String</code>
00186    */
00187   public String displayText(Object[][] data)
00188   {
00189     this.data = getDataTypes(data);
00190     columnNames = getColumnNames();
00191     setLabels();
00192     return displayText(getDataTypes(data));
00193   }
00194 
00195   /**
00196    * Format data for text consoles
00197    * 
00198    * @param data to display
00199    * @return a formatted string with tabs and end of line
00200    */
00201   public String displayText(String[][] data)
00202   {
00203     if (data == null)
00204     {
00205       return "";
00206     }
00207 
00208     /* Lasse's version starts here */
00209 
00210     // constants used for formatting the output
00211     final String columnPadding = "    ";
00212     final String nameValueSeparator = ":  ";
00213 
00214     // holds the column names
00215     String[] columns = getColumnNames();
00216 
00217     // solve the maximum length for column names
00218     // TODO: refactor this into its own method
00219     int maxNameLength = 0;
00220     for (int i = 0; i < columns.length; i++)
00221     {
00222       maxNameLength = Math.max(maxNameLength, columns[i].length());
00223     }
00224 
00225     // solve the maximum length for column values
00226     // TODO: refactor this into its own method
00227     int maxValueLength = 0;
00228     for (int i = 0; i < data.length; i++)
00229     {
00230       for (int j = 0; j < data[i].length; j++)
00231       {
00232         maxValueLength = Math.max(maxValueLength, data[i][j].length());
00233       }
00234     }
00235 
00236     // construct a separator line based on maximum column and value lengths
00237     // TODO: extract numbers into constants and this block into a new method
00238     char[] separator = new char[columnPadding.length() + maxNameLength
00239         + nameValueSeparator.length() + maxValueLength + 1]; /*
00240      * the newline
00241      * character
00242      */
00243     for (int i = 0; i < separator.length; i++)
00244     {
00245       separator[i] = '-';
00246     }
00247     separator[separator.length - 1] = '\n';
00248 
00249     // loop through all the data and print padded lines into the StringBuffer
00250     StringBuffer sb = new StringBuffer();
00251     for (int i = 0; i < data.length; i++)
00252     {
00253       sb.append(separator);
00254       for (int j = 0; j < data[i].length; j++)
00255       {
00256         // create the padding needed for this particular column
00257         // TODO: extract this into its own method
00258         char[] namePadding = new char[maxNameLength - columns[j].length()];
00259         for (int x = 0; x < namePadding.length; x++)
00260         {
00261           namePadding[x] = ' ';
00262         }
00263 
00264         sb.append(columnPadding);
00265         sb.append(columns[j]);
00266         sb.append(nameValueSeparator);
00267         sb.append(namePadding);
00268         sb.append(data[i][j]);
00269         sb.append("\n");
00270       }
00271       if (i + 1 == data.length)
00272       {
00273         sb.append(separator);
00274       }
00275     }
00276     return sb.toString();
00277   }
00278 
00279   /**
00280    * Create the GUI and show it.
00281    */
00282   public void display()
00283   {
00284     //Schedule a job for the event-dispatching thread:
00285     //creating and showing this application's GUI.
00286     javax.swing.SwingUtilities.invokeLater(new Runnable()
00287     {
00288       public void run()
00289       {
00290         createAndShowGUI();
00291       }
00292     });
00293   }
00294 
00295   /** <code>SQLStatViewer</code> menu bar. */
00296   protected class InfoViewerMenuBar extends JMenuBar
00297   {
00298 
00299     /** Creates an new <code>SQLStatViewerMenuBar</code> menu bar. */
00300     private InfoViewerMenuBar()
00301     {
00302       JMenu menu = new JMenu(infoViewerMenuBarString);
00303       JMenuItem menuItem = new JMenuItem(new ExportAction());
00304       menuItem.setText("Save As...");
00305       menuItem.setMnemonic('S');
00306       menuItem.setAccelerator(KeyStroke
00307           .getKeyStroke('s', ActionEvent.CTRL_MASK));
00308       menu.add(menuItem);
00309       add(menu);
00310     }
00311   }
00312 
00313   /** <code>InfoViewer</code> export action. */
00314   protected class ExportAction extends AbstractAction
00315   {
00316 
00317     protected static final String SEPARATOR = "\t";
00318     protected File                outputFile;
00319 
00320     /**
00321      * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
00322      */
00323     public void actionPerformed(ActionEvent e)
00324     {
00325       // Open file
00326       JFileChooser chooser = new JFileChooser(outputFile);
00327       chooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
00328       chooser.setApproveButtonText("Export");
00329       chooser.setApproveButtonMnemonic('s');
00330       chooser.setApproveButtonToolTipText(actionToolTipText);
00331       chooser.setDialogTitle("Choose the file name");
00332 
00333       if (chooser.showSaveDialog(frame) == JFileChooser.APPROVE_OPTION)
00334       {
00335         outputFile = chooser.getSelectedFile();
00336         if (outputFile != null)
00337         {
00338           // Export data
00339           try
00340           {
00341             PrintStream out = new PrintStream(new FileOutputStream(outputFile));
00342             int columnNumber, rowNumber;
00343             columnNumber = sorter.getColumnCount();
00344             rowNumber = sorter.getRowCount();
00345             for (int i = 0; i < rowNumber; i++)
00346             {
00347               for (int j = 0; j < columnNumber; j++)
00348               {
00349                 out.print(sorter.getValueAt(i, j));
00350                 out.print(SEPARATOR);
00351               }
00352               out.println();
00353             }
00354             out.close();
00355           }
00356           catch (Exception ex)
00357           {
00358             JOptionPane.showMessageDialog(frame, Translate.get(
00359                 actionErrorMessage, ex), "Unexpected Error",
00360                 JOptionPane.ERROR_MESSAGE);
00361             return;
00362           }
00363           JOptionPane.showMessageDialog(frame, Translate.get(
00364               actionSuccessMessage, outputFile), "Action Performed",
00365               JOptionPane.INFORMATION_MESSAGE);
00366         }
00367       }
00368     }
00369   }
00370 
00371   /**
00372    * 
00373    * This class defines a InfoTableModel
00374    * 
00375    * @version 1.0
00376    */
00377   class InfoTableModel extends AbstractTableModel
00378   {
00379     private Object[][] data;
00380 
00381     /**
00382      * Creates a new <code>InfoTableModel</code> object
00383      * 
00384      * @param stats <code>Object[][]</code> instance with data
00385      */
00386     public InfoTableModel(Object[][] stats)
00387     {
00388       this.data = stats;
00389     }
00390 
00391     /**
00392      * 
00393      * Set the data of this <tt>InfoTableModel</tt>
00394      * 
00395      * @param data <code>Object[][]</code> instance with data
00396      */
00397     public void setData(Object[][] data)
00398     {
00399       this.data = data;
00400     }
00401 
00402     /**
00403      * 
00404      * @see javax.swing.table.TableModel#getColumnCount()
00405      */
00406     public int getColumnCount()
00407     {
00408       return columnNames.length;
00409     }
00410 
00411     /**
00412      * 
00413      * @see javax.swing.table.TableModel#getRowCount()
00414      */
00415     public int getRowCount()
00416     {
00417       return data.length;
00418     }
00419 
00420     /**
00421      * 
00422      * @see javax.swing.table.TableModel#getColumnName(int)
00423      */
00424     public String getColumnName(int col)
00425     {
00426       return columnNames[col];
00427     }
00428 
00429     /**
00430      * 
00431      * @see javax.swing.table.TableModel#getValueAt(int, int)
00432      */
00433     public Object getValueAt(int row, int col)
00434     {
00435       return data[row][col];
00436     }
00437 
00438     /**
00439      * JTable uses this method to determine the default renderer/ editor for
00440      * each cell. If we didn't implement this method, then the last column would
00441      * contain text ("true"/"false"), rather than a check box.
00442      */
00443     public Class getColumnClass(int c)
00444     {
00445       return getValueAt(0, c).getClass();
00446     }
00447 
00448     /**
00449      * Don't need to implement this method unless your table's editable.
00450      */
00451     public boolean isCellEditable(int row, int col)
00452     {
00453       return false;
00454     }
00455   }
00456 
00457   /**
00458    * @return Returns the frameTitle.
00459    */
00460   public String getFrameTitle()
00461   {
00462     return frameTitle;
00463   }
00464 
00465   /**
00466    * @return Returns the data.
00467    */
00468   public Object[][] getData()
00469   {
00470     return data;
00471   }
00472 }

Generated on Mon Apr 11 22:01:32 2005 for C-JDBC by  doxygen 1.3.9.1