diff --git a/core/src/main/java/hudson/AboutJenkins.java b/core/src/main/java/hudson/AboutJenkins.java index 46c91f796064..cf51bf96f9a9 100644 --- a/core/src/main/java/hudson/AboutJenkins.java +++ b/core/src/main/java/hudson/AboutJenkins.java @@ -18,7 +18,7 @@ public class AboutJenkins extends ManagementLink { @Override public String getIconFileName() { - return "help.svg"; + return "symbol-help-circle"; } @Override diff --git a/core/src/main/java/hudson/Functions.java b/core/src/main/java/hudson/Functions.java index 5c690f7637f1..b9d66b694bb9 100644 --- a/core/src/main/java/hudson/Functions.java +++ b/core/src/main/java/hudson/Functions.java @@ -161,6 +161,7 @@ import org.apache.commons.jexl.parser.ASTSizeFunction; import org.apache.commons.jexl.util.Introspector; import org.apache.commons.lang.StringUtils; +import org.jenkins.ui.icon.Icon; import org.jenkins.ui.icon.IconSet; import org.jvnet.tiger_types.Types; import org.kohsuke.accmod.Restricted; @@ -2290,6 +2291,68 @@ public static boolean isContextMenuVisible(Action a) { } } + @Restricted(NoExternalUse.class) + public static Icon tryGetIcon(String iconGuess) { + // Jenkins Symbols don't have metadata so return null + if (iconGuess == null || iconGuess.startsWith("symbol-")) { + return null; + } + + StaplerRequest currentRequest = Stapler.getCurrentRequest(); + currentRequest.getWebApp().getDispatchValidator().allowDispatch(currentRequest, Stapler.getCurrentResponse()); + Icon iconMetadata = IconSet.icons.getIconByClassSpec(iconGuess); + + if (iconMetadata == null) { + // Icon could be provided as a simple iconFileName e.g. "settings.png" + iconMetadata = IconSet.icons.getIconByClassSpec(IconSet.toNormalizedIconNameClass(iconGuess) + " icon-md"); + } + + if (iconMetadata == null) { + // Icon could be provided as an absolute iconFileName e.g. "/plugin/foo/abc.png" + iconMetadata = IconSet.icons.getIconByUrl(iconGuess); + } + + return iconMetadata; + } + + @Restricted(NoExternalUse.class) + public static String tryGetIconPath(String iconGuess, JellyContext context) { + if (iconGuess == null) { + return null; + } + + if (iconGuess.startsWith("symbol-")) { + return iconGuess; + } + + StaplerRequest currentRequest = Stapler.getCurrentRequest(); + currentRequest.getWebApp().getDispatchValidator().allowDispatch(currentRequest, Stapler.getCurrentResponse()); + String rootURL = currentRequest.getContextPath(); + Icon iconMetadata = tryGetIcon(iconGuess); + String iconSource = null; + + if (iconMetadata != null) { + iconSource = iconMetadata.getQualifiedUrl(context); + } + + if (iconMetadata == null) { + if (!iconGuess.startsWith("/")) { + iconGuess = "/" + iconGuess; + } + + iconSource = rootURL + (iconGuess.startsWith("/images/") || iconGuess.startsWith("/plugin/") ? getResourcePath() : "") + iconGuess; + } + + if (iconMetadata != null && iconMetadata.getClassSpec() != null) { + String translatedIcon = IconSet.tryTranslateTangoIconToSymbol(iconMetadata.getClassSpec()); + if (translatedIcon != null) { + return translatedIcon; + } + } + + return iconSource; + } + @SuppressFBWarnings(value = "PREDICTABLE_RANDOM", justification = "True randomness isn't necessary for form item IDs") @Restricted(NoExternalUse.class) public static String generateItemId() { diff --git a/core/src/main/java/hudson/model/Action.java b/core/src/main/java/hudson/model/Action.java index 08addd77361e..17b21a2ca7c9 100644 --- a/core/src/main/java/hudson/model/Action.java +++ b/core/src/main/java/hudson/model/Action.java @@ -78,15 +78,18 @@ */ public interface Action extends ModelObject { /** - * Gets the file name of the icon. + * Gets the name of the icon. * * @return + * If the icon name is prefixed with "symbol-", a Jenkins Symbol + * will be used. + *
* If just a file name (like "abc.gif") is returned, it will be * interpreted as a file name inside {@code /images/24x24}. * This is useful for using one of the stock images. *
* If an absolute file name that starts from '/' is returned (like - * "/plugin/foo/abc.gif'), then it will be interpreted as a path + * "/plugin/foo/abc.gif"), then it will be interpreted as a path * from the context root of Jenkins. This is useful to pick up * image files from a plugin. *
@@ -94,6 +97,7 @@ public interface Action extends ModelObject {
* but this can be used for actions that only contribute {@code floatBox.jelly}
* and no task list item. The other case where this is useful is
* to avoid showing links that require a privilege when the user is anonymous.
+ * @see Jenkins Symbols
* @see Functions#isAnonymous()
* @see Functions#getIconFilePath(Action)
*/
diff --git a/core/src/main/java/hudson/model/ManageJenkinsAction.java b/core/src/main/java/hudson/model/ManageJenkinsAction.java
index caf33d077eca..605801c42e1d 100644
--- a/core/src/main/java/hudson/model/ManageJenkinsAction.java
+++ b/core/src/main/java/hudson/model/ManageJenkinsAction.java
@@ -38,7 +38,7 @@ public class ManageJenkinsAction implements RootAction {
@Override
public String getIconFileName() {
if (Jenkins.get().hasAnyPermission(Jenkins.MANAGE, Jenkins.SYSTEM_READ))
- return "gear.png";
+ return "symbol-settings";
else
return null;
}
diff --git a/core/src/main/java/jenkins/management/ConfigureLink.java b/core/src/main/java/jenkins/management/ConfigureLink.java
index 785e838a4ca0..5f34e75ec5c1 100644
--- a/core/src/main/java/jenkins/management/ConfigureLink.java
+++ b/core/src/main/java/jenkins/management/ConfigureLink.java
@@ -39,7 +39,7 @@ public class ConfigureLink extends ManagementLink {
@Override
public String getIconFileName() {
- return "gear.svg";
+ return "symbol-settings";
}
@Override
diff --git a/core/src/main/java/jenkins/model/ModelObjectWithContextMenu.java b/core/src/main/java/jenkins/model/ModelObjectWithContextMenu.java
index 7f2bddda2224..f6cae43f50e6 100644
--- a/core/src/main/java/jenkins/model/ModelObjectWithContextMenu.java
+++ b/core/src/main/java/jenkins/model/ModelObjectWithContextMenu.java
@@ -133,6 +133,18 @@ public ContextMenu add(String url, String icon, String text, boolean post, boole
return this;
}
+ /** @since TODO */
+ public ContextMenu add(String url, String icon, String iconXml, String text, boolean post, boolean requiresConfirmation) {
+ if (text != null && icon != null && url != null) {
+ MenuItem item = new MenuItem(url, icon, text);
+ item.iconXml = iconXml;
+ item.post = post;
+ item.requiresConfirmation = requiresConfirmation;
+ items.add(item);
+ }
+ return this;
+ }
+
/**
* Add a header row (no icon, no URL, rendered in header style).
*
@@ -268,6 +280,11 @@ class MenuItem {
@SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD", justification = "read by Stapler")
public String icon;
+ /**
+ * Optional icon XML, if set it's used instead of @icon for the menu item
+ */
+ private String iconXml;
+
/**
* True to make a POST request rather than GET.
* @since 1.504
@@ -300,6 +317,11 @@ class MenuItem {
@SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD", justification = "read by Stapler")
public ContextMenu subMenu;
+ @Exported
+ public String getIconXml() {
+ return iconXml;
+ }
+
public MenuItem(String url, String icon, String displayName) {
withUrl(url).withIcon(icon).withDisplayName(displayName);
}
diff --git a/core/src/main/java/org/jenkins/ui/icon/IconSet.java b/core/src/main/java/org/jenkins/ui/icon/IconSet.java
index 273964ea2cc7..21ae91c641cd 100644
--- a/core/src/main/java/org/jenkins/ui/icon/IconSet.java
+++ b/core/src/main/java/org/jenkins/ui/icon/IconSet.java
@@ -35,6 +35,8 @@
import org.apache.commons.io.IOUtils;
import org.apache.commons.jelly.JellyContext;
import org.apache.commons.lang.StringUtils;
+import org.kohsuke.accmod.Restricted;
+import org.kohsuke.accmod.restrictions.NoExternalUse;
/**
* An icon set.
@@ -45,7 +47,7 @@ public class IconSet {
public static final IconSet icons = new IconSet();
- private static final Map