0001: /*
0002: * MainWindow.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;
0013:
0014: import java.awt.BorderLayout;
0015: import java.awt.Color;
0016: import java.awt.Component;
0017: import java.awt.Container;
0018: import java.awt.EventQueue;
0019: import java.awt.datatransfer.DataFlavor;
0020: import java.awt.datatransfer.Transferable;
0021: import java.awt.datatransfer.UnsupportedFlavorException;
0022: import java.awt.dnd.DnDConstants;
0023: import java.awt.dnd.DropTarget;
0024: import java.awt.dnd.DropTargetListener;
0025: import java.awt.event.MouseEvent;
0026: import java.awt.event.MouseListener;
0027: import java.awt.event.WindowEvent;
0028: import java.awt.event.WindowListener;
0029: import java.beans.PropertyChangeEvent;
0030: import java.beans.PropertyChangeListener;
0031: import java.io.File;
0032: import java.io.IOException;
0033: import java.util.ArrayList;
0034: import java.util.Collections;
0035: import java.util.HashMap;
0036: import java.util.List;
0037: import javax.swing.Action;
0038: import javax.swing.JDialog;
0039: import javax.swing.JFrame;
0040: import javax.swing.JMenu;
0041: import javax.swing.JMenuBar;
0042: import javax.swing.JMenuItem;
0043: import javax.swing.JOptionPane;
0044: import javax.swing.JTabbedPane;
0045: import javax.swing.SwingUtilities;
0046: import javax.swing.WindowConstants;
0047: import javax.swing.event.ChangeEvent;
0048: import javax.swing.event.ChangeListener;
0049: import workbench.WbManager;
0050: import workbench.db.ConnectionMgr;
0051: import workbench.db.ConnectionProfile;
0052: import workbench.db.WbConnection;
0053: import workbench.gui.actions.AboutAction;
0054: import workbench.gui.actions.ConfigureShortcutsAction;
0055: import workbench.gui.actions.ShowManualAction;
0056: import workbench.gui.actions.WbAction;
0057: import workbench.gui.components.RunningJobIndicator;
0058: import workbench.interfaces.Moveable;
0059: import workbench.util.ExceptionUtil;
0060: import workbench.gui.actions.AddMacroAction;
0061: import workbench.gui.actions.AddTabAction;
0062: import workbench.gui.actions.AssignWorkspaceAction;
0063: import workbench.gui.actions.CloseWorkspaceAction;
0064: import workbench.gui.actions.DataPumperAction;
0065: import workbench.gui.actions.FileConnectAction;
0066: import workbench.gui.actions.FileDisconnectAction;
0067: import workbench.gui.actions.FileExitAction;
0068: import workbench.gui.actions.FileNewWindowAction;
0069: import workbench.gui.actions.LoadWorkspaceAction;
0070: import workbench.gui.actions.ManageDriversAction;
0071: import workbench.gui.actions.ManageMacroAction;
0072: import workbench.gui.actions.NewDbExplorerPanelAction;
0073: import workbench.gui.actions.NewDbExplorerWindowAction;
0074: import workbench.gui.actions.RemoveTabAction;
0075: import workbench.gui.actions.RunMacroAction;
0076: import workbench.gui.actions.SaveAsNewWorkspaceAction;
0077: import workbench.gui.actions.SaveWorkspaceAction;
0078: import workbench.gui.actions.SelectTabAction;
0079: import workbench.gui.actions.ShowDbExplorerAction;
0080: import workbench.gui.actions.VersionCheckAction;
0081: import workbench.gui.actions.ViewLineNumbers;
0082: import workbench.gui.actions.WbAction;
0083: import workbench.gui.components.ConnectionSelector;
0084: import workbench.gui.components.WbMenu;
0085: import workbench.gui.components.WbTabbedPane;
0086: import workbench.gui.components.WbToolbar;
0087: import workbench.gui.dbobjects.DbExplorerPanel;
0088: import workbench.gui.menu.SqlTabPopup;
0089: import workbench.gui.sql.SqlPanel;
0090: import workbench.interfaces.Connectable;
0091: import workbench.interfaces.DbExecutionListener;
0092: import workbench.interfaces.FilenameChangeListener;
0093: import workbench.interfaces.MacroChangeListener;
0094: import workbench.interfaces.MainPanel;
0095: import workbench.log.LogMgr;
0096: import workbench.resource.ResourceMgr;
0097: import workbench.resource.Settings;
0098: import workbench.sql.MacroManager;
0099: import workbench.util.FileDialogUtil;
0100: import workbench.util.StringUtil;
0101: import workbench.util.WbThread;
0102: import workbench.util.WbWorkspace;
0103: import workbench.gui.actions.FileSaveProfiles;
0104: import workbench.gui.actions.InsertTabAction;
0105: import workbench.gui.actions.OptionsDialogAction;
0106: import workbench.gui.actions.ShowHelpAction;
0107: import workbench.gui.actions.CreateNewConnection;
0108: import workbench.gui.actions.DisconnectTabAction;
0109: import workbench.gui.actions.ViewToolbarAction;
0110: import workbench.gui.actions.WhatsNewAction;
0111: import workbench.gui.dbobjects.DbExplorerWindow;
0112: import workbench.interfaces.ToolWindow;
0113: import workbench.util.NumberStringCache;
0114:
0115: /**
0116: * The main window for the Workbench.
0117: * It will display several {@link workbench.gui.sql.SqlPanel}s in
0118: * a tabbed pane. Additionally one or more {@link workbench.gui.dbobjects.DbExplorerPanel}
0119: * might also be displayed inside the JTabbedPane
0120: *
0121: * @author support@sql-workbench.net
0122: */
0123: public class MainWindow extends JFrame implements MouseListener,
0124: WindowListener, ChangeListener, DropTargetListener,
0125: MacroChangeListener, DbExecutionListener, Connectable,
0126: PropertyChangeListener, Moveable {
0127: private static final String DEFAULT_WORKSPACE = "%ConfigDir%/Default.wksp";
0128: private static int instanceCount;
0129: private int windowId;
0130:
0131: private WbConnection currentConnection;
0132: private ConnectionProfile currentProfile;
0133: protected ConnectionSelector connectionSelector;
0134:
0135: private FileDisconnectAction disconnectAction;
0136: private CreateNewConnection createNewConnection;
0137: private DisconnectTabAction disconnectTab;
0138: private ShowDbExplorerAction dbExplorerAction;
0139: private NewDbExplorerPanelAction newDbExplorerPanel;
0140: private NewDbExplorerWindowAction newDbExplorerWindow;
0141:
0142: private WbTabbedPane sqlTab;
0143: private WbToolbar currentToolbar;
0144: private ArrayList<JMenuBar> panelMenus = new ArrayList<JMenuBar>(13);
0145:
0146: private String currentWorkspaceFile;
0147:
0148: private CloseWorkspaceAction closeWorkspaceAction;
0149: private SaveWorkspaceAction saveWorkspaceAction;
0150: private SaveAsNewWorkspaceAction saveAsWorkspaceAction;
0151: private LoadWorkspaceAction loadWorkspaceAction;
0152: private AssignWorkspaceAction assignWorkspaceAction;
0153:
0154: private boolean isProfileWorkspace;
0155: private boolean tabRemovalInProgress;
0156:
0157: // will indicate a connect or disconnect in progress
0158: // connecting and disconnecting is done in a separate thread
0159: // so that slow connections do not block the GUI
0160: private boolean connectInProgress;
0161:
0162: private AddMacroAction createMacro;
0163: private ManageMacroAction manageMacros;
0164:
0165: private List<ToolWindow> explorerWindows = new ArrayList<ToolWindow>();
0166:
0167: private RunningJobIndicator jobIndicator;
0168: protected WbThread connectThread;
0169:
0170: public MainWindow() {
0171: super (ResourceMgr.TXT_PRODUCT_NAME);
0172: this .windowId = ++instanceCount;
0173:
0174: sqlTab = new WbTabbedPane();
0175: sqlTab.setFocusable(false);
0176:
0177: String policy = Settings.getInstance().getProperty(
0178: "workbench.gui.sqltab.policy", "wrap");
0179: if ("wrap".equalsIgnoreCase(policy)) {
0180: sqlTab.setTabLayoutPolicy(JTabbedPane.WRAP_TAB_LAYOUT);
0181: } else if ("scroll".equalsIgnoreCase(policy)) {
0182: sqlTab.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT);
0183: }
0184:
0185: this
0186: .setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
0187:
0188: initMenu();
0189: setIconImage(ResourceMgr.getPicture("workbench16").getImage());
0190:
0191: this .getContentPane().add(this .sqlTab, BorderLayout.CENTER);
0192:
0193: this .restoreSettings();
0194:
0195: this .checkWorkspaceActions();
0196:
0197: this .sqlTab.addChangeListener(this );
0198: this .sqlTab.addMouseListener(this );
0199:
0200: this .addWindowListener(this );
0201: MacroManager.getInstance().addChangeListener(this );
0202: this .jobIndicator = new RunningJobIndicator(this );
0203:
0204: new DropTarget(this .sqlTab, DnDConstants.ACTION_COPY, this );
0205: sqlTab.enableDragDropReordering(this );
0206: Settings.getInstance().addPropertyChangeListener(this ,
0207: Settings.PROPERTY_SHOW_TOOLBAR);
0208: }
0209:
0210: public void display() {
0211: this .restoreState();
0212: this .setVisible(true);
0213: this .addTab(true, false);
0214: this .updateGuiForTab(0);
0215: this .updateWindowTitle();
0216: }
0217:
0218: /**
0219: * The listener will be notified when the name of a tab changes.
0220: * This is used in the {@link workbench.gui.dbobjects.TableListPanel}
0221: * to display the available panels in the context menu
0222: * @see workbench.gui.dbobjects.EditorTabSelectMenu#fileNameChanged(Object, String)
0223: */
0224: public void addFilenameChangeListener(
0225: FilenameChangeListener aListener) {
0226: for (int i = 0; i < this .sqlTab.getTabCount(); i++) {
0227: MainPanel panel = this .getSqlPanel(i);
0228: if (panel instanceof SqlPanel) {
0229: SqlPanel sql = (SqlPanel) panel;
0230: sql.addFilenameChangeListener(aListener);
0231: }
0232: }
0233: }
0234:
0235: /**
0236: * Remove the file name change listener.
0237: * @see #addFilenameChangeListener(FilenameChangeListener )
0238: */
0239: public void removeFilenameChangeListener(
0240: FilenameChangeListener aListener) {
0241: for (int i = 0; i < this .sqlTab.getTabCount(); i++) {
0242: MainPanel panel = this .getSqlPanel(i);
0243: if (panel instanceof SqlPanel) {
0244: SqlPanel sql = (SqlPanel) panel;
0245: sql.removeFilenameChangeListener(aListener);
0246: }
0247: }
0248: }
0249:
0250: /**
0251: * The listener will be notified when the current tab changes.
0252: * This is used in the {@link workbench.gui.dbobjects.TableListPanel}
0253: * to highlight the current tab the context menu
0254: * @see workbench.gui.dbobjects.TableListPanel#stateChanged(ChangeEvent)
0255: */
0256: public void addIndexChangeListener(ChangeListener aListener) {
0257: this .sqlTab.addChangeListener(aListener);
0258: }
0259:
0260: public void removeIndexChangeListener(ChangeListener aListener) {
0261: this .sqlTab.removeChangeListener(aListener);
0262: }
0263:
0264: public void addExecutionListener(DbExecutionListener l) {
0265: int count = this .sqlTab.getTabCount();
0266: for (int i = 0; i < count; i++) {
0267: MainPanel p = this .getSqlPanel(i);
0268: if (p instanceof SqlPanel) {
0269: ((SqlPanel) p).addDbExecutionListener(l);
0270: }
0271: }
0272: }
0273:
0274: public void removeExecutionListener(DbExecutionListener l) {
0275: int count = this .sqlTab.getTabCount();
0276: for (int i = 0; i < count; i++) {
0277: MainPanel p = this .getSqlPanel(i);
0278: if (p instanceof SqlPanel) {
0279: ((SqlPanel) p).removeDbExecutionListener(l);
0280: }
0281: }
0282: }
0283:
0284: protected void checkWorkspaceActions() {
0285: this .saveWorkspaceAction
0286: .setEnabled(this .currentWorkspaceFile != null);
0287: this .assignWorkspaceAction
0288: .setEnabled(this .currentWorkspaceFile != null
0289: && this .currentProfile != null);
0290: this .closeWorkspaceAction
0291: .setEnabled(this .currentWorkspaceFile != null);
0292: }
0293:
0294: private void initMenu() {
0295: this .disconnectAction = new FileDisconnectAction(this );
0296: this .disconnectAction.setEnabled(false);
0297: this .assignWorkspaceAction = new AssignWorkspaceAction(this );
0298: this .closeWorkspaceAction = new CloseWorkspaceAction(this );
0299: this .saveAsWorkspaceAction = new SaveAsNewWorkspaceAction(this );
0300:
0301: this .createNewConnection = new CreateNewConnection(this );
0302: this .disconnectTab = new DisconnectTabAction(this );
0303:
0304: this .loadWorkspaceAction = new LoadWorkspaceAction(this );
0305: this .saveWorkspaceAction = new SaveWorkspaceAction(this );
0306:
0307: this .createMacro = new AddMacroAction();
0308:
0309: this .createMacro.setEnabled(false);
0310: this .manageMacros = new ManageMacroAction(this );
0311:
0312: this .dbExplorerAction = new ShowDbExplorerAction(this );
0313: this .dbExplorerAction.setEnabled(false);
0314:
0315: this .newDbExplorerPanel = new NewDbExplorerPanelAction(this );
0316: this .newDbExplorerPanel.setEnabled(false);
0317:
0318: this .newDbExplorerWindow = new NewDbExplorerWindowAction(this );
0319: this .newDbExplorerWindow.setEnabled(false);
0320:
0321: int tabCount = this .sqlTab.getTabCount();
0322: for (int tab = 0; tab < tabCount; tab++) {
0323: MainPanel sql = (MainPanel) this .sqlTab.getComponentAt(tab);
0324: JMenuBar menuBar = this .createMenuForPanel(sql);
0325: this .panelMenus.add(menuBar);
0326: }
0327: }
0328:
0329: private JMenuBar createMenuForPanel(MainPanel aPanel) {
0330: HashMap<String, JMenu> menus = new HashMap<String, JMenu>(10);
0331:
0332: JMenuBar menuBar = new JMenuBar();
0333: menuBar.setBorderPainted(false);
0334: menuBar.putClientProperty("jgoodies.headerStyle", "Single");
0335:
0336: // Create the file menu for all tabs
0337: JMenu menu = new WbMenu(ResourceMgr
0338: .getString(ResourceMgr.MNU_TXT_FILE));
0339: menu.setName(ResourceMgr.MNU_TXT_FILE);
0340: menuBar.add(menu);
0341: menus.put(ResourceMgr.MNU_TXT_FILE, menu);
0342:
0343: WbAction action;
0344:
0345: action = new FileConnectAction(this );
0346: action.addToMenu(menu);
0347: this .disconnectAction.addToMenu(menu);
0348: menu.addSeparator();
0349: this .createNewConnection.addToMenu(menu);
0350: this .disconnectTab.addToMenu(menu);
0351: menu.addSeparator();
0352:
0353: action = new FileSaveProfiles();
0354: action.addToMenu(menu);
0355:
0356: action = new FileNewWindowAction();
0357: action.addToMenu(menu);
0358:
0359: // now create the menus for the current tab
0360: List actions = aPanel.getActions();
0361:
0362: // Create the menus in the correct order
0363: menu = new WbMenu(ResourceMgr
0364: .getString(ResourceMgr.MNU_TXT_EDIT));
0365: menu.setName(ResourceMgr.MNU_TXT_EDIT);
0366: menu.setVisible(false);
0367: menuBar.add(menu);
0368: menus.put(ResourceMgr.MNU_TXT_EDIT, menu);
0369:
0370: menu = new WbMenu(ResourceMgr
0371: .getString(ResourceMgr.MNU_TXT_VIEW));
0372: menu.setName(ResourceMgr.MNU_TXT_VIEW);
0373: menu.setVisible(true);
0374: menuBar.add(menu);
0375: menus.put(ResourceMgr.MNU_TXT_VIEW, menu);
0376:
0377: int tabCount = this .sqlTab.getTabCount();
0378: for (int i = 0; i < tabCount; i++) {
0379: action = new SelectTabAction(this .sqlTab, i);
0380: menu.add(action.getMenuItem());
0381: }
0382:
0383: menu = new WbMenu(ResourceMgr
0384: .getString(ResourceMgr.MNU_TXT_DATA));
0385: menu.setName(ResourceMgr.MNU_TXT_DATA);
0386: menu.setVisible(false);
0387: menuBar.add(menu);
0388: menus.put(ResourceMgr.MNU_TXT_DATA, menu);
0389:
0390: menu = new WbMenu(ResourceMgr
0391: .getString(ResourceMgr.MNU_TXT_SQL));
0392: menu.setName(ResourceMgr.MNU_TXT_SQL);
0393: menu.setVisible(false);
0394: menuBar.add(menu);
0395: menus.put(ResourceMgr.MNU_TXT_SQL, menu);
0396:
0397: if (aPanel instanceof SqlPanel) {
0398: final WbMenu macroMenu = new WbMenu(ResourceMgr
0399: .getString(ResourceMgr.MNU_TXT_MACRO));
0400: macroMenu.setName(ResourceMgr.MNU_TXT_MACRO);
0401: macroMenu.setVisible(true);
0402: menuBar.add(macroMenu);
0403: menus.put(ResourceMgr.MNU_TXT_MACRO, macroMenu);
0404: buildMacroMenu(macroMenu);
0405: }
0406:
0407: menu = new WbMenu(ResourceMgr
0408: .getString(ResourceMgr.MNU_TXT_WORKSPACE));
0409: menu.setName(ResourceMgr.MNU_TXT_WORKSPACE);
0410: menuBar.add(menu);
0411: menus.put(ResourceMgr.MNU_TXT_WORKSPACE, menu);
0412: menu.add(this .saveWorkspaceAction);
0413: menu.add(this .saveAsWorkspaceAction);
0414: menu.add(this .loadWorkspaceAction);
0415: menu.addSeparator();
0416: menu.add(this .closeWorkspaceAction);
0417: menu.addSeparator();
0418: menu.add(this .assignWorkspaceAction);
0419:
0420: WbMenu submenu = null;
0421: String menuName = null;
0422: for (int i = 0; i < actions.size(); i++) {
0423: submenu = null;
0424: action = null;
0425: menuName = null;
0426: Object entry = actions.get(i);
0427: boolean menuSep = false;
0428: if (entry instanceof WbAction) {
0429: action = (WbAction) actions.get(i);
0430: menuName = action.getMenuItemName();
0431: menuSep = action.getCreateMenuSeparator();
0432: } else if (entry instanceof WbMenu) {
0433: submenu = (WbMenu) entry;
0434: menuName = submenu.getParentMenuId();
0435: menuSep = submenu.getCreateMenuSeparator();
0436: }
0437:
0438: if (menuName == null) {
0439: LogMgr.logWarning(this , "Action " + action.getClass()
0440: + " does not define a main menu entry!");
0441: continue;
0442: }
0443: menu = menus.get(menuName);
0444: if (menu == null) {
0445: menu = new WbMenu(ResourceMgr.getString(menuName));
0446: menuBar.add(menu);
0447: menus.put(menuName, menu);
0448: }
0449:
0450: if (menuSep) {
0451: menu.addSeparator();
0452: }
0453: if (action != null) {
0454: action.addToMenu(menu);
0455: } else if (submenu != null) {
0456: menu.add(submenu);
0457: }
0458: menu.setVisible(true);
0459: }
0460:
0461: menu = menus.get(ResourceMgr.MNU_TXT_FILE);
0462: menu.addSeparator();
0463: menu.add(new ManageDriversAction());
0464: menu.addSeparator();
0465:
0466: action = new FileExitAction();
0467: menu.add(action.getMenuItem());
0468:
0469: menu = menus.get(workbench.resource.ResourceMgr.MNU_TXT_VIEW);
0470: AddTabAction add = new AddTabAction(this );
0471: menu.addSeparator();
0472: menu.add(add.getMenuItem());
0473: InsertTabAction insert = new InsertTabAction(this );
0474: menu.add(insert.getMenuItem());
0475:
0476: RemoveTabAction rem = new RemoveTabAction(this );
0477: menu.add(rem.getMenuItem());
0478: menu.addSeparator();
0479: ViewLineNumbers v = new ViewLineNumbers();
0480: v.addToMenu(menu);
0481:
0482: WbAction vTb = new ViewToolbarAction();
0483: vTb.addToMenu(menu);
0484:
0485: menuBar.add(this .buildToolsMenu());
0486: menuBar.add(this .buildHelpMenu());
0487:
0488: aPanel.addToToolbar(this .dbExplorerAction, true);
0489: return menuBar;
0490: }
0491:
0492: /**
0493: * Removes or makes the toolbar visible depending on
0494: * {@link Settings#getShowToolbar}. This method will
0495: * <i>validate</i> this' {@link #getContentPane content pane}
0496: * in case a change on the toolbar's visibility is performed.
0497: */
0498: private void updateToolbarVisibility() {
0499: boolean needInvalidate = false;
0500: final Container content = this .getContentPane();
0501: if (this .currentToolbar != null) {
0502: content.remove(this .currentToolbar);
0503: this .currentToolbar = null;
0504: needInvalidate = true;
0505: }
0506:
0507: if (Settings.getInstance().getShowToolbar()) {
0508: final MainPanel curPanel = this .getCurrentPanel();
0509: if (curPanel != null) {
0510: this .currentToolbar = curPanel.getToolbar();
0511: content.add(this .currentToolbar, BorderLayout.NORTH);
0512: needInvalidate = true;
0513: }
0514: }
0515: if (needInvalidate) {
0516: content.validate();
0517: }
0518: }
0519:
0520: public void propertyChange(PropertyChangeEvent evt) {
0521: if (Settings.PROPERTY_SHOW_TOOLBAR
0522: .equals(evt.getPropertyName())) {
0523: this
0524: .setShowToolbar(Settings.getInstance()
0525: .getShowToolbar());
0526: }
0527: }
0528:
0529: private void setShowToolbar(final boolean show) {
0530: final MainPanel current = this .getCurrentPanel();
0531: if (current != null) {
0532: this .updateToolbarVisibility();
0533: }
0534: }
0535:
0536: private void checkViewMenu(int index) {
0537: JMenu view = getViewMenu(index);
0538: int count = view.getItemCount();
0539: MainPanel p = getCurrentPanel();
0540: boolean isExplorer = (p instanceof DbExplorerPanel);
0541: for (int i = 0; i < count; i++) {
0542: JMenuItem item = view.getItem(i);
0543: if (item == null)
0544: continue;
0545: Action a = item.getAction();
0546: if (a instanceof RemoveTabAction) {
0547: a.setEnabled(isExplorer || canCloseTab());
0548: }
0549: }
0550: }
0551:
0552: private void checkMacroMenuForPanel(int index) {
0553: MainPanel p = this .getSqlPanel(index);
0554: try {
0555: JMenu macro = this .getMacroMenu(index);
0556: setItemStates(macro, p.isConnected());
0557: } catch (Exception e) {
0558: LogMgr.logError("MainWindow.checkMacroMenuForPanel()",
0559: "Error during macro update", e);
0560: }
0561: }
0562:
0563: private void setMacroMenuEnabled(boolean enabled) {
0564: int count = this .sqlTab.getTabCount();
0565: for (int i = 0; i < count; i++) {
0566: JMenu macro = this .getMacroMenu(i);
0567: setItemStates(macro, enabled);
0568: }
0569: }
0570:
0571: private void setItemStates(JMenu menu, boolean enabled) {
0572: if (menu != null) {
0573: int itemCount = menu.getItemCount();
0574: for (int in = 2; in < itemCount; in++) {
0575: JMenuItem item = menu.getItem(in);
0576: if (item != null)
0577: item.setEnabled(enabled);
0578: }
0579: }
0580: }
0581:
0582: public void macroListChanged() {
0583: int count = this .sqlTab.getTabCount();
0584: for (int i = 0; i < count; i++) {
0585: JMenu macros = this .getMacroMenu(i);
0586: if (macros != null) {
0587: this .buildMacroMenu(macros);
0588: MainPanel p = this .getSqlPanel(i);
0589: this .setItemStates(macros, p.isConnected());
0590: }
0591: }
0592: }
0593:
0594: private void buildMacroMenu(JMenu macroMenu) {
0595: macroMenu.removeAll();
0596: this .createMacro.addToMenu(macroMenu);
0597: this .manageMacros.addToMenu(macroMenu);
0598:
0599: List<String> macros = MacroManager.getInstance().getMacroList();
0600: if (macros == null || macros.size() == 0)
0601: return;
0602:
0603: macroMenu.addSeparator();
0604:
0605: Collections.sort(macros);
0606: int count = macros.size();
0607: RunMacroAction run = null;
0608: int maxItems = Settings.getInstance().getMaxMacrosInMenu();
0609: for (int i = 0; (i < count && i < maxItems); i++) {
0610: String name = macros.get(i);
0611: run = new RunMacroAction(this , name, i + 1);
0612: run.addToMenu(macroMenu);
0613: }
0614: }
0615:
0616: public int getCurrentPanelIndex() {
0617: return this .sqlTab.getSelectedIndex();
0618: }
0619:
0620: public int getIndexForPanel(MainPanel panel) {
0621: int tabCount = this .sqlTab.getTabCount();
0622: for (int i = 0; i < tabCount; i++) {
0623: MainPanel p = this .getSqlPanel(i);
0624: if (p.getId().equals(panel.getId()))
0625: return i;
0626: }
0627: return -1;
0628: }
0629:
0630: public String[] getPanelLabels() {
0631: int tabCount = this .sqlTab.getTabCount();
0632:
0633: int realCount = 0;
0634: for (int i = 0; i < tabCount; i++) {
0635: MainPanel p = this .getSqlPanel(i);
0636: if (p instanceof SqlPanel) {
0637: realCount++;
0638: }
0639: }
0640:
0641: String[] result = new String[realCount];
0642: for (int i = 0; i < realCount; i++) {
0643: MainPanel p = this .getSqlPanel(i);
0644: if (i < 9) {
0645: result[i] = p.getTabTitle() + " &"
0646: + NumberStringCache.getNumberString(i + 1);
0647: } else {
0648: result[i] = p.getTabTitle() + " "
0649: + NumberStringCache.getNumberString(i + 1);
0650: }
0651: }
0652: return result;
0653: }
0654:
0655: public MainPanel getCurrentPanel() {
0656: int index = this .sqlTab.getSelectedIndex();
0657: if (index > -1)
0658: return this .getSqlPanel(index);
0659: else
0660: return null;
0661: }
0662:
0663: public SqlPanel getCurrentSqlPanel() {
0664: MainPanel p = this .getCurrentPanel();
0665: if (p instanceof SqlPanel) {
0666: return (SqlPanel) p;
0667: }
0668: return null;
0669: }
0670:
0671: public MainPanel getSqlPanel(int anIndex) {
0672: try {
0673: return (MainPanel) this .sqlTab.getComponentAt(anIndex);
0674: } catch (Exception e) {
0675: LogMgr.logDebug("MainWindow.getSqlPanel()",
0676: "Invalid index [" + anIndex + "] specified!", e);
0677: return null;
0678: }
0679: }
0680:
0681: public void selectTab(int anIndex) {
0682: this .sqlTab.setSelectedIndex(anIndex);
0683: }
0684:
0685: private boolean isConnectInProgress() {
0686: return this .connectInProgress;
0687: }
0688:
0689: private void clearConnectIsInProgress() {
0690: this .connectInProgress = false;
0691: }
0692:
0693: private void setConnectIsInProgress() {
0694: this .connectInProgress = true;
0695: }
0696:
0697: private void checkConnectionForPanel(final MainPanel aPanel) {
0698: if (aPanel.isConnected())
0699: return;
0700: if (this .isConnectInProgress())
0701: return;
0702:
0703: try {
0704: if (this .currentProfile != null
0705: && this .currentProfile
0706: .getUseSeparateConnectionPerTab()) {
0707: createNewConnectionForPanel(aPanel);
0708: } else if (this .currentConnection != null) {
0709: aPanel.setConnection(this .currentConnection);
0710: }
0711: } catch (Exception e) {
0712: LogMgr.logError("MainWindow.checkConnectionForPanel()",
0713: "Error when checking connection", e);
0714: }
0715: }
0716:
0717: public void disconnectCurrentPanel() {
0718: if (this .currentProfile == null)
0719: return;
0720: if (this .currentProfile.getUseSeparateConnectionPerTab())
0721: return;
0722:
0723: final MainPanel p = this .getCurrentPanel();
0724: WbConnection con = p.getConnection();
0725: if (con == this .currentConnection)
0726: return;
0727:
0728: Thread t = new WbThread("Disconnect panel " + p.getId()) {
0729: public void run() {
0730: disconnectPanel(p);
0731: }
0732: };
0733: t.start();
0734: }
0735:
0736: protected void disconnectPanel(final MainPanel panel) {
0737: if (this .isConnectInProgress())
0738: return;
0739: setConnectIsInProgress();
0740: showDisconnectInfo();
0741: showStatusMessage(ResourceMgr.getString("MsgDisconnecting"));
0742: try {
0743: WbConnection old = panel.getConnection();
0744: panel.disconnect();
0745: ConnectionMgr.getInstance().disconnect(old);
0746: panel.setConnection(currentConnection);
0747: int index = this .getIndexForPanel(panel);
0748: sqlTab.setForegroundAt(index, null);
0749: } catch (Throwable e) {
0750: LogMgr.logError("MainWindow.connectPanel()",
0751: "Error when disconnecting panel " + panel.getId(),
0752: e);
0753: String error = ExceptionUtil.getDisplay(e);
0754: WbSwingUtilities.showErrorMessage(this , error);
0755: } finally {
0756: showStatusMessage("");
0757: closeConnectingInfo();
0758: clearConnectIsInProgress();
0759: }
0760:
0761: EventQueue.invokeLater(new Runnable() {
0762: public void run() {
0763: createNewConnection.checkState();
0764: disconnectTab.checkState();
0765: }
0766: });
0767: }
0768:
0769: public boolean canUseSeparateConnection() {
0770: if (this .currentProfile == null)
0771: return false;
0772: return !this .currentProfile.getUseSeparateConnectionPerTab();
0773: }
0774:
0775: public boolean usesSeparateConnection() {
0776: if (!canUseSeparateConnection())
0777: return false;
0778: final MainPanel current = this .getCurrentPanel();
0779: WbConnection conn = current.getConnection();
0780:
0781: return (currentConnection != null && conn != this .currentConnection);
0782: }
0783:
0784: public void createNewConnectionForCurrentPanel() {
0785: final MainPanel panel = getCurrentPanel();
0786: createNewConnectionForPanel(panel);
0787: EventQueue.invokeLater(new Runnable() {
0788: public void run() {
0789: int index = getIndexForPanel(panel);
0790: sqlTab.setForegroundAt(index, Color.BLUE);
0791: }
0792: });
0793: }
0794:
0795: protected void createNewConnectionForPanel(final MainPanel aPanel) {
0796: if (this .isConnectInProgress())
0797: return;
0798: if (this .connectThread != null)
0799: return;
0800:
0801: this .connectThread = new WbThread("Panel Connect "
0802: + aPanel.getId()) {
0803: public void run() {
0804: connectPanel(aPanel);
0805: }
0806: };
0807: this .connectThread.start();
0808: }
0809:
0810: /**
0811: * Connect the given panel to the database. This will always
0812: * create a new physical connection to the database.
0813: */
0814: protected void connectPanel(final MainPanel aPanel) {
0815: if (this .isConnectInProgress())
0816: return;
0817: this .setConnectIsInProgress();
0818: this .showConnectingInfo();
0819: try {
0820: WbConnection conn = this .getConnectionForTab(aPanel, true);
0821: int index = this .getIndexForPanel(aPanel);
0822: this .tabConnected(aPanel, conn, index);
0823: } catch (Throwable e) {
0824: LogMgr.logError("MainWindow.connectPanel()",
0825: "Error when connecting panel " + aPanel.getId(), e);
0826: showStatusMessage("");
0827: String error = ExceptionUtil.getDisplay(e);
0828: String msg = ResourceMgr.getFormattedString(
0829: "ErrConnectFailed", error.trim());
0830: WbSwingUtilities.showErrorMessage(this , msg);
0831: } finally {
0832: closeConnectingInfo();
0833: clearConnectIsInProgress();
0834: this .connectThread = null;
0835: }
0836: }
0837:
0838: public void waitForConnection() {
0839: if (this .connectThread != null) {
0840: try {
0841: this .connectThread.join();
0842: } catch (Exception e) {
0843: e.printStackTrace();
0844: }
0845: }
0846: }
0847:
0848: private void tabConnected(final MainPanel panel, WbConnection conn,
0849: final int anIndex) {
0850: this .closeConnectingInfo();
0851: panel.setConnection(conn);
0852:
0853: WbSwingUtilities.waitForEmptyQueue();
0854: WbSwingUtilities.invoke(new Runnable() {
0855: public void run() {
0856: updateGuiForTab(anIndex);
0857: }
0858: });
0859: }
0860:
0861: protected void updateGuiForTab(int anIndex) {
0862: if (anIndex < 0)
0863: return;
0864:
0865: Container content = this .getContentPane();
0866: final MainPanel current = this .getSqlPanel(anIndex);
0867: if (current == null)
0868: return;
0869:
0870: JMenuBar menu = this .panelMenus.get(anIndex);
0871: if (menu == null)
0872: return;
0873:
0874: this .setJMenuBar(menu);
0875:
0876: this .updateToolbarVisibility();
0877:
0878: this .createNewConnection.checkState();
0879: this .disconnectTab.checkState();
0880:
0881: this .checkMacroMenuForPanel(anIndex);
0882: this .checkViewMenu(anIndex);
0883: SwingUtilities.invokeLater(new Runnable() {
0884: public void run() {
0885: current.panelSelected();
0886: }
0887: });
0888: }
0889:
0890: protected void tabSelected(final int index) {
0891: // Make sure this is executed on the EDT
0892: WbSwingUtilities.invoke(new Runnable() {
0893: public void run() {
0894: updateCurrentTab(index);
0895: }
0896: });
0897: }
0898:
0899: protected void updateCurrentTab(int index) {
0900: MainPanel current = getSqlPanel(index);
0901: if (current == null)
0902: return;
0903: this .updateGuiForTab(index);
0904: this .updateAddMacroAction();
0905: this .updateWindowTitle();
0906: this .checkConnectionForPanel(current);
0907: }
0908:
0909: protected void updateAddMacroAction() {
0910: SqlPanel sql = this .getCurrentSqlPanel();
0911: if (sql != null) {
0912: this .createMacro.setClient(sql.getEditor());
0913: }
0914: }
0915:
0916: public void restoreState() {
0917: String state = Settings.getInstance().getProperty(
0918: this .getClass().getName() + ".state", "0");
0919: int i = 0;
0920: try {
0921: i = Integer.parseInt(state);
0922: } catch (Exception e) {
0923: i = 0;
0924: }
0925: if (i == MAXIMIZED_BOTH) {
0926: this .setExtendedState(i);
0927: }
0928: }
0929:
0930: public void restoreSettings() {
0931: Settings s = Settings.getInstance();
0932:
0933: if (!s.restoreWindowSize(this )) {
0934: this .setSize(950, 750);
0935: }
0936:
0937: if (!s.restoreWindowPosition(this )) {
0938: WbSwingUtilities.center(this , null);
0939: }
0940: }
0941:
0942: public void saveSettings() {
0943: Settings sett = Settings.getInstance();
0944: int state = this .getExtendedState();
0945: sett.setProperty(this .getClass().getName() + ".state", state);
0946:
0947: if (state != MAXIMIZED_BOTH) {
0948: sett.storeWindowPosition(this );
0949: sett.storeWindowSize(this );
0950: }
0951: }
0952:
0953: public void windowOpened(WindowEvent windowEvent) {
0954: }
0955:
0956: public void windowClosed(WindowEvent e) {
0957: }
0958:
0959: public void windowDeiconified(WindowEvent windowEvent) {
0960: }
0961:
0962: public void windowClosing(WindowEvent windowEvent) {
0963: WbManager.getInstance().windowClosing(this );
0964: }
0965:
0966: public void windowDeactivated(WindowEvent windowEvent) {
0967: }
0968:
0969: public void windowActivated(WindowEvent windowEvent) {
0970: // When switching between Applications (using Alt-Tab in Windows)
0971: // sometimes the main menu is selected (as if the Alt key was pressed
0972: // once to activate the menu). This is trying to workaround this bug
0973: // but does not really work in all cases. As this happens with other Java
0974: // applications as well, I think this is a JDK bug.
0975:
0976: // If the "oppositeWindow is not null, then we have a focus switch inside
0977: // our application, so we don't need to do anything
0978: // if (windowEvent.getOppositeWindow() != null) return;
0979: //
0980: // EventQueue.invokeLater(new Runnable()
0981: // {
0982: // public void run()
0983: // {
0984: // JMenu menu = null;
0985: // JMenuBar bar = null;
0986: //
0987: // int index = getCurrentPanelIndex();
0988: // if (panelMenus != null && index > -1)
0989: // {
0990: // bar = panelMenus.get(index);
0991: // if (bar != null)
0992: // {
0993: // try
0994: // {
0995: // menu = bar.getMenu(0);
0996: // }
0997: // catch (Throwable th)
0998: // {
0999: // menu = null;
1000: // }
1001: // }
1002: // }
1003: // try { if (menu != null) menu.setSelected(false); } catch (Throwable th) {}
1004: // try { if (bar != null) bar.setSelected(null); } catch (Throwable th) {}
1005: // }
1006: // });
1007: }
1008:
1009: public void windowIconified(WindowEvent windowEvent) {
1010: }
1011:
1012: /**
1013: * Display a message in the status bar
1014: */
1015: public void showStatusMessage(final String aMsg) {
1016: final MainPanel current = this .getCurrentPanel();
1017: if (current == null)
1018: return;
1019:
1020: WbSwingUtilities.invoke(new Runnable() {
1021: public void run() {
1022: if (StringUtil.isEmptyString(aMsg))
1023: current.clearStatusMessage();
1024: else
1025: current.showStatusMessage(aMsg);
1026: }
1027: });
1028: }
1029:
1030: public void showLogMessage(String aMsg) {
1031: MainPanel current = this .getCurrentPanel();
1032: if (current != null)
1033: current.showLogMessage(aMsg);
1034: }
1035:
1036: public void connectBegin(final ConnectionProfile aProfile) {
1037: if (this .currentWorkspaceFile != null) {
1038: this .saveWorkspace(this .currentWorkspaceFile, true);
1039: }
1040: disconnect(false, false, false);
1041:
1042: // it is important to set this flag, otherwise
1043: // loading the workspace will already trigger a
1044: // panel switch which might cause a connect
1045: // to the current profile before the ConnectionSelector
1046: // has actually finished.
1047: // this has to be set AFTER calling disconnect(), because
1048: // disconnect respects this flag and does nothing...
1049: this .setConnectIsInProgress();
1050:
1051: this .currentProfile = aProfile;
1052:
1053: showStatusMessage(ResourceMgr.getString("MsgLoadingWorkspace"));
1054: loadWorkspaceForProfile(this .currentProfile);
1055:
1056: Settings.getInstance().setLastConnection(this .currentProfile);
1057: showStatusMessage(ResourceMgr.getString("MsgConnecting"));
1058: }
1059:
1060: private String getConnectionIdForPanel(MainPanel p) {
1061: return "Wb" + NumberStringCache.getNumberString(windowId) + "-"
1062: + p.getId();
1063: }
1064:
1065: /**
1066: * Return the internal ID that should be used when connecting
1067: * to the given connection profile
1068: * @return an id specific for the current tab or a "global" id the connection
1069: * is shared between all tabs of this window
1070: */
1071: public String getConnectionId(ConnectionProfile aProfile) {
1072: if (aProfile != null
1073: && aProfile.getUseSeparateConnectionPerTab()) {
1074: return getConnectionIdForPanel(this .getCurrentPanel());
1075: } else {
1076: return "WbWin-"
1077: + NumberStringCache.getNumberString(windowId);
1078: }
1079: }
1080:
1081: private ConnectionSelector getSelector() {
1082: if (this .connectionSelector == null) {
1083: this .connectionSelector = new ConnectionSelector(this , this );
1084: }
1085: return this .connectionSelector;
1086: }
1087:
1088: public void connectTo(ConnectionProfile profile, boolean showDialog) {
1089: getSelector().connectTo(profile, showDialog);
1090: }
1091:
1092: /**
1093: * Call-back function which gets executed on the AWT thread after
1094: * the initial connection has been completed
1095: */
1096: public void connected(WbConnection conn) {
1097: if (this .currentProfile.getUseSeparateConnectionPerTab()) {
1098: this .getCurrentPanel().setConnection(conn);
1099: } else {
1100: this .setConnection(conn);
1101: }
1102: this .setMacroMenuEnabled(true);
1103: this .updateWindowTitle();
1104:
1105: this .dbExplorerAction.setEnabled(true);
1106: this .newDbExplorerPanel.setEnabled(true);
1107: this .newDbExplorerWindow.setEnabled(true);
1108:
1109: this .disconnectAction.setEnabled(true);
1110: this .createNewConnection.checkState();
1111: this .disconnectTab.checkState();
1112: this .getCurrentPanel().clearLog();
1113: this .getCurrentPanel().showResultPanel();
1114:
1115: String warn = conn.getWarnings();
1116: if (warn != null) {
1117: this .getCurrentPanel().showLogMessage(warn);
1118: }
1119: selectCurrentEditor();
1120: }
1121:
1122: public void connectFailed(String error) {
1123: disconnected();
1124: this .updateWindowTitle();
1125:
1126: try {
1127: String msg = ResourceMgr.getFormattedString(
1128: "ErrConnectFailed", error);
1129: WbSwingUtilities.showErrorMessage(this , msg);
1130: } catch (Throwable th) {
1131: LogMgr.logError("MainWindow.connectFailed()",
1132: "Could not display connection error!", th);
1133: WbSwingUtilities.showErrorMessage(this , error);
1134: }
1135: }
1136:
1137: public void connectCancelled() {
1138: if (this .exitOnCancel) {
1139: WbManager.getInstance().windowClosing(this );
1140: }
1141: }
1142:
1143: public void connectEnded() {
1144: for (int i = 0; i < sqlTab.getTabCount(); i++) {
1145: MainPanel sql = getSqlPanel(i);
1146: sql.clearStatusMessage();
1147: }
1148: this .clearConnectIsInProgress();
1149: }
1150:
1151: private static final int CREATE_WORKSPACE = 0;
1152: private static final int LOAD_OTHER_WORKSPACE = 1;
1153: private static final int IGNORE_MISSING_WORKSPACE = 2;
1154:
1155: private int checkNonExistingWorkspace() {
1156: String[] options = new String[] {
1157: ResourceMgr.getString("LblCreateWorkspace"),
1158: ResourceMgr.getString("LblLoadWorkspace"),
1159: ResourceMgr.getString("LblIgnore") };
1160: JOptionPane ignorePane = new JOptionPane(ResourceMgr
1161: .getString("MsgProfileWorkspaceNotFound"),
1162: JOptionPane.QUESTION_MESSAGE,
1163: JOptionPane.YES_NO_CANCEL_OPTION, null, options);
1164: JDialog dialog = ignorePane.createDialog(this ,
1165: ResourceMgr.TXT_PRODUCT_NAME);
1166: try {
1167: dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
1168: dialog.setResizable(true);
1169: dialog.pack();
1170: dialog.setVisible(true);
1171: } finally {
1172: dialog.dispose();
1173: }
1174: Object result = ignorePane.getValue();
1175: if (result == null)
1176: return CREATE_WORKSPACE;
1177: else if (result.equals(options[0]))
1178: return CREATE_WORKSPACE;
1179: else if (result.equals(options[1]))
1180: return LOAD_OTHER_WORKSPACE;
1181: else
1182: return IGNORE_MISSING_WORKSPACE;
1183: }
1184:
1185: private void handleWorkspaceLoadError(Throwable e,
1186: String realFilename) {
1187: String error = ExceptionUtil.getDisplay(e);
1188: String msg = StringUtil.replace(ResourceMgr
1189: .getString("ErrLoadingWorkspace"), "%error%", error);
1190: if (e instanceof OutOfMemoryError) {
1191: msg = ResourceMgr.getString("MsgOutOfMemoryError");
1192: }
1193: boolean create = WbSwingUtilities.getYesNo(this , msg);
1194: if (create) {
1195: this .currentWorkspaceFile = realFilename;
1196: } else {
1197: this .currentWorkspaceFile = null;
1198: }
1199: }
1200:
1201: private void loadDefaultWorkspace() {
1202: if (!this .loadWorkspace(DEFAULT_WORKSPACE)) {
1203: resetWorkspace();
1204: this .currentWorkspaceFile = DEFAULT_WORKSPACE;
1205: }
1206: }
1207:
1208: private void resetWorkspace() {
1209: this .closeWorkspace(false);
1210: this .resetTabTitles();
1211: }
1212:
1213: private boolean resultForWorkspaceClose;
1214:
1215: public boolean loadWorkspace(String filename) {
1216: if (filename == null)
1217: return false;
1218: final String realFilename = FileDialogUtil
1219: .replaceConfigDir(filename);
1220:
1221: File f = new File(realFilename);
1222: if (!f.exists()) {
1223: // if the file does not exist, set all variables as if it did
1224: // thus the file will be created automatically.
1225: this .resetWorkspace();
1226: this .currentWorkspaceFile = realFilename;
1227: this .updateWindowTitle();
1228: this .checkWorkspaceActions();
1229: return true;
1230: }
1231:
1232: this .currentWorkspaceFile = null;
1233: this .resultForWorkspaceClose = false;
1234:
1235: WbSwingUtilities.invoke(new Runnable() {
1236: public void run() {
1237: WbWorkspace w = null;
1238: try {
1239: //removeAllPanels();
1240:
1241: w = new WbWorkspace(realFilename, false);
1242: int entryCount = w.getEntryCount();
1243: if (entryCount == 0)
1244: entryCount = 1;
1245:
1246: adjustTabCount(entryCount);
1247:
1248: int explorerCount = w.getDbExplorerVisibleCount();
1249:
1250: adjustDbExplorerCount(explorerCount);
1251:
1252: int count = sqlTab.getTabCount();
1253: for (int i = 0; i < count; i++) {
1254: MainPanel p = getSqlPanel(i);
1255: p.readFromWorkspace(w, i);
1256: if (p instanceof SqlPanel) {
1257: SqlPanel sql = (SqlPanel) p;
1258: updateViewMenu(i, getPlainTabTitle(i));
1259: }
1260: }
1261: currentWorkspaceFile = realFilename;
1262:
1263: int newIndex = w.getSelectedTab();
1264: if (newIndex < sqlTab.getTabCount()) {
1265: // the stateChanged event will be ignored as we
1266: // have the repainting for the tab suspended
1267: sqlTab.setSelectedIndex(newIndex);
1268: }
1269: resultForWorkspaceClose = true;
1270: } catch (Throwable e) {
1271: LogMgr.logWarning("MainWindow.loadWorkspace()",
1272: "Error loading workspace " + realFilename,
1273: e);
1274: handleWorkspaceLoadError(e, realFilename);
1275: } finally {
1276: try {
1277: w.close();
1278: } catch (Throwable th) {
1279: }
1280: }
1281:
1282: validate();
1283: updateWindowTitle();
1284: checkWorkspaceActions();
1285: updateAddMacroAction();
1286: }
1287: });
1288:
1289: return resultForWorkspaceClose;
1290: }
1291:
1292: private void loadWorkspaceForProfile(ConnectionProfile aProfile) {
1293: String realFilename = null;
1294: try {
1295: String workspaceFilename = aProfile.getWorkspaceFile();
1296: if (workspaceFilename != null
1297: && !workspaceFilename.endsWith(".wksp"))
1298: workspaceFilename += ".wksp";
1299:
1300: realFilename = FileDialogUtil
1301: .replaceConfigDir(workspaceFilename);
1302: if (realFilename == null)
1303: realFilename = "";
1304:
1305: File f = new File(realFilename);
1306: if (realFilename.length() > 0 && !f.exists()) {
1307: int action = this .checkNonExistingWorkspace();
1308: if (action == LOAD_OTHER_WORKSPACE) {
1309: FileDialogUtil util = new FileDialogUtil();
1310: workspaceFilename = util.getWorkspaceFilename(this ,
1311: false, true);
1312: aProfile.setWorkspaceFile(workspaceFilename);
1313: } else if (action == IGNORE_MISSING_WORKSPACE) {
1314: workspaceFilename = null;
1315: aProfile.setWorkspaceFile(null);
1316: } else {
1317: // start with an empty workspace
1318: // and create a new workspace file.
1319: if (!f.isAbsolute()) {
1320: // if no directory was given, assume the configuration directory
1321: workspaceFilename = FileDialogUtil.CONFIG_DIR_KEY
1322: + "/" + workspaceFilename;
1323: }
1324: resetWorkspace();
1325: }
1326: }
1327:
1328: if (workspaceFilename != null
1329: && workspaceFilename.trim().length() > 0) {
1330: // loadWorkspace will replace the %ConfigDir% placeholder,
1331: // so we need to pass the original filename
1332: this .isProfileWorkspace = true;
1333: this .loadWorkspace(workspaceFilename);
1334: } else {
1335: this .loadDefaultWorkspace();
1336: }
1337: } catch (Throwable e) {
1338: LogMgr.logError("MainWindow.loadWorkspaceForProfile()",
1339: "Error reading workspace " + realFilename, e);
1340: this .handleWorkspaceLoadError(e, realFilename);
1341: }
1342: }
1343:
1344: public void disconnect(final boolean background,
1345: final boolean closeWorkspace, final boolean saveWorkspace) {
1346: if (this .isConnectInProgress())
1347: return;
1348: this .setConnectIsInProgress();
1349:
1350: Runnable run = new Runnable() {
1351: public void run() {
1352: if (saveWorkspace)
1353: saveWorkspace(false);
1354: if (background)
1355: showDisconnectInfo();
1356: doDisconnect();
1357: if (closeWorkspace)
1358: closeWorkspace(background);
1359: if (background)
1360: closeConnectingInfo();
1361: }
1362: };
1363:
1364: if (background) {
1365: Thread t = new WbThread(run, "MainWindow Disconnect");
1366: t.start();
1367: } else {
1368: WbSwingUtilities.invoke(run);
1369: }
1370: }
1371:
1372: /**
1373: * This does the real disconnect action.
1374: */
1375: private void doDisconnect() {
1376: try {
1377: ConnectionMgr mgr = ConnectionMgr.getInstance();
1378: WbConnection conn = null;
1379:
1380: for (int i = 0; i < this .sqlTab.getTabCount(); i++) {
1381: final MainPanel sql = (MainPanel) this .sqlTab
1382: .getComponentAt(i);
1383: if (sql instanceof SqlPanel) {
1384: ((SqlPanel) sql).abortExecution();
1385: }
1386: conn = sql.getConnection();
1387: sql.disconnect();
1388: if (conn != null && !conn.isClosed()) {
1389: showStatusMessage(ResourceMgr
1390: .getString("MsgDisconnecting"));
1391: mgr.disconnect(conn);
1392: }
1393: }
1394: this .closeExplorerWindows(true);
1395: } finally {
1396: // this must be called on the AWT thread
1397: // and it must be called synchronously!
1398: WbSwingUtilities.invoke(new Runnable() {
1399: public void run() {
1400: disconnected();
1401: }
1402: });
1403: }
1404: }
1405:
1406: private void disconnected() {
1407: this .currentProfile = null;
1408: this .currentConnection = null;
1409: this .closeWorkspace(false);
1410: this .setMacroMenuEnabled(false);
1411: this .updateWindowTitle();
1412: this .disconnectAction.setEnabled(false);
1413: this .createNewConnection.checkState();
1414: this .disconnectTab.checkState();
1415: this .dbExplorerAction.setEnabled(false);
1416: this .newDbExplorerPanel.setEnabled(false);
1417: this .newDbExplorerWindow.setEnabled(false);
1418: this .showStatusMessage("");
1419: for (int i = 0; i < sqlTab.getTabCount(); i++) {
1420: sqlTab.setForegroundAt(i, null);
1421: }
1422: this .clearConnectIsInProgress();
1423: }
1424:
1425: public boolean abortAll() {
1426: boolean success = true;
1427: try {
1428: for (int i = 0; i < this .sqlTab.getTabCount(); i++) {
1429: MainPanel sql = (MainPanel) this .sqlTab
1430: .getComponentAt(i);
1431: if (sql instanceof SqlPanel) {
1432: SqlPanel sp = (SqlPanel) sql;
1433: success = success && sp.abortExecution();
1434: }
1435: }
1436: } catch (Exception e) {
1437: LogMgr.logWarning("MainWindow.abortAll()",
1438: "Error stopping execution", e);
1439: success = false;
1440: }
1441: return success;
1442: }
1443:
1444: public void selectCurrentEditor() {
1445: MainPanel p = this .getCurrentPanel();
1446: if (p instanceof SqlPanel) {
1447: SqlPanel sql = (SqlPanel) p;
1448: sql.selectEditor();
1449: }
1450: }
1451:
1452: protected String getCurrentEditorFile() {
1453: String filename = null;
1454:
1455: MainPanel p = this .getCurrentPanel();
1456: if (p instanceof SqlPanel) {
1457: SqlPanel sql = (SqlPanel) p;
1458: filename = sql.getCurrentFileName();
1459: }
1460: return filename;
1461: }
1462:
1463: protected void updateWindowTitle() {
1464: WbSwingUtilities.invoke(new Runnable() {
1465: public void run() {
1466: WindowTitleBuilder titleBuilder = new WindowTitleBuilder();
1467: String title = titleBuilder.getWindowTitle(
1468: currentProfile, currentWorkspaceFile,
1469: getCurrentEditorFile());
1470: setTitle(title);
1471: jobIndicator.baseTitleChanged();
1472: }
1473: });
1474: }
1475:
1476: protected void closeConnectingInfo() {
1477: getSelector().closeConnectingInfo();
1478: }
1479:
1480: protected void showDisconnectInfo() {
1481: getSelector().showDisconnectInfo();
1482: }
1483:
1484: /** Display a little PopupWindow to tell the user that the
1485: * workbench is currently connecting to the DB
1486: */
1487: protected void showConnectingInfo() {
1488: getSelector().showConnectingInfo();
1489: }
1490:
1491: private void setConnection(WbConnection con) {
1492: int count = this .sqlTab.getTabCount();
1493: for (int i = 0; i < count; i++) {
1494: MainPanel sql = (MainPanel) this .sqlTab.getComponentAt(i);
1495: sql.setConnection(con);
1496: }
1497: this .currentConnection = con;
1498: if (this .currentProfile == null)
1499: this .currentProfile = con.getProfile();
1500: }
1501:
1502: public void selectConnection() {
1503: selectConnection(false);
1504: }
1505:
1506: private boolean exitOnCancel = false;
1507:
1508: public void selectConnection(boolean exit) {
1509: this .exitOnCancel = exit;
1510: getSelector().selectConnection();
1511: }
1512:
1513: public JMenu getMacroMenu(int panelIndex) {
1514: JMenu menu = this
1515: .getMenu(ResourceMgr.MNU_TXT_MACRO, panelIndex);
1516: return menu;
1517: }
1518:
1519: public JMenu getViewMenu(int panelIndex) {
1520: return this .getMenu(ResourceMgr.MNU_TXT_VIEW, panelIndex);
1521: }
1522:
1523: public JMenu getMenu(String aName, int panelIndex) {
1524: if (panelIndex < 0 || panelIndex >= this .panelMenus.size())
1525: return null;
1526: if (aName == null)
1527: return null;
1528: JMenuBar menubar = this .panelMenus.get(panelIndex);
1529: int count = menubar.getMenuCount();
1530: for (int k = 0; k < count; k++) {
1531: JMenu item = menubar.getMenu(k);
1532: if (item == null)
1533: continue;
1534: if (aName.equals(item.getName()))
1535: return item;
1536: }
1537: return null;
1538: }
1539:
1540: private void updateViewMenu(int sqlTabIndex, String aName) {
1541: int panelCount = this .panelMenus.size();
1542: if (aName == null)
1543: aName = ResourceMgr.getDefaultTabLabel();
1544: for (int i = 0; i < panelCount; i++) {
1545: JMenu view = this .getViewMenu(i);
1546:
1547: int count = view.getItemCount();
1548: for (int k = 0; k < count; k++) {
1549: JMenuItem item = view.getItem(k);
1550: if (item == null)
1551: continue;
1552: Action ac = item.getAction();
1553: if (ac == null)
1554: continue;
1555:
1556: if (ac instanceof SelectTabAction) {
1557: SelectTabAction a = (SelectTabAction) ac;
1558: if (a.getIndex() == sqlTabIndex) {
1559: a.setMenuText(aName);
1560: break;
1561: }
1562: }
1563: }
1564: WbSwingUtilities.repaintNow(view);
1565: }
1566: }
1567:
1568: /**
1569: * Add the approriate menu item to select a given tab
1570: * to the View menu.
1571: */
1572: public void addToViewMenu(SelectTabAction anAction) {
1573: int panelCount = this .panelMenus.size();
1574: int lastActionIndex = -1;
1575:
1576: SelectTabAction lastAction = null;
1577:
1578: for (int i = 0; i < panelCount; i++) {
1579: JMenu view = this .getViewMenu(i);
1580:
1581: // insert the item at the correct index
1582: // (if it is a SelectTabAction)
1583: // otherwise insert it after the last SelectTabAction
1584: int count = view.getItemCount();
1585: int inserted = -1;
1586: for (int k = 0; k < count; k++) {
1587: JMenuItem item = view.getItem(k);
1588: if (item == null)
1589: continue;
1590: Action ac = item.getAction();
1591: if (ac == null)
1592: continue;
1593: if (!(ac instanceof SelectTabAction)) {
1594: break;
1595: }
1596: SelectTabAction a = (SelectTabAction) ac;
1597: lastAction = a;
1598: lastActionIndex = k;
1599:
1600: if (a.getIndex() > anAction.getIndex()) {
1601: view.insert(anAction.getMenuItem(), k);
1602: inserted = k;
1603: break;
1604: }
1605: }
1606:
1607: if (inserted == -1) {
1608: if (lastActionIndex == -1) {
1609: // no index found which is greater or equal than the new one
1610: // so add it to the end
1611: if (!(view.getItem(count - 1).getAction() instanceof SelectTabAction))
1612: view.addSeparator();
1613:
1614: view.add(anAction.getMenuItem());
1615: } else if (lastAction != null
1616: && lastAction.getIndex() != anAction.getIndex()) {
1617: // we found at least one SelectTabAction, so we'll
1618: // insert the new one right behind the last one.
1619: // (there might be other items in the view menu!)
1620:
1621: view.insert(anAction.getMenuItem(),
1622: lastActionIndex + 1);
1623: }
1624: } else {
1625: // renumber the shortcuts for the remaining actions
1626: int newIndex = anAction.getIndex() + 1;
1627: for (int k = inserted + 1; k < panelCount; k++) {
1628: SelectTabAction a = (SelectTabAction) view.getItem(
1629: k).getAction();
1630: a.setNewIndex(newIndex);
1631: newIndex++;
1632: }
1633: }
1634: }
1635: }
1636:
1637: private WbConnection getConnectionForTab(MainPanel aPanel,
1638: boolean returnNew) throws Exception {
1639: if (this .currentConnection != null && !returnNew)
1640: return this .currentConnection;
1641: String id = this .getConnectionIdForPanel(aPanel);
1642:
1643: aPanel.showStatusMessage(ResourceMgr
1644: .getString("MsgConnectingTo")
1645: + " " + this .currentProfile.getName() + " ...");
1646: ConnectionMgr mgr = ConnectionMgr.getInstance();
1647: WbConnection conn = null;
1648: try {
1649: conn = mgr.getConnection(this .currentProfile, id);
1650: } finally {
1651: aPanel.clearStatusMessage();
1652: }
1653: return conn;
1654: }
1655:
1656: public void addDbExplorerTab(DbExplorerPanel explorer) {
1657: JMenuBar dbmenu = this .createMenuForPanel(explorer);
1658:
1659: this .sqlTab.add(explorer);
1660: explorer
1661: .setTabTitle(this .sqlTab, this .sqlTab.getTabCount() - 1);
1662:
1663: SelectTabAction action = new SelectTabAction(this .sqlTab,
1664: this .sqlTab.getTabCount() - 1);
1665: action.setMenuText(explorer.getTabTitle());
1666: this .panelMenus.add(dbmenu);
1667: this .addToViewMenu(action);
1668: }
1669:
1670: /**
1671: * Displays the DbExplorer. Either in a separate tab,
1672: * or as a new window. If an explorer window is already open
1673: * that instance will be re-used
1674: */
1675: public void showDbExplorer() {
1676: boolean useTab = Settings.getInstance()
1677: .getShowDbExplorerInMainWindow();
1678: if (useTab) {
1679: int index = this .findFirstExplorerTab();
1680: if (index > -1) {
1681: this .selectTab(index);
1682: } else {
1683: this .newDbExplorerPanel(true);
1684: }
1685: } else {
1686: if (this .explorerWindows.size() > 0) {
1687: ToolWindow w = this .explorerWindows.get(0);
1688: w.activate();
1689: } else {
1690: this .newDbExplorerWindow();
1691: }
1692: }
1693: }
1694:
1695: /**
1696: * Returns the index of the las SQL Panel
1697: */
1698: public int getLastSqlPanelIndex() {
1699: int explorer = findFirstExplorerTab();
1700: if (explorer == -1)
1701: return this .sqlTab.getTabCount() - 1;
1702: else
1703: return explorer - 1;
1704: }
1705:
1706: /**
1707: * Returns the index of the first explorer tab
1708: */
1709: private int findFirstExplorerTab() {
1710: int count = this .sqlTab.getTabCount();
1711: for (int i = 0; i < count; i++) {
1712: Component c = this .sqlTab.getComponentAt(i);
1713: if (c instanceof DbExplorerPanel) {
1714: return i;
1715: }
1716: }
1717: return -1;
1718: }
1719:
1720: public void closeExplorerWindows(boolean doDisconnect) {
1721: for (ToolWindow w : explorerWindows) {
1722: if (doDisconnect) {
1723: WbConnection conn = w.getConnection();
1724: if (conn != this .currentConnection) {
1725: ConnectionMgr.getInstance().disconnect(conn);
1726: }
1727: w.closeWindow();
1728: }
1729: }
1730: }
1731:
1732: protected void removeAllPanels() {
1733: try {
1734: while (sqlTab.getTabCount() > 1) {
1735: removeTab(1);
1736: }
1737: MainPanel p = getSqlPanel(0);
1738: p.reset();
1739: } catch (Exception e) {
1740: LogMgr.logError("MainWindow.removeAllPanels()",
1741: "Error when removing all panels", e);
1742: }
1743: }
1744:
1745: public void newDbExplorerWindow() {
1746: DbExplorerPanel explorer = new DbExplorerPanel(this );
1747: explorer.restoreSettings();
1748: DbExplorerWindow w = explorer.openWindow(this .currentProfile
1749: .getName());
1750: if (this .currentProfile.getUseSeparateConnectionPerTab()
1751: || this .currentConnection == null) {
1752: explorer.connect(this .currentProfile);
1753: } else {
1754: explorer.setConnection(this .currentConnection);
1755: }
1756: this .explorerWindows.add(w);
1757: }
1758:
1759: public void explorerWindowClosed(DbExplorerWindow w) {
1760: this .explorerWindows.remove(w);
1761: }
1762:
1763: public void newDbExplorerPanel(boolean select) {
1764: DbExplorerPanel explorer = new DbExplorerPanel(this );
1765: explorer.restoreSettings();
1766: this .addDbExplorerTab(explorer);
1767: if (select) {
1768: // Switching to the new tab will initiate the connection if necessary
1769: this .sqlTab.setSelectedIndex(this .sqlTab.getTabCount() - 1);
1770: }
1771: }
1772:
1773: public ConnectionProfile getCurrentProfile() {
1774: return this .currentProfile;
1775: }
1776:
1777: public JMenu buildHelpMenu() {
1778: JMenu result = new WbMenu(ResourceMgr
1779: .getString(ResourceMgr.MNU_TXT_HELP));
1780: result.setName(ResourceMgr.MNU_TXT_HELP);
1781: new ShowHelpAction().addToMenu(result);
1782: new ShowManualAction().addToMenu(result);
1783: result.addSeparator();
1784:
1785: result.add(WhatsNewAction.getInstance());
1786: new VersionCheckAction().addToMenu(result);
1787: new AboutAction().addToMenu(result);
1788:
1789: return result;
1790: }
1791:
1792: /**
1793: * Create the tools menu for a panel menu. This will be called
1794: * for each panel that gets added to the main window.
1795: * Actions that are singletons (like the db explorer stuff)
1796: * should not be created here
1797: */
1798: public JMenu buildToolsMenu() {
1799: JMenu result = new WbMenu(ResourceMgr
1800: .getString(ResourceMgr.MNU_TXT_TOOLS));
1801: result.setName(ResourceMgr.MNU_TXT_TOOLS);
1802:
1803: result.add(this .dbExplorerAction);
1804: result.add(this .newDbExplorerPanel);
1805: result.add(this .newDbExplorerWindow);
1806: result.addSeparator();
1807:
1808: result.add(new DataPumperAction(this ));
1809:
1810: result.addSeparator();
1811:
1812: new OptionsDialogAction().addToMenu(result);
1813: new ConfigureShortcutsAction().addToMenu(result);
1814:
1815: return result;
1816: }
1817:
1818: private boolean checkMakeProfileWorkspace() {
1819: boolean assigned = false;
1820: boolean saveIt = WbSwingUtilities.getYesNo(this , ResourceMgr
1821: .getString("MsgAttachWorkspaceToProfile"));
1822: if (saveIt) {
1823: this .assignWorkspace();
1824: assigned = true;
1825: }
1826: return assigned;
1827: }
1828:
1829: private int getNumberOfExplorerPanels() {
1830: int count = 0;
1831: int num = this .sqlTab.getTabCount();
1832: for (int i = 0; i < num; i++) {
1833: Component c = this .sqlTab.getComponentAt(i);
1834: if (c instanceof DbExplorerPanel)
1835: count++;
1836: }
1837: return count;
1838: }
1839:
1840: private void adjustDbExplorerCount(int newCount) {
1841: int count = this .getNumberOfExplorerPanels();
1842: if (count == newCount)
1843: return;
1844: if (newCount > count) {
1845: for (int i = 0; i < (newCount - count); i++) {
1846: newDbExplorerPanel(false);
1847: }
1848: } else if (newCount < count) {
1849: for (int i = 0; i < (count - newCount); i++) {
1850: this .removeLastTab(true);
1851: }
1852: }
1853: }
1854:
1855: /**
1856: * Creates or removes SQL tabs until newCount tabs are displayed
1857: */
1858: private void adjustTabCount(int newCount) {
1859: int tabCount = this .sqlTab.getTabCount()
1860: - getNumberOfExplorerPanels();
1861:
1862: if (newCount > tabCount) {
1863: for (int i = 0; i < (newCount - tabCount); i++) {
1864: this .addTab(false, false);
1865: }
1866: } else if (newCount < tabCount) {
1867: for (int i = 0; i < (tabCount - newCount); i++) {
1868: this .removeLastTab(newCount == 1);
1869: }
1870: }
1871: }
1872:
1873: /**
1874: * Sets the default title for all tab titles
1875: */
1876: private void resetTabTitles() {
1877: String defaultTitle = ResourceMgr.getDefaultTabLabel();
1878: int count = this .sqlTab.getTabCount();
1879: for (int i = 0; i < count; i++) {
1880: MainPanel p = this .getSqlPanel(i);
1881: if (p == null)
1882: continue;
1883: if (p instanceof SqlPanel) {
1884: SqlPanel sql = (SqlPanel) p;
1885: sql.closeFile(true, false);
1886: this .setTabTitle(i, defaultTitle);
1887: }
1888: }
1889: }
1890:
1891: /**
1892: * Returns true if at least one of the SQL panels is currently
1893: * executing a SQL statement.
1894: * This method calls isBusy() for each tab.
1895: */
1896: public boolean isBusy() {
1897: int count = this .sqlTab.getTabCount();
1898: for (int i = 0; i < count; i++) {
1899: MainPanel p = this .getSqlPanel(i);
1900: if (p.isBusy())
1901: return true;
1902: }
1903: return false;
1904: }
1905:
1906: public String getCurrentWorkspaceFile() {
1907: return this .currentWorkspaceFile;
1908: }
1909:
1910: public void loadWorkspace() {
1911: FileDialogUtil dialog = new FileDialogUtil();
1912: String filename = dialog
1913: .getWorkspaceFilename(this , false, true);
1914: if (filename == null)
1915: return;
1916: if (this .loadWorkspace(filename)) {
1917: this .isProfileWorkspace = this .checkMakeProfileWorkspace();
1918: } else {
1919: this .isProfileWorkspace = false;
1920: }
1921: }
1922:
1923: public void closeWorkspace() {
1924: closeWorkspace(true);
1925: }
1926:
1927: /**
1928: * Closes the current workspace.
1929: * The tab count is reset to 1, the SQL history for the tab will be emptied
1930: * and the workspace filename will be "forgotten".
1931: */
1932: public void closeWorkspace(boolean checkUnsaved) {
1933: this .currentWorkspaceFile = null;
1934: this .isProfileWorkspace = false;
1935:
1936: if (checkUnsaved) {
1937: int count = this .sqlTab.getTabCount();
1938: for (int i = 0; i < count; i++) {
1939: MainPanel p = getSqlPanel(i);
1940: if (p.canCloseTab())
1941: return;
1942: }
1943: }
1944:
1945: WbSwingUtilities.invoke(new Runnable() {
1946: public void run() {
1947: try {
1948: removeAllPanels();
1949: } catch (Exception e) {
1950: LogMgr.logError("MainWindow.closeWorkspace()",
1951: "Error when resetting workspace", e);
1952: }
1953: updateWindowTitle();
1954: checkWorkspaceActions();
1955: }
1956: });
1957: }
1958:
1959: /**
1960: * This will assign the current workspace name to the current profile.
1961: */
1962: public void assignWorkspace() {
1963: if (this .currentWorkspaceFile == null)
1964: return;
1965: if (this .currentProfile == null)
1966: return;
1967: FileDialogUtil util = new FileDialogUtil();
1968: String filename = util
1969: .putConfigDirKey(this .currentWorkspaceFile);
1970: this .currentProfile.setWorkspaceFile(filename);
1971: this .isProfileWorkspace = true;
1972: this .updateWindowTitle();
1973: }
1974:
1975: public boolean saveWorkspace() {
1976: return saveWorkspace(true);
1977: }
1978:
1979: /**
1980: * Save the currently loaded workspace
1981: */
1982: public boolean saveWorkspace(boolean checkUnsaved) {
1983: if (this .currentWorkspaceFile != null) {
1984: return this .saveWorkspace(this .currentWorkspaceFile,
1985: checkUnsaved);
1986: }
1987: return true;
1988: }
1989:
1990: /**
1991: * Saves the current SQL history to a workspace with the given filename
1992: * If filename == null, a SaveAs dialog will be displayed.
1993: * If the workspace is saved with a new name (filename == null) the user
1994: * will be asked if the workspace should be assigned to the current profile
1995: */
1996: public boolean saveWorkspace(String filename, boolean checkUnsaved) {
1997: WbWorkspace w = null;
1998: boolean interactive = false;
1999:
2000: if (filename == null) {
2001: interactive = true;
2002: FileDialogUtil util = new FileDialogUtil();
2003: filename = util.getWorkspaceFilename(this , true);
2004: if (filename == null)
2005: return true;
2006: }
2007:
2008: String realFilename = FileDialogUtil.replaceConfigDir(filename);
2009:
2010: // Make a backup of the existing workspace
2011: // if saving of the workspace fails, the backup
2012: // will be renamed back to the original name
2013: // otherwise it will be deleted if no backups should be made
2014: File f = new File(realFilename);
2015: File bck = new File(realFilename + ".bck");
2016: try {
2017: bck.delete();
2018: f.renameTo(bck);
2019: } catch (Exception e) {
2020: LogMgr.logWarning("MainWindow.saveWorkspace()",
2021: "Error when creating backup file!", e);
2022: }
2023:
2024: try {
2025: int count = this .sqlTab.getTabCount();
2026:
2027: if (checkUnsaved) {
2028: for (int i = 0; i < count; i++) {
2029: MainPanel p = (MainPanel) this .sqlTab
2030: .getComponentAt(i);
2031: if (!p.canCloseTab())
2032: return false;
2033: }
2034: }
2035: w = new WbWorkspace(realFilename, true);
2036: int selected = this .sqlTab.getSelectedIndex();
2037: w.setSelectedTab(selected);
2038: for (int i = 0; i < count; i++) {
2039: MainPanel p = getSqlPanel(i);
2040: p.saveToWorkspace(w, i);
2041: }
2042: if (WbManager.getInstance().outOfMemoryOcurred()) {
2043: // sometimes when an OoM occurred, saving of the workspace
2044: // succeeds but the ZIP file is not written correctly.
2045: // This tries to prevent the old file from beeing overwritten, just in case...
2046: bck.renameTo(new File(realFilename + ".saved"));
2047: } else if (!Settings.getInstance()
2048: .getCreateWorkspaceBackup()) {
2049: bck.delete();
2050: }
2051: } catch (Throwable e) {
2052: LogMgr.logError("MainWindow.saveWorkspace()",
2053: "Error saving workspace: " + filename, e);
2054: WbSwingUtilities.showErrorMessage(this , ResourceMgr
2055: .getString("ErrSavingWorkspace")
2056: + "\n" + ExceptionUtil.getDisplay(e));
2057: } finally {
2058: try {
2059: w.close();
2060: } catch (Throwable th) {
2061: }
2062: }
2063:
2064: this .currentWorkspaceFile = filename;
2065:
2066: if (interactive) {
2067: this .checkMakeProfileWorkspace();
2068: }
2069: this .updateWindowTitle();
2070: this .checkWorkspaceActions();
2071: return true;
2072: }
2073:
2074: /**
2075: * Invoked when the a different SQL panel has been selected
2076: * This fires the tabSelected() method
2077: * @param e a ChangeEvent object
2078: *
2079: */
2080: public void stateChanged(ChangeEvent e) {
2081: if (e.getSource() == this .sqlTab) {
2082: if (this .tabRemovalInProgress)
2083: return;
2084: int index = this .sqlTab.getSelectedIndex();
2085: this .tabSelected(index);
2086: }
2087: }
2088:
2089: public MainPanel insertTab() {
2090: return addTab(true, true, false);
2091: }
2092:
2093: public MainPanel addTab() {
2094: return this .addTab(true, true, true);
2095: }
2096:
2097: /**
2098: * Adds a new SQL tab to the main window. This will be inserted
2099: * before the first DbExplorer tab
2100: *
2101: * @param selectNew if true the new tab is automatically selected
2102: * @param checkConnection if true, the panel will automatically be connected
2103: * this is important if a Profile is used where each panel gets its own
2104: * connection
2105: */
2106: public MainPanel addTab(boolean selectNew, boolean checkConnection) {
2107: return addTab(selectNew, checkConnection, true);
2108: }
2109:
2110: public MainPanel addTab(boolean selectNew, boolean checkConnection,
2111: boolean append) {
2112: int index = -1;
2113: if (append) {
2114: index = this .findFirstExplorerTab();
2115: } else {
2116: index = this .sqlTab.getSelectedIndex() + 1;
2117: }
2118:
2119: if (index == -1)
2120: index = sqlTab.getTabCount();
2121: final SqlPanel sql = new SqlPanel(index + 1);
2122: sql.setConnectionClient(this );
2123: sql.addDbExecutionListener(this );
2124:
2125: if (checkConnection)
2126: this .checkConnectionForPanel(sql);
2127:
2128: JMenuBar menuBar = this .createMenuForPanel(sql);
2129: this .panelMenus.add(index, menuBar);
2130: this .sqlTab.add(sql, index);
2131:
2132: // setTabTitle needs to be called after adding the panel!
2133: // this will set the correct title with Mnemonics
2134: this .setTabTitle(index, ResourceMgr.getDefaultTabLabel());
2135:
2136: this .setMacroMenuEnabled(sql.isConnected());
2137:
2138: this .renumberTabs();
2139:
2140: sql.initDivider(sqlTab.getHeight() - sqlTab.getTabHeight());
2141:
2142: if (selectNew) {
2143: // if no connection was created initially the switcht to a new
2144: // panel will initiate the connection.
2145: this .sqlTab.setSelectedIndex(index);
2146: }
2147:
2148: return sql;
2149: }
2150:
2151: /**
2152: * Returns the real title of a tab (without the index number)
2153: */
2154: private String getPlainTabTitle(int index) {
2155: String title = this .sqlTab.getTitleAt(index);
2156: int pos = title.lastIndexOf(' ');
2157: if (pos > -1) {
2158: title = title.substring(0, pos);
2159: }
2160: return title;
2161: }
2162:
2163: /**
2164: * Sets the title of a tab and appends the index number to
2165: * the title, so that a shortcut Ctrl-n can be defined
2166: */
2167: private void setTabTitle(int anIndex, String aName) {
2168: MainPanel p = this .getSqlPanel(anIndex);
2169: p.setTabName(aName);
2170: p.setTabTitle(this .sqlTab, anIndex);
2171: this .updateViewMenu(anIndex, p.getTabTitle());
2172: }
2173:
2174: public void removeLastTab(boolean includeExplorer) {
2175: int index = this .sqlTab.getTabCount() - 1;
2176: if (!includeExplorer) {
2177: while (this .getSqlPanel(index) instanceof DbExplorerPanel) {
2178: index--;
2179: }
2180: }
2181: this .closeTab(index);
2182: }
2183:
2184: public boolean canCloseTab() {
2185: int numTabs = this .getLastSqlPanelIndex();
2186: int currentIndex = this .sqlTab.getSelectedIndex();
2187: if (currentIndex > numTabs)
2188: return true;
2189: return numTabs > 0;
2190: }
2191:
2192: public boolean canRenameTab() {
2193: boolean canRename = (this .currentWorkspaceFile != null);
2194: MainPanel p = this .getCurrentPanel();
2195: canRename = canRename && (p instanceof SqlPanel);
2196: return canRename;
2197: }
2198:
2199: public void renameTab() {
2200: if (this .getCurrentPanel() instanceof DbExplorerPanel)
2201: return;
2202:
2203: int index = this .sqlTab.getSelectedIndex();
2204:
2205: String oldName = this .getPlainTabTitle(index);
2206: String newName = WbSwingUtilities.getUserInput(this .sqlTab,
2207: ResourceMgr.getString("MsgEnterNewTabName"), oldName);
2208: if (newName != null) {
2209: this .setTabTitle(index, newName);
2210: }
2211: }
2212:
2213: public void removeTab() {
2214: if (!canCloseTab())
2215: return;
2216: int index = this .sqlTab.getSelectedIndex();
2217: this .closeTab(index);
2218: }
2219:
2220: private void renumberTabs() {
2221: int count = this .sqlTab.getTabCount();
2222: for (int i = 0; i < count; i++) {
2223: MainPanel p = this .getSqlPanel(i);
2224: p.setTabTitle(sqlTab, i);
2225: }
2226: for (int panel = 0; panel < count; panel++) {
2227: rebuildViewMenu(panel);
2228: }
2229: }
2230:
2231: /**
2232: * Rebuild the part of the view menu that handles the
2233: * selecting of tabs
2234: */
2235: private void rebuildViewMenu(int panel) {
2236: JMenu menu = this .getViewMenu(panel);
2237: JMenuItem item = menu.getItem(0);
2238: while (item != null
2239: && (item.getAction() instanceof SelectTabAction)) {
2240: menu.remove(0);
2241: item = menu.getItem(0);
2242: }
2243: int count = this .sqlTab.getTabCount();
2244: for (int i = 0; i < count; i++) {
2245: SelectTabAction a = new SelectTabAction(sqlTab, i);
2246: a.setMenuText(getPlainTabTitle(i));
2247: menu.insert(a, i);
2248: }
2249: if (this .sqlTab.getSelectedIndex() == panel) {
2250: WbSwingUtilities.repaintNow(menu);
2251: }
2252: }
2253:
2254: /**
2255: * Moves the current sql tab to the left (i.e. index := index - 1)
2256: * If index == 0 nothing happens
2257: */
2258: public void moveTabLeft() {
2259: int index = this .getCurrentPanelIndex();
2260: if (index <= 0)
2261: return;
2262: moveTab(index, index - 1);
2263: }
2264:
2265: /**
2266: * Moves the current sql tab to the right (i.e. index := index + 1)
2267: * If oldIndex denotes the last SQL Tab, nothing happens
2268: */
2269: public void moveTabRight() {
2270: int index = this .getCurrentPanelIndex();
2271: int lastIndex = this .getLastSqlPanelIndex();
2272: if (index >= lastIndex)
2273: return;
2274: moveTab(index, index + 1);
2275: }
2276:
2277: public void moveTab(int oldIndex, int newIndex) {
2278: SqlPanel p = (SqlPanel) this .getSqlPanel(oldIndex);
2279: JMenuBar oldMenu = this .panelMenus.get(oldIndex);
2280: this .sqlTab.remove(oldIndex);
2281: this .panelMenus.remove(oldIndex);
2282: this .panelMenus.add(newIndex, oldMenu);
2283:
2284: this .sqlTab.add(p, newIndex);
2285: this .sqlTab.setSelectedIndex(newIndex);
2286:
2287: renumberTabs();
2288: this .tabSelected(newIndex);
2289: this .validate();
2290: }
2291:
2292: /**
2293: * Removes the tab at the give location. If the current profile
2294: * uses a separate connection per tab, then a disconnect will be
2295: * triggered as well. This disconnect will be started in a
2296: * background thread.
2297: */
2298: public void closeTab(int index) {
2299: MainPanel panel = this .getSqlPanel(index);
2300: if (panel == null)
2301: return;
2302: if (!panel.canCloseTab())
2303: return;
2304: removeTab(index);
2305: }
2306:
2307: /**
2308: * Removes the indicated tab without checking for modified file etc.
2309: */
2310: protected void removeTab(int index) {
2311: MainPanel panel = this .getSqlPanel(index);
2312: if (panel == null)
2313: return;
2314:
2315: int newTab = -1;
2316:
2317: boolean inProgress = this .isConnectInProgress();
2318: if (!inProgress)
2319: this .setConnectIsInProgress();
2320: try {
2321: this .tabRemovalInProgress = true;
2322: WbConnection conn = panel.getConnection();
2323:
2324: // this does not really close the connection
2325: // it simply tells the panel that it should
2326: // release anything attached to the connection!
2327: // the actual disconnect from the DB is done afterwards
2328: // through the ConnectionMgr in a separate thread
2329: panel.disconnect();
2330: try {
2331: panel.dispose();
2332: } catch (Throwable th) {
2333: LogMgr.logError("MainWindow.removeTab()",
2334: "Error when removing tab", th);
2335: }
2336:
2337: if (this .currentProfile != null
2338: && this .currentProfile
2339: .getUseSeparateConnectionPerTab()
2340: && conn != null) {
2341: final String id = conn.getId();
2342: Thread t = new WbThread("Panel " + panel.getId()
2343: + " disconnect thread") {
2344: public void run() {
2345: ConnectionMgr.getInstance().disconnect(id);
2346: }
2347: };
2348: t.start();
2349: }
2350:
2351: this .panelMenus.remove(index);
2352: this .sqlTab.remove(index);
2353: this .renumberTabs();
2354: newTab = this .sqlTab.getSelectedIndex();
2355: } catch (Throwable e) {
2356: LogMgr.logError("MainWindows.removeTab()",
2357: "Error removing tab index=" + index, e);
2358: } finally {
2359: this .tabRemovalInProgress = false;
2360: if (!inProgress)
2361: this .clearConnectIsInProgress();
2362: }
2363: if (newTab >= 0) {
2364: this .tabSelected(newTab);
2365: }
2366: return;
2367: }
2368:
2369: public void mouseClicked(MouseEvent e) {
2370: if (e.getSource() == this .sqlTab
2371: && e.getButton() == MouseEvent.BUTTON3) {
2372: SqlTabPopup pop = new SqlTabPopup(this );
2373: pop.show(this .sqlTab, e.getX(), e.getY());
2374: }
2375: }
2376:
2377: public void mouseEntered(MouseEvent e) {
2378: }
2379:
2380: public void mouseExited(MouseEvent e) {
2381: }
2382:
2383: public void mousePressed(MouseEvent e) {
2384: }
2385:
2386: public void mouseReleased(MouseEvent e) {
2387: }
2388:
2389: public void executionEnd(WbConnection conn, Object source) {
2390: jobIndicator.jobEnded();
2391: }
2392:
2393: public void executionStart(WbConnection conn, Object source) {
2394: if (Settings.getInstance().getAutoSaveWorkspace()) {
2395: this .saveWorkspace();
2396: }
2397: jobIndicator.jobStarted();
2398: }
2399:
2400: public void dragEnter(
2401: java.awt.dnd.DropTargetDragEvent dropTargetDragEvent) {
2402: dropTargetDragEvent.acceptDrag(DnDConstants.ACTION_COPY);
2403: }
2404:
2405: public void dragExit(java.awt.dnd.DropTargetEvent dropTargetEvent) {
2406: }
2407:
2408: public void dragOver(
2409: java.awt.dnd.DropTargetDragEvent dropTargetDragEvent) {
2410: }
2411:
2412: public void drop(
2413: java.awt.dnd.DropTargetDropEvent dropTargetDropEvent) {
2414: try {
2415: Transferable tr = dropTargetDropEvent.getTransferable();
2416: if (tr.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) {
2417: dropTargetDropEvent
2418: .acceptDrop(DnDConstants.ACTION_COPY);
2419: List fileList = (List) tr
2420: .getTransferData(DataFlavor.javaFileListFlavor);
2421: if (fileList != null) {
2422: int files = fileList.size();
2423: for (int i = 0; i < files; i++) {
2424: File file = (File) fileList.get(i);
2425: this .addTab(true, true, true);
2426: SqlPanel sql = this .getCurrentSqlPanel();
2427: sql.readFile(file.getAbsolutePath(), null);
2428: }
2429: }
2430: } else {
2431: dropTargetDropEvent.rejectDrop();
2432: }
2433: } catch (IOException io) {
2434: LogMgr.logError("MainWindow.drop()",
2435: "Error processing drop event", io);
2436: dropTargetDropEvent.rejectDrop();
2437: } catch (UnsupportedFlavorException ufe) {
2438: LogMgr.logError("MainWindow.drop()",
2439: "Error processing drop event", ufe);
2440: dropTargetDropEvent.rejectDrop();
2441: }
2442: }
2443:
2444: public void dropActionChanged(
2445: java.awt.dnd.DropTargetDragEvent dropTargetDragEvent) {
2446: }
2447:
2448: }
|