# NetBeans IDE HG Patch # This patch file was generated by NetBeans IDE # Following Index: paths are relative to: D:\ws\core-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: openide.loaders/apichanges.xml --- openide.loaders/apichanges.xml +++ openide.loaders/apichanges.xml @@ -109,6 +109,31 @@ + + + Introduces a system property to override case-sensitive ordering of DataFolder's children. + + + + + + The case-sensitivity behaviour for ordering children (folders and files) of a Datafolder can be overriden by a system property named org.netbeans.modules.masterfs.case. +

+ It can be set to + sensitive + or + insensitive + value in order to override the system default. +

+ This property has been already introduced into "masterfs" to address problems when mixing various types of network file systems (as described in bug + 198946 + ) +
+ + +
Introduces SortMode for natural sorting. Index: openide.loaders/arch.xml --- openide.loaders/arch.xml +++ openide.loaders/arch.xml @@ -533,6 +533,20 @@ between successive refreshes of contents of a folder. Can be used to tweak performance of folder refresh. Defaults to 10. + + + The case-sensitivity behaviour for ordering children (folders and files) of a Datafolder can be overriden by a system property named org.netbeans.modules.masterfs.case. +

+ It can be set to + sensitive + or + insensitive + value in order to override the system default. +

+ This property has been already introduced into "masterfs" to address problems when mixing various types of network file systems (as described in bug + 198946 + ) +
If set to true, the DataObject.copy, move, createFromTemplate Index: openide.loaders/manifest.mf --- openide.loaders/manifest.mf +++ openide.loaders/manifest.mf @@ -1,6 +1,6 @@ Manifest-Version: 1.0 OpenIDE-Module: org.openide.loaders -OpenIDE-Module-Specification-Version: 7.66 +OpenIDE-Module-Specification-Version: 7.67 OpenIDE-Module-Localizing-Bundle: org/openide/loaders/Bundle.properties OpenIDE-Module-Provides: org.netbeans.modules.templates.v1_0 OpenIDE-Module-Layer: org/netbeans/modules/openide/loaders/layer.xml Index: openide.loaders/src/org/openide/loaders/FolderComparator.java --- openide.loaders/src/org/openide/loaders/FolderComparator.java +++ openide.loaders/src/org/openide/loaders/FolderComparator.java @@ -49,6 +49,7 @@ import java.util.Enumeration; import org.openide.filesystems.FileObject; import org.openide.nodes.Node; +import org.openide.util.BaseUtilities; /** * Compares objects in a folder. @@ -148,9 +149,44 @@ return obj; } + /** + * Compares two strings (f.e. filenames, filename extentsion or path elements) lexiographically. + *

+ * The compare is done case-sensitive by default. + *

+ *

+ * The case-sensitivity can be altered by the system property "org.netbeans.modules.masterfs.case", which was introduced in #198946. + *

    + *
  • + * If the property value is "sensitive", then the compare is case-sensitive. + *
  • + *
  • + * If the property value is "insensitive", then the compare is case-insensitive. + *
  • + *
  • + * If the property isn't set (=null), then the compare is case-sensitive (for backward-compatibility reasons). + *
  • + *
+ *

+ * @since 7.67 + */ + private static int compare(String o1, String o2) { + /* + * backwards compatibility + */ + if (SENSITIVE == null) { + return o1.compareTo(o2); + } + if (Boolean.TRUE.equals(SENSITIVE)) { + return o1.compareTo(o2); + } else { + return o1.compareToIgnoreCase(o2); + } + } + /** for sorting data objects by names */ private int compareNames(Object o1, Object o2) { - return findFileObject(o1).getNameExt().compareTo(findFileObject(o2).getNameExt()); + return compare(findFileObject(o1).getNameExt(), findFileObject(o2).getNameExt()); } /** for sorting folders first and then by names */ @@ -177,14 +213,14 @@ if (folder1 != folder2) { return folder1 ? -1 : 1; // folders first } else if (folder1) { // && folder2 - return obj1.getNameExt().compareTo(obj2.getNameExt()); // by nameExt + return compare(obj1.getNameExt(), obj2.getNameExt()); // by nameExt } else { String ext1 = obj1.getExt(); String ext2 = obj2.getExt(); if (ext1.equals(ext2)) { // same extensions - return obj1.getName().compareTo(obj2.getName()); // by name + return compare(obj1.getName(), obj2.getName()); // by name } else { // different extensions - return ext1.compareTo(ext2); // by extension + return compare(ext1, ext2); // by extension } } } @@ -245,7 +281,7 @@ } else if (d2.after(d1)) { return 1; } else { - return fo1.getNameExt().compareTo(fo2.getNameExt()); + return compare(fo1.getNameExt(), fo2.getNameExt()); } } @@ -269,7 +305,7 @@ } else if (s2 > s1) { return 1; } else { - return fo1.getNameExt().compareTo(fo2.getNameExt()); + return compare(fo1.getNameExt(), fo2.getNameExt()); } } @@ -323,14 +359,14 @@ boolean unfinished1 = p1 < n1.length(); boolean unfinished2 = p2 < n2.length(); if (!unfinished1 && !unfinished2) { - return name1.compareTo(name2); + return compare(name1, name2); } else if (unfinished1) { return 1; // first string is longer (prefix of second string) } else if (unfinished2) { return -1; // second string is longer (prefix of first string) } else { assert false : "Invalid state in natural comparator"; //NOI18N - return n1.compareTo(n2); + return compare(n1, n2); } } @@ -392,4 +428,27 @@ return endPos; } } + + /** + * #139753 Copied from org.netbeans.modules.masterfs.filebasedfs.utils.Utils to prevent dependency to masterfs. + */ + private static final Boolean SENSITIVE = findCase(); + + /** + * #139753 Copied from org.netbeans.modules.masterfs.filebasedfs.utils.Utils to prevent dependency to masterfs. + */ + private static Boolean findCase() { + String userDef = System.getProperty("org.netbeans.modules.masterfs.case"); // NOI18N + if ("insensitive".equals(userDef)) { // NOI18N + return false; + } + if ("sensitive".equals(userDef)) { // NOI18N + return true; + } + assert userDef == null : "Wrong value " + userDef; + if (BaseUtilities.isMac()) { + return false; + } + return null; + } } Index: openide.loaders/test/unit/src/org/openide/loaders/FolderComparatorCaseInsensitiveTest.java --- openide.loaders/test/unit/src/org/openide/loaders/FolderComparatorCaseInsensitiveTest.java +++ openide.loaders/test/unit/src/org/openide/loaders/FolderComparatorCaseInsensitiveTest.java @@ -0,0 +1,208 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2015 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): + * + * Portions Copyrighted 2015 Sun Microsystems, Inc. + */ +package org.openide.loaders; + +import java.awt.EventQueue; +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import static junit.framework.TestCase.assertEquals; +import static junit.framework.TestCase.assertNotNull; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.openide.filesystems.FileObject; +import org.openide.filesystems.FileSystem; +import org.openide.filesystems.FileUtil; + +/** + * + * @author jhavlin + */ +public class FolderComparatorCaseInsensitiveTest { + + private String backup; + + public FolderComparatorCaseInsensitiveTest() { + } + + @Before + public void _before() { + backup = System.getProperty("org.netbeans.modules.masterfs.case"); + System.setProperty("org.netbeans.modules.masterfs.case", "insensitive"); + } + + @After + public void _after() { + if (null != backup) { + System.setProperty("org.netbeans.modules.masterfs.case", backup); + } + } + + + @Test + public void testNaturalComparatorBasic() throws IOException { + testNaturalComparator(new String[]{ + "b 10.txt", + "b 9.txt", + "a2.txt", + "a 4 9.txt", + "a10.txt", + "b0070.txt", + "a 3.txt", + "b08.txt" + }, new String[]{ + "a2.txt", + "a 3.txt", + "a 4 9.txt", + "a10.txt", + "b08.txt", + "b 9.txt", + "b 10.txt", + "b0070.txt" + }); + } + + @Test + public void testNaturalComparatorWithSuffixes() throws IOException { + testNaturalComparator(new String[]{ + "a01b", + "a2x", + "a02", + "a1" + }, new String[]{ + "a1", + "a01b", + "a02", + "a2x" + }); + } + + @Test + public void testUseCustomComparator() throws IOException, + InterruptedException, InvocationTargetException { + + FileSystem fs = FileUtil.createMemoryFileSystem(); + + fs.getRoot().createData("aaaa.txt"); + fs.getRoot().createData("bbb.txt"); + fs.getRoot().createData("cc.txt"); + fs.getRoot().createData("d.txt"); + fs.getRoot().refresh(); + + DataFolder.SortMode custom = new DataFolder.SortMode() { + @Override + public int compare(DataObject o1, DataObject o2) { + return o1.getName().length() - o2.getName().length(); + } + }; + + DataFolder df = DataFolder.findFolder(fs.getRoot()); + df.setSortMode(custom); + EventQueue.invokeAndWait(new Runnable() { + @Override + public void run() { + } + }); + DataObject[] children = df.getChildren(); + assertEquals("d.txt", children[0].getName()); + assertEquals("cc.txt", children[1].getName()); + assertEquals("bbb.txt", children[2].getName()); + assertEquals("aaaa.txt", children[3].getName()); + } + + @Test + public void testNaturalComparatorFallback() throws IOException { + testNaturalComparator(new String[]{ + "a01.txt", + "a001.txt", + "A1.txt" + }, new String[]{ + "a001.txt", + "a01.txt", + "A1.txt", + }); + } + + /** + * #139753 - test if "org.netbeans.modules.masterfs.case=insensitive" is used. + * + * @throws IOException + */ + @Test + public void testCaseSensitivity() throws IOException { + testComparator(new String[]{ + "CustomerInvoice.txt", + "Customerappro.txt", + "CustomerABC.txt", + "Customerinterview.txt" + }, new String[]{ + "CustomerABC.txt", + "Customerappro.txt", + "Customerinterview.txt", + "CustomerInvoice.txt",}, FolderComparator.FOLDER_NAMES); + } + + private void testComparator(String[] fileNames, String[] expectedOrder, int mode) throws IOException { + FolderComparator c = new FolderComparator(mode); + FileSystem fs = FileUtil.createMemoryFileSystem(); + FileObject root = fs.getRoot(); + List list = new ArrayList(); + for (String n : fileNames) { + FileObject fo = root.createData(n); + assertNotNull(fo); + list.add(DataObject.find(fo)); + } + + Collections.sort(list, c); + for (int i = 0; i < expectedOrder.length; i++) { + assertEquals(expectedOrder[i], list.get(i).getName()); + } + } + + private void testNaturalComparator(String[] fileNames, + String[] expectedOrder) throws IOException { + testComparator(fileNames, expectedOrder, FolderComparator.NATURAL); + } +} Index: openide.loaders/test/unit/src/org/openide/loaders/FolderComparatorCaseSensitiveTest.java --- openide.loaders/test/unit/src/org/openide/loaders/FolderComparatorCaseSensitiveTest.java +++ openide.loaders/test/unit/src/org/openide/loaders/FolderComparatorCaseSensitiveTest.java @@ -0,0 +1,208 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2015 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): + * + * Portions Copyrighted 2015 Sun Microsystems, Inc. + */ +package org.openide.loaders; + +import java.awt.EventQueue; +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import static junit.framework.TestCase.assertEquals; +import static junit.framework.TestCase.assertNotNull; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.openide.filesystems.FileObject; +import org.openide.filesystems.FileSystem; +import org.openide.filesystems.FileUtil; + +/** + * + * @author jhavlin + */ +public class FolderComparatorCaseSensitiveTest { + + private String backup; + + public FolderComparatorCaseSensitiveTest() { + } + + @Before + public void _before() { + backup = System.getProperty("org.netbeans.modules.masterfs.case"); + System.setProperty("org.netbeans.modules.masterfs.case", "sensitive"); + } + + @After + public void _after() { + if (null != backup) { + System.setProperty("org.netbeans.modules.masterfs.case", backup); + } + } + + + @Test + public void testNaturalComparatorBasic() throws IOException { + testNaturalComparator(new String[]{ + "b 10.txt", + "b 9.txt", + "a2.txt", + "a 4 9.txt", + "a10.txt", + "b0070.txt", + "a 3.txt", + "b08.txt" + }, new String[]{ + "a2.txt", + "a 3.txt", + "a 4 9.txt", + "a10.txt", + "b08.txt", + "b 9.txt", + "b 10.txt", + "b0070.txt" + }); + } + + @Test + public void testNaturalComparatorWithSuffixes() throws IOException { + testNaturalComparator(new String[]{ + "a01b", + "a2x", + "a02", + "a1" + }, new String[]{ + "a1", + "a01b", + "a02", + "a2x" + }); + } + + @Test + public void testUseCustomComparator() throws IOException, + InterruptedException, InvocationTargetException { + + FileSystem fs = FileUtil.createMemoryFileSystem(); + + fs.getRoot().createData("aaaa.txt"); + fs.getRoot().createData("bbb.txt"); + fs.getRoot().createData("cc.txt"); + fs.getRoot().createData("d.txt"); + fs.getRoot().refresh(); + + DataFolder.SortMode custom = new DataFolder.SortMode() { + @Override + public int compare(DataObject o1, DataObject o2) { + return o1.getName().length() - o2.getName().length(); + } + }; + + DataFolder df = DataFolder.findFolder(fs.getRoot()); + df.setSortMode(custom); + EventQueue.invokeAndWait(new Runnable() { + @Override + public void run() { + } + }); + DataObject[] children = df.getChildren(); + assertEquals("d.txt", children[0].getName()); + assertEquals("cc.txt", children[1].getName()); + assertEquals("bbb.txt", children[2].getName()); + assertEquals("aaaa.txt", children[3].getName()); + } + + @Test + public void testNaturalComparatorFallback() throws IOException { + testNaturalComparator(new String[]{ + "a01.txt", + "a001.txt", + "A1.txt" + }, new String[]{ + "A1.txt", + "a001.txt", + "a01.txt" + }); + } + + /** + * #139753 - test if "org.netbeans.modules.masterfs.case=sensitive" is used. + * + * @throws IOException + */ + @Test + public void testCaseSensitivity() throws IOException { + testComparator(new String[]{ + "CustomerInvoice.txt", + "Customerappro.txt", + "CustomerABC.txt", + "Customerinterview.txt" + }, new String[]{ + "CustomerABC.txt", + "CustomerInvoice.txt", + "Customerappro.txt", + "Customerinterview.txt",}, FolderComparator.FOLDER_NAMES); + } + + private void testComparator(String[] fileNames, String[] expectedOrder, int mode) throws IOException { + FolderComparator c = new FolderComparator(mode); + FileSystem fs = FileUtil.createMemoryFileSystem(); + FileObject root = fs.getRoot(); + List list = new ArrayList(); + for (String n : fileNames) { + FileObject fo = root.createData(n); + assertNotNull(fo); + list.add(DataObject.find(fo)); + } + + Collections.sort(list, c); + for (int i = 0; i < expectedOrder.length; i++) { + assertEquals(expectedOrder[i], list.get(i).getName()); + } + } + + private void testNaturalComparator(String[] fileNames, + String[] expectedOrder) throws IOException { + testComparator(fileNames, expectedOrder, FolderComparator.NATURAL); + } +}