0001: /*
0002: * SqlPanel.java
0003: *
0004: * This file is part of SQL Workbench/J, http://www.sql-workbench.net
0005: *
0006: * Copyright 2002-2008, Thomas Kellerer
0007: * No part of this code maybe reused without the permission of the author
0008: *
0009: * To contact the author please send an email to: support@sql-workbench.net
0010: *
0011: */
0012: package workbench.gui.sql;
0013:
0014: import java.awt.BorderLayout;
0015: import java.awt.Component;
0016: import java.awt.Container;
0017: import java.awt.EventQueue;
0018: import java.awt.Font;
0019: import java.awt.Window;
0020: import java.beans.PropertyChangeEvent;
0021: import java.beans.PropertyChangeListener;
0022: import java.io.File;
0023: import java.io.IOException;
0024: import java.sql.ResultSet;
0025: import java.sql.SQLException;
0026: import java.util.Collections;
0027: import java.util.Iterator;
0028: import java.util.LinkedList;
0029: import java.util.LinkedList;
0030: import java.util.List;
0031: import java.util.Properties;
0032: import java.util.regex.Pattern;
0033: import javax.swing.Action;
0034: import javax.swing.ActionMap;
0035: import javax.swing.ComponentInputMap;
0036: import javax.swing.Icon;
0037: import javax.swing.ImageIcon;
0038: import javax.swing.InputMap;
0039: import javax.swing.JOptionPane;
0040: import javax.swing.JPanel;
0041: import javax.swing.JScrollPane;
0042: import javax.swing.JSplitPane;
0043: import javax.swing.JTabbedPane;
0044: import javax.swing.JTextArea;
0045: import javax.swing.SwingUtilities;
0046: import javax.swing.border.Border;
0047: import javax.swing.border.CompoundBorder;
0048: import javax.swing.border.EmptyBorder;
0049: import javax.swing.border.EtchedBorder;
0050: import javax.swing.event.ChangeEvent;
0051: import javax.swing.event.ChangeListener;
0052: import workbench.WbManager;
0053: import workbench.db.DbSettings;
0054: import workbench.db.WbConnection;
0055: import workbench.db.exporter.DataExporter;
0056: import workbench.db.importer.DataStoreImporter;
0057: import workbench.gui.MainWindow;
0058: import workbench.gui.actions.AppendResultsAction;
0059: import workbench.gui.actions.CloseResultTabAction;
0060: import workbench.gui.actions.FilterDataAction;
0061: import workbench.gui.actions.FilterPickerAction;
0062: import workbench.gui.actions.ImportClipboardAction;
0063: import workbench.gui.actions.ReplaceDataAction;
0064: import workbench.gui.actions.ResetFilterAction;
0065: import workbench.gui.actions.SelectionFilterAction;
0066: import workbench.gui.actions.ViewMessageLogAction;
0067: import workbench.gui.components.GenericRowMonitor;
0068: import workbench.gui.components.WbTabbedPane;
0069: import workbench.gui.dialogs.dataimport.ImportFileDialog;
0070: import workbench.interfaces.DbExecutionNotifier;
0071: import workbench.interfaces.ParameterPrompter;
0072: import workbench.interfaces.ResultReceiver;
0073: import workbench.interfaces.StatementRunner;
0074: import workbench.sql.StatementRunnerResult;
0075: import workbench.util.ExceptionUtil;
0076: import workbench.gui.WbSwingUtilities;
0077: import workbench.gui.actions.AutoCompletionAction;
0078: import workbench.gui.actions.AutoJumpNextStatement;
0079: import workbench.gui.actions.CheckPreparedStatementsAction;
0080: import workbench.gui.actions.CleanJavaCodeAction;
0081: import workbench.gui.actions.ClearCompletionCacheAction;
0082: import workbench.gui.actions.CommitAction;
0083: import workbench.gui.actions.CopyAsSqlDeleteInsertAction;
0084: import workbench.gui.actions.CopyAsSqlInsertAction;
0085: import workbench.gui.actions.CopyAsSqlUpdateAction;
0086: import workbench.gui.actions.CopyRowAction;
0087: import workbench.gui.actions.CreateDeleteScriptAction;
0088: import workbench.gui.actions.CreateSnippetAction;
0089: import workbench.gui.actions.CopyAsTextAction;
0090: import workbench.gui.actions.DeleteDependentRowsAction;
0091: import workbench.gui.actions.DeleteRowAction;
0092: import workbench.gui.actions.ExecuteAllAction;
0093: import workbench.gui.actions.ExecuteCurrentAction;
0094: import workbench.gui.actions.ExecuteSelAction;
0095: import workbench.gui.actions.ExpandEditorAction;
0096: import workbench.gui.actions.ExpandResultAction;
0097: import workbench.gui.actions.FileDiscardAction;
0098: import workbench.gui.actions.FindAction;
0099: import workbench.gui.actions.FindDataAction;
0100: import workbench.gui.actions.FindDataAgainAction;
0101: import workbench.gui.actions.FormatSqlAction;
0102: import workbench.gui.actions.HighlightCurrentStatement;
0103: import workbench.gui.actions.IgnoreErrorsAction;
0104: import workbench.gui.actions.ImportFileAction;
0105: import workbench.gui.actions.InsertRowAction;
0106: import workbench.gui.actions.MakeInListAction;
0107: import workbench.gui.actions.MakeLowerCaseAction;
0108: import workbench.gui.actions.MakeNonCharInListAction;
0109: import workbench.gui.actions.MakeUpperCaseAction;
0110: import workbench.gui.actions.OptimizeAllColumnsAction;
0111: import workbench.gui.actions.PrintAction;
0112: import workbench.gui.actions.PrintPreviewAction;
0113: import workbench.gui.actions.RedoAction;
0114: import workbench.gui.actions.ResetHighlightAction;
0115: import workbench.gui.actions.RollbackAction;
0116: import workbench.gui.actions.SaveDataAsAction;
0117: import workbench.gui.actions.SelectEditorAction;
0118: import workbench.gui.actions.SelectKeyColumnsAction;
0119: import workbench.gui.actions.SelectMaxRowsAction;
0120: import workbench.gui.actions.SelectResultAction;
0121: import workbench.gui.actions.SpoolDataAction;
0122: import workbench.gui.actions.StopAction;
0123: import workbench.gui.actions.ToggleAutoCommitAction;
0124: import workbench.gui.actions.UndoAction;
0125: import workbench.gui.actions.UndoExpandAction;
0126: import workbench.gui.actions.UpdateDatabaseAction;
0127: import workbench.gui.actions.WbAction;
0128: import workbench.gui.components.ConnectionInfo;
0129: import workbench.gui.components.DataStoreTableModel;
0130: import workbench.gui.components.EtchedBorderTop;
0131: import workbench.gui.components.WbMenu;
0132: import workbench.gui.components.WbScrollPane;
0133: import workbench.gui.components.WbSplitPane;
0134: import workbench.gui.components.WbTable;
0135: import workbench.gui.components.WbToolbar;
0136: import workbench.gui.components.WbToolbarSeparator;
0137: import workbench.gui.dialogs.dataimport.ImportOptions;
0138: import workbench.gui.dialogs.dataimport.TextImportOptions;
0139: import workbench.gui.menu.TextPopup;
0140: import workbench.gui.preparedstatement.ParameterEditor;
0141: import workbench.interfaces.Commitable;
0142: import workbench.interfaces.Connectable;
0143: import workbench.interfaces.DbExecutionListener;
0144: import workbench.interfaces.DbUpdater;
0145: import workbench.interfaces.ExecutionController;
0146: import workbench.interfaces.FilenameChangeListener;
0147: import workbench.interfaces.FontChangedListener;
0148: import workbench.interfaces.FormattableSql;
0149: import workbench.interfaces.Interruptable;
0150: import workbench.interfaces.JobErrorHandler;
0151: import workbench.interfaces.MainPanel;
0152: import workbench.interfaces.ResultLogger;
0153: import workbench.interfaces.Exporter;
0154: import workbench.interfaces.TextChangeListener;
0155: import workbench.log.LogMgr;
0156: import workbench.resource.ResourceMgr;
0157: import workbench.resource.Settings;
0158: import workbench.sql.DelimiterDefinition;
0159: import workbench.sql.MacroManager;
0160: import workbench.sql.ScriptParser;
0161: import workbench.sql.commands.SingleVerbCommand;
0162: import workbench.sql.preparedstatement.PreparedStatementPool;
0163: import workbench.sql.preparedstatement.StatementParameters;
0164: import workbench.storage.DataStore;
0165: import workbench.util.MessageBuffer;
0166: import workbench.util.SqlUtil;
0167: import workbench.util.NumberStringCache;
0168: import workbench.util.StringUtil;
0169: import workbench.util.WbProperties;
0170: import workbench.util.WbThread;
0171: import workbench.util.WbWorkspace;
0172:
0173: /**
0174: * A panel with an SQL editor (EditorPanel), a log panel and
0175: * a panel for displaying SQL results (DwPanel)
0176: *
0177: * @author support@sql-workbench.net
0178: */
0179: public class SqlPanel extends JPanel implements FontChangedListener,
0180: TextChangeListener, PropertyChangeListener, ChangeListener,
0181: MainPanel, Exporter, DbUpdater, Interruptable, FormattableSql,
0182: Commitable, JobErrorHandler, ExecutionController, ResultLogger,
0183: ParameterPrompter, DbExecutionNotifier, FilenameChangeListener,
0184: ResultReceiver {
0185: //<editor-fold defaultstate="collapsed" desc=" Variables ">
0186: protected EditorPanel editor;
0187: protected DwPanel currentData;
0188: protected SqlHistory sqlHistory;
0189:
0190: protected JTextArea log;
0191: protected WbTabbedPane resultTab;
0192: protected JSplitPane contentPanel;
0193: protected boolean threadBusy;
0194: protected boolean cancelExecution;
0195:
0196: private List actions = new LinkedList();
0197: private List<WbAction> toolbarActions = new LinkedList<WbAction>();
0198:
0199: private List<FilenameChangeListener> filenameChangeListeners;
0200:
0201: protected StopAction stopAction;
0202: protected ExecuteAllAction executeAll;
0203: protected ExecuteCurrentAction executeCurrent;
0204: protected ExecuteSelAction executeSelected;
0205:
0206: private int internalId;
0207:
0208: // Actions from DwPanel
0209: protected CopyAsTextAction dataToClipboard;
0210: protected SaveDataAsAction exportDataAction;
0211: protected CopyAsSqlInsertAction copyAsSqlInsert;
0212: protected CopyAsSqlUpdateAction copyAsSqlUpdate;
0213: protected CopyAsSqlDeleteInsertAction copyAsSqlDeleteInsert;
0214: protected CreateDeleteScriptAction createDeleteScript;
0215: protected ImportFileAction importFileAction;
0216: protected ImportClipboardAction importClipAction;
0217: protected PrintAction printDataAction;
0218: protected PrintPreviewAction printPreviewAction;
0219: protected UpdateDatabaseAction updateAction;
0220: protected InsertRowAction insertRow;
0221: protected CopyRowAction duplicateRow;
0222: protected DeleteRowAction deleteRow;
0223: protected DeleteDependentRowsAction deleteDependentRow;
0224: protected SelectKeyColumnsAction selectKeys;
0225: protected FilterDataAction filterAction;
0226: protected SelectionFilterAction selectionFilterAction;
0227: protected FilterPickerAction filterPicker;
0228: protected ResetFilterAction resetFilterAction;
0229: protected OptimizeAllColumnsAction optimizeAllCol;
0230: protected AppendResultsAction appendResultsAction;
0231:
0232: protected CheckPreparedStatementsAction checkPreparedAction;
0233: protected ClearCompletionCacheAction clearCompletionCache;
0234: protected AutoCompletionAction autoCompletion;
0235:
0236: protected WbMenu copySelectedMenu;
0237: protected ToggleAutoCommitAction toggleAutoCommit;
0238: protected CommitAction commitAction;
0239: protected RollbackAction rollbackAction;
0240:
0241: protected FormatSqlAction formatSql;
0242: protected SpoolDataAction spoolData;
0243:
0244: protected FileDiscardAction fileDiscardAction;
0245: protected FindDataAction findDataAction;
0246: protected FindDataAgainAction findDataAgainAction;
0247: protected ReplaceDataAction replaceDataAction;
0248: protected ResetHighlightAction resetHighlightAction;
0249:
0250: protected WbToolbar toolbar;
0251: protected ConnectionInfo connectionInfo;
0252:
0253: protected WbConnection dbConnection;
0254: private Connectable connectionClient;
0255:
0256: private Object connectionLock = new Object();
0257:
0258: protected boolean importRunning;
0259: protected boolean updateRunning;
0260: protected boolean textModified;
0261: protected String tabName;
0262:
0263: private List<DbExecutionListener> execListener;
0264: protected Thread executionThread;
0265: protected Interruptable worker;
0266:
0267: private static final Border statusBarBorder = new CompoundBorder(
0268: new EmptyBorder(2, 1, 0, 1), new EtchedBorder());
0269:
0270: private boolean appendResults = false;
0271:
0272: protected DwStatusBar statusBar;
0273: protected StatementRunner stmtRunner;
0274: protected GenericRowMonitor rowMonitor;
0275:
0276: //</editor-fold>
0277:
0278: public SqlPanel(int anId) {
0279: this .setId(anId);
0280: this .setBorder(WbSwingUtilities.EMPTY_BORDER);
0281: this .setLayout(new BorderLayout());
0282:
0283: editor = EditorPanel.createSqlEditor();
0284: statusBar = new DwStatusBar(true, true);
0285: statusBar.setBorder(statusBarBorder);
0286: editor.setStatusBar(statusBar);
0287: editor.setBorder(new EtchedBorderTop());
0288: editor.setName("sqleditor" + anId);
0289: log = new LogArea();
0290: log.setName("msg" + anId);
0291:
0292: this .resultTab = new WbTabbedPane();
0293: this .resultTab.setTabPlacement(JTabbedPane.TOP);
0294: this .resultTab.setDoubleBuffered(true);
0295: this .resultTab.setFocusable(false);
0296: this .resultTab.setName("resultspane");
0297:
0298: JScrollPane scroll = new WbScrollPane(log);
0299: this .resultTab.addTab(ResourceMgr.getString("LblTabMessages"),
0300: scroll);
0301:
0302: this .contentPanel = new WbSplitPane(JSplitPane.VERTICAL_SPLIT,
0303: true, this .editor, this .resultTab);
0304: this .contentPanel.setBorder(WbSwingUtilities.EMPTY_BORDER);
0305: this .contentPanel.setOneTouchExpandable(true);
0306: this .contentPanel.setContinuousLayout(true);
0307:
0308: this .add(this .contentPanel, BorderLayout.CENTER);
0309: this .add(statusBar, BorderLayout.SOUTH);
0310:
0311: this .initStatementHistory();
0312:
0313: this .initActions();
0314: this .initToolbar();
0315: this .setupActionMap();
0316:
0317: Settings s = Settings.getInstance();
0318: s.addFontChangedListener(this );
0319: s.addPropertyChangeListener(this ,
0320: Settings.PROPERTY_ANIMATED_ICONS);
0321:
0322: this .makeReadOnly();
0323: this .checkResultSetActions();
0324:
0325: this .editor.addTextChangeListener(this );
0326: this .rowMonitor = new GenericRowMonitor(this .statusBar);
0327:
0328: // The listeners have to be added as late as possible to ensure
0329: // that everything is created properly in case an event is fired
0330: this .resultTab.addChangeListener(this );
0331: this .editor.addFilenameChangeListener(this );
0332: }
0333:
0334: public String getId() {
0335: return NumberStringCache.getNumberString(this .internalId);
0336: }
0337:
0338: public void setId(int anId) {
0339: this .setName("sqlpanel" + anId);
0340: this .internalId = anId;
0341: }
0342:
0343: public void setConnectionClient(Connectable client) {
0344: this .connectionClient = client;
0345: }
0346:
0347: public boolean getAppendResults() {
0348: return appendResults;
0349: }
0350:
0351: public void setAppendResults(boolean flag) {
0352: this .appendResults = flag;
0353: }
0354:
0355: public void initDivider() {
0356: int myHeight = (int) this .getPreferredSize().getHeight();
0357: initDivider(myHeight);
0358: }
0359:
0360: public void initDivider(int height) {
0361: height -= (this .statusBar.getPreferredSize().getHeight() * 3);
0362: height -= this .editor.getHScrollBarHeight();
0363: height -= this .resultTab.getTabHeight();
0364: height -= this .contentPanel.getDividerSize();
0365: height -= 8;
0366: int loc = height / 2;
0367: if (loc <= 50)
0368: loc = -1;
0369: this .contentPanel.setDividerLocation(loc);
0370: }
0371:
0372: public WbToolbar getToolbar() {
0373: return this .toolbar;
0374: }
0375:
0376: private void initToolbar() {
0377: this .toolbar = new WbToolbar();
0378: this .toolbar.addDefaultBorder();
0379:
0380: Iterator<WbAction> itr = this .toolbarActions.iterator();
0381: while (itr.hasNext()) {
0382: WbAction a = itr.next();
0383: boolean toolbarSep = a.getCreateToolbarSeparator();
0384: if (toolbarSep) {
0385: toolbar.addSeparator();
0386: }
0387: a.addToToolbar(toolbar);
0388: }
0389: toolbar.addSeparator();
0390: this .connectionInfo = new ConnectionInfo(this .toolbar
0391: .getBackground());
0392: toolbar.add(this .connectionInfo);
0393: }
0394:
0395: public void addToToolbar(WbAction anAction, boolean withSeperator) {
0396: this .toolbar.add(anAction.getToolbarButton(true), this .toolbar
0397: .getComponentCount() - 1);
0398: if (withSeperator)
0399: this .toolbar.add(new WbToolbarSeparator(), this .toolbar
0400: .getComponentCount() - 1);
0401: }
0402:
0403: public void addResultTabChangeListener(ChangeListener l) {
0404: this .resultTab.addChangeListener(l);
0405: }
0406:
0407: public boolean readFile(String aFilename, String encoding) {
0408: if (aFilename == null)
0409: return false;
0410:
0411: boolean result = false;
0412:
0413: File f = new File(aFilename);
0414:
0415: if (this .editor.readFile(f, encoding)) {
0416: this .selectEditor();
0417: result = true;
0418: } else {
0419: this .removeIconFromTab();
0420: result = false;
0421: }
0422: return result;
0423: }
0424:
0425: public boolean hasFileLoaded() {
0426: return this .editor.hasFileLoaded();
0427: }
0428:
0429: public boolean checkAndSaveFile() {
0430: if (this .editor == null)
0431: return true;
0432: int result = this .editor.checkAndSaveFile();
0433: if (result == JOptionPane.CANCEL_OPTION)
0434: return false;
0435: return true;
0436: }
0437:
0438: public String getLogMessage() {
0439: return this .log.getText();
0440: }
0441:
0442: public EditorPanel getEditor() {
0443: return this .editor;
0444: }
0445:
0446: public void clearSqlHistory(boolean removeEditorText) {
0447: if (this .sqlHistory != null)
0448: this .sqlHistory.clear();
0449: this .editor.setText("");
0450: }
0451:
0452: public boolean closeFile(boolean emptyEditor) {
0453: return closeFile(emptyEditor, true);
0454: }
0455:
0456: public boolean closeFile(boolean emptyEditor, boolean checkUnsaved) {
0457: if (this .editor == null)
0458: return true;
0459: if (checkUnsaved) {
0460: boolean canClose = this .checkAndSaveFile();
0461: if (!canClose)
0462: return false;
0463: }
0464: if (this .editor.closeFile(emptyEditor)) {
0465: this .selectEditorLater();
0466: this .clearSqlHistory(false);
0467: return true;
0468: }
0469: return false;
0470: }
0471:
0472: public void fileNameChanged(Object sender, String newFilename) {
0473: if (sender == this .editor) {
0474: boolean hasFile = editor.hasFileLoaded();
0475: this .fileDiscardAction.setEnabled(hasFile);
0476: if (hasFile) {
0477: // reset a user-defined tab name if a file is loaded
0478: this .tabName = null;
0479: }
0480: updateTabTitle();
0481: }
0482: }
0483:
0484: private void fireFilenameChanged(String aNewName) {
0485: updateTabTitle();
0486: if (this .filenameChangeListeners == null)
0487: return;
0488: Iterator<FilenameChangeListener> itr = filenameChangeListeners
0489: .iterator();
0490: while (itr.hasNext()) {
0491: FilenameChangeListener l = itr.next();
0492: l.fileNameChanged(this , aNewName);
0493: }
0494: }
0495:
0496: public void addFilenameChangeListener(
0497: FilenameChangeListener aListener) {
0498: if (aListener == null)
0499: return;
0500: if (this .filenameChangeListeners == null)
0501: this .filenameChangeListeners = new LinkedList<FilenameChangeListener>();
0502: this .filenameChangeListeners.add(aListener);
0503: }
0504:
0505: public void removeFilenameChangeListener(
0506: FilenameChangeListener aListener) {
0507: if (aListener == null)
0508: return;
0509: if (this .filenameChangeListeners == null)
0510: return;
0511: this .filenameChangeListeners.remove(aListener);
0512: }
0513:
0514: @SuppressWarnings("unchecked")
0515: private void initActions() {
0516: WbAction a;
0517: this .executeAll = new ExecuteAllAction(this );
0518: this .executeSelected = new ExecuteSelAction(this );
0519: this .executeCurrent = new ExecuteCurrentAction(this );
0520:
0521: MakeLowerCaseAction makeLower = new MakeLowerCaseAction(
0522: this .editor);
0523: MakeUpperCaseAction makeUpper = new MakeUpperCaseAction(
0524: this .editor);
0525:
0526: this .editor.showFindOnPopupMenu();
0527: this .editor.showFormatSql();
0528:
0529: this .editor.addPopupMenuItem(this .executeSelected, true);
0530: this .editor.addPopupMenuItem(this .executeAll, false);
0531: this .editor.addPopupMenuItem(this .executeCurrent, false);
0532:
0533: TextPopup pop = (TextPopup) this .editor.getRightClickPopup();
0534:
0535: this .actions.add(editor.getFileOpenAction());
0536: this .actions.add(editor.getFileSaveAction());
0537: this .actions.add(editor.getFileSaveAsAction());
0538:
0539: this .fileDiscardAction = new FileDiscardAction(this );
0540: this .actions.add(this .fileDiscardAction);
0541: this .actions.add(this .editor.getReloadAction());
0542:
0543: this .actions.add(new UndoAction(this .editor));
0544: this .actions.add(new RedoAction(this .editor));
0545:
0546: a = pop.getCutAction();
0547: a.setCreateMenuSeparator(true);
0548: this .actions.add(a);
0549: this .actions.add(pop.getCopyAction());
0550: this .actions.add(pop.getPasteAction());
0551:
0552: a = pop.getClearAction();
0553: a.setCreateMenuSeparator(true);
0554: this .actions.add(a);
0555: this .actions.add(pop.getSelectAllAction());
0556: this .actions.add(editor.getColumnSelection());
0557:
0558: FindAction f = this .editor.getFindAction();
0559: f.setCreateMenuSeparator(true);
0560: this .actions.add(f);
0561: this .actions.add(this .editor.getFindAgainAction());
0562: this .actions.add(this .editor.getReplaceAction());
0563:
0564: makeLower.setCreateMenuSeparator(true);
0565: this .actions.add(makeLower);
0566: this .actions.add(makeUpper);
0567: this .actions.add(this .editor.getCommentAction());
0568: this .actions.add(this .editor.getUnCommentAction());
0569: this .actions.add(this .editor.getMatchBracketAction());
0570:
0571: // The update actions are proxies for the real ones
0572: // Once a result tab (DwPanel) has been displayed
0573: // they are "dispatched" to the real ones
0574: this .updateAction = new UpdateDatabaseAction(null);
0575: this .insertRow = new InsertRowAction(null);
0576: this .deleteRow = new DeleteRowAction(null);
0577: this .deleteDependentRow = new DeleteDependentRowsAction(null);
0578: this .duplicateRow = new CopyRowAction(null);
0579: this .selectKeys = new SelectKeyColumnsAction(null);
0580:
0581: this .actions.add(this .selectKeys);
0582: this .actions.add(this .updateAction);
0583: this .actions.add(this .insertRow);
0584: this .actions.add(this .duplicateRow);
0585: this .actions.add(this .deleteRow);
0586: this .actions.add(this .deleteDependentRow);
0587:
0588: this .createDeleteScript = new CreateDeleteScriptAction(null);
0589: this .actions.add(this .createDeleteScript);
0590:
0591: this .exportDataAction = new SaveDataAsAction(null);
0592: this .exportDataAction.setCreateMenuSeparator(true);
0593: this .exportDataAction.setEnabled(false);
0594:
0595: SelectEditorAction sea = new SelectEditorAction(this );
0596: sea.setCreateMenuSeparator(true);
0597: this .actions.add(sea);
0598: this .actions.add(new SelectResultAction(this ));
0599: this .actions.add(new SelectMaxRowsAction(this .statusBar));
0600: this .actions.add(new ViewMessageLogAction(this ));
0601:
0602: SplitPaneExpander expander = new SplitPaneExpander(
0603: this .contentPanel);
0604: a = new ExpandEditorAction(expander);
0605: a.setCreateMenuSeparator(true);
0606: this .actions.add(a);
0607: this .actions.add(new ExpandResultAction(expander));
0608: this .actions.add(new UndoExpandAction(expander));
0609:
0610: this .optimizeAllCol = new OptimizeAllColumnsAction(null);
0611: this .optimizeAllCol.setCreateMenuSeparator(true);
0612: this .optimizeAllCol.setEnabled(false);
0613: this .optimizeAllCol.removeIcon();
0614: this .optimizeAllCol.setMenuItemName(ResourceMgr.MNU_TXT_VIEW);
0615: this .actions.add(this .optimizeAllCol);
0616:
0617: this .dataToClipboard = new CopyAsTextAction(null);
0618: this .dataToClipboard.setEnabled(false);
0619: this .actions.add(this .exportDataAction);
0620: this .actions.add(this .dataToClipboard);
0621:
0622: this .copyAsSqlInsert = new CopyAsSqlInsertAction(null);
0623: this .actions.add(this .copyAsSqlInsert);
0624:
0625: this .copyAsSqlUpdate = new CopyAsSqlUpdateAction(null);
0626: this .actions.add(this .copyAsSqlUpdate);
0627:
0628: this .copyAsSqlDeleteInsert = new CopyAsSqlDeleteInsertAction(
0629: null);
0630: this .actions.add(this .copyAsSqlDeleteInsert);
0631:
0632: copySelectedMenu = WbTable.createCopySelectedMenu();
0633: copySelectedMenu.setEnabled(false);
0634: this .actions.add(copySelectedMenu);
0635:
0636: this .importFileAction = new ImportFileAction(this );
0637: this .importFileAction.setCreateMenuSeparator(true);
0638: this .actions.add(this .importFileAction);
0639:
0640: this .importClipAction = new ImportClipboardAction(this );
0641: this .actions.add(this .importClipAction);
0642:
0643: this .printDataAction = new PrintAction(null);
0644: this .printPreviewAction = new PrintPreviewAction(null);
0645:
0646: this .actions.add(this .executeAll);
0647: this .actions.add(this .executeSelected);
0648: this .actions.add(this .executeCurrent);
0649:
0650: this .spoolData = new SpoolDataAction(this , "MnuTxtSpoolSql");
0651: this .spoolData.setCreateMenuSeparator(true);
0652: this .spoolData.setEditor(this .editor);
0653: this .actions.add(this .spoolData);
0654:
0655: this .stopAction = new StopAction(this );
0656: this .stopAction.setEnabled(false);
0657: this .stopAction.setCreateMenuSeparator(false);
0658: this .actions.add(this .stopAction);
0659:
0660: this .commitAction = new CommitAction(this );
0661: this .commitAction.setCreateMenuSeparator(true);
0662: this .commitAction.setEnabled(false);
0663: this .actions.add(this .commitAction);
0664: this .rollbackAction = new RollbackAction(this );
0665: this .rollbackAction.setEnabled(false);
0666: this .actions.add(this .rollbackAction);
0667: this .toggleAutoCommit = new ToggleAutoCommitAction();
0668: this .actions.add(this .toggleAutoCommit);
0669:
0670: this .actions.add(this .sqlHistory.getShowFirstStatementAction());
0671: this .actions.add(this .sqlHistory
0672: .getShowPreviousStatementAction());
0673: this .actions.add(this .sqlHistory.getShowNextStatementAction());
0674: this .actions.add(this .sqlHistory.getShowLastStatementAction());
0675: this .actions.add(this .sqlHistory.getClearHistoryAction());
0676:
0677: this .actions.add(new AutoJumpNextStatement());
0678: this .appendResultsAction = new AppendResultsAction(this );
0679: this .appendResultsAction.setEnabled(false);
0680: this .actions.add(appendResultsAction);
0681: a = new HighlightCurrentStatement();
0682: a.setCreateMenuSeparator(false);
0683: this .actions.add(a);
0684: this .checkPreparedAction = new CheckPreparedStatementsAction();
0685: this .actions.add(this .checkPreparedAction);
0686: IgnoreErrorsAction ignore = new IgnoreErrorsAction();
0687: this .actions.add(ignore);
0688: this .executeAll.setEnabled(false);
0689: this .executeSelected.setEnabled(false);
0690:
0691: this .toolbarActions.add(this .executeSelected);
0692: this .toolbarActions.add(this .executeCurrent);
0693:
0694: this .stopAction.setCreateToolbarSeparator(true);
0695: this .toolbarActions.add(this .stopAction);
0696: this .toolbarActions.add(this .sqlHistory
0697: .getShowFirstStatementAction());
0698: this .toolbarActions.add(this .sqlHistory
0699: .getShowPreviousStatementAction());
0700: this .toolbarActions.add(this .sqlHistory
0701: .getShowNextStatementAction());
0702: this .toolbarActions.add(this .sqlHistory
0703: .getShowLastStatementAction());
0704:
0705: this .toolbarActions.add(this .updateAction);
0706: this .toolbarActions.add(this .insertRow);
0707: this .toolbarActions.add(this .duplicateRow);
0708: this .toolbarActions.add(this .deleteRow);
0709:
0710: this .filterAction = new FilterDataAction(null);
0711: this .selectionFilterAction = new SelectionFilterAction();
0712: this .filterPicker = new FilterPickerAction(null);
0713:
0714: filterAction.setCreateToolbarSeparator(true);
0715: filterAction.setCreateMenuSeparator(true);
0716: this .selectionFilterAction.setCreateToolbarSeparator(true);
0717: this .toolbarActions.add(selectionFilterAction);
0718: this .toolbarActions.add(filterAction);
0719: this .toolbarActions.add(filterPicker);
0720: this .resetFilterAction = new ResetFilterAction(null);
0721: this .resetFilterAction.setCreateToolbarSeparator(true);
0722: this .toolbarActions.add(this .resetFilterAction);
0723:
0724: this .commitAction.setCreateToolbarSeparator(true);
0725: this .toolbarActions.add(this .commitAction);
0726: this .toolbarActions.add(this .rollbackAction);
0727: ignore.setCreateToolbarSeparator(true);
0728: this .toolbarActions.add(ignore);
0729: appendResultsAction.setCreateToolbarSeparator(true);
0730: this .toolbarActions.add(appendResultsAction);
0731: this .findDataAction = new FindDataAction(null);
0732: this .findDataAction.setMenuTextByKey("MnuTxtFindData");
0733: this .findDataAction.setEnabled(false);
0734: this .findDataAction.setCreateMenuSeparator(true);
0735: this .findDataAgainAction = new FindDataAgainAction(null);
0736: this .findDataAgainAction
0737: .setMenuTextByKey("MnuTxtFindDataAgain");
0738: this .findDataAgainAction.setEnabled(false);
0739: this .replaceDataAction = new ReplaceDataAction(null);
0740: this .replaceDataAction.setEnabled(false);
0741:
0742: this .autoCompletion = new AutoCompletionAction(this .editor,
0743: this .statusBar);
0744: this .autoCompletion.setCreateMenuSeparator(true);
0745: this .actions.add(this .autoCompletion);
0746: this .clearCompletionCache = new ClearCompletionCacheAction();
0747: this .actions.add(this .clearCompletionCache);
0748:
0749: this .formatSql = this .editor.getFormatSqlAction();
0750: this .formatSql.setCreateMenuSeparator(true);
0751: this .actions.add(this .formatSql);
0752:
0753: a = new CreateSnippetAction(this .editor);
0754: this .actions.add(a);
0755: a = new CleanJavaCodeAction(this .editor);
0756: this .actions.add(a);
0757:
0758: a = new MakeInListAction(this .editor);
0759: a.setCreateMenuSeparator(true);
0760: this .actions.add(a);
0761: this .actions.add(new MakeNonCharInListAction(this .editor));
0762:
0763: this .findDataAction.setCreateMenuSeparator(true);
0764: this .resetHighlightAction = new ResetHighlightAction(null);
0765:
0766: this .actions.add(this .findDataAction);
0767: this .actions.add(this .findDataAgainAction);
0768: this .actions.add(this .replaceDataAction);
0769: this .actions.add(this .resetHighlightAction);
0770: this .actions.add(filterAction);
0771: this .actions.add(selectionFilterAction);
0772: this .actions.add(this .resetFilterAction);
0773: CloseResultTabAction closeResult = new CloseResultTabAction(
0774: this );
0775: closeResult.setCreateMenuSeparator(true);
0776: this .actions.add(closeResult);
0777:
0778: this .printDataAction.setCreateMenuSeparator(true);
0779: this .actions.add(this .printDataAction);
0780: this .actions.add(this .printPreviewAction);
0781:
0782: this .setExecuteActionStates(false);
0783: }
0784:
0785: public void setVisible(boolean flag) {
0786: super .setVisible(flag);
0787: if (!flag) {
0788: this .autoCompletion.closePopup();
0789: }
0790: }
0791:
0792: private void setupActionMap() {
0793: InputMap im = new ComponentInputMap(this );
0794: ActionMap am = new ActionMap();
0795: //this.setInputMap(WHEN_IN_FOCUSED_WINDOW, im);
0796: this .setInputMap(WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, im);
0797: this .setActionMap(am);
0798:
0799: Iterator itr = this .actions.iterator();
0800: while (itr.hasNext()) {
0801: Object entry = itr.next();
0802: if (entry instanceof WbAction) {
0803: WbAction wb = (WbAction) entry;
0804: wb.addToInputMap(im, am);
0805: }
0806: }
0807: editor.getInputMap().setParent(im);
0808: editor.getActionMap().setParent(am);
0809: }
0810:
0811: private Runnable selector = new Runnable() {
0812: public void run() {
0813: _selectEditor();
0814: }
0815: };
0816:
0817: public void selectEditorLater() {
0818: EventQueue.invokeLater(selector);
0819: }
0820:
0821: public void selectEditor() {
0822: WbSwingUtilities.invoke(selector);
0823: }
0824:
0825: protected void _selectEditor() {
0826: // make sure the panel and its window are really visible
0827: // before putting the focus to the editor
0828: // otherwise requestFocusInWindow() would bring the window to
0829: // front, which we do not want
0830: Window w = SwingUtilities.getWindowAncestor(this );
0831: if (w == null)
0832: return;
0833:
0834: if (w.isActive() && w.isVisible() && w.isFocused()
0835: && this .isCurrentTab() && editor != null) {
0836: editor.requestFocusInWindow();
0837: }
0838: }
0839:
0840: public void reformatSql() {
0841: this .storeStatementInHistory();
0842: this .editor.reformatSql();
0843: this .selectEditorLater();
0844: }
0845:
0846: private boolean isCurrentTab() {
0847: JTabbedPane parentTab = null;
0848: Component p = this .getParent();
0849: if (p instanceof JTabbedPane) {
0850: parentTab = (JTabbedPane) p;
0851: }
0852: if (parentTab == null)
0853: return false;
0854:
0855: return (parentTab.getSelectedComponent() == this );
0856: }
0857:
0858: public void selectResult() {
0859: if (this .isVisible() && this .isCurrentTab()
0860: && currentData != null) {
0861: showResultPanel();
0862: currentData.getTable().requestFocusInWindow();
0863: }
0864: }
0865:
0866: public void saveChangesToDatabase() {
0867: if (this .currentData == null) {
0868: Exception e = new IllegalStateException("No data panel!");
0869: LogMgr.logError("SqlPanel.saveChangesToDatabase()",
0870: "Save called without a current DwPanel!", e);
0871: return;
0872: }
0873:
0874: if (!this .currentData.prepareDatabaseUpdate())
0875: return;
0876:
0877: this .setBusy(true);
0878: this .setCancelState(true);
0879: this .setExecuteActionStates(false);
0880:
0881: Thread t = new WbThread("Workbench DB Update Thread") {
0882: public void run() {
0883: updateDb();
0884: }
0885: };
0886: t.start();
0887: }
0888:
0889: public void updateDb() {
0890: try {
0891: fireDbExecStart();
0892: this .updateRunning = true;
0893: setLogText(ResourceMgr.getString("MsgUpdatingDatabase")
0894: + "\n");
0895: this .currentData.saveChanges(this .dbConnection, this );
0896: } catch (OutOfMemoryError mem) {
0897: setLogText(ExceptionUtil.getDisplay(mem));
0898: showBusyIcon(false);
0899: EventQueue.invokeLater(new Runnable() {
0900: public void run() {
0901: WbSwingUtilities.showErrorMessage(SqlPanel.this ,
0902: ResourceMgr
0903: .getString("MsgOutOfMemoryError"));
0904: }
0905: });
0906: } catch (Exception e) {
0907: LogMgr.logError("SqlPanel.updatedb()",
0908: "Error during update", e);
0909: } finally {
0910: this .updateRunning = false;
0911: this .setCancelState(false);
0912: this .setBusy(false);
0913: fireDbExecEnd();
0914: WbSwingUtilities.showDefaultCursor(this );
0915: }
0916: appendToLog(this .currentData.getLastMessage());
0917: this .checkResultSetActions();
0918: }
0919:
0920: public void panelSelected() {
0921: selectEditorLater();
0922: }
0923:
0924: public List getActions() {
0925: return this .actions;
0926: }
0927:
0928: public void makeReadOnly() {
0929: if (this .currentData == null)
0930: return;
0931: this .currentData.endEdit();
0932: }
0933:
0934: /**
0935: * Show a message in the log panel. This will also switch
0936: * the display to the log panel (away from the result panel)
0937: */
0938: public void showLogMessage(String aMsg) {
0939: this .showLogPanel();
0940: setLogText(aMsg);
0941: }
0942:
0943: /**
0944: * Clear the message log, but do not switch the panel display to it.
0945: */
0946: public void clearLog() {
0947: setLogText("");
0948: }
0949:
0950: protected void setLogText(final String msg) {
0951: WbSwingUtilities.invoke(new Runnable() {
0952: public void run() {
0953: log.setText(msg);
0954: }
0955: });
0956: }
0957:
0958: /**
0959: * Show the panel with the log messages.
0960: */
0961: public void showLogPanel() {
0962: WbSwingUtilities.invoke(new Runnable() {
0963: public void run() {
0964: int index = resultTab.getTabCount() - 1;
0965: resultTab.setSelectedIndex(index);
0966: }
0967: });
0968: }
0969:
0970: public void showResultPanel() {
0971: showResultPanel(0);
0972: }
0973:
0974: /**
0975: * Show the panel with the result set
0976: */
0977: public void showResultPanel(final int index) {
0978: WbSwingUtilities.invoke(new Runnable() {
0979: public void run() {
0980: resultTab.setSelectedIndex(index);
0981: }
0982: });
0983: }
0984:
0985: /**
0986: * Display a message in the status bar of the DwPanel.
0987: */
0988: public void showStatusMessage(String aMsg) {
0989: this .statusBar.setStatusMessage(aMsg);
0990: this .statusBar.forcePaint();
0991: }
0992:
0993: /**
0994: * Clear the message in the status bar of the DwPanel
0995: */
0996: public void clearStatusMessage() {
0997: this .statusBar.clearStatusMessage();
0998: }
0999:
1000: public void initStatementHistory() {
1001: int size = Settings.getInstance().getMaxHistorySize();
1002: this .sqlHistory = new SqlHistory(editor, size);
1003: }
1004:
1005: public void readFromWorkspace(WbWorkspace w, int index)
1006: throws IOException {
1007: if (this .hasFileLoaded()) {
1008: this .closeFile(true, false);
1009: } else {
1010: this .editor.setText("");
1011: }
1012:
1013: //this.reset();
1014:
1015: try {
1016: w.readHistoryData(index, this .sqlHistory);
1017: } catch (Exception e) {
1018: LogMgr.logWarning("SqlPanel.readFromWorkspace()",
1019: "Could not read history data for index=" + index);
1020: this .clearSqlHistory(false);
1021: }
1022:
1023: String filename = w.getExternalFileName(index);
1024: this .tabName = w.getTabTitle(index);
1025: if (this .tabName != null && this .tabName.length() == 0) {
1026: this .tabName = null;
1027: }
1028:
1029: int v = w.getMaxRows(index);
1030: this .statusBar.setMaxRows(v);
1031: v = w.getQueryTimeout(index);
1032: this .statusBar.setQueryTimeout(v);
1033:
1034: boolean fileLoaded = false;
1035: if (filename != null) {
1036: String encoding = w.getExternalFileEncoding(index);
1037: fileLoaded = this .readFile(filename, encoding);
1038: }
1039:
1040: if (!fileLoaded) {
1041: try {
1042: this .sqlHistory.showCurrent();
1043: } catch (Exception e) {
1044: e.printStackTrace();
1045: }
1046: } else {
1047: int cursorPos = w.getExternalFileCursorPos(index);
1048: if (cursorPos > -1
1049: && cursorPos < this .editor.getText().length())
1050: this .editor.setCaretPosition(cursorPos);
1051: }
1052:
1053: WbProperties props = w.getSettings();
1054:
1055: int loc = props.getIntProperty("tab" + (index)
1056: + ".divider.location", 200);
1057: this .contentPanel.setDividerLocation(loc);
1058: loc = props.getIntProperty("tab" + (index)
1059: + ".divider.lastlocation", 0);
1060: if (loc > 0)
1061: this .contentPanel.setLastDividerLocation(loc);
1062:
1063: this .appendResults = props.getBoolProperty("tab" + (index)
1064: + ".append.results", false);
1065: if (this .appendResultsAction != null)
1066: this .appendResultsAction.setSwitchedOn(this .appendResults);
1067: this .updateTabTitle();
1068: this .editor.clearUndoBuffer();
1069: this .editor.resetModified();
1070: }
1071:
1072: /** Do any work which should be done during the process of saving the
1073: * current workspace, but before the workspace file is actually opened!
1074: * This is to prevent a corrupted workspace due to interrupting the saving
1075: * because of the check for unsaved changes in the current editor file
1076: */
1077: public boolean canCloseTab() {
1078: return this .checkAndSaveFile();
1079: }
1080:
1081: public void saveToWorkspace(WbWorkspace w, int index)
1082: throws IOException {
1083: this .saveHistory(w);
1084: Properties props = w.getSettings();
1085:
1086: int location = this .contentPanel.getDividerLocation();
1087: int last = this .contentPanel.getLastDividerLocation();
1088: props.setProperty("tab" + (index) + ".divider.location",
1089: Integer.toString(location));
1090: props.setProperty("tab" + (index) + ".divider.lastlocation",
1091: Integer.toString(last));
1092: props.setProperty("tab" + (index) + ".append.results", Boolean
1093: .toString(this .appendResults));
1094:
1095: w.setMaxRows(index, this .statusBar.getMaxRows());
1096: w.setQueryTimeout(index, this .statusBar.getQueryTimeout());
1097: if (this .hasFileLoaded()) {
1098: w.setExternalFileName(index, this .getCurrentFileName());
1099: w.setExternalFileCursorPos(index, this .editor
1100: .getCaretPosition());
1101: w.setExternalFileEncoding(index, this .editor
1102: .getCurrentFileEncoding());
1103: }
1104: if (this .tabName != null) {
1105: w.setTabTitle(index, this .tabName);
1106: }
1107: }
1108:
1109: public void saveHistory(WbWorkspace w) throws IOException {
1110: this .storeStatementInHistory();
1111: w.addHistoryEntry("WbStatements" + this .internalId + ".txt",
1112: this .sqlHistory);
1113: }
1114:
1115: /**
1116: * Implementation of the ResultReceiver interface
1117: */
1118: public String getTitle() {
1119: return getTabTitle();
1120: }
1121:
1122: public String getTabTitle() {
1123: String defaultLabel = ResourceMgr.getDefaultTabLabel();
1124:
1125: String fname = this .getCurrentFileName();
1126: if (fname != null) {
1127: File f = new File(fname);
1128: String tName = getTabName();
1129: if (tName == null || tName.startsWith(defaultLabel)) {
1130: fname = f.getName();
1131: } else {
1132: fname = "[" + tName + "]";
1133: }
1134: } else {
1135: fname = this .getTabName();
1136: }
1137: if (fname == null)
1138: fname = defaultLabel;
1139: return fname;
1140: }
1141:
1142: private void updateTabTitle() {
1143: Container parent = this .getParent();
1144: if (parent instanceof JTabbedPane) {
1145: JTabbedPane tab = (JTabbedPane) parent;
1146: int index = tab.indexOfComponent(this );
1147: setTabTitle(tab, index);
1148: }
1149: }
1150:
1151: public void setTabTitle(JTabbedPane tab, int index) {
1152: String fname = null;
1153: String tooltip = null;
1154: this .setId(index + 1);
1155:
1156: fname = this .getCurrentFileName();
1157: if (fname != null) {
1158: File f = new File(fname);
1159: tooltip = f.getAbsolutePath();
1160: this .showIconForTab(getFileIcon());
1161: } else {
1162: this .removeIconFromTab();
1163: }
1164:
1165: String tabTitle = getTabTitle();
1166: String title = tabTitle + " " + Integer.toString(index + 1);
1167: tab.setTitleAt(index, title);
1168: if (index < 9) {
1169: char c = Integer.toString(index + 1).charAt(0);
1170: int pos = tabTitle.length() + 1;
1171: tab.setMnemonicAt(index, c);
1172: // The Mnemonic index has to be set explicitely otherwise
1173: // the display would be wrong if the tab title contains
1174: // the mnemonic character
1175: tab.setDisplayedMnemonicIndexAt(index, pos);
1176: }
1177: tab.setToolTipTextAt(index, tooltip);
1178: }
1179:
1180: public String getTabName() {
1181: return this .tabName;
1182: }
1183:
1184: public void setTabName(String aName) {
1185: if (StringUtil.isEmptyString(aName))
1186: this .tabName = null;
1187: else
1188: this .tabName = aName;
1189: this .fireFilenameChanged(aName);
1190: }
1191:
1192: public String getCurrentFileName() {
1193: if (this .editor == null)
1194: return null;
1195: return this .editor.getCurrentFileName();
1196: }
1197:
1198: public void appendStatementText(String text) {
1199: this .editor.appendLine("\n\n");
1200: int pos = this .editor.getText().length();
1201: this .editor.appendLine(text);
1202: this .editor.setCaretPosition(pos);
1203: this .editor.scrollToCaret();
1204: }
1205:
1206: public void setStatementText(String aStatement) {
1207: this .storeStatementInHistory();
1208: if (this .editor.getCurrentFile() != null)
1209: this .editor.saveCurrentFile();
1210: this .editor.closeFile(true);
1211: this .editor.setText(aStatement);
1212: }
1213:
1214: public void disconnect() {
1215: synchronized (this ) {
1216: if (this .dbConnection != null) {
1217: this .setConnection(null);
1218: }
1219: this .clearResultTabs();
1220: this .makeReadOnly();
1221: setLogText("");
1222: }
1223: }
1224:
1225: public WbConnection getConnection() {
1226: synchronized (this .connectionLock) {
1227: return this .dbConnection;
1228: }
1229: }
1230:
1231: public boolean isConnected() {
1232: // I'm only checking if the connection is defined, because
1233: // MainWindow will make sure a valid connection is set
1234: // for the panel. When using only one connection for all
1235: // panels, isClosed() will block the entire AWT thread!
1236: synchronized (this .connectionLock) {
1237: return (this .dbConnection != null);
1238: }
1239: }
1240:
1241: public void setConnection(WbConnection aConnection) {
1242: synchronized (this .connectionLock) {
1243: if (this .dbConnection != null) {
1244: this .dbConnection.removeChangeListener(this );
1245: }
1246:
1247: this .dbConnection = aConnection;
1248: }
1249:
1250: this .toggleAutoCommit.setConnection(this .dbConnection);
1251:
1252: if (this .clearCompletionCache != null)
1253: this .clearCompletionCache.setConnection(this .dbConnection);
1254: if (this .autoCompletion != null)
1255: this .autoCompletion.setConnection(this .dbConnection);
1256:
1257: if (this .stmtRunner == null) {
1258: this .stmtRunner = StatementRunner.Factory.createRunner();
1259: this .stmtRunner.setRowMonitor(this .rowMonitor);
1260: }
1261:
1262: if (this .stmtRunner != null) {
1263: this .stmtRunner.setConnection(aConnection);
1264: this .stmtRunner.setConnectionClient(connectionClient);
1265: this .stmtRunner.setResultLogger(this );
1266: }
1267:
1268: if (this .connectionInfo != null)
1269: this .connectionInfo.setConnection(aConnection);
1270: this .setExecuteActionStates(aConnection != null);
1271:
1272: if (this .editor != null)
1273: this .editor.setDatabaseConnection(this .dbConnection);
1274:
1275: if (this .dbConnection != null) {
1276: this .dbConnection.addChangeListener(this );
1277: }
1278:
1279: this .checkResultSetActions();
1280: this .checkCommitAction();
1281: }
1282:
1283: /**
1284: * Check the autoCommit property of the current connection
1285: * and enable/disable the rollback and commit actions
1286: * accordingly
1287: */
1288: protected void checkCommitAction() {
1289: EventQueue.invokeLater(new Runnable() {
1290: public void run() {
1291: if (dbConnection != null) {
1292: // if autocommit is enabled, then rollback and commit will
1293: // be disabled
1294: boolean flag = dbConnection.getAutoCommit();
1295: commitAction.setEnabled(!flag);
1296: rollbackAction.setEnabled(!flag);
1297: } else {
1298: commitAction.setEnabled(false);
1299: rollbackAction.setEnabled(false);
1300: }
1301: }
1302: });
1303: }
1304:
1305: public boolean isRequestFocusEnabled() {
1306: return true;
1307: }
1308:
1309: public void storeStatementInHistory() {
1310: this .sqlHistory.addContent(editor);
1311: }
1312:
1313: public void cancelUpdate() {
1314: if (this .currentData == null)
1315: return;
1316:
1317: WbTable table = this .currentData.getTable();
1318: if (table != null) {
1319: DataStoreTableModel model = (DataStoreTableModel) table
1320: .getModel();
1321: if (model == null)
1322: return;
1323: DataStore ds = table.getDataStore();
1324: if (ds == null)
1325: return;
1326: ds.cancelUpdate();
1327:
1328: if (!this .dbConnection.getAutoCommit()) {
1329: String msg = ResourceMgr
1330: .getString("MsgCommitPartialUpdate");
1331: int commit = WbSwingUtilities
1332: .getCommitRollbackQuestion(this , msg);
1333: {
1334: try {
1335: if (commit == WbSwingUtilities.DO_COMMIT) {
1336: this .dbConnection.commit();
1337: ds.resetStatusForSentRows();
1338: } else {
1339: this .dbConnection.rollback();
1340: ds.resetDmlSentStatus();
1341: }
1342:
1343: } catch (SQLException e) {
1344: LogMgr.logError("SqlPanel.cancelExecution()",
1345: "Commit failed!", e);
1346: msg = e.getMessage();
1347: WbSwingUtilities.showErrorMessage(this , msg);
1348: }
1349: }
1350: this .currentData.rowCountChanged();
1351: WbSwingUtilities.repaintLater(this );
1352: } else {
1353: ds.resetStatusForSentRows();
1354: }
1355: }
1356: this .setCancelState(false);
1357: }
1358:
1359: public void forceAbort() {
1360: if (!this .isBusy())
1361: return;
1362: if (this .executionThread == null)
1363: return;
1364: try {
1365: this .cancelExecution = true;
1366: this .executionThread.interrupt();
1367: this .executionThread = null;
1368: } catch (Exception e) {
1369: LogMgr.logWarning("SqlPanel.forceAbort()",
1370: "Error when trying to kill background thread", e);
1371: } finally {
1372: this .setBusy(false);
1373: }
1374: }
1375:
1376: public boolean abortExecution() {
1377: if (!this .isBusy())
1378: return true;
1379: if (this .executionThread == null)
1380: return true;
1381:
1382: boolean success = false;
1383: int wait = Settings.getInstance().getIntProperty(
1384: this .getClass().getName() + ".abortwait", 1);
1385: try {
1386: LogMgr.logDebug("SqlPanel.abortExecution()",
1387: "Interrupting SQL Thread...");
1388: this .executionThread.interrupt();
1389: this .executionThread.join(wait * 1000);
1390: if (this .isBusy()) {
1391: LogMgr
1392: .logDebug("SqlPanel.abortExecution()",
1393: "SQL Thread still running after "
1394: + wait + "s!");
1395: } else {
1396: success = true;
1397: }
1398: } catch (Exception e) {
1399: LogMgr.logError("SqlPanel.abortExecution()",
1400: "Error when interrupting SQL thread", e);
1401: }
1402: return success;
1403: }
1404:
1405: public boolean confirmCancel() {
1406: return true;
1407: }
1408:
1409: /**
1410: * Implementation of the Interruptable Interface.
1411: */
1412: public void cancelExecution() {
1413: if (!this .isBusy())
1414: return;
1415:
1416: this .showStatusMessage(ResourceMgr
1417: .getString("MsgCancellingStmt")
1418: + "\n");
1419: try {
1420: if (this .worker != null) {
1421: this .worker.cancelExecution();
1422: } else if (this .updateRunning) {
1423: this .cancelUpdate();
1424: } else {
1425: WbThread t = new WbThread("Cancel Thread") {
1426: public void run() {
1427: cancelRetrieve();
1428: }
1429: };
1430: t.start();
1431: }
1432: } catch (Throwable th) {
1433: LogMgr.logError("SqlPanel.cancelExecution()",
1434: "Error cancelling execution", th);
1435: }
1436: }
1437:
1438: protected void cancelRetrieve() {
1439: this .showCancelIcon();
1440: this .cancelExecution = true;
1441: this .setCancelState(false);
1442: this .stmtRunner.cancel();
1443: }
1444:
1445: public void setCancelState(final boolean aFlag) {
1446: //this.stopAction.setEnabled(aFlag);
1447: setActionState(stopAction, aFlag);
1448: }
1449:
1450: /**
1451: * Modify the enabled state of the given action.
1452: */
1453: public void setActionState(final Action anAction,
1454: final boolean aFlag) {
1455: setActionState(new Action[] { anAction }, aFlag);
1456: }
1457:
1458: public void setActionState(final Action[] anActionList,
1459: final boolean aFlag) {
1460: WbSwingUtilities.invoke(new Runnable() {
1461: public void run() {
1462: for (int i = 0; i < anActionList.length; i++) {
1463: anActionList[i].setEnabled(aFlag);
1464: }
1465: }
1466: });
1467: }
1468:
1469: private String getStatementAtCursor() {
1470: ScriptParser parser = createScriptParser();
1471: parser.setScript(this .editor.getText());
1472: int index = parser.getCommandIndexAtCursorPos(this .editor
1473: .getCaretPosition());
1474: String currentStatement = parser.getCommand(index);
1475: return currentStatement;
1476: }
1477:
1478: public void runCurrentStatement() {
1479: String sql = this .editor.getText();
1480: int caret = this .editor.getCaretPosition();
1481: startExecution(sql, 0, caret, true, this .appendResults);
1482: }
1483:
1484: public void runSelectedStatement() {
1485: String sql = this .editor.getSelectedStatement();
1486: int offset = 0;
1487: boolean highlight = true;
1488: if (this .editor.isTextSelected()) {
1489: offset = this .editor.getSelectionStart();
1490: highlight = false;
1491: }
1492: this .startExecution(sql, offset, -1, highlight,
1493: this .appendResults);
1494: }
1495:
1496: public void commit() {
1497: this .startExecution(SingleVerbCommand.COMMIT.getVerb(), 0, -1,
1498: false, this .appendResults);
1499: }
1500:
1501: public void rollback() {
1502: this .startExecution(SingleVerbCommand.ROLLBACK.getVerb(), 0,
1503: -1, false, this .appendResults);
1504: }
1505:
1506: public void runAll() {
1507: String sql = this .editor.getText();
1508: this .startExecution(sql, 0, -1, true, this .appendResults);
1509: }
1510:
1511: private void startExecution(final String sql, final int offset,
1512: final int commandAtIndex, final boolean highlight,
1513: final boolean appendResult) {
1514: if (this .isBusy()) {
1515: return;
1516: }
1517:
1518: if (!this .isConnected()) {
1519: LogMgr
1520: .logError(
1521: "SqlPanel.startExecution()",
1522: "startExecution() was called but no connection available!",
1523: null);
1524: return;
1525: }
1526:
1527: if (this .dbConnection.isBusy()) {
1528: showLogMessage(ResourceMgr.getString("ErrConnectionBusy"));
1529: return;
1530: }
1531:
1532: this .executionThread = new WbThread("SQL Execution Thread "
1533: + this .getId()) {
1534: public void run() {
1535: runStatement(sql, offset, commandAtIndex, highlight,
1536: appendResult);
1537: }
1538: };
1539: this .executionThread.start();
1540: }
1541:
1542: /**
1543: * Execute the given SQL string. This is invoked from the the run() and other
1544: * methods in order to execute the SQL command. It takes care of updating the
1545: * actions and the menu.
1546: * The actual execution and display of the result is handled by displayResult()
1547: *
1548: * This is only public to allow a direct call during
1549: * GUI testing (to avoid multi-threading)
1550: */
1551: public void runStatement(String sql, int selectionOffset,
1552: int commandAtIndex, boolean highlightOnError,
1553: boolean appendResult) {
1554: this
1555: .showStatusMessage(ResourceMgr
1556: .getString("MsgExecutingSql"));
1557:
1558: this .storeStatementInHistory();
1559: cancelExecution = false;
1560: setBusy(true);
1561:
1562: // the dbStart should be fired *after* updating the
1563: // history, as the history might be saved ("AutoSaveHistory") if the MainWindow
1564: // receives the execStart event
1565: fireDbExecStart();
1566:
1567: setCancelState(true);
1568: makeReadOnly();
1569:
1570: try {
1571: this .displayResult(sql, selectionOffset, commandAtIndex,
1572: highlightOnError, appendResult);
1573: } finally {
1574: clearStatusMessage();
1575: setCancelState(false);
1576: updateResultInfos();
1577: this .fireDbExecEnd();
1578:
1579: // setBusy(false) should be called after dbExecEnd()
1580: // otherwise the panel would indicate it's not busy, but
1581: // the connection would still be marked as busy
1582: this .setBusy(false);
1583: this .selectEditorLater();
1584: this .executionThread = null;
1585: }
1586: }
1587:
1588: private boolean macroExecution = false;
1589:
1590: public void executeMacro(final String macroName,
1591: final boolean replaceText) {
1592: if (isBusy())
1593: return;
1594:
1595: MacroManager mgr = MacroManager.getInstance();
1596: String sql = mgr.getMacroText(macroName);
1597: if (sql == null || sql.trim().length() == 0)
1598: return;
1599:
1600: if (mgr.hasSelectedKey(sql)) {
1601: String selected = this .editor.getSelectedText();
1602: if (selected == null) {
1603: WbSwingUtilities.showErrorMessage(this , ResourceMgr
1604: .getString("ErrNoSelection4Macro"));
1605: return;
1606: }
1607: sql = mgr.replaceSelected(sql, selected);
1608: }
1609:
1610: if (mgr.hasCurrentKey(sql)) {
1611: String current = getStatementAtCursor();
1612: if (current == null) {
1613: WbSwingUtilities.showErrorMessage(this , ResourceMgr
1614: .getString("ErrNoCurrent4Macro"));
1615: return;
1616: }
1617: sql = mgr.replaceCurrent(sql, current);
1618: }
1619:
1620: if (mgr.hasTextKey(sql)) {
1621: sql = mgr.replaceEditorText(sql, editor.getText());
1622: }
1623:
1624: if (replaceText) {
1625: this .storeStatementInHistory();
1626: this .editor.setText(sql);
1627: this .macroExecution = false;
1628: } else {
1629: this .macroExecution = true;
1630: }
1631: this .startExecution(sql, 0, -1, false, this .appendResults);
1632: }
1633:
1634: public void exportData() {
1635: final String sql = SqlUtil.makeCleanSql(this .editor
1636: .getSelectedStatement(), false);
1637:
1638: this .cancelExecution = false;
1639:
1640: final DataExporter exporter = new DataExporter(
1641: this .dbConnection);
1642: exporter.setRowMonitor(this .rowMonitor);
1643: exporter.setSql(sql);
1644: this .worker = exporter;
1645:
1646: boolean selected = exporter.selectOutput(getParentWindow());
1647: if (selected) {
1648: String msg = ResourceMgr.getString("MsgQueryExportInit");
1649: msg = StringUtil.replace(msg, "%type%", exporter
1650: .getTypeDisplay());
1651: msg = StringUtil.replace(msg, "%sql%", StringUtil
1652: .getMaxSubstring(sql, 100));
1653: showLogMessage(msg);
1654:
1655: this .executionThread = new WbThread("ExportSQL") {
1656: public void run() {
1657: setBusy(true);
1658: setCancelState(true);
1659: fireDbExecStart();
1660: try {
1661: boolean newLineAppended = false;
1662: StringBuilder messages = new StringBuilder();
1663: long start = System.currentTimeMillis();
1664: long rowCount = exporter.startExport();
1665: long execTime = (System.currentTimeMillis() - start);
1666: CharSequence errors = exporter.getErrors();
1667: if (errors.length() > 0) {
1668: messages.append('\n');
1669: newLineAppended = true;
1670: messages.append(errors);
1671: messages.append('\n');
1672: }
1673:
1674: CharSequence warnings = exporter.getWarnings();
1675: if (warnings.length() > 0) {
1676: if (!newLineAppended)
1677: messages.append('\n');
1678: messages.append(warnings);
1679: messages.append('\n');
1680: }
1681: if (exporter.isSuccess()) {
1682: String msg2 = ResourceMgr.getString(
1683: "MsgSpoolOk").replaceAll("%rows%",
1684: Long.toString(rowCount));
1685: messages.append("\n");
1686: messages.append(msg2);
1687: messages.append("\n");
1688: msg2 = ResourceMgr
1689: .getString("MsgSpoolTarget")
1690: + " "
1691: + exporter.getFullOutputFilename();
1692: messages.append(msg2);
1693: messages.append("\n\n");
1694: }
1695: messages.append(ResourceMgr
1696: .getString("MsgExecTime")
1697: + " "
1698: + (((double) execTime) / 1000.0)
1699: + "s\n");
1700: appendToLog(messages.toString());
1701: showLogPanel();
1702: } catch (Exception e) {
1703: LogMgr.logError("SqlPanel.spoolData()",
1704: "Error exporting data", e);
1705: } finally {
1706: setBusy(false);
1707: fireDbExecEnd();
1708: clearStatusMessage();
1709: setCancelState(false);
1710: executionThread = null;
1711: worker = null;
1712: }
1713: }
1714: };
1715: this .executionThread.start();
1716: }
1717: }
1718:
1719: public void fatalError(String msg) {
1720: WbSwingUtilities.showErrorMessage(this , msg);
1721: }
1722:
1723: public int getActionOnError(int errorRow, String errorColumn,
1724: String dataLine, String errorMessage) {
1725: if (this .importRunning) {
1726: return this .getImportErrorAction(errorRow, errorColumn,
1727: dataLine, errorMessage);
1728: } else if (this .updateRunning) {
1729: return this .getUpdateErrorAction(errorRow, errorColumn,
1730: dataLine, errorMessage);
1731: }
1732: return JobErrorHandler.JOB_ABORT;
1733: }
1734:
1735: /**
1736: * We are implementing our own getUpdateErrorAction() (and not using the one from
1737: * DwPanel) because it's necessary to turn off the loading indicator before displaying a message box.
1738: *
1739: * DwPanel's getUpdateErrorAction is called from here after turning off the loading indicator.
1740: */
1741: public int getUpdateErrorAction(int errorRow, String errorColumn,
1742: String dataLine, String errorMessage) {
1743: this .showBusyIcon(false);
1744: int choice = this .currentData.getActionOnError(errorRow,
1745: errorColumn, dataLine, errorMessage);
1746: this .showBusyIcon(true);
1747: return choice;
1748: }
1749:
1750: public int getImportErrorAction(int errorRow, String errorColumn,
1751: String dataLine, String errorMessage) {
1752: String msg = null;
1753: if (errorColumn != null) {
1754: msg = ResourceMgr.getString("ErrColumnImportError");
1755: msg = msg.replaceAll("%row%", NumberStringCache
1756: .getNumberString(errorRow));
1757: msg = msg.replaceAll("%column%", errorColumn);
1758: msg = msg.replaceAll("%data%", dataLine);
1759: } else {
1760: msg = ResourceMgr.getString("ErrRowImportError");
1761: msg = msg.replaceAll("%row%", NumberStringCache
1762: .getNumberString(errorRow));
1763: msg = msg.replaceAll("%data%", dataLine == null ? "(null)"
1764: : dataLine.substring(0, 40) + " ...");
1765: }
1766:
1767: this .showBusyIcon(false);
1768: int choice = WbSwingUtilities.getYesNoIgnoreAll(this , msg);
1769: int result = JobErrorHandler.JOB_ABORT;
1770: this .showBusyIcon(true);
1771: if (choice == JOptionPane.YES_OPTION) {
1772: result = JobErrorHandler.JOB_CONTINUE;
1773: } else if (choice == WbSwingUtilities.IGNORE_ALL) {
1774: result = JobErrorHandler.JOB_IGNORE_ALL;
1775: }
1776: return result;
1777: }
1778:
1779: public void importFile() {
1780: if (this .currentData == null)
1781: return;
1782: if (!this .currentData.startEdit())
1783: return;
1784: ImportFileDialog dialog = new ImportFileDialog(this );
1785: dialog.allowImportModeSelection(false);
1786: boolean ok = dialog.selectInput(ResourceMgr
1787: .getString("TxtWindowTitleSelectImportFile"));
1788: if (!ok)
1789: return;
1790: DataStoreImporter importer = new DataStoreImporter(currentData
1791: .getTable().getDataStore(),
1792: currentData.getRowMonitor(), this );
1793: File importFile = dialog.getSelectedFile();
1794: importer.setImportOptions(importFile, dialog.getImportType(),
1795: dialog.getGeneralOptions(), dialog.getTextOptions(),
1796: dialog.getXmlOptions());
1797:
1798: Settings.getInstance().setLastImportDir(importFile.getParent());
1799: dialog.saveSettings();
1800: runImporter(importer);
1801: }
1802:
1803: public void importString(String content, boolean showOptions) {
1804: if (this .currentData == null)
1805: return;
1806: if (!this .currentData.startEdit())
1807: return;
1808:
1809: DataStore ds = currentData.getTable().getDataStore();
1810:
1811: ImportStringVerifier v = new ImportStringVerifier(content, ds
1812: .getResultInfo());
1813: DataStoreImporter importer = new DataStoreImporter(ds,
1814: currentData.getRowMonitor(), this );
1815: if (showOptions || !v.checkData()) {
1816: boolean checked = false;
1817: while (!checked) {
1818: boolean ok = v.showOptionsDialog();
1819: if (!ok)
1820: return; // user cancelled dialog
1821: checked = v.checkData();
1822: }
1823: TextImportOptions textOptions = v.getTextImportOptions();
1824: ImportOptions options = v.getImportOptions();
1825: importer.importString(content, options, textOptions);
1826: } else {
1827: importer.importString(content);
1828: }
1829: if (!this .currentData.startEdit())
1830: return;
1831:
1832: runImporter(importer);
1833: }
1834:
1835: public synchronized void runImporter(
1836: final DataStoreImporter importer) {
1837: this .setActionState(this .importFileAction, false);
1838: this .setBusy(true);
1839: this .setCancelState(true);
1840: this .worker = importer;
1841: WbThread importThread = new WbThread("DataImport") {
1842: public void run() {
1843: try {
1844: importRunning = true;
1845: fireDbExecStart();
1846: importer.startImport();
1847: } catch (Throwable e) {
1848: LogMgr.logError(
1849: "SqlPanel.importData() - worker thread",
1850: "Error when importing data", e);
1851: } finally {
1852: importRunning = false;
1853: setBusy(false);
1854: fireDbExecEnd();
1855: currentData.getTable().getDataStoreTableModel()
1856: .fileImported();
1857: currentData.rowCountChanged();
1858: currentData.clearStatusMessage();
1859: MessageBuffer buff = importer.getMessage();
1860: if (buff != null && buff.getLength() > 0) {
1861: appendToLog(buff.getBuffer().toString());
1862: }
1863: setCancelState(false);
1864: checkResultSetActions();
1865: }
1866: }
1867: };
1868: importThread.start();
1869: this .selectEditor();
1870: }
1871:
1872: public void appendToLog(final String logMessage) {
1873: WbSwingUtilities.invoke(new Runnable() {
1874: public void run() {
1875: log.append(logMessage);
1876: log.setCaretPosition(log.getDocument().getLength());
1877: }
1878: });
1879: }
1880:
1881: /** Used for storing the result of the confirmExecution() callback */
1882: private boolean executeAllStatements = true;
1883: private boolean cancelAll = false;
1884:
1885: public boolean confirmExecution(String command) {
1886: if (executeAllStatements)
1887: return true;
1888: boolean result = false;
1889: this .showBusyIcon(false);
1890: try {
1891: String msg = ResourceMgr.getString("MsgConfirmExecution")
1892: + "\n" + StringUtil.getMaxSubstring(command, 60);
1893: int choice = WbSwingUtilities.getYesNoExecuteAll(this , msg);
1894: switch (choice) {
1895: case JOptionPane.YES_OPTION:
1896: result = true;
1897: break;
1898: case JOptionPane.NO_OPTION:
1899: result = false;
1900: break;
1901: case JOptionPane.CANCEL_OPTION:
1902: result = false;
1903: this .executeAllStatements = false;
1904: this .cancelAll = true;
1905: break;
1906: case WbSwingUtilities.EXECUTE_ALL:
1907: result = true;
1908: this .executeAllStatements = true;
1909: break;
1910: default:
1911: result = false;
1912: }
1913: } finally {
1914: this .showBusyIcon(true);
1915: }
1916: return result;
1917: }
1918:
1919: private boolean ignoreStateChange = false;
1920:
1921: public void stateChanged(ChangeEvent evt) {
1922: if (this .ignoreStateChange)
1923: return;
1924: updateResultInfos();
1925: }
1926:
1927: private void updateResultInfos() {
1928: if (currentData != null) {
1929: this .currentData.removePropertyChangeListener(this );
1930: this .currentData.getTable().stopEditing();
1931: }
1932:
1933: int newIndex = this .resultTab.getSelectedIndex();
1934:
1935: if (newIndex == this .resultTab.getTabCount() - 1) {
1936: this .currentData = null;
1937: } else {
1938: this .currentData = (DwPanel) this .resultTab
1939: .getSelectedComponent();
1940: this .currentData.updateStatusBar();
1941: this .currentData.addPropertyChangeListener("updateTable",
1942: this );
1943: }
1944: updateProxiedActions();
1945: checkResultSetActions();
1946:
1947: }
1948:
1949: public void closeCurrentResult() {
1950: int index = resultTab.getSelectedIndex();
1951: if (index == resultTab.getTabCount() - 1)
1952: return;
1953:
1954: try {
1955: DwPanel panel = (DwPanel) resultTab.getComponentAt(index);
1956: panel.removePropertyChangeListener(SqlPanel.this );
1957: panel.clearContent();
1958: resultTab.removeTabAt(index);
1959: currentData = null;
1960: // if the index stayed the same (e.g. because the first tab is still selected)
1961: // no stateChange has been fired and we need to "fake" that because
1962: // several actions need to be informed that a different ResultTab is
1963: // now active
1964: if (index == resultTab.getSelectedIndex()) {
1965: EventQueue.invokeLater(new Runnable() {
1966: public void run() {
1967: resultTab.fireStateChanged();
1968: }
1969: });
1970: }
1971: } catch (Exception e) {
1972: LogMgr.logError("SqlPanel.closeCurrentResult()",
1973: "Error closing current result tab", e);
1974: }
1975:
1976: }
1977:
1978: private void clearResultTabs() {
1979: try {
1980: ignoreStateChange = true;
1981: while (resultTab.getTabCount() > 1) {
1982: Component c = resultTab.getComponentAt(0);
1983: if (c instanceof DwPanel) {
1984: DwPanel panel = (DwPanel) c;
1985: panel.removePropertyChangeListener(SqlPanel.this );
1986: panel.clearContent();
1987: }
1988: resultTab.removeTabAt(0);
1989: }
1990: resultTab.setSelectedIndex(0);
1991: currentData = null;
1992: updateProxiedActions();
1993: checkResultSetActions();
1994: } finally {
1995: ignoreStateChange = false;
1996: }
1997: }
1998:
1999: private void updateProxiedActions() {
2000: WbSwingUtilities.invoke(new Runnable() {
2001: public void run() {
2002: _updateProxiedActions();
2003: }
2004: });
2005: }
2006:
2007: private void _updateProxiedActions() {
2008: if (this .currentData == null) {
2009: this .updateAction.setOriginal(null);
2010: this .insertRow.setOriginal(null);
2011: this .deleteRow.setOriginal(null);
2012: this .deleteDependentRow.setOriginal(null);
2013: this .duplicateRow.setOriginal(null);
2014: this .selectKeys.setOriginal(null);
2015: this .createDeleteScript.setClient(null);
2016: this .exportDataAction.setOriginal(null);
2017: this .optimizeAllCol.setClient(null);
2018: this .dataToClipboard.setOriginal(null);
2019: this .copyAsSqlInsert.setOriginal(null);
2020: this .copyAsSqlUpdate.setOriginal(null);
2021: this .copyAsSqlDeleteInsert.setOriginal(null);
2022: this .findDataAction.setOriginal(null);
2023: this .findDataAgainAction.setOriginal(null);
2024: copySelectedMenu.removeAll();
2025: copySelectedMenu.setEnabled(false);
2026: this .printDataAction.setOriginal(null);
2027: this .printPreviewAction.setOriginal(null);
2028: this .filterAction.setOriginal(null);
2029: this .filterPicker.setClient(null);
2030: this .resetFilterAction.setOriginal(null);
2031: this .selectionFilterAction.setClient(null);
2032: this .resetHighlightAction.setOriginal(null);
2033: } else {
2034: this .updateAction.setOriginal(this .currentData
2035: .getUpdateDatabaseAction());
2036: this .insertRow.setOriginal(this .currentData
2037: .getInsertRowAction());
2038: this .deleteRow.setOriginal(this .currentData
2039: .getDeleteRowAction());
2040: this .deleteDependentRow.setOriginal(this .currentData
2041: .getDeleteDependentRowsAction());
2042: this .duplicateRow.setOriginal(this .currentData
2043: .getCopyRowAction());
2044: this .selectKeys.setOriginal(this .currentData
2045: .getSelectKeysAction());
2046: this .createDeleteScript.setClient(this .currentData
2047: .getTable());
2048: this .exportDataAction.setOriginal(this .currentData
2049: .getTable().getExportAction());
2050: this .optimizeAllCol.setClient(this .currentData.getTable());
2051: this .dataToClipboard.setOriginal(this .currentData
2052: .getTable().getDataToClipboardAction());
2053: this .copyAsSqlInsert.setOriginal(this .currentData
2054: .getTable().getCopyAsInsertAction());
2055: this .copyAsSqlUpdate.setOriginal(this .currentData
2056: .getTable().getCopyAsUpdateAction());
2057: this .copyAsSqlDeleteInsert.setOriginal(this .currentData
2058: .getTable().getCopyAsDeleteInsertAction());
2059: this .findDataAction.setOriginal(this .currentData.getTable()
2060: .getReplacer().getFindAction());
2061: this .findDataAgainAction.setOriginal(this .currentData
2062: .getTable().getReplacer().getFindAgainAction());
2063: this .replaceDataAction.setOriginal(this .currentData
2064: .getTable().getReplacer().getReplaceAction());
2065: copySelectedMenu.removeAll();
2066: this .currentData.getTable().populateCopySelectedMenu(
2067: copySelectedMenu);
2068: copySelectedMenu.setEnabled(true);
2069: this .printDataAction.setOriginal(this .currentData
2070: .getTable().getPrintAction());
2071: this .printPreviewAction.setOriginal(this .currentData
2072: .getTable().getPrintPreviewAction());
2073: this .filterAction.setOriginal(this .currentData.getTable()
2074: .getFilterAction());
2075: this .filterPicker.setClient(this .currentData.getTable());
2076: this .resetFilterAction.setOriginal(this .currentData
2077: .getTable().getResetFilterAction());
2078: this .selectionFilterAction.setClient(this .currentData
2079: .getTable());
2080: this .resetHighlightAction.setOriginal(this .currentData
2081: .getTable().getResetHighlightAction());
2082: }
2083: }
2084:
2085: private ScriptParser createScriptParser() {
2086: ScriptParser scriptParser = new ScriptParser();
2087: DelimiterDefinition altDelim = Settings.getInstance()
2088: .getAlternateDelimiter(this .dbConnection);
2089:
2090: scriptParser.setAlternateDelimiter(altDelim);
2091: scriptParser.setCheckEscapedQuotes(Settings.getInstance()
2092: .getCheckEscapedQuotes());
2093: DbSettings db = this .dbConnection.getDbSettings();
2094: if (db == null) {
2095: LogMgr.logError("SqlPanel.createScriptParser()",
2096: "No db settings available!", null);
2097: return scriptParser;
2098: }
2099: scriptParser.setSupportOracleInclude(db.supportShortInclude());
2100: scriptParser.setCheckForSingleLineCommands(db
2101: .supportSingleLineCommands());
2102: scriptParser.setAlternateLineComment(db.getLineComment());
2103: return scriptParser;
2104: }
2105:
2106: private VariablePrompter prompter;
2107: private boolean checkPrepared;
2108:
2109: public boolean processParameterPrompts(String sql) {
2110: boolean goOn = true;
2111:
2112: if (prompter == null)
2113: prompter = new VariablePrompter();
2114: prompter.setSql(sql);
2115: if (prompter.needsInput()) {
2116: // the animated gif needs to be turned off when a
2117: // dialog is displayed, otherwise Swing uses too much CPU
2118: this .showBusyIcon(false);
2119: goOn = prompter.getPromptValues();
2120: this .showBusyIcon(true);
2121: }
2122:
2123: if (goOn && this .checkPrepared) {
2124: PreparedStatementPool pool = this .dbConnection
2125: .getPreparedStatementPool();
2126: try {
2127: if (pool.isRegistered(sql)
2128: || pool.addPreparedStatement(sql)) {
2129: StatementParameters parms = pool.getParameters(sql);
2130: this .showBusyIcon(false);
2131: goOn = ParameterEditor.showParameterDialog(parms);
2132: this .showBusyIcon(true);
2133: }
2134: } catch (SQLException e) {
2135: this .showBusyIcon(false);
2136: String msg = ResourceMgr
2137: .getString("ErrCheckPreparedStatement");
2138: msg = StringUtil.replace(msg, "%error%", ExceptionUtil
2139: .getDisplay(e));
2140: WbSwingUtilities.showErrorMessage(this , msg);
2141: this .showBusyIcon(true);
2142:
2143: // Ignore errors in prepared statements...
2144: goOn = true;
2145:
2146: // Disable checking as the current driver does not seem to support it
2147: Settings.getInstance()
2148: .setCheckPreparedStatements(false);
2149: }
2150: }
2151: return goOn;
2152:
2153: }
2154:
2155: private void displayResult(String script, int selectionOffset,
2156: int commandAtIndex, boolean highlightOnError,
2157: boolean appendResult) {
2158: if (script == null)
2159: return;
2160:
2161: boolean logWasCompressed = false;
2162: boolean jumpToNext = (commandAtIndex > -1 && Settings
2163: .getInstance().getAutoJumpNextStatement());
2164: boolean highlightCurrent = false;
2165: boolean restoreSelection = false;
2166: boolean shouldRestoreSelection = Settings.getInstance()
2167: .getBoolProperty("workbench.gui.sql.restoreselection",
2168: true);
2169: boolean macroRun = false;
2170: String nl = Settings.getInstance()
2171: .getInternalEditorLineEnding();
2172: Pattern fixNLPattern = null;
2173: // do we need to convert the \n used in the editor
2174: // before sending the SQL to the DBMS?
2175: if (!nl.equals("\n")) {
2176: fixNLPattern = Pattern.compile("\n");
2177: }
2178:
2179: this .checkPrepared = Settings.getInstance()
2180: .getCheckPreparedStatements();
2181: this .executeAllStatements = false;
2182: this .cancelAll = false;
2183:
2184: ScriptParser scriptParser = createScriptParser();
2185:
2186: int oldSelectionStart = -1;
2187: int oldSelectionEnd = -1;
2188:
2189: if (this .dbConnection.getProfile().isConfirmUpdates()) {
2190: this .stmtRunner.setExecutionController(this );
2191: } else {
2192: this .stmtRunner.setExecutionController(null);
2193: }
2194: this .stmtRunner.setParameterPrompter(this );
2195:
2196: // If a file is loaded in the editor, make sure the StatementRunner
2197: // is using the file's directory as the base directory
2198: // Thanks to Christian d'Heureuse for this fix!
2199: if (this .editor.hasFileLoaded()) {
2200: try {
2201: File f = new File(editor.getCurrentFileName());
2202: String dir = f.getCanonicalFile().getParent();
2203: this .stmtRunner.setBaseDir(dir);
2204: } catch (IOException e) {
2205: this .stmtRunner.setBaseDir(System
2206: .getProperty("user.dir"));
2207: }
2208: } else {
2209: this .stmtRunner.setBaseDir(System.getProperty("user.dir"));
2210: }
2211:
2212: int maxRows = this .statusBar.getMaxRows();
2213: int timeout = this .statusBar.getQueryTimeout();
2214: int firstResultIndex = 0;
2215:
2216: StatementRunnerResult statementResult = null;
2217:
2218: try {
2219: if (appendResult) {
2220: firstResultIndex = this .resultTab.getTabCount() - 1;
2221: appendToLog("\n");
2222: } else {
2223: setLogText("");
2224: this .clearResultTabs();
2225: firstResultIndex = 0;
2226: }
2227:
2228: String cleanSql = SqlUtil.makeCleanSql(script, false);
2229: String macro = MacroManager.getInstance().getMacroText(
2230: cleanSql);
2231: if (macro != null) {
2232: appendToLog(ResourceMgr.getString("MsgExecutingMacro")
2233: + ":\n" + cleanSql + "\n");
2234: script = macro;
2235: macroRun = true;
2236: }
2237:
2238: if (this .macroExecution) {
2239: // executeMacro() will set this variable so that we can
2240: // log the macro statement here. Otherwise we wouldn know at this point
2241: // that a macro is beeing executed
2242: this .macroExecution = false;
2243:
2244: macroRun = true;
2245: appendToLog(ResourceMgr.getString("MsgExecutingMacro")
2246: + ":\n" + script + "\n");
2247: }
2248:
2249: scriptParser.setScript(script);
2250:
2251: int commandWithError = -1;
2252: int startIndex = 0;
2253: int count = scriptParser.getSize();
2254: int endIndex = count;
2255: int failuresIgnored = 0;
2256:
2257: if (count == 0) {
2258: this .appendToLog(ResourceMgr.getString("ErrNoCommand"));
2259: this .showLogPanel();
2260: return;
2261: }
2262:
2263: if (commandAtIndex > -1) {
2264: count = 1;
2265: startIndex = scriptParser
2266: .getCommandIndexAtCursorPos(commandAtIndex);
2267: endIndex = startIndex + 1;
2268: if (startIndex == -1) {
2269: this .appendToLog(ResourceMgr
2270: .getString("ErrNoCurrentStatement"));
2271: this .showLogPanel();
2272: return;
2273: }
2274: }
2275:
2276: if (count > 1)
2277: logWasCompressed = !this .stmtRunner.getVerboseLogging();
2278:
2279: StringBuilder finishedMsg1 = new StringBuilder(ResourceMgr
2280: .getString("TxtScriptStatementFinished1"));
2281: finishedMsg1.append(' ');
2282: StringBuilder finishedMsg2 = new StringBuilder(20);
2283: finishedMsg2.append(' ');
2284: String msg = ResourceMgr
2285: .getString("TxtScriptStatementFinished2");
2286: msg = StringUtil.replace(msg, "%total%", NumberStringCache
2287: .getNumberString(count));
2288: finishedMsg2.append(msg);
2289:
2290: final int finishedSize = finishedMsg1.length()
2291: + finishedMsg2.length() + 5;
2292:
2293: boolean onErrorAsk = !Settings.getInstance()
2294: .getIgnoreErrors();
2295:
2296: // Displays the first "result" tab. As no result is available
2297: // at this point, it merely shows the message log
2298: this .showResultPanel();
2299:
2300: highlightCurrent = ((count > 1 || commandAtIndex > -1)
2301: && (!macroRun) && Settings.getInstance()
2302: .getHighlightCurrentStatement());
2303:
2304: if (highlightCurrent) {
2305: oldSelectionStart = this .editor.getSelectionStart();
2306: oldSelectionEnd = this .editor.getSelectionEnd();
2307: restoreSelection = shouldRestoreSelection;
2308: }
2309:
2310: long startTime = System.currentTimeMillis();
2311: statusBar.executionStart();
2312: long stmtTotal = 0;
2313: int executedCount = 0;
2314: String currentSql = null;
2315:
2316: int resultSets = 0;
2317: this .ignoreStateChange = false;
2318: this .macroExecution = false;
2319:
2320: long totalRows = 0;
2321:
2322: for (int i = startIndex; i < endIndex; i++) {
2323: currentSql = scriptParser.getCommand(i);
2324: if (fixNLPattern != null) {
2325: currentSql = fixNLPattern.matcher(currentSql)
2326: .replaceAll(nl);
2327: }
2328: if (currentSql.length() == 0)
2329: continue;
2330:
2331: // By calling yield() we make sure that
2332: // this thread can actually be interrupted!
2333: Thread.yield();
2334: if (cancelExecution)
2335: break;
2336:
2337: if (highlightCurrent) {
2338: highlightStatement(scriptParser, i, selectionOffset);
2339: }
2340:
2341: this .stmtRunner.runStatement(currentSql, maxRows,
2342: timeout);
2343: statementResult = this .stmtRunner.getResult();
2344:
2345: if (statementResult.stopScript()) {
2346: String cancelMsg = ResourceMgr
2347: .getString("MsgScriptCancelled");
2348: this .appendToLog(cancelMsg);
2349: this .appendToLog("\n");
2350: this .showLogPanel();
2351: break;
2352: }
2353:
2354: if (statementResult.promptingWasCancelled()) {
2355: String cancelMsg = ResourceMgr
2356: .getString("MsgSqlCancelledDuringPrompt");
2357: cancelMsg = cancelMsg.replaceAll("%nr%",
2358: NumberStringCache.getNumberString(i + 1));
2359: this .appendToLog(cancelMsg);
2360: this .showLogPanel();
2361: continue;
2362: }
2363:
2364: if (statementResult == null)
2365: continue;
2366:
2367: resultSets += this .addResult(statementResult);
2368: stmtTotal += statementResult.getExecutionTime();
2369:
2370: // the WbFeedback command might change the feedback level
2371: // so it needs to be checked each time.
2372: if (count > 1)
2373: logWasCompressed = logWasCompressed
2374: || !this .stmtRunner.getVerboseLogging();
2375:
2376: StringBuilder finishedMsg = new StringBuilder(
2377: finishedSize);
2378: finishedMsg.append(finishedMsg1);
2379: finishedMsg.append(NumberStringCache
2380: .getNumberString(i + 1));
2381: finishedMsg.append(finishedMsg2);
2382: String currentMsg = finishedMsg.toString();
2383:
2384: if (!logWasCompressed) {
2385: showResultMessage(statementResult);
2386: StringBuilder logmsg = new StringBuilder(100);
2387: String timing = statementResult.getTimingMessage();
2388: if (timing != null) {
2389: logmsg.append('\n');
2390: logmsg.append(timing);
2391: }
2392:
2393: logmsg.append('\n');
2394: if (count > 1) {
2395: logmsg.append('(');
2396: logmsg.append(currentMsg);
2397: logmsg.append(")\n\n");
2398: }
2399: this .appendToLog(logmsg.toString());
2400: } else if (statementResult.hasWarning()) {
2401: // Warnings should always be shown, even if the log output is "compressed"
2402: String verb = SqlUtil.getSqlVerb(currentSql);
2403: String warn = StringUtil.replace(ResourceMgr
2404: .getString("MsgStmtCompletedWarn"),
2405: "%verb%", verb);
2406: this .appendToLog(warn + "\n");
2407: }
2408:
2409: if (count > 1) {
2410: this .statusBar.setStatusMessage(currentMsg);
2411: }
2412:
2413: // this will be set by confirmExecution() if
2414: // Cancel was selected
2415: if (this .cancelAll)
2416: break;
2417:
2418: if (statementResult.isSuccess()) {
2419: totalRows += statementResult.getTotalUpdateCount();
2420: } else {
2421: commandWithError = i;
2422:
2423: // error messages should always be shown in the log
2424: // panel, even if compressLog is enabled (if it is not enabled
2425: // the messages have been appended to the log already)
2426: if (logWasCompressed)
2427: this .appendToLog(statementResult
2428: .getMessageBuffer().toString());
2429:
2430: if (count > 1 && onErrorAsk && (i < (count - 1))) {
2431: // the animated gif needs to be turned off when a
2432: // dialog is displayed, otherwise Swing uses too much CPU
2433: this .showBusyIcon(false);
2434:
2435: if (!macroRun)
2436: this .highlightError(scriptParser,
2437: commandWithError, selectionOffset);
2438:
2439: // force a refresh in order to display the selection
2440: WbSwingUtilities.repaintLater(this );
2441: Thread.yield();
2442:
2443: String question = ResourceMgr
2444: .getString("MsgScriptStatementError");
2445: question = StringUtil.replace(question, "%nr%",
2446: Integer.toString(i + 1));
2447: question = StringUtil.replace(question,
2448: "%count%", Integer.toString(count));
2449: int choice = WbSwingUtilities
2450: .getYesNoIgnoreAll(this , question);
2451: this .showBusyIcon(true);
2452:
2453: if (choice == JOptionPane.NO_OPTION) {
2454: break;
2455: } else if (choice == WbSwingUtilities.IGNORE_ALL) {
2456: onErrorAsk = false;
2457: }
2458: }
2459: failuresIgnored++;
2460: }
2461: executedCount++;
2462: this .stmtRunner.statementDone();
2463: if (this .cancelExecution)
2464: break;
2465:
2466: } // end for loop over all statements
2467:
2468: long execTime = (System.currentTimeMillis() - startTime);
2469:
2470: // this will automatically stop the execution timer in the status bar
2471: statusBar.setExecutionTime(stmtTotal);
2472: statusBar.clearStatusMessage();
2473:
2474: if (commandWithError > -1 && highlightOnError && !macroRun) {
2475: restoreSelection = false;
2476: final ScriptParser p = scriptParser;
2477: final int command = commandWithError;
2478: final int offset = selectionOffset;
2479:
2480: EventQueue.invokeLater(new Runnable() {
2481: public void run() {
2482: highlightError(p, command, offset);
2483: }
2484: });
2485: }
2486:
2487: if (failuresIgnored > 0) {
2488: this .appendToLog("\n"
2489: + failuresIgnored
2490: + " "
2491: + ResourceMgr
2492: .getString("MsgTotalStatementsFailed")
2493: + "\n");
2494: }
2495:
2496: if (logWasCompressed) {
2497: msg = executedCount
2498: + " "
2499: + ResourceMgr
2500: .getString("MsgTotalStatementsExecuted")
2501: + "\n";
2502: this .appendToLog(msg);
2503: msg = totalRows + " "
2504: + ResourceMgr.getString("MsgTotalRowsAffected")
2505: + "\n\n";
2506: this .appendToLog(msg);
2507: }
2508:
2509: ignoreStateChange = false;
2510: if (resultSets > 0) {
2511: this .showResultPanel(firstResultIndex);
2512: } else {
2513: this .showLogPanel();
2514: }
2515:
2516: if (count > 1) {
2517: this .appendToLog(ResourceMgr
2518: .getString("TxtScriptFinished")
2519: + "\n");
2520: String s = ResourceMgr.getString("MsgScriptExecTime")
2521: + " " + (((double) execTime) / 1000.0) + "s\n";
2522: this .appendToLog(s);
2523: }
2524:
2525: if (!jumpToNext && restoreSelection
2526: && oldSelectionStart > -1 && oldSelectionEnd > -1) {
2527: final int selstart = oldSelectionStart;
2528: final int selend = oldSelectionEnd;
2529: EventQueue.invokeLater(new Runnable() {
2530: public void run() {
2531: editor.select(selstart, selend);
2532: }
2533: });
2534: }
2535:
2536: if (highlightCurrent && !restoreSelection) {
2537: int startPos = scriptParser
2538: .getStartPosForCommand(endIndex - 1);
2539: startPos = scriptParser.findNextLineStart(startPos);
2540: if (startPos > -1
2541: && startPos < this .editor.getText().length()) {
2542: this .editor.setCaretPosition(startPos);
2543: }
2544: }
2545:
2546: if (commandWithError == -1 && jumpToNext) {
2547: int nextCommand = startIndex + 1;
2548: int startPos = scriptParser
2549: .getStartPosForCommand(nextCommand);
2550: startPos = scriptParser.findNextLineStart(startPos);
2551: if (startPos > -1) {
2552: this .editor.setCaretPosition(startPos);
2553: } else if (oldSelectionStart > -1) {
2554: this .editor.setCaretPosition(oldSelectionStart);
2555: }
2556: }
2557: } catch (SQLException e) {
2558: if (statementResult != null)
2559: this .showLogMessage(statementResult.getMessageBuffer()
2560: .toString());
2561: } catch (Throwable e) {
2562: if (e instanceof OutOfMemoryError) {
2563: if (statementResult != null) {
2564: try {
2565: stmtRunner.statementDone();
2566: } catch (Throwable th) {
2567: }
2568: statementResult.clearResultData();
2569: }
2570: WbManager.getInstance().showOutOfMemoryError();
2571: }
2572: LogMgr.logError("SqlPanel.displayResult()",
2573: "Error executing statement", e);
2574: if (statementResult != null) {
2575: this .showLogMessage(statementResult.getMessageBuffer()
2576: .toString());
2577: statementResult.clear();
2578: }
2579: } finally {
2580: this .stmtRunner.done();
2581: ignoreStateChange = false;
2582: }
2583: }
2584:
2585: private void showResultMessage(StatementRunnerResult result) {
2586: CharSequence msg = result.getMessageBuffer();
2587: if (msg == null)
2588: return;
2589: try {
2590: this .appendToLog(msg.toString() + "\n");
2591: } catch (OutOfMemoryError oome) {
2592: result.clearMessageBuffer();
2593: System.gc();
2594: final boolean success = result.isSuccess();
2595: EventQueue.invokeLater(new Runnable() {
2596: public void run() {
2597: if (success) {
2598: log.append(ResourceMgr
2599: .getString("ErrLogNoMemSuccess"));
2600: } else {
2601: log.append(ResourceMgr
2602: .getString("ErrLogNoMemError"));
2603: }
2604: log.append("\n");
2605: log.append(ResourceMgr
2606: .getString("ErrLogNoMemCheckLog"));
2607: log.append("\n");
2608: log.setCaretPosition(log.getDocument().getLength());
2609: }
2610: });
2611: }
2612: }
2613:
2614: private DwPanel createDwPanel() throws SQLException {
2615: DwPanel data = new DwPanel(statusBar);
2616: data.setBorder(WbSwingUtilities.EMPTY_BORDER);
2617: data.setConnection(this .dbConnection);
2618: data.setUpdateHandler(this );
2619: MainWindow w = null;
2620: try {
2621: w = (MainWindow) SwingUtilities.getWindowAncestor(this );
2622: } catch (Exception e) {
2623: LogMgr.logError("SqlPanel.createDwPanel()",
2624: "Could not find MainWindow!", e);
2625: w = null;
2626: }
2627:
2628: if (w != null) {
2629: data.initTableNavigation(w);
2630: }
2631: return data;
2632: }
2633:
2634: /**
2635: * Implementation of the ResultReceiver interface.
2636: * The given sql will be executed and the result will always
2637: * be displayed in a new result tab
2638: */
2639: public void showResult(final String sql, String comment,
2640: ResultReceiver.ShowType how) {
2641: if (how == ResultReceiver.ShowType.logText) {
2642: appendToLog("\n"
2643: + ResourceMgr.getString("MsgLoadRelatedData")
2644: + "\n" + sql + "\n\n");
2645: } else if (how != ResultReceiver.ShowType.showNone) {
2646: int pos = this .editor.getDocumentLength();
2647: if (how == ResultReceiver.ShowType.replaceText) {
2648: this .editor.setText("");
2649: pos = 0;
2650: } else {
2651: if (comment != null) {
2652: this .editor.appendLine("\n" + comment + "\n");
2653: } else {
2654: this .editor.appendLine("\n\n");
2655: }
2656: pos = this .editor.getDocumentLength();
2657: }
2658: this .editor.appendLine(sql + ";\n");
2659: this .editor.setCaretPosition(pos);
2660: this .editor.scrollToCaret();
2661: }
2662: startExecution(sql, 0, -1, false, true);
2663: }
2664:
2665: private void addResultTab(DwPanel data, String sql) {
2666: int newIndex = this .resultTab.getTabCount() - 1;
2667: this .resultTab.insertTab(ResourceMgr.getString("LblTabResult"),
2668: null, data, sql, newIndex);
2669: data.setName("dwresult" + newIndex);
2670: if (this .resultTab.getTabCount() == 2) {
2671: this .resultTab.setSelectedIndex(0);
2672: }
2673: }
2674:
2675: /**
2676: * Display the data contained in the StatementRunnerResult.
2677: * For each DataStore or ResultSet in the result, an additional
2678: * result {@link workbench.gui.sql.DwPanel} will be added.
2679: *
2680: * @param result the result to be displayed (obtained from a {@link workbench.interfaces.StatementRunner})
2681: * @see workbench.gui.sql.DwPanel
2682: */
2683: public int addResult(StatementRunnerResult result)
2684: throws SQLException {
2685: if (!result.isSuccess())
2686: return 0;
2687: final String sql = result.getSourceCommand();
2688:
2689: int count = 0;
2690: if (result.hasDataStores()) {
2691: final List<DataStore> results = result.getDataStores();
2692: count += results.size();
2693: WbSwingUtilities.invoke(new Runnable() {
2694: public void run() {
2695: try {
2696: for (DataStore ds : results) {
2697: DwPanel p = createDwPanel();
2698: p.showData(ds, sql);
2699: addResultTab(p, sql);
2700: }
2701: } catch (Exception e) {
2702: LogMgr
2703: .logError(
2704: "SqlPanel.addResult()",
2705: "Error when adding new DwPanel with DataStore",
2706: e);
2707: }
2708: }
2709: });
2710: }
2711:
2712: if (result.hasResultSets()) {
2713: final List<ResultSet> results = result.getResultSets();
2714: count += results.size();
2715: WbSwingUtilities.invoke(new Runnable() {
2716: public void run() {
2717: try {
2718: for (ResultSet rs : results) {
2719: DwPanel p = createDwPanel();
2720: p.showData(rs, sql);
2721: addResultTab(p, sql);
2722: }
2723: } catch (Exception e) {
2724: LogMgr
2725: .logError(
2726: "SqlPanel.addResult()",
2727: "Error when adding new DwPanel with ResultSet",
2728: e);
2729: }
2730: }
2731: });
2732: }
2733:
2734: return count;
2735: }
2736:
2737: private void highlightStatement(ScriptParser scriptParser,
2738: int command, int startOffset) {
2739: if (this .editor == null)
2740: return;
2741: final int startPos = scriptParser
2742: .getStartPosForCommand(command)
2743: + startOffset;
2744: final int endPos = scriptParser.getEndPosForCommand(command)
2745: + startOffset;
2746: final int line = this .editor.getLineOfOffset(startPos);
2747:
2748: WbSwingUtilities.invoke(new Runnable() {
2749: public void run() {
2750: editor.scrollTo(line, 0);
2751: editor.selectStatementTemporary(startPos, endPos);
2752: }
2753: });
2754: }
2755:
2756: protected void highlightError(ScriptParser scriptParser,
2757: int commandWithError, int startOffset) {
2758: if (this .editor == null)
2759: return;
2760:
2761: final int startPos = scriptParser
2762: .getStartPosForCommand(commandWithError)
2763: + startOffset;
2764: final int endPos = scriptParser
2765: .getEndPosForCommand(commandWithError)
2766: + startOffset;
2767: final int line = this .editor.getLineOfOffset(startPos);
2768:
2769: WbSwingUtilities.invoke(new Runnable() {
2770: public void run() {
2771: editor.select(0, 0);
2772: editor.scrollTo(line, 0);
2773: editor.selectError(startPos, endPos);
2774: }
2775: });
2776: }
2777:
2778: protected void checkResultSetActions() {
2779: final boolean hasResult = currentData != null ? currentData
2780: .hasResultSet() : false;
2781: final boolean mayEdit = hasResult
2782: && currentData.hasUpdateableColumns();
2783: final boolean findNext = hasResult
2784: && (currentData.getTable().canSearchAgain());
2785: Action[] actionList = new Action[] { dataToClipboard,
2786: exportDataAction, optimizeAllCol, printDataAction,
2787: printPreviewAction };
2788: setActionState(actionList, hasResult);
2789:
2790: WbSwingUtilities.invoke(new Runnable() {
2791: public void run() {
2792: importFileAction.setEnabled(mayEdit);
2793: importClipAction.setEnabled(mayEdit);
2794:
2795: findDataAgainAction.setEnabled(findNext);
2796: copySelectedMenu.setEnabled(hasResult);
2797: }
2798: });
2799: }
2800:
2801: private void setExecuteActionStates(final boolean aFlag) {
2802: EventQueue.invokeLater(new Runnable() {
2803: public void run() {
2804: executeAll.setEnabled(aFlag);
2805: executeSelected.setEnabled(aFlag);
2806: executeCurrent.setEnabled(aFlag);
2807: if (aFlag) {
2808: checkCommitAction();
2809: } else {
2810: commitAction.setEnabled(aFlag);
2811: rollbackAction.setEnabled(aFlag);
2812: }
2813: spoolData.canExport(aFlag);
2814: appendResultsAction.setEnabled(aFlag);
2815: }
2816: });
2817: }
2818:
2819: private ImageIcon fileIcon = null;
2820: private ImageIcon fileModifiedIcon = null;
2821: private ImageIcon cancelIcon = null;
2822: private ImageIcon loadingIcon;
2823:
2824: private void showCancelIcon() {
2825: this .showIconForTab(this .getCancelIndicator());
2826: if (this .loadingIcon != null)
2827: this .loadingIcon.getImage().flush();
2828: }
2829:
2830: private ImageIcon getLoadingIndicator() {
2831: if (this .loadingIcon == null) {
2832: if (Settings.getInstance().getUseAnimatedIcon()) {
2833: String name = Settings.getInstance().getProperty(
2834: "workbench.gui.animatedicon.name", "loading");
2835: this .loadingIcon = ResourceMgr.getPicture(name);
2836: } else {
2837: this .loadingIcon = ResourceMgr
2838: .getPicture("loading-static");
2839: }
2840: }
2841: return this .loadingIcon;
2842: }
2843:
2844: private ImageIcon getCancelIndicator() {
2845: if (this .cancelIcon == null) {
2846: if (Settings.getInstance().getUseAnimatedIcon()) {
2847: this .cancelIcon = ResourceMgr.getPicture("cancelling");
2848: } else {
2849: this .cancelIcon = ResourceMgr
2850: .getPicture("cancelling-static");
2851: }
2852: }
2853: return this .cancelIcon;
2854: }
2855:
2856: private ImageIcon getFileIcon() {
2857: ImageIcon icon = null;
2858: if (this .textModified) {
2859: if (this .fileModifiedIcon == null) {
2860: this .fileModifiedIcon = ResourceMgr
2861: .getPicture("file-modified-icon");
2862: }
2863: icon = this .fileModifiedIcon;
2864: } else {
2865: if (this .fileIcon == null) {
2866: this .fileIcon = ResourceMgr.getPicture("file-icon");
2867: }
2868: icon = this .fileIcon;
2869: }
2870:
2871: return icon;
2872: }
2873:
2874: private void removeIconFromTab() {
2875: if (this .isBusy())
2876: return;
2877: this .showIconForTab(null);
2878: }
2879:
2880: private void showFileIcon() {
2881: if (this .isBusy())
2882: return;
2883: this .showIconForTab(this .getFileIcon());
2884: }
2885:
2886: private void showIconForTab(ImageIcon icon) {
2887: Container parent = this .getParent();
2888: if (parent instanceof JTabbedPane) {
2889: JTabbedPane tab = (JTabbedPane) parent;
2890: int index = tab.indexOfComponent(this );
2891: Icon oldIcon = tab.getIconAt(index);
2892: if (icon == null && oldIcon == null)
2893: return;
2894: if (icon != oldIcon) {
2895: tab.setIconAt(index, icon);
2896: }
2897: }
2898: }
2899:
2900: private Runnable hideBusyRunnable = new Runnable() {
2901: public void run() {
2902: _showBusyIcon(false);
2903: }
2904: };
2905:
2906: private Runnable showBusyRunnable = new Runnable() {
2907: public void run() {
2908: _showBusyIcon(true);
2909: }
2910: };
2911:
2912: private void showBusyIcon(boolean show) {
2913: if (show) {
2914: WbSwingUtilities.invoke(showBusyRunnable);
2915: } else {
2916: WbSwingUtilities.invoke(hideBusyRunnable);
2917: }
2918: }
2919:
2920: private void _showBusyIcon(boolean show) {
2921: Container parent = this .getParent();
2922: if (parent instanceof JTabbedPane) {
2923: final JTabbedPane tab = (JTabbedPane) parent;
2924: int index = tab.indexOfComponent(this );
2925: if (index >= 0 && index < tab.getTabCount()) {
2926: try {
2927: if (show) {
2928: tab.setIconAt(index, getLoadingIndicator());
2929: } else {
2930: if (this .hasFileLoaded()) {
2931: tab.setIconAt(index, getFileIcon());
2932: } else {
2933: tab.setIconAt(index, null);
2934: }
2935: if (Settings.getInstance().getUseAnimatedIcon()) {
2936: // flushing the animated icons also stops the thread that
2937: // is used for the animation. If this is not done it will still
2938: // "animate" in the background (at least on older JDKs) and thus
2939: // degrade performance
2940: // For a static icon this is not necessary, actually not flushing
2941: // the static icon improves performance when it's re-displayed
2942: if (this .loadingIcon != null)
2943: this .loadingIcon.getImage().flush();
2944: if (this .cancelIcon != null)
2945: this .cancelIcon.getImage().flush();
2946: }
2947: }
2948: } catch (Throwable th) {
2949: LogMgr.logWarning("SqlPanel.setBusy()",
2950: "Error when setting busy icon!", th);
2951: }
2952: WbSwingUtilities.repaintLater(tab);
2953: }
2954: }
2955: }
2956:
2957: protected void setBusy(final boolean busy) {
2958: synchronized (this ) {
2959: this .threadBusy = busy;
2960: this .showBusyIcon(busy);
2961: this .setExecuteActionStates(!busy);
2962: }
2963: }
2964:
2965: public boolean isBusy() {
2966: return this .threadBusy;
2967: }
2968:
2969: public void fontChanged(String aFontId, Font newFont) {
2970: if (aFontId.equals(Settings.PROPERTY_MSGLOG_FONT)) {
2971: this .log.setFont(newFont);
2972: }
2973: }
2974:
2975: public Window getParentWindow() {
2976: return SwingUtilities.getWindowAncestor(this );
2977: }
2978:
2979: public void textStatusChanged(boolean modified) {
2980: this .textModified = modified;
2981: // Make sure the icon for the file is updated to reflect
2982: // the modidified status
2983: if (this .hasFileLoaded())
2984: this .showFileIcon();
2985: }
2986:
2987: public void addDbExecutionListener(DbExecutionListener l) {
2988: if (this .execListener == null)
2989: this .execListener = Collections
2990: .synchronizedList(new LinkedList<DbExecutionListener>());
2991: this .execListener.add(l);
2992: }
2993:
2994: public void removeDbExecutionListener(DbExecutionListener l) {
2995: if (this .execListener == null)
2996: return;
2997: this .execListener.remove(l);
2998: }
2999:
3000: protected void fireDbExecStart() {
3001: synchronized (this ) {
3002: if (this .execListener != null) {
3003: for (DbExecutionListener l : this .execListener) {
3004: if (l != null)
3005: l.executionStart(this .dbConnection, this );
3006: }
3007: }
3008: if (this .dbConnection != null) {
3009: this .dbConnection.setBusy(true);
3010: }
3011:
3012: }
3013: }
3014:
3015: protected void fireDbExecEnd() {
3016: synchronized (this ) {
3017: // It is important to first tell the connection that we are finished
3018: // otherwise the connection still thinks it's "busy" although it is not
3019: if (this .dbConnection != null) {
3020: this .dbConnection.setBusy(false);
3021: }
3022: if (this .execListener != null) {
3023: for (DbExecutionListener l : this .execListener) {
3024: if (l != null)
3025: l.executionEnd(this .dbConnection, this );
3026: }
3027: }
3028: }
3029: }
3030:
3031: public void reset() {
3032: this .editor.reset();
3033: this .clearLog();
3034: this .clearResultTabs();
3035: if (this .currentData != null)
3036: this .currentData.clearContent();
3037: this .currentData = null;
3038: if (cancelIcon != null)
3039: cancelIcon.getImage().flush();
3040: if (loadingIcon != null)
3041: loadingIcon.getImage().flush();
3042: if (fileIcon != null)
3043: fileIcon.getImage().flush();
3044: if (fileModifiedIcon != null)
3045: fileModifiedIcon.getImage().flush();
3046: if (this .sqlHistory != null)
3047: this .sqlHistory.clear();
3048: }
3049:
3050: public void dispose() {
3051: Settings.getInstance().removePropertyChangeListener(this );
3052: Settings.getInstance().removeFontChangedListener(this );
3053:
3054: reset();
3055:
3056: if (this .stmtRunner != null)
3057: this .stmtRunner.dispose();
3058: if (this .execListener != null)
3059: execListener.clear();
3060: if (this .editor != null)
3061: this .editor.dispose();
3062: this .editor = null;
3063: if (this .actions != null)
3064: this .actions.clear();
3065: if (this .toolbarActions != null)
3066: this .toolbarActions.clear();
3067: if (this .filenameChangeListeners != null)
3068: this .filenameChangeListeners.clear();
3069: if (this .execListener != null)
3070: this .execListener.clear();
3071: if (this .toolbar != null)
3072: this .toolbar.removeAll();
3073: this .toolbar = null;
3074: this .abortExecution();
3075: this .executionThread = null;
3076: this .connectionInfo = null;
3077: }
3078:
3079: public void propertyChange(PropertyChangeEvent evt) {
3080: String prop = evt.getPropertyName();
3081: if (prop == null)
3082: return;
3083: if (evt.getSource() == Settings.getInstance()
3084: && prop.equals(Settings.PROPERTY_ANIMATED_ICONS)) {
3085: if (this .cancelIcon != null) {
3086: this .cancelIcon.getImage().flush();
3087: this .cancelIcon = null;
3088: }
3089: if (this .loadingIcon != null) {
3090: this .loadingIcon.getImage().flush();
3091: this .loadingIcon = null;
3092: }
3093: } else if (evt.getSource() == this .dbConnection
3094: && WbConnection.PROP_AUTOCOMMIT.equals(prop)) {
3095: this .checkCommitAction();
3096: } else if (evt.getSource() == this .currentData
3097: && prop.equals("updateTable")) {
3098: this.checkResultSetActions();
3099: }
3100: }
3101:
3102: }
|