modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/tab/TwoLevelTab.java
| 47 ++++
modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/tab/TwoLevelTabSet.java
| 111 +++++++++-
2 files changed, 154 insertions(+), 4 deletions(-)
New commits:
commit 4ad367088998fcb67b0a058c4fb8bd5ed4133838
Author: John Sanda <jsanda(a)redhat.com>
Date: Tue Feb 21 13:46:19 2012 -0500
[BZ 781602] Adding logic to keep order of tabs consistent
The set of visible tabs can vary from one resource to another; however,
the order of tabs relative to one another is fixed. For example, the
Operations tab could appear as the 3rd or 4th tab, and it could be the
last tab. Note that it should always appear after the summary,
inventory, monitoring, and events tabs in that order. So if the
monitoring and events tabs are not visible, then the order should be
summary, inventory, operations, etc.
This commit adds an internal data structure to TwoLevelTabSet, similar
to a singly linked list a tab is a list node. Each node maintains two
pointers - one to the next visible tab and one to the next actual tab.
diff --git
a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/tab/TwoLevelTab.java
b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/tab/TwoLevelTab.java
index fa62e45..79afade 100644
---
a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/tab/TwoLevelTab.java
+++
b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/tab/TwoLevelTab.java
@@ -23,11 +23,14 @@ import com.smartgwt.client.widgets.Canvas;
import org.rhq.enterprise.gui.coregui.client.components.view.ViewName;
/**
- * @author Greg Hinkle
+ * @author John Sanda
* @author Jay Shaughnessy
*/
public class TwoLevelTab extends NamedTab {
private SubTabLayout layout;
+
+ private TwoLevelTab actualNext;
+ private TwoLevelTab visibleNext;
public TwoLevelTab(String locatorId, ViewName viewName, String icon) {
super(locatorId, viewName, icon);
@@ -78,6 +81,48 @@ public class TwoLevelTab extends NamedTab {
return layout;
}
+ /**
+ * This is the successor or tab immediately to the right of this tab when all tabs
+ * are visible. The tab to which actualNext refers does not change whereas the tab
to
+ * which {@link #getVisibleNext visibleNext} refers can change.
+ *
+ * @return The successor or tab immediately to the right of this tab when all tabs
are
+ * visible.
+ */
+ public TwoLevelTab getActualNext() {
+ return actualNext;
+ }
+
+ /**
+ * @param actualNext The successor or tab immediately to the right of this tab when
all
+ * tabs are visible. The tab to which actualNext refers does not change whereas the
tab
+ * to which {@link #getVisibleNext visibleNext} refers can change.
+ */
+ public void setActualNext(TwoLevelTab actualNext) {
+ this.actualNext = actualNext;
+ }
+
+ /**
+ * The successor or tab immediately to the right of this tab among the set of
visible
+ * tabs. The tab to which visibleNext refers can change whereas the tab to which
+ * {@link #getActualNext actualNext} refers will not change.
+ *
+ * @return The successor or tab immediately to the right of this tab among the set
of
+ * visible tabs.
+ */
+ public TwoLevelTab getVisibleNext() {
+ return visibleNext;
+ }
+
+ /**
+ * @param visibleNext The successor or tab immediately to the right of this tab
among
+ * the set of visible tabs. The tab to which visibleNext refers can change whereas
the
+ * tab to which {@link #getActualNext actualNext} refers will not change.
+ */
+ public void setVisibleNext(TwoLevelTab visibleNext) {
+ this.visibleNext = visibleNext;
+ }
+
@Override
public String toString() {
return "TwoLevelTab[title=" + getTitle() + ", locatorId=" +
getLocatorId() + "]";
diff --git
a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/tab/TwoLevelTabSet.java
b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/tab/TwoLevelTabSet.java
index 572f035..573c543 100644
---
a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/tab/TwoLevelTabSet.java
+++
b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/tab/TwoLevelTabSet.java
@@ -39,9 +39,19 @@ public class TwoLevelTabSet extends NamedTabSet implements
TabSelectedHandler, T
private Map<String, TwoLevelTab> hiddenTabs = new LinkedHashMap<String,
TwoLevelTab>();
private boolean ignoreSelectEvents = false;
+
+ private TwoLevelTab head;
+
+ /**
+ * This is the visible tail. Because the actual order of tabs is fixed we know that
the
+ * actual tail will always be the content tab.
+ */
+ private TwoLevelTab tail;
public TwoLevelTabSet(String locatorId) {
super(locatorId);
+ // Need to set destroyPanes property to false so that we do not lose tab
+ // content when hiding a tab.
setDestroyPanes(false);
}
@@ -51,10 +61,29 @@ public class TwoLevelTabSet extends NamedTabSet implements
TabSelectedHandler, T
tab.getLayout().addTwoLevelTabSelectedHandler(this);
updateTab(tab, tab.getPane());
}
-
+ buildTabList();
addTabSelectedHandler(this);
}
+ /**
+ * This method initializes the head and tail pointers. Then it initializes the
+ * {@link TwoLevelTab#getActualNext actualNext} and {@link TwoLevelTab#getVisibleNext
visibleNext}
+ * properties of each tab. This list is built so that when hiding and showing tabs,
the
+ * tab order remains consistent. The order of the list is the same as the order of
the
+ * tabs passed to {@link #setTabs(TwoLevelTab...)}
+ */
+ private void buildTabList() {
+ TwoLevelTab[] tabs = getTabs();
+ head = tabs[0];
+ tail = tabs[tabs.length - 1];
+ TwoLevelTab current = head;
+ for (int i = 1; i < tabs.length; ++i) {
+ current.setActualNext(tabs[i]);
+ current.setVisibleNext(tabs[i]);
+ current = tabs[i];
+ }
+ }
+
public TwoLevelTab[] getTabs() {
Tab[] tabs = super.getTabs();
TwoLevelTab[] twoLevelTabs = new TwoLevelTab[tabs.length];
@@ -75,9 +104,29 @@ public class TwoLevelTabSet extends NamedTabSet implements
TabSelectedHandler, T
if (hiddenTabs.containsKey(tab.getLocatorId())) {
return;
}
+
+ TwoLevelTab visiblePrevious = findClosestVisiblePredecessor(tab);
+ if (visiblePrevious == null) {
+ // if visiblePrevious is null then that means we are updating
+ // then head. Note that as of now (02/21/2012), the visible head,
+ // the summary tab, is fixed, so we don't really need to worry
+ // about updating the head; however, doing so will make it easier
+ // to support things like hiding arbitrary tabs or reordering tabs.
+ head = tab.getVisibleNext();
+
+ } else {
+ visiblePrevious.setVisibleNext(tab.getVisibleNext());
+ // check to see if the tail needs to be updated. If the
+ // following check is true, then that means visiblePrevious is
+ // now the tail.
+ if (visiblePrevious.getVisibleNext() == null) {
+ tail = visiblePrevious;
+ }
+ }
+ tab.setVisibleNext(null);
// Note that removing the tab does *not* destroy its content pane
// since we set the destroyPanes property to false in the
- removeTab(tab);
+ removeTab(tab);
hiddenTabs.put(tab.getLocatorId(), tab);
} else {
if (!hiddenTabs.containsKey(tab.getLocatorId())) {
@@ -85,10 +134,66 @@ public class TwoLevelTabSet extends NamedTabSet implements
TabSelectedHandler, T
}
hiddenTabs.remove(tab.getLocatorId());
- addTab(tab);
+ TwoLevelTab successor = findClosestVisibleSuccessor(tab);
+ if (successor == null) {
+ // if successor is null then that means we are updating the tail
+ tail.setVisibleNext(tab);
+ tail = tab;
+ addTab(tab);
+ } else {
+ TwoLevelTab visiblePrevious = findClosestVisiblePredecessor(successor);
+ tab.setVisibleNext(visiblePrevious.getVisibleNext());
+ visiblePrevious.setVisibleNext(tab);
+ addTab(tab, (getTabNumber(visiblePrevious.getID()) + 1));
+ }
}
}
+ /**
+ * Walks the list of tabs to find the closest, visible predecessor.
+ *
+ * @param tab A {@link TwoLevelTab tab} that is currently visible
+ * @return The closest, visible predecessor or null if have the head
+ */
+ private TwoLevelTab findClosestVisiblePredecessor(TwoLevelTab tab) {
+ if (tab == head) {
+ return null;
+ }
+
+ TwoLevelTab current = head;
+ while (current != tab) {
+ // if we have reached the visible tail or the immediate predecessor
+ // of the tab, then return it.
+ if (current.getVisibleNext() == null || current.getVisibleNext() == tab) {
+ return current;
+ }
+ current = current.getVisibleNext();
+ }
+ // Not sure what we should do if we get here. return null for now
+ return null;
+ }
+
+ /**
+ * Walks the list to find the closest, visible successor.
+ *
+ * @param tab A {@link TwoLevelTab tab} that is currently hidden
+ * @return The closest, visisble successor or null if the insertion point
+ * is the tail.
+ */
+ private TwoLevelTab findClosestVisibleSuccessor(TwoLevelTab tab) {
+ TwoLevelTab current = tab;
+ while (current != null) {
+ // Walk the list of tabs until we reach a visible successor or the tail
+ if (current.getVisibleNext() == null && current != tail) {
+ current = current.getActualNext();
+ } else {
+ return current;
+ }
+ }
+ // if we reach this point then that means we will be inserting at the tail
+ return null;
+ }
+
public void destroyViews() {
for (TwoLevelTab tab : getTabs()) {
tab.getLayout().destroyViews();