diff --git a/api.search/src/org/netbeans/api/search/SearchPattern.java b/api.search/src/org/netbeans/api/search/SearchPattern.java --- a/api.search/src/org/netbeans/api/search/SearchPattern.java +++ b/api.search/src/org/netbeans/api/search/SearchPattern.java @@ -80,8 +80,8 @@ * The pattern follows java.util.regex.Pattern syntax. */ REGEXP(Bundle.LBL_MatchType_Regular_Expression(), 'R'); - private String displayName; - private char canonicalPatternFlag; + private final String displayName; + private final char canonicalPatternFlag; private MatchType(String displayName, char canonicalPatternFlag) { this.displayName = displayName; @@ -166,7 +166,7 @@ public static SearchPattern create(String searchExpression, boolean wholeWords, boolean matchCase, boolean regExp) { return new SearchPattern(searchExpression, wholeWords, matchCase, - regExp ? MatchType.REGEXP : MatchType.BASIC); + regExp ? MatchType.REGEXP : MatchType.LITERAL); } /** diff --git a/api.search/src/org/netbeans/api/search/ui/SearchPatternController.java b/api.search/src/org/netbeans/api/search/ui/SearchPatternController.java --- a/api.search/src/org/netbeans/api/search/ui/SearchPatternController.java +++ b/api.search/src/org/netbeans/api/search/ui/SearchPatternController.java @@ -86,27 +86,12 @@ MATCH_CASE, WHOLE_WORDS, REGULAR_EXPRESSION } - /** - * Options of search patterns that are not boolean, but can have more than - * two values, e.g. {@link MatchType}. - * - * Please note that more items can be added to the enum in the future. - * - * @since api.search/1.11 - */ - public enum MultiOption { - - MATCH_TYPE - } - private final Map bindings = new EnumMap(Option.class); - private final Map comboBindings = - new EnumMap(MultiOption.class); private final Map options = new EnumMap(Option.class); - private final Map multiOptions = - new EnumMap(MultiOption.class); + private JComboBox matchTypeComboBox = null; + private MatchType matchType = MatchType.LITERAL; private final ItemListener listener; private boolean valid; private Color defaultTextColor = null; @@ -161,18 +146,17 @@ break; } } - for (Map.Entry be - : comboBindings.entrySet()) { - switch (be.getKey()) { - case MATCH_TYPE: - be.getValue().setSelectedItem(sp.getMatchType()); - break; - } + if (matchTypeComboBox != null) { + matchTypeComboBox.setSelectedItem(sp.getMatchType()); + // set only to match type that is supported by the combo + matchType = + (MatchType) matchTypeComboBox.getSelectedItem(); + } else { + matchType = sp.getMatchType(); } options.put(Option.MATCH_CASE, sp.isMatchCase()); options.put(Option.WHOLE_WORDS, sp.isWholeWords()); options.put(Option.REGULAR_EXPRESSION, sp.isRegExp()); - multiOptions.put(MultiOption.MATCH_TYPE, sp.getMatchType()); } } }); @@ -253,10 +237,8 @@ button.setSelected(value); } if (option == Option.REGULAR_EXPRESSION) { - if ((getOption(MultiOption.MATCH_TYPE) == MatchType.REGEXP) - != value) { - setOption(MultiOption.MATCH_TYPE, - value ? MatchType.REGEXP : MatchType.LITERAL); + if ((matchType == MatchType.REGEXP) != value) { + setMatchType(value ? MatchType.REGEXP : MatchType.LITERAL); } updateValidity(); } @@ -264,31 +246,28 @@ } /** - * Get current value of an option of the search pattern. - */ - private Object getOption(MultiOption option) { - Parameters.notNull("option", option); //NOI18N - return multiOptions.get(option); - } - - /** * Set value of a search pattern option. The correct item in corresponding * combo box will be selected accordingly. */ - private void setOption(MultiOption option, Object value) { - Parameters.notNull("option", option); //NOI18N - multiOptions.put(option, value); - JComboBox combo = comboBindings.get(option); - if (combo != null && combo.getSelectedItem() != value) { - combo.setSelectedItem(value); + private void setMatchType(MatchType newMatchType) { + Parameters.notNull("matchType", matchType); //NOI18N + if (matchTypeComboBox != null) { + // use only match types contained in the combo box + if (matchTypeComboBox.getSelectedItem() != newMatchType) + matchTypeComboBox.setSelectedItem(newMatchType); + matchType = (MatchType) matchTypeComboBox.getSelectedItem(); + } else { + matchType = newMatchType; } - if (option == MultiOption.MATCH_TYPE) { - if (getOption(Option.REGULAR_EXPRESSION) - != (MatchType.REGEXP == value)) { - setOption(Option.REGULAR_EXPRESSION, value == MatchType.REGEXP); - } - updateValidity(); + if (matchTypeComboBox != null + && matchTypeComboBox.getSelectedItem() != matchType) { + matchTypeComboBox.setSelectedItem(matchType); } + if (getOption(Option.REGULAR_EXPRESSION) + != (MatchType.REGEXP == matchType)) { + setOption(Option.REGULAR_EXPRESSION, matchType == MatchType.REGEXP); + } + updateValidity(); fireChange(); } @@ -299,7 +278,7 @@ return SearchPattern.create(getText(), getOption(Option.WHOLE_WORDS), getOption(Option.MATCH_CASE), - (MatchType) getOption(MultiOption.MATCH_TYPE)); + matchType); } /** @@ -310,7 +289,7 @@ setText(searchPattern.getSearchExpression()); setOption(Option.WHOLE_WORDS, searchPattern.isWholeWords()); setOption(Option.MATCH_CASE, searchPattern.isMatchCase()); - setOption(MultiOption.MATCH_TYPE, searchPattern.getMatchType()); + setMatchType(searchPattern.getMatchType()); } /** @@ -340,29 +319,46 @@ } /** - * Bind a combo box to a SearchPattern option. + * Bind Match Type option to a combo box. * - * @param option Option whose value the button should represent. - * @param comboBox Combo box to control and display the option. + * @param comboBox Combo box to control and display the match type. The + * model of the combo box can contain only items of type {@link MatchType}. + * {@link MatchType.LITERAL} and {@link MatchType.REGEXP} are mandatory in + * the model. * * @since api.search/1.11 */ - public void bind(@NonNull final MultiOption option, - @NonNull final JComboBox comboBox) { - Parameters.notNull("option", option); //NOI18N + public void bindMatchTypeComboBox(@NonNull final JComboBox comboBox) { Parameters.notNull("comboBox", comboBox); //NOI18N - if (comboBindings.containsKey(option)) { + boolean regexpFound = false, literalFound = false; + for (int i = 0; i < comboBox.getItemCount(); i++) { + if (comboBox.getItemAt(i) == MatchType.LITERAL) { + literalFound = true; + } else if (comboBox.getItemAt(i) == MatchType.REGEXP) { + regexpFound = true; + } else if (!(comboBox.getItemAt(i) instanceof MatchType)) { + throw new IllegalArgumentException("Model of the combo "//NOI18N + + "box can contain only MatchType items"); //NOI18N + } + } + if (!(regexpFound && literalFound)) { + throw new IllegalArgumentException( + "At least MatchType.LITERAL and MatchType.REGEXP " //NOI18N + + "must be contained in the combo box model."); //NOI18N + } + if (matchTypeComboBox != null) { throw new IllegalStateException( - "Already bound with option " + option); // NOI18N + "Already bound with option MATCH_TYPE"); //NOI18N } - - comboBindings.put(option, comboBox); - comboBox.setSelectedItem(getOption(option)); + this.matchTypeComboBox = comboBox; + comboBox.setEditable(false); + setMatchType(this.matchType); //update match type, check it is supported + comboBox.setSelectedItem(matchType); comboBox.addItemListener(new ItemListener() { @Override public void itemStateChanged(ItemEvent e) { - setOption(option, comboBox.getSelectedItem()); + setMatchType((MatchType) comboBox.getSelectedItem()); } }); } diff --git a/api.search/src/org/netbeans/modules/search/BasicSearchForm.java b/api.search/src/org/netbeans/modules/search/BasicSearchForm.java --- a/api.search/src/org/netbeans/modules/search/BasicSearchForm.java +++ b/api.search/src/org/netbeans/modules/search/BasicSearchForm.java @@ -76,7 +76,6 @@ import org.netbeans.api.search.ui.ScopeController; import org.netbeans.api.search.ui.ScopeOptionsController; import org.netbeans.api.search.ui.SearchPatternController; -import org.netbeans.api.search.ui.SearchPatternController.MultiOption; import org.netbeans.api.search.ui.SearchPatternController.Option; import org.netbeans.modules.search.ui.FormLayoutHelper; import org.netbeans.modules.search.ui.LinkButtonPanel; @@ -417,7 +416,7 @@ } textToFindType.addItemListener(this); - cboxTextToFind.bind(MultiOption.MATCH_TYPE, textToFindType); + cboxTextToFind.bindMatchTypeComboBox(textToFindType); cboxTextToFind.bind(Option.MATCH_CASE, chkCaseSensitive); cboxTextToFind.bind(Option.WHOLE_WORDS, chkWholeWords); textToFindType.addActionListener(new ActionListener() { diff --git a/api.search/src/org/netbeans/modules/search/Bundle.properties b/api.search/src/org/netbeans/modules/search/Bundle.properties --- a/api.search/src/org/netbeans/modules/search/Bundle.properties +++ b/api.search/src/org/netbeans/modules/search/Bundle.properties @@ -236,7 +236,7 @@ BasicSearchForm.chkCaseSensitive.AccessibleDescription=Whether the fulltext search should be case-sensitive. -BasicSearchForm.textToFindType.label.text=T&ype: +BasicSearchForm.textToFindType.label.text=M&atch: BasicSearchForm.chkPreserveCase.text=Preser&ve Case when Replacing @@ -244,7 +244,7 @@ BasicSearchForm.textToFindType.AccessibleDescription=Choose whether you want to use the Text to Find value as literal text, text with basic wildcards, or regular expression. -BasicSearchForm.chkArchives.text=Search in &Archives +BasicSearchForm.chkArchives.text=Search i&n Archives BasicSearchForm.chkGenerated.text=Search in &Generated Sources diff --git a/api.search/test/unit/src/org/netbeans/api/search/SearchPatternTest.java b/api.search/test/unit/src/org/netbeans/api/search/SearchPatternTest.java --- a/api.search/test/unit/src/org/netbeans/api/search/SearchPatternTest.java +++ b/api.search/test/unit/src/org/netbeans/api/search/SearchPatternTest.java @@ -116,8 +116,8 @@ false, false, true).changeMatchType(MatchType.BASIC) .getMatchType()); - assertEquals("If not specified exactly, match type should be BASIC", - MatchType.BASIC, SearchPattern.create("test", + assertEquals("If not specified exactly, match type should be LITERAL", + MatchType.LITERAL, SearchPattern.create("test", false, false, false).getMatchType()); } } diff --git a/api.search/test/unit/src/org/netbeans/api/search/ui/SearchPatternControllerTest.java b/api.search/test/unit/src/org/netbeans/api/search/ui/SearchPatternControllerTest.java --- a/api.search/test/unit/src/org/netbeans/api/search/ui/SearchPatternControllerTest.java +++ b/api.search/test/unit/src/org/netbeans/api/search/ui/SearchPatternControllerTest.java @@ -46,7 +46,6 @@ import static org.junit.Assert.*; import org.netbeans.api.search.SearchPattern; import org.netbeans.api.search.SearchPattern.MatchType; -import org.netbeans.api.search.ui.SearchPatternController.MultiOption; /** * @@ -65,10 +64,10 @@ JComboBox matchTypeCb = new JComboBox(new Object[]{ MatchType.BASIC, MatchType.LITERAL, MatchType.REGEXP}); assertEquals(MatchType.BASIC, matchTypeCb.getSelectedItem()); - controller.bind(MultiOption.MATCH_TYPE, matchTypeCb); + controller.bindMatchTypeComboBox(matchTypeCb); boolean thrown = false; try { - controller.bind(MultiOption.MATCH_TYPE, matchTypeCb); + controller.bindMatchTypeComboBox(matchTypeCb); } catch (Exception e) { thrown = true; } @@ -99,4 +98,74 @@ assertEquals(MatchType.BASIC, controller.getSearchPattern().getMatchType()); } + + @Test + public void testBindMatchTypeComboBoxWithoutMandatoryItems() { + + checkExceptionsWhenEnsuringItemsAreCorrect( + true, "Exception should be thrown when trying to bind " + + "combo box with no items"); + + checkExceptionsWhenEnsuringItemsAreCorrect( + true, "Exception should be thrown when trying to bind " + + "combo box without REGEXP item", + MatchType.BASIC, MatchType.LITERAL); + + checkExceptionsWhenEnsuringItemsAreCorrect( + true, "Exception should be thrown when trying to bind " + + "combo box without LITERAL item", + MatchType.BASIC, MatchType.REGEXP); + + checkExceptionsWhenEnsuringItemsAreCorrect( + false, "No exception should be thrown when trying to bind " + + "combo with LITERAL and REGEXP item", + MatchType.LITERAL, MatchType.REGEXP); + } + + @Test + public void testBindMatchTypeComboBoxWithUnsupportedItems() { + checkExceptionsWhenEnsuringItemsAreCorrect( + true, "Exception should be thrown when trying to bind " + + "combo box with non-MatchType items", + MatchType.LITERAL, MatchType.REGEXP, "Alien string item"); + } + + private void checkExceptionsWhenEnsuringItemsAreCorrect( + boolean exceptionExpected, String message, Object... comboItems) { + + JComboBox cb = new JComboBox(); + SearchPatternController controller = + ComponentUtils.adjustComboForSearchPattern(cb); + JComboBox matchTypeCb = new JComboBox(comboItems); + boolean thrown = false; + try { + controller.bindMatchTypeComboBox(matchTypeCb); + } catch (Exception e) { + thrown = true; + } + assertEquals(message, exceptionExpected, thrown); + } + + @Test + public void testMatchTypeComboBoxWithUnsupportedTypes() { + JComboBox cb = new JComboBox(); + SearchPatternController controller = + ComponentUtils.adjustComboForSearchPattern(cb); + JComboBox matchTypeCb = new JComboBox( + new Object[]{MatchType.LITERAL, MatchType.REGEXP}); + controller.bindMatchTypeComboBox(matchTypeCb); + assertEquals(MatchType.LITERAL, matchTypeCb.getSelectedItem()); + controller.setSearchPattern(SearchPattern.create("test", false, false, + MatchType.BASIC)); + assertEquals(MatchType.LITERAL, + controller.getSearchPattern().getMatchType()); + controller.setSearchPattern(SearchPattern.create("test", false, false, + MatchType.REGEXP)); + assertEquals(MatchType.REGEXP, + controller.getSearchPattern().getMatchType()); + controller.setSearchPattern(SearchPattern.create("test", false, false, + MatchType.BASIC)); + assertEquals(MatchType.REGEXP, + controller.getSearchPattern().getMatchType()); + } }