JAL-3368 removed parsing web colours (now on a separate branch)
[jalview.git] / src / jalview / util / ColorUtils.java
index d7829df..d465632 100644 (file)
 package jalview.util;
 
 import java.awt.Color;
+import java.util.HashMap;
+import java.util.Map;
 import java.util.Random;
 
+/**
+ * A class with utility methods for manipulating AWT colours/colors
+ */
 public class ColorUtils
 {
+  private static final int MAX_CACHE_SIZE = 1729;
+
+  /*
+   * a cache for colours generated from text strings
+   */
+  static Map<String, Color> myColours = new HashMap<>();
 
   /**
    * Generates a random color, will mix with input color. Code taken from
@@ -134,12 +145,12 @@ public class ColorUtils
      * prop = proportion of the way value is from minValue to maxValue
      */
     float prop = (value - minValue) / (maxValue - minValue);
-    float r = minColour.getRed() + prop
-            * (maxColour.getRed() - minColour.getRed());
-    float g = minColour.getGreen() + prop
-            * (maxColour.getGreen() - minColour.getGreen());
-    float b = minColour.getBlue() + prop
-            * (maxColour.getBlue() - minColour.getBlue());
+    float r = minColour.getRed()
+            + prop * (maxColour.getRed() - minColour.getRed());
+    float g = minColour.getGreen()
+            + prop * (maxColour.getGreen() - minColour.getGreen());
+    float b = minColour.getBlue()
+            + prop * (maxColour.getBlue() - minColour.getBlue());
     return new Color(r / 255, g / 255, b / 255);
   }
 
@@ -196,8 +207,8 @@ public class ColorUtils
    * Parses a string into a Color, where the accepted formats are
    * <ul>
    * <li>an AWT colour name e.g. white</li>
-   * <li>a hex colour value (without prefix) e.g. ff0000</li>
-   * <li>an rgb triple e.g. 100,50,150</li>
+   * <li>a six digit rgb hex colour value (without prefix) e.g. ff0000</li>
+   * <li>a comma-separated rgb triple e.g. 100,50,150</li>
    * </ul>
    * 
    * @param colour
@@ -210,21 +221,24 @@ public class ColorUtils
       return null;
     }
     colour = colour.trim();
-  
+
     Color col = null;
-    try
-    {
-      int value = Integer.parseInt(colour, 16);
-      col = new Color(value);
-    } catch (NumberFormatException ex)
+    if (colour.length() == 6 && StringUtils.isHexString(colour))
     {
+      try
+      {
+        int value = Integer.parseInt(colour, 16);
+        col = new Color(value);
+      } catch (NumberFormatException ex)
+      {
+      }
     }
-  
+
     if (col == null)
     {
-      col = ColorUtils.getAWTColorFromName(colour);
+      col = ColorUtils.getColorFromName(colour);
     }
-  
+
     if (col == null)
     {
       try
@@ -237,12 +251,12 @@ public class ColorUtils
           int b = Integer.parseInt(tokens[2].trim());
           col = new Color(r, g, b);
         }
-      } catch (Exception ex)
+      } catch (IllegalArgumentException ex)
       {
         // non-numeric token or out of 0-255 range
       }
     }
-  
+
     return col;
   }
 
@@ -260,98 +274,94 @@ public class ColorUtils
     {
       return Color.white;
     }
+    if (myColours.containsKey(name))
+    {
+      return myColours.get(name);
+    }
     int lsize = name.length();
     int start = 0;
     int end = lsize / 3;
-  
+
     int rgbOffset = Math.abs(name.hashCode() % 10) * 15; // 0-135
-  
+
     /*
      * red: first third
      */
-    int r = Math.abs(name.substring(start, end).hashCode() + rgbOffset) % 210 + 20;
+    int r = Math.abs(name.substring(start, end).hashCode() + rgbOffset)
+            % 210 + 20;
     start = end;
     end += lsize / 3;
     if (end > lsize)
     {
       end = lsize;
     }
-  
+
     /*
      * green: second third
      */
-    int g = Math.abs(name.substring(start, end).hashCode() + rgbOffset) % 210 + 20;
-  
+    int g = Math.abs(name.substring(start, end).hashCode() + rgbOffset)
+            % 210 + 20;
+
     /*
      * blue: third third
      */
     int b = Math.abs(name.substring(end).hashCode() + rgbOffset) % 210 + 20;
-  
+
     Color color = new Color(r, g, b);
-  
+
+    if (myColours.size() < MAX_CACHE_SIZE)
+    {
+      myColours.put(name, color);
+    }
+
     return color;
   }
 
   /**
    * Returns the Color constant for a given colour name e.g. "pink", or null if
-   * the name is not recognised
+   * the name is not recognised. Currently recognises only AWT colour names, but
+   * could be extended to support others e.g. standard html colour names.
    * 
    * @param name
    * @return
    */
-  public static Color getAWTColorFromName(String name)
+  public static Color getColorFromName(String name)
   {
     if (name == null)
     {
       return null;
     }
-    Color col = null;
-    name = name.toLowerCase();
-  
     // or make a static map; or use reflection on the field name
-    switch (name)
+    switch (name.toLowerCase())
     {
     case "black":
-      col = Color.black;
-      break;
+      return Color.black;
     case "blue":
-      col = Color.blue;
-      break;
+      return Color.blue;
     case "cyan":
-      col = Color.cyan;
-      break;
+      return Color.cyan;
     case "darkgray":
-      col = Color.darkGray;
-      break;
+      return Color.darkGray;
     case "gray":
-      col = Color.gray;
-      break;
+      return Color.gray;
     case "green":
-      col = Color.green;
-      break;
+      return Color.green;
     case "lightgray":
-      col = Color.lightGray;
-      break;
+      return Color.lightGray;
     case "magenta":
-      col = Color.magenta;
-      break;
+      return Color.magenta;
     case "orange":
-      col = Color.orange;
-      break;
+      return Color.orange;
     case "pink":
-      col = Color.pink;
-      break;
+      return Color.pink;
     case "red":
-      col = Color.red;
-      break;
+      return Color.red;
     case "white":
-      col = Color.white;
-      break;
+      return Color.white;
     case "yellow":
-      col = Color.yellow;
-      break;
+      return Color.yellow;
+    default:
+      return null;
     }
-  
-    return col;
   }
 }