package com.hackerdude.apps.sqlide.plugins.isql;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Event;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Blob;
import java.sql.Clob;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.text.MessageFormat;
import java.util.ArrayList;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSplitPane;
import javax.swing.JTable;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;
import javax.swing.table.TableModel;
import com.hackerdude.apps.sqlide.ProgramConfig;
import com.hackerdude.apps.sqlide.ProgramIcons;
import com.hackerdude.apps.sqlide.SqlIdeApplication;
import com.hackerdude.apps.sqlide.components.ResultSetColumnModel;
import com.hackerdude.apps.sqlide.dataaccess.DatabaseProcess;
import com.hackerdude.apps.sqlide.dataaccess.QueryResults;
import com.hackerdude.apps.sqlide.dialogs.ClobEditorDialog;
import com.hackerdude.apps.sqlide.plugins.SyntaxTextArea;
import com.hackerdude.apps.sqlide.plugins.SyntaxTextAreaFactory;
import com.hackerdude.apps.sqlide.xml.HostConfigFactory;
import com.hackerdude.apps.sqlide.xml.hostconfig.QueryHistory;
import com.hackerdude.swing.table.ModalButtonCellEditor;
/**
* The main Interactive SQL Panel.
*
* @author David Martinez
* @version 1.0
*/
public class MainISQLPanel extends JPanel {
public final Action ACTION_RUN_COMMAND = new ActionCommandRunner();
public final Action ACTION_VIEW_CLOB = new ActionViewText();
public final Action ACTION_HISTORY_PREV = new HistoryPreviousAction();
public final Action ACTION_HISTORY_NEXT = new HistoryNextAction();
private DatabaseProcess ideprocess;
final DBChangeListener cbListener = new DBChangeListener();
private ResultSetPanel resultSetPanel = new ResultSetPanel();
private SyntaxTextArea sqlTextArea = SyntaxTextAreaFactory.createTextArea();
ModalButtonCellEditor buttonCellEditor = new ModalButtonCellEditor(ACTION_VIEW_CLOB);
private BorderLayout blMainLayout = new BorderLayout();
private JPanel pnlBottomPanel = new JPanel();
private JPanel pnlTopPanel = new JPanel();
private JPanel pnlCenter = new JPanel();
private JSplitPane jSplitPane1 = new JSplitPane();
private BorderLayout borderLayout1 = new BorderLayout();
private JLabel lblCatalog = new JLabel();
private JComboBox cbCatalogs = new JComboBox();
private JButton btnGo = new JButton(ACTION_RUN_COMMAND);
private JCheckBox cbAsUpdate = new JCheckBox();
private int historyBackCount = 0;
private JCheckBox cbUpdatable = new JCheckBox();
public final PropertyChangeListener QUERY_REFRESH_LISTENER = new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent evt) {
executeCurrentQuery();
}
};
public final PropertyChangeListener SQL_EXCEPTION_LISTENER = new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent evt) {
SQLException exception = (SQLException)evt.getNewValue();
resultSetPanel.logSQLException(exception);
resultSetPanel.addStatusText("Please correct and try again.");
}
};
public MainISQLPanel() {
try {
jbInit();
cbCatalogs.addActionListener(cbListener);
resultSetPanel.setViewClobAction(ACTION_VIEW_CLOB);
InputMap inputMap = sqlTextArea.getTextArea().getInputMap();
ActionMap actionMap = sqlTextArea.getTextArea().getActionMap();
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, KeyEvent.CTRL_MASK), "historyPrev");
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, KeyEvent.CTRL_MASK), "historyNext");
actionMap.put("historyPrev", ACTION_HISTORY_PREV);
actionMap.put("historyNext", ACTION_HISTORY_NEXT);
resultSetPanel.addPropertyChangeListener(ResultSetPanel.PROPERTY_QUERY_REFRESH_REQUEST, QUERY_REFRESH_LISTENER);
resultSetPanel.addPropertyChangeListener(ResultSetPanel.PROPERTY_SQL_EXCEPTION_REPORTED, SQL_EXCEPTION_LISTENER);
} catch (Exception ex) {
ex.printStackTrace();
}
}
void jbInit() throws Exception {
sqlTextArea.setMinimumSize(new Dimension(200, 150));
this.setLayout(blMainLayout);
pnlCenter.setLayout(borderLayout1);
jSplitPane1.setOrientation(JSplitPane.VERTICAL_SPLIT);
lblCatalog.setText("Catalog:");
btnGo.setText("Go!");
cbAsUpdate.setText("As Update");
cbAsUpdate.setMnemonic('U');
cbUpdatable.setActionCommand("updatable");
cbUpdatable.setText("Updatable");
this.add(pnlBottomPanel, BorderLayout.SOUTH);
this.add(pnlTopPanel, BorderLayout.NORTH);
pnlTopPanel.add(lblCatalog, null);
pnlTopPanel.add(cbCatalogs, null);
pnlTopPanel.add(btnGo, null);
pnlTopPanel.add(cbAsUpdate, null);
pnlTopPanel.add(cbUpdatable, null);
this.add(pnlCenter, BorderLayout.CENTER);
pnlCenter.add(jSplitPane1, BorderLayout.CENTER);
jSplitPane1.add(sqlTextArea, JSplitPane.TOP);
jSplitPane1.add(resultSetPanel, JSplitPane.BOTTOM);
jSplitPane1.setDividerLocation(100);
}
/**
* This executes the current query for this interactive SQL Window.
*/
public void executeCurrentQuery() {
setCursor(new Cursor(Cursor.WAIT_CURSOR));
resultSetPanel.addStatusText("Executing Query. Please Wait...");
final String queryText = sqlTextArea.getText();
Object db = cbCatalogs.getSelectedItem();
if (db != null) ideprocess.changeCatalog(db.toString());
final boolean asUpdate = cbAsUpdate.isSelected();
final boolean updatable = cbUpdatable.isSelected();
ACTION_RUN_COMMAND.setEnabled(false);
new Thread() {
public void run() {
try {
final QueryResults queryResults = ideprocess.runQuery(queryText, asUpdate, updatable);
sqlTextArea.setText(ideprocess.lastQuery);
SwingUtilities.invokeLater(new Runnable() {
public void run() {
addToHistoryIfNeeded(queryText);
displayResults(asUpdate, updatable, queryResults);
}
});
} catch (final SQLException exc) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
resultSetPanel.logSQLException(exc);
resultSetPanel.clearResultSetModel();
}
});
//JOptionPane.showMessageDialog(this, "SQL Exception: " + exc, "SQL Exception", JOptionPane.ERROR_MESSAGE);.
} finally {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
setCursor(Cursor.getDefaultCursor());
ACTION_RUN_COMMAND.setEnabled(true);
}
});
}
}
}.start();
}
/**
* This function displays the QueryResults in the results table.
* If it cannot do it, it clears the current results and logs a message.
* @param asUpdate True if this was an update.
* @param updatable True if the query was updatable.
* @param queryResults The results of the query.
*/
private void displayResults(boolean asUpdate, boolean updatable, QueryResults queryResults) {
try {
if (queryResults != null && queryResults.getResultSet() != null) {
Font theFont = ProgramConfig.getInstance().getResultSetFont();
ResultSetColumnModel newColumnModel = new ResultSetColumnModel(
queryResults, theFont, this);
setDefaultEditors(ideprocess.getTableModel(), newColumnModel);
TableModel tableModel = ideprocess.getTableModel();
ResultSet resultSet = queryResults.getResultSet();
updatable = ! (resultSet.getConcurrency() == ResultSet.CONCUR_READ_ONLY);
resultSetPanel.setResultSetModel(newColumnModel, tableModel, resultSet);
setClobEditors(queryResults, newColumnModel);
}
String message = "Ran " + (asUpdate ? " update" : "query ") + (updatable ? " (<B>updatable result obtained</B>)" : "");
if (queryResults != null)
message = message + ". Elapsed time " + formatElapsedTime(queryResults.getElapsedTime());
resultSetPanel.addStatusText(message);
if (queryResults != null)
if (asUpdate)
resultSetPanel.addStatusText("Rows updated: " + queryResults.getRowsAffected());
} catch (SQLException exc) {
resultSetPanel.logSQLException(exc);
resultSetPanel.clearResultSetModel();
}
}
public String formatElapsedTime(long elapsedTime) {
long millis = elapsedTime;
millis = millis>1000?elapsedTime % 1000:millis;
long seconds = millis / 1000;
seconds = seconds > 60 ? seconds % 60 : seconds;
long minutes = seconds / 60;
Object[] PARAMS = {
new Long(minutes), new Long(seconds), new Long(millis)
};
String format = "{2} msec";
if ( seconds > 0 ) format = "{1} seconds "+format;
if ( minutes > 0 ) format = "{0} minutes"+format;
return MessageFormat.format(format, PARAMS);
}
private void addToHistoryIfNeeded(String query) {
// Add to the history if the last query is different than the current one.
QueryHistory queryHistory = ideprocess.getHostConfiguration().getQueryHistory();
if (queryHistory == null) {
queryHistory = new QueryHistory();
ideprocess.getHostConfiguration().setQueryHistory(queryHistory);
}
String lastQueryInHistory = queryHistory.getHistoryItemCount() < 1 ? "" : queryHistory.getHistoryItem(queryHistory.getHistoryItemCount() - 1);
if (!lastQueryInHistory.equalsIgnoreCase(query))
queryHistory.addHistoryItem(query);
try {
HostConfigFactory.saveSqlideHostConfig(ideprocess.getHostConfiguration());
} catch (IOException ex) {
}
}
private void setClobEditors(QueryResults queryResults,
ResultSetColumnModel columnModel) {
for (int i = 0; i < queryResults.getColumnSQLTypes().length; i++) {
if ( queryResults.getColumnSQLTypes()[i] == java.sql.Types.CLOB ||
queryResults.getColumnSQLTypes()[i] == java.sql.Types.BLOB) {
columnModel.getColumn(i).setCellEditor(buttonCellEditor);
}
}
}
/**
* This action runs the current command.
*/
class ActionCommandRunner extends AbstractAction {
public ActionCommandRunner() {
super("Go!", ProgramIcons.getInstance().findIcon("images/VCRPlay.gif"));
putValue(ACCELERATOR_KEY,
KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, Event.CTRL_MASK, false));
putValue(MNEMONIC_KEY, new Integer(KeyEvent.VK_G));
}
public void actionPerformed(ActionEvent evt) {
executeCurrentQuery();
}
}
public void setQueryText(String queryText) {
sqlTextArea.setText(queryText);
}
public String getQueryText() {
return sqlTextArea.getText();
}
public void cut() {
sqlTextArea.cut();
}
public void copy() {
sqlTextArea.copy();
}
public void paste() {
sqlTextArea.paste();
}
public void setDatabaseProcess(DatabaseProcess proc) {
ideprocess = proc;
try {
ArrayList dbs = ideprocess.getCatalogs();
for (int i = 0; i < dbs.size(); i++) {
cbCatalogs.addItem(dbs.get(i));
}
lblCatalog.setVisible(cbCatalogs.getItemCount()>0);
cbCatalogs.setVisible(cbCatalogs.getItemCount()>0);
} catch (SQLException exc) {
}
}
public void refreshFromConfig() {
sqlTextArea.fireConfigurationChanged();
}
class DBChangeListener
implements ActionListener {
public void actionPerformed(ActionEvent e) {
String actionString = e.getActionCommand();
if (ideprocess != null && actionString.equals("comboBoxChanged"))
ideprocess.changeCatalog(cbCatalogs.getSelectedItem().toString());
}
}
public void selectCatalog(String catalogName) {
cbCatalogs.setSelectedItem(catalogName);
}
public JPanel getExceptionPanel(String msg, Exception exc) {
String exceptionString = exc.toString();
String exceptionText = getExceptionText(exc);
JPanel panel = new JPanel(new BorderLayout());
JLabel message = new JLabel("<HTML>" + exceptionString + "<P><PRE>" +
exceptionText + "</PRE>",
ProgramIcons.
getInstance().findIcon("images/Error.gif"),
JLabel.CENTER);
JLabel label = new JLabel();
JLabel lbl = new JLabel(msg,
ProgramIcons.getInstance().findIcon(
"images/Error.gif"),
JLabel.CENTER);
panel.add(lbl, BorderLayout.NORTH);
panel.add(message, BorderLayout.CENTER);
return panel;
}
public String getExceptionText(Exception exc) {
ByteArrayOutputStream bos = new ByteArrayOutputStream(8192);
PrintWriter pw = new PrintWriter(bos) {
public void println(String item) {
super.println("<P>" + item);
}
};
exc.printStackTrace(pw);
String exception = new String(bos.toByteArray());
return exception;
}
public void setDefaultEditors(TableModel model, TableColumnModel columnModel) {
for (int i = 0; i < columnModel.getColumnCount(); i++) {
TableColumn column = columnModel.getColumn(i);
// System.out.println(column);
// System.out.println(model.getColumnClass(i));
if (java.sql.Clob.class.isAssignableFrom(model.getColumnClass(i))) {
column.setCellRenderer(new ClobCellRenderer());
/** @todo Come up with a cell editor using the Clob editor dialog. */
// column.setCellEditor(new ClobCellEditor());
}
}
}
class ClobCellRenderer
implements TableCellRenderer {
JButton viewButton = new JButton("Text",
ProgramIcons.getInstance().getServerIcon()); //, JLabel.LEFT);
public ClobCellRenderer() {
super();
viewButton.setAction(ACTION_VIEW_CLOB);
}
public Component getTableCellRendererComponent(JTable table,
Object value,
boolean isSelected,
boolean hasFocus,
int row,
int column) {
return viewButton;
}
}
class ActionViewText extends AbstractAction {
ClobEditorDialog editorDialog = new ClobEditorDialog();
public ActionViewText() {
super("(Large) ", ProgramIcons.getInstance().getServerIcon());
}
public void actionPerformed(ActionEvent evt) {
int column = resultSetPanel.tblResults.getSelectedColumn();
int row = resultSetPanel.tblResults.getSelectedRow();
Object object = resultSetPanel.tblResults.getModel().getValueAt(row,
column);
String fieldName = resultSetPanel.tblResults.getModel().getColumnName(
column);
if (object instanceof Clob) {
Clob clob = (Clob) object;
editorDialog.showClobEditor(SqlIdeApplication.getFrame(),
"Clob View for " + fieldName, fieldName,
clob);
} else if (object instanceof Blob) {
Blob blob = (Blob) object;
editorDialog.showBlobEditor(SqlIdeApplication.getFrame(),
"Blob View for " + fieldName, fieldName,
blob);
}
}
}
class HistoryPreviousAction extends AbstractAction {
public void actionPerformed(ActionEvent evt) {
QueryHistory queryHistory = ideprocess.getHostConfiguration().getQueryHistory();
if (queryHistory == null)
return;
int historyIndex = queryHistory.getHistoryItemCount() - 1 + historyBackCount--;
if (historyIndex > queryHistory.getHistoryItemCount() - 1)
return;
if (historyIndex < 0) {
historyBackCount = -1; return;
}
String historyText = queryHistory.getHistoryItem(historyIndex);
setQueryText(historyText);
}
}
class HistoryNextAction extends AbstractAction {
public void actionPerformed(ActionEvent evt) {
QueryHistory queryHistory = ideprocess.getHostConfiguration().getQueryHistory();
if (queryHistory == null)
return;
int historyIndex = queryHistory.getHistoryItemCount() + historyBackCount++;
if (historyIndex > queryHistory.getHistoryItemCount() - 1) {
historyBackCount = 0;
setQueryText("");
return;
}
String historyText = queryHistory.getHistoryItem(historyIndex);
setQueryText(historyText);
}
}
}