package net.sourceforge.sqlexplorer.dbdetail; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import net.sourceforge.sqlexplorer.Messages; import net.sourceforge.sqlexplorer.dbdetail.tab.ColumnInfoTab; import net.sourceforge.sqlexplorer.dbdetail.tab.ColumnPriviligesTab; import net.sourceforge.sqlexplorer.dbdetail.tab.ConnectionInfoTab; import net.sourceforge.sqlexplorer.dbdetail.tab.ExportedKeysTab; import net.sourceforge.sqlexplorer.dbdetail.tab.ImportedKeysTab; import net.sourceforge.sqlexplorer.dbdetail.tab.IndexesTab; import net.sourceforge.sqlexplorer.dbdetail.tab.PreviewTab; import net.sourceforge.sqlexplorer.dbdetail.tab.PrimaryKeysTab; import net.sourceforge.sqlexplorer.dbdetail.tab.PriviligesTab; import net.sourceforge.sqlexplorer.dbdetail.tab.RowCountTab; import net.sourceforge.sqlexplorer.dbdetail.tab.RowIdsTab; import net.sourceforge.sqlexplorer.dbdetail.tab.TableInfoTab; import net.sourceforge.sqlexplorer.dbdetail.tab.VersionsTab; import net.sourceforge.sqlexplorer.dbproduct.MetaDataSession; import net.sourceforge.sqlexplorer.dbproduct.Session; import net.sourceforge.sqlexplorer.dbstructure.nodes.DatabaseNode; import net.sourceforge.sqlexplorer.dbstructure.nodes.INode; import net.sourceforge.sqlexplorer.dbstructure.nodes.TableNode; import net.sourceforge.sqlexplorer.plugin.SQLExplorerPlugin; import net.sourceforge.sqlexplorer.util.TextUtil; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.eclipse.core.runtime.IConfigurationElement; import org.eclipse.core.runtime.IExtension; import org.eclipse.core.runtime.IExtensionPoint; import org.eclipse.core.runtime.IExtensionRegistry; import org.eclipse.core.runtime.Platform; import org.eclipse.swt.SWT; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.SelectionListener; import org.eclipse.swt.layout.FillLayout; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.TabFolder; import org.eclipse.swt.widgets.TabItem; /** * Controls creation of detail tabs for all nodes. All detail tabs are cached. * * @author Davy Vanherbergen */ public class DetailTabManager { private static String _activeTabName = null; private static final Log _logger = LogFactory.getLog(DetailTabManager.class); private static final HashMap<Session, HashMap<String, List<IDetailTab>>> _sessionTabCache = new HashMap(); /** * Clear the detail tab cache for a given node. * * @param node INode to remove from cache. */ public static void clearCacheForNode(INode node) { if (_logger.isDebugEnabled()) { _logger.debug("Clearing tab cache for: " + node.getUniqueIdentifier());//$NON-NLS-1$ } HashMap<String, List<IDetailTab>> tabCache = _sessionTabCache.get(node.getSession()); tabCache.remove(node.getUniqueIdentifier()); } /** * Clear cache of a given session. This method is called when a session is * closed or when the database node is refreshed. * * @param session SessionTreeNode */ public static void clearCacheForSession(MetaDataSession session) { if (_logger.isDebugEnabled()) { _logger.debug("Clearing tab cache for: " + session.toString());//$NON-NLS-1$ } _sessionTabCache.remove(session); } /** * Creates all the tabs in the detail pane to display the information for a * given node. * * @param composite * @param node */ public static void createTabs(Composite composite, INode node) { List tabs = getTabs(node); if (tabs == null || tabs.size() == 0) { // no detail found.. Label label = new Label(composite, SWT.FILL); label.setText(Messages.getString("DatabaseDetailView.Tab.Unavailable") + " " + node.getLabelText());//$NON-NLS-2$ label.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); return; } // create tabs TabFolder tabFolder = new TabFolder(composite, SWT.NULL); // only init tabs when the tab becomes active tabFolder.addSelectionListener(new SelectionListener() { public void widgetDefaultSelected(SelectionEvent e) { // noop } public void widgetSelected(SelectionEvent e) { TabItem tabItem = (TabItem) e.item; IDetailTab tab = (IDetailTab) tabItem.getData(); if (tab != null) { // create composite on tab and fill it.. Composite detailComposite = new Composite(tabItem.getParent(), SWT.FILL); tabItem.setControl(detailComposite); detailComposite.setLayout(new FillLayout()); tab.fillComposite(detailComposite); detailComposite.layout(); // store tab name, so we can reselect when other node is // chosen DetailTabManager.setActiveTabName(tabItem.getText()); } } }); // add tabs to folder Iterator it = tabs.iterator(); int tabIndex = 0; while (it.hasNext()) { IDetailTab detailTab = (IDetailTab) it.next(); // create tab TabItem tabItem = new TabItem(tabFolder, SWT.NULL); tabItem.setText(detailTab.getLabelText()); tabItem.setToolTipText(detailTab.getLabelToolTipText()); // store tab so we can fill later tabItem.setData(detailTab); // reselect same tab as was previous selected if (tabItem.getText() != null && _activeTabName != null) { if (tabItem.getText().equals(_activeTabName)) { tabFolder.setSelection(tabIndex); } } tabIndex++; } // load data for active tab, default to first one if none is selected tabIndex = tabFolder.getSelectionIndex(); if (tabIndex == -1) { tabIndex = 0; } TabItem tabItem = tabFolder.getItem(tabIndex); if (tabItem != null) { Composite detailComposite = new Composite(tabItem.getParent(), SWT.FILL); tabItem.setControl(detailComposite); detailComposite.setLayout(new FillLayout()); IDetailTab tab = (IDetailTab) tabItem.getData(); tab.fillComposite(detailComposite); detailComposite.layout(); } tabFolder.layout(); } /** * Returns a list of all available tabs for a given node. These tabs can be * standard or plugin tabs. * * @param node for which to find tabs. * @return List of tabs */ private static List<IDetailTab> createTabs(INode node) { if (_logger.isDebugEnabled()) { _logger.debug("Creating tabs for: " + node.getUniqueIdentifier());//$NON-NLS-1$ } ArrayList<IDetailTab> tabList = new ArrayList<IDetailTab>(); // create connection info tab if needed if (node instanceof DatabaseNode) { IDetailTab dbTab = new ConnectionInfoTab(); dbTab.setNode(node); tabList.add(dbTab); } // create our basic table tabs if (node instanceof TableNode) { IDetailTab tab1 = new ColumnInfoTab(); IDetailTab tab2 = new TableInfoTab(); IDetailTab tab3 = new PreviewTab(); IDetailTab tab4 = new RowCountTab(); IDetailTab tab5 = new PrimaryKeysTab(); IDetailTab tab6 = new ExportedKeysTab(); IDetailTab tab7 = new ImportedKeysTab(); IDetailTab tab8 = new IndexesTab(); IDetailTab tab9 = new PriviligesTab(); IDetailTab tab10 = new ColumnPriviligesTab(); IDetailTab tab11 = new RowIdsTab(); IDetailTab tab12 = new VersionsTab(); tab1.setNode(node); tab2.setNode(node); tab3.setNode(node); tab4.setNode(node); tab5.setNode(node); tab6.setNode(node); tab7.setNode(node); tab8.setNode(node); tab9.setNode(node); tab10.setNode(node); tab11.setNode(node); tab12.setNode(node); tabList.add(tab1); tabList.add(tab2); tabList.add(tab3); tabList.add(tab4); tabList.add(tab5); tabList.add(tab6); tabList.add(tab7); tabList.add(tab8); tabList.add(tab9); tabList.add(tab10); tabList.add(tab11); tabList.add(tab12); } // create extension point tabs String databaseProductName = node.getSession().getRoot().getDatabaseProductName().toLowerCase().trim(); String nodeType = node.getType().toLowerCase().trim(); IExtensionRegistry registry = Platform.getExtensionRegistry(); IExtensionPoint point = registry.getExtensionPoint("net.sourceforge.sqlexplorer", "nodeDetailTab");//$NON-NLS-1$ $NON-NLS-2$ IExtension[] extensions = point.getExtensions(); for (int i = 0; i < extensions.length; i++) { IExtension e = extensions[i]; IConfigurationElement[] ces = e.getConfigurationElements(); for (int j = 0; j < ces.length; j++) { try { boolean isValidProduct = false; boolean isValidNodeType = false; String[] validProducts = ces[j].getAttribute("database-product-name").split(",");//$NON-NLS-1$ $NON-NLS-2$ String[] validNodeTypes = ces[j].getAttribute("node-type").split(",");//$NON-NLS-1$ $NON-NLS-2$ // check if tab is valid for current database product for (int k = 0; k < validProducts.length; k++) { String product = validProducts[k].toLowerCase().trim(); if (product.length() == 0) { continue; } if (product.equals("*")) {//$NON-NLS-1$ isValidProduct = true; break; } String regex = TextUtil.replaceChar(product, '*', ".*");//$NON-NLS-1$ $NON-NLS-2$ if (databaseProductName.matches(regex)) { isValidProduct = true; break; } } if (!isValidProduct) { continue; } // check if tab is valid for current node type for (int k = 0; k < validNodeTypes.length; k++) { String type = validNodeTypes[k].toLowerCase().trim(); if (type.length() == 0) { continue; } if (type.equals("*")) {//$NON-NLS-1$ isValidNodeType = true; break; } String regex = TextUtil.replaceChar(type, '*', ".*");//$NON-NLS-1$ $NON-NLS-2$ if (nodeType.matches(regex)) { isValidNodeType = true; break; } } if (!isValidNodeType) { continue; } // add tab to list IDetailTab tab = (IDetailTab) ces[j].createExecutableExtension("class");//$NON-NLS-1$ tab.setNode(node); tabList.add(tab); } catch (Throwable ex) { SQLExplorerPlugin.error(Messages.getString("DataSetTableActionGroup.cannotCreateMenuAction"), ex); } } } return tabList; } /** * This method returns the tabs for a given node from the cache. Tabs are * cached per sessionTreeNode. If the tabs don't exist in the cache, they * are created. * * @param node INode for which to retrieve tabs. * @return List of tabs. */ private static List getTabs(INode node) { if (_logger.isDebugEnabled()) { _logger.debug("Loading tabs for: " + node.getUniqueIdentifier());//$NON-NLS-1$ } HashMap<String, List<IDetailTab>> tabCache = _sessionTabCache.get(node.getSession()); if (tabCache == null) { // create cache tabCache = new HashMap<String, List<IDetailTab>>(); _sessionTabCache.put(node.getSession(), tabCache); } List<IDetailTab> tabs = tabCache.get(node.getUniqueIdentifier()); if (tabs == null) { // create tabs & store for later tabs = createTabs(node); tabCache.put(node.getUniqueIdentifier(), tabs); } // display parent details if we have nothing for this node.. if ((tabs == null || tabs.size() == 0) && node.getParent() != null) { return getTabs(node.getParent()); } return tabs; } /** * Store the name of the active tab, so that we can reselect it when a * different node is selected. * * @param name tab label */ public static void setActiveTabName(String name) { _activeTabName = name; } }