Package net.sourceforge.squirrel_sql.client.session.mainpanel.objecttree.tabs.table

Source Code of net.sourceforge.squirrel_sql.client.session.mainpanel.objecttree.tabs.table.ContentsTab

package net.sourceforge.squirrel_sql.client.session.mainpanel.objecttree.tabs.table;
/*
* Copyright (C) 2001-2004 Colin Bell
* colbell@users.sourceforge.net
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import net.sourceforge.squirrel_sql.client.gui.session.SessionPanel;
import net.sourceforge.squirrel_sql.client.preferences.SquirrelPreferences;
import net.sourceforge.squirrel_sql.client.session.DataSetUpdateableTableModelImpl;
import net.sourceforge.squirrel_sql.client.session.ISession;
import net.sourceforge.squirrel_sql.client.session.mainpanel.PleaseWaitDialog;
import net.sourceforge.squirrel_sql.client.session.mainpanel.objecttree.ObjectTreePanel;
import net.sourceforge.squirrel_sql.client.session.properties.SessionProperties;
import net.sourceforge.squirrel_sql.client.session.sqlfilter.OrderByClausePanel;
import net.sourceforge.squirrel_sql.client.session.sqlfilter.SQLFilterClauses;
import net.sourceforge.squirrel_sql.client.session.sqlfilter.WhereClausePanel;
import net.sourceforge.squirrel_sql.fw.datasetviewer.ColumnDisplayDefinition;
import net.sourceforge.squirrel_sql.fw.datasetviewer.DataSetException;
import net.sourceforge.squirrel_sql.fw.datasetviewer.DataSetUpdateableTableModelListener;
import net.sourceforge.squirrel_sql.fw.datasetviewer.IDataModelImplementationDetails;
import net.sourceforge.squirrel_sql.fw.datasetviewer.IDataSet;
import net.sourceforge.squirrel_sql.fw.datasetviewer.IDataSetUpdateableTableModel;
import net.sourceforge.squirrel_sql.fw.datasetviewer.ResultSetDataSet;
import net.sourceforge.squirrel_sql.fw.dialects.DialectFactory;
import net.sourceforge.squirrel_sql.fw.gui.GUIUtils;
import net.sourceforge.squirrel_sql.fw.sql.IDatabaseObjectInfo;
import net.sourceforge.squirrel_sql.fw.sql.ISQLConnection;
import net.sourceforge.squirrel_sql.fw.sql.ISQLDatabaseMetaData;
import net.sourceforge.squirrel_sql.fw.sql.ITableInfo;
import net.sourceforge.squirrel_sql.fw.sql.SQLUtilities;
import net.sourceforge.squirrel_sql.fw.sql.TableColumnInfo;
import net.sourceforge.squirrel_sql.fw.sql.dbobj.BestRowIdentifier;
import net.sourceforge.squirrel_sql.fw.util.StringManager;
import net.sourceforge.squirrel_sql.fw.util.StringManagerFactory;
import net.sourceforge.squirrel_sql.fw.util.log.ILogger;
import net.sourceforge.squirrel_sql.fw.util.log.LoggerController;

/**
* This is the tab showing the contents (data) of the table.
*
* @author  <A HREF="mailto:colbell@users.sourceforge.net">Colin Bell</A>
*/
public class ContentsTab extends BaseTableTab
  implements IDataSetUpdateableTableModel
{
   private DataSetUpdateableTableModelImpl _dataSetUpdateableTableModel = new DataSetUpdateableTableModelImpl();

    /** Internationalized strings for this class. */
    private static final StringManager s_stringMgr =
        StringManagerFactory.getStringManager(ContentsTab.class)

  /**
   * Name of the table that this tab displayed last time it was loaded.
   * This is needed to prevent an on-demand edit operation from turning
   * all data into editable tables.
   * The initial value of "" allows us to dispense with a check for null
   * on the first pass.
   */
  String previousTableName = "";

   private SQLFilterClauses _sqlFilterClauses = new SQLFilterClauses();


  /** Logger for this class. */
  private static final ILogger s_log =
    LoggerController.createLogger(ContentsTab.class);


  private ObjectTreePanel _treePanel = null;
 
   private PleaseWaitDialog _waitDialog = null;

  private SquirrelPreferences _prefs = null;
  
   public ContentsTab(ObjectTreePanel treePanel) {
      _treePanel = treePanel;
     _prefs = _treePanel.getSession().getApplication().getSquirrelPreferences();

   }

  /**
   * Return the title for the tab.
   *
   * @return  The title for the tab.
   */
  public String getTitle()
  {
    return getContentsTabTitle();
  }

  /**
   * Return the title for the tab.
   *
   * @return  The title for the tab.
   */
  public static String getContentsTabTitle()
  {
    // i18n[ContentsTab.title=Content]
    return s_stringMgr.getString("ContentsTab.title");
  }
 
 
  /**
   * Return the hint for the tab.
   *
   * @return  The hint for the tab.
   */
  public String getHint()
  {
    // i18n[ContentsTab.hint=View the contents of the selected table]
    return s_stringMgr.getString("ContentsTab.hint");
  }
 

   public SQLFilterClauses getSQLFilterClauses()
   {
      return _sqlFilterClauses;
   }


   /**
    * Create the <TT>IDataSet</TT> to be displayed in this tab.
    */
   protected IDataSet createDataSet() throws DataSetException
   {
      final ISession session = getSession();
      final ISQLConnection conn = session.getSQLConnection();
      ISQLDatabaseMetaData md = session.getMetaData();

     
      try
      {
         final Statement stmt = conn.createStatement();
         try
         {
            final SessionProperties props = session.getProperties();
            if (props.getContentsLimitRows())
            {
               try
               {
                  stmt.setMaxRows(props.getContentsNbrRowsToShow());
               }
               catch (Exception ex)
               {
                  s_log.error("Error on Statement.setMaxRows()", ex);
               }
            }
            final ITableInfo ti = getTableInfo();

            /**
             * When the SessionProperties are set to read-only (either table or text)
             * but the user has selected "Make Editable" on the Popup menu, we want
             * to limit the edit capability to only that table, and only for as long
             * as the user is looking at that one table.  When the user switches away
             * to another table, that new table should not be editable.
             */
            final String currentTableName = ti.getQualifiedName();
            if (!currentTableName.equals(previousTableName))
            {
               previousTableName = currentTableName;  // needed to prevent an infinite loop
               _dataSetUpdateableTableModel.setEditModeForced(false);

               /**
                * Tell the GUI to rebuild itself.
                * Unfortunately, this has the side effect of calling this same function
                * another time.  The second call does not seem to be a problem,
                * but we need to have reset the previousTableName before makeing
                * this call or we will be in an infinite loop.
                */
               //props.forceTableContentsOutputClassNameChange();
            }

            /**
             * If the table has a pseudo-column that is the best unique
             * identifier for the rows (like Oracle's rowid), then we
             * want to include that field in the query so that it will
             * be available if the user wants to edit the data later.
             */
            String pseudoColumn = "";

            try
            {
               BestRowIdentifier[] rowIDs = md.getBestRowIdentifier(ti);
               for (int i = 0; i < rowIDs.length; ++i)
               {
                  short pseudo = rowIDs[i].getPseudoColumn();
                  if (pseudo == DatabaseMetaData.bestRowPseudo)
                  {
                     pseudoColumn = " ," + rowIDs[i].getColumnName();
                     break;
                  }
               }
            }

            // Some DBMS's (EG Think SQL) throw an exception on a call to
            // getBestRowIdentifier.
            catch (Throwable th)
            {
              if (s_log.isDebugEnabled()) {
                 s_log.debug("getBestRowIdentifier not supported for table "+ currentTableName, th);
              }
            }

            // TODO: - Col - Add method to Databasemetadata that returns array
            // of objects for getBestRowIdentifier. For PostgreSQL put this kludge in
            // the new function. THis way all the kludges are kept in one place.
            //
            // KLUDGE!!!!!!
            //
            // For some DBs (e.g. PostgreSQL) there is actually a pseudo-column
            // providing the rowId, but the getBestRowIdentifier function is not
            // implemented.  This kludge hardcodes the knowledge that specific
            // DBs use a specific pseudo-column.  Additionally, as of pg 8.1,
            // you must create the table using "WITH OID" appended to the create
            // statement.  Otherwise, OID column is not available by default.
            //
            if (pseudoColumn.length() == 0)
            {
                if (DialectFactory.isPostgreSQL(md)) {
                    pseudoColumn = ", oid";
                }
                if (DialectFactory.isOracle(md)) {
                    pseudoColumn = ", ROWID";
                }
            }

            ResultSet rs = null;
            try
            {
               // Note. Some DBMSs such as Oracle do not allow:
               // "select *, rowid from table"
               // You cannot have any column name in the columns clause
               // if you have * in there. Aliasing the table name seems to
               // be the best way to get around the problem.
               final StringBuffer buf = new StringBuffer();
               buf.append("select tbl.*")
                  .append(pseudoColumn)
                  .append(" from ")
                  .append(ti.getQualifiedName())
                  .append(" tbl");

               String clause = _sqlFilterClauses.get(WhereClausePanel.getClauseIdentifier(), ti.getQualifiedName());
               if ((clause != null) && (clause.length() > 0))
               {
                 buf.append(" where ").append(clause);
               }
               clause = _sqlFilterClauses.get(OrderByClausePanel.getClauseIdentifier(), ti.getQualifiedName());
               if ((clause != null) && (clause.length() > 0))
               {
                 buf.append(" order by ").append(clause);
               }

               if (s_log.isDebugEnabled()) {
                   s_log.debug("createDataSet running SQL: "+buf.toString());
               }
                          
               showWaitDialog(stmt);              

               rs = stmt.executeQuery(buf.toString());

            }
            catch (SQLException ex)
            {
                if (s_log.isDebugEnabled()) {
                        s_log.debug(
                            "createDataSet: exception from pseudocolumn query - "
                                    + ex, ex);
                    }
                // We assume here that if the pseudoColumn was used in the query,
                // then it was likely to have caused the SQLException.  If not,
                // (length == 0), then retrying the query won't help - just throw
                // the exception.
               if (pseudoColumn.length() == 0)
               {
                  throw ex;
               }
               // pseudocolumn query failed, so reset it.  Otherwise, we'll
               // mistake the last column for a pseudocolumn and make it
               // uneditable
               pseudoColumn = "";

               // Some tables have pseudo column primary keys and others
               // do not.  JDBC on some DBMSs does not handle pseudo
               // columns 'correctly'.  Also, getTables returns 'views' as
               // well as tables, so the thing we are looking at might not
               // be a table. (JDBC does not give a simple way to
               // determine what we are looking at since the type of
               // object is described in a DBMS-specific encoding.)  For
               // these reasons, rather than testing for all these
               // conditions, we just try using the pseudo column info to
               // get the table data, and if that fails, we try to get the
               // table data without using the pseudo column.
               // TODO: Should we change the mode from editable to
               // non-editable?
               final StringBuffer buf = new StringBuffer();
               buf.append("select *")
                  .append(" from ")
                  .append(ti.getQualifiedName())
                  .append(" tbl");

               String clause = _sqlFilterClauses.get(WhereClausePanel.getClauseIdentifier(), ti.getQualifiedName());
               if ((clause != null) && (clause.length() > 0))
               {
                 buf.append(" where ").append(clause);
               }
               clause = _sqlFilterClauses.get(OrderByClausePanel.getClauseIdentifier(), ti.getQualifiedName());
               if ((clause != null) && (clause.length() > 0))
               {
                 buf.append(" order by ").append(clause);
               }

               rs = stmt.executeQuery(buf.toString());
            }

            final ResultSetDataSet rsds = new ResultSetDataSet();

            // to allow the fw to save and reload user options related to
            // specific columns, we construct a unique name for the table
            // so the column can be associcated with only that table.
            // Some drivers do not provide the catalog or schema info, so
            // those parts of the name will end up as null.  That's ok since
            // this string is never viewed by the user and is just used to
            // distinguish this table from other tables in the DB.
            // We also include the URL used to connect to the DB so that
            // the same table/DB on different machines is treated differently.
            rsds.setContentsTabResultSet(rs,
                                         _dataSetUpdateableTableModel.getFullTableName(),
                                         DialectFactory.getDialectType(md));
            if (rs != null) {
                try { rs.close(); } catch (SQLException e) {}
            }
            // KLUDGE:
            // We want some info about the columns to be available for validating the
            // user input during cell editing operations.  Ideally we would get that
            // info inside the ResultSetDataSet class during the creation of the
            // columnDefinition objects by using various functions in ResultSetMetaData
            // such as isNullable(idx).  Unfortunately, in at least some DBMSs (e.g.
            // Postgres, HSDB) the results of those calls are not the same (and are less accurate
            // than) the SQLMetaData.getColumns() call used in ColumnsTab to get the column info.
            // Even more unfortunate is the fact that the set of attributes reported on by the two
            // calls is not the same, with the ResultSetMetadata listing things not provided by
            // getColumns.  Most of the data provided by the ResultSetMetaData calls is correct.
            // However, the nullable/not-nullable property is not set correctly in at least two
            // DBMSs, while it is correct for those DBMSs in the getColumns() info.  Therefore,
            // we collect the collumn nullability information from getColumns() and pass that
            // info to the ResultSet to override what it got from the ResultSetMetaData.
            TableColumnInfo[] columnInfos = md.getColumnInfo(getTableInfo());
            final ColumnDisplayDefinition[] colDefs =
                rsds.getDataSetDefinition().getColumnDefinitions();

            // get the nullability information and pass it into the ResultSet
            // Unfortunately, not all DBMSs provide the column number in object 17 as stated in the
            // SQL documentation, so we have to guess that the result set is in column order
            for (int i = 0; i < columnInfos.length; i++) {
                boolean isNullable = true;
                TableColumnInfo info = columnInfos[i];
                if (info.isNullAllowed() == DatabaseMetaData.columnNoNulls) {
                    isNullable = false;
                }
                if (i < colDefs.length) {
                    colDefs[i].setIsNullable(isNullable);
                }
            }

            //?? remember which column is the rowID (if any) so we can
            //?? prevent editing on it
            if (pseudoColumn.length() > 0)
            {
               _dataSetUpdateableTableModel.setRowIDCol(rsds.getColumnCount() - 1);
            }

            return rsds;
         }
         finally
         {
             SQLUtilities.closeStatement(stmt);
         }

      }
      catch (SQLException ex)
      {
         throw new DataSetException(ex);
      } finally {
          disposeWaitDialog();
      }
   }

   /**
    * Returns true if the ObjectTree tab is selected.
    *
    * @return Returns true if the ObjectTree tab is selected.
    *                 false is returned otherwise.
    */
   private boolean objectTreeTabIsSelected() {
      boolean result = false;
      ISession session = _treePanel.getSession();
      if (session != null) {
         SessionPanel sessionPanel = session.getSessionSheet();
         if (sessionPanel != null) {
            result = sessionPanel.isObjectTreeTabSelected();
         }
      }
      return result;
   }
  
   /**
    * Initialize the dialog to ask the user to wait, because the query can
    * take a while, but only if the ObjectTreeTab is selected.
    *
    * @param stmt the Statement to cancel.
    */
   private void showWaitDialog(final Statement stmt) {
     
    
      if (!_prefs.getShowPleaseWaitDialog()) return;
     
      // Only do this if the object tree
      // (and hence this contents tab) is visible.
      if (objectTreeTabIsSelected()) {
        
         // Save off selections so that selection/focus can be restored
         // later.
         _treePanel.saveSelectedPaths();
        
         GUIUtils.processOnSwingEventThread(new Runnable() {
            public void run() {
               _waitDialog = new PleaseWaitDialog(stmt, _app);
               _waitDialog.showDialog(_app);                                         
               // Restore the paths
               _treePanel.restoreSavedSelectedPaths();
            }
         });        
      }
   }
  
   /**
    * Hide the dialog if one is shown
    *
    * @param _waitDialog the PleaseWaitDialog to close - can be null.
    */
   private void disposeWaitDialog() {
     if (!_prefs.getShowPleaseWaitDialog()) return;
      if (_waitDialog != null) {
          GUIUtils.processOnSwingEventThread(new Runnable() {
              public void run() {
                  _waitDialog.dispose();
              }
          });
      }      
   }
  
   public void setDatabaseObjectInfo(IDatabaseObjectInfo value)
   {
      super.setDatabaseObjectInfo(value);
      _dataSetUpdateableTableModel.setTableInfo(getTableInfo());
   }

   public void setSession(ISession session) throws IllegalArgumentException
   {
      super.setSession(session);
      _dataSetUpdateableTableModel.setSession(session);
   }


  /**
   * return the name of the table that is unambiguous across DB accesses,
   * including the same DB on different machines.
   * This function is static because it is used elsewhere to generate the same
   * name as is used within instances of this class.
   *
   * @return the name of the table that is unique for this DB access
   */
  public static String getUnambiguousTableName(ISession session, String name)
   {
    return DataSetUpdateableTableModelImpl.getUnambiguousTableName(session, name);
  }

   ////////////////////////////////////////////////////////
   // Implementataion of IDataSetUpdateableTableModel:
   // Delegation to _dataSetUpdateableTableModel
   public String getWarningOnCurrentData(Object[] values, ColumnDisplayDefinition[] colDefs, int col, Object oldValue)
   {
      return _dataSetUpdateableTableModel.getWarningOnCurrentData(values, colDefs, col, oldValue);
   }

   public String getWarningOnProjectedUpdate(Object[] values, ColumnDisplayDefinition[] colDefs, int col, Object newValue)
   {
      return _dataSetUpdateableTableModel.getWarningOnProjectedUpdate(values, colDefs, col, newValue);
   }

   public Object reReadDatum(Object[] values, ColumnDisplayDefinition[] colDefs, int col, StringBuffer message)
   {
      return _dataSetUpdateableTableModel.reReadDatum(values, colDefs, col, message);
   }

   public String updateTableComponent(Object[] values, ColumnDisplayDefinition[] colDefs, int col, Object oldValue, Object newValue)
   {
      return _dataSetUpdateableTableModel.updateTableComponent(values, colDefs, col, oldValue, newValue);
   }

   public int getRowidCol()
   {
      return _dataSetUpdateableTableModel.getRowidCol();
   }

   public String deleteRows(Object[][] rowData, ColumnDisplayDefinition[] colDefs)
   {
      return _dataSetUpdateableTableModel.deleteRows(rowData, colDefs);
   }

   public String[] getDefaultValues(ColumnDisplayDefinition[] colDefs)
   {
      return _dataSetUpdateableTableModel.getDefaultValues(colDefs);
   }

   public String insertRow(Object[] values, ColumnDisplayDefinition[] colDefs)
   {
      return _dataSetUpdateableTableModel.insertRow(values, colDefs);
   }

   public void addListener(DataSetUpdateableTableModelListener l)
   {
      _dataSetUpdateableTableModel.addListener(l);
   }

   public void removeListener(DataSetUpdateableTableModelListener l)
   {
      _dataSetUpdateableTableModel.removeListener(l);
   }

   public void forceEditMode(boolean mode)
   {
      _dataSetUpdateableTableModel.forceEditMode(mode);
   }

   public boolean editModeIsForced()
   {
      return _dataSetUpdateableTableModel.editModeIsForced();
   }

   public IDataModelImplementationDetails getDataModelImplementationDetails()
   {
      return new IDataModelImplementationDetails()
      {
         public String getStatementSeparator()
         {
            return getSession().getQueryTokenizer().getSQLStatementSeparator();
         }
      };
   }

   protected String getDestinationClassName()
   {
      return _dataSetUpdateableTableModel.getDestinationClassName();
   }
   //
   //////////////////////////////////////////////////////////////////////////////////
}
TOP

Related Classes of net.sourceforge.squirrel_sql.client.session.mainpanel.objecttree.tabs.table.ContentsTab

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.