# This patch file was generated by NetBeans IDE # Following Index: paths are relative to: D:\workspace\nb72-src\main # This patch can be applied using context Tools: Patch action on respective folder. # It uses platform neutral UTF-8 encoding and \n newlines. # Above lines and this line are ignored by the patching process. Index: jumpto/src/org/netbeans/modules/jumpto/type/GoToPanel.java --- jumpto/src/org/netbeans/modules/jumpto/type/GoToPanel.java Base (BASE) +++ jumpto/src/org/netbeans/modules/jumpto/type/GoToPanel.java Locally Modified (Based On LOCAL) @@ -30,6 +30,8 @@ * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun * Microsystems, Inc. All Rights Reserved. * + * markiewb@netbeans.org + * * 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 @@ -71,6 +73,7 @@ import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import javax.swing.text.BadLocationException; +import javax.swing.text.Document; import org.netbeans.modules.jumpto.SearchHistory; import org.netbeans.spi.jumpto.type.TypeDescriptor; import org.openide.filesystems.FileObject; @@ -131,7 +134,7 @@ // matchesList.setBackground( bgColorBrighter ); // matchesScrollPane1.setBackground( bgColorBrighter ); - matchesList.setCellRenderer( contentProvider.getListCellRenderer( matchesList ) ); + matchesList.setCellRenderer( contentProvider.getListCellRenderer( matchesList, nameField.getDocument())); contentProvider.setListModel( this, null ); PatternListener pl = new PatternListener( this ); @@ -570,7 +573,7 @@ public static interface ContentProvider { - public ListCellRenderer getListCellRenderer( JList list ); + public ListCellRenderer getListCellRenderer( JList list, Document document); public void setListModel( GoToPanel panel, String text ); Index: jumpto/src/org/netbeans/modules/jumpto/type/GoToTypeAction.java --- jumpto/src/org/netbeans/modules/jumpto/type/GoToTypeAction.java Base (BASE) +++ jumpto/src/org/netbeans/modules/jumpto/type/GoToTypeAction.java Locally Modified (Based On LOCAL) @@ -30,6 +30,8 @@ * Software is Sun Microsystems, Inc. Portions Copyright 1997-2011 Sun * Microsystems, Inc. All Rights Reserved. * + * markiewb@netbeans.org + * * 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 @@ -85,6 +87,10 @@ import javax.swing.ListModel; import javax.swing.SwingUtilities; import javax.swing.event.ChangeEvent; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; +import javax.swing.text.BadLocationException; +import javax.swing.text.Document; import org.netbeans.api.jumpto.type.TypeBrowser; import org.netbeans.api.project.ui.OpenProjects; import org.netbeans.modules.jumpto.EntitiesListCellRenderer; @@ -219,8 +225,13 @@ @Override - public ListCellRenderer getListCellRenderer( JList list ) { - return new Renderer( list ); + public ListCellRenderer getListCellRenderer(JList list, Document nameFieldDocument) { + + Renderer renderer = new Renderer(list); + //notify the render of the changed search text + nameFieldDocument.addDocumentListener(renderer); + + return renderer; } @@ -622,7 +633,7 @@ task.waitFinished(); } - private static final class Renderer extends EntitiesListCellRenderer { + private static final class Renderer extends EntitiesListCellRenderer implements DocumentListener { private MyPanel rendererComponent; private JLabel jlName = new JLabel(); @@ -638,6 +649,8 @@ private Color fgSelectionColor; private JList jList; + private String searchText = ""; + private final HighlightingTypeNameFormatter typeNameFormatter; @SuppressWarnings("LeakingThisInConstructor") public Renderer( JList list ) { @@ -713,6 +726,9 @@ ); bgSelectionColor = list.getSelectionBackground(); fgSelectionColor = list.getSelectionForeground(); + //TODO: get caseSensitive mode and init the highlighter + boolean caseSensitive=false; + this.typeNameFormatter = new HighlightingTypeNameFormatter(fgColor, bgColor, caseSensitive); } public @Override Component getListCellRendererComponent( JList list, @@ -751,7 +767,11 @@ long time = System.currentTimeMillis(); TypeDescriptor td = (TypeDescriptor)value; jlName.setIcon(td.getIcon()); - jlName.setText(td.getTypeName()); + + //highlight matching search text patterns in type + String typeName = td.getTypeName(); + String formattedTypeName = typeNameFormatter.formatTypeName(typeName, searchText); + jlName.setText(String.format("%s", formattedTypeName)); jlPkg.setText(td.getContextName()); setProjectName(jlPrj, td.getProjectName()); jlPrj.setIcon(td.getProjectIcon()); @@ -778,6 +798,26 @@ jList.setFixedCellWidth(jv.getExtentSize().width); } + @Override + public void insertUpdate(DocumentEvent e) { + changedUpdate(e); + } + + @Override + public void removeUpdate(DocumentEvent e) { + changedUpdate(e); + } + + @Override + public void changedUpdate(DocumentEvent e) { + + try { + String text = e.getDocument().getText(0, e.getDocument().getLength()); + searchText = text; + } catch (BadLocationException ex) { + searchText = ""; + } + } } // Renderer private class DialogButtonListener implements ActionListener { Index: jumpto/src/org/netbeans/modules/jumpto/type/HighlightingTypeNameFormatter.java --- jumpto/src/org/netbeans/modules/jumpto/type/HighlightingTypeNameFormatter.java Base (BASE) +++ jumpto/src/org/netbeans/modules/jumpto/type/HighlightingTypeNameFormatter.java Locally New @@ -0,0 +1,136 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2012 Oracle and/or its affiliates. All rights reserved. + * + * Oracle and Java are registered trademarks of Oracle and/or its affiliates. + * Other names may be trademarks of their respective owners. + * + * 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle 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): markiewb@netbeans.org + * + * Portions Copyrighted 2012 Sun Microsystems, Inc. + */ +package org.netbeans.modules.jumpto.type; + +import java.awt.Color; +import java.util.Arrays; +import java.util.BitSet; +import java.util.List; + +/** + * Highlight the match of text patterns. The matching parts will be placed + * within HTML-tags, so it can be used easily within the Swing UI. + * @author markiewb + */ +class HighlightingTypeNameFormatter { + + private static final String FORMATPATTERN = "%s"; + private final boolean caseSensitive; + private String formatPattern; + + HighlightingTypeNameFormatter(Color bgColor, Color fgColor, boolean caseSensitive) { + String bgColorHighlight = Integer.toHexString(bgColor.getRGB()).substring(2); + String fgColorHighlight = Integer.toHexString(fgColor.getRGB()).substring(2); + formatPattern = String.format(FORMATPATTERN, bgColorHighlight, fgColorHighlight, "%s"); + this.caseSensitive = caseSensitive; + } + + List splitByCamelCaseAndWildcards(String searchText) { + //AbcDeFGhiJo -> [Abc, De, F, Ghi, Jo] + StringBuilder sb = new StringBuilder(searchText.length()); + for (char c : searchText.toCharArray()) { + if (Character.isUpperCase(c)) { + //add magic split marker into text before the uppercase char + //example: AbcDeFGhiJo -> &Abc&De&F&Ghi&Jo + sb.append("&"); + sb.append(c); + } else { + sb.append(c); + } + } + //split by camelcase (using the split marker) or the wildcards *,? + String[] split = sb.toString().split("[&|\\*|\\?]"); + return Arrays.asList(split); + } + + public String formatTypeName(String typeName, String textToFind) { + + if (null == textToFind || "".equals(textToFind)) { + return typeName; + } + BitSet bitSet = new BitSet(typeName.length()); + List parts = splitByCamelCaseAndWildcards(textToFind); + + String convertedTypeName = caseSensitive ? typeName : typeName.toLowerCase(); + //mark the chars to be highlighted + int startIndex = 0; + for (String camelCasePart : parts) { + + int indexOf = convertedTypeName.indexOf(caseSensitive ? camelCasePart : camelCasePart.toLowerCase(), startIndex); + if (indexOf != -1) { + + //mark the chars + bitSet.set(indexOf, indexOf + camelCasePart.length(), true); + } else { + break; + } + startIndex = indexOf + camelCasePart.length(); + } + + //highlight the marked chars via tags + StringBuilder formattedTypeName = new StringBuilder(); + int i = 0; + while (i < typeName.toCharArray().length) { + + boolean isMarked = bitSet.get(i); + + if (isMarked) { + int numberOfContinuousHighlights = bitSet.nextClearBit(i) - i; + String part = typeName.substring(i, i + numberOfContinuousHighlights); + formattedTypeName.append(String.format(formatPattern, part)); + i += numberOfContinuousHighlights; + } else { + formattedTypeName.append(typeName.charAt(i)); + i++; + } + } + return formattedTypeName.toString(); + } + + /** + * Allow to inject a pattern, so it can be tested easier. + * @param pattern + */ + void setFormatPattern(String pattern) { + this.formatPattern = pattern; + } +} Index: jumpto/test/unit/src/org/netbeans/modules/jumpto/type/HighlightingTypeNameFormatterTest.java --- jumpto/test/unit/src/org/netbeans/modules/jumpto/type/HighlightingTypeNameFormatterTest.java Base (BASE) +++ jumpto/test/unit/src/org/netbeans/modules/jumpto/type/HighlightingTypeNameFormatterTest.java Locally New @@ -0,0 +1,115 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2012 Oracle and/or its affiliates. All rights reserved. + * + * Oracle and Java are registered trademarks of Oracle and/or its affiliates. + * Other names may be trademarks of their respective owners. + * + * 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle 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): + * markiewb@netbeans.org + * + * Portions Copyrighted 2012 Sun Microsystems, Inc. + */ +package org.netbeans.modules.jumpto.type; + +import java.awt.Color; +import java.util.List; +import org.junit.Test; +import static org.junit.Assert.*; +import org.junit.Before; + +/** + * Tests if the pattern will be highlighted the correct way. + * @author markiewb + */ +public class HighlightingTypeNameFormatterTest { + + private Color fg = Color.WHITE; + private Color bg = Color.BLACK; + private HighlightingTypeNameFormatter cut; + + @Before + public void before() { + cut = new HighlightingTypeNameFormatter(fg, bg, true); + cut.setFormatPattern("[%s]"); + } + + @Test + public void testFormatTypeName_CamelCase() { + String typeName = "AbstractDummyBarTest"; + + assertEquals("[AbstractDummyBarTest]", cut.formatTypeName(typeName, "AbstractDummyBarTest")); + assertEquals("[Abstra]ct[D]ummy[B]arTest", cut.formatTypeName(typeName, "AbstraDB")); + assertEquals("[A]bstract[Dum]my[B]arTest", cut.formatTypeName(typeName, "ADumB")); + assertEquals("[A]bstract[D]ummy[Ba]rTest", cut.formatTypeName(typeName, "ADBa")); + assertEquals("[A]bstract[D]ummy[B]ar[Test]", cut.formatTypeName(typeName, "ADBTest")); + assertEquals("[Ab]stract[Du]mmy[B]ar[Test]", cut.formatTypeName(typeName, "AbDuBTest")); + } + + @Test + public void testFormatTypeName_NullOrEmpty() { + String typeName = "AbstractDummyBarTest"; + assertEquals("AbstractDummyBarTest", cut.formatTypeName(typeName, null)); + assertEquals("AbstractDummyBarTest", cut.formatTypeName(typeName, "")); + } + + @Test + public void testFormatTypeName_Wildcard_CaseSensitive() { + cut = new HighlightingTypeNameFormatter(fg, bg, true); + cut.setFormatPattern("[%s]"); + String typeName = "AbstractDummyBarTest"; + + assertEquals("[A]bstractDummyBar[Test]", cut.formatTypeName(typeName, "A*Test")); + assertEquals("[A]bstractDummy[B]ar[Test]", cut.formatTypeName(typeName, "A*B*Test")); + assertEquals("[A]bstractDummy[BarTest]", cut.formatTypeName(typeName, "A*Bar*Test")); + } + + @Test + public void testFormatTypeName_Wildcard_CaseInSensitive() { + cut = new HighlightingTypeNameFormatter(fg, bg, false); + cut.setFormatPattern("[%s]"); + String typeName = "AbstractDummyBarTest"; + + assertEquals("[A]bstractDummyBar[Test]", cut.formatTypeName(typeName, "A*Test")); + assertEquals("[Ab]stractDummyBar[Test]", cut.formatTypeName(typeName, "A*B*Test")); + assertEquals("[A]bstractDummy[BarTest]", cut.formatTypeName(typeName, "A*Bar*Test")); + } + + @Test + public void testFormatTypeName_FullFormat() { + cut = new HighlightingTypeNameFormatter(fg, bg, false); + String typeName = "AbstractDummyBarTest"; + + assertEquals("AbstractDummyBarTest", cut.formatTypeName(typeName, "ADBTest")); + } +}