diff --git a/changelog.html b/changelog.html
index 5624dfadf0..913cc44915 100644
--- a/changelog.html
+++ b/changelog.html
@@ -55,7 +55,9 @@ Upcoming changes
diff --git a/core/src/main/java/hudson/Functions.java b/core/src/main/java/hudson/Functions.java
index c73b72f4c5..cdb19d5bae 100644
--- a/core/src/main/java/hudson/Functions.java
+++ b/core/src/main/java/hudson/Functions.java
@@ -974,6 +974,67 @@ public class Functions {
return Items.getAllItems(root, TopLevelItem.class);
}
+ /**
+ * Gets the relative name or display name to the given item from the specified group.
+ *
+ * @since 1.515
+ * @param p the Item we want the relative display name
+ * @param g the ItemGroup used as point of reference for the item
+ * @param useDisplayName if true, returns a display name, otherwise returns a name
+ * @return
+ * String like "foo » bar"
+ */
+ public static String getRelativeNameFrom(Item p, ItemGroup g, boolean useDisplayName) {
+ if (p == null) return null;
+ if (g == null) return useDisplayName ? p.getFullDisplayName() : p.getFullName();
+ String separationString = useDisplayName ? " » " : "/";
+
+ // first list up all the parents
+ Map parents = new HashMap();
+ int depth=0;
+ while (g!=null) {
+ parents.put(g, depth++);
+ if (g instanceof Item)
+ g = ((Item)g).getParent();
+ else
+ g = null;
+ }
+
+ StringBuilder buf = new StringBuilder();
+ Item i=p;
+ while (true) {
+ if (buf.length()>0) buf.insert(0,separationString);
+ buf.insert(0,useDisplayName ? i.getDisplayName() : i.getName());
+ ItemGroup gr = i.getParent();
+
+ Integer d = parents.get(gr);
+ if (d!=null) {
+ String s="";
+ for (int j=d; j>0; j--)
+ s+=".." + separationString;
+ return s+buf;
+ }
+
+ if (gr instanceof Item)
+ i = (Item)gr;
+ else
+ return null;
+ }
+ }
+
+ /**
+ * Gets the name to the given item relative to given group.
+ *
+ * @since 1.515
+ * @param p the Item we want the relative display name
+ * @param g the ItemGroup used as point of reference for the item
+ * @return
+ * String like "foo » bar"
+ */
+ public static String getRelativeNameFrom(Item p, ItemGroup g) {
+ return getRelativeNameFrom(p, g, false);
+ }
+
/**
* Gets the relative display name to the given item from the specified group.
@@ -985,10 +1046,7 @@ public class Functions {
* String like "foo » bar"
*/
public static String getRelativeDisplayNameFrom(Item p, ItemGroup g) {
- if (p == null) return null;
- String relativeName = p.getRelativeNameFrom(g);
- if (relativeName == null) return null;
- return relativeName.replace("/", " » ");
+ return getRelativeNameFrom(p, g, true);
}
public static Map dumpAllThreads() {
diff --git a/core/src/main/java/hudson/model/AbstractItem.java b/core/src/main/java/hudson/model/AbstractItem.java
index 436e62dfe4..f9acf3759d 100644
--- a/core/src/main/java/hudson/model/AbstractItem.java
+++ b/core/src/main/java/hudson/model/AbstractItem.java
@@ -327,6 +327,18 @@ public abstract class AbstractItem extends Actionable implements Item, HttpDelet
else return n+" \u00BB "+getDisplayName();
}
+ /**
+ * Gets the display name of the current item relative to the given group.
+ *
+ * @since XXX
+ * @param p the ItemGroup used as point of reference for the item
+ * @return
+ * String like "foo » bar"
+ */
+ public String getRelativeDisplayNameFrom(ItemGroup p) {
+ return Functions.getRelativeDisplayNameFrom(this, p);
+ }
+
/**
* This method only exists to disambiguate {@link #getRelativeNameFrom(ItemGroup)} and {@link #getRelativeNameFrom(Item)}
* @since 1.512
@@ -344,38 +356,7 @@ public abstract class AbstractItem extends Actionable implements Item, HttpDelet
* Nested ItemGroups are separated by / character.
*/
public String getRelativeNameFrom(ItemGroup p) {
- if (p == null) return getFullName();
- // first list up all the parents
- Map parents = new HashMap();
- int depth=0;
- while (p!=null) {
- parents.put(p, depth++);
- if (p instanceof Item)
- p = ((Item)p).getParent();
- else
- p = null;
- }
-
- StringBuilder buf = new StringBuilder();
- Item i=this;
- while (true) {
- if (buf.length()>0) buf.insert(0,'/');
- buf.insert(0,i.getName());
- ItemGroup g = i.getParent();
-
- Integer d = parents.get(g);
- if (d!=null) {
- String s="";
- for (int j=d; j>0; j--)
- s+="../";
- return s+buf;
- }
-
- if (g instanceof Item)
- i = (Item)g;
- else
- return null;
- }
+ return Functions.getRelativeNameFrom(this, p);
}
public String getRelativeNameFrom(Item item) {
diff --git a/core/src/test/java/hudson/FunctionsTest.java b/core/src/test/java/hudson/FunctionsTest.java
index 03b6179e81..8b703dce22 100644
--- a/core/src/test/java/hudson/FunctionsTest.java
+++ b/core/src/test/java/hudson/FunctionsTest.java
@@ -28,6 +28,7 @@ import static org.powermock.api.mockito.PowerMockito.mock;
import static org.powermock.api.mockito.PowerMockito.mockStatic;
import static org.powermock.api.mockito.PowerMockito.when;
import hudson.model.Action;
+import hudson.model.Item;
import hudson.model.ItemGroup;
import hudson.model.TopLevelItem;
import hudson.model.View;
@@ -171,6 +172,30 @@ public class FunctionsTest {
assertEquals("job/i/", result);
}
+ @Test
+ public void testGetRelativeDisplayName() {
+ Item i = mock(Item.class);
+ when(i.getName()).thenReturn("jobName");
+ when(i.getFullDisplayName()).thenReturn("displayName");
+ assertEquals("displayName",Functions.getRelativeDisplayNameFrom(i, null));
+ }
+
+ @Test
+ public void testGetRelativeDisplayNameInsideItemGroup() {
+ Item i = mock(Item.class);
+ when(i.getName()).thenReturn("jobName");
+ when(i.getDisplayName()).thenReturn("displayName");
+ TopLevelItemAndItemGroup ig = mock(TopLevelItemAndItemGroup.class);
+ Jenkins j = mock(Jenkins.class);
+ when(ig.getName()).thenReturn("parent");
+ when(ig.getDisplayName()).thenReturn("parentDisplay");
+ when(ig.getParent()).thenReturn((ItemGroup) j);
+ when(i.getParent()).thenReturn(ig);
+
+ assertEquals("displayName", Functions.getRelativeDisplayNameFrom(i, ig));
+ assertEquals("parentDisplay » displayName", Functions.getRelativeDisplayNameFrom(i, j));
+ }
+
private void createMockAncestors(StaplerRequest req, Ancestor... ancestors) {
List ancestorsList = Arrays.asList(ancestors);
when(req.getAncestors()).thenReturn(ancestorsList);