0001: package net.sourceforge.squirrel_sql.client.session.mainpanel.objecttree;
0002:
0003: /*
0004: * Copyright (C) 2002-2004 Colin Bell
0005: * colbell@users.sourceforge.net
0006: *
0007: * Modifications Copyright (C) 2003-2004 Jason Height
0008: *
0009: * This library is free software; you can redistribute it and/or
0010: * modify it under the terms of the GNU Lesser General Public
0011: * License as published by the Free Software Foundation; either
0012: * version 2.1 of the License, or (at your option) any later version.
0013: *
0014: * This library is distributed in the hope that it will be useful,
0015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
0016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0017: * Lesser General Public License for more details.
0018: *
0019: * You should have received a copy of the GNU Lesser General Public
0020: * License along with this library; if not, write to the Free Software
0021: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
0022: */
0023: import java.awt.BorderLayout;
0024: import java.awt.Component;
0025: import java.awt.Dimension;
0026: import java.beans.PropertyChangeEvent;
0027: import java.beans.PropertyChangeListener;
0028: import java.util.HashMap;
0029: import java.util.Iterator;
0030: import java.util.List;
0031: import java.util.Map;
0032:
0033: import javax.swing.Action;
0034: import javax.swing.BorderFactory;
0035: import javax.swing.JMenu;
0036: import javax.swing.JPanel;
0037: import javax.swing.JScrollPane;
0038: import javax.swing.JSplitPane;
0039: import javax.swing.JTabbedPane;
0040: import javax.swing.SwingUtilities;
0041: import javax.swing.event.ChangeEvent;
0042: import javax.swing.event.ChangeListener;
0043: import javax.swing.event.TreeModelListener;
0044: import javax.swing.event.TreeSelectionEvent;
0045: import javax.swing.event.TreeSelectionListener;
0046: import javax.swing.tree.TreePath;
0047:
0048: import net.sourceforge.squirrel_sql.client.session.IObjectTreeAPI;
0049: import net.sourceforge.squirrel_sql.client.session.ISession;
0050: import net.sourceforge.squirrel_sql.client.session.mainpanel.objecttree.tabs.BaseDataSetTab;
0051: import net.sourceforge.squirrel_sql.client.session.mainpanel.objecttree.tabs.DatabaseObjectInfoTab;
0052: import net.sourceforge.squirrel_sql.client.session.mainpanel.objecttree.tabs.IObjectTab;
0053: import net.sourceforge.squirrel_sql.client.session.mainpanel.objecttree.tabs.database.CatalogsTab;
0054: import net.sourceforge.squirrel_sql.client.session.mainpanel.objecttree.tabs.database.ConnectionStatusTab;
0055: import net.sourceforge.squirrel_sql.client.session.mainpanel.objecttree.tabs.database.DataTypesTab;
0056: import net.sourceforge.squirrel_sql.client.session.mainpanel.objecttree.tabs.database.KeywordsTab;
0057: import net.sourceforge.squirrel_sql.client.session.mainpanel.objecttree.tabs.database.MetaDataTab;
0058: import net.sourceforge.squirrel_sql.client.session.mainpanel.objecttree.tabs.database.NumericFunctionsTab;
0059: import net.sourceforge.squirrel_sql.client.session.mainpanel.objecttree.tabs.database.SchemasTab;
0060: import net.sourceforge.squirrel_sql.client.session.mainpanel.objecttree.tabs.database.StringFunctionsTab;
0061: import net.sourceforge.squirrel_sql.client.session.mainpanel.objecttree.tabs.database.SystemFunctionsTab;
0062: import net.sourceforge.squirrel_sql.client.session.mainpanel.objecttree.tabs.database.TableTypesTab;
0063: import net.sourceforge.squirrel_sql.client.session.mainpanel.objecttree.tabs.database.TimeDateFunctionsTab;
0064: import net.sourceforge.squirrel_sql.client.session.mainpanel.objecttree.tabs.procedure.ProcedureColumnsTab;
0065: import net.sourceforge.squirrel_sql.client.session.mainpanel.objecttree.tabs.table.ColumnPriviligesTab;
0066: import net.sourceforge.squirrel_sql.client.session.mainpanel.objecttree.tabs.table.ColumnsTab;
0067: import net.sourceforge.squirrel_sql.client.session.mainpanel.objecttree.tabs.table.ContentsTab;
0068: import net.sourceforge.squirrel_sql.client.session.mainpanel.objecttree.tabs.table.ExportedKeysTab;
0069: import net.sourceforge.squirrel_sql.client.session.mainpanel.objecttree.tabs.table.ImportedKeysTab;
0070: import net.sourceforge.squirrel_sql.client.session.mainpanel.objecttree.tabs.table.IndexesTab;
0071: import net.sourceforge.squirrel_sql.client.session.mainpanel.objecttree.tabs.table.PrimaryKeyTab;
0072: import net.sourceforge.squirrel_sql.client.session.mainpanel.objecttree.tabs.table.RowCountTab;
0073: import net.sourceforge.squirrel_sql.client.session.mainpanel.objecttree.tabs.table.RowIDTab;
0074: import net.sourceforge.squirrel_sql.client.session.mainpanel.objecttree.tabs.table.TablePriviligesTab;
0075: import net.sourceforge.squirrel_sql.client.session.mainpanel.objecttree.tabs.table.VersionColumnsTab;
0076: import net.sourceforge.squirrel_sql.client.session.properties.SessionProperties;
0077: import net.sourceforge.squirrel_sql.client.util.IdentifierFactory;
0078: import net.sourceforge.squirrel_sql.fw.datasetviewer.DataSetException;
0079: import net.sourceforge.squirrel_sql.fw.datasetviewer.DataSetUpdateableTableModelListener;
0080: import net.sourceforge.squirrel_sql.fw.gui.GUIUtils;
0081: import net.sourceforge.squirrel_sql.fw.id.IIdentifier;
0082: import net.sourceforge.squirrel_sql.fw.sql.DatabaseObjectType;
0083: import net.sourceforge.squirrel_sql.fw.sql.IDatabaseObjectInfo;
0084: import net.sourceforge.squirrel_sql.fw.sql.ITableInfo;
0085: import net.sourceforge.squirrel_sql.fw.sql.SQLDatabaseMetaData;
0086: import net.sourceforge.squirrel_sql.fw.util.log.ILogger;
0087: import net.sourceforge.squirrel_sql.fw.util.log.LoggerController;
0088:
0089: /**
0090: * This is the panel for the Object Tree tab.
0091: *
0092: * @author <A HREF="mailto:colbell@users.sourceforge.net">Colin Bell</A>
0093: */
0094: public class ObjectTreePanel extends JPanel implements IObjectTreeAPI {
0095:
0096: private static final long serialVersionUID = -2257109602127706539L;
0097:
0098: /** Logger for this class. */
0099: private static final ILogger s_log = LoggerController
0100: .createLogger(ObjectTreePanel.class);
0101:
0102: /** The <TT>IIdentifier</TT> that uniquely identifies this object. */
0103: private IIdentifier _id = IdentifierFactory.getInstance()
0104: .createIdentifier();
0105:
0106: /** Current session. */
0107: private ISession _session;
0108:
0109: /** Tree of objects within the database. */
0110: private ObjectTree _tree;
0111:
0112: /** Split pane between the object tree and the data panel. */
0113: private final JSplitPane _splitPane = new JSplitPane(
0114: JSplitPane.HORIZONTAL_SPLIT);
0115:
0116: /**
0117: * Empty data panel. Used if the object selected in the object
0118: * tree doesn't require a panel.
0119: */
0120: private final ObjectTreeTabbedPane _emptyTabPane;
0121:
0122: /**
0123: * Contains instances of <TT>ObjectTreeTabbedPane</TT> objects keyed by
0124: * the node type. I.E. the tabbed folders for each node type are kept here.
0125: */
0126: private final Map<IIdentifier, ObjectTreeTabbedPane> _tabbedPanes = new HashMap<IIdentifier, ObjectTreeTabbedPane>();
0127:
0128: /** Listens to changes in session properties. */
0129: private SessionPropertiesListener _propsListener;
0130:
0131: /** Listens to changes in each of the tabbed folders. */
0132: private TabbedPaneListener _tabPnlListener;
0133:
0134: private ObjectTreeSelectionListener _objTreeSelLis = null;
0135:
0136: private ObjectTreeTabbedPane _selectedObjTreeTabbedPane = null;
0137:
0138: /** used to save and restore previously selected object tree paths */
0139: private TreePath[] previouslySelectedPaths = null;
0140:
0141: /**
0142: * ctor specifying the current session.
0143: *
0144: * @param session Current session.
0145: *
0146: * @throws IllegalArgumentException
0147: * Thrown if <TT>null</TT> <TT>ISession</TT> passed.
0148: */
0149: public ObjectTreePanel(ISession session) {
0150: super ();
0151: if (session == null) {
0152: throw new IllegalArgumentException("ISession == null");
0153: }
0154: _session = session;
0155:
0156: _emptyTabPane = new ObjectTreeTabbedPane(_session);
0157:
0158: createGUI();
0159:
0160: session.getApplication().getThreadPool().addTask(
0161: new Runnable() {
0162: public void run() {
0163: doBackgroundInitializations();
0164: }
0165: });
0166: }
0167:
0168: private void doBackgroundInitializations() {
0169: try {
0170: // Register tabs to display in the details panel for database nodes.
0171: addDetailTab(DatabaseObjectType.SESSION, new MetaDataTab());
0172: addDetailTab(DatabaseObjectType.SESSION,
0173: new ConnectionStatusTab());
0174:
0175: try {
0176: SQLDatabaseMetaData md = _session.getSQLConnection()
0177: .getSQLMetaData();
0178: if (md.supportsCatalogs()) {
0179: _addDetailTab(DatabaseObjectType.SESSION,
0180: new CatalogsTab());
0181: }
0182: } catch (Throwable th) {
0183: s_log.error("Error in supportsCatalogs()", th);
0184: }
0185:
0186: try {
0187: SQLDatabaseMetaData md = _session.getSQLConnection()
0188: .getSQLMetaData();
0189: if (md.supportsSchemas()) {
0190: _addDetailTab(DatabaseObjectType.SESSION,
0191: new SchemasTab());
0192: }
0193: } catch (Throwable th) {
0194: s_log.error("Error in supportsCatalogs()", th);
0195: }
0196: _addDetailTab(DatabaseObjectType.SESSION,
0197: new TableTypesTab());
0198: _addDetailTab(DatabaseObjectType.SESSION,
0199: new DataTypesTab());
0200: _addDetailTab(DatabaseObjectType.SESSION,
0201: new NumericFunctionsTab());
0202: _addDetailTab(DatabaseObjectType.SESSION,
0203: new StringFunctionsTab());
0204: _addDetailTab(DatabaseObjectType.SESSION,
0205: new SystemFunctionsTab());
0206: _addDetailTab(DatabaseObjectType.SESSION,
0207: new TimeDateFunctionsTab());
0208: _addDetailTab(DatabaseObjectType.SESSION, new KeywordsTab());
0209:
0210: // Register tabs to display in the details panel for catalog nodes.
0211: _addDetailTab(DatabaseObjectType.CATALOG,
0212: new DatabaseObjectInfoTab());
0213:
0214: // Register tabs to display in the details panel for schema nodes.
0215: _addDetailTab(DatabaseObjectType.SCHEMA,
0216: new DatabaseObjectInfoTab());
0217:
0218: _addDetailTabForTableLikeObjects(DatabaseObjectType.TABLE);
0219: _addDetailTabForTableLikeObjects(DatabaseObjectType.VIEW);
0220:
0221: // Register tabs to display in the details panel for procedure nodes.
0222: _addDetailTab(DatabaseObjectType.PROCEDURE,
0223: new DatabaseObjectInfoTab());
0224: _addDetailTab(DatabaseObjectType.PROCEDURE,
0225: new ProcedureColumnsTab());
0226:
0227: // Register tabs to display in the details panel for UDT nodes.
0228: _addDetailTab(DatabaseObjectType.UDT,
0229: new DatabaseObjectInfoTab());
0230:
0231: _session
0232: .getSchemaInfo()
0233: .addSchemaInfoUpdateListener(
0234: new net.sourceforge.squirrel_sql.client.session.schemainfo.SchemaInfoUpdateListener() {
0235: public void schemaInfoUpdated() {
0236: refreshTree(false);
0237: }
0238: });
0239:
0240: } catch (Throwable th) {
0241: s_log
0242: .error(
0243: "Error doing background initalization of Object tree",
0244: th);
0245: }
0246: }
0247:
0248: private void _addDetailTabForTableLikeObjects(
0249: final DatabaseObjectType type) {
0250: GUIUtils.processOnSwingEventThread(new Runnable() {
0251: public void run() {
0252: addDetailTabForTableLikeObjects(type);
0253: }
0254: });
0255: }
0256:
0257: private void addDetailTabForTableLikeObjects(DatabaseObjectType type) {
0258: // Register tabs to display in the details panel for table nodes.
0259: addDetailTab(type, new DatabaseObjectInfoTab());
0260:
0261: ContentsTab conttentsTab = new ContentsTab(this );
0262: conttentsTab
0263: .addListener(new DataSetUpdateableTableModelListener() {
0264: public void forceEditMode(boolean mode) {
0265: onForceEditMode(mode);
0266: }
0267: });
0268: addDetailTab(type, conttentsTab);
0269:
0270: addDetailTab(type, new RowCountTab());
0271: addDetailTab(type, new ColumnsTab());
0272: addDetailTab(type, new PrimaryKeyTab());
0273: addDetailTab(type, new ExportedKeysTab());
0274: addDetailTab(type, new ImportedKeysTab());
0275: addDetailTab(type, new IndexesTab());
0276: addDetailTab(type, new TablePriviligesTab());
0277: addDetailTab(type, new ColumnPriviligesTab());
0278: addDetailTab(type, new RowIDTab());
0279: addDetailTab(type, new VersionColumnsTab());
0280: }
0281:
0282: /**
0283: * Return the unique identifier for this object.
0284: *
0285: * @return the unique identifier for this object.
0286: */
0287: public IIdentifier getIdentifier() {
0288: return _id;
0289: }
0290:
0291: public void addNotify() {
0292: super .addNotify();
0293: _tabPnlListener = new TabbedPaneListener();
0294: _propsListener = new SessionPropertiesListener();
0295: _session.getProperties().addPropertyChangeListener(
0296: _propsListener);
0297:
0298: Iterator<ObjectTreeTabbedPane> it = _tabbedPanes.values()
0299: .iterator();
0300: while (it.hasNext()) {
0301: //setupTabbedPane((ObjectTreeTabbedPane)it.next());
0302: ObjectTreeTabbedPane ottp = it.next();
0303: ottp.getTabbedPane().addChangeListener(_tabPnlListener);
0304: }
0305:
0306: _objTreeSelLis = new ObjectTreeSelectionListener();
0307: _tree.addTreeSelectionListener(_objTreeSelLis);
0308: }
0309:
0310: public void removeNotify() {
0311: super .removeNotify();
0312:
0313: if (_propsListener != null) {
0314: _session.getProperties().removePropertyChangeListener(
0315: _propsListener);
0316: _propsListener = null;
0317: }
0318:
0319: Iterator<ObjectTreeTabbedPane> it = _tabbedPanes.values()
0320: .iterator();
0321: while (it.hasNext()) {
0322: ObjectTreeTabbedPane pane = it.next();
0323: pane.getTabbedPane().removeChangeListener(_tabPnlListener);
0324: }
0325: _tabPnlListener = null;
0326: if (_objTreeSelLis != null) {
0327: _tree.removeTreeSelectionListener(_objTreeSelLis);
0328: _objTreeSelLis = null;
0329: }
0330: }
0331:
0332: /**
0333: * Add an expander for the specified database object type.
0334: *
0335: * @param dboType Database object type.
0336: * @param expander Expander called to add children to a parent node.
0337: *
0338: * @throws IllegalArgumentException
0339: * Thrown if a <TT>null</TT> <TT>DatabaseObjectType</TT>
0340: * or <TT>INodeExpander</TT> passed.
0341: */
0342: public void addExpander(DatabaseObjectType dboType,
0343: INodeExpander expander) {
0344: if (dboType == null) {
0345: throw new IllegalArgumentException(
0346: "Null DatabaseObjectType passed");
0347: }
0348: if (expander == null) {
0349: throw new IllegalArgumentException(
0350: "Null INodeExpander passed");
0351: }
0352: _tree.getTypedModel().addExpander(dboType, expander);
0353: }
0354:
0355: /**
0356: * Expands the specified tree node.
0357: *
0358: * @param node the tree node to expand
0359: */
0360: public void expandNode(ObjectTreeNode node) {
0361: IDatabaseObjectInfo info = node.getDatabaseObjectInfo();
0362: TreePath path = getTreePath(info.getCatalogName(), info
0363: .getSchemaName(), info.getSimpleName());
0364: _tree.fireTreeExpanded(path);
0365: }
0366:
0367: private void _addDetailTab(final DatabaseObjectType dboType,
0368: final IObjectTab tab) {
0369: GUIUtils.processOnSwingEventThread(new Runnable() {
0370: public void run() {
0371: addDetailTab(dboType, tab);
0372: }
0373: });
0374: }
0375:
0376: /**
0377: * Add a tab to be displayed in the detail panel for the passed
0378: * database object type type.
0379: *
0380: * @param dboType Database Object type.
0381: * @param tab Tab to be displayed.
0382: *
0383: * @throws IllegalArgumentException
0384: * Thrown when a <TT>null</TT> <TT>DatabaseObjectType</TT> or
0385: * <TT>IObjectPanelTab</TT> passed.
0386: */
0387: public void addDetailTab(DatabaseObjectType dboType, IObjectTab tab) {
0388: if (dboType == null) {
0389: throw new IllegalArgumentException(
0390: "Null DatabaseObjectType passed");
0391: }
0392: if (tab == null) {
0393: throw new IllegalArgumentException(
0394: "IObjectPanelTab == null");
0395: }
0396:
0397: getOrCreateObjectPanelTabbedPane(dboType)
0398: .addObjectPanelTab(tab);
0399: }
0400:
0401: /**
0402: * Add a listener to the object tree for structure changes. I.E nodes
0403: * added/removed.
0404: *
0405: * @param lis The <TT>TreeModelListener</TT> you want added.
0406: *
0407: * @throws IllegalArgumentException
0408: * Thrown if <TT>null</TT> <TT>TreeModelListener</TT> passed.
0409: */
0410: public void addTreeModelListener(TreeModelListener lis) {
0411: if (lis == null) {
0412: throw new IllegalArgumentException(
0413: "TreeModelListener == null");
0414: }
0415: _tree.getModel().addTreeModelListener(lis);
0416: }
0417:
0418: /**
0419: * Remove a structure changes listener from the object tree.
0420: *
0421: * @param lis The <TT>TreeModelListener</TT> you want removed.
0422: *
0423: * @throws IllegalArgumentException
0424: * Thrown if <TT>null</TT> <TT>TreeModelListener</TT> passed.
0425: */
0426: public void removeTreeModelListener(TreeModelListener lis) {
0427: if (lis == null) {
0428: throw new IllegalArgumentException(
0429: "TreeModelListener == null");
0430: }
0431: _tree.getModel().removeTreeModelListener(lis);
0432: }
0433:
0434: /**
0435: * Add a listener to the object tree for selection changes.
0436: *
0437: * @param lis The <TT>TreeSelectionListener</TT> you want added.
0438: *
0439: * @throws IllegalArgumentException
0440: * Thrown if <TT>null</TT> <TT>TreeSelectionListener</TT> passed.
0441: */
0442: public void addTreeSelectionListener(TreeSelectionListener lis) {
0443: if (lis == null) {
0444: throw new IllegalArgumentException(
0445: "TreeSelectionListener == null");
0446: }
0447: _tree.addTreeSelectionListener(lis);
0448: }
0449:
0450: /**
0451: * Remove a listener from the object tree for selection changes.
0452: *
0453: * @param lis The <TT>TreeSelectionListener</TT> you want removed.
0454: *
0455: * @throws IllegalArgumentException
0456: * Thrown if <TT>null</TT> <TT>TreeSelectionListener</TT> passed.
0457: */
0458: public void removeTreeSelectionListener(TreeSelectionListener lis) {
0459: if (lis == null) {
0460: throw new IllegalArgumentException(
0461: "TreeSelectionListener == null");
0462: }
0463: _tree.removeTreeSelectionListener(lis);
0464: }
0465:
0466: /**
0467: * Add a listener to the object tree.
0468: *
0469: * @param lis The <TT>ObjectTreeListener</TT> you want added.
0470: *
0471: * @throws IllegalArgumentException
0472: * Thrown if <TT>null</TT> <TT>ObjectTreeListener</TT> passed.
0473: */
0474: public void addObjectTreeListener(IObjectTreeListener lis) {
0475: if (lis == null) {
0476: throw new IllegalArgumentException(
0477: "IObjectTreeListener == null");
0478: }
0479: _tree.addObjectTreeListener(lis);
0480: }
0481:
0482: /**
0483: * Remove a listener from the object tree.
0484: *
0485: * @param lis The <TT>ObjectTreeListener</TT> you want removed.
0486: *
0487: * @throws IllegalArgumentException
0488: * Thrown if <TT>null</TT> <TT>ObjectTreeListener</TT> passed.
0489: */
0490: public void removeObjectTreeListener(IObjectTreeListener lis) {
0491: if (lis == null) {
0492: throw new IllegalArgumentException(
0493: "IObjectTreeListener == null");
0494: }
0495: _tree.removeObjectTreeListener(lis);
0496: }
0497:
0498: /**
0499: * Add an item to the popup menu for the specified database object type
0500: * in the object tree.
0501: *
0502: * @param dboType Database Object type.
0503: *
0504: * @throws IllegalArgumentException
0505: * Thrown if a <TT>null</passed> <TT>DatabaseObjectType</TT>
0506: * or <TT>Action</TT> passed.
0507: */
0508: public void addToPopup(DatabaseObjectType dboType, Action action) {
0509: if (dboType == null) {
0510: throw new IllegalArgumentException(
0511: "Null DatabaseObjectType passed");
0512: }
0513: if (action == null) {
0514: throw new IllegalArgumentException("Null Action passed");
0515: }
0516: _tree.addToPopup(dboType, action);
0517: }
0518:
0519: /**
0520: * Add an item to the popup menu for all node types in the object
0521: * tree.
0522: *
0523: * @param action Action to add to menu.
0524: *
0525: * @throws IllegalArgumentException
0526: * Thrown if a <TT>null</TT> <TT>Action</TT> passed.
0527: */
0528: public void addToPopup(Action action) {
0529: if (action == null) {
0530: throw new IllegalArgumentException("Null Action passed");
0531: }
0532: _tree.addToPopup(action);
0533: }
0534:
0535: /**
0536: * Add an hierarchical menu to the popup menu for the specified database
0537: * object type.
0538: *
0539: * @param dboType Database object type.
0540: * @param menu <TT>JMenu</TT> to add to menu.
0541: *
0542: * @throws IllegalArgumentException
0543: * Thrown if a <TT>null</TT> <TT>DatabaseObjectType</TT> or
0544: * <TT>JMenu</TT> thrown.
0545: */
0546: public void addToPopup(DatabaseObjectType dboType, JMenu menu) {
0547: if (dboType == null) {
0548: throw new IllegalArgumentException(
0549: "DatabaseObjectType == null");
0550: }
0551: if (menu == null) {
0552: throw new IllegalArgumentException("JMenu == null");
0553: }
0554: _tree.addToPopup(dboType, menu);
0555: }
0556:
0557: /**
0558: * Add an hierarchical menu to the popup menu for all node types.
0559: *
0560: * @param menu <TT>JMenu</TT> to add to menu.
0561: *
0562: * @throws IllegalArgumentException
0563: * Thrown if a <TT>null</TT> <TT>JMenu</TT> thrown.
0564: */
0565: public void addToPopup(JMenu menu) {
0566: if (menu == null) {
0567: throw new IllegalArgumentException("JMenu == null");
0568: }
0569: _tree.addToPopup(menu);
0570: }
0571:
0572: public ISession getSession() {
0573: return _session;
0574: }
0575:
0576: /**
0577: * Return an array of the currently selected nodes.
0578: *
0579: * @return array of <TT>ObjectTreeNode</TT> objects.
0580: */
0581: public ObjectTreeNode[] getSelectedNodes() {
0582: return _tree.getSelectedNodes();
0583: }
0584:
0585: /**
0586: * Return a type-safe list of the currently selected database tables
0587: *
0588: * @return list of <TT>ITableInfo</TT> objects.
0589: */
0590: public List<ITableInfo> getSelectedTables() {
0591: return _tree.getSelectedTables();
0592: }
0593:
0594: /**
0595: * Saves the tree paths that are currently selected. These can then be
0596: * restored with restoreSavedSelectedPaths.
0597: */
0598: public void saveSelectedPaths() {
0599: previouslySelectedPaths = _tree.getSelectionPaths();
0600: }
0601:
0602: /**
0603: * Used to restore selected tree paths that were saved with saveSelectedPaths.
0604: */
0605: public void restoreSavedSelectedPaths() {
0606: _tree.setSelectionPaths(previouslySelectedPaths);
0607: _tree.requestFocusInWindow();
0608: }
0609:
0610: /**
0611: * Return an array of the currently selected database
0612: * objects. This is guaranteed to be non-null.
0613: *
0614: * @return array of <TT>ObjectTreeNode</TT> objects.
0615: */
0616: public IDatabaseObjectInfo[] getSelectedDatabaseObjects() {
0617: return _tree.getSelectedDatabaseObjects();
0618: }
0619:
0620: /**
0621: * Retrieve details about all object types that can be in this
0622: * tree.
0623: *
0624: * @return DatabaseObjectType[] Array of object type info objects.
0625: */
0626: public DatabaseObjectType[] getDatabaseObjectTypes() {
0627: return _tree.getTypedModel().getDatabaseObjectTypes();
0628: }
0629:
0630: /**
0631: * Refresh object tree.
0632: */
0633: public void refreshTree() {
0634: refreshTree(false);
0635: }
0636:
0637: public void refreshTree(boolean reloadSchemaInfo) {
0638: _tree.refresh(reloadSchemaInfo);
0639: }
0640:
0641: /**
0642: * Refresh the nodes currently selected in the object tree.
0643: */
0644: public void refreshSelectedNodes() {
0645: _tree.refreshSelectedNodes();
0646: }
0647:
0648: /**
0649: * Remove one or more nodes from the tree.
0650: *
0651: * @param nodes Array of nodes to be removed.
0652: *
0653: * @throws IllegalArgumentException
0654: * Thrown if a <TT>null</TT> <TT>ObjectTreeNode[]</TT> thrown.
0655: */
0656: public void removeNodes(ObjectTreeNode[] nodes) {
0657: if (nodes == null) {
0658: throw new IllegalArgumentException(
0659: "ObjectTreeNode[] == null");
0660: }
0661: ObjectTreeModel model = _tree.getTypedModel();
0662: for (int i = 0; i < nodes.length; ++i) {
0663: model.removeNodeFromParent(nodes[i]);
0664: }
0665: }
0666:
0667: public IObjectTab getTabbedPaneIfSelected(
0668: DatabaseObjectType dbObjectType, String title) {
0669: return getTabbedPane(dbObjectType).getTabIfSelected(title);
0670: }
0671:
0672: /**
0673: * Calls refreshComponent on the selected tab in the current
0674: * ObjectTreeTabbedPane, if the selected tab happens to be a BaseDataSetTab
0675: * type.
0676: *
0677: * @throws DataSetException if there was a problem refreshing the component.
0678: */
0679: public void refreshSelectedTab() throws DataSetException {
0680: if (_selectedObjTreeTabbedPane != null) {
0681: IObjectTab tab = _selectedObjTreeTabbedPane
0682: .getSelectedTab();
0683: if (tab != null) {
0684: if (tab instanceof BaseDataSetTab) {
0685: BaseDataSetTab btab = (BaseDataSetTab) tab;
0686: btab.refreshComponent();
0687: }
0688: }
0689: }
0690: }
0691:
0692: /**
0693: * Tries to locate the object given by the paramteres in the Object tree.
0694: * The first matching object found is selected.
0695: *
0696: * @param catalog null means any catalog
0697: * @param schema null means any schema
0698: * @return true if the Object was found and selected.
0699: */
0700: public boolean selectInObjectTree(String catalog, String schema,
0701: String object) {
0702: if ("".equals(object)) {
0703: return false;
0704: }
0705:
0706: TreePath treePath = getTreePath(catalog, schema, object);
0707: if (null != treePath) {
0708: _tree.setSelectionPath(treePath);
0709: _tree.scrollPathToVisible(treePath);
0710: return true;
0711: } else {
0712: return false;
0713: }
0714: }
0715:
0716: /**
0717: * Get the TreePath to the node with the specified catalog, schema and
0718: * object name.
0719: *
0720: * @param catalog the catalog that the node is located in - can be null
0721: * @param schema the schema that the node is located in - can be null
0722: * @param object display name of the node
0723: *
0724: * @return the TreePath to the node with the specified criteria, or the root
0725: * node if a node with matching characteristics isn't found.
0726: */
0727: private TreePath getTreePath(String catalog, String schema,
0728: String object) {
0729: ObjectTreeModel otm = (ObjectTreeModel) _tree.getModel();
0730: TreePath treePath = otm.getPathToDbInfo(catalog, schema,
0731: object, (ObjectTreeNode) otm.getRoot(), false);
0732: if (null == treePath) {
0733: treePath = otm.getPathToDbInfo(catalog, schema, object,
0734: (ObjectTreeNode) otm.getRoot(), true);
0735: }
0736: return treePath;
0737: }
0738:
0739: /**
0740: * Add a known database object type to the object tree.
0741: *
0742: * @param dboType The new database object type.
0743: */
0744: public void addKnownDatabaseObjectType(DatabaseObjectType dboType) {
0745: _tree.getTypedModel().addKnownDatabaseObjectType(dboType);
0746: }
0747:
0748: /**
0749: * Set the panel to be shown in the data area for the passed
0750: * path.
0751: *
0752: * @param path path of node currently selected.
0753: */
0754: private void setSelectedObjectPanel(final TreePath path) {
0755: GUIUtils.processOnSwingEventThread(new Runnable() {
0756: public void run() {
0757: ObjectTreeTabbedPane tabPane = null;
0758: if (path != null) {
0759: Object lastComp = path.getLastPathComponent();
0760: if (lastComp instanceof ObjectTreeNode) {
0761: ObjectTreeNode node = (ObjectTreeNode) lastComp;
0762: tabPane = getDetailPanel(node);
0763: tabPane.setDatabaseObjectInfo(node
0764: .getDatabaseObjectInfo());
0765: tabPane.selectCurrentTab();
0766: }
0767: }
0768: setSelectedObjectPanel(tabPane);
0769: }
0770: });
0771: }
0772:
0773: /**
0774: * Set the panel in the data area to that passed.
0775: *
0776: */
0777: private void setSelectedObjectPanel(ObjectTreeTabbedPane pane) {
0778: _selectedObjTreeTabbedPane = pane;
0779: JTabbedPane comp = null;
0780: if (pane != null) {
0781: comp = pane.getTabbedPane();
0782: }
0783: if (comp == null) {
0784: comp = _emptyTabPane.getTabbedPane();
0785: }
0786:
0787: int divLoc = _splitPane.getDividerLocation();
0788: Component existing = _splitPane.getRightComponent();
0789: if (existing != null) {
0790: _splitPane.remove(existing);
0791: }
0792: _splitPane.add(comp, JSplitPane.RIGHT);
0793: _splitPane.setDividerLocation(divLoc);
0794:
0795: if (pane != null) {
0796: pane.selectCurrentTab();
0797: }
0798: }
0799:
0800: /**
0801: * Get the detail panel to be displayed for the passed node.
0802: *
0803: * @param node Node to get details panel for.
0804: *
0805: * @throws IllegalArgumentException
0806: * Thrown if a <TT>null</TT> <TT>ObjectTreeNode</TT> passed.
0807: */
0808: private ObjectTreeTabbedPane getDetailPanel(ObjectTreeNode node) {
0809: if (node == null) {
0810: throw new IllegalArgumentException("ObjectTreeNode == null");
0811: }
0812:
0813: ObjectTreeTabbedPane tabPane = getTabbedPane(node
0814: .getDatabaseObjectType());
0815: if (tabPane != null) {
0816: return tabPane;
0817: }
0818:
0819: return _emptyTabPane;
0820: }
0821:
0822: /**
0823: * Return the tabbed pane for the passed object tree node type.
0824: *
0825: * @param dboType The database object type we are getting a tabbed
0826: * pane for.
0827: *
0828: * @return the <TT>ObjectTreeTabbedPane</TT> for the passed database object
0829: * type.
0830: */
0831: private ObjectTreeTabbedPane getTabbedPane(
0832: DatabaseObjectType dboType) {
0833: return _tabbedPanes.get(dboType.getIdentifier());
0834: }
0835:
0836: /**
0837: * Return the tabbed pane for the passed database object type. If one
0838: * doesn't exist then create it.
0839: *
0840: * @param dboType The database object type we are getting a tabbed
0841: * pane for.
0842: *
0843: * @return the <TT>List</TT> containing all the <TT>IObjectPanelTab</TT>
0844: * instances for the passed object tree node type.
0845: */
0846: private ObjectTreeTabbedPane getOrCreateObjectPanelTabbedPane(
0847: DatabaseObjectType dboType) {
0848: if (dboType == null) {
0849: throw new IllegalArgumentException(
0850: "Null DatabaseObjectType passed");
0851: }
0852:
0853: final IIdentifier key = dboType.getIdentifier();
0854: ObjectTreeTabbedPane tabPane = _tabbedPanes.get(key);
0855: if (tabPane == null) {
0856: tabPane = new ObjectTreeTabbedPane(_session);
0857: setupTabbedPane(tabPane);
0858: _tabbedPanes.put(key, tabPane);
0859: }
0860: return tabPane;
0861: }
0862:
0863: /**
0864: * Create the user interface.
0865: */
0866: private void createGUI() {
0867: setLayout(new BorderLayout());
0868:
0869: _tree = new ObjectTree(_session);
0870:
0871: _splitPane.setOneTouchExpandable(true);
0872: _splitPane.setContinuousLayout(true);
0873: // final JScrollPane sp = new JScrollPane();
0874: // sp.setBorder(BorderFactory.createEmptyBorder());
0875: // sp.setViewportView(_tree);
0876: // sp.setPreferredSize(new Dimension(200, 200));
0877:
0878: _splitPane.add(new LeftPanel(), JSplitPane.LEFT);
0879: add(_splitPane, BorderLayout.CENTER);
0880: _splitPane.setDividerLocation(200);
0881:
0882: // _tree.addTreeSelectionListener(new ObjectTreeSelectionListener());
0883: // _objTreeSelLis = new ObjectTreeSelectionListener();
0884: // _tree.addTreeSelectionListener(_objTreeSelLis);
0885:
0886: _tree.setSelectionRow(0);
0887: }
0888:
0889: private synchronized void propertiesHaveChanged(String propName) {
0890: if (propName == null
0891: || propName
0892: .equals(SessionProperties.IPropertyNames.META_DATA_OUTPUT_CLASS_NAME)
0893: || propName
0894: .equals(SessionProperties.IPropertyNames.TABLE_CONTENTS_OUTPUT_CLASS_NAME)
0895: || propName
0896: .equals(SessionProperties.IPropertyNames.SQL_RESULTS_OUTPUT_CLASS_NAME)
0897: || propName
0898: .equals(SessionProperties.IPropertyNames.OBJECT_TAB_PLACEMENT)) {
0899: final SessionProperties props = _session.getProperties();
0900:
0901: Iterator<ObjectTreeTabbedPane> it = _tabbedPanes.values()
0902: .iterator();
0903: while (it.hasNext()) {
0904: ObjectTreeTabbedPane pane = it.next();
0905:
0906: if (propName == null
0907: || propName
0908: .equals(SessionProperties.IPropertyNames.META_DATA_OUTPUT_CLASS_NAME)
0909: || propName
0910: .equals(SessionProperties.IPropertyNames.TABLE_CONTENTS_OUTPUT_CLASS_NAME)
0911: || propName
0912: .equals(SessionProperties.IPropertyNames.SQL_RESULTS_OUTPUT_CLASS_NAME)) {
0913: pane.rebuild();
0914: }
0915: if (propName == null
0916: || propName
0917: .equals(SessionProperties.IPropertyNames.OBJECT_TAB_PLACEMENT)) {
0918: pane.getTabbedPane().setTabPlacement(
0919: props.getObjectTabPlacement());
0920: }
0921: }
0922: }
0923: }
0924:
0925: private void onForceEditMode(boolean editable) {
0926: Iterator<ObjectTreeTabbedPane> it = _tabbedPanes.values()
0927: .iterator();
0928: while (it.hasNext()) {
0929: ObjectTreeTabbedPane pane = it.next();
0930: pane.rebuild();
0931:
0932: }
0933: }
0934:
0935: private void setupTabbedPane(ObjectTreeTabbedPane pane) {
0936: final SessionProperties props = _session.getProperties();
0937: pane.rebuild();
0938: final JTabbedPane p = pane.getTabbedPane();
0939: p.setTabPlacement(props.getObjectTabPlacement());
0940: p.addChangeListener(_tabPnlListener);
0941: }
0942:
0943: public void sessionWindowClosing() {
0944: _tree.dispose();
0945: }
0946:
0947: private final class LeftPanel extends JPanel {
0948: LeftPanel() {
0949: super (new BorderLayout());
0950: // add(new TreeHeaderPanel(), BorderLayout.NORTH);
0951: final JScrollPane sp = new JScrollPane();
0952: sp.setBorder(BorderFactory.createEmptyBorder());
0953: sp.setViewportView(_tree);
0954: sp.setPreferredSize(new Dimension(200, 200));
0955: add(sp, BorderLayout.CENTER);
0956: }
0957: }
0958:
0959: // private final class TreeHeaderPanel extends JPanel
0960: // {
0961: // JPopupMenu _pop = new JPopupMenu("abc");
0962: // TreeHeaderPanel()
0963: // {
0964: // super(new FlowLayout());
0965: // JLabel lbl = new JLabel("DB Explorer");
0966: // add(lbl);
0967: //
0968: // _pop.add("Filter...");
0969: // add(_pop);
0970: // }
0971: // }
0972:
0973: /**
0974: * This class listens for changes in the node selected in the tree
0975: * and displays the appropriate detail panel for the node.
0976: */
0977: private final class ObjectTreeSelectionListener implements
0978: TreeSelectionListener {
0979: public void valueChanged(TreeSelectionEvent evt) {
0980: setSelectedObjectPanel(evt.getNewLeadSelectionPath());
0981: }
0982: }
0983:
0984: /**
0985: * Listen for changes in session properties.
0986: */
0987: private class SessionPropertiesListener implements
0988: PropertyChangeListener {
0989: public void propertyChange(PropertyChangeEvent evt) {
0990: propertiesHaveChanged(evt.getPropertyName());
0991: }
0992: }
0993:
0994: /**
0995: * When a different tab is selected in one of the tabbed panels then
0996: * refresh the newly selected tab.
0997: */
0998: private class TabbedPaneListener implements ChangeListener {
0999: public void stateChanged(ChangeEvent evt) {
1000: final Object src = evt.getSource();
1001: if (!(src instanceof JTabbedPane)) {
1002: StringBuffer buf = new StringBuffer();
1003: buf
1004: .append(
1005: "Source object in TabbedPaneListener was not a JTabbedpane")
1006: .append(" - it was ").append(
1007: src == null ? "null" : src.getClass()
1008: .getName());
1009: s_log.error(buf.toString());
1010: return;
1011: }
1012: JTabbedPane tabPane = (JTabbedPane) src;
1013:
1014: Object prop = tabPane
1015: .getClientProperty(ObjectTreeTabbedPane.IClientPropertiesKeys.TABBED_PANE_OBJ);
1016: if (!(prop instanceof ObjectTreeTabbedPane)) {
1017: StringBuffer buf = new StringBuffer();
1018: buf
1019: .append(
1020: "Client property in JTabbedPane was not an ObjectTreeTabbedPane")
1021: .append(" - it was ").append(
1022: prop == null ? "null" : prop.getClass()
1023: .getName());
1024: s_log.error(buf.toString());
1025: return;
1026: }
1027:
1028: ((ObjectTreeTabbedPane) prop).selectCurrentTab();
1029: }
1030: }
1031:
1032: /* (non-Javadoc)
1033: * @see net.sourceforge.squirrel_sql.client.session.IObjectTreeAPI#selectRoot()
1034: */
1035: public void selectRoot() {
1036: // TODO: Figure out why the selection of the root node in the object tree
1037: // is undone if we don't delay. It seems like some other thread racing
1038: // to set the selected node to none. When this happens, the detail pane
1039: // for the root node disappears when a session is first opened, or when
1040: // an ObjectTree frame is created. This is a really crappy and unreliable
1041: // way to fix this problem, but it hides the problem for now. A better
1042: // understanding of the architecture of session creation is required
1043: // before a proper solution can be attempted. RMM 20051217
1044: _session.getApplication().getThreadPool().addTask(
1045: new delaySelectionRunnable());
1046: }
1047:
1048: private class delaySelectionRunnable implements Runnable {
1049: public void run() {
1050: try {
1051: Thread.sleep(50);
1052: } catch (Exception e) {
1053: }
1054: SwingUtilities.invokeLater(new Runnable() {
1055: public void run() {
1056: TreePath rootPath = _tree.getPathForRow(0);
1057: _tree.setSelectionPath(rootPath);
1058: }
1059: });
1060: }
1061: }
1062: }
|