/* * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package com.sun.tools.visualvm.core.properties; import com.sun.tools.visualvm.core.datasource.DataSource; import com.sun.tools.visualvm.core.datasupport.Positionable; import com.sun.tools.visualvm.core.ui.components.ScrollableContainer; import com.sun.tools.visualvm.core.ui.components.SectionSeparator; import com.sun.tools.visualvm.core.ui.components.Spacer; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Font; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.swing.BorderFactory; import javax.swing.JLabel; import javax.swing.JTabbedPane; import javax.swing.UIManager; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; /** * UI component for presenting user-customizable properties of a DataSource. * This class is to be used by DataSource providers supporting defining the * initial DataSource properties. Use PropertiesSupport.getCustomizer(Class) * method to get an instance of PropertiesCustomizer for a concrete DataSource * type. * * @since VisualVM 1.2 * @author Jiri Sedlacek */ public final class PropertiesCustomizer<X extends DataSource> extends PropertiesPanel { private final X dataSource; private final List<List<PropertiesProvider<X>>> groups; private final List<PropertiesPanel> panels; private final ChangeListener listener = new ChangeListener() { public void stateChanged(ChangeEvent e) { update(); } }; private JTabbedPane tabbedPane; private final Map<Integer, Integer> categories; PropertiesCustomizer(X dataSource, Class<X> type) { this.dataSource = dataSource; groups = createGroups(PropertiesSupport.sharedInstance().getProviders(dataSource, type)); panels = createPanels(groups, dataSource); categories = new HashMap(); initComponents(); update(); registerListeners(); } /** * Invokes PropertiesProvider.propertiesDefined method for every * PropertiesProvider supporting the provided DataSource. To be called by * DataSource providers when the New DataSource dialog displaying editable * properties has been accepted by the user and new DataSource has been * created. * * @param dataSource newly created DataSource */ public void propertiesDefined(X dataSource) { unregisterListeners(); for (int i = 0; i < groups.size(); i++) { List<PropertiesProvider<X>> providers = groups.get(i); List<PropertiesPanel> categoriesPanels = new ArrayList(); if (providers.size() == 1) { categoriesPanels.add(panels.get(i)); } else { MultiPropertiesPanel multiPanel = (MultiPropertiesPanel)panels.get(i); categoriesPanels.addAll(multiPanel.getPanels()); } for (int j = 0; j < providers.size(); j++) providers.get(j).propertiesDefined(categoriesPanels.get(j), dataSource); } } /** * Invokes PropertiesProvider.propertiesCancelled method for every * PropertiesProvider supporting the DataSource type defined for this * PropertiesCustomizer. To be called by DataSource providers when the New * DataSource dialog displaying editable properites has been cancelled and * no DataSource has been created. */ public void propertiesCancelled() { unregisterListeners(); for (int i = 0; i < groups.size(); i++) { List<PropertiesProvider<X>> providers = groups.get(i); List<PropertiesPanel> categoriesPanels = new ArrayList(); if (providers.size() == 1) { categoriesPanels.add(panels.get(i)); } else { MultiPropertiesPanel multiPanel = (MultiPropertiesPanel)panels.get(i); categoriesPanels.addAll(multiPanel.getPanels()); } for (int j = 0; j < providers.size(); j++) providers.get(j).propertiesCancelled(categoriesPanels.get(j), dataSource); } } void propertiesChanged() { unregisterListeners(); for (int i = 0; i < groups.size(); i++) { List<PropertiesProvider<X>> providers = groups.get(i); List<PropertiesPanel> categoriesPanels = new ArrayList(); if (providers.size() == 1) { categoriesPanels.add(panels.get(i)); } else { MultiPropertiesPanel multiPanel = (MultiPropertiesPanel)panels.get(i); categoriesPanels.addAll(multiPanel.getPanels()); } for (int j = 0; j < providers.size(); j++) providers.get(j).propertiesChanged(categoriesPanels.get(j), dataSource); } } void selectCategory(int category) { Integer tabIndex = categories.get(category); if (tabIndex != null) tabbedPane.setSelectedIndex(tabIndex); } private void registerListeners() { for (PropertiesPanel panel : panels) panel.addChangeListener(listener); } private void unregisterListeners() { for (PropertiesPanel panel : panels) panel.removeChangeListener(listener); } private void update() { for (PropertiesPanel panel : panels) if (!panel.settingsValid()) { setSettingsValid(false); return; } setSettingsValid(true); } private void initComponents() { tabbedPane = new JTabbedPane(); tabbedPane.setFocusable(false); for (int i = 0; i < panels.size(); i++) { PropertiesPanel panel = panels.get(i); PropertiesProvider provider = groups.get(i).get(0); ScrollableContainer c = new ScrollableContainer(panel); c.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); c.setViewportBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); categories.put(provider.getPropertiesCategory(), tabbedPane.getTabCount()); tabbedPane.addTab(provider.getPropertiesName(), null, c, provider.getPropertiesDescription()); } setLayout(new BorderLayout()); add(tabbedPane, BorderLayout.CENTER); } private static <Y extends DataSource> List<List<PropertiesProvider<Y>>> createGroups(List<PropertiesProvider<Y>> providers) { Collections.sort(providers, new CategoriesComparator()); List<List<PropertiesProvider<Y>>> groupedProviders = new ArrayList(); int currentCategory = -1; List<PropertiesProvider<Y>> currentGroup = null; for (PropertiesProvider<Y> provider : providers) { int providerCategory = provider.getPropertiesCategory(); if (currentGroup == null || providerCategory != currentCategory) { currentCategory = providerCategory; if (currentGroup != null) Collections.sort(currentGroup, Positionable.COMPARATOR); currentGroup = new ArrayList(); groupedProviders.add(currentGroup); } if (currentGroup != null && currentCategory == providerCategory) currentGroup.add(provider); } if (currentGroup != null) Collections.sort(currentGroup, Positionable.COMPARATOR); return groupedProviders; } private static <Y extends DataSource> List<PropertiesPanel> createPanels(List<List<PropertiesProvider<Y>>> groups, Y dataSource) { List<PropertiesPanel> panels = new ArrayList(groups.size()); for (List<PropertiesProvider<Y>> group : groups) if (group.size() == 1) panels.add(group.get(0).createPanel(dataSource)); else panels.add(new MultiPropertiesPanel(group, dataSource)); return panels; } private static class MultiPropertiesPanel<Y extends DataSource> extends PropertiesPanel { private static final Color separatorColor = separatorColor(); private static final Font separatorFont = separatorFont(); private final List<PropertiesPanel> panels; private final ChangeListener listener = new ChangeListener() { public void stateChanged(ChangeEvent e) { update(); } }; public MultiPropertiesPanel(List<PropertiesProvider<Y>> providers, Y dataSource) { panels = new ArrayList(providers.size()); for (PropertiesProvider provider : providers) panels.add(provider.createPanel(dataSource)); initComponents(providers); update(); } public List<PropertiesPanel> getPanels() { return panels; } private void update() { boolean valid = true; for (PropertiesPanel panel : panels) if (!panel.settingsValid()) { valid = false; break; } setSettingsValid(valid); } private void initComponents(List<PropertiesProvider<Y>> providers) { setOpaque(false); setBorder(BorderFactory.createEmptyBorder()); setLayout(new GridBagLayout()); int currentRow = 0; int providerIndex = 1; GridBagConstraints constraints; for (PropertiesPanel panel : panels) { constraints = createConstraints(currentRow++); add(panel, constraints); panel.addChangeListener(listener); if (providerIndex < providers.size()) { PropertiesProvider provider = providers.get(providerIndex++); SectionSeparator separator = new SectionSeparator(provider.getPropertiesName()); separator.setForeground(separatorColor); separator.setFont(separatorFont); separator.setToolTipText(provider.getPropertiesDescription()); constraints = createConstraints(currentRow++); constraints.insets = new Insets(10, 0, 5, 0); add(separator, constraints); } } constraints = createConstraints(currentRow++); constraints.weightx = 1; constraints.weighty = 1; add(Spacer.create(), constraints); } private static GridBagConstraints createConstraints(int row) { GridBagConstraints c = new GridBagConstraints(); c.gridx = 0; c.gridy = row; c.gridwidth = GridBagConstraints.REMAINDER; c.anchor = GridBagConstraints.NORTHWEST; c.fill = GridBagConstraints.BOTH; return c; } } private static Color separatorColor() { Color color = UIManager.getColor("TitledBorder.titleColor"); // NOI18N if (color == null) color = new JLabel().getForeground(); return color; } private static Font separatorFont() { Font font = UIManager.getFont("TitledBorder.font"); // NOI18N if (font == null) font = new JLabel().getFont(); return font; } private static class CategoriesComparator implements Comparator { public int compare(Object o1, Object o2) { PropertiesProvider p1 = (PropertiesProvider)o1; PropertiesProvider p2 = (PropertiesProvider)o2; int category1 = p1.getPropertiesCategory(); int category2 = p2.getPropertiesCategory(); if (category1 > category2) return 1; if (category1 < category2) return -1; return p1.getPropertiesName().compareTo(p2.getPropertiesName()); } } }