001: package net.sourceforge.squirrel_sql.client.session.mainpanel;
002:
003: /*
004: * Copyright (C) 2001-2004 Johan Compagner
005: * jcompagner@j-com.nl
006: *
007: * Modifications Copyright (C) 2003-2004 Jason Height
008: *
009: * Modifications copyright (C) 2004 Colin Bell
010: * colbell@users.sourceforge.net
011: *
012: * This library is free software; you can redistribute it and/or
013: * modify it under the terms of the GNU Lesser General Public
014: * License as published by the Free Software Foundation; either
015: * version 2.1 of the License, or (at your option) any later version.
016: *
017: * This library is distributed in the hope that it will be useful,
018: * but WITHOUT ANY WARRANTY; without even the implied warranty of
019: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
020: * Lesser General Public License for more details.
021: *
022: * You should have received a copy of the GNU Lesser General Public
023: * License along with this library; if not, write to the Free Software
024: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
025: */
026: import java.awt.BorderLayout;
027: import java.awt.Component;
028: import java.awt.GridBagConstraints;
029: import java.awt.GridBagLayout;
030: import java.awt.GridLayout;
031: import java.awt.Insets;
032: import java.awt.event.ActionEvent;
033: import java.beans.PropertyChangeEvent;
034: import java.beans.PropertyChangeListener;
035: import java.text.NumberFormat;
036:
037: import javax.swing.*;
038:
039: import net.sourceforge.squirrel_sql.fw.datasetviewer.*;
040: import net.sourceforge.squirrel_sql.fw.gui.MultipleLineLabel;
041: import net.sourceforge.squirrel_sql.fw.id.IHasIdentifier;
042: import net.sourceforge.squirrel_sql.fw.id.IIdentifier;
043: import net.sourceforge.squirrel_sql.fw.util.StringManager;
044: import net.sourceforge.squirrel_sql.fw.util.StringManagerFactory;
045: import net.sourceforge.squirrel_sql.fw.util.StringUtilities;
046:
047: import net.sourceforge.squirrel_sql.client.IApplication;
048: import net.sourceforge.squirrel_sql.client.action.SquirrelAction;
049: import net.sourceforge.squirrel_sql.client.gui.builders.UIFactory;
050: import net.sourceforge.squirrel_sql.client.session.ISession;
051: import net.sourceforge.squirrel_sql.client.session.SQLExecutionInfo;
052: import net.sourceforge.squirrel_sql.client.session.EditableSqlCheck;
053: import net.sourceforge.squirrel_sql.client.session.properties.SessionProperties;
054:
055: public class ResultTab extends JPanel implements IHasIdentifier,
056: IResultTab {
057: private static final long serialVersionUID = 1L;
058:
059: /** Uniquely identifies this ResultTab. */
060: private IIdentifier _id;
061:
062: /** Current session. */
063: transient private ISession _session;
064:
065: /** SQL Execution information. */
066: transient private SQLExecutionInfo _exInfo;
067:
068: /** Panel displaying the SQL results. */
069: transient private IDataSetViewer _resultSetOutput;
070:
071: /** Panel displaying the SQL results meta data. */
072: transient private IDataSetViewer _metaDataOutput;
073:
074: /** Scroll pane for <TT>_resultSetOutput</TT>. */
075: private JScrollPane _resultSetSp = new JScrollPane();
076:
077: /** Scroll pane for <TT>_metaDataOutput</TT>. */
078: private JScrollPane _metaDataSp = new JScrollPane();
079:
080: /** Tabbed pane containing the SQL results the the results meta data. */
081: private JTabbedPane _tp;
082:
083: /** <TT>SQLExecuterPanel</TT> that this tab is showing results for. */
084: private SQLResultExecuterPanel _sqlPanel;
085:
086: /** Label shows the current SQL script. */
087: private JLabel _currentSqlLbl = new JLabel();
088:
089: /** The SQL execurtes, cleaned up for display. */
090: private String _sql;
091:
092: /** Panel showing the query information. */
093: private QueryInfoPanel _queryInfoPanel = new QueryInfoPanel();
094:
095: /** Listener to the sessions properties. */
096: private PropertyChangeListener _propsListener;
097:
098: private boolean _allowEditing;
099:
100: transient private IDataSetUpdateableTableModel _creator;
101:
102: transient private ResultSetDataSet _rsds;
103:
104: /** Internationalized strings for this class. */
105: private static final StringManager s_stringMgr = StringManagerFactory
106: .getStringManager(ResultTab.class);
107: private ResultTabListener _resultTabListener;
108:
109: /**
110: * Ctor.
111: *
112: * @param session Current session.
113: * @param sqlPanel <TT>SQLResultExecuterPanel</TT> that this tab is
114: * showing results for.
115: * @param id Unique ID for this object.
116: *
117: * @thrown IllegalArgumentException
118: * Thrown if a <TT>null</TT> <TT>ISession</TT>,
119: * <<TT>SQLResultExecuterPanel</TT> or <TT>IIdentifier</TT> passed.
120: */
121: public ResultTab(ISession session, SQLResultExecuterPanel sqlPanel,
122: IIdentifier id, SQLExecutionInfo exInfo,
123: IDataSetUpdateableTableModel creator,
124: ResultTabListener resultTabListener)
125: throws IllegalArgumentException {
126: super ();
127: _resultTabListener = resultTabListener;
128: if (session == null) {
129: throw new IllegalArgumentException("Null ISession passed");
130: }
131: if (sqlPanel == null) {
132: throw new IllegalArgumentException("Null SQLPanel passed");
133: }
134: if (id == null) {
135: throw new IllegalArgumentException(
136: "Null IIdentifier passed");
137: }
138:
139: _session = session;
140: _sqlPanel = sqlPanel;
141: _id = id;
142: reInit(creator, exInfo);
143:
144: createGUI();
145: propertiesHaveChanged(null);
146: }
147:
148: /**
149: * @see net.sourceforge.squirrel_sql.client.session.mainpanel.IResultTab#reInit(net.sourceforge.squirrel_sql.fw.datasetviewer.IDataSetUpdateableTableModel, net.sourceforge.squirrel_sql.client.session.SQLExecutionInfo)
150: */
151: public void reInit(IDataSetUpdateableTableModel creator,
152: SQLExecutionInfo exInfo) {
153: _creator = creator;
154: _creator.addListener(new DataSetUpdateableTableModelListener() {
155: public void forceEditMode(boolean mode) {
156: onForceEditMode(mode);
157: }
158: });
159:
160: _allowEditing = new EditableSqlCheck(exInfo).allowsEditing();
161:
162: final SessionProperties props = _session.getProperties();
163:
164: if (_allowEditing) {
165: _resultSetOutput = BaseDataSetViewerDestination
166: .getInstance(props.getSQLResultsOutputClassName(),
167: _creator);
168:
169: } else {
170: // sql contains columns from multiple tables,
171: // so we cannot use all of the columns in a WHERE clause
172: // and it becomes difficult to know which table (or tables!) an
173: // edited column belongs to. Therefore limit the output
174: // to be read-only
175: _resultSetOutput = BaseDataSetViewerDestination
176: .getInstance(props
177: .getReadOnlySQLResultsOutputClassName(),
178: null);
179: }
180:
181: _resultSetSp.setViewportView(_resultSetOutput.getComponent());
182: _resultSetSp.setRowHeader(null);
183:
184: if (_session.getProperties().getShowResultsMetaData()) {
185: _metaDataOutput = BaseDataSetViewerDestination.getInstance(
186: props.getMetaDataOutputClassName(), null);
187: _metaDataSp.setViewportView(_metaDataOutput.getComponent());
188: _metaDataSp.setRowHeader(null);
189: }
190: }
191:
192: /**
193: * Panel is being added to its parent. Setup any required listeners.
194: */
195: public void addNotify() {
196: super .addNotify();
197: if (_propsListener == null) {
198: _propsListener = new PropertyChangeListener() {
199: public void propertyChange(PropertyChangeEvent evt) {
200: propertiesHaveChanged(evt);
201: }
202: };
203: _session.getProperties().addPropertyChangeListener(
204: _propsListener);
205: }
206: }
207:
208: /**
209: * Panel is being removed from its parent. Remove any required listeners.
210: */
211: public void removeNotify() {
212: super .removeNotify();
213: if (_propsListener != null) {
214: _session.getProperties().removePropertyChangeListener(
215: _propsListener);
216: _propsListener = null;
217: }
218: }
219:
220: /**
221: * @see net.sourceforge.squirrel_sql.client.session.mainpanel.IResultTab#showResults(net.sourceforge.squirrel_sql.fw.datasetviewer.ResultSetDataSet, net.sourceforge.squirrel_sql.fw.datasetviewer.ResultSetMetaDataDataSet, net.sourceforge.squirrel_sql.client.session.SQLExecutionInfo)
222: */
223: public void showResults(ResultSetDataSet rsds,
224: ResultSetMetaDataDataSet mdds, SQLExecutionInfo exInfo)
225: throws DataSetException {
226: _exInfo = exInfo;
227: _sql = StringUtilities.cleanString(exInfo.getSQL());
228:
229: // Display the result set.
230: _resultSetOutput.show(rsds, null);
231: _rsds = rsds;
232:
233: final int rowCount = _resultSetOutput.getRowCount();
234:
235: final int maxRows = _exInfo.getMaxRows();
236: if (maxRows > 0 && rowCount >= maxRows) {
237: String buf = _sql.replaceAll("&", "&");
238: buf = buf.replaceAll("<", "<");
239: buf = buf.replaceAll("<", ">");
240: buf = buf.replaceAll("\"", """);
241: // i18n[ResultTab.limitMessage=Limited to <font color='red'> {0} </font> rows]
242: String limitMsg = s_stringMgr
243: .getString("ResultTab.limitMessage", Integer
244: .valueOf(rowCount));
245: _currentSqlLbl.setText("<html><pre> " + limitMsg
246: + "; " + buf + "</pre></html>");
247: } else {
248: _currentSqlLbl.setText(_sql);
249: }
250:
251: // Display the result set metadata.
252: if (mdds != null && _metaDataOutput != null) {
253: _metaDataOutput.show(mdds, null); // Why null??
254: }
255:
256: exInfo.resultsProcessingComplete();
257:
258: // And the query info.
259: _queryInfoPanel.load(rsds, rowCount, exInfo);
260: }
261:
262: /**
263: * @see net.sourceforge.squirrel_sql.client.session.mainpanel.IResultTab#clear()
264: */
265: public void clear() {
266: if (_metaDataOutput != null) {
267: _metaDataOutput.clear();
268: }
269: if (_resultSetOutput != null) {
270: _resultSetOutput.clear();
271: }
272: _exInfo = null;
273: _currentSqlLbl.setText("");
274: _sql = "";
275: }
276:
277: /**
278: * @see net.sourceforge.squirrel_sql.client.session.mainpanel.IResultTab#getSqlString()
279: */
280: public String getSqlString() {
281: return _exInfo != null ? _exInfo.getSQL() : null;
282: }
283:
284: /**
285: * @see net.sourceforge.squirrel_sql.client.session.mainpanel.IResultTab#getViewableSqlString()
286: */
287: public String getViewableSqlString() {
288: return StringUtilities.cleanString(getSqlString());
289: }
290:
291: /**
292: * @see net.sourceforge.squirrel_sql.client.session.mainpanel.IResultTab#getTitle()
293: */
294: public String getTitle() {
295: String title = _sql;
296: if (title.length() < 20) {
297: return title;
298: }
299: return title.substring(0, 15);
300: }
301:
302: /**
303: * @see net.sourceforge.squirrel_sql.client.session.mainpanel.IResultTab#closeTab()
304: */
305: public void closeTab() {
306: add(_tp, BorderLayout.CENTER);
307: _sqlPanel.closeTab(this );
308: }
309:
310: /**
311: * @see net.sourceforge.squirrel_sql.client.session.mainpanel.IResultTab#returnToTabbedPane()
312: */
313: public void returnToTabbedPane() {
314: add(_tp, BorderLayout.CENTER);
315: _sqlPanel.returnToTabbedPane(this );
316: }
317:
318: /**
319: * @see net.sourceforge.squirrel_sql.client.session.mainpanel.IResultTab#getOutputComponent()
320: */
321: public Component getOutputComponent() {
322: return _tp;
323: }
324:
325: /**
326: * @see net.sourceforge.squirrel_sql.client.session.mainpanel.IResultTab#reRunSQL()
327: */
328: public void reRunSQL() {
329: _resultTabListener.rerunSQL(_exInfo.getSQL(), ResultTab.this );
330: }
331:
332: /**
333: * Session properties have changed so update GUI if required.
334: *
335: * @param propertyName Name of property that has changed.
336: */
337: private void propertiesHaveChanged(PropertyChangeEvent evt) {
338: SessionProperties props = _session.getProperties();
339: if (evt == null
340: || evt
341: .getPropertyName()
342: .equals(
343: SessionProperties.IPropertyNames.SQL_RESULTS_TAB_PLACEMENT)) {
344: _tp.setTabPlacement(props.getSQLResultsTabPlacement());
345: }
346: }
347:
348: private void onForceEditMode(boolean editable) {
349: try {
350: if (editable) {
351: if (_allowEditing) {
352: _resultSetOutput = BaseDataSetViewerDestination
353: .getInstance(
354: SessionProperties.IDataSetDestinations.EDITABLE_TABLE,
355: _creator);
356: _resultSetSp.setViewportView(_resultSetOutput
357: .getComponent());
358: _resultSetSp.setRowHeader(null);
359: _rsds.resetCursor();
360: _resultSetOutput.show(_rsds, null);
361: } else {
362: // i18n[ResultTab.cannotedit=This SQL can not be edited.]
363: String msg = s_stringMgr
364: .getString("ResultTab.cannotedit");
365: JOptionPane.showMessageDialog(_session
366: .getApplication().getMainFrame(), msg);
367: }
368: } else {
369: SessionProperties props = _session.getProperties();
370:
371: String readOnlyOutput = props
372: .getReadOnlySQLResultsOutputClassName();
373:
374: _resultSetOutput = BaseDataSetViewerDestination
375: .getInstance(readOnlyOutput, _creator);
376: _resultSetSp.setViewportView(_resultSetOutput
377: .getComponent());
378: _resultSetSp.setRowHeader(null);
379: _rsds.resetCursor();
380: _resultSetOutput.show(_rsds, null);
381: }
382: } catch (DataSetException e) {
383: throw new RuntimeException(e);
384: }
385: }
386:
387: private void createGUI() {
388: // final Resources rsrc = _session.getApplication().getResources();
389: setLayout(new BorderLayout());
390:
391: int sqlResultsTabPlacement = _session.getProperties()
392: .getSQLResultsTabPlacement();
393: _tp = UIFactory.getInstance().createTabbedPane(
394: sqlResultsTabPlacement);
395:
396: JPanel panel1 = new JPanel();
397: JPanel panel2 = new JPanel();
398: panel2.setLayout(new GridLayout(1, 3, 0, 0));
399: panel2.add(new TabButton(new RerunAction(_session
400: .getApplication())));
401: panel2.add(new TabButton(new CreateResultTabFrameAction(
402: _session.getApplication())));
403: panel2.add(new TabButton(new CloseAction()));
404: panel1.setLayout(new BorderLayout());
405: panel1.add(panel2, BorderLayout.EAST);
406: panel1.add(_currentSqlLbl, BorderLayout.CENTER);
407: add(panel1, BorderLayout.NORTH);
408: add(_tp, BorderLayout.CENTER);
409:
410: _resultSetSp.setBorder(BorderFactory.createEmptyBorder());
411:
412: // i18n[ResultTab.resultsTabTitle=Results]
413: String resultsTabTitle = s_stringMgr
414: .getString("ResultTab.resultsTabTitle");
415: _tp.addTab(resultsTabTitle, _resultSetSp);
416:
417: if (_session.getProperties().getShowResultsMetaData()) {
418: _metaDataSp.setBorder(BorderFactory.createEmptyBorder());
419:
420: // i18n[ResultTab.metadataTabTitle=MetaData]
421: String metadataTabTitle = s_stringMgr
422: .getString("ResultTab.metadataTabTitle");
423: _tp.addTab(metadataTabTitle, _metaDataSp);
424: }
425:
426: final JScrollPane sp = new JScrollPane(_queryInfoPanel);
427: sp.setBorder(BorderFactory.createEmptyBorder());
428:
429: // i18n[ResultTab.infoTabTitle=Info]
430: String infoTabTitle = s_stringMgr
431: .getString("ResultTab.infoTabTitle");
432: _tp.addTab(infoTabTitle, sp);
433: }
434:
435: private final class TabButton extends JButton {
436: TabButton(Action action) {
437: super (action);
438: setMargin(new Insets(0, 0, 0, 0));
439: setBorderPainted(false);
440: setText("");
441: }
442: }
443:
444: private class CloseAction extends SquirrelAction {
445: CloseAction() {
446: super (_session.getApplication(), _session.getApplication()
447: .getResources());
448: }
449:
450: public void actionPerformed(ActionEvent evt) {
451: closeTab();
452: }
453: }
454:
455: private class CreateResultTabFrameAction extends SquirrelAction {
456: CreateResultTabFrameAction(IApplication app) {
457: super (app, app.getResources());
458: }
459:
460: public void actionPerformed(ActionEvent evt) {
461: _sqlPanel.createWindow(ResultTab.this );
462: }
463: }
464:
465: public class RerunAction extends SquirrelAction {
466: RerunAction(IApplication app) {
467: super (app, app.getResources());
468: }
469:
470: public void actionPerformed(ActionEvent evt) {
471: reRunSQL();
472: }
473: }
474:
475: /**
476: * @see net.sourceforge.squirrel_sql.client.session.mainpanel.IResultTab#getIdentifier()
477: */
478: public IIdentifier getIdentifier() {
479: return _id;
480: }
481:
482: private static class QueryInfoPanel extends JPanel {
483: private static final long serialVersionUID = 2124193091025851544L;
484:
485: private MultipleLineLabel _queryLbl = new MultipleLineLabel();
486: private JLabel _rowCountLbl = new JLabel();
487: private JLabel _executedLbl = new JLabel();
488: private JLabel _elapsedLbl = new JLabel();
489:
490: QueryInfoPanel() {
491: super ();
492: createGUI();
493: }
494:
495: void load(ResultSetDataSet rsds, int rowCount,
496: SQLExecutionInfo exInfo) {
497: _queryLbl.setText(StringUtilities.cleanString(exInfo
498: .getSQL()));
499: _rowCountLbl.setText(String.valueOf(rowCount));
500: _executedLbl.setText(exInfo.getSQLExecutionStartTime()
501: .toString());
502: _elapsedLbl.setText(formatElapsedTime(exInfo));
503: }
504:
505: private String formatElapsedTime(SQLExecutionInfo exInfo) {
506: final NumberFormat nbrFmt = NumberFormat
507: .getNumberInstance();
508: double executionLength = exInfo
509: .getSQLExecutionElapsedMillis() / 1000.0;
510: double outputLength = exInfo
511: .getResultsProcessingElapsedMillis() / 1000.0;
512:
513: String totalTime = nbrFmt.format(executionLength
514: + outputLength);
515: String queryTime = nbrFmt.format(executionLength);
516: String outputTime = nbrFmt.format(outputLength);
517:
518: // i18n[ResultTab.elapsedTime=Total: {0}, SQL query: {1}, Building output: {2}]
519: String elapsedTime = s_stringMgr.getString(
520: "ResultTab.elapsedTime", new String[] { totalTime,
521: queryTime, outputTime });
522: return elapsedTime;
523: }
524:
525: private void createGUI() {
526: setLayout(new GridBagLayout());
527: GridBagConstraints gbc = new GridBagConstraints();
528:
529: gbc.anchor = GridBagConstraints.NORTHWEST;
530: gbc.gridwidth = 1;
531: gbc.weightx = 0;
532:
533: gbc.gridx = 0;
534: gbc.gridy = 0;
535: gbc.insets = new Insets(5, 10, 5, 10);
536: gbc.fill = GridBagConstraints.HORIZONTAL;
537: // i18n[ResultTab.executedLabel=Executed:]
538: String label = s_stringMgr
539: .getString("ResultTab.executedLabel");
540: add(new JLabel(label, SwingConstants.RIGHT), gbc);
541:
542: ++gbc.gridy;
543: // i18n[ResultTab.rowCountLabel=Row Count:]
544: label = s_stringMgr.getString("ResultTab.rowCountLabel");
545: add(new JLabel(label, SwingConstants.RIGHT), gbc);
546:
547: ++gbc.gridy;
548: // i18n[ResultTab.statementLabel=SQL:]
549: label = s_stringMgr.getString("ResultTab.statementLabel");
550: add(new JLabel(label, SwingConstants.RIGHT), gbc);
551:
552: ++gbc.gridy;
553: // i18n[ResultTab.elapsedTimeLabel=Elapsed Time (seconds):]
554: label = s_stringMgr.getString("ResultTab.elapsedTimeLabel");
555: add(new JLabel(label, SwingConstants.RIGHT), gbc);
556:
557: gbc.gridwidth = GridBagConstraints.REMAINDER;
558: gbc.weightx = 1;
559:
560: gbc.gridx = 1;
561: gbc.gridy = 0;
562: add(_executedLbl, gbc);
563:
564: ++gbc.gridy;
565: add(_rowCountLbl, gbc);
566:
567: ++gbc.gridy;
568: add(_queryLbl, gbc);
569:
570: ++gbc.gridy;
571: add(_elapsedLbl, gbc);
572: }
573: }
574: }
|