001: package net.sourceforge.squirrel_sql.client.gui.session;
002:
003: /*
004: * Copyright (C) 2001-2004 Colin Bell
005: * colbell@users.sourceforge.net
006: *
007: * Modifications Copyright (C) 2003-2004 Jason Height
008: *
009: * This library is free software; you can redistribute it and/or
010: * modify it under the terms of the GNU Lesser General Public
011: * License as published by the Free Software Foundation; either
012: * version 2.1 of the License, or (at your option) any later version.
013: *
014: * This library is distributed in the hope that it will be useful,
015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
017: * Lesser General Public License for more details.
018: *
019: * You should have received a copy of the GNU Lesser General Public
020: * License along with this library; if not, write to the Free Software
021: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
022: */
023: import java.awt.BorderLayout;
024: import java.awt.Font;
025: import java.awt.event.ActionEvent;
026: import java.awt.event.ActionListener;
027: import java.beans.PropertyChangeEvent;
028: import java.beans.PropertyChangeListener;
029: import java.sql.SQLException;
030: import java.util.Vector;
031:
032: import javax.swing.Action;
033: import javax.swing.JComponent;
034: import javax.swing.JPanel;
035: import javax.swing.JTabbedPane;
036: import javax.swing.event.TreeSelectionEvent;
037: import javax.swing.event.TreeSelectionListener;
038: import javax.swing.tree.TreePath;
039:
040: import net.sourceforge.squirrel_sql.client.IApplication;
041: import net.sourceforge.squirrel_sql.client.action.ActionCollection;
042: import net.sourceforge.squirrel_sql.client.session.IObjectTreeAPI;
043: import net.sourceforge.squirrel_sql.client.session.ISQLEntryPanel;
044: import net.sourceforge.squirrel_sql.client.session.ISQLPanelAPI;
045: import net.sourceforge.squirrel_sql.client.session.ISession;
046: import net.sourceforge.squirrel_sql.client.session.action.ExecuteSqlAction;
047: import net.sourceforge.squirrel_sql.client.session.action.FileAppendAction;
048: import net.sourceforge.squirrel_sql.client.session.action.FileCloseAction;
049: import net.sourceforge.squirrel_sql.client.session.action.FileNewAction;
050: import net.sourceforge.squirrel_sql.client.session.action.FileOpenAction;
051: import net.sourceforge.squirrel_sql.client.session.action.FilePrintAction;
052: import net.sourceforge.squirrel_sql.client.session.action.FileSaveAction;
053: import net.sourceforge.squirrel_sql.client.session.action.FileSaveAsAction;
054: import net.sourceforge.squirrel_sql.client.session.action.NextSqlAction;
055: import net.sourceforge.squirrel_sql.client.session.action.PreviousSqlAction;
056: import net.sourceforge.squirrel_sql.client.session.action.RefreshSchemaInfoAction;
057: import net.sourceforge.squirrel_sql.client.session.action.SQLFilterAction;
058: import net.sourceforge.squirrel_sql.client.session.action.SelectSqlAction;
059: import net.sourceforge.squirrel_sql.client.session.action.SessionPropertiesAction;
060: import net.sourceforge.squirrel_sql.client.session.mainpanel.IMainPanelTab;
061: import net.sourceforge.squirrel_sql.client.session.mainpanel.SQLPanel;
062: import net.sourceforge.squirrel_sql.client.session.mainpanel.objecttree.IObjectTreeListener;
063: import net.sourceforge.squirrel_sql.client.session.mainpanel.objecttree.ObjectTreeNode;
064: import net.sourceforge.squirrel_sql.client.session.mainpanel.objecttree.ObjectTreePanel;
065: import net.sourceforge.squirrel_sql.client.session.properties.SessionProperties;
066: import net.sourceforge.squirrel_sql.fw.gui.GUIUtils;
067: import net.sourceforge.squirrel_sql.fw.gui.SQLCatalogsComboBox;
068: import net.sourceforge.squirrel_sql.fw.gui.StatusBar;
069: import net.sourceforge.squirrel_sql.fw.gui.ToolBar;
070: import net.sourceforge.squirrel_sql.fw.id.IIdentifier;
071: import net.sourceforge.squirrel_sql.fw.util.StringManager;
072: import net.sourceforge.squirrel_sql.fw.util.StringManagerFactory;
073: import net.sourceforge.squirrel_sql.fw.util.log.ILogger;
074: import net.sourceforge.squirrel_sql.fw.util.log.LoggerController;
075:
076: public class SessionPanel extends JPanel {
077: private static final long serialVersionUID = 1L;
078:
079: /** Logger for this class. */
080: @SuppressWarnings("unused")
081: private static final ILogger s_log = LoggerController
082: .createLogger(SessionPanel.class);
083:
084: /** Internationalized strings for this class. */
085: @SuppressWarnings("unused")
086: private static final StringManager s_stringMgr = StringManagerFactory
087: .getStringManager(SessionPanel.class);
088:
089: /** Application API. */
090: transient private final IApplication _app;
091:
092: /** ID of the session for this window. */
093: private IIdentifier _sessionId;
094:
095: /** Listener to the sessions properties. */
096: private PropertyChangeListener _propsListener;
097:
098: private MainPanel _mainTabPane;
099: // private JSplitPane _msgSplit;
100:
101: /** Toolbar for window. */
102: private MyToolBar _toolBar;
103:
104: private Vector _externallyAddedToolbarActionsAndSeparators = new Vector();
105:
106: private StatusBar _statusBar = new StatusBar();
107: private boolean _hasBeenVisible;
108:
109: // private boolean _buildingListOfCatalogs = false;
110:
111: private ObjectTreeSelectionListener _objTreeSelectionLis = null;
112:
113: public SessionPanel(ISession session) {
114: super (new BorderLayout());
115:
116: if (session == null) {
117: throw new IllegalArgumentException("ISession == null");
118: }
119:
120: _app = session.getApplication();
121: _sessionId = session.getIdentifier();
122:
123: createGUI(session);
124: propertiesHaveChanged(null);
125:
126: _propsListener = new PropertyChangeListener() {
127: public void propertyChange(PropertyChangeEvent evt) {
128: propertiesHaveChanged(evt.getPropertyName());
129: }
130: };
131: session.getProperties().addPropertyChangeListener(
132: _propsListener);
133:
134: }
135:
136: public void addToToolsPopUp(String selectionString, Action action) {
137: getSQLPaneAPI().addToToolsPopUp(selectionString, action);
138: }
139:
140: // public void setVisible(boolean value)
141: // {
142: public void addNotify() {
143: // super.setVisible(value);
144: super .addNotify();
145: // if (!_hasBeenVisible && value == true)
146: if (!_hasBeenVisible) {
147: _hasBeenVisible = true;
148: // _msgSplit.setDividerLocation(0.9d);
149: // _msgSplit.setResizeWeight(1.0);
150:
151: // Done this late so that plugins have time to register expanders
152: // with the object tree prior to it being built.
153: // getSession().getObjectTreeAPI(_app.getDummyAppPlugin()).refreshTree();
154: _mainTabPane.getObjectTreePanel().refreshTree();
155: }
156: }
157:
158: public boolean hasConnection() {
159: return getSession().getSQLConnection() != null;
160: }
161:
162: /**
163: * Retrieve the session attached to this window.
164: *
165: * @return the session attached to this window.
166: */
167: public ISession getSession() {
168: return _app.getSessionManager().getSession(_sessionId);
169: }
170:
171: public void sessionHasClosed() {
172: if (_objTreeSelectionLis != null) {
173: getObjectTreePanel().removeTreeSelectionListener(
174: _objTreeSelectionLis);
175: _objTreeSelectionLis = null;
176: }
177:
178: final ISession session = getSession();
179: if (session != null) {
180: if (_propsListener != null) {
181: session.getProperties().removePropertyChangeListener(
182: _propsListener);
183: _propsListener = null;
184: }
185: _mainTabPane.sessionClosing(session);
186: _sessionId = null;
187: }
188: }
189:
190: public void sessionWindowClosing() {
191: _mainTabPane.sessionWindowClosing();
192: }
193:
194: /*
195: * TODO: This should not be public. Check all usages of it
196: * and put appropriate methods in an API object.
197: */
198: public ObjectTreePanel getObjectTreePanel() {
199: return _mainTabPane.getObjectTreePanel();
200: }
201:
202: void closeConnection() {
203: try {
204: getSession().closeSQLConnection();
205: } catch (SQLException ex) {
206: showError(ex);
207: }
208: }
209:
210: /**
211: * Select a tab in the main tabbed pane.
212: *
213: * @param tabIndex The tab to select. @see #IMainTabIndexes
214: *
215: * @throws llegalArgumentException
216: * Thrown if an invalid <TT>tabIndex</TT> passed.
217: */
218: public void selectMainTab(int tabIndex) {
219: final JTabbedPane tabPnl = _mainTabPane.getTabbedPane();
220: if (tabIndex >= tabPnl.getTabCount()) {
221: throw new IllegalArgumentException(
222: ""
223: + tabIndex
224: + " is not a valid index into the main tabbed pane.");
225: }
226: if (tabPnl.getSelectedIndex() != tabIndex) {
227: tabPnl.setSelectedIndex(tabIndex);
228: }
229: }
230:
231: public int getSelectedMainTabIndex() {
232: return _mainTabPane.getTabbedPane().getSelectedIndex();
233: }
234:
235: /**
236: * Add a tab to the main tabbed panel.
237: *
238: * tab Describes the tab to be added.
239: *
240: * @return The index of th added tab.
241: *
242: * @throws IllegalArgumentException
243: * If <TT>tab</TT> is <TT>null</TT>.
244: */
245: public int addMainTab(IMainPanelTab tab) {
246: if (tab == null) {
247: throw new IllegalArgumentException("IMainPanelTab == null");
248: }
249: return _mainTabPane.addMainPanelTab(tab);
250: }
251:
252: public void insertMainTab(IMainPanelTab tab, int idx) {
253: insertMainTab(tab, idx, true);
254: }
255:
256: public void insertMainTab(IMainPanelTab tab, int idx,
257: boolean selectInsertedTab) {
258: if (tab == null) {
259: throw new IllegalArgumentException(
260: "Null IMainPanelTab passed");
261: }
262: if (idx == MainPanel.ITabIndexes.SQL_TAB
263: || idx == MainPanel.ITabIndexes.OBJECT_TREE_TAB) {
264: throw new IllegalArgumentException("Index " + idx
265: + "conflicts with standard tabs");
266: }
267:
268: _mainTabPane.insertMainPanelTab(tab, idx, selectInsertedTab);
269: }
270:
271: public int removeMainTab(IMainPanelTab tab) {
272: if (tab == null) {
273: throw new IllegalArgumentException(
274: "Null IMainPanelTab passed");
275: }
276: return _mainTabPane.removeMainPanelTab(tab);
277: }
278:
279: public void setStatusBarMessage(final String msg) {
280: GUIUtils.processOnSwingEventThread(new Runnable() {
281: public void run() {
282: _statusBar.setText(msg);
283: }
284: });
285: }
286:
287: public void setStatusBarProgress(final String msg,
288: final int minimum, final int maximum, final int value) {
289: GUIUtils.processOnSwingEventThread(new Runnable() {
290: public void run() {
291: _statusBar.setStatusBarProgress(msg, minimum, maximum,
292: value);
293: }
294: });
295: }
296:
297: public void setStatusBarProgressFinished() {
298: GUIUtils.processOnSwingEventThread(new Runnable() {
299: public void run() {
300: _statusBar.setStatusBarProgressFinished();
301: }
302: });
303:
304: }
305:
306: public String getStatusBarMessage() {
307: return _statusBar.getText();
308: }
309:
310: SQLPanel getSQLPanel() {
311: return _mainTabPane.getSQLPanel();
312: }
313:
314: public ISQLPanelAPI getSQLPaneAPI() {
315: return _mainTabPane.getSQLPanel().getSQLPanelAPI();
316: }
317:
318: /**
319: * TODO: This shouldn't be public. Its only been done for the JComplete
320: * plugin. At some stage this method will be returned to package visibility.
321: */
322: public ISQLEntryPanel getSQLEntryPanel() {
323: return getSQLPanel().getSQLEntryPanel();
324: }
325:
326: /**
327: * Add the passed action to the session toolbar.
328: *
329: * @param action Action to be added.
330: */
331: public synchronized void addToToolbar(Action action) {
332: _externallyAddedToolbarActionsAndSeparators.add(action);
333: if (null != _toolBar) {
334: _toolBar.add(action);
335: }
336: }
337:
338: public synchronized void addSeparatorToToolbar() {
339: _externallyAddedToolbarActionsAndSeparators
340: .add(new SeparatorMarker());
341: if (null != _toolBar) {
342: _toolBar.addSeparator();
343: }
344: }
345:
346: /**
347: * Add component to the session sheets status bar.
348: *
349: * @param comp Component to add.
350: */
351: public void addToStatusBar(JComponent comp) {
352: _statusBar.addJComponent(comp);
353: }
354:
355: /**
356: * Remove component from the session sheets status bar.
357: *
358: * @param comp Component to remove.
359: */
360: public void removeFromStatusBar(JComponent comp) {
361: _statusBar.remove(comp);
362: }
363:
364: private void showError(Exception ex) {
365: _app.showErrorDialog(ex);
366: }
367:
368: private void propertiesHaveChanged(String propertyName) {
369: final ISession session = getSession();
370: final SessionProperties props = session.getProperties();
371: if (propertyName == null
372: || propertyName
373: .equals(SessionProperties.IPropertyNames.COMMIT_ON_CLOSING_CONNECTION)) {
374: _app.getThreadPool().addTask(new Runnable() {
375: public void run() {
376: session.getSQLConnection().setCommitOnClose(
377: props.getCommitOnClosingConnection());
378: }
379: });
380: }
381: if (propertyName == null
382: || propertyName
383: .equals(SessionProperties.IPropertyNames.SHOW_TOOL_BAR)) {
384: synchronized (this ) {
385: boolean show = props.getShowToolBar();
386: if (show != (_toolBar != null)) {
387: if (show) {
388: if (_toolBar == null) {
389: _toolBar = new MyToolBar(session);
390: for (int i = 0; i < _externallyAddedToolbarActionsAndSeparators
391: .size(); i++) {
392: if (_externallyAddedToolbarActionsAndSeparators
393: .get(i) instanceof Action) {
394: _toolBar
395: .add((Action) _externallyAddedToolbarActionsAndSeparators
396: .get(i));
397: } else {
398: _toolBar.addSeparator();
399: }
400: }
401: add(_toolBar, BorderLayout.NORTH);
402: }
403: } else {
404: if (_toolBar != null) {
405: remove(_toolBar);
406: _toolBar = null;
407: }
408: }
409: }
410: }
411: }
412: }
413:
414: private void createGUI(ISession session) {
415: final IApplication app = session.getApplication();
416:
417: _mainTabPane = new MainPanel(session);
418:
419: add(_mainTabPane, BorderLayout.CENTER);
420:
421: Font fn = app.getFontInfoStore().getStatusBarFontInfo()
422: .createFont();
423: _statusBar.setFont(fn);
424: add(_statusBar, BorderLayout.SOUTH);
425:
426: _objTreeSelectionLis = new ObjectTreeSelectionListener();
427: getObjectTreePanel().addTreeSelectionListener(
428: _objTreeSelectionLis);
429:
430: RowColumnLabel lblRowCol = new RowColumnLabel(_mainTabPane
431: .getSQLPanel().getSQLEntryPanel());
432: addToStatusBar(lblRowCol);
433: validate();
434: }
435:
436: public boolean isSQLTabSelected() {
437: return MainPanel.ITabIndexes.SQL_TAB == _mainTabPane
438: .getTabbedPane().getSelectedIndex();
439: }
440:
441: public boolean isObjectTreeTabSelected() {
442: return MainPanel.ITabIndexes.OBJECT_TREE_TAB == _mainTabPane
443: .getTabbedPane().getSelectedIndex();
444: }
445:
446: private class MyToolBar extends ToolBar {
447: private static final long serialVersionUID = 1L;
448: private IObjectTreeListener _lis;
449: private CatalogsPanel _catalogsPanel;
450:
451: MyToolBar(final ISession session) {
452: super ();
453: createGUI(session);
454: }
455:
456: public void addNotify() {
457: super .addNotify();
458: if (!_hasBeenVisible) {
459: _hasBeenVisible = true;
460: _mainTabPane.getObjectTreePanel().refreshTree();
461: }
462: }
463:
464: public void removeNotify() {
465: super .removeNotify();
466: if (_lis != null) {
467: getObjectTreePanel().removeObjectTreeListener(_lis);
468: _lis = null;
469: }
470: }
471:
472: private void createGUI(ISession session) {
473: _catalogsPanel = new CatalogsPanel(session, this );
474: _catalogsPanel
475: .addActionListener(new CatalogsComboListener());
476:
477: add(_catalogsPanel);
478: ActionCollection actions = session.getApplication()
479: .getActionCollection();
480: setUseRolloverButtons(true);
481: setFloatable(false);
482: add(actions.get(SessionPropertiesAction.class));
483: add(actions.get(RefreshSchemaInfoAction.class));
484: addSeparator();
485: add(actions.get(ExecuteSqlAction.class));
486: addSeparator();
487: // actions.get(ExecuteSqlAction.class).setEnabled(false);
488: add(actions.get(SQLFilterAction.class));
489: // actions.get(SQLFilterAction.class).setEnabled(false);
490: addSeparator();
491: add(actions.get(FileNewAction.class));
492: add(actions.get(FileOpenAction.class));
493: add(actions.get(FileAppendAction.class));
494: add(actions.get(FileSaveAction.class));
495: add(actions.get(FileSaveAsAction.class));
496: add(actions.get(FilePrintAction.class));
497: add(actions.get(FileCloseAction.class));
498: addSeparator();
499: add(actions.get(PreviousSqlAction.class));
500: add(actions.get(NextSqlAction.class));
501: add(actions.get(SelectSqlAction.class));
502:
503: }
504: }
505:
506: private final class CatalogsComboListener implements ActionListener {
507: public void actionPerformed(ActionEvent evt) {
508: String selectedCatalog = SessionPanel.this ._toolBar._catalogsPanel
509: .getSelectedCatalog();
510: if (selectedCatalog != null) {
511: try {
512: ISession session = getSession();
513: session.getSQLConnection().setCatalog(
514: selectedCatalog);
515: refreshSchemaInBackground();
516: } catch (SQLException ex) {
517: getSession().showErrorMessage(ex);
518: SessionPanel.this ._toolBar._catalogsPanel
519: .refreshCatalogs();
520: }
521: }
522: }
523:
524: private void refreshSchemaInBackground() {
525: final ISession session = getSession();
526: session.getApplication().getThreadPool().addTask(
527: new Runnable() {
528: public void run() {
529: session.getSchemaInfo().reloadAll();
530: expandTreeInForeground();
531: }
532: });
533: }
534:
535: private void expandTreeInForeground() {
536:
537: final ISession session = getSession();
538: final String selectedCatalog = SessionPanel.this ._toolBar._catalogsPanel
539: .getSelectedCatalog();
540:
541: GUIUtils.processOnSwingEventThread(new Runnable() {
542: public void run() {
543: expandTablesForCatalog(session, selectedCatalog);
544: }
545: });
546: }
547:
548: /**
549: * Since the catalog has changed, it is necessary to reload the schema info and expand the tables node
550: * in the tree. Saves the user a few clicks.
551: *
552: * @param session
553: * the session whose ObjectTreePanel should be updated
554: * @param selectedCatalog
555: * the catalog that was selected.
556: */
557: private void expandTablesForCatalog(ISession session,
558: String selectedCatalog) {
559: IObjectTreeAPI api = session
560: .getObjectTreeAPIOfActiveSessionWindow();
561: api.refreshTree(true);
562: if (api.selectInObjectTree(selectedCatalog, null, "TABLE")) {
563: ObjectTreeNode[] nodes = api.getSelectedNodes();
564:
565: if (nodes.length > 0) {
566: ObjectTreeNode tableNode = nodes[0];
567:
568: // send a tree expansion event to the object tree
569: api.expandNode(tableNode);
570: }
571: }
572: }
573: }
574:
575: private final class ObjectTreeSelectionListener implements
576: TreeSelectionListener {
577: public void valueChanged(TreeSelectionEvent evt) {
578: final TreePath selPath = evt.getNewLeadSelectionPath();
579: if (selPath != null) {
580: StringBuffer buf = new StringBuffer();
581: Object[] fullPath = selPath.getPath();
582: for (int i = 0; i < fullPath.length; ++i) {
583: if (fullPath[i] instanceof ObjectTreeNode) {
584: ObjectTreeNode node = (ObjectTreeNode) fullPath[i];
585: buf.append('/').append(node.toString());
586: }
587: }
588: setStatusBarMessage(buf.toString());
589: }
590: }
591: }
592:
593: private static class SeparatorMarker {
594:
595: }
596: }
|