[550436] Fix tabs order algorithm
The algorithm processing 'afterTab' elements was bugged and leaded to
have wrong tabs order. Also add test cases.
Bug: https://bugs.eclipse.org/bugs/show_bug.cgi?id=550436
Change-Id: Idf802fdc0a0812486d279395751d138e0b3ccf50
Signed-off-by: Axel RICHARD <axel.richard@obeo.fr>
diff --git a/plugins/org.eclipse.eef.properties.ui.legacy/src/org/eclipse/eef/properties/ui/legacy/internal/extension/impl/LegacyPropertyTabRegistry.java b/plugins/org.eclipse.eef.properties.ui.legacy/src/org/eclipse/eef/properties/ui/legacy/internal/extension/impl/LegacyPropertyTabRegistry.java
index ef9a6d5..a3e9839 100644
--- a/plugins/org.eclipse.eef.properties.ui.legacy/src/org/eclipse/eef/properties/ui/legacy/internal/extension/impl/LegacyPropertyTabRegistry.java
+++ b/plugins/org.eclipse.eef.properties.ui.legacy/src/org/eclipse/eef/properties/ui/legacy/internal/extension/impl/LegacyPropertyTabRegistry.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2015, 2018 Obeo.
+ * Copyright (c) 2015, 2019 Obeo.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
@@ -16,7 +16,6 @@
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
-import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@@ -36,11 +35,6 @@
public class LegacyPropertyTabRegistry implements IItemRegistry {
/**
- * The after tab top value.
- */
- private static final String TOP = "top"; //$NON-NLS-1$
-
- /**
* The map of the identifier of the description to the {@link LegacyPropertyTabItemDescriptor}.
*/
private Map<String, List<IItemDescriptor>> id2descriptors = new HashMap<>();
@@ -112,31 +106,21 @@
return tabs;
}
List<IEEFTabDescriptor> sorted = new ArrayList<IEEFTabDescriptor>();
- int categoryIndex = 0;
for (int i = 0; i < propertyCategories.size(); i++) {
// Get all the tabs of a category
final List<IEEFTabDescriptor> categoryList = new ArrayList<IEEFTabDescriptor>();
String category = propertyCategories.get(i);
- int topOfCategory = categoryIndex;
- int endOfCategory = categoryIndex;
- while (endOfCategory < tabs.size() && tabs.get(endOfCategory).getCategory().equals(category)) {
- endOfCategory++;
- }
- for (int j = topOfCategory; j < endOfCategory; j++) {
- IEEFTabDescriptor tab = tabs.get(j);
- if (tab.getAfterTab().equals(TOP)) {
- categoryList.add(0, tabs.get(j));
- } else {
- categoryList.add(tabs.get(j));
+
+ for (IEEFTabDescriptor tab : tabs) {
+ if (category.equals(tab.getCategory())) {
+ categoryList.add(tab);
}
}
-
List<IEEFTabDescriptor> sortedTabs = sortCategoryTabsByAfterTab(categoryList);
for (int j = 0; j < sortedTabs.size(); j++) {
sorted.add(sortedTabs.get(j));
}
- categoryIndex = endOfCategory;
}
return sorted;
}
@@ -149,37 +133,7 @@
* @return List of tabs sorted by after tab
*/
private List<IEEFTabDescriptor> sortCategoryTabsByAfterTab(List<IEEFTabDescriptor> categoryList) {
- List<IEEFTabDescriptor> sorted = new LinkedList<IEEFTabDescriptor>();
- for (IEEFTabDescriptor tab : categoryList) {
- String afterTabId = tab.getAfterTab();
- int indexOfAfterTab = -1;
- if (afterTabId != null && !afterTabId.isEmpty()) {
- IEEFTabDescriptor afterTab = getTab(categoryList, afterTabId);
- if (afterTab != null) {
- indexOfAfterTab = sorted.indexOf(afterTab);
- }
- }
- sorted.add(indexOfAfterTab + 1, tab);
- }
- return sorted;
- }
-
- /**
- * Get a tab in a list of tabs according to its id.
- *
- * @param tabId
- * The tab id
- * @param tabs
- * The tabs list
- * @return the Tab
- */
- private IEEFTabDescriptor getTab(List<IEEFTabDescriptor> tabs, String tabId) {
- for (IEEFTabDescriptor tab : tabs) {
- if (tabId.equals(tab.getId())) {
- return tab;
- }
- }
- return null;
+ return new LegacyPropertyTabSorter().sortTabsByAfterTab(categoryList);
}
/**
diff --git a/plugins/org.eclipse.eef.properties.ui.legacy/src/org/eclipse/eef/properties/ui/legacy/internal/extension/impl/LegacyPropertyTabSorter.java b/plugins/org.eclipse.eef.properties.ui.legacy/src/org/eclipse/eef/properties/ui/legacy/internal/extension/impl/LegacyPropertyTabSorter.java
new file mode 100644
index 0000000..738ef66
--- /dev/null
+++ b/plugins/org.eclipse.eef.properties.ui.legacy/src/org/eclipse/eef/properties/ui/legacy/internal/extension/impl/LegacyPropertyTabSorter.java
@@ -0,0 +1,109 @@
+/*******************************************************************************
+ * Copyright (c) 2019 Obeo.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors: Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.eef.properties.ui.legacy.internal.extension.impl;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.eclipse.eef.properties.ui.api.IEEFTabDescriptor;
+
+/**
+ * Utility class used to sort the property tabs.
+ *
+ * @author arichard
+ */
+public class LegacyPropertyTabSorter {
+
+ /**
+ * Sort tabs by after tab. Top tabs and tabs without after tab are put at the beginning of the list as they appear.
+ *
+ * @param tabs
+ * List of tabs
+ * @return List of tabs sorted by after tab
+ */
+ public List<IEEFTabDescriptor> sortTabsByAfterTab(Collection<IEEFTabDescriptor> tabs) {
+ List<IEEFTabDescriptor> sorted = new ArrayList<IEEFTabDescriptor>(tabs);
+ List<IEEFTabDescriptor> processed = new ArrayList<IEEFTabDescriptor>();
+ int lastIndex = sorted.size() - 1;
+
+ for (int i = 0; i <= lastIndex; i++) {
+ IEEFTabDescriptor lastUnprocessedTab = getLastUnprocessedTab(sorted, processed);
+ if (lastUnprocessedTab != null) {
+ String lastUnprocessedTabId = lastUnprocessedTab.getId();
+ if (!isNullEmpty(lastUnprocessedTabId)) {
+ for (IEEFTabDescriptor tab : tabs) {
+ if (lastUnprocessedTabId.equals(tab.getAfterTab())) {
+ sorted.remove(tab);
+ sorted.add(sorted.indexOf(lastUnprocessedTab) + 1, tab);
+ }
+ }
+ }
+ processed.add(lastUnprocessedTab);
+ }
+ }
+
+ // Move top tabs and tabs without afterTab at the beginning of the list
+ int index = 0;
+ for (IEEFTabDescriptor tab : tabs) {
+ String afterTab = tab.getAfterTab();
+ if (isNullEmpty(afterTab) || isTop(afterTab)) {
+ sorted.remove(tab);
+ sorted.add(index, tab);
+ index++;
+ }
+ }
+
+ return sorted;
+ }
+
+ /**
+ * Get the last tab that has not been processed yet by {@link #sortTabsByAfterTab(Collection)}.
+ *
+ * @param tabs
+ * The list of tabs.
+ * @param processed
+ * The list of already processed tabs.
+ * @return The last tab that has not been processed yet by {@link #sortTabsByAfterTab(Collection)}
+ */
+ private IEEFTabDescriptor getLastUnprocessedTab(List<IEEFTabDescriptor> tabs, List<IEEFTabDescriptor> processed) {
+ for (int i = tabs.size() - 1; i >= 0; i--) {
+ IEEFTabDescriptor lastUnprocessedTab = tabs.get(i);
+ if (!processed.contains(lastUnprocessedTab)) {
+ return lastUnprocessedTab;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Indicates if the given id is null, or an empty string.
+ *
+ * @param id
+ * The id
+ * @return <code>true</code> if the id is null, or an empty string
+ */
+ private boolean isNullEmpty(String id) {
+ return id == null || id.isEmpty();
+ }
+
+ /**
+ * Indicates if the given after tab is top.
+ *
+ * @param afterTab
+ * The after tab
+ * @return <code>true</code> if the after tab is top
+ */
+ private boolean isTop(String afterTab) {
+ return "top".equals(afterTab); //$NON-NLS-1$
+ }
+}
diff --git a/tests/org.eclipse.eef.ui.tests/src/org/eclipse/eef/ui/tests/internal/AllUiTests.java b/tests/org.eclipse.eef.ui.tests/src/org/eclipse/eef/ui/tests/internal/AllUiTests.java
index e6e61c5..bfa1bee 100644
--- a/tests/org.eclipse.eef.ui.tests/src/org/eclipse/eef/ui/tests/internal/AllUiTests.java
+++ b/tests/org.eclipse.eef.ui.tests/src/org/eclipse/eef/ui/tests/internal/AllUiTests.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2018 Obeo.
+ * Copyright (c) 2018, 2019 Obeo.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
@@ -21,7 +21,7 @@
* @author sbegaudeau
*/
@RunWith(Suite.class)
-@SuiteClasses({ LegacyPropertySectionSorterTests.class })
+@SuiteClasses({ LegacyPropertySectionSorterTests.class, LegacyPropertyTabSorterTests.class })
public final class AllUiTests {
/**
* The constructor.
diff --git a/tests/org.eclipse.eef.ui.tests/src/org/eclipse/eef/ui/tests/internal/LegacyPropertyTabSorterTests.java b/tests/org.eclipse.eef.ui.tests/src/org/eclipse/eef/ui/tests/internal/LegacyPropertyTabSorterTests.java
new file mode 100644
index 0000000..1c99271
--- /dev/null
+++ b/tests/org.eclipse.eef.ui.tests/src/org/eclipse/eef/ui/tests/internal/LegacyPropertyTabSorterTests.java
@@ -0,0 +1,226 @@
+/*******************************************************************************
+ * Copyright (c) 2019 Obeo.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors: Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.eef.ui.tests.internal;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.eef.properties.ui.api.EEFTabContents;
+import org.eclipse.eef.properties.ui.api.IEEFSectionDescriptor;
+import org.eclipse.eef.properties.ui.api.IEEFTabDescriptor;
+import org.eclipse.eef.properties.ui.legacy.internal.extension.impl.LegacyPropertyTabSorter;
+import org.eclipse.swt.graphics.Image;
+import org.junit.Test;
+
+/**
+ * Test class for the LegacyPropertyTabSorter.
+ *
+ * @author arichard
+ */
+@SuppressWarnings({ "checkstyle:javadocmethod" })
+public class LegacyPropertyTabSorterTests {
+
+ /**
+ * The special after tab for the TOP tab.
+ */
+ private static final String TOP = "top"; //$NON-NLS-1$
+
+ /**
+ * Utility class to test the tab descriptor.
+ *
+ * @author arichard
+ */
+ private static class TestTabDescriptor implements IEEFTabDescriptor {
+
+ /**
+ * The id.
+ */
+ private String id;
+
+ /**
+ * The after tab.
+ */
+ private String afterTab;
+
+ /**
+ * The constructor.
+ *
+ * @param id
+ * The id
+ * @param afterTab
+ * The after tab
+ */
+ TestTabDescriptor(String id, String afterTab) {
+ this.id = id;
+ this.afterTab = afterTab;
+ }
+
+ @Override
+ public String getId() {
+ return this.id;
+ }
+
+ @Override
+ public String getAfterTab() {
+ return this.afterTab;
+ }
+
+ @Override
+ public String toString() {
+ return this.id;
+ }
+
+ @Override
+ public Image getImage() {
+ return null;
+ }
+
+ @Override
+ public String getText() {
+ return null;
+ }
+
+ @Override
+ public boolean isSelected() {
+ return false;
+ }
+
+ @Override
+ public boolean isIndented() {
+ return false;
+ }
+
+ @Override
+ public EEFTabContents createTab() {
+ return null;
+ }
+
+ @Override
+ public String getCategory() {
+ return null;
+ }
+
+ @Override
+ public String getLabel() {
+ return null;
+ }
+
+ @Override
+ public List<IEEFSectionDescriptor> getSectionDescriptors() {
+ return null;
+ }
+
+ }
+
+ @Test
+ public void testOrderedTabs() {
+ List<IEEFTabDescriptor> tabs = new ArrayList<>();
+ tabs.add(new TestTabDescriptor("1", null)); //$NON-NLS-1$
+ tabs.add(new TestTabDescriptor("2", null)); //$NON-NLS-1$
+ tabs.add(new TestTabDescriptor("3", null)); //$NON-NLS-1$
+
+ List<IEEFTabDescriptor> sortedTabs = new LegacyPropertyTabSorter().sortTabsByAfterTab(tabs);
+
+ assertEquals("[1, 2, 3]", sortedTabs.toString()); //$NON-NLS-1$
+ }
+
+ @Test
+ public void testOrderedTabsWithAfterTab() {
+ List<IEEFTabDescriptor> tabs = new ArrayList<>();
+ tabs.add(new TestTabDescriptor("4", "6")); //$NON-NLS-1$ //$NON-NLS-2$
+ tabs.add(new TestTabDescriptor("5", TOP)); //$NON-NLS-1$
+ tabs.add(new TestTabDescriptor("6", "5")); //$NON-NLS-1$ //$NON-NLS-2$
+
+ List<IEEFTabDescriptor> sortedTabs = new LegacyPropertyTabSorter().sortTabsByAfterTab(tabs);
+
+ assertEquals("[5, 6, 4]", sortedTabs.toString()); //$NON-NLS-1$
+ }
+
+ @Test
+ public void testOrderedTabsWithAfterTab2() {
+ List<IEEFTabDescriptor> tabs = new ArrayList<>();
+ tabs.add(new TestTabDescriptor("9", "10")); //$NON-NLS-1$ //$NON-NLS-2$
+ tabs.add(new TestTabDescriptor("7", "8")); //$NON-NLS-1$ //$NON-NLS-2$
+ tabs.add(new TestTabDescriptor("8", "9")); //$NON-NLS-1$ //$NON-NLS-2$
+ tabs.add(new TestTabDescriptor("10", TOP)); //$NON-NLS-1$
+
+ List<IEEFTabDescriptor> sortedTabs = new LegacyPropertyTabSorter().sortTabsByAfterTab(tabs);
+
+ assertEquals("[10, 9, 8, 7]", sortedTabs.toString()); //$NON-NLS-1$
+ }
+
+ @Test
+ public void testOrderedTabsWithAfterTab3() {
+ List<IEEFTabDescriptor> tabs = new ArrayList<>();
+ tabs.add(new TestTabDescriptor("17", TOP)); //$NON-NLS-1$
+ tabs.add(new TestTabDescriptor("16", "17")); //$NON-NLS-1$ //$NON-NLS-2$
+ tabs.add(new TestTabDescriptor("13", "14")); //$NON-NLS-1$ //$NON-NLS-2$
+ tabs.add(new TestTabDescriptor("14", "15")); //$NON-NLS-1$ //$NON-NLS-2$
+ tabs.add(new TestTabDescriptor("15", "16")); //$NON-NLS-1$ //$NON-NLS-2$
+ tabs.add(new TestTabDescriptor("12", "13")); //$NON-NLS-1$ //$NON-NLS-2$
+ tabs.add(new TestTabDescriptor("11", "12")); //$NON-NLS-1$ //$NON-NLS-2$
+
+ List<IEEFTabDescriptor> sortedTabs = new LegacyPropertyTabSorter().sortTabsByAfterTab(tabs);
+
+ assertEquals("[17, 16, 15, 14, 13, 12, 11]", sortedTabs.toString()); //$NON-NLS-1$
+ }
+
+ @Test
+ public void testOrderedTabsWithAfterTab4() {
+ List<IEEFTabDescriptor> tabs = new ArrayList<>();
+ tabs.add(new TestTabDescriptor("1", null)); //$NON-NLS-1$
+ tabs.add(new TestTabDescriptor("2", "1")); //$NON-NLS-1$ //$NON-NLS-2$
+ tabs.add(new TestTabDescriptor("3", null)); //$NON-NLS-1$
+ tabs.add(new TestTabDescriptor("5", null)); //$NON-NLS-1$
+ tabs.add(new TestTabDescriptor("4", "5")); //$NON-NLS-1$ //$NON-NLS-2$
+ tabs.add(new TestTabDescriptor("6", "5")); //$NON-NLS-1$ //$NON-NLS-2$
+
+ List<IEEFTabDescriptor> sortedTabs = new LegacyPropertyTabSorter().sortTabsByAfterTab(tabs);
+
+ assertEquals("[1, 3, 5, 2, 6, 4]", sortedTabs.toString()); //$NON-NLS-1$
+ }
+
+ @Test
+ public void testOrderedTabsWithAfterTab5() {
+ List<IEEFTabDescriptor> tabs = new ArrayList<>();
+ tabs.add(new TestTabDescriptor("5b", "4")); //$NON-NLS-1$ //$NON-NLS-2$
+ tabs.add(new TestTabDescriptor("1", null)); //$NON-NLS-1$
+ tabs.add(new TestTabDescriptor("2", "1")); //$NON-NLS-1$ //$NON-NLS-2$
+ tabs.add(new TestTabDescriptor("3", "2")); //$NON-NLS-1$ //$NON-NLS-2$
+ tabs.add(new TestTabDescriptor("4", "3")); //$NON-NLS-1$ //$NON-NLS-2$
+ tabs.add(new TestTabDescriptor("5", "4")); //$NON-NLS-1$ //$NON-NLS-2$
+ tabs.add(new TestTabDescriptor("6", "5")); //$NON-NLS-1$ //$NON-NLS-2$
+
+ List<IEEFTabDescriptor> sortedTabs = new LegacyPropertyTabSorter().sortTabsByAfterTab(tabs);
+
+ assertEquals("[1, 2, 3, 4, 5, 5b, 6]", sortedTabs.toString()); //$NON-NLS-1$
+ }
+
+ @Test
+ public void testOrderedTabsWithAfterTab6() {
+ List<IEEFTabDescriptor> tabs = new ArrayList<>();
+ tabs.add(new TestTabDescriptor("A", "C")); //$NON-NLS-1$ //$NON-NLS-2$
+ tabs.add(new TestTabDescriptor("B", null)); //$NON-NLS-1$
+ tabs.add(new TestTabDescriptor("C", "H")); //$NON-NLS-1$ //$NON-NLS-2$
+ tabs.add(new TestTabDescriptor("D", "E")); //$NON-NLS-1$ //$NON-NLS-2$
+ tabs.add(new TestTabDescriptor("E", "H")); //$NON-NLS-1$ //$NON-NLS-2$
+ tabs.add(new TestTabDescriptor("F", null)); //$NON-NLS-1$
+ tabs.add(new TestTabDescriptor("G", "B")); //$NON-NLS-1$ //$NON-NLS-2$
+ tabs.add(new TestTabDescriptor("H", "G")); //$NON-NLS-1$ //$NON-NLS-2$
+
+ List<IEEFTabDescriptor> sortedTabs = new LegacyPropertyTabSorter().sortTabsByAfterTab(tabs);
+
+ assertEquals("[B, F, G, H, E, D, C, A]", sortedTabs.toString()); //$NON-NLS-1$
+ }
+}