You can subscribe to this list here.
2008 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
(3) |
Nov
(46) |
Dec
(57) |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2009 |
Jan
(51) |
Feb
(10) |
Mar
|
Apr
|
May
(14) |
Jun
|
Jul
(13) |
Aug
(30) |
Sep
(83) |
Oct
(56) |
Nov
(148) |
Dec
(107) |
2010 |
Jan
(260) |
Feb
(164) |
Mar
(183) |
Apr
(99) |
May
(160) |
Jun
(40) |
Jul
(33) |
Aug
(48) |
Sep
(22) |
Oct
(24) |
Nov
(1) |
Dec
(12) |
2011 |
Jan
(6) |
Feb
(15) |
Mar
(13) |
Apr
(37) |
May
(27) |
Jun
(29) |
Jul
(33) |
Aug
(20) |
Sep
(17) |
Oct
(20) |
Nov
(33) |
Dec
(17) |
2012 |
Jan
(39) |
Feb
(38) |
Mar
(20) |
Apr
(21) |
May
(17) |
Jun
(22) |
Jul
(16) |
Aug
(3) |
Sep
(9) |
Oct
(10) |
Nov
|
Dec
|
From: Frederick W. <fre...@us...> - 2012-02-19 15:57:32
|
rails/sound/SoundContext.java | 18 +++++++++++------- rails/sound/SoundPlayer.java | 36 +++++++++++++++++++++++++++--------- 2 files changed, 38 insertions(+), 16 deletions(-) New commits: commit 1f16f2ebfa66afd2971dc0c28675d4d360b6d804 Author: Frederick Weld <fre...@gm...> Date: Sun Feb 19 16:56:16 2012 +0100 Fixed bug of initially playing 2 music files for command line loading diff --git a/rails/sound/SoundContext.java b/rails/sound/SoundContext.java index c38b334..f18f190 100644 --- a/rails/sound/SoundContext.java +++ b/rails/sound/SoundContext.java @@ -70,8 +70,10 @@ public class SoundContext { } private void playBackgroundMusic() { - //do nothing if music is not enabled - if (!SoundConfig.isBGMEnabled()) return; + //do nothing if + // - music is not enabled + // - phase is not initialized + if (!SoundConfig.isBGMEnabled() || currentPhase == null) return; String currentRoundConfigKey = null; if (currentRound instanceof StartRound) { @@ -83,7 +85,9 @@ public class SoundContext { } else if (currentRound instanceof EndOfGameRound) { currentRoundConfigKey = SoundConfig.KEY_BGM_EndOfGameRound; } - //only play anything if round is recognized and new music is to be played + //only play anything if + // - round is recognized + // - new music is to be played if (currentRoundConfigKey != null) { String currentPhaseName = ""; if (currentPhase != null) currentPhaseName = currentPhase.getName(); @@ -95,15 +99,15 @@ public class SoundContext { } } } - public void notifyOfPhase(PhaseI newPhase) { - if (!newPhase.equals(currentPhase)) { + synchronized public void notifyOfPhase(PhaseI newPhase) { + if (newPhase != null && !newPhase.equals(currentPhase)) { currentPhase = newPhase; playBackgroundMusic(); } } - public void notifyOfRound(RoundI newRound) { - if (!newRound.equals(currentRound)) { + synchronized public void notifyOfRound(RoundI newRound) { + if (newRound != null && !newRound.equals(currentRound)) { //play stock market opening bell if stock round became current round //and the round before was not commit d6567259d5bee060e02f84393e1db655f8b13342 Author: Frederick Weld <fre...@gm...> Date: Sun Feb 19 16:33:11 2012 +0100 Added caching of sound files (both sfx and background music) diff --git a/rails/sound/SoundPlayer.java b/rails/sound/SoundPlayer.java index be380d3..ecb60fb 100644 --- a/rails/sound/SoundPlayer.java +++ b/rails/sound/SoundPlayer.java @@ -4,7 +4,11 @@ package rails.sound; import java.io.BufferedInputStream; +import java.io.ByteArrayInputStream; +import java.io.File; import java.io.FileInputStream; +import java.util.HashMap; +import java.util.Map; import javazoom.jl.decoder.JavaLayerException; import javazoom.jl.player.Player; @@ -21,6 +25,23 @@ import javazoom.jl.player.advanced.AdvancedPlayer; */ public class SoundPlayer { + private class SoundFileBuffer { + private Map<String,byte[]> fileBuffer = new HashMap<String,byte[]>(); + synchronized public BufferedInputStream getFileInputStream(String fileName) { + if (!fileBuffer.containsKey(fileName)) { + try { + long length = new File(fileName).length(); + FileInputStream fis = new FileInputStream(fileName); + byte[] fileContent = new byte[(int)length]; + fis.read(fileContent); + fileBuffer.put(fileName, fileContent); + } catch (Exception e) {return null;} + } + return new BufferedInputStream( + new ByteArrayInputStream(fileBuffer.get(fileName))); + } + } + private class PlayerThread extends Thread { String fileName; PlayerThread priorThread; @@ -56,9 +77,7 @@ public class SoundPlayer { } public void play() { try { - FileInputStream fis = new FileInputStream(fileName); - BufferedInputStream bis = new BufferedInputStream(fis); - Player player = new Player(bis); + Player player = new Player(soundFileBuffer.getFileInputStream(fileName)); player.play(); player.close(); } @@ -82,9 +101,8 @@ public class SoundPlayer { @Override public void play() { try { - FileInputStream fis = new FileInputStream(fileName); - BufferedInputStream bis = new BufferedInputStream(fis); - PortionPlayer player = new PortionPlayer(bis); + PortionPlayer player = new PortionPlayer( + soundFileBuffer.getFileInputStream(fileName)); player.play(startPos, endPos); player.close(); } @@ -137,9 +155,7 @@ public class SoundPlayer { } while (!isStopped) { - FileInputStream fis = new FileInputStream(fileName); - BufferedInputStream bis = new BufferedInputStream(fis); - player = new Player(bis); + player = new Player(soundFileBuffer.getFileInputStream(fileName)); player.play(); player.close(); } @@ -163,6 +179,8 @@ public class SoundPlayer { private LoopPlayerThread lastBGMThread = null; + private SoundFileBuffer soundFileBuffer = new SoundFileBuffer(); + /** * atomic switching of the pointer to the last thread which played an sfx. * @param newThread Player thread for the new sfx |
From: Frederick W. <fre...@us...> - 2012-02-19 12:21:52
|
rails/ui/swing/ReportWindowDynamic.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) New commits: commit 5467d59293b48a45470ccf779b84520040495ffa Author: Frederick Weld <fre...@gm...> Date: Sun Feb 19 13:19:39 2012 +0100 Fixed order of initing DynamicReportWindow (pack only after layout done) Found out issue when running on other computer: Report window gets zero size. This commit fixes this issue which was traced back to a premature call of super.init to the AbstractReportWindow's pack - dyn report window only sets up layout afterwards (against EDT rules). This is fixed by postponing the super.init call to the point in time when the layout is ready. diff --git a/rails/ui/swing/ReportWindowDynamic.java b/rails/ui/swing/ReportWindowDynamic.java index 00daad2..df789f8 100644 --- a/rails/ui/swing/ReportWindowDynamic.java +++ b/rails/ui/swing/ReportWindowDynamic.java @@ -55,8 +55,6 @@ public class ReportWindowDynamic extends AbstractReportWindow implements Action @Override public void init() { - super.init(); - setLayout(new BorderLayout()); JPanel messagePanel = new JPanel(); @@ -142,6 +140,8 @@ public class ReportWindowDynamic extends AbstractReportWindow implements Action ); buttonPanel.add(commentButton); + super.init(); + } @Override |
From: Frederick W. <fre...@us...> - 2012-02-18 06:25:00
|
images/icon/notile_2towns.png |binary images/icon/notile_station.png |binary rails/ui/swing/SplashWindow.java | 1 + 3 files changed, 1 insertion(+) New commits: commit 3e53fe3344012e2c4ee3b1d10e2d1823224c4b00 Author: Frederick Weld <fre...@gm...> Date: Sat Feb 18 07:23:36 2012 +0100 Added initial hexes (no-tile laid) for splash screen icon visualization diff --git a/images/icon/notile_2towns.png b/images/icon/notile_2towns.png new file mode 100644 index 0000000..84c0d63 Binary files /dev/null and b/images/icon/notile_2towns.png differ diff --git a/images/icon/notile_station.png b/images/icon/notile_station.png new file mode 100644 index 0000000..8a5987e Binary files /dev/null and b/images/icon/notile_station.png differ diff --git a/rails/ui/swing/SplashWindow.java b/rails/ui/swing/SplashWindow.java index 8104a6d..ab5a3f8 100644 --- a/rails/ui/swing/SplashWindow.java +++ b/rails/ui/swing/SplashWindow.java @@ -108,6 +108,7 @@ public class SplashWindow { private final static String iconPath = "/images/icon/"; private final static String[][] icons = new String[][] { + { "notile_2towns.png" , "notile_station.png" }, { "yellow_track.png" , "yellow_station.png" }, { "green_track.png" , "green_station.png" }, { "russet_track.png" , "russet_station.png" }, |
From: Stefan F. <ste...@us...> - 2012-02-17 19:12:42
|
rails/algorithms/RevenueManager.java | 4 rails/common/GuiHints.java | 4 rails/game/Bank.java | 118 +-- rails/game/BaseToken.java | 1 rails/game/Certificate.java | 14 rails/game/Company.java | 24 rails/game/CompanyManager.java | 2 rails/game/Game.java | 3 rails/game/GameManager.java | 68 - rails/game/MapHex.java | 10 rails/game/MapManager.java | 4 rails/game/OperatingRound.java | 48 - rails/game/PhaseManager.java | 4 rails/game/Player.java | 175 +++- rails/game/PlayerManager.java | 13 rails/game/PrivateCompany.java | 33 rails/game/PublicCertificate.java | 39 - rails/game/PublicCompany.java | 45 - rails/game/Round.java | 28 rails/game/ShareSellingRound.java | 6 rails/game/StartItem.java | 14 rails/game/StartRound.java | 6 rails/game/StartRoundI.java | 2 rails/game/StockMarket.java | 4 rails/game/StockRound.java | 28 rails/game/StockSpace.java | 2 rails/game/Tile.java | 6 rails/game/TileManager.java | 2 rails/game/Token.java | 23 rails/game/Train.java | 35 rails/game/TrainCertificateType.java | 4 rails/game/TrainManager.java | 4 rails/game/TreasuryShareRound.java | 12 rails/game/action/BuyCertificate.java | 10 rails/game/action/BuyTrain.java | 12 rails/game/correct/CashCorrectionManager.java | 8 rails/game/correct/CorrectionManager.java | 4 rails/game/model/AbstractOwnable.java | 46 - rails/game/model/BaseTokensModel.java | 31 rails/game/model/BonusModel.java | 24 rails/game/model/CalculatedMoneyModel.java | 86 -- rails/game/model/CashModel.java | 85 -- rails/game/model/CashMoneyModel.java | 68 + rails/game/model/CashOwner.java | 8 rails/game/model/CertificateCountModel.java | 32 rails/game/model/CertificatesModel.java | 80 -- rails/game/model/DirectCashOwner.java | 33 rails/game/model/DirectOwner.java | 45 - rails/game/model/Model.java | 47 - rails/game/model/MoneyModel.java | 168 ++-- rails/game/model/Ownable.java | 19 rails/game/model/Owner.java | 28 rails/game/model/Owners.java | 75 -- rails/game/model/Portfolio.java | 648 ------------------ rails/game/model/PortfolioCashOwner.java | 28 rails/game/model/PortfolioModel.java | 629 +++++++++++++++++ rails/game/model/PortfolioOwner.java | 39 - rails/game/model/PresidentModel.java | 16 rails/game/model/PriceModel.java | 15 rails/game/model/PrivatesModel.java | 41 + rails/game/model/SingleOwner.java | 63 - rails/game/model/Storage.java | 37 - rails/game/model/StorageModel.java | 109 --- rails/game/model/TrainsModel.java | 50 - rails/game/special/SpecialProperty.java | 4 rails/game/special/SpecialPropertyI.java | 3 rails/game/specific/_1825/StockRound_1825.java | 6 rails/game/specific/_1835/OperatingRound_1835.java | 6 rails/game/specific/_1835/PrussianFormationRound.java | 6 rails/game/specific/_1835/StockRound_1835.java | 4 rails/game/specific/_1856/CGRFormationRound.java | 13 rails/game/specific/_1856/OperatingRound_1856.java | 8 rails/game/specific/_1856/StockRound_1856.java | 4 rails/game/specific/_1880/StartRound_1880.java | 2 rails/game/specific/_1889/OperatingRound_1889.java | 2 rails/game/specific/_18AL/OperatingRound_18AL.java | 4 rails/game/specific/_18EU/GameManager_18EU.java | 7 rails/game/specific/_18EU/OperatingRound_18EU.java | 10 rails/game/specific/_18EU/StockRound_18EU.java | 16 rails/game/state/AbstractItem.java | 76 ++ rails/game/state/ArrayListMultimapState.java | 25 rails/game/state/ArrayListState.java | 30 rails/game/state/BooleanState.java | 28 rails/game/state/ChangeStack.java | 22 rails/game/state/Context.java | 180 ++--- rails/game/state/CountableItem.java | 6 rails/game/state/GameItem.java | 73 -- rails/game/state/GenericState.java | 29 rails/game/state/HashMapState.java | 36 - rails/game/state/HashMultimapState.java | 28 rails/game/state/HashSetState.java | 47 - rails/game/state/IntegerState.java | 35 rails/game/state/Item.java | 25 rails/game/state/ItemType.java | 5 rails/game/state/Model.java | 42 + rails/game/state/MultimapState.java | 4 rails/game/state/Observable.java | 26 rails/game/state/OwnableItem.java | 13 rails/game/state/Portfolio.java | 55 + rails/game/state/PortfolioChange.java | 8 rails/game/state/PortfolioList.java | 71 + rails/game/state/PortfolioManager.java | 20 rails/game/state/PortfolioMap.java | 100 ++ rails/game/state/PortfolioNG.java | 117 --- rails/game/state/Root.java | 88 ++ rails/game/state/State.java | 73 -- rails/game/state/StateManager.java | 53 - rails/game/state/StringState.java | 30 rails/game/state/Wallet.java | 29 rails/game/state/WalletManager.java | 15 rails/ui/swing/GameStatus.java | 6 rails/ui/swing/GridPanel.java | 2 rails/ui/swing/ORUIManager.java | 6 rails/ui/swing/RemainingTilesWindow.java | 2 rails/ui/swing/elements/GUIStockSpace.java | 2 rails/ui/swing/hexmap/GUIHex.java | 2 116 files changed, 2151 insertions(+), 2722 deletions(-) New commits: commit 0a640b489db8e119f3567e6eb4e5267772562fee Author: Stefan Frey <ste...@we...> Date: Mon Feb 13 18:52:12 2012 +0100 Updated Item and Context mechanisms Removing the previous storage and owner mechanism Refactored StateManager and ChangeStack mechanisms Refactored MoneyModel, CashModel and CalculatedMoneyModel Refactored Player, Bank diff --git a/rails/algorithms/RevenueManager.java b/rails/algorithms/RevenueManager.java index 06c506f..bfba854 100644 --- a/rails/algorithms/RevenueManager.java +++ b/rails/algorithms/RevenueManager.java @@ -12,7 +12,7 @@ import rails.common.parser.ConfigurableComponentI; import rails.common.parser.ConfigurationException; import rails.common.parser.Tag; import rails.game.GameManager; -import rails.game.state.GameItem; +import rails.game.state.AbstractItem; import rails.game.state.ArrayListState; /** @@ -25,7 +25,7 @@ import rails.game.state.ArrayListState; * */ -public final class RevenueManager extends GameItem implements ConfigurableComponentI { +public final class RevenueManager extends AbstractItem implements ConfigurableComponentI { protected static Logger log = Logger.getLogger(RevenueManager.class.getPackage().getName()); diff --git a/rails/common/GuiHints.java b/rails/common/GuiHints.java index 64d8dde..b386bc8 100644 --- a/rails/common/GuiHints.java +++ b/rails/common/GuiHints.java @@ -5,7 +5,7 @@ import java.util.ArrayList; import java.util.List; import rails.game.RoundI; -import rails.game.state.GameItem; +import rails.game.state.AbstractItem; import rails.game.state.GenericState; /** @@ -16,7 +16,7 @@ import rails.game.state.GenericState; * @author VosE * */ -public class GuiHints extends GameItem implements Serializable{ +public class GuiHints extends AbstractItem implements Serializable{ public static final long serialVersionUID = 1L; diff --git a/rails/game/Bank.java b/rails/game/Bank.java index e35d100..5bf426a 100644 --- a/rails/game/Bank.java +++ b/rails/game/Bank.java @@ -9,14 +9,18 @@ import rails.common.parser.Config; import rails.common.parser.ConfigurableComponentI; import rails.common.parser.ConfigurationException; import rails.common.parser.Tag; -import rails.game.model.CashModel; +import rails.game.model.CashMoneyModel; import rails.game.model.CashOwner; +import rails.game.model.MoneyModel; import rails.game.model.PortfolioModel; -import rails.game.state.GameItem; +import rails.game.state.AbstractItem; import rails.game.state.BooleanState; +import rails.game.state.Item; import rails.util.*; -public class Bank extends GameItem implements CashOwner, ConfigurableComponentI { +public class Bank extends AbstractItem implements CashOwner, ConfigurableComponentI { + + private static Bank instance = null; /** Specific portfolio names */ public static final String IPO_NAME = "IPO"; @@ -29,21 +33,19 @@ public class Bank extends GameItem implements CashOwner, ConfigurableComponentI private static final String DEFAULT_MONEY_FORMAT = "$@"; /** The Bank's amount of cash */ - private CashModel money; + private final CashMoneyModel cash; /** The IPO */ - private PortfolioModel ipo = null; + private final PortfolioModel ipo; /** The Bank Pool */ - private PortfolioModel pool = null; + private final PortfolioModel pool; /** Collection of items that will (may) become available in the future */ - private PortfolioModel unavailable = null; + private final PortfolioModel unavailable; /** Collection of items that have been discarded (but are kept to allow Undo) */ - private PortfolioModel scrapHeap = null; - - private static Bank instance = null; + private final PortfolioModel scrapHeap; - /** Is the bank broken (remains true once set) */ - private BooleanState broken = BooleanState.create(this, "Bank.broken", false); + /** Is the bank broken */ + private final BooleanState broken; /** * The money format template. '@' is replaced by the numeric amount, the @@ -55,22 +57,40 @@ public class Bank extends GameItem implements CashOwner, ConfigurableComponentI Logger.getLogger(Bank.class.getPackage().getName()); public Bank() { + super(Bank.class.getSimpleName()); instance = this; - money = CashModel.create(this); + cash = MoneyModel.createCash("cash"); + // Create the IPO and the Bank Pool. - ipo = new PortfolioModel(ipo, IPO_NAME); - pool = new PortfolioModel(pool, POOL_NAME); - unavailable = new PortfolioModel(unavailable, UNAVAILABLE_NAME); - scrapHeap = new PortfolioModel(scrapHeap, SCRAPHEAP_NAME); + ipo = PortfolioModel.create(IPO_NAME); + pool = PortfolioModel.create(POOL_NAME); + unavailable = PortfolioModel.create(UNAVAILABLE_NAME); + scrapHeap = PortfolioModel.create(SCRAPHEAP_NAME); + broken = BooleanState.create("broken"); + String configFormat = Config.get("money_format"); if (Util.hasValue(configFormat) && configFormat.matches(".*@.*")) { moneyFormat = configFormat; } } + @Override + public Bank init(Item parent) { + super.init(parent); + + cash.init(this); + ipo.init(this); + pool.init(this); + unavailable.init(this); + scrapHeap.init(this); + broken.init(this); + + return this; + } + /** * @see rails.common.parser.ConfigurableComponentI#configureFromXML(org.w3c.dom.Element) */ @@ -94,7 +114,7 @@ public class Bank extends GameItem implements CashOwner, ConfigurableComponentI Tag bankTag = tag.getChild("Bank"); if (bankTag != null) { - money.set(bankTag.getAttributeAsInteger("amount", + cash.set(bankTag.getAttributeAsInteger("amount", DEFAULT_BANK_AMOUNT)); } @@ -103,7 +123,7 @@ public class Bank extends GameItem implements CashOwner, ConfigurableComponentI public void finishConfiguration (GameManager gameManager) { ReportBuffer.add(LocalText.getText("BankSizeIs", - format(money.value()))); + format(cash.value()))); // Add privates List<PrivateCompany> privates = @@ -118,9 +138,9 @@ public class Bank extends GameItem implements CashOwner, ConfigurableComponentI for (PublicCompany comp : companies) { for (PublicCertificate cert : comp.getCertificates()) { if (cert.isInitiallyAvailable()) { - cert.moveTo(ipo); + ipo.moveInto(cert); } else { - cert.moveTo(unavailable); + unavailable.moveInto(cert); } } } @@ -137,30 +157,15 @@ public class Bank extends GameItem implements CashOwner, ConfigurableComponentI return scrapHeap; } - /** - * @return Bank's current cash level - */ - public int getCashValue() { - return money.value(); - } - - /** - * Adds cash back to the bank - */ - public void addCash(int amount) { - - money.add(amount); - - /* + /* FIXME: Add broken check somewhere * Check if the bank has broken. In some games <0 could apply, so this * will become configurable. - */ - if (money.value() <= 0 && !broken.booleanValue()) { + if (cash.value() <= 0 && !broken.booleanValue()) { broken.set(true); - money.setText(LocalText.getText("BROKEN")); + cash.setText(LocalText.getText("BROKEN")); GameManager.getInstance().registerBrokenBank(); } - } + */ /** * @return Portfolio of stock in Bank Pool @@ -176,19 +181,13 @@ public class Bank extends GameItem implements CashOwner, ConfigurableComponentI return unavailable; } - /** - * @param Set Bank's cash. - */ - public void setCash(int i) { - money.set(i); - } - public String getId() { return LocalText.getText("BANK"); } - public String getFormattedCash() { - return money.getText(); + // CashOwner interface + public CashMoneyModel getCash() { + return cash; } public static String format(int amount) { @@ -198,7 +197,7 @@ public class Bank extends GameItem implements CashOwner, ConfigurableComponentI if (amount < 0) result = result.replaceFirst("(.+)-", "-$1"); return result; } - // start sfy 1889 for integerarrays + public static String formatIntegerArray(int[] amountList) { StringBuilder result = new StringBuilder(); for (int i = 0; i < amountList.length;++i) { @@ -207,14 +206,5 @@ public class Bank extends GameItem implements CashOwner, ConfigurableComponentI } return result.toString(); } - // end sfy 1889 - - public int getCash() { - return money.value(); - } - - public CashModel getCashModel() { - return money; - } } diff --git a/rails/game/BaseToken.java b/rails/game/BaseToken.java index bba6edd..2c879b1 100644 --- a/rails/game/BaseToken.java +++ b/rails/game/BaseToken.java @@ -24,6 +24,7 @@ public class BaseToken extends Token { this.company = company; /* Initially. a BaseToken is always owned by a company. */ + company.getBaseTokensModel(). this.moveTo(company); } diff --git a/rails/game/Company.java b/rails/game/Company.java index b9175b4..2156e53 100644 --- a/rails/game/Company.java +++ b/rails/game/Company.java @@ -14,11 +14,11 @@ import rails.game.model.StorageModel; import rails.game.model.PortfolioModel; import rails.game.special.SpecialPropertyI; import rails.game.state.BooleanState; -import rails.game.state.GameItem; +import rails.game.state.AbstractItem; import rails.game.state.OwnableItem; import rails.util.Util; -public abstract class Company extends GameItem implements ConfigurableComponentI, +public abstract class Company extends AbstractItem implements ConfigurableComponentI, Cloneable, Comparable<Company> { /** The name of the XML tag used to configure a company. */ diff --git a/rails/game/CompanyManager.java b/rails/game/CompanyManager.java index 25f946a..5a00ee5 100644 --- a/rails/game/CompanyManager.java +++ b/rails/game/CompanyManager.java @@ -1 +1 @@ -package rails.game; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.log4j.Logger; import rails.common.LocalText; import rails.common.parser.ConfigurableComponentI; import rails.common.parser.ConfigurationException; import rails.common.parser.Tag; import rails.game.state.GameItem; public class CompanyManager extends GameItem implements CompanyManagerI, ConfigurableComponentI { /** A List with all private companies */ private List<PrivateCompany> lPrivateCompanies = new ArrayList<PrivateCompany>(); /** A List with all public companies */ private List<PublicCompany> lPublicCompanies = new ArrayList<PublicCompany>(); /** A map with all private companies by name */ private Map<String, PrivateCompany> mPrivateCompanies = new HashMap<String, PrivateCompany>(); /** A map with all public (i.e. non-private) companies by name */ private Map<String, PublicCompany> mPublicCompanies = new HashMap<String, PublicCompany>(); /** A map of all type names to maps of companies of that type by name */ // TODO Redundant, current usage can be replaced. private Map<String, Map<String, Company>> mCompaniesByTypeAndName = new HashMap<String, Map<String, Company>>(); /** A list of all company types */ private List<CompanyTypeI> lCompanyTypes = new ArrayList<CompanyTypeI>(); /** A list of all start packets (usually one) */ private List<StartPacket> startPackets = new ArrayList<StartPacket>(); /** A map of all start packets, keyed by name. Default name is "Initial" */ private Map<String, StartPacket> startPacketMap = new HashMap<String, StartPacket>(); /** A map to enable translating aliases to names */ protected Map<String, String> aliases = null; private int numberOfPublicCompanies = 0; protected static Logger log = Logger.getLogger(CompanyManager.class.getPackage().getName()); protected Game |
From: Frederick W. <fre...@us...> - 2012-02-17 17:32:42
|
LocalisedText.properties | 17 + data/Properties.xml | 1 data/profiles/default.profile | 2 data/profiles/root.profile | 1 images/icon/green_station.png |binary images/icon/green_track.png |binary images/icon/grey_station.png |binary images/icon/grey_track.png |binary images/icon/russet_station.png |binary images/icon/russet_track.png |binary images/icon/yellow_station.png |binary images/icon/yellow_track.png |binary rails/game/GameManager.java | 13 - rails/ui/swing/AbstractReportWindow.java | 9 rails/ui/swing/ConfigWindow.java | 11 rails/ui/swing/GameSetupWindow.java | 63 +++-- rails/ui/swing/GameUIManager.java | 99 +++++++- rails/ui/swing/ORWindow.java | 48 ++-- rails/ui/swing/SplashWindow.java | 356 ++++++++++++++++++++++++++++++ rails/ui/swing/StartRoundWindow.java | 10 rails/ui/swing/StatusWindow.java | 10 rails/ui/swing/StockChart.java | 10 rails/ui/swing/elements/DockingFrame.java | 6 rails/util/RunGame.java | 19 - 24 files changed, 582 insertions(+), 93 deletions(-) New commits: commit 0dd7547b2f850ea7e6e5b5c7ccf01c846ab5898c Author: Frederick Weld <fre...@gm...> Date: Fri Feb 17 18:30:28 2012 +0100 Added splash screen option to the root profile Default is on. Prior behavior cannot be restored anyway as the option only triggers whether the splash screen appears (and not whether window popup is occurs prematurely). diff --git a/data/profiles/root.profile b/data/profiles/root.profile index a553e4c..3e08d4d 100644 --- a/data/profiles/root.profile +++ b/data/profiles/root.profile @@ -34,6 +34,7 @@ or.window.dockablePanels=no report.window.type=dynamic report.window.open=yes report.window.editable=no +splash.window.open=yes stockchart.window.open=yes ### Panel Format commit 2d3fd85bfff93e46f42125bdc6fafd13bfd11e6c Author: Frederick Weld <fre...@gm...> Date: Fri Feb 17 17:55:22 2012 +0100 Visualized game initializing progress (splash) by tile upgrades Reused http://rails.sourceforge.net/ icons for this purpose. diff --git a/images/icon/green_station.png b/images/icon/green_station.png new file mode 100644 index 0000000..993e4f0 Binary files /dev/null and b/images/icon/green_station.png differ diff --git a/images/icon/green_track.png b/images/icon/green_track.png new file mode 100644 index 0000000..3d79ec5 Binary files /dev/null and b/images/icon/green_track.png differ diff --git a/images/icon/grey_station.png b/images/icon/grey_station.png new file mode 100644 index 0000000..9597307 Binary files /dev/null and b/images/icon/grey_station.png differ diff --git a/images/icon/grey_track.png b/images/icon/grey_track.png new file mode 100644 index 0000000..6c498f3 Binary files /dev/null and b/images/icon/grey_track.png differ diff --git a/images/icon/russet_station.png b/images/icon/russet_station.png new file mode 100644 index 0000000..625bcea Binary files /dev/null and b/images/icon/russet_station.png differ diff --git a/images/icon/russet_track.png b/images/icon/russet_track.png new file mode 100644 index 0000000..acddde2 Binary files /dev/null and b/images/icon/russet_track.png differ diff --git a/images/icon/yellow_station.png b/images/icon/yellow_station.png new file mode 100644 index 0000000..0bc7f8c Binary files /dev/null and b/images/icon/yellow_station.png differ diff --git a/images/icon/yellow_track.png b/images/icon/yellow_track.png new file mode 100644 index 0000000..1034612 Binary files /dev/null and b/images/icon/yellow_track.png differ diff --git a/rails/ui/swing/SplashWindow.java b/rails/ui/swing/SplashWindow.java index 618e677..8104a6d 100644 --- a/rails/ui/swing/SplashWindow.java +++ b/rails/ui/swing/SplashWindow.java @@ -11,6 +11,7 @@ import java.util.List; import java.util.Set; import javax.swing.BoxLayout; +import javax.swing.ImageIcon; import javax.swing.JComponent; import javax.swing.JFrame; import javax.swing.JLabel; @@ -38,33 +39,33 @@ public class SplashWindow { /** * in millisecs */ - private static long PROGRESS_UPDATE_INTERVAL = 200; + private final static long PROGRESS_UPDATE_INTERVAL = 200; - private static String DUMMY_STEP_BEFORE_START = "-1"; - private static String DUMMY_STEP_START = "0"; - private static String DUMMY_STEP_END = "inf"; + private final static String DUMMY_STEP_BEFORE_START = "-1"; + private final static String DUMMY_STEP_START = "0"; + private final static String DUMMY_STEP_END = "inf"; - public static String STEP_LOAD_GAME = "Splash.step.loadGame"; - public static String STEP_INIT_UI = "Splash.step.initUI"; - public static String STEP_STOCK_CHART = "Splash.step.stockChart"; - public static String STEP_REPORT_WINDOW = "Splash.step.reportWindow"; - public static String STEP_OR_INIT_DOCKING_FRAME = "Splash.step.or.initDockingFrame"; - public static String STEP_OR_INIT_PANELS = "Splash.step.or.initPanels"; - public static String STEP_OR_INIT_TILES = "Splash.step.or.initTiles"; - public static String STEP_OR_APPLY_DOCKING_FRAME = "Splash.step.or.applyDockingFrame"; - public static String STEP_STATUS_WINDOW = "Splash.step.statusWindow"; - public static String STEP_INIT_NEW_GAME = "Splash.step.initNewGame"; - public static String STEP_CONFIG_WINDOW = "Splash.step.configWindow"; - public static String STEP_INIT_SOUND = "Splash.step.initSound"; - public static String STEP_INIT_LOADED_GAME = "Splash.step.initLoadedGame"; - public static String STEP_FINALIZE = "Splash.step.finalize"; + public final static String STEP_LOAD_GAME = "Splash.step.loadGame"; + public final static String STEP_INIT_UI = "Splash.step.initUI"; + public final static String STEP_STOCK_CHART = "Splash.step.stockChart"; + public final static String STEP_REPORT_WINDOW = "Splash.step.reportWindow"; + public final static String STEP_OR_INIT_DOCKING_FRAME = "Splash.step.or.initDockingFrame"; + public final static String STEP_OR_INIT_PANELS = "Splash.step.or.initPanels"; + public final static String STEP_OR_INIT_TILES = "Splash.step.or.initTiles"; + public final static String STEP_OR_APPLY_DOCKING_FRAME = "Splash.step.or.applyDockingFrame"; + public final static String STEP_STATUS_WINDOW = "Splash.step.statusWindow"; + public final static String STEP_INIT_NEW_GAME = "Splash.step.initNewGame"; + public final static String STEP_CONFIG_WINDOW = "Splash.step.configWindow"; + public final static String STEP_INIT_SOUND = "Splash.step.initSound"; + public final static String STEP_INIT_LOADED_GAME = "Splash.step.initLoadedGame"; + public final static String STEP_FINALIZE = "Splash.step.finalize"; - private static List<String> STEP_GROUP_LOAD = Arrays.asList(new String[] { + private final static List<String> STEP_GROUP_LOAD = Arrays.asList(new String[] { STEP_LOAD_GAME, STEP_INIT_LOADED_GAME }); - private static List<String> STEP_GROUP_DOCKING_LAYOUT = Arrays.asList(new String[] { + private final static List<String> STEP_GROUP_DOCKING_LAYOUT = Arrays.asList(new String[] { STEP_OR_INIT_DOCKING_FRAME, STEP_OR_INIT_TILES, STEP_OR_APPLY_DOCKING_FRAME, @@ -78,7 +79,7 @@ public class SplashWindow { this.labelConfigKey = labelConfigKey; } } - private static StepDuration[] stepDuration = { + private final static StepDuration[] stepDuration = { new StepDuration ( 0, DUMMY_STEP_BEFORE_START), // used to facilitate array border handling new StepDuration ( 0, DUMMY_STEP_START), // used to facilitate array border handling new StepDuration ( 6000, STEP_LOAD_GAME ), @@ -97,15 +98,22 @@ public class SplashWindow { new StepDuration ( 1000, STEP_FINALIZE), new StepDuration ( 0, DUMMY_STEP_END), // used to facilitate array border handling }; - + private long totalDuration = 0; private long[] cumulativeDuration = null; private Set<JFrame> framesRegisteredAsVisible = new HashSet<JFrame>(); private List<JFrame> framesRegisteredToFront = new ArrayList<JFrame>(); - private static Dimension iconSize = new Dimension(90,78); - + private final static String iconPath = "/images/icon/"; + + private final static String[][] icons = new String[][] { + { "yellow_track.png" , "yellow_station.png" }, + { "green_track.png" , "green_station.png" }, + { "russet_track.png" , "russet_station.png" }, + { "grey_track.png" , "grey_station.png" } + }; + private JWindow myWin = null; private JLabel leftIcon = null; private JLabel rightIcon = null; @@ -114,7 +122,8 @@ public class SplashWindow { private ProgressVisualizer progressVisualizer = null; - private int currentStep = 1; //the start step + private int currentStep = 0; + private int currentIconIndex = 0; public SplashWindow(boolean isLoad, String initDetailsText) { //quit directly when no visualization required @@ -139,16 +148,19 @@ public class SplashWindow { myWin = new JWindow(); leftIcon = new JLabel(); - leftIcon.setPreferredSize(iconSize); + setIcon(leftIcon,icons[currentIconIndex][0]); + leftIcon.setBorder(new CompoundBorder(new EmptyBorder(5,5,5,5),new EtchedBorder())); rightIcon = new JLabel(); - rightIcon.setPreferredSize(iconSize); + setIcon(rightIcon,icons[currentIconIndex][1]); + rightIcon.setBorder(new CompoundBorder(new EmptyBorder(5,5,5,5),new EtchedBorder())); progressBar = new JProgressBar(0,(int)totalDuration); progressBar.setStringPainted(true); progressBar.setMinimum(0); - stepLabel = new JLabel(); + stepLabel = new JLabel(" "); // needed in order to allocate vertical space stepLabel.setAlignmentX(Component.CENTER_ALIGNMENT); + stepLabel.setBorder(new EmptyBorder(5,5,5,5)); //set up static elements @@ -160,7 +172,7 @@ public class SplashWindow { String commandTextKey = isLoad ? "Splash.command.loadGame" : "Splash.command.newGame"; JLabel commandLabel = new JLabel( LocalText.getText(commandTextKey,initDetailsText)); - commandLabel.setFont(commandLabel.getFont().deriveFont(Font.ITALIC)); + commandLabel.setFont(commandLabel.getFont().deriveFont(Font.BOLD)); commandLabel.setAlignmentX(Component.CENTER_ALIGNMENT); //plug elements together and set up layout @@ -169,12 +181,14 @@ public class SplashWindow { railsCommandPanel.setLayout(new BoxLayout(railsCommandPanel, BoxLayout.Y_AXIS)); railsCommandPanel.add(railsLabel); railsCommandPanel.add(commandLabel); + railsCommandPanel.setBorder(new EmptyBorder(3,3,3,3)); JPanel idPanel = new JPanel(); idPanel.setLayout(new BoxLayout(idPanel, BoxLayout.X_AXIS)); idPanel.add(leftIcon); idPanel.add(railsCommandPanel); idPanel.add(rightIcon); + idPanel.setBorder(new EmptyBorder(3,3,3,3)); JComponent contentPane = (JComponent)myWin.getContentPane(); contentPane.setLayout(new BoxLayout(contentPane, BoxLayout.Y_AXIS)); @@ -201,7 +215,7 @@ public class SplashWindow { } catch (Exception e) {} progressVisualizer = new ProgressVisualizer(); - progressVisualizer.setCurrentStep(currentStep); + notifyOfStep(DUMMY_STEP_START); progressVisualizer.start(); } @@ -218,10 +232,10 @@ public class SplashWindow { } /** - * @param elapsedDuration Refers to a duration normalized based on the expected durations + * @param elapsedTime Refers to a duration normalized based on the expected durations * of the process steps. */ - synchronized private void visualizeProgress(long elapsedDuration, int currentStep) { + synchronized private void visualizeProgress(long elapsedTime, int currentStep) { //update current step (including description) if (currentStep != this.currentStep) { this.currentStep = currentStep; @@ -232,13 +246,32 @@ public class SplashWindow { } } + //update icon + int newIconIndex = (int)(icons.length * elapsedTime / totalDuration); + newIconIndex = Math.max( Math.min(icons.length-1 , newIconIndex) , 0); + if (newIconIndex != currentIconIndex) { + currentIconIndex = newIconIndex; + setIcon(leftIcon,icons[newIconIndex][0]); + setIcon(rightIcon,icons[newIconIndex][1]); + } + //show progress - progressBar.setValue((int)elapsedDuration); + progressBar.setValue((int)elapsedTime); //ensure visibility of window myWin.toFront(); } + private void setIcon(JLabel iconLabel, String iconFileName) { + String path = iconPath + iconFileName; + java.net.URL imgURL = getClass().getResource(path); + if (imgURL != null) { + iconLabel.setIcon(new ImageIcon(imgURL)); + } else { + System.err.println("Couldn't find file: " + path); + } + } + /** * Remembers that this frame is to be put to visible at the end of the splash process */ commit 682539e88405e444c60fc0bc8649ed43c7c40dbd Author: Frederick Weld <fre...@gm...> Date: Fri Feb 17 17:25:17 2012 +0100 Added texts for game init steps (displayed in progress bar) diff --git a/LocalisedText.properties b/LocalisedText.properties index d5f8f37..ac4899b 100644 --- a/LocalisedText.properties +++ b/LocalisedText.properties @@ -642,6 +642,20 @@ SoldOutNoRaise={0} is sold out, but price stays at {1}({2}) SPECIAL=Special Splash.command.loadGame=Loading Game: {0} Splash.command.newGame=Starting New Game: {0} +Splash.step.loadGame=Replaying game... +Splash.step.initUI=Initializing user interface... +Splash.step.stockChart=Building stock chart... +Splash.step.reportWindow=Building report window... +Splash.step.or.initDockingFrame=Initializing docking framework for flexible panels... +Splash.step.or.initPanels=Building operating round window... +Splash.step.or.initTiles=Initializing tiles... +Splash.step.or.applyDockingFrame=Applying docking framework to operating round window... +Splash.step.statusWindow=Building status window... +Splash.step.initNewGame=Initializing new game... +Splash.step.configWindow=Building configuration window... +Splash.step.initSound=Initializing sound... +Splash.step.initLoadedGame=Initializing loaded game... +Splash.step.finalize=Finalizing... SPLIT=Split SRHelpText=Stock round help text goes here. START_COMPANY={0} starts {1} at {2}. diff --git a/rails/ui/swing/ORWindow.java b/rails/ui/swing/ORWindow.java index 68f2ce5..89d037f 100644 --- a/rails/ui/swing/ORWindow.java +++ b/rails/ui/swing/ORWindow.java @@ -191,10 +191,6 @@ public class ORWindow extends DockingFrame implements ActionPerformer { if (isDockingFrameworkEnabled()) { initLayout(); - - //trigger early painting in order to parallelize OR window setup - //with other setup activities - repaint(); } } }); diff --git a/rails/ui/swing/SplashWindow.java b/rails/ui/swing/SplashWindow.java index 0d6ebdb..618e677 100644 --- a/rails/ui/swing/SplashWindow.java +++ b/rails/ui/swing/SplashWindow.java @@ -88,7 +88,7 @@ public class SplashWindow { new StepDuration ( 2600, STEP_OR_INIT_DOCKING_FRAME ), new StepDuration ( 1650, STEP_OR_INIT_PANELS ), new StepDuration ( 5000, STEP_OR_INIT_TILES ), - new StepDuration ( 1000, STEP_OR_APPLY_DOCKING_FRAME ), + new StepDuration ( 3000, STEP_OR_APPLY_DOCKING_FRAME ), new StepDuration ( 400, STEP_STATUS_WINDOW ), new StepDuration ( 300, STEP_INIT_NEW_GAME ), new StepDuration ( 1200, STEP_CONFIG_WINDOW ), @@ -214,6 +214,7 @@ public class SplashWindow { progressVisualizer.setCurrentStep(i); } } + } /** @@ -226,29 +227,19 @@ public class SplashWindow { this.currentStep = currentStep; //only display step description for non-dummy steps if (stepDuration[currentStep].expectedDurationInMillis > 0) { - stepLabel.setText(stepDuration[currentStep].labelConfigKey); - enforeGUIUpdate(stepLabel); + stepLabel.setText(LocalText.getText( + stepDuration[currentStep].labelConfigKey)); } } //show progress progressBar.setValue((int)elapsedDuration); - enforeGUIUpdate(progressBar); //ensure visibility of window myWin.toFront(); } /** - * ensure that progress is updated even if EDT is very busy - * CAUTION: paintImmediately is called outside of EDT - * works but not guideline-conform - */ - private void enforeGUIUpdate(JComponent c) { - c.paintImmediately(c.getBounds()); - } - - /** * Remembers that this frame is to be put to visible at the end of the splash process */ public void registerFrameForDeferredVisibility(JFrame frame,boolean setToVisible) { commit 116db12ebbaceffb1e5f112bfb3bd9c55a2d96d2 Author: Frederick Weld <fre...@gm...> Date: Fri Feb 17 17:13:01 2012 +0100 Added splash screen label for init operation New label indicates "Starting New Game: xyz" or "Loading Game: xyz". diff --git a/LocalisedText.properties b/LocalisedText.properties index ee7f6f5..d5f8f37 100644 --- a/LocalisedText.properties +++ b/LocalisedText.properties @@ -640,6 +640,8 @@ SharesPutInTreasury=The remaining {0}% shares of {1} are put in its treasury SoldOut={0} is sold out, price rises from {1}({2}) to {3}({4}) SoldOutNoRaise={0} is sold out, but price stays at {1}({2}) SPECIAL=Special +Splash.command.loadGame=Loading Game: {0} +Splash.command.newGame=Starting New Game: {0} SPLIT=Split SRHelpText=Stock round help text goes here. START_COMPANY={0} starts {1} at {2}. diff --git a/rails/ui/swing/GameSetupWindow.java b/rails/ui/swing/GameSetupWindow.java index 6a633a9..4d7e73d 100644 --- a/rails/ui/swing/GameSetupWindow.java +++ b/rails/ui/swing/GameSetupWindow.java @@ -228,7 +228,7 @@ public class GameSetupWindow extends JDialog implements ActionListener { */ private void loadAndStartGame(String filePath, String saveDirectory) { prepareGameUIInit(); - SplashWindow splashWindow = new SplashWindow(true); + SplashWindow splashWindow = new SplashWindow(true,filePath); splashWindow.notifyOfStep(SplashWindow.STEP_LOAD_GAME); if ((game = Game.load(filePath)) == null) { JOptionPane.showMessageDialog(this, @@ -500,7 +500,12 @@ public class GameSetupWindow extends JDialog implements ActionListener { } } - game = new Game(this.getSelectedGameInfo().getName(), playerNames, selectedOptions); + String gameName = getSelectedGameInfo().getName(); + + SplashWindow splashWindow = new SplashWindow(false,gameName); + + game = new Game(gameName, playerNames, selectedOptions); + if (!game.setup()) { JOptionPane.showMessageDialog(this, DisplayBuffer.get(), "", JOptionPane.ERROR_MESSAGE); @@ -517,7 +522,6 @@ public class GameSetupWindow extends JDialog implements ActionListener { System.exit(-1); } prepareGameUIInit(); - SplashWindow splashWindow = new SplashWindow(false); startGameUIManager (game, false, splashWindow); gameUIManager.gameUIInit(true); // true indicates new game completeGameUIInit(splashWindow); diff --git a/rails/ui/swing/SplashWindow.java b/rails/ui/swing/SplashWindow.java index 1e1201e..0d6ebdb 100644 --- a/rails/ui/swing/SplashWindow.java +++ b/rails/ui/swing/SplashWindow.java @@ -2,6 +2,7 @@ package rails.ui.swing; import java.awt.Component; import java.awt.Dimension; +import java.awt.Font; import java.awt.Toolkit; import java.util.ArrayList; import java.util.Arrays; @@ -21,6 +22,7 @@ import javax.swing.border.CompoundBorder; import javax.swing.border.EmptyBorder; import javax.swing.border.EtchedBorder; +import rails.common.LocalText; import rails.common.parser.Config; import rails.game.Game; @@ -114,7 +116,7 @@ public class SplashWindow { private int currentStep = 1; //the start step - public SplashWindow(boolean isLoad) { + public SplashWindow(boolean isLoad, String initDetailsText) { //quit directly when no visualization required //all visualization related attributes remain null then if ("no".equals(Config.get("splash.window.open"))) return; @@ -155,7 +157,10 @@ public class SplashWindow { (float)2.0 * railsLabel.getFont().getSize())); railsLabel.setAlignmentX(Component.CENTER_ALIGNMENT); - JLabel commandLabel = new JLabel("Setting up new game / loading game"); + String commandTextKey = isLoad ? "Splash.command.loadGame" : "Splash.command.newGame"; + JLabel commandLabel = new JLabel( + LocalText.getText(commandTextKey,initDetailsText)); + commandLabel.setFont(commandLabel.getFont().deriveFont(Font.ITALIC)); commandLabel.setAlignmentX(Component.CENTER_ALIGNMENT); //plug elements together and set up layout diff --git a/rails/util/RunGame.java b/rails/util/RunGame.java index 8206c25..3c08442 100644 --- a/rails/util/RunGame.java +++ b/rails/util/RunGame.java @@ -49,11 +49,12 @@ public class RunGame { static void loadGame (String[] args) { - SplashWindow splashWindow = new SplashWindow(true); - splashWindow.notifyOfStep(SplashWindow.STEP_LOAD_GAME); - Game game = null; String filepath = args[0]; + + SplashWindow splashWindow = new SplashWindow(true,filepath); + splashWindow.notifyOfStep(SplashWindow.STEP_LOAD_GAME); + System.out.println("Starting game from saved file "+filepath); if ((game = Game.load(filepath)) == null) { System.err.println("Loading file "+filepath+" was unsuccessful"); commit b28efc90ce9a591119f83d6613d16df57990917a Author: Frederick Weld <fre...@gm...> Date: Fri Feb 17 16:27:15 2012 +0100 Laid out splash screen (incl. rails version, progress bar) diff --git a/LocalisedText.properties b/LocalisedText.properties index 9c1ccd7..ee7f6f5 100644 --- a/LocalisedText.properties +++ b/LocalisedText.properties @@ -213,7 +213,7 @@ Config.label.route.colour.1=Route color for first train Config.label.route.colour.2=Route color for second train Config.label.route.colour.3=Route color for third train Config.label.route.colour.4=Route color for fourth train -Config.label.splash.window.open=Splash window open +Config.label.splash.window.open=Display splash screen Config.label.sound.backgroundMusic=Background Music Config.label.sound.backgroundMusic.endOfGameRound=End of Game Config.label.sound.backgroundMusic.gameSetup=Initial Game Setup diff --git a/rails/ui/swing/SplashWindow.java b/rails/ui/swing/SplashWindow.java index edb8cad..1e1201e 100644 --- a/rails/ui/swing/SplashWindow.java +++ b/rails/ui/swing/SplashWindow.java @@ -1,18 +1,28 @@ package rails.ui.swing; -import java.awt.Rectangle; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.Toolkit; import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Set; +import javax.swing.BoxLayout; +import javax.swing.JComponent; import javax.swing.JFrame; import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JProgressBar; import javax.swing.JWindow; import javax.swing.SwingUtilities; +import javax.swing.border.CompoundBorder; +import javax.swing.border.EmptyBorder; +import javax.swing.border.EtchedBorder; import rails.common.parser.Config; +import rails.game.Game; /** * Splash window shown during setup of game UI components and game loading. @@ -32,20 +42,20 @@ public class SplashWindow { private static String DUMMY_STEP_START = "0"; private static String DUMMY_STEP_END = "inf"; - public static String STEP_LOAD_GAME = "1"; - public static String STEP_INIT_UI = "2"; - public static String STEP_STOCK_CHART = "3"; - public static String STEP_REPORT_WINDOW = "4"; - public static String STEP_OR_INIT_DOCKING_FRAME = "5A"; - public static String STEP_OR_INIT_PANELS = "5B"; - public static String STEP_OR_INIT_TILES = "5C"; - public static String STEP_OR_APPLY_DOCKING_FRAME = "5D"; - public static String STEP_STATUS_WINDOW = "6"; - public static String STEP_INIT_NEW_GAME = "7"; - public static String STEP_CONFIG_WINDOW = "8"; - public static String STEP_INIT_SOUND = "9"; - public static String STEP_INIT_LOADED_GAME = "10"; - public static String STEP_FINALIZE = "11"; + public static String STEP_LOAD_GAME = "Splash.step.loadGame"; + public static String STEP_INIT_UI = "Splash.step.initUI"; + public static String STEP_STOCK_CHART = "Splash.step.stockChart"; + public static String STEP_REPORT_WINDOW = "Splash.step.reportWindow"; + public static String STEP_OR_INIT_DOCKING_FRAME = "Splash.step.or.initDockingFrame"; + public static String STEP_OR_INIT_PANELS = "Splash.step.or.initPanels"; + public static String STEP_OR_INIT_TILES = "Splash.step.or.initTiles"; + public static String STEP_OR_APPLY_DOCKING_FRAME = "Splash.step.or.applyDockingFrame"; + public static String STEP_STATUS_WINDOW = "Splash.step.statusWindow"; + public static String STEP_INIT_NEW_GAME = "Splash.step.initNewGame"; + public static String STEP_CONFIG_WINDOW = "Splash.step.configWindow"; + public static String STEP_INIT_SOUND = "Splash.step.initSound"; + public static String STEP_INIT_LOADED_GAME = "Splash.step.initLoadedGame"; + public static String STEP_FINALIZE = "Splash.step.finalize"; private static List<String> STEP_GROUP_LOAD = Arrays.asList(new String[] { STEP_LOAD_GAME, @@ -92,11 +102,15 @@ public class SplashWindow { private Set<JFrame> framesRegisteredAsVisible = new HashSet<JFrame>(); private List<JFrame> framesRegisteredToFront = new ArrayList<JFrame>(); + private static Dimension iconSize = new Dimension(90,78); + private JWindow myWin = null; - private ProgressVisualizer progressVisualizer = null; + private JLabel leftIcon = null; + private JLabel rightIcon = null; + private JProgressBar progressBar = null; + private JLabel stepLabel = null; - //TODO remove temp label - private JLabel tempL = null; + private ProgressVisualizer progressVisualizer = null; private int currentStep = 1; //the start step @@ -104,17 +118,7 @@ public class SplashWindow { //quit directly when no visualization required //all visualization related attributes remain null then if ("no".equals(Config.get("splash.window.open"))) return; - - myWin = new JWindow(); - myWin.setBounds(new Rectangle(200,200,400,200)); - - //TODO remove temp - tempL = new JLabel(""); - myWin.getContentPane().add(tempL); - tempL.setVisible(true); - //TODO set up frame (incl. title, icons, bar, status text) - myWin.setVisible(true); - + //calculate estimated duration for the respective steps cumulativeDuration = new long[stepDuration.length]; boolean isDockingLayout = "yes".equals(Config.get("or.window.dockablePanels")); @@ -128,6 +132,69 @@ public class SplashWindow { cumulativeDuration[i] = totalDuration; } + //set up dynamic elements + + myWin = new JWindow(); + + leftIcon = new JLabel(); + leftIcon.setPreferredSize(iconSize); + rightIcon = new JLabel(); + rightIcon.setPreferredSize(iconSize); + + progressBar = new JProgressBar(0,(int)totalDuration); + progressBar.setStringPainted(true); + progressBar.setMinimum(0); + + stepLabel = new JLabel(); + stepLabel.setAlignmentX(Component.CENTER_ALIGNMENT); + + //set up static elements + + JLabel railsLabel = new JLabel("Rails " + Game.getFullVersion()); + railsLabel.setFont(railsLabel.getFont().deriveFont( + (float)2.0 * railsLabel.getFont().getSize())); + railsLabel.setAlignmentX(Component.CENTER_ALIGNMENT); + + JLabel commandLabel = new JLabel("Setting up new game / loading game"); + commandLabel.setAlignmentX(Component.CENTER_ALIGNMENT); + + //plug elements together and set up layout + + JPanel railsCommandPanel = new JPanel(); + railsCommandPanel.setLayout(new BoxLayout(railsCommandPanel, BoxLayout.Y_AXIS)); + railsCommandPanel.add(railsLabel); + railsCommandPanel.add(commandLabel); + + JPanel idPanel = new JPanel(); + idPanel.setLayout(new BoxLayout(idPanel, BoxLayout.X_AXIS)); + idPanel.add(leftIcon); + idPanel.add(railsCommandPanel); + idPanel.add(rightIcon); + + JComponent contentPane = (JComponent)myWin.getContentPane(); + contentPane.setLayout(new BoxLayout(contentPane, BoxLayout.Y_AXIS)); + contentPane.add(idPanel); + contentPane.add(progressBar); + contentPane.add(stepLabel); + contentPane.setBorder(new CompoundBorder(new EtchedBorder(),new EmptyBorder(5,5,5,5))); + + //perform layout within the EDT + //blocking call as further initialization requires the layout to be frozen + try { + SwingUtilities.invokeAndWait(new Thread() { + @Override + public void run() { + myWin.pack(); + Dimension dim = Toolkit.getDefaultToolkit().getScreenSize(); + myWin.setLocation( + (dim.width - myWin.getSize().width) / 2, + (dim.height - myWin.getSize().height) / 2 + ); + myWin.setVisible(true); + } + }); + } catch (Exception e) {} + progressVisualizer = new ProgressVisualizer(); progressVisualizer.setCurrentStep(currentStep); progressVisualizer.start(); @@ -154,24 +221,29 @@ public class SplashWindow { this.currentStep = currentStep; //only display step description for non-dummy steps if (stepDuration[currentStep].expectedDurationInMillis > 0) { - //TODO + stepLabel.setText(stepDuration[currentStep].labelConfigKey); + enforeGUIUpdate(stepLabel); } } //show progress - double percentage = 100.0 * elapsedDuration / totalDuration; - tempL.setText("<html>" + percentage + "<br>" + stepDuration[currentStep].labelConfigKey + "</html>"); + progressBar.setValue((int)elapsedDuration); + enforeGUIUpdate(progressBar); - //ensure that progress is updated even if EDT is very busy - //CAUTION: paintImmediately is called outside of EDT - // works but not guideline-conform - tempL.paintImmediately(tempL.getBounds()); - //ensure visibility of window myWin.toFront(); } /** + * ensure that progress is updated even if EDT is very busy + * CAUTION: paintImmediately is called outside of EDT + * works but not guideline-conform + */ + private void enforeGUIUpdate(JComponent c) { + c.paintImmediately(c.getBounds()); + } + + /** * Remembers that this frame is to be put to visible at the end of the splash process */ public void registerFrameForDeferredVisibility(JFrame frame,boolean setToVisible) { commit 1aa89dfdc7568950f5f6b0b8833c0e12e25e1eee Author: Frederick Weld <fre...@gm...> Date: Fri Feb 17 06:19:19 2012 +0100 Added option to display splash screen (default yes) Even if splash screen is not to be displayed, the init logic (deferring setVisible/toFront, parallelization EDT and non-EDT) is applied. diff --git a/LocalisedText.properties b/LocalisedText.properties index 087534b..9c1ccd7 100644 --- a/LocalisedText.properties +++ b/LocalisedText.properties @@ -213,6 +213,7 @@ Config.label.route.colour.1=Route color for first train Config.label.route.colour.2=Route color for second train Config.label.route.colour.3=Route color for third train Config.label.route.colour.4=Route color for fourth train +Config.label.splash.window.open=Splash window open Config.label.sound.backgroundMusic=Background Music Config.label.sound.backgroundMusic.endOfGameRound=End of Game Config.label.sound.backgroundMusic.gameSetup=Initial Game Setup diff --git a/data/Properties.xml b/data/Properties.xml index 9399a9f..1e5c37e 100644 --- a/data/Properties.xml +++ b/data/Properties.xml @@ -41,6 +41,7 @@ <Property name="report.window.editable" type="BOOLEAN" /> <Property name="stockchart.window.open" type="BOOLEAN" /> <Property name="or.window.dockablePanels" type="BOOLEAN" /> + <Property name="splash.window.open" type="BOOLEAN" /> </Section> <Section name="Format"> <Property name="money_format" type="STRING" /> diff --git a/data/profiles/default.profile b/data/profiles/default.profile index 03d7a58..122c1b7 100644 --- a/data/profiles/default.profile +++ b/data/profiles/default.profile @@ -1,2 +1,2 @@ ### Default profile currently is identical to root.profile -### so no change here \ No newline at end of file +### so no change here diff --git a/rails/ui/swing/SplashWindow.java b/rails/ui/swing/SplashWindow.java index 68fddda..edb8cad 100644 --- a/rails/ui/swing/SplashWindow.java +++ b/rails/ui/swing/SplashWindow.java @@ -87,20 +87,24 @@ public class SplashWindow { }; private long totalDuration = 0; - private long[] cumulativeDuration; + private long[] cumulativeDuration = null; private Set<JFrame> framesRegisteredAsVisible = new HashSet<JFrame>(); private List<JFrame> framesRegisteredToFront = new ArrayList<JFrame>(); - private JWindow myWin; - private ProgressVisualizer progressVisualizer; + private JWindow myWin = null; + private ProgressVisualizer progressVisualizer = null; //TODO remove temp label - private JLabel tempL; + private JLabel tempL = null; private int currentStep = 1; //the start step public SplashWindow(boolean isLoad) { + //quit directly when no visualization required + //all visualization related attributes remain null then + if ("no".equals(Config.get("splash.window.open"))) return; + myWin = new JWindow(); myWin.setBounds(new Rectangle(200,200,400,200)); @@ -130,6 +134,9 @@ public class SplashWindow { } public void notifyOfStep(String stepLabelConfigKey) { + //ignore if no visualization requested + if (myWin == null) return; + for (int i = 0 ; i < stepDuration.length ; i++) { if (stepDuration[i].labelConfigKey.equals(stepLabelConfigKey)) { progressVisualizer.setCurrentStep(i); @@ -208,10 +215,11 @@ public class SplashWindow { }); } catch (Exception e) {} - progressVisualizer.interrupt(); - - myWin.dispose(); - + //clean up visualization only if it was requested + if (myWin != null) { + progressVisualizer.interrupt(); + myWin.dispose(); + } } private class ProgressVisualizer extends Thread { commit 2f2e71b6e7de9340e5c9e64388b1f10a097f5e41 Author: Frederick Weld <fre...@gm...> Date: Thu Feb 16 19:59:37 2012 +0100 Added context dependent progress calculation (new/load, conv/docking) Init time largely depend on whether - new game is started or old game is loaded (latter lasts longer) - conventional layout or docking layout is used (latter is longer) Now, the splash window's heuristic takes into account this context information for better display of the progress. diff --git a/rails/ui/swing/GameSetupWindow.java b/rails/ui/swing/GameSetupWindow.java index c7ebea1..6a633a9 100644 --- a/rails/ui/swing/GameSetupWindow.java +++ b/rails/ui/swing/GameSetupWindow.java @@ -228,7 +228,7 @@ public class GameSetupWindow extends JDialog implements ActionListener { */ private void loadAndStartGame(String filePath, String saveDirectory) { prepareGameUIInit(); - SplashWindow splashWindow = new SplashWindow(); + SplashWindow splashWindow = new SplashWindow(true); splashWindow.notifyOfStep(SplashWindow.STEP_LOAD_GAME); if ((game = Game.load(filePath)) == null) { JOptionPane.showMessageDialog(this, @@ -517,7 +517,7 @@ public class GameSetupWindow extends JDialog implements ActionListener { System.exit(-1); } prepareGameUIInit(); - SplashWindow splashWindow = new SplashWindow(); + SplashWindow splashWindow = new SplashWindow(false); startGameUIManager (game, false, splashWindow); gameUIManager.gameUIInit(true); // true indicates new game completeGameUIInit(splashWindow); diff --git a/rails/ui/swing/SplashWindow.java b/rails/ui/swing/SplashWindow.java index 0f030a1..68fddda 100644 --- a/rails/ui/swing/SplashWindow.java +++ b/rails/ui/swing/SplashWindow.java @@ -2,6 +2,7 @@ package rails.ui.swing; import java.awt.Rectangle; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -11,6 +12,8 @@ import javax.swing.JLabel; import javax.swing.JWindow; import javax.swing.SwingUtilities; +import rails.common.parser.Config; + /** * Splash window shown during setup of game UI components and game loading. * Provides for a progress bar, status bar, and ensures that frames only become visible @@ -43,6 +46,17 @@ public class SplashWindow { public static String STEP_INIT_SOUND = "9"; public static String STEP_INIT_LOADED_GAME = "10"; public static String STEP_FINALIZE = "11"; + + private static List<String> STEP_GROUP_LOAD = Arrays.asList(new String[] { + STEP_LOAD_GAME, + STEP_INIT_LOADED_GAME + }); + + private static List<String> STEP_GROUP_DOCKING_LAYOUT = Arrays.asList(new String[] { + STEP_OR_INIT_DOCKING_FRAME, + STEP_OR_INIT_TILES, + STEP_OR_APPLY_DOCKING_FRAME, + }); private static class StepDuration { long expectedDurationInMillis; @@ -62,7 +76,7 @@ public class SplashWindow { new StepDuration ( 2600, STEP_OR_INIT_DOCKING_FRAME ), new StepDuration ( 1650, STEP_OR_INIT_PANELS ), new StepDuration ( 5000, STEP_OR_INIT_TILES ), - new StepDuration ( 3000, STEP_OR_APPLY_DOCKING_FRAME ), + new StepDuration ( 1000, STEP_OR_APPLY_DOCKING_FRAME ), new StepDuration ( 400, STEP_STATUS_WINDOW ), new StepDuration ( 300, STEP_INIT_NEW_GAME ), new StepDuration ( 1200, STEP_CONFIG_WINDOW ), @@ -86,20 +100,27 @@ public class SplashWindow { private int currentStep = 1; //the start step - public SplashWindow() { + public SplashWindow(boolean isLoad) { myWin = new JWindow(); myWin.setBounds(new Rectangle(200,200,400,200)); //TODO remove temp - tempL = new JLabel("sghsghsghsfghws"); + tempL = new JLabel(""); myWin.getContentPane().add(tempL); tempL.setVisible(true); //TODO set up frame (incl. title, icons, bar, status text) myWin.setVisible(true); + //calculate estimated duration for the respective steps cumulativeDuration = new long[stepDuration.length]; + boolean isDockingLayout = "yes".equals(Config.get("or.window.dockablePanels")); for (int i = 0 ; i < stepDuration.length ; i++) { - totalDuration += stepDuration[i].expectedDurationInMillis; + //only consider step if relevant for this setup + if ( (isLoad || !STEP_GROUP_LOAD.contains(stepDuration[i].labelConfigKey)) + && + (isDockingLayout || !STEP_GROUP_DOCKING_LAYOUT.contains(stepDuration[i].labelConfigKey)) ) { + totalDuration += stepDuration[i].expectedDurationInMillis; + } cumulativeDuration[i] = totalDuration; } diff --git a/rails/util/RunGame.java b/rails/util/RunGame.java index 461035a..8206c25 100644 --- a/rails/util/RunGame.java +++ b/rails/util/RunGame.java @@ -49,7 +49,7 @@ public class RunGame { static void loadGame (String[] args) { - SplashWindow splashWindow = new SplashWindow(); + SplashWindow splashWindow = new SplashWindow(true); splashWindow.notifyOfStep(SplashWindow.STEP_LOAD_GAME); Game game = null; commit 88c68529a44f51f2a17bb7c9932b6b2eeff2f112 Author: Frederick Weld <fre...@gm...> Date: Thu Feb 16 16:55:11 2012 +0100 Ensured that progress is visualized even if EDT is busy diff --git a/rails/ui/swing/SplashWindow.java b/rails/ui/swing/SplashWindow.java index b8ba47d..0f030a1 100644 --- a/rails/ui/swing/SplashWindow.java +++ b/rails/ui/swing/SplashWindow.java @@ -23,7 +23,7 @@ public class SplashWindow { /** * in millisecs */ - private static long PROGRESS_UPDATE_INTERVAL = 100; + private static long PROGRESS_UPDATE_INTERVAL = 200; private static String DUMMY_STEP_BEFORE_START = "-1"; private static String DUMMY_STEP_START = "0"; @@ -133,6 +133,11 @@ public class SplashWindow { //show progress double percentage = 100.0 * elapsedDuration / totalDuration; tempL.setText("<html>" + percentage + "<br>" + stepDuration[currentStep].labelConfigKey + "</html>"); + + //ensure that progress is updated even if EDT is very busy + //CAUTION: paintImmediately is called outside of EDT + // works but not guideline-conform + tempL.paintImmediately(tempL.getBounds()); //ensure visibility of window myWin.toFront(); commit e75ec0326113597cb78ca5836c3017b47537ceb5 Author: Frederick Weld <fre...@gm...> Date: Thu Feb 16 16:41:33 2012 +0100 Added support for setting frames in correct front-to-back order after init diff --git a/rails/ui/swing/GameUIManager.java b/rails/ui/swing/GameUIManager.java index 809dcf4..7e59194 100644 --- a/rails/ui/swing/GameUIManager.java +++ b/rails/ui/swing/GameUIManager.java @@ -475,7 +475,7 @@ public class GameUIManager implements DialogOwner { setMeVisible(stockChart,stockChartVisibilityHint); previousStockChartVisibilityHint = stockChartVisibilityHint; } - if (hint.getVisibility()) stockChart.toFront(); + if (hint.getVisibility()) setMeToFront(stockChart); break; case STATUS: boolean statusWindowVisibilityHint = hint.getVisibility(); @@ -483,7 +483,7 @@ public class GameUIManager implements DialogOwner { setMeVisible(statusWindow,statusWindowVisibilityHint); previousStatusWindowVisibilityHint = statusWindowVisibilityHint; } - if (statusWindowVisibilityHint) statusWindow.toFront(); + if (statusWindowVisibilityHint) setMeToFront(statusWindow); break; case MAP: boolean orWindowVisibilityHint = hint.getVisibility(); @@ -491,7 +491,7 @@ public class GameUIManager implements DialogOwner { setMeVisible(orWindow,orWindowVisibilityHint); previousORWindowVisibilityHint = orWindowVisibilityHint; } - if (orWindowVisibilityHint) orWindow.toFront(); + if (orWindowVisibilityHint) setMeToFront(orWindow); break; case START_ROUND: // Handled elsewhere @@ -511,7 +511,7 @@ public class GameUIManager implements DialogOwner { log.debug("Entering Start Round UI type"); activeWindow = startRoundWindow; setMeVisible(startRoundWindow,true); - startRoundWindow.toFront(); + setMeToFront(startRoundWindow); } else if (uiHints.getActivePanel() == GuiDef.Panel.STATUS || correctionOverride) { @@ -519,14 +519,14 @@ public class GameUIManager implements DialogOwner { activeWindow = statusWindow; stockChart.setVisible(true); setMeVisible(statusWindow,true); - statusWindow.toFront(); + setMeToFront(statusWindow); } else if (uiHints.getActivePanel() == GuiDef.Panel.MAP && !correctionOverride) { log.debug("Entering Operating Round UI type "); activeWindow = orWindow; setMeVisible(orWindow,true); - orWindow.toFront(); + setMeToFront(orWindow); } @@ -1146,6 +1146,19 @@ public class GameUIManager implements DialogOwner { } /** + * Only set frame directly to front if the splash phase is already over. + * Otherwise, the splash framework remembers this toFront request and + * postpones the toFront to the point in time where the splash is completed. + */ + public void setMeToFront(JFrame frame) { + if (splashWindow == null) { + frame.toFront(); + } else { + splashWindow.registerFrameForDeferredToFront(frame); + } + } + + /** * called when the splash process is completed * (and visibility changes are not to be deferred any more) */ diff --git a/rails/ui/swing/SplashWindow.java b/rails/ui/swing/SplashWindow.java index 8a279ce..b8ba47d 100644 --- a/rails/ui/swing/SplashWindow.java +++ b/rails/ui/swing/SplashWindow.java @@ -1,7 +1,9 @@ package rails.ui.swing; import java.awt.Rectangle; +import java.util.ArrayList; import java.util.HashSet; +import java.util.List; import java.util.Set; import javax.swing.JFrame; @@ -40,6 +42,7 @@ public class SplashWindow { public static String STEP_CONFIG_WINDOW = "8"; public static String STEP_INIT_SOUND = "9"; public static String STEP_INIT_LOADED_GAME = "10"; + public static String STEP_FINALIZE = "11"; private static class StepDuration { long expectedDurationInMillis; @@ -59,12 +62,13 @@ public class SplashWindow { new StepDuration ( 2600, STEP_OR_INIT_DOCKING_FRAME ), new StepDuration ( 1650, STEP_OR_INIT_PANELS ), new StepDuration ( 5000, STEP_OR_INIT_TILES ), - new StepDuration ( 2000, STEP_OR_APPLY_DOCKING_FRAME ), + new StepDuration ( 3000, STEP_OR_APPLY_DOCKING_FRAME ), new StepDuration ( 400, STEP_STATUS_WINDOW ), new StepDuration ( 300, STEP_INIT_NEW_GAME ), new StepDuration ( 1200, STEP_CONFIG_WINDOW ), new StepDuration ( 200, STEP_INIT_SOUND ), new StepDuration ( 1000, STEP_INIT_LOADED_GAME ), + new StepDuration ( 1000, STEP_FINALIZE), new StepDuration ( 0, DUMMY_STEP_END), // used to facilitate array border handling }; @@ -72,6 +76,7 @@ public class SplashWindow { private long[] cumulativeDuration; private Set<JFrame> framesRegisteredAsVisible = new HashSet<JFrame>(); + private List<JFrame> framesRegisteredToFront = new ArrayList<JFrame>(); private JWindow myWin; private ProgressVisualizer progressVisualizer; @@ -119,7 +124,8 @@ public class SplashWindow { //update current step (including description) if (currentStep != this.currentStep) { this.currentStep = currentStep; - if (currentStep != 0 && currentStep != stepDuration.length - 1) { + //only display step description for non-dummy steps + if (stepDuration[currentStep].expectedDurationInMillis > 0) { //TODO } } @@ -143,19 +149,38 @@ public class SplashWindow { } } + /** + * Remembers that this frame is to be put to front at the end of the splash process + * Handles the list of to front requests in order to + * - apply all requests in a FIFO manner + * - ensure that each frame is only sent to the front once (at the latest registered time) + */ + public void registerFrameForDeferredToFront(JFrame frame) { + framesRegisteredToFront.remove(frame); + framesRegisteredToFront.add(frame); + } + public void finalizeGameInit() { - progressVisualizer.setCurrentStep(stepDuration.length - 1); + notifyOfStep(STEP_FINALIZE); - //finally restore visibility of registered frames + //finally restore visibility / toFront of registered frames //only after EDT is ready (as window built-up could still be pending) - SwingUtilities.invokeLater(new Thread() { - @Override - public void run() { - for (JFrame frame : framesRegisteredAsVisible) { - frame.setVisible(true); + //block any frame disposal to the point in time when this is through + try { + SwingUtilities.invokeAndWait(new Thread() { + @Override + public void run() { + //visibility + for (JFrame frame : framesRegisteredAsVisible) { + frame.setVisible(true); + } + //to front + for (JFrame frame : framesRegisteredToFront) { + frame.toFront(); + } } - } - }); + }); + } catch (Exception e) {} progressVisualizer.interrupt(); @@ -164,24 +189,24 @@ public class SplashWindow { } private class ProgressVisualizer extends Thread { - private long elapsedDuration = 0; + private long elapsedTime = 0; private int currentStep = 0; @Override public void run() { try { while (!isInterrupted()) { - visualizeProgress(elapsedDuration, currentStep); + visualizeProgress(elapsedTime, currentStep); sleep(PROGRESS_UPDATE_INTERVAL); //adjusted elapsed duration synchronized (this) { - elapsedDuration += PROGRESS_UPDATE_INTERVAL; + elapsedTime += PROGRESS_UPDATE_INTERVAL; //elapsed duration must remain within the bounds of the estimated cumulative duration //between the end of last step and the end of the current step - elapsedDuration = Math.max ( + elapsedTime = Math.max ( cumulativeDuration[currentStep-1], - Math.min( elapsedDuration, cumulativeDuration[currentStep] ) + Math.min( elapsedTime, cumulativeDuration[currentStep] ) ); } } @@ -190,6 +215,7 @@ public class SplashWindow { synchronized private void setCurrentStep(int currentStep) { this.currentStep = currentStep; + //System.out.println("Time: "+elapsedTime + " (Step: "+stepDuration[currentStep].labelConfigKey+")"); } } } \ No newline at end of file commit c71458876f4beb07d49543bbf6fdc74bae3c8ae8 Author: Frederick Weld <fre...@gm...> Date: Thu Feb 16 16:16:10 2012 +0100 Removed multi-instance GameManager concept / set GameManager to singleton diff --git a/rails/game/GameManager.java b/rails/game/GameManager.java index c147924..15915f0 100644 --- a/rails/game/GameManager.java +++ b/rails/game/GameManager.java @@ -136,6 +136,12 @@ public class GameManager implements ConfigurableComponentI, GameManagerI { new EnumMap<GuiDef.Parm, Boolean>(GuiDef.Parm.class); /** + * Update: + * NDC concept has been replaced by the origin singleton one. + * Target design to be decided when distributed rails is being conceived + * and developed. + * + * Former design: * Map of GameManager instances. * Currently there can be only one instance, but in a possible * future multi-game server there may be several instances @@ -237,8 +243,8 @@ public class GameManager implements ConfigurableComponentI, GameManagerI { public GameManager() { gmName = GM_NAME; gmKey = GM_KEY; - NDC.clear(); - NDC.push (GM_KEY); + //NDC.clear(); + //NDC.push (GM_KEY); gameManagerMap.put(GM_KEY, this); displayBuffer = new DisplayBuffer(); reportBuffer = new ReportBuffer(); @@ -633,7 +639,8 @@ public class GameManager implements ConfigurableComponentI, GameManagerI { * @return instance of GameManager */ public static GameManagerI getInstance () { - return gameManagerMap.get(NDC.peek()); +// return gameManagerMap.get(NDC.peek()); + return gameManagerMap.get(GM_KEY); } /* (non-Javadoc) commit 33e8c3cf880ee791cfd1c941eef6be64395394a4 Author: Frederick Weld <fre...@gm...> Date: Thu Feb 16 16:11:36 2012 +0100 Removed game init by default from EDT / put pack explicitly into EDT diff --git a/rails/ui/swing/ConfigWindow.java b/rails/ui/swing/ConfigWindow.java index db03e10..e5fb185 100644 --- a/rails/ui/swing/ConfigWindow.java +++ b/rails/ui/swing/ConfigWindow.java @@ -8,6 +8,7 @@ import java.awt.GraphicsEnvironment; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; +import java.awt.Rectangle; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.FocusEvent; @@ -43,6 +44,7 @@ import javax.swing.JSpinner; import javax.swing.JTabbedPane; import javax.swing.SpinnerNumberModel; import javax.swing.SwingConstants; +import javax.swing.SwingUtilities; import javax.swing.UIManager; import javax.swing.WindowConstants; import javax.swing.border.Border; @@ -105,8 +107,13 @@ class ConfigWindow extends JFrame { setupProfilePanel(); setupConfigPane(); setupButtonPanel(); - this.pack(); - setSize(600,400); + + SwingUtilities.invokeLater(new Thread() { + public void run() { + ConfigWindow.this.pack(); + ConfigWindow.this.setSize(600,400); + } + }); } private void setupProfilePanel() { diff --git a/rails/ui/swing/ORWindow.java b/rails/ui/swing/ORWindow.java index c67a23f..68f2ce5 100644 --- a/rails/ui/swing/ORWindow.java +++ b/rails/ui/swing/ORWindow.java @@ -189,7 +189,13 @@ public class ORWindow extends DockingFrame implements ActionPerformer { if (bounds.width != -1 && bounds.height != -1) setSize(bounds.getSize()); ws.set(frame); - if (isDockingFrameworkEnabled()) initLayout(); + if (isDockingFrameworkEnabled()) { + initLayout(); + + //trigger early painting in order to parallelize OR window setup + //with other setup activities + repaint(); + } } }); diff --git a/rails/ui/swing/SplashWindow.java b/rails/ui/swing/SplashWindow.java index 406af02..8a279ce 100644 --- a/rails/ui/swing/SplashWindow.java +++ b/rails/ui/swing/SplashWindow.java @@ -104,7 +104,6 @@ public class SplashWindow { } public void notifyOfStep(String stepLabelConfigKey) { - myWin.toFront(); for (int i = 0 ; i < stepDuration.length ; i++) { if (stepDuration[i].labelConfigKey.equals(stepLabelConfigKey)) { progressVisualizer.setCurrentStep(i); @@ -128,6 +127,9 @@ public class SplashWindow { //show progress double percentage = 100.0 * elapsedDuration / totalDuration; tempL.setText("<html>" + percentage + "<br>" + stepDuration[currentStep].labelConfigKey + "</html>"); + + //ensure visibility of window + myWin.toFront(); } /** diff --git a/rails/util/RunGame.java b/rails/util/RunGame.java index 55e6fb5..461035a 100644 --- a/rails/util/RunGame.java +++ b/rails/util/RunGame.java @@ -39,14 +39,7 @@ public class RunGame { static void loadGameOnEventQueue(final String[] args) { try { - java.awt.EventQueue.invokeAndWait( - new Runnable() - { - public void run() { - loadGame(args); - } - } - ); + loadGame(args); } catch (Exception e) { System.err.println("Cannot load game: "+e.getMessage()); e.printStackTrace(System.err); commit 8d63d4c97bf2847f79af079da18eb34e3a841656 Author: Frederick Weld <fre...@gm...> Date: Thu Feb 16 16:00:06 2012 +0100 Added continuous visualization of init progress Before, progress was updated upon the completion of a init step. Now, progress is updated continuously based on a heuristic that gets the expected duration of the init steps as an input parameter. diff --git a/rails/ui/swing/SplashWindow.java b/rails/ui/swing/SplashWindow.java index 439fba1..406af02 100644 --- a/rails/ui/swing/SplashWindow.java +++ b/rails/ui/swing/SplashWindow.java @@ -1,6 +1,3 @@ -/** - * - */ package rails.ui.swing; import java.awt.Rectangle; @@ -21,6 +18,15 @@ import javax.swing.SwingUtilities; */ public class SplashWindow { + /** + * in millisecs + */ + private static long PROGRESS_UPDATE_INTERVAL = 100; + + private static String DUMMY_STEP_BEFORE_START = "-1"; + private static String DUMMY_STEP_START = "0"; + private static String DUMMY_STEP_END = "inf"; + public static String STEP_LOAD_GAME = "1"; public static String STEP_INIT_UI = "2"; public static String STEP_STOCK_CHART = "3"; @@ -36,15 +42,16 @@ public class SplashWindow { public static String STEP_INIT_LOADED_GAME = "10"; private static class StepDuration { - int expectedDurationInMillis; + long expectedDurationInMillis; String labelConfigKey; - StepDuration(int expDurationInMillis,String labelConfigKey) { - this.expectedDurationInMillis = expDurationInMillis; + StepDuration(int expectedDurationInMillis,String labelConfigKey) { + this.expectedDurationInMillis = expectedDurationInMillis; this.labelConfigKey = labelConfigKey; } } private static StepDuration[] stepDuration = { - new StepDuration ( 0, "Start"), // used to facilitate array border handling + new StepDuration ( 0, DUMMY_STEP_BEFORE_START), // used to facilitate array border handling + new StepDuration ( 0, DUMMY_STEP_START), // used to facilitate array border handling new StepDuration ( 6000, STEP_LOAD_GAME ), new StepDuration ( 500, STEP_INIT_UI ), new StepDuration ( 230, STEP_STOCK_CHART ), @@ -58,19 +65,22 @@ public class SplashWindow { new StepDuration ( 1200, STEP_CONFIG_WINDOW ), new StepDuration ( 200, STEP_INIT_SOUND ), new StepDuration ( 1000, STEP_INIT_LOADED_GAME ), - ... [truncated message content] |
From: Stefan F. <ste...@us...> - 2012-02-17 13:44:40
|
data/profiles/ORDocking.profile | 3 + data/profiles/default.profile | 61 ---------------------- data/profiles/default.profiles | 7 ++ data/profiles/prettyUI.profile | 9 +++ data/profiles/root.profile | 62 ++++++++++++++++++++++ data/profiles/test.profile | 110 ---------------------------------------- rails/common/parser/Config.java | 15 ++++- 7 files changed, 93 insertions(+), 174 deletions(-) New commits: commit 0e0a46edc14d03cf2a07bd12cde541f93af47a12 Author: Stefan Frey <ste...@we...> Date: Fri Feb 17 14:43:51 2012 +0100 added new profiles and a 3-tier structure for the configuration profiles diff --git a/data/profiles/ORDocking.profile b/data/profiles/ORDocking.profile new file mode 100644 index 0000000..e5f8d80 --- /dev/null +++ b/data/profiles/ORDocking.profile @@ -0,0 +1,3 @@ +### ORDocking profile +### activates the docking framework +or.window.dockablePanels=yes diff --git a/data/profiles/default.profile b/data/profiles/default.profile index b4e4cb9..03d7a58 100644 --- a/data/profiles/default.profile +++ b/data/profiles/default.profile @@ -1,59 +1,2 @@ -### Panel General -locale=en_US -default_game=1830 -default_players= -local.player.names= - -### Panel Save -save.directory= -save.filename.date_time_pattern=yyyyMMdd_HHmm -save.filename.date_time_zone=UTC -save.filename.suffix=NEXT_PLAYER -save.filename.extension=rails -save.recovery.active=no -save.recovery.filepath=18xx_autosave.rails - -### Panel Font -font.ui.scale=1 -font.ui.name= -font.ui.style=bold - -### Panel Map -map.autoscroll=yes -map.defaultZoomFitOption=none -map.displayCurrentRoutes=yes -map.highlightHexes=yes -map.image.display=no -map.zoomstep=10 - -### Panel Windows -or.window.dockablePanels=no -report.window.type=dynamic -report.window.open=yes -report.window.editable=no -stockchart.window.open=yes - -### Panel Format -money_format= -or.number_format=composite - -### Panel Appearance -button.iconText=text and icon -button.iconSize=small -button.iconPosition=left -gridPanel.tableBorders=enabled -route.colour.1=00ffff -route.colour.2=ffc0cb -route.colour.3=ffa500 -route.colour.4=808080 - -### Panel Log -#report.directory=log -#report.filename.date_time_pattern=yyyyMMdd -#report.filename.extension=log - -### Panel Music -sound.backgroundMusic=disabled - -### Panel SFX -sound.sfx=disabled +### Default profile currently is identical to root.profile +### so no change here \ No newline at end of file diff --git a/data/profiles/default.profiles b/data/profiles/default.profiles index 66511a9..9cedd38 100644 --- a/data/profiles/default.profiles +++ b/data/profiles/default.profiles @@ -1,2 +1,7 @@ -default=data/profiles/default.profile +### This is the list of (predefined) profiles and their file locations +### A dot (".") before the profilename prevents displaying those to the user selection +.root=data/profiles/root.profile .test=data/profiles/test.profile +default=data/profiles/default.profile +prettyUI=data/profiles/prettyUI.profile +ORDocking=data/profiles/ORDocking.profile diff --git a/data/profiles/prettyUI.profile b/data/profiles/prettyUI.profile new file mode 100644 index 0000000..a537864 --- /dev/null +++ b/data/profiles/prettyUI.profile @@ -0,0 +1,9 @@ +### prettyUI profile +### activates the new UI options of Frederick +button.iconPosition=left +button.iconText=text and icon +button.iconSize=small +gridPanel.tableBorders=enabled +map.image.display=yes +map.displayCurrentRoutes=yes +map.highlightHexes=yes diff --git a/data/profiles/root.profile b/data/profiles/root.profile new file mode 100644 index 0000000..a553e4c --- /dev/null +++ b/data/profiles/root.profile @@ -0,0 +1,62 @@ +### Root profile defines the settings used for all (predefined) default profiles +### All others define only deviations + +### Panel General +locale=en_US +default_game=1830 +default_players= +local.player.names= + +### Panel Save +save.directory= +save.filename.date_time_pattern=yyyyMMdd_HHmm +save.filename.date_time_zone=UTC +save.filename.suffix=NEXT_PLAYER +save.filename.extension=rails +save.recovery.active=no +save.recovery.filepath=18xx_autosave.rails + +### Panel Font +font.ui.scale=1 +font.ui.name= +font.ui.style=bold + +### Panel Map +map.autoscroll=yes +map.defaultZoomFitOption=none +map.displayCurrentRoutes=no +map.highlightHexes=no +map.image.display=no +map.zoomstep=10 + +### Panel Windows +or.window.dockablePanels=no +report.window.type=dynamic +report.window.open=yes +report.window.editable=no +stockchart.window.open=yes + +### Panel Format +money_format= +or.number_format=composite + +### Panel Appearance +button.iconText=only text +button.iconSize=small +button.iconPosition=left +gridPanel.tableBorder=disabled +route.colour.1=00ffff +route.colour.2=ffc0cb +route.colour.3=ffa500 +route.colour.4=808080 + +### Panel Log +#report.directory=log +#report.filename.date_time_pattern=yyyyMMdd +#report.filename.extension=log + +### Panel Music +sound.backgroundMusic=disabled + +### Panel SFX +sound.sfx=disabled diff --git a/data/profiles/test.profile b/data/profiles/test.profile index 2b39565..897ee6d 100644 --- a/data/profiles/test.profile +++ b/data/profiles/test.profile @@ -3,123 +3,13 @@ # Those are the settings used for automated testing # ######################################################################## -# -# Preferred tile format. -# The only currently supported format is svg. Anything else is ignored. -#tile.format_preference=svg -# Root directory for the tile images (just above directory 'tiles'). -# Not required if tile images are provided included in the Rails jar file. -#tile.root_directory= - -### Locale #### -# Language: two-letter ISO code (lower case; default is en=English). -# Country: two-letter ISO code (upper case; specifies country -# (implying a language variant of that country; no default). -# Locale: concatenation of the above. If present, overrides any of the above. -# Examples: en, en_US, en_UK, fr_FR, fr_CA. locale=te_ST -#language= -#country= -### Money display ### -# Each game has a specific format for monetary amounts (e.g. $100, 100M). # An overriding format can be specified here, but then applies to all games. # The @ character must be present and is replaced by the amount. # Example: �@ to specify a pound sign prefix: �100. money_format=@ -### Save file directory -# If the below entry exists, is not empty, and specifies an existing -# directory, that directory is used as a starting point for any -# file choosing action for the Save and Load commands. -# The path may be relative or absolute. save.directory=test/data -# The default Save filename is <gamename>_<datetimepattern>.<extension> -# This name will be initially proposed. -# As soon as that proposal has been changed once in a Save action, -# the last used name is always proposed in stead. -# The default date/time pattern is yyyyMMdd_HHmm -# The pattern codes are as defined in the Java class -# SimpleDateFormat (just Google that name to find the codes). -#save.filename.date_time_pattern=yyyyMMdd_HHmm -# The default timezone is local time. -# A specific timezone (such as UTC) can be set; the value must be a Java timezone ID -#save.filename.date_time_zone=UTC -# Optionally, a suffix (e.g. player name) can be added after the time stamp -# with a preceding underscore (which is automatically added) -# The special value NEXT_PLAYER puts the next moving player name into this spot. -#save.filename.suffix=NEXT_PLAYER -# The default extension is .rails -save.filename.extension=rails - -### Game report directory -# If the below entry exists, is not empty, and specifies an existing -# directory, a copy of the Game Report (as displayed in the Report Window) -# will be saved there. The path may be relative or absolute. -#report.directory=log -# The default file name includes the game name and the game start time: -# 18XX_yyyymmdd_hhmm.txt where 18XX is the game name. -# You can specify different values for the date/time part and teh extension here. -# The date/time pattern must be as defined in the Java SimpleDateFormat class. -#report.filename.date_time_pattern=yyyyMMdd report.filename.extension=report failed.filename.extension=failed - -### Windows -## Report window visibility -# By default the report window is hidden when starting or loading a game. -# This property allows to open it automatically. -# Valid values are yes and no (default). -#report.window.open=yes -## Report window editability -# Specify if the report window is editable, so you can add your own comments. -# Valid values are yes and no (default). -#report.window.editable=yes -## Stock Chart window visibility -# By default the stock chart hides at the end of an SR. -# By specifying "yes" here, the window will not be automatically hidden any more -#stockchart.window.open=yes - -### Player info -## Default players -# Comma-separated list of player names. -# Useful for game testing purposes. -#default_players=Alice,Bob,Charlie -# -## Local player name -# Useful for distributed usage (Internet, PBEM, cloud storage/dropbox) -# Required for "request turn" facility with cloud storage (dropbox) -#local.player.name=Alice - -### Default game -# Name of game selected in the game selection window. -# Useful for game testing purposes. -#default_game=1830 - -### Various options -# Show simple (ORx) or composite (ORx.x) OR number. -# Valid values: "simple" and "composite" (default) -#or.number_format=simple - -####################### Log4J properties ############################## -# For information on how to customise log4j logging, see for instance -# http://www.vipan.com/htdocs/log4jhelp.html -# It's a bit outdated: Category is now named Logger, -# and Priority is now named Level. -# But it's the best intro I know on how to configure Appenders. (EV) -####################################################################### -# Set root logger level to DEBUG and use appender F(file) -#log4j.debug=true -log4j.rootLogger=DEBUG, F - -# Define the Log file appender -log4j.appender.F=org.apache.log4j.FileAppender - -# Log file properties -log4j.appender.F.File=test/test.log -log4j.appender.F.append=false - -# Log file layout -log4j.appender.F.layout=org.apache.log4j.PatternLayout -log4j.appender.F.layout.ConversionPattern=%-5p %m%n -################## End of Log4J properties ############################# \ No newline at end of file diff --git a/rails/common/parser/Config.java b/rails/common/parser/Config.java index 107e888..296fcb3 100644 --- a/rails/common/parser/Config.java +++ b/rails/common/parser/Config.java @@ -55,6 +55,7 @@ public final class Config { private static Properties userProfiles = new Properties(); private static boolean profilesLoaded = false; private static String DEFAULT_PROFILE_SELECTION = "default"; // can be overwritten + private static final String ROOT_PROFILE_SELECTION = ".root"; // used for the 3-tier structure: ROOT-DEFAULT-USER private static final String TEST_PROFILE_SELECTION = ".test"; // used as default profile for integration tests private static final String STANDARD_PROFILE_SELECTION = "user"; private static final String DEFAULTPROFILE_PROPERTY = "default.profile"; @@ -65,7 +66,8 @@ public final class Config { private static boolean legacyConfigFile; /** properties storage. */ - private static Properties defaultProperties = new Properties(); + private static Properties rootProperties = null; + private static Properties defaultProperties = null; private static Properties userProperties = new Properties(); private static boolean propertiesLoaded = false; @@ -191,6 +193,7 @@ public final class Config { } if (userProperties.containsKey(key)) return userProperties.getProperty(key).trim(); if (defaultProperties.containsKey(key)) return defaultProperties.getProperty(key).trim(); + if (rootProperties.containsKey(key)) return rootProperties.getProperty(key).trim(); return defaultValue; } @@ -497,9 +500,8 @@ public final class Config { * if not defined or loadable, creates a default user profile */ private static void loadProfile(String userProfile) { - // reset properties + // reset user properties userProperties = new Properties(); - defaultProperties = new Properties(); String userConfigFile = null; if (Util.hasValue(userProfile)) { @@ -524,7 +526,7 @@ public final class Config { /** * loads the associated default profile - * if none is defined, uses standard default profile + * the default profile is defined as delta to the root profile */ private static void loadDefaultProfile() { String defaultConfigFile = null; @@ -536,6 +538,11 @@ public final class Config { defaultConfigFile = defaultProfiles.getProperty(DEFAULT_PROFILE_SELECTION); userProperties.setProperty(DEFAULTPROFILE_PROPERTY, DEFAULT_PROFILE_SELECTION); } + if (rootProperties == null) { + rootProperties = new Properties(); + loadPropertyFile(rootProperties, defaultProfiles.getProperty(ROOT_PROFILE_SELECTION), true); + } + defaultProperties = new Properties(); loadPropertyFile(defaultProperties, defaultConfigFile, true); } |
From: Erik V. <ev...@us...> - 2012-02-16 15:35:33
|
rails/game/GameManager.java | 7 rails/game/GameManagerI.java | 4 rails/game/specific/_1835/StartRound_1835.java | 16 - test/data/test/1835_NatSingleShare.report | 339 +++++++++++++++++++--- test/data/test/1835_SwapPresForDoubleShare.report | 339 +++++++++++++++++++--- 5 files changed, 629 insertions(+), 76 deletions(-) New commits: commit f311be5af549febd7e4d81cefaf2097c0d07c7e6 Merge: 190aa16 366e5cf Author: Erik Vos <eri...@xs...> Date: Thu Feb 16 16:35:19 2012 +0100 Merge branch 'master' of ssh://rails.git.sourceforge.net/gitroot/rails/rails commit 190aa165b93f5a1ab9b4454d9906e6ddb1979e99 Author: Erik Vos <eri...@xs...> Date: Thu Feb 16 16:32:58 2012 +0100 Fixed start round number management for 1835 JUnit testing. The start round number has been moved from StartRound_1835 to GameManager and is now a generic feature, though it is only used yet in 1835. It is no longer Java-static. The same applies to the turn number, which stayed in StartRound_1835. The NatDoubleShare test case now works. The NatSingleShare and SwapPresForDoubleShare cases were wrong and have been replaced. diff --git a/rails/game/GameManager.java b/rails/game/GameManager.java index f35ed6a..c147924 100644 --- a/rails/game/GameManager.java +++ b/rails/game/GameManager.java @@ -110,6 +110,9 @@ public class GameManager implements ConfigurableComponentI, GameManagerI { protected State currentRound = new State("CurrentRound", Round.class); protected RoundI interruptedRound = null; + /** Number of the current start round. Currently only used in some 1835 variants. */ + protected IntegerState startRoundNumber = new IntegerState ("StartRoundNumber", 0); + protected IntegerState srNumber = new IntegerState ("SRNumber"); protected IntegerState absoluteORNumber = @@ -721,6 +724,7 @@ public class GameManager implements ConfigurableComponentI, GameManagerI { System.exit(1); } StartRound startRound = createRound (startRoundClass); + startRoundNumber.add(1); startRound.start (); } @@ -805,6 +809,9 @@ public class GameManager implements ConfigurableComponentI, GameManagerI { return numOfORs.getText(); } + public int getStartRoundNumber () { + return startRoundNumber.intValue(); + } /* (non-Javadoc) * @see rails.game.GameManagerI#getSRNumber() */ diff --git a/rails/game/GameManagerI.java b/rails/game/GameManagerI.java index 06b404c..92f2a88 100644 --- a/rails/game/GameManagerI.java +++ b/rails/game/GameManagerI.java @@ -41,6 +41,8 @@ public interface GameManagerI extends MoveableHolder, ConfigurableComponentI { public int getRelativeORNumber(); public int getAbsoluteORNumber (); + public int getStartRoundNumber (); + public abstract int getSRNumber(); public abstract void startShareSellingRound(Player player, int cashToRaise, @@ -101,7 +103,7 @@ public interface GameManagerI extends MoveableHolder, ConfigurableComponentI { public abstract RoundI getCurrentRound(); public abstract ModelObject getCurrentRoundModel(); - + public abstract ModelObject getCurrentPlayerModel(); /** diff --git a/rails/game/specific/_1835/StartRound_1835.java b/rails/game/specific/_1835/StartRound_1835.java index 0768fce..f0f6b98 100644 --- a/rails/game/specific/_1835/StartRound_1835.java +++ b/rails/game/specific/_1835/StartRound_1835.java @@ -16,10 +16,7 @@ import rails.game.state.IntegerState; public class StartRound_1835 extends StartRound { /* To control the player sequence in the Clemens and Snake variants */ - private static IntegerState turn = new IntegerState("TurnNumber", 0); - - private static IntegerState startRoundNumber = - new IntegerState("StartRoundNumber", 0); + private IntegerState turn = new IntegerState("TurnNumber", 0); /* Additional variants */ public static final String CLEMENS_VARIANT = "Clemens"; @@ -41,7 +38,6 @@ public class StartRound_1835 extends StartRound { @Override public void start() { super.start(); - startRoundNumber.add(1); if (variant.equalsIgnoreCase(CLEMENS_VARIANT)) { setCurrentPlayerIndex (numPlayers-1); @@ -173,7 +169,7 @@ public class StartRound_1835 extends StartRound { /* Select the player that has the turn. */ - if (startRoundNumber.intValue() == 1) { + if (gameManager.getStartRoundNumber() == 1) { /* * Some variants have a reversed player order in the first or second * cycle of the first round (a cycle spans one turn of all players). @@ -203,9 +199,11 @@ public class StartRound_1835 extends StartRound { setCurrentPlayerIndex(newIndex); Player newPlayer = getCurrentPlayer(); log.debug("Game turn has moved from " + oldPlayer.getName() - + " to " + newPlayer.getName() + " [startRound=" - + startRoundNumber + " cycle=" + cycleNumber + " turn=" - + turnNumber + " newIndex=" + newIndex + "]"); + + " to " + newPlayer.getName() + + " [startRound=" + gameManager.getStartRoundNumber() + + " cycle=" + cycleNumber + + " turn=" + turnNumber + + " newIndex=" + newIndex + "]"); } else { diff --git a/test/data/test/1835_NatSingleShare.report b/test/data/test/1835_NatSingleShare.report index f1eadbb..a7d01c4 100644 --- a/test/data/test/1835_NatSingleShare.report +++ b/test/data/test/1835_NatSingleShare.report @@ -10,43 +10,43 @@ StartOfInitialRound HasPriority,T1 BuysItemFor,T3,M5,80 FloatsWithCash,M5,80 -BuysItemFor,T1,M1,80 +BuysItemFor,T2,M1,80 FloatsWithCash,M1,80 -BuysItemFor,T2,M3,80 +BuysItemFor,T1,M3,80 FloatsWithCash,M3,80 -BuysItemFor,T3,M6,80 +BuysItemFor,T1,M6,80 FloatsWithCash,M6,80 -BuysItemFor,T1,M2,170 +BuysItemFor,T2,M2,170 FloatsWithCash,M2,170 -BuysItemFor,T2,PRES_CERT_NAME,BY,20,184 -BuysItemFor,T3,LD,190 -ALSO_GETS,T3,PRES_CERT_NAME,SX,20 -BuysItemFor,T1,HB,160 -BuysItemFor,T2,OBB,120 +BuysItemFor,T3,PRES_CERT_NAME,BY,20,184 +BuysItemFor,T1,LD,190 +ALSO_GETS,T1,PRES_CERT_NAME,SX,20 +BuysItemFor,T2,HB,160 +BuysItemFor,T3,OBB,120 +ALSO_GETS,T3,CERT_NAME,BY,10 +BuysItemFor,T1,BB,130 +BuysItemFor,T2,NF,100 ALSO_GETS,T2,CERT_NAME,BY,10 -BuysItemFor,T3,BB,130 -BuysItemFor,T1,NF,100 -ALSO_GETS,T1,CERT_NAME,BY,10 -BuysItemFor,T2,M4,160 +BuysItemFor,T3,M4,160 FloatsWithCash,M4,160 -CannotBuyAnything,T3 CannotBuyAnything,T1 CannotBuyAnything,T2 +CannotBuyAnything,T3 Has,M1,80 Has,M2,170 Has,M3,80 Has,M4,160 Has,M5,80 Has,M6,80 -Has,T1,90 -Has,T2,56 -Has,T3,120 +Has,T1,120 +Has,T2,90 +Has,T3,56 START_OR,0.0 -ReceivesFor,T1,5,NF -ReceivesFor,T2,10,OBB -ReceivesFor,T3,20,LD -ReceivesFor,T3,25,BB -ReceivesFor,T1,30,HB +ReceivesFor,T2,5,NF +ReceivesFor,T3,10,OBB +ReceivesFor,T1,20,LD +ReceivesFor,T1,25,BB +ReceivesFor,T2,30,HB ShortORExecuted Has,M1,80 Has,M2,170 @@ -54,13 +54,14 @@ Has,M3,80 Has,M4,160 Has,M5,80 Has,M6,80 -Has,T1,125 -Has,T2,66 -Has,T3,165 +Has,T1,165 +Has,T2,125 +Has,T3,66 StartOfInitialRound -HasPriority,T3 -BuysItemFor,T3,PfB,150 -ALSO_GETS,T3,CERT_NAME,BY,10 +HasPriority,T1 +CannotBuyAnything,T3 +BuysItemFor,T1,PfB,150 +ALSO_GETS,T1,CERT_NAME,BY,10 FloatsWithCash,BY,460 Has,M1,80 Has,M2,170 @@ -69,9 +70,281 @@ Has,M4,160 Has,M5,80 Has,M6,80 Has,BY,460 -Has,T1,125 -Has,T2,66 -Has,T3,15 +Has,T1,15 +Has,T2,125 +Has,T3,66 StartStockRound,1 -HasPriority,T1 -LoadInterrupted,13 +HasPriority,T2 +BUY_SHARE_LOG,T2,10,BY,IPO,92 +PriceIsPaidTo,92,BY +PASSES,T3 +PASSES,T1 +PASSES,T2 + +END_SR,1 +Has,M1,80 +Has,M2,170 +Has,M3,80 +Has,M4,160 +Has,M5,80 +Has,M6,80 +Has,BY,552 +Has,T1,15 +Has,T2,33 +Has,T3,66 +START_OR,1.1 +ReceivesFor,T2,5,NF +ReceivesFor,T3,10,OBB +ReceivesFor,T1,15,PfB +ReceivesFor,T1,20,LD +ReceivesFor,T1,25,BB +ReceivesFor,T2,30,HB + +CompanyOperates,M1,T2 +LaysTileAt,M1,201,H2,SW +CompanyDoesNotPayDividend,M1 +BuysTrain,M1,2,IPO,80 +FirstTrainBought,2 + +CompanyOperates,M2,T2 +LaysTileAt,M2,8,E17,NW +CompanyDoesNotPayDividend,M2 +BuysTrain,M2,2,IPO,80 + +CompanyOperates,M3,T1 +LaysTileAt,M3,6,F14,NW +CompanyDoesNotPayDividend,M3 +BuysTrain,M3,2,IPO,80 + +CompanyOperates,M4,T3 +LaysTileAt,M4,57,G5,SW +CompanyDoesNotPayDividend,M4 +BuysTrain,M4,2,IPO,80 +BuysTrain,M4,2,IPO,80 + +CompanyOperates,M5,T3 +LaysTileAt,M5,8,D18,NE +CompanyDoesNotPayDividend,M5 +BuysTrain,M5,2,IPO,80 + +CompanyOperates,M6,T1 +LaysTileAt,M6,9,B10,NW +CompanyDoesNotPayDividend,M6 +BuysTrain,M6,2,IPO,80 + +CompanyOperates,BY,T3 +LaysTileAt,BY,202,O15,E +LaysTileAt,BY,8,O13,NW +CompanyDoesNotPayDividend,BY +PRICE_MOVES_LOG,BY,92,C3,86,B3 +BuysTrain,BY,2,IPO,80 +BuysTrain,BY,2,IPO,80 +All 2-trains are sold out, 2+2-trains now available +BuysTrain,BY,2+2,IPO,120 +FirstTrainBought,2+2 + +EndOfOperatingRound,1.1 +ORWorthIncrease,T1,1.1,54 +ORWorthIncrease,T2,1.1,23 +ORWorthIncrease,T3,1.1,-8 +Has,M1,0 +Has,M2,90 +Has,M3,0 +Has,M4,0 +Has,M5,0 +Has,M6,0 +Has,BY,272 +Has,T1,75 +Has,T2,68 +Has,T3,76 +StartStockRound,2 +HasPriority,T3 +PASSES,T3 +PASSES,T1 +PASSES,T2 + +END_SR,2 +Has,M1,0 +Has,M2,90 +Has,M3,0 +Has,M4,0 +Has,M5,0 +Has,M6,0 +Has,BY,272 +Has,T1,75 +Has,T2,68 +Has,T3,76 +START_OR,2.1 +ReceivesFor,T2,5,NF +ReceivesFor,T3,10,OBB +ReceivesFor,T1,15,PfB +ReceivesFor,T1,20,LD +ReceivesFor,T1,25,BB +ReceivesFor,T2,30,HB + +CompanyOperates,M1,T2 +LaysTileAt,M1,9,J2,NW +CompanyRevenue,M1,40 +CompanySplits,M1,40 +M1 receives 20 +Payout,T2,20,1,100 + +CompanyOperates,M2,T2 +LaysTileAt,M2,8,D16,SE +CompanyRevenue,M2,0 +CompanyDoesNotPayDividend,M2 + +CompanyOperates,M3,T1 +LaysTileAt,M3,4,G15,NW +CompanyRevenue,M3,40 +CompanySplits,M3,40 +M3 receives 20 +Payout,T1,20,1,100 + +CompanyOperates,M4,T3 +LaysTileAt,M4,2,H4,NE +CompanyRevenue,M4,30 +CompanySplits,M4,30 +M4 receives 15 +Payout,T3,15,1,100 + +CompanyOperates,M5,T3 +LaysTileAt,M5,8,C19,E +CompanyRevenue,M5,50 +CompanySplits,M5,50 +M5 receives 25 +Payout,T3,25,1,100 + +CompanyOperates,M6,T1 +LaysTileAt,M6,6,A11,NW +CompanyRevenue,M6,60 +CompanySplits,M6,60 +M6 receives 30 +Payout,T1,30,1,100 + +CompanyOperates,BY,T3 +LaysTileAt,BY,8,N16,SW +LaysTileAt,BY,4,M15,NW +LaysTileAt,BY,6,N12,NW +LAYS_TOKEN_ON,BY,L14,60 +CompanyRevenue,BY,130 +CompanyPaysOutFull,BY,130 +Payout,T1,13,1,10 +Payout,T2,26,2,10 +Payout,T3,39,3,10 +PRICE_MOVES_LOG,BY,86,B3,92,C3 + +EndOfOperatingRound,2.1 +ORWorthIncrease,T1,2.1,129 +ORWorthIncrease,T2,2.1,93 +ORWorthIncrease,T3,2.1,107 +Has,M1,20 +Has,M2,90 +Has,M3,20 +Has,M4,15 +Has,M5,25 +Has,M6,30 +Has,BY,212 +Has,T1,198 +Has,T2,149 +Has,T3,165 +StartStockRound,3 +HasPriority,T3 +BUY_SHARE_LOG,T3,10,BY,IPO,92 +PriceIsPaidTo,92,BY +BUY_SHARE_LOG,T1,10,BY,IPO,92 +PriceIsPaidTo,92,BY +BUY_SHARE_LOG,T2,10,BY,IPO,92 +PriceIsPaidTo,92,BY +PASSES,T3 +BUY_SHARE_LOG,T1,10,BY,IPO,92 +PriceIsPaidTo,92,BY +SELL_SHARE_LOG,T1,10,BY,92 +PRICE_MOVES_LOG,BY,92,C3,88,C4 +PASSES,T2 +PASSES,T3 +SELL_SHARE_LOG,T1,10,BY,88 +PRICE_MOVES_LOG,BY,88,C4,86,C5 +BUY_SHARE_LOG,T1,10,SX,IPO,88 +PASSES,T2 +PASSES,T3 +SELL_SHARE_LOG,T1,10,BY,86 +PRICE_MOVES_LOG,BY,86,C5,82,C6 +BUY_SHARE_LOG,T1,10,SX,IPO,88 +PASSES,T2 +PASSES,T3 +BUY_SHARE_LOG,T1,10,SX,IPO,88 +FloatsWithCash,SX,440 +PASSES,T2 +PASSES,T3 +PASSES,T1 + +END_SR,3 +Has,M1,20 +Has,M2,90 +Has,M3,20 +Has,M4,15 +Has,M5,25 +Has,M6,30 +Has,BY,580 +Has,SX,440 +Has,T1,16 +Has,T2,57 +Has,T3,73 +START_OR,3.1 +ReceivesFor,T2,5,NF +ReceivesFor,T3,10,OBB +ReceivesFor,T1,15,PfB +ReceivesFor,T1,20,LD +ReceivesFor,T1,25,BB +ReceivesFor,T2,30,HB + +CompanyOperates,M1,T2 +LaysTileAt,M1,4,K3,NW +CompanyRevenue,M1,40 +CompanySplits,M1,40 +M1 receives 20 +Payout,T2,20,1,100 + +CompanyOperates,M2,T2 +LaysTileAtFor,M2,8,D14,NW,50 +CompanyRevenue,M2,70 +CompanySplits,M2,70 +M2 receives 35 +Payout,T2,35,1,100 + +CompanyOperates,M3,T1 +LaysTileAt,M3,57,H16,NW +CompanyRevenue,M3,40 +CompanySplits,M3,40 +M3 receives 20 +Payout,T1,20,1,100 + +CompanyOperates,M4,T3 +LaysTileAt,M4,58,F6,E +CompanyRevenue,M4,60 +CompanySplits,M4,60 +M4 receives 30 +Payout,T3,30,1,100 + +CompanyOperates,M5,T3 +CompanyRevenue,M5,50 +CompanySplits,M5,50 +M5 receives 25 +Payout,T3,25,1,100 + +CompanyOperates,M6,T1 +LaysTileAt,M6,58,B12,SW +CompanyRevenue,M6,60 +CompanySplits,M6,60 +M6 receives 30 +Payout,T1,30,1,100 + +CompanyOperates,SX,T1 +LaysTileAt,SX,56,I17,NE +LaysTileAt,SX,202,H20,W +CompanyDoesNotPayDividend,SX +PRICE_MOVES_LOG,SX,88,C4,84,B4 + +CompanyOperates,BY,T3 +LoadInterrupted,121 diff --git a/test/data/test/1835_SwapPresForDoubleShare.report b/test/data/test/1835_SwapPresForDoubleShare.report index f1eadbb..a7d01c4 100644 --- a/test/data/test/1835_SwapPresForDoubleShare.report +++ b/test/data/test/1835_SwapPresForDoubleShare.report @@ -10,43 +10,43 @@ StartOfInitialRound HasPriority,T1 BuysItemFor,T3,M5,80 FloatsWithCash,M5,80 -BuysItemFor,T1,M1,80 +BuysItemFor,T2,M1,80 FloatsWithCash,M1,80 -BuysItemFor,T2,M3,80 +BuysItemFor,T1,M3,80 FloatsWithCash,M3,80 -BuysItemFor,T3,M6,80 +BuysItemFor,T1,M6,80 FloatsWithCash,M6,80 -BuysItemFor,T1,M2,170 +BuysItemFor,T2,M2,170 FloatsWithCash,M2,170 -BuysItemFor,T2,PRES_CERT_NAME,BY,20,184 -BuysItemFor,T3,LD,190 -ALSO_GETS,T3,PRES_CERT_NAME,SX,20 -BuysItemFor,T1,HB,160 -BuysItemFor,T2,OBB,120 +BuysItemFor,T3,PRES_CERT_NAME,BY,20,184 +BuysItemFor,T1,LD,190 +ALSO_GETS,T1,PRES_CERT_NAME,SX,20 +BuysItemFor,T2,HB,160 +BuysItemFor,T3,OBB,120 +ALSO_GETS,T3,CERT_NAME,BY,10 +BuysItemFor,T1,BB,130 +BuysItemFor,T2,NF,100 ALSO_GETS,T2,CERT_NAME,BY,10 -BuysItemFor,T3,BB,130 -BuysItemFor,T1,NF,100 -ALSO_GETS,T1,CERT_NAME,BY,10 -BuysItemFor,T2,M4,160 +BuysItemFor,T3,M4,160 FloatsWithCash,M4,160 -CannotBuyAnything,T3 CannotBuyAnything,T1 CannotBuyAnything,T2 +CannotBuyAnything,T3 Has,M1,80 Has,M2,170 Has,M3,80 Has,M4,160 Has,M5,80 Has,M6,80 -Has,T1,90 -Has,T2,56 -Has,T3,120 +Has,T1,120 +Has,T2,90 +Has,T3,56 START_OR,0.0 -ReceivesFor,T1,5,NF -ReceivesFor,T2,10,OBB -ReceivesFor,T3,20,LD -ReceivesFor,T3,25,BB -ReceivesFor,T1,30,HB +ReceivesFor,T2,5,NF +ReceivesFor,T3,10,OBB +ReceivesFor,T1,20,LD +ReceivesFor,T1,25,BB +ReceivesFor,T2,30,HB ShortORExecuted Has,M1,80 Has,M2,170 @@ -54,13 +54,14 @@ Has,M3,80 Has,M4,160 Has,M5,80 Has,M6,80 -Has,T1,125 -Has,T2,66 -Has,T3,165 +Has,T1,165 +Has,T2,125 +Has,T3,66 StartOfInitialRound -HasPriority,T3 -BuysItemFor,T3,PfB,150 -ALSO_GETS,T3,CERT_NAME,BY,10 +HasPriority,T1 +CannotBuyAnything,T3 +BuysItemFor,T1,PfB,150 +ALSO_GETS,T1,CERT_NAME,BY,10 FloatsWithCash,BY,460 Has,M1,80 Has,M2,170 @@ -69,9 +70,281 @@ Has,M4,160 Has,M5,80 Has,M6,80 Has,BY,460 -Has,T1,125 -Has,T2,66 -Has,T3,15 +Has,T1,15 +Has,T2,125 +Has,T3,66 StartStockRound,1 -HasPriority,T1 -LoadInterrupted,13 +HasPriority,T2 +BUY_SHARE_LOG,T2,10,BY,IPO,92 +PriceIsPaidTo,92,BY +PASSES,T3 +PASSES,T1 +PASSES,T2 + +END_SR,1 +Has,M1,80 +Has,M2,170 +Has,M3,80 +Has,M4,160 +Has,M5,80 +Has,M6,80 +Has,BY,552 +Has,T1,15 +Has,T2,33 +Has,T3,66 +START_OR,1.1 +ReceivesFor,T2,5,NF +ReceivesFor,T3,10,OBB +ReceivesFor,T1,15,PfB +ReceivesFor,T1,20,LD +ReceivesFor,T1,25,BB +ReceivesFor,T2,30,HB + +CompanyOperates,M1,T2 +LaysTileAt,M1,201,H2,SW +CompanyDoesNotPayDividend,M1 +BuysTrain,M1,2,IPO,80 +FirstTrainBought,2 + +CompanyOperates,M2,T2 +LaysTileAt,M2,8,E17,NW +CompanyDoesNotPayDividend,M2 +BuysTrain,M2,2,IPO,80 + +CompanyOperates,M3,T1 +LaysTileAt,M3,6,F14,NW +CompanyDoesNotPayDividend,M3 +BuysTrain,M3,2,IPO,80 + +CompanyOperates,M4,T3 +LaysTileAt,M4,57,G5,SW +CompanyDoesNotPayDividend,M4 +BuysTrain,M4,2,IPO,80 +BuysTrain,M4,2,IPO,80 + +CompanyOperates,M5,T3 +LaysTileAt,M5,8,D18,NE +CompanyDoesNotPayDividend,M5 +BuysTrain,M5,2,IPO,80 + +CompanyOperates,M6,T1 +LaysTileAt,M6,9,B10,NW +CompanyDoesNotPayDividend,M6 +BuysTrain,M6,2,IPO,80 + +CompanyOperates,BY,T3 +LaysTileAt,BY,202,O15,E +LaysTileAt,BY,8,O13,NW +CompanyDoesNotPayDividend,BY +PRICE_MOVES_LOG,BY,92,C3,86,B3 +BuysTrain,BY,2,IPO,80 +BuysTrain,BY,2,IPO,80 +All 2-trains are sold out, 2+2-trains now available +BuysTrain,BY,2+2,IPO,120 +FirstTrainBought,2+2 + +EndOfOperatingRound,1.1 +ORWorthIncrease,T1,1.1,54 +ORWorthIncrease,T2,1.1,23 +ORWorthIncrease,T3,1.1,-8 +Has,M1,0 +Has,M2,90 +Has,M3,0 +Has,M4,0 +Has,M5,0 +Has,M6,0 +Has,BY,272 +Has,T1,75 +Has,T2,68 +Has,T3,76 +StartStockRound,2 +HasPriority,T3 +PASSES,T3 +PASSES,T1 +PASSES,T2 + +END_SR,2 +Has,M1,0 +Has,M2,90 +Has,M3,0 +Has,M4,0 +Has,M5,0 +Has,M6,0 +Has,BY,272 +Has,T1,75 +Has,T2,68 +Has,T3,76 +START_OR,2.1 +ReceivesFor,T2,5,NF +ReceivesFor,T3,10,OBB +ReceivesFor,T1,15,PfB +ReceivesFor,T1,20,LD +ReceivesFor,T1,25,BB +ReceivesFor,T2,30,HB + +CompanyOperates,M1,T2 +LaysTileAt,M1,9,J2,NW +CompanyRevenue,M1,40 +CompanySplits,M1,40 +M1 receives 20 +Payout,T2,20,1,100 + +CompanyOperates,M2,T2 +LaysTileAt,M2,8,D16,SE +CompanyRevenue,M2,0 +CompanyDoesNotPayDividend,M2 + +CompanyOperates,M3,T1 +LaysTileAt,M3,4,G15,NW +CompanyRevenue,M3,40 +CompanySplits,M3,40 +M3 receives 20 +Payout,T1,20,1,100 + +CompanyOperates,M4,T3 +LaysTileAt,M4,2,H4,NE +CompanyRevenue,M4,30 +CompanySplits,M4,30 +M4 receives 15 +Payout,T3,15,1,100 + +CompanyOperates,M5,T3 +LaysTileAt,M5,8,C19,E +CompanyRevenue,M5,50 +CompanySplits,M5,50 +M5 receives 25 +Payout,T3,25,1,100 + +CompanyOperates,M6,T1 +LaysTileAt,M6,6,A11,NW +CompanyRevenue,M6,60 +CompanySplits,M6,60 +M6 receives 30 +Payout,T1,30,1,100 + +CompanyOperates,BY,T3 +LaysTileAt,BY,8,N16,SW +LaysTileAt,BY,4,M15,NW +LaysTileAt,BY,6,N12,NW +LAYS_TOKEN_ON,BY,L14,60 +CompanyRevenue,BY,130 +CompanyPaysOutFull,BY,130 +Payout,T1,13,1,10 +Payout,T2,26,2,10 +Payout,T3,39,3,10 +PRICE_MOVES_LOG,BY,86,B3,92,C3 + +EndOfOperatingRound,2.1 +ORWorthIncrease,T1,2.1,129 +ORWorthIncrease,T2,2.1,93 +ORWorthIncrease,T3,2.1,107 +Has,M1,20 +Has,M2,90 +Has,M3,20 +Has,M4,15 +Has,M5,25 +Has,M6,30 +Has,BY,212 +Has,T1,198 +Has,T2,149 +Has,T3,165 +StartStockRound,3 +HasPriority,T3 +BUY_SHARE_LOG,T3,10,BY,IPO,92 +PriceIsPaidTo,92,BY +BUY_SHARE_LOG,T1,10,BY,IPO,92 +PriceIsPaidTo,92,BY +BUY_SHARE_LOG,T2,10,BY,IPO,92 +PriceIsPaidTo,92,BY +PASSES,T3 +BUY_SHARE_LOG,T1,10,BY,IPO,92 +PriceIsPaidTo,92,BY +SELL_SHARE_LOG,T1,10,BY,92 +PRICE_MOVES_LOG,BY,92,C3,88,C4 +PASSES,T2 +PASSES,T3 +SELL_SHARE_LOG,T1,10,BY,88 +PRICE_MOVES_LOG,BY,88,C4,86,C5 +BUY_SHARE_LOG,T1,10,SX,IPO,88 +PASSES,T2 +PASSES,T3 +SELL_SHARE_LOG,T1,10,BY,86 +PRICE_MOVES_LOG,BY,86,C5,82,C6 +BUY_SHARE_LOG,T1,10,SX,IPO,88 +PASSES,T2 +PASSES,T3 +BUY_SHARE_LOG,T1,10,SX,IPO,88 +FloatsWithCash,SX,440 +PASSES,T2 +PASSES,T3 +PASSES,T1 + +END_SR,3 +Has,M1,20 +Has,M2,90 +Has,M3,20 +Has,M4,15 +Has,M5,25 +Has,M6,30 +Has,BY,580 +Has,SX,440 +Has,T1,16 +Has,T2,57 +Has,T3,73 +START_OR,3.1 +ReceivesFor,T2,5,NF +ReceivesFor,T3,10,OBB +ReceivesFor,T1,15,PfB +ReceivesFor,T1,20,LD +ReceivesFor,T1,25,BB +ReceivesFor,T2,30,HB + +CompanyOperates,M1,T2 +LaysTileAt,M1,4,K3,NW +CompanyRevenue,M1,40 +CompanySplits,M1,40 +M1 receives 20 +Payout,T2,20,1,100 + +CompanyOperates,M2,T2 +LaysTileAtFor,M2,8,D14,NW,50 +CompanyRevenue,M2,70 +CompanySplits,M2,70 +M2 receives 35 +Payout,T2,35,1,100 + +CompanyOperates,M3,T1 +LaysTileAt,M3,57,H16,NW +CompanyRevenue,M3,40 +CompanySplits,M3,40 +M3 receives 20 +Payout,T1,20,1,100 + +CompanyOperates,M4,T3 +LaysTileAt,M4,58,F6,E +CompanyRevenue,M4,60 +CompanySplits,M4,60 +M4 receives 30 +Payout,T3,30,1,100 + +CompanyOperates,M5,T3 +CompanyRevenue,M5,50 +CompanySplits,M5,50 +M5 receives 25 +Payout,T3,25,1,100 + +CompanyOperates,M6,T1 +LaysTileAt,M6,58,B12,SW +CompanyRevenue,M6,60 +CompanySplits,M6,60 +M6 receives 30 +Payout,T1,30,1,100 + +CompanyOperates,SX,T1 +LaysTileAt,SX,56,I17,NE +LaysTileAt,SX,202,H20,W +CompanyDoesNotPayDividend,SX +PRICE_MOVES_LOG,SX,88,C4,84,B4 + +CompanyOperates,BY,T3 +LoadInterrupted,121 |
From: Frederick W. <fre...@us...> - 2012-02-15 19:16:37
|
data/profiles/default.profile | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) New commits: commit 366e5cfc52cdc0df0627a5854984389d17b90be5 Author: Frederick Weld <fre...@gm...> Date: Wed Feb 15 20:14:14 2012 +0100 Updated default profile with all recent config changes diff --git a/data/profiles/default.profile b/data/profiles/default.profile index 250611d..b4e4cb9 100644 --- a/data/profiles/default.profile +++ b/data/profiles/default.profile @@ -13,23 +13,35 @@ save.filename.extension=rails save.recovery.active=no save.recovery.filepath=18xx_autosave.rails -### Panel UI -report.window.type=dynamic -report.window.open=yes -report.window.editable=no -stockchart.window.open=yes +### Panel Font font.ui.scale=1 font.ui.name= font.ui.style=bold ### Panel Map map.autoscroll=yes +map.defaultZoomFitOption=none +map.displayCurrentRoutes=yes +map.highlightHexes=yes map.image.display=no map.zoomstep=10 +### Panel Windows +or.window.dockablePanels=no +report.window.type=dynamic +report.window.open=yes +report.window.editable=no +stockchart.window.open=yes + ### Panel Format money_format= or.number_format=composite + +### Panel Appearance +button.iconText=text and icon +button.iconSize=small +button.iconPosition=left +gridPanel.tableBorders=enabled route.colour.1=00ffff route.colour.2=ffc0cb route.colour.3=ffa500 @@ -39,3 +51,9 @@ route.colour.4=808080 #report.directory=log #report.filename.date_time_pattern=yyyyMMdd #report.filename.extension=log + +### Panel Music +sound.backgroundMusic=disabled + +### Panel SFX +sound.sfx=disabled |
From: Stefan F. <ste...@us...> - 2012-02-13 22:26:59
|
data/1856/TileSet.xml | 14 ++--- test/data/bugs/1835_changePresidentAtStart.rails |binary test/data/bugs/1835_changePresidentAtStart.report | 54 ++++++++++++++++++++++ 3 files changed, 61 insertions(+), 7 deletions(-) New commits: commit 6ae9b3b88d0ed1ffb3ed0f55eebd04da6b208d23 Author: Bill Rosgen <ro...@gm...> Date: Tue Feb 7 11:32:44 2012 +0800 1856: fix dit upgrade phases Signed-off-by: Stefan Frey <ste...@we...> (cherry picked from commit ebdd8eb314e14eacc48e60bdcd7dc3a63be73812) diff --git a/data/1856/TileSet.xml b/data/1856/TileSet.xml index cf36367..f926f6f 100644 --- a/data/1856/TileSet.xml +++ b/data/1856/TileSet.xml @@ -28,16 +28,16 @@ <!-- Yellow tiles --> <Tile id="1" quantity="1"> - <Upgrade id="14" phase="5,6"/> + <Upgrade id="14" phase="6,D"/> </Tile> <Tile id="2" quantity="1"> - <Upgrade id="15" phase="5,6"/> + <Upgrade id="15" phase="6,D"/> </Tile> <Tile id="3" quantity="3"> - <Upgrade id="5,7" phase="5,6"/> + <Upgrade id="5,7" phase="6,D"/> </Tile> <Tile id="4" quantity="3"> - <Upgrade id="57,9" phase="5,6"/> + <Upgrade id="57,9" phase="6,D"/> </Tile> <Tile id="5" quantity="2"> <Upgrade id="14,15" /> @@ -55,16 +55,16 @@ <Upgrade id="18,19,20,23,24,26,27" /> </Tile> <Tile id="55" quantity="1"> - <Upgrade id="14" phase="5,6"/> + <Upgrade id="14" phase="6,D"/> </Tile> <Tile id="56" quantity="1"> - <Upgrade id="15" phase="5,6"/> + <Upgrade id="15" phase="6,D"/> </Tile> <Tile id="57" quantity="4"> <Upgrade id="14,15" /> </Tile> <Tile id="58" quantity="3"> - <Upgrade id="6,8" phase="5,6"/> + <Upgrade id="6,8" phase="6,D"/> </Tile> <Tile id="69" quantity="1" /> commit 89dc9dd5a93ce245a31bc6b836f0497ef92e13f3 Author: Stefan Frey <ste...@we...> Date: Mon Feb 13 23:25:17 2012 +0100 added 1835 test case that checks that presidency changes during StartRound diff --git a/test/data/bugs/1835_changePresidentAtStart.rails b/test/data/bugs/1835_changePresidentAtStart.rails new file mode 100644 index 0000000..a1d91f0 Binary files /dev/null and b/test/data/bugs/1835_changePresidentAtStart.rails differ diff --git a/test/data/bugs/1835_changePresidentAtStart.report b/test/data/bugs/1835_changePresidentAtStart.report new file mode 100644 index 0000000..4af4eb4 --- /dev/null +++ b/test/data/bugs/1835_changePresidentAtStart.report @@ -0,0 +1,54 @@ +GameIs,1835 +PlayerIs,1,Klaus-Jürgen +PlayerIs,2,Jupp +PlayerIs,3,Sven K. +PlayerIs,4,Volker S. +PlayerCash,475 +BankHas,10100 +StartOfPhase,2 +BankSizeIs,10100 +StartOfInitialRound +HasPriority,Klaus-Jürgen +BuysItemFor,Volker S.,M3,80 +FloatsWithCash,M3,80 +BuysItemFor,Sven K.,M2,170 +FloatsWithCash,M2,170 +BuysItemFor,Jupp,M5,80 +FloatsWithCash,M5,80 +BuysItemFor,Klaus-Jürgen,M1,80 +FloatsWithCash,M1,80 +BuysItemFor,Klaus-Jürgen,M6,80 +FloatsWithCash,M6,80 +BuysItemFor,Jupp,LD,190 +ALSO_GETS,Jupp,PRES_CERT_NAME,SX,20 +BuysItemFor,Sven K.,M4,160 +FloatsWithCash,M4,160 +BuysItemFor,Volker S.,NF,100 +ALSO_GETS,Volker S.,CERT_NAME,BY,10 +BuysItemFor,Klaus-Jürgen,BB,130 +BuysItemFor,Jupp,HB,160 +PASSES,Sven K. +BuysItemFor,Volker S.,OBB,120 +ALSO_GETS,Volker S.,CERT_NAME,BY,10 +BuysItemFor,Klaus-Jürgen,PRES_CERT_NAME,BY,20,184 +CannotBuyAnything,Jupp +CannotBuyAnything,Sven K. +BuysItemFor,Volker S.,PfB,150 +ALSO_GETS,Volker S.,CERT_NAME,BY,10 +FloatsWithCash,BY,460 +IS_NOW_PRES_OF,Volker S.,BY +Has,M1,80 +Has,M2,170 +Has,M3,80 +Has,M4,160 +Has,M5,80 +Has,M6,80 +Has,BY,460 +Has,Klaus-Jürgen,1 +Has,Jupp,45 +Has,Sven K.,145 +Has,Volker S.,25 +StartStockRound,1 +HasPriority,Klaus-Jürgen +PASSES,Klaus-Jürgen +PASSES,Jupp |
From: Stefan F. <ste...@us...> - 2012-02-13 21:52:59
|
dev/null |binary rails/ui/images/train.png |binary 2 files changed New commits: commit 7f69d992ea2f4a1d019748b147f9b44840ae8276 Author: Stefan Frey <ste...@we...> Date: Mon Feb 13 22:31:25 2012 +0100 fixed type in filename of train.png diff --git a/rails/ui/images/Train.png b/rails/ui/images/Train.png deleted file mode 100644 index 0957b13..0000000 Binary files a/rails/ui/images/Train.png and /dev/null differ diff --git a/rails/ui/images/train.png b/rails/ui/images/train.png new file mode 100644 index 0000000..0957b13 Binary files /dev/null and b/rails/ui/images/train.png differ |
From: Frederick W. <fre...@us...> - 2012-02-12 17:53:12
|
LocalisedText.properties | 1 + data/Properties.xml | 2 ++ rails/ui/swing/elements/RailsIconButton.java | 18 ++++++++++++++++++ 3 files changed, 21 insertions(+) New commits: commit d9c6cff3c38f8348c2725f91699e9be931bd7fc6 Author: Frederick Weld <fre...@gm...> Date: Sun Feb 12 18:51:42 2012 +0100 Added option to display button icons above icon texts Motivation: Putting icons above is probably the preferred option if large icons and small fonts are used. Further advantage: Icons are horizontally aligned in case of vertical stacking of command buttons. diff --git a/LocalisedText.properties b/LocalisedText.properties index eac4de9..087534b 100644 --- a/LocalisedText.properties +++ b/LocalisedText.properties @@ -184,6 +184,7 @@ Config.infoText.sound.sfx.or.buyTrain=<html>Enter assignment of sound effect fil Config.infoText.sound.sfx.or.setRevenue=<html><ul><li>Only the latter portion of this file is played.<ul><li>For an average revenue, the last third is played.</ul><li>The higher the company's revenue the longer this file is played.<ul><li>But the file is at most played once as a whole.</li></ul></html> Config.infoText.sound.sfx.sr.newPresident=This also includes becoming the president when buying the president share. Config.label.button.iconText=Button display type +Config.label.button.iconPosition=Button icon position relative to text Config.label.button.iconSize=Button icon size Config.label.default_game=Default game Config.label.default_players=Default players diff --git a/data/Properties.xml b/data/Properties.xml index c207cbc..9399a9f 100644 --- a/data/Properties.xml +++ b/data/Properties.xml @@ -52,6 +52,8 @@ initClass="rails.ui.swing.elements.RailsIconButton" initMethod="resetRailsIcons" initParameter="no" /> <Property name="button.iconSize" type="LIST" values="small,large" initClass="rails.ui.swing.elements.RailsIconButton" initMethod="resetRailsIcons" initParameter="no" /> + <Property name="button.iconPosition" type="LIST" values="left,above" + initClass="rails.ui.swing.elements.RailsIconButton" initMethod="resetRailsIcons" initParameter="no" /> <Property name="route.colour.1" type="COLOR" initClass="rails.ui.swing.hexmap.HexMap" initMethod="setRouteColours" /> <Property name="route.colour.2" type="COLOR" diff --git a/rails/ui/swing/elements/RailsIconButton.java b/rails/ui/swing/elements/RailsIconButton.java index 3f6d628..fd1d165 100644 --- a/rails/ui/swing/elements/RailsIconButton.java +++ b/rails/ui/swing/elements/RailsIconButton.java @@ -9,6 +9,7 @@ import java.util.HashSet; import java.util.Set; import javax.swing.JButton; +import javax.swing.SwingConstants; import rails.common.parser.Config; @@ -65,11 +66,23 @@ public class RailsIconButton extends JButton { */ private void showRailsIcon() { if (railsIcon != null) { + //set icon/text positioning + if (isIconAboveText()) { + setVerticalTextPosition(SwingConstants.BOTTOM); + setHorizontalTextPosition(SwingConstants.CENTER); + } else { + setVerticalTextPosition(SwingConstants.CENTER); + setHorizontalTextPosition(SwingConstants.TRAILING); + } + + //set text if (isTextEnabled() || railsIcon.largeIcon == null) { super.setText(railsIcon.description); } else { super.setText(null); } + + //set icon and tool tip text if (isIconEnabled() || railsIcon.description == null) { if (isIconSizeSmall()) { super.setIcon(railsIcon.smallIcon); @@ -97,6 +110,11 @@ public class RailsIconButton extends JButton { //small is default return !"large".equals(Config.get("button.iconSize")); } + + private boolean isIconAboveText() { + //left of text is default + return "above".equals(Config.get("button.iconPosition")); + } /** * Should only be used if an arbitrary text is to displayed without icon. |
From: Frederick W. <fre...@us...> - 2012-02-12 09:39:03
|
rails/ui/swing/ORPanel.java | 20 +++++++++++ rails/ui/swing/ORWindow.java | 6 ++- rails/ui/swing/UpgradesPanel.java | 64 +++++++++++++++++++++++++++++--------- 3 files changed, 74 insertions(+), 16 deletions(-) New commits: commit 223e9fc1754a08fd2eca8aba99b63fb9aeb1bd45 Author: Frederick Weld <fre...@gm...> Date: Sun Feb 12 10:37:37 2012 +0100 Moved upgrade panel buttons to ORPanel button panel (dockable layout only) diff --git a/rails/ui/swing/ORPanel.java b/rails/ui/swing/ORPanel.java index 0dd18ce..58d4967 100644 --- a/rails/ui/swing/ORPanel.java +++ b/rails/ui/swing/ORPanel.java @@ -1366,4 +1366,24 @@ implements ActionListener, KeyListener, RevenueListener { public JMenuBar getMenuBar() { return menuBar; } + + /** + * Adds buttons to the button panel (adjusting their size to the standard size) + * @param index The position where to add the buttons + */ + public void addToButtonPanel(RailsIconButton[] buttons, int index) { + //get standard size + Dimension standardSize = null; + Component[] existingButtons = buttonPanel.getComponents(); + if (existingButtons != null && existingButtons.length > 0) { + standardSize = existingButtons[0].getPreferredSize(); + } + + //apply sizing to new buttons + //add buttons to the panel + for (int i=buttons.length-1 ; i >= 0 ; i--) { + buttons[i].setPreferredSize(standardSize); + buttonPanel.add(buttons[i],index); + } + } } diff --git a/rails/ui/swing/ORWindow.java b/rails/ui/swing/ORWindow.java index 9b049a5..6fc127a 100644 --- a/rails/ui/swing/ORWindow.java +++ b/rails/ui/swing/ORWindow.java @@ -66,7 +66,7 @@ public class ORWindow extends DockingFrame implements ActionPerformer { JScrollPane messagePanelSlider = new JScrollPane(messagePanel); messagePanel.setParentSlider(messagePanelSlider); - upgradePanel = new UpgradesPanel(orUIManager); + upgradePanel = new UpgradesPanel(orUIManager,isDockingFrameworkEnabled()); addMouseListener(upgradePanel); mapPanel = new MapPanel(gameUIManager); @@ -76,6 +76,10 @@ public class ORWindow extends DockingFrame implements ActionPerformer { //create docking / conventional layout if (isDockingFrameworkEnabled()) { + //set up the button panel (which is separated from its OR panel parent) + //adding upgrade panel buttons on top + orPanel.addToButtonPanel(upgradePanel.getButtons(),0); + //initialize remaining tile panel as it is no optional part in the docking layout JScrollPane remainingTilesPanelSlider = new RemainingTilesWindow(this).getScrollPane(); diff --git a/rails/ui/swing/UpgradesPanel.java b/rails/ui/swing/UpgradesPanel.java index c1a9df7..a471004 100644 --- a/rails/ui/swing/UpgradesPanel.java +++ b/rails/ui/swing/UpgradesPanel.java @@ -50,6 +50,13 @@ public class UpgradesPanel extends Box implements MouseListener, ActionListener private RailsIconButton doneButton = new RailsIconButton(RailsIcon.LAY_TILE); private HexMap hexMap; + /** + * If set, done/cancel buttons are not added to the pane. Instead, the + * visibility property of these buttons are handled such that they are set to + * visible if they normally would be added to the pane. + */ + private boolean omitButtons; + //list of tiles with an attached reason why it would represent an invalid upgrade private Map<TileI,String> invalidTileUpgrades = null; private static final String invalidUpgradeNoTilesLeft = "NoTilesLeft"; @@ -58,10 +65,11 @@ public class UpgradesPanel extends Box implements MouseListener, ActionListener protected static Logger log = Logger.getLogger(UpgradesPanel.class.getPackage().getName()); - public UpgradesPanel(ORUIManager orUIManager) { + public UpgradesPanel(ORUIManager orUIManager,boolean omitButtons) { super(BoxLayout.Y_AXIS); this.orUIManager = orUIManager; + this.omitButtons = omitButtons; preferredSize = new Dimension((int)Math.round(110 * (2 + Scale.getFontScale())/3), 200); setSize(preferredSize); @@ -85,6 +93,11 @@ public class UpgradesPanel extends Box implements MouseListener, ActionListener cancelButton.setActionCommand("Cancel"); cancelButton.setMnemonic(KeyEvent.VK_C); cancelButton.addActionListener(this); + + if (omitButtons) { + doneButton.setVisible(false); + cancelButton.setVisible(false); + } add(scrollPane); } @@ -136,7 +149,7 @@ public class UpgradesPanel extends Box implements MouseListener, ActionListener } public void showUpgrades() { - upgradePanel.removeAll(); + clearPanel(); // reset to the number of elements GridLayout panelLayout = (GridLayout)upgradePanel.getLayout(); @@ -214,9 +227,8 @@ public class UpgradesPanel extends Box implements MouseListener, ActionListener } } - upgradePanel.add(doneButton); - upgradePanel.add(cancelButton); - + addButtons(); + //repaint(); revalidate(); } @@ -269,7 +281,7 @@ public class UpgradesPanel extends Box implements MouseListener, ActionListener tokenMode = false; // activate upgrade panel - upgradePanel.removeAll(); + clearPanel(); GridLayout panelLayout = (GridLayout)upgradePanel.getLayout(); List<TileI> tiles = orUIManager.tileUpgrades; @@ -304,8 +316,7 @@ public class UpgradesPanel extends Box implements MouseListener, ActionListener } } - upgradePanel.add(doneButton); - upgradePanel.add(cancelButton); + addButtons(); // repaint(); revalidate(); @@ -318,7 +329,7 @@ public class UpgradesPanel extends Box implements MouseListener, ActionListener tokenMode = false; // activate upgrade panel - upgradePanel.removeAll(); + clearPanel(); GridLayout panelLayout = (GridLayout)upgradePanel.getLayout(); List<? extends TokenI> tokens = orUIManager.tokenLays; @@ -357,8 +368,8 @@ public class UpgradesPanel extends Box implements MouseListener, ActionListener } } - upgradePanel.add(doneButton); - upgradePanel.add(cancelButton); + + addButtons(); // repaint(); revalidate(); @@ -366,9 +377,8 @@ public class UpgradesPanel extends Box implements MouseListener, ActionListener } public void clear() { - upgradePanel.removeAll(); - upgradePanel.add(doneButton); - upgradePanel.add(cancelButton); + clearPanel(); + addButtons(); upgradePanel.repaint(); } @@ -537,7 +547,31 @@ public class UpgradesPanel extends Box implements MouseListener, ActionListener setDoneEnabled(false); setCancelEnabled(false); } - + + private void clearPanel() { + upgradePanel.removeAll(); + if (omitButtons) { + doneButton.setVisible(false); + cancelButton.setVisible(false); + } + } + + private void addButtons() { + if (omitButtons) { + //only set externally managed buttons to visible if at least + //one of them is enabled + boolean isVisible = doneButton.isEnabled() || cancelButton.isEnabled(); + doneButton.setVisible(isVisible); + cancelButton.setVisible(isVisible); + } else { + upgradePanel.add(doneButton); + upgradePanel.add(cancelButton); + } + } + + public RailsIconButton[] getButtons() { + return new RailsIconButton[] {doneButton, cancelButton}; + } /** ActionLabel extension that allows to attach the token */ private class CorrectionTokenLabel extends ActionLabel { |
From: Frederick W. <fre...@us...> - 2012-02-12 06:31:18
|
LocalisedText.properties | 4 data/Properties.xml | 8 - rails/ui/images/add.png |binary rails/ui/images/cancel.png |binary rails/ui/swing/UpgradesPanel.java | 13 +- rails/ui/swing/elements/ActionButton.java | 102 ---------------------- rails/ui/swing/elements/NonModalDialog.java | 7 - rails/ui/swing/elements/RailsIcon.java | 9 +- rails/ui/swing/elements/RailsIconButton.java | 121 +++++++++++++++++++++++++++ 9 files changed, 146 insertions(+), 118 deletions(-) New commits: commit 827a52602ab7f82c1831d8a64648b5e37300bc0c Author: Frederick Weld <fre...@gm...> Date: Sun Feb 12 07:29:44 2012 +0100 Applied rails icon functionality to upgrade panel buttons diff --git a/rails/ui/images/add.png b/rails/ui/images/add.png new file mode 100644 index 0000000..60a7a29 Binary files /dev/null and b/rails/ui/images/add.png differ diff --git a/rails/ui/swing/UpgradesPanel.java b/rails/ui/swing/UpgradesPanel.java index edf24a2..c1a9df7 100644 --- a/rails/ui/swing/UpgradesPanel.java +++ b/rails/ui/swing/UpgradesPanel.java @@ -18,6 +18,8 @@ import rails.game.*; import rails.game.action.*; import rails.game.correct.MapCorrectionAction; import rails.ui.swing.elements.ActionLabel; +import rails.ui.swing.elements.RailsIcon; +import rails.ui.swing.elements.RailsIconButton; import rails.ui.swing.hexmap.GUIHex; import rails.ui.swing.hexmap.GUITile; import rails.ui.swing.hexmap.HexHighlightMouseListener; @@ -42,13 +44,10 @@ public class UpgradesPanel extends Box implements MouseListener, ActionListener private JScrollPane scrollPane; private Dimension preferredSize; private Border border = new EtchedBorder(); - private final String INIT_CANCEL_TEXT = "NoTile"; - private final String INIT_DONE_TEXT = "LayTile"; private boolean tokenMode = false; private boolean correctionTokenMode = false; - private JButton cancelButton = - new JButton(LocalText.getText(INIT_CANCEL_TEXT)); - private JButton doneButton = new JButton(LocalText.getText(INIT_DONE_TEXT)); + private RailsIconButton cancelButton = new RailsIconButton(RailsIcon.NO_TILE); + private RailsIconButton doneButton = new RailsIconButton(RailsIcon.LAY_TILE); private HexMap hexMap; //list of tiles with an attached reason why it would represent an invalid upgrade @@ -452,11 +451,11 @@ public class UpgradesPanel extends Box implements MouseListener, ActionListener } public void setCancelText(String text) { - cancelButton.setText(LocalText.getText(text)); + cancelButton.setRailsIcon(RailsIcon.getByConfigKey(text)); } public void setDoneText(String text) { - doneButton.setText(LocalText.getText(text)); + doneButton.setRailsIcon(RailsIcon.getByConfigKey(text)); } public void setDoneEnabled(boolean enabled) { commit 29e2d4953062a95616a3a1333b7930091f7be8e9 Author: Frederick Weld <fre...@gm...> Date: Sun Feb 12 07:23:02 2012 +0100 Applied rails icon functionality to non modal dialogs Model dialogs will stay unaffected as they don't provide for an easy way to customize the option buttons. diff --git a/rails/ui/images/cancel.png b/rails/ui/images/cancel.png new file mode 100644 index 0000000..1b20ae0 Binary files /dev/null and b/rails/ui/images/cancel.png differ diff --git a/rails/ui/swing/elements/NonModalDialog.java b/rails/ui/swing/elements/NonModalDialog.java index 72718d2..36d8581 100644 --- a/rails/ui/swing/elements/NonModalDialog.java +++ b/rails/ui/swing/elements/NonModalDialog.java @@ -7,7 +7,6 @@ import javax.swing.*; import org.apache.log4j.Logger; -import rails.common.LocalText; import rails.util.Util; public abstract class NonModalDialog extends JDialog implements ActionListener { @@ -22,7 +21,7 @@ public abstract class NonModalDialog extends JDialog implements ActionListener { GridBagConstraints gc; JPanel optionsPane, buttonPane; - JButton okButton, cancelButton; + RailsIconButton okButton, cancelButton; String okTextKey = "OK"; String cancelTextKey = "Cancel"; @@ -58,13 +57,13 @@ public abstract class NonModalDialog extends JDialog implements ActionListener { optionsPane = new JPanel(); buttonPane = new JPanel(); - okButton = new JButton(LocalText.getText(okTextKey)); + okButton = new RailsIconButton(RailsIcon.getByConfigKey(okTextKey)); okButton.setMnemonic(okTextKey.startsWith("Y") ? KeyEvent.VK_Y : KeyEvent.VK_O); okButton.addActionListener(this); buttonPane.add(okButton); if (hasCancelButton) { - cancelButton = new JButton(LocalText.getText(cancelTextKey)); + cancelButton = new RailsIconButton(RailsIcon.getByConfigKey(cancelTextKey)); cancelButton.setMnemonic(cancelTextKey.startsWith("N") ? KeyEvent.VK_N : KeyEvent.VK_C); cancelButton.addActionListener(this); buttonPane.add(cancelButton); diff --git a/rails/ui/swing/elements/RailsIcon.java b/rails/ui/swing/elements/RailsIcon.java index bc420b0..90db59c 100644 --- a/rails/ui/swing/elements/RailsIcon.java +++ b/rails/ui/swing/elements/RailsIcon.java @@ -20,9 +20,15 @@ public enum RailsIcon { BID ("money_add.png","BID"), BUY_PRIVATE ("money_bag.png","BUY_PRIVATE"), BUY_TRAIN ("train.png","BUY_TRAIN"), + CANCEL ("cancel.png","CANCEL"), DONE ("accept.png","Done"), INFO ("information.png","Info"), - LAY_TILE ("rails32.png","LayTile"), + LAY_TILE ("add.png","LayTile"), + LAY_TOKEN ("add.png","LayToken"), + NO ("cancel.png","No"), + NO_TILE ("control_play_blue.png","NoTile"), + NO_TOKEN ("control_play_blue.png","NoToken"), + OK ("accept.png","OK"), PANEL_OR ("participation_rate.png","Dockable.orWindow.orPanel"), PANEL_OR_BUTTONS ("button.png","Dockable.orWindow.buttonPanel"), PANEL_MAP ("globe_model.png","Dockable.orWindow.mapPanel"), @@ -40,6 +46,7 @@ public enum RailsIcon { SPLIT ("traffic_lights_yellow.png","SPLIT"), UNDO ("arrow_undo.png","UNDO"), WITHHOLD ("traffic_lights_red.png","WITHHOLD"), + YES ("accept.png","Yes"), //no icons by purpose END_OF_GAME_CLOSE_ALL_WINDOWS ("","END_OF_GAME_CLOSE_ALL_WINDOWS"), commit 484cea4cbdc5d083c3f4587a682c624d0dc835a5 Author: Frederick Weld <fre...@gm...> Date: Sun Feb 12 06:57:46 2012 +0100 Extracted icon functionality from ActionButton to generic superclass Needed in order to prepare for using the same icon functionality on non-action buttons. diff --git a/LocalisedText.properties b/LocalisedText.properties index a6f24f6..eac4de9 100644 --- a/LocalisedText.properties +++ b/LocalisedText.properties @@ -183,8 +183,8 @@ Config.infoText.sound.sfx.gen.newCurrentPlayer=<html>Enter assignment of sound e Config.infoText.sound.sfx.or.buyTrain=<html>Enter assignment of sound effect files to train types.<ul><li>Separate the assignments by commas.<li>Each assignment has the syntax trainName=complete file path<li>Default sound effect is defined by omitting "trainName=" in the assignment.</ul><strong>Examples:</strong><ul><li>Set default sound effect: <br><code>c:\BuyTrain-default.mp3</code><li>Set train-dependent sound effect and a default (for trains above 6): <br><code>2=c:\BuyTrain-2.mp3,3=c:\BuyTrain-3.mp3,4=c:\BuyTrain-4.mp3,5=c:\BuyTrain-5.mp3,6=c:\BuyTrain-6.mp3,c:\BuyTrain-D.mp3</code></ul> </html> Config.infoText.sound.sfx.or.setRevenue=<html><ul><li>Only the latter portion of this file is played.<ul><li>For an average revenue, the last third is played.</ul><li>The higher the company's revenue the longer this file is played.<ul><li>But the file is at most played once as a whole.</li></ul></html> Config.infoText.sound.sfx.sr.newPresident=This also includes becoming the president when buying the president share. -Config.label.actionButton.iconText=Button display type -Config.label.actionButton.iconSize=Icon size +Config.label.button.iconText=Button display type +Config.label.button.iconSize=Button icon size Config.label.default_game=Default game Config.label.default_players=Default players Config.label.font.ui.name=Font selection diff --git a/data/Properties.xml b/data/Properties.xml index b78d097..c207cbc 100644 --- a/data/Properties.xml +++ b/data/Properties.xml @@ -48,10 +48,10 @@ </Section> <Section name="Appearance"> <Property name="gridPanel.tableBorders" type="LIST" values="disabled,enabled"/> - <Property name="actionButton.iconText" type="LIST" values="text and icon,only text,only icon" - initClass="rails.ui.swing.elements.ActionButton" initMethod="resetRailsIcons" initParameter="no" /> - <Property name="actionButton.iconSize" type="LIST" values="small,large" - initClass="rails.ui.swing.elements.ActionButton" initMethod="resetRailsIcons" initParameter="no" /> + <Property name="button.iconText" type="LIST" values="text and icon,only text,only icon" + initClass="rails.ui.swing.elements.RailsIconButton" initMethod="resetRailsIcons" initParameter="no" /> + <Property name="button.iconSize" type="LIST" values="small,large" + initClass="rails.ui.swing.elements.RailsIconButton" initMethod="resetRailsIcons" initParameter="no" /> <Property name="route.colour.1" type="COLOR" initClass="rails.ui.swing.hexmap.HexMap" initMethod="setRouteColours" /> <Property name="route.colour.2" type="COLOR" diff --git a/rails/ui/swing/elements/ActionButton.java b/rails/ui/swing/elements/ActionButton.java index d07bbba..b591fd3 100644 --- a/rails/ui/swing/elements/ActionButton.java +++ b/rails/ui/swing/elements/ActionButton.java @@ -1,16 +1,9 @@ /* $Header: /Users/blentz/rails_rcs/cvs/18xx/rails/ui/swing/elements/ActionButton.java,v 1.5 2008/06/04 19:00:38 evos Exp $*/ package rails.ui.swing.elements; -import java.awt.Insets; import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashSet; import java.util.List; -import java.util.Set; -import javax.swing.JButton; - -import rails.common.parser.Config; import rails.game.action.ActionTaker; import rails.game.action.PossibleAction; @@ -19,38 +12,14 @@ import rails.game.action.PossibleAction; * * @see ClickField */ -public class ActionButton extends JButton implements ActionTaker { +public class ActionButton extends RailsIconButton implements ActionTaker { private static final long serialVersionUID = 1L; - private static final Set<String> KEYS_TEXT_DISPLAY = new HashSet<String> - (Arrays.asList( new String[] { - "text and icon", - "only text", - "", - null - })); - private static final Set<String> KEYS_ICON_DISPLAY = new HashSet<String> - (Arrays.asList( new String[] { - "text and icon", - "only icon" - })); - - private static Set<ActionButton> actionButtons = new HashSet<ActionButton>(); - private List<PossibleAction> actions = new ArrayList<PossibleAction>(1); - /** - * null value means that the action button is not set up by an appropriate - * RailsIcon (eg., by calling setText directly). - */ - private RailsIcon railsIcon = null; - public ActionButton(RailsIcon railsIcon) { - super(); - setRailsIcon(railsIcon); - this.setMargin(new Insets(2,2,2,2)); - actionButtons.add(this); + super(railsIcon); } public void addPossibleAction(PossibleAction o) { @@ -70,71 +39,4 @@ public class ActionButton extends JButton implements ActionTaker { addPossibleAction(action); } - public void setRailsIcon(RailsIcon railsIcon) { - if (railsIcon == null) railsIcon = RailsIcon.NULL; - this.railsIcon = railsIcon; - showRailsIcon(); - } - - /** - * Display according to configuration. - * If no text/icon is attached, then icon/text is displayed as fallback - * (irrespective of configuration). - * Text becomes the tool tip text in case of icon-only display. - */ - private void showRailsIcon() { - if (railsIcon != null) { - if (isTextEnabled() || railsIcon.largeIcon == null) { - super.setText(railsIcon.description); - } else { - super.setText(null); - } - if (isIconEnabled() || railsIcon.description == null) { - if (isIconSizeSmall()) { - super.setIcon(railsIcon.smallIcon); - } else { - super.setIcon(railsIcon.largeIcon); - } - if (!isTextEnabled()) { - super.setToolTipText(railsIcon.description); - } - } else { - super.setIcon(null); - } - } - } - - private boolean isTextEnabled() { - return KEYS_TEXT_DISPLAY.contains(Config.get("actionButton.iconText","")); - } - - private boolean isIconEnabled() { - return KEYS_ICON_DISPLAY.contains(Config.get("actionButton.iconText","")); - } - - private boolean isIconSizeSmall() { - //small is default - return !"large".equals(Config.get("actionButton.iconSize")); - } - - /** - * Should only be used if an arbitrary text is to displayed without icon. - * In any other case, setRailsIcon should be used. - */ - @Override - public void setText(String text) { - super.setText(text); - setIcon(null); - railsIcon = null; - } - - /** - * To be called upon change of button display type - */ - public static void resetRailsIcons() { - for (ActionButton ab : actionButtons) { - ab.showRailsIcon(); - } - } - } diff --git a/rails/ui/swing/elements/RailsIconButton.java b/rails/ui/swing/elements/RailsIconButton.java new file mode 100644 index 0000000..3f6d628 --- /dev/null +++ b/rails/ui/swing/elements/RailsIconButton.java @@ -0,0 +1,121 @@ +/** + * + */ +package rails.ui.swing.elements; + +import java.awt.Insets; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +import javax.swing.JButton; + +import rails.common.parser.Config; + +/** + * A JButton which is able to hold/manage a RailsIcon (specifying what + * text / icon is to be displayed) + * + * @author Frederick Weld + * + */ +public class RailsIconButton extends JButton { + + private static final long serialVersionUID = 1L; + + private static final Set<String> KEYS_TEXT_DISPLAY = new HashSet<String> + (Arrays.asList( new String[] { + "text and icon", + "only text", + "", + null + })); + private static final Set<String> KEYS_ICON_DISPLAY = new HashSet<String> + (Arrays.asList( new String[] { + "text and icon", + "only icon" + })); + + private static Set<RailsIconButton> railsIconButtons = new HashSet<RailsIconButton>(); + + /** + * null value means that the button is not set up by an appropriate + * RailsIcon (eg., by calling setText directly). + */ + private RailsIcon railsIcon = null; + + public RailsIconButton(RailsIcon railsIcon) { + super(); + setRailsIcon(railsIcon); + this.setMargin(new Insets(2,2,2,2)); + railsIconButtons.add(this); + } + + public void setRailsIcon(RailsIcon railsIcon) { + if (railsIcon == null) railsIcon = RailsIcon.NULL; + this.railsIcon = railsIcon; + showRailsIcon(); + } + + /** + * Display according to configuration. + * If no text/icon is attached, then icon/text is displayed as fallback + * (irrespective of configuration). + * Text becomes the tool tip text in case of icon-only display. + */ + private void showRailsIcon() { + if (railsIcon != null) { + if (isTextEnabled() || railsIcon.largeIcon == null) { + super.setText(railsIcon.description); + } else { + super.setText(null); + } + if (isIconEnabled() || railsIcon.description == null) { + if (isIconSizeSmall()) { + super.setIcon(railsIcon.smallIcon); + } else { + super.setIcon(railsIcon.largeIcon); + } + if (!isTextEnabled()) { + super.setToolTipText(railsIcon.description); + } + } else { + super.setIcon(null); + } + } + } + + private boolean isTextEnabled() { + return KEYS_TEXT_DISPLAY.contains(Config.get("button.iconText","")); + } + + private boolean isIconEnabled() { + return KEYS_ICON_DISPLAY.contains(Config.get("button.iconText","")); + } + + private boolean isIconSizeSmall() { + //small is default + return !"large".equals(Config.get("button.iconSize")); + } + + /** + * Should only be used if an arbitrary text is to displayed without icon. + * In any other case, setRailsIcon should be used. + */ + @Override + public void setText(String text) { + super.setText(text); + setIcon(null); + railsIcon = null; + } + + /** + * To be called upon change of button display type + */ + public static void resetRailsIcons() { + for (RailsIconButton rib : railsIconButtons) { + rib.showRailsIcon(); + } + } + +} |
From: Frederick W. <fre...@us...> - 2012-02-11 18:42:22
|
LocalisedText.properties | 2 data/GamesList.xml | 63 +++++++------- data/Properties.xml | 4 rails/ui/images/Train.png |binary rails/ui/images/accept.png |binary rails/ui/images/arrow_redo.png |binary rails/ui/images/arrow_undo.png |binary rails/ui/images/auction_hammer_gavel.png |binary rails/ui/images/bricks.png |binary rails/ui/images/button.png |binary rails/ui/images/cash_stack.png |binary rails/ui/images/clock_add.png |binary rails/ui/images/clock_delete.png |binary rails/ui/images/coins_in_hand.png |binary rails/ui/images/control_fastforward_blue.png |binary rails/ui/images/control_play_blue.png |binary rails/ui/images/globe_model.png |binary rails/ui/images/hand_property.png |binary rails/ui/images/information.png |binary rails/ui/images/money_add.png |binary rails/ui/images/money_bag.png |binary rails/ui/images/participation_rate.png |binary rails/ui/images/rails32.png |binary rails/ui/images/script.png |binary rails/ui/images/traffic_lights_green.png |binary rails/ui/images/traffic_lights_red.png |binary rails/ui/images/traffic_lights_yellow.png |binary rails/ui/swing/ConfigWindow.java | 2 rails/ui/swing/GameSetupWindow.java | 2 rails/ui/swing/ORPanel.java | 28 +++--- rails/ui/swing/ORWindow.java | 12 +- rails/ui/swing/ReportWindowDynamic.java | 5 - rails/ui/swing/StartRoundWindow.java | 12 +- rails/ui/swing/StatusWindow.java | 14 +-- rails/ui/swing/elements/ActionButton.java | 100 ++++++++++++++++++++++ rails/ui/swing/elements/DockingFrame.java | 5 - rails/ui/swing/elements/RailsIcon.java | 119 +++++++++++++++++++++++++-- 37 files changed, 290 insertions(+), 78 deletions(-) New commits: commit b7e95f18296f06fcce810682b89a542608ce5b71 Author: Frederick Weld <fre...@gm...> Date: Sat Feb 11 19:39:51 2012 +0100 Included and pre-configured icon set for action buttons and dockables Attribution now part of the credits. diff --git a/data/GamesList.xml b/data/GamesList.xml index 10d120d..3b6b2c5 100644 --- a/data/GamesList.xml +++ b/data/GamesList.xml @@ -315,33 +315,38 @@ Known Issues: </Game> - <Credits>Rails is a computer implementation of a number of board games. - These games all have a railroad theme. They are collectively known as "18xx" - games due to the naming scheme used by many games in the genre. - -Contributors: - Erik Vos - Stefan Frey - Freek Dijkstra - Scott Peterson - Adam Badura - Phil Davies - Bill Rosgen - Martin Brumm - Chris Shaffer - Brett Lentz - -All rights reserved by the respective owners of the original games -(see the Game Notes per game for specific acknowledgements). - -No challenge to the original author's or publisher's rights, licensing, or status is intended. - -Rails is intended as a play aid for owners of each respective boardgame. - -The Rails application and source code are distributed under -version 2 of the GNU Public License (GPL). - -A copy of the GPL should have been shipped with the game files and is also available here: - http://www.gnu.org/licenses/old-licenses/gpl-2.0.html - </Credits> + <Credits><html>Rails is a computer implementation of a number of board games.<br> + These games all have a railroad theme. They are collectively known as "18xx" <br> + games due to the naming scheme used by many games in the genre. <br> + <br> +Contributors: <br> + Erik Vos<br> + Stefan Frey<br> + Freek Dijkstra<br> + Scott Peterson<br> + Adam Badura<br> + Phil Davies<br> + Bill Rosgen<br> + Martin Brumm<br> + Chris Shaffer <br> + Brett Lentz<br> +<br> +All rights reserved by the respective owners of the original games<br> +(see the Game Notes per game for specific acknowledgements).<br> +<br> +No challenge to the original author's or publisher's rights, licensing, or status is intended.<br> +<br> +Rails is intended as a play aid for owners of each respective boardgame.<br> +<br> +The Rails application and source code are distributed under<br> +version 2 of the GNU Public License (GPL).<br> +<br> +A copy of the GPL should have been shipped with the game files and is also available here:<br> + <a href="http://www.gnu.org/licenses/old-licenses/gpl-2.0.html">http://www.gnu.org/licenses/old-licenses/gpl-2.0.html</a><br> +<br> +Icon sets are taken from the following sites:<ul> + <li><a href="http://www.fatcow.com/">http://www.fatcow.com/</a><br> + under a Creative Commons Attribution 3.0 License (<a href="http://creativecommons.org/licenses/by/3.0/us/">http://creativecommons.org/licenses/by/3.0/us/</a>) + </ul> + </html></Credits> </GamesList> diff --git a/rails/ui/images/Train.png b/rails/ui/images/Train.png new file mode 100644 index 0000000..0957b13 Binary files /dev/null and b/rails/ui/images/Train.png differ diff --git a/rails/ui/images/accept.png b/rails/ui/images/accept.png new file mode 100644 index 0000000..7786ac7 Binary files /dev/null and b/rails/ui/images/accept.png differ diff --git a/rails/ui/images/arrow_redo.png b/rails/ui/images/arrow_redo.png new file mode 100644 index 0000000..c80608a Binary files /dev/null and b/rails/ui/images/arrow_redo.png differ diff --git a/rails/ui/images/arrow_undo.png b/rails/ui/images/arrow_undo.png new file mode 100644 index 0000000..be4f8e9 Binary files /dev/null and b/rails/ui/images/arrow_undo.png differ diff --git a/rails/ui/images/auction_hammer_gavel.png b/rails/ui/images/auction_hammer_gavel.png new file mode 100644 index 0000000..c27c3f5 Binary files /dev/null and b/rails/ui/images/auction_hammer_gavel.png differ diff --git a/rails/ui/images/bricks.png b/rails/ui/images/bricks.png new file mode 100644 index 0000000..a453ca0 Binary files /dev/null and b/rails/ui/images/bricks.png differ diff --git a/rails/ui/images/button.png b/rails/ui/images/button.png new file mode 100644 index 0000000..4b1eb80 Binary files /dev/null and b/rails/ui/images/button.png differ diff --git a/rails/ui/images/cash_stack.png b/rails/ui/images/cash_stack.png new file mode 100644 index 0000000..ee8e307 Binary files /dev/null and b/rails/ui/images/cash_stack.png differ diff --git a/rails/ui/images/clock_add.png b/rails/ui/images/clock_add.png new file mode 100644 index 0000000..c61c062 Binary files /dev/null and b/rails/ui/images/clock_add.png differ diff --git a/rails/ui/images/clock_delete.png b/rails/ui/images/clock_delete.png new file mode 100644 index 0000000..2f8ffb8 Binary files /dev/null and b/rails/ui/images/clock_delete.png differ diff --git a/rails/ui/images/coins_in_hand.png b/rails/ui/images/coins_in_hand.png new file mode 100644 index 0000000..aaceea1 Binary files /dev/null and b/rails/ui/images/coins_in_hand.png differ diff --git a/rails/ui/images/control_fastforward_blue.png b/rails/ui/images/control_fastforward_blue.png new file mode 100644 index 0000000..e348959 Binary files /dev/null and b/rails/ui/images/control_fastforward_blue.png differ diff --git a/rails/ui/images/control_play_blue.png b/rails/ui/images/control_play_blue.png new file mode 100644 index 0000000..a1f7345 Binary files /dev/null and b/rails/ui/images/control_play_blue.png differ diff --git a/rails/ui/images/globe_model.png b/rails/ui/images/globe_model.png new file mode 100644 index 0000000..66a5c0b Binary files /dev/null and b/rails/ui/images/globe_model.png differ diff --git a/rails/ui/images/hand_property.png b/rails/ui/images/hand_property.png new file mode 100644 index 0000000..fe4725e Binary files /dev/null and b/rails/ui/images/hand_property.png differ diff --git a/rails/ui/images/information.png b/rails/ui/images/information.png new file mode 100644 index 0000000..93c67f2 Binary files /dev/null and b/rails/ui/images/information.png differ diff --git a/rails/ui/images/money_add.png b/rails/ui/images/money_add.png new file mode 100644 index 0000000..62154f3 Binary files /dev/null and b/rails/ui/images/money_add.png differ diff --git a/rails/ui/images/money_bag.png b/rails/ui/images/money_bag.png new file mode 100644 index 0000000..24a1a06 Binary files /dev/null and b/rails/ui/images/money_bag.png differ diff --git a/rails/ui/images/participation_rate.png b/rails/ui/images/participation_rate.png new file mode 100644 index 0000000..1c30d07 Binary files /dev/null and b/rails/ui/images/participation_rate.png differ diff --git a/rails/ui/images/rails32.png b/rails/ui/images/rails32.png new file mode 100644 index 0000000..c62e18c Binary files /dev/null and b/rails/ui/images/rails32.png differ diff --git a/rails/ui/images/script.png b/rails/ui/images/script.png new file mode 100644 index 0000000..8755c17 Binary files /dev/null and b/rails/ui/images/script.png differ diff --git a/rails/ui/images/traffic_lights_green.png b/rails/ui/images/traffic_lights_green.png new file mode 100644 index 0000000..bd53d89 Binary files /dev/null and b/rails/ui/images/traffic_lights_green.png differ diff --git a/rails/ui/images/traffic_lights_red.png b/rails/ui/images/traffic_lights_red.png new file mode 100644 index 0000000..fd00be2 Binary files /dev/null and b/rails/ui/images/traffic_lights_red.png differ diff --git a/rails/ui/images/traffic_lights_yellow.png b/rails/ui/images/traffic_lights_yellow.png new file mode 100644 index 0000000..54034fc Binary files /dev/null and b/rails/ui/images/traffic_lights_yellow.png differ diff --git a/rails/ui/swing/StartRoundWindow.java b/rails/ui/swing/StartRoundWindow.java index 4011121..a6ea8d6 100644 --- a/rails/ui/swing/StartRoundWindow.java +++ b/rails/ui/swing/StartRoundWindow.java @@ -134,7 +134,7 @@ implements ActionListener, KeyListener, ActionPerformer, DialogOwner { buttonPanel = new JPanel(); - buyButton = new ActionButton(RailsIcon.BUY); + buyButton = new ActionButton(RailsIcon.AUCTION_BUY); buyButton.setMnemonic(KeyEvent.VK_B); buyButton.addActionListener(this); buyButton.setEnabled(false); diff --git a/rails/ui/swing/elements/RailsIcon.java b/rails/ui/swing/elements/RailsIcon.java index eed61ff..bc420b0 100644 --- a/rails/ui/swing/elements/RailsIcon.java +++ b/rails/ui/swing/elements/RailsIcon.java @@ -15,27 +15,35 @@ import rails.common.LocalText; public enum RailsIcon { // in parentheses the image file - AUTOPASS ("","Autopass"), - BID ("","BID"), - BUY ("","BUY"), - BUY_PRIVATE ("","BUY_PRIVATE"), - BUY_TRAIN ("","BUY_TRAIN"), - DONE ("","Done"), + AUCTION_BUY ("auction_hammer_gavel.png","BUY"), + AUTOPASS ("control_fastforward_blue.png","Autopass"), + BID ("money_add.png","BID"), + BUY_PRIVATE ("money_bag.png","BUY_PRIVATE"), + BUY_TRAIN ("train.png","BUY_TRAIN"), + DONE ("accept.png","Done"), + INFO ("information.png","Info"), + LAY_TILE ("rails32.png","LayTile"), + PANEL_OR ("participation_rate.png","Dockable.orWindow.orPanel"), + PANEL_OR_BUTTONS ("button.png","Dockable.orWindow.buttonPanel"), + PANEL_MAP ("globe_model.png","Dockable.orWindow.mapPanel"), + PANEL_MESSAGE ("script.png","Dockable.orWindow.messagePanel"), + PANEL_REMAINING_TILES ("rails32.png","Dockable.orWindow.remainingTilesPanel"), + PANEL_UPGRADE ("bricks.png","Dockable.orWindow.upgradePanel"), + PASS ("control_play_blue.png","PASS"), + PAYOUT ("traffic_lights_green.png","PAYOUT"), + REDO ("arrow_redo.png","REDO"), + REPAY_LOANS ("cash_stack.png","RepayLoans"), + REPORT_MOVE_BACKWARD ("clock_delete.png","REPORT_MOVE_BACKWARD"), + REPORT_MOVE_FORWARD ("clock_add.png","REPORT_MOVE_FORWARD"), + SELECT_NO_BID ("hand_property.png","SelectNoBid"), + SET_REVENUE ("coins_in_hand.png","SET_REVENUE"), + SPLIT ("traffic_lights_yellow.png","SPLIT"), + UNDO ("arrow_undo.png","UNDO"), + WITHHOLD ("traffic_lights_red.png","WITHHOLD"), + + //no icons by purpose END_OF_GAME_CLOSE_ALL_WINDOWS ("","END_OF_GAME_CLOSE_ALL_WINDOWS"), - INFO ("Inform.gif","Info"), - LAY_TILE ("","LayTile"), OPERATING_COST ("","OCButtonLabel"), - PASS ("","PASS"), - PAYOUT ("","PAYOUT"), - REDO ("","REDO"), - REPAY_LOANS ("","RepayLoans"), - REPORT_MOVE_BACKWARD ("","REPORT_MOVE_BACKWARD"), - REPORT_MOVE_FORWARD ("","REPORT_MOVE_FORWARD"), - SELECT_NO_BID ("","SelectNoBid"), - SET_REVENUE ("","SET_REVENUE"), - SPLIT ("","SPLIT"), - UNDO ("","UNDO"), - WITHOLD ("","WITHHOLD"), //null meaning all public fields are null NULL (); commit d0d630d07e4b5b7edd5764ee1b6b125fc806df49 Author: Frederick Weld <fre...@gm...> Date: Sat Feb 11 17:30:59 2012 +0100 Added support for icons in dockable panels / further refactoring As a result, add dockable now also gets the config key in order to be able to map the dockable to the respective icon. diff --git a/rails/ui/swing/ConfigWindow.java b/rails/ui/swing/ConfigWindow.java index 4d25293..db03e10 100644 --- a/rails/ui/swing/ConfigWindow.java +++ b/rails/ui/swing/ConfigWindow.java @@ -419,7 +419,7 @@ class ConfigWindow extends JFrame { } // add info icon for infoText if (infoText != null) { - JLabel infoIcon = new JLabel(RailsIcon.INFO.largeIcon); + JLabel infoIcon = new JLabel(RailsIcon.INFO.smallIcon); infoIcon.addMouseListener(new MouseListener() { public void mousePressed(MouseEvent e) { final JDialog dialog = new JDialog(ConfigWindow.this, false); diff --git a/rails/ui/swing/GameSetupWindow.java b/rails/ui/swing/GameSetupWindow.java index e91880d..4e69739 100644 --- a/rails/ui/swing/GameSetupWindow.java +++ b/rails/ui/swing/GameSetupWindow.java @@ -324,7 +324,7 @@ public class GameSetupWindow extends JDialog implements ActionListener { System.exit(0); } else if (arg0.getSource().equals(creditsButton)) { JOptionPane.showMessageDialog(this, - credits, + new JLabel(credits), //enable html rendering LocalText.getText("CREDITS"), JOptionPane.INFORMATION_MESSAGE); } else if (arg0.getSource().equals(gameNameBox)) { diff --git a/rails/ui/swing/ORPanel.java b/rails/ui/swing/ORPanel.java index ec8c7ec..0dd18ce 100644 --- a/rails/ui/swing/ORPanel.java +++ b/rails/ui/swing/ORPanel.java @@ -1183,7 +1183,7 @@ implements ActionListener, KeyListener, RevenueListener { setSelect(revenue[orCompIndex], revenueSelect[orCompIndex], false); if (withhold) { - button1.setRailsIcon(RailsIcon.WITHOLD); + button1.setRailsIcon(RailsIcon.WITHHOLD); button1.setActionCommand(WITHHOLD_CMD); clonedAction = (SetDividend) action.clone(); clonedAction.setRevenueAllocation(SetDividend.WITHHOLD); diff --git a/rails/ui/swing/ORWindow.java b/rails/ui/swing/ORWindow.java index acee3e9..9b049a5 100644 --- a/rails/ui/swing/ORWindow.java +++ b/rails/ui/swing/ORWindow.java @@ -82,22 +82,22 @@ public class ORWindow extends DockingFrame implements ActionPerformer { //generate layout addDockable ( messagePanelSlider, - LocalText.getText("Dockable.orWindow.messagePanel"), + "Dockable.orWindow.messagePanel", 0, 0, 100, 10, DockableProperty.closeable); addDockable ( upgradePanel, - LocalText.getText("Dockable.orWindow.upgradePanel"), + "Dockable.orWindow.upgradePanel", 0, 10, 20, 70, DockableProperty.standard); addDockable ( mapPanel, - LocalText.getText("Dockable.orWindow.mapPanel"), + "Dockable.orWindow.mapPanel", 20, 10, 80, 70, DockableProperty.standard); addDockable ( remainingTilesPanelSlider, - LocalText.getText("Dockable.orWindow.remainingTilesPanel"), + "Dockable.orWindow.remainingTilesPanel", 100, 0, 120, 100, DockableProperty.initially_hidden); addDockable ( orPanel, - LocalText.getText("Dockable.orWindow.orPanel"), + "Dockable.orWindow.orPanel", 0, 80, 100, 15, DockableProperty.standard); addDockable ( orPanel.getButtonPanel(), - LocalText.getText("Dockable.orWindow.buttonPanel"), + "Dockable.orWindow.buttonPanel", 0, 95, 100, 5, DockableProperty.standard); deployDockables(); diff --git a/rails/ui/swing/StartRoundWindow.java b/rails/ui/swing/StartRoundWindow.java index a2c83eb..4011121 100644 --- a/rails/ui/swing/StartRoundWindow.java +++ b/rails/ui/swing/StartRoundWindow.java @@ -797,7 +797,7 @@ implements ActionListener, KeyListener, ActionPerformer, DialogOwner { } private ImageIcon createInfoIcon() { - return RailsIcon.INFO.largeIcon; + return RailsIcon.INFO.smallIcon; } public void keyPressed(KeyEvent e) { diff --git a/rails/ui/swing/elements/ActionButton.java b/rails/ui/swing/elements/ActionButton.java index 2594741..d07bbba 100644 --- a/rails/ui/swing/elements/ActionButton.java +++ b/rails/ui/swing/elements/ActionButton.java @@ -113,7 +113,8 @@ public class ActionButton extends JButton implements ActionTaker { } private boolean isIconSizeSmall() { - return "small".equals(Config.get("actionButton.iconSize")); + //small is default + return !"large".equals(Config.get("actionButton.iconSize")); } /** diff --git a/rails/ui/swing/elements/DockingFrame.java b/rails/ui/swing/elements/DockingFrame.java index 78edec1..82c0ea6 100644 --- a/rails/ui/swing/elements/DockingFrame.java +++ b/rails/ui/swing/elements/DockingFrame.java @@ -114,13 +114,14 @@ public abstract class DockingFrame extends JFrame { * The dockable is only deployed to the frame if deployDockables is called. */ protected void addDockable(JComponent c, - String dockableTitle, + String dockableConfigKey, int x, int y, int width, int height, DockableProperty dockableProperty) { + String dockableTitle = LocalText.getText(dockableConfigKey); DefaultSingleCDockable d = new DefaultSingleCDockable( dockableTitle, dockableTitle ); d.add( c, BorderLayout.CENTER ); - d.setTitleIcon(null); + d.setTitleIcon(RailsIcon.getByConfigKey(dockableConfigKey).smallIcon); d.setCloseable( ( dockableProperty == DockableProperty.closeable || dockableProperty == DockableProperty.initially_hidden ) commit 9ee0450b4dfce30542923740000d050bbe7b8cd1 Author: Frederick Weld <fre...@gm...> Date: Sat Feb 11 15:28:21 2012 +0100 Added framework for managing/displaying icons on ActionButtons RailsIcon and ActionButton have undergone rework / extensions. ActionButton's construction and setText is not based on label text any more. Instead RailsIcon enum instances are used for this purpose. Added two options (display text/icon/both and small/large icons). diff --git a/LocalisedText.properties b/LocalisedText.properties index a0f256f..a6f24f6 100644 --- a/LocalisedText.properties +++ b/LocalisedText.properties @@ -183,6 +183,8 @@ Config.infoText.sound.sfx.gen.newCurrentPlayer=<html>Enter assignment of sound e Config.infoText.sound.sfx.or.buyTrain=<html>Enter assignment of sound effect files to train types.<ul><li>Separate the assignments by commas.<li>Each assignment has the syntax trainName=complete file path<li>Default sound effect is defined by omitting "trainName=" in the assignment.</ul><strong>Examples:</strong><ul><li>Set default sound effect: <br><code>c:\BuyTrain-default.mp3</code><li>Set train-dependent sound effect and a default (for trains above 6): <br><code>2=c:\BuyTrain-2.mp3,3=c:\BuyTrain-3.mp3,4=c:\BuyTrain-4.mp3,5=c:\BuyTrain-5.mp3,6=c:\BuyTrain-6.mp3,c:\BuyTrain-D.mp3</code></ul> </html> Config.infoText.sound.sfx.or.setRevenue=<html><ul><li>Only the latter portion of this file is played.<ul><li>For an average revenue, the last third is played.</ul><li>The higher the company's revenue the longer this file is played.<ul><li>But the file is at most played once as a whole.</li></ul></html> Config.infoText.sound.sfx.sr.newPresident=This also includes becoming the president when buying the president share. +Config.label.actionButton.iconText=Button display type +Config.label.actionButton.iconSize=Icon size Config.label.default_game=Default game Config.label.default_players=Default players Config.label.font.ui.name=Font selection diff --git a/data/Properties.xml b/data/Properties.xml index da62099..b78d097 100644 --- a/data/Properties.xml +++ b/data/Properties.xml @@ -48,6 +48,10 @@ </Section> <Section name="Appearance"> <Property name="gridPanel.tableBorders" type="LIST" values="disabled,enabled"/> + <Property name="actionButton.iconText" type="LIST" values="text and icon,only text,only icon" + initClass="rails.ui.swing.elements.ActionButton" initMethod="resetRailsIcons" initParameter="no" /> + <Property name="actionButton.iconSize" type="LIST" values="small,large" + initClass="rails.ui.swing.elements.ActionButton" initMethod="resetRailsIcons" initParameter="no" /> <Property name="route.colour.1" type="COLOR" initClass="rails.ui.swing.hexmap.HexMap" initMethod="setRouteColours" /> <Property name="route.colour.2" type="COLOR" diff --git a/rails/ui/swing/ConfigWindow.java b/rails/ui/swing/ConfigWindow.java index 8c9e7e8..4d25293 100644 --- a/rails/ui/swing/ConfigWindow.java +++ b/rails/ui/swing/ConfigWindow.java @@ -419,7 +419,7 @@ class ConfigWindow extends JFrame { } // add info icon for infoText if (infoText != null) { - JLabel infoIcon = new JLabel(RailsIcon.INFO.icon); + JLabel infoIcon = new JLabel(RailsIcon.INFO.largeIcon); infoIcon.addMouseListener(new MouseListener() { public void mousePressed(MouseEvent e) { final JDialog dialog = new JDialog(ConfigWindow.this, false); diff --git a/rails/ui/swing/ORPanel.java b/rails/ui/swing/ORPanel.java index 280ef18..ec8c7ec 100644 --- a/rails/ui/swing/ORPanel.java +++ b/rails/ui/swing/ORPanel.java @@ -285,39 +285,39 @@ implements ActionListener, KeyListener, RevenueListener { private void initButtonPanel() { // sfy: operatingcosts button - buttonOC = new ActionButton(LocalText.getText("OCButtonLabel")); + buttonOC = new ActionButton(RailsIcon.OPERATING_COST); buttonOC.setActionCommand(OPERATING_COST_CMD); buttonOC.setMnemonic(KeyEvent.VK_O); buttonOC.addActionListener(this); buttonOC.setEnabled(false); buttonOC.setVisible(false); - button1 = new ActionButton(LocalText.getText("LayTile")); + button1 = new ActionButton(RailsIcon.LAY_TILE); button1.setActionCommand(LAY_TILE_CMD); button1.setMnemonic(KeyEvent.VK_T); button1.addActionListener(this); button1.setEnabled(false); - button2 = new ActionButton(LocalText.getText("BUY_PRIVATE")); + button2 = new ActionButton(RailsIcon.BUY_PRIVATE); button2.setActionCommand(BUY_PRIVATE_CMD); button2.setMnemonic(KeyEvent.VK_V); button2.addActionListener(this); button2.setEnabled(false); button2.setVisible(false); - button3 = new ActionButton(LocalText.getText("Done")); + button3 = new ActionButton(RailsIcon.DONE); button3.setActionCommand(DONE_CMD); button3.setMnemonic(KeyEvent.VK_D); button3.addActionListener(this); button3.setEnabled(false); - undoButton = new ActionButton(LocalText.getText("UNDO")); + undoButton = new ActionButton(RailsIcon.UNDO); undoButton.setActionCommand(UNDO_CMD); undoButton.setMnemonic(KeyEvent.VK_U); undoButton.addActionListener(this); undoButton.setEnabled(false); - redoButton = new ActionButton(LocalText.getText("REDO")); + redoButton = new ActionButton(RailsIcon.REDO); redoButton.setActionCommand(REDO_CMD); redoButton.setMnemonic(KeyEvent.VK_R); redoButton.addActionListener(this); @@ -1134,7 +1134,7 @@ implements ActionListener, KeyListener, RevenueListener { setSelect(revenue[orCompIndex], revenueSelect[orCompIndex], true); - button1.setText(LocalText.getText("SET_REVENUE")); + button1.setRailsIcon(RailsIcon.SET_REVENUE); button1.setActionCommand(SET_REVENUE_CMD); button1.setPossibleAction(action); button1.setMnemonic(KeyEvent.VK_R); @@ -1183,7 +1183,7 @@ implements ActionListener, KeyListener, RevenueListener { setSelect(revenue[orCompIndex], revenueSelect[orCompIndex], false); if (withhold) { - button1.setText(LocalText.getText("WITHHOLD")); + button1.setRailsIcon(RailsIcon.WITHOLD); button1.setActionCommand(WITHHOLD_CMD); clonedAction = (SetDividend) action.clone(); clonedAction.setRevenueAllocation(SetDividend.WITHHOLD); @@ -1196,7 +1196,7 @@ implements ActionListener, KeyListener, RevenueListener { } if (split) { - button2.setText(LocalText.getText("SPLIT")); + button2.setRailsIcon(RailsIcon.SPLIT); button2.setActionCommand(SPLIT_CMD); clonedAction = (SetDividend) action.clone(); clonedAction.setRevenueAllocation(SetDividend.SPLIT); @@ -1209,7 +1209,7 @@ implements ActionListener, KeyListener, RevenueListener { } if (payout) { - button3.setText(LocalText.getText("PAYOUT")); + button3.setRailsIcon(RailsIcon.PAYOUT); button3.setActionCommand(PAYOUT_CMD); clonedAction = (SetDividend) action.clone(); clonedAction.setRevenueAllocation(SetDividend.PAYOUT); @@ -1227,7 +1227,7 @@ implements ActionListener, KeyListener, RevenueListener { setHighlight(trains[orCompIndex],true); setHighlight(newTrainCost[orCompIndex],true); - button1.setText(LocalText.getText("BUY_TRAIN")); + button1.setRailsIcon(RailsIcon.BUY_TRAIN); button1.setActionCommand(BUY_TRAIN_CMD); button1.setMnemonic(KeyEvent.VK_T); button1.setEnabled(enabled); @@ -1248,7 +1248,7 @@ implements ActionListener, KeyListener, RevenueListener { if (privatesCanBeBought) { if (enabled) { - button2.setText(LocalText.getText("BUY_PRIVATE")); + button2.setRailsIcon(RailsIcon.BUY_PRIVATE); button2.setActionCommand(BUY_PRIVATE_CMD); button2.setMnemonic(KeyEvent.VK_V); } @@ -1280,7 +1280,7 @@ implements ActionListener, KeyListener, RevenueListener { public void enableDone(NullAction action) { - button3.setText(LocalText.getText("Done")); + button3.setRailsIcon(RailsIcon.DONE); button3.setActionCommand(DONE_CMD); button3.setMnemonic(KeyEvent.VK_D); button3.setPossibleAction(action); @@ -1310,7 +1310,7 @@ implements ActionListener, KeyListener, RevenueListener { loansCaption.setHighlight(true); setHighlight(compLoans[orCompIndex],true); - button1.setText(LocalText.getText("RepayLoans")); + button1.setRailsIcon(RailsIcon.REPAY_LOANS); button1.setActionCommand(REPAY_LOANS_CMD); button1.setPossibleAction(action); button1.setMnemonic(KeyEvent.VK_R); diff --git a/rails/ui/swing/ReportWindowDynamic.java b/rails/ui/swing/ReportWindowDynamic.java index a5c6128..00daad2 100644 --- a/rails/ui/swing/ReportWindowDynamic.java +++ b/rails/ui/swing/ReportWindowDynamic.java @@ -22,6 +22,7 @@ import rails.game.action.PossibleActions; import rails.game.move.MoveStack; import rails.sound.SoundManager; import rails.ui.swing.elements.ActionButton; +import rails.ui.swing.elements.RailsIcon; /** * Dynamic Report window that acts as linked game history @@ -109,11 +110,11 @@ public class ReportWindowDynamic extends AbstractReportWindow implements Action buttonPanel = new JPanel(); add(buttonPanel, "South"); - backwardButton = new ActionButton(LocalText.getText("REPORT_MOVE_BACKWARD")); + backwardButton = new ActionButton(RailsIcon.REPORT_MOVE_BACKWARD); backwardButton.addActionListener(this); buttonPanel.add(backwardButton); - forwardButton = new ActionButton(LocalText.getText("REPORT_MOVE_FORWARD")); + forwardButton = new ActionButton(RailsIcon.REPORT_MOVE_FORWARD); forwardButton.addActionListener(this); buttonPanel.add(forwardButton); diff --git a/rails/ui/swing/StartRoundWindow.java b/rails/ui/swing/StartRoundWindow.java index 1ff36cd..a2c83eb 100644 --- a/rails/ui/swing/StartRoundWindow.java +++ b/rails/ui/swing/StartRoundWindow.java @@ -134,14 +134,14 @@ implements ActionListener, KeyListener, ActionPerformer, DialogOwner { buttonPanel = new JPanel(); - buyButton = new ActionButton(LocalText.getText("BUY")); + buyButton = new ActionButton(RailsIcon.BUY); buyButton.setMnemonic(KeyEvent.VK_B); buyButton.addActionListener(this); buyButton.setEnabled(false); buttonPanel.add(buyButton); if (includeBidding) { - bidButton = new ActionButton(LocalText.getText("BID") + ":"); + bidButton = new ActionButton(RailsIcon.BID); bidButton.setMnemonic(KeyEvent.VK_D); bidButton.addActionListener(this); bidButton.setEnabled(false); @@ -156,7 +156,7 @@ implements ActionListener, KeyListener, ActionPerformer, DialogOwner { buttonPanel.add(bidAmount); } - passButton = new ActionButton(LocalText.getText("PASS")); + passButton = new ActionButton(RailsIcon.PASS); passButton.setMnemonic(KeyEvent.VK_P); passButton.addActionListener(this); passButton.setEnabled(false); @@ -518,7 +518,7 @@ implements ActionListener, KeyListener, ActionPerformer, DialogOwner { // only one NullAction is allowed NullAction na = inactiveItems.get(0); // nullActions differ in text to display - passButton.setText(LocalText.getText(na.toString())); + passButton.setRailsIcon(RailsIcon.getByConfigKey(na.toString())); passAllowed = true; passButton.setPossibleAction(na); passButton.setMnemonic(KeyEvent.VK_P); @@ -586,7 +586,7 @@ implements ActionListener, KeyListener, ActionPerformer, DialogOwner { // In this case, "Pass" becomes "Select, don't buy" passButton.setPossibleAction(currentActiveItem); passButton.setEnabled(true); - passButton.setText(LocalText.getText("SelectNoBid")); + passButton.setRailsIcon(RailsIcon.SELECT_NO_BID); passButton.setVisible(true); // if (!repacked) { pack(); @@ -797,7 +797,7 @@ implements ActionListener, KeyListener, ActionPerformer, DialogOwner { } private ImageIcon createInfoIcon() { - return RailsIcon.INFO.icon; + return RailsIcon.INFO.largeIcon; } public void keyPressed(KeyEvent e) { diff --git a/rails/ui/swing/StatusWindow.java b/rails/ui/swing/StatusWindow.java index 77db336..6271180 100644 --- a/rails/ui/swing/StatusWindow.java +++ b/rails/ui/swing/StatusWindow.java @@ -285,13 +285,13 @@ KeyListener, ActionPerformer { buttonPanel = new JPanel(); - passButton = new ActionButton(LocalText.getText("PASS")); + passButton = new ActionButton(RailsIcon.PASS); passButton.setMnemonic(KeyEvent.VK_P); buttonPanel.add(passButton); passButton.setActionCommand(DONE_CMD); passButton.addActionListener(this); - autopassButton = new ActionButton(LocalText.getText("Autopass")); + autopassButton = new ActionButton(RailsIcon.AUTOPASS); autopassButton.setMnemonic(KeyEvent.VK_A); buttonPanel.add(autopassButton); autopassButton.setActionCommand(AUTOPASS_CMD); @@ -547,14 +547,14 @@ KeyListener, ActionPerformer { for (NullAction na : inactiveItems) { switch (na.getMode()) { case NullAction.PASS: - passButton.setText(LocalText.getText("PASS")); + passButton.setRailsIcon(RailsIcon.PASS); passButton.setEnabled(true); passButton.setActionCommand(PASS_CMD); passButton.setMnemonic(KeyEvent.VK_P); passButton.setPossibleAction(na); break; case NullAction.DONE: - passButton.setText(LocalText.getText("Done")); + passButton.setRailsIcon(RailsIcon.DONE); passButton.setEnabled(true); passButton.setActionCommand(DONE_CMD); passButton.setMnemonic(KeyEvent.VK_D); @@ -698,9 +698,9 @@ KeyListener, ActionPerformer { if (action != null) { int mode = action.getMode(); if (mode == NullAction.PASS) { - passButton.setText(LocalText.getText("PASS")); + passButton.setRailsIcon(RailsIcon.PASS); } else if (mode == NullAction.DONE) { - passButton.setText(LocalText.getText("Done")); + passButton.setRailsIcon(RailsIcon.DONE); } passButton.setEnabled(true); passButton.setVisible(true); @@ -750,7 +750,7 @@ KeyListener, ActionPerformer { // Enable Passbutton passButton.setEnabled(true); - passButton.setText(LocalText.getText("END_OF_GAME_CLOSE_ALL_WINDOWS")); + passButton.setRailsIcon(RailsIcon.END_OF_GAME_CLOSE_ALL_WINDOWS); gameUIManager.orWindow.finish(); } diff --git a/rails/ui/swing/elements/ActionButton.java b/rails/ui/swing/elements/ActionButton.java index b2c06aa..2594741 100644 --- a/rails/ui/swing/elements/ActionButton.java +++ b/rails/ui/swing/elements/ActionButton.java @@ -1,11 +1,16 @@ /* $Header: /Users/blentz/rails_rcs/cvs/18xx/rails/ui/swing/elements/ActionButton.java,v 1.5 2008/06/04 19:00:38 evos Exp $*/ package rails.ui.swing.elements; +import java.awt.Insets; import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; import java.util.List; +import java.util.Set; import javax.swing.JButton; +import rails.common.parser.Config; import rails.game.action.ActionTaker; import rails.game.action.PossibleAction; @@ -18,10 +23,34 @@ public class ActionButton extends JButton implements ActionTaker { private static final long serialVersionUID = 1L; + private static final Set<String> KEYS_TEXT_DISPLAY = new HashSet<String> + (Arrays.asList( new String[] { + "text and icon", + "only text", + "", + null + })); + private static final Set<String> KEYS_ICON_DISPLAY = new HashSet<String> + (Arrays.asList( new String[] { + "text and icon", + "only icon" + })); + + private static Set<ActionButton> actionButtons = new HashSet<ActionButton>(); + private List<PossibleAction> actions = new ArrayList<PossibleAction>(1); - public ActionButton(String text) { - super(text); + /** + * null value means that the action button is not set up by an appropriate + * RailsIcon (eg., by calling setText directly). + */ + private RailsIcon railsIcon = null; + + public ActionButton(RailsIcon railsIcon) { + super(); + setRailsIcon(railsIcon); + this.setMargin(new Insets(2,2,2,2)); + actionButtons.add(this); } public void addPossibleAction(PossibleAction o) { @@ -41,4 +70,70 @@ public class ActionButton extends JButton implements ActionTaker { addPossibleAction(action); } + public void setRailsIcon(RailsIcon railsIcon) { + if (railsIcon == null) railsIcon = RailsIcon.NULL; + this.railsIcon = railsIcon; + showRailsIcon(); + } + + /** + * Display according to configuration. + * If no text/icon is attached, then icon/text is displayed as fallback + * (irrespective of configuration). + * Text becomes the tool tip text in case of icon-only display. + */ + private void showRailsIcon() { + if (railsIcon != null) { + if (isTextEnabled() || railsIcon.largeIcon == null) { + super.setText(railsIcon.description); + } else { + super.setText(null); + } + if (isIconEnabled() || railsIcon.description == null) { + if (isIconSizeSmall()) { + super.setIcon(railsIcon.smallIcon); + } else { + super.setIcon(railsIcon.largeIcon); + } + if (!isTextEnabled()) { + super.setToolTipText(railsIcon.description); + } + } else { + super.setIcon(null); + } + } + } + + private boolean isTextEnabled() { + return KEYS_TEXT_DISPLAY.contains(Config.get("actionButton.iconText","")); + } + + private boolean isIconEnabled() { + return KEYS_ICON_DISPLAY.contains(Config.get("actionButton.iconText","")); + } + + private boolean isIconSizeSmall() { + return "small".equals(Config.get("actionButton.iconSize")); + } + + /** + * Should only be used if an arbitrary text is to displayed without icon. + * In any other case, setRailsIcon should be used. + */ + @Override + public void setText(String text) { + super.setText(text); + setIcon(null); + railsIcon = null; + } + + /** + * To be called upon change of button display type + */ + public static void resetRailsIcons() { + for (ActionButton ab : actionButtons) { + ab.showRailsIcon(); + } + } + } diff --git a/rails/ui/swing/elements/RailsIcon.java b/rails/ui/swing/elements/RailsIcon.java index 0eaba36..eed61ff 100644 --- a/rails/ui/swing/elements/RailsIcon.java +++ b/rails/ui/swing/elements/RailsIcon.java @@ -1,30 +1,125 @@ package rails.ui.swing.elements; +import java.awt.Image; + import javax.swing.ImageIcon; +import rails.common.LocalText; + /** * Enumeration that provides a specific ImageIcon - * Simply use RailsIcon.{IconName}.create + * Simply use RailsIcon.{IconName}.icon/description * @author freystef */ public enum RailsIcon { // in parentheses the image file - INFO ("Inform.gif"); - - private final static String IMAGE_PATH = "/rails/ui/images/"; - public final ImageIcon icon; + AUTOPASS ("","Autopass"), + BID ("","BID"), + BUY ("","BUY"), + BUY_PRIVATE ("","BUY_PRIVATE"), + BUY_TRAIN ("","BUY_TRAIN"), + DONE ("","Done"), + END_OF_GAME_CLOSE_ALL_WINDOWS ("","END_OF_GAME_CLOSE_ALL_WINDOWS"), + INFO ("Inform.gif","Info"), + LAY_TILE ("","LayTile"), + OPERATING_COST ("","OCButtonLabel"), + PASS ("","PASS"), + PAYOUT ("","PAYOUT"), + REDO ("","REDO"), + REPAY_LOANS ("","RepayLoans"), + REPORT_MOVE_BACKWARD ("","REPORT_MOVE_BACKWARD"), + REPORT_MOVE_FORWARD ("","REPORT_MOVE_FORWARD"), + SELECT_NO_BID ("","SelectNoBid"), + SET_REVENUE ("","SET_REVENUE"), + SPLIT ("","SPLIT"), + UNDO ("","UNDO"), + WITHOLD ("","WITHHOLD"), + + //null meaning all public fields are null + NULL (); + + private final static String IMAGE_PATH = "/rails/ui/images/"; + private final static int SMALL_IMAGE_WIDTH = 16; + private final static int SMALL_IMAGE_HEIGHT = 16; + private final String configKey; + /** + * icon in original resolution + */ + public final ImageIcon largeIcon; + /** + * icon in restricted / small resolution + */ + public final ImageIcon smallIcon; + public final String description; + + private RailsIcon() { + configKey = null; + largeIcon = null; + smallIcon = null; + description = null; + } + + private RailsIcon(String fileName,String configKey) { + this.configKey = configKey; + this.description = LocalText.getText(configKey); + largeIcon = createIcon(fileName,description); + smallIcon = createSmallIcon(largeIcon); + } - private RailsIcon(String fileName) { + private ImageIcon createIcon(String fileName, String description) { + //check whether icon is expected to be found + //don't write error messages if icon not expected to be found + if (fileName == null || fileName.equals("")) { + return null; + } + + //get icon String path = IMAGE_PATH + fileName; java.net.URL imgURL = getClass().getResource(path); if (imgURL != null) { - icon = new ImageIcon(imgURL, "Info"); + return new ImageIcon(imgURL, description); } else { System.err.println("Couldn't find file: " + path); - icon = null; + return null; + } + } + + private ImageIcon createSmallIcon(ImageIcon originalIcon) { + ImageIcon smallIcon = null; + if (originalIcon != null) { + Image img = originalIcon.getImage(); + if (img != null) { + smallIcon = new ImageIcon( + img.getScaledInstance( + SMALL_IMAGE_WIDTH, + SMALL_IMAGE_HEIGHT, + Image.SCALE_SMOOTH + ), + originalIcon.getDescription() + ); + } + } + return smallIcon; + } + + /** + * @return The Rails icon associated with the key or, if nothing is found, + * RailsConfig.NULL + */ + public static RailsIcon getByConfigKey(String configKey) { + if (configKey == null) return RailsIcon.NULL; + + RailsIcon ri = null; + for (RailsIcon r : RailsIcon.values()) { + //ignore case necessary as both Pass and PASS are used by consumers + if (configKey.equalsIgnoreCase(r.configKey)) ri = r; + } + if (ri == null) { + ri = RailsIcon.NULL; } + return ri; } } |
From: Frederick W. <fre...@us...> - 2012-02-10 17:58:59
|
LocalisedText.properties | 1 rails/ui/swing/ORPanel.java | 18 +++-- rails/ui/swing/ORWindow.java | 39 +++++++---- rails/ui/swing/RemainingTilesWindow.java | 80 +++++++++++++++++++----- rails/ui/swing/elements/DockingFrame.java | 98 ++++++++++++++++++++++++------ 5 files changed, 184 insertions(+), 52 deletions(-) New commits: commit feb1ae94d3506dcd676c09e9b439e8df894c2d6a Author: Frederick Weld <fre...@gm...> Date: Fri Feb 10 18:25:48 2012 +0100 Included "Remaining Tiles" into docking layout (as a dockable) Change only applies to the docking layout. Now, the remaining tiles panel is part of the ORWindow. Its activation/positioning is done in the context of the docking framework instead of the ORPanel menu and the JFrame. Additionally, docking framework handles the tiles / messages window as closable dockables. A dedicated menu option is available for toggling the visibility. diff --git a/LocalisedText.properties b/LocalisedText.properties index 4f344b2..a0f256f 100644 --- a/LocalisedText.properties +++ b/LocalisedText.properties @@ -295,6 +295,7 @@ Dockable.orWindow.buttonPanel = Commands Dockable.orWindow.mapPanel = Map Dockable.orWindow.messagePanel = Messages Dockable.orWindow.orPanel = Companies +Dockable.orWindow.remainingTilesPanel = Tiles Dockable.orWindow.upgradePanel = Upgrades DockingFrame.menu.layout = Layout DockingFrame.menu.layout.applyFrom = Apply From... diff --git a/rails/ui/swing/ORPanel.java b/rails/ui/swing/ORPanel.java index bd3ea58..280ef18 100644 --- a/rails/ui/swing/ORPanel.java +++ b/rails/ui/swing/ORPanel.java @@ -171,11 +171,17 @@ implements ActionListener, KeyListener, RevenueListener { infoMenu = new JMenu(LocalText.getText("Info")); infoMenu.setEnabled(true); - remainingTilesMenuItem = - new JMenuItem(LocalText.getText("RemainingTiles")); - remainingTilesMenuItem.addActionListener(this); - remainingTilesMenuItem.setActionCommand(REM_TILES_CMD); - infoMenu.add(remainingTilesMenuItem); + + //only add remaining tiles display option for conventional layout + //as this is always included as a dockable panel in the docking frame layout + if (!parent.isDockingFrameworkEnabled()) { + remainingTilesMenuItem = + new JMenuItem(LocalText.getText("RemainingTiles")); + remainingTilesMenuItem.addActionListener(this); + remainingTilesMenuItem.setActionCommand(REM_TILES_CMD); + infoMenu.add(remainingTilesMenuItem); + } + menuBar.add(infoMenu); addCompanyInfo(); @@ -1360,4 +1366,4 @@ implements ActionListener, KeyListener, RevenueListener { public JMenuBar getMenuBar() { return menuBar; } -} \ No newline at end of file +} diff --git a/rails/ui/swing/ORWindow.java b/rails/ui/swing/ORWindow.java index 278e9b0..acee3e9 100644 --- a/rails/ui/swing/ORWindow.java +++ b/rails/ui/swing/ORWindow.java @@ -63,8 +63,8 @@ public class ORWindow extends DockingFrame implements ActionPerformer { orUIManager.setGameUIManager(gameUIManager); messagePanel = new MessagePanel(); - JScrollPane slider = new JScrollPane(messagePanel); - messagePanel.setParentSlider(slider); + JScrollPane messagePanelSlider = new JScrollPane(messagePanel); + messagePanel.setParentSlider(messagePanelSlider); upgradePanel = new UpgradesPanel(orUIManager); addMouseListener(upgradePanel); @@ -72,22 +72,33 @@ public class ORWindow extends DockingFrame implements ActionPerformer { mapPanel = new MapPanel(gameUIManager); orPanel = new ORPanel(this, orUIManager); - + //create docking / conventional layout if (isDockingFrameworkEnabled()) { + + //initialize remaining tile panel as it is no optional part in the docking layout + JScrollPane remainingTilesPanelSlider = + new RemainingTilesWindow(this).getScrollPane(); //generate layout - addDockable ( slider, LocalText.getText("Dockable.orWindow.messagePanel"), - 0, 0, 100, 10); - addDockable ( upgradePanel, LocalText.getText("Dockable.orWindow.upgradePanel"), - 0, 10, 20, 70); - addDockable ( mapPanel, LocalText.getText("Dockable.orWindow.mapPanel"), - 20, 10, 80, 70); - addDockable ( orPanel, LocalText.getText("Dockable.orWindow.orPanel"), - 0, 80, 100, 15); + addDockable ( messagePanelSlider, + LocalText.getText("Dockable.orWindow.messagePanel"), + 0, 0, 100, 10, DockableProperty.closeable); + addDockable ( upgradePanel, + LocalText.getText("Dockable.orWindow.upgradePanel"), + 0, 10, 20, 70, DockableProperty.standard); + addDockable ( mapPanel, + LocalText.getText("Dockable.orWindow.mapPanel"), + 20, 10, 80, 70, DockableProperty.standard); + addDockable ( remainingTilesPanelSlider, + LocalText.getText("Dockable.orWindow.remainingTilesPanel"), + 100, 0, 120, 100, DockableProperty.initially_hidden); + addDockable ( orPanel, + LocalText.getText("Dockable.orWindow.orPanel"), + 0, 80, 100, 15, DockableProperty.standard); addDockable ( orPanel.getButtonPanel(), LocalText.getText("Dockable.orWindow.buttonPanel"), - 0, 95, 100, 5); + 0, 95, 100, 5, DockableProperty.standard); deployDockables(); //take over or panel's menu bar as the frame menu bar @@ -99,7 +110,7 @@ public class ORWindow extends DockingFrame implements ActionPerformer { // CONVENTIONAL LAYOUT getContentPane().setLayout(new BorderLayout()); - getContentPane().add(slider, BorderLayout.NORTH); + getContentPane().add(messagePanelSlider, BorderLayout.NORTH); getContentPane().add(mapPanel, BorderLayout.CENTER); getContentPane().add(upgradePanel, BorderLayout.WEST); getContentPane().add(orPanel, BorderLayout.SOUTH); @@ -268,4 +279,4 @@ public class ORWindow extends DockingFrame implements ActionPerformer { + gameUIManager.getGameManager().getGameName() ; } -} \ No newline at end of file +} diff --git a/rails/ui/swing/RemainingTilesWindow.java b/rails/ui/swing/RemainingTilesWindow.java index f969505..0c3924f 100644 --- a/rails/ui/swing/RemainingTilesWindow.java +++ b/rails/ui/swing/RemainingTilesWindow.java @@ -44,6 +44,7 @@ public class RemainingTilesWindow extends JFrame implements WindowListener, tilePanel = new AlignedWidthPanel(); slider = new JScrollPane(tilePanel); slider.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED); + slider.setPreferredSize(new Dimension(200,200)); tilePanel.setParentSlider(slider); //use flow layout as it provides for necessary line breaks @@ -53,7 +54,7 @@ public class RemainingTilesWindow extends JFrame implements WindowListener, //setup the JFrame and assign the contents (slider containing tilePane) //only for conventional layout as this is a dockable pane for the docking layout - if (true || !orWindow.isDockingFrameworkEnabled()) { + if (!orWindow.isDockingFrameworkEnabled()) { setTitle("Rails: Remaining Tiles"); setVisible(false); setContentPane(slider); diff --git a/rails/ui/swing/elements/DockingFrame.java b/rails/ui/swing/elements/DockingFrame.java index 8cc1203..78edec1 100644 --- a/rails/ui/swing/elements/DockingFrame.java +++ b/rails/ui/swing/elements/DockingFrame.java @@ -4,6 +4,8 @@ import java.awt.BorderLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.File; +import java.util.ArrayList; +import java.util.List; import java.util.Locale; import javax.swing.JComponent; @@ -30,14 +32,17 @@ import bibliothek.gui.dock.common.action.predefined.CBlank; import bibliothek.gui.dock.common.event.CDockableStateListener; import bibliothek.gui.dock.common.intern.CDockable; import bibliothek.gui.dock.common.intern.DefaultCDockable; +import bibliothek.gui.dock.common.intern.DefaultCommonDockable; import bibliothek.gui.dock.common.intern.ui.CSingleParentRemover; import bibliothek.gui.dock.common.menu.CThemeMenuPiece; +import bibliothek.gui.dock.common.menu.SingleCDockableListMenuPiece; import bibliothek.gui.dock.common.mode.ExtendedMode; import bibliothek.gui.dock.common.theme.ThemeMap; import bibliothek.gui.dock.event.DockStationAdapter; import bibliothek.gui.dock.facile.menu.RootMenuPiece; import bibliothek.gui.dock.facile.menu.SubmenuPiece; import bibliothek.gui.dock.station.LayoutLocked; +import bibliothek.gui.dock.support.menu.SeparatingMenuPiece; import org.apache.log4j.Logger; @@ -53,6 +58,7 @@ import org.apache.log4j.Logger; * */ public abstract class DockingFrame extends JFrame { + public static enum DockableProperty { standard, closeable, initially_hidden }; private static final long serialVersionUID = 1L; private static final String layoutDirectoryName = "DockableLayout"; private static final String layoutFileSuffix = "_layout.rails_ini"; @@ -64,7 +70,13 @@ public abstract class DockingFrame extends JFrame { private boolean isDockingFrameworkEnabled; private CControl control = null; private CGrid gridLayout = null; - + + /** + * All dockables under the control (currently only single dockables) + */ + List<DefaultSingleCDockable> dockables = new ArrayList<DefaultSingleCDockable>(); + List<DefaultSingleCDockable> dockables_initiallyHidden = new ArrayList<DefaultSingleCDockable>(); + /** * Decision whether docking framework should be activated for a frame * has to be done at the beginning as later switching is not supported @@ -101,19 +113,34 @@ public abstract class DockingFrame extends JFrame { * Registers a component that is to become a dockable. * The dockable is only deployed to the frame if deployDockables is called. */ - protected void addDockable(JComponent c, String dockableTitle, int x, int y, int width, int height) { + protected void addDockable(JComponent c, + String dockableTitle, + int x, int y, int width, int height, + DockableProperty dockableProperty) { DefaultSingleCDockable d = new DefaultSingleCDockable( dockableTitle, dockableTitle ); d.add( c, BorderLayout.CENTER ); - d.setCloseable( false ); + d.setTitleIcon(null); + d.setCloseable( + ( dockableProperty == DockableProperty.closeable + || dockableProperty == DockableProperty.initially_hidden ) + ); gridLayout.add( x, y, width, height, d ); + dockables.add(d); + if (dockableProperty == DockableProperty.initially_hidden) { + dockables_initiallyHidden.add(d); + } } /** - * Deploys to the frame all dockables that have been added before + * Deploys to the frame all dockables that have been added before. + * Dockables are initially set to invisible if this is as specified */ protected void deployDockables() { control.getContentArea().deploy( gridLayout ); + for (CDockable d : dockables_initiallyHidden) { + if (d.isCloseable()) d.setVisible(false); + } } /** @@ -123,12 +150,26 @@ public abstract class DockingFrame extends JFrame { RootMenuPiece layoutMenu = new RootMenuPiece( LocalText.getText("DockingFrame.menu.layout"), false); + layoutMenu.add( new SubmenuPiece( LocalText.getText("DockingFrame.menu.layout.theme"), false, new CThemeMenuPiece( control ) )); - layoutMenu.getMenu().addSeparator(); + + SingleCDockableListMenuPiece closeableDockableMenuPiece = + new SingleCDockableListMenuPiece(control) { + @Override + protected void show(Dockable dockable) { + super.show(dockable); + //ensure that, if the dockable is externalized, the max button is disabled + if (dockable instanceof DefaultCommonDockable) { + adjustExternalizedActions((DefaultCommonDockable)dockable); + } + } + }; + layoutMenu.add(new SeparatingMenuPiece(closeableDockableMenuPiece,true,true,true)); + JMenuItem resetMenuItem = new JMenuItem ( LocalText.getText("DockingFrame.menu.layout.reset")); resetMenuItem.addActionListener(new ActionListener() { @@ -224,22 +265,42 @@ public abstract class DockingFrame extends JFrame { return; } - //ensure that all dockables that are externalized according to layout - //information don't have the default maximize button (as it won't work - //for the adjusted externalization setup) - for (int i = 0 ; i < control.getCDockableCount() ; i++ ) { - CDockable d = control.getCDockable(i); - if (d instanceof DefaultCDockable) { - DefaultCDockable dd = (DefaultCDockable)d; - if (ExtendedMode.EXTERNALIZED.equals(d.getExtendedMode())) { - dd.putAction( CDockable.ACTION_KEY_MAXIMIZE, CBlank.BLANK ); - } else { - dd.putAction( CDockable.ACTION_KEY_MAXIMIZE, null ); - } + adjustExternalizedActions(); + } + + /** + * Ensures for all dockables that, if they are externalized, they do not have + * the default maximize button + * (as it won't work for the adjusted externalization setup). + */ + private void adjustExternalizedActions() { + for (CDockable d : dockables) { + adjustExternalizedActions(d); + } + } + + /** + * Ensure that externalized dockable does not have default maximize button + * (as it won't work for the adjusted externalization setup). + * @param d Dockable for which the actions are to be adjusted + */ + private void adjustExternalizedActions(CDockable d) { + if (d instanceof DefaultSingleCDockable) { + DefaultSingleCDockable sd = (DefaultSingleCDockable)d; + if (ExtendedMode.EXTERNALIZED.equals(sd.getExtendedMode())) { + sd.putAction( CDockable.ACTION_KEY_MAXIMIZE, CBlank.BLANK ); + } else { + sd.putAction( CDockable.ACTION_KEY_MAXIMIZE, null ); } } } + private void adjustExternalizedActions(Dockable d) { + if (d instanceof DefaultCommonDockable) { + adjustExternalizedActions(((DefaultCommonDockable)d).getDockable()); + } + } + /** * Lets user choose a layout in a file chooser popup and then loads/applies it */ @@ -340,6 +401,9 @@ public abstract class DockingFrame extends JFrame { // and enable events after we finished controller.meltLayout(); } + + //ensure the correct availability of the maximize button + adjustExternalizedActions(dockable); } } commit e2fd3ff42eea4edeee1d7a97f579e750af729d84 Author: Frederick Weld <fre...@gm...> Date: Thu Feb 9 20:13:41 2012 +0100 Enabled variable layout of "Remaining Tiles" incl. vertical scroll bar diff --git a/rails/ui/swing/RemainingTilesWindow.java b/rails/ui/swing/RemainingTilesWindow.java index 9c9d2ff..f969505 100644 --- a/rails/ui/swing/RemainingTilesWindow.java +++ b/rails/ui/swing/RemainingTilesWindow.java @@ -1,7 +1,9 @@ /* $Header: /Users/blentz/rails_rcs/cvs/18xx/rails/ui/swing/RemainingTilesWindow.java,v 1.8 2009/12/15 18:56:11 evos Exp $*/ package rails.ui.swing; -import java.awt.GridLayout; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.FlowLayout; import java.awt.Image; import java.awt.event.*; import java.awt.image.BufferedImage; @@ -20,39 +22,49 @@ import rails.ui.swing.elements.Field; import rails.ui.swing.hexmap.GUIHex; /** - * This Window displays the available operations that may be performed during an - * Operating Round. This window also contains the Game Map. + * This Window displays the availability of tiles. */ public class RemainingTilesWindow extends JFrame implements WindowListener, ActionListener { private static final long serialVersionUID = 1L; private GameUIManager gameUIManager; private ORUIManager orUIManager; + private AlignedWidthPanel tilePanel; + private JScrollPane slider; private List<Field> labels = new ArrayList<Field>(); private List<TileI> shownTiles = new ArrayList<TileI>(); - private final static int COLUMNS = 10; - protected static Logger log = Logger.getLogger(RemainingTilesWindow.class.getPackage().getName()); public RemainingTilesWindow(ORWindow orWindow) { super(); - getContentPane().setLayout(new GridLayout(0, COLUMNS, 5, 5)); + tilePanel = new AlignedWidthPanel(); + slider = new JScrollPane(tilePanel); + slider.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED); + tilePanel.setParentSlider(slider); - setTitle("Rails: Remaining Tiles"); - setVisible(false); - setSize(800, 600); - addWindowListener(this); + //use flow layout as it provides for necessary line breaks + tilePanel.setLayout(new FlowLayout(FlowLayout.LEFT)); init(orWindow.getGameUIManager()); - this.setDefaultCloseOperation(WindowConstants.HIDE_ON_CLOSE); - this.setLocationRelativeTo(orWindow); - pack(); - setVisible(true); + //setup the JFrame and assign the contents (slider containing tilePane) + //only for conventional layout as this is a dockable pane for the docking layout + if (true || !orWindow.isDockingFrameworkEnabled()) { + setTitle("Rails: Remaining Tiles"); + setVisible(false); + setContentPane(slider); + setSize(800, 600); + addWindowListener(this); + + this.setDefaultCloseOperation(WindowConstants.HIDE_ON_CLOSE); + this.setLocationRelativeTo(orWindow); + + setVisible(true); + } } private void init(GameUIManager gameUIManager) { @@ -87,7 +99,7 @@ public class RemainingTilesWindow extends JFrame implements WindowListener, label.setHorizontalTextPosition(Field.CENTER); label.setVisible(true); - getContentPane().add(label); + tilePanel.add(label); shownTiles.add(tile); labels.add(label); @@ -134,4 +146,41 @@ public class RemainingTilesWindow extends JFrame implements WindowListener, * */ public void finish() {} + + /** + * @return The scroll pane which holds as child the tile panel + */ + public JScrollPane getScrollPane() { + return slider; + } + + /** + * custom content pane that will align its width with the parent scroll pane + * needed to ensure only vertical scroll bar is used + */ + private static class AlignedWidthPanel extends JPanel { + private static final long serialVersionUID = 1L; + private JScrollPane parentSlider = null; + @Override + public Dimension getPreferredSize() { + //width based on parent slider + int width = parentSlider.getSize().width + - parentSlider.getVerticalScrollBar().getWidth() + - 5; + if (width <= 0) width = 1; + + //height based on contained components + //(no need to take into account width discrepancies since + // method is invoked several times) + int height = 1; //minimum height + for (Component c : this.getComponents()) { + height = Math.max(height, c.getY() + c.getHeight()); + } + return new Dimension (width , height); + } + public void setParentSlider(JScrollPane parentSlider) { + this.parentSlider = parentSlider; + } + } + } |
From: Frederick W. <fre...@us...> - 2012-02-08 18:31:46
|
rails/ui/swing/MessagePanel.java | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) New commits: commit f9839fa2ddce01e0b850d384fa10613f7de51812 Author: Frederick Weld <fre...@gm...> Date: Wed Feb 8 19:29:33 2012 +0100 Allowed for dynamic line breaks and vertical centering of message panel Main motivation for rework is that the dockable message text might be put in a vertical alignment (of narrow width). For the message panel, new behavior is that - no horizontal scroll bar is used - if panel's width inferior to message label's native width, a line break is inserted into the label text - technically done by using a layout manager and basing the panel's preferred width on the parent scrollpane's one An additional benefit of using the layout manager is that, for the first time since having added the scrollbar to the panel, messages are vertically centered. diff --git a/rails/ui/swing/MessagePanel.java b/rails/ui/swing/MessagePanel.java index 3b3d2cc..ed785de 100644 --- a/rails/ui/swing/MessagePanel.java +++ b/rails/ui/swing/MessagePanel.java @@ -3,6 +3,7 @@ package rails.ui.swing; import java.awt.Color; import java.awt.Dimension; +import java.awt.GridLayout; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; @@ -37,6 +38,10 @@ public class MessagePanel extends JPanel { setBackground(background); setBorder(new EmptyBorder(0,0,0,0)); + //add layout manager + //necessary for auto word-wrap when diminishing width + setLayout(new GridLayout(1,1)); + message = new JLabel(""); message.setBackground(background); message.setVerticalAlignment(SwingConstants.CENTER); @@ -138,5 +143,15 @@ public class MessagePanel extends JPanel { currentDetails = "<BR>" + detailText; updateMessageText(); } - + + @Override + public Dimension getPreferredSize() { + Dimension nativeSize = super.getPreferredSize(); + if (parentSlider == null) return nativeSize; + int width = parentSlider.getSize().width + - parentSlider.getVerticalScrollBar().getWidth() + - 5; + if (width <= 0) width = 1; + return new Dimension (width , nativeSize.height); + } } |
From: Frederick W. <fre...@us...> - 2012-02-08 17:17:51
|
LocalisedText.properties | 14 - rails/ui/swing/GameUIManager.java | 2 rails/ui/swing/ORPanel.java | 19 + rails/ui/swing/ORWindow.java | 276 ++--------------------- rails/ui/swing/UpgradesPanel.java | 2 rails/ui/swing/elements/DockingFrame.java | 346 ++++++++++++++++++++++++++++++ 6 files changed, 402 insertions(+), 257 deletions(-) New commits: commit 85873585f82f47e4a5f752195b76412eb12edd33 Author: Frederick Weld <fre...@gm...> Date: Wed Feb 8 18:17:01 2012 +0100 Corrected comment for ORPanel's add JSpinner to Grid diff --git a/rails/ui/swing/ORPanel.java b/rails/ui/swing/ORPanel.java index ab3bf8f..bd3ea58 100644 --- a/rails/ui/swing/ORPanel.java +++ b/rails/ui/swing/ORPanel.java @@ -604,9 +604,9 @@ implements ActionListener, KeyListener, RevenueListener { f = revenue[i] = new Field(c.getLastRevenueModel()); addField(f, revXOffset, revYOffset + i, 1, 1, 0, visible); f = revenueSelect[i] = new Spinner(0, 0, 0, 10); - //zero-border so that size matches revenue field (thus, averting or panel resize) + //align spinner size with field size + //(so that changes to visibility don't affect panel sizing) f.setPreferredSize(revenue[i].getPreferredSize()); - //f.setBorder(new javax.swing.border.EmptyBorder(0,0,0,0)); addField(f, revXOffset, revYOffset + i, 1, 1, 0, false); // deactived below, as this caused problems by gridpanel rowvisibility function -- sfy // revenue[i].addDependent(revenueSelect[i]); commit d0bc83b44b210e1f9dc0cddb32dc543a4067ef84 Author: Frederick Weld <fre...@gm...> Date: Tue Feb 7 19:49:01 2012 +0100 Reworked dockingframe logging / popups Now: - logging entry instead of popup for layout save. - no popup during initial tentative layout load. diff --git a/rails/ui/swing/elements/DockingFrame.java b/rails/ui/swing/elements/DockingFrame.java index 8452ce0..8cc1203 100644 --- a/rails/ui/swing/elements/DockingFrame.java +++ b/rails/ui/swing/elements/DockingFrame.java @@ -158,7 +158,7 @@ public abstract class DockingFrame extends JFrame { */ protected void initLayout() { control.save(layoutName_initial); - loadLayout(); + loadLayout(getLayoutFile(),true); } /** @@ -199,17 +199,16 @@ public abstract class DockingFrame extends JFrame { control.writeXML(layoutFile); log.info("Layout saved to " + layoutFile.getName()); } catch (Exception e) { - JOptionPane.showMessageDialog(this, - "Unable to save layout to " + layoutFile.getName()); + log.error("Layout could not be saved to " + layoutFile.getName()); return; } } - private void loadLayout() { - loadLayout(getLayoutFile()); - } - - private void loadLayout(File layoutFile) { + /** + * @param isTentative If true, then method only tries to load specified layout + * but would not produce any error popup. + */ + private void loadLayout(File layoutFile, boolean isTentative) { if (!isDockingFrameworkEnabled) return; try { @@ -217,8 +216,11 @@ public abstract class DockingFrame extends JFrame { control.load(layoutName_current); log.info("Layout loaded from " + layoutFile.getName()); } catch (Exception e) { - JOptionPane.showMessageDialog(this, - "Unable to load layout from " + layoutFile.getName()); + if (!isTentative) { + JOptionPane.showMessageDialog(this, + "Unable to load layout from " + layoutFile.getName()); + } + log.error("Layout could not be loaded from " + layoutFile.getName()); return; } @@ -245,7 +247,7 @@ public abstract class DockingFrame extends JFrame { JFileChooser jfc = new JFileChooser(); jfc.setCurrentDirectory(getLayoutDirectory()); if (jfc.showOpenDialog(getContentPane()) != JFileChooser.APPROVE_OPTION) return; // cancel pressed - loadLayout(jfc.getSelectedFile()); + loadLayout(jfc.getSelectedFile(),false); } /** commit 21afe1d386c3a4d3d5b2987f8dab27d2c01698b0 Author: Frederick Weld <fre...@gm...> Date: Tue Feb 7 17:49:58 2012 +0100 Added docking features: apply template, logging, error popups Added feature to pick existing docking layouts as template. Menu item is called "Apply from..." and lets the user choose from the list of persisted layouts. Logging and error popups are added to the steps of loading/saving docking layouts. diff --git a/rails/ui/swing/elements/DockingFrame.java b/rails/ui/swing/elements/DockingFrame.java index 52375d0..8452ce0 100644 --- a/rails/ui/swing/elements/DockingFrame.java +++ b/rails/ui/swing/elements/DockingFrame.java @@ -1,6 +1,3 @@ -/** - * - */ package rails.ui.swing.elements; import java.awt.BorderLayout; @@ -10,9 +7,11 @@ import java.io.File; import java.util.Locale; import javax.swing.JComponent; +import javax.swing.JFileChooser; import javax.swing.JFrame; import javax.swing.JMenuBar; import javax.swing.JMenuItem; +import javax.swing.JOptionPane; import javax.swing.SwingUtilities; import rails.common.LocalText; @@ -40,6 +39,8 @@ import bibliothek.gui.dock.facile.menu.RootMenuPiece; import bibliothek.gui.dock.facile.menu.SubmenuPiece; import bibliothek.gui.dock.station.LayoutLocked; +import org.apache.log4j.Logger; + /** * Superclass for all application frames that want to use the docking * framework for managing its panels. @@ -53,12 +54,13 @@ import bibliothek.gui.dock.station.LayoutLocked; */ public abstract class DockingFrame extends JFrame { private static final long serialVersionUID = 1L; - private static final String layoutFolderName = "DockableLayout"; + private static final String layoutDirectoryName = "DockableLayout"; private static final String layoutFileSuffix = "_layout.rails_ini"; private static final String layoutName_initial = "InitialLayout"; private static final String layoutName_current = "CurrentLayout"; private static final String defaultTheme = ThemeMap.KEY_BASIC_THEME; - + private static Logger log = Logger.getLogger(DockingFrame.class.getPackage().getName()); + private boolean isDockingFrameworkEnabled; private CControl control = null; private CGrid gridLayout = null; @@ -140,7 +142,7 @@ public abstract class DockingFrame extends JFrame { LocalText.getText("DockingFrame.menu.layout.applyFrom")); applyFromMenuItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { - //TODO: apply from + loadLayoutUserDefined(); } }); layoutMenu.getMenu().add(applyFromMenuItem); @@ -165,31 +167,41 @@ public abstract class DockingFrame extends JFrame { */ abstract protected String getLayoutFileName(); - private File getLayoutFile() { + /** + * get layout directory (and ensure that it is available) + */ + private File getLayoutDirectory() { try { - //get layout folder (and ensure that it is available) - File layoutFolder = new File(Config.get("save.directory"),layoutFolderName); - if (!layoutFolder.isDirectory()) { - layoutFolder.mkdirs(); + File layoutDirectory = new File(Config.get("save.directory"),layoutDirectoryName); + if (!layoutDirectory.isDirectory()) { + layoutDirectory.mkdirs(); } - File layoutFile = new File(layoutFolder, - getLayoutFileName() + layoutFileSuffix ); - return layoutFile; - } catch (Exception e) { + return layoutDirectory; + } + catch (Exception e) { //return no valid file if anything goes wrong return null; } } + private File getLayoutFile() { + File layoutFile = new File(getLayoutDirectory(), + getLayoutFileName() + layoutFileSuffix ); + return layoutFile; + } + public void saveLayout() { if (!isDockingFrameworkEnabled) return; File layoutFile = getLayoutFile(); - if (layoutFile != null) { - try { - control.save(layoutName_current); - control.writeXML(layoutFile); - } catch (Exception e) {} //skip in case of issue + try { + control.save(layoutName_current); + control.writeXML(layoutFile); + log.info("Layout saved to " + layoutFile.getName()); + } catch (Exception e) { + JOptionPane.showMessageDialog(this, + "Unable to save layout to " + layoutFile.getName()); + return; } } @@ -200,11 +212,14 @@ public abstract class DockingFrame extends JFrame { private void loadLayout(File layoutFile) { if (!isDockingFrameworkEnabled) return; - if (layoutFile != null) { - try { - control.readXML(layoutFile); - control.load(layoutName_current); - } catch (Exception e) {} //skip if layout not found + try { + control.readXML(layoutFile); + control.load(layoutName_current); + log.info("Layout loaded from " + layoutFile.getName()); + } catch (Exception e) { + JOptionPane.showMessageDialog(this, + "Unable to load layout from " + layoutFile.getName()); + return; } //ensure that all dockables that are externalized according to layout @@ -224,6 +239,16 @@ public abstract class DockingFrame extends JFrame { } /** + * Lets user choose a layout in a file chooser popup and then loads/applies it + */ + private void loadLayoutUserDefined() { + JFileChooser jfc = new JFileChooser(); + jfc.setCurrentDirectory(getLayoutDirectory()); + if (jfc.showOpenDialog(getContentPane()) != JFileChooser.APPROVE_OPTION) return; // cancel pressed + loadLayout(jfc.getSelectedFile()); + } + + /** * The behavior of the specified CControl is altered by the following: * If a dockable is detached / externalized, it would normally put directly * under the ScreenDockStation - thus inhibiting any docking to/from this @@ -316,4 +341,4 @@ public abstract class DockingFrame extends JFrame { } } -} +} \ No newline at end of file commit b19b2c0926fceec643a42074a657975a12072555 Author: Frederick Weld <fre...@gm...> Date: Tue Feb 7 17:49:27 2012 +0100 Merged OR panel's menu bar into ORWindow's menu bar (docking layout) diff --git a/rails/ui/swing/ORPanel.java b/rails/ui/swing/ORPanel.java index 357d208..ab3bf8f 100644 --- a/rails/ui/swing/ORPanel.java +++ b/rails/ui/swing/ORPanel.java @@ -233,7 +233,11 @@ implements ActionListener, KeyListener, RevenueListener { zoomMenu.add(calibrateMap); menuBar.add(zoomMenu); - add(menuBar, BorderLayout.NORTH); + // only add menu bar for conventional layout + // (otherwise part of DockingFrame) + if (!parent.isDockingFrameworkEnabled()) { + add(menuBar, BorderLayout.NORTH); + } setVisible(true); @@ -1353,4 +1357,7 @@ implements ActionListener, KeyListener, RevenueListener { return buttonPanel; } + public JMenuBar getMenuBar() { + return menuBar; + } } \ No newline at end of file diff --git a/rails/ui/swing/ORWindow.java b/rails/ui/swing/ORWindow.java index f9d4d4f..278e9b0 100644 --- a/rails/ui/swing/ORWindow.java +++ b/rails/ui/swing/ORWindow.java @@ -90,8 +90,8 @@ public class ORWindow extends DockingFrame implements ActionPerformer { 0, 95, 100, 5); deployDockables(); - //create the frame menu - JMenuBar menuBar = new JMenuBar(); + //take over or panel's menu bar as the frame menu bar + JMenuBar menuBar = orPanel.getMenuBar(); addDockingFrameMenu(menuBar); setJMenuBar( menuBar ); @@ -268,4 +268,4 @@ public class ORWindow extends DockingFrame implements ActionPerformer { + gameUIManager.getGameManager().getGameName() ; } -} +} \ No newline at end of file commit 477e51b07cf09c0ed71e96af6f2a6c072ad6441c Author: Frederick Weld <fre...@gm...> Date: Mon Feb 6 18:24:40 2012 +0100 Refactored docking logic - separated it from ORWin to separate class Now, ORWindow inherits from this new class (elements.DockingFrame). As a result, ORWindow does not have any single reference to the DockingFrame framework - the new class acts both as a facade and as a rails-aware decorator to the framework's features. During refactoring, the following was also done: - Enablement of config option is only tested once (at the beginning) - due to potential issues when changing during a game - Enhanced scope of layout menu item "reset" - now also encompasses resetting the theme - Menu items "Look and Feel" and "Preferences" are dropped - they could not be reset properly - they had side-effects on other windows diff --git a/LocalisedText.properties b/LocalisedText.properties index 4f46859..4f344b2 100644 --- a/LocalisedText.properties +++ b/LocalisedText.properties @@ -292,15 +292,14 @@ DoesNotExist=Item does not exist DoesNotForm={0} does not form DoesNotHaveTheShares=Does not have the shares Dockable.orWindow.buttonPanel = Commands -Dockable.orWindow.menu.appearance = Appearance -Dockable.orWindow.menu.appearance.lookAndFeel = Look and Feel -Dockable.orWindow.menu.appearance.theme = Theme -Dockable.orWindow.menu.appearance.preferences = Preferences -Dockable.orWindow.menu.appearance.resetLayout = Reset Layout Dockable.orWindow.mapPanel = Map Dockable.orWindow.messagePanel = Messages Dockable.orWindow.orPanel = Companies Dockable.orWindow.upgradePanel = Upgrades +DockingFrame.menu.layout = Layout +DockingFrame.menu.layout.applyFrom = Apply From... +DockingFrame.menu.layout.theme = Theme +DockingFrame.menu.layout.reset = Reset Done=Done DoubleHeadingModifier1825={0} are two {1}-trains running as a {2}-train (double heading). ShortORExecuted=A short OR has been held, in which only the sold privates have paid out. diff --git a/rails/ui/swing/GameUIManager.java b/rails/ui/swing/GameUIManager.java index f281034..1440df6 100644 --- a/rails/ui/swing/GameUIManager.java +++ b/rails/ui/swing/GameUIManager.java @@ -126,7 +126,7 @@ public class GameUIManager implements DialogOwner { public void terminate () { getWindowSettings ().save(); - if (orWindow != null) orWindow.saveDockableLayout(); + if (orWindow != null) orWindow.saveLayout(); System.exit(0); } diff --git a/rails/ui/swing/ORPanel.java b/rails/ui/swing/ORPanel.java index 453db01..357d208 100644 --- a/rails/ui/swing/ORPanel.java +++ b/rails/ui/swing/ORPanel.java @@ -163,7 +163,7 @@ implements ActionListener, KeyListener, RevenueListener { add(statusPanel, BorderLayout.CENTER); //only add button panel directly for conventional layout - if (!parent.isDockablePanelsEnabled()) { + if (!parent.isDockingFrameworkEnabled()) { add(buttonPanel, BorderLayout.SOUTH); } @@ -314,7 +314,7 @@ implements ActionListener, KeyListener, RevenueListener { redoButton.setEnabled(false); //choose button panel layout depending on whether panel becomes a dockable - if (orWindow.isDockablePanelsEnabled()) { + if (orWindow.isDockingFrameworkEnabled()) { //customized panel for dockable layout //the minimal size is defined by the size of one button @@ -357,7 +357,7 @@ implements ActionListener, KeyListener, RevenueListener { //for dockable button panel, ensure that all buttons have the same size //(necessary, otherwise vertical/box layout will look ugly) - if (orWindow.isDockablePanelsEnabled()) { + if (orWindow.isDockingFrameworkEnabled()) { //get maximum size Dimension maxSize = new Dimension(); diff --git a/rails/ui/swing/ORWindow.java b/rails/ui/swing/ORWindow.java index 057e6a2..f9d4d4f 100644 --- a/rails/ui/swing/ORWindow.java +++ b/rails/ui/swing/ORWindow.java @@ -2,61 +2,31 @@ package rails.ui.swing; import java.awt.BorderLayout; -import java.awt.MenuItem; import java.awt.Rectangle; import java.awt.event.*; -import java.io.File; import java.util.ArrayList; import java.util.List; -import java.util.Locale; import javax.swing.JFrame; -import javax.swing.JMenu; import javax.swing.JMenuBar; -import javax.swing.JMenuItem; import javax.swing.JOptionPane; import javax.swing.JScrollPane; -import javax.swing.SwingUtilities; import org.apache.log4j.Logger; -import bibliothek.gui.DockController; -import bibliothek.gui.Dockable; -import bibliothek.gui.DockStation; -import bibliothek.gui.dock.ScreenDockStation; -import bibliothek.gui.dock.SplitDockStation; -import bibliothek.gui.dock.common.CControl; -import bibliothek.gui.dock.common.CGrid; -import bibliothek.gui.dock.common.CStation; -import bibliothek.gui.dock.common.DefaultSingleCDockable; -import bibliothek.gui.dock.common.action.predefined.CBlank; -import bibliothek.gui.dock.common.event.CDockableStateListener; -import bibliothek.gui.dock.common.intern.CDockable; -import bibliothek.gui.dock.common.intern.DefaultCDockable; -import bibliothek.gui.dock.common.intern.ui.CSingleParentRemover; -import bibliothek.gui.dock.common.menu.CLayoutChoiceMenuPiece; -import bibliothek.gui.dock.common.menu.CLookAndFeelMenuPiece; -import bibliothek.gui.dock.common.menu.CPreferenceMenuPiece; -import bibliothek.gui.dock.common.menu.CThemeMenuPiece; -import bibliothek.gui.dock.common.mode.ExtendedMode; -import bibliothek.gui.dock.common.theme.ThemeMap; -import bibliothek.gui.dock.event.DockStationAdapter; -import bibliothek.gui.dock.facile.menu.RootMenuPiece; -import bibliothek.gui.dock.facile.menu.SubmenuPiece; -import bibliothek.gui.dock.station.LayoutLocked; - import rails.common.GuiDef; import rails.common.LocalText; import rails.common.parser.Config; import rails.game.GameManager; import rails.game.OperatingRound; import rails.game.action.*; +import rails.ui.swing.elements.DockingFrame; /** * This Window displays the available operations that may be performed during an * Operating Round. This window also contains the Game Map. */ -public class ORWindow extends JFrame implements ActionPerformer { +public class ORWindow extends DockingFrame implements ActionPerformer { private static final long serialVersionUID = 1L; protected GameUIManager gameUIManager; protected ORUIManager orUIManager; @@ -72,17 +42,11 @@ public class ORWindow extends JFrame implements ActionPerformer { List<LayTile> allowedTileLays = new ArrayList<LayTile>(); List<LayToken> allowedTokenLays = new ArrayList<LayToken>(); - CControl orWindowControl = null; - - private static final String layoutFolderName = "DockableLayout"; - private static final String layoutFileSuffix = "_layout.rails_ini"; - private static final String initialLayoutName = "InitialDockableLayout"; - protected static Logger log = Logger.getLogger(ORWindow.class.getPackage().getName()); public ORWindow(GameUIManager gameUIManager) { - super(); + super( "yes".equals(Config.get("or.window.dockablePanels")) ); this.gameUIManager = gameUIManager; String orUIManagerClassName = gameUIManager.getClassName(GuiDef.ClassName.OR_UI_MANAGER); @@ -109,93 +73,27 @@ public class ORWindow extends JFrame implements ActionPerformer { orPanel = new ORPanel(this, orUIManager); - //create docking / conventional layout depending config - if (isDockablePanelsEnabled()) { - //DOCKABLE LAYOUT - - //build the docking layout - orWindowControl = new CControl( this ); - add( orWindowControl.getContentArea() ); - CGrid orWindowLayout = new CGrid( orWindowControl ); - - //ensure that externalized dockables get a split station as parent - //necessary, otherwise externalized dockables cannot be docked together - alwaysAddStationsToExternalizedDockables(orWindowControl); - - //set docks tooltip language - if ("en_us".equalsIgnoreCase(Config.get("locale"))) { - //hard setting to default in case of US as this is DockingFrames default language - //don't use Locale constant as it is en_US (case sensitive) - orWindowControl.setLanguage(new Locale("")); - } - - //add message panel - String dockableName = LocalText.getText("Dockable.orWindow.messagePanel"); - DefaultSingleCDockable singleDockable = new DefaultSingleCDockable( dockableName, dockableName ); - singleDockable.add( slider, BorderLayout.CENTER ); - singleDockable.setCloseable( false ); - orWindowLayout.add( 0, 0, 100, 10, singleDockable ); + //create docking / conventional layout + if (isDockingFrameworkEnabled()) { - //add upgrade panel - dockableName = LocalText.getText("Dockable.orWindow.upgradePanel"); - singleDockable = new DefaultSingleCDockable( dockableName, dockableName ); - singleDockable.add( upgradePanel, BorderLayout.CENTER ); - singleDockable.setCloseable( false ); - orWindowLayout.add( 0, 10, 20, 70, singleDockable ); - - //add map panel - dockableName = LocalText.getText("Dockable.orWindow.mapPanel"); - singleDockable = new DefaultSingleCDockable( dockableName, dockableName ); - singleDockable.add( mapPanel, BorderLayout.CENTER ); - singleDockable.setCloseable( false ); - orWindowLayout.add( 20, 10, 80, 70, singleDockable ); - - //add or panel - dockableName = LocalText.getText("Dockable.orWindow.orPanel"); - singleDockable = new DefaultSingleCDockable( dockableName, dockableName ); - singleDockable.add( orPanel, BorderLayout.CENTER ); - singleDockable.setCloseable( false ); - orWindowLayout.add( 0, 80, 100, 15, singleDockable ); - - //add button panel of or panel - dockableName = LocalText.getText("Dockable.orWindow.buttonPanel"); - singleDockable = new DefaultSingleCDockable( dockableName, dockableName ); - singleDockable.add( orPanel.getButtonPanel(), BorderLayout.CENTER ); - singleDockable.setCloseable( false ); - orWindowLayout.add( 0, 95, 100, 5, singleDockable ); - - //deploy layout to control's content area - orWindowControl.getContentArea().deploy( orWindowLayout ); + //generate layout + addDockable ( slider, LocalText.getText("Dockable.orWindow.messagePanel"), + 0, 0, 100, 10); + addDockable ( upgradePanel, LocalText.getText("Dockable.orWindow.upgradePanel"), + 0, 10, 20, 70); + addDockable ( mapPanel, LocalText.getText("Dockable.orWindow.mapPanel"), + 20, 10, 80, 70); + addDockable ( orPanel, LocalText.getText("Dockable.orWindow.orPanel"), + 0, 80, 100, 15); + addDockable ( orPanel.getButtonPanel(), + LocalText.getText("Dockable.orWindow.buttonPanel"), + 0, 95, 100, 5); + deployDockables(); //create the frame menu - JMenuBar menubar = new JMenuBar(); - RootMenuPiece appearanceMenu = new RootMenuPiece( - LocalText.getText("Dockable.orWindow.menu.appearance"), - false); - appearanceMenu.add( new SubmenuPiece( - LocalText.getText("Dockable.orWindow.menu.appearance.lookAndFeel"), - false, - new CLookAndFeelMenuPiece( orWindowControl ) - )); - appearanceMenu.add( new SubmenuPiece( - LocalText.getText("Dockable.orWindow.menu.appearance.theme"), - false, - new CThemeMenuPiece( orWindowControl ) - )); - appearanceMenu.add( CPreferenceMenuPiece.setup( orWindowControl )); - appearanceMenu.getMenu().addSeparator(); - JMenuItem resetLayoutMenuItem = new JMenuItem ( - LocalText.getText("Dockable.orWindow.menu.appearance.resetLayout")); - resetLayoutMenuItem.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - orWindowControl.load(initialLayoutName); - } - }); - appearanceMenu.getMenu().add(resetLayoutMenuItem); - - //deploy menu - menubar.add( appearanceMenu.getMenu() ); - setJMenuBar( menubar ); + JMenuBar menuBar = new JMenuBar(); + addDockingFrameMenu(menuBar); + setJMenuBar( menuBar ); } else { // CONVENTIONAL LAYOUT @@ -230,9 +128,9 @@ public class ORWindow extends JFrame implements ActionPerformer { addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent e) { - saveDockableLayout(); + saveLayout(); StatusWindow.uncheckMenuItemBox(StatusWindow.MAP_CMD); - if (!isDockablePanelsEnabled()) { + if (!isDockingFrameworkEnabled()) { frame.dispose(); } else { setVisible(false); @@ -251,7 +149,7 @@ public class ORWindow extends JFrame implements ActionPerformer { }); //rearrange layout only if no docking framework active - if (!isDockablePanelsEnabled()) { + if (!isDockingFrameworkEnabled()) { pack(); } @@ -263,11 +161,7 @@ public class ORWindow extends JFrame implements ActionPerformer { gameUIManager.reportWindow.updateLog(); - //dockable panes: save initial layout and restore former layout - if (isDockablePanelsEnabled()) { - orWindowControl.save(initialLayoutName); - loadDockableLayout(); - } + if (isDockingFrameworkEnabled()) initLayout(); } public ORUIManager getORUIManager() { @@ -319,7 +213,7 @@ public class ORWindow extends JFrame implements ActionPerformer { public void repaintORPanel() { //rearrange layout only if no docking framework active - if (!isDockablePanelsEnabled()) { + if (!isDockingFrameworkEnabled()) { orPanel.revalidate(); } } @@ -335,7 +229,7 @@ public class ORWindow extends JFrame implements ActionPerformer { numORs )); //rearrange layout only if no docking framework active - if (!isDockablePanelsEnabled()) { + if (!isDockingFrameworkEnabled()) { pack(); if (lastBounds != null) { Rectangle newBounds = getBounds(); @@ -368,160 +262,10 @@ public class ORWindow extends JFrame implements ActionPerformer { messagePanel.setMessage(""); setTitle(LocalText.getText("MapWindowTitle")); } - - public boolean isDockablePanelsEnabled() { - return "yes".equals(Config.get("or.window.dockablePanels")); - } - - - private String getLayoutName() { + + protected String getLayoutFileName() { return getClass().getSimpleName() + "_" + gameUIManager.getGameManager().getGameName() ; } - - private File getLayoutFile() { - try { - //get layout folder (and ensure that it is available) - File layoutFolder = new File(Config.get("save.directory"),layoutFolderName); - if (!layoutFolder.isDirectory()) { - layoutFolder.mkdirs(); - } - File layoutFile = new File(layoutFolder, - getLayoutName() + layoutFileSuffix ); - return layoutFile; - } catch (Exception e) { - //return no valid file if anything goes wrong - return null; - } - } - - public void saveDockableLayout() { - if (!isDockablePanelsEnabled()) return; - - File layoutFile = getLayoutFile(); - if (layoutFile != null) { - try { - orWindowControl.save(getLayoutName()); - orWindowControl.writeXML(layoutFile); - } catch (Exception e) {} //skip in case of issue - } - } - - private void loadDockableLayout() { - if (!isDockablePanelsEnabled()) return; - - File layoutFile = getLayoutFile(); - if (layoutFile != null) { - try { - orWindowControl.readXML(layoutFile); - orWindowControl.load(getLayoutName()); - } catch (Exception e) {} //skip if layout not found - } - - //ensure that all dockables that are externalized according to layout - //information don't have the deault maximize button (as it won't work - //for the adjusted externalization setup) - for (int i = 0 ; i < orWindowControl.getCDockableCount() ; i++ ) { - CDockable d = orWindowControl.getCDockable(i); - if (d instanceof DefaultCDockable) { - DefaultCDockable dd = (DefaultCDockable)d; - if (ExtendedMode.EXTERNALIZED.equals(d.getExtendedMode())) { - dd.putAction( CDockable.ACTION_KEY_MAXIMIZE, CBlank.BLANK ); - } - } - } - } - - /** - * The behavior of the specified CControl is altered by the following: - * If a dockable is detached / externalized, it would normally put directly - * under the ScreenDockStation - thus inhibiting any docking to/from this - * dockable. This is changed such that a split station (that would allow for - * that) is put in between the ScreenDockStation and the Dockable. - */ - private void alwaysAddStationsToExternalizedDockables(CControl cc) { - // access the DockStation which shows our detached (externalized) items - CStation<?> screen = (CStation<?>) - cc.getStation( CControl.EXTERNALIZED_STATION_ID ); - - // remove the standard maximize action when externalizing - // and adds it back when unexternalizing - // (as maximize won't work for the adjusted externalization setup) - cc.addStateListener( new CDockableStateListener() { - public void visibilityChanged( CDockable cd ){ - // ignore - } - - public void extendedModeChanged( CDockable cd, ExtendedMode mode ){ - if( cd instanceof DefaultCDockable ) { - DefaultCDockable dockable = (DefaultCDockable) cd; - if( mode.equals( ExtendedMode.EXTERNALIZED ) ) { - dockable.putAction( CDockable.ACTION_KEY_MAXIMIZE, CBlank.BLANK ); - } - else { - dockable.putAction( CDockable.ACTION_KEY_MAXIMIZE, null ); - } - } - } - }); - - // if a Dockable is added to that station... - screen.getStation().addDockStationListener( new ScreenDockStationListener()); - - // make sure a SplitDockStation with one child and a parent - // that is a ScreenDockStation does not get removed - cc.intern().getController().setSingleParentRemover( - new CSingleParentRemover( cc ){ - @Override - protected boolean shouldTest( DockStation station ){ - if( station instanceof SplitDockStation ) { - SplitDockStation split = (SplitDockStation) station; - if( split.getDockParent() instanceof ScreenDockStation ) { - // but we want to remove the station if it does - // not have any children at all - return split.getDockableCount() == 0; - } - } - return super.shouldTest( station ); - } - } ); - } - - @LayoutLocked(locked = false) - private class ScreenDockStationListener extends DockStationAdapter { - public void dockableAdded( DockStation station, final Dockable dockable ){ - // ... and the new child is not a SplitDockStation ... - if( !(dockable instanceof SplitDockStation) ) { - SwingUtilities.invokeLater( new Runnable(){ - public void run(){ - checkAndReplace( dockable ); - } - } ); - } - } - private void checkAndReplace( Dockable dockable ){ - DockStation station = dockable.getDockParent(); - if( !(station instanceof ScreenDockStation) ) { - // cancel - return; - } - - // .. then we just insert a SplitDockStation - SplitDockStation split = new SplitDockStation(); - DockController controller = station.getController(); - - try { - // disable events while rearranging our layout - controller.freezeLayout(); - - station.replace( dockable, split ); - split.drop( dockable ); - } - finally { - // and enable events after we finished - controller.meltLayout(); - } - } - } } diff --git a/rails/ui/swing/UpgradesPanel.java b/rails/ui/swing/UpgradesPanel.java index 02556b6..edf24a2 100644 --- a/rails/ui/swing/UpgradesPanel.java +++ b/rails/ui/swing/UpgradesPanel.java @@ -409,7 +409,7 @@ public class UpgradesPanel extends Box implements MouseListener, ActionListener * could be necessary when displaying tiles of an arbitrary size */ private int getZoomStep() { - if (orUIManager.getORWindow().isDockablePanelsEnabled()) { + if (orUIManager.getORWindow().isDockingFrameworkEnabled()) { return hexMap.getZoomStep(); } else { return UPGRADE_TILE_ZOOM_STEP; diff --git a/rails/ui/swing/elements/DockingFrame.java b/rails/ui/swing/elements/DockingFrame.java new file mode 100644 index 0000000..52375d0 --- /dev/null +++ b/rails/ui/swing/elements/DockingFrame.java @@ -0,0 +1,319 @@ +/** + * + */ +package rails.ui.swing.elements; + +import java.awt.BorderLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.io.File; +import java.util.Locale; + +import javax.swing.JComponent; +import javax.swing.JFrame; +import javax.swing.JMenuBar; +import javax.swing.JMenuItem; +import javax.swing.SwingUtilities; + +import rails.common.LocalText; +import rails.common.parser.Config; + +import bibliothek.gui.DockController; +import bibliothek.gui.DockStation; +import bibliothek.gui.Dockable; +import bibliothek.gui.dock.ScreenDockStation; +import bibliothek.gui.dock.SplitDockStation; +import bibliothek.gui.dock.common.CControl; +import bibliothek.gui.dock.common.CGrid; +import bibliothek.gui.dock.common.CStation; +import bibliothek.gui.dock.common.DefaultSingleCDockable; +import bibliothek.gui.dock.common.action.predefined.CBlank; +import bibliothek.gui.dock.common.event.CDockableStateListener; +import bibliothek.gui.dock.common.intern.CDockable; +import bibliothek.gui.dock.common.intern.DefaultCDockable; +import bibliothek.gui.dock.common.intern.ui.CSingleParentRemover; +import bibliothek.gui.dock.common.menu.CThemeMenuPiece; +import bibliothek.gui.dock.common.mode.ExtendedMode; +import bibliothek.gui.dock.common.theme.ThemeMap; +import bibliothek.gui.dock.event.DockStationAdapter; +import bibliothek.gui.dock.facile.menu.RootMenuPiece; +import bibliothek.gui.dock.facile.menu.SubmenuPiece; +import bibliothek.gui.dock.station.LayoutLocked; + +/** + * Superclass for all application frames that want to use the docking + * framework for managing its panels. + * + * All references to the docking framework are private by purpose. This + * enforces that any sub-class must not deal with any framework related + * issues (this superclass acts as a facade to the framework). + * + * @author Frederick Weld + * + */ +public abstract class DockingFrame extends JFrame { + private static final long serialVersionUID = 1L; + private static final String layoutFolderName = "DockableLayout"; + private static final String layoutFileSuffix = "_layout.rails_ini"; + private static final String layoutName_initial = "InitialLayout"; + private static final String layoutName_current = "CurrentLayout"; + private static final String defaultTheme = ThemeMap.KEY_BASIC_THEME; + + private boolean isDockingFrameworkEnabled; + private CControl control = null; + private CGrid gridLayout = null; + + /** + * Decision whether docking framework should be activated for a frame + * has to be done at the beginning as later switching is not supported + */ + protected DockingFrame(boolean isDockingFrameworkEnabled) { + this.isDockingFrameworkEnabled = isDockingFrameworkEnabled; + if (!isDockingFrameworkEnabled) return; + + //init the ccontrol + control = new CControl( this ); + control.setTheme(defaultTheme); + add( control.getContentArea() ); + if ("en_us".equalsIgnoreCase(Config.get("locale"))) { + //hard setting to default in case of US as this is DockingFrames default language + //don't use Locale constant as it is en_US (case sensitive) + control.setLanguage(new Locale("")); + } + + //init the grid layout + gridLayout = new CGrid( control ); + + //ensure that externalized dockables get a split station as parent + //necessary, otherwise externalized dockables cannot be docked together + alwaysAddStationsToExternalizedDockables(control); + + + } + + public boolean isDockingFrameworkEnabled() { + return isDockingFrameworkEnabled; + } + + /** + * Registers a component that is to become a dockable. + * The dockable is only deployed to the frame if deployDockables is called. + */ + protected void addDockable(JComponent c, String dockableTitle, int x, int y, int width, int height) { + DefaultSingleCDockable d = new DefaultSingleCDockable( + dockableTitle, dockableTitle ); + d.add( c, BorderLayout.CENTER ); + d.setCloseable( false ); + gridLayout.add( x, y, width, height, d ); + } + + /** + * Deploys to the frame all dockables that have been added before + */ + protected void deployDockables() { + control.getContentArea().deploy( gridLayout ); + } + + /** + * Creates a generic layout menu and adds it to the specified menu bar + */ + protected void addDockingFrameMenu(JMenuBar menuBar) { + RootMenuPiece layoutMenu = new RootMenuPiece( + LocalText.getText("DockingFrame.menu.layout"), + false); + layoutMenu.add( new SubmenuPiece( + LocalText.getText("DockingFrame.menu.layout.theme"), + false, + new CThemeMenuPiece( control ) + )); + layoutMenu.getMenu().addSeparator(); + JMenuItem resetMenuItem = new JMenuItem ( + LocalText.getText("DockingFrame.menu.layout.reset")); + resetMenuItem.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + control.load(layoutName_initial); + control.setTheme(defaultTheme); + } + }); + layoutMenu.getMenu().add(resetMenuItem); + JMenuItem applyFromMenuItem = new JMenuItem ( + LocalText.getText("DockingFrame.menu.layout.applyFrom")); + applyFromMenuItem.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + //TODO: apply from + } + }); + layoutMenu.getMenu().add(applyFromMenuItem); + + //deploy menu + menuBar.add( layoutMenu.getMenu() ); + } + + /** + * May only be called once the docking frame's layout has been constructed. + * Remembers that layout as the initial one. + * Loads a former layout if that was persisted in a prior session. + */ + protected void initLayout() { + control.save(layoutName_initial); + loadLayout(); + } + + /** + * @return The file name which is to be used for storing the layout upon exit + * and restoring prior layout when entering a session. + */ + abstract protected String getLayoutFileName(); + + private File getLayoutFile() { + try { + //get layout folder (and ensure that it is available) + File layoutFolder = new File(Config.get("save.directory"),layoutFolderName); + if (!layoutFolder.isDirectory()) { + layoutFolder.mkdirs(); + } + File layoutFile = new File(layoutFolder, + getLayoutFileName() + layoutFileSuffix ); + return layoutFile; + } catch (Exception e) { + //return no valid file if anything goes wrong + return null; + } + } + + public void saveLayout() { + if (!isDockingFrameworkEnabled) return; + + File layoutFile = getLayoutFile(); + if (layoutFile != null) { + try { + control.save(layoutName_current); + control.writeXML(layoutFile); + } catch (Exception e) {} //skip in case of issue + } + } + + private void loadLayout() { + loadLayout(getLayoutFile()); + } + + private void loadLayout(File layoutFile) { + if (!isDockingFrameworkEnabled) return; + + if (layoutFile != null) { + try { + control.readXML(layoutFile); + control.load(layoutName_current); + } catch (Exception e) {} //skip if layout not found + } + + //ensure that all dockables that are externalized according to layout + //information don't have the default maximize button (as it won't work + //for the adjusted externalization setup) + for (int i = 0 ; i < control.getCDockableCount() ; i++ ) { + CDockable d = control.getCDockable(i); + if (d instanceof DefaultCDockable) { + DefaultCDockable dd = (DefaultCDockable)d; + if (ExtendedMode.EXTERNALIZED.equals(d.getExtendedMode())) { + dd.putAction( CDockable.ACTION_KEY_MAXIMIZE, CBlank.BLANK ); + } else { + dd.putAction( CDockable.ACTION_KEY_MAXIMIZE, null ); + } + } + } + } + + /** + * The behavior of the specified CControl is altered by the following: + * If a dockable is detached / externalized, it would normally put directly + * under the ScreenDockStation - thus inhibiting any docking to/from this + * dockable. This is changed such that a split station (that would allow for + * that) is put in between the ScreenDockStation and the Dockable. + */ + private void alwaysAddStationsToExternalizedDockables(CControl cc) { + + // access the DockStation which shows our detached (externalized) items + CStation<?> screen = (CStation<?>) + cc.getStation( CControl.EXTERNALIZED_STATION_ID ); + + // remove the standard maximize action when externalizing + // and adds it back when unexternalizing + // (as maximize won't work for the adjusted externalization setup) + cc.addStateListener( new CDockableStateListener() { + public void visibilityChanged( CDockable cd ){ + // ignore + } + + public void extendedModeChanged( CDockable cd, ExtendedMode mode ){ + if( cd instanceof DefaultCDockable ) { + DefaultCDockable dockable = (DefaultCDockable) cd; + if( mode.equals( ExtendedMode.EXTERNALIZED ) ) { + dockable.putAction( CDockable.ACTION_KEY_MAXIMIZE, CBlank.BLANK ); + } + else { + dockable.putAction( CDockable.ACTION_KEY_MAXIMIZE, null ); + } + } + } + }); + + // if a Dockable is added to that station... + screen.getStation().addDockStationListener( new ScreenDockStationListener()); + + // make sure a SplitDockStation with one child and a parent + // that is a ScreenDockStation does not get removed + cc.intern().getController().setSingleParentRemover( + new CSingleParentRemover( cc ){ + @Override + protected boolean shouldTest( DockStation station ){ + if( station instanceof SplitDockStation ) { + SplitDockStation split = (SplitDockStation) station; + if( split.getDockParent() instanceof ScreenDockStation ) { + // but we want to remove the station if it does + // not have any children at all + return split.getDockableCount() == 0; + } + } + return super.shouldTest( station ); + } + } ); + } + + @LayoutLocked(locked = false) + private class ScreenDockStationListener extends DockStationAdapter { + public void dockableAdded( DockStation station, final Dockable dockable ){ + // ... and the new child is not a SplitDockStation ... + if( !(dockable instanceof SplitDockStation) ) { + SwingUtilities.invokeLater( new Runnable(){ + public void run(){ + checkAndReplace( dockable ); + } + } ); + } + } + private void checkAndReplace( Dockable dockable ){ + DockStation station = dockable.getDockParent(); + if( !(station instanceof ScreenDockStation) ) { + // cancel + return; + } + + // .. then we just insert a SplitDockStation + SplitDockStation split = new SplitDockStation(); + DockController controller = station.getController(); + + try { + // disable events while rearranging our layout + controller.freezeLayout(); + + station.replace( dockable, split ); + split.drop( dockable ); + } + finally { + // and enable events after we finished + controller.meltLayout(); + } + } + } + +} commit 862f6ee2affe8b2400bb615dca8854bb8f835534 Author: Frederick Weld <fre...@gm...> Date: Sun Feb 5 19:34:30 2012 +0100 Added OR Window menu (for dockables) incl. reset layout Apart from reset layout (restores standard rails layout of the OR window), further appearance options of DockingFrames are exposed. diff --git a/LocalisedText.properties b/LocalisedText.properties index 6aaa145..4f46859 100644 --- a/LocalisedText.properties +++ b/LocalisedText.properties @@ -291,11 +291,16 @@ DiscardsBaseToken={0} discards a {1} base token on {2} DoesNotExist=Item does not exist DoesNotForm={0} does not form DoesNotHaveTheShares=Does not have the shares -DockableTitle.orWindow.messagePanel = Messages -DockableTitle.orWindow.upgradePanel = Upgrades -DockableTitle.orWindow.mapPanel = Map -DockableTitle.orWindow.orPanel = Companies -DockableTitle.orWindow.buttonPanel = Commands +Dockable.orWindow.buttonPanel = Commands +Dockable.orWindow.menu.appearance = Appearance +Dockable.orWindow.menu.appearance.lookAndFeel = Look and Feel +Dockable.orWindow.menu.appearance.theme = Theme +Dockable.orWindow.menu.appearance.preferences = Preferences +Dockable.orWindow.menu.appearance.resetLayout = Reset Layout +Dockable.orWindow.mapPanel = Map +Dockable.orWindow.messagePanel = Messages +Dockable.orWindow.orPanel = Companies +Dockable.orWindow.upgradePanel = Upgrades Done=Done DoubleHeadingModifier1825={0} are two {1}-trains running as a {2}-train (double heading). ShortORExecuted=A short OR has been held, in which only the sold privates have paid out. diff --git a/rails/ui/swing/ORWindow.java b/rails/ui/swing/ORWindow.java index 441be07..057e6a2 100644 --- a/rails/ui/swing/ORWindow.java +++ b/rails/ui/swing/ORWindow.java @@ -2,6 +2,7 @@ package rails.ui.swing; import java.awt.BorderLayout; +import java.awt.MenuItem; import java.awt.Rectangle; import java.awt.event.*; import java.io.File; @@ -10,6 +11,9 @@ import java.util.List; import java.util.Locale; import javax.swing.JFrame; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JMenuItem; import javax.swing.JOptionPane; import javax.swing.JScrollPane; import javax.swing.SwingUtilities; @@ -30,9 +34,15 @@ import bibliothek.gui.dock.common.event.CDockableStateListener; import bibliothek.gui.dock.common.intern.CDockable; import bibliothek.gui.dock.common.intern.DefaultCDockable; import bibliothek.gui.dock.common.intern.ui.CSingleParentRemover; +import bibliothek.gui.dock.common.menu.CLayoutChoiceMenuPiece; +import bibliothek.gui.dock.common.menu.CLookAndFeelMenuPiece; +import bibliothek.gui.dock.common.menu.CPreferenceMenuPiece; +import bibliothek.gui.dock.common.menu.CThemeMenuPiece; import bibliothek.gui.dock.common.mode.ExtendedMode; import bibliothek.gui.dock.common.theme.ThemeMap; import bibliothek.gui.dock.event.DockStationAdapter; +import bibliothek.gui.dock.facile.menu.RootMenuPiece; +import bibliothek.gui.dock.facile.menu.SubmenuPiece; import bibliothek.gui.dock.station.LayoutLocked; import rails.common.GuiDef; @@ -66,6 +76,7 @@ public class ORWindow extends JFrame implements ActionPerformer { private static final String layoutFolderName = "DockableLayout"; private static final String layoutFileSuffix = "_layout.rails_ini"; + private static final String initialLayoutName = "InitialDockableLayout"; protected static Logger log = Logger.getLogger(ORWindow.class.getPackage().getName()); @@ -104,7 +115,6 @@ public class ORWindow extends JFrame implements ActionPerformer { //build the docking layout orWindowControl = new CControl( this ); - orWindowControl.setTheme( ThemeMap.KEY_SMOOTH_THEME ); add( orWindowControl.getContentArea() ); CGrid orWindowLayout = new CGrid( orWindowControl ); @@ -120,42 +130,73 @@ public class ORWindow extends JFrame implements ActionPerformer { } //add message panel - String dockableName = LocalText.getText("DockableTitle.orWindow.messagePanel"); + String dockableName = LocalText.getText("Dockable.orWindow.messagePanel"); DefaultSingleCDockable singleDockable = new DefaultSingleCDockable( dockableName, dockableName ); singleDockable.add( slider, BorderLayout.CENTER ); singleDockable.setCloseable( false ); orWindowLayout.add( 0, 0, 100, 10, singleDockable ); //add upgrade panel - dockableName = LocalText.getText("DockableTitle.orWindow.upgradePanel"); + dockableName = LocalText.getText("Dockable.orWindow.upgradePanel"); singleDockable = new DefaultSingleCDockable( dockableName, dockableName ); singleDockable.add( upgradePanel, BorderLayout.CENTER ); singleDockable.setCloseable( false ); orWindowLayout.add( 0, 10, 20, 70, singleDockable ); //add map panel - dockableName = LocalText.getText("DockableTitle.orWindow.mapPanel"); + dockableName = LocalText.getText("Dockable.orWindow.mapPanel"); singleDockable = new DefaultSingleCDockable( dockableName, dockableName ); singleDockable.add( mapPanel, BorderLayout.CENTER ); singleDockable.setCloseable( false ); orWindowLayout.add( 20, 10, 80, 70, singleDockable ); //add or panel - dockableName = LocalText.getText("DockableTitle.orWindow.orPanel"); + dockableName = LocalText.getText("Dockable.orWindow.orPanel"); singleDockable = new DefaultSingleCDockable( dockableName, dockableName ); singleDockable.add( orPanel, BorderLayout.CENTER ); singleDockable.setCloseable( false ); orWindowLayout.add( 0, 80, 100, 15, singleDockable ); //add button panel of or panel - dockableName = LocalText.getText("DockableTitle.orWindow.buttonPanel"); + dockableName = LocalText.getText("Dockable.orWindow.buttonPanel"); singleDockable = new DefaultSingleCDockable( dockableName, dockableName ); singleDockable.add( orPanel.getButtonPanel(), BorderLayout.CENTER ); singleDockable.setCloseable( false ); orWindowLayout.add( 0, 95, 100, 5, singleDockable ); + //deploy layout to control's content area orWindowControl.getContentArea().deploy( orWindowLayout ); + //create the frame menu + JMenuBar menubar = new JMenuBar(); + RootMenuPiece appearanceMenu = new RootMenuPiece( + LocalText.getText("Dockable.orWindow.menu.appearance"), + false); + appearanceMenu.add( new SubmenuPiece( + LocalText.getText("Dockable.orWindow.menu.appearance.lookAndFeel"), + false, + new CLookAndFeelMenuPiece( orWindowControl ) + )); + appearanceMenu.add( new SubmenuPiece( + LocalText.getText("Dockable.orWindow.menu.appearance.theme"), + false, + new CThemeMenuPiece( orWindowControl ) + )); + appearanceMenu.add( CPreferenceMenuPiece.setup( orWindowControl )); + appearanceMenu.getMenu().addSeparator(); + JMenuItem resetLayoutMenuItem = new JMenuItem ( + LocalText.getText("Dockable.orWindow.menu.appearance.resetLayout")); + resetLayoutMenuItem.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + orWindowControl.load(initialLayoutName); + } + }); + appearanceMenu.getMenu().add(resetLayoutMenuItem); + + //deploy menu + menubar.add( appearanceMenu.getMenu() ); + setJMenuBar( menubar ); + } else { // CONVENTIONAL LAYOUT @@ -222,8 +263,11 @@ public class ORWindow extends JFrame implements ActionPerformer { gameUIManager.reportWindow.updateLog(); - //dockable panes: restore former layout (depending on game variant) - loadDockableLayout(); + //dockable panes: save initial layout and restore former layout + if (isDockablePanelsEnabled()) { + orWindowControl.save(initialLayoutName); + loadDockableLayout(); + } } public ORUIManager getORUIManager() { |
From: Frederick W. <fre...@us...> - 2012-02-08 16:50:21
|
rails/ui/swing/GridPanel.java | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) New commits: commit 5f70d21472cf24abf7ac417896273245f39074e8 Author: Frederick Weld <fre...@gm...> Date: Wed Feb 8 17:49:20 2012 +0100 Increased robustness for GridPanel(2): Added field may have null-border diff --git a/rails/ui/swing/GridPanel.java b/rails/ui/swing/GridPanel.java index d2ea42b..ddc4582 100644 --- a/rails/ui/swing/GridPanel.java +++ b/rails/ui/swing/GridPanel.java @@ -244,24 +244,30 @@ implements ActionListener, KeyListener { private class FieldBorder extends CompoundBorder { private static final long serialVersionUID = 1L; Border nativeInnerBorder; - DynamicBorder highlightedInnerBorder; + /** + * remains null if nativeInnerBorder is null or broken + */ + DynamicBorder highlightedInnerBorder = null; DynamicBorder outlineBorder; DynamicBorder outerBorder; public FieldBorder(Border innerBorder,DynamicBorder outlineBorder,DynamicBorder outerBorder) { super(new CompoundBorder(outerBorder,outlineBorder),innerBorder); - this.nativeInnerBorder = innerBorder; + nativeInnerBorder = innerBorder; this.outlineBorder = outlineBorder; this.outerBorder = outerBorder; - Insets nativeInnerBorderInsets = nativeInnerBorder.getBorderInsets(null); - if (nativeInnerBorderInsets == null) { - nativeInnerBorderInsets = new Insets(0,0,0,0); + + //prepare highlighted inner border + if (nativeInnerBorder != null) { + Insets nativeInnerBorderInsets = nativeInnerBorder.getBorderInsets(null); + if (nativeInnerBorderInsets != null) { + highlightedInnerBorder = new DynamicBorder( + highlightedBorderColor, + nativeInnerBorderInsets.top, + nativeInnerBorderInsets.left, + nativeInnerBorderInsets.bottom, + nativeInnerBorderInsets.right); + } } - this.highlightedInnerBorder = new DynamicBorder( - highlightedBorderColor, - nativeInnerBorderInsets.top, - nativeInnerBorderInsets.left, - nativeInnerBorderInsets.bottom, - nativeInnerBorderInsets.right); } public void setHighlight(boolean isToBeHighlighted) { outlineBorder.setHighlight(isToBeHighlighted); |
From: Erik V. <ev...@us...> - 2012-02-07 22:02:17
|
rails/game/StartRound.java | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) New commits: commit c60ac2a448bd5b3d727673a23fa879da839c4d54 Author: Erik Vos <eri...@xs...> Date: Tue Feb 7 23:01:08 2012 +0100 Fix for 1835 bug: BY presidency not transferred during start round. Presidency check was missing and has now been added in the start round. diff --git a/rails/game/StartRound.java b/rails/game/StartRound.java index c9ab5b6..73008d1 100644 --- a/rails/game/StartRound.java +++ b/rails/game/StartRound.java @@ -3,9 +3,7 @@ package rails.game; import java.util.ArrayList; import java.util.List; -import rails.common.DisplayBuffer; -import rails.common.GuiDef; -import rails.common.LocalText; +import rails.common.*; import rails.common.parser.GameOption; import rails.game.action.*; import rails.game.model.ModelObject; @@ -18,7 +16,7 @@ public abstract class StartRound extends Round { protected int[] itemIndex; protected List<StartItem> itemsToSell = null; protected State auctionItemState = - new State("AuctionItem", StartItem.class); + new State("AuctionItem", StartItem.class); protected IntegerState numPasses = new IntegerState("StartRoundPasses"); protected int numPlayers; protected String variant; @@ -120,7 +118,7 @@ public abstract class StartRound extends Round { BuyStartItem buyAction = (BuyStartItem) startItemAction; if (buyAction.hasSharePriceToSet() - && buyAction.getAssociatedSharePrice() == 0) { + && buyAction.getAssociatedSharePrice() == 0) { // We still need a share price for this item startItemAction.getStartItem().setStatus( StartItem.NEEDS_SHARE_PRICE); @@ -138,7 +136,7 @@ public abstract class StartRound extends Round { DisplayBuffer.add(LocalText.getText("UnexpectedAction", action.toString())); } - + startPacketChecks(); if (startPacket.areAllSold()) { @@ -210,14 +208,14 @@ public abstract class StartRound extends Round { sharePrice = boughtItem.getAssociatedSharePrice(); if (sharePrice == 0) { errMsg = - LocalText.getText("NoSharePriceSet", shareCompName); + LocalText.getText("NoSharePriceSet", shareCompName); break; } if ((stockMarket.getStartSpace(sharePrice)) == null) { errMsg = - LocalText.getText("InvalidStartPrice", - Bank.format(sharePrice), - shareCompName ); + LocalText.getText("InvalidStartPrice", + Bank.format(sharePrice), + shareCompName ); break; } } @@ -302,7 +300,7 @@ public abstract class StartRound extends Round { if (comp.hasStarted() && !comp.hasFloated()) { checkFlotation(comp); } - + if (comp.hasStarted()) comp.checkPresidency(); // Needed for 1835 BY } } @@ -318,9 +316,9 @@ public abstract class StartRound extends Round { super.finishRound(); } - /*----- Setting up the UI for the next action -----*/ + /*----- Setting up the UI for the next action -----*/ - /** + /** * Get the currentPlayer index in the player list (starting at 0). * * @return The index of the current Player. |
From: Stefan F. <ste...@us...> - 2012-02-07 18:05:12
|
rails/game/state/ArrayListMultimapState.java | 4 rails/game/state/Context.java | 2 rails/game/state/CountableItem.java | 11 ++ rails/game/state/HashMultimapState.java | 2 rails/game/state/ItemType.java | 5 + rails/game/state/MultimapState.java | 2 rails/game/state/OwnableItem.java | 16 +++ rails/game/state/PortfolioChange.java | 44 ++++++++++ rails/game/state/PortfolioManager.java | 38 ++++++++ rails/game/state/PortfolioNG.java | 117 +++++++++++++++++++++++++++ rails/game/state/StateManager.java | 61 +++++++++++--- rails/game/state/Wallet.java | 111 +++++++++++++++++++++++++ rails/game/state/WalletChange.java | 50 +++++++++++ rails/game/state/WalletManager.java | 38 ++++++++ 14 files changed, 485 insertions(+), 16 deletions(-) New commits: commit 6d9cd8a9cc6a0e0f1f638d7b518fd75d9b363f7f Author: Stefan Frey <ste...@we...> Date: Mon Feb 6 20:27:46 2012 +0100 Creation of next generation portfolio mechanism based on a portfolio class that extends State class Creation of a wallet class that allows countable items diff --git a/rails/game/state/ArrayListMultimapState.java b/rails/game/state/ArrayListMultimapState.java index 406a90e..d23a0eb 100644 --- a/rails/game/state/ArrayListMultimapState.java +++ b/rails/game/state/ArrayListMultimapState.java @@ -42,7 +42,7 @@ public class ArrayListMultimapState<K,V> extends MultimapState<K,V> { */ public boolean put(K key, V value) { - new MultimapChange<K,V>(this, key, value, true ); + new MultimapChange<K,V>(this, key, value, true); return true; } @@ -65,7 +65,7 @@ public class ArrayListMultimapState<K,V> extends MultimapState<K,V> { return map.toString(); } - public void change(K key, V value, boolean addToMap) { + void change(K key, V value, boolean addToMap) { if (addToMap) { map.put(key, value); } else { diff --git a/rails/game/state/Context.java b/rails/game/state/Context.java index 65b69ba..2036777 100644 --- a/rails/game/state/Context.java +++ b/rails/game/state/Context.java @@ -68,7 +68,7 @@ public class Context extends GameItem { private Context initRoot() { super.init(this); // sets parent identical to ROOT - stateManager = new StateManager(this); + stateManager = StateManager.create(); return this; } diff --git a/rails/game/state/CountableItem.java b/rails/game/state/CountableItem.java new file mode 100644 index 0000000..122b22c --- /dev/null +++ b/rails/game/state/CountableItem.java @@ -0,0 +1,11 @@ +package rails.game.state; + +/** + * Identifies items which are countable + * They are stored inside wallets + * @author freystef + */ + +public interface CountableItem extends Item { + +} diff --git a/rails/game/state/HashMultimapState.java b/rails/game/state/HashMultimapState.java index 0c2faa4..50a3640 100644 --- a/rails/game/state/HashMultimapState.java +++ b/rails/game/state/HashMultimapState.java @@ -106,7 +106,7 @@ public final class HashMultimapState<K,V> extends MultimapState<K,V> implements return map.toString(); } - public void change(K key, V value, boolean addToMap) { + void change(K key, V value, boolean addToMap) { if (addToMap) { map.put(key, value); } else { diff --git a/rails/game/state/ItemType.java b/rails/game/state/ItemType.java new file mode 100644 index 0000000..efd0639 --- /dev/null +++ b/rails/game/state/ItemType.java @@ -0,0 +1,5 @@ +package rails.game.state; + +public interface ItemType extends Item { + +} diff --git a/rails/game/state/MultimapState.java b/rails/game/state/MultimapState.java index 3750ffb..f9f3550 100644 --- a/rails/game/state/MultimapState.java +++ b/rails/game/state/MultimapState.java @@ -13,6 +13,6 @@ abstract class MultimapState<K,V> extends State { public abstract boolean remove(K key, V value); - public abstract void change(K key, V value, boolean addToMap); + abstract void change(K key, V value, boolean addToMap); } diff --git a/rails/game/state/OwnableItem.java b/rails/game/state/OwnableItem.java new file mode 100644 index 0000000..aad0cad --- /dev/null +++ b/rails/game/state/OwnableItem.java @@ -0,0 +1,16 @@ +package rails.game.state; + + +public interface OwnableItem<T extends OwnableItem<T>> extends Item { + + /** + * @return the parent of an ownableItem has to be an ItemType + */ + public ItemType getParent(); + + /** + * @return the current portfolio + */ + public PortfolioNG<T> getPortfolio(); + +} diff --git a/rails/game/state/PortfolioChange.java b/rails/game/state/PortfolioChange.java new file mode 100644 index 0000000..acdf5d3 --- /dev/null +++ b/rails/game/state/PortfolioChange.java @@ -0,0 +1,44 @@ +package rails.game.state; + +final class PortfolioChange<T extends OwnableItem<T>> implements Change { + + private final PortfolioNG<T> in; + private final PortfolioNG<T> out; // can be null + private final T item; + + PortfolioChange(PortfolioNG<T> in, PortfolioNG<T> out, T item) { + this.in = in; + this.out = out; + this.item = item; + + ChangeStack.add(this); + } + + public void execute() { + in.change(item, true); + if (out != null) { + out.change(item, false); + } + } + + public void undo() { + in.change(item, false); + if (out != null) { + out.change(item, true); + } + } + + public PortfolioNG<T> getState() { + return in; + } + + @Override + public String toString() { + if (out == null) { + return "PortfolioChange: Adds item " + item + " to portfolio " + in.getId(); + } else { + return "PortfolioChange: Moves item " + item + " from portfolio " + out.getId() + " to portfolio " + in.getId(); + } + } + +} diff --git a/rails/game/state/PortfolioManager.java b/rails/game/state/PortfolioManager.java new file mode 100644 index 0000000..b7dab6c --- /dev/null +++ b/rails/game/state/PortfolioManager.java @@ -0,0 +1,38 @@ +package rails.game.state; + +import com.google.common.collect.HashMultimap; + +/** + * PortfolioManager stores links to all existing portfolios + * @author freystef + */ + +public class PortfolioManager extends Context { + + public static final String ID = "Portfolios"; + + private final HashMultimap<Item, PortfolioNG<?>> portfolios = HashMultimap.create(); + + private PortfolioManager() { + super(ID); + } + + static PortfolioManager create() { + return new PortfolioManager(); + } + + @Override + public PortfolioManager init(Item parent) { + super.init(parent); + return this; + } + + boolean addPortfolio(PortfolioNG<?> p){ + return portfolios.put(p.getParent(), p); + } + + boolean removePortfolio(PortfolioNG<?> p){ + return portfolios.remove(p.getParent(), p); + } + +} diff --git a/rails/game/state/PortfolioNG.java b/rails/game/state/PortfolioNG.java new file mode 100644 index 0000000..e6eb2b3 --- /dev/null +++ b/rails/game/state/PortfolioNG.java @@ -0,0 +1,117 @@ +package rails.game.state; + +import java.util.Collection; + +import com.google.common.collect.ArrayListMultimap; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableListMultimap; +import com.google.common.collect.ImmutableMap; + +public final class PortfolioNG<T extends OwnableItem<T>> extends State { + + private final ArrayListMultimap<ItemType, T> portfolio; + + private PortfolioNG(String id) { + super(id); + portfolio = ArrayListMultimap.create(); + } + + /** + * Creates an owned and empty Portfolio + */ + public static <T extends OwnableItem<T>> PortfolioNG<T> create(Item parent, String id){ + return new PortfolioNG<T>(id).init(parent); + } + + /** + * Creates an unowned and empty Portfolio + * Remark: Still requires a call to the init-method + */ + public static <T extends OwnableItem<T>> PortfolioNG<T> create( String id){ + return new PortfolioNG<T>(id); + } + + @Override + public PortfolioNG<T> init(Item parent){ + super.init(parent); + return this; + } + + /** + * Adds an item to the portfolio + * @param item to add + * @return false if portfolio already contains the item, otherwise true + */ + public boolean initialAdd(T item) { + if (portfolio.containsValue(item)) return false; + new PortfolioChange<T>(this, null, item); + return true; + } + + /** + * Move a new item to the portfolio + * and removes the item from the previous portfolio + * @param item to move + * @return false if the portfolio already contains the item, otherwise true + */ + public boolean moveInto(T item) { + if (portfolio.containsValue(item)) return false; + new PortfolioChange<T>(this, item.getPortfolio(), item); + return true; + } + + /** + * @param item that is checked if it is in the portfolio + * @return true if contained, false otherwise + */ + public boolean containsItem(T item) { + return portfolio.containsValue(item); + } + + /** + * @param type that is checked if there are items stored for + * @return true if there a items stored under that type, false otherwise + */ + public boolean containsKey(ItemType type) { + return portfolio.containsKey(type); + } + + /** + * @return all items contained in the portfolio + */ + public ImmutableList<T> items() { + return ImmutableList.copyOf(portfolio.values()); + } + + + /** + * @param key that defines the specific itemtype for which the portfolio members get returned + * @return all items of type key contained in the portfolio + */ + public ImmutableList<T> getItems(ItemType key) { + return ImmutableList.copyOf(portfolio.get(key)); + } + + /** + * @return a ListMultimap view of the Portfolio + */ + public ImmutableListMultimap<ItemType, T> view() { + return ImmutableListMultimap.copyOf(portfolio); + } + + /** + * @return a Map view of the Portfolio + */ + public ImmutableMap<ItemType, Collection<T>> viewAsMap() { + return ImmutableMap.copyOf(portfolio.asMap()); + } + + void change (T item, boolean intoPortfolio){ + if (intoPortfolio) { + portfolio.put(item.getParent(), item); + } else { + portfolio.remove(item.getParent(), item); + } + } + +} diff --git a/rails/game/state/StateManager.java b/rails/game/state/StateManager.java index 7ef27c5..3812e44 100644 --- a/rails/game/state/StateManager.java +++ b/rails/game/state/StateManager.java @@ -15,33 +15,72 @@ import com.google.common.collect.Sets; import rails.game.GameManager; import rails.game.model.Model; +// TODO: Change it to a Context subclass + public final class StateManager extends GameItem { + public static final String ID = "States"; + protected static Logger log = Logger.getLogger(StateManager.class.getPackage().getName()); private final Set<State> allStates = new HashSet<State>(); + + private final PortfolioManager portfolioManager = PortfolioManager.create(); + private final WalletManager walletManager = WalletManager.create(); + + private StateManager() { + super(ID); + } /** - * Creates a StateManager (only possible for a root GameContext) - * @param parent a root GameContext + * Creates an (unowned) StateManager + * Remark: Still requires a call to the init-method */ - StateManager(Context parent) { - super("StateManager"); - - if (parent.getId() != Context.ROOT) { + public static StateManager create(){ + return new StateManager(); + } + + /** + * @exception IllegalArgumentException if parent is not the Context with an id equal to Context.ROOT + */ + @Override + public StateManager init(Item parent) { + if (!(parent instanceof Context && parent.getId() != Context.ROOT)) { throw new IllegalArgumentException("StateManager can only be created for a root GameContext"); } - // immediate initialization - init(parent); + super.init(parent); + portfolioManager.init(parent); + walletManager.init(parent); + return this; } - void registerState(State state) { - allStates.add(state); + /** + * Register states + * Remark: Portfolios and Wallets get added from their respective managers automatically + */ + boolean registerState(State state) { + if (!allStates.add(state)) return false; + if (state instanceof PortfolioNG) { + return portfolioManager.addPortfolio((PortfolioNG<?>) state); + } else if (state instanceof Wallet) { + return walletManager.addWallet((Wallet<?>) state); + } + return true; } + /** + * De-Register states + * Remark: Portfolios and Wallets are removed from their respective managers automatically + */ boolean deRegisterState(State state) { - return allStates.remove(state); + if (!allStates.remove(state)) return false; + if (state instanceof PortfolioNG) { + return portfolioManager.removePortfolio((PortfolioNG<?>) state); + } else if (state instanceof Wallet) { + return walletManager.removeWallet((Wallet<?>) state); + } + return true; } /** diff --git a/rails/game/state/Wallet.java b/rails/game/state/Wallet.java new file mode 100644 index 0000000..da119bd --- /dev/null +++ b/rails/game/state/Wallet.java @@ -0,0 +1,111 @@ +package rails.game.state; + +import com.google.common.collect.HashMultiset; +import com.google.common.collect.ImmutableMultiset; + +/** + * A wallet allows the storage of CountableItem(s) + * + * Remark: It is a wrapper around a Multiset, thus it does not support negative + * numbers. + * + * @author freystef + */ + +public final class Wallet<T extends CountableItem> extends State { + + + private final HashMultiset<T> wallet; + + + private Wallet(String id) { + super(id); + wallet = HashMultiset.create(); + } + + /** + * Creates an owned and empty Wallet + */ + public static <T extends CountableItem> Wallet<T> create(Item parent, String id){ + return new Wallet<T>(id).init(parent); + } + + /** + * Creates an unowned and empty Wallet + * Remark: Still requires a call to the init-method + */ + public static <T extends CountableItem> Wallet<T> create( String id){ + return new Wallet<T>(id); + } + + @Override + public Wallet<T> init(Item parent){ + super.init(parent); + return this; + } + + /** + * Sets an item to the wallet to the amount given (only if there is no amount defined yet) + * @param item to set + * @param amount initial (has to be positive) + * @return false if portfolio already contains the item (=> no change), otherwise true + + * @exception IllegalArgumentException if amount is negative + */ + public boolean initialSet(T item, int amount) { + if (amount < 0) throw new IllegalArgumentException("Wallet amounts have to be positive"); + if (wallet.contains(item)) return false; + + new WalletChange<T>(this, null, item, amount); + return true; + } + + /** + * Adds a specific amount to the specified item + * @param item to change + * @param amount initial (has to be positive) + * @param source the wallet from which the amount is moved + + * @exception IllegalArgumentException if amount is negative + * @exception ArithmeticException if wallet which is used as source does not contain at least the amount + */ + + public void moveInto(T item, int amount, Wallet<T> source) { + if (amount < 0) throw new IllegalArgumentException("Wallet amounts have to be positive"); + + if (amount > source.count(item)) throw new ArithmeticException("Source wallet does not contain required amount"); + + new WalletChange<T>(this, source, item, amount); + } + + /** + * Adds one unit of the specified item + * @param item to change + * @param from the wallet from which the unit is taken + */ + public void moveInto(T item, Wallet<T> from) { + moveInto(item, 1, from); + } + + + /** + * @param item to count + * @return the current number of the specified amount in the wallet + */ + public int count(T item) { + return wallet.count(item); + } + + /** + * @return a Multiset view of the Wallet + */ + public ImmutableMultiset<T> view() { + return ImmutableMultiset.copyOf(wallet); + } + + + void change (T item, int value) { + wallet.add(item, value); + } + +} diff --git a/rails/game/state/WalletChange.java b/rails/game/state/WalletChange.java new file mode 100644 index 0000000..da646c3 --- /dev/null +++ b/rails/game/state/WalletChange.java @@ -0,0 +1,50 @@ +package rails.game.state; + +final class WalletChange<T extends CountableItem> implements Change { + + private final Wallet<T> in; + private final Wallet<T> out; + private final T item; + private final int amount; + + + WalletChange(Wallet<T> in, Wallet<T> out, T item, int amount) { + this.in = in; + this.out = out; + this.item = item; + this.amount = amount; + + ChangeStack.add(this); + } + + + public void execute() { + in.change(item, amount); + if (out != null) { + out.change(item, - amount); + } + } + + public void undo() { + in.change(item, - amount); + if (out != null) { + out.change(item, amount); + } + } + + public Wallet<T> getState() { + return in; + } + + @Override + public String toString() { + if (out == null) { + return "WalletChange: Sets " + amount + " of " + item + " in wallet " + in.getId(); + } else { + return "WalletChange: Moves " + amount + " of " + item + " from wallet " + out.getId() + " to wallet " + in.getId(); + } + } + + + +} diff --git a/rails/game/state/WalletManager.java b/rails/game/state/WalletManager.java new file mode 100644 index 0000000..2d00847 --- /dev/null +++ b/rails/game/state/WalletManager.java @@ -0,0 +1,38 @@ +package rails.game.state; + +import com.google.common.collect.HashMultimap; + +/** + * WalletManager stores links to all existing wallets + * @author freystef + */ + +public class WalletManager extends Context { + + public static final String ID = "Wallets"; + + private final HashMultimap<Item, Wallet<?>> wallets = HashMultimap.create(); + + private WalletManager() { + super(ID); + } + + static WalletManager create() { + return new WalletManager(); + } + + @Override + public WalletManager init(Item parent) { + super.init(parent); + return this; + } + + boolean addWallet(Wallet<?> w){ + return wallets.put(w.getParent(), w); + } + + boolean removeWallet(Wallet<?> w){ + return wallets.remove(w.getParent(), w); + } + +} |
From: Frederick W. <fre...@us...> - 2012-02-07 16:37:37
|
rails/ui/swing/GridPanel.java | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) New commits: commit 59e98fa0bda31a4f2944fee0dac6bd123b322bb0 Author: Frederick Weld <fre...@gm...> Date: Tue Feb 7 17:36:03 2012 +0100 Increased robustness of grid panel highlighting getBorderInsets was reported to return null under some conditions. Now, GridPanel is able to handle that. diff --git a/rails/ui/swing/GridPanel.java b/rails/ui/swing/GridPanel.java index 9f11f42..d2ea42b 100644 --- a/rails/ui/swing/GridPanel.java +++ b/rails/ui/swing/GridPanel.java @@ -252,12 +252,16 @@ implements ActionListener, KeyListener { this.nativeInnerBorder = innerBorder; this.outlineBorder = outlineBorder; this.outerBorder = outerBorder; + Insets nativeInnerBorderInsets = nativeInnerBorder.getBorderInsets(null); + if (nativeInnerBorderInsets == null) { + nativeInnerBorderInsets = new Insets(0,0,0,0); + } this.highlightedInnerBorder = new DynamicBorder( highlightedBorderColor, - nativeInnerBorder.getBorderInsets(null).top, - nativeInnerBorder.getBorderInsets(null).left, - nativeInnerBorder.getBorderInsets(null).bottom, - nativeInnerBorder.getBorderInsets(null).right); + nativeInnerBorderInsets.top, + nativeInnerBorderInsets.left, + nativeInnerBorderInsets.bottom, + nativeInnerBorderInsets.right); } public void setHighlight(boolean isToBeHighlighted) { outlineBorder.setHighlight(isToBeHighlighted); |
From: Stefan F. <ste...@us...> - 2012-02-07 11:53:44
|
Tag '1.6.3' created by Stefan Frey <ste...@we...> at 2012-02-07 11:53 +0000 version 1.6.3 Changes since v1.6.2-2: --- 0 files changed --- |
From: Frederick W. <fre...@us...> - 2012-02-05 13:24:18
|
rails/ui/swing/ORWindow.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) New commits: commit 6d5f311591d781cecd4bfe4bb2fcf3e2a9b8be65 Author: Frederick Weld <fre...@gm...> Date: Sun Feb 5 14:21:31 2012 +0100 Fixed: Externalized panels taken into account when close/open OR window Stefan had observed that externalized panels were not correctly restored when closing / re-opening the OR Window. diff --git a/rails/ui/swing/ORWindow.java b/rails/ui/swing/ORWindow.java index b35bc3e..441be07 100644 --- a/rails/ui/swing/ORWindow.java +++ b/rails/ui/swing/ORWindow.java @@ -191,7 +191,11 @@ public class ORWindow extends JFrame implements ActionPerformer { public void windowClosing(WindowEvent e) { saveDockableLayout(); StatusWindow.uncheckMenuItemBox(StatusWindow.MAP_CMD); - frame.dispose(); + if (!isDockablePanelsEnabled()) { + frame.dispose(); + } else { + setVisible(false); + } } }); addComponentListener(new ComponentAdapter() { |
From: Frederick W. <fre...@us...> - 2012-02-05 10:26:18
|
rails/ui/swing/ORWindow.java | 126 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 125 insertions(+), 1 deletion(-) New commits: commit 9b2b2d123eee75c646a4e0159f8420b672865504 Author: Frederick Weld <fre...@gm...> Date: Sun Feb 5 11:16:10 2012 +0100 Added support for docking externalized panels to each other Solution consists of adding a SplitDockStation in between and fine tuning the default dockable options (maximize button). Based on http://forum.byte-welt.de/showthread.php?t=3097&page=2 diff --git a/rails/ui/swing/ORWindow.java b/rails/ui/swing/ORWindow.java index 5f75ad9..b35bc3e 100644 --- a/rails/ui/swing/ORWindow.java +++ b/rails/ui/swing/ORWindow.java @@ -12,13 +12,28 @@ import java.util.Locale; import javax.swing.JFrame; import javax.swing.JOptionPane; import javax.swing.JScrollPane; +import javax.swing.SwingUtilities; import org.apache.log4j.Logger; +import bibliothek.gui.DockController; +import bibliothek.gui.Dockable; +import bibliothek.gui.DockStation; +import bibliothek.gui.dock.ScreenDockStation; +import bibliothek.gui.dock.SplitDockStation; import bibliothek.gui.dock.common.CControl; import bibliothek.gui.dock.common.CGrid; +import bibliothek.gui.dock.common.CStation; import bibliothek.gui.dock.common.DefaultSingleCDockable; +import bibliothek.gui.dock.common.action.predefined.CBlank; +import bibliothek.gui.dock.common.event.CDockableStateListener; +import bibliothek.gui.dock.common.intern.CDockable; +import bibliothek.gui.dock.common.intern.DefaultCDockable; +import bibliothek.gui.dock.common.intern.ui.CSingleParentRemover; +import bibliothek.gui.dock.common.mode.ExtendedMode; import bibliothek.gui.dock.common.theme.ThemeMap; +import bibliothek.gui.dock.event.DockStationAdapter; +import bibliothek.gui.dock.station.LayoutLocked; import rails.common.GuiDef; import rails.common.LocalText; @@ -92,7 +107,11 @@ public class ORWindow extends JFrame implements ActionPerformer { orWindowControl.setTheme( ThemeMap.KEY_SMOOTH_THEME ); add( orWindowControl.getContentArea() ); CGrid orWindowLayout = new CGrid( orWindowControl ); - + + //ensure that externalized dockables get a split station as parent + //necessary, otherwise externalized dockables cannot be docked together + alwaysAddStationsToExternalizedDockables(orWindowControl); + //set docks tooltip language if ("en_us".equalsIgnoreCase(Config.get("locale"))) { //hard setting to default in case of US as this is DockingFrames default language @@ -350,6 +369,111 @@ public class ORWindow extends JFrame implements ActionPerformer { orWindowControl.load(getLayoutName()); } catch (Exception e) {} //skip if layout not found } + + //ensure that all dockables that are externalized according to layout + //information don't have the deault maximize button (as it won't work + //for the adjusted externalization setup) + for (int i = 0 ; i < orWindowControl.getCDockableCount() ; i++ ) { + CDockable d = orWindowControl.getCDockable(i); + if (d instanceof DefaultCDockable) { + DefaultCDockable dd = (DefaultCDockable)d; + if (ExtendedMode.EXTERNALIZED.equals(d.getExtendedMode())) { + dd.putAction( CDockable.ACTION_KEY_MAXIMIZE, CBlank.BLANK ); + } + } + } + } + + /** + * The behavior of the specified CControl is altered by the following: + * If a dockable is detached / externalized, it would normally put directly + * under the ScreenDockStation - thus inhibiting any docking to/from this + * dockable. This is changed such that a split station (that would allow for + * that) is put in between the ScreenDockStation and the Dockable. + */ + private void alwaysAddStationsToExternalizedDockables(CControl cc) { + + // access the DockStation which shows our detached (externalized) items + CStation<?> screen = (CStation<?>) + cc.getStation( CControl.EXTERNALIZED_STATION_ID ); + + // remove the standard maximize action when externalizing + // and adds it back when unexternalizing + // (as maximize won't work for the adjusted externalization setup) + cc.addStateListener( new CDockableStateListener() { + public void visibilityChanged( CDockable cd ){ + // ignore + } + + public void extendedModeChanged( CDockable cd, ExtendedMode mode ){ + if( cd instanceof DefaultCDockable ) { + DefaultCDockable dockable = (DefaultCDockable) cd; + if( mode.equals( ExtendedMode.EXTERNALIZED ) ) { + dockable.putAction( CDockable.ACTION_KEY_MAXIMIZE, CBlank.BLANK ); + } + else { + dockable.putAction( CDockable.ACTION_KEY_MAXIMIZE, null ); + } + } + } + }); + + // if a Dockable is added to that station... + screen.getStation().addDockStationListener( new ScreenDockStationListener()); + + // make sure a SplitDockStation with one child and a parent + // that is a ScreenDockStation does not get removed + cc.intern().getController().setSingleParentRemover( + new CSingleParentRemover( cc ){ + @Override + protected boolean shouldTest( DockStation station ){ + if( station instanceof SplitDockStation ) { + SplitDockStation split = (SplitDockStation) station; + if( split.getDockParent() instanceof ScreenDockStation ) { + // but we want to remove the station if it does + // not have any children at all + return split.getDockableCount() == 0; + } + } + return super.shouldTest( station ); + } + } ); } + @LayoutLocked(locked = false) + private class ScreenDockStationListener extends DockStationAdapter { + public void dockableAdded( DockStation station, final Dockable dockable ){ + // ... and the new child is not a SplitDockStation ... + if( !(dockable instanceof SplitDockStation) ) { + SwingUtilities.invokeLater( new Runnable(){ + public void run(){ + checkAndReplace( dockable ); + } + } ); + } + } + private void checkAndReplace( Dockable dockable ){ + DockStation station = dockable.getDockParent(); + if( !(station instanceof ScreenDockStation) ) { + // cancel + return; + } + + // .. then we just insert a SplitDockStation + SplitDockStation split = new SplitDockStation(); + DockController controller = station.getController(); + + try { + // disable events while rearranging our layout + controller.freezeLayout(); + + station.replace( dockable, split ); + split.drop( dockable ); + } + finally { + // and enable events after we finished + controller.meltLayout(); + } + } + } } |
From: Frederick W. <fre...@us...> - 2012-02-05 06:35:36
|
LocalisedText.properties | 3 +++ data/Properties.xml | 2 ++ rails/game/GameManager.java | 4 ++++ rails/game/GameManagerI.java | 2 ++ rails/sound/SoundConfig.java | 6 ++++-- rails/sound/SoundEventInterpreter.java | 28 ++++++++++++++++++++++++++-- 6 files changed, 41 insertions(+), 4 deletions(-) New commits: commit 4439e439edd8982aca87b35c0ea64e331a4981cb Author: Frederick Weld <fre...@gm...> Date: Sun Feb 5 07:28:16 2012 +0100 Added new sfx options (gameOverPending and "laid last available tile") diff --git a/LocalisedText.properties b/LocalisedText.properties index 071d381..6aaa145 100644 --- a/LocalisedText.properties +++ b/LocalisedText.properties @@ -178,6 +178,7 @@ Config.infoText.sound.backgroundMusic=The only music file type supported is mp3. Config.infoText.sound.backgroundMusic.stockRound=<html>Enter assignment of music files to phases.<ul><li>Separate the assignments by commas.<li>Each assignment has the syntax phaseName=complete file path<li>Default music is defined by omitting "phaseName=" in the assignment.</ul><strong>Examples:</strong><ul><li>Set default music: <br><code>c:\SR-default.mp3</code><li>Set phase-dependent music and a default (for trains above 6): <br><code>2=c:\SR-2.mp3,3=c:\SR-3.mp3,4=c:\SR-4.mp3,5=c:\SR-5.mp3,6=c:\SR-6.mp3,c:\SR-D.mp3</code></ul> </html> Config.infoText.sound.backgroundMusic.operatingRound=<html>Enter assignment of music files to phases.<ul><li>Separate the assignments by commas.<li>Each assignment has the syntax phaseName=complete file path<li>Default music is defined by omitting "phaseName=" in the assignment.</ul><strong>Examples:</strong><ul><li>Set default music: <br><code>c:\OR-default.mp3</code><li>Set phase-dependent music and a default (for trains above 6): <br><code>2=c:\OR-2.mp3,3=c:\OR-3.mp3,4=c:\OR-4.mp3,5=c:\OR-5.mp3,6=c:\OR-6.mp3,c:\OR-D.mp3</code></ul> </html> Config.infoText.sound.sfx=The only sound effects file type supported is mp3. +Config.infoText.sound.sfx.gen.gameOverPending=<html>Sound effect is played in case of any event that triggers the end of the game. Examples:<ul><li>Bank is broken.<li>Share price reaches maximum (only game-end trigger for some 18xx variants).</ul></html> Config.infoText.sound.sfx.gen.newCurrentPlayer=<html>Enter assignment of sound effect files to player names.<br>The assigned sound is played if the player becomes the active one - meaning, the user interface is responsive for this player's commands.<ul><li>Separate the assignments by commas.<li>Each assignment has the syntax playerName=complete file path<li>Default sound effect is defined by omitting "playerName=" in the assignment.</ul><strong>Examples:</strong><ul><li>Set default sound effect: <br><code>c:\ChangeActivePlayer.mp3</code><li>Set player-dependent sound effect and a default (for all other players): <br><code>Tom=c:\ChangeActivePlayer_Tom.mp3,Sarah=c:\ChangeActivePlayer_Sarah.mp3,c:\ChangeActivePlayer_default.mp3</code></ul> </html> Config.infoText.sound.sfx.or.buyTrain=<html>Enter assignment of sound effect files to train types.<ul><li>Separate the assignments by commas.<li>Each assignment has the syntax trainName=complete file path<li>Default sound effect is defined by omitting "trainName=" in the assignment.</ul><strong>Examples:</strong><ul><li>Set default sound effect: <br><code>c:\BuyTrain-default.mp3</code><li>Set train-dependent sound effect and a default (for trains above 6): <br><code>2=c:\BuyTrain-2.mp3,3=c:\BuyTrain-3.mp3,4=c:\BuyTrain-4.mp3,5=c:\BuyTrain-5.mp3,6=c:\BuyTrain-6.mp3,c:\BuyTrain-D.mp3</code></ul> </html> Config.infoText.sound.sfx.or.setRevenue=<html><ul><li>Only the latter portion of this file is played.<ul><li>For an average revenue, the last third is played.</ul><li>The higher the company's revenue the longer this file is played.<ul><li>But the file is at most played once as a whole.</li></ul></html> @@ -216,6 +217,7 @@ Config.label.sound.backgroundMusic.startRound=Start Round Config.label.sound.backgroundMusic.stockRound=Stock Round (several files) Config.label.sound.backgroundMusic.operatingRound=Operating Round (several files) Config.label.sound.sfx=Sound Effects +Config.label.sound.sfx.gen.gameOverPending=Imminent Game End Config.label.sound.sfx.gen.newCurrentPlayer=Change of active player Config.label.sound.sfx.gen.pass=Pass Config.label.sound.sfx.gen.select=Select (hexes, click fields) @@ -228,6 +230,7 @@ Config.label.sound.sfx.or.decision.split=Split Revenue Config.label.sound.sfx.or.decision.withhold=Withhold Revenue Config.label.sound.sfx.or.layTile.city=Lay Tile (city) Config.label.sound.sfx.or.layTile.track=Lay Tile (track, town) +Config.label.sound.sfx.or.layTile.lastTileLaid=Last available tile is laid Config.label.sound.sfx.or.layToken=Lay Token Config.label.sound.sfx.or.rotateTile=Rotate Tile Config.label.sound.sfx.or.setRevenue=Set Revenue diff --git a/data/Properties.xml b/data/Properties.xml index 4802f74..da62099 100644 --- a/data/Properties.xml +++ b/data/Properties.xml @@ -77,6 +77,7 @@ <Property name="sound.sfx.gen.pass" type="FILE" /> <Property name="sound.sfx.gen.select" type="FILE" /> <Property name="sound.sfx.gen.newCurrentPlayer" type="STRING" /> + <Property name="sound.sfx.gen.gameOverPending" type="FILE" /> <Property name="sound.sfx.str.bidStartItem" type="FILE" /> <Property name="sound.sfx.str.buyStartItem" type="FILE" /> <Property name="sound.sfx.sr.openingBell" type="FILE" /> @@ -89,6 +90,7 @@ <Property name="sound.sfx.or.rotateTile" type="FILE" /> <Property name="sound.sfx.or.layTile.track" type="FILE" /> <Property name="sound.sfx.or.layTile.city" type="FILE" /> + <Property name="sound.sfx.or.layTile.lastTileLaid" type="FILE" /> <Property name="sound.sfx.or.layToken" type="FILE" /> <Property name="sound.sfx.or.setRevenue" type="FILE" /> <Property name="sound.sfx.or.decision.payout" type="FILE" /> diff --git a/rails/sound/SoundConfig.java b/rails/sound/SoundConfig.java index 6867ddf..5e3aa03 100644 --- a/rails/sound/SoundConfig.java +++ b/rails/sound/SoundConfig.java @@ -24,6 +24,7 @@ public class SoundConfig { public static final String KEY_BGM_OperatingRound = "sound.backgroundMusic.operatingRound"; public static final String KEY_BGM_EndOfGameRound = "sound.backgroundMusic.endOfGameRound"; public static final String KEY_SFX_Enabled = "sound.sfx"; + public static final String KEY_SFX_GEN_GameOverPending = "sound.sfx.gen.gameOverPending"; public static final String KEY_SFX_GEN_Pass = "sound.sfx.gen.pass"; public static final String KEY_SFX_GEN_Select = "sound.sfx.gen.select"; public static final String KEY_SFX_GEN_NewCurrentPlayer = "sound.sfx.gen.newCurrentPlayer"; @@ -37,8 +38,9 @@ public class SoundConfig { public static final String KEY_SFX_SR_SellShare_NonPresident = "sound.sfx.sr.sellShare.nonPresident"; public static final String KEY_SFX_SR_CompanyFloats = "sound.sfx.sr.companyFloats"; public static final String KEY_SFX_OR_RotateTile = "sound.sfx.or.rotateTile"; - public static final String KEY_SFX_OR_LayTile_track = "sound.sfx.or.layTile.track"; - public static final String KEY_SFX_OR_LayTile_city = "sound.sfx.or.layTile.city"; + public static final String KEY_SFX_OR_LayTile_Track = "sound.sfx.or.layTile.track"; + public static final String KEY_SFX_OR_LayTile_City = "sound.sfx.or.layTile.city"; + public static final String KEY_SFX_OR_LayTile_LastTileLaid = "sound.sfx.or.layTile.lastTileLaid"; public static final String KEY_SFX_OR_LayToken = "sound.sfx.or.layToken"; public static final String KEY_SFX_OR_SetRevenue = "sound.sfx.or.setRevenue"; public static final String KEY_SFX_OR_Decision_Payout = "sound.sfx.or.decision.payout"; diff --git a/rails/sound/SoundEventInterpreter.java b/rails/sound/SoundEventInterpreter.java index 48a8df2..889ade6 100644 --- a/rails/sound/SoundEventInterpreter.java +++ b/rails/sound/SoundEventInterpreter.java @@ -105,10 +105,14 @@ public class SoundEventInterpreter { LayTile lt = (LayTile)action; if (lt.getLaidTile().getNumStations() == 0) { //track upgrade - player.playSFXByConfigKey (SoundConfig.KEY_SFX_OR_LayTile_track); + player.playSFXByConfigKey (SoundConfig.KEY_SFX_OR_LayTile_Track); } else { //city upgrade - player.playSFXByConfigKey (SoundConfig.KEY_SFX_OR_LayTile_city); + player.playSFXByConfigKey (SoundConfig.KEY_SFX_OR_LayTile_City); + } + if (lt.getLaidTile().countFreeTiles() == 1) { + //last available tile is about to be laid + player.playSFXByConfigKey (SoundConfig.KEY_SFX_OR_LayTile_LastTileLaid); } } else if (action instanceof LayToken) { @@ -194,6 +198,26 @@ public class SoundEventInterpreter { }); } + //subscribe to changes to game over pending + if (gameManager.getGameOverPendingModel() != null) { + gameManager.getGameOverPendingModel().addObserver( + new Observer() { + private boolean gameOverPending = false; + public void update(Observable o, Object arg) { + if (o instanceof BooleanState) { + BooleanState s = (BooleanState)o; + if (!gameOverPending && s.booleanValue()) { + if (SoundConfig.isSFXEnabled()) { + player.playSFXByConfigKey ( + SoundConfig.KEY_SFX_GEN_GameOverPending); + } + } + gameOverPending = s.booleanValue(); + } + } + }); + } + //subscribe to phase changes if (gameManager.getPhaseManager() != null) { gameManager.getPhaseManager().getCurrentPhaseModel().addObserver( commit 2614a3132315acee7b4a2411314b26754accc5c9 Merge: 08f42f7 b16bcfb Author: Frederick Weld <fre...@gm...> Date: Sun Feb 5 07:28:05 2012 +0100 Exposed GameManager's GameOverPending BooleanState on interface commit b16bcfb3f1d186b10fbe6fc6a8bae95019ad15bf Author: Frederick Weld <fre...@gm...> Date: Sun Feb 5 07:19:48 2012 +0100 Exposed GameManager's GameOverPending BooleanState on interface diff --git a/LocalisedText.properties b/LocalisedText.properties index 071d381..6aaa145 100644 --- a/LocalisedText.properties +++ b/LocalisedText.properties @@ -178,6 +178,7 @@ Config.infoText.sound.backgroundMusic=The only music file type supported is mp3. Config.infoText.sound.backgroundMusic.stockRound=<html>Enter assignment of music files to phases.<ul><li>Separate the assignments by commas.<li>Each assignment has the syntax phaseName=complete file path<li>Default music is defined by omitting "phaseName=" in the assignment.</ul><strong>Examples:</strong><ul><li>Set default music: <br><code>c:\SR-default.mp3</code><li>Set phase-dependent music and a default (for trains above 6): <br><code>2=c:\SR-2.mp3,3=c:\SR-3.mp3,4=c:\SR-4.mp3,5=c:\SR-5.mp3,6=c:\SR-6.mp3,c:\SR-D.mp3</code></ul> </html> Config.infoText.sound.backgroundMusic.operatingRound=<html>Enter assignment of music files to phases.<ul><li>Separate the assignments by commas.<li>Each assignment has the syntax phaseName=complete file path<li>Default music is defined by omitting "phaseName=" in the assignment.</ul><strong>Examples:</strong><ul><li>Set default music: <br><code>c:\OR-default.mp3</code><li>Set phase-dependent music and a default (for trains above 6): <br><code>2=c:\OR-2.mp3,3=c:\OR-3.mp3,4=c:\OR-4.mp3,5=c:\OR-5.mp3,6=c:\OR-6.mp3,c:\OR-D.mp3</code></ul> </html> Config.infoText.sound.sfx=The only sound effects file type supported is mp3. +Config.infoText.sound.sfx.gen.gameOverPending=<html>Sound effect is played in case of any event that triggers the end of the game. Examples:<ul><li>Bank is broken.<li>Share price reaches maximum (only game-end trigger for some 18xx variants).</ul></html> Config.infoText.sound.sfx.gen.newCurrentPlayer=<html>Enter assignment of sound effect files to player names.<br>The assigned sound is played if the player becomes the active one - meaning, the user interface is responsive for this player's commands.<ul><li>Separate the assignments by commas.<li>Each assignment has the syntax playerName=complete file path<li>Default sound effect is defined by omitting "playerName=" in the assignment.</ul><strong>Examples:</strong><ul><li>Set default sound effect: <br><code>c:\ChangeActivePlayer.mp3</code><li>Set player-dependent sound effect and a default (for all other players): <br><code>Tom=c:\ChangeActivePlayer_Tom.mp3,Sarah=c:\ChangeActivePlayer_Sarah.mp3,c:\ChangeActivePlayer_default.mp3</code></ul> </html> Config.infoText.sound.sfx.or.buyTrain=<html>Enter assignment of sound effect files to train types.<ul><li>Separate the assignments by commas.<li>Each assignment has the syntax trainName=complete file path<li>Default sound effect is defined by omitting "trainName=" in the assignment.</ul><strong>Examples:</strong><ul><li>Set default sound effect: <br><code>c:\BuyTrain-default.mp3</code><li>Set train-dependent sound effect and a default (for trains above 6): <br><code>2=c:\BuyTrain-2.mp3,3=c:\BuyTrain-3.mp3,4=c:\BuyTrain-4.mp3,5=c:\BuyTrain-5.mp3,6=c:\BuyTrain-6.mp3,c:\BuyTrain-D.mp3</code></ul> </html> Config.infoText.sound.sfx.or.setRevenue=<html><ul><li>Only the latter portion of this file is played.<ul><li>For an average revenue, the last third is played.</ul><li>The higher the company's revenue the longer this file is played.<ul><li>But the file is at most played once as a whole.</li></ul></html> @@ -216,6 +217,7 @@ Config.label.sound.backgroundMusic.startRound=Start Round Config.label.sound.backgroundMusic.stockRound=Stock Round (several files) Config.label.sound.backgroundMusic.operatingRound=Operating Round (several files) Config.label.sound.sfx=Sound Effects +Config.label.sound.sfx.gen.gameOverPending=Imminent Game End Config.label.sound.sfx.gen.newCurrentPlayer=Change of active player Config.label.sound.sfx.gen.pass=Pass Config.label.sound.sfx.gen.select=Select (hexes, click fields) @@ -228,6 +230,7 @@ Config.label.sound.sfx.or.decision.split=Split Revenue Config.label.sound.sfx.or.decision.withhold=Withhold Revenue Config.label.sound.sfx.or.layTile.city=Lay Tile (city) Config.label.sound.sfx.or.layTile.track=Lay Tile (track, town) +Config.label.sound.sfx.or.layTile.lastTileLaid=Last available tile is laid Config.label.sound.sfx.or.layToken=Lay Token Config.label.sound.sfx.or.rotateTile=Rotate Tile Config.label.sound.sfx.or.setRevenue=Set Revenue diff --git a/data/Properties.xml b/data/Properties.xml index 4802f74..da62099 100644 --- a/data/Properties.xml +++ b/data/Properties.xml @@ -77,6 +77,7 @@ <Property name="sound.sfx.gen.pass" type="FILE" /> <Property name="sound.sfx.gen.select" type="FILE" /> <Property name="sound.sfx.gen.newCurrentPlayer" type="STRING" /> + <Property name="sound.sfx.gen.gameOverPending" type="FILE" /> <Property name="sound.sfx.str.bidStartItem" type="FILE" /> <Property name="sound.sfx.str.buyStartItem" type="FILE" /> <Property name="sound.sfx.sr.openingBell" type="FILE" /> @@ -89,6 +90,7 @@ <Property name="sound.sfx.or.rotateTile" type="FILE" /> <Property name="sound.sfx.or.layTile.track" type="FILE" /> <Property name="sound.sfx.or.layTile.city" type="FILE" /> + <Property name="sound.sfx.or.layTile.lastTileLaid" type="FILE" /> <Property name="sound.sfx.or.layToken" type="FILE" /> <Property name="sound.sfx.or.setRevenue" type="FILE" /> <Property name="sound.sfx.or.decision.payout" type="FILE" /> diff --git a/rails/game/GameManager.java b/rails/game/GameManager.java index c4c2289..f35ed6a 100644 --- a/rails/game/GameManager.java +++ b/rails/game/GameManager.java @@ -1380,6 +1380,10 @@ public class GameManager implements ConfigurableComponentI, GameManagerI { return gameOver.booleanValue(); } + public ModelObject getGameOverPendingModel() { + return gameOverPending; + } + public void setGameOverReportedUI(boolean b){ gameOverReportedUI = b; } diff --git a/rails/game/GameManagerI.java b/rails/game/GameManagerI.java index f098de6..06b404c 100644 --- a/rails/game/GameManagerI.java +++ b/rails/game/GameManagerI.java @@ -80,6 +80,8 @@ public interface GameManagerI extends MoveableHolder, ConfigurableComponentI { */ public abstract boolean isGameOver(); + public ModelObject getGameOverPendingModel(); + public void setGameOverReportedUI(boolean b); public boolean getGameOverReportedUI(); diff --git a/rails/sound/SoundConfig.java b/rails/sound/SoundConfig.java index 6867ddf..5e3aa03 100644 --- a/rails/sound/SoundConfig.java +++ b/rails/sound/SoundConfig.java @@ -24,6 +24,7 @@ public class SoundConfig { public static final String KEY_BGM_OperatingRound = "sound.backgroundMusic.operatingRound"; public static final String KEY_BGM_EndOfGameRound = "sound.backgroundMusic.endOfGameRound"; public static final String KEY_SFX_Enabled = "sound.sfx"; + public static final String KEY_SFX_GEN_GameOverPending = "sound.sfx.gen.gameOverPending"; public static final String KEY_SFX_GEN_Pass = "sound.sfx.gen.pass"; public static final String KEY_SFX_GEN_Select = "sound.sfx.gen.select"; public static final String KEY_SFX_GEN_NewCurrentPlayer = "sound.sfx.gen.newCurrentPlayer"; @@ -37,8 +38,9 @@ public class SoundConfig { public static final String KEY_SFX_SR_SellShare_NonPresident = "sound.sfx.sr.sellShare.nonPresident"; public static final String KEY_SFX_SR_CompanyFloats = "sound.sfx.sr.companyFloats"; public static final String KEY_SFX_OR_RotateTile = "sound.sfx.or.rotateTile"; - public static final String KEY_SFX_OR_LayTile_track = "sound.sfx.or.layTile.track"; - public static final String KEY_SFX_OR_LayTile_city = "sound.sfx.or.layTile.city"; + public static final String KEY_SFX_OR_LayTile_Track = "sound.sfx.or.layTile.track"; + public static final String KEY_SFX_OR_LayTile_City = "sound.sfx.or.layTile.city"; + public static final String KEY_SFX_OR_LayTile_LastTileLaid = "sound.sfx.or.layTile.lastTileLaid"; public static final String KEY_SFX_OR_LayToken = "sound.sfx.or.layToken"; public static final String KEY_SFX_OR_SetRevenue = "sound.sfx.or.setRevenue"; public static final String KEY_SFX_OR_Decision_Payout = "sound.sfx.or.decision.payout"; diff --git a/rails/sound/SoundEventInterpreter.java b/rails/sound/SoundEventInterpreter.java index 48a8df2..889ade6 100644 --- a/rails/sound/SoundEventInterpreter.java +++ b/rails/sound/SoundEventInterpreter.java @@ -105,10 +105,14 @@ public class SoundEventInterpreter { LayTile lt = (LayTile)action; if (lt.getLaidTile().getNumStations() == 0) { //track upgrade - player.playSFXByConfigKey (SoundConfig.KEY_SFX_OR_LayTile_track); + player.playSFXByConfigKey (SoundConfig.KEY_SFX_OR_LayTile_Track); } else { //city upgrade - player.playSFXByConfigKey (SoundConfig.KEY_SFX_OR_LayTile_city); + player.playSFXByConfigKey (SoundConfig.KEY_SFX_OR_LayTile_City); + } + if (lt.getLaidTile().countFreeTiles() == 1) { + //last available tile is about to be laid + player.playSFXByConfigKey (SoundConfig.KEY_SFX_OR_LayTile_LastTileLaid); } } else if (action instanceof LayToken) { @@ -194,6 +198,26 @@ public class SoundEventInterpreter { }); } + //subscribe to changes to game over pending + if (gameManager.getGameOverPendingModel() != null) { + gameManager.getGameOverPendingModel().addObserver( + new Observer() { + private boolean gameOverPending = false; + public void update(Observable o, Object arg) { + if (o instanceof BooleanState) { + BooleanState s = (BooleanState)o; + if (!gameOverPending && s.booleanValue()) { + if (SoundConfig.isSFXEnabled()) { + player.playSFXByConfigKey ( + SoundConfig.KEY_SFX_GEN_GameOverPending); + } + } + gameOverPending = s.booleanValue(); + } + } + }); + } + //subscribe to phase changes if (gameManager.getPhaseManager() != null) { gameManager.getPhaseManager().getCurrentPhaseModel().addObserver( |