/** * Copyright (C) 2002-2012 The FreeCol Team * * This file is part of FreeCol. * * FreeCol is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * FreeCol is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with FreeCol. If not, see <http://www.gnu.org/licenses/>. */ package net.sf.freecol.client.gui.panel; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.freecolandroid.repackaged.javax.swing.JButton; import org.freecolandroid.repackaged.javax.swing.JTextPane; import org.freecolandroid.repackaged.javax.swing.JViewport; import org.freecolandroid.repackaged.javax.swing.text.StyleConstants; import org.freecolandroid.repackaged.javax.swing.text.StyledDocument; import net.miginfocom.swing.MigLayout; import net.sf.freecol.client.FreeColClient; import net.sf.freecol.client.gui.GUI; import net.sf.freecol.client.gui.i18n.Messages; import net.sf.freecol.common.model.Building; import net.sf.freecol.common.model.Colony; import net.sf.freecol.common.model.ColonyTile; import net.sf.freecol.common.model.GoodsType; import net.sf.freecol.common.model.Map.Direction; import net.sf.freecol.common.model.ProductionInfo; import net.sf.freecol.common.model.Specification; import net.sf.freecol.common.model.StringTemplate; import net.sf.freecol.common.model.Tile; import net.sf.freecol.common.model.TypeCountMap; import net.sf.freecol.common.model.Unit; import net.sf.freecol.common.model.UnitType; /** * This panel displays the Advanced Colony Report. */ public final class ReportRequirementsPanel extends ReportPanel { /** * A list of all the player's colonies. */ private List<Colony> colonies; /** * Records the number of units indexed by colony and unit type. */ private Map<Colony, TypeCountMap<UnitType>> unitCount = new HashMap<Colony, TypeCountMap<UnitType>>(); /** * Records whether a colony can train a type of unit. */ private Map<Colony, Set<UnitType>> canTrain = new HashMap<Colony, Set<UnitType>>(); /** * The constructor that will add the items to this panel. * @param freeColClient * * @param gui The parent of this panel. */ public ReportRequirementsPanel(FreeColClient freeColClient, GUI gui) { super(freeColClient, gui, Messages.message("reportRequirementsAction.name")); colonies = getSortedColonies(); // Display Panel // create a text pane JTextPane textPane = getDefaultTextPane(); StyledDocument doc = textPane.getStyledDocument(); // check which colonies can train which units for (Colony colony : colonies) { TypeCountMap<UnitType> newUnitCount = new TypeCountMap<UnitType>(); Set<UnitType> newCanTrain = new HashSet<UnitType>(); for (Unit unit : colony.getUnitList()) { newUnitCount.incrementCount(unit.getType(), 1); if (colony.canTrain(unit.getType())) { newCanTrain.add(unit.getType()); } } unitCount.put(colony, newUnitCount); canTrain.put(colony, newCanTrain); } for (Colony colony : colonies) { checkColony(colony, doc); } // text area int width = ((JViewport) reportPanel.getParent()).getWidth(); reportPanel.setLayout(new MigLayout("width " + width + "!")); reportPanel.add(textPane); textPane.setCaretPosition(0); } private void checkColony(Colony colony, StyledDocument doc) { final Specification spec = getSpecification(); try { if (doc.getLength() > 0) { doc.insertString(doc.getLength(), "\n\n", doc.getStyle("regular")); } StyleConstants.setComponent(doc.getStyle("button"), createColonyButton(colony, true)); doc.insertString(doc.getLength(), " ", doc.getStyle("button")); } catch (Exception e) { logger.warning(e.toString()); } Set<UnitType> missingExpertWarning = new HashSet<UnitType>(); Set<UnitType> badAssignmentWarning = new HashSet<UnitType>(); Set<GoodsType> productionWarning = new HashSet<GoodsType>(); // Check if all unit requirements are met. for (Unit expert : colony.getUnitList()) { if (expert.getSkillLevel() <= 0) continue; Unit better = colony.getBetterExpert(expert); if (better != null && !badAssignmentWarning.contains(expert)) { addBadAssignmentWarning(doc, colony, expert, better); badAssignmentWarning.add(expert.getType()); } } for (ColonyTile colonyTile : colony.getColonyTiles()) { for (Unit unit : colonyTile.getUnitList()) { GoodsType workType = unit.getWorkType(); UnitType expert = spec.getExpertForProducing(workType); if (unitCount.get(colony).getCount(expert) == 0 && !missingExpertWarning.contains(expert)) { addExpertWarning(doc, colony, workType, expert); missingExpertWarning.add(expert); } } } for (Building building : colony.getBuildings()) { GoodsType goodsType = building.getGoodsOutputType(); UnitType expert = building.getExpertUnitType(); // check if this building has no expert producing goods if (goodsType != null && expert != null && !building.getUnitList().isEmpty() && !missingExpertWarning.contains(expert) && unitCount.get(colony).getCount(expert) == 0) { addExpertWarning(doc, colony, goodsType, expert); missingExpertWarning.add(expert); } // not enough input ProductionInfo info = building.getProductionInfo(); if (goodsType != null && info != null && !info.hasMaximumProduction() && !productionWarning.contains(goodsType)) { addProductionWarning(doc, colony, goodsType, building.getGoodsInputType()); productionWarning.add(goodsType); } } List<Tile> exploreTiles = new ArrayList<Tile>(); List<Tile> clearTiles = new ArrayList<Tile>(); List<Tile> plowTiles = new ArrayList<Tile>(); List<Tile> roadTiles = new ArrayList<Tile>(); colony.getColonyTileTodo(exploreTiles, clearTiles, plowTiles, roadTiles); for (Tile t : exploreTiles) { addTileWarning(doc, colony, "report.requirements.exploreTile", t); } for (Tile t : clearTiles) { addTileWarning(doc, colony, "report.requirements.clearTile", t); } for (Tile t : plowTiles) { if (t == colony.getTile()) { addPlowCenterWarning(doc, colony); } else { addTileWarning(doc, colony, "report.requirements.plowTile", t); } } for (Tile t : roadTiles) { addTileWarning(doc, colony, "report.requirements.roadTile", t); } if (exploreTiles.isEmpty() && clearTiles.isEmpty() && plowTiles.isEmpty() && roadTiles.isEmpty() && missingExpertWarning.isEmpty() && badAssignmentWarning.isEmpty() && productionWarning.isEmpty()) { try { doc.insertString(doc.getLength(), "\n\n" + Messages.message("report.requirements.met"), doc.getStyle("regular")); } catch (Exception e) { logger.warning(e.toString()); } } } private void addTileWarning(StyledDocument doc, Colony colony, String messageId, Tile tile) { Direction direction = colony.getTile().getDirection(tile); String message = Messages.message(StringTemplate.template(messageId) .add("%type%", tile.getType().getNameKey()) .add("%direction%", direction.getNameKey()) .addName("%colony%", colony.getName())); try { doc.insertString(doc.getLength(), "\n\n" + message, doc.getStyle("regular")); } catch (Exception e) { logger.warning(e.toString()); } } private void addPlowCenterWarning(StyledDocument doc, Colony colony) { String message = Messages.message(StringTemplate.template("report.requirements.plowCenter") .addName("%colony%", colony.getName())); try { doc.insertString(doc.getLength(), "\n\n" + message, doc.getStyle("regular")); } catch (Exception e) { logger.warning(e.toString()); } } private void addBadAssignmentWarning(StyledDocument doc, Colony colony, Unit expert, Unit nonExpert) { GoodsType expertGoods = expert.getWorkType(); GoodsType nonExpertGoods = nonExpert.getWorkType(); String colonyName = colony.getName(); String expertName = Messages.message(expert.getType().getNameKey()); String nonExpertName = Messages.message(nonExpert.getType().getNameKey()); String expertProductionName = Messages.message(expertGoods.getWorkingAsKey()); String nonExpertProductionName = Messages.message(nonExpertGoods.getWorkingAsKey()); String newMessage = Messages.message(StringTemplate.template("report.requirements.badAssignment") .addName("%colony%", colonyName) .addName("%expert%", expertName) .addName("%expertWork%", expertProductionName) .addName("%nonExpert%", nonExpertName) .addName("%nonExpertWork%", nonExpertProductionName)); try { doc.insertString(doc.getLength(), "\n\n" + newMessage, doc.getStyle("regular")); } catch(Exception e) { logger.warning(e.toString()); } } private void addExpertWarning(StyledDocument doc, Colony c, GoodsType goodsType, UnitType workType) { String newMessage = Messages.message(StringTemplate.template("report.requirements.noExpert") .addName("%colony%", c.getName()) .addName("%goods%", goodsType) .addName("%unit%", workType)); try { doc.insertString(doc.getLength(), "\n\n" + newMessage, doc.getStyle("regular")); ArrayList<Colony> misusedExperts = new ArrayList<Colony>(); ArrayList<Colony> severalExperts = new ArrayList<Colony>(); ArrayList<Colony> canTrainExperts = new ArrayList<Colony>(); for (Colony colony : colonies) { for (Unit unit : colony.getUnitList()) { GoodsType expertise = unit.getType().getExpertProduction(); if ((unit.getSkillLevel() > 0) && (expertise == goodsType)) { if (unit.getLocation() instanceof Building) { if (((Building) unit.getLocation()).getGoodsOutputType() != goodsType) { misusedExperts.add(colony); } } else if (expertise != unit.getWorkType()) { misusedExperts.add(colony); } } } if (unitCount.get(colony).getCount(workType) > 1) { severalExperts.add(colony); } if (canTrain.get(colony).contains(workType)) { canTrainExperts.add(colony); } } if (!misusedExperts.isEmpty()) { doc.insertString(doc.getLength(), "\n" + Messages.message(StringTemplate.template("report.requirements.misusedExperts") .addName("%unit%", workType) .add("%work%", goodsType.getWorkingAsKey())) + " ", doc.getStyle("regular")); insertColonyButtons(doc, misusedExperts); } if (!severalExperts.isEmpty()) { doc.insertString(doc.getLength(), "\n" + Messages.message(StringTemplate.template("report.requirements.severalExperts") .addName("%unit%", workType)) + " ", doc.getStyle("regular")); insertColonyButtons(doc, severalExperts); } if (!canTrainExperts.isEmpty()) { doc.insertString(doc.getLength(), "\n" + Messages.message(StringTemplate.template("report.requirements.canTrainExperts") .addName("%unit%", workType)) + " ", doc.getStyle("regular")); insertColonyButtons(doc, canTrainExperts); } } catch(Exception e) { logger.warning(e.toString()); } } private void insertColonyButtons(StyledDocument doc, List<Colony> colonies) throws Exception { for (Colony colony : colonies) { StyleConstants.setComponent(doc.getStyle("button"), createColonyButton(colony, false)); doc.insertString(doc.getLength(), " ", doc.getStyle("button")); doc.insertString(doc.getLength(), ", ", doc.getStyle("regular")); } doc.remove(doc.getLength() - 2, 2); } private void addProductionWarning(StyledDocument doc, Colony colony, GoodsType output, GoodsType input) { String colonyName = colony.getName(); String newMessage = Messages.message(StringTemplate.template("report.requirements.missingGoods") .addName("%colony%", colonyName) .add("%goods%", output.getNameKey()) .add("%input%", input.getNameKey())); try { doc.insertString(doc.getLength(), "\n\n" + newMessage, doc.getStyle("regular")); ArrayList<Colony> withSurplus = new ArrayList<Colony>(); ArrayList<Integer> theSurplus = new ArrayList<Integer>(); for (Colony col : colonies) { int amount = colony.getAdjustedNetProductionOf(input); if (amount > 0) { withSurplus.add(col); theSurplus.add(amount); } } if (!withSurplus.isEmpty()) { doc.insertString(doc.getLength(), "\n" + Messages.message(StringTemplate.template("report.requirements.surplus") .add("%goods%", input.getNameKey())) + " ", doc.getStyle("regular")); for (int index = 0; index < withSurplus.size() - 1; index++) { String amount = " (" + theSurplus.get(index) + ")"; StyleConstants.setComponent(doc.getStyle("button"), createColonyButton(withSurplus.get(index), amount, false)); doc.insertString(doc.getLength(), " ", doc.getStyle("button")); doc.insertString(doc.getLength(), ", ", doc.getStyle("regular")); } Colony lastColony = withSurplus.get(withSurplus.size() - 1); String amount = " (" + theSurplus.get(theSurplus.size() - 1) + ")"; StyleConstants.setComponent(doc.getStyle("button"), createColonyButton(lastColony, amount, false)); doc.insertString(doc.getLength(), " ", doc.getStyle("button")); } } catch(Exception e) { logger.warning(e.toString()); } } private JButton createColonyButton(Colony colony, boolean headline) { return createColonyButton(colony, "", headline); } private JButton createColonyButton(Colony colony, String info, boolean headline) { JButton button = getLinkButton(colony.getName() + info, null, colony.getId()); if (headline) { button.setFont(smallHeaderFont); } button.addActionListener(this); return button; } }