diff --git a/core/src/main/java/hudson/Functions.java b/core/src/main/java/hudson/Functions.java index fc263f5efa..38ea40b8a6 100644 --- a/core/src/main/java/hudson/Functions.java +++ b/core/src/main/java/hudson/Functions.java @@ -25,13 +25,33 @@ */ package hudson; -import com.google.common.base.Predicate; -import com.google.common.base.Predicates; import hudson.cli.CLICommand; import hudson.console.ConsoleAnnotationDescriptor; import hudson.console.ConsoleAnnotatorFactory; -import hudson.model.*; +import hudson.model.AbstractProject; +import hudson.model.Action; +import hudson.model.Describable; +import hudson.model.Descriptor; +import hudson.model.DescriptorVisibilityFilter; +import hudson.model.Hudson; +import hudson.model.Item; +import hudson.model.ItemGroup; +import hudson.model.Items; +import hudson.model.JDK; +import hudson.model.Job; +import hudson.model.JobPropertyDescriptor; +import hudson.model.ModelObject; +import hudson.model.Node; +import hudson.model.PageDecorator; +import hudson.model.ParameterDefinition; import hudson.model.ParameterDefinition.ParameterDescriptor; +import hudson.model.Project; +import hudson.model.Run; +import hudson.model.TopLevelItem; +import hudson.model.User; +import hudson.model.View; +import hudson.scm.SCM; +import hudson.scm.SCMDescriptor; import hudson.search.SearchableModelObject; import hudson.security.AccessControlled; import hudson.security.AuthorizationStrategy; @@ -53,36 +73,11 @@ import hudson.tasks.Publisher; import hudson.tasks.UserAvatarResolver; import hudson.util.Area; import hudson.util.Iterators; -import hudson.scm.SCM; -import hudson.scm.SCMDescriptor; import hudson.util.Secret; import hudson.views.MyViewsTabBar; import hudson.views.ViewsTabBar; import hudson.widgets.RenderOnDemandClosure; -import jenkins.model.GlobalConfiguration; -import jenkins.model.GlobalConfigurationCategory; -import jenkins.model.GlobalConfigurationCategory.Unclassified; -import jenkins.model.Jenkins; -import jenkins.model.ModelObjectWithContextMenu; -import org.acegisecurity.providers.anonymous.AnonymousAuthenticationToken; -import org.apache.commons.jelly.JellyContext; -import org.apache.commons.jelly.JellyTagException; -import org.apache.commons.jelly.Script; -import org.apache.commons.jelly.XMLOutput; -import org.apache.commons.jexl.parser.ASTSizeFunction; -import org.apache.commons.jexl.util.Introspector; -import org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement; -import org.jvnet.tiger_types.Types; -import org.kohsuke.stapler.Ancestor; -import org.kohsuke.stapler.Stapler; -import org.kohsuke.stapler.StaplerRequest; -import org.kohsuke.stapler.StaplerResponse; -import org.kohsuke.stapler.jelly.InternationalizedStringExpression.RawHtmlArgument; -import javax.servlet.ServletException; -import javax.servlet.http.Cookie; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; import java.io.File; import java.io.IOException; import java.io.PrintWriter; @@ -93,8 +88,8 @@ import java.lang.management.ManagementFactory; import java.lang.management.MonitorInfo; import java.lang.management.ThreadInfo; import java.lang.management.ThreadMXBean; -import java.lang.reflect.Type; import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; import java.net.MalformedURLException; import java.net.URI; import java.net.URISyntaxException; @@ -108,6 +103,7 @@ import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.ConcurrentModificationException; +import java.util.Date; import java.util.Enumeration; import java.util.HashMap; import java.util.List; @@ -115,14 +111,42 @@ import java.util.Locale; import java.util.Map; import java.util.SortedMap; import java.util.TreeMap; -import java.util.Date; import java.util.logging.Level; import java.util.logging.LogManager; import java.util.logging.LogRecord; import java.util.logging.Logger; import java.util.logging.SimpleFormatter; import java.util.regex.Pattern; + +import javax.servlet.ServletException; +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import jenkins.model.GlobalConfiguration; +import jenkins.model.GlobalConfigurationCategory; +import jenkins.model.GlobalConfigurationCategory.Unclassified; +import jenkins.model.Jenkins; +import jenkins.model.ModelObjectWithContextMenu; + +import org.acegisecurity.providers.anonymous.AnonymousAuthenticationToken; +import org.apache.commons.jelly.JellyContext; +import org.apache.commons.jelly.JellyTagException; +import org.apache.commons.jelly.Script; +import org.apache.commons.jelly.XMLOutput; +import org.apache.commons.jexl.parser.ASTSizeFunction; +import org.apache.commons.jexl.util.Introspector; import org.apache.commons.lang.StringUtils; +import org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement; +import org.jvnet.tiger_types.Types; +import org.kohsuke.stapler.Ancestor; +import org.kohsuke.stapler.Stapler; +import org.kohsuke.stapler.StaplerRequest; +import org.kohsuke.stapler.StaplerResponse; +import org.kohsuke.stapler.jelly.InternationalizedStringExpression.RawHtmlArgument; + +import com.google.common.base.Predicate; +import com.google.common.base.Predicates; /** * Utility functions used in views. @@ -921,6 +945,17 @@ public class Functions { i = (Item) ig; } } + + public static List getAllTopLevelItems(ItemGroup root) { + return Items.getAllItems(root, TopLevelItem.class); + } + + 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("/", " \u00BB "); + } public static Map dumpAllThreads() { Map sorted = new TreeMap(new ThreadSorter()); diff --git a/core/src/main/java/hudson/model/AbstractItem.java b/core/src/main/java/hudson/model/AbstractItem.java index ca00e912c4..9a1fe0cad1 100644 --- a/core/src/main/java/hudson/model/AbstractItem.java +++ b/core/src/main/java/hudson/model/AbstractItem.java @@ -43,8 +43,6 @@ import hudson.util.AtomicFileWriter; import hudson.util.IOException2; import hudson.util.IOUtils; import jenkins.model.Jenkins; - -import org.apache.commons.lang.StringUtils; import org.apache.tools.ant.taskdefs.Copy; import org.apache.tools.ant.types.FileSet; import org.kohsuke.stapler.WebMethod; @@ -56,7 +54,6 @@ import java.io.IOException; import java.util.Collection; import java.util.HashMap; import java.util.Map; -import java.util.StringTokenizer; import org.kohsuke.stapler.StaplerRequest; import org.kohsuke.stapler.StaplerResponse; @@ -330,21 +327,22 @@ public abstract class AbstractItem extends Actionable implements Item, HttpDelet else return n+" \u00BB "+getDisplayName(); } - public String getRelativeDisplayNameFrom(ItemGroup p) { - String relativeName = getRelativeNameFrom(p); - if (relativeName == null) return null; - return relativeName.replace("/", " \u00BB "); - } - /** - * This method only exists to disambiguate getRelativeNameFrom(Itemgroup) and getRelativeNameFrom(Item) - * @param p - * @return + * This method only exists to disambiguate {@link #getRelativeNameFrom(ItemGroup)} and {@link #getRelativeNameFrom(Item)} + * @since XXX + * @see #getRelativeNameFrom(ItemGroup) */ public String getRelativeNameFromGroup(ItemGroup p) { return getRelativeNameFrom(p); } + /** + * @param p + * The ItemGroup instance used as context to evaluate the relative name of this AbstractItem + * @return + * The name of the current item, relative to p. + * Nested ItemGroups are separated by / character. + */ public String getRelativeNameFrom(ItemGroup p) { // first list up all the parents Map parents = new HashMap(); @@ -385,7 +383,7 @@ public abstract class AbstractItem extends Actionable implements Item, HttpDelet /** * Called right after when a {@link Item} is loaded from disk. - * This is an opportunity to do a post load processing. + * This is an opporunity to do a post load processing. */ public void onLoad(ItemGroup parent, String name) throws IOException { this.parent = parent; @@ -425,7 +423,7 @@ public abstract class AbstractItem extends Actionable implements Item, HttpDelet public String getShortUrl() { return getParent().getUrlChildPrefix()+'/'+Util.rawEncode(getName())+'/'; } - + public String getSearchUrl() { return getShortUrl(); } diff --git a/core/src/main/java/hudson/model/Item.java b/core/src/main/java/hudson/model/Item.java index 003c9e1a19..b9092facfa 100644 --- a/core/src/main/java/hudson/model/Item.java +++ b/core/src/main/java/hudson/model/Item.java @@ -124,14 +124,6 @@ public interface Item extends PersistenceRoot, SearchableModelObject, AccessCont * of the ancestors. */ String getFullDisplayName(); - - /** - * Gets the relative display name to this item from the specified group - * - * @since 1.512 - * @return - */ - String getRelativeDisplayNameFrom(ItemGroup g); /** * Gets the relative name to this item from the specified group. @@ -167,7 +159,7 @@ public interface Item extends PersistenceRoot, SearchableModelObject, AccessCont * URL that ends with '/'. */ String getShortUrl(); - + /** * Returns the absolute URL of this item. This relies on the current * {@link StaplerRequest} to figure out what the host name is, diff --git a/core/src/main/java/hudson/model/Items.java b/core/src/main/java/hudson/model/Items.java index e4cb36b692..22255b820a 100644 --- a/core/src/main/java/hudson/model/Items.java +++ b/core/src/main/java/hudson/model/Items.java @@ -239,8 +239,10 @@ public class Items { /** * Gets all the {@link Item}s recursively in the {@link ItemGroup} tree * and filter them by the given type. + * + * @since XXX */ - public static List getAllItems(ItemGroup root, Class type) { + public static List getAllItems(final ItemGroup root, Class type) { List r = new ArrayList(); Stack q = new Stack(); @@ -257,7 +259,23 @@ public class Items { q.push((ItemGroup)i); } } - + // sort by relative name, ignoring case + Collections.sort(r, new Comparator() { + @Override + public int compare(T o1, T o2) { + if (o1 == null) { + if (o2 == null) { + return 0; + } + return 1; + } + if (o2 == null) { + return -1; + } + return o1.getRelativeNameFrom(root).compareToIgnoreCase(o2.getRelativeNameFrom(root)); + } + + }); return r; } diff --git a/core/src/main/java/hudson/model/ListView.java b/core/src/main/java/hudson/model/ListView.java index f406582ca0..849b77af56 100644 --- a/core/src/main/java/hudson/model/ListView.java +++ b/core/src/main/java/hudson/model/ListView.java @@ -39,7 +39,6 @@ import java.util.ArrayList; import java.util.LinkedHashSet; import java.util.List; import java.util.SortedSet; -import java.util.StringTokenizer; import java.util.TreeSet; import java.util.regex.Pattern; import java.util.regex.PatternSyntaxException; @@ -85,7 +84,7 @@ public class ListView extends View implements Saveable { /** * Whether to recurse in ItemGroups */ - private boolean recurse = true; + private boolean recurse; /** * Compiled include pattern from the includeRegex string. @@ -186,27 +185,6 @@ public class ListView extends View implements Saveable { return items; } - private TopLevelItem getItem(ItemGroup parent, String name) { - if (!name.contains("/")) { // same namespace - return parent.getItem(name); - } - StringTokenizer stringTokenizer = new StringTokenizer(name, "/"); - TopLevelItem leaf = null; - ItemGroup node = parent; - // Navigate down to the item using / as separator - while(stringTokenizer.hasMoreTokens()) { - leaf = node.getItem(stringTokenizer.nextToken()); - if (stringTokenizer.hasMoreTokens()) { - if (leaf instanceof ItemGroup) { - node = (ItemGroup)leaf; - } else { - return null; - } - } - } - return leaf; - } - private void includeItems(ItemGroup parent, SortedSet names) { includeItems(parent, parent, names); } @@ -224,6 +202,11 @@ public class ListView extends View implements Saveable { } } } + + public synchronized boolean jobNamesContains(TopLevelItem item) { + if (item == null) return false; + return jobNames.contains(item.getRelativeNameFrom(getOwnerItemGroup())); + } public synchronized boolean contains(TopLevelItem item) { if(allJobNames == null) { @@ -317,10 +300,19 @@ public class ListView extends View implements Saveable { protected void submit(StaplerRequest req) throws ServletException, FormException, IOException { JSONObject json = req.getSubmittedForm(); synchronized (this) { + recurse = json.optBoolean("recurse", true); jobNames.clear(); - for (TopLevelItem item : getOwnerItemGroup().getItems()) { - if(req.getParameter(item.getName())!=null) - jobNames.add(item.getName()); + Iterable items; + if (recurse) { + items = Items.getAllItems(getOwnerItemGroup(), TopLevelItem.class); + } else { + items = getOwnerItemGroup().getItems(); + } + for (TopLevelItem item : items) { + String relativeNameFrom = item.getRelativeNameFrom(getOwnerItemGroup()); + if(req.getParameter(relativeNameFrom)!=null) { + jobNames.add(relativeNameFrom); + } } } @@ -334,7 +326,6 @@ public class ListView extends View implements Saveable { includeRegex = null; includePattern = null; } - recurse = json.optBoolean("recurse", true); if (columns == null) { columns = new DescribableList>(this); diff --git a/core/src/main/resources/hudson/model/ListView/configure-entries.jelly b/core/src/main/resources/hudson/model/ListView/configure-entries.jelly index 26e59290d4..167ef8e22a 100644 --- a/core/src/main/resources/hudson/model/ListView/configure-entries.jelly +++ b/core/src/main/resources/hudson/model/ListView/configure-entries.jelly @@ -36,24 +36,27 @@ THE SOFTWARE. ${%Disabled jobs only} + + + +
- - -
+ + + +
+
+ checked="${it.includeRegex != null}" help="/help/view-config/includeregex.html"> - - - @@ -69,5 +72,18 @@ THE SOFTWARE. + + diff --git a/core/src/main/resources/hudson/model/View/main.groovy b/core/src/main/resources/hudson/model/View/main.groovy index fdf1b73fce..8f51aab6f9 100644 --- a/core/src/main/resources/hudson/model/View/main.groovy +++ b/core/src/main/resources/hudson/model/View/main.groovy @@ -11,7 +11,7 @@ if (items.isEmpty()) { } include(my,"noJob.jelly"); } else { - t.projectView(jobs: items, jobBaseUrl: "", showViewTabs: true, columnExtensions: my.columns, indenter: my.indenter, useFullName: true) { + t.projectView(jobs: items, jobBaseUrl: "", showViewTabs: true, columnExtensions: my.columns, indenter: my.indenter) { set("views",my.owner.views); set("currentView",my); if (my.owner.class == hudson.model.MyViewsProperty.class) { diff --git a/core/src/main/resources/hudson/views/BuildButtonColumn/column.jelly b/core/src/main/resources/hudson/views/BuildButtonColumn/column.jelly index 6e12e9ed6e..f959ec86e9 100644 --- a/core/src/main/resources/hudson/views/BuildButtonColumn/column.jelly +++ b/core/src/main/resources/hudson/views/BuildButtonColumn/column.jelly @@ -26,7 +26,7 @@ THE SOFTWARE. - + ${%Schedule a build} - ${useFullName ? job.getRelativeDisplayNameFrom(currentView.owner.itemGroup) : job.displayName} + ${useFullName ? job.fullDisplayName : h.getRelativeDisplayNameFrom(job,currentView.owner.itemGroup)} \ No newline at end of file diff --git a/core/src/main/resources/lib/hudson/projectView.jelly b/core/src/main/resources/lib/hudson/projectView.jelly index fb257a70ab..74b7943be7 100644 --- a/core/src/main/resources/lib/hudson/projectView.jelly +++ b/core/src/main/resources/lib/hudson/projectView.jelly @@ -79,7 +79,7 @@ THE SOFTWARE. - +