All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.sourceforge.squirrel_sql.client.session.mainpanel.SQLResultExecuterPanel Maven / Gradle / Ivy

Go to download

This is the jar that contains the main application classes which are very specific to SQuirreLSQL.

There is a newer version: 3.5.0
Show newest version
package net.sourceforge.squirrel_sql.client.session.mainpanel;
/*
 * Copyright (C) 2003-2004 Jason Height
 * [email protected]
 *
 * 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.awt.BorderLayout;
import java.awt.Component;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.SQLWarning;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.swing.Action;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JLayeredPane;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JTabbedPane;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
import javax.swing.event.EventListenerList;

import net.sourceforge.squirrel_sql.client.action.ActionCollection;
import net.sourceforge.squirrel_sql.client.gui.builders.UIFactory;
import net.sourceforge.squirrel_sql.client.gui.desktopcontainer.DialogWidget;
import net.sourceforge.squirrel_sql.client.preferences.SquirrelPreferences;
import net.sourceforge.squirrel_sql.client.session.ISQLEntryPanel;
import net.sourceforge.squirrel_sql.client.session.ISQLExecuterHandler;
import net.sourceforge.squirrel_sql.client.session.ISession;
import net.sourceforge.squirrel_sql.client.session.SQLExecuterTask;
import net.sourceforge.squirrel_sql.client.session.SQLExecutionInfo;
import net.sourceforge.squirrel_sql.client.session.action.CloseAllSQLResultTabsAction;
import net.sourceforge.squirrel_sql.client.session.action.CloseAllSQLResultTabsButCurrentAction;
import net.sourceforge.squirrel_sql.client.session.action.CloseCurrentSQLResultTabAction;
import net.sourceforge.squirrel_sql.client.session.action.ToggleCurrentSQLResultTabStickyAction;
import net.sourceforge.squirrel_sql.client.session.event.IResultTabListener;
import net.sourceforge.squirrel_sql.client.session.event.ISQLExecutionListener;
import net.sourceforge.squirrel_sql.client.session.event.ResultTabEvent;
import net.sourceforge.squirrel_sql.client.session.properties.SessionProperties;
import net.sourceforge.squirrel_sql.fw.datasetviewer.*;
import net.sourceforge.squirrel_sql.fw.datasetviewer.cellcomponent.DataTypeClob;
import net.sourceforge.squirrel_sql.fw.dialects.DialectFactory;
import net.sourceforge.squirrel_sql.fw.dialects.DialectType;
import net.sourceforge.squirrel_sql.fw.id.IIdentifier;
import net.sourceforge.squirrel_sql.fw.id.IntegerIdentifierFactory;
import net.sourceforge.squirrel_sql.fw.sql.ISQLConnection;
import net.sourceforge.squirrel_sql.fw.sql.SQLExecutionException;
import net.sourceforge.squirrel_sql.fw.util.Resources;
import net.sourceforge.squirrel_sql.fw.util.StringManager;
import net.sourceforge.squirrel_sql.fw.util.StringManagerFactory;
import net.sourceforge.squirrel_sql.fw.util.StringUtilities;
import net.sourceforge.squirrel_sql.fw.util.log.ILogger;
import net.sourceforge.squirrel_sql.fw.util.log.LoggerController;
/**
 * This is the panel where SQL scripts are executed and results presented.
 *
 */
public class SQLResultExecuterPanel extends JPanel
									implements ISQLResultExecuter
{
    static final long serialVersionUID = 6961615570741567740L;
    
	/** Logger for this class. */
	private static final ILogger s_log = 
        LoggerController.createLogger(SQLResultExecuterPanel.class);

    /** Internationalized strings for this class. */
    private static final StringManager s_stringMgr =
        StringManagerFactory.getStringManager(SQLResultExecuterPanel.class);
    
    static interface i18n {
        // i18n[SQLResultExecuterPanel.exec=Executing SQL]
        String EXEC_SQL_MSG = 
            s_stringMgr.getString("SQLResultExecuterPanel.exec");
        // i18n[SQLResultExecuterPanel.cancelMsg=Press Cancel to Stop]
        String CANCEL_SQL_MSG = 
            s_stringMgr.getString("SQLResultExecuterPanel.cancelMsg");
        
    }
    
	private ISession _session;

	private MyPropertiesListener _propsListener;

	/** Each tab is a ResultTab showing the results of a query. */
	private JTabbedPane _tabbedExecutionsPanel;

	/**
	 * Collection of ResultTabInfo objects for all
	 * ResultTab objects that have been created. Keyed
	 * by ResultTab.getIdentifier().
	 */
	private Map _allTabs = 
        new HashMap();


	/**
	 * Pool of ResultTabInfo objects currently being used.
	 */
	private ArrayList _usedTabs = new ArrayList();

	/** Listeners */
	private EventListenerList _listeners = new EventListenerList();

	/** Factory for generating unique IDs for new ResultTab objects. */
	private IntegerIdentifierFactory _idFactory = new IntegerIdentifierFactory();
   private IResultTab _stickyTab;
   
   private SquirrelPreferences _prefs = null;

	/** Reference to the executor so that it can be called from the CancelPanel*/
	private SQLExecuterTask _executer;

    private static enum SQLType { INSERT, SELECT, UPDATE, DELETE, UNKNOWN };
   /**
	 * Ctor.
	 *
	 * @param	session	 Current session.
	 *
	 * @throws	IllegalArgumentException
	 *			Thrown if a null ISession passed.
	 */
	public SQLResultExecuterPanel(ISession session)
	{
		super();
		setSession(session);
		createGUI();
		propertiesHaveChanged(null);
	}

	public String getTitle()
	{
        // i18n[SQLResultExecuterPanel.title=Results]
		return s_stringMgr.getString("SQLResultExecuterPanel.title");
	}

	public JComponent getComponent()
	{
		return this;
	}

	/**
	 * Set the current session.
	 *
	 * @param	session	 Current session.
	 *
	 * @throws	IllegalArgumentException
	 *			Thrown if a null ISession passed.
	 */
	public synchronized void setSession(ISession session)
	{
		if (session == null)
		{
			throw new IllegalArgumentException("Null ISession passed");
		}
		sessionClosing();
		_session = session;
        _prefs = _session.getApplication().getSquirrelPreferences();
		_propsListener = new MyPropertiesListener();
		_session.getProperties().addPropertyChangeListener(_propsListener);
	}

	/** Current session. */
	public ISession getSession()
	{
		return _session;
	}

	/**
	 * Add a listener listening for SQL Execution.
	 *
	 * @param	lis	 Listener
	 *
	 * @throws	IllegalArgumentException
	 *			If a null ISQLExecutionListener passed.
	 */
	public synchronized void addSQLExecutionListener(ISQLExecutionListener lis)
	{
		if (lis == null)
		{
			throw new IllegalArgumentException("ISQLExecutionListener == null");
		}
		_listeners.add(ISQLExecutionListener.class, lis);
	}

	/**
	 * Remove an SQL execution listener.
	 *
	 * @param	lis	Listener
	 *
	 * @throws	IllegalArgumentException
	 *			If a null ISQLExecutionListener passed.
	 */
	public synchronized void removeSQLExecutionListener(ISQLExecutionListener lis)
	{
		if (lis == null)
		{
			throw new IllegalArgumentException("ISQLExecutionListener == null");
		}
		_listeners.remove(ISQLExecutionListener.class, lis);
	}

	/**
	 * Add a listener listening for events on result tabs.
	 *
	 * @param	lis	Listener
	 *
	 * @throws	IllegalArgumentException
	 *			If a null IResultTabListener passed.
	 */
	public synchronized void addResultTabListener(IResultTabListener lis)
	{
		if (lis == null)
		{
			throw new IllegalArgumentException("IResultTabListener == null");
		}
		_listeners.add(IResultTabListener.class, lis);
	}

	/**
	 * Remove a listener listening for events on result tabs.
	 *
	 * @param	lis	Listener
	 *
	 * @throws	IllegalArgumentException
	 *			If a null IResultTabListener passed.
	 */
	public synchronized void removeResultTabListener(IResultTabListener lis)
	{
		if (lis == null)
		{
			throw new IllegalArgumentException("IResultTabListener == null");
		}
		_listeners.remove(IResultTabListener.class, lis);
	}

	public void execute(ISQLEntryPanel sqlPanel)
	{
		String sql = sqlPanel.getSQLToBeExecuted();
		if (sql != null && sql.length() > 0)
		{
			executeSQL(sql);
		}
		else
		{
            // i18n[SQLResultExecuterPanel.nosqlselected=No SQL selected for execution.]
            String msg = 
                s_stringMgr.getString("SQLResultExecuterPanel.nosqlselected");
			_session.showErrorMessage(msg);
		}
	}

	public void executeSQL(String sql)
	{
		if (sql != null && sql.trim().length() > 0)
		{
            String origSQL = sql; 
	        sql = fireSQLToBeExecutedEvent(sql);
            
            // This can happen if an impl of ISQLExecutionListener returns null 
            // from the statementExecuting API method, to indicate that the SQL 
            // shouldn't be executed.            
            if (sql == null) {
                s_log.info(
                    "executeSQL: An ISQLExecutionListener veto'd execution of "+
                    "the following SQL: "+origSQL);
                return;
            }
            
            ISQLExecutionListener[] executionListeners =
                _listeners.getListeners(ISQLExecutionListener.class);
            SQLExecutionHandler handler = new SQLExecutionHandler(null);
            _executer = new SQLExecuterTask(_session, sql, handler, executionListeners);
	        
            if (_prefs.getLargeScriptStmtCount() > 0 
                    && _executer.getQueryCount() > _prefs.getLargeScriptStmtCount()) {
                _executer.setExecutionListeners(new ISQLExecutionListener[0]);
                handler.setLargeScript(true);
            }
            
            _session.getApplication().getThreadPool().addTask(_executer);
		}
	}

   private void onRerunSQL(String sql, IResultTab resultTab)
   {
      _executer = new SQLExecuterTask(_session, sql, new SQLExecutionHandler(resultTab), new ISQLExecutionListener[0]);
      _session.getApplication().getThreadPool().addTask(_executer);
   }


   /**
	 * Close all the Results frames.
	 */
	public synchronized void closeAllSQLResultFrames()
	{
		List tabs = new ArrayList(_usedTabs);
		for (Iterator it = tabs.iterator(); it.hasNext();)
		{
			ResultTabInfo ti = it.next();
			if (ti._resultFrame != null)
			{
				ti._resultFrame.dispose();
				ti._resultFrame = null;
			}
		}
	}

	/**
	 * Close all the Results tabs.
	 */
	public synchronized void closeAllSQLResultTabs()
	{
		List tabs = new ArrayList(_usedTabs);
		for (Iterator it = tabs.iterator(); it.hasNext();)
		{
			ResultTabInfo ti = it.next();
			if (ti._resultFrame == null)
			{
				closeTab(ti._tab);
			}
		}
	}

   public synchronized void closeAllButCurrentResultTabs()
   {
      Component selectedTab = _tabbedExecutionsPanel.getSelectedComponent();

      List tabs = new ArrayList(_usedTabs);
      for (Iterator it = tabs.iterator(); it.hasNext();)
      {
         ResultTabInfo ti = it.next();
         if(false == ti._tab.equals(selectedTab))
         {
            if (ti._resultFrame == null)
            {
               closeTab(ti._tab);
            }
         }
      }
   }

   public synchronized void toggleCurrentSQLResultTabSticky()
   {
      if (null != _stickyTab)
      {
         if(_stickyTab.equals(_tabbedExecutionsPanel.getSelectedComponent()))
         {
            // Sticky is turned off. Just remove sticky and return.
            _stickyTab = null;
            _tabbedExecutionsPanel.setIconAt(_tabbedExecutionsPanel.getSelectedIndex(), null);
            return;

         }
         else
         {
            // remove old sticky tab
            int indexOfStickyTab = getIndexOfTab(_stickyTab);
            if(-1 != indexOfStickyTab)
            {
               _tabbedExecutionsPanel.setIconAt(indexOfStickyTab, null);
            }
            _stickyTab = null;
         }
      }

      if(false == _tabbedExecutionsPanel.getSelectedComponent() instanceof IResultTab)
      {
          //i18n[SQLResultExecuterPanel.nonStickyPanel=Cannot make a cancel panel sticky]
          String msg = 
              s_stringMgr.getString("SQLResultExecuterPanel.nonStickyPanel");
         JOptionPane.showMessageDialog(_session.getApplication().getMainFrame(), 
                                       msg);
         return;
      }

      _stickyTab = (IResultTab) _tabbedExecutionsPanel.getSelectedComponent();
      int selectedIndex = _tabbedExecutionsPanel.getSelectedIndex();

      ImageIcon icon = getStickyIcon();

      _tabbedExecutionsPanel.setIconAt(selectedIndex, icon);
   }

   private ImageIcon getStickyIcon()
   {
      ActionCollection actionCollection = _session.getApplication().getActionCollection();

      ImageIcon icon =
         (ImageIcon) actionCollection.get(ToggleCurrentSQLResultTabStickyAction.class).getValue(Action.SMALL_ICON);
      return icon;
   }

   private int getIndexOfTab(IResultTab resultTab)
   {
      if(null == resultTab)
      {
         return -1;
      }

      for (int i = 0; i < _tabbedExecutionsPanel.getTabCount(); i++)
      {
         if (resultTab.equals(_tabbedExecutionsPanel.getComponentAt(i)))
         {
            return i;
         }
      }
      return -1;
   }



   public synchronized void closeCurrentResultTab()
   {
      Component selectedTab = _tabbedExecutionsPanel.getSelectedComponent();

      List tabs = new ArrayList(_usedTabs);
      for (Iterator it = tabs.iterator(); it.hasNext();)
      {
         ResultTabInfo ti = it.next();
         if(ti._tab.equals(selectedTab))
         {
            if (ti._resultFrame == null)
            {
               closeTab(ti._tab);
            }
         }
      }
   }

   /**
	 * Sesssion is ending.
	 * Remove all listeners that this component has setup. Close all
	 * torn off result tab windows.
	 */
	void sessionClosing()
	{
		if (_propsListener != null)
		{
			_session.getProperties().removePropertyChangeListener(
					_propsListener);
			_propsListener = null;
		}

		closeAllSQLResultFrames();
	}

	/**
	 * Close the passed ResultTab. This is done by clearing
	 * all data from the tab, removing it from the tabbed panel
	 * and adding it to the list of available tabs.
	 *
	 * @throws	IllegalArgumentException
	 *			Thrown if a null ResultTab passed.
	 */
	public void closeTab(ResultTab tab)
	{
		if (tab == null)
		{
			throw new IllegalArgumentException("Null ResultTab passed");
		}
		s_log
				.debug("SQLPanel.closeTab(" + tab.getIdentifier().toString()
						+ ")");
		tab.clear();
		_tabbedExecutionsPanel.remove(tab);
		ResultTabInfo tabInfo = _allTabs.get(tab.getIdentifier());
		_usedTabs.remove(tabInfo);
		tabInfo._resultFrame = null;
		fireTabRemovedEvent(tab);
	}

	/**
	 * Display the next tab in the SQL results.
	 */
	public void gotoNextResultsTab()
	{
		final int tabCount = _tabbedExecutionsPanel.getTabCount();
		if (tabCount > 1)
		{
			int nextTabIdx = _tabbedExecutionsPanel.getSelectedIndex() + 1;
			if (nextTabIdx >= tabCount)
			{
				nextTabIdx = 0;
			}
			_tabbedExecutionsPanel.setSelectedIndex(nextTabIdx);
		}
	}

	/**
	 * Display the previous tab in the SQL results.
	 */
	public void gotoPreviousResultsTab()
	{
		final int tabCount = _tabbedExecutionsPanel.getTabCount();
		if (tabCount > 1)
		{
			int prevTabIdx = _tabbedExecutionsPanel.getSelectedIndex() - 1;
			if (prevTabIdx < 0)
			{
				prevTabIdx = tabCount - 1;
			}
			_tabbedExecutionsPanel.setSelectedIndex(prevTabIdx);
		}
	}

	protected void fireTabAddedEvent(IResultTab tab)
	{
		// Guaranteed to be non-null.
		Object[] listeners = _listeners.getListenerList();
		// Process the listeners last to first, notifying
		// those that are interested in this event.
		ResultTabEvent evt = null;
		for (int i = listeners.length - 2; i >= 0; i -= 2)
		{
			if (listeners[i] == IResultTabListener.class)
			{
				// Lazily create the event:
				if (evt == null)
				{
					evt = new ResultTabEvent(_session, tab);
				}
				((IResultTabListener)listeners[i + 1]).resultTabAdded(evt);
			}
		}
	}

	protected void fireTabRemovedEvent(IResultTab tab)
	{
		// Guaranteed to be non-null.
		Object[] listeners = _listeners.getListenerList();
		// Process the listeners last to first, notifying
		// those that are interested in this event.
		ResultTabEvent evt = null;
		for (int i = listeners.length - 2; i >= 0; i -= 2)
		{
			if (listeners[i] == IResultTabListener.class)
			{
				// Lazily create the event:
				if (evt == null)
				{
					evt = new ResultTabEvent(_session, tab);
				}
				((IResultTabListener)listeners[i + 1]).resultTabRemoved(evt);
			}
		}
	}

	protected void fireTabTornOffEvent(IResultTab tab)
	{
		// Guaranteed to be non-null.
		Object[] listeners = _listeners.getListenerList();
		// Process the listeners last to first, notifying
		// those that are interested in this event.
		ResultTabEvent evt = null;
		for (int i = listeners.length - 2; i >= 0; i -= 2)
		{
			if (listeners[i] == IResultTabListener.class)
			{
				// Lazily create the event:
				if (evt == null)
				{
					evt = new ResultTabEvent(_session, tab);
				}
				((IResultTabListener)listeners[i + 1]).resultTabTornOff(evt);
			}
		}
	}

	protected void fireTornOffResultTabReturned(IResultTab tab)
	{
		// Guaranteed to be non-null.
		Object[] listeners = _listeners.getListenerList();
		// Process the listeners last to first, notifying
		// those that are interested in this event.
		ResultTabEvent evt = null;
		for (int i = listeners.length - 2; i >= 0; i -= 2)
		{
			if (listeners[i] == IResultTabListener.class)
			{
				// Lazily create the event:
				if (evt == null)
				{
					evt = new ResultTabEvent(_session, tab);
				}
				((IResultTabListener)listeners[i + 1])
						.tornOffResultTabReturned(evt);
			}
		}
	}

   protected String fireSQLToBeExecutedEvent(String sql)
	{
		// Guaranteed to be non-null.
		Object[] listeners = _listeners.getListenerList();
		// Process the listeners last to first, notifying
		// those that are interested in this event.
		for (int i = listeners.length - 2; i >= 0; i -= 2)
		{
			if (listeners[i] == ISQLExecutionListener.class)
			{
				sql = ((ISQLExecutionListener)listeners[i + 1]).statementExecuting(sql);
				if (sql == null)
				{
					break;
				}
			}
		}
		return sql;
	}

	/**
	 * Create an internal frame for the specified tab and
	 * display the tab in the internal frame after removing
	 * it from the tabbed pane.
	 *
	 * @param	tab	ResultTab to be displayed in
	 *				an internal frame.
	 *
	 * @throws	IllegalArgumentException
	 *			Thrown if a null ResultTab passed.
	 */
	public void createWindow(ResultTab tab)
	{
		if (tab == null)
		{
			throw new IllegalArgumentException("Null ResultTab passed");
		}
		s_log.debug("SQLPanel.createWindow(" + tab.getIdentifier().toString()
				+ ")");
		_tabbedExecutionsPanel.remove(tab);
		ResultFrame frame = new ResultFrame(_session, tab);
		ResultTabInfo tabInfo = _allTabs.get(tab.getIdentifier());
		tabInfo._resultFrame = frame;
		_session.getApplication().getMainFrame().addWidget(frame);
      frame.setLayer(JLayeredPane.PALETTE_LAYER);
		fireTabTornOffEvent(tab);

      if (false == _session.getApplication().getDesktopStyle().supportsLayers())
      {
         frame.pack();
         DialogWidget.centerWithinDesktop(frame);
      }
      frame.setVisible(true);

      // There used to be a frame.pack() here but it resized the frame
		// to be very wide if text output was used.

		frame.toFront();
		frame.requestFocus();


   }

	/**
	 * Return the passed tab back into the tabbed pane.
	 *
	 * @param	tab	Resulttab to be returned
	 *
	 * @throws	IllegalArgumentException
	 *			Thrown if a null ResultTab passed.
	 */
	public void returnToTabbedPane(ResultTab tab)
	{
		if (tab == null)
		{
			throw new IllegalArgumentException("Null ResultTab passed");
		}

		s_log.debug("SQLPanel.returnToTabbedPane("
				+ tab.getIdentifier().toString() + ")");

		ResultTabInfo tabInfo = _allTabs.get(tab.getIdentifier());
		if (tabInfo._resultFrame != null)
		{
			addResultsTab(tab, null);
			fireTornOffResultTabReturned(tab);
			tabInfo._resultFrame = null;
		}
	}

    /**
     * @see net.sourceforge.squirrel_sql.client.session.mainpanel.ISQLResultExecuter#getSelectedResultTab()
     */
    public IResultTab getSelectedResultTab() {
        return (IResultTab)_tabbedExecutionsPanel.getSelectedComponent();
    }
    
    /**
     * The idea here is to allow the caller to force the result to be re-run, 
     * potentially altering the output in the case where readFully is true and 
     * the result previously contained data placeholders ().  This will 
     * be useful for automating export to CSV/Excel of CLOB data, where it is 
     * most likely that the user doesn't want to see  in the resultant 
     * export file.
     * 
     * @param readFully if true, then the configuration will (temporarily) be
     * set so that clob data is read and displayed.
     */
    public void reRunSelectedResultTab(boolean readFully) {
        boolean clobReadOrigVal = DataTypeClob.getReadCompleteClob();
        if (readFully) {
            DataTypeClob.setReadCompleteClob(true);
        }
        IResultTab rt = (IResultTab)_tabbedExecutionsPanel.getSelectedComponent();
        rt.reRunSQL();
        if (readFully) {
            DataTypeClob.setReadCompleteClob(clobReadOrigVal);
        }
    }

	private void addResultsTab(final SQLExecutionInfo exInfo,
                              final ResultSetDataSet rsds,
                              final ResultSetMetaDataDataSet mdds,
                              final JPanel cancelPanel,
                              final IDataSetUpdateableTableModel creator,
                              final IResultTab resultTabToReplace)
	{
      final ResultTabListener resultTabListener = new ResultTabListener()
      {
         public void rerunSQL(String sql, IResultTab resultTab)
         {
            onRerunSQL(sql, resultTab);
         }
      };

      // We are in a thread. Do GUI work on event queque
      SwingUtilities.invokeLater(new Runnable()
      {
         public void run()
         {
            try
            {
               ResultTab tab = new ResultTab(_session, SQLResultExecuterPanel.this, _idFactory.createIdentifier(), exInfo, creator, resultTabListener);
               ResultTabInfo ti = new ResultTabInfo(tab);
               _allTabs.put(tab.getIdentifier(), ti);
               _usedTabs.add(ti);
               s_log.debug("Created new tab " + tab.getIdentifier().toString()
                     + " for results.");

               tab.showResults(rsds, mdds, exInfo);

               _tabbedExecutionsPanel.remove(cancelPanel);
               addResultsTab(tab, resultTabToReplace);
               _tabbedExecutionsPanel.setSelectedComponent(tab);
               fireTabAddedEvent(tab);
            }
            catch (Throwable t)
            {
               _session.showErrorMessage(t);
            }
         }
      });
	}

	private void addResultsTab(ResultTab tab, IResultTab resultTabToReplace)
	{
      if(null == resultTabToReplace && null == _stickyTab)
      {
   		_tabbedExecutionsPanel.addTab(tab.getTitle(), null, tab, tab.getViewableSqlString());
         checkResultTabLimit();
      }
      else
      {
         if (null != resultTabToReplace && _session.getProperties().getKeepTableLayoutOnRerun())
         {
            TableState sortableTableState = resultTabToReplace.getResultSortableTableState();
            if (null != sortableTableState)
            {
               tab.applyResultSortableTableState(sortableTableState);
            }
         }


         int indexToReplace = -1;
         ImageIcon tabIcon = null;

         // Either resultTabToReplace or _stickyTab must be not null here
         if(null != resultTabToReplace && _stickyTab != resultTabToReplace)
         {
            indexToReplace = getIndexOfTab(resultTabToReplace);
         }
         else
         {
            indexToReplace = getIndexOfTab(_stickyTab);
            if(-1 == indexToReplace)
            {
               // sticky tab was closed
               _stickyTab = null;
            }
            else
            {
               tabIcon = getStickyIcon();
               _stickyTab = tab;
            }
         }


         if(-1 == indexToReplace)
         {
            // Just add the tab
            addResultsTab(tab, null);
            return;
         }

         closeResultTabAt(indexToReplace);
         _tabbedExecutionsPanel.insertTab(tab.getTitle(), tabIcon, tab, tab.getViewableSqlString(), indexToReplace);
      }
	}

   private void checkResultTabLimit()
   {
      SessionProperties props = _session.getProperties();

      while(props.getLimitSQLResultTabs() && props.getSqlResultTabLimit() < _tabbedExecutionsPanel.getTabCount())
      {
         closeResultTabAt(0);
      }
   }


   private void closeResultTabAt(int index)
   {
      Component selectedTab = _tabbedExecutionsPanel.getComponentAt(index);

      List tabs = new ArrayList(_usedTabs);
      for (Iterator it = tabs.iterator(); it.hasNext();)
      {
         ResultTabInfo ti = it.next();
         if(ti._tab.equals(selectedTab))
         {
            if (ti._resultFrame == null)
            {
               closeTab(ti._tab);
            }
         }
      }
   }


   private void propertiesHaveChanged(String propName)
	{
		final SessionProperties props = _session.getProperties();

		if (propName == null
		        || propName.equals(SessionProperties.IPropertyNames.AUTO_COMMIT))
		{
            SetAutoCommitTask task = new SetAutoCommitTask();
		    if (SwingUtilities.isEventDispatchThread()) {
                _session.getApplication().getThreadPool().addTask(task);
            } else {
                task.run();
            }
        }

		if (propName == null
				|| propName
						.equals(SessionProperties.IPropertyNames.SQL_EXECUTION_TAB_PLACEMENT))
		{
			_tabbedExecutionsPanel.setTabPlacement(props.getSQLExecutionTabPlacement());
		}
	}

    private class SetAutoCommitTask implements Runnable {
                
        public void run() {
            final ISQLConnection conn = _session.getSQLConnection();
            final SessionProperties props = _session.getProperties();
            if (conn != null)
            {
                boolean auto = true;
                try
                {
                    auto = conn.getAutoCommit();
                }
                catch (SQLException ex)
                {
                    s_log.error("Error with transaction control", ex);
                    _session.showErrorMessage(ex);
                }
                try
                {
                    conn.setAutoCommit(props.getAutoCommit());
                }
                catch (SQLException ex)
                {
                    props.setAutoCommit(auto);
                    _session.showErrorMessage(ex);
                }
            }        
        }
    }
   
	private void createGUI()
	{
      final SessionProperties props = _session.getProperties();
		_tabbedExecutionsPanel = UIFactory.getInstance().createTabbedPane(props.getSQLExecutionTabPlacement());


      createTabPopup();


      setLayout(new BorderLayout());

		add(_tabbedExecutionsPanel, BorderLayout.CENTER);
	}


   /**
    * Due to JDK 1.4 Bug 4465870 this doesn't work with JDK 1.4. when scrollable tabbed pane is used.
    */
   private void createTabPopup()
   {
      final JPopupMenu popup = new JPopupMenu();

      // i18n[SQLResultExecuterPanel.close=Close]
      String closeLabel = s_stringMgr.getString("SQLResultExecuterPanel.close");
      JMenuItem mnuClose = new JMenuItem(closeLabel);
      initAccelerator(CloseCurrentSQLResultTabAction.class, mnuClose);
      mnuClose.addActionListener(new ActionListener()
      {
         public void actionPerformed(ActionEvent e)
         {
            closeCurrentResultTab();
         }
      });
      popup.add(mnuClose);

      // i18n[SQLResultExecuterPanel.closeAllButThis=Close all but this]
      String cabtLabel = 
          s_stringMgr.getString("SQLResultExecuterPanel.closeAllButThis");
      JMenuItem mnuCloseAllButThis = new JMenuItem(cabtLabel);
      initAccelerator(CloseAllSQLResultTabsButCurrentAction.class, mnuCloseAllButThis);
      mnuCloseAllButThis.addActionListener(new ActionListener()
      {
         public void actionPerformed(ActionEvent e)
         {
            closeAllButCurrentResultTabs();
         }
      });
      popup.add(mnuCloseAllButThis);

      // i18n[SQLResultExecuterPanel.closeAll=Close all]
      String caLabel = s_stringMgr.getString("SQLResultExecuterPanel.closeAll");
      JMenuItem mnuCloseAll = new JMenuItem(caLabel);
      initAccelerator(CloseAllSQLResultTabsAction.class, mnuCloseAll);
      mnuCloseAll.addActionListener(new ActionListener()
      {
         public void actionPerformed(ActionEvent e)
         {
            closeAllSQLResultTabs();
         }
      });
      popup.add(mnuCloseAll);

      // i18n[SQLResultExecuterPanel.toggleSticky=Toggle sticky]
      String tsLabel = 
          s_stringMgr.getString("SQLResultExecuterPanel.toggleSticky");
      JMenuItem mnuToggleSticky = new JMenuItem(tsLabel);
      initAccelerator(ToggleCurrentSQLResultTabStickyAction.class, mnuToggleSticky);
      mnuToggleSticky.addActionListener(new ActionListener()
      {
         public void actionPerformed(ActionEvent e)
         {
            toggleCurrentSQLResultTabSticky();
         }
      });
      popup.add(mnuToggleSticky);

      _tabbedExecutionsPanel.addMouseListener(new MouseAdapter()
      {
         public void mousePressed(MouseEvent e)
         {
            maybeShowPopup(e, popup);
         }

         public void mouseReleased(MouseEvent e)
         {
            maybeShowPopup(e, popup);
         }
      });
   }

   private void initAccelerator(Class actionClass, JMenuItem mnuItem)
   {
      Action action = _session.getApplication().getActionCollection().get(actionClass);

      String accel = (String) action.getValue(Resources.ACCELERATOR_STRING);
      if(   null != accel
         && 0 != accel.trim().length())
      {
         mnuItem.setAccelerator(KeyStroke.getKeyStroke(accel));
      }
   }

   private void maybeShowPopup(MouseEvent e, JPopupMenu popup)
   {
      if (e.isPopupTrigger())
      {
         int tab = _tabbedExecutionsPanel.getUI().tabForCoordinate(_tabbedExecutionsPanel, e.getX(), e.getY());
         if (-1 != tab)
         {
            popup.show(e.getComponent(), e.getX(), e.getY());
         }
      }
   }

   private SQLType getSQLType(String sql) {
       SQLType result = SQLType.UNKNOWN;
       if (sql.toLowerCase().startsWith("insert")) {
           result = SQLType.INSERT;
       }
       if (sql.toLowerCase().startsWith("update")) {
           result = SQLType.UPDATE;
       }
       if (sql.toLowerCase().startsWith("select")) {
           result = SQLType.SELECT;
       }
       if (sql.toLowerCase().startsWith("delete")) {
           result = SQLType.DELETE;
       }
       return result;
   }
   
   /** This class is the handler for the execution of sql against the SQLExecuterPanel
	*
	*/
    private class SQLExecutionHandler implements ISQLExecuterHandler
	{
        private CancelPanel _cancelPanel = new CancelPanel();

        /**
         * Hold onto the current ResultDataSet so if the execution is
         * cancelled then this can be cancelled.
         */
        private ResultSetDataSet rsds = null;

        private String sqlToBeExecuted = null;
        private SQLType sqlType = null;
        private IResultTab _resultTabToReplace;
        private boolean _largeScript = false;
        private double _scriptTotalTime = 0;
        private double _scriptQueryTime = 0;
        private double _scriptOutptutTime = 0;
        private int _scriptRowsInserted = 0;
        private int _scriptRowsSelected = 0;
        private int _scriptRowsUpdated = 0;
        private int _scriptRowsDeleted = 0;
      
        public SQLExecutionHandler(IResultTab resultTabToReplace)
        {
            super();
            _resultTabToReplace = resultTabToReplace;
            setCancelPanel(_cancelPanel);
        }

        /**
         * Set whether or not the script is large.  If the script is large, then
         * do some performance optimizations with the GUI so that it remains 
         * responsive.  If the UI is not responsive, then the user is not able
         * to see what is happening, nor are they able to control it (cancelling
         * becomes ineffective)
         * 
         * @param aBoolean whether or not the script is large.
         */
        public void setLargeScript(boolean aBoolean) {
            _largeScript = aBoolean;
        }
      
        /**
         * Determines whether or not the current statement SQL should be rendered.
         * Since too many statements can cause the UI to stop rendering the 
         * statements, we back off rendering after many statements so that the UI 
         * can continue to provide feedback to the user. 
         * 
         * @param current
         * @param total
         * @return
         */
        private boolean shouldRenderSQL(int current, int total) {
            if (!_largeScript) {
                return true;
            }
            boolean result = true;
            // Back-off a bit after a hundred updates to allow the UI to update
            if (total > 200 && current > 100 && current % 10 != 0) {
                result = false;
            }
            if (total > 1000 && current > 500 && current % 50 != 0) {
                result = false;
            }
            if (total > 2000 && current > 1000 && current % 100 != 0) {
                result = false;
            }
            return result;
        }

        public void sqlToBeExecuted(final String sql)
        {
            _cancelPanel.incCurrentQueryIndex();
            int currentStmtCount = _cancelPanel.getCurrentQueryIndex();
            if (!shouldRenderSQL(currentStmtCount,_cancelPanel.getTotalCount())) {
                return;
            }
            final String cleanSQL = StringUtilities.cleanString(sql);
            sqlToBeExecuted = cleanSQL;
            sqlType = getSQLType(cleanSQL);

            SwingUtilities.invokeLater(new Runnable() {
                public void run() {
                    _cancelPanel.setSQL(sqlToBeExecuted);

                    // i18n[SQLResultExecuterPanel.execStatus=Executing SQL...]
                    String status = 
                        s_stringMgr.getString("SQLResultExecuterPanel.execStatus");
                    _cancelPanel.setStatusLabel(status);
                }
            });
        }

        /**
         * This will - depending on the size of the script - print a message 
         * indicating the time that it took to execute one or more queries.  
         * When executing a large script (as defined by the user, but default is
         * > 200 statements) we don't want to keep sending messages to the 
         * message panel, otherwise the UI will get behind and slow the execution
         * of the script and prevent the user from cancelling the operation.  So
         * this method will track the total time when executing a large script, 
         * otherwise for small scripts it puts out a message for every statement.
         */
        public void sqlExecutionComplete(SQLExecutionInfo exInfo, 
                int processedStatementCount, 
                int statementCount)
        {
            double executionLength = ((double)exInfo.getSQLExecutionElapsedMillis())/1000;
            double outputLength = ((double)exInfo.getResultsProcessingElapsedMillis())/1000;            
            double totalLength = executionLength + outputLength;
            Integer numberResultRowsRead = exInfo.getNumberResultRowsRead();

           if (_largeScript) {
                // Track the time in aggregate for the script.
                _scriptQueryTime += executionLength;
                _scriptOutptutTime += outputLength;
                _scriptTotalTime += totalLength;

                // When we get to the last statement, if the script is large,
                // show the user the total execution time.                 
                if (statementCount == processedStatementCount) {
                    printScriptExecDetails(statementCount,
                            _scriptQueryTime,
                            _scriptOutptutTime,
                            _scriptTotalTime);
                }
            } else {
                printStatementExecTime(
                        processedStatementCount,
                        statementCount,
                        numberResultRowsRead,
                        executionLength,
                        outputLength,
                        totalLength);
            }
        }

        private void printScriptExecDetails(int statementCount,
                double executionLength,
                double outputLength,
                double totalLength) 
        {
            final NumberFormat nbrFmt = NumberFormat.getNumberInstance();

            Object[] args = new Object[] {
                Integer.valueOf(statementCount),
                nbrFmt.format(totalLength),
                nbrFmt.format(executionLength),
                nbrFmt.format(outputLength)
            };

            //i18n[SQLResultExecuterPanel.scriptQueryStatistics=Executed {0} 
            //queries; elapsed time (seconds) - Total: {1}, SQL query: {2}, 
            //Building output: {3}]
            String stats = 
                s_stringMgr.getString(
                        "SQLResultExecuterPanel.scriptQueryStatistics", 
                        args);

            String[] counts = 
                new String[] {Integer.toString(_scriptRowsInserted),
                    Integer.toString(_scriptRowsSelected),
                    Integer.toString(_scriptRowsUpdated),
                    Integer.toString(_scriptRowsDeleted)};

            //i18n[SQLResultExecuterPanel.scriptStmtCounts=Row update 
            //counts: {0} Inserts, {1} Selects, {2} Updates, {3} Deletes
            String msg = 
                s_stringMgr.getString("SQLResultExecuterPanel.scriptStmtCounts",
                        counts);
            getSession().showMessage(msg);
            getSession().showMessage(stats);
        }

        private void printStatementExecTime(
                int processedStatementCount,
                int statementCount,
                Integer numberResultRowsRead,
                double executionLength,
                double outputLength,
                double totalLength)
        {
            final NumberFormat nbrFmt = NumberFormat.getNumberInstance();

            Object[] args = new Object[] {
                    Integer.valueOf(processedStatementCount),
                    Integer.valueOf(statementCount),
                    numberResultRowsRead == null ? 0: numberResultRowsRead,
                    nbrFmt.format(totalLength),
                    nbrFmt.format(executionLength),
                    nbrFmt.format(outputLength)
            };

            //i18n[SQLResultExecuterPanel.queryStatistics=Query {0} of {1} 
            //elapsed time (seconds) - Total: {2}, SQL query: {3}, 
            //Building output: {4}]
            String stats = 
                s_stringMgr.getString("SQLResultExecuterPanel.queryStatistics", 
                        args);

            getSession().showMessage(stats);            
        }

        public void sqlExecutionCancelled()
        {
            if (rsds != null) {
                rsds.cancelProcessing();
            }
            // i18n[SQLResultExecuterPanel.canceleRequested=Query execution cancel requested by user.]
//          String canc = 
//          s_stringMgr.getString("SQLResultExecuterPanel.canceleRequested");
//          getSession().getMessageHandler().showMessage(canc);
        }

		public void sqlDataUpdated(int updateCount)
		{
            
            Integer count = Integer.valueOf(updateCount);
            String msg = "";
            
            switch (sqlType) {
                case INSERT:
                    if (_largeScript) {
                        _scriptRowsInserted++;
                    } else {
                        // i18n[SQLResultExecuterPanel.rowsUpdated={0} Row(s) Inserted]
                        msg = s_stringMgr.getString("SQLResultExecuterPanel.rowsInserted",
                                                    count);                               
                    }
                    break;
                case SELECT:
                    if (_largeScript) {
                        _scriptRowsSelected++;
                    } else {
                        // i18n[SQLResultExecuterPanel.rowsSelected={0} Row(s) Selected]
                        msg = s_stringMgr.getString("SQLResultExecuterPanel.rowsSelected",
                                                    count);
                    }
                    break;
                case UPDATE:
                    if (_largeScript) {
                        _scriptRowsUpdated++;
                    } else {
                        // i18n[SQLResultExecuterPanel.rowsUpdated={0} Row(s) Updated]
                        msg = s_stringMgr.getString("SQLResultExecuterPanel.rowsUpdated",
                                                  count);
                    }
                    break;
                case DELETE:
                    if (_largeScript) {
                        _scriptRowsDeleted++;
                    } else {
                        // i18n[SQLResultExecuterPanel.rowsDeleted={0} Row(s) Deleted]
                        msg = s_stringMgr.getString("SQLResultExecuterPanel.rowsDeleted",
                                                    count);                                                        
                    }
                    break;
            }            
            if (_largeScript) {
                return;
            }
            getSession().showMessage(msg);
		}

		public void sqlResultSetAvailable(ResultSet rs, SQLExecutionInfo info,
				IDataSetUpdateableTableModel model) throws DataSetException
		{
            // i18n[SQLResultExecuterPanel.outputStatus=Building output...]
            String outputStatus = 
                s_stringMgr.getString("SQLResultExecuterPanel.outputStatus");
			_cancelPanel.setStatusLabel(outputStatus);
			rsds = new ResultSetDataSet();
			SessionProperties props = getSession().getProperties();
			ResultSetMetaDataDataSet rsmdds = null;
            if (props.getShowResultsMetaData())
            {
               rsmdds = new ResultSetMetaDataDataSet(rs);
            }
         DialectType dialectType = 
            DialectFactory.getDialectType(getSession().getMetaData());
			info.setNumberResultRowsRead(rsds.setResultSet(rs, dialectType));

			addResultsTab(info, rsds, rsmdds, _cancelPanel, model, _resultTabToReplace);
			rsds = null;
		}

		public void sqlExecutionWarning(SQLWarning warn)
		{
		    getSession().showMessage(warn);
		}

		public void sqlStatementCount(int statementCount)
		{
		    _cancelPanel.setQueryCount(statementCount);
		}

		public void sqlCloseExecutionHandler()
		{
		    removeCancelPanel(_cancelPanel);
		    _executer = null;
		}

		public void sqlExecutionException(Throwable th, String postErrorString)
		{
		    SQLExecutionException ex = 
		        new SQLExecutionException(th, postErrorString);

		    String message = getSession().formatException(ex);

		    getSession().showErrorMessage(message);

		    if(getSession().getProperties().getWriteSQLErrorsToLog())
		    {
		        s_log.info(message);   
		    }
		}


		private void removeCancelPanel(final JPanel cancelPanel)
		{
		    SwingUtilities.invokeLater(new Runnable()
		    {
		        public void run()
		        {
		            _tabbedExecutionsPanel.remove(cancelPanel);

		            int indexToSelect = -1;
		            if(null == _resultTabToReplace)
		            {
		                indexToSelect = getIndexOfTab(_stickyTab);
		            }
		            else
		            {
		                indexToSelect = getIndexOfTab(_resultTabToReplace);
		            }

		            if(-1 != indexToSelect)
		            {
		                _tabbedExecutionsPanel.setSelectedIndex(indexToSelect);
		            }

		        }
		    });
		}

		private void setCancelPanel(final JPanel panel)
		{
		    SwingUtilities.invokeLater(new Runnable()
		    {
		        public void run()
		        {
		            _tabbedExecutionsPanel.addTab(i18n.EXEC_SQL_MSG, 
                                                  null, 
                                                  panel,	
                                                  i18n.CANCEL_SQL_MSG);
		            _tabbedExecutionsPanel.setSelectedComponent(panel);
		        }
		    });
		}
      
		private final class CancelPanel extends JPanel
		implements ActionListener
		{
            private static final long serialVersionUID = 1L;
            private JLabel _sqlLbl = new JLabel();
		    private JLabel _currentStatusLbl = new JLabel();

		    /** Total number of queries that will be executed. */
		    private int _queryCount;

		    /** Number of the query currently being executed (starts from 1). */
		    private int _currentQueryIndex = 0;

		    private CancelPanel()
		    {
		        super(new GridBagLayout());

		        // i18n[SQLResultExecuterPanel.cancelButtonLabel=Cancel]
		        String label = 
		            s_stringMgr.getString("SQLResultExecuterPanel.cancelButtonLabel");
		        JButton cancelBtn = new JButton(label);
		        cancelBtn.addActionListener(this);

		        GridBagConstraints gbc = new GridBagConstraints();

		        gbc.anchor = GridBagConstraints.WEST;
		        gbc.insets = new Insets(5, 10, 5, 10);

		        gbc.gridx = 0;
		        gbc.gridy = 0;

		        // i18n[SQLResultExecuterPanel.sqlLabel=SQL:]
		        label = s_stringMgr.getString("SQLResultExecuterPanel.sqlLabel");
		        add(new JLabel(label), gbc);

		        gbc.weightx = 1;
		        ++gbc.gridx;
		        add(_sqlLbl, gbc);

		        gbc.weightx = 0;
		        gbc.gridx = 0;
		        ++gbc.gridy;
		        // i18n[SQLResultExecuterPanel.statusLabel=Status:]
		        label = 
		            s_stringMgr.getString("SQLResultExecuterPanel.statusLabel");
		        add(new JLabel(label), gbc);

		        ++gbc.gridx;
		        add(_currentStatusLbl, gbc);

		        gbc.gridx = 0;
		        ++gbc.gridy;
		        gbc.fill = GridBagConstraints.NONE;
		        add(cancelBtn, gbc);
		    }

		    public void incCurrentQueryIndex() {
		        ++_currentQueryIndex;
		    }

		    public void setSQL(String sql)
		    {
		        // i18n[SQLResultExecuterPanel.currentSQLLabel={0} of {1} - {2}]
		        String label = 
		            s_stringMgr.getString("SQLResultExecuterPanel.currentSQLLabel",
		                    new Object[] { String.valueOf(_currentQueryIndex),
		                    String.valueOf(_queryCount),
		                    sql} );                
		        _sqlLbl.setText(label);
		    }

		    public void setStatusLabel(String text)
		    {
		        _currentStatusLbl.setText(text);
		    }

		    public void setQueryCount(int value)
		    {
		        _queryCount = value;
		        _currentQueryIndex = 0;
		    }

		    public int getTotalCount() {
		        return _queryCount;
		    }

		    public int getCurrentQueryIndex() {
		        return _currentQueryIndex;
		    }


		    public void actionPerformed(ActionEvent event)
		    {
		        try
		        {
		            if (_executer != null){
		                _executer.cancel();
		            }
		        }
		        catch (Throwable th)
		        {
		            s_log.error("Error occured cancelling SQL", th);
		        }
		    }
		}
	}

	private class MyPropertiesListener implements PropertyChangeListener
	{
		private boolean _listening = true;

		void stopListening()
		{
			_listening = false;
		}

		void startListening()
		{
			_listening = true;
		}

		public void propertyChange(PropertyChangeEvent evt)
		{
			if (_listening)
			{
				propertiesHaveChanged(evt.getPropertyName());
			}
		}
	}

	private final static class ResultTabInfo
	{
		final ResultTab _tab;
		ResultFrame _resultFrame;

		ResultTabInfo(ResultTab tab)
		{
			if (tab == null)
			{
				throw new IllegalArgumentException("Null ResultTab passed");
			}
			_tab = tab;
		}
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy