diff -r 50bd9aed0840 options.api/apichanges.xml --- a/options.api/apichanges.xml Thu May 22 16:44:23 2008 -0700 +++ b/options.api/apichanges.xml Fri May 23 12:01:58 2008 +0200 @@ -72,6 +72,19 @@ + + + API to open the options dialog with some subcategory pre-selected + + + + + + Added API to open the options dialog with some subcategory pre-selected. + + + + API to open the options dialog with some category pre-selected diff -r 50bd9aed0840 options.api/manifest.mf --- a/options.api/manifest.mf Thu May 22 16:44:23 2008 -0700 +++ b/options.api/manifest.mf Fri May 23 12:01:58 2008 +0200 @@ -2,6 +2,6 @@ OpenIDE-Module: org.netbeans.modules.options.api/1 OpenIDE-Module-Localizing-Bundle: org/netbeans/modules/options/Bundle.properties OpenIDE-Module-Layer: org/netbeans/modules/options/resources/mf-layer.xml -OpenIDE-Module-Specification-Version: 1.7 +OpenIDE-Module-Specification-Version: 1.8 AutoUpdate-Show-In-Client: false AutoUpdate-Essential-Module: true diff -r 50bd9aed0840 options.api/src/org/netbeans/api/options/OptionsDisplayer.java --- a/options.api/src/org/netbeans/api/options/OptionsDisplayer.java Thu May 22 16:44:23 2008 -0700 +++ b/options.api/src/org/netbeans/api/options/OptionsDisplayer.java Fri May 23 12:01:58 2008 +0200 @@ -24,7 +24,7 @@ * Contributor(s): * * The Original Software is NetBeans. The Initial Developer of the Original - * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2008 Sun * Microsystems, Inc. All Rights Reserved. * * If you wish your version of this file to be governed by only the CDDL @@ -55,6 +55,8 @@ private static final OptionsDisplayer INSTANCE = new OptionsDisplayer(); private final OptionsDisplayerImpl impl = new OptionsDisplayerImpl(false); private static Logger log = Logger.getLogger(OptionsDisplayer.class.getName()); + /** Registration name of Advanced category (aka Miscellaneous). */ + public static final String ADVANCED = "Advanced"; // NOI18N private OptionsDisplayer() {} /** @@ -76,29 +78,49 @@ } /** - * Open the options dialog with some category pre-selected. - * @param categoryId ID representing required category which is registration name - * (e.g. "FooOptionsPanelID" for following registration: + * Open the options dialog with some category and subcategory pre-selected + * according to given path. + * @param path path of category and subcategories to be selected. Path is + * composed from registration names divided by slash. E.g. "MyCategory" or + * "MyCategory/Subcategory2" for the following registration: *
      * <folder name="OptionsDialog">
-     *     <file name="FooOptionsPanelID.instance">
-     *         <attr name="instanceClass" stringvalue="org.foo.FooOptionsPanel"/>
+     *     <file name="MyCategory.instance">
+     *         <attr name="instanceClass" stringvalue="org.foo.MyCategory"/>
+     *         <attr name="position" intvalue="900"/>
+     *     </file>
+     *     <folder name="MyCategory">
+     *         <file name="SubCategory1.instance">
+     *             <attr name="instanceClass" stringvalue="org.foo.Subcategory1"/>
+     *         </file>
+     *         <file name="SubCategory2.instance">
+     *             <attr name="instanceClass" stringvalue="org.foo.Subcategory2"/>
+     *         </file>
      *     </file>
      * </folder>
- * @return true if optins dialog was sucesfully opened with required category pre-selected. + * @return true if optins dialog was sucesfully opened with required category. * If this method is called when options dialog is already opened then this method * will return immediately false without affecting currently selected category * in opened options dialog. - * If categoryId passed as a parameter does not correspond to any + * If category (i.e. the first item in the path) does not correspond to any * of registered categories then false is returned and options dialog is not opened * at all (e.g. in case that module providing such category is not installed or enabled). + * If subcategory doesn't exist, it opens with category selected and + * it returns true. It is up to particular OptionsPanelController + * to handle such situation. */ - public boolean open(final String categoryId) { - log.fine("Open Options Dialog: " + categoryId); //NOI18N - return openImpl(categoryId); + public boolean open(final String path) { + log.fine("Open Options Dialog: " + path); //NOI18N + return openImpl(path); } - - private boolean openImpl(final String categoryId) { + + private boolean openImpl(final String path) { + if(path == null) { + log.warning("Category to open is null."); //NOI18N + return false; + } + final String categoryId = path.indexOf('/') == -1 ? path : path.substring(0, path.indexOf('/')); + final String subpath = path.indexOf('/') == -1 ? null : path.substring(path.indexOf('/')+1); Boolean retval = Mutex.EVENT.readAccess(new Mutex.Action () { public Boolean run() { Boolean r = impl.isOpen(); @@ -112,7 +134,7 @@ log.warning("Options Dialog is opened"); //NOI18N } if (retvalForRun) { - impl.showOptionsDialog(categoryId); + impl.showOptionsDialog(categoryId, subpath); } return Boolean.valueOf(retvalForRun); } diff -r 50bd9aed0840 options.api/src/org/netbeans/modules/options/CategoryModel.java --- a/options.api/src/org/netbeans/modules/options/CategoryModel.java Thu May 22 16:44:23 2008 -0700 +++ b/options.api/src/org/netbeans/modules/options/CategoryModel.java Fri May 23 12:01:58 2008 +0200 @@ -328,6 +328,10 @@ setCurrentCategoryID(getID()); } + public void setCurrentSubcategory(String subpath) { + create().setCurrentSubcategory(subpath); + } + private void setHighlited(boolean highlited) { if (highlited) { highlitedCategoryID = getID(); diff -r 50bd9aed0840 options.api/src/org/netbeans/modules/options/OptionsDisplayerImpl.java --- a/options.api/src/org/netbeans/modules/options/OptionsDisplayerImpl.java Thu May 22 16:44:23 2008 -0700 +++ b/options.api/src/org/netbeans/modules/options/OptionsDisplayerImpl.java Fri May 23 12:01:58 2008 +0200 @@ -93,7 +93,7 @@ return dialog != null; } - public void showOptionsDialog (String categoryID) { + public void showOptionsDialog (String categoryID, String subpath) { if (isOpen()) { // dialog already opened dialog.setVisible (true); @@ -137,9 +137,9 @@ } dialog = DialogDisplayer.getDefault ().createDialog (descriptor); - optionsPanel.initCurrentCategory(categoryID); + optionsPanel.initCurrentCategory(categoryID, subpath); dialog.addWindowListener (new MyWindowListener (optionsPanel)); - dialog.setVisible (true); + dialog.setVisible (true); } private static String loc (String key) { diff -r 50bd9aed0840 options.api/src/org/netbeans/modules/options/OptionsPanel.java --- a/options.api/src/org/netbeans/modules/options/OptionsPanel.java Thu May 22 16:44:23 2008 -0700 +++ b/options.api/src/org/netbeans/modules/options/OptionsPanel.java Fri May 23 12:01:58 2008 +0200 @@ -24,7 +24,7 @@ * Contributor(s): * * The Original Software is NetBeans. The Initial Developer of the Original - * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2008 Sun * Microsystems, Inc. All Rights Reserved. * * If you wish your version of this file to be governed by only the CDDL @@ -119,13 +119,13 @@ private String getCategoryID(String categoryID) { return categoryID == null ? CategoryModel.getInstance().getCurrentCategoryID() : categoryID; } - - void initCurrentCategory (final String categoryID) { + + void initCurrentCategory (final String categoryID, final String subpath) { //generalpanel should be moved to core/options and then could be implemented better //generalpanel doesn't need lookup boolean isGeneralPanel = "General".equals(getCategoryID(categoryID));//NOI18N if (CategoryModel.getInstance().isLookupInitialized() || isGeneralPanel) { - setCurrentCategory(CategoryModel.getInstance().getCategory(getCategoryID(categoryID))); + setCurrentCategory(CategoryModel.getInstance().getCategory(getCategoryID(categoryID)), subpath); initActions(); } else { RequestProcessor.getDefault().post(new Runnable() { @@ -141,7 +141,7 @@ final Cursor cursor = frame.getCursor(); frame.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); - setCurrentCategory(CategoryModel.getInstance().getCategory(getCategoryID(categoryID))); + setCurrentCategory(CategoryModel.getInstance().getCategory(getCategoryID(categoryID)), subpath); initActions(); // reset cursor frame.setCursor(cursor); @@ -153,7 +153,7 @@ } } - private void setCurrentCategory (final CategoryModel.Category category) { + private void setCurrentCategory (final CategoryModel.Category category, String subpath) { CategoryModel.Category oldCategory = CategoryModel.getInstance().getCurrent(); if (oldCategory != null) { (buttons.get(oldCategory.getID())).setNormal (); @@ -162,7 +162,7 @@ (buttons.get(category.getID())).setSelected (); } - CategoryModel.getInstance().setCurrent(category); + CategoryModel.getInstance().setCurrent(category); JComponent component = category.getComponent(); category.update(controllerListener, false); final Dimension size = component.getSize(); @@ -175,6 +175,9 @@ ((CategoryButton) buttons.get (CategoryModel.getInstance().getCurrentCategoryID())).requestFocus(); } */ firePropertyChange ("buran" + OptionsPanelController.PROP_HELP_CTX, null, null); + if(subpath != null) { + category.setCurrentSubcategory(subpath); + } } HelpCtx getHelpCtx () { @@ -382,7 +385,7 @@ this.category = category; } public void actionPerformed (ActionEvent e) { - setCurrentCategory (category); + setCurrentCategory (category, null); } } @@ -390,20 +393,20 @@ public void actionPerformed(ActionEvent e) { CategoryModel.Category highlightedB = CategoryModel.getInstance().getCategory(CategoryModel.getInstance().getHighlitedCategoryID()); if (highlightedB != null) { - setCurrentCategory(highlightedB); + setCurrentCategory(highlightedB, null); } } } private class PreviousAction extends AbstractAction { public void actionPerformed (ActionEvent e) { - setCurrentCategory (CategoryModel.getInstance().getPreviousCategory()); + setCurrentCategory (CategoryModel.getInstance().getPreviousCategory(), null); } } private class NextAction extends AbstractAction { public void actionPerformed (ActionEvent e) { - setCurrentCategory (CategoryModel.getInstance().getNextCategory()); + setCurrentCategory (CategoryModel.getInstance().getNextCategory(), null); } } @@ -498,7 +501,7 @@ public void mouseReleased (MouseEvent e) { if (!category.isCurrent() && category.isHighlited() && CategoryModel.getInstance().getCurrent() != null) { - setCurrentCategory(category); + setCurrentCategory(category, null); } } diff -r 50bd9aed0840 options.api/src/org/netbeans/modules/options/advanced/Advanced.java --- a/options.api/src/org/netbeans/modules/options/advanced/Advanced.java Thu May 22 16:44:23 2008 -0700 +++ b/options.api/src/org/netbeans/modules/options/advanced/Advanced.java Fri May 23 12:01:58 2008 +0200 @@ -24,7 +24,7 @@ * Contributor(s): * * The Original Software is NetBeans. The Initial Developer of the Original - * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2008 Sun * Microsystems, Inc. All Rights Reserved. * * If you wish your version of this file to be governed by only the CDDL @@ -57,12 +57,15 @@ */ public final class Advanced extends OptionsCategory { + private OptionsPanelController controller; + private static String loc (String key) { return NbBundle.getMessage (Advanced.class, key); } private static Icon icon; + @Override public Icon getIcon () { if (icon == null) icon = new ImageIcon ( @@ -85,6 +88,9 @@ } public OptionsPanelController create () { - return new AdvancedPanelController (); - } + if (controller == null) { + controller = new AdvancedPanelController("Advanced"); + } + return controller; + } } diff -r 50bd9aed0840 options.api/src/org/netbeans/modules/options/advanced/AdvancedPanel.java --- a/options.api/src/org/netbeans/modules/options/advanced/AdvancedPanel.java Thu May 22 16:44:23 2008 -0700 +++ b/options.api/src/org/netbeans/modules/options/advanced/AdvancedPanel.java Fri May 23 12:01:58 2008 +0200 @@ -24,7 +24,7 @@ * Contributor(s): * * The Original Software is NetBeans. The Initial Developer of the Original - * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2008 Sun * Microsystems, Inc. All Rights Reserved. * * If you wish your version of this file to be governed by only the CDDL @@ -44,6 +44,7 @@ import java.awt.BorderLayout; import java.util.Iterator; import java.util.List; +import java.util.logging.Logger; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JPanel; @@ -54,7 +55,6 @@ import org.netbeans.spi.options.OptionsPanelController; import org.openide.util.HelpCtx; import org.openide.util.Lookup; -import org.netbeans.modules.options.*; import org.openide.util.LookupEvent; import org.openide.util.LookupListener; @@ -65,16 +65,26 @@ * @author Jan Jancura */ public final class AdvancedPanel extends JPanel { - JTabbedPane tabbedPanel; + JTabbedPane tabbedPanel; + private static final Logger LOGGER = Logger.getLogger(AdvancedPanel.class.getName()); private LookupListener listener = new LookupListenerImpl(); - private Model model = new Model (listener); + private Model model; + private String subpath; private ChangeListener changeListener = new ChangeListener () { public void stateChanged(ChangeEvent e) { handleTabSwitched(); } }; - AdvancedPanel () {} + /* + * @param subpath path to folder under OptionsDialog folder containing + * instances of AdvancedOption class. Path is composed from registration + * names divided by slash. + */ + AdvancedPanel(String subpath) { + this.subpath = subpath; + this.model = new Model(subpath, listener); + } public void update () { int idx = tabbedPanel.getSelectedIndex(); @@ -117,7 +127,7 @@ add (tabbedPanel, BorderLayout.CENTER); initTabbedPane (masterLookup); } - + private void initTabbedPane(Lookup masterLookup) { tabbedPanel.removeChangeListener(changeListener); tabbedPanel.removeAll(); @@ -130,6 +140,38 @@ } tabbedPanel.addChangeListener(changeListener); handleTabSwitched(); + } + + public void setCurrentSubcategory(String path) { + String subcategoryID = path.indexOf('/') == -1 ? path : path.substring(0, path.indexOf('/')); + final String subcategorySubpath = path.indexOf('/') == -1 ? null : path.substring(path.indexOf('/')+1); + LOGGER.fine("Set current subcategory: "+path); + if(!model.getIDs().contains(subcategoryID)) { + LOGGER.warning("Subcategory "+subcategoryID+" not found."); + return; + } + String newDisplayName = model.getDisplayName(subcategoryID); + String currentDisplayName = getSelectedDisplayName(); + if (!newDisplayName.equals(currentDisplayName)) { + for (int i = 0; i < tabbedPanel.getComponentCount(); i++) { + if (tabbedPanel.getTitleAt(i).equals(newDisplayName)) { + tabbedPanel.setSelectedIndex(i); + break; + } + } + } + if(subcategorySubpath != null) { + model.getController(subcategoryID).setCurrentSubcategory(subcategorySubpath); + } + } + + private String getSelectedDisplayName() { + String categoryDisplayName = null; + final int selectedIndex = tabbedPanel.getSelectedIndex(); + if (selectedIndex != -1) { + categoryDisplayName = tabbedPanel.getTitleAt(selectedIndex); + } + return categoryDisplayName; } private void handleTabSwitched() { @@ -148,7 +190,7 @@ private class LookupListenerImpl implements LookupListener { public void resultChanged(LookupEvent ev) { Lookup masterLookup = model.getLookup(); - model = new Model(listener); + model = new Model(subpath, listener); initTabbedPane(masterLookup); } } diff -r 50bd9aed0840 options.api/src/org/netbeans/modules/options/advanced/AdvancedPanelController.java --- a/options.api/src/org/netbeans/modules/options/advanced/AdvancedPanelController.java Thu May 22 16:44:23 2008 -0700 +++ b/options.api/src/org/netbeans/modules/options/advanced/AdvancedPanelController.java Fri May 23 12:01:58 2008 +0200 @@ -24,7 +24,7 @@ * Contributor(s): * * The Original Software is NetBeans. The Initial Developer of the Original - * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2008 Sun * Microsystems, Inc. All Rights Reserved. * * If you wish your version of this file to be governed by only the CDDL @@ -55,6 +55,16 @@ */ public final class AdvancedPanelController extends OptionsPanelController { + private String subpath = null; + + /* Creates new AdvancedPanelController. + * @param subpath path to folder under OptionsDialog folder containing + * instances of AdvancedOption class. Path is composed from registration + * names divided by slash. + */ + public AdvancedPanelController(String subpath) { + this.subpath = subpath; + } public void update () { getAdvancedPanel ().update (); @@ -85,6 +95,11 @@ return getAdvancedPanel (); } + @Override + public void setCurrentSubcategory(String subpath) { + getAdvancedPanel().setCurrentSubcategory(subpath); + } + public HelpCtx getHelpCtx () { return getAdvancedPanel ().getHelpCtx (); } @@ -101,7 +116,7 @@ private AdvancedPanel getAdvancedPanel () { if (advancedPanel == null) - advancedPanel = new AdvancedPanel (); + advancedPanel = new AdvancedPanel(subpath); return advancedPanel; } } diff -r 50bd9aed0840 options.api/src/org/netbeans/modules/options/advanced/Model.java --- a/options.api/src/org/netbeans/modules/options/advanced/Model.java Thu May 22 16:44:23 2008 -0700 +++ b/options.api/src/org/netbeans/modules/options/advanced/Model.java Fri May 23 12:01:58 2008 +0200 @@ -24,7 +24,7 @@ * Contributor(s): * * The Original Software is NetBeans. The Initial Developer of the Original - * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2008 Sun * Microsystems, Inc. All Rights Reserved. * * If you wish your version of this file to be governed by only the CDDL @@ -47,17 +47,20 @@ import java.util.Collections; import java.util.HashMap; import java.util.Iterator; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import javax.swing.JComponent; import javax.swing.border.Border; import javax.swing.border.CompoundBorder; import javax.swing.border.EmptyBorder; +import org.netbeans.api.options.OptionsDisplayer; import org.netbeans.modules.options.ui.TabbedPanelModel; import org.netbeans.spi.options.AdvancedOption; import org.netbeans.spi.options.OptionsPanelController; import org.openide.util.HelpCtx; import org.openide.util.Lookup; +import org.openide.util.Lookup.Item; import org.openide.util.Lookup.Result; import org.openide.util.LookupListener; import org.openide.util.lookup.Lookups; @@ -69,28 +72,64 @@ */ public final class Model extends TabbedPanelModel { - private Map categoryToOption = new HashMap(); + private Map idToCategory = new HashMap(); + private Map categoryToOption = new LinkedHashMap(); private Map categoryToPanel = new HashMap (); private Map categoryToController = new HashMap(); private Lookup masterLookup; private LookupListener lkpListener; private Result lkpResult; + private String subpath; - public Model(LookupListener listener) { + /** + * @param subpath path to folder under OptionsDialog folder containing + * instances of AdvancedOption class. Path is composed from registration + * names divided by slash. + */ + public Model(String subpath, LookupListener listener) { + this.subpath = subpath; this.lkpListener = listener; } - public List getCategories () { init (); List l = new ArrayList(categoryToOption.keySet ()); - Collections.sort(l, Collator.getInstance()); + // Sort Miscellaneous (aka Advanced) subcategories. Order of other categories + // can be defined in layer by position attribute. + if(OptionsDisplayer.ADVANCED.equals(subpath)) { + Collections.sort(l, Collator.getInstance()); + } return l; } + /** Returns list of IDs in this model. + * @return list of IDs in this model + */ + public List getIDs() { + init(); + return new ArrayList(idToCategory.keySet()); + } + public String getToolTip (String category) { AdvancedOption option = categoryToOption.get (category); return option.getTooltip (); + } + + /** Returns display name for given categoryID. + * @param categoryID ID of category as defined in layer xml + * @return display name of given category + */ + public String getDisplayName(String categoryID) { + AdvancedOption option = categoryToOption.get(idToCategory.get(categoryID)); + return option.getDisplayName(); + } + + /** Returns controller for given categoryID. + * @param categoryID ID of category as defined in layer xml + * @return controller of given category + */ + public OptionsPanelController getController(String categoryID) { + return categoryToController.get(getDisplayName(categoryID)); } public JComponent getPanel (String category) { @@ -182,15 +221,18 @@ if (initialized) return; initialized = true; - Lookup lookup = Lookups.forPath("OptionsDialog/Advanced"); // NOI18N + String path = "OptionsDialog/"+subpath; // NOI18N + Lookup lookup = Lookups.forPath(path); lkpResult = lookup.lookup(new Lookup.Template(AdvancedOption.class)); lkpResult.addLookupListener(lkpListener); lkpListener = null; - Iterator it = lkpResult. - allInstances ().iterator (); - while (it.hasNext ()) { - AdvancedOption option = it.next (); - categoryToOption.put (option.getDisplayName (), option); + for(Item item : lkpResult.allItems()) { + // don't lookup in subfolders + if(item.getId().substring(0, item.getId().lastIndexOf('/')).equals(path)) { // NOI18N + AdvancedOption option = item.getInstance(); + categoryToOption.put(option.getDisplayName(), option); + idToCategory.put(item.getId().substring(path.length()+1), item.getInstance().getDisplayName()); + } } } @@ -233,6 +275,11 @@ return delegate.getComponent(masterLookup); } + @Override + public void setCurrentSubcategory(String subpath) { + delegate.setCurrentSubcategory(subpath); + } + public HelpCtx getHelpCtx() { return delegate.getHelpCtx(); } diff -r 50bd9aed0840 options.api/src/org/netbeans/spi/options/OptionsPanelController.java --- a/options.api/src/org/netbeans/spi/options/OptionsPanelController.java Thu May 22 16:44:23 2008 -0700 +++ b/options.api/src/org/netbeans/spi/options/OptionsPanelController.java Fri May 23 12:01:58 2008 +0200 @@ -1,7 +1,48 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * The Original Software is NetBeans. The Initial Developer of the Original + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2008 Sun + * Microsystems, Inc. All Rights Reserved. + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + */ package org.netbeans.spi.options; import java.beans.PropertyChangeListener; import javax.swing.JComponent; +import org.netbeans.modules.options.advanced.AdvancedPanelController; import org.openide.util.HelpCtx; import org.openide.util.Lookup; @@ -26,6 +67,32 @@ * Property name constant. */ public static final String PROP_HELP_CTX = "helpCtx"; + + /** + * Creates an advanced tabbed controller, just like Miscellaneous section. + * @param subpath path to folder under OptionsDialog folder containing + * instances of AdvancedOption class. Path is composed from registration + * names divided by slash. E.g. "MyCategory" for the following registration: + *
+     * <folder name="OptionsDialog">
+     *     <file name="MyCategory.instance">
+     *         <attr name="instanceClass" stringvalue="org.foo.MyCategory"/>
+     *         <attr name="position" intvalue="900"/>
+     *     </file>
+     *     <folder name="MyCategory">
+     *         <file name="SubCategory1.instance">
+     *             <attr name="instanceClass" stringvalue="org.foo.Subcategory1"/>
+     *         </file>
+     *         <file name="SubCategory2.instance">
+     *             <attr name="instanceClass" stringvalue="org.foo.Subcategory2"/>
+     *         </file>
+     *     </file>
+     * </folder>
+ * @return OptionsPanelController a controller wrapping all AdvancedOption instances found in the folder + */ + public static final OptionsPanelController createAdvanced(String subpath) { + return new AdvancedPanelController(subpath); + } /** * Component should load its data here. You should not do any @@ -95,6 +162,17 @@ public abstract JComponent getComponent (Lookup masterLookup); /** + * Enables to handle selection of current subcategory. It is called from + * {@link org.netbeans.api.options.OptionsDisplayer#open(java.lang.String)}, + * if some subpath is defined. + * @param subpath path of subcategories to be selected. Path is + * composed from registration names divided by slash. + * @see org.netbeans.api.options.OptionsDisplayer + */ + public void setCurrentSubcategory(String subpath) { + } + + /** * * Get current help context asociated with this panel. * diff -r 50bd9aed0840 options.api/test/unit/src/org/netbeans/api/options/MyAdvancedCategory.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/options.api/test/unit/src/org/netbeans/api/options/MyAdvancedCategory.java Fri May 23 12:01:58 2008 +0200 @@ -0,0 +1,70 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + * + * Contributor(s): + * + * Portions Copyrighted 2008 Sun Microsystems, Inc. + */ +package org.netbeans.api.options; + +import javax.swing.Icon; +import javax.swing.ImageIcon; +import org.netbeans.spi.options.OptionsCategory; +import org.netbeans.spi.options.OptionsPanelController; +import org.openide.util.Utilities; + +public final class MyAdvancedCategory extends OptionsCategory { + + private OptionsPanelController controller; + + @Override + public Icon getIcon() { + return new ImageIcon(Utilities.loadImage("org/netbeans/modules/options/resources/advanced.png")); + } + + public String getCategoryName() { + return "MyAdvancedCategory"; + } + + public String getTitle() { + return "My Advanced Category"; + } + + public OptionsPanelController create() { + if(controller == null) { + controller = OptionsPanelController.createAdvanced("MyAdvancedCategory"); + } + return controller; + } +} diff -r 50bd9aed0840 options.api/test/unit/src/org/netbeans/api/options/OptionsDisplayerOpenTest.java --- a/options.api/test/unit/src/org/netbeans/api/options/OptionsDisplayerOpenTest.java Thu May 22 16:44:23 2008 -0700 +++ b/options.api/test/unit/src/org/netbeans/api/options/OptionsDisplayerOpenTest.java Fri May 23 12:01:58 2008 +0200 @@ -24,7 +24,7 @@ * Contributor(s): * * The Original Software is NetBeans. The Initial Developer of the Original - * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2008 Sun * Microsystems, Inc. All Rights Reserved. * * If you wish your version of this file to be governed by only the CDDL @@ -51,6 +51,7 @@ import java.awt.Dialog; import java.awt.event.ActionEvent; import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import java.util.Collection; import java.util.logging.Level; import java.util.logging.Logger; @@ -58,6 +59,10 @@ import javax.swing.JDialog; import javax.swing.SwingUtilities; import org.netbeans.junit.NbTestCase; +import org.netbeans.modules.options.advanced.Advanced; +import org.netbeans.modules.options.advanced.AdvancedPanel; +import org.netbeans.modules.options.advanced.AdvancedPanelController; +import org.netbeans.spi.options.OptionsCategory; import org.openide.DialogDescriptor; import org.openide.DialogDisplayer; import org.openide.NotifyDescriptor; @@ -82,17 +87,22 @@ public OptionsDisplayerOpenTest(String testName) { super(testName); } - + + private Lookup lookup; + + @Override protected void setUp() throws Exception { log = Logger.getLogger("[Test - " + getName() + "]"); - Lookup lookup = Lookups.forPath("OptionsDialog"); // NOI18N + lookup = Lookups.forPath("OptionsDialog"); // NOI18N Lookup.Result result = lookup.lookup(new Lookup.Template(RegisteredCategory.class)); all = result.allInstances(); assertTrue(all.size() > 0); } + @Override protected void tearDown() throws Exception { } + /** * Test of getDefault method, of class org.netbeans.api.options.OptionsDisplayer. */ @@ -156,7 +166,70 @@ testOpenFromWorkerThread(); testOpenFromAWT(); } + + /** Tests method setCurrentSubcategory is called in implementing OptionsPanelController + * when OptionsDisplayer.open(categoryId, subcategoryId) is called. + */ + public void testSetCurrentSubcategoryCalled() { + open("Registered/SubcategoryID", true); + assertEquals("Subcategory not set.", "SubcategoryID", RegisteredCategory.subcategoryID); + close(); + open("Registered", true); + // check RegisteredCategory.create().setCurrentSubcategory not called + assertEquals("Subcategory should not be set.", "SubcategoryID", RegisteredCategory.subcategoryID); + close(); + } + /** + * Tests selection of subcategories in Advanced (aka Miscellaneous) category. + */ + public void testAdvancedSubcategorySelection() throws Exception { + open(OptionsDisplayer.ADVANCED, true); + assertEquals("First subcategory should be selected by default.", Subcategory1.DISPLAY_NAME, getSelectedSubcategory(Advanced.class)); + close(); + open(OptionsDisplayer.ADVANCED+"/Subcategory2", true); + assertEquals("Wrong subcategory selected.", Subcategory2.DISPLAY_NAME, getSelectedSubcategory(Advanced.class)); + close(); + open(OptionsDisplayer.ADVANCED+"/UnknownID", true); + assertEquals("Wrong subcategory selected.", Subcategory2.DISPLAY_NAME, getSelectedSubcategory(Advanced.class)); + close(); + open(OptionsDisplayer.ADVANCED+"/Subcategory1", true); + assertEquals("Wrong subcategory selected.", Subcategory1.DISPLAY_NAME, getSelectedSubcategory(Advanced.class)); + close(); + } + + /** + * Tests selection of subcategories in user-created category. + */ + public void testSubcategorySelection() throws Exception { + open("MyAdvancedCategory", true); + assertEquals("Subcategory2 should be first and selected by default.", Subcategory2.DISPLAY_NAME, getSelectedSubcategory(MyAdvancedCategory.class)); + close(); + open("MyAdvancedCategory/Subcategory1", true); + assertEquals("Wrong subcategory selected.", Subcategory1.DISPLAY_NAME, getSelectedSubcategory(MyAdvancedCategory.class)); + close(); + open("MyAdvancedCategory/UnknownID", true); + assertEquals("Wrong subcategory selected.", Subcategory1.DISPLAY_NAME, getSelectedSubcategory(MyAdvancedCategory.class)); + close(); + open("MyAdvancedCategory/Subcategory2", true); + assertEquals("Wrong subcategory selected.", Subcategory2.DISPLAY_NAME, getSelectedSubcategory(MyAdvancedCategory.class)); + close(); + open("MyAdvancedCategory/Subcategory2/Subcategory22", true); + assertEquals("setCurrentSubcategory not called in Subcategory2 controller.", "Subcategory22", Subcategory2.getSubpath()); + close(); + } + + /** Returns display name of subcategory selected in AdvancedPanel. */ + private String getSelectedSubcategory(Class categoryClass) throws Exception { + OptionsCategory category = (OptionsCategory) lookup.lookup(categoryClass); + Method getAdvancedPanelMethod = AdvancedPanelController.class.getDeclaredMethod("getAdvancedPanel", (Class[])null); + getAdvancedPanelMethod.setAccessible(true); + AdvancedPanel advancedPanel = (AdvancedPanel)getAdvancedPanelMethod.invoke(category.create(), (Object[])null); + Method getSelectedDisplayNameMethod = AdvancedPanel.class.getDeclaredMethod("getSelectedDisplayName", (Class[])null); + getSelectedDisplayNameMethod.setAccessible(true); + return getSelectedDisplayNameMethod.invoke(advancedPanel, (Object[])null).toString(); + } + public void openOpen(String categoryId) { for (int i = 0; i < REPEATER; i++) { if (categoryId == null) { @@ -209,12 +282,12 @@ assertEquals(expectedResult, latestResult); } - public void open(String categoryId, boolean expectedResult) { + public void open(String path, boolean expectedResult) { modality(displayer.descriptor); - boolean latestResult = OptionsDisplayer.getDefault().open(categoryId); + boolean latestResult = OptionsDisplayer.getDefault().open(path); assertEquals(expectedResult, latestResult); } - + public void modality(DialogDescriptor desc) { if (desc != null) { assertFalse(desc.isModal()); @@ -231,6 +304,7 @@ displayer.close(); } + @Override protected Level logLevel() { return Level.FINE; } @@ -281,10 +355,11 @@ super((Frame)null, descriptor.getTitle(), descriptor.isModal()); } + @Override public void setVisible(boolean b) { if (isModal()) { super.setVisible(b); - } } } +} } \ No newline at end of file diff -r 50bd9aed0840 options.api/test/unit/src/org/netbeans/api/options/RegisteredCategory.java --- a/options.api/test/unit/src/org/netbeans/api/options/RegisteredCategory.java Thu May 22 16:44:23 2008 -0700 +++ b/options.api/test/unit/src/org/netbeans/api/options/RegisteredCategory.java Fri May 23 12:01:58 2008 +0200 @@ -24,7 +24,7 @@ * Contributor(s): * * The Original Software is NetBeans. The Initial Developer of the Original - * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2008 Sun * Microsystems, Inc. All Rights Reserved. * * If you wish your version of this file to be governed by only the CDDL @@ -106,6 +106,8 @@ } + public static String subcategoryID; + public OptionsPanelController create() { return new OptionsPanelController() { @@ -152,6 +154,11 @@ calls.add("getComponent()"); return new JLabel(); } + + @Override + public void setCurrentSubcategory(String id) { + subcategoryID = id; + } public void addPropertyChangeListener(PropertyChangeListener l) { propertyChangeListener = l; diff -r 50bd9aed0840 options.api/test/unit/src/org/netbeans/api/options/Subcategory1.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/options.api/test/unit/src/org/netbeans/api/options/Subcategory1.java Fri May 23 12:01:58 2008 +0200 @@ -0,0 +1,112 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + * + * Contributor(s): + * + * Portions Copyrighted 2008 Sun Microsystems, Inc. + */ + +package org.netbeans.api.options; + +import java.beans.PropertyChangeListener; +import javax.swing.JComponent; +import javax.swing.JLabel; +import org.netbeans.spi.options.AdvancedOption; +import org.netbeans.spi.options.OptionsPanelController; +import org.openide.util.HelpCtx; +import org.openide.util.Lookup; + +/** + */ +public class Subcategory1 extends AdvancedOption { + + public static final String DISPLAY_NAME = "Subcategory1 display name"; + + @Override + public String getDisplayName() { + return DISPLAY_NAME; + } + + @Override + public String getTooltip() { + return "Subcategory1 tooltip"; + } + + @Override + public OptionsPanelController create() { + return new OptionsPanelController() { + + @Override + public void update() { + } + + @Override + public void applyChanges() { + } + + @Override + public void cancel() { + } + + @Override + public boolean isValid() { + return true; + } + + @Override + public boolean isChanged() { + return false; + } + + @Override + public JComponent getComponent(Lookup masterLookup) { + return new JLabel(); + } + + @Override + public HelpCtx getHelpCtx() { + return null; + } + + @Override + public void addPropertyChangeListener(PropertyChangeListener l) { + } + + @Override + public void removePropertyChangeListener(PropertyChangeListener l) { + } + }; + } + +} diff -r 50bd9aed0840 options.api/test/unit/src/org/netbeans/api/options/Subcategory2.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/options.api/test/unit/src/org/netbeans/api/options/Subcategory2.java Fri May 23 12:01:58 2008 +0200 @@ -0,0 +1,123 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + * + * Contributor(s): + * + * Portions Copyrighted 2008 Sun Microsystems, Inc. + */ + +package org.netbeans.api.options; + +import java.beans.PropertyChangeListener; +import javax.swing.JComponent; +import javax.swing.JLabel; +import org.netbeans.spi.options.AdvancedOption; +import org.netbeans.spi.options.OptionsPanelController; +import org.openide.util.HelpCtx; +import org.openide.util.Lookup; + +/** + */ +public class Subcategory2 extends AdvancedOption { + + public static final String DISPLAY_NAME = "Subcategory2 display name"; + public static String currentSubpath; + + @Override + public String getDisplayName() { + return DISPLAY_NAME; + } + + @Override + public String getTooltip() { + return "Subcategory2 tooltip"; + } + + /** Needed just for tests. */ + public static String getSubpath() { + return currentSubpath; + } + + @Override + public OptionsPanelController create() { + return new OptionsPanelController() { + + @Override + public void update() { + } + + @Override + public void applyChanges() { + } + + @Override + public void cancel() { + } + + @Override + public boolean isValid() { + return true; + } + + @Override + public boolean isChanged() { + return false; + } + + @Override + public JComponent getComponent(Lookup masterLookup) { + return new JLabel(); + } + + @Override + public void setCurrentSubcategory(String subpath) { + currentSubpath = subpath; + } + + @Override + public HelpCtx getHelpCtx() { + return null; + } + + @Override + public void addPropertyChangeListener(PropertyChangeListener l) { + } + + @Override + public void removePropertyChangeListener(PropertyChangeListener l) { + } + }; + } + +} diff -r 50bd9aed0840 options.api/test/unit/src/org/netbeans/api/options/mf-layer.xml --- a/options.api/test/unit/src/org/netbeans/api/options/mf-layer.xml Thu May 22 16:44:23 2008 -0700 +++ b/options.api/test/unit/src/org/netbeans/api/options/mf-layer.xml Fri May 23 12:01:58 2008 +0200 @@ -26,7 +26,7 @@ Contributor(s): The Original Software is NetBeans. The Initial Developer of the Original -Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun +Software is Sun Microsystems, Inc. Portions Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. If you wish your version of this file to be governed by only the CDDL @@ -47,5 +47,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + +