Thread safety: Tightened up conditions in FProgressBar, made a few changes to skin loading as appropriate.

This commit is contained in:
Doublestrike
2012-01-31 00:08:56 +00:00
parent 6d7e567d0d
commit d32b3c8e32
7 changed files with 139 additions and 105 deletions

View File

@@ -35,6 +35,8 @@ import java.util.regex.Pattern;
import java.util.zip.ZipEntry; import java.util.zip.ZipEntry;
import java.util.zip.ZipFile; import java.util.zip.ZipFile;
import javax.swing.SwingUtilities;
import net.slightlymagic.braids.util.UtilFunctions; import net.slightlymagic.braids.util.UtilFunctions;
import net.slightlymagic.braids.util.generator.FindNonDirectoriesSkipDotDirectoriesGenerator; import net.slightlymagic.braids.util.generator.FindNonDirectoriesSkipDotDirectoriesGenerator;
import net.slightlymagic.braids.util.generator.GeneratorFunctions; import net.slightlymagic.braids.util.generator.GeneratorFunctions;
@@ -273,8 +275,11 @@ public class CardReader implements Runnable {
} }
if (barProgress != null) { if (barProgress != null) {
barProgress.setMaximum((int) this.estimatedFilesRemaining); barProgress.setMaximum((int) estimatedFilesRemaining);
barProgress.setDescription("Preloading card images: "); SwingUtilities.invokeLater(new Runnable() { @Override
public void run() {
barProgress.setDescription("Preloading card images: ");
} });
} }
for (final File cardTxtFile : this.findNonDirsIterable) { for (final File cardTxtFile : this.findNonDirsIterable) {

View File

@@ -30,6 +30,7 @@ import forge.CardReader;
import forge.Singletons; import forge.Singletons;
import forge.card.CardRules; import forge.card.CardRules;
import forge.error.ErrorViewer; import forge.error.ErrorViewer;
import forge.gui.GuiUtils;
import forge.item.CardDb; import forge.item.CardDb;
import forge.properties.ForgeProps; import forge.properties.ForgeProps;
import forge.properties.NewConstants; import forge.properties.NewConstants;
@@ -76,6 +77,7 @@ public class PreloadingCardFactory extends AbstractCardFactory {
*/ */
public PreloadingCardFactory(final File file) { public PreloadingCardFactory(final File file) {
super(file); super(file);
GuiUtils.checkEDT("PreloadingCardFactory$constructor", false);
try { try {
this.readCards(file); this.readCards(file);

View File

@@ -155,7 +155,7 @@ public class ControlSettings {
FSkin skin = new FSkin(name); FSkin skin = new FSkin(name);
skin.loadFontsAndImages(); skin.load();
prefs.setPref(FPref.UI_SKIN, name); prefs.setPref(FPref.UI_SKIN, name);
Singletons.getView().setSkin(skin); Singletons.getView().setSkin(skin);

View File

@@ -35,6 +35,7 @@ import javax.swing.Box;
import javax.swing.ImageIcon; import javax.swing.ImageIcon;
import javax.swing.JList; import javax.swing.JList;
import javax.swing.JPanel; import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener; import javax.swing.event.ListSelectionListener;
@@ -411,7 +412,8 @@ public final class GuiUtils {
} }
/** Duplicate in DeckEditorQuestMenu and /** Duplicate in DeckEditorQuestMenu and
* probably elsewhere...can streamline at some point. * probably elsewhere...can streamline at some point
* (probably shouldn't be here).
* *
* @param in   {@link java.lang.String} * @param in   {@link java.lang.String}
* @return {@link java.lang.String} * @return {@link java.lang.String}
@@ -428,4 +430,24 @@ public final class GuiUtils {
return out.toString(); return out.toString();
} }
/** Checks if calling method uses event dispatch thread.
* Exception thrown if method is on "wrong" thread.
* A boolean is passed to indicate if the method must be EDT or not.
*
* @param methodName   String, part of the custom exception message.
* @param mustBeEDT   boolean: true = exception if not EDT, false = exception if EDT
*/
public static void checkEDT(String methodName, boolean mustBeEDT) {
boolean isEDT = SwingUtilities.isEventDispatchThread();
if (!isEDT && mustBeEDT) {
throw new IllegalStateException(
methodName + " must be accessed from the event dispatch thread.");
}
else if (isEDT && !mustBeEDT) {
throw new IllegalStateException(
methodName + " may not be accessed from the event dispatch thread.");
}
}
} }

View File

@@ -105,16 +105,15 @@ public class FView {
AllZone.getCardFactory(); AllZone.getCardFactory();
// Preloads skin components (using progress bar). // Preloads skin components (using progress bar).
FView.this.skin.loadFontsAndImages(); FView.this.skin.load();
// Does not use progress bar, due to be deprecated in favor of skin. // Does not use progress bar, due to be deprecated with battlefield refactoring.
CardFaceSymbols.loadImages(); CardFaceSymbols.loadImages();
barProgress.setDescription("Creating display components.");
SwingUtilities.invokeLater(new Runnable() { SwingUtilities.invokeLater(new Runnable() {
@Override @Override
public void run() { public void run() {
barProgress.setDescription("Creating display components.");
final GuiTopLevel g = new GuiTopLevel(); final GuiTopLevel g = new GuiTopLevel();
AllZone.setDisplay(g); AllZone.setDisplay(g);
g.getController().changeState(FControl.HOME_SCREEN); g.getController().changeState(FControl.HOME_SCREEN);

View File

@@ -1,28 +1,25 @@
package forge.view.toolbox; package forge.view.toolbox;
import java.util.Date; import java.util.Date;
import javax.swing.JProgressBar; import javax.swing.JProgressBar;
import javax.swing.SwingUtilities; import javax.swing.SwingUtilities;
import forge.gui.GuiUtils;
/** /**
* A simple progress bar component using the Forge skin. * A simple progress bar component using the Forge skin.
* *
* Can show * Can show
* *
*/ */
@SuppressWarnings("serial")
public class FProgressBar extends JProgressBar { public class FProgressBar extends JProgressBar {
private static final long serialVersionUID = 3479715871723156426L; private long startMillis = 0, tempMillis = 0;
private int tempVal = 0;
private long startMillis = 0;
private long tempMillis = 0;
private float timePerUnit = 0; private float timePerUnit = 0;
private int eta = 0; private int tempVal = 0, etaMillis = 0;
private boolean isIncrementing = false;
private int hours, minutes, seconds; private int hours, minutes, seconds;
private String desc = ""; private String desc = "", count = "", eta = "";
private String str = "";
private boolean showETA = true; private boolean showETA = true;
private boolean showCount = true; private boolean showCount = true;
@@ -33,58 +30,43 @@ public class FProgressBar extends JProgressBar {
this.setStringPainted(true); this.setStringPainted(true);
} }
/** @param s0   A description to prepend before statistics. */ /**
* Sets description on bar. Must be called from EDT.
*
* @param s0   A description to prepend before statistics.
*/
public void setDescription(final String s0) { public void setDescription(final String s0) {
GuiUtils.checkEDT("FProgressBar$setDescription", true);
this.desc = s0; this.desc = s0;
this.setString(s0); this.setString(s0);
} }
/** */ /** Increments bar, thread safe. Calculations executed on separate thread. */
public void increment() { public void increment() {
if (isIncrementing) { System.out.println("Rejected."); return; } final Runnable r = new Runnable() {
@Override
public void run() {
tempVal++;
count = (showCount ? " " + tempVal + " of " + getMaximum() : "");
eta = (showETA ? calculateETA(tempVal) : "");
isIncrementing = true; // When calculations finished; EDT can be used.
tempVal++; SwingUtilities.invokeLater(new Runnable() {
this.setValue(tempVal); @Override
str = desc; public void run() {
if (showCount) { calculateCount(tempVal); } FProgressBar.this.setValue(tempVal);
if (showETA) { calculateETA(tempVal); } updateString();
updateString(); }
isIncrementing = false; });
}
};
r.run();
} }
private void calculateCount(int v0) { /** Resets the various values required for this class. Must be called from EDT. */
str += " " + v0 + " of " + this.getMaximum();
}
/** */
private void calculateETA(int v0) {
tempMillis = new Date().getTime();
timePerUnit = (tempMillis - startMillis) / (float) v0;
eta = (int) ((this.getMaximum() - v0) * timePerUnit) / 1000;
seconds = eta;
hours = seconds >= 3600 ? (seconds / 3600) : 0;
seconds = eta % 3600;
minutes = seconds >= 60 ? (seconds / 60) : 0;
seconds = eta % 60 + 1;
str += ", ETA " + String.format("%02d", hours) + ":"
+ String.format("%02d", minutes) + ":"
+ String.format("%02d", seconds);
}
private void updateString() {
this.setString(str);
}
/** Resets the various values required for this class. */
public void reset() { public void reset() {
if (!SwingUtilities.isEventDispatchThread()) { GuiUtils.checkEDT("FProgressBar$reset", true);
throw new IllegalStateException(
"FProgressBar > reset() must be accessed from an event dispatch thread.");
}
this.setIndeterminate(true); this.setIndeterminate(true);
this.setValue(0); this.setValue(0);
this.tempVal = 0; this.tempVal = 0;
@@ -99,18 +81,30 @@ public class FProgressBar extends JProgressBar {
this.showETA = b0; this.showETA = b0;
} }
/** @return b0   Boolean, show the ETA statistic or not */
public boolean isShowETA() {
return showETA;
}
/** @param b0   Boolean, show the ETA statistic or not */ /** @param b0   Boolean, show the ETA statistic or not */
public void setShowCount(boolean b0) { public void setShowCount(boolean b0) {
this.showCount = b0; this.showCount = b0;
} }
/** @return b0   Boolean, show the ETA statistic or not */ /** */
public boolean isShowCount() { private String calculateETA(int v0) {
return showCount; GuiUtils.checkEDT("FProgressBar$calculateETA", false);
tempMillis = new Date().getTime();
timePerUnit = (tempMillis - startMillis) / (float) v0;
etaMillis = (int) ((this.getMaximum() - v0) * timePerUnit) / 1000;
seconds = etaMillis;
hours = seconds >= 3600 ? (seconds / 3600) : 0;
seconds = etaMillis % 3600;
minutes = seconds >= 60 ? (seconds / 60) : 0;
seconds = etaMillis % 60 + 1;
return ", ETA " + String.format("%02d", hours) + ":"
+ String.format("%02d", minutes) + ":"
+ String.format("%02d", seconds);
}
private void updateString() {
this.setString(desc + count + eta);
} }
} }

View File

@@ -45,16 +45,6 @@ import forge.gui.GuiUtils;
*/ */
public class FSkin { public class FSkin {
/** Properties of various components that make up the skin. */
public interface SkinProp { }
/** Add this interface for sub-sprite components, storing their coords. */
public interface Coords {
/** */
int[] COORDS = null;
/** @return int[] */
int[] getCoords();
}
/** */ /** */
public enum Backgrounds implements SkinProp { /** */ public enum Backgrounds implements SkinProp { /** */
BG_SPLASH, /** */ BG_SPLASH, /** */
@@ -331,6 +321,16 @@ public class FSkin {
public int[] getCoords() { return coords; } public int[] getCoords() { return coords; }
} }
/** Properties of various components that make up the skin. */
public interface SkinProp { }
/** Add this interface for sub-sprite components, storing their coords. */
public interface Coords {
/** */
int[] COORDS = null;
/** @return int[] */
int[] getCoords();
}
private Map<SkinProp, ImageIcon> icons; private Map<SkinProp, ImageIcon> icons;
private Map<SkinProp, Image> images; private Map<SkinProp, Image> images;
private Map<SkinProp, Color> colors; private Map<SkinProp, Color> colors;
@@ -375,6 +375,8 @@ public class FSkin {
* the skin name * the skin name
*/ */
public FSkin(final String skinName) { public FSkin(final String skinName) {
GuiUtils.checkEDT("FSkin$constructor", false);
this.preferredName = skinName; this.preferredName = skinName;
this.preferredDir = FILE_SKINS_DIR + preferredName + "/"; this.preferredDir = FILE_SKINS_DIR + preferredName + "/";
this.defaultDir = FILE_SKINS_DIR + "default/"; this.defaultDir = FILE_SKINS_DIR + "default/";
@@ -423,7 +425,8 @@ public class FSkin {
* preferred takes precedence over default, but if something is * preferred takes precedence over default, but if something is
* missing, the default picture is retrieved. * missing, the default picture is retrieved.
*/ */
public void loadFontsAndImages() { public void load() {
GuiUtils.checkEDT("FSkin$load", false);
barProgress = Singletons.getView().getProgressBar(); barProgress = Singletons.getView().getProgressBar();
SwingUtilities.invokeLater(new Runnable() { SwingUtilities.invokeLater(new Runnable() {
@@ -431,13 +434,12 @@ public class FSkin {
public void run() { public void run() {
barProgress.reset(); barProgress.reset();
barProgress.setShowETA(false); barProgress.setShowETA(false);
barProgress.setDescription("Processing fonts and image sprites: "); barProgress.setDescription("Processing image sprites: ");
} }
}); });
barProgress.setMaximum(57);
// Grab and test various sprite files. // Grab and test various sprite files.
barProgress.setMaximum(4);
final File f1 = new File(defaultDir + FILE_ICON_SPRITE); final File f1 = new File(defaultDir + FILE_ICON_SPRITE);
final File f2 = new File(preferredDir + FILE_ICON_SPRITE); final File f2 = new File(preferredDir + FILE_ICON_SPRITE);
final File f3 = new File(defaultDir + FILE_CREATURE_SPRITE); final File f3 = new File(defaultDir + FILE_CREATURE_SPRITE);
@@ -445,10 +447,13 @@ public class FSkin {
try { try {
bimDefaultSprite = ImageIO.read(f1); bimDefaultSprite = ImageIO.read(f1);
barProgress.increment();
bimPreferredSprite = ImageIO.read(f2); bimPreferredSprite = ImageIO.read(f2);
barProgress.increment();
bimCreatures = ImageIO.read(f3); bimCreatures = ImageIO.read(f3);
barProgress.increment();
bimFoils = ImageIO.read(f4); bimFoils = ImageIO.read(f4);
barProgress.increment();
preferredH = bimPreferredSprite.getHeight(); preferredH = bimPreferredSprite.getHeight();
preferredW = bimPreferredSprite.getWidth(); preferredW = bimPreferredSprite.getWidth();
@@ -458,31 +463,41 @@ public class FSkin {
e.printStackTrace(); e.printStackTrace();
} }
// Images loaded; can start UI init.
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
barProgress.setShowETA(false);
barProgress.setShowCount(false);
barProgress.setDescription("Creating display components.");
}
});
// Pre-derive most fonts (plain, bold, and italic). // Pre-derive most fonts (plain, bold, and italic).
// Exceptions handled inside method. // Exceptions handled inside method.
this.font = GuiUtils.newFont(FILE_SKINS_DIR + preferredName + "/" + FILE_FONT); this.font = GuiUtils.newFont(FILE_SKINS_DIR + preferredName + "/" + FILE_FONT);
plainFonts = new HashMap<Integer, Font>(); plainFonts = new HashMap<Integer, Font>();
setFontAndIncrement(10); setFont(10);
setFontAndIncrement(11); setFont(11);
setFontAndIncrement(12); setFont(12);
setFontAndIncrement(13); setFont(13);
setFontAndIncrement(14); setFont(14);
setFontAndIncrement(15); setFont(15);
setFontAndIncrement(16); setFont(16);
setFontAndIncrement(18); setFont(18);
setFontAndIncrement(20); setFont(20);
setFontAndIncrement(22); setFont(22);
boldFonts = new HashMap<Integer, Font>(); boldFonts = new HashMap<Integer, Font>();
setBoldFontAndIncrement(12); setBoldFont(12);
setBoldFontAndIncrement(14); setBoldFont(14);
setBoldFontAndIncrement(16); setBoldFont(16);
setBoldFontAndIncrement(18); setBoldFont(18);
setBoldFontAndIncrement(20); setBoldFont(20);
italicFonts = new HashMap<Integer, Font>(); italicFonts = new HashMap<Integer, Font>();
setItalicFontAndIncrement(12); setItalicFont(12);
setItalicFontAndIncrement(14); setItalicFont(14);
// Put various images into map (except sprite and splash). // Put various images into map (except sprite and splash).
// Exceptions handled inside method. // Exceptions handled inside method.
@@ -749,19 +764,16 @@ public class FSkin {
this.colors.put(s0, c0); this.colors.put(s0, c0);
} }
private void setFontAndIncrement(int size) { private void setFont(int size) {
plainFonts.put(size, font.deriveFont(Font.PLAIN, size)); plainFonts.put(size, font.deriveFont(Font.PLAIN, size));
if (barProgress != null) { barProgress.increment(); }
} }
private void setBoldFontAndIncrement(int size) { private void setBoldFont(int size) {
boldFonts.put(size, font.deriveFont(Font.BOLD, size)); boldFonts.put(size, font.deriveFont(Font.BOLD, size));
if (barProgress != null) { barProgress.increment(); }
} }
private void setItalicFontAndIncrement(int size) { private void setItalicFont(int size) {
italicFonts.put(size, font.deriveFont(Font.ITALIC, size)); italicFonts.put(size, font.deriveFont(Font.ITALIC, size));
if (barProgress != null) { barProgress.increment(); }
} }
private void setIcon(final SkinProp s0) { private void setIcon(final SkinProp s0) {