Unsafe public fields in UpdateInterface class: make public fields final
This commit makes the UpdateInterface class immutable. The Config -> UpdateInterface initialization is moved to the UpdateInterface constructor. Default values for the fields are moved to the constructor as well. Instances of String[] are changed to List<String> and made immutable. Instances of java.awt.Rectangle (which is mutable) are replaced with a new immutable com.threerings.getdown.util.Rectangle class. Although java.awt.Color is (sort of) immutable, it was also removed and replaced with a new immutable com.threerings.getdown.util.Color class, since it was the last dependency from the getdown core module to anything in the java.awt package, which means that when we migrate to Java 9+ the core module should no longer require a dependency on the java.desktop module. The assertions and expected values in ColorTest have been verified against the corresponding java.awt.Color values. (Triggered by internal security audit and Fortify analysis.)
This commit is contained in:
@@ -5,8 +5,6 @@
|
|||||||
|
|
||||||
package com.threerings.getdown.data;
|
package com.threerings.getdown.data;
|
||||||
|
|
||||||
import java.awt.Color;
|
|
||||||
import java.awt.Rectangle;
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.net.MalformedURLException;
|
import java.net.MalformedURLException;
|
||||||
@@ -57,7 +55,7 @@ public class Application
|
|||||||
public static final String MANIFEST_CLASS = "manifest";
|
public static final String MANIFEST_CLASS = "manifest";
|
||||||
|
|
||||||
/** Used to communicate information about the UI displayed when updating the application. */
|
/** Used to communicate information about the UI displayed when updating the application. */
|
||||||
public static class UpdateInterface
|
public static final class UpdateInterface
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* The major steps involved in updating, along with some arbitrary percentages
|
* The major steps involved in updating, along with some arbitrary percentages
|
||||||
@@ -85,68 +83,67 @@ public class Application
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** The human readable name of this application. */
|
/** The human readable name of this application. */
|
||||||
public String name;
|
public final String name;
|
||||||
|
|
||||||
/** A background color, just in case. */
|
/** A background color, just in case. */
|
||||||
public Color background = Color.white;
|
public final Color background;
|
||||||
|
|
||||||
/** Background image specifiers for `RotatingBackgrounds`. */
|
/** Background image specifiers for `RotatingBackgrounds`. */
|
||||||
public String[] rotatingBackgrounds;
|
public final List<String> rotatingBackgrounds;
|
||||||
|
|
||||||
/** The error background image for `RotatingBackgrounds`. */
|
/** The error background image for `RotatingBackgrounds`. */
|
||||||
public String errorBackground;
|
public final String errorBackground;
|
||||||
|
|
||||||
/** The paths (relative to the appdir) of images for the window icon. */
|
/** The paths (relative to the appdir) of images for the window icon. */
|
||||||
public String[] iconImages;
|
public final List<String> iconImages;
|
||||||
|
|
||||||
/** The path (relative to the appdir) to a single background image. */
|
/** The path (relative to the appdir) to a single background image. */
|
||||||
public String backgroundImage;
|
public final String backgroundImage;
|
||||||
|
|
||||||
/** The path (relative to the appdir) to the progress bar image. */
|
/** The path (relative to the appdir) to the progress bar image. */
|
||||||
public String progressImage;
|
public final String progressImage;
|
||||||
|
|
||||||
/** The dimensions of the progress bar. */
|
/** The dimensions of the progress bar. */
|
||||||
public Rectangle progress = new Rectangle(5, 5, 300, 15);
|
public final Rectangle progress;
|
||||||
|
|
||||||
/** The color of the progress text. */
|
/** The color of the progress text. */
|
||||||
public Color progressText = Color.black;
|
public final Color progressText;
|
||||||
|
|
||||||
/** The color of the progress bar. */
|
/** The color of the progress bar. */
|
||||||
public Color progressBar = new Color(0x6699CC);
|
public final Color progressBar;
|
||||||
|
|
||||||
/** The dimensions of the status display. */
|
/** The dimensions of the status display. */
|
||||||
public Rectangle status = new Rectangle(5, 25, 500, 100);
|
public final Rectangle status;
|
||||||
|
|
||||||
/** The color of the status text. */
|
/** The color of the status text. */
|
||||||
public Color statusText = Color.black;
|
public final Color statusText;
|
||||||
|
|
||||||
/** The color of the text shadow. */
|
/** The color of the text shadow. */
|
||||||
public Color textShadow;
|
public final Color textShadow;
|
||||||
|
|
||||||
/** Where to point the user for help with install errors. */
|
/** Where to point the user for help with install errors. */
|
||||||
public String installError;
|
public final String installError;
|
||||||
|
|
||||||
/** The dimensions of the patch notes button. */
|
/** The dimensions of the patch notes button. */
|
||||||
public Rectangle patchNotes = new Rectangle(5, 50, 112, 26);
|
public final Rectangle patchNotes;
|
||||||
|
|
||||||
/** The patch notes URL. */
|
/** The patch notes URL. */
|
||||||
public String patchNotesUrl;
|
public final String patchNotesUrl;
|
||||||
|
|
||||||
/** Whether window decorations are hidden for the UI. */
|
/** Whether window decorations are hidden for the UI. */
|
||||||
public boolean hideDecorations;
|
public final boolean hideDecorations;
|
||||||
|
|
||||||
/** Whether progress text should be hidden or not. */
|
/** Whether progress text should be hidden or not. */
|
||||||
public boolean hideProgressText;
|
public final boolean hideProgressText;
|
||||||
|
|
||||||
/** The minimum number of seconds to display the GUI. This is to prevent the GUI from
|
/** The minimum number of seconds to display the GUI. This is to prevent the GUI from
|
||||||
* flashing up on the screen and immediately disappearing, which can be confusing to the
|
* flashing up on the screen and immediately disappearing, which can be confusing to the
|
||||||
* user. */
|
* user. */
|
||||||
public int minShowSeconds = 5;
|
public final int minShowSeconds;
|
||||||
|
|
||||||
/** The global percentages for each step. A step may have more than one, and
|
/** The global percentages for each step. A step may have more than one, and
|
||||||
* the lowest reasonable one is used if a step is revisited. */
|
* the lowest reasonable one is used if a step is revisited. */
|
||||||
public Map<Step, List<Integer>> stepPercentages =
|
public final Map<Step, List<Integer>> stepPercentages;
|
||||||
new EnumMap<Step, List<Integer>>(Step.class);
|
|
||||||
|
|
||||||
/** Generates a string representation of this instance. */
|
/** Generates a string representation of this instance. */
|
||||||
@Override
|
@Override
|
||||||
@@ -160,11 +157,56 @@ public class Application
|
|||||||
", hideProgressText" + hideProgressText + ", minShow=" + minShowSeconds + "]";
|
", hideProgressText" + hideProgressText + ", minShow=" + minShowSeconds + "]";
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Initializer */
|
public UpdateInterface (Config config)
|
||||||
{
|
{
|
||||||
|
this.name = config.getString("ui.name");
|
||||||
|
this.progress = config.getRect("ui.progress", new Rectangle(5, 5, 300, 15));
|
||||||
|
this.progressText = config.getColor("ui.progress_text", Color.BLACK);
|
||||||
|
this.hideProgressText = config.getBoolean("ui.hide_progress_text");
|
||||||
|
this.minShowSeconds = config.getInt("ui.min_show_seconds", 5);
|
||||||
|
this.progressBar = config.getColor("ui.progress_bar", new Color(0x66, 0x99, 0xCC));
|
||||||
|
this.status = config.getRect("ui.status", new Rectangle(5, 25, 500, 100));
|
||||||
|
this.statusText = config.getColor("ui.status_text", Color.BLACK);
|
||||||
|
this.textShadow = config.getColor("ui.text_shadow", null);
|
||||||
|
this.hideDecorations = config.getBoolean("ui.hide_decorations");
|
||||||
|
this.backgroundImage = config.getString("ui.background_image",
|
||||||
|
config.getString("ui.background")); // support legacy format
|
||||||
|
// and now ui.background can refer to the background color, but fall back to black
|
||||||
|
// or white, depending on the brightness of the progressText
|
||||||
|
Color defaultBackground = (.5f < this.progressText.brightness())
|
||||||
|
? Color.BLACK
|
||||||
|
: Color.WHITE;
|
||||||
|
this.background = config.getColor("ui.background", defaultBackground);
|
||||||
|
this.progressImage = config.getString("ui.progress_image");
|
||||||
|
this.rotatingBackgrounds = stringsToList(config.getMultiValue("ui.rotating_background"));
|
||||||
|
this.iconImages = stringsToList(config.getMultiValue("ui.icon"));
|
||||||
|
this.errorBackground = config.getString("ui.error_background");
|
||||||
|
|
||||||
|
// On an installation error, where do we point the user.
|
||||||
|
String installError = config.getUrl("ui.install_error", null);
|
||||||
|
this.installError = (installError == null) ?
|
||||||
|
"m.default_install_error" : MessageUtil.taint(installError);
|
||||||
|
|
||||||
|
// the patch notes bits
|
||||||
|
this.patchNotes = config.getRect("ui.patch_notes", new Rectangle(5, 50, 112, 26));
|
||||||
|
this.patchNotesUrl = config.getUrl("ui.patch_notes_url", null);
|
||||||
|
|
||||||
|
// step progress percentage (defaults and then customized values)
|
||||||
|
EnumMap<Step, List<Integer>> stepPercentages = new EnumMap<Step, List<Integer>>(Step.class);
|
||||||
for (Step step : Step.values()) {
|
for (Step step : Step.values()) {
|
||||||
stepPercentages.put(step, step.defaultPercents);
|
stepPercentages.put(step, step.defaultPercents);
|
||||||
}
|
}
|
||||||
|
for (UpdateInterface.Step step : UpdateInterface.Step.values()) {
|
||||||
|
String spec = config.getString("ui.percents." + step.name());
|
||||||
|
if (spec != null) {
|
||||||
|
try {
|
||||||
|
stepPercentages.put(step, intsToList(StringUtil.parseIntArray(spec)));
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.warning("Failed to parse percentages for " + step + ": " + spec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.stepPercentages = Collections.unmodifiableMap(stepPercentages);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -696,59 +738,13 @@ public class Application
|
|||||||
_codeCacheRetentionDays = config.getInt("code_cache_retention_days", 7);
|
_codeCacheRetentionDays = config.getInt("code_cache_retention_days", 7);
|
||||||
|
|
||||||
// parse and return our application config
|
// parse and return our application config
|
||||||
UpdateInterface ui = new UpdateInterface();
|
UpdateInterface ui = new UpdateInterface(config);
|
||||||
_name = ui.name = config.getString("ui.name");
|
_name = ui.name;
|
||||||
ui.progress = config.getRect("ui.progress", ui.progress);
|
|
||||||
ui.progressText = config.getColor("ui.progress_text", ui.progressText);
|
|
||||||
ui.hideProgressText = config.getBoolean("ui.hide_progress_text");
|
|
||||||
ui.minShowSeconds = config.getInt("ui.min_show_seconds", ui.minShowSeconds);
|
|
||||||
ui.progressBar = config.getColor("ui.progress_bar", ui.progressBar);
|
|
||||||
ui.status = config.getRect("ui.status", ui.status);
|
|
||||||
ui.statusText = config.getColor("ui.status_text", ui.statusText);
|
|
||||||
ui.textShadow = config.getColor("ui.text_shadow", ui.textShadow);
|
|
||||||
ui.hideDecorations = config.getBoolean("ui.hide_decorations");
|
|
||||||
ui.backgroundImage = config.getString("ui.background_image");
|
|
||||||
if (ui.backgroundImage == null) { // support legacy format
|
|
||||||
ui.backgroundImage = config.getString("ui.background");
|
|
||||||
}
|
|
||||||
// and now ui.background can refer to the background color, but fall back to black
|
|
||||||
// or white, depending on the brightness of the progressText
|
|
||||||
Color defaultBackground = (.5f < Color.RGBtoHSB(
|
|
||||||
ui.progressText.getRed(), ui.progressText.getGreen(), ui.progressText.getBlue(),
|
|
||||||
null)[2])
|
|
||||||
? Color.BLACK
|
|
||||||
: Color.WHITE;
|
|
||||||
ui.background = config.getColor("ui.background", defaultBackground);
|
|
||||||
ui.progressImage = config.getString("ui.progress_image");
|
|
||||||
ui.rotatingBackgrounds = config.getMultiValue("ui.rotating_background");
|
|
||||||
ui.iconImages = config.getMultiValue("ui.icon");
|
|
||||||
ui.errorBackground = config.getString("ui.error_background");
|
|
||||||
_dockIconPath = config.getString("ui.mac_dock_icon");
|
_dockIconPath = config.getString("ui.mac_dock_icon");
|
||||||
if (_dockIconPath == null) {
|
if (_dockIconPath == null) {
|
||||||
_dockIconPath = "../desktop.icns"; // use a sensible default
|
_dockIconPath = "../desktop.icns"; // use a sensible default
|
||||||
}
|
}
|
||||||
|
|
||||||
// On an installation error, where do we point the user.
|
|
||||||
String installError = config.getUrl("ui.install_error", null);
|
|
||||||
ui.installError = (installError == null) ?
|
|
||||||
"m.default_install_error" : MessageUtil.taint(installError);
|
|
||||||
|
|
||||||
// the patch notes bits
|
|
||||||
ui.patchNotes = config.getRect("ui.patch_notes", ui.patchNotes);
|
|
||||||
ui.patchNotesUrl = config.getUrl("ui.patch_notes_url", null);
|
|
||||||
|
|
||||||
// step progress percentages
|
|
||||||
for (UpdateInterface.Step step : UpdateInterface.Step.values()) {
|
|
||||||
String spec = config.getString("ui.percents." + step.name());
|
|
||||||
if (spec != null) {
|
|
||||||
try {
|
|
||||||
ui.stepPercentages.put(step, intsToList(StringUtil.parseIntArray(spec)));
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.warning("Failed to parse percentages for " + step + ": " + spec);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ui;
|
return ui;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1639,6 +1635,18 @@ public class Application
|
|||||||
return Collections.unmodifiableList(list);
|
return Collections.unmodifiableList(list);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Make an immutable List from the specified String array.
|
||||||
|
*/
|
||||||
|
public static List<String> stringsToList (String[] values)
|
||||||
|
{
|
||||||
|
List<String> list = new ArrayList<>(values.length);
|
||||||
|
for (String val : values) {
|
||||||
|
list.add(val);
|
||||||
|
}
|
||||||
|
return Collections.unmodifiableList(list);
|
||||||
|
}
|
||||||
|
|
||||||
/** Used to parse resources with the specified name. */
|
/** Used to parse resources with the specified name. */
|
||||||
protected void parseResources (Config config, String name, EnumSet<Resource.Attr> attrs,
|
protected void parseResources (Config config, String name, EnumSet<Resource.Attr> attrs,
|
||||||
List<Resource> list)
|
List<Resource> list)
|
||||||
|
|||||||
@@ -0,0 +1,81 @@
|
|||||||
|
//
|
||||||
|
// Getdown - application installer, patcher and launcher
|
||||||
|
// Copyright (C) 2004-2016 Getdown authors
|
||||||
|
// https://github.com/threerings/getdown/blob/master/LICENSE
|
||||||
|
|
||||||
|
package com.threerings.getdown.util;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An immutable color.
|
||||||
|
*/
|
||||||
|
public class Color
|
||||||
|
{
|
||||||
|
public final static Color WHITE = new Color(255, 255, 255);
|
||||||
|
public final static Color BLACK = new Color(0, 0, 0);
|
||||||
|
|
||||||
|
public final int red;
|
||||||
|
public final int green;
|
||||||
|
public final int blue;
|
||||||
|
public final int alpha;
|
||||||
|
|
||||||
|
public Color (int r, int g, int b)
|
||||||
|
{
|
||||||
|
this.red = Math.min(Math.max(r, 0), 255);
|
||||||
|
this.green = Math.min(Math.max(g, 0), 255);
|
||||||
|
this.blue = Math.min(Math.max(b, 0), 255);
|
||||||
|
this.alpha = 255;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Color (int rgba, boolean hasAlpha)
|
||||||
|
{
|
||||||
|
this.red = (rgba >> 16) & 0xFF;
|
||||||
|
this.green = (rgba >> 8) & 0xFF;
|
||||||
|
this.blue = (rgba >> 0) & 0xFF;
|
||||||
|
|
||||||
|
if (hasAlpha) {
|
||||||
|
this.alpha = (rgba >> 24) & 0xFF;
|
||||||
|
} else {
|
||||||
|
this.alpha = 255;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the combined RBGA value for this color.
|
||||||
|
*/
|
||||||
|
public int rgba ()
|
||||||
|
{
|
||||||
|
return ((alpha & 0xFF) << 24) |
|
||||||
|
((red & 0xFF) << 16) |
|
||||||
|
((green & 0xFF) << 8) |
|
||||||
|
((blue & 0xFF) << 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the brightness of this color, per the standard HSB model.
|
||||||
|
*/
|
||||||
|
public float brightness ()
|
||||||
|
{
|
||||||
|
int max = Math.max(Math.max(red, green), blue);
|
||||||
|
return ((float) max) / 255.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object other)
|
||||||
|
{
|
||||||
|
return other instanceof Color && ((Color)other).rgba() == this.rgba();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
@Override
|
||||||
|
public int hashCode()
|
||||||
|
{
|
||||||
|
return rgba();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
public String toString ()
|
||||||
|
{
|
||||||
|
return getClass().getName() + "[r=" + red + ", g=" + green + ", b=" + blue + ", a=" + alpha + "]";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,9 +5,6 @@
|
|||||||
|
|
||||||
package com.threerings.getdown.util;
|
package com.threerings.getdown.util;
|
||||||
|
|
||||||
import java.awt.Color;
|
|
||||||
import java.awt.Rectangle;
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@@ -32,6 +29,9 @@ import static com.threerings.getdown.Log.log;
|
|||||||
*/
|
*/
|
||||||
public class Config
|
public class Config
|
||||||
{
|
{
|
||||||
|
/** Empty configuration. */
|
||||||
|
public static final Config EMPTY = new Config(new HashMap<String, Object>());
|
||||||
|
|
||||||
/** Options that control the {@link #parsePairs} function. */
|
/** Options that control the {@link #parsePairs} function. */
|
||||||
public static class ParseOpts {
|
public static class ParseOpts {
|
||||||
// these should be tweaked as desired by the caller
|
// these should be tweaked as desired by the caller
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
//
|
||||||
|
// Getdown - application installer, patcher and launcher
|
||||||
|
// Copyright (C) 2004-2016 Getdown authors
|
||||||
|
// https://github.com/threerings/getdown/blob/master/LICENSE
|
||||||
|
|
||||||
|
package com.threerings.getdown.util;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An immutable rectangle.
|
||||||
|
*/
|
||||||
|
public class Rectangle
|
||||||
|
{
|
||||||
|
public final int x;
|
||||||
|
public final int y;
|
||||||
|
public final int width;
|
||||||
|
public final int height;
|
||||||
|
|
||||||
|
public Rectangle (int x, int y, int width, int height)
|
||||||
|
{
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
this.width = width;
|
||||||
|
this.height = height;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
public String toString ()
|
||||||
|
{
|
||||||
|
return getClass().getName() + "[x=" + x + ", y=" + y + ", width=" + width + ", height=" + height + "]";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,111 @@
|
|||||||
|
//
|
||||||
|
// Getdown - application installer, patcher and launcher
|
||||||
|
// Copyright (C) 2004-2016 Getdown authors
|
||||||
|
// https://github.com/threerings/getdown/blob/master/LICENSE
|
||||||
|
|
||||||
|
package com.threerings.getdown.util;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests {@link Color}.
|
||||||
|
*/
|
||||||
|
public class ColorTest
|
||||||
|
{
|
||||||
|
@Test
|
||||||
|
public void testRgbConstructor ()
|
||||||
|
{
|
||||||
|
Color color1 = new Color(0, 0, 0);
|
||||||
|
assertEquals(0, color1.red);
|
||||||
|
assertEquals(0, color1.green);
|
||||||
|
assertEquals(0, color1.blue);
|
||||||
|
assertEquals(255, color1.alpha);
|
||||||
|
assertEquals(0xFF000000, color1.rgba());
|
||||||
|
assertEquals(0, color1.brightness(), 0.0000001);
|
||||||
|
assertEquals(Color.BLACK, color1);
|
||||||
|
|
||||||
|
Color color2 = new Color(255, 255, 255);
|
||||||
|
assertEquals(255, color2.red);
|
||||||
|
assertEquals(255, color2.green);
|
||||||
|
assertEquals(255, color2.blue);
|
||||||
|
assertEquals(255, color2.alpha);
|
||||||
|
assertEquals(0xFFFFFFFF, color2.rgba());
|
||||||
|
assertEquals(1, color2.brightness(), 0.0000001);
|
||||||
|
assertEquals(Color.WHITE, color2);
|
||||||
|
|
||||||
|
Color color3 = new Color(1, 2, 3);
|
||||||
|
assertEquals(1, color3.red);
|
||||||
|
assertEquals(2, color3.green);
|
||||||
|
assertEquals(3, color3.blue);
|
||||||
|
assertEquals(255, color3.alpha);
|
||||||
|
assertEquals(0xFF010203, color3.rgba());
|
||||||
|
assertEquals(0.0117647, color3.brightness(), 0.0000001);
|
||||||
|
|
||||||
|
Color color4 = new Color(-100, 300, 200);
|
||||||
|
assertEquals(0, color4.red);
|
||||||
|
assertEquals(255, color4.green);
|
||||||
|
assertEquals(200, color4.blue);
|
||||||
|
assertEquals(255, color4.alpha);
|
||||||
|
assertEquals(0xFF00FFC8, color4.rgba());
|
||||||
|
assertEquals(1, color4.brightness(), 0.0000001);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRgbaConstructor ()
|
||||||
|
{
|
||||||
|
Color color1 = new Color(0, false);
|
||||||
|
assertEquals(0, color1.red);
|
||||||
|
assertEquals(0, color1.green);
|
||||||
|
assertEquals(0, color1.blue);
|
||||||
|
assertEquals(255, color1.alpha);
|
||||||
|
assertEquals(0xFF000000, color1.rgba());
|
||||||
|
assertEquals(0, color1.brightness(), 0.0000001);
|
||||||
|
assertEquals(Color.BLACK, color1);
|
||||||
|
|
||||||
|
Color color2 = new Color(0, true);
|
||||||
|
assertEquals(0, color2.red);
|
||||||
|
assertEquals(0, color2.green);
|
||||||
|
assertEquals(0, color2.blue);
|
||||||
|
assertEquals(0, color2.alpha);
|
||||||
|
assertEquals(0, color2.rgba());
|
||||||
|
assertEquals(0, color2.brightness(), 0.0000001);
|
||||||
|
assertFalse(Color.BLACK.equals(color2));
|
||||||
|
|
||||||
|
Color color3 = new Color(0x00FFFFFF, false);
|
||||||
|
assertEquals(255, color3.red);
|
||||||
|
assertEquals(255, color3.green);
|
||||||
|
assertEquals(255, color3.blue);
|
||||||
|
assertEquals(255, color3.alpha);
|
||||||
|
assertEquals(0xFFFFFFFF, color3.rgba());
|
||||||
|
assertEquals(1, color3.brightness(), 0.0000001);
|
||||||
|
assertEquals(Color.WHITE, color3);
|
||||||
|
|
||||||
|
Color color4 = new Color(0x00FFFFFF, true);
|
||||||
|
assertEquals(255, color4.red);
|
||||||
|
assertEquals(255, color4.green);
|
||||||
|
assertEquals(255, color4.blue);
|
||||||
|
assertEquals(0, color4.alpha);
|
||||||
|
assertEquals(0x00FFFFFF, color4.rgba());
|
||||||
|
assertEquals(1, color4.brightness(), 0.0000001);
|
||||||
|
assertFalse(Color.WHITE.equals(color4));
|
||||||
|
|
||||||
|
Color color5 = new Color(0x00010203, false);
|
||||||
|
assertEquals(1, color5.red);
|
||||||
|
assertEquals(2, color5.green);
|
||||||
|
assertEquals(3, color5.blue);
|
||||||
|
assertEquals(255, color5.alpha);
|
||||||
|
assertEquals(0xFF010203, color5.rgba());
|
||||||
|
assertEquals(0.0117647, color5.brightness(), 0.0000001);
|
||||||
|
|
||||||
|
Color color6 = new Color(0x00010203, true);
|
||||||
|
assertEquals(1, color6.red);
|
||||||
|
assertEquals(2, color6.green);
|
||||||
|
assertEquals(3, color6.blue);
|
||||||
|
assertEquals(0, color6.alpha);
|
||||||
|
assertEquals(0x00010203, color6.rgba());
|
||||||
|
assertEquals(0.0117647, color6.brightness(), 0.0000001);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,17 +7,15 @@ package com.threerings.getdown.launcher;
|
|||||||
|
|
||||||
import java.awt.BorderLayout;
|
import java.awt.BorderLayout;
|
||||||
import java.awt.Container;
|
import java.awt.Container;
|
||||||
import java.awt.Cursor;
|
|
||||||
import java.awt.Dimension;
|
import java.awt.Dimension;
|
||||||
import java.awt.EventQueue;
|
import java.awt.EventQueue;
|
||||||
import java.awt.Image;
|
import java.awt.Image;
|
||||||
|
import java.awt.Rectangle;
|
||||||
import java.awt.event.ActionEvent;
|
import java.awt.event.ActionEvent;
|
||||||
import java.awt.event.ActionListener;
|
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
|
|
||||||
import javax.imageio.ImageIO;
|
import javax.imageio.ImageIO;
|
||||||
import javax.swing.AbstractAction;
|
import javax.swing.AbstractAction;
|
||||||
import javax.swing.ImageIcon;
|
|
||||||
import javax.swing.JButton;
|
import javax.swing.JButton;
|
||||||
import javax.swing.JFrame;
|
import javax.swing.JFrame;
|
||||||
import javax.swing.JLayeredPane;
|
import javax.swing.JLayeredPane;
|
||||||
@@ -890,7 +888,9 @@ public abstract class Getdown extends Thread
|
|||||||
_status.setSize(size);
|
_status.setSize(size);
|
||||||
_layers.setPreferredSize(size);
|
_layers.setPreferredSize(size);
|
||||||
|
|
||||||
_patchNotes.setBounds(_ifc.patchNotes);
|
Rectangle patchNotes = new Rectangle(_ifc.patchNotes.x, _ifc.patchNotes.y,
|
||||||
|
_ifc.patchNotes.width, _ifc.patchNotes.height);
|
||||||
|
_patchNotes.setBounds(patchNotes);
|
||||||
_patchNotes.setVisible(false);
|
_patchNotes.setVisible(false);
|
||||||
|
|
||||||
// we were displaying progress while the UI wasn't up. Now that it is, whatever progress
|
// we were displaying progress while the UI wasn't up. Now that it is, whatever progress
|
||||||
@@ -1131,7 +1131,7 @@ public abstract class Getdown extends Thread
|
|||||||
};
|
};
|
||||||
|
|
||||||
protected Application _app;
|
protected Application _app;
|
||||||
protected Application.UpdateInterface _ifc = new Application.UpdateInterface();
|
protected Application.UpdateInterface _ifc = new Application.UpdateInterface(Config.EMPTY);
|
||||||
|
|
||||||
protected ResourceBundle _msgs;
|
protected ResourceBundle _msgs;
|
||||||
protected Container _container;
|
protected Container _container;
|
||||||
|
|||||||
@@ -142,7 +142,7 @@ public class GetdownApp
|
|||||||
});
|
});
|
||||||
_frame.setUndecorated(_ifc.hideDecorations);
|
_frame.setUndecorated(_ifc.hideDecorations);
|
||||||
try {
|
try {
|
||||||
_frame.setBackground(_ifc.background);
|
_frame.setBackground(new Color(_ifc.background.rgba(), true));
|
||||||
} catch (UnsupportedOperationException e) {
|
} catch (UnsupportedOperationException e) {
|
||||||
log.warning("Failed to set background", e);
|
log.warning("Failed to set background", e);
|
||||||
} catch (IllegalComponentStateException e) {
|
} catch (IllegalComponentStateException e) {
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
package com.threerings.getdown.launcher;
|
package com.threerings.getdown.launcher;
|
||||||
|
|
||||||
import java.awt.Image;
|
import java.awt.Image;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import static com.threerings.getdown.Log.log;
|
import static com.threerings.getdown.Log.log;
|
||||||
|
|
||||||
@@ -42,15 +43,15 @@ public class RotatingBackgrounds
|
|||||||
* time when the next should be shown. In that case, it's left up until its been there for its
|
* time when the next should be shown. In that case, it's left up until its been there for its
|
||||||
* minimum display time and then the next one gets to come up.
|
* minimum display time and then the next one gets to come up.
|
||||||
*/
|
*/
|
||||||
public RotatingBackgrounds (String[] backgrounds, String errorBackground, ImageLoader loader)
|
public RotatingBackgrounds (List<String> backgrounds, String errorBackground, ImageLoader loader)
|
||||||
{
|
{
|
||||||
percentages = new int[backgrounds.length];
|
percentages = new int[backgrounds.size()];
|
||||||
minDisplayTime = new int[backgrounds.length];
|
minDisplayTime = new int[backgrounds.size()];
|
||||||
images = new Image[backgrounds.length];
|
images = new Image[backgrounds.size()];
|
||||||
for (int ii = 0; ii < backgrounds.length; ii++) {
|
for (int ii = 0; ii < backgrounds.size(); ii++) {
|
||||||
String[] pieces = backgrounds[ii].split(";");
|
String[] pieces = backgrounds.get(ii).split(";");
|
||||||
if (pieces.length != 2) {
|
if (pieces.length != 2) {
|
||||||
log.warning("Unable to parse background image '" + backgrounds[ii] + "'");
|
log.warning("Unable to parse background image '" + backgrounds.get(ii) + "'");
|
||||||
makeEmpty();
|
makeEmpty();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -59,11 +60,11 @@ public class RotatingBackgrounds
|
|||||||
minDisplayTime[ii] = Integer.parseInt(pieces[1]);
|
minDisplayTime[ii] = Integer.parseInt(pieces[1]);
|
||||||
} catch (NumberFormatException e) {
|
} catch (NumberFormatException e) {
|
||||||
log.warning("Unable to parse background image display time '" +
|
log.warning("Unable to parse background image display time '" +
|
||||||
backgrounds[ii] + "'");
|
backgrounds.get(ii) + "'");
|
||||||
makeEmpty();
|
makeEmpty();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
percentages[ii] = (int)((ii/(float)backgrounds.length) * 100);
|
percentages[ii] = (int)((ii/(float)backgrounds.size()) * 100);
|
||||||
}
|
}
|
||||||
if (errorBackground == null) {
|
if (errorBackground == null) {
|
||||||
errorImage = images[0];
|
errorImage = images[0];
|
||||||
|
|||||||
@@ -64,7 +64,9 @@ public class StatusPanel extends JComponent
|
|||||||
int width = img == null ? -1 : img.getWidth(this);
|
int width = img == null ? -1 : img.getWidth(this);
|
||||||
int height = img == null ? -1 : img.getHeight(this);
|
int height = img == null ? -1 : img.getHeight(this);
|
||||||
if (width == -1 || height == -1) {
|
if (width == -1 || height == -1) {
|
||||||
Rectangle bounds = ifc.progress.union(ifc.status);
|
Rectangle progress = new Rectangle(ifc.progress.x, ifc.progress.y, ifc.progress.width, ifc.progress.height);
|
||||||
|
Rectangle status = new Rectangle(ifc.status.x, ifc.status.y, ifc.status.width, ifc.status.height);
|
||||||
|
Rectangle bounds = progress.union(status);
|
||||||
// assume the x inset defines the frame padding; add it on the left, right, and bottom
|
// assume the x inset defines the frame padding; add it on the left, right, and bottom
|
||||||
_psize = new Dimension(bounds.x + bounds.width + bounds.x,
|
_psize = new Dimension(bounds.x + bounds.width + bounds.x,
|
||||||
bounds.y + bounds.height + bounds.x);
|
bounds.y + bounds.height + bounds.x);
|
||||||
@@ -107,7 +109,7 @@ public class StatusPanel extends JComponent
|
|||||||
_progress = percent;
|
_progress = percent;
|
||||||
if (!_ifc.hideProgressText) {
|
if (!_ifc.hideProgressText) {
|
||||||
String msg = MessageFormat.format(get("m.complete"), percent);
|
String msg = MessageFormat.format(get("m.complete"), percent);
|
||||||
_newplab = createLabel(msg, _ifc.progressText);
|
_newplab = createLabel(msg, new Color(_ifc.progressText.rgba(), true));
|
||||||
}
|
}
|
||||||
needsRepaint = true;
|
needsRepaint = true;
|
||||||
}
|
}
|
||||||
@@ -132,7 +134,7 @@ public class StatusPanel extends JComponent
|
|||||||
int minutes = (int)(remaining / 60), seconds = (int)(remaining % 60);
|
int minutes = (int)(remaining / 60), seconds = (int)(remaining % 60);
|
||||||
String remstr = minutes + ":" + ((seconds < 10) ? "0" : "") + seconds;
|
String remstr = minutes + ":" + ((seconds < 10) ? "0" : "") + seconds;
|
||||||
String msg = MessageFormat.format(get("m.remain"), remstr);
|
String msg = MessageFormat.format(get("m.remain"), remstr);
|
||||||
_newrlab = createLabel(msg, _ifc.statusText);
|
_newrlab = createLabel(msg, new Color(_ifc.statusText.rgba(), true));
|
||||||
}
|
}
|
||||||
needsRepaint = true;
|
needsRepaint = true;
|
||||||
|
|
||||||
@@ -226,7 +228,7 @@ public class StatusPanel extends JComponent
|
|||||||
gfx.drawImage(_barimg, _ifc.progress.x, _ifc.progress.y, null);
|
gfx.drawImage(_barimg, _ifc.progress.x, _ifc.progress.y, null);
|
||||||
gfx.setClip(null);
|
gfx.setClip(null);
|
||||||
} else {
|
} else {
|
||||||
gfx.setColor(_ifc.progressBar);
|
gfx.setColor(new Color(_ifc.progressBar.rgba(), true));
|
||||||
gfx.fillRect(_ifc.progress.x, _ifc.progress.y,
|
gfx.fillRect(_ifc.progress.x, _ifc.progress.y,
|
||||||
_progress * _ifc.progress.width / 100,
|
_progress * _ifc.progress.width / 100,
|
||||||
_ifc.progress.height);
|
_ifc.progress.height);
|
||||||
@@ -270,7 +272,7 @@ public class StatusPanel extends JComponent
|
|||||||
status += " .";
|
status += " .";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_newlab = createLabel(status, _ifc.statusText);
|
_newlab = createLabel(status, new Color(_ifc.statusText.rgba(), true));
|
||||||
// set the width of the label to the width specified
|
// set the width of the label to the width specified
|
||||||
int width = _ifc.status.width;
|
int width = _ifc.status.width;
|
||||||
if (width == 0) {
|
if (width == 0) {
|
||||||
@@ -305,7 +307,7 @@ public class StatusPanel extends JComponent
|
|||||||
{
|
{
|
||||||
Label label = new Label(text, color, FONT);
|
Label label = new Label(text, color, FONT);
|
||||||
if (_ifc.textShadow != null) {
|
if (_ifc.textShadow != null) {
|
||||||
label.setAlternateColor(_ifc.textShadow);
|
label.setAlternateColor(new Color(_ifc.textShadow.rgba(), true));
|
||||||
label.setStyle(LabelStyleConstants.SHADOW);
|
label.setStyle(LabelStyleConstants.SHADOW);
|
||||||
}
|
}
|
||||||
return label;
|
return label;
|
||||||
|
|||||||
Reference in New Issue
Block a user