diff --git a/options.api/apichanges.xml b/options.api/apichanges.xml --- a/options.api/apichanges.xml +++ b/options.api/apichanges.xml @@ -75,6 +75,20 @@ + + + Annotation to register keywords for some panel in the Options dialog + + + + + + Introduced an annotation inside OptionsPanelController + to register keywords for some panel in the Options dialog declaratively. + + + + Annotations to register dialog panels diff --git a/options.api/manifest.mf b/options.api/manifest.mf --- a/options.api/manifest.mf +++ b/options.api/manifest.mf @@ -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.27 +OpenIDE-Module-Specification-Version: 1.28 AutoUpdate-Show-In-Client: false AutoUpdate-Essential-Module: true diff --git a/options.api/src/org/netbeans/modules/options/CategoryModel.java b/options.api/src/org/netbeans/modules/options/CategoryModel.java --- a/options.api/src/org/netbeans/modules/options/CategoryModel.java +++ b/options.api/src/org/netbeans/modules/options/CategoryModel.java @@ -81,6 +81,7 @@ Collections.synchronizedMap(new LinkedHashMap()); private MasterLookup masterLookup; static final String OD_LAYER_FOLDER_NAME = "OptionsDialog"; // NOI18N + static final String OD_LAYER_KEYWORDPANELS_FOLDER_NAME = "OptionsDialog/KeywordPanels"; // NOI18N private Result result; Set> getCategories() { diff --git a/options.api/src/org/netbeans/modules/options/OptionsPanelControllerProcessor.java b/options.api/src/org/netbeans/modules/options/OptionsPanelControllerProcessor.java --- a/options.api/src/org/netbeans/modules/options/OptionsPanelControllerProcessor.java +++ b/options.api/src/org/netbeans/modules/options/OptionsPanelControllerProcessor.java @@ -43,7 +43,10 @@ package org.netbeans.modules.options; import java.lang.annotation.Annotation; +import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; import java.util.HashSet; import java.util.Set; import javax.annotation.processing.Processor; @@ -52,10 +55,14 @@ import javax.lang.model.SourceVersion; import javax.lang.model.element.Element; import javax.lang.model.element.TypeElement; +import javax.swing.JPanel; +import org.netbeans.api.options.OptionsDisplayer; import org.netbeans.spi.options.AdvancedOption; import org.netbeans.spi.options.OptionsCategory; import org.netbeans.spi.options.OptionsPanelController; import org.netbeans.spi.options.OptionsPanelController.ContainerRegistration; +import org.netbeans.spi.options.OptionsPanelController.KeywordPanel; +import org.netbeans.spi.options.OptionsPanelController.KeywordPanels; import org.netbeans.spi.options.OptionsPanelController.SubRegistration; import org.netbeans.spi.options.OptionsPanelController.TopLevelRegistration; import org.openide.filesystems.annotations.LayerBuilder; @@ -72,7 +79,9 @@ return new HashSet(Arrays.asList( TopLevelRegistration.class.getCanonicalName(), ContainerRegistration.class.getCanonicalName(), - SubRegistration.class.getCanonicalName() + SubRegistration.class.getCanonicalName(), + KeywordPanels.class.getCanonicalName(), + KeywordPanel.class.getCanonicalName() )); } @@ -108,6 +117,29 @@ keywords(e, r.keywords(), r.keywordsCategory(), r, file); file.write(); } + + ArrayList advanced = new ArrayList(); + for (Element e : roundEnv.getElementsAnnotatedWith(KeywordPanel.class)) { + KeywordPanel annotation = e.getAnnotation(KeywordPanel.class); + if (annotation != null) { + String location = annotation.location(); + if(location.equals(OptionsDisplayer.ADVANCED)) { + advanced.add(annotation); + } + } + } + Collections.sort(advanced, new AdvancedComparable()); + + for (Element e : roundEnv.getElementsAnnotatedWith(KeywordPanel.class)) { + handleElement(e, e.getAnnotation(KeywordPanel.class), advanced, ""); + } + for (Element e : roundEnv.getElementsAnnotatedWith(KeywordPanels.class)) { + KeywordPanels r = e.getAnnotation(KeywordPanels.class); + KeywordPanel[] panels = r.value(); + for (int i = 0; i < panels.length; i++) { + handleElement(e, panels[i], advanced, Integer.toString(-(i + 1))); + } + } for (Element e : roundEnv.getElementsAnnotatedWith(ContainerRegistration.class)) { ContainerRegistration r = e.getAnnotation(ContainerRegistration.class); LayerBuilder builder = layer(e); @@ -123,6 +155,32 @@ } return true; } + + private void handleElement(Element e, KeywordPanel annotation, ArrayList advanced, String name) throws LayerGenerationException { + int index = annotation.index(); + if (annotation.location().equals(OptionsDisplayer.ADVANCED)) { + index = advanced.indexOf(annotation); + } + File file = layer(e). + file("OptionsDialog/KeywordPanels/".concat(e.asType().toString()).concat(name)). + stringvalue("instanceOf", JPanel.class.getName()). + bundlevalue("location", annotation.location(), annotation, "location"). + bundlevalue("id", annotation.id()). + intvalue("index", index); + int i = 1; + for (String keyword : annotation.keywords()) { + file.bundlevalue("keyword-".concat(Integer.toString(i++)), keyword, annotation, "keywords"); + } + file.write(); + } + + private class AdvancedComparable implements Comparator { + + @Override + public int compare(KeywordPanel r1, KeywordPanel r2) { + return r1.id().compareTo(r2.id()); + } + } private void iconBase(Element e, String iconBase, Annotation r, File file, LayerBuilder builder) throws LayerGenerationException { builder.validateResource(iconBase, e, r, "iconBase", true); diff --git a/options.api/src/org/netbeans/spi/options/OptionsPanelController.java b/options.api/src/org/netbeans/spi/options/OptionsPanelController.java --- a/options.api/src/org/netbeans/spi/options/OptionsPanelController.java +++ b/options.api/src/org/netbeans/spi/options/OptionsPanelController.java @@ -316,4 +316,62 @@ int position() default Integer.MAX_VALUE; } + /** + * Similar to {@link KeywordPanel} but permits multiple registrations of + * one class. + * + * @since org.netbeans.modules.options.api/1 1.28 + */ + @Target({ElementType.TYPE}) + @Retention(RetentionPolicy.SOURCE) + public @interface KeywordPanels { + + /** + * List of KeywordPanel registrations. + */ + KeywordPanel[] value(); + } + + /** + * Registers keywords for some panel in the Options dialog. Should be placed + * on a {@link JPanel} instance. + * + * @since org.netbeans.modules.options.api/1 1.28 + */ + @Target({ElementType.TYPE}) + @Retention(RetentionPolicy.SOURCE) + public @interface KeywordPanel { + + /** + * Keywords for use with search inside the Options dialog. You may use + * {@code #key} syntax. + */ + String[] keywords(); + + /** + * Keyword category for use with search inside the Options dialog. + * + * Location of this panel inside some top-level panel matching + * {@link ContainerRegistration#id} or {@link SubRegistration#location}. + * Typically this should be a reference to a compile-time constant also + * used for the container's ID. + */ + String location(); + + /** + * Path that can be used (with {@link #location}) in + * {@link OptionsDisplayer#open(String)} matching + * {@link SubRegistration#id}. Typically this should be a reference to a + * compile-time constant to which other code can refer. You may use + * {@code #key} syntax. + */ + String id(); + + /** + * Position relative to sibling subpanels matching the tab index in a tabbed pane. + * Miscellaneous panel's tabs are always sorted alphabetically. + */ + int index(); + } + }